OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 """Client-side script to send a try job to the try server. It communicates to | 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 | 6 the try server by either writting to a svn repository or by directly connecting |
7 to the server by HTTP. | 7 to the server by HTTP. |
8 """ | 8 """ |
9 | 9 |
10 | 10 |
11 import datetime | 11 import datetime |
12 import getpass | 12 import getpass |
13 import logging | 13 import logging |
14 import optparse | 14 import optparse |
15 import os | 15 import os |
16 import shutil | 16 import shutil |
17 import socket | 17 import socket |
18 import subprocess | 18 import subprocess |
19 import sys | 19 import sys |
20 import tempfile | 20 import tempfile |
21 import traceback | 21 import traceback |
22 import urllib | 22 import urllib |
23 | 23 |
24 import gcl | 24 import gcl |
25 import gclient | 25 import gclient |
26 import gclient_scm | 26 import gclient_scm |
| 27 import presubmit_support |
27 import upload | 28 import upload |
28 | 29 |
29 __version__ = '1.1.1' | 30 __version__ = '1.1.1' |
30 | 31 |
31 | 32 |
32 # Constants | 33 # Constants |
33 HELP_STRING = "Sorry, Tryserver is not available." | 34 HELP_STRING = "Sorry, Tryserver is not available." |
34 USAGE = r"""%prog [options] | 35 USAGE = r"""%prog [options] |
35 | 36 |
36 Client-side script to send a try job to the try server. It communicates to | 37 Client-side script to send a try job to the try server. It communicates to |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 "======\n") | 189 "======\n") |
189 # Note: Should we use /dev/null instead? | 190 # Note: Should we use /dev/null instead? |
190 data += "--- %s\n" % file | 191 data += "--- %s\n" % file |
191 data += "+++ %s\n" % file | 192 data += "+++ %s\n" % file |
192 data += "@@ -0,0 +1,%d @@\n" % nb_lines | 193 data += "@@ -0,0 +1,%d @@\n" % nb_lines |
193 data += ''.join(file_content) | 194 data += ''.join(file_content) |
194 diff.append(data) | 195 diff.append(data) |
195 os.chdir(previous_cwd) | 196 os.chdir(previous_cwd) |
196 return "".join(diff) | 197 return "".join(diff) |
197 | 198 |
| 199 def GetFileNames(self): |
| 200 """Return the list of files in the diff.""" |
| 201 return self.change_info.GetFileNames() |
| 202 |
| 203 def GetLocalRoot(self): |
| 204 """Return the path of the repository root.""" |
| 205 return self.change_info.GetLocalRoot() |
| 206 |
198 def ProcessOptions(self): | 207 def ProcessOptions(self): |
199 if not self.options.diff: | 208 if not self.options.diff: |
200 # Generate the diff with svn and write it to the submit queue path. The | 209 # Generate the diff with svn and write it to the submit queue path. The |
201 # files are relative to the repository root, but we need patches relative | 210 # files are relative to the repository root, but we need patches relative |
202 # to one level up from there (i.e., 'src'), so adjust both the file | 211 # to one level up from there (i.e., 'src'), so adjust both the file |
203 # paths and the root of the diff. | 212 # paths and the root of the diff. |
204 source_root = GetSourceRoot() | 213 source_root = GetSourceRoot() |
205 prefix = PathDifference(source_root, gcl.GetRepositoryRoot()) | 214 prefix = PathDifference(source_root, gcl.GetRepositoryRoot()) |
206 adjusted_paths = [os.path.join(prefix, x) for x in self.options.files] | 215 adjusted_paths = [os.path.join(prefix, x) for x in self.options.files] |
207 self.options.diff = self.GenerateDiff(adjusted_paths, root=source_root) | 216 self.options.diff = self.GenerateDiff(adjusted_paths, root=source_root) |
| 217 self.change_info = gcl.LoadChangelistInfoForMultiple(self.options.name, |
| 218 gcl.GetRepositoryRoot(), True, True) |
208 | 219 |
209 | 220 |
210 class GIT(SCM): | 221 class GIT(SCM): |
211 """Gathers the options and diff for a git checkout.""" | 222 """Gathers the options and diff for a git checkout.""" |
212 def GenerateDiff(self): | 223 def GenerateDiff(self): |
213 """Get the diff we'll send to the try server. We ignore the files list.""" | 224 """Get the diff we'll send to the try server. We ignore the files list.""" |
214 branch = upload.RunShell(['git', 'cl', 'upstream']).strip() | 225 branch = upload.RunShell(['git', 'cl', 'upstream']).strip() |
215 diff = upload.RunShell(['git', 'diff-tree', '-p', '--no-prefix', | 226 diff = upload.RunShell(['git', 'diff-tree', '-p', '--no-prefix', |
216 branch, 'HEAD']).splitlines(True) | 227 branch, 'HEAD']).splitlines(True) |
217 for i in range(len(diff)): | 228 for i in range(len(diff)): |
218 # In the case of added files, replace /dev/null with the path to the | 229 # In the case of added files, replace /dev/null with the path to the |
219 # file being added. | 230 # file being added. |
220 if diff[i].startswith('--- /dev/null'): | 231 if diff[i].startswith('--- /dev/null'): |
221 diff[i] = '--- %s' % diff[i+1][4:] | 232 diff[i] = '--- %s' % diff[i+1][4:] |
222 return ''.join(diff) | 233 return ''.join(diff) |
223 | 234 |
224 def GetEmail(self): | 235 def GetEmail(self): |
225 # TODO: check for errors here? | 236 # TODO: check for errors here? |
226 return upload.RunShell(['git', 'config', 'user.email']).strip() | 237 return upload.RunShell(['git', 'config', 'user.email']).strip() |
227 | 238 |
| 239 def GetFileNames(self): |
| 240 """Return the list of files in the diff.""" |
| 241 return self.options.files |
| 242 |
| 243 def GetLocalRoot(self): |
| 244 """Return the path of the repository root.""" |
| 245 # TODO: check for errors here? |
| 246 root = upload.RunShell(['git', 'rev-parse', '--show-cdup']).strip() |
| 247 return os.path.abspath(root) |
| 248 |
228 def GetPatchName(self): | 249 def GetPatchName(self): |
229 """Construct a name for this patch.""" | 250 """Construct a name for this patch.""" |
230 # TODO: perhaps include the hash of the current commit, to distinguish | 251 # TODO: perhaps include the hash of the current commit, to distinguish |
231 # patches? | 252 # patches? |
232 branch = upload.RunShell(['git', 'symbolic-ref', 'HEAD']).strip() | 253 branch = upload.RunShell(['git', 'symbolic-ref', 'HEAD']).strip() |
233 if not branch.startswith('refs/heads/'): | 254 if not branch.startswith('refs/heads/'): |
234 raise "Couldn't figure out branch name" | 255 raise "Couldn't figure out branch name" |
235 branch = branch[len('refs/heads/'):] | 256 branch = branch[len('refs/heads/'):] |
236 return branch | 257 return branch |
237 | 258 |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 raise | 424 raise |
404 | 425 |
405 raise NoTryServerAccess("Could not guess version control system. " | 426 raise NoTryServerAccess("Could not guess version control system. " |
406 "Are you in a working copy directory?") | 427 "Are you in a working copy directory?") |
407 | 428 |
408 | 429 |
409 def TryChange(argv, | 430 def TryChange(argv, |
410 file_list, | 431 file_list, |
411 swallow_exception, | 432 swallow_exception, |
412 prog=None): | 433 prog=None): |
| 434 """ |
| 435 Args: |
| 436 argv: Arguments and options. |
| 437 file_list: Default value to pass to --file. |
| 438 swallow_exception: Whether we raise or swallow exceptions. |
| 439 """ |
413 default_settings = GetTryServerSettings() | 440 default_settings = GetTryServerSettings() |
414 transport_functions = { 'http': _SendChangeHTTP, 'svn': _SendChangeSVN } | 441 transport_functions = { 'http': _SendChangeHTTP, 'svn': _SendChangeSVN } |
415 default_transport = transport_functions.get( | 442 default_transport = transport_functions.get( |
416 default_settings.get('default_transport')) | 443 default_settings.get('default_transport')) |
417 | 444 |
418 # Parse argv | 445 # Parse argv |
419 parser = optparse.OptionParser(usage=USAGE, | 446 parser = optparse.OptionParser(usage=USAGE, |
420 version=__version__, | 447 version=__version__, |
421 prog=prog) | 448 prog=prog) |
422 | 449 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 options.diff = gcl.ReadFile(options.diff) | 562 options.diff = gcl.ReadFile(options.diff) |
536 # Process the VCS in any case at least to retrieve the email address. | 563 # Process the VCS in any case at least to retrieve the email address. |
537 try: | 564 try: |
538 options.scm = GuessVCS(options) | 565 options.scm = GuessVCS(options) |
539 options.scm.ProcessOptions() | 566 options.scm.ProcessOptions() |
540 except NoTryServerAccess, e: | 567 except NoTryServerAccess, e: |
541 # If we got the diff, we don't care. | 568 # If we got the diff, we don't care. |
542 if not options.diff: | 569 if not options.diff: |
543 raise | 570 raise |
544 | 571 |
| 572 # Get try slaves from PRESUBMIT.py files if not specified. |
| 573 if not options.bot: |
| 574 root_presubmit = gcl.GetCachedFile('PRESUBMIT.py', use_root=True) |
| 575 options.bot = presubmit_support.DoGetTrySlaves(options.scm.GetFileNames(), |
| 576 options.scm.GetLocalRoot(), |
| 577 root_presubmit, |
| 578 False, |
| 579 sys.stdout) |
| 580 |
545 # Send the patch. | 581 # Send the patch. |
546 patch_name = options.send_patch(options) | 582 patch_name = options.send_patch(options) |
547 print 'Patch \'%s\' sent to try server.' % patch_name | 583 print 'Patch \'%s\' sent to try server: %s' % (patch_name, |
| 584 ', '.join(options.bot)) |
548 if patch_name == 'Unnamed': | 585 if patch_name == 'Unnamed': |
549 print "Note: use --name NAME to change the try's name." | 586 print "Note: use --name NAME to change the try's name." |
550 except (InvalidScript, NoTryServerAccess), e: | 587 except (InvalidScript, NoTryServerAccess), e: |
551 if swallow_exception: | 588 if swallow_exception: |
552 return | 589 return |
553 print e | 590 print e |
554 | 591 |
555 | 592 |
556 if __name__ == "__main__": | 593 if __name__ == "__main__": |
557 TryChange(None, None, False) | 594 TryChange(None, None, False) |
OLD | NEW |