git-try.py 5.2 KB

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