blob: 39849176aa78d98abff68a355dd46b22969053df [file] [log] [blame]
[email protected]cabf2ad2009-08-22 01:26:311#!/usr/bin/python
[email protected]6f943c22009-09-01 00:41:142# Copyright (c) 2009 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.
[email protected]565db0e2009-06-05 18:08:545
[email protected]cabf2ad2009-08-22 01:26:316import getpass
7import optparse
8import os
9import subprocess
10import tempfile
11import traceback
12import urllib
13import sys
[email protected]b0e621f2009-08-25 21:01:5114import re
15import trychange
[email protected]565db0e2009-06-05 18:08:5416
[email protected]cabf2ad2009-08-22 01:26:3117
[email protected]742eb522009-09-22 16:18:4218def Backquote(cmd, cwd=None):
[email protected]cabf2ad2009-08-22 01:26:3119 """Like running `cmd` in a shell script."""
[email protected]742eb522009-09-22 16:18:4220 return subprocess.Popen(cmd,
21 cwd=cwd,
22 stdout=subprocess.PIPE).communicate()[0].strip()
[email protected]cabf2ad2009-08-22 01:26:3123
24
25def GetTryServerConfig():
26 """Returns the dictionary of try server options or None if they
27 cannot be found."""
28 script_path = 'tools/tryserver/tryserver.py'
29 root_dir = Backquote(['git', 'rev-parse', '--show-cdup'])
30 try:
31 script_file = open(os.path.join(root_dir, script_path))
32 except IOError:
33 return None
34 locals = {}
35 try:
36 exec(script_file, locals)
37 except Exception, e:
38 return None
39 return locals
40
41
[email protected]742eb522009-09-22 16:18:4242def GetBranchName(working_dir=None):
[email protected]cabf2ad2009-08-22 01:26:3143 """Return name of current git branch."""
[email protected]742eb522009-09-22 16:18:4244 branch = Backquote(['git', 'symbolic-ref', 'HEAD'], working_dir)
[email protected]cabf2ad2009-08-22 01:26:3145 if not branch.startswith('refs/heads/'):
46 raise "Couldn't figure out branch name"
47 branch = branch[len('refs/heads/'):]
48 return branch
49
50
[email protected]742eb522009-09-22 16:18:4251def GetPatchName(working_dir=None):
[email protected]cabf2ad2009-08-22 01:26:3152 """Construct a name for this patch."""
[email protected]742eb522009-09-22 16:18:4253 short_sha = Backquote(['git', 'rev-parse', '--short=4', 'HEAD'], working_dir)
[email protected]cabf2ad2009-08-22 01:26:3154 return GetBranchName() + '-' + short_sha
55
56
[email protected]cabf2ad2009-08-22 01:26:3157def GetRietveldIssueNumber():
58 return Backquote(['git', 'config',
59 'branch.%s.rietveldissue' % GetBranchName()])
60
61
62def GetRietveldPatchsetNumber():
63 return Backquote(['git', 'config',
64 'branch.%s.rietveldpatchset' % GetBranchName()])
65
[email protected]742eb522009-09-22 16:18:4266def GetSubRepWorkingDir(sub_rep_path):
67 """Computes the path to the sub repository"""
68 if sub_rep_path:
69 root_dir = os.path.abspath(Backquote(['git', 'rev-parse', '--show-cdup']))
70 return os.path.join(root_dir, sub_rep_path)
71 return None
[email protected]cabf2ad2009-08-22 01:26:3172
[email protected]742eb522009-09-22 16:18:4273def GetMungedDiff(branch, prefix, sub_rep_path):
74 """Get the diff we'll send to the try server. We munge paths to match svn.
[email protected]de243452009-10-06 21:02:5675 We add the prefix that the try bot is expecting. If sub_rep_path is
76 provided, diff will be calculated in the sub repository.
77 We also return the list of files in this diff, without munged paths."""
[email protected]cabf2ad2009-08-22 01:26:3178 # Make the following changes:
[email protected]832179b2009-09-17 17:13:2479 # - Prepend "src/" (or some other prefix) to paths as svn is expecting
[email protected]cabf2ad2009-08-22 01:26:3180 # - In the case of added files, replace /dev/null with the path to the file
81 # being added.
[email protected]742eb522009-09-22 16:18:4282
83 cwd = GetSubRepWorkingDir(sub_rep_path)
84
[email protected]cabf2ad2009-08-22 01:26:3185 output = []
86 if not branch:
87 # Try to guess the upstream branch.
[email protected]742eb522009-09-22 16:18:4288 branch = Backquote(['git', 'cl', 'upstream'], cwd)
89 command = ['git', 'diff-tree', '-p']
90
91 new_cwd = None
92 if not sub_rep_path:
93 command.extend(['--no-prefix'])
94 else:
95 # Append /
96 sub_rep_path = os.path.join(sub_rep_path, '')
97 # Add the right prefix
98 command.extend(['--src-prefix=' + sub_rep_path])
99 command.extend(['--dst-prefix=' + sub_rep_path])
[email protected]de243452009-10-06 21:02:56100
[email protected]742eb522009-09-22 16:18:42101 command.extend([branch, 'HEAD'])
102
103 # Run diff tree
104 diff = subprocess.Popen(command,
105 stdout=subprocess.PIPE,
106 cwd=cwd).stdout.readlines()
107 # Replace --- /dev/null with --- <new file name>
[email protected]cabf2ad2009-08-22 01:26:31108 for i in range(len(diff)):
109 line = diff[i]
110 if line.startswith('--- /dev/null'):
[email protected]742eb522009-09-22 16:18:42111 line = '--- %s' % diff[i+1][4:]
112 output.append(line)
113 diff = output
114
115 # Add root prefix
116 output = []
[email protected]de243452009-10-06 21:02:56117 file_set = set()
[email protected]742eb522009-09-22 16:18:42118 for line in diff:
119 if line.startswith('--- ') or line.startswith('+++ '):
[email protected]de243452009-10-06 21:02:56120 filename = line[4:]
121 line = line[0:4] + os.path.join(prefix, filename)
122 file_set.add(filename.rstrip('\r\n'))
[email protected]cabf2ad2009-08-22 01:26:31123 output.append(line)
124
125 munged_diff = ''.join(output)
126 if len(munged_diff.strip()) == 0:
127 raise Exception("Patch was empty, did you give the right remote branch?")
128
[email protected]de243452009-10-06 21:02:56129 return (munged_diff, list(file_set))
[email protected]cabf2ad2009-08-22 01:26:31130
[email protected]742eb522009-09-22 16:18:42131def OneRepositoryDiff(diff_file, patch_names, branch, prefix, sub_rep_path):
132 """Computes a diff for one git repository at a given path against a given
133 branch. Writes the diff into diff_file and appends a name to the
[email protected]de243452009-10-06 21:02:56134 patch_names list.
135
136 Returns the list of files in the diff."""
137
138 (diff, file_list) = GetMungedDiff(branch, prefix, sub_rep_path)
[email protected]742eb522009-09-22 16:18:42139
140 # Write the diff out
141 diff_file.write(diff)
142
143 # Add patch name to list of patches
144 patch_name = GetPatchName(GetSubRepWorkingDir(sub_rep_path))
145 patch_names.extend([patch_name])
[email protected]de243452009-10-06 21:02:56146 return file_list
[email protected]742eb522009-09-22 16:18:42147
[email protected]cabf2ad2009-08-22 01:26:31148
[email protected]b0e621f2009-08-25 21:01:51149def ValidEmail(email):
150 return re.match(r"^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email)
151
152
[email protected]cabf2ad2009-08-22 01:26:31153def GetEmail():
[email protected]b0e621f2009-08-25 21:01:51154 email = Backquote(['git', 'config', 'user.email'])
155 runmsg = "Try: git config user.email <EMAIL>"
156 assert ValidEmail(email), "Email '%s' is not valid. %s" % (email, runmsg)
157 return email
[email protected]cabf2ad2009-08-22 01:26:31158
159
[email protected]de243452009-10-06 21:02:56160def TryChange(args, file_list):
[email protected]b0e621f2009-08-25 21:01:51161 """Put a patch on the try server."""
[email protected]de243452009-10-06 21:02:56162 trychange.TryChange(args, file_list, False)
[email protected]cabf2ad2009-08-22 01:26:31163
164
[email protected]cabf2ad2009-08-22 01:26:31165if __name__ == '__main__':
166 parser = optparse.OptionParser(
167 usage='git try [options] [branch]',
168 description='Upload the current diff of branch...HEAD to the try server.')
[email protected]6f3c2c62009-10-15 20:36:26169 parser.add_option("-b", "--bot", action="append",
[email protected]cabf2ad2009-08-22 01:26:31170 help="Force the use of a specific build slave (eg mac, "
171 "win, or linux)")
172 parser.add_option("-c", "--clobber", action="store_true",
173 help="Make the try run use be a clobber build")
174 parser.add_option("-r", "--revision",
175 help="Specify the SVN base revision to use")
[email protected]742eb522009-09-22 16:18:42176 parser.add_option("--root", default="src", metavar="PATH",
[email protected]de243452009-10-06 21:02:56177 help="Specify the root prefix that is prepended to paths "
[email protected]742eb522009-09-22 16:18:42178 "in the patch")
179 parser.add_option("--dry_run", action="store_true",
180 help="Print the diff but don't send it to the try bots")
[email protected]de243452009-10-06 21:02:56181 parser.add_option("--sub_rep", nargs=2, action="append", default=[],
182 metavar="PATH BRANCH",
[email protected]742eb522009-09-22 16:18:42183 help="Specify a path to a git sub-repository and a branch "
184 "to diff with in order to simultanously try changes "
185 "in multiple git repositories. Option may be "
186 "specified multiple times.")
187 parser.add_option("--webkit", metavar="BRANCH",
188 help="Specify webkit branch. Syntactic sugar for "
189 "--sub_rep third_party/WebKit/ <branch>")
[email protected]de243452009-10-06 21:02:56190
[email protected]cabf2ad2009-08-22 01:26:31191 (options, args) = parser.parse_args(sys.argv)
192
[email protected]742eb522009-09-22 16:18:42193 if options.webkit:
194 options.sub_rep.extend([('third_party/WebKit/', options.webkit)])
195
[email protected]cabf2ad2009-08-22 01:26:31196 branch = None
197 if len(args) > 1:
198 branch = args[1]
[email protected]742eb522009-09-22 16:18:42199 patch_names = []
[email protected]cabf2ad2009-08-22 01:26:31200
[email protected]742eb522009-09-22 16:18:42201 # Dump all diffs into one diff file.
[email protected]b0e621f2009-08-25 21:01:51202 diff_file = tempfile.NamedTemporaryFile()
[email protected]de243452009-10-06 21:02:56203
[email protected]742eb522009-09-22 16:18:42204 # Calculate diff for main git repository.
[email protected]de243452009-10-06 21:02:56205 file_list = OneRepositoryDiff(diff_file, patch_names, branch, options.root,
206 None)
207
[email protected]742eb522009-09-22 16:18:42208 # Calculate diff for each extra git repository.
209 for path_and_branch in options.sub_rep:
[email protected]de243452009-10-06 21:02:56210 file_list.extend(OneRepositoryDiff(diff_file,
211 patch_names,
212 path_and_branch[1],
213 options.root,
214 path_and_branch[0]))
[email protected]742eb522009-09-22 16:18:42215 # Make diff file ready for reading.
[email protected]b0e621f2009-08-25 21:01:51216 diff_file.flush()
217
[email protected]742eb522009-09-22 16:18:42218 # Concatenate patch names
219 # Prepare args for TryChange
[email protected]b0e621f2009-08-25 21:01:51220 email = GetEmail()
221 user = email.partition('@')[0]
222 args = [
223 '-u', user,
224 '-e', email,
[email protected]742eb522009-09-22 16:18:42225 '-n', '-'.join(patch_names),
[email protected]de243452009-10-06 21:02:56226 '--diff', diff_file.name,
[email protected]b0e621f2009-08-25 21:01:51227 ]
228
229 # Send to try server via HTTP if we can parse the config, otherwise
[email protected]cabf2ad2009-08-22 01:26:31230 # upload via SVN.
231 config = GetTryServerConfig()
232 if config is not None:
[email protected]742eb522009-09-22 16:18:42233 sendmsg = "Sending %s using HTTP..." % '-'.join(patch_names)
[email protected]b0e621f2009-08-25 21:01:51234 args.extend(['--use_http'])
235 if config['try_server_http_host'] is not None:
236 args.extend(['--host', config['try_server_http_host']])
237 if config['try_server_http_port'] is not None:
238 args.extend(['--port', config['try_server_http_port']])
239
[email protected]cabf2ad2009-08-22 01:26:31240 else:
241 print "Could not get server config -- if you're within Google, "
242 print "do you have have src-internal checked out?"
[email protected]8871f452009-09-23 15:48:36243 sendmsg = "Sending %s using SVN..." % '-'.join(patch_names)
[email protected]b0e621f2009-08-25 21:01:51244 args.extend([
245 '--use_svn', '--svn_repo',
246 'svn://svn.chromium.org/chrome-try/try',
247 ])
[email protected]cabf2ad2009-08-22 01:26:31248
[email protected]5ab676c2009-10-16 00:15:46249 if options.bot:
250 for bot in options.bot:
251 args.extend(['--bot', bot])
[email protected]b0e621f2009-08-25 21:01:51252 if options.clobber:
253 args.append('--clobber')
254 if options.revision:
255 args.extend(['-r', options.revision])
[email protected]b0e621f2009-08-25 21:01:51256 if GetRietveldPatchsetNumber():
257 args.extend([
258 '--issue', GetRietveldIssueNumber(),
259 '--patchset', GetRietveldPatchsetNumber(),
260 ])
[email protected]cabf2ad2009-08-22 01:26:31261
[email protected]742eb522009-09-22 16:18:42262 if options.dry_run:
263 print open(diff_file.name, 'r').read()
264 exit(0)
265
[email protected]b0e621f2009-08-25 21:01:51266 print sendmsg
[email protected]de243452009-10-06 21:02:56267 TryChange(args, file_list)