Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """Update third_party/WebKit using git.
      7 
      8 Under the assumption third_party/WebKit is a clone of git.webkit.org,
      9 we can use git commands to make it match the version requested by DEPS.
     10 
     11 See http://code.google.com/p/chromium/wiki/UsingWebKitGit for details on
     12 how to use this.
     13 """
     14 
     15 import logging
     16 import optparse
     17 import os
     18 import re
     19 import subprocess
     20 import sys
     21 import urllib
     22 
     23 
     24 def RunGit(command):
     25   """Run a git subcommand, returning its output."""
     26   # On Windows, use shell=True to get PATH interpretation.
     27   command = ['git'] + command
     28   logging.info(' '.join(command))
     29   shell = (os.name == 'nt')
     30   proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE)
     31   out = proc.communicate()[0].strip()
     32   logging.info('Returned "%s"' % out)
     33   return out
     34 
     35 
     36 def GetOverrideShortBranchName():
     37   """Returns the user-configured override branch name, if any."""
     38   override_config_name = 'chromium.sync-branch'
     39   return RunGit(['config', '--get', override_config_name])
     40 
     41 
     42 def GetGClientBranchName():
     43   """Returns the name of the magic branch that lets us know that DEPS is
     44   managing the update cycle."""
     45   # Is there an override branch specified?
     46   override_branch_name = GetOverrideShortBranchName()
     47   if not override_branch_name:
     48     return 'refs/heads/gclient' # No override, so return the default branch.
     49 
     50   # Verify that the branch from config exists.
     51   ref_branch = 'refs/heads/' + override_branch_name
     52   current_head = RunGit(['show-ref', '--hash', ref_branch])
     53   if current_head:
     54     return ref_branch
     55 
     56   # Inform the user about the problem and how to fix it.
     57   print ("The specified override branch ('%s') doesn't appear to exist." %
     58          override_branch_name)
     59   print "Please fix your git config value '%s'." % overide_config_name
     60   sys.exit(1)
     61 
     62 
     63 def GetWebKitRev():
     64   """Extract the 'webkit_revision' variable out of DEPS."""
     65   locals = {'Var': lambda _: locals["vars"][_],
     66             'From': lambda *args: None}
     67   execfile('DEPS', {}, locals)
     68   return locals['vars']['webkit_revision']
     69 
     70 
     71 def GetWebKitRevFromTarball(version):
     72   """Extract the 'webkit_revision' variable out of tarball DEPS."""
     73   deps_url = "http://src.chromium.org/svn/releases/" + version + "/DEPS"
     74   f = urllib.urlopen(deps_url)
     75   s = f.read()
     76   m = re.search('(?<=/Source@)\w+', s)
     77   return m.group(0)
     78 
     79 
     80 def HasGitRev(target_rev):
     81   """Finds if a git hash exists in the repository."""
     82 
     83   cmd = ['git', 'rev-list', '--max-count=1', target_rev]
     84   logging.info(' '.join(cmd))
     85   result = subprocess.call(cmd, shell=(os.name == 'nt'), stdout=subprocess.PIPE)
     86   return result == 0
     87 
     88 
     89 def GetRemote():
     90   branch = GetOverrideShortBranchName()
     91   if not branch:
     92     branch = 'gclient'
     93 
     94   remote = RunGit(['config', '--get', 'branch.' + branch + '.remote'])
     95   if remote:
     96     return remote
     97   return 'origin'
     98 
     99 
    100 def UpdateGClientBranch(webkit_rev, magic_gclient_branch):
    101   """Update the magic gclient branch to point at |webkit_rev|.
    102 
    103   Returns: true if the branch didn't need changes."""
    104   if not HasGitRev(webkit_rev):
    105     print "%s not available; fetching." % webkit_rev
    106     subprocess.check_call(['git', 'fetch', GetRemote()],
    107                           shell=(os.name == 'nt'))
    108     if not HasGitRev(webkit_rev):
    109       print "ERROR: Couldn't find %s in the repository." % webkit_rev
    110       sys.exit(1)
    111 
    112   current = RunGit(['show-ref', '--hash', magic_gclient_branch])
    113   if current == webkit_rev:
    114     return False  # No change necessary.
    115 
    116   subprocess.check_call(['git', 'update-ref', '-m', 'gclient sync',
    117                          magic_gclient_branch, webkit_rev],
    118                          shell=(os.name == 'nt'))
    119   return True
    120 
    121 
    122 def UpdateCurrentCheckoutIfAppropriate(magic_gclient_branch):
    123   """Reset the current gclient branch if that's what we have checked out."""
    124   branch = RunGit(['symbolic-ref', '-q', 'HEAD'])
    125   if branch != magic_gclient_branch:
    126     print "We have now updated the 'gclient' branch, but third_party/WebKit"
    127     print "has some other branch ('%s') checked out." % branch
    128     print "Run 'git checkout gclient' under third_party/WebKit if you want"
    129     print "to switch it to the version requested by DEPS."
    130     return 1
    131 
    132   if subprocess.call(['git', 'diff-index', '--exit-code', '--shortstat',
    133                       'HEAD'], shell=(os.name == 'nt')):
    134     print "Resetting tree state to new revision."
    135     subprocess.check_call(['git', 'reset', '--hard'], shell=(os.name == 'nt'))
    136 
    137 
    138 def main():
    139   parser = optparse.OptionParser()
    140   parser.add_option('-v', '--verbose', action='store_true')
    141   parser.add_option('-r', '--revision', help="switch to desired revision")
    142   parser.add_option('-t', '--tarball', help="switch to desired tarball release")
    143   options, args = parser.parse_args()
    144   if options.verbose:
    145     logging.basicConfig(level=logging.INFO)
    146   if not os.path.exists('third_party/WebKit/.git'):
    147     if os.path.exists('third_party/WebKit'):
    148       print "ERROR: third_party/WebKit appears to not be under git control."
    149     else:
    150       print "ERROR: third_party/WebKit could not be found."
    151       print "Did you run this script from the right directory?"
    152 
    153     print "See http://code.google.com/p/chromium/wiki/UsingWebKitGit for"
    154     print "setup instructions."
    155     return 1
    156 
    157   if options.revision:
    158     webkit_rev = options.revision
    159     if options.tarball:
    160       print "WARNING: --revision is given, so ignore --tarball"
    161   else:
    162     if options.tarball:
    163       webkit_rev = GetWebKitRevFromTarball(options.tarball)
    164     else:
    165       webkit_rev = GetWebKitRev()
    166 
    167   print 'Desired revision: %s.' % webkit_rev
    168   os.chdir('third_party/WebKit')
    169   magic_gclient_branch = GetGClientBranchName()
    170   changed = UpdateGClientBranch(webkit_rev, magic_gclient_branch)
    171   if changed:
    172     return UpdateCurrentCheckoutIfAppropriate(magic_gclient_branch)
    173   else:
    174     print "Already on correct revision."
    175   return 0
    176 
    177 
    178 if __name__ == '__main__':
    179   sys.exit(main())
    180