Coverage for pylucid/pylucid_boot.py : 52%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
#!/usr/bin/python3
PyLucid Boot Admin ~~~~~~~~~~~~~~~~~~
A interactive shell for booting PyLucid.
Note: - This file is "self contained". - It used **only** stuff from Python lib. - So it's "run able" on a bare python 3 installation - On debian / ubuntu the 'python3-venv' package is needed!
usage, e.g.:
$ wget https://raw.githubusercontent.com/jedie/PyLucid/pylucid_v3/pylucid/pylucid_boot.py $ python3 pylucid_boot.py
pylucid_boot.py> boot ~/PyLucid_env
:created: 08.02.2018 by Jens Diemer, www.jensdiemer.de :copyleft: 2018 by the PyLucid team, see AUTHORS for more details. :license: GNU General Public License v3 or later (GPLv3+), see LICENSE for more details. """
print("\nERROR: Python 3.5 or greater is required!") print("(Current Python Verison is %s)\n" % sys.version.split(" ",1)[0]) sys.exit(101)
except ImportError as err: # e.g.: debian / ubuntu doesn't have venv installed, isn't it?!? print("\nERROR: 'venv' not available: %s (Maybe 'python3-venv' package not installed?!?)" % err)
except ImportError as err: # e.g.: debian / ubuntu doesn't have venv installed, isn't it?!? print("\nERROR: 'ensurepip' not available: %s (Maybe 'python3-venv' package not installed?!?)" % err)
# TODO: Remove "--pre" after v3 release "--pre", # https://pip.pypa.io/en/stable/reference/pip_install/#pre-release-versions "pylucid" ]
""" Verbose Subprocess """ """ :param popenargs: 'args' for subprocess.Popen() :param env_updates: dict to overwrite os.environ. :param timeout: pass to subprocess.Popen() :param kwargs: pass to subprocess.Popen() """
self.txt += " env: %s" % repr(env_updates) env=os.environ.copy() env.update(env_updates) self.kwargs["env"] = env
""" run subprocess.call()
:param check: if True and subprocess exit_code !=0: sys.exit(exit_code) after run. :return: process exit code """
except KeyboardInterrupt: print("\nExit %r\n" % self.args_str, flush=True) exit_code=None # good idea?!?
sys.exit(exit_code)
""" run subprocess.check_output()
:param check: if True and subprocess exit_code !=0: sys.exit(exit_code) after run. :return: process output """
sys.exit(err.returncode)
try: return func(*args, **kwargs) except Exception as err: traceback.print_exc(file=sys.stderr) return "%s: %s" % (err.__class__.__name__, err)
""" Enhanced version of 'Cmd' class: - command alias - methods can be called directly from commandline: e.g.: ./foobar.py --help - Display """
"q": "quit", "EOF": "quit", "": "help", # If user just send a ENTER ;) "--help": "help", "-h": "help", "-?": "help", }
# Will be append to 'doc_leader' in self.do_help():
'\n{filename} shell v{version}\n' 'Type help or ? to list commands.\n' ).format( filename=self.own_filename, version=self.version )
"\nHint: All commands can be called directly from commandline.\n" "e.g.: $ ./{filename} help\n" ).format( filename=self.own_filename, )
# e.g.: $ pylucid_admin.py boot /tmp/PyLucid-env -> run self.do_boot("/tmp/PyLucid-env") on startup
def _complete_path(self, text, line, begidx, endidx): """ complete a command argument with a existing path
usage e.g.: class FooCmd(Cmd2): def complete_foobar(self, text, line, begidx, endidx): return self._complete_path(text, line, begidx, endidx)
def do_foobar(self, path): # 'path' is type string! print("path:", path) """ try: destination = line.split(" ", 1)[1] except IndexError: destination = "."
if destination=="~": return [os.sep]
destination = Path(destination).expanduser().resolve()
if not destination.is_dir(): destination = destination.parent.resolve()
if destination.is_dir(): complete_list = [x.stem + os.sep for x in destination.iterdir() if x.is_dir()] if text: if text in complete_list: return [text + os.sep]
complete_list = [x for x in complete_list if x.startswith(text)] else: complete_list = []
return complete_list
""" List available commands with "help" or detailed help with "help cmd". """ except ImportError: self.doc_leader += self.missing_complete else:
"Exit this interactiv shell" print("\n\nbye") return True
# stop if we are called with commandline arguments
super().__init__(with_pip=True) self.requirements = requirements
print(" * Create the directories for the environment.") return super().ensure_directories(env_dir)
print(" * Create 'pyvenv.cfg' configuration file.") return super().create_configuration(context)
print(" * Set up a Python executable in the environment.") return super().setup_python(context)
print(" * Installs or upgrades pip in a virtual environment.") return super()._setup_pip(context)
print(" * Set up scripts into the created environment.") return super().setup_scripts(context)
""" Set up any packages which need to be pre-installed into the virtual environment being created.
:param context: The information for the virtual environment creation request being processed. """ print(" * post-setup modification")
def call_new_python(*args, **kwargs): """ Do the same as bin/activate so that <args> runs in a "activated" virtualenv. """ kwargs.update({ "env_updates": { "VIRTUAL_ENV": context.env_dir, "PATH": "%s:%s" % (context.bin_path, os.environ["PATH"]), } }) VerboseSubprocess(*args, **kwargs).verbose_call( check=True # sys.exit(return_code) if return_code != 0 )
call_new_python("pip", "install", "--upgrade", "pip")
# Install PyLucid # in normal mode as package from PyPi # in dev. mode as editable from github call_new_python("pip", "install", "--verbose", *self.requirements)
# Check if ".../bin/pylucid_admin" exists pylucid_admin_path = Path(context.bin_path, "pylucid_admin") if not pylucid_admin_path.is_file(): print("ERROR: pylucid_admin not found here: '%s'" % pylucid_admin_path) VerboseSubprocess("ls", "-la", str(context.bin_path)).verbose_call() sys.exit(-1)
# Install all requirements by call 'pylucid_admin update_env' from installed PyLucid call_new_python("pylucid_admin", "update_env", timeout=240) # extended timeout for slow Travis ;)
#_________________________________________________________________________ # Normal user commands:
return Path(path).expanduser().resolve()
# print("text: %r" % text) # print("line: %r" % line) return self._complete_path(text, line, begidx, endidx)
requirements = [] for line in requirement_string.splitlines(): line = line.strip() if line and not line.startswith("#"):
line = line.split("# ", 1)[0] # Remove pip-compile comments e.g.: "... # via foo" line = line.rstrip()
if line.startswith("-e"): # split editables requirements += line.split(" ") else: requirements.append(line) return requirements
""" Create a PyLucid virtualenv and install requirements. """
self.stdout.write("Create virtualenv: '%s'...\n\n" % destination)
builder = PyLucidEnvBuilder(requirements) builder.create(str(destination))
self.stdout.write("\n")
if not destination.is_dir(): self.stdout.write("ERROR: Creating virtualenv!\n") sys.exit(1) else: self.stdout.write("virtualenv created at: '%s'\n" % destination)
""" bootstrap PyLucid virtualenv in "normal" mode.
usage: > boot [path]
Create a PyLucid virtualenv in the given [path]. Install packages via PyPi and read-only sources from github.
The destination path must not exist yet!
(used the requirements/normal_installation.txt) """
""" bootstrap PyLucid virtualenv in "developer" mode: All own projects installed as editables via github HTTPS (readonly)
**Should be only used for developing/contributing. All others: Use normal 'boot' ;) **
usage: > boot_developer [path]
Create a PyLucid virtualenv in the given [path]. Install packages via PyPi and read-only sources from github.
The destination path must not exist yet!
(used the requirements/developer_installation.txt) """ self._boot(destination, requirements=DEVELOPER_INSTALL)
if __name__ == '__main__': main() |