Add workaround to ignore the first solution specified with --revision solution@rev

TEST=new smoke test
BUG=chromiums-os:3465

Review URL: http://codereview.chromium.org/2304002

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@48490 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gclient.py b/gclient.py
index 2da24b2..5813029 100644
--- a/gclient.py
+++ b/gclient.py
@@ -503,6 +503,36 @@
       if matching_file_list:
         self._RunHookAction(hook_dict, matching_file_list)
 
+  def _EnforceRevisions(self, solutions):
+    """Checks for revision overrides."""
+    revision_overrides = {}
+    solutions = [s['name'] for s in solutions]
+    if self._options.revisions:
+      revision = self._options.revisions[0]
+      # Ignore solution@
+      rev = revision
+      if '@' in revision:
+        rev = revision.split('@', 1)[1]
+      revision_overrides[solutions[0]] = rev
+
+    if len(self._options.revisions) > 1:
+      # Enforce solution@rev format for following params.
+      for revision in self._options.revisions[1:]:
+        if not '@' in revision:
+          raise gclient_utils.Error(
+              'Specify the full dependency when specifying a revision number '
+              'for non-primary solution.')
+        sol, rev = revision.split("@", 1)
+        # Disallow conflicting revs
+        if revision_overrides.get(sol, rev) != rev:
+          raise gclient_utils.Error(
+              'Conflicting revision numbers specified for %s: %s and %s.' %
+                  (sol, revision_overrides[sol], rev))
+        if not sol in solutions:
+          raise gclient_utils.Error('%s is not a valid solution.' % sol)
+        revision_overrides[sol] = rev
+    return revision_overrides
+
   def RunOnDeps(self, command, args):
     """Runs a command on each dependency in a client and its dependencies.
 
@@ -518,23 +548,10 @@
     if not command in self.supported_commands:
       raise gclient_utils.Error("'%s' is an unsupported command" % command)
 
-    # Check for revision overrides.
-    revision_overrides = {}
-    for revision in self._options.revisions:
-      if revision.find("@") == -1:
-        raise gclient_utils.Error(
-            "Specify the full dependency when specifying a revision number.")
-      revision_elem = revision.split("@")
-      # Disallow conflicting revs
-      if revision_overrides.has_key(revision_elem[0]) and \
-         revision_overrides[revision_elem[0]] != revision_elem[1]:
-        raise gclient_utils.Error(
-            "Conflicting revision numbers specified.")
-      revision_overrides[revision_elem[0]] = revision_elem[1]
-
     solutions = self.GetVar("solutions")
     if not solutions:
       raise gclient_utils.Error("No solution specified")
+    revision_overrides = self._EnforceRevisions(solutions)
 
     # When running runhooks --force, there's no need to consult the SCM.
     # All known hooks are expected to run unconditionally regardless of working
@@ -679,35 +696,13 @@
     """Output revision info mapping for the client and its dependencies.
 
     This allows the capture of an overall "revision" for the source tree that
-    can be used to reproduce the same tree in the future. The actual output
-    contains enough information (source paths, svn server urls and revisions)
-    that it can be used either to generate external svn/git commands (without
-    gclient) or as input to gclient's --rev option (with some massaging of
-    the data).
-
-    Since we care about the revision of the current source tree, for git
-    repositories this command uses the revision of the HEAD. For subversion we
-    use BASE.
+    can be used to reproduce the same tree in the future. It is only useful for
+    "unpinned dependencies", i.e. DEPS/deps references without a svn revision
+    number or a git hash. A git branch name isn't "pinned" since the actual
+    commit can change.
 
     The --snapshot option allows creating a .gclient file to reproduce the tree.
-
-    Raises:
-      Error: If the client has conflicting entries.
     """
-    # Check for revision overrides.
-    revision_overrides = {}
-    for revision in self._options.revisions:
-      if revision.find("@") < 0:
-        raise gclient_utils.Error(
-            "Specify the full dependency when specifying a revision number.")
-      revision_elem = revision.split("@")
-      # Disallow conflicting revs
-      if revision_overrides.has_key(revision_elem[0]) and \
-         revision_overrides[revision_elem[0]] != revision_elem[1]:
-        raise gclient_utils.Error(
-            "Conflicting revision numbers specified.")
-      revision_overrides[revision_elem[0]] = revision_elem[1]
-
     solutions = self.GetVar("solutions")
     if not solutions:
       raise gclient_utils.Error("No solution specified")
@@ -933,9 +928,10 @@
                     help="don't run hooks after the update is complete")
   parser.add_option("-r", "--revision", action="append",
                     dest="revisions", metavar="REV", default=[],
-                    help="update given solution to specified revision, "
-                         "can be used multiple times for each solution, "
-                         "e.g. -r src@123, -r internal@32")
+                    help="Enforces revision/hash for the primary solution. "
+                         "To modify a secondary solution, use it at least once "
+                         "for the primary solution and then use the format "
+                         "solution@rev/hash, e.g. -r src@123")
   parser.add_option("--head", action="store_true",
                     help="skips any safesync_urls specified in "
                          "configured solutions and sync to head instead")
@@ -959,15 +955,18 @@
   if not options.head:
     solutions = client.GetVar('solutions')
     if solutions:
+      first = True
       for s in solutions:
-        if s.get('safesync_url', ''):
+        if s.get('safesync_url', None):
           # rip through revisions and make sure we're not over-riding
           # something that was explicitly passed
           has_key = False
+          r_first = True
           for r in options.revisions:
-            if r.split('@')[0] == s['name']:
+            if (first and r_first) or r.split('@', 1)[0] == s['name']:
               has_key = True
               break
+            r_first = False
 
           if not has_key:
             handle = urllib.urlopen(s['safesync_url'])
@@ -975,6 +974,7 @@
             handle.close()
             if len(rev):
               options.revisions.append(s['name']+'@'+rev)
+        first = False
 
   if options.verbose:
     # Print out the .gclient file.  This is longer than if we just printed the