blob: cfc75a37792a93f209a0e7543d577a18d004a615 [file] [log] [blame]
#!/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())