def uninstall(pilist: list, ipmap: dict, env: Environment = None, logger: TextLogger = None): """ Build the list of packages to uninstall. Dependencies are preserved (ie dependencies needed by other installed packages are kept) Packages are sorted for uninstall order. Returns a list of InstalledPackage """ def _log(message): if logger is not None and logger.isverbose(): logger.print_verbose(message) out = [] # Build the list from installed packages DependencyUtils.__build_tree(pilist, ipmap, out, env=env, ignore_unknown=True) # for uninstall, reverse order out = list(reversed(out)) # Remove read only packages ro_packages = list(filter(lambda ip: ip.read_only, out)) if len(ro_packages) > 0 and logger is not None and logger.isverbose(): logger.print_verbose("System package(s) cannot be uninstalled: " + ", ".join(map(str, ro_packages))) # Maintain dependencies other_pi_list = [ ip.identifier for ip in ipmap.values() if ip not in out ] # Keep all configurations (ie env=None) for all other installed packages for needed_ip in DependencyUtils.installed(other_pi_list, ipmap, env=None, ignore_unknown=True): if needed_ip in out: if logger is not None and logger.isverbose(): # Print packages which needs this package rdepends = DependencyUtils.rdepends([needed_ip.identifier], ipmap, env=env) _log( "Cannot uninstall {ip.identifier} (dependency of {text})" .format(ip=needed_ip, text=", ".join(map(str, rdepends)))) out.remove(needed_ip) out = [ip for ip in out if ip not in ro_packages] return out
def __init__(self): ConfigurationManager.__init__(self) # If the theme file does not exists, try to find a skeleton self.__tm = ThemeManager( self.find_configuration_file(LeafFiles.THEMES_FILENAME, check_exists=True) or LeafFiles.ETC_PREFIX / LeafFiles.THEMES_FILENAME) self.__logger = TextLogger()
def download_and_verify_file(url: str, output: Path, logger: TextLogger = None, hashstr: str = None): """ Download an artifact and check its hash if given """ if output.exists(): if hashstr is None: logger.print_verbose( "File exists but cannot be verified, {file.name} will be re-downloaded" .format(file=output)) os.remove(str(output)) elif not hash_check(output, hashstr, raise_exception=False): logger.print_verbose( "File exists but hash differs, {file.name} will be re-downloaded" .format(file=output)) os.remove(str(output)) else: logger.print_verbose( "File {file.name} is already downloaded".format(file=output)) if not output.exists(): download_file(url, output, logger=logger) if hashstr: hash_check(output, hashstr, raise_exception=True) return output
def _display_progress(logger: TextLogger, message: str, worked: int = None, total: int = None, end: str = "", try_percent=True): if logger: if worked is None or total is None: logger.print_default(message, end=end, flush=True) else: kwargs = { "message": message, "worked": worked, "total": total, "progress": "??" } if try_percent and 0 <= worked <= total and total > 0: kwargs["progress"] = "{0:.0%}".format(worked / total) else: kwargs["progress"] = "{0}/{1}".format(worked, total) logger.print_default("\r[{progress}] {message} ".format(**kwargs), end=end, flush=True)
def execute(self, args, uargs): # Check argcomplete if subprocess.call(["which", CompletionPlugin.__ARGCOMPLETE_BIN], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) != 0: raise LeafException( "Cannot find argcomplete: {bin}".format( bin=CompletionPlugin.__ARGCOMPLETE_BIN), hints=[ "You can install argcomplete with 'sudo apt-get install python3-argcomplete'", "or using 'pip install argcomplete' if you are in a virtualenv", ], ) # Guess shell if not provided shell = args.shell if shell is None and CommonSettings.SHELL.is_set(): shell = CommonSettings.SHELL.as_path().name # Check supported shell if shell not in CompletionPlugin.__SUPPORTED_SHELLS: raise LeafException("Unsupported shell") # Print commands logger = TextLogger() logger.print_default( "# Evaluate the following lines to load leaf completion for {shell}" .format(shell=shell)) logger.print_default( '# e.g. with: eval "$(leaf completion -q -s {shell})"'.format( shell=shell)) if shell == "bash": logger.print_quiet('eval "$({bin} -s bash leaf)";'.format( bin=CompletionPlugin.__ARGCOMPLETE_BIN)) elif shell == "zsh": logger.print_quiet("autoload bashcompinit;") logger.print_quiet("bashcompinit;") logger.print_quiet("autoload compinit;") logger.print_quiet("compinit;") logger.print_quiet('eval "$({bin} -s bash leaf)";'.format( bin=CompletionPlugin.__ARGCOMPLETE_BIN)) elif shell == "tcsh": logger.print_quiet('eval "$({bin} -s tcsh leaf)";'.format( bin=CompletionPlugin.__ARGCOMPLETE_BIN))
def _download_file_http(url: str, output: Path, logger: TextLogger, resume: bool = None, retry: int = None, buffer_size: int = 262144): # Handle default values if retry is None: retry = LeafSettings.DOWNLOAD_RETRY.as_int() if resume is None: resume = not LeafSettings.DOWNLOAD_NORESUME.as_boolean() _display_progress(logger, "Downloading {0.name}".format(output)) iteration = 0 while True: try: headers = {} size_current = 0 if output.exists(): if resume: size_current = output.stat().st_size headers = {"Range": "bytes={0}-".format(size_current)} else: output.unlink() with output.open("ab" if resume else "wb") as fp: req = requests.get( url, stream=True, headers=headers, timeout=LeafSettings.DOWNLOAD_TIMEOUT.as_int()) # Get total size on first request size_total = int(req.headers.get("content-length", -1)) + size_current # Read remote data and write to output file for data in req.iter_content(buffer_size): size_current += fp.write(data) _display_progress(logger, "Downloading {0.name}".format(output), size_current, size_total) # Rare case when no exception raised and download is not finished if 0 < size_current < size_total: raise ValueError("Incomplete download") # End the progress display _display_progress(logger, "Downloading {0.name}".format(output), 1, 1, end="\n") return size_current except (ValueError, requests.RequestException, requests.ConnectionError, requests.HTTPError, requests.Timeout) as e: iteration += 1 # Check retry if iteration > retry: raise e # Log the retry attempt if logger: logger.print_default( "\nError while downloading, retry {0}/{1}".format( iteration, retry)) print_trace() # Prevent imediate retry time.sleep(1)