forked from platypush/platypush
Added new platyvenv Python script.
This commit is contained in:
parent
f230fa79bb
commit
dafd65dc21
2 changed files with 201 additions and 0 deletions
196
platypush/platyvenv/__init__.py
Executable file
196
platypush/platyvenv/__init__.py
Executable 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:
|
5
platypush/platyvenv/__main__.py
Normal file
5
platypush/platyvenv/__main__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from platypush.platyvenv import main
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
Loading…
Reference in a new issue