1# Copyright 2019 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 built host tools into Pigweed's host_tools directory.""" 15 16import argparse 17import logging 18from pathlib import Path 19import shutil 20import sys 21 22import pw_cli.log 23 24_LOG = logging.getLogger(__name__) 25 26 27def argument_parser( 28 parser: argparse.ArgumentParser | None = None, 29) -> argparse.ArgumentParser: 30 """Registers the script's arguments on an argument parser.""" 31 32 if parser is None: 33 parser = argparse.ArgumentParser(description=__doc__) 34 35 parser.add_argument( 36 '--dst', type=Path, required=True, help='Path to host tools directory' 37 ) 38 parser.add_argument('--name', help='Name for the installed tool') 39 parser.add_argument( 40 '--out-root', 41 type=Path, 42 required=True, 43 help='Root of Ninja out directory', 44 ) 45 parser.add_argument( 46 '--src', type=Path, required=True, help='Path to host tool executable' 47 ) 48 49 return parser 50 51 52def main() -> int: 53 """Copies a host tool into a destination directory.""" 54 args = argument_parser().parse_args() 55 56 if not args.src.is_file(): 57 _LOG.error('%s is not a file', args.src) 58 return 1 59 60 args.dst.mkdir(parents=True, exist_ok=True) 61 62 if args.name is not None: 63 if '/' in args.name: 64 _LOG.error('Host tool name cannot contain "/"') 65 return 1 66 name = args.name 67 else: 68 name = args.src.name 69 70 try: 71 shutil.copy2(args.src, args.dst.joinpath(name)) 72 except OSError as err: 73 _LOG.error('%s', err) 74 75 # Errno 26 (text file busy) indicates that a host tool binary is 76 # currently running. 77 # TODO(frolv): Check if this works on Windows. 78 if err.errno == 26: 79 _LOG.error('') 80 _LOG.error(' %s has been rebuilt but cannot be', name) 81 _LOG.error(' copied into the host tools directory:') 82 _LOG.error('') 83 _LOG.error( 84 ' %s', args.dst.relative_to(args.out_root).joinpath(name) 85 ) 86 _LOG.error('') 87 _LOG.error(' This can occur if the program is already running.') 88 _LOG.error( 89 ' If it is running, exit it and try re-running the build.' 90 ) 91 _LOG.error('') 92 93 return 1 94 95 return 0 96 97 98if __name__ == '__main__': 99 pw_cli.log.install() 100 sys.exit(main()) 101