#!/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): """Like running `cmd` in a shell script.""" return subprocess.Popen(cmd, 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(): """Return name of current git branch.""" branch = Backquote(['git', 'symbolic-ref', 'HEAD']) if not branch.startswith('refs/heads/'): raise "Couldn't figure out branch name" branch = branch[len('refs/heads/'):] return branch def GetPatchName(): """Construct a name for this patch.""" short_sha = Backquote(['git', 'rev-parse', '--short=4', 'HEAD']) 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 GetMungedDiff(branch, prefix='src/'): """Get the diff we'll send to the try server. We munge paths to match svn.""" # 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. output = [] if not branch: # Try to guess the upstream branch. branch = Backquote(['git', 'cl', 'upstream']) diff = subprocess.Popen(['git', 'diff-tree', '-p', '--no-prefix', branch, 'HEAD'], stdout=subprocess.PIPE).stdout.readlines() for i in range(len(diff)): line = diff[i] if line.startswith('--- /dev/null'): line = '--- %s' % prefix + diff[i+1][4:] elif line.startswith('--- ') or line.startswith('+++ '): line = line[0:4] + prefix + line[4:] 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 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 " assert ValidEmail(email), "Email '%s' is not valid. %s" % (email, runmsg) return email def TryChange(args): """Put a patch on the try server.""" root_dir = Backquote(['git', 'rev-parse', '--show-cdup']) trychange.checkout_root = os.path.abspath(root_dir) trychange.TryChange(args, None, 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") (options, args) = parser.parse_args(sys.argv) branch = None if len(args) > 1: branch = args[1] patch_name = GetPatchName() diff = GetMungedDiff(branch) # Write the diff out to a temporary file diff_file = tempfile.NamedTemporaryFile() diff_file.write(diff) diff_file.flush() email = GetEmail() user = email.partition('@')[0] args = [ '-u', user, '-e', email, '-n', patch_name, '--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..." % patch_name 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..." % patch_name 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(), ]) print sendmsg TryChange(args=args)