-
-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[platform] Install ltchiptool in separate virtual environment (#166)
* [platform] Install ltchiptool in separate virtual environment * [platform] Fix f-string syntax, set LibreTiny path in ltchiptool * [platform] Fix venv site-packages path * [platform] Fix installing pip without ensurepip * [platform] Install binary dependencies only
- Loading branch information
Showing
12 changed files
with
456 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# Copyright (c) Kuba Szczodrzyński 2023-09-07. | ||
|
||
import json | ||
import site | ||
import subprocess | ||
import sys | ||
from pathlib import Path | ||
|
||
import semantic_version | ||
from platformio.compat import IS_WINDOWS | ||
from platformio.package.version import pepver_to_semver | ||
from platformio.platform.base import PlatformBase | ||
from SCons.Script import DefaultEnvironment, Environment | ||
|
||
env: Environment = DefaultEnvironment() | ||
platform: PlatformBase = env.PioPlatform() | ||
|
||
# code borrowed and modified from espressif32/builder/frameworks/espidf.py | ||
|
||
|
||
def env_configure_python_venv(env: Environment): | ||
venv_path = Path(env.subst("${PROJECT_CORE_DIR}"), "penv", ".libretiny") | ||
|
||
pip_path = venv_path.joinpath( | ||
"Scripts" if IS_WINDOWS else "bin", | ||
"pip" + (".exe" if IS_WINDOWS else ""), | ||
) | ||
python_path = venv_path.joinpath( | ||
"Scripts" if IS_WINDOWS else "bin", | ||
"python" + (".exe" if IS_WINDOWS else ""), | ||
) | ||
site_path = venv_path.joinpath( | ||
"Lib" if IS_WINDOWS else "lib", | ||
"." if IS_WINDOWS else f"python{sys.version_info[0]}.{sys.version_info[1]}", | ||
"site-packages", | ||
) | ||
|
||
if not pip_path.is_file(): | ||
# Use the built-in PlatformIO Python to create a standalone virtual env | ||
result = env.Execute( | ||
env.VerboseAction( | ||
f'"$PYTHONEXE" -m venv --clear "{venv_path.absolute()}"', | ||
"LibreTiny: Creating a virtual environment for Python dependencies", | ||
) | ||
) | ||
if not python_path.is_file(): | ||
# Creating the venv failed | ||
raise RuntimeError( | ||
f"Failed to create virtual environment. Error code {result}" | ||
) | ||
if not pip_path.is_file(): | ||
# Creating the venv succeeded but pip didn't get installed | ||
# (i.e. Debian/Ubuntu without ensurepip) | ||
print( | ||
"LibreTiny: Failed to install pip, running get-pip.py", file=sys.stderr | ||
) | ||
import requests | ||
|
||
with requests.get("https://bootstrap.pypa.io/get-pip.py") as r: | ||
p = subprocess.Popen( | ||
args=str(python_path.absolute()), | ||
stdin=subprocess.PIPE, | ||
) | ||
p.communicate(r.content) | ||
p.wait() | ||
|
||
assert ( | ||
pip_path.is_file() | ||
), f"Error: Missing the pip binary in virtual environment `{pip_path.absolute()}`" | ||
assert ( | ||
python_path.is_file() | ||
), f"Error: Missing Python executable file `{python_path.absolute()}`" | ||
assert ( | ||
site_path.is_dir() | ||
), f"Error: Missing site-packages directory `{site_path.absolute()}`" | ||
|
||
env.Replace(LTPYTHONEXE=python_path.absolute(), LTPYTHONENV=venv_path.absolute()) | ||
site.addsitedir(str(site_path.absolute())) | ||
|
||
|
||
def env_install_python_dependencies(env: Environment, dependencies: dict): | ||
try: | ||
pip_output = subprocess.check_output( | ||
[ | ||
env.subst("${LTPYTHONEXE}"), | ||
"-m", | ||
"pip", | ||
"list", | ||
"--format=json", | ||
"--disable-pip-version-check", | ||
] | ||
) | ||
pip_data = json.loads(pip_output) | ||
packages = {p["name"]: pepver_to_semver(p["version"]) for p in pip_data} | ||
except: | ||
print( | ||
"LibreTiny: Warning! Couldn't extract the list of installed Python packages" | ||
) | ||
packages = {} | ||
|
||
to_install = [] | ||
for name, spec in dependencies.items(): | ||
install_spec = f'"{name}{dependencies[name]}"' | ||
if name not in packages: | ||
to_install.append(install_spec) | ||
elif spec: | ||
version_spec = semantic_version.Spec(spec) | ||
if not version_spec.match(packages[name]): | ||
to_install.append(install_spec) | ||
|
||
if to_install: | ||
env.Execute( | ||
env.VerboseAction( | ||
'"${LTPYTHONEXE}" -m pip install --prefer-binary -U ' | ||
+ " ".join(to_install), | ||
"LibreTiny: Installing Python dependencies", | ||
) | ||
) | ||
|
||
|
||
env.AddMethod(env_configure_python_venv, "ConfigurePythonVenv") | ||
env.AddMethod(env_install_python_dependencies, "InstallPythonDependencies") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Copyright (c) Kuba Szczodrzyński 2023-09-07. | ||
|
||
from .board import Board | ||
from .dict import RecursiveDict, merge_dicts | ||
from .family import Family | ||
|
||
# TODO refactor and remove all this from here | ||
|
||
__all__ = [ | ||
"Board", | ||
"Family", | ||
"RecursiveDict", | ||
"merge_dicts", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Copyright (c) Kuba Szczodrzyński 2022-07-29. | ||
|
||
from typing import Union | ||
|
||
from genericpath import isfile | ||
|
||
from .dict import merge_dicts | ||
from .fileio import readjson | ||
from .lvm import lvm_load_json | ||
|
||
|
||
class Board: | ||
@staticmethod | ||
def get_data(board: Union[str, dict]) -> dict: | ||
if not isinstance(board, dict): | ||
if isfile(board): | ||
board = readjson(board) | ||
if not board: | ||
raise FileNotFoundError(f"Board not found: {board}") | ||
else: | ||
source = board | ||
board = lvm_load_json(f"boards/{board}.json") | ||
board["source"] = source | ||
if "_base" in board: | ||
base = board["_base"] | ||
if not isinstance(base, list): | ||
base = [base] | ||
result = {} | ||
for base_name in base: | ||
board_base = lvm_load_json(f"boards/_base/{base_name}.json") | ||
merge_dicts(result, board_base) | ||
merge_dicts(result, board) | ||
board = result | ||
return board |
Oops, something went wrong.