1# Copyright 2021 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Copies files from CIPD to a specified directory. 15 16By default, Pigweed installs packages from a manifest file to a CIPD 17subdirectory as part of environment setup. This script will copy files from this 18directory into a specified output directory. 19 20Here's an example of how to use this script: 21 22Let's say you have a package with a static library: 23 24CIPD path: `pigweed/third_party/libsomething` 25Files: 26 ./libsomething/include/something.h 27 ./libsomething/libsomething.a 28 29And this package was referenced in my_project_packages.json, which was provided 30as a --cipd-package-file in your bootstrap script. 31 32To copy the static libraryto $PW_PROJECT_ROOT/static_libraries, you'd have an 33invocation something like this: 34 35copy_from_cipd --package-name=pigweed/third_party/libsomething \ 36 --mainfest=$PW_PROJECT_ROOT/tools/my_project_packages.json \ 37 --file=libsomething/libsomething.a \ 38 --out=$PW_PROJECT_ROOT/static_libraries 39""" 40 41import argparse 42import json 43import logging 44import os 45import shutil 46import subprocess 47import sys 48from pathlib import Path 49 50import pw_env_setup.cipd_setup.update 51 52logger = logging.getLogger(__name__) 53 54 55def parse_args(): 56 parser = argparse.ArgumentParser(description=__doc__) 57 parser.add_argument('--verbose', 58 '-v', 59 help='Verbose output', 60 action='store_true') 61 parser.add_argument('--manifest', 62 required=True, 63 type=Path, 64 help='Path to CIPD JSON manifest file') 65 parser.add_argument('--out-dir', 66 type=Path, 67 default='.', 68 help='Output folder to copy the specified file to') 69 parser.add_argument('--package-name', 70 required=True, 71 help='The CIPD package name') 72 # TODO(pwbug/334) Support multiple values for --file. 73 parser.add_argument('--file', 74 required=True, 75 type=Path, 76 help='Path of the file to copy from the CIPD package. ' 77 'This is relative to the CIPD package root of the ' 78 'provided manifest.') 79 parser.add_argument('--cipd-package-root', 80 type=Path, 81 help="Path to the root of the package's install " 82 'directory. This is usually at ' 83 'PW_{manifest name}_CIPD_INSTALL_DIR') 84 return parser.parse_args() 85 86 87def check_version(manifest, cipd_path, package_name): 88 base_package_name = os.path.basename(package_name) 89 instance_id_path = os.path.join(cipd_path, '.versions', 90 f'{base_package_name}.cipd_version') 91 with open(instance_id_path, 'r') as ins: 92 instance_id = json.load(ins)['instance_id'] 93 94 with open(manifest, 'r') as ins: 95 data = json.load(ins) 96 # TODO(pwbug/599) Always assume this is a dict. 97 if isinstance(data, dict): 98 data = data['packages'] 99 100 path = None 101 expected_version = None 102 for entry in data: 103 if package_name in entry['path']: 104 path = entry['path'] 105 expected_version = entry['tags'][0] 106 if not path: 107 raise LookupError(f'failed to find {package_name} entry') 108 109 cmd = ['cipd', 'describe', path, '-version', instance_id] 110 output = subprocess.check_output(cmd).decode() 111 if expected_version not in output: 112 pw_env_setup.cipd_setup.update.update( 113 'cipd', (manifest, ), os.environ['PW_CIPD_INSTALL_DIR'], 114 os.environ['CIPD_CACHE_DIR']) 115 116 117def main(): 118 args = parse_args() 119 120 if args.verbose: 121 logger.setLevel(logging.DEBUG) 122 123 # Try to infer CIPD install root from the manifest name. 124 if args.cipd_package_root is None: 125 file_base_name = args.manifest.stem 126 args.cipd_var = 'PW_{}_CIPD_INSTALL_DIR'.format(file_base_name.upper()) 127 try: 128 args.cipd_package_root = os.environ[args.cipd_var] 129 except KeyError: 130 logger.error( 131 "The %s environment variable isn't set. Did you forget to run " 132 '`. ./bootstrap.sh`? Is the %s manifest installed to a ' 133 'different path?', args.cipd_var, file_base_name) 134 sys.exit(1) 135 136 check_version(args.manifest, args.cipd_package_root, args.package_name) 137 138 shutil.copyfile(os.path.join(args.cipd_package_root, args.file), 139 os.path.join(args.out_dir, args.file)) 140 141 142if __name__ == '__main__': 143 logging.basicConfig() 144 main() 145