/buildtools/ensure_gn_version.py
Python | 134 lines | 102 code | 15 blank | 17 comment | 10 complexity | d79aa7cdefc7eaa191df95672a2cc129 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
- #!/usr/bin/env python
- # Copyright 2019 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- """Ensure that CIPD fetched the right GN version.
- Due to crbug.com/944367, using cipd in gclient to fetch GN binaries
- may not always work right. This is a script that can be used as
- a backup method to force-install GN at the right revision, just in case.
- It should be used as a gclient hook alongside fetching GN via CIPD
- until we have a proper fix in place.
- TODO(crbug.com/944667): remove this script when it is no longer needed.
- """
- from __future__ import print_function
- import argparse
- import errno
- import io
- import os
- import re
- import stat
- import subprocess
- import sys
- try:
- import urllib2 as urllib
- except ImportError:
- import urllib.request as urllib
- import zipfile
- BUILDTOOLS_DIR = os.path.abspath(os.path.dirname(__file__))
- SRC_DIR = os.path.dirname(BUILDTOOLS_DIR)
- def ChmodGnFile(path_to_exe):
- """Makes the gn binary executable for all and writable for the user."""
- os.chmod(path_to_exe,
- stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | # This is 0o755.
- stat.S_IRGRP | stat.S_IXGRP |
- stat.S_IROTH | stat.S_IXOTH)
- def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('version',
- help='CIPD "git_revision:XYZ" label for GN to sync to')
- args = parser.parse_args()
- if not args.version.startswith('git_revision:'):
- print('Unknown version format: %s' % args.version)
- return 2
- desired_revision = args.version[len('git_revision:'):]
- if sys.platform == 'darwin':
- platform, member, dest_dir = ('mac-amd64', 'gn', 'mac')
- elif sys.platform == 'win32':
- platform, member, dest_dir = ('windows-amd64', 'gn.exe', 'win')
- else:
- platform, member, dest_dir = ('linux-amd64', 'gn', 'linux64')
- path_to_exe = os.path.join(BUILDTOOLS_DIR, dest_dir, member)
- cmd = [path_to_exe, '--version']
- cmd_str = ' '.join(cmd)
- try:
- out = subprocess.check_output(cmd,
- stderr=subprocess.STDOUT,
- cwd=SRC_DIR).decode(errors='replace')
- except subprocess.CalledProcessError as e:
- print('`%s` returned %d:\n%s' % (cmd_str, e.returncode, e.output))
- return 1
- except OSError as e:
- if e.errno != errno.ENOENT:
- print('`%s` failed:\n%s' % (cmd_str, e.strerror))
- return 1
- # The tool doesn't exist, so redownload it.
- out = ''
- if out:
- current_revision_match = re.findall(r'\((.*)\)', out)
- if current_revision_match:
- current_revision = current_revision_match[0]
- if desired_revision.startswith(current_revision):
- # We're on the right version, so we're done.
- return 0
- print("`%s` returned '%s', which wasn't what we were expecting."
- % (cmd_str, out.strip()))
- print("Force-installing %s to update it." % desired_revision)
- url = 'https://chrome-infra-packages.appspot.com/dl/gn/gn/%s/+/%s' % (
- platform, args.version)
- try:
- zipdata = urllib.urlopen(url).read()
- except urllib.HTTPError as e:
- print('Failed to download the package from %s: %d %s' % (
- url, e.code, e.reason))
- return 1
- try:
- # Make the existing file writable so that we can overwrite it.
- ChmodGnFile(path_to_exe)
- except OSError as e:
- if e.errno != errno.ENOENT:
- print('Failed to make %s writable:\n%s\n' % (path_to_exe, e.strerror))
- return 1
- try:
- zf = zipfile.ZipFile(io.BytesIO(zipdata))
- zf.extract(member, os.path.join(BUILDTOOLS_DIR, dest_dir))
- except OSError as e:
- print('Failed to extract the binary:\n%s\n' % e.strerror)
- return 1
- except (zipfile.LargeZipFile, zipfile.BadZipfile) as e:
- print('Zip containing gn was corrupt:\n%s\n' % e)
- return 1
- try:
- ChmodGnFile(path_to_exe)
- except OSError as e:
- print('Failed to make %s executable:\n%s\n' % (path_to_exe, e.strerror))
- return 1
- return 0
- if __name__ == '__main__':
- sys.exit(main())