Пример #1
0
    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
Пример #2
0
 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()
Пример #3
0
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
Пример #4
0
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)
Пример #5
0
    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))
Пример #6
0
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)