| # Copyright 2020 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Install and check status of teensy-core.""" |
| |
| import json |
| import logging |
| import re |
| import subprocess |
| import tempfile |
| from pathlib import Path |
| from typing import Sequence |
| |
| from pw_arduino_build import core_installer |
| |
| import pw_package.package_manager |
| |
| _LOG: logging.Logger = logging.getLogger(__name__) |
| |
| |
| class ArduinoCore(pw_package.package_manager.Package): |
| """Install and check status of arduino cores.""" |
| def __init__(self, core_name, *args, **kwargs): |
| super().__init__(*args, name=core_name, **kwargs) |
| |
| def status(self, path: Path) -> bool: |
| return (path / 'hardware').is_dir() |
| |
| def populate_download_cache_from_cipd(self, path: Path) -> None: |
| """Check for arduino core availability in pigweed_internal cipd.""" |
| package_path = path.parent.resolve() |
| core_name = self.name |
| core_cache_path = package_path / ".cache" / core_name |
| core_cache_path.mkdir(parents=True, exist_ok=True) |
| |
| cipd_package_subpath = "pigweed_internal/third_party/" |
| cipd_package_subpath += core_name |
| cipd_package_subpath += "/${platform}" |
| |
| # Check if teensy cipd package is readable |
| |
| with tempfile.NamedTemporaryFile(prefix='cipd', |
| delete=True) as temp_json: |
| cipd_acl_check_command = [ |
| "cipd", |
| "acl-check", |
| cipd_package_subpath, |
| "-reader", |
| "-json-output", |
| temp_json.name, |
| ] |
| subprocess.run(cipd_acl_check_command, capture_output=True) |
| # Return if no packages are readable. |
| if not json.load(temp_json)['result']: |
| return |
| |
| def _run_command(command): |
| _LOG.debug("Running: `%s`", " ".join(command)) |
| result = subprocess.run(command, capture_output=True) |
| _LOG.debug("Output:\n%s", |
| result.stdout.decode() + result.stderr.decode()) |
| |
| _run_command(["cipd", "init", "-force", core_cache_path.as_posix()]) |
| _run_command([ |
| "cipd", "install", cipd_package_subpath, "-root", |
| core_cache_path.as_posix(), "-force" |
| ]) |
| |
| _LOG.debug( |
| "Available Cache Files:\n%s", |
| "\n".join([p.as_posix() for p in core_cache_path.glob("*")])) |
| |
| def install(self, path: Path) -> None: |
| self.populate_download_cache_from_cipd(path) |
| |
| if self.status(path): |
| return |
| # Otherwise delete current version and reinstall |
| core_installer.install_core(path.parent.resolve().as_posix(), |
| self.name) |
| |
| def info(self, path: Path) -> Sequence[str]: |
| packages_root = path.parent.resolve() |
| arduino_package_path = path |
| arduino_package_name = None |
| |
| message = [ |
| f'{self.name} currently installed in: {path}', |
| ] |
| # Make gn args sample copy/paste-able by omitting the starting timestamp |
| # and INF log on each line. |
| message_gn_args = [ |
| 'Enable by running "gn args out" and adding these lines:', |
| f' pw_arduino_build_CORE_PATH = "{packages_root}"', |
| f' pw_arduino_build_CORE_NAME = "{self.name}"' |
| ] |
| |
| # Search for first valid 'package/version' directory |
| for hardware_dir in [ |
| path for path in (path / 'hardware').iterdir() |
| if path.is_dir() |
| ]: |
| if path.name in ["arduino", "tools"]: |
| continue |
| for subdir in [ |
| path for path in hardware_dir.iterdir() if path.is_dir() |
| ]: |
| if subdir.name == 'avr' or re.match(r'[0-9.]+', subdir.name): |
| arduino_package_name = f'{hardware_dir.name}/{subdir.name}' |
| break |
| |
| if arduino_package_name: |
| message_gn_args += [ |
| f' pw_arduino_build_PACKAGE_NAME = "{arduino_package_name}"', |
| ' pw_arduino_build_BOARD = "BOARD_NAME"' |
| ] |
| message += ["\n".join(message_gn_args)] |
| message += [ |
| 'Where BOARD_NAME is any supported board.', |
| # Have arduino_builder command appear on it's own line. |
| 'List available boards by running:\n' |
| ' arduino_builder ' |
| f'--arduino-package-path {arduino_package_path} ' |
| f'--arduino-package-name {arduino_package_name} list-boards' |
| ] |
| return message |
| |
| |
| for arduino_core_name in core_installer.supported_cores(): |
| pw_package.package_manager.register(ArduinoCore, |
| core_name=arduino_core_name) |