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 """Parse arguments.""" 57 parser = argparse.ArgumentParser(description=__doc__) 58 parser.add_argument( 59 '--verbose', '-v', help='Verbose output', action='store_true' 60 ) 61 parser.add_argument( 62 '--manifest', 63 required=True, 64 type=Path, 65 help='Path to CIPD JSON manifest file', 66 ) 67 parser.add_argument( 68 '--out-dir', 69 type=Path, 70 default='.', 71 help='Output folder to copy the specified file to', 72 ) 73 parser.add_argument( 74 '--package-name', required=True, help='The CIPD package name' 75 ) 76 # TODO(pwbug/334) Support multiple values for --file. 77 parser.add_argument( 78 '--file', 79 required=True, 80 type=Path, 81 help='Path of the file to copy from the CIPD package. ' 82 'This is relative to the CIPD package root of the ' 83 'provided manifest.', 84 ) 85 parser.add_argument( 86 '--cipd-package-root', 87 type=Path, 88 help="Path to the root of the package's install " 89 'directory. This is usually at ' 90 'PW_{manifest name}_CIPD_INSTALL_DIR', 91 ) 92 return parser.parse_args() 93 94 95def check_version(manifest, cipd_path, package_name): 96 base_package_name = os.path.basename(package_name) 97 instance_id_path = os.path.join( 98 cipd_path, '.versions', f'{base_package_name}.cipd_version' 99 ) 100 with open(instance_id_path, 'r') as ins: 101 instance_id = json.load(ins)['instance_id'] 102 103 with open(manifest, 'r') as ins: 104 data = json.load(ins)['packages'] 105 106 path = None 107 expected_version = None 108 for entry in data: 109 if package_name in entry['path']: 110 path = entry['path'] 111 expected_version = entry['tags'][0] 112 if not path: 113 raise LookupError(f'failed to find {package_name} entry') 114 115 cmd = ['cipd', 'describe', path, '-version', instance_id] 116 output = subprocess.check_output(cmd).decode() 117 if expected_version not in output: 118 pw_env_setup.cipd_setup.update.update( 119 'cipd', 120 (manifest,), 121 os.environ['PW_CIPD_INSTALL_DIR'], 122 os.environ['CIPD_CACHE_DIR'], 123 ) 124 125 126def main(): 127 args = parse_args() 128 129 if args.verbose: 130 logger.setLevel(logging.DEBUG) 131 132 # Try to infer CIPD install root from the manifest name. 133 if args.cipd_package_root is None: 134 file_base_name = args.manifest.stem 135 args.cipd_var = 'PW_{}_CIPD_INSTALL_DIR'.format(file_base_name.upper()) 136 try: 137 args.cipd_package_root = os.environ[args.cipd_var] 138 except KeyError: 139 logger.error( 140 "The %s environment variable isn't set. Did you forget to run " 141 '`. ./bootstrap.sh`? Is the %s manifest installed to a ' 142 'different path?', 143 args.cipd_var, 144 file_base_name, 145 ) 146 sys.exit(1) 147 148 check_version(args.manifest, args.cipd_package_root, args.package_name) 149 150 shutil.copyfile( 151 os.path.join(args.cipd_package_root, args.file), 152 os.path.join(args.out_dir, args.file), 153 ) 154 155 156if __name__ == '__main__': 157 logging.basicConfig() 158 main() 159