tools/git-sync-deps: enforce commit hash in DEPS, not tags or branches

Change variable name to reflect that.

Also, pass '--no-checkout' to git-clone to suppress "warning: remote
HEAD refers to nonexistent ref, unable to checkout" error message.

Also, change '@' to '>' in verbose output if anything changes in the
repositories.

Change-Id: I27d0b026d121c163e378f34ab2bbe81233ddba1a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/252177
Reviewed-by: Eric Boren <borenet@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
diff --git a/tools/git-sync-deps b/tools/git-sync-deps
index c7379c0..ff121b1 100755
--- a/tools/git-sync-deps
+++ b/tools/git-sync-deps
@@ -99,16 +99,17 @@
     return False
 
 
-def status(directory, checkoutable):
+def status(directory, commithash, change):
   def truncate(s, length):
     return s if len(s) <= length else s[:(length - 3)] + '...'
   dlen = 36
   directory = truncate(directory, dlen)
-  checkoutable = truncate(checkoutable, 40)
-  sys.stdout.write('%-*s @ %s\n' % (dlen, directory, checkoutable))
+  commithash = truncate(commithash, 40)
+  symbol = '>' if change else '@'
+  sys.stdout.write('%-*s %s %s\n' % (dlen, directory, symbol, commithash))
 
 
-def git_checkout_to_directory(git, repo, checkoutable, directory, verbose):
+def git_checkout_to_directory(git, repo, commithash, directory, verbose):
   """Checkout (and clone if needed) a Git repository.
 
   Args:
@@ -117,8 +118,7 @@
     repo (string) the location of the repository, suitable
          for passing to `git clone`.
 
-    checkoutable (string) a tag, branch, or commit, suitable for
-                 passing to `git checkout`
+    commithash (string) a commit, suitable for passing to `git checkout`
 
     directory (string) the path into which the repository
               should be checked out.
@@ -129,7 +129,12 @@
   """
   if not os.path.isdir(directory):
     subprocess.check_call(
-      [git, 'clone', '--quiet', repo, directory])
+      [git, 'clone', '--quiet', '--no-checkout', repo, directory])
+    subprocess.check_call([git, 'checkout', '--quiet', commithash],
+                          cwd=directory)
+    if verbose:
+      status(directory, commithash, True)
+    return
 
   if not is_git_toplevel(git, directory):
     # if the directory exists, but isn't a git repo, you will modify
@@ -145,11 +150,11 @@
   with open(os.devnull, 'w') as devnull:
     # If this fails, we will fetch before trying again.  Don't spam user
     # with error infomation.
-    if 0 == subprocess.call([git, 'checkout', '--quiet', checkoutable],
+    if 0 == subprocess.call([git, 'checkout', '--quiet', commithash],
                             cwd=directory, stderr=devnull):
       # if this succeeds, skip slow `git fetch`.
       if verbose:
-        status(directory, checkoutable)  # Success.
+        status(directory, commithash, False)  # Success.
       return
 
   # If the repo has changed, always force use of the correct repo.
@@ -159,10 +164,10 @@
 
   subprocess.check_call([git, 'fetch', '--quiet'], cwd=directory)
 
-  subprocess.check_call([git, 'checkout', '--quiet', checkoutable], cwd=directory)
+  subprocess.check_call([git, 'checkout', '--quiet', commithash], cwd=directory)
 
   if verbose:
-    status(directory, checkoutable)  # Success.
+    status(directory, commithash, True)  # Success.
 
 
 def parse_file_to_dict(path):
@@ -171,6 +176,11 @@
   return dictionary
 
 
+def is_sha1_sum(s):
+  """SHA1 sums are 160 bits, encoded as lowercase hexadecimal."""
+  return len(s) == 40 and all(c in '0123456789abcdef' for c in s)
+
+
 def git_sync_deps(deps_file_path, command_line_os_requests, verbose):
   """Grab dependencies, with optional platform support.
 
@@ -209,14 +219,16 @@
         print 'Skipping "%s".' % directory
       continue
     if '@' in dependencies[directory]:
-      repo, checkoutable = dependencies[directory].split('@', 1)
+      repo, commithash = dependencies[directory].split('@', 1)
     else:
-      raise Exception("please specify commit or tag")
+      raise Exception("please specify commit")
+    if not is_sha1_sum(commithash):
+      raise Exception("poorly formed commit hash: %r" % commithash)
 
     relative_directory = os.path.join(deps_file_directory, directory)
 
     list_of_arg_lists.append(
-      (git, repo, checkoutable, relative_directory, verbose))
+      (git, repo, commithash, relative_directory, verbose))
 
   multithread(git_checkout_to_directory, list_of_arg_lists)