168 lines
5.1 KiB
Python
Executable file
168 lines
5.1 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# Copyright 2017 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.
|
|
|
|
"""Updates the Fuchsia SDK to the given revision. Should be used in a 'hooks_os'
|
|
entry so that it only runs when .gclient's target_os includes 'fuchsia'."""
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tarfile
|
|
|
|
from common import GetHostOsFromPlatform, GetHostArchFromPlatform, \
|
|
DIR_SOURCE_ROOT, SDK_ROOT
|
|
|
|
sys.path.append(os.path.join(DIR_SOURCE_ROOT, 'build'))
|
|
import find_depot_tools
|
|
|
|
SDK_SIGNATURE_FILE = '.hash'
|
|
SDK_TARBALL_PATH_TEMPLATE = (
|
|
'gs://{bucket}/development/{sdk_hash}/sdk/{platform}-amd64/gn.tar.gz')
|
|
|
|
|
|
def ReadFile(filename):
|
|
with open(os.path.join(os.path.dirname(__file__), filename), 'r') as f:
|
|
return f.read()
|
|
|
|
|
|
# TODO(crbug.com/1138433): Investigate whether we can deprecate
|
|
# use of sdk_bucket.txt.
|
|
def GetOverrideCloudStorageBucket():
|
|
"""Read bucket entry from sdk_bucket.txt"""
|
|
return ReadFile('sdk-bucket.txt').strip()
|
|
|
|
|
|
def GetSdkHash(bucket):
|
|
hashes = GetSdkHashList()
|
|
return (max(hashes, key=lambda sdk: GetSdkGeneration(bucket, sdk))
|
|
if hashes else None)
|
|
|
|
|
|
def GetSdkHashList():
|
|
"""Read filename entries from sdk-hash-files.list (one per line), substitute
|
|
{platform} in each entry if present, and read from each filename."""
|
|
platform = GetHostOsFromPlatform()
|
|
filenames = [
|
|
line.strip() for line in ReadFile('sdk-hash-files.list').replace(
|
|
'{platform}', platform).splitlines()
|
|
]
|
|
sdk_hashes = [ReadFile(filename).strip() for filename in filenames]
|
|
return sdk_hashes
|
|
|
|
|
|
def GetSdkGeneration(bucket, hash):
|
|
if not hash:
|
|
return None
|
|
|
|
sdk_path = GetSdkTarballPath(bucket, hash)
|
|
cmd = [
|
|
os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gsutil.py'), 'ls', '-L',
|
|
sdk_path
|
|
]
|
|
logging.debug("Running '%s'", " ".join(cmd))
|
|
sdk_details = subprocess.check_output(cmd).decode('utf-8')
|
|
m = re.search('Generation:\s*(\d*)', sdk_details)
|
|
if not m:
|
|
raise RuntimeError('Could not find SDK generation for {sdk_path}'.format(
|
|
sdk_path=sdk_path))
|
|
return int(m.group(1))
|
|
|
|
|
|
def GetSdkTarballPath(bucket, sdk_hash):
|
|
return SDK_TARBALL_PATH_TEMPLATE.format(
|
|
bucket=bucket, sdk_hash=sdk_hash, platform=GetHostOsFromPlatform())
|
|
|
|
|
|
# Updates the modification timestamps of |path| and its contents to the
|
|
# current time.
|
|
def UpdateTimestampsRecursive():
|
|
for root, dirs, files in os.walk(SDK_ROOT):
|
|
for f in files:
|
|
os.utime(os.path.join(root, f), None)
|
|
for d in dirs:
|
|
os.utime(os.path.join(root, d), None)
|
|
|
|
|
|
# Fetches a tarball from GCS and uncompresses it to |output_dir|.
|
|
def DownloadAndUnpackFromCloudStorage(url, output_dir):
|
|
# Pass the compressed stream directly to 'tarfile'; don't bother writing it
|
|
# to disk first.
|
|
cmd = [os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gsutil.py'),
|
|
'cp', url, '-']
|
|
logging.debug('Running "%s"', ' '.join(cmd))
|
|
task = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
try:
|
|
tarfile.open(mode='r|gz', fileobj=task.stdout).extractall(path=output_dir)
|
|
except tarfile.ReadError:
|
|
task.wait()
|
|
stderr = task.stderr.read()
|
|
raise subprocess.CalledProcessError(task.returncode, cmd,
|
|
"Failed to read a tarfile from gsutil.py.{}".format(
|
|
stderr if stderr else ""))
|
|
task.wait()
|
|
if task.returncode:
|
|
raise subprocess.CalledProcessError(task.returncode, cmd,
|
|
task.stderr.read())
|
|
|
|
|
|
def MakeCleanDirectory(directory_name):
|
|
if (os.path.exists(directory_name)):
|
|
shutil.rmtree(directory_name)
|
|
os.mkdir(directory_name)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--verbose', '-v',
|
|
action='store_true',
|
|
help='Enable debug-level logging.')
|
|
parser.add_argument(
|
|
'--default-bucket',
|
|
type=str,
|
|
default='fuchsia',
|
|
help='The Google Cloud Storage bucket in which the Fuchsia SDK is '
|
|
'stored. Entry in sdk-bucket.txt will override this flag.')
|
|
args = parser.parse_args()
|
|
|
|
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
|
|
|
|
# Quietly exit if there's no SDK support for this platform.
|
|
try:
|
|
GetHostOsFromPlatform()
|
|
except:
|
|
return 0
|
|
|
|
# Use the bucket in sdk-bucket.txt if an entry exists.
|
|
# Otherwise use the default bucket.
|
|
bucket = GetOverrideCloudStorageBucket() or args.default_bucket
|
|
|
|
sdk_hash = GetSdkHash(bucket)
|
|
if not sdk_hash:
|
|
return 1
|
|
|
|
signature_filename = os.path.join(SDK_ROOT, SDK_SIGNATURE_FILE)
|
|
current_signature = (open(signature_filename, 'r').read().strip()
|
|
if os.path.exists(signature_filename) else '')
|
|
if current_signature != sdk_hash:
|
|
logging.info('Downloading GN SDK %s...' % sdk_hash)
|
|
|
|
MakeCleanDirectory(SDK_ROOT)
|
|
DownloadAndUnpackFromCloudStorage(GetSdkTarballPath(bucket, sdk_hash),
|
|
SDK_ROOT)
|
|
|
|
with open(signature_filename, 'w') as f:
|
|
f.write(sdk_hash)
|
|
|
|
UpdateTimestampsRecursive()
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|