def ensure_keys(name, config, *keys): values = [] for required_key in keys: if required_key not in config: raise OzyError(f"Missing required key '{required_key}' in '{name}'") values.append(config[required_key]) return values
def install(apps): """Ensures the named applications are installed at their current prevailing versions.""" config = load_config() for app_name in apps: if app_name not in config['apps']: raise OzyError(f"App '{app_name}' was not found") app = App(app_name, config) app.ensure_installed()
def download_to_file_obj(dest_file_obj: BinaryIO, url: str): response = requests.get(url, stream=True) if not response.ok: raise OzyError(f"Unable to fetch url '{url}' - {response}") total_size = int(response.headers.get('content-length', 0)) with tqdm(total=total_size, unit='iB', unit_scale=True) as t: for data in response.iter_content(_DOWNLOAD_CHUNK_SIZE): t.update(len(data)) dest_file_obj.write(data)
def resolve(config, templates): if 'template' in config: template_name = config['template'] if template_name not in templates: raise OzyError(f"Unable to find template '{template_name}'") # TODO had these the wrong way round to start with. make a test config = ChainMap(config, templates[template_name]) return {key: safe_expand(config, value) for key, value in config.items()}
def _run(app, arguments, version=None): tool = find_app(app, version) if not tool: raise OzyError(f"Unable to find ozy-controlled app '{app}'") tool.ensure_installed() try: os.execv(tool.executable, [tool.executable] + list(arguments)) except Exception as e: _LOGGER.error("Unable to execute %s: %s", tool.executable, e) raise
def __init__(self, name, config, *required_keys, **default_keys): self._name = name self._config = default_keys.copy() for required_key in required_keys: if required_key not in config: raise OzyError( f"Missing required key '{required_key}' in '{name}'") self._config[required_key] = config[required_key] for optional_key in default_keys.keys(): if optional_key in config: self._config[optional_key] = config[optional_key]
def __init__(self, name, root_config): self._name = name self._root_config = root_config self._config = resolve(root_config['apps'][name], self._root_config.get('templates', {})) self._executable_path = self._config.get('executable_path', self.name) self._relocatable = self._config.get('relocatable', True) self._post_install = fixup_post_install(self._config.get('post_install', [])) self._version, install_type = ensure_keys(name, self._config, 'version', 'type') if install_type not in SUPPORTED_INSTALLERS: raise OzyError(f"Unsupported installation type '{install_type}'") self._installer = SUPPORTED_INSTALLERS[install_type](name, self._config)
def safe_expand(format_params, to_expand): if isinstance(to_expand, list): return [safe_expand(format_params, x) for x in to_expand] elif not isinstance(to_expand, str): return to_expand params = get_system_variables() params.update(format_params) try: return to_expand.format(**params) except KeyError as ke: raise OzyError(f"Could not find key {ke} in expansion '{to_expand}' with params '{format_params}'")
def _run(app, arguments, version=None): tool = find_app(app, version) if not tool: raise OzyError(f"Unable to find ozy-controlled app '{app}'") tool.ensure_installed() try: # The child process shouldn't get any of our overridden variables; put the original ones back. environment = restore_overridden_env_vars(os.environ) os.execve(tool.executable, [tool.executable] + list(arguments), environment) except Exception as e: _LOGGER.error("Unable to execute %s: %s", tool.executable, e) raise
def __init__(self, name: str, config: dict, *required_keys, **default_keys): self._name = name self._config = default_keys.copy() self._executable_path = config.get('executable_path', name) for required_key in required_keys: if required_key not in config: raise OzyError( f"Missing required key '{required_key}' in '{name}'") self._config[required_key] = config[required_key] for optional_key in default_keys.keys(): if optional_key in config: self._config[optional_key] = config[optional_key]
def install(self, to_dir): app_name = self.config('app_name') url = self.config('url') os.makedirs(to_dir) app_path = os.path.join(to_dir, app_name) with NamedTemporaryFile() as temp_file: download_to_file_obj(temp_file, url) temp_file.flush() zf = ZipFile(temp_file.name) contents = zf.namelist() if len(contents) != 1: raise OzyError( f"More than one file in the zipfile at {url}! ({contents})" ) with open(app_path, 'wb') as out_file: with zf.open(contents[0]) as in_file: out_file.write(in_file.read()) os.chmod(app_path, 0o774)
def update(dry_run, url): """Update base configuration from the remote URL.""" user_conf = load_ozy_user_conf() if not url: if 'url' not in user_conf: raise OzyError('Missing url in configuration') url = user_conf['url'] ozy_conf_filename = f"{get_ozy_dir()}/ozy.yaml" tmp_filename = ozy_conf_filename + ".tmp" download_to(tmp_filename, url) new_conf_root = parse_ozy_conf(tmp_filename) old_conf_root = parse_ozy_conf(ozy_conf_filename) changed = False for app, new_conf in new_conf_root['apps'].items(): old_conf = old_conf_root['apps'].get(app, None) if not old_conf: _LOGGER.info('%s new app %s (%s)', "Would install" if dry_run else "Installing", app, new_conf['version']) changed = True elif old_conf['version'] != new_conf['version']: _LOGGER.info('%s %s from %s to %s', "Would upgrade" if dry_run else "Upgrading", app, old_conf['version'], new_conf['version']) changed = True if not dry_run: ozy_bin_dir = get_ozy_bin_dir() user_conf['url'] = url save_ozy_user_conf(user_conf) os.rename(tmp_filename, ozy_conf_filename) symlink_binaries(ozy_bin_dir, new_conf_root) if not changed: _LOGGER.info("No changes made") else: if changed: _LOGGER.info("Dry run only - no changes made") else: _LOGGER.info( "Dry run only - no changes would be made, even without --dry-run" ) os.unlink(tmp_filename)
def get_home_dir() -> str: if 'HOME' in os.environ: return os.environ['HOME'] raise OzyError("HOME env variable not found")