| 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 import datetime | 10 import datetime |
| 11 import getpass | 11 import getpass |
| 12 import logging | 12 import logging |
| 13 import optparse | 13 import optparse |
| 14 import os | 14 import os |
| 15 import shutil | 15 import shutil |
| 16 import socket | 16 import socket |
| 17 import subprocess | 17 import subprocess |
| 18 import sys | 18 import sys |
| 19 import tempfile | 19 import tempfile |
| 20 import urllib | 20 import urllib |
| 21 | 21 |
| 22 import breakpad | 22 import breakpad |
| 23 | 23 |
| 24 import gcl | 24 import gcl |
| 25 import gclient_utils |
| 25 import scm | 26 import scm |
| 26 import presubmit_support | 27 import presubmit_support |
| 27 import upload | 28 import upload |
| 28 | 29 |
| 29 __version__ = '1.1.2' | 30 __version__ = '1.1.2' |
| 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 [change_name] [options] | 35 USAGE = r"""%prog [change_name] [options] |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 settings['default_transport'] = 'http' | 112 settings['default_transport'] = 'http' |
| 112 elif settings.get('svn_repo'): | 113 elif settings.get('svn_repo'): |
| 113 settings['default_transport'] = 'svn' | 114 settings['default_transport'] = 'svn' |
| 114 return settings | 115 return settings |
| 115 | 116 |
| 116 | 117 |
| 117 def EscapeDot(name): | 118 def EscapeDot(name): |
| 118 return name.replace('.', '-') | 119 return name.replace('.', '-') |
| 119 | 120 |
| 120 | 121 |
| 121 def RunCommand(command): | |
| 122 output, retcode = gcl.RunShellWithReturnCode(command) | |
| 123 if retcode: | |
| 124 raise NoTryServerAccess(' '.join(command) + '\nOuput:\n' + output) | |
| 125 return output | |
| 126 | |
| 127 | |
| 128 class SCM(object): | 122 class SCM(object): |
| 129 """Simplistic base class to implement one function: ProcessOptions.""" | 123 """Simplistic base class to implement one function: ProcessOptions.""" |
| 130 def __init__(self, options): | 124 def __init__(self, options): |
| 131 self.options = options | 125 self.options = options |
| 132 | 126 |
| 133 def ProcessOptions(self): | 127 def ProcessOptions(self): |
| 134 raise NotImplementedError | 128 raise NotImplementedError |
| 135 | 129 |
| 136 | 130 |
| 137 class SVN(SCM): | 131 class SVN(SCM): |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 ' try server svn repository to connect to.') | 289 ' try server svn repository to connect to.') |
| 296 | 290 |
| 297 values = _ParseSendChangeOptions(options) | 291 values = _ParseSendChangeOptions(options) |
| 298 description = '' | 292 description = '' |
| 299 for (k,v) in values.iteritems(): | 293 for (k,v) in values.iteritems(): |
| 300 description += "%s=%s\n" % (k,v) | 294 description += "%s=%s\n" % (k,v) |
| 301 | 295 |
| 302 # Do an empty checkout. | 296 # Do an empty checkout. |
| 303 temp_dir = tempfile.mkdtemp() | 297 temp_dir = tempfile.mkdtemp() |
| 304 temp_file = tempfile.NamedTemporaryFile() | 298 temp_file = tempfile.NamedTemporaryFile() |
| 305 temp_file_name = temp_file.name | |
| 306 try: | 299 try: |
| 307 # Don't use '--non-interactive', since we want it to prompt for | 300 try: |
| 308 # crendentials if necessary. | 301 command = ['svn', 'checkout', '--depth', 'empty', '-q', |
| 309 command = ['svn', 'checkout', '--depth', 'empty', '-q', | 302 options.svn_repo, temp_dir] |
| 310 options.svn_repo, temp_dir] | 303 if options.email: |
| 311 if options.email: | 304 command += ['--username', options.email] |
| 312 command += ['--username', options.email] | 305 gclient_utils.CheckCall(command) |
| 313 # Don't use RunCommand() since svn may prompt for information. | |
| 314 use_shell = sys.platform.startswith("win") | |
| 315 subprocess.Popen(command, shell=use_shell).communicate() | |
| 316 | 306 |
| 317 # TODO(maruel): Use a subdirectory per user? | 307 # TODO(maruel): Use a subdirectory per user? |
| 318 current_time = str(datetime.datetime.now()).replace(':', '.') | 308 current_time = str(datetime.datetime.now()).replace(':', '.') |
| 319 file_name = (EscapeDot(options.user) + '.' + EscapeDot(options.name) + | 309 file_name = (EscapeDot(options.user) + '.' + EscapeDot(options.name) + |
| 320 '.%s.diff' % current_time) | 310 '.%s.diff' % current_time) |
| 321 full_path = os.path.join(temp_dir, file_name) | 311 full_path = os.path.join(temp_dir, file_name) |
| 322 full_url = options.svn_repo + '/' + file_name | 312 full_url = options.svn_repo + '/' + file_name |
| 323 file_found = False | 313 file_found = False |
| 324 try: | 314 try: |
| 325 RunCommand(['svn', 'ls', full_url]) | 315 gclient_utils.CheckCall(['svn', 'ls', full_url]) |
| 326 file_found = True | 316 file_found = True |
| 327 except NoTryServerAccess: | 317 except gclient_utils.CheckCallError: |
| 328 pass | 318 pass |
| 329 if file_found: | 319 if file_found: |
| 330 # The file already exists in the repo. Note that commiting a file is a | 320 # The file already exists in the repo. Note that commiting a file is a |
| 331 # no-op if the file's content (the diff) is not modified. This is why the | 321 # no-op if the file's content (the diff) is not modified. This is why |
| 332 # file name contains the date and time. | 322 # the file name contains the date and time. |
| 333 RunCommand(['svn', 'update', full_path]) | 323 gclient_utils.CheckCall(['svn', 'update', full_path]) |
| 334 f = open(full_path, 'wb') | 324 f = open(full_path, 'wb') |
| 335 f.write(options.diff) | 325 f.write(options.diff) |
| 336 f.close() | 326 f.close() |
| 337 else: | 327 else: |
| 338 # Add the file to the repo | 328 # Add the file to the repo |
| 339 f = open(full_path, 'wb') | 329 f = open(full_path, 'wb') |
| 340 f.write(options.diff) | 330 f.write(options.diff) |
| 341 f.close() | 331 f.close() |
| 342 RunCommand(["svn", "add", full_path]) | 332 gclient_utils.CheckCall(["svn", "add", full_path]) |
| 343 temp_file.write(description) | 333 temp_file.write(description) |
| 344 temp_file.flush() | 334 temp_file.flush() |
| 345 RunCommand(["svn", "commit", full_path, '--file', | 335 gclient_utils.CheckCall(["svn", "commit", full_path, '--file', |
| 346 temp_file_name]) | 336 temp_file.name]) |
| 337 except gclient_utils.CheckCallError, e: |
| 338 raise NoTryServerAccess(' '.join(e.command) + '\nOuput:\n' + |
| 339 e.stdout) |
| 347 finally: | 340 finally: |
| 348 temp_file.close() | 341 temp_file.close() |
| 349 shutil.rmtree(temp_dir, True) | 342 shutil.rmtree(temp_dir, True) |
| 350 | 343 |
| 351 | 344 |
| 352 def GuessVCS(options): | 345 def GuessVCS(options): |
| 353 """Helper to guess the version control system. | 346 """Helper to guess the version control system. |
| 354 | 347 |
| 355 NOTE: Very similar to upload.GuessVCS. Doesn't look for hg since we don't | 348 NOTE: Very similar to upload.GuessVCS. Doesn't look for hg since we don't |
| 356 support it yet. | 349 support it yet. |
| 357 | 350 |
| 358 This examines the current directory, guesses which SCM we're using, and | 351 This examines the current directory, guesses which SCM we're using, and |
| 359 returns an instance of the appropriate class. Exit with an error if we can't | 352 returns an instance of the appropriate class. Exit with an error if we can't |
| 360 figure it out. | 353 figure it out. |
| 361 | 354 |
| 362 Returns: | 355 Returns: |
| 363 A SCM instance. Exits if the SCM can't be guessed. | 356 A SCM instance. Exits if the SCM can't be guessed. |
| 364 """ | 357 """ |
| 365 __pychecker__ = 'no-returnvalues' | 358 __pychecker__ = 'no-returnvalues' |
| 366 # Subversion has a .svn in all working directories. | 359 # Subversion has a .svn in all working directories. |
| 367 if os.path.isdir('.svn'): | 360 if os.path.isdir('.svn'): |
| 368 logging.info("Guessed VCS = Subversion") | 361 logging.info("Guessed VCS = Subversion") |
| 369 return SVN(options) | 362 return SVN(options) |
| 370 | 363 |
| 371 # Git has a command to test if you're in a git tree. | 364 # Git has a command to test if you're in a git tree. |
| 372 # Try running it, but don't die if we don't have git installed. | 365 # Try running it, but don't die if we don't have git installed. |
| 373 try: | 366 try: |
| 374 out, returncode = gcl.RunShellWithReturnCode(["git", "rev-parse", | 367 out, returncode = subprocess.Popen( |
| 375 "--is-inside-work-tree"]) | 368 ["git", "rev-parse", "--is-inside-work-tree"], |
| 369 shell=sys.platform.startswith('win'), |
| 370 stdout=subprocess.PIPE).communicate()[0] |
| 376 if returncode == 0: | 371 if returncode == 0: |
| 377 logging.info("Guessed VCS = Git") | 372 logging.info("Guessed VCS = Git") |
| 378 return GIT(options) | 373 return GIT(options) |
| 379 except OSError, (errno, message): | 374 except OSError, (errno, message): |
| 380 if errno != 2: # ENOENT -- they don't have git installed. | 375 if errno != 2: # ENOENT -- they don't have git installed. |
| 381 raise | 376 raise |
| 382 | 377 |
| 383 raise NoTryServerAccess("Could not guess version control system. " | 378 raise NoTryServerAccess("Could not guess version control system. " |
| 384 "Are you in a working copy directory?") | 379 "Are you in a working copy directory?") |
| 385 | 380 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 not options.diff and not options.url): | 508 not options.diff and not options.url): |
| 514 # TODO(maruel): It should just try the modified files showing up in a | 509 # TODO(maruel): It should just try the modified files showing up in a |
| 515 # svn status. | 510 # svn status. |
| 516 parser.error('Nothing to try, changelist is empty.') | 511 parser.error('Nothing to try, changelist is empty.') |
| 517 | 512 |
| 518 try: | 513 try: |
| 519 # Convert options.diff into the content of the diff. | 514 # Convert options.diff into the content of the diff. |
| 520 if options.url: | 515 if options.url: |
| 521 options.diff = urllib.urlopen(options.url).read() | 516 options.diff = urllib.urlopen(options.url).read() |
| 522 elif options.diff: | 517 elif options.diff: |
| 523 options.diff = gcl.gclient_utils.FileRead(options.diff, 'rb') | 518 options.diff = gclient_utils.FileRead(options.diff, 'rb') |
| 524 # Process the VCS in any case at least to retrieve the email address. | 519 # Process the VCS in any case at least to retrieve the email address. |
| 525 try: | 520 try: |
| 526 options.scm = GuessVCS(options) | 521 options.scm = GuessVCS(options) |
| 527 options.scm.ProcessOptions() | 522 options.scm.ProcessOptions() |
| 528 except NoTryServerAccess, e: | 523 except NoTryServerAccess, e: |
| 529 # If we got the diff, we don't care. | 524 # If we got the diff, we don't care. |
| 530 if not options.diff: | 525 if not options.diff: |
| 531 # TODO(maruel): Raise what? | 526 # TODO(maruel): Raise what? |
| 532 raise | 527 raise |
| 533 | 528 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 561 except (InvalidScript, NoTryServerAccess), e: | 556 except (InvalidScript, NoTryServerAccess), e: |
| 562 if swallow_exception: | 557 if swallow_exception: |
| 563 return 1 | 558 return 1 |
| 564 print e | 559 print e |
| 565 return 1 | 560 return 1 |
| 566 return 0 | 561 return 0 |
| 567 | 562 |
| 568 | 563 |
| 569 if __name__ == "__main__": | 564 if __name__ == "__main__": |
| 570 sys.exit(TryChange(None, None, False)) | 565 sys.exit(TryChange(None, None, False)) |
| OLD | NEW |