Added new platyvenv Python script.

This commit is contained in:
Fabio Manganiello 2023-08-23 11:53:14 +02:00
parent f230fa79bb
commit dafd65dc21
Signed by: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 201 additions and 0 deletions

196
platypush/platyvenv/__init__.py Executable file
View file

@ -0,0 +1,196 @@
"""
Platyvenv is a helper script that allows you to automatically create a
virtual environment for Platypush starting from a configuration file.
"""
import argparse
import inspect
import os
import pathlib
import re
import subprocess
import sys
from typing import Sequence
import venv
from platypush.config import Config
from platypush.utils import get_src_root
from platypush.utils.manifest import (
Dependencies,
InstallContext,
)
# pylint: disable=too-few-public-methods
class VenvBuilder:
"""
Build a virtual environment from on a configuration file.
:param cfgfile: Path to the configuration file.
:param image: The base image to use.
"""
def __init__(self, cfgfile: str, gitref: str, output_dir: str) -> None:
self.cfgfile = os.path.abspath(os.path.expanduser(cfgfile))
self.output_dir = os.path.abspath(os.path.expanduser(output_dir))
self.gitref = gitref
@property
def _pip_cmd(self) -> Sequence[str]:
"""
:return: The pip install command to use for the selected environment.
"""
return (
os.path.join(self.output_dir, 'bin', 'python'),
'-m',
'pip',
'install',
'-U',
'--no-cache-dir',
'--no-input',
)
def _install_system_packages(self, deps: Dependencies):
"""
Install the required system packages.
"""
for cmd in deps.to_pkg_install_commands():
print(f'Installing system packages: {cmd}')
subprocess.call(re.split(r'\s+', cmd.strip()))
def _prepare_venv(self) -> None:
"""
Installs the virtual environment under the configured output_dir.
"""
print(f'Creating virtual environment under {self.output_dir}...')
venv.create(
self.output_dir,
symlinks=True,
with_pip=True,
upgrade_deps=True,
)
print(
f'Installing base Python dependencies under {self.output_dir}...',
)
subprocess.call([*self._pip_cmd, 'pip'])
pwd = os.getcwd()
try:
os.chdir(os.path.dirname(get_src_root()))
subprocess.call([*self._pip_cmd, '.'])
finally:
os.chdir(pwd)
def _install_extra_pip_packages(self, deps: Dependencies):
"""
Install the extra pip dependencies parsed through the
"""
pip_deps = list(deps.to_pip_install_commands(full_command=False))
if not pip_deps:
return
print(
f'Installing extra pip dependencies under {self.output_dir}: '
+ ' '.join(pip_deps)
)
subprocess.call([*self._pip_cmd, *pip_deps])
def build(self):
"""
Build a Dockerfile based on a configuration file.
"""
Config.init(self.cfgfile)
deps = Dependencies.from_config(
self.cfgfile,
install_context=InstallContext.VENV,
)
self._install_system_packages(deps)
self._prepare_venv()
self._install_extra_pip_packages(deps)
@classmethod
def from_cmdline(cls, args: Sequence[str]) -> 'VenvBuilder':
"""
Create a DockerfileGenerator instance from command line arguments.
:param args: Command line arguments.
:return: A DockerfileGenerator instance.
"""
parser = argparse.ArgumentParser(
prog='platyvenv',
add_help=False,
description='Create a Platypush virtual environment from a config.yaml.',
)
parser.add_argument(
'-h', '--help', dest='show_usage', action='store_true', help='Show usage'
)
parser.add_argument(
'cfgfile',
type=str,
nargs='?',
help='The path to the configuration file. If not specified a minimal '
'virtual environment only with the base dependencies will be '
'generated.',
)
parser.add_argument(
'-o',
'--output',
dest='output_dir',
type=str,
required=False,
default='venv',
help='Target directory for the virtual environment (default: ./venv)',
)
parser.add_argument(
'--ref',
'-r',
dest='gitref',
required=False,
type=str,
default='master',
help='If platyvenv is not run from a Platypush installation directory, '
'it will clone the sources via git. You can specify through this '
'option which branch, tag or commit hash to use. Defaults to master.',
)
opts, _ = parser.parse_known_args(args)
if opts.show_usage:
parser.print_help()
sys.exit(0)
if not opts.cfgfile:
opts.cfgfile = os.path.join(
str(pathlib.Path(inspect.getfile(Config)).parent),
'config.auto.yaml',
)
print(
f'No configuration file specified. Using {opts.cfgfile}.',
file=sys.stderr,
)
return cls(opts.cfgfile, gitref=opts.gitref, output_dir=opts.output_dir)
def main():
"""
Generates a virtual environment based on the configuration file.
"""
VenvBuilder.from_cmdline(sys.argv[1:]).build()
if __name__ == '__main__':
sys.exit(main())
# vim:sw=4:ts=4:et:

View file

@ -0,0 +1,5 @@
from platypush.platyvenv import main
main()
# vim:sw=4:ts=4:et: