manifest: Support a default upstream value

It's convenient to set upstream for all projects in a manifest instead of
repeating the same value for each project.

Change-Id: I946b1de4efb01b351c332dfad108fa7d4f443cba
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index 56bdf14..0c957dd 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -44,6 +44,7 @@
     <!ATTLIST default remote      IDREF #IMPLIED>
     <!ATTLIST default revision    CDATA #IMPLIED>
     <!ATTLIST default dest-branch CDATA #IMPLIED>
+    <!ATTLIST default upstream    CDATA #IMPLIED>
     <!ATTLIST default sync-j      CDATA #IMPLIED>
     <!ATTLIST default sync-c      CDATA #IMPLIED>
     <!ATTLIST default sync-s      CDATA #IMPLIED>
@@ -164,6 +165,11 @@
 this value. If this value is not set, projects will use `revision`
 by default instead.
 
+Attribute `upstream`: Name of the Git ref in which a sha1
+can be found.  Used when syncing a revision locked manifest in
+-c mode to avoid having to sync the entire ref space. Project elements
+not setting their own `upstream` will inherit this value.
+
 Attribute `sync-j`: Number of parallel jobs to use when synching.
 
 Attribute `sync-c`: Set to true to only sync the given Git
diff --git a/manifest_xml.py b/manifest_xml.py
index 60d6116..d0211ea 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -59,6 +59,7 @@
 
   revisionExpr = None
   destBranchExpr = None
+  upstreamExpr = None
   remote = None
   sync_j = 1
   sync_c = False
@@ -230,6 +231,9 @@
     if d.destBranchExpr:
       have_default = True
       e.setAttribute('dest-branch', d.destBranchExpr)
+    if d.upstreamExpr:
+      have_default = True
+      e.setAttribute('upstream', d.upstreamExpr)
     if d.sync_j > 1:
       have_default = True
       e.setAttribute('sync-j', '%d' % d.sync_j)
@@ -295,7 +299,8 @@
         revision = self.remotes[p.remote.orig_name].revision or d.revisionExpr
         if not revision or revision != p.revisionExpr:
           e.setAttribute('revision', p.revisionExpr)
-        if p.upstream and p.upstream != p.revisionExpr:
+        if (p.upstream and (p.upstream != p.revisionExpr or
+                            p.upstream != d.upstreamExpr)):
           e.setAttribute('upstream', p.upstream)
 
       if p.dest_branch and p.dest_branch != d.destBranchExpr:
@@ -694,6 +699,7 @@
       d.revisionExpr = None
 
     d.destBranchExpr = node.getAttribute('dest-branch') or None
+    d.upstreamExpr = node.getAttribute('upstream') or None
 
     sync_j = node.getAttribute('sync-j')
     if sync_j == '' or sync_j is None:
@@ -830,7 +836,7 @@
 
     dest_branch = node.getAttribute('dest-branch') or self._default.destBranchExpr
 
-    upstream = node.getAttribute('upstream')
+    upstream = node.getAttribute('upstream') or self._default.upstreamExpr
 
     groups = ''
     if node.hasAttribute('groups'):