Adding instrumentation to locate the source of jankiness.
[chromium-blink-merge.git] / tools / sync-webkit-git.py
blob4babf1114e4632957fd484441e8e4b1dcd78aea6
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.
6 """Update third_party/WebKit using git.
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.
11 See http://code.google.com/p/chromium/wiki/UsingWebKitGit for details on
12 how to use this.
13 """
15 import logging
16 import optparse
17 import os
18 import re
19 import subprocess
20 import sys
21 import urllib
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
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])
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.
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
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)
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']
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)
80 def HasGitRev(target_rev):
81 """Finds if a git hash exists in the repository."""
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
89 def GetRemote():
90 branch = GetOverrideShortBranchName()
91 if not branch:
92 branch = 'gclient'
94 remote = RunGit(['config', '--get', 'branch.' + branch + '.remote'])
95 if remote:
96 return remote
97 return 'origin'
100 def UpdateGClientBranch(webkit_rev, magic_gclient_branch):
101 """Update the magic gclient branch to point at |webkit_rev|.
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)
112 current = RunGit(['show-ref', '--hash', magic_gclient_branch])
113 if current == webkit_rev:
114 return False # No change necessary.
116 subprocess.check_call(['git', 'update-ref', '-m', 'gclient sync',
117 magic_gclient_branch, webkit_rev],
118 shell=(os.name == 'nt'))
119 return True
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
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'))
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?"
153 print "See http://code.google.com/p/chromium/wiki/UsingWebKitGit for"
154 print "setup instructions."
155 return 1
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()
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
178 if __name__ == '__main__':
179 sys.exit(main())