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