diff --git a/.gitignore b/.gitignore index 4ebf856..126a54f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ d2/book1/books *.tar.gz .vscode/* !.vscode/launch.json +python/build diff --git a/deps/com.github.aiortc.aiortc b/deps/com.github.aiortc.aiortc index 1c158ef..64d8fec 160000 --- a/deps/com.github.aiortc.aiortc +++ b/deps/com.github.aiortc.aiortc @@ -1 +1 @@ -Subproject commit 1c158ef28435e2e0345a5d2682db8a2057d71522 +Subproject commit 64d8fecc5740fb77dcd40ef45a8b3c74c2187ba0 diff --git a/python/online/fxreader/pr34/commands_typed/cli.py b/python/online/fxreader/pr34/commands_typed/cli.py index 23fc950..6a25d5c 100644 --- a/python/online/fxreader/pr34/commands_typed/cli.py +++ b/python/online/fxreader/pr34/commands_typed/cli.py @@ -12,6 +12,7 @@ from .os import shutil_which from typing import ( Optional, + Literal, ) logger = logging.getLogger(__name__) @@ -22,12 +23,107 @@ class Project: build_dir : pathlib.Path dest_dir : pathlib.Path +@dataclasses.dataclass +class Dependency: + name: str + mode : Literal['pyproject', 'meson', 'meson-python', 'm'] + source_path : pathlib.Path + args: Optional[list[str]] = None + +@dataclasses.dataclass +class DistSettings: + wheel_dir : pathlib.Path + python_path: pathlib.Path + env_path: pathlib.Path + class CLI(abc.ABC): + @property + @abc.abstractmethod + def dist_settings(self) -> DistSettings: + raise NotImplementedError + @property @abc.abstractmethod def projects(self) -> dict[str, Project]: raise NotImplementedError + @property + @abc.abstractmethod + def dependencies(self) -> dict[str, Dependency]: + raise NotImplementedError + + def deploy_fetch_dist( + self, + force: bool, + ) -> None: + for k, o in self.dependencies.items(): + whl_glob = self.dist_settings.wheel_dir / ('*%s*.whl' % o.name.replace('.', '_')) + if len(glob.glob( + str(whl_glob) + )) == 0 or force: + if o.source_path.exists(): + def whl_files_get() -> list[dict[str, Any]]: + return [ + dict( + path=o, + stat=os.stat(o).st_mtime, + ) + for o in glob.glob( + str(whl_glob) + ) + ] + + present_files = whl_files_get() + + if o.mode == 'm': + if (o.source_path / 'm.py').exists(): + cmd = [ + sys.executable, + o.source_path / 'm.py', + 'deploy:wheel', + '-o', self.settings.wheel_dir, + ] + + if not o.args is None: + cmd.extend(o.args) + + subprocess.check_call(cmd) + else: + raise NotImplementedError + + updated_files = whl_files_get() + + def index_get(o: dict[str, Any]) -> tuple[Any, ...]: + return (o['path'], o['stat']) + + present_files_index = { + index_get(o) : o + for o in present_files + } + + new_files : list[dict[str, Any]] = [] + + for o in updated_files: + entry_index = index_get(o) + + if not entry_index in present_files_index: + new_files.append(o) + + if len(new_files) == 0: + raise NotImplementedError + + latest_file = sorted( + new_files, + key=lambda x: x['stat'] + )[-1] + + subprocess.check_call([ + self.dist_settings.python_path, + '-m', 'pip', + 'install', + latest_file['path'], + ]) + def deploy_wheel( self, project_name: str, diff --git a/python/online/fxreader/pr34/commands_typed/cli_bootstrap.py b/python/online/fxreader/pr34/commands_typed/cli_bootstrap.py new file mode 100644 index 0000000..eef4e17 --- /dev/null +++ b/python/online/fxreader/pr34/commands_typed/cli_bootstrap.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +import glob +import pathlib +import sys +import subprocess +import os + +env_path = pathlib.Path(__file__).parent / '.venv' +python_path = env_path / 'bin' / 'python3' + +if not env_path.exists(): + subprocess.check_call([ + 'uv', 'venv', '--seed', '--offline', + str(env_path) + ]) + + subprocess.check_call([ + 'uv', + 'pip', + 'install', + '-p', + python_path, + '--offline', + 'uv', + ]) + + subprocess.check_call([ + python_path, + '-m', + 'uv', 'pip', 'install', + '--offline', + 'build', 'setuptools', 'meson-python', 'pybind11', + ]) + + early_wheels = glob.glob( + str( + pathlib.Path(__file__).parent / 'deps' / 'dist' / 'early' / '*.whl' + ) + ) + if len(early_wheels) > 0: + subprocess.check_call([ + python_path, + '-m', + 'uv', 'pip', 'install', + '--offline', + *early_wheels, + ]) + + +if __name__ == '__main__': + if pathlib.Path(sys.executable).absolute() != python_path.absolute(): + os.execv( + str(python_path), + [ + str(python_path), + *sys.argv, + ] + ) + + os.execv( + str(python_path), + [ + str(python_path), + pathlib.Path(__file__).parent / 'cli.py', + *sys.argv[1:], + ] + ) \ No newline at end of file