def remove_path(self, config_name=None, force=False): """ Remove path. :param config_name: Config name (str?) :param force: Force (bool) (default: False) """ if config_name: user_config_root = self.get_paths().get_user_configuration_root( config_name) else: user_config_root = self.get_paths().get_user_root() if not os.path.exists(user_config_root): Logger.info(f"user configuration folder {user_config_root} " f"does not exist") else: if prompt_yes_no( f"/!\\ are you sure you want to remove the " f"user folder {user_config_root}?", force, ): shutil.rmtree(user_config_root) Logger.info(f"user configuration folder `{user_config_root}` " f"removed")
def show_environments(self): """Show environments.""" if len(self.environments) == 0: Logger.warn("no env file found") else: for name in self.environments.keys(): Logger.raw(f"- Environment: {name}")
def parse_args(self, args): """ Parse command-line args. :param args: Arguments (iterable) """ # Verbose mode activation if args.verbose: Logger.set_log_level("DEBUG") else: Logger.set_log_level("INFO") # Command detection if args.command is None: self.parser.print_help() sys.exit(1) # Command help detection if args.command is not None: cmd = args.command subcmd_name = "{0}_cmd".format(cmd) if cmd in self.subparsers.choices: subpar = self.subparsers.choices[cmd] if hasattr(args, subcmd_name): if getattr(args, subcmd_name) is None: subpar.print_help() sys.exit(1) return handle_parsers(self, args)
def _handle(args): str_args = " ".join(args.args) Logger.raw( "`machine` command has been removed. use `service` instead.", color=Fore.YELLOW, ) Logger.raw(f"example: `docknv service {str_args}`", color=Fore.YELLOW) sys.exit(1)
def load_from_project(cls, project_path, name): """ Load from project. :param project_path: Project path (str) :param name: Environment name (str) """ imported = set() def _load(project_path, name): path = env_get_yaml_path(project_path, name) if not os.path.isfile(path): raise MissingEnvironment(name) loaded_env = OrderedDict() with io_open(path, mode="r") as handle: env_content = yaml_ordered_load(handle.read()) # Detect imports imports = [] if "imports" in env_content: for entry in env_content["imports"]: imports.append(entry) for imported_env in imports: # Ignore self-import if imported_env == name: continue # Ignore already imported envs if imported_env in imported: continue # Save imported imported.add(imported_env) # Load imported environments result = _load(project_path, imported_env) for key, value in result.data.items(): loaded_env[key] = value # Load environment if env_content.get("environment", None): for key in env_content["environment"]: loaded_env[key] = env_content["environment"][key] return Environment(name, loaded_env) env = _load(project_path, name) # Resolve environment try: loaded_env = env_yaml_resolve_variables(env.data) env.data = loaded_env except UnresolvableEnvironment as exc: Logger.warn(f"unresolvable environment: {name}") Logger.warn(f" details: {str(exc)}") return env
def _handle(args): project_path = args.project if not project_is_valid(project_path): Logger.warn("no custom commands found") return commands_dir = os.path.join(project_path, "commands") if not os.path.exists(commands_dir): Logger.warn("no custom commands found") return shell = CustomShell() for root, _, files in os.walk(commands_dir): for filename in files: if filename.endswith(".py"): # Ignore __init__.py if filename == "__init__.py": continue base_filename, ext = os.path.splitext(filename) abs_f = os.path.join(root, filename) # Ignore __pycache__ if "__pycache__" in abs_f: continue src = imp.load_source("commands", abs_f) if hasattr(src, "pre_parse") and hasattr(src, "post_parse"): pre_parse = src.pre_parse post_parse = src.post_parse error = None try: pre_parse(shell) except BaseException as exc: error = exc if error: raise MalformedCommand( f"{base_filename} - {str(error)}" ) shell.register_post_parser(post_parse) # Pass arguments to custom shell cmd_args = ["--project", project_path] if args.verbose: cmd_args += ["-v"] if args.dry_run: cmd_args += ["--dry-run"] if args.config: cmd_args += ["-c", args.config] cmd_args += args.args shell.run(cmd_args)
def show_configuration_list(self): """Show configuration list.""" len_values = len(self.configurations) if len_values == 0: Logger.warn( "no configuration found. " "use `docknv config create` to generate configurations.") else: Logger.info("known configurations:") for conf in self.configurations.values(): conf.show()
def disable_logger(): """ Temporarily disable logger. **Context manager** """ lvl = Logger.get_log_level() Logger.set_log_level("NONE") try: yield finally: Logger.set_log_level(lvl)
def _handle_status(args): project = load_project(args.project) config_name = project.get_current_configuration() if config_name: config = project.database.get_configuration(config_name) Logger.info("current configuration: ") config.show() else: Logger.warn("no configuration selected. " "use 'docknv config set [configuration]' " "to select a configuration.")
def show(self): """Show.""" Logger.raw(f"- Environment: {self.name}") for key, value in self.data.items(): Logger.raw(f" {key}", color=Fore.YELLOW, linebreak=False) Logger.raw(" = ", linebreak=False) Logger.raw(value, color=Fore.BLUE)
def post_parse(shell, args, project, context): """Post parse.""" if args.command == "notebook": config = project.get_command_parameters("notebook") service_name = config.get("service", None) if service_name is None: Logger.error( "ipython machine name is not configured in `config.yml`." ) if args.notebook_cmd == "password": Logger.info("generating notebook password...") cmd = 'python -c "from IPython.lib import passwd; print(passwd())"' project.lifecycle.service.run( service_name, cmd, dry_run=args.dry_run )
def try_lock(self, timeout=0): """ Try to set the user lock. if timeout == 0: - Do not wait, raise on lock failure elif timeout > 0: - Try to lock until timeout else: - Try to lock until it is possible :param timeout: Timeout in seconds """ start_time = time.time() message_shown = False while True: if self.lock(): # OK, go! break else: if timeout == 0: raise ProjectLocked(self.project_path) elif timeout > 0: elapsed_time = time.time() - start_time if elapsed_time > timeout: raise ProjectLocked(self.project_path) # Sleep for 1 seconds time.sleep(1) if timeout == -1 and not message_shown: if time.time() - start_time > 3: Logger.info( f"Waiting for lockfile... If you know what you are doing, remove the file {self.get_file()}." ) message_shown = True try: yield except BaseException as exc: self.unlock() raise exc self.unlock()
def show(self): """Show.""" name = self.name namespace = self.namespace environment = self.environment services = self.services networks = self.networks volumes = self.volumes user = self.user Logger.raw( f"- Configuration '{name}'\n" f" Namespace: {namespace}\n" f" Environment: {environment}\n" f" Services: {services}\n" f" Volumes: {volumes}\n" f" Networks: {networks}\n" f" User: {user}\n\n", color=Fore.BLUE, )
def docknv_entry_point(): """Entry point for docknv.""" shell = Shell() try: return shell.run(sys.argv[1:]) except BaseException as e: if isinstance(e, (LoggerError, SystemExit)): sys.exit(1) elif isinstance( e, ( FailedCommandExecution, StoppedCommandExecution, MalformedCommand, ), ): Logger.error(str(e), crash=False) sys.exit(1) else: Logger.error(traceback.format_exc(), crash=False) sys.exit(1)
def exec_process(args, cwd=None, shell=False, dry_run=False): """ Execute a process. :param args: Arguments (list) :param cwd: Working directory (str?) :param shell: Shell? (bool) (default: False) :param dry_run: Dry run? (bool) (default: False) :rtype: Arguments or return code """ try: Logger.debug(f"executing command {args}...") if dry_run: return args rc = subprocess.call(args, cwd=cwd, shell=shell) except KeyboardInterrupt: raise StoppedCommandExecution("CTRL+C") except BaseException as exc: raise FailedCommandExecution(str(exc)) if rc != 0: raise FailedCommandExecution(f"bad return code: {rc}") return rc
def test_log(): """Simple logger tests.""" with using_temporary_stdout() as stdout: # Info Logger.info("Pouet") assert "[INFO]" in stdout.getvalue(), "Should be an info message" with using_temporary_stdout() as stdout: # Warn Logger.warn("Pouet") assert "[WARN]" in stdout.getvalue(), "Should be a warn message" with using_temporary_stdout() as stdout: # Debug Logger.debug("Pouet") assert "[DEBUG]" in stdout.getvalue(), "Should be a debug message" with using_temporary_stdout() as stdout: # Raw Logger.raw("Pouet pouet") assert stdout.getvalue().endswith("\n"), "Should end with a newline" with using_temporary_stdout() as stdout: Logger.raw("Pouet", color=Fore.BLUE) assert stdout.getvalue().startswith( "\x1b[34m" ), "Should start with blue color" with using_temporary_stdout() as stdout: Logger.raw("Pouet pouet", linebreak=False) assert not stdout.getvalue().endswith( "\n" ), "Should not end with a newline" with using_temporary_stdout() as stdout: Logger.info("H\x82h\x82 hoho") if six.PY2: res = "H\x82h\x82 hoho".decode("utf-8", errors="replace") else: res = "H\x82h\x82 hoho" assert res in stdout.getvalue(), "Should work" with using_temporary_stdout() as stdout: # Error Logger.error("Pouet", crash=False) with pytest.raises(LoggerError): Logger.error("Pouet", crash=True)
"""Install docs.""" import os import argparse import shutil from docknv.utils.prompt import prompt_yes_no from docknv.logger import Logger html_docs = os.path.join("_build", "html") parser = argparse.ArgumentParser(description="install documentation to path") parser.add_argument("output_path") args = parser.parse_args() if not os.path.exists(html_docs): Logger.error("you must build the HTML docs.") if not os.path.exists(args.output_path): Logger.error("output path {0} does not exist.".format(args.output_path)) else: choice = prompt_yes_no( "/!\\ the folder {0} will be removed and recreated. " "are you sure you want to install?".format(args.output_path) ) if choice: shutil.rmtree(args.output_path) shutil.copytree(html_docs, args.output_path)
def show(self): """Show image.""" Logger.raw(f"- {self.name} ", color=Fore.GREEN, linebreak=False) Logger.raw(f"({self.path})")
def show(self): """Show schema.""" Logger.raw(f"- Schema: {self.name}", color=Fore.GREEN) if len(self.services) > 0: Logger.raw(" Services: ", color=Fore.BLUE) for service in self.services: Logger.raw(f" - {service}") if len(self.volumes) > 0: Logger.raw(" Volumes: ", color=Fore.BLUE) for volume in self.volumes: Logger.raw(f" - {volume}") if len(self.networks) > 0: Logger.raw(" Networks: ", color=Fore.BLUE) for network in self.networks: Logger.raw(f" - {network}")