• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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