1#!/usr/bin/env python3 2# Copyright 2022 The Chromium Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5"""Check out the Fuchsia SDK from a given GCS path. Should be used in a 6'hooks_os' entry so that it only runs when .gclient's custom_vars includes 7'fuchsia'.""" 8 9import argparse 10import json 11import logging 12import os 13import platform 14import subprocess 15import sys 16from typing import Optional 17 18from gcs_download import DownloadAndUnpackFromCloudStorage 19 20sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 21 'test'))) 22 23from common import SDK_ROOT, get_host_os, make_clean_directory 24 25_VERSION_FILE = os.path.join(SDK_ROOT, 'meta', 'manifest.json') 26 27 28def _GetHostArch(): 29 host_arch = platform.machine() 30 # platform.machine() returns AMD64 on 64-bit Windows. 31 if host_arch in ['x86_64', 'AMD64']: 32 return 'amd64' 33 elif host_arch == 'aarch64': 34 return 'arm64' 35 raise Exception('Unsupported host architecture: %s' % host_arch) 36 37 38def GetSDKOverrideGCSPath(path: Optional[str] = None) -> Optional[str]: 39 """Fetches the sdk override path from a file. 40 41 Args: 42 path: the full file path to read the data from. 43 defaults to sdk_override.txt in the directory of this file. 44 45 Returns: 46 The contents of the file, stripped of white space. 47 Example: gs://fuchsia-artifacts/development/some-id/sdk 48 """ 49 if not path: 50 path = os.path.join(os.path.dirname(__file__), 'sdk_override.txt') 51 52 if not os.path.isfile(path): 53 return None 54 55 with open(path, 'r') as f: 56 return f.read().strip() 57 58 59def _GetTarballPath(gcs_tarball_prefix: str) -> str: 60 """Get the full path to the sdk tarball on GCS""" 61 platform = get_host_os() 62 arch = _GetHostArch() 63 return f'{gcs_tarball_prefix}/{platform}-{arch}/core.tar.gz' 64 65 66def main(): 67 parser = argparse.ArgumentParser() 68 parser.add_argument('--cipd-prefix', help='CIPD base directory for the SDK.') 69 parser.add_argument('--version', help='Specifies the SDK version.') 70 parser.add_argument('--verbose', 71 '-v', 72 action='store_true', 73 help='Enable debug-level logging.') 74 args = parser.parse_args() 75 76 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO) 77 78 # Exit if there's no SDK support for this platform. 79 try: 80 host_plat = get_host_os() 81 except: 82 logging.warning('Fuchsia SDK is not supported on this platform.') 83 return 0 84 85 gcs_tarball_prefix = GetSDKOverrideGCSPath() 86 new_version = gcs_tarball_prefix if gcs_tarball_prefix else args.version 87 curr_version = None 88 if os.path.exists(_VERSION_FILE): 89 with open(_VERSION_FILE) as f: 90 curr_version = json.load(f)['id'] 91 92 if new_version == curr_version: 93 return 94 make_clean_directory(SDK_ROOT) 95 96 # Download from CIPD if there is no override file. 97 if not gcs_tarball_prefix: 98 if not args.cipd_prefix: 99 parser.exit(1, '--cipd-prefix must be specified.') 100 if not args.version: 101 parser.exit(2, '--version must be specified.') 102 logging.info('Downloading SDK from CIPD...') 103 ensure_file = '%s%s-%s %s' % (args.cipd_prefix, host_plat, _GetHostArch(), 104 args.version) 105 subprocess.run(('cipd', 'ensure', '-ensure-file', '-', '-root', SDK_ROOT, 106 '-log-level', 'warning'), 107 check=True, 108 text=True, 109 input=ensure_file) 110 else: 111 logging.info('Downloading SDK from GCS...') 112 DownloadAndUnpackFromCloudStorage(_GetTarballPath(gcs_tarball_prefix), 113 SDK_ROOT) 114 115 # Build rules (e.g. fidl_library()) depend on updates to the top-level 116 # manifest to spot when to rebuild for an SDK update. Ensure that ninja 117 # sees that the SDK manifest has changed, regardless of the mtime set by 118 # the download & unpack steps above, by setting mtime to now. 119 # See crbug.com/1457463 120 os.utime(os.path.join(SDK_ROOT, 'meta', 'manifest.json'), None) 121 122 root_dir = os.path.dirname(os.path.realpath(__file__)) 123 build_def_cmd = [ 124 os.path.join(root_dir, 'gen_build_defs.py'), 125 ] 126 subprocess.run(build_def_cmd, check=True) 127 128 return 0 129 130 131if __name__ == '__main__': 132 sys.exit(main()) 133