[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # 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. |
| 5 | """Client-side script to send a try job to the try server. It communicates to |
| 6 | the try server by either writting to a svn repository or by directly connecting |
| 7 | to the server by HTTP. |
| 8 | """ |
| 9 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 10 | import datetime |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 11 | import errno |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 12 | import getpass |
| 13 | import logging |
| 14 | import optparse |
| 15 | import os |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 16 | import posixpath |
[email protected] | 8ede00e | 2010-01-12 14:35:28 | [diff] [blame] | 17 | import re |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 18 | import shutil |
| 19 | import sys |
| 20 | import tempfile |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 21 | import urllib |
| 22 | |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 23 | try: |
[email protected] | 57af171 | 2010-03-18 00:31:51 | [diff] [blame] | 24 | import simplejson as json |
| 25 | except ImportError: |
| 26 | try: |
| 27 | import json |
| 28 | except ImportError: |
| 29 | json = None |
| 30 | |
| 31 | try: |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 32 | import breakpad |
| 33 | except ImportError: |
| 34 | pass |
[email protected] | 82f2c08 | 2009-12-08 21:25:37 | [diff] [blame] | 35 | |
[email protected] | 9a2f37e | 2009-12-19 16:03:28 | [diff] [blame] | 36 | import gclient_utils |
[email protected] | 5aeb7dd | 2009-11-17 18:09:01 | [diff] [blame] | 37 | import scm |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 38 | |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 39 | __version__ = '1.2' |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 40 | |
| 41 | |
| 42 | # Constants |
| 43 | HELP_STRING = "Sorry, Tryserver is not available." |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 44 | USAGE = r"""%prog [options] |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 45 | |
| 46 | Client-side script to send a try job to the try server. It communicates to |
| 47 | the try server by either writting to a svn repository or by directly connecting |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 48 | to the server by HTTP.""" |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 49 | |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 50 | EPILOG = """ |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 51 | Examples: |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 52 | Send a patch directly from rietveld: |
| 53 | %(prog)s -R codereview.chromium.org/1337 |
| 54 | --email [email protected] --root src |
| 55 | |
[email protected] | 4e9f491 | 2009-10-23 19:37:33 | [diff] [blame] | 56 | Try a change against a particular revision: |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 57 | %(prog)s -r 123 |
[email protected] | 4e9f491 | 2009-10-23 19:37:33 | [diff] [blame] | 58 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 59 | A git patch off a web site (git inserts a/ and b/) and fix the base dir: |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 60 | %(prog)s --url http://url/to/patch.diff --patchlevel 1 --root src |
[email protected] | 5f42314 | 2010-01-30 05:46:36 | [diff] [blame] | 61 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 62 | Use svn to store the try job, specify an alternate email address and use a |
| 63 | premade diff file on the local drive: |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 64 | %(prog)s --email [email protected] |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 65 | --svn_repo svn://svn.chromium.org/chrome-try/try --diff foo.diff |
| 66 | |
[email protected] | 4e9f491 | 2009-10-23 19:37:33 | [diff] [blame] | 67 | Running only on a 'mac' slave with revision 123 and clobber first; specify |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 68 | manually the 3 source files to use for the try job: |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 69 | %(prog)s --bot mac --revision 123 --clobber -f src/a.cc -f src/a.h |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 70 | -f include/b.h |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 71 | """ |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 72 | |
| 73 | class InvalidScript(Exception): |
| 74 | def __str__(self): |
| 75 | return self.args[0] + '\n' + HELP_STRING |
| 76 | |
| 77 | |
| 78 | class NoTryServerAccess(Exception): |
| 79 | def __str__(self): |
| 80 | return self.args[0] + '\n' + HELP_STRING |
| 81 | |
| 82 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 83 | def EscapeDot(name): |
| 84 | return name.replace('.', '-') |
| 85 | |
| 86 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 87 | class SCM(object): |
| 88 | """Simplistic base class to implement one function: ProcessOptions.""" |
[email protected] | 1c7db8e | 2010-01-07 02:00:19 | [diff] [blame] | 89 | def __init__(self, options, path): |
| 90 | items = path.split('@') |
| 91 | assert len(items) <= 2 |
| 92 | self.checkout_root = items[0] |
| 93 | items.append(None) |
| 94 | self.diff_against = items[1] |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 95 | self.options = options |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 96 | self.files = self.options.files |
| 97 | self.options.files = None |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 98 | self.codereview_settings = None |
| 99 | self.codereview_settings_file = 'codereview.settings' |
[email protected] | 2b9aa8e | 2010-08-25 20:01:42 | [diff] [blame] | 100 | self.gclient_root = None |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 101 | |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 102 | def GetFileNames(self): |
| 103 | """Return the list of files in the diff.""" |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 104 | return self.files |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 105 | |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 106 | def GetCodeReviewSetting(self, key): |
| 107 | """Returns a value for the given key for this repository. |
| 108 | |
| 109 | Uses gcl-style settings from the repository.""" |
| 110 | if self.codereview_settings is None: |
| 111 | self.codereview_settings = {} |
| 112 | settings_file = self.ReadRootFile(self.codereview_settings_file) |
| 113 | if settings_file: |
| 114 | for line in settings_file.splitlines(): |
| 115 | if not line or line.lstrip().startswith('#'): |
| 116 | continue |
| 117 | k, v = line.split(":", 1) |
| 118 | self.codereview_settings[k.strip()] = v.strip() |
| 119 | return self.codereview_settings.get(key, '') |
| 120 | |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 121 | def _GclStyleSettings(self): |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 122 | """Set default settings based on the gcl-style settings from the |
| 123 | repository.""" |
| 124 | settings = { |
| 125 | 'port': self.GetCodeReviewSetting('TRYSERVER_HTTP_PORT'), |
| 126 | 'host': self.GetCodeReviewSetting('TRYSERVER_HTTP_HOST'), |
| 127 | 'svn_repo': self.GetCodeReviewSetting('TRYSERVER_SVN_URL'), |
| 128 | 'project': self.GetCodeReviewSetting('TRYSERVER_PROJECT'), |
| 129 | 'root': self.GetCodeReviewSetting('TRYSERVER_ROOT'), |
| 130 | 'patchlevel': self.GetCodeReviewSetting('TRYSERVER_PATCHLEVEL'), |
| 131 | } |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 132 | logging.info('\n'.join(['%s: %s' % (k, v) |
| 133 | for (k, v) in settings.iteritems() if v])) |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 134 | for (k, v) in settings.iteritems(): |
| 135 | if v and getattr(self.options, k) is None: |
| 136 | setattr(self.options, k, v) |
| 137 | |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 138 | def _GclientStyleSettings(self): |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 139 | """Find the root, assuming a gclient-style checkout.""" |
| 140 | if not self.options.no_gclient and not self.options.root: |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 141 | root = self.checkout_root |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 142 | self.gclient_root = gclient_utils.FindGclientRoot(root) |
| 143 | if self.gclient_root: |
| 144 | logging.info('Found .gclient at %s' % self.gclient_root) |
| 145 | self.options.root = gclient_utils.PathDifference(self.gclient_root, |
| 146 | root) |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 147 | |
| 148 | def AutomagicalSettings(self): |
| 149 | """Determines settings based on supported code review and checkout tools. |
| 150 | """ |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 151 | self._GclientStyleSettings() |
| 152 | self._GclStyleSettings() |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 153 | |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 154 | def ReadRootFile(self, filename): |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 155 | if not self.options.root: |
| 156 | filepath = os.path.join(self.checkout_root, filename) |
| 157 | if os.path.isfile(filepath): |
| 158 | logging.info('Found %s at %s' % (filename, self.checkout_root)) |
[email protected] | a8e36cb | 2010-05-27 23:47:18 | [diff] [blame] | 159 | return gclient_utils.FileRead(filepath) |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 160 | return None |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 161 | cur = os.path.abspath(self.checkout_root) |
[email protected] | 258d17f | 2010-05-17 17:30:33 | [diff] [blame] | 162 | if self.gclient_root: |
| 163 | root = os.path.abspath(self.gclient_root) |
| 164 | else: |
| 165 | root = gclient_utils.FindGclientRoot(cur) |
[email protected] | 21779a5 | 2010-09-02 00:40:53 | [diff] [blame] | 166 | if not root: |
| 167 | root = cur |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 168 | assert cur.startswith(root), (root, cur) |
| 169 | while cur.startswith(root): |
| 170 | filepath = os.path.join(cur, filename) |
| 171 | if os.path.isfile(filepath): |
| 172 | logging.info('Found %s at %s' % (filename, cur)) |
| 173 | return gclient_utils.FileRead(filepath) |
| 174 | cur = os.path.dirname(cur) |
| 175 | logging.warning('Didn\'t find %s' % filename) |
| 176 | return None |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 177 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 178 | |
| 179 | class SVN(SCM): |
| 180 | """Gathers the options and diff for a subversion checkout.""" |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 181 | def __init__(self, *args, **kwargs): |
| 182 | SCM.__init__(self, *args, **kwargs) |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 183 | self.checkout_root = scm.SVN.GetCheckoutRoot(self.checkout_root) |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 184 | if not self.options.email: |
| 185 | # Assumes the svn credential is an email address. |
| 186 | self.options.email = scm.SVN.GetEmail(self.checkout_root) |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 187 | logging.info("SVN(%s)" % self.checkout_root) |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 188 | |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 189 | def ReadRootFile(self, filename): |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 190 | data = SCM.ReadRootFile(self, filename) |
| 191 | if data: |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 192 | return data |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 193 | |
| 194 | # Try to search on the subversion repository for the file. |
| 195 | try: |
| 196 | from gcl import GetCachedFile |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 197 | except ImportError: |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 198 | return None |
| 199 | data = GetCachedFile(filename) |
| 200 | logging.debug('%s:\n%s' % (filename, data)) |
| 201 | return data |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 202 | |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 203 | def GenerateDiff(self): |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 204 | """Returns a string containing the diff for the given file list. |
| 205 | |
| 206 | The files in the list should either be absolute paths or relative to the |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 207 | given root. |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 208 | """ |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 209 | if not self.files: |
[email protected] | f2f9d55 | 2009-12-22 00:12:57 | [diff] [blame] | 210 | previous_cwd = os.getcwd() |
| 211 | os.chdir(self.checkout_root) |
[email protected] | 8ede00e | 2010-01-12 14:35:28 | [diff] [blame] | 212 | |
[email protected] | f2f9d55 | 2009-12-22 00:12:57 | [diff] [blame] | 213 | excluded = ['!', '?', 'X', ' ', '~'] |
[email protected] | 8ede00e | 2010-01-12 14:35:28 | [diff] [blame] | 214 | def Excluded(f): |
| 215 | if f[0][0] in excluded: |
| 216 | return True |
| 217 | for r in self.options.exclude: |
| 218 | if re.search(r, f[1]): |
| 219 | logging.info('Ignoring "%s"' % f[1]) |
| 220 | return True |
| 221 | return False |
| 222 | |
| 223 | self.files = [f[1] for f in scm.SVN.CaptureStatus(self.checkout_root) |
| 224 | if not Excluded(f)] |
[email protected] | f2f9d55 | 2009-12-22 00:12:57 | [diff] [blame] | 225 | os.chdir(previous_cwd) |
[email protected] | 1c7db8e | 2010-01-07 02:00:19 | [diff] [blame] | 226 | return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True, |
| 227 | revision=self.diff_against) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 228 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 229 | |
| 230 | class GIT(SCM): |
| 231 | """Gathers the options and diff for a git checkout.""" |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 232 | def __init__(self, *args, **kwargs): |
| 233 | SCM.__init__(self, *args, **kwargs) |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 234 | self.checkout_root = scm.GIT.GetCheckoutRoot(self.checkout_root) |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 235 | if not self.options.name: |
[email protected] | b24a8e1 | 2009-12-22 13:45:48 | [diff] [blame] | 236 | self.options.name = scm.GIT.GetPatchName(self.checkout_root) |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 237 | if not self.options.email: |
[email protected] | b24a8e1 | 2009-12-22 13:45:48 | [diff] [blame] | 238 | self.options.email = scm.GIT.GetEmail(self.checkout_root) |
[email protected] | 81e012c | 2010-04-29 16:07:24 | [diff] [blame] | 239 | if not self.diff_against: |
| 240 | self.diff_against = scm.GIT.GetUpstreamBranch(self.checkout_root) |
| 241 | if not self.diff_against: |
[email protected] | a630bd7 | 2010-04-29 23:32:34 | [diff] [blame] | 242 | raise NoTryServerAccess( |
| 243 | "Unable to determine default branch to diff against. " |
| 244 | "Verify this branch is set up to track another" |
| 245 | "(via the --track argument to \"git checkout -b ...\"") |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 246 | logging.info("GIT(%s)" % self.checkout_root) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 247 | |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 248 | def GenerateDiff(self): |
[email protected] | 8ede00e | 2010-01-12 14:35:28 | [diff] [blame] | 249 | if not self.files: |
| 250 | self.files = scm.GIT.GetDifferentFiles(self.checkout_root, |
| 251 | branch=self.diff_against) |
| 252 | |
| 253 | def NotExcluded(f): |
| 254 | for r in self.options.exclude: |
| 255 | if re.search(r, f): |
| 256 | logging.info('Ignoring "%s"' % f) |
| 257 | return False |
| 258 | return True |
| 259 | |
| 260 | self.files = filter(NotExcluded, self.files) |
| 261 | return scm.GIT.GenerateDiff(self.checkout_root, files=self.files, |
| 262 | full_move=True, |
[email protected] | 1c7db8e | 2010-01-07 02:00:19 | [diff] [blame] | 263 | branch=self.diff_against) |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 264 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 265 | |
| 266 | def _ParseSendChangeOptions(options): |
| 267 | """Parse common options passed to _SendChangeHTTP and _SendChangeSVN.""" |
| 268 | values = {} |
| 269 | if options.email: |
| 270 | values['email'] = options.email |
| 271 | values['user'] = options.user |
| 272 | values['name'] = options.name |
| 273 | if options.bot: |
| 274 | values['bot'] = ','.join(options.bot) |
| 275 | if options.revision: |
| 276 | values['revision'] = options.revision |
| 277 | if options.clobber: |
| 278 | values['clobber'] = 'true' |
[email protected] | c305768 | 2010-05-01 01:47:02 | [diff] [blame] | 279 | if options.testfilter: |
| 280 | values['testfilter'] = ','.join(options.testfilter) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 281 | if options.root: |
| 282 | values['root'] = options.root |
| 283 | if options.patchlevel: |
| 284 | values['patchlevel'] = options.patchlevel |
| 285 | if options.issue: |
| 286 | values['issue'] = options.issue |
| 287 | if options.patchset: |
| 288 | values['patchset'] = options.patchset |
[email protected] | b3b00a4 | 2009-07-03 00:47:34 | [diff] [blame] | 289 | if options.target: |
| 290 | values['target'] = options.target |
[email protected] | 833b227 | 2009-09-10 18:30:23 | [diff] [blame] | 291 | if options.project: |
| 292 | values['project'] = options.project |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 293 | return values |
| 294 | |
| 295 | |
| 296 | def _SendChangeHTTP(options): |
| 297 | """Send a change to the try server using the HTTP protocol.""" |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 298 | if not options.host: |
[email protected] | f7fb33e | 2009-06-17 12:59:15 | [diff] [blame] | 299 | raise NoTryServerAccess('Please use the --host option to specify the try ' |
| 300 | 'server host to connect to.') |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 301 | if not options.port: |
[email protected] | f7fb33e | 2009-06-17 12:59:15 | [diff] [blame] | 302 | raise NoTryServerAccess('Please use the --port option to specify the try ' |
| 303 | 'server port to connect to.') |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 304 | |
| 305 | values = _ParseSendChangeOptions(options) |
[email protected] | 2b9aa8e | 2010-08-25 20:01:42 | [diff] [blame] | 306 | description = ''.join("%s=%s\n" % (k, v) for (k, v) in values.iteritems()) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 307 | values['patch'] = options.diff |
| 308 | |
| 309 | url = 'http://%s:%s/send_try_patch' % (options.host, options.port) |
| 310 | proxies = None |
| 311 | if options.proxy: |
| 312 | if options.proxy.lower() == 'none': |
| 313 | # Effectively disable HTTP_PROXY or Internet settings proxy setup. |
| 314 | proxies = {} |
| 315 | else: |
| 316 | proxies = {'http': options.proxy, 'https': options.proxy} |
[email protected] | c308a74 | 2009-12-22 18:29:33 | [diff] [blame] | 317 | |
[email protected] | 7538b86 | 2010-01-08 21:41:33 | [diff] [blame] | 318 | logging.info('Sending by HTTP') |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 319 | logging.info(description) |
| 320 | logging.info(url) |
| 321 | logging.info(options.diff) |
[email protected] | c308a74 | 2009-12-22 18:29:33 | [diff] [blame] | 322 | if options.dry_run: |
[email protected] | c308a74 | 2009-12-22 18:29:33 | [diff] [blame] | 323 | return |
| 324 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 325 | try: |
| 326 | connection = urllib.urlopen(url, urllib.urlencode(values), proxies=proxies) |
| 327 | except IOError, e: |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 328 | logging.warning(str(e)) |
[email protected] | cce9e1c | 2009-10-14 00:50:22 | [diff] [blame] | 329 | if (values.get('bot') and len(e.args) > 2 and |
| 330 | e.args[2] == 'got a bad status line'): |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 331 | raise NoTryServerAccess('%s is unaccessible. Bad --bot argument?' % url) |
| 332 | else: |
[email protected] | cce9e1c | 2009-10-14 00:50:22 | [diff] [blame] | 333 | raise NoTryServerAccess('%s is unaccessible. Reason: %s' % (url, |
| 334 | str(e.args))) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 335 | if not connection: |
| 336 | raise NoTryServerAccess('%s is unaccessible.' % url) |
[email protected] | 6f6a801 | 2009-12-22 18:48:39 | [diff] [blame] | 337 | response = connection.read() |
| 338 | if response != 'OK': |
| 339 | raise NoTryServerAccess('%s is unaccessible. Got:\n%s' % (url, response)) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 340 | |
| 341 | |
| 342 | def _SendChangeSVN(options): |
| 343 | """Send a change to the try server by committing a diff file on a subversion |
| 344 | server.""" |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 345 | if not options.svn_repo: |
[email protected] | f7fb33e | 2009-06-17 12:59:15 | [diff] [blame] | 346 | raise NoTryServerAccess('Please use the --svn_repo option to specify the' |
| 347 | ' try server svn repository to connect to.') |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 348 | |
| 349 | values = _ParseSendChangeOptions(options) |
[email protected] | 2b9aa8e | 2010-08-25 20:01:42 | [diff] [blame] | 350 | description = ''.join("%s=%s\n" % (k, v) for (k, v) in values.iteritems()) |
[email protected] | 7538b86 | 2010-01-08 21:41:33 | [diff] [blame] | 351 | logging.info('Sending by SVN') |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 352 | logging.info(description) |
| 353 | logging.info(options.svn_repo) |
| 354 | logging.info(options.diff) |
[email protected] | c308a74 | 2009-12-22 18:29:33 | [diff] [blame] | 355 | if options.dry_run: |
[email protected] | c308a74 | 2009-12-22 18:29:33 | [diff] [blame] | 356 | return |
| 357 | |
[email protected] | 34d73cb | 2010-04-28 16:39:56 | [diff] [blame] | 358 | # Create a temporary directory, put a uniquely named file in it with the diff |
| 359 | # content and svn import that. |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 360 | temp_dir = tempfile.mkdtemp() |
| 361 | temp_file = tempfile.NamedTemporaryFile() |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 362 | try: |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 363 | try: |
[email protected] | 34d73cb | 2010-04-28 16:39:56 | [diff] [blame] | 364 | # Description |
| 365 | temp_file.write(description) |
| 366 | temp_file.flush() |
[email protected] | 9a2f37e | 2009-12-19 16:03:28 | [diff] [blame] | 367 | |
[email protected] | 34d73cb | 2010-04-28 16:39:56 | [diff] [blame] | 368 | # Diff file |
[email protected] | 9a2f37e | 2009-12-19 16:03:28 | [diff] [blame] | 369 | current_time = str(datetime.datetime.now()).replace(':', '.') |
| 370 | file_name = (EscapeDot(options.user) + '.' + EscapeDot(options.name) + |
| 371 | '.%s.diff' % current_time) |
| 372 | full_path = os.path.join(temp_dir, file_name) |
[email protected] | 34d73cb | 2010-04-28 16:39:56 | [diff] [blame] | 373 | gclient_utils.FileWrite(full_path, options.diff, 'wb') |
| 374 | |
| 375 | # Committing it will trigger a try job. |
[email protected] | 1dd0eea | 2010-04-28 20:13:42 | [diff] [blame] | 376 | if sys.platform == "cygwin": |
| 377 | # Small chromium-specific issue here: |
| 378 | # git-try uses /usr/bin/python on cygwin but svn.bat will be used |
| 379 | # instead of /usr/bin/svn by default. That causes bad things(tm) since |
| 380 | # Windows' svn.exe has no clue about cygwin paths. Hence force to use |
| 381 | # the cygwin version in this particular context. |
| 382 | exe = "/usr/bin/svn" |
| 383 | else: |
| 384 | exe = "svn" |
| 385 | command = [exe, 'import', '-q', temp_dir, options.svn_repo, '--file', |
[email protected] | 34d73cb | 2010-04-28 16:39:56 | [diff] [blame] | 386 | temp_file.name] |
| 387 | gclient_utils.CheckCall(command) |
[email protected] | 9a2f37e | 2009-12-19 16:03:28 | [diff] [blame] | 388 | except gclient_utils.CheckCallError, e: |
[email protected] | 6fb1090 | 2010-03-24 19:16:28 | [diff] [blame] | 389 | out = e.stdout |
| 390 | if e.stderr: |
| 391 | out += e.stderr |
| 392 | raise NoTryServerAccess(' '.join(e.command) + '\nOuput:\n' + out) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 393 | finally: |
| 394 | temp_file.close() |
| 395 | shutil.rmtree(temp_dir, True) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 396 | |
| 397 | |
[email protected] | b6d3649 | 2009-12-26 14:22:41 | [diff] [blame] | 398 | def PrintSuccess(options): |
| 399 | if not options.dry_run: |
| 400 | text = 'Patch \'%s\' sent to try server' % options.name |
| 401 | if options.bot: |
| 402 | text += ': %s' % ', '.join(options.bot) |
| 403 | print(text) |
| 404 | |
| 405 | |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 406 | def GuessVCS(options, path): |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 407 | """Helper to guess the version control system. |
| 408 | |
| 409 | NOTE: Very similar to upload.GuessVCS. Doesn't look for hg since we don't |
| 410 | support it yet. |
| 411 | |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 412 | This examines the path directory, guesses which SCM we're using, and |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 413 | returns an instance of the appropriate class. Exit with an error if we can't |
| 414 | figure it out. |
| 415 | |
| 416 | Returns: |
| 417 | A SCM instance. Exits if the SCM can't be guessed. |
| 418 | """ |
[email protected] | 5aeb7dd | 2009-11-17 18:09:01 | [diff] [blame] | 419 | __pychecker__ = 'no-returnvalues' |
[email protected] | 1c7db8e | 2010-01-07 02:00:19 | [diff] [blame] | 420 | real_path = path.split('@')[0] |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 421 | logging.info("GuessVCS(%s)" % path) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 422 | # Subversion has a .svn in all working directories. |
[email protected] | 1c7db8e | 2010-01-07 02:00:19 | [diff] [blame] | 423 | if os.path.isdir(os.path.join(real_path, '.svn')): |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 424 | return SVN(options, path) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 425 | |
| 426 | # Git has a command to test if you're in a git tree. |
| 427 | # Try running it, but don't die if we don't have git installed. |
| 428 | try: |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 429 | gclient_utils.CheckCall(["git", "rev-parse", "--is-inside-work-tree"], |
[email protected] | 1c7db8e | 2010-01-07 02:00:19 | [diff] [blame] | 430 | real_path) |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 431 | return GIT(options, path) |
[email protected] | 1811135 | 2009-12-20 17:21:28 | [diff] [blame] | 432 | except gclient_utils.CheckCallError, e: |
[email protected] | 66c83e6 | 2010-09-07 14:18:45 | [diff] [blame] | 433 | if e.returncode != errno.ENOENT and e.returncode != 128: |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 434 | # ENOENT == 2 = they don't have git installed. |
| 435 | # 128 = git error code when not in a repo. |
[email protected] | 37e8987 | 2010-09-07 16:11:33 | [diff] [blame] | 436 | logging.warn('Unexpected error code: %s' % e.returncode) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 437 | raise |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 438 | raise NoTryServerAccess("Could not guess version control system. " |
| 439 | "Are you in a working copy directory?") |
| 440 | |
| 441 | |
[email protected] | c2190cb | 2010-01-10 01:57:06 | [diff] [blame] | 442 | def GetMungedDiff(path_diff, diff): |
| 443 | # Munge paths to match svn. |
| 444 | for i in range(len(diff)): |
| 445 | if diff[i].startswith('--- ') or diff[i].startswith('+++ '): |
| 446 | new_file = posixpath.join(path_diff, diff[i][4:]).replace('\\', '/') |
| 447 | diff[i] = diff[i][0:4] + new_file |
| 448 | return diff |
| 449 | |
| 450 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 451 | def TryChange(argv, |
| 452 | file_list, |
| 453 | swallow_exception, |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 454 | prog=None, |
| 455 | extra_epilog=None): |
[email protected] | de24345 | 2009-10-06 21:02:56 | [diff] [blame] | 456 | """ |
| 457 | Args: |
| 458 | argv: Arguments and options. |
| 459 | file_list: Default value to pass to --file. |
| 460 | swallow_exception: Whether we raise or swallow exceptions. |
| 461 | """ |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 462 | # Parse argv |
[email protected] | 1e3b8f0 | 2010-05-31 23:47:51 | [diff] [blame] | 463 | parser = optparse.OptionParser(usage=USAGE, |
| 464 | version=__version__, |
| 465 | prog=prog) |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 466 | epilog = EPILOG % { 'prog': prog } |
| 467 | if extra_epilog: |
| 468 | epilog += extra_epilog |
[email protected] | 1e3b8f0 | 2010-05-31 23:47:51 | [diff] [blame] | 469 | parser.epilog = epilog |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 470 | # Remove epilog formatting |
| 471 | parser.format_epilog = lambda x: parser.epilog |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 472 | parser.add_option("-v", "--verbose", action="count", default=0, |
| 473 | help="Prints debugging infos") |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 474 | group = optparse.OptionGroup(parser, "Result and status") |
| 475 | group.add_option("-u", "--user", default=getpass.getuser(), |
| 476 | help="Owner user name [default: %default]") |
[email protected] | e1555a6 | 2009-11-09 17:05:54 | [diff] [blame] | 477 | group.add_option("-e", "--email", |
| 478 | default=os.environ.get('TRYBOT_RESULTS_EMAIL_ADDRESS', |
| 479 | os.environ.get('EMAIL_ADDRESS')), |
| 480 | help="Email address where to send the results. Use either " |
| 481 | "the TRYBOT_RESULTS_EMAIL_ADDRESS environment " |
| 482 | "variable or EMAIL_ADDRESS to set the email address " |
| 483 | "the try bots report results to [default: %default]") |
[email protected] | c9f06b0 | 2009-11-03 19:32:08 | [diff] [blame] | 484 | group.add_option("-n", "--name", |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 485 | help="Descriptive name of the try job") |
| 486 | group.add_option("--issue", type='int', |
| 487 | help="Update rietveld issue try job status") |
| 488 | group.add_option("--patchset", type='int', |
[email protected] | 5f42314 | 2010-01-30 05:46:36 | [diff] [blame] | 489 | help="Update rietveld issue try job status. This is " |
| 490 | "optional if --issue is used, In that case, the " |
| 491 | "latest patchset will be used.") |
[email protected] | c308a74 | 2009-12-22 18:29:33 | [diff] [blame] | 492 | group.add_option("--dry_run", action='store_true', |
| 493 | help="Just prints the diff and quits") |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 494 | parser.add_option_group(group) |
| 495 | |
| 496 | group = optparse.OptionGroup(parser, "Try job options") |
| 497 | group.add_option("-b", "--bot", action="append", |
| 498 | help="Only use specifics build slaves, ex: '--bot win' to " |
| 499 | "run the try job only on the 'win' slave; see the try " |
[email protected] | 833b227 | 2009-09-10 18:30:23 | [diff] [blame] | 500 | "server waterfall for the slave's name") |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 501 | group.add_option("-r", "--revision", |
| 502 | help="Revision to use for the try job; default: the " |
| 503 | "revision will be determined by the try server; see " |
| 504 | "its waterfall for more info") |
| 505 | group.add_option("-c", "--clobber", action="store_true", |
| 506 | help="Force a clobber before building; e.g. don't do an " |
| 507 | "incremental build") |
[email protected] | b3b00a4 | 2009-07-03 00:47:34 | [diff] [blame] | 508 | # TODO(maruel): help="Select a specific configuration, usually 'debug' or " |
| 509 | # "'release'" |
| 510 | group.add_option("--target", help=optparse.SUPPRESS_HELP) |
| 511 | |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 512 | group.add_option("--project", |
[email protected] | c308a74 | 2009-12-22 18:29:33 | [diff] [blame] | 513 | help="Override which project to use. Projects are defined " |
| 514 | "server-side to define what default bot set to use") |
[email protected] | 833b227 | 2009-09-10 18:30:23 | [diff] [blame] | 515 | |
[email protected] | c305768 | 2010-05-01 01:47:02 | [diff] [blame] | 516 | group.add_option("-t", "--testfilter", action="append", |
| 517 | help="Add a gtest_filter to a test. Use multiple times to " |
| 518 | "specify filters for different tests. (i.e. " |
| 519 | "--testfilter base_unittests:ThreadTest.* " |
| 520 | "--testfilter ui_tests) If you specify any testfilters " |
| 521 | "the test results will not be reported in rietveld and " |
| 522 | "only tests with filters will run.") |
| 523 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 524 | parser.add_option_group(group) |
| 525 | |
| 526 | group = optparse.OptionGroup(parser, "Patch to run") |
| 527 | group.add_option("-f", "--file", default=file_list, dest="files", |
| 528 | metavar="FILE", action="append", |
| 529 | help="Use many times to list the files to include in the " |
| 530 | "try, relative to the repository root") |
| 531 | group.add_option("--diff", |
| 532 | help="File containing the diff to try") |
| 533 | group.add_option("--url", |
[email protected] | d089192 | 2010-05-31 18:33:16 | [diff] [blame] | 534 | help="Url where to grab a patch, e.g. " |
| 535 | "http://example.com/x.diff") |
| 536 | group.add_option("-R", "--rietveld_url", default="codereview.appspot.com", |
| 537 | metavar="URL", |
| 538 | help="Has 2 usages, both refer to the rietveld instance: " |
| 539 | "Specify which code review patch to use as the try job " |
| 540 | "or rietveld instance to update the try job results " |
| 541 | "Default:%default") |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 542 | group.add_option("--root", |
| 543 | help="Root to use for the patch; base subdirectory for " |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 544 | "patch created in a subdirectory") |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 545 | group.add_option("-p", "--patchlevel", type='int', metavar="LEVEL", |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 546 | help="Used as -pN parameter to patch") |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 547 | group.add_option("-s", "--sub_rep", action="append", default=[], |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 548 | help="Subcheckout to use in addition. This is mainly " |
[email protected] | 1c7db8e | 2010-01-07 02:00:19 | [diff] [blame] | 549 | "useful for gclient-style checkouts. Use @rev or " |
| 550 | "@branch or @branch1..branch2 to specify the " |
| 551 | "revision/branch to diff against.") |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 552 | group.add_option("--no_gclient", action="store_true", |
| 553 | help="Disable automatic search for gclient checkout.") |
[email protected] | 8ede00e | 2010-01-12 14:35:28 | [diff] [blame] | 554 | group.add_option("-E", "--exclude", action="append", |
| 555 | default=['ChangeLog'], metavar='REGEXP', |
| 556 | help="Regexp patterns to exclude files. Default: %default") |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 557 | parser.add_option_group(group) |
| 558 | |
| 559 | group = optparse.OptionGroup(parser, "Access the try server by HTTP") |
[email protected] | f7fb33e | 2009-06-17 12:59:15 | [diff] [blame] | 560 | group.add_option("--use_http", |
| 561 | action="store_const", |
| 562 | const=_SendChangeHTTP, |
| 563 | dest="send_patch", |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 564 | help="Use HTTP to talk to the try server [default]") |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 565 | group.add_option("-H", "--host", |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 566 | help="Host address") |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 567 | group.add_option("-P", "--port", |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 568 | help="HTTP port") |
| 569 | group.add_option("--proxy", |
| 570 | help="HTTP proxy") |
| 571 | parser.add_option_group(group) |
| 572 | |
| 573 | group = optparse.OptionGroup(parser, "Access the try server with SVN") |
[email protected] | f7fb33e | 2009-06-17 12:59:15 | [diff] [blame] | 574 | group.add_option("--use_svn", |
| 575 | action="store_const", |
| 576 | const=_SendChangeSVN, |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 577 | dest="send_patch", |
| 578 | help="Use SVN to talk to the try server") |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 579 | group.add_option("-S", "--svn_repo", |
[email protected] | f7fb33e | 2009-06-17 12:59:15 | [diff] [blame] | 580 | metavar="SVN_URL", |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 581 | help="SVN url to use to write the changes in; --use_svn is " |
| 582 | "implied when using --svn_repo") |
| 583 | parser.add_option_group(group) |
| 584 | |
| 585 | options, args = parser.parse_args(argv) |
[email protected] | d05e5fb | 2010-07-30 20:44:14 | [diff] [blame] | 586 | |
| 587 | # Note that the args array includes the script name, so |
| 588 | # a single argument results in len(args) == 2. |
| 589 | |
| 590 | # If they've asked for help, give it to them |
| 591 | if len(args) == 2 and args[1] == 'help': |
[email protected] | 3ccbf7e | 2009-12-22 20:46:42 | [diff] [blame] | 592 | parser.print_help() |
[email protected] | d05e5fb | 2010-07-30 20:44:14 | [diff] [blame] | 593 | return 0 |
| 594 | |
| 595 | # If they've said something confusing, don't spawn a try job until you |
| 596 | # understand what they want. |
| 597 | if len(args) > 1: |
| 598 | plural = "" |
| 599 | if len(args) > 2: |
| 600 | plural = "s" |
| 601 | print "Argument%s \"%s\" not understood" % (plural, " ".join(args[1:])) |
| 602 | parser.print_help() |
| 603 | return 1 |
[email protected] | f7fb33e | 2009-06-17 12:59:15 | [diff] [blame] | 604 | |
[email protected] | 2c0b77d | 2010-06-07 13:35:41 | [diff] [blame] | 605 | LOG_FORMAT = '%(levelname)s %(filename)s(%(lineno)d): %(message)s' |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 606 | if not swallow_exception: |
| 607 | if options.verbose == 0: |
[email protected] | 2c0b77d | 2010-06-07 13:35:41 | [diff] [blame] | 608 | logging.basicConfig(level=logging.WARNING, format=LOG_FORMAT) |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 609 | elif options.verbose == 1: |
[email protected] | 2c0b77d | 2010-06-07 13:35:41 | [diff] [blame] | 610 | logging.basicConfig(level=logging.INFO, format=LOG_FORMAT) |
[email protected] | 28a5a52 | 2010-05-08 00:14:05 | [diff] [blame] | 611 | elif options.verbose > 1: |
[email protected] | 2c0b77d | 2010-06-07 13:35:41 | [diff] [blame] | 612 | logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 613 | |
[email protected] | 7538b86 | 2010-01-08 21:41:33 | [diff] [blame] | 614 | logging.debug(argv) |
| 615 | |
[email protected] | 58a7c7d | 2010-05-31 01:15:18 | [diff] [blame] | 616 | # Strip off any @ in the user, otherwise svn gets confused. |
| 617 | options.user = options.user.split('@', 1)[0] |
| 618 | |
[email protected] | 5f42314 | 2010-01-30 05:46:36 | [diff] [blame] | 619 | if options.rietveld_url: |
| 620 | # Try to extract the review number if possible and fix the protocol. |
| 621 | if not '://' in options.rietveld_url: |
| 622 | options.rietveld_url = 'http://' + options.rietveld_url |
| 623 | match = re.match(r'^(.*)/(\d+)$', options.rietveld_url) |
| 624 | if match: |
| 625 | if options.issue or options.patchset: |
| 626 | parser.error('Cannot use both --issue and use a review number url') |
| 627 | options.issue = int(match.group(2)) |
| 628 | options.rietveld_url = match.group(1) |
| 629 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 630 | try: |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 631 | # Always include os.getcwd() in the checkout settings. |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 632 | checkouts = [] |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 633 | checkouts.append(GuessVCS(options, os.getcwd())) |
| 634 | checkouts[0].AutomagicalSettings() |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 635 | for item in options.sub_rep: |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 636 | checkout = GuessVCS(options, os.path.join(checkouts[0].checkout_root, |
| 637 | item)) |
| 638 | if checkout.checkout_root in [c.checkout_root for c in checkouts]: |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 639 | parser.error('Specified the root %s two times.' % |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 640 | checkout.checkout_root) |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 641 | checkouts.append(checkout) |
| 642 | |
[email protected] | b6d3649 | 2009-12-26 14:22:41 | [diff] [blame] | 643 | can_http = options.port and options.host |
| 644 | can_svn = options.svn_repo |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 645 | # If there was no transport selected yet, now we must have enough data to |
| 646 | # select one. |
[email protected] | b6d3649 | 2009-12-26 14:22:41 | [diff] [blame] | 647 | if not options.send_patch and not (can_http or can_svn): |
| 648 | parser.error('Please specify an access method.') |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 649 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 650 | # Convert options.diff into the content of the diff. |
| 651 | if options.url: |
[email protected] | 3ccbf7e | 2009-12-22 20:46:42 | [diff] [blame] | 652 | if options.files: |
| 653 | parser.error('You cannot specify files and --url at the same time.') |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 654 | options.diff = urllib.urlopen(options.url).read() |
| 655 | elif options.diff: |
[email protected] | 3ccbf7e | 2009-12-22 20:46:42 | [diff] [blame] | 656 | if options.files: |
| 657 | parser.error('You cannot specify files and --diff at the same time.') |
[email protected] | 9a2f37e | 2009-12-19 16:03:28 | [diff] [blame] | 658 | options.diff = gclient_utils.FileRead(options.diff, 'rb') |
[email protected] | 346737c | 2010-01-10 05:41:24 | [diff] [blame] | 659 | elif options.issue and options.patchset is None: |
[email protected] | c2190cb | 2010-01-10 01:57:06 | [diff] [blame] | 660 | # Retrieve the patch from rietveld when the diff is not specified. |
[email protected] | 5f42314 | 2010-01-30 05:46:36 | [diff] [blame] | 661 | # When patchset is specified, it's because it's done by gcl/git-try. |
[email protected] | 57af171 | 2010-03-18 00:31:51 | [diff] [blame] | 662 | if json is None: |
| 663 | parser.error('json or simplejson library is missing, please install.') |
[email protected] | 5f42314 | 2010-01-30 05:46:36 | [diff] [blame] | 664 | api_url = '%s/api/%d' % (options.rietveld_url, options.issue) |
| 665 | logging.debug(api_url) |
[email protected] | 57af171 | 2010-03-18 00:31:51 | [diff] [blame] | 666 | contents = json.loads(urllib.urlopen(api_url).read()) |
[email protected] | 5f42314 | 2010-01-30 05:46:36 | [diff] [blame] | 667 | options.patchset = contents['patchsets'][-1] |
| 668 | diff_url = ('%s/download/issue%d_%d.diff' % |
| 669 | (options.rietveld_url, options.issue, options.patchset)) |
[email protected] | c2190cb | 2010-01-10 01:57:06 | [diff] [blame] | 670 | diff = GetMungedDiff('', urllib.urlopen(diff_url).readlines()) |
| 671 | options.diff = ''.join(diff) |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 672 | else: |
| 673 | # Use this as the base. |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 674 | root = checkouts[0].checkout_root |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 675 | diffs = [] |
| 676 | for checkout in checkouts: |
| 677 | diff = checkout.GenerateDiff().splitlines(True) |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 678 | path_diff = gclient_utils.PathDifference(root, checkout.checkout_root) |
[email protected] | c2190cb | 2010-01-10 01:57:06 | [diff] [blame] | 679 | # Munge it. |
| 680 | diffs.extend(GetMungedDiff(path_diff, diff)) |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 681 | options.diff = ''.join(diffs) |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 682 | |
[email protected] | de24345 | 2009-10-06 21:02:56 | [diff] [blame] | 683 | if not options.bot: |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 684 | # Get try slaves from PRESUBMIT.py files if not specified. |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 685 | # Even if the diff comes from options.url, use the local checkout for bot |
| 686 | # selection. |
| 687 | try: |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 688 | import presubmit_support |
[email protected] | d9141bf | 2009-12-23 16:13:32 | [diff] [blame] | 689 | root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py') |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 690 | options.bot = presubmit_support.DoGetTrySlaves( |
[email protected] | f7ae6d5 | 2009-12-22 20:49:04 | [diff] [blame] | 691 | checkouts[0].GetFileNames(), |
[email protected] | 01d8c1d | 2010-01-07 01:56:59 | [diff] [blame] | 692 | checkouts[0].checkout_root, |
[email protected] | ea8c1a9 | 2009-12-20 17:21:59 | [diff] [blame] | 693 | root_presubmit, |
| 694 | False, |
| 695 | sys.stdout) |
| 696 | except ImportError: |
| 697 | pass |
| 698 | # If no bot is specified, either the default pool will be selected or the |
| 699 | # try server will refuse the job. Either case we don't need to interfere. |
[email protected] | de24345 | 2009-10-06 21:02:56 | [diff] [blame] | 700 | |
[email protected] | c9f06b0 | 2009-11-03 19:32:08 | [diff] [blame] | 701 | if options.name is None: |
| 702 | if options.issue: |
[email protected] | e3608df | 2009-11-10 20:22:57 | [diff] [blame] | 703 | options.name = 'Issue %s' % options.issue |
[email protected] | c9f06b0 | 2009-11-03 19:32:08 | [diff] [blame] | 704 | else: |
| 705 | options.name = 'Unnamed' |
| 706 | print('Note: use --name NAME to change the try job name.') |
| 707 | if not options.email: |
[email protected] | 3ccbf7e | 2009-12-22 20:46:42 | [diff] [blame] | 708 | parser.error('Using an anonymous checkout. Please use --email or set ' |
| 709 | 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.') |
[email protected] | e1555a6 | 2009-11-09 17:05:54 | [diff] [blame] | 710 | else: |
| 711 | print('Results will be emailed to: ' + options.email) |
[email protected] | c9f06b0 | 2009-11-03 19:32:08 | [diff] [blame] | 712 | |
[email protected] | c305768 | 2010-05-01 01:47:02 | [diff] [blame] | 713 | # Prevent rietveld updates if we aren't running all the tests. |
| 714 | if options.testfilter is not None: |
| 715 | options.issue = None |
| 716 | options.patchset = None |
| 717 | |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 718 | # Send the patch. |
[email protected] | b6d3649 | 2009-12-26 14:22:41 | [diff] [blame] | 719 | if options.send_patch: |
| 720 | # If forced. |
| 721 | options.send_patch(options) |
| 722 | PrintSuccess(options) |
| 723 | return 0 |
| 724 | try: |
| 725 | if can_http: |
| 726 | _SendChangeHTTP(options) |
| 727 | PrintSuccess(options) |
| 728 | return 0 |
| 729 | except NoTryServerAccess: |
| 730 | if not can_svn: |
| 731 | raise |
| 732 | _SendChangeSVN(options) |
| 733 | PrintSuccess(options) |
| 734 | return 0 |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 735 | except (InvalidScript, NoTryServerAccess), e: |
| 736 | if swallow_exception: |
[email protected] | c9f06b0 | 2009-11-03 19:32:08 | [diff] [blame] | 737 | return 1 |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 738 | print e |
[email protected] | c9f06b0 | 2009-11-03 19:32:08 | [diff] [blame] | 739 | return 1 |
| 740 | return 0 |
[email protected] | fb2b8eb | 2009-04-23 21:03:42 | [diff] [blame] | 741 | |
| 742 | |
| 743 | if __name__ == "__main__": |
[email protected] | 2185f00 | 2009-12-18 21:03:47 | [diff] [blame] | 744 | sys.exit(TryChange(None, [], False)) |