aboutsummaryrefslogtreecommitdiff
path: root/pw_arduino_build/py/pw_arduino_build/core_installer.py
diff options
context:
space:
mode:
Diffstat (limited to 'pw_arduino_build/py/pw_arduino_build/core_installer.py')
-rw-r--r--pw_arduino_build/py/pw_arduino_build/core_installer.py329
1 files changed, 113 insertions, 216 deletions
diff --git a/pw_arduino_build/py/pw_arduino_build/core_installer.py b/pw_arduino_build/py/pw_arduino_build/core_installer.py
index dcb1fe186..758072894 100644
--- a/pw_arduino_build/py/pw_arduino_build/core_installer.py
+++ b/pw_arduino_build/py/pw_arduino_build/core_installer.py
@@ -15,19 +15,20 @@
"""Arduino Core Installer."""
import argparse
+import importlib.resources
import logging
-import operator
import os
+from pathlib import Path
import platform
import shutil
-import stat
-import subprocess
-import sys
-import time
-from pathlib import Path
-from typing import Dict, List
+from typing import Dict
-from pw_arduino_build import file_operations
+try:
+ from pw_arduino_build import file_operations
+
+except ImportError:
+ # Load this directory if pw_arduino_build is not available.
+ import file_operations # type: ignore
_LOG = logging.getLogger(__name__)
@@ -36,79 +37,70 @@ class ArduinoCoreNotSupported(Exception):
"""Exception raised when a given core can not be installed."""
+class ArduinoCoreInstallationFailed(Exception):
+ """Exception raised when a given core failed to be installed."""
+
+
_ARDUINO_CORE_ARTIFACTS: Dict[str, Dict] = {
# pylint: disable=line-too-long
"teensy": {
+ "all": {
+ "core": {
+ "version": "1.58.1",
+ "url": "https://www.pjrc.com/teensy/td_158-1/teensy-package.tar.bz2",
+ "file_name": "teensy-package.tar.bz2",
+ "sha256": "3a3f3728045621d25068c5b5dfc24bf171550127e9fae4d0e8be2574c6636cff",
+ }
+ },
"Linux": {
- "arduino-ide": {
- "url": "https://downloads.arduino.cc/arduino-1.8.13-linux64.tar.xz",
- "file_name": "arduino-1.8.13-linux64.tar.xz",
- "sha256": "1b20d0ec850a2a63488009518725f058668bb6cb48c321f82dcf47dc4299b4ad",
- },
- "teensyduino": {
- "url": "https://www.pjrc.com/teensy/td_153/TeensyduinoInstall.linux64",
- "sha256": "2e6cd99a757bc80593ea3de006de4cc934bcb0a6ec74cad8ec327f0289d40f0b",
- "file_name": "TeensyduinoInstall.linux64",
+ "teensy-tools": {
+ "url": "https://www.pjrc.com/teensy/td_158/teensy-tools-linux64.tar.bz2",
+ "file_name": "teensy-tools-linux64.tar.bz2",
+ "sha256": "0a272575ca42b4532ab89516df160e1d68e449fe1538c0bd71dbb768f1b3c0b6",
+ "version": "1.58.0",
},
},
# TODO(tonymd): Handle 32-bit Linux Install?
"Linux32": {
- "arduino-ide": {
- "url": "https://downloads.arduino.cc/arduino-1.8.13-linux32.tar.xz",
- "file_name": "arduino-1.8.13-linux32.tar.xz",
- "sha256": "",
- },
- "teensyduino": {
- "url": "https://www.pjrc.com/teensy/td_153/TeensyduinoInstall.linux32",
- "file_name": "TeensyduinoInstall.linux32",
- "sha256": "",
+ "teensy-tools": {
+ "url": "https://www.pjrc.com/teensy/td_158/teensy-tools-linux32.tar.bz2",
+ "file_name": "teensy-tools-linux32.tar.bz2",
+ "sha256": "995d974935c8118ad6d4c191206453dd8f57c1e299264bb4cffcc62c96c6d077",
+ "version": "1.58.0",
},
},
# TODO(tonymd): Handle ARM32 (Raspberry Pi) Install?
"LinuxARM32": {
- "arduino-ide": {
- "url": "https://downloads.arduino.cc/arduino-1.8.13-linuxarm.tar.xz",
- "file_name": "arduino-1.8.13-linuxarm.tar.xz",
- "sha256": "",
- },
- "teensyduino": {
- "url": "https://www.pjrc.com/teensy/td_153/TeensyduinoInstall.linuxarm",
- "file_name": "TeensyduinoInstall.linuxarm",
- "sha256": "",
+ "teensy-tools": {
+ "url": "https://www.pjrc.com/teensy/td_158/teensy-tools-linuxarm.tar.bz2",
+ "file_name": "teensy-tools-linuxarm.tar.bz2",
+ "sha256": "88cf8e55549f5d5937fa7dbc763cad49bd3680d4e5185b318c667f541035e633",
+ "version": "1.58.0",
},
},
# TODO(tonymd): Handle ARM64 Install?
"LinuxARM64": {
- "arduino-ide": {
- "url": "https://downloads.arduino.cc/arduino-1.8.13-linuxaarch64.tar.xz",
- "file_name": "arduino-1.8.13-linuxaarch64.tar.xz",
- "sha256": "",
- },
- "teensyduino": {
- "url": "https://www.pjrc.com/teensy/td_153/TeensyduinoInstall.linuxaarch64",
- "file_name": "TeensyduinoInstall.linuxaarch64",
- "sha256": "",
+ "teensy-tools": {
+ "url": "https://www.pjrc.com/teensy/td_158/teensy-tools-linuxaarch64.tar.bz2",
+ "file_name": "teensy-tools-linuxaarch64.tar.bz2",
+ "sha256": "a20b1c5e91fe51c3b6591e4cfcf711d4a4c0a0bb5120c59d1c8dd8d32ae44e31",
+ "version": "1.58.0",
},
},
"Darwin": {
- "teensyduino": {
- "url": "https://www.pjrc.com/teensy/td_153/Teensyduino_MacOS_Catalina.zip",
- "file_name": "Teensyduino_MacOS_Catalina.zip",
- "sha256": "401ef42c6e83e621cdda20191a4ef9b7db8a214bede5a94a9e26b45f79c64fe2",
+ "teensy-tools": {
+ "url": "https://www.pjrc.com/teensy/td_158/teensy-tools-macos.tar.bz2",
+ "file_name": "teensy-tools-macos.tar.bz2",
+ "sha256": "d386412e38fe6dd6c5d849c2b1f8eea00cbf7bc3659fb6ba9f83cebfb736924b",
+ "version": "1.58.0",
},
},
"Windows": {
- "arduino-ide": {
- "url": "https://downloads.arduino.cc/arduino-1.8.13-windows.zip",
- "file_name": "arduino-1.8.13-windows.zip",
- "sha256": "78d3e96827b9e9b31b43e516e601c38d670d29f12483e88cbf6d91a0f89ef524",
- },
- "teensyduino": {
- "url": "https://www.pjrc.com/teensy/td_153/TeensyduinoInstall.exe",
- # The installer should be named 'Teensyduino.exe' instead of
- # 'TeensyduinoInstall.exe' to trigger a non-admin installation.
- "file_name": "Teensyduino.exe",
- "sha256": "88f58681e5c4772c54e462bc88280320e4276e5b316dcab592fe38d96db990a1",
+ "teensy-tools": {
+ "url": "https://www.pjrc.com/teensy/td_158/teensy-tools-windows.tar.bz2",
+ "file_name": "teensy-tools-windows.tar.bz2",
+ "sha256": "206315ddc82381d2da92da9f633a1719e00c0e8f5432acfed434573409a48de1",
+ "version": "1.58.0",
},
},
},
@@ -141,10 +133,10 @@ _ARDUINO_CORE_ARTIFACTS: Dict[str, Dict] = {
"stm32duino": {
"all": {
"core": {
- "version": "1.9.0",
- "url": "https://github.com/stm32duino/Arduino_Core_STM32/archive/1.9.0.tar.gz",
- "file_name": "stm32duino-1.9.0.tar.gz",
- "sha256": "4f75ba7a117d90392e8f67c58d31d22393749b9cdd3279bc21e7261ec06c62bf",
+ "version": "2.6.0",
+ "url": "https://github.com/stm32duino/Arduino_Core_STM32/archive/2.6.0.tar.gz",
+ "file_name": "stm32duino-2.6.0.tar.gz",
+ "sha256": "53f37df1202b1bccfb353e4775200f63b36d487fe734fdb8ca9bfa00c2f3429f",
}
},
"Linux": {},
@@ -171,12 +163,7 @@ def install_core(prefix, core_name):
os.makedirs(cache_dir, exist_ok=True)
if core_name == "teensy":
- if platform.system() == "Linux":
- install_teensy_core_linux(install_prefix, install_dir, cache_dir)
- elif platform.system() == "Darwin":
- install_teensy_core_mac(install_prefix, install_dir, cache_dir)
- elif platform.system() == "Windows":
- install_teensy_core_windows(install_prefix, install_dir, cache_dir)
+ install_teensy_core(install_prefix, install_dir, cache_dir)
apply_teensy_patches(install_dir)
elif core_name == "adafruit-samd":
install_adafruit_samd_core(install_prefix, install_dir, cache_dir)
@@ -196,158 +183,59 @@ def supported_cores():
return _ARDUINO_CORE_ARTIFACTS.keys()
-def get_windows_process_names() -> List[str]:
- result = subprocess.run("wmic process get description", capture_output=True)
- output = result.stdout.decode().splitlines()
- return [line.strip() for line in output if line]
-
-
-def install_teensy_core_windows(install_prefix, install_dir, cache_dir):
- """Download and install Teensyduino artifacts for Windows."""
- teensy_artifacts = _ARDUINO_CORE_ARTIFACTS["teensy"][platform.system()]
-
- arduino_artifact = teensy_artifacts["arduino-ide"]
- arduino_zipfile = file_operations.download_to_cache(
- url=arduino_artifact["url"],
- expected_sha256sum=arduino_artifact["sha256"],
+def install_teensy_core(_install_prefix: str, install_dir: str, cache_dir: str):
+ """Install teensy core files and tools."""
+ # Install the Teensy core source files
+ artifacts = _ARDUINO_CORE_ARTIFACTS["teensy"]["all"]["core"]
+ core_tarfile = file_operations.download_to_cache(
+ url=artifacts["url"],
+ expected_sha256sum=artifacts["sha256"],
cache_directory=cache_dir,
- downloaded_file_name=arduino_artifact["file_name"],
+ downloaded_file_name=artifacts["file_name"],
)
- teensyduino_artifact = teensy_artifacts["teensyduino"]
- teensyduino_installer = file_operations.download_to_cache(
- url=teensyduino_artifact["url"],
- expected_sha256sum=teensyduino_artifact["sha256"],
- cache_directory=cache_dir,
- downloaded_file_name=teensyduino_artifact["file_name"],
+ package_path = os.path.join(
+ install_dir, "hardware", "avr", artifacts["version"]
)
+ os.makedirs(package_path, exist_ok=True)
+ file_operations.extract_archive(core_tarfile, package_path, cache_dir)
- file_operations.extract_archive(arduino_zipfile, install_dir, cache_dir)
-
- # "teensy" here should match args.core_name
- teensy_core_dir = os.path.join(install_prefix, "teensy")
-
- # Change working directory for installation
- original_working_dir = os.getcwd()
- os.chdir(install_prefix)
+ expected_files = [
+ Path(package_path) / 'boards.txt',
+ Path(package_path) / 'platform.txt',
+ ]
- install_command = [teensyduino_installer, "--dir=teensy"]
- _LOG.info(" Running: %s", " ".join(install_command))
- _LOG.info(
- " Please click yes on the Windows 'User Account Control' " "dialog."
- )
- _LOG.info(" You should see: 'Verified publisher: PRJC.COM LLC'")
-
- def wait_for_process(
- process_name, timeout=30, result_operator=operator.truth
- ):
- start_time = time.time()
- while result_operator(process_name in get_windows_process_names()):
- time.sleep(1)
- if time.time() > start_time + timeout:
- _LOG.error(
- "Error: Installation Failed.\n"
- "Please click yes on the Windows 'User Account Control' "
- "dialog."
- )
- sys.exit(1)
-
- # Run Teensyduino installer with admin rights (non-blocking)
- # User Account Control (UAC) will prompt the user for consent
- import ctypes # pylint: disable=import-outside-toplevel
-
- ctypes.windll.shell32.ShellExecuteW(
- None, # parent window handle
- "runas", # operation
- teensyduino_installer, # file to run
- subprocess.list2cmdline(install_command), # command parameters
- install_prefix, # working directory
- 1,
- ) # Display mode (SW_SHOWNORMAL: Activates and displays a window)
-
- # Wait for teensyduino_installer to start running
- wait_for_process("TeensyduinoInstall.exe", result_operator=operator.not_)
-
- _LOG.info("Waiting for TeensyduinoInstall.exe to finish.")
- # Wait till teensyduino_installer is finished
- wait_for_process("TeensyduinoInstall.exe", timeout=360)
-
- if not os.path.exists(os.path.join(teensy_core_dir, "hardware", "teensy")):
- _LOG.error(
- "Error: Installation Failed.\n"
- "Please try again and ensure Teensyduino is installed in "
- "the folder:\n"
- "%s",
- teensy_core_dir,
+ if any(not expected_file.is_file() for expected_file in expected_files):
+ expected_files_str = "".join(
+ list(f" {expected_file}\n" for expected_file in expected_files)
)
- sys.exit(1)
- else:
- _LOG.info("Install complete!")
-
- file_operations.remove_empty_directories(install_dir)
- os.chdir(original_working_dir)
-
-
-def install_teensy_core_mac(unused_install_prefix, install_dir, cache_dir):
- """Download and install Teensyduino artifacts for Mac."""
- teensy_artifacts = _ARDUINO_CORE_ARTIFACTS["teensy"][platform.system()]
-
- teensyduino_artifact = teensy_artifacts["teensyduino"]
- teensyduino_zip = file_operations.download_to_cache(
- url=teensyduino_artifact["url"],
- expected_sha256sum=teensyduino_artifact["sha256"],
- cache_directory=cache_dir,
- downloaded_file_name=teensyduino_artifact["file_name"],
- )
- extracted_files = file_operations.extract_archive(
- teensyduino_zip,
- install_dir,
- cache_dir,
- remove_single_toplevel_folder=False,
- )
- toplevel_folder = sorted(extracted_files)[0]
- os.symlink(
- os.path.join(toplevel_folder, "Contents", "Java", "hardware"),
- os.path.join(install_dir, "hardware"),
- target_is_directory=True,
- )
-
-
-def install_teensy_core_linux(install_prefix, install_dir, cache_dir):
- """Download and install Teensyduino artifacts for Windows."""
- teensy_artifacts = _ARDUINO_CORE_ARTIFACTS["teensy"][platform.system()]
+ raise ArduinoCoreInstallationFailed(
+ "\n\nError: Installation Failed.\n"
+ "Please remove the package:\n\n"
+ " pw package remove teensy\n\n"
+ "Try again and ensure the following files exist:\n\n"
+ + expected_files_str
+ )
- arduino_artifact = teensy_artifacts["arduino-ide"]
- arduino_tarfile = file_operations.download_to_cache(
- url=arduino_artifact["url"],
- expected_sha256sum=arduino_artifact["sha256"],
- cache_directory=cache_dir,
- downloaded_file_name=arduino_artifact["file_name"],
- )
+ teensy_tools = _ARDUINO_CORE_ARTIFACTS["teensy"][platform.system()]
- teensyduino_artifact = teensy_artifacts["teensyduino"]
- teensyduino_installer = file_operations.download_to_cache(
- url=teensyduino_artifact["url"],
- expected_sha256sum=teensyduino_artifact["sha256"],
- cache_directory=cache_dir,
- downloaded_file_name=teensyduino_artifact["file_name"],
- )
+ for tool_name, artifacts in teensy_tools.items():
+ tool_tarfile = file_operations.download_to_cache(
+ url=artifacts["url"],
+ expected_sha256sum=artifacts["sha256"],
+ cache_directory=cache_dir,
+ downloaded_file_name=artifacts["file_name"],
+ )
- file_operations.extract_archive(arduino_tarfile, install_dir, cache_dir)
- os.chmod(
- teensyduino_installer,
- os.stat(teensyduino_installer).st_mode | stat.S_IEXEC,
- )
+ tool_path = os.path.join(
+ install_dir, "tools", tool_name, artifacts["version"]
+ )
- original_working_dir = os.getcwd()
- os.chdir(install_prefix)
- # "teensy" here should match args.core_name
- install_command = [teensyduino_installer, "--dir=teensy"]
- subprocess.run(install_command)
+ os.makedirs(tool_path, exist_ok=True)
+ file_operations.extract_archive(tool_tarfile, tool_path, cache_dir)
- file_operations.remove_empty_directories(install_dir)
- os.chdir(original_working_dir)
+ return True
def apply_teensy_patches(install_dir):
@@ -357,19 +245,28 @@ def apply_teensy_patches(install_dir):
# Resolve paths since `git apply` doesn't work if a path is beyond a
# symbolic link.
patch_root_path = (
- Path(install_dir) / "hardware/teensy/avr/cores"
+ Path(install_dir) / "hardware/avr/1.58.1/cores"
).resolve()
- # Get all *.diff files relative to this python file's parent directory.
- patch_file_paths = sorted(
- (Path(__file__).parent / "core_patches/teensy").glob("*.diff")
+ # Get all *.diff files for the teensy core.
+ patches_python_package = 'pw_arduino_build.core_patches.teensy'
+
+ patch_file_names = sorted(
+ patch
+ for patch in importlib.resources.contents(patches_python_package)
+ if Path(patch).suffix in ['.diff']
)
# Apply each patch file.
- for diff_path in patch_file_paths:
- file_operations.git_apply_patch(
- patch_root_path.as_posix(), diff_path.as_posix(), unsafe_paths=True
- )
+ for diff_name in patch_file_names:
+ with importlib.resources.path(
+ patches_python_package, diff_name
+ ) as diff_path:
+ file_operations.git_apply_patch(
+ patch_root_path.as_posix(),
+ diff_path.as_posix(),
+ unsafe_paths=True,
+ )
def install_arduino_samd_core(