OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 |
| 3 # Repo lives in ~evanm/projects/git-try -- feel free to send patches. |
| 4 |
| 5 import getpass |
| 6 import optparse |
| 7 import os |
| 8 import subprocess |
| 9 import tempfile |
| 10 import traceback |
| 11 import urllib |
| 12 import sys |
| 13 |
| 14 |
| 15 def Backquote(cmd): |
| 16 """Like running `cmd` in a shell script.""" |
| 17 return subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0].strip() |
| 18 |
| 19 |
| 20 def GetTryServerConfig(): |
| 21 """Returns the dictionary of try server options or None if they |
| 22 cannot be found.""" |
| 23 script_path = 'tools/tryserver/tryserver.py' |
| 24 root_dir = Backquote(['git', 'rev-parse', '--show-cdup']) |
| 25 try: |
| 26 script_file = open(os.path.join(root_dir, script_path)) |
| 27 except IOError: |
| 28 return None |
| 29 locals = {} |
| 30 try: |
| 31 exec(script_file, locals) |
| 32 except Exception, e: |
| 33 return None |
| 34 return locals |
| 35 |
| 36 |
| 37 def GetBranchName(): |
| 38 """Return name of current git branch.""" |
| 39 branch = Backquote(['git', 'symbolic-ref', 'HEAD']) |
| 40 if not branch.startswith('refs/heads/'): |
| 41 raise "Couldn't figure out branch name" |
| 42 branch = branch[len('refs/heads/'):] |
| 43 return branch |
| 44 |
| 45 |
| 46 def GetPatchName(): |
| 47 """Construct a name for this patch.""" |
| 48 # TODO: perhaps include the hash of the current commit, to distinguish |
| 49 # patches? |
| 50 return GetBranchName() |
| 51 |
| 52 |
| 53 def GetRevision(): |
| 54 """Get the latest Subversion revision number.""" |
| 55 for line in Backquote(['git', 'svn', 'info']).split('\n'): |
| 56 if line.startswith('Revision:'): |
| 57 return line[len('Revision:'):].strip() |
| 58 raise "Couldn't figure out latest revision" |
| 59 |
| 60 |
| 61 def GetRietveldIssueNumber(): |
| 62 return Backquote(['git', 'config', |
| 63 'branch.%s.rietveldissue' % GetBranchName()]) |
| 64 |
| 65 |
| 66 def GetRietveldPatchsetNumber(): |
| 67 return Backquote(['git', 'config', |
| 68 'branch.%s.rietveldpatchset' % GetBranchName()]) |
| 69 |
| 70 |
| 71 def GetMungedDiff(branch): |
| 72 """Get the diff we'll send to the try server. We munge paths to match svn.""" |
| 73 # Make the following changes: |
| 74 # - Prepend "src/" to paths as svn is expecting |
| 75 # - In the case of added files, replace /dev/null with the path to the file |
| 76 # being added. |
| 77 output = [] |
| 78 if not branch: |
| 79 # Try to guess the upstream branch. |
| 80 branch = Backquote(['git', 'cl', 'upstream']) |
| 81 diff = subprocess.Popen(['git', 'diff-tree', '-p', '--no-prefix', |
| 82 branch, 'HEAD'], |
| 83 stdout=subprocess.PIPE).stdout.readlines() |
| 84 for i in range(len(diff)): |
| 85 line = diff[i] |
| 86 if line.startswith('--- /dev/null'): |
| 87 line = '--- %s' % diff[i+1][4:] |
| 88 elif line.startswith('--- ') or line.startswith('+++ '): |
| 89 line = line[0:4] + 'src/' + line[4:] |
| 90 output.append(line) |
| 91 |
| 92 return ''.join(output) |
| 93 |
| 94 |
| 95 def GetEmail(): |
| 96 # TODO: check for errors here? |
| 97 return Backquote(['git', 'config', 'user.email']) |
| 98 |
| 99 |
| 100 def TryChange(args): |
| 101 """Put a patch on the try server using SVN.""" |
| 102 # TODO: figure out a better way to load trychange |
| 103 script_path = '../depot_tools/release' |
| 104 root_dir = Backquote(['git', 'rev-parse', '--show-cdup']) |
| 105 sys.path.append(os.path.join(root_dir, script_path)) |
| 106 import trychange |
| 107 trychange.checkout_root = os.path.abspath(root_dir) |
| 108 trychange.TryChange(args, None, False) |
| 109 |
| 110 |
| 111 def WriteTryDiffHTTP(config, patch_name, diff, options): |
| 112 """Put a patch on the try server.""" |
| 113 params = { |
| 114 'user': getpass.getuser(), |
| 115 'name': patch_name, |
| 116 'patch': diff |
| 117 } |
| 118 |
| 119 if options.bot: |
| 120 params['bot'] = options.bot |
| 121 |
| 122 if options.clobber: |
| 123 params['clobber'] = 'true' |
| 124 |
| 125 url = 'http://%s:%s/send_try_patch' % (config['try_server_http_host'], |
| 126 config['try_server_http_port']) |
| 127 connection = urllib.urlopen(url, urllib.urlencode(params)) |
| 128 response = connection.read() |
| 129 if (response != 'OK'): |
| 130 print "Error posting to", url |
| 131 print response |
| 132 assert False |
| 133 |
| 134 |
| 135 if __name__ == '__main__': |
| 136 parser = optparse.OptionParser( |
| 137 usage='git try [branch]', |
| 138 description='Upload the current diff of branch...HEAD to the try server.') |
| 139 parser.add_option("-b", "--bot", |
| 140 help="Force the use of a specific build slave (eg mac, " |
| 141 "win, or linux)") |
| 142 parser.add_option("-c", "--clobber", action="store_true", |
| 143 help="Make the try run use be a clobber build") |
| 144 (options, args) = parser.parse_args(sys.argv) |
| 145 |
| 146 branch = None |
| 147 if len(args) > 1: |
| 148 branch = args[1] |
| 149 |
| 150 patch_name = GetPatchName() |
| 151 diff = GetMungedDiff(branch) |
| 152 |
| 153 # Send directly to try server if we can parse the config, otherwise |
| 154 # upload via SVN. |
| 155 config = GetTryServerConfig() |
| 156 if config is not None: |
| 157 print "Sending %s using HTTP..." % patch_name |
| 158 WriteTryDiffHTTP(config=config, patch_name=patch_name, diff=diff, |
| 159 options=options) |
| 160 else: |
| 161 print "Sending %s using SVN..." % patch_name |
| 162 |
| 163 # Write the diff out to a temporary file |
| 164 diff_file = tempfile.NamedTemporaryFile() |
| 165 diff_file.write(diff) |
| 166 diff_file.flush() |
| 167 |
| 168 email = GetEmail() |
| 169 user = email.partition('@')[0] |
| 170 args = [ |
| 171 '--use_svn', |
| 172 '--svn_repo', 'svn://svn.chromium.org/chrome-try/try', |
| 173 '-u', user, |
| 174 '-e', email, |
| 175 '-n', patch_name, |
| 176 '-r', GetRevision(), |
| 177 '--diff', diff_file.name, |
| 178 ] |
| 179 if GetRietveldPatchsetNumber(): |
| 180 args.extend([ |
| 181 '--issue', GetRietveldIssueNumber(), |
| 182 '--patchset', GetRietveldPatchsetNumber(), |
| 183 ]) |
| 184 TryChange(args=args) |
OLD | NEW |