| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Utility functions used by the bisect tool. | 5 """Utility functions used by the bisect tool. |
| 6 | 6 |
| 7 This includes functions related to checking out the depot and outputting | 7 This includes functions related to checking out the depot and outputting |
| 8 annotations for the Buildbot waterfall. | 8 annotations for the Buildbot waterfall. |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import errno | 11 import errno |
| 12 import imp | 12 import imp |
| 13 import os | 13 import os |
| 14 import shutil | |
| 15 import stat | 14 import stat |
| 16 import subprocess | 15 import subprocess |
| 17 import sys | 16 import sys |
| 18 | 17 |
| 19 DEFAULT_GCLIENT_CUSTOM_DEPS = { | 18 DEFAULT_GCLIENT_CUSTOM_DEPS = { |
| 20 'src/data/page_cycler': 'https://chrome-internal.googlesource.com/' | 19 'src/data/page_cycler': 'https://chrome-internal.googlesource.com/' |
| 21 'chrome/data/page_cycler/.git', | 20 'chrome/data/page_cycler/.git', |
| 22 'src/data/dom_perf': 'https://chrome-internal.googlesource.com/' | 21 'src/data/dom_perf': 'https://chrome-internal.googlesource.com/' |
| 23 'chrome/data/dom_perf/.git', | 22 'chrome/data/dom_perf/.git', |
| 24 'src/data/mach_ports': 'https://chrome-internal.googlesource.com/' | 23 'src/data/mach_ports': 'https://chrome-internal.googlesource.com/' |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 CROS_SCRIPT_KEY_PATH = os.path.join( | 75 CROS_SCRIPT_KEY_PATH = os.path.join( |
| 77 '..', 'cros', 'src', 'scripts', 'mod_for_test_scripts', 'ssh_keys', | 76 '..', 'cros', 'src', 'scripts', 'mod_for_test_scripts', 'ssh_keys', |
| 78 'testing_rsa') | 77 'testing_rsa') |
| 79 | 78 |
| 80 REPO_PARAMS = [ | 79 REPO_PARAMS = [ |
| 81 'https://chrome-internal.googlesource.com/chromeos/manifest-internal/', | 80 'https://chrome-internal.googlesource.com/chromeos/manifest-internal/', |
| 82 '--repo-url', | 81 '--repo-url', |
| 83 'https://git.chromium.org/external/repo.git' | 82 'https://git.chromium.org/external/repo.git' |
| 84 ] | 83 ] |
| 85 | 84 |
| 85 # Bisect working directory. |
| 86 BISECT_DIR = 'bisect' |
| 87 |
| 86 | 88 |
| 87 def OutputAnnotationStepStart(name): | 89 def OutputAnnotationStepStart(name): |
| 88 """Outputs annotation to signal the start of a step to a try bot. | 90 """Outputs annotation to signal the start of a step to a try bot. |
| 89 | 91 |
| 90 Args: | 92 Args: |
| 91 name: The name of the step. | 93 name: The name of the step. |
| 92 """ | 94 """ |
| 93 print | 95 print |
| 94 print '@@@SEED_STEP %s@@@' % name | 96 print '@@@SEED_STEP %s@@@' % name |
| 95 print '@@@STEP_CURSOR %s@@@' % name | 97 print '@@@STEP_CURSOR %s@@@' % name |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 | 157 |
| 156 Args: | 158 Args: |
| 157 working_directory: The directory to create the new 'bisect' directory in. | 159 working_directory: The directory to create the new 'bisect' directory in. |
| 158 | 160 |
| 159 Returns: | 161 Returns: |
| 160 True if the directory was successfully created (or already existed). | 162 True if the directory was successfully created (or already existed). |
| 161 """ | 163 """ |
| 162 cwd = os.getcwd() | 164 cwd = os.getcwd() |
| 163 os.chdir(working_directory) | 165 os.chdir(working_directory) |
| 164 try: | 166 try: |
| 165 os.mkdir('bisect') | 167 os.mkdir(BISECT_DIR) |
| 166 except OSError, e: | 168 except OSError, e: |
| 167 if e.errno != errno.EEXIST: # EEXIST indicates that it already exists. | 169 if e.errno != errno.EEXIST: # EEXIST indicates that it already exists. |
| 168 os.chdir(cwd) | 170 os.chdir(cwd) |
| 169 return False | 171 return False |
| 170 os.chdir('bisect') | 172 os.chdir(BISECT_DIR) |
| 171 return True | 173 return True |
| 172 | 174 |
| 173 | 175 |
| 174 def _SubprocessCall(cmd, cwd=None): | 176 def _SubprocessCall(cmd, cwd=None): |
| 175 """Runs a command in a subprocess. | 177 """Runs a command in a subprocess. |
| 176 | 178 |
| 177 Args: | 179 Args: |
| 178 cmd: The command to run. | 180 cmd: The command to run. |
| 179 cwd: Working directory to run from. | 181 cwd: Working directory to run from. |
| 180 | 182 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 path: The path name passed to func. | 303 path: The path name passed to func. |
| 302 _: Exception information from sys.exc_info(). Not used. | 304 _: Exception information from sys.exc_info(). Not used. |
| 303 """ | 305 """ |
| 304 if not os.access(path, os.W_OK): | 306 if not os.access(path, os.W_OK): |
| 305 os.chmod(path, stat.S_IWUSR) | 307 os.chmod(path, stat.S_IWUSR) |
| 306 func(path) | 308 func(path) |
| 307 else: | 309 else: |
| 308 raise | 310 raise |
| 309 | 311 |
| 310 | 312 |
| 311 def RemoveThirdPartyDirectory(dir_name): | |
| 312 """Removes third_party directory from the source. | |
| 313 | |
| 314 At some point, some of the third_parties were causing issues to changes in | |
| 315 the way they are synced. We remove such folder in order to avoid sync errors | |
| 316 while bisecting. | |
| 317 | |
| 318 Returns: | |
| 319 True on success, otherwise False. | |
| 320 """ | |
| 321 path_to_dir = os.path.join(os.getcwd(), 'third_party', dir_name) | |
| 322 try: | |
| 323 if os.path.exists(path_to_dir): | |
| 324 shutil.rmtree(path_to_dir, onerror=OnAccessError) | |
| 325 except OSError, e: | |
| 326 print 'Error #%d while running shutil.rmtree(%s): %s' % ( | |
| 327 e.errno, path_to_dir, str(e)) | |
| 328 if e.errno != errno.ENOENT: | |
| 329 return False | |
| 330 return True | |
| 331 | |
| 332 | |
| 333 def _CleanupPreviousGitRuns(): | 313 def _CleanupPreviousGitRuns(): |
| 334 """Cleans up any leftover index.lock files after running git.""" | 314 """Cleans up any leftover index.lock files after running git.""" |
| 335 # If a previous run of git crashed, or bot was reset, etc., then we might | 315 # If a previous run of git crashed, or bot was reset, etc., then we might |
| 336 # end up with leftover index.lock files. | 316 # end up with leftover index.lock files. |
| 337 for path, _, files in os.walk(os.getcwd()): | 317 for path, _, files in os.walk(os.getcwd()): |
| 338 for cur_file in files: | 318 for cur_file in files: |
| 339 if cur_file.endswith('index.lock'): | 319 if cur_file.endswith('index.lock'): |
| 340 path_to_file = os.path.join(path, cur_file) | 320 path_to_file = os.path.join(path, cur_file) |
| 341 os.remove(path_to_file) | 321 os.remove(path_to_file) |
| 342 | 322 |
| 343 | 323 |
| 344 def RunGClientAndSync(cwd=None): | 324 def RunGClientAndSync(cwd=None): |
| 345 """Runs gclient and does a normal sync. | 325 """Runs gclient and does a normal sync. |
| 346 | 326 |
| 347 Args: | 327 Args: |
| 348 cwd: Working directory to run from. | 328 cwd: Working directory to run from. |
| 349 | 329 |
| 350 Returns: | 330 Returns: |
| 351 The return code of the call. | 331 The return code of the call. |
| 352 """ | 332 """ |
| 353 params = ['sync', '--verbose', '--nohooks', '--reset', '--force'] | 333 params = ['sync', '--verbose', '--nohooks', '--reset', '--force', |
| 334 '--delete_unversioned_trees'] |
| 354 return RunGClient(params, cwd=cwd) | 335 return RunGClient(params, cwd=cwd) |
| 355 | 336 |
| 356 | 337 |
| 357 def SetupGitDepot(opts, custom_deps): | 338 def SetupGitDepot(opts, custom_deps): |
| 358 """Sets up the depot for the bisection. | 339 """Sets up the depot for the bisection. |
| 359 | 340 |
| 360 The depot will be located in a subdirectory called 'bisect'. | 341 The depot will be located in a subdirectory called 'bisect'. |
| 361 | 342 |
| 362 Args: | 343 Args: |
| 363 opts: The options parsed from the command line through parse_args(). | 344 opts: The options parsed from the command line through parse_args(). |
| 364 custom_deps: A dictionary of additional dependencies to add to .gclient. | 345 custom_deps: A dictionary of additional dependencies to add to .gclient. |
| 365 | 346 |
| 366 Returns: | 347 Returns: |
| 367 True if gclient successfully created the config file and did a sync, False | 348 True if gclient successfully created the config file and did a sync, False |
| 368 otherwise. | 349 otherwise. |
| 369 """ | 350 """ |
| 370 name = 'Setting up Bisection Depot' | 351 name = 'Setting up Bisection Depot' |
| 352 try: |
| 353 if opts.output_buildbot_annotations: |
| 354 OutputAnnotationStepStart(name) |
| 371 | 355 |
| 372 if opts.output_buildbot_annotations: | 356 if RunGClientAndCreateConfig(opts, custom_deps): |
| 373 OutputAnnotationStepStart(name) | 357 return False |
| 374 | 358 |
| 375 passed = False | 359 _CleanupPreviousGitRuns() |
| 376 | 360 RunGClient(['revert']) |
| 377 if not RunGClientAndCreateConfig(opts, custom_deps): | 361 return not RunGClientAndSync() |
| 378 passed_deps_check = True | 362 finally: |
| 379 if os.path.isfile(os.path.join('src', FILE_DEPS_GIT)): | 363 if opts.output_buildbot_annotations: |
| 380 cwd = os.getcwd() | 364 OutputAnnotationStepClosed() |
| 381 os.chdir('src') | |
| 382 if passed_deps_check: | |
| 383 passed_deps_check = RemoveThirdPartyDirectory('libjingle') | |
| 384 if passed_deps_check: | |
| 385 passed_deps_check = RemoveThirdPartyDirectory('skia') | |
| 386 os.chdir(cwd) | |
| 387 | |
| 388 if passed_deps_check: | |
| 389 _CleanupPreviousGitRuns() | |
| 390 | |
| 391 RunGClient(['revert']) | |
| 392 if not RunGClientAndSync(): | |
| 393 passed = True | |
| 394 | |
| 395 if opts.output_buildbot_annotations: | |
| 396 print | |
| 397 OutputAnnotationStepClosed() | |
| 398 | |
| 399 return passed | |
| 400 | 365 |
| 401 | 366 |
| 402 def CheckIfBisectDepotExists(opts): | 367 def CheckIfBisectDepotExists(opts): |
| 403 """Checks if the bisect directory already exists. | 368 """Checks if the bisect directory already exists. |
| 404 | 369 |
| 405 Args: | 370 Args: |
| 406 opts: The options parsed from the command line through parse_args(). | 371 opts: The options parsed from the command line through parse_args(). |
| 407 | 372 |
| 408 Returns: | 373 Returns: |
| 409 Returns True if it exists. | 374 Returns True if it exists. |
| 410 """ | 375 """ |
| 411 path_to_dir = os.path.join(opts.working_directory, 'bisect', 'src') | 376 path_to_dir = os.path.join(opts.working_directory, BISECT_DIR, 'src') |
| 412 return os.path.exists(path_to_dir) | 377 return os.path.exists(path_to_dir) |
| 413 | 378 |
| 414 | 379 |
| 415 def CheckRunGit(command, cwd=None): | 380 def CheckRunGit(command, cwd=None): |
| 416 """Run a git subcommand, returning its output and return code. Asserts if | 381 """Run a git subcommand, returning its output and return code. Asserts if |
| 417 the return code of the call is non-zero. | 382 the return code of the call is non-zero. |
| 418 | 383 |
| 419 Args: | 384 Args: |
| 420 command: A list containing the args to git. | 385 command: A list containing the args to git. |
| 421 | 386 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 444 | 409 |
| 445 | 410 |
| 446 def CreateBisectDirectoryAndSetupDepot(opts, custom_deps): | 411 def CreateBisectDirectoryAndSetupDepot(opts, custom_deps): |
| 447 """Sets up a subdirectory 'bisect' and then retrieves a copy of the depot | 412 """Sets up a subdirectory 'bisect' and then retrieves a copy of the depot |
| 448 there using gclient. | 413 there using gclient. |
| 449 | 414 |
| 450 Args: | 415 Args: |
| 451 opts: The options parsed from the command line through parse_args(). | 416 opts: The options parsed from the command line through parse_args(). |
| 452 custom_deps: A dictionary of additional dependencies to add to .gclient. | 417 custom_deps: A dictionary of additional dependencies to add to .gclient. |
| 453 """ | 418 """ |
| 419 if CheckIfBisectDepotExists(opts): |
| 420 path_to_dir = os.path.join(os.path.abspath(opts.working_directory), |
| 421 BISECT_DIR, 'src') |
| 422 (output, _) = RunGit(['rev-parse', '--is-inside-work-tree'], |
| 423 cwd=path_to_dir) |
| 424 if output.strip() == 'true': |
| 425 # Checks out the master branch, throws an exception if git command fails. |
| 426 CheckRunGit(['checkout', '-f', 'master'], cwd=path_to_dir) |
| 427 |
| 454 if not _CreateAndChangeToSourceDirectory(opts.working_directory): | 428 if not _CreateAndChangeToSourceDirectory(opts.working_directory): |
| 455 raise RuntimeError('Could not create bisect directory.') | 429 raise RuntimeError('Could not create bisect directory.') |
| 456 | 430 |
| 457 if not SetupGitDepot(opts, custom_deps): | 431 if not SetupGitDepot(opts, custom_deps): |
| 458 raise RuntimeError('Failed to grab source.') | 432 raise RuntimeError('Failed to grab source.') |
| 459 | 433 |
| 460 | 434 |
| 461 def RunProcess(command): | 435 def RunProcess(command): |
| 462 """Runs an arbitrary command. | 436 """Runs an arbitrary command. |
| 463 | 437 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 platform = os.environ.get('PROCESSOR_ARCHITECTURE') | 509 platform = os.environ.get('PROCESSOR_ARCHITECTURE') |
| 536 return platform and platform in ['AMD64', 'I64'] | 510 return platform and platform in ['AMD64', 'I64'] |
| 537 | 511 |
| 538 | 512 |
| 539 def IsLinuxHost(): | 513 def IsLinuxHost(): |
| 540 return sys.platform.startswith('linux') | 514 return sys.platform.startswith('linux') |
| 541 | 515 |
| 542 | 516 |
| 543 def IsMacHost(): | 517 def IsMacHost(): |
| 544 return sys.platform.startswith('darwin') | 518 return sys.platform.startswith('darwin') |
| OLD | NEW |