OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 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 | 5 |
6 """Performance Test Bisect Tool | 6 """Performance Test Bisect Tool |
7 | 7 |
8 This script bisects a series of changelists using binary search. It starts at | 8 This script bisects a series of changelists using binary search. It starts at |
9 a bad revision where a performance metric has regressed, and asks for a last | 9 a bad revision where a performance metric has regressed, and asks for a last |
10 known-good revision. It will then binary search across this revision range by | 10 known-good revision. It will then binary search across this revision range by |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 | 475 |
476 def FetchFromCloudStorage(bucket_name, source_path, destination_path): | 476 def FetchFromCloudStorage(bucket_name, source_path, destination_path): |
477 """Fetches file(s) from the Google Cloud Storage. | 477 """Fetches file(s) from the Google Cloud Storage. |
478 | 478 |
479 Args: | 479 Args: |
480 bucket_name: Google Storage bucket name. | 480 bucket_name: Google Storage bucket name. |
481 source_path: Source file path. | 481 source_path: Source file path. |
482 destination_path: Destination file path. | 482 destination_path: Destination file path. |
483 | 483 |
484 Returns: | 484 Returns: |
485 True if the fetching succeeds, otherwise False. | 485 Downloaded file path if exisits, otherwise None. |
486 """ | 486 """ |
487 target_file = os.path.join(destination_path, os.path.basename(source_path)) | 487 target_file = os.path.join(destination_path, os.path.basename(source_path)) |
488 try: | 488 try: |
489 if cloud_storage.Exists(bucket_name, source_path): | 489 if cloud_storage.Exists(bucket_name, source_path): |
490 print 'Fetching file from gs//%s/%s ...' % (bucket_name, source_path) | 490 print 'Fetching file from gs//%s/%s ...' % (bucket_name, source_path) |
491 cloud_storage.Get(bucket_name, source_path, destination_path) | 491 cloud_storage.Get(bucket_name, source_path, destination_path) |
492 if os.path.exists(target_file): | 492 if os.path.exists(target_file): |
493 return True | 493 return target_file |
494 else: | 494 else: |
495 print ('File gs://%s/%s not found in cloud storage.' % ( | 495 print ('File gs://%s/%s not found in cloud storage.' % ( |
496 bucket_name, source_path)) | 496 bucket_name, source_path)) |
497 except Exception as e: | 497 except Exception as e: |
498 print 'Something went wrong while fetching file from cloud: %s' % e | 498 print 'Something went wrong while fetching file from cloud: %s' % e |
499 if os.path.exists(target_file): | 499 if os.path.exists(target_file): |
500 os.remove(target_file) | 500 os.remove(target_file) |
501 return False | 501 return None |
502 | 502 |
503 | 503 |
504 # This is copied from Chromium's project build/scripts/common/chromium_utils.py. | 504 # This is copied from Chromium's project build/scripts/common/chromium_utils.py. |
505 def MaybeMakeDirectory(*path): | 505 def MaybeMakeDirectory(*path): |
506 """Creates an entire path, if it doesn't already exist.""" | 506 """Creates an entire path, if it doesn't already exist.""" |
507 file_path = os.path.join(*path) | 507 file_path = os.path.join(*path) |
508 try: | 508 try: |
509 os.makedirs(file_path) | 509 os.makedirs(file_path) |
510 except OSError, e: | 510 except OSError, e: |
511 if e.errno != errno.EEXIST: | 511 if e.errno != errno.EEXIST: |
(...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1546 source_dir = os.path.join(build_dir, build_type) | 1546 source_dir = os.path.join(build_dir, build_type) |
1547 destination_dir = os.path.join(build_dir, '%s.bak' % build_type) | 1547 destination_dir = os.path.join(build_dir, '%s.bak' % build_type) |
1548 if restore: | 1548 if restore: |
1549 source_dir, destination_dir = destination_dir, source_dir | 1549 source_dir, destination_dir = destination_dir, source_dir |
1550 if os.path.exists(source_dir): | 1550 if os.path.exists(source_dir): |
1551 RmTreeAndMkDir(destination_dir, skip_makedir=True) | 1551 RmTreeAndMkDir(destination_dir, skip_makedir=True) |
1552 shutil.move(source_dir, destination_dir) | 1552 shutil.move(source_dir, destination_dir) |
1553 return destination_dir | 1553 return destination_dir |
1554 return None | 1554 return None |
1555 | 1555 |
| 1556 def GetBuildArchiveForRevision(self, revision, gs_bucket, target_arch, |
| 1557 patch_sha, out_dir): |
| 1558 """Checks and downloads build archive for a given revision. |
| 1559 |
| 1560 Checks for build archive with Git hash or SVN revision. If either of the |
| 1561 file exists, then downloads the archive file. |
| 1562 |
| 1563 Args: |
| 1564 revision: A Git hash revision. |
| 1565 gs_bucket: Cloud storage bucket name |
| 1566 target_arch: 32 or 64 bit build target |
| 1567 patch: A DEPS patch (used while bisecting 3rd party repositories). |
| 1568 out_dir: Build output directory where downloaded file is stored. |
| 1569 |
| 1570 Returns: |
| 1571 Downloaded archive file path if exists, otherwise None. |
| 1572 """ |
| 1573 # Source archive file path on cloud storage using Git revision. |
| 1574 source_file = GetRemoteBuildPath(revision, target_arch, patch_sha) |
| 1575 downloaded_archive = FetchFromCloudStorage(gs_bucket, source_file, out_dir) |
| 1576 if not downloaded_archive: |
| 1577 # Get SVN revision for the given SHA. |
| 1578 svn_revision = self.source_control.SVNFindRev(revision) |
| 1579 if svn_revision: |
| 1580 # Source archive file path on cloud storage using SVN revision. |
| 1581 source_file = GetRemoteBuildPath(svn_revision, target_arch, patch_sha) |
| 1582 return FetchFromCloudStorage(gs_bucket, source_file, out_dir) |
| 1583 return downloaded_archive |
| 1584 |
1556 def DownloadCurrentBuild(self, revision, build_type='Release', patch=None): | 1585 def DownloadCurrentBuild(self, revision, build_type='Release', patch=None): |
1557 """Downloads the build archive for the given revision. | 1586 """Downloads the build archive for the given revision. |
1558 | 1587 |
1559 Args: | 1588 Args: |
1560 revision: The SVN revision to build. | 1589 revision: The Git revision to download or build. |
1561 build_type: Target build type ('Release', 'Debug', 'Release_x64' etc.) | 1590 build_type: Target build type ('Release', 'Debug', 'Release_x64' etc.) |
| 1591 patch: A DEPS patch (used while bisecting 3rd party repositories). |
1562 | 1592 |
1563 Returns: | 1593 Returns: |
1564 True if download succeeds, otherwise False. | 1594 True if download succeeds, otherwise False. |
1565 """ | 1595 """ |
1566 patch_sha = None | 1596 patch_sha = None |
1567 if patch: | 1597 if patch: |
1568 # Get the SHA of the DEPS changes patch. | 1598 # Get the SHA of the DEPS changes patch. |
1569 patch_sha = GetSHA1HexDigest(patch) | 1599 patch_sha = GetSHA1HexDigest(patch) |
1570 | 1600 |
1571 # Update the DEPS changes patch with a patch to create a new file named | 1601 # Update the DEPS changes patch with a patch to create a new file named |
1572 # 'DEPS.sha' and add patch_sha evaluated above to it. | 1602 # 'DEPS.sha' and add patch_sha evaluated above to it. |
1573 patch = '%s\n%s' % (patch, DEPS_SHA_PATCH % {'deps_sha': patch_sha}) | 1603 patch = '%s\n%s' % (patch, DEPS_SHA_PATCH % {'deps_sha': patch_sha}) |
1574 | 1604 |
1575 # Source archive file path on cloud storage. | |
1576 source_file = GetRemoteBuildPath(revision, self.opts.target_arch, patch_sha) | |
1577 | |
1578 # Get Build output directory | 1605 # Get Build output directory |
1579 abs_build_dir = os.path.abspath( | 1606 abs_build_dir = os.path.abspath( |
1580 self.builder.GetBuildOutputDirectory(self.opts, self.src_cwd)) | 1607 self.builder.GetBuildOutputDirectory(self.opts, self.src_cwd)) |
1581 # Downloaded archive file path. | |
1582 downloaded_file = os.path.join( | |
1583 abs_build_dir, | |
1584 GetZipFileName(revision, self.opts.target_arch, patch_sha)) | |
1585 | 1608 |
1586 fetch_build_func = lambda: FetchFromCloudStorage(self.opts.gs_bucket, | 1609 fetch_build_func = lambda: self.GetBuildArchiveForRevision( |
1587 source_file, | 1610 revision, self.opts.gs_bucket, self.opts.target_arch, |
1588 abs_build_dir) | 1611 patch_sha, abs_build_dir) |
1589 | 1612 |
1590 if not fetch_build_func(): | 1613 # Downloaded archive file path, downloads build archive for given revision. |
1591 if not self.PostBuildRequestAndWait(revision, | 1614 downloaded_file = fetch_build_func() |
1592 fetch_build=fetch_build_func, | 1615 |
1593 patch=patch): | 1616 # When build archive doesn't exists, post a build request to tryserver |
1594 raise RuntimeError('Somewthing went wrong while processing build' | 1617 # and wait for the build to be produced. |
1595 'request for: %s' % revision) | 1618 if not downloaded_file: |
| 1619 downloaded_file = self.PostBuildRequestAndWait( |
| 1620 revision, fetch_build=fetch_build_func, patch=patch) |
| 1621 if not downloaded_file: |
| 1622 return False |
| 1623 |
1596 # Generic name for the archive, created when archive file is extracted. | 1624 # Generic name for the archive, created when archive file is extracted. |
1597 output_dir = os.path.join( | 1625 output_dir = os.path.join( |
1598 abs_build_dir, GetZipFileName(target_arch=self.opts.target_arch)) | 1626 abs_build_dir, GetZipFileName(target_arch=self.opts.target_arch)) |
1599 # Unzip build archive directory. | 1627 # Unzip build archive directory. |
1600 try: | 1628 try: |
1601 RmTreeAndMkDir(output_dir, skip_makedir=True) | 1629 RmTreeAndMkDir(output_dir, skip_makedir=True) |
1602 ExtractZip(downloaded_file, abs_build_dir) | 1630 ExtractZip(downloaded_file, abs_build_dir) |
1603 if os.path.exists(output_dir): | 1631 if os.path.exists(output_dir): |
1604 self.BackupOrRestoreOutputdirectory(restore=False) | 1632 self.BackupOrRestoreOutputdirectory(restore=False) |
1605 # Build output directory based on target(e.g. out/Release, out/Debug). | 1633 # Build output directory based on target(e.g. out/Release, out/Debug). |
(...skipping 21 matching lines...) Expand all Loading... |
1627 | 1655 |
1628 Args: | 1656 Args: |
1629 fetch_build: Function to check and download build from cloud storage. | 1657 fetch_build: Function to check and download build from cloud storage. |
1630 bot_name: Builder bot name on tryserver. | 1658 bot_name: Builder bot name on tryserver. |
1631 builder_host Tryserver hostname. | 1659 builder_host Tryserver hostname. |
1632 builder_port: Tryserver port. | 1660 builder_port: Tryserver port. |
1633 build_request_id: A unique ID of the build request posted to tryserver. | 1661 build_request_id: A unique ID of the build request posted to tryserver. |
1634 max_timeout: Maximum time to wait for the build. | 1662 max_timeout: Maximum time to wait for the build. |
1635 | 1663 |
1636 Returns: | 1664 Returns: |
1637 True if build exists and download is successful, otherwise throws | 1665 Downloaded archive file path if exists, otherwise None. |
1638 RuntimeError exception when time elapse. | |
1639 """ | 1666 """ |
1640 # Build number on the tryserver. | 1667 # Build number on the tryserver. |
1641 build_num = None | 1668 build_num = None |
1642 # Interval to check build on cloud storage. | 1669 # Interval to check build on cloud storage. |
1643 poll_interval = 60 | 1670 poll_interval = 60 |
1644 # Interval to check build status on tryserver. | 1671 # Interval to check build status on tryserver. |
1645 status_check_interval = 600 | 1672 status_check_interval = 600 |
1646 last_status_check = time.time() | 1673 last_status_check = time.time() |
1647 start_time = time.time() | 1674 start_time = time.time() |
1648 while True: | 1675 while True: |
1649 # Checks for build on gs://chrome-perf and download if exists. | 1676 # Checks for build on gs://chrome-perf and download if exists. |
1650 res = fetch_build() | 1677 res = fetch_build() |
1651 if res: | 1678 if res: |
1652 return (res, 'Build successfully found') | 1679 return (res, 'Build successfully found') |
1653 elapsed_status_check = time.time() - last_status_check | 1680 elapsed_status_check = time.time() - last_status_check |
1654 # To avoid overloading tryserver with status check requests, we check | 1681 # To avoid overloading tryserver with status check requests, we check |
1655 # build status for every 10 mins. | 1682 # build status for every 10 mins. |
1656 if elapsed_status_check > status_check_interval: | 1683 if elapsed_status_check > status_check_interval: |
1657 last_status_check = time.time() | 1684 last_status_check = time.time() |
1658 if not build_num: | 1685 if not build_num: |
1659 # Get the build number on tryserver for the current build. | 1686 # Get the build number on tryserver for the current build. |
1660 build_num = bisect_builder.GetBuildNumFromBuilder( | 1687 build_num = bisect_builder.GetBuildNumFromBuilder( |
1661 build_request_id, bot_name, builder_host, builder_port) | 1688 build_request_id, bot_name, builder_host, builder_port) |
1662 # Check the status of build using the build number. | 1689 # Check the status of build using the build number. |
1663 # Note: Build is treated as PENDING if build number is not found | 1690 # Note: Build is treated as PENDING if build number is not found |
1664 # on the the tryserver. | 1691 # on the the tryserver. |
1665 build_status, status_link = bisect_builder.GetBuildStatus( | 1692 build_status, status_link = bisect_builder.GetBuildStatus( |
1666 build_num, bot_name, builder_host, builder_port) | 1693 build_num, bot_name, builder_host, builder_port) |
1667 if build_status == bisect_builder.FAILED: | 1694 if build_status == bisect_builder.FAILED: |
1668 return (False, 'Failed to produce build, log: %s' % status_link) | 1695 return (None, 'Failed to produce build, log: %s' % status_link) |
1669 elapsed_time = time.time() - start_time | 1696 elapsed_time = time.time() - start_time |
1670 if elapsed_time > max_timeout: | 1697 if elapsed_time > max_timeout: |
1671 return (False, 'Timed out: %ss without build' % max_timeout) | 1698 return (None, 'Timed out: %ss without build' % max_timeout) |
1672 | 1699 |
1673 print 'Time elapsed: %ss without build.' % elapsed_time | 1700 print 'Time elapsed: %ss without build.' % elapsed_time |
1674 time.sleep(poll_interval) | 1701 time.sleep(poll_interval) |
1675 | 1702 |
1676 def PostBuildRequestAndWait(self, revision, fetch_build, patch=None): | 1703 def PostBuildRequestAndWait(self, revision, fetch_build, patch=None): |
1677 """POSTs the build request job to the tryserver instance.""" | 1704 """POSTs the build request job to the tryserver instance. |
| 1705 |
| 1706 A try job build request is posted to tryserver.chromium.perf master, |
| 1707 and waits for the binaries to be produced and archived on cloud storage. |
| 1708 Once the build is ready and stored onto cloud, build archive is downloaded |
| 1709 into the output folder. |
| 1710 |
| 1711 Args: |
| 1712 revision: A Git hash revision. |
| 1713 fetch_build: Function to check and download build from cloud storage. |
| 1714 patch: A DEPS patch (used while bisecting 3rd party repositories). |
| 1715 |
| 1716 Returns: |
| 1717 Downloaded archive file path when requested build exists and download is |
| 1718 successful, otherwise None. |
| 1719 """ |
| 1720 # Get SVN revision for the given SHA. |
| 1721 svn_revision = self.source_control.SVNFindRev(revision) |
| 1722 if not svn_revision: |
| 1723 raise RuntimeError( |
| 1724 'Failed to determine SVN revision for %s' % revision) |
1678 | 1725 |
1679 def GetBuilderNameAndBuildTime(target_arch='ia32'): | 1726 def GetBuilderNameAndBuildTime(target_arch='ia32'): |
1680 """Gets builder bot name and buildtime in seconds based on platform.""" | 1727 """Gets builder bot name and buildtime in seconds based on platform.""" |
1681 # Bot names should match the one listed in tryserver.chromium's | 1728 # Bot names should match the one listed in tryserver.chromium's |
1682 # master.cfg which produces builds for bisect. | 1729 # master.cfg which produces builds for bisect. |
1683 if IsWindows(): | 1730 if IsWindows(): |
1684 if Is64BitWindows() and target_arch == 'x64': | 1731 if Is64BitWindows() and target_arch == 'x64': |
1685 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) | 1732 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) |
1686 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) | 1733 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) |
1687 if IsLinux(): | 1734 if IsLinux(): |
1688 return ('linux_perf_bisect_builder', MAX_LINUX_BUILD_TIME) | 1735 return ('linux_perf_bisect_builder', MAX_LINUX_BUILD_TIME) |
1689 if IsMac(): | 1736 if IsMac(): |
1690 return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME) | 1737 return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME) |
1691 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) | 1738 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) |
1692 if not fetch_build: | 1739 if not fetch_build: |
1693 return False | 1740 return False |
1694 | 1741 |
1695 bot_name, build_timeout = GetBuilderNameAndBuildTime(self.opts.target_arch) | 1742 bot_name, build_timeout = GetBuilderNameAndBuildTime(self.opts.target_arch) |
1696 builder_host = self.opts.builder_host | 1743 builder_host = self.opts.builder_host |
1697 builder_port = self.opts.builder_port | 1744 builder_port = self.opts.builder_port |
1698 # Create a unique ID for each build request posted to tryserver builders. | 1745 # Create a unique ID for each build request posted to tryserver builders. |
1699 # This ID is added to "Reason" property in build's json. | 1746 # This ID is added to "Reason" property in build's json. |
1700 build_request_id = GetSHA1HexDigest( | 1747 build_request_id = GetSHA1HexDigest( |
1701 '%s-%s-%s' % (revision, patch, time.time())) | 1748 '%s-%s-%s' % (svn_revision, patch, time.time())) |
1702 | 1749 |
1703 # Creates a try job description. | 1750 # Creates a try job description. |
1704 job_args = {'host': builder_host, | 1751 job_args = {'host': builder_host, |
1705 'port': builder_port, | 1752 'port': builder_port, |
1706 'revision': 'src@%s' % revision, | 1753 'revision': 'src@%s' % svn_revision, |
1707 'bot': bot_name, | 1754 'bot': bot_name, |
1708 'name': build_request_id | 1755 'name': build_request_id |
1709 } | 1756 } |
1710 # Update patch information if supplied. | 1757 # Update patch information if supplied. |
1711 if patch: | 1758 if patch: |
1712 job_args['patch'] = patch | 1759 job_args['patch'] = patch |
1713 # Posts job to build the revision on the server. | 1760 # Posts job to build the revision on the server. |
1714 if bisect_builder.PostTryJob(job_args): | 1761 if bisect_builder.PostTryJob(job_args): |
1715 status, error_msg = self.WaitUntilBuildIsReady(fetch_build, | 1762 target_file, error_msg = self.WaitUntilBuildIsReady(fetch_build, |
1716 bot_name, | 1763 bot_name, |
1717 builder_host, | 1764 builder_host, |
1718 builder_port, | 1765 builder_port, |
1719 build_request_id, | 1766 build_request_id, |
1720 build_timeout) | 1767 build_timeout) |
1721 if not status: | 1768 if not target_file: |
1722 raise RuntimeError('%s [revision: %s]' % (error_msg, revision)) | 1769 print '%s [revision: %s]' % (error_msg, svn_revision) |
1723 return True | 1770 return None |
1724 return False | 1771 return target_file |
| 1772 print 'Failed to post build request for revision: [%s]' % svn_revision |
| 1773 return None |
1725 | 1774 |
1726 def IsDownloadable(self, depot): | 1775 def IsDownloadable(self, depot): |
1727 """Checks if build is downloadable based on target platform and depot.""" | 1776 """Checks if build is downloadable based on target platform and depot.""" |
1728 if self.opts.target_platform in ['chromium'] and self.opts.gs_bucket: | 1777 if self.opts.target_platform in ['chromium'] and self.opts.gs_bucket: |
1729 return (depot == 'chromium' or | 1778 return (depot == 'chromium' or |
1730 'chromium' in DEPOT_DEPS_NAME[depot]['from'] or | 1779 'chromium' in DEPOT_DEPS_NAME[depot]['from'] or |
1731 'v8' in DEPOT_DEPS_NAME[depot]['from']) | 1780 'v8' in DEPOT_DEPS_NAME[depot]['from']) |
1732 return False | 1781 return False |
1733 | 1782 |
1734 def UpdateDeps(self, revision, depot, deps_file): | 1783 def UpdateDeps(self, revision, depot, deps_file): |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1914 return True | 1963 return True |
1915 cwd = os.getcwd() | 1964 cwd = os.getcwd() |
1916 os.chdir(self.src_cwd) | 1965 os.chdir(self.src_cwd) |
1917 # Fetch build archive for the given revision from the cloud storage when | 1966 # Fetch build archive for the given revision from the cloud storage when |
1918 # the storage bucket is passed. | 1967 # the storage bucket is passed. |
1919 if self.IsDownloadable(depot) and revision: | 1968 if self.IsDownloadable(depot) and revision: |
1920 deps_patch = None | 1969 deps_patch = None |
1921 if depot != 'chromium': | 1970 if depot != 'chromium': |
1922 # Create a DEPS patch with new revision for dependency repository. | 1971 # Create a DEPS patch with new revision for dependency repository. |
1923 (revision, deps_patch) = self.CreateDEPSPatch(depot, revision) | 1972 (revision, deps_patch) = self.CreateDEPSPatch(depot, revision) |
1924 # Get SVN revision for the given SHA, since builds are archived using SVN | 1973 if self.DownloadCurrentBuild(revision, patch=deps_patch): |
1925 # revision. | |
1926 chromium_revision = self.source_control.SVNFindRev(revision) | |
1927 if not chromium_revision: | |
1928 raise RuntimeError( | |
1929 'Failed to determine SVN revision for %s' % revision) | |
1930 if self.DownloadCurrentBuild(chromium_revision, patch=deps_patch): | |
1931 os.chdir(cwd) | 1974 os.chdir(cwd) |
1932 if deps_patch: | 1975 if deps_patch: |
1933 # Reverts the changes to DEPS file. | 1976 # Reverts the changes to DEPS file. |
1934 self.source_control.CheckoutFileAtRevision(bisect_utils.FILE_DEPS, | 1977 self.source_control.CheckoutFileAtRevision(bisect_utils.FILE_DEPS, |
1935 revision, | 1978 revision, |
1936 cwd=self.src_cwd) | 1979 cwd=self.src_cwd) |
1937 return True | 1980 return True |
1938 raise RuntimeError('Failed to download build archive for revision %s.\n' | 1981 return False |
1939 'Unfortunately, bisection couldn\'t continue any ' | |
1940 'further. Please try running script without ' | |
1941 '--gs_bucket flag to produce local builds.' % revision) | |
1942 | 1982 |
1943 | 1983 # These codes are executed when bisect bots builds binaries locally. |
1944 build_success = self.builder.Build(depot, self.opts) | 1984 build_success = self.builder.Build(depot, self.opts) |
1945 os.chdir(cwd) | 1985 os.chdir(cwd) |
1946 return build_success | 1986 return build_success |
1947 | 1987 |
1948 def RunGClientHooks(self): | 1988 def RunGClientHooks(self): |
1949 """Runs gclient with runhooks command. | 1989 """Runs gclient with runhooks command. |
1950 | 1990 |
1951 Returns: | 1991 Returns: |
1952 True if gclient reports no errors. | 1992 True if gclient reports no errors. |
1953 """ | 1993 """ |
(...skipping 2023 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3977 # The perf dashboard scrapes the "results" step in order to comment on | 4017 # The perf dashboard scrapes the "results" step in order to comment on |
3978 # bugs. If you change this, please update the perf dashboard as well. | 4018 # bugs. If you change this, please update the perf dashboard as well. |
3979 bisect_utils.OutputAnnotationStepStart('Results') | 4019 bisect_utils.OutputAnnotationStepStart('Results') |
3980 print 'Error: %s' % e.message | 4020 print 'Error: %s' % e.message |
3981 if opts.output_buildbot_annotations: | 4021 if opts.output_buildbot_annotations: |
3982 bisect_utils.OutputAnnotationStepClosed() | 4022 bisect_utils.OutputAnnotationStepClosed() |
3983 return 1 | 4023 return 1 |
3984 | 4024 |
3985 if __name__ == '__main__': | 4025 if __name__ == '__main__': |
3986 sys.exit(main()) | 4026 sys.exit(main()) |
OLD | NEW |