Merge changes from topic "windows-support"

* changes:
  Port os.rename calls to work on Windows
  Workaround shutil.rmtree limitation on Windows
  Add support for creating symbolic links on Windows
  Make "git command" and "forall" work on Windows
diff --git a/git_config.py b/git_config.py
index e00f6be..8c24739 100644
--- a/git_config.py
+++ b/git_config.py
@@ -50,16 +50,24 @@
 from git_command import GitCommand
 from git_command import ssh_sock
 from git_command import terminate_ssh_clients
+from git_refs import R_CHANGES, R_HEADS, R_TAGS
 
-R_HEADS = 'refs/heads/'
-R_TAGS  = 'refs/tags/'
 ID_RE = re.compile(r'^[0-9a-f]{40}$')
 
 REVIEW_CACHE = dict()
 
+def IsChange(rev):
+  return rev.startswith(R_CHANGES)
+
 def IsId(rev):
   return ID_RE.match(rev)
 
+def IsTag(rev):
+  return rev.startswith(R_TAGS)
+
+def IsImmutable(rev):
+    return IsChange(rev) or IsId(rev) or IsTag(rev)
+
 def _key(name):
   parts = name.split('.')
   if len(parts) < 2:
diff --git a/git_refs.py b/git_refs.py
index 3c26606..58c838a 100644
--- a/git_refs.py
+++ b/git_refs.py
@@ -16,11 +16,12 @@
 import os
 from trace import Trace
 
-HEAD    = 'HEAD'
-R_HEADS = 'refs/heads/'
-R_TAGS  = 'refs/tags/'
-R_PUB   = 'refs/published/'
-R_M     = 'refs/remotes/m/'
+HEAD      = 'HEAD'
+R_CHANGES = 'refs/changes/'
+R_HEADS   = 'refs/heads/'
+R_TAGS    = 'refs/tags/'
+R_PUB     = 'refs/published/'
+R_M       = 'refs/remotes/m/'
 
 
 class GitRefs(object):
diff --git a/progress.py b/progress.py
index d948654..0dd5d1a 100644
--- a/progress.py
+++ b/progress.py
@@ -21,7 +21,8 @@
 _NOT_TTY = not os.isatty(2)
 
 class Progress(object):
-  def __init__(self, title, total=0, units=''):
+  def __init__(self, title, total=0, units='', print_newline=False,
+               always_print_percentage=False):
     self._title = title
     self._total = total
     self._done = 0
@@ -29,6 +30,8 @@
     self._start = time()
     self._show = False
     self._units = units
+    self._print_newline = print_newline
+    self._always_print_percentage = always_print_percentage
 
   def update(self, inc=1):
     self._done += inc
@@ -50,13 +53,14 @@
     else:
       p = (100 * self._done) / self._total
 
-      if self._lastp != p:
+      if self._lastp != p or self._always_print_percentage:
         self._lastp = p
-        sys.stderr.write('\r%s: %3d%% (%d%s/%d%s)  ' % (
+        sys.stderr.write('\r%s: %3d%% (%d%s/%d%s)%s' % (
           self._title,
           p,
           self._done, self._units,
-          self._total, self._units))
+          self._total, self._units,
+          "\n" if self._print_newline else ""))
         sys.stderr.flush()
 
   def end(self):
diff --git a/project.py b/project.py
index e8de484..e700d16 100644
--- a/project.py
+++ b/project.py
@@ -177,11 +177,15 @@
   def UploadForReview(self, people,
                       auto_topic=False,
                       draft=False,
+                      private=False,
+                      wip=False,
                       dest_branch=None):
     self.project.UploadForReview(self.name,
                                  people,
                                  auto_topic=auto_topic,
                                  draft=draft,
+                                 private=private,
+                                 wip=wip,
                                  dest_branch=dest_branch)
 
   def GetPublishedRefs(self):
@@ -1108,6 +1112,8 @@
                       people=([], []),
                       auto_topic=False,
                       draft=False,
+                      private=False,
+                      wip=False,
                       dest_branch=None):
     """Uploads the named branch for code review.
     """
@@ -1159,9 +1165,14 @@
                                   dest_branch)
     if auto_topic:
       ref_spec = ref_spec + '/' + branch.name
+
     if not url.startswith('ssh://'):
       rp = ['r=%s' % p for p in people[0]] + \
            ['cc=%s' % p for p in people[1]]
+      if private:
+        rp = rp + ['private']
+      if wip:
+        rp = rp + ['wip']
       if rp:
         ref_spec = ref_spec + '%' + ','.join(rp)
     cmd.append(ref_spec)
@@ -1275,7 +1286,7 @@
 
     need_to_fetch = not (optimized_fetch and
                          (ID_RE.match(self.revisionExpr) and
-                          self._CheckForSha1()))
+                          self._CheckForImmutableRevision()))
     if (need_to_fetch and
         not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir,
                               current_branch_only=current_branch_only,
@@ -1885,7 +1896,7 @@
 
 
 # Direct Git Commands ##
-  def _CheckForSha1(self):
+  def _CheckForImmutableRevision(self):
     try:
       # if revision (sha or tag) is not present then following function
       # throws an error.
@@ -1939,7 +1950,9 @@
         tag_name = self.revisionExpr[len(R_TAGS):]
 
       if is_sha1 or tag_name is not None:
-        if self._CheckForSha1():
+        if self._CheckForImmutableRevision():
+          print('Skipped fetching project %s (already have persistent ref)'
+                % self.name)
           return True
       if is_sha1 and not depth:
         # When syncing a specific commit and --depth is not set:
@@ -2095,7 +2108,7 @@
       # We just synced the upstream given branch; verify we
       # got what we wanted, else trigger a second run of all
       # refs.
-      if not self._CheckForSha1():
+      if not self._CheckForImmutableRevision():
         if current_branch_only and depth:
           # Sync the current branch only with depth set to None
           return self._RemoteFetch(name=name,
@@ -2961,14 +2974,14 @@
           self.revisionExpr = base
           self.revisionId = None
 
-  def MetaBranchSwitch(self):
+  def MetaBranchSwitch(self, submodules=False):
     """ Prepare MetaProject for manifest branch switch
     """
 
     # detach and delete manifest branch, allowing a new
     # branch to take over
     syncbuf = SyncBuffer(self.config, detach_head=True)
-    self.Sync_LocalHalf(syncbuf)
+    self.Sync_LocalHalf(syncbuf, submodules=submodules)
     syncbuf.Finish()
 
     return GitCommand(self,
diff --git a/subcmds/download.py b/subcmds/download.py
index a029462..e1010aa 100644
--- a/subcmds/download.py
+++ b/subcmds/download.py
@@ -26,11 +26,12 @@
   common = True
   helpSummary = "Download and checkout a change"
   helpUsage = """
-%prog {project change[/patchset]}...
+%prog {[project] change[/patchset]}...
 """
   helpDescription = """
 The '%prog' command downloads a change from the review system and
 makes it available in your project's local working directory.
+If no project is specified try to use current directory as a project.
 """
 
   def _Options(self, p):
@@ -55,7 +56,7 @@
       m = CHANGE_RE.match(a)
       if m:
         if not project:
-          self.Usage()
+          project = self.GetProjects(".")[0]
         chg_id = int(m.group(1))
         if m.group(2):
           ps_id = int(m.group(2))
diff --git a/subcmds/init.py b/subcmds/init.py
index e647091..eeddca0 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -256,7 +256,7 @@
       sys.exit(1)
 
     if opt.manifest_branch:
-      m.MetaBranchSwitch()
+      m.MetaBranchSwitch(submodules=opt.submodules)
 
     syncbuf = SyncBuffer(m.config)
     m.Sync_LocalHalf(syncbuf, submodules=opt.submodules)
diff --git a/subcmds/stage.py b/subcmds/stage.py
index 2884976..9d35426 100644
--- a/subcmds/stage.py
+++ b/subcmds/stage.py
@@ -60,8 +60,8 @@
       out.nl()
 
       for i in range(len(all_projects)):
-        p = all_projects[i]
-        out.write('%3d:    %s', i + 1, p.relpath + '/')
+        project = all_projects[i]
+        out.write('%3d:    %s', i + 1, project.relpath + '/')
         out.nl()
       out.nl()
 
diff --git a/subcmds/start.py b/subcmds/start.py
index 290b689..c3ec303 100644
--- a/subcmds/start.py
+++ b/subcmds/start.py
@@ -18,7 +18,7 @@
 import sys
 
 from command import Command
-from git_config import IsId
+from git_config import IsImmutable
 from git_command import git
 import gitc_utils
 from progress import Progress
@@ -96,11 +96,11 @@
           project.Sync_LocalHalf(sync_buf)
           project.revisionId = gitc_project.old_revision
 
-      # If the current revision is a specific SHA1 then we can't push back
-      # to it; so substitute with dest_branch if defined, or with manifest
-      # default revision instead.
+      # If the current revision is immutable, such as a SHA1, a tag or
+      # a change, then we can't push back to it. Substitute with
+      # dest_branch, if defined; or with manifest default revision instead.
       branch_merge = ''
-      if IsId(project.revisionExpr):
+      if IsImmutable(project.revisionExpr):
         if project.dest_branch:
           branch_merge = project.dest_branch
         else:
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 797fc40..b88c596 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -356,7 +356,9 @@
   def _Fetch(self, projects, opt):
     fetched = set()
     lock = _threading.Lock()
-    pm = Progress('Fetching projects', len(projects))
+    pm = Progress('Fetching projects', len(projects),
+                  print_newline=not(opt.quiet),
+                  always_print_percentage=opt.quiet)
 
     objdir_project_map = dict()
     for project in projects:
@@ -393,7 +395,7 @@
       t.join()
 
     # If we saw an error, exit with code 1 so that other scripts can check.
-    if err_event.isSet():
+    if err_event.isSet() and not opt.force_broken:
       print('\nerror: Exited sync due to fetch errors', file=sys.stderr)
       sys.exit(1)
 
@@ -779,8 +781,8 @@
       # generate a new args list to represent the opened projects.
       # TODO: make this more reliable -- if there's a project name/path overlap,
       # this may choose the wrong project.
-      args = [os.path.relpath(self.manifest.paths[p].worktree, os.getcwd())
-              for p in opened_projects]
+      args = [os.path.relpath(self.manifest.paths[path].worktree, os.getcwd())
+              for path in opened_projects]
       if not args:
         return
     all_projects = self.GetProjects(args,
diff --git a/subcmds/upload.py b/subcmds/upload.py
index 1172dad..61b18bc 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -154,6 +154,12 @@
     p.add_option('-d', '--draft',
                  action='store_true', dest='draft', default=False,
                  help='If specified, upload as a draft.')
+    p.add_option('-p', '--private',
+                 action='store_true', dest='private', default=False,
+                 help='If specified, upload as a private change.')
+    p.add_option('-w', '--wip',
+                 action='store_true', dest='wip', default=False,
+                 help='If specified, upload as a work-in-progress change.')
     p.add_option('-D', '--destination', '--dest',
                  type='string', action='store', dest='dest_branch',
                  metavar='BRANCH',
@@ -198,7 +204,8 @@
       commit_list = branch.commits
 
       destination = opt.dest_branch or project.dest_branch or project.revisionExpr
-      print('Upload project %s/ to remote branch %s:' % (project.relpath, destination))
+      print('Upload project %s/ to remote branch %s%s:' %
+            (project.relpath, destination, ' (draft)' if opt.draft else ''))
       print('  branch %s (%2d commit%s, %s):' % (
                     name,
                     len(commit_list),
@@ -377,7 +384,12 @@
             branch.uploaded = False
             continue
 
-        branch.UploadForReview(people, auto_topic=opt.auto_topic, draft=opt.draft, dest_branch=destination)
+        branch.UploadForReview(people,
+                               auto_topic=opt.auto_topic,
+                               draft=opt.draft,
+                               private=opt.private,
+                               wip=opt.wip,
+                               dest_branch=destination)
         branch.uploaded = True
       except UploadError as e:
         branch.error = e
@@ -463,8 +475,8 @@
                       self.manifest.topdir,
                       self.manifest.manifestProject.GetRemote('origin').url,
                       abort_if_user_denies=True)
-      pending_proj_names = [project.name for (project, avail) in pending]
-      pending_worktrees = [project.worktree for (project, avail) in pending]
+      pending_proj_names = [project.name for (project, available) in pending]
+      pending_worktrees = [project.worktree for (project, available) in pending]
       try:
         hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
                  worktree_list=pending_worktrees)