You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
8.5 KiB
Python
267 lines
8.5 KiB
Python
#!/usr/bin/python
|
|
# Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import getpass
|
|
import optparse
|
|
import os
|
|
import subprocess
|
|
import tempfile
|
|
import traceback
|
|
import urllib
|
|
import sys
|
|
import re
|
|
import trychange
|
|
|
|
|
|
def Backquote(cmd, cwd=None):
|
|
"""Like running `cmd` in a shell script."""
|
|
return subprocess.Popen(cmd,
|
|
cwd=cwd,
|
|
stdout=subprocess.PIPE).communicate()[0].strip()
|
|
|
|
|
|
def GetTryServerConfig():
|
|
"""Returns the dictionary of try server options or None if they
|
|
cannot be found."""
|
|
script_path = 'tools/tryserver/tryserver.py'
|
|
root_dir = Backquote(['git', 'rev-parse', '--show-cdup'])
|
|
try:
|
|
script_file = open(os.path.join(root_dir, script_path))
|
|
except IOError:
|
|
return None
|
|
locals = {}
|
|
try:
|
|
exec(script_file, locals)
|
|
except Exception, e:
|
|
return None
|
|
return locals
|
|
|
|
|
|
def GetBranchName(working_dir=None):
|
|
"""Return name of current git branch."""
|
|
branch = Backquote(['git', 'symbolic-ref', 'HEAD'], working_dir)
|
|
if not branch.startswith('refs/heads/'):
|
|
raise "Couldn't figure out branch name"
|
|
branch = branch[len('refs/heads/'):]
|
|
return branch
|
|
|
|
|
|
def GetPatchName(working_dir=None):
|
|
"""Construct a name for this patch."""
|
|
short_sha = Backquote(['git', 'rev-parse', '--short=4', 'HEAD'], working_dir)
|
|
return GetBranchName() + '-' + short_sha
|
|
|
|
|
|
def GetRietveldIssueNumber():
|
|
return Backquote(['git', 'config',
|
|
'branch.%s.rietveldissue' % GetBranchName()])
|
|
|
|
|
|
def GetRietveldPatchsetNumber():
|
|
return Backquote(['git', 'config',
|
|
'branch.%s.rietveldpatchset' % GetBranchName()])
|
|
|
|
def GetSubRepWorkingDir(sub_rep_path):
|
|
"""Computes the path to the sub repository"""
|
|
if sub_rep_path:
|
|
root_dir = os.path.abspath(Backquote(['git', 'rev-parse', '--show-cdup']))
|
|
return os.path.join(root_dir, sub_rep_path)
|
|
return None
|
|
|
|
def GetMungedDiff(branch, prefix, sub_rep_path):
|
|
"""Get the diff we'll send to the try server. We munge paths to match svn.
|
|
We add the prefix that the try bot is expecting. If sub_rep_path is
|
|
provided, diff will be calculated in the sub repository.
|
|
We also return the list of files in this diff, without munged paths."""
|
|
# Make the following changes:
|
|
# - Prepend "src/" (or some other prefix) to paths as svn is expecting
|
|
# - In the case of added files, replace /dev/null with the path to the file
|
|
# being added.
|
|
|
|
cwd = GetSubRepWorkingDir(sub_rep_path)
|
|
|
|
output = []
|
|
if not branch:
|
|
# Try to guess the upstream branch.
|
|
branch = Backquote(['git', 'cl', 'upstream'], cwd)
|
|
command = ['git', 'diff-tree', '-p']
|
|
|
|
new_cwd = None
|
|
if not sub_rep_path:
|
|
command.extend(['--no-prefix'])
|
|
else:
|
|
# Append /
|
|
sub_rep_path = os.path.join(sub_rep_path, '')
|
|
# Add the right prefix
|
|
command.extend(['--src-prefix=' + sub_rep_path])
|
|
command.extend(['--dst-prefix=' + sub_rep_path])
|
|
|
|
command.extend([branch, 'HEAD'])
|
|
|
|
# Run diff tree
|
|
diff = subprocess.Popen(command,
|
|
stdout=subprocess.PIPE,
|
|
cwd=cwd).stdout.readlines()
|
|
# Replace --- /dev/null with --- <new file name>
|
|
for i in range(len(diff)):
|
|
line = diff[i]
|
|
if line.startswith('--- /dev/null'):
|
|
line = '--- %s' % diff[i+1][4:]
|
|
output.append(line)
|
|
diff = output
|
|
|
|
# Add root prefix
|
|
output = []
|
|
file_set = set()
|
|
for line in diff:
|
|
if line.startswith('--- ') or line.startswith('+++ '):
|
|
filename = line[4:]
|
|
line = line[0:4] + os.path.join(prefix, filename)
|
|
file_set.add(filename.rstrip('\r\n'))
|
|
output.append(line)
|
|
|
|
munged_diff = ''.join(output)
|
|
if len(munged_diff.strip()) == 0:
|
|
raise Exception("Patch was empty, did you give the right remote branch?")
|
|
|
|
return (munged_diff, list(file_set))
|
|
|
|
def OneRepositoryDiff(diff_file, patch_names, branch, prefix, sub_rep_path):
|
|
"""Computes a diff for one git repository at a given path against a given
|
|
branch. Writes the diff into diff_file and appends a name to the
|
|
patch_names list.
|
|
|
|
Returns the list of files in the diff."""
|
|
|
|
(diff, file_list) = GetMungedDiff(branch, prefix, sub_rep_path)
|
|
|
|
# Write the diff out
|
|
diff_file.write(diff)
|
|
|
|
# Add patch name to list of patches
|
|
patch_name = GetPatchName(GetSubRepWorkingDir(sub_rep_path))
|
|
patch_names.extend([patch_name])
|
|
return file_list
|
|
|
|
|
|
def ValidEmail(email):
|
|
return re.match(r"^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email)
|
|
|
|
|
|
def GetEmail():
|
|
email = Backquote(['git', 'config', 'user.email'])
|
|
runmsg = "Try: git config user.email <EMAIL>"
|
|
assert ValidEmail(email), "Email '%s' is not valid. %s" % (email, runmsg)
|
|
return email
|
|
|
|
|
|
def TryChange(args, file_list):
|
|
"""Put a patch on the try server."""
|
|
trychange.TryChange(args, file_list, False)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = optparse.OptionParser(
|
|
usage='git try [options] [branch]',
|
|
description='Upload the current diff of branch...HEAD to the try server.')
|
|
parser.add_option("-b", "--bot",
|
|
help="Force the use of a specific build slave (eg mac, "
|
|
"win, or linux)")
|
|
parser.add_option("-c", "--clobber", action="store_true",
|
|
help="Make the try run use be a clobber build")
|
|
parser.add_option("-r", "--revision",
|
|
help="Specify the SVN base revision to use")
|
|
parser.add_option("--root", default="src", metavar="PATH",
|
|
help="Specify the root prefix that is prepended to paths "
|
|
"in the patch")
|
|
parser.add_option("--dry_run", action="store_true",
|
|
help="Print the diff but don't send it to the try bots")
|
|
parser.add_option("--sub_rep", nargs=2, action="append", default=[],
|
|
metavar="PATH BRANCH",
|
|
help="Specify a path to a git sub-repository and a branch "
|
|
"to diff with in order to simultanously try changes "
|
|
"in multiple git repositories. Option may be "
|
|
"specified multiple times.")
|
|
parser.add_option("--webkit", metavar="BRANCH",
|
|
help="Specify webkit branch. Syntactic sugar for "
|
|
"--sub_rep third_party/WebKit/ <branch>")
|
|
|
|
(options, args) = parser.parse_args(sys.argv)
|
|
|
|
if options.webkit:
|
|
options.sub_rep.extend([('third_party/WebKit/', options.webkit)])
|
|
|
|
branch = None
|
|
if len(args) > 1:
|
|
branch = args[1]
|
|
patch_names = []
|
|
|
|
# Dump all diffs into one diff file.
|
|
diff_file = tempfile.NamedTemporaryFile()
|
|
|
|
# Calculate diff for main git repository.
|
|
file_list = OneRepositoryDiff(diff_file, patch_names, branch, options.root,
|
|
None)
|
|
|
|
# Calculate diff for each extra git repository.
|
|
for path_and_branch in options.sub_rep:
|
|
file_list.extend(OneRepositoryDiff(diff_file,
|
|
patch_names,
|
|
path_and_branch[1],
|
|
options.root,
|
|
path_and_branch[0]))
|
|
# Make diff file ready for reading.
|
|
diff_file.flush()
|
|
|
|
# Concatenate patch names
|
|
# Prepare args for TryChange
|
|
email = GetEmail()
|
|
user = email.partition('@')[0]
|
|
args = [
|
|
'-u', user,
|
|
'-e', email,
|
|
'-n', '-'.join(patch_names),
|
|
'--diff', diff_file.name,
|
|
]
|
|
|
|
# Send to try server via HTTP if we can parse the config, otherwise
|
|
# upload via SVN.
|
|
config = GetTryServerConfig()
|
|
if config is not None:
|
|
sendmsg = "Sending %s using HTTP..." % '-'.join(patch_names)
|
|
args.extend(['--use_http'])
|
|
if config['try_server_http_host'] is not None:
|
|
args.extend(['--host', config['try_server_http_host']])
|
|
if config['try_server_http_port'] is not None:
|
|
args.extend(['--port', config['try_server_http_port']])
|
|
|
|
else:
|
|
print "Could not get server config -- if you're within Google, "
|
|
print "do you have have src-internal checked out?"
|
|
sendmsg = "Sending %s using SVN..." % '-'.join(patch_names)
|
|
args.extend([
|
|
'--use_svn', '--svn_repo',
|
|
'svn://svn.chromium.org/chrome-try/try',
|
|
])
|
|
|
|
if options.bot:
|
|
args.extend(['--bot', options.bot])
|
|
if options.clobber:
|
|
args.append('--clobber')
|
|
if options.revision:
|
|
args.extend(['-r', options.revision])
|
|
if GetRietveldPatchsetNumber():
|
|
args.extend([
|
|
'--issue', GetRietveldIssueNumber(),
|
|
'--patchset', GetRietveldPatchsetNumber(),
|
|
])
|
|
|
|
if options.dry_run:
|
|
print open(diff_file.name, 'r').read()
|
|
exit(0)
|
|
|
|
print sendmsg
|
|
TryChange(args, file_list)
|