Exemplo n.º 1
0
def format_package(
    graph: DirectedGraph,
    package: Package,
    required: str = "",
    prefix: str = "",
    visited=None,
) -> str:
    """Format one package.

    :param graph: the dependency graph
    :param package: the package instance
    :param required: the version required by its parent
    :param prefix: prefix text for children
    :param visited: the visited package collection
    """
    if visited is None:
        visited = set()
    result = []
    version = (
        stream.red("[ not installed ]")
        if not package.version
        else stream.red(package.version)
        if required
        and required != "Any"
        and not SpecifierSet(required).contains(package.version)
        else stream.yellow(package.version)
    )
    if package.name in visited:
        version = stream.red("[circular]")
    required = f"[ required: {required} ]" if required else ""
    result.append(f"{stream.green(package.name, bold=True)} {version} {required}\n")
    if package.name in visited:
        return "".join(result)
    visited.add(package.name)
    try:
        *children, last = sorted(graph.iter_children(package), key=lambda p: p.name)
    except ValueError:  # No children nodes
        pass
    else:
        for child in children:
            required = str(package.requirements[child.name].specifier or "Any")
            result.append(
                prefix
                + NON_LAST_CHILD
                + format_package(
                    graph, child, required, prefix + NON_LAST_PREFIX, visited.copy()
                )
            )
        required = str(package.requirements[last.name].specifier or "Any")
        result.append(
            prefix
            + LAST_CHILD
            + format_package(
                graph, last, required, prefix + LAST_PREFIX, visited.copy()
            )
        )
    return "".join(result)
Exemplo n.º 2
0
def set_env_in_reg(env_name: str, value: str) -> None:
    """Manipulate the WinReg, and add value to the
    environment variable if exists or create new.
    """
    import winreg

    value = os.path.normcase(value)

    with winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) as root:
        with winreg.OpenKey(root, "Environment", 0,
                            winreg.KEY_ALL_ACCESS) as env_key:
            try:
                old_value, type_ = winreg.QueryValueEx(env_key, env_name)
                if value in [
                        os.path.normcase(item)
                        for item in old_value.split(os.pathsep)
                ]:
                    return
            except FileNotFoundError:
                old_value, type_ = "", winreg.REG_EXPAND_SZ
            new_value = ";".join(old_value, value) if old_value else value
            try:
                winreg.SetValueEx(env_key, env_name, 0, type_, new_value)
            except PermissionError:
                stream.echo(
                    stream.red(
                        "Permission denied, please run the terminal as administrator."
                    ),
                    err=True,
                )
                sys.exit(1)
    stream.echo(
        stream.green("The environment variable has been saved, "
                     "please restart the session to take effect."))
Exemplo n.º 3
0
def deprecate_global_option(value) -> Project:
    if value:
        stream.echo(
            stream.red(
                "DEPRECATION: -g/--global with argument is deprecated and will be "
                "removed in v1.5.0, please use '-gp <PROJECT_PATH>' instead."),
            err=True,
        )
    return Project.create_global(value)
Exemplo n.º 4
0
def format_package(
    graph: DirectedGraph,
    package: Package,
    required: str = "",
    prefix: str = "",
    visited=None,
) -> str:
    """Format one package.

    :param graph: the dependency graph
    :param package: the package instance
    :param required: the version required by its parent
    :param prefix: prefix text for children
    :param visited: the visited package collection
    """
    if visited is None:
        visited = set()
    result = []
    version = (stream.red("[ not installed ]")
               if not package.version else stream.red(package.version)
               if required and required not in ("Any", "This project")
               and not SpecifierSet(required).contains(package.version) else
               stream.yellow(package.version))
    if package.name in visited:
        version = stream.red("[circular]")
    required = f"[ required: {required} ]" if required else "[ Not required ]"
    result.append(
        f"{stream.green(package.name, bold=True)} {version} {required}\n")
    if package.name in visited:
        return "".join(result)
    visited.add(package.name)
    children = sorted(graph.iter_children(package), key=lambda p: p.name)
    for i, child in enumerate(children):
        is_last = i == len(children) - 1
        head = LAST_CHILD if is_last else NON_LAST_CHILD
        cur_prefix = LAST_PREFIX if is_last else NON_LAST_PREFIX
        required = str(package.requirements[child.name].specifier or "Any")
        result.append(prefix + head +
                      format_package(graph, child, required, prefix +
                                     cur_prefix, visited.copy()))
    return "".join(result)
Exemplo n.º 5
0
def format_reverse_package(
    graph: DirectedGraph,
    package: Package,
    child: Optional[Package] = None,
    requires: str = "",
    prefix: str = "",
    visited=None,
):
    """Format one package for output reverse dependency graph."""
    if visited is None:
        visited = set()
    result = []
    version = (stream.red("[ not installed ]")
               if not package.version else stream.yellow(package.version))
    if package.name in visited:
        version = stream.red("[circular]")
    requires = (f"[ requires: {stream.red(requires)} ]"
                if requires not in ("Any", "") and child and child.version
                and not SpecifierSet(requires).contains(child.version) else
                "" if not requires else f"[ requires: {requires} ]")
    result.append(
        f"{stream.green(package.name, bold=True)} {version} {requires}\n")
    if package.name in visited:
        return "".join(result)
    visited.add(package.name)
    parents = sorted(filter(None, graph.iter_parents(package)),
                     key=lambda p: p.name)
    for i, parent in enumerate(parents):
        is_last = i == len(parents) - 1
        head = LAST_CHILD if is_last else NON_LAST_CHILD
        cur_prefix = LAST_PREFIX if is_last else NON_LAST_PREFIX
        requires = str(parent.requirements[package.name].specifier or "Any")
        result.append(
            prefix + head +
            format_reverse_package(graph, parent, package, requires, prefix +
                                   cur_prefix, visited.copy()))
    return "".join(result)
Exemplo n.º 6
0
    def synchronize(self, clean: bool = True, dry_run: bool = False) -> None:
        """Synchronize the working set with pinned candidates.

        :param clean: Whether to remove unneeded packages, defaults to True.
        :param dry_run: If set to True, only prints actions without actually do them.
        """
        to_add, to_update, to_remove = self.compare_with_working_set()
        if not clean:
            to_remove = []
        if not any([to_add, to_update, to_remove]):
            stream.echo(
                stream.yellow(
                    "All packages are synced to date, nothing to do."))
            if not dry_run:
                with stream.logging("install"):
                    self.update_project_egg_info()
            return
        to_do = {"remove": to_remove, "update": to_update, "add": to_add}
        self._show_headline(to_do)

        if dry_run:
            self._show_summary(to_do)
            return

        handlers = {
            "add": self.install_candidate,
            "update": self.update_candidate,
            "remove": self.remove_distribution,
        }

        sequential_jobs = []
        parallel_jobs = []
        # Self package will be installed after all other dependencies are installed.
        install_self = None
        for kind in to_do:
            for key in to_do[kind]:
                if (key == self.environment.project.meta.name and
                        self.environment.project.meta.project_name.lower()):
                    install_self = (kind, key)
                elif key in self.SEQUENTIAL_PACKAGES:
                    sequential_jobs.append((kind, key))
                elif key in self.candidates and self.candidates[
                        key].req.editable:
                    # Editable packages are installed sequentially.
                    sequential_jobs.append((kind, key))
                else:
                    parallel_jobs.append((kind, key))

        errors: List[str] = []
        failed_jobs: List[Tuple[str, str]] = []

        def update_progress(future, kind, key):
            if future.exception():
                failed_jobs.append((kind, key))
                error = future.exception()
                errors.extend([f"{kind} {stream.green(key)} failed:\n"] +
                              traceback.format_exception(
                                  type(error), error, error.__traceback__))

        with stream.logging("install"), self.environment.activate():
            with stream.indent("  "):
                for job in sequential_jobs:
                    kind, key = job
                    handlers[kind](key)
                for i in range(self.retry_times + 1):
                    with self.create_executor() as executor:
                        for job in parallel_jobs:
                            kind, key = job
                            future = executor.submit(handlers[kind], key)
                            future.add_done_callback(
                                functools.partial(update_progress,
                                                  kind=kind,
                                                  key=key))
                    if not failed_jobs or i == self.retry_times:
                        break
                    parallel_jobs, failed_jobs = failed_jobs, []
                    errors.clear()
                    stream.echo("Retry failed jobs")

            if errors:
                stream.echo(stream.red("\nERRORS:"))
                stream.echo("".join(errors), err=True)
                raise InstallationError(
                    "Some package operations are not complete yet")

            if install_self:
                stream.echo("Installing the project as an editable package...")
                with stream.indent("  "):
                    handlers[install_self[0]](install_self[1])
            else:
                self.update_project_egg_info()
            stream.echo(f"\n{CELE} All complete!")
Exemplo n.º 7
0
    def synchronize(self, clean: bool = True, dry_run: bool = False) -> None:
        """Synchronize the working set with pinned candidates.

        :param clean: Whether to remove unneeded packages, defaults to True.
        :param dry_run: If set to True, only prints actions without actually do them.
        """
        to_add, to_update, to_remove = self.compare_with_working_set()
        if not clean:
            to_remove = []
        lists_to_check = [to_add, to_update, to_remove]
        if not any(lists_to_check):
            stream.echo("All packages are synced to date, nothing to do.")
            return

        if dry_run:
            result = dict(
                add=[self.candidates[key] for key in to_add],
                update=[
                    (self.working_set[key], self.candidates[key]) for key in to_update
                ],
                remove=[self.working_set[key] for key in to_remove],
            )
            self.summarize(result, dry_run)
            return

        handlers = {
            "add": self.install_candidate,
            "update": self.update_candidate,
            "remove": self.remove_distribution,
        }

        result = defaultdict(list)
        failed = defaultdict(list)
        to_do = {"add": to_add, "update": to_update, "remove": to_remove}
        # Keep track of exceptions
        errors = []

        def update_progress(future, section, key, bar):
            if future.exception():
                failed[section].append(key)
                errors.append(future.exception())
            else:
                result[section].append(future.result())
            bar.update(1)

        with self.progressbar(
            "Synchronizing:", sum(len(l) for l in to_do.values())
        ) as (bar, pool):

            for section in to_do:
                for key in to_do[section]:
                    future = pool.submit(handlers[section], key)
                    future.add_done_callback(
                        functools.partial(
                            update_progress, section=section, key=key, bar=bar
                        )
                    )

        # Retry for failed items
        for i in range(self.RETRY_TIMES):
            if not any(failed.values()):
                break
            to_do = failed
            failed = defaultdict(list)
            errors.clear()
            with self.progressbar(
                f"Retrying ({i + 1}/{self.RETRY_TIMES}):",
                sum(len(l) for l in to_do.values()),
            ) as (bar, pool):

                for section in to_do:
                    for key in to_do[section]:
                        future = pool.submit(handlers[section], key)
                        future.add_done_callback(
                            functools.partial(
                                update_progress, section=section, key=key, bar=bar
                            )
                        )
        stream.echo()
        self.summarize(result)
        if not any(failed.values()):
            return
        stream.echo(stream.red("[ERROR]", bold=True))
        if failed["add"] + failed["update"]:
            stream.echo(
                f"Installation failed: {', '.join(failed['add'] + failed['update'])}"
            )
        if failed["remove"]:
            stream.echo(f"Removal failed: {', '.join(failed['remove'])}")
        for error in errors:
            stream.echo(
                "".join(
                    traceback.format_exception(type(error), error, error.__traceback__)
                ),
                verbosity=stream.DEBUG,
            )