Add a baground color for Ash on Windows
[chromium-blink-merge.git] / tools / sync-webkit-git.py
blob3c7c5484c7d4bc2795e6755d5a1b57a9a502b790
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 FindSVNRev(branch_name, target_rev):
81 """Map an SVN revision to a git hash.
82 Like 'git svn find-rev' but without the git-svn bits."""
84 # We iterate through the commit log looking for "git-svn-id" lines,
85 # which contain the SVN revision of that commit. We can stop once
86 # we've found our target (or hit a revision number lower than what
87 # we're looking for, indicating not found).
89 target_rev = int(target_rev)
91 # regexp matching the "commit" line from the log.
92 commit_re = re.compile(r'^commit ([a-f\d]{40})$')
93 # regexp matching the git-svn line from the log.
94 git_svn_re = re.compile(r'^\s+git-svn-id: [^@]+@(\d+) ')
95 if not branch_name:
96 branch_name = 'origin/master'
97 cmd = ['git', 'log', '--no-color', '--first-parent', '--pretty=medium',
98 branch_name]
99 logging.info(' '.join(cmd))
100 log = subprocess.Popen(cmd, shell=(os.name == 'nt'), stdout=subprocess.PIPE)
101 # Track whether we saw a revision *later* than the one we're seeking.
102 saw_later = False
103 for line in log.stdout:
104 match = commit_re.match(line)
105 if match:
106 commit = match.group(1)
107 continue
108 match = git_svn_re.match(line)
109 if match:
110 rev = int(match.group(1))
111 if rev <= target_rev:
112 log.stdout.close() # Break pipe.
113 if rev < target_rev:
114 if not saw_later:
115 return None # Can't be sure whether this rev is ok.
116 print ("WARNING: r%d not found, so using next nearest earlier r%d" %
117 (target_rev, rev))
118 return commit
119 else:
120 saw_later = True
122 print "Error: reached end of log without finding commit info."
123 print "Something has likely gone horribly wrong."
124 return None
127 def GetRemote():
128 branch = GetOverrideShortBranchName()
129 if not branch:
130 branch = 'gclient'
132 remote = RunGit(['config', '--get', 'branch.' + branch + '.remote'])
133 if remote:
134 return remote
135 return 'origin'
138 def UpdateGClientBranch(branch_name, webkit_rev, magic_gclient_branch):
139 """Update the magic gclient branch to point at |webkit_rev|.
141 Returns: true if the branch didn't need changes."""
142 target = FindSVNRev(branch_name, webkit_rev)
143 if not target:
144 print "r%s not available; fetching." % webkit_rev
145 subprocess.check_call(['git', 'fetch', GetRemote()],
146 shell=(os.name == 'nt'))
147 target = FindSVNRev(branch_name, webkit_rev)
148 if not target:
149 print "ERROR: Couldn't map r%s to a git revision." % webkit_rev
150 sys.exit(1)
152 current = RunGit(['show-ref', '--hash', magic_gclient_branch])
153 if current == target:
154 return False # No change necessary.
156 subprocess.check_call(['git', 'update-ref', '-m', 'gclient sync',
157 magic_gclient_branch, target],
158 shell=(os.name == 'nt'))
159 return True
162 def UpdateCurrentCheckoutIfAppropriate(magic_gclient_branch):
163 """Reset the current gclient branch if that's what we have checked out."""
164 branch = RunGit(['symbolic-ref', '-q', 'HEAD'])
165 if branch != magic_gclient_branch:
166 print "We have now updated the 'gclient' branch, but third_party/WebKit"
167 print "has some other branch ('%s') checked out." % branch
168 print "Run 'git checkout gclient' under third_party/WebKit if you want"
169 print "to switch it to the version requested by DEPS."
170 return 1
172 if subprocess.call(['git', 'diff-index', '--exit-code', '--shortstat',
173 'HEAD'], shell=(os.name == 'nt')):
174 print "Resetting tree state to new revision."
175 subprocess.check_call(['git', 'reset', '--hard'], shell=(os.name == 'nt'))
178 def main():
179 parser = optparse.OptionParser()
180 parser.add_option('-v', '--verbose', action='store_true')
181 parser.add_option('-r', '--revision', help="switch to desired revision")
182 parser.add_option('-t', '--tarball', help="switch to desired tarball release")
183 parser.add_option('-b', '--branch', help="branch name that gclient generate")
184 options, args = parser.parse_args()
185 if options.verbose:
186 logging.basicConfig(level=logging.INFO)
187 if not os.path.exists('third_party/WebKit/.git'):
188 if os.path.exists('third_party/WebKit'):
189 print "ERROR: third_party/WebKit appears to not be under git control."
190 else:
191 print "ERROR: third_party/WebKit could not be found."
192 print "Did you run this script from the right directory?"
194 print "See http://code.google.com/p/chromium/wiki/UsingWebKitGit for"
195 print "setup instructions."
196 return 1
198 if options.revision:
199 webkit_rev = options.revision
200 if options.tarball:
201 print "WARNING: --revision is given, so ignore --tarball"
202 else:
203 if options.tarball:
204 webkit_rev = GetWebKitRevFromTarball(options.tarball)
205 else:
206 webkit_rev = GetWebKitRev()
208 print 'Desired revision: r%s.' % webkit_rev
209 os.chdir('third_party/WebKit')
210 magic_gclient_branch = GetGClientBranchName()
211 changed = UpdateGClientBranch(options.branch, webkit_rev,
212 magic_gclient_branch)
213 if changed:
214 return UpdateCurrentCheckoutIfAppropriate(magic_gclient_branch)
215 else:
216 print "Already on correct revision."
217 return 0
220 if __name__ == '__main__':
221 sys.exit(main())