Example #1
0
def sanitize_user_input(user_input: Sequence[str], system: 'System') -> Set[str]:
    """
    Finds the names of the packages for the user_input
    Needed since user may also specify the version of a package,
    hence package1>1.0 may yield package1 since package1 has version 2.0

    :param user_input:      The user input in a sequence
    :param system:          The system to check the providing of
    :return:                A set containing the packages names
    """
    sanitized_names = set()
    for name in user_input:
        providers_for_name = system.provided_by(name)
        if not providers_for_name:
            aurman_error("No providers for {} found.".format(Colors.BOLD(Colors.LIGHT_MAGENTA(name))))
            sys.exit(1)
        elif len(providers_for_name) == 1:
            sanitized_names.add(providers_for_name[0].name)
        # more than one provider
        else:
            dep_name = strip_versioning_from_name(name)
            providers_names = [package.name for package in providers_for_name]
            if dep_name in providers_names:
                sanitized_names.add(dep_name)
            else:
                aurman_error("Multiple providers found for {}\n"
                             "None of the providers has the name "
                             "of the dep without versioning.\n"
                             "The providers are: {}".format(Colors.BOLD(Colors.LIGHT_MAGENTA(name)), ", ".join(
                    [system.repo_of_package(provider_for_name) for provider_for_name in providers_names])))
                sys.exit(1)

    return sanitized_names
Example #2
0
def show_unread_news():
    """
    Shows unread news from archlinux.org
    """
    # load list of already seen news
    try:
        os.makedirs(Package.cache_dir, mode=0o700, exist_ok=True)
    except OSError:
        logging.error("Creating cache dir {} failed".format(Package.cache_dir))
        raise InvalidInput("Creating cache dir {} failed".format(
            Package.cache_dir))

    seen_ids_file = os.path.join(Package.cache_dir, "seen_news_ids")
    if not os.path.isfile(seen_ids_file):
        open(seen_ids_file, 'a').close()

    with open(seen_ids_file, 'r') as seenidsfile:
        seen_ids: Set[str] = set(
            [line for line in seenidsfile.read().strip().splitlines()])

    # fetch current news and filter unseen news
    news_to_show = list(
        reversed(
            list(
                filter(
                    lambda entry: entry['id'] not in seen_ids,
                    feedparser.parse(
                        "https://www.archlinux.org/feeds/news/").entries))))

    # if no unread news, return
    if not news_to_show:
        return

    # show unseen news
    aurman_status("There are {} unseen news on archlinux.org".format(
        Colors.BOLD(Colors.LIGHT_MAGENTA(len(news_to_show)))))
    for entry in news_to_show:
        aurman_note("{} [{}]".format(
            Colors.BOLD(Colors.LIGHT_MAGENTA(entry['title'])),
            entry['published']),
                    new_line=True)
        print(re.sub('<[^<]+?>', '', entry['summary']))

    if ask_user("Have you read the news?", False, True):
        with open(seen_ids_file, 'a') as seenidsfile:
            seenidsfile.write(
                '\n'.join([entry['id'] for entry in news_to_show]) + '\n')
    else:
        logging.error(
            "User did not read the unseen news, but wanted to install packages on the system"
        )
        raise InvalidInput(
            "User did not read the unseen news, but wanted to install packages on the system"
        )
Example #3
0
def packages_from_other_sources() -> Tuple[Set[str], Dict[str, str]]:
    """
    Returns the packages which should be installed
    from sources where they normally would not be installed from.

    :return:        A tuple containing two items:
                        First item:
                            Set containing the names of packages to install from the aur

                        Second item:
                            Dict containing names from known repo packages as keys
                            and the repo to install those packages from as values
    """
    config = AurmanConfig.aurman_config
    if config is None:
        aurman_error("aurman config not loaded")
        raise InvalidInput("aurman config not loaded")

    aur_set = set()
    if 'aur_packages' in config:
        for aur_package_name in config['aur_packages']:
            aur_set.add(aur_package_name)

    repo_dict = {}
    if 'repo_packages' in config:
        for repo_package_name in config['repo_packages']:
            if config['repo_packages'][repo_package_name] is None:
                continue

            repo_dict[repo_package_name] = str(
                config['repo_packages'][repo_package_name])

    for name in aur_set:
        if name in repo_dict:
            aurman_error("Package {} listed for aur and repo.".format(
                Colors.BOLD(Colors.LIGHT_MAGENTA(name))))
            raise InvalidInput("Package {} listed for aur and repo.".format(
                Colors.BOLD(Colors.LIGHT_MAGENTA(name))))

    return aur_set, repo_dict
Example #4
0
def show_packages_info(pacman_args: 'PacmanArgs',
                       packages_of_user_names: List[str]) -> None:
    """
    shows the information of packages, just as pacman -Si
    :param pacman_args:             the parsed args
    :param packages_of_user_names:  the targets to show the information of
    """
    # pacman output
    run(["pacman"] + pacman_args.args_as_list(), stderr=DEVNULL)

    # output for aur packages
    for package_dict in get_aur_info(packages_of_user_names):
        for key, value in package_dict.items():
            if type(value) is list:
                value = '  '.join(value)
            elif key in ["OutOfDate", "FirstSubmitted", "LastModified"
                         ] and value is not None:
                value = datetime.fromtimestamp(value).replace(
                    tzinfo=tzlocal()).strftime('%c')
            print("{}{} {}".format(Colors.BOLD(key.ljust(16)),
                                   Colors.BOLD(':'), value))
        print()

    sys.exit(0)
Example #5
0
def search_and_print(names: Sequence[str], installed_system,
                     pacman_params: str, repo: bool, aur: bool):
    """
    Searches for something and prints the results

    :param names:               The things to search for
    :param installed_system:    A system containing the installed packages
    :param pacman_params:       parameters for pacman as string
    :param repo:                search only in repo
    :param aur:                 search only in aur
    """
    if not names:
        return

    if not aur:
        # escape for pacman
        to_escape = list("()+?|{}")
        for char in to_escape:
            pacman_params = pacman_params.replace(char, "\{}".format(char))

        run("pacman {}".format(pacman_params), shell=True)

    if not repo:
        # see: https://docs.python.org/3/howto/regex.html
        regex_chars = list("^.+*?$[](){}\|")

        regex_patterns = [
            regex.compile(name, regex.IGNORECASE) for name in names
        ]
        names_beginnings_without_regex = []
        for name in names:
            index_start = -1
            index_end = len(name)
            for i, char in enumerate(name):
                if char not in regex_chars and index_start == -1:
                    index_start = i
                elif char in regex_chars and index_start != -1:
                    # must be at least two consecutive non regex chars
                    if i - index_start < 2:
                        index_start = -1
                        continue
                    index_end = i
                    break

            if index_start == -1 or index_end - index_start < 2:
                aurman_error(
                    "Your query {} contains not enough non regex chars!".
                    format(Colors.BOLD(Colors.LIGHT_MAGENTA(name))))
                raise InvalidInput(
                    "Your query {} contains not enough non regex chars!".
                    format(Colors.BOLD(Colors.LIGHT_MAGENTA(name))))

            names_beginnings_without_regex.append(name[index_start:index_end])

        found_names = set(
            ret_dict['Name'] for ret_dict in get_aur_info(
                [names_beginnings_without_regex[0]], True)
            if regex_patterns[0].findall(ret_dict['Name'])
            or isinstance(ret_dict['Description'], str)
            and regex_patterns[0].findall(ret_dict['Description']))

        for i in range(1, len(names)):
            found_names &= set(
                ret_dict['Name'] for ret_dict in get_aur_info(
                    [names_beginnings_without_regex[i]], True)
                if regex_patterns[i].findall(ret_dict['Name'])
                or isinstance(ret_dict['Description'], str)
                and regex_patterns[i].findall(ret_dict['Description']))

        search_return = get_aur_info(found_names)

        for ret_dict in sorted(search_return,
                               key=lambda x: float(x['Popularity']),
                               reverse=True):
            repo_with_slash = Colors.BOLD(Colors.LIGHT_MAGENTA("aur/"))
            name = Colors.BOLD(ret_dict['Name'])
            if ret_dict['OutOfDate'] is None:
                version = Colors.BOLD(Colors.GREEN(ret_dict['Version']))
            else:
                version = Colors.BOLD(Colors.RED(ret_dict['Version']))

            first_line = "{}{} {} ({}, {})".format(repo_with_slash, name,
                                                   version,
                                                   ret_dict['NumVotes'],
                                                   ret_dict['Popularity'])
            if ret_dict['Name'] in installed_system.all_packages_dict:
                if version_comparison(
                        ret_dict['Version'], "=",
                        installed_system.all_packages_dict[
                            ret_dict['Name']].version):
                    first_line += " {}".format(
                        Colors.BOLD(Colors.CYAN("[installed]")))
                else:
                    first_line += " {}".format(
                        Colors.BOLD(
                            Colors.CYAN("[installed: {}]".format(
                                installed_system.all_packages_dict[
                                    ret_dict['Name']].version))))
            print(first_line)
            print("    {}".format(ret_dict['Description']))
Example #6
0
File: main.py Project: njfox/aurman
def process(args):
    import aurman.aur_utilities

    readconfig()
    check_privileges()
    pacman_args = parse_parameters(args)

    if pacman_args.operation is PacmanOperations.HELP:
        show_help()

    if pacman_args.operation is PacmanOperations.VERSION:
        show_version()

    # if not -S or --sync, just redirect to pacman
    if pacman_args.operation is not PacmanOperations.SYNC:
        redirect_pacman(pacman_args, args)

    # -S or --sync
    # parse arguments
    Package.optimistic_versioning = pacman_args.optimistic_versioning  # if --optimistic_versioning
    packages_of_user_names = list(
        set(pacman_args.targets
            ))  # targets of the aurman command without duplicates
    sysupgrade = pacman_args.sysupgrade  # if -u or --sysupgrade
    sysupgrade_force = sysupgrade and not isinstance(
        sysupgrade, bool)  # if -u -u or --sysupgrade --sysupgrade
    needed = pacman_args.needed  # if --needed
    noedit = pacman_args.noedit  # if --noedit
    always_edit = pacman_args.always_edit  # if --always_edit
    show_changes = pacman_args.show_changes  # if --show_changes
    devel = pacman_args.devel  # if --devel
    only_unfulfilled_deps = not pacman_args.deep_search  # if not --deep_search
    pgp_fetch = pacman_args.pgp_fetch  # if --pgp_fetch
    noconfirm = pacman_args.noconfirm  # if --noconfirm
    search = pacman_args.search  # if --search
    solution_way = pacman_args.solution_way  # if --solution_way
    do_everything = pacman_args.do_everything  # if --do_everything
    clean = pacman_args.clean  # if --clean
    rebuild = pacman_args.rebuild  # if --rebuild
    clean_force = clean and not isinstance(clean, bool)  # if --clean --clean
    aur = pacman_args.aur  # do only aur things
    repo = pacman_args.repo  # do only repo things

    # if the default for showing changes of pkgbuilds etc. should be yes instead of no
    default_show_changes = 'miscellaneous' in AurmanConfig.aurman_config \
                           and 'default_show_changes' in AurmanConfig.aurman_config['miscellaneous']

    # if to pass -A to makepkg
    ignore_arch = 'miscellaneous' in AurmanConfig.aurman_config and \
                  'ignore_arch' in AurmanConfig.aurman_config['miscellaneous']

    # validity check for user arguments
    # unrecognized parameters
    if pacman_args.invalid_args:
        aurman_error(
            "The following parameters are not recognized yet: {}".format(
                pacman_args.invalid_args))
        aurman_note("aurman --help or aurman -h")
        sys.exit(1)

    if noedit and show_changes:
        aurman_error("--noedit and --show_changes is not what you want")
        sys.exit(1)

    if noedit and always_edit:
        aurman_error("--noedit and --always_edit is not what you want")
        sys.exit(1)

    if repo and aur:
        aurman_error("--repo and --aur is not what you want")
        sys.exit(1)

    # do not allow -y without -u
    if pacman_args.refresh and not sysupgrade:
        aurman_error("-y without -u is not allowed!")
        sys.exit(1)

    # packages to not notify about being unknown in either repos or the aur
    # global
    no_notification_unknown_packages = 'miscellaneous' in AurmanConfig.aurman_config and \
                                       'no_notification_unknown_packages' in AurmanConfig.aurman_config['miscellaneous']
    # single packages
    if 'no_notification_unknown_packages' in AurmanConfig.aurman_config:
        concrete_no_notification_packages = set([
            package_name for package_name in
            AurmanConfig.aurman_config['no_notification_unknown_packages']
        ])
    else:
        concrete_no_notification_packages = set()

    # disable sudo loop if configured by the user
    sudo_acquired = 'miscellaneous' in AurmanConfig.aurman_config \
                    and 'no_sudo_loop' in AurmanConfig.aurman_config['miscellaneous']
    pacman_called = False

    # get holdpkgs
    not_remove = get_holdpkgs(pacman_args)

    # set keyserver
    keyserver = get_keyserver(pacman_args)

    # change aur domain if configured by the user
    if pacman_args.domain:
        aurman.aur_utilities.aur_domain = pacman_args.domain[0]

    # set the folder to save `aurman` cache files
    if 'miscellaneous' in AurmanConfig.aurman_config \
            and 'cache_dir' in AurmanConfig.aurman_config['miscellaneous']:
        Package.cache_dir = AurmanConfig.aurman_config['miscellaneous'][
            'cache_dir']

    # --- start actually executing things --- #

    # if user wants to --clean
    if clean:
        clean_cache(pacman_args, aur, repo, clean_force, noconfirm)

    # if user just wants to search
    if search:
        search_packages(pacman_args, packages_of_user_names, repo, aur)

    # groups are for pacman
    # removes found groups from packages_of_user_names
    groups_chosen = get_groups_to_install(packages_of_user_names, aur)

    # pacman call in the beginning of the routine
    if not aur and \
            (sysupgrade and (not do_everything or pacman_args.refresh) or groups_chosen):
        sudo_acquired, pacman_called = pacman_beginning_routine(
            pacman_args, groups_chosen, sudo_acquired, do_everything)

    # nothing to do for us - exit
    if not sysupgrade and not packages_of_user_names:
        sys.exit(0)

    # delete -u --sysupgrade -y --refresh from parsed args
    # not needed anymore
    pacman_args.sysupgrade = False
    pacman_args.refresh = False

    # one status message
    if pacman_called:
        aurman_status("initializing {}...".format(Colors.BOLD("aurman")), True)
    else:
        aurman_status("initializing {}...".format(Colors.BOLD("aurman")),
                      False)

    # analyzing installed packages
    try:
        installed_system = System(System.get_installed_packages())
    except InvalidInput:
        sys.exit(1)

    # print unknown packages for the user
    packages_to_show = [
        package for package in installed_system.not_repo_not_aur_packages_list
        if package.name not in concrete_no_notification_packages
    ]

    if packages_to_show and not no_notification_unknown_packages:
        aurman_status(
            "the following packages are neither in known repos nor in the aur")
        for package in packages_to_show:
            aurman_note("{}".format(Colors.BOLD(
                Colors.LIGHT_MAGENTA(package))))

    # fetching upstream repo packages...
    try:
        upstream_system = System(System.get_repo_packages())
    except InvalidInput:
        sys.exit(1)

    # fetching needed aur packages
    if not repo:
        upstream_system.append_packages_by_name(packages_of_user_names)
        # fetch info for all installed aur packages, too
        names_of_installed_aur_packages = [
            package.name for package in installed_system.aur_packages_list
        ]
        names_of_installed_aur_packages.extend(
            [package.name for package in installed_system.devel_packages_list])
        upstream_system.append_packages_by_name(
            names_of_installed_aur_packages)

    # remove known repo packages in case of --aur
    if aur:
        for package in upstream_system.repo_packages_list:
            del upstream_system.all_packages_dict[package.name]
        upstream_system = System(
            list(upstream_system.all_packages_dict.values()))

    # sanitize user input
    try:
        sanitized_names = upstream_system.sanitize_user_input(
            packages_of_user_names)
        sanitized_not_to_be_removed = installed_system.sanitize_user_input(
            not_remove)
    except InvalidInput:
        sys.exit(1)

    # names to not be removed must be also known on the upstream system,
    # otherwise aurman solving cannot handle this case.
    for name in sanitized_not_to_be_removed:
        if name not in upstream_system.all_packages_dict:
            aurman_error(
                "Packages you want to be not removed must be aur or repo packages.\n"
                "   {} is not known.".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA(name))))
            sys.exit(1)

    # for dep solving not to be removed has to be treated as wanted to install
    sanitized_names |= sanitized_not_to_be_removed

    # fetching ignored packages
    ignored_packages_names = Package.get_ignored_packages_names(
        pacman_args.ignore, pacman_args.ignoregroup, upstream_system)
    # explicitly typed in names will not be ignored
    ignored_packages_names -= sanitized_names

    # print ignored packages for the user
    for ignored_packages_name in ignored_packages_names:
        if ignored_packages_name in upstream_system.all_packages_dict:
            if ignored_packages_name in installed_system.all_packages_dict:
                aurman_note("{} {} package {}".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                    Colors.BOLD(Colors.LIGHT_CYAN("installed")),
                    Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                upstream_system.all_packages_dict[
                    ignored_packages_name] = installed_system.all_packages_dict[
                        ignored_packages_name]
            else:
                aurman_note("{} {} package {}".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                    Colors.BOLD(Colors.LIGHT_BLUE("upstream ")),
                    Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                del upstream_system.all_packages_dict[ignored_packages_name]

    # recreating upstream system
    if ignored_packages_names:
        upstream_system = System(
            list(upstream_system.all_packages_dict.values()))

    # if user entered --devel and not --repo, fetch all needed pkgbuilds etc. for the devel packages
    if devel and not repo:
        aurman_status(
            "looking for new pkgbuilds of devel packages and fetching them...")
        for package in upstream_system.devel_packages_list:
            if package.name not in ignored_packages_names:
                package.fetch_pkgbuild()
        try:
            for package in upstream_system.devel_packages_list:
                if package.name not in ignored_packages_names:
                    package.show_pkgbuild(noedit, show_changes, pgp_fetch,
                                          keyserver, always_edit,
                                          default_show_changes)
        except InvalidInput:
            sys.exit(1)
        for package in upstream_system.devel_packages_list:
            if package.name not in ignored_packages_names:
                package.get_devel_version()

    # checking which packages need to be installed
    if not needed:
        concrete_packages_to_install = [
            upstream_system.all_packages_dict[name] for name in sanitized_names
        ]
    else:
        possible_packages = [
            upstream_system.all_packages_dict[name] for name in sanitized_names
        ]
        concrete_packages_to_install = []
        for package in possible_packages:
            if package.name in installed_system.all_packages_dict:
                installed_package = installed_system.all_packages_dict[
                    package.name]
                if not version_comparison(installed_package.version, "=",
                                          package.version):
                    concrete_packages_to_install.append(package)
            else:
                concrete_packages_to_install.append(package)

    # in case of sysupgrade fetch all installed packages, of which newer versions are available
    if sysupgrade:
        installed_packages = []
        if not repo:
            installed_packages.extend(
                [package for package in installed_system.aur_packages_list])
            installed_packages.extend(
                [package for package in installed_system.devel_packages_list])
        if not aur:
            installed_packages.extend(
                [package for package in installed_system.repo_packages_list])
        for package in installed_packages:
            # must not be that we have not received the upstream information
            assert package.name in upstream_system.all_packages_dict
            upstream_package = upstream_system.all_packages_dict[package.name]
            # normal sysupgrade
            if not sysupgrade_force:
                if version_comparison(upstream_package.version, ">",
                                      package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)
            # sysupgrade with downgrades
            else:
                if not version_comparison(upstream_package.version, "=",
                                          package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)

    # start calculating solutions
    aurman_status("calculating solutions...")
    if only_unfulfilled_deps:
        solutions = Package.dep_solving(concrete_packages_to_install,
                                        installed_system, upstream_system)
    else:
        solutions = Package.dep_solving(concrete_packages_to_install, System(
            ()), upstream_system)

    # validates the found solutions and lets the user choose one of them, if there are more than one valid solutions
    try:
        chosen_solution = installed_system.validate_and_choose_solution(
            solutions, concrete_packages_to_install)
    except InvalidInput:
        aurman_error("we could not find a solution")
        # if not --deep_search
        if only_unfulfilled_deps:
            aurman_error(
                "if you think that there should be one, rerun aurman with the --deep_search flag"
            )
        sys.exit(1)

    # needed because deep_search ignores installed packages
    if not only_unfulfilled_deps:
        pacman_args.needed = True

    # solution contains no packages
    if not chosen_solution:
        aurman_note("nothing to do... everything is up to date")
        sys.exit(0)

    # show solution to the user
    try:
        installed_system.show_solution_differences_to_user(
            chosen_solution, upstream_system, noconfirm,
            not only_unfulfilled_deps, solution_way)
    except InvalidInput:
        sys.exit(1)

    # fetch pkgbuilds
    if not repo:
        aurman_status("looking for new pkgbuilds and fetching them...")
        for package in chosen_solution:
            if package.type_of is PossibleTypes.REPO_PACKAGE \
                    or devel and package.type_of is PossibleTypes.DEVEL_PACKAGE:
                continue
            package.fetch_pkgbuild()
        try:
            for package in chosen_solution:
                if package.type_of is PossibleTypes.REPO_PACKAGE \
                        or devel and package.type_of is PossibleTypes.DEVEL_PACKAGE:
                    continue
                package.show_pkgbuild(noedit, show_changes, pgp_fetch,
                                      keyserver, always_edit,
                                      default_show_changes)
        except InvalidInput:
            sys.exit(1)

    # install packages
    if not sudo_acquired:
        acquire_sudo()
        sudo_acquired = True

    # repo packages to install from other sources
    repo_packages_dict = packages_from_other_sources()[1]

    # generate pacman args for the aur packages
    pacman_args_copy = deepcopy(pacman_args)
    pacman_args_copy.operation = PacmanOperations.UPGRADE
    pacman_args_copy.targets = []

    args_for_explicit = str(pacman_args_copy)
    pacman_args_copy.asdeps = True
    pacman_args_copy.asexplicit = False
    args_for_dependency = str(pacman_args_copy)

    # calc chunks to install
    solution_packages_chunks = System.calc_install_chunks(chosen_solution)

    # install the chunks
    for package_chunk in solution_packages_chunks:
        # repo chunk
        if package_chunk[0].type_of is PossibleTypes.REPO_PACKAGE:
            # container for explicit repo deps
            as_explicit_container = set()
            for package in package_chunk:
                if package.name in sanitized_names and package.name not in sanitized_not_to_be_removed \
                        or ((package.name in installed_system.all_packages_dict)
                            and (installed_system.all_packages_dict[package.name].install_reason == 'explicit')):
                    as_explicit_container.add(package.name)

            pacman_args_copy = deepcopy(pacman_args)
            pacman_args_copy.targets = [
                package.name for package in package_chunk
                if package.name not in repo_packages_dict
            ]

            pacman_args_copy.targets.extend([
                "{}/".format(repo_packages_dict[package.name]) + package.name
                for package in package_chunk
                if package.name in repo_packages_dict
            ])
            pacman_args_copy.asdeps = True
            pacman_args_copy.asexplicit = False
            try:
                pacman(str(pacman_args_copy), False, use_ask=True)
            except InvalidInput:
                sys.exit(1)

            if as_explicit_container:
                pacman("-D --asexplicit {}".format(
                    " ".join(as_explicit_container)),
                       True,
                       sudo=True)
        # aur chunks always consist of one package
        else:
            package = package_chunk[0]
            try:
                package.build(ignore_arch, rebuild)
                if package.name in sanitized_names and package.name not in sanitized_not_to_be_removed \
                        or ((package.name in installed_system.all_packages_dict)
                            and (installed_system.all_packages_dict[package.name].install_reason == 'explicit')):
                    package.install(args_for_explicit, use_ask=True)
                else:
                    package.install(args_for_dependency, use_ask=True)
            except InvalidInput:
                sys.exit(1)
Example #7
0
File: main.py Project: njfox/aurman
def clean_cache(pacman_args: 'PacmanArgs', aur: bool, repo: bool,
                clean_force: bool, noconfirm: bool) -> None:
    """
    cleans the cache of pacman and aurman
    :param pacman_args: the parsed args
    :param aur: if --aur
    :param repo: if --aur
    :param clean_force: if -cc
    :param noconfirm: if --noconfirm
    """
    if not aur:
        pacman(str(pacman_args), False, sudo=True)

    if not repo:
        if not os.path.isdir(Package.cache_dir):
            aurman_error("Cache directory {} not found."
                         "".format(
                             Colors.BOLD(
                                 Colors.LIGHT_MAGENTA(Package.cache_dir))))
            sys.exit(1)

        aurman_note("Cache directory: {}".format(
            Colors.BOLD(Colors.LIGHT_MAGENTA(Package.cache_dir))))

        if clean_force:
            if noconfirm or \
                    ask_user("Do you want to remove {} from cache?"
                             "".format(Colors.BOLD(Colors.LIGHT_MAGENTA("all files"))), False):
                aurman_status("Deleting cache dir...")
                if run("rm -rf {}".format(Package.cache_dir),
                       shell=True,
                       stdout=DEVNULL,
                       stderr=DEVNULL).returncode != 0:
                    aurman_error("Directory {} could not be deleted"
                                 "".format(
                                     Colors.BOLD(
                                         Colors.LIGHT_MAGENTA(
                                             Package.cache_dir))))
                    sys.exit(1)
        else:
            if noconfirm or \
                    ask_user("Do you want to remove {} clones from cache?"
                             "".format(Colors.BOLD(Colors.LIGHT_MAGENTA("all uninstalled"))), False):
                aurman_status("Deleting uninstalled clones from cache...")

                # if pkgbase not available, the name of the package is the base
                expac_returns = expac("-Q -1", ("e", "n"), ())
                dirs_to_not_delete = set()
                for expac_return in expac_returns:
                    pkgbase = expac_return.split("?!")[0]
                    if pkgbase == "(null)":
                        dirs_to_not_delete.add(expac_return.split("?!")[1])
                    else:
                        dirs_to_not_delete.add(pkgbase)

                for thing in os.listdir(Package.cache_dir):
                    if os.path.isdir(os.path.join(Package.cache_dir, thing)):
                        if thing not in dirs_to_not_delete:
                            dir_to_delete = os.path.join(
                                Package.cache_dir, thing)
                            if run("rm -rf {}".format(dir_to_delete),
                                   shell=True,
                                   stdout=DEVNULL,
                                   stderr=DEVNULL).returncode != 0:
                                aurman_error(
                                    "Directory {} could not be deleted"
                                    "".format(
                                        Colors.BOLD(
                                            Colors.LIGHT_MAGENTA(
                                                dir_to_delete))))
                                sys.exit(1)

            if not noconfirm and \
                    ask_user("Do you want to remove {} from cache? ({})"
                             "".format(Colors.BOLD(Colors.LIGHT_MAGENTA("all untracked git files")),
                                       Colors.BOLD(Colors.LIGHT_MAGENTA("even from installed packages"))), False):
                aurman_status("Deleting untracked git files from cache...")
                for thing in os.listdir(Package.cache_dir):
                    if os.path.isdir(os.path.join(Package.cache_dir, thing)):
                        dir_to_clean = os.path.join(Package.cache_dir, thing)
                        if run("git clean -ffdx"
                               "",
                               shell=True,
                               stdout=DEVNULL,
                               stderr=DEVNULL,
                               cwd=dir_to_clean).returncode != 0:
                            aurman_error(
                                "Directory {} could not be cleaned"
                                "".format(
                                    Colors.BOLD(
                                        Colors.LIGHT_MAGENTA(dir_to_clean))))
                            sys.exit(1)

    sys.exit(0)
Example #8
0
def process(args):
    import aurman.aur_utilities

    try:
        read_config()  # read config - available via AurmanConfig.aurman_config
    except InvalidInput:
        sys.exit(1)

    if os.getuid() == 0:
        aurman_error("Do not run aurman with sudo")
        sys.exit(1)

    # parse parameters of user
    pacman_args = parse_pacman_args(args)

    if pacman_args.operation is not PacmanOperations.SYNC or pacman_args.invalid_args:
        sys.exit(1)

    # -S or --sync
    Package.optimistic_versioning = pacman_args.optimistic_versioning  # if --optimistic_versioning
    packages_of_user_names = list(set(pacman_args.targets))  # targets of the aurman command without duplicates
    sysupgrade = pacman_args.sysupgrade  # if -u or --sysupgrade
    sysupgrade_force = sysupgrade and not isinstance(sysupgrade, bool)  # if -u -u or --sysupgrade --sysupgrade
    no_notification_unknown_packages = 'miscellaneous' in AurmanConfig.aurman_config \
                                       and 'no_notification_unknown_packages' in AurmanConfig.aurman_config[
                                           'miscellaneous']
    concrete_no_notification_packages = set()
    if 'no_notification_unknown_packages' in AurmanConfig.aurman_config:
        for package_name in AurmanConfig.aurman_config['no_notification_unknown_packages']:
            concrete_no_notification_packages.add(package_name)

    # nothing to do for us
    if not sysupgrade and not packages_of_user_names:
        sys.exit(1)

    needed = pacman_args.needed  # if --needed
    devel = pacman_args.devel  # if --devel
    only_unfulfilled_deps = not pacman_args.deep_search  # if not --deep_search

    not_remove = pacman_args.holdpkg  # list containing the specified packages for --holdpkg
    # if --holdpkg_conf append holdpkg from pacman.conf
    if pacman_args.holdpkg_conf:
        not_remove.extend(pacman_conf("HoldPkg"))
    # remove duplicates
    not_remove = list(set(not_remove))

    aur = pacman_args.aur  # do only aur things
    repo = pacman_args.repo  # do only repo things
    if repo and aur:
        aurman_error("--repo and --aur is not what you want")
        sys.exit(1)

    if pacman_args.domain:
        aurman.aur_utilities.aur_domain = pacman_args.domain[0]

    # analyzing installed packages
    try:
        installed_system = System(System.get_installed_packages())
    except InvalidInput:
        sys.exit(1)

    packages_to_show = [package for package in installed_system.not_repo_not_aur_packages_list
                        if package.name not in concrete_no_notification_packages]
    if packages_to_show and not no_notification_unknown_packages:
        if not pacman_args.show_unknown:
            logging.debug("the following packages are neither in known repos nor in the aur")
            for package in packages_to_show:
                logging.debug("{}".format(Colors.BOLD(Colors.LIGHT_MAGENTA(package))))
        else:
            print("\n".join([package.name for package in packages_to_show]))

    if pacman_args.show_unknown:
        sys.exit(0)

    # fetching upstream repo packages...
    try:
        upstream_system = System(System.get_repo_packages())
    except InvalidInput:
        sys.exit(1)

    # fetching needed aur packages
    if not repo:
        upstream_system.append_packages_by_name(packages_of_user_names)
        # fetch info for all installed aur packages, too
        names_of_installed_aur_packages = [package.name for package in installed_system.aur_packages_list]
        names_of_installed_aur_packages.extend([package.name for package in installed_system.devel_packages_list])
        upstream_system.append_packages_by_name(names_of_installed_aur_packages)

    # remove known repo packages in case of --aur
    if aur:
        for package in upstream_system.repo_packages_list:
            del upstream_system.all_packages_dict[package.name]
        upstream_system = System(list(upstream_system.all_packages_dict.values()))

    # sanitize user input
    sanitized_names = sanitize_user_input(packages_of_user_names, upstream_system)
    sanitized_not_to_be_removed = sanitize_user_input(not_remove, installed_system)

    # names to not be removed must be also known on the upstream system,
    # otherwise aurman solving cannot handle this case.
    for name in sanitized_not_to_be_removed:
        if name not in upstream_system.all_packages_dict:
            aurman_error("Packages you want to be not removed must be aur or repo packages.\n"
                         "   {} is not known.".format(Colors.BOLD(Colors.LIGHT_MAGENTA(name))))
            sys.exit(1)

    # for dep solving not to be removed has to be treated as wanted to install
    sanitized_names |= sanitized_not_to_be_removed

    # fetching ignored packages
    ignored_packages_names = Package.get_ignored_packages_names(pacman_args.ignore, pacman_args.ignoregroup,
                                                                upstream_system)
    # explicitly typed in names will not be ignored
    ignored_packages_names -= sanitized_names
    for ignored_packages_name in ignored_packages_names:
        if ignored_packages_name in upstream_system.all_packages_dict:
            if ignored_packages_name in installed_system.all_packages_dict:
                logging.debug("{} {} package {}".format(Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                                                        Colors.BOLD(Colors.LIGHT_CYAN("installed")),
                                                        Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                upstream_system.all_packages_dict[ignored_packages_name] = installed_system.all_packages_dict[
                    ignored_packages_name]
            else:
                logging.debug("{} {} package {}".format(Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                                                        Colors.BOLD(Colors.LIGHT_BLUE("upstream ")),
                                                        Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                del upstream_system.all_packages_dict[ignored_packages_name]

    # recreating upstream system
    if ignored_packages_names:
        upstream_system = System(list(upstream_system.all_packages_dict.values()))

    # if user entered --devel and not --repo, fetch all current versions of devel packages
    if devel and not repo:
        for package in upstream_system.devel_packages_list:
            package_dir = os.path.join(Package.cache_dir, package.pkgbase)
            if not os.path.isdir(package_dir):
                aurman_error("Package dir of {} not found".format(Colors.BOLD(Colors.LIGHT_MAGENTA(package.name))))
                sys.exit(1)
            makepkg("-odc --noprepare --skipinteg", True, package_dir)

            package.version = package.version_from_srcinfo()

    # checking which packages need to be installed
    if not needed:
        concrete_packages_to_install = [upstream_system.all_packages_dict[name] for name in sanitized_names]
    else:
        possible_packages = [upstream_system.all_packages_dict[name] for name in sanitized_names]
        concrete_packages_to_install = []
        for package in possible_packages:
            if package.name in installed_system.all_packages_dict:
                installed_package = installed_system.all_packages_dict[package.name]
                if not version_comparison(installed_package.version, "=", package.version):
                    concrete_packages_to_install.append(package)
            else:
                concrete_packages_to_install.append(package)

    # in case of sysupgrade fetch all installed packages, of which newer versions are available
    if sysupgrade:
        installed_packages = []
        if not repo:
            installed_packages.extend([package for package in installed_system.aur_packages_list])
            installed_packages.extend([package for package in installed_system.devel_packages_list])
        if not aur:
            installed_packages.extend([package for package in installed_system.repo_packages_list])
        for package in installed_packages:
            # must not be that we have not received the upstream information
            assert package.name in upstream_system.all_packages_dict
            upstream_package = upstream_system.all_packages_dict[package.name]
            # normal sysupgrade
            if not sysupgrade_force:
                if version_comparison(upstream_package.version, ">", package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)
            # sysupgrade with downgrades
            else:
                if not version_comparison(upstream_package.version, "=", package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)

    # calc solutions
    if only_unfulfilled_deps:
        solutions = Package.dep_solving(concrete_packages_to_install, installed_system, upstream_system)
    else:
        solutions = Package.dep_solving(concrete_packages_to_install, System(()), upstream_system)

    # fetch valid solutions
    sol_tuples = installed_system.validate_solutions(solutions, concrete_packages_to_install)
    valid_solutions = [sol_tuple[1] for sol_tuple in sol_tuples]
    if not valid_solutions:
        aurman_error("we could not find a solution")
        aurman_error("if you think that there should be one, rerun aurman with the --deep_search flag")
        sys.exit(1)

    print(json.dumps(
        [valid_solutions, installed_system.differences_between_systems([sol_tuple[0] for sol_tuple in sol_tuples])],
        cls=SolutionEncoder, indent=4))
Example #9
0
def process(args):
    import aurman.aur_utilities

    try:
        read_config()  # read config - available via AurmanConfig.aurman_config
    except InvalidInput:
        sys.exit(1)

    if os.getuid() == 0:
        aurman_error("Do not run aurman with sudo")
        sys.exit(1)

    # parse parameters of user
    try:
        pacman_args = parse_pacman_args(args)
    except InvalidInput:
        aurman_note("aurman --help or aurman -h")
        sys.exit(1)

    # show help
    if pacman_args.operation is PacmanOperations.HELP:
        # remove colors in case of not terminal
        if stdout.isatty():
            print(aurman_help)
        else:
            print(Colors.strip_colors(str(aurman_help)))
        sys.exit(0)

    # show version
    if pacman_args.operation is PacmanOperations.VERSION:
        # remove colors in case of not terminal
        if stdout.isatty():
            aurman_note(expac("-Q", ("v", ), ("aurman-git", "aurman"))[0])
        else:
            print(expac("-Q", ("v", ), ("aurman-git", "aurman"))[0])
        sys.exit(0)

    # if not -S or --sync, just redirect to pacman
    if pacman_args.operation is not PacmanOperations.SYNC:
        try:
            if pacman_args.operation in [
                    PacmanOperations.UPGRADE, PacmanOperations.REMOVE,
                    PacmanOperations.DATABASE
            ]:
                run("sudo pacman {}".format(" ".join(
                    ["'{}'".format(arg) for arg in args])),
                    shell=True)
            else:
                run("pacman {}".format(" ".join(
                    ["'{}'".format(arg) for arg in args])),
                    shell=True)
        except InvalidInput:
            sys.exit(1)

        sys.exit(0)

    # -S or --sync
    Package.optimistic_versioning = pacman_args.optimistic_versioning  # if --optimistic_versioning
    packages_of_user_names = list(
        set(pacman_args.targets
            ))  # targets of the aurman command without duplicates
    sysupgrade = pacman_args.sysupgrade  # if -u or --sysupgrade
    sysupgrade_force = sysupgrade and not isinstance(
        sysupgrade, bool)  # if -u -u or --sysupgrade --sysupgrade
    needed = pacman_args.needed  # if --needed
    noedit = pacman_args.noedit  # if --noedit
    always_edit = pacman_args.always_edit  # if --always_edit
    show_changes = pacman_args.show_changes  # if --show_changes
    devel = pacman_args.devel  # if --devel
    only_unfulfilled_deps = not pacman_args.deep_search  # if not --deep_search
    pgp_fetch = pacman_args.pgp_fetch  # if --pgp_fetch
    noconfirm = pacman_args.noconfirm  # if --noconfirm
    search = pacman_args.search  # list containing the specified strings for -s and --search
    solution_way = pacman_args.solution_way  # if --solution_way
    do_everything = pacman_args.do_everything  # if --do_everything
    clean = pacman_args.clean  # if --clean
    clean_force = clean and not isinstance(clean, bool)  # if --clean --clean
    no_notification_unknown_packages = 'miscellaneous' in AurmanConfig.aurman_config \
                                       and 'no_notification_unknown_packages' in AurmanConfig.aurman_config[
                                           'miscellaneous']
    concrete_no_notification_packages = set()
    if 'no_notification_unknown_packages' in AurmanConfig.aurman_config:
        for package_name in AurmanConfig.aurman_config[
                'no_notification_unknown_packages']:
            concrete_no_notification_packages.add(package_name)

    sudo_acquired = 'miscellaneous' in AurmanConfig.aurman_config \
                    and 'no_sudo_loop' in AurmanConfig.aurman_config['miscellaneous']
    pacman_called = False

    not_remove = pacman_args.holdpkg  # list containing the specified packages for --holdpkg
    # if --holdpkg_conf append holdpkg from pacman.conf
    if pacman_args.holdpkg_conf:
        not_remove.extend(
            PacmanConfig(conf="/etc/pacman.conf").options['HoldPkg'])
    # remove duplicates
    not_remove = list(set(not_remove))

    if noedit and show_changes:
        aurman_error("--noedit and --show_changes is not what you want")
        sys.exit(1)

    if noedit and always_edit:
        aurman_error("--noedit and --always_edit is not what you want")
        sys.exit(1)

    aur = pacman_args.aur  # do only aur things
    repo = pacman_args.repo  # do only repo things
    if repo and aur:
        aurman_error("--repo and --aur is not what you want")
        sys.exit(1)

    if pacman_args.keyserver:
        keyserver = pacman_args.keyserver[0]
    else:
        keyserver = None

    if keyserver is None \
            and 'miscellaneous' in AurmanConfig.aurman_config \
            and 'keyserver' in AurmanConfig.aurman_config['miscellaneous']:
        keyserver = AurmanConfig.aurman_config['miscellaneous']['keyserver']

    if pacman_args.domain:
        aurman.aur_utilities.aur_domain = pacman_args.domain[0]

    # do not allow -y without -u
    if pacman_args.refresh and not sysupgrade:
        aurman_error("-y without -u is not allowed!")
        sys.exit(1)

    # unrecognized parameters
    if pacman_args.invalid_args:
        aurman_error(
            "The following parameters are not recognized yet: {}".format(
                pacman_args.invalid_args))
        aurman_note("aurman --help or aurman -h")
        sys.exit(1)

    # if user wants to --clean
    if clean:
        if not aur:
            pacman(str(pacman_args), False, sudo=True)

        if not repo:
            if not os.path.isdir(Package.cache_dir):
                aurman_error("Cache directory {} not found."
                             "".format(
                                 Colors.BOLD(
                                     Colors.LIGHT_MAGENTA(Package.cache_dir))))
                sys.exit(1)

            aurman_note("Cache directory: {}".format(
                Colors.BOLD(Colors.LIGHT_MAGENTA(Package.cache_dir))))

            if clean_force:
                if noconfirm or \
                        ask_user("Do you want to remove {} from cache?"
                                 "".format(Colors.BOLD(Colors.LIGHT_MAGENTA("all files"))), False):
                    aurman_status("Deleting cache dir...")
                    if run("rm -rf {}".format(Package.cache_dir),
                           shell=True,
                           stdout=DEVNULL,
                           stderr=DEVNULL).returncode != 0:
                        aurman_error("Directory {} could not be deleted"
                                     "".format(
                                         Colors.BOLD(
                                             Colors.LIGHT_MAGENTA(
                                                 Package.cache_dir))))
                        sys.exit(1)
            else:
                if noconfirm or \
                        ask_user("Do you want to remove {} clones from cache?"
                                 "".format(Colors.BOLD(Colors.LIGHT_MAGENTA("all uninstalled"))), False):
                    aurman_status("Deleting uninstalled clones from cache...")

                    # if pkgbase not available, the name of the package is the base
                    expac_returns = expac("-Q -1", ("e", "n"), ())
                    dirs_to_not_delete = set()
                    for expac_return in expac_returns:
                        pkgbase = expac_return.split("?!")[0]
                        if pkgbase == "(null)":
                            dirs_to_not_delete.add(expac_return.split("?!")[1])
                        else:
                            dirs_to_not_delete.add(pkgbase)

                    for thing in os.listdir(Package.cache_dir):
                        if os.path.isdir(os.path.join(Package.cache_dir,
                                                      thing)):
                            if thing not in dirs_to_not_delete:
                                dir_to_delete = os.path.join(
                                    Package.cache_dir, thing)
                                if run("rm -rf {}".format(dir_to_delete),
                                       shell=True,
                                       stdout=DEVNULL,
                                       stderr=DEVNULL).returncode != 0:
                                    aurman_error(
                                        "Directory {} could not be deleted"
                                        "".format(
                                            Colors.BOLD(
                                                Colors.LIGHT_MAGENTA(
                                                    dir_to_delete))))
                                    sys.exit(1)

                if not noconfirm and \
                        ask_user("Do you want to remove {} from cache? ({})"
                                 "".format(Colors.BOLD(Colors.LIGHT_MAGENTA("all untracked git files")),
                                           Colors.BOLD(Colors.LIGHT_MAGENTA("even from installed packages"))), False):
                    aurman_status("Deleting untracked git files from cache...")
                    for thing in os.listdir(Package.cache_dir):
                        if os.path.isdir(os.path.join(Package.cache_dir,
                                                      thing)):
                            dir_to_clean = os.path.join(
                                Package.cache_dir, thing)
                            if run("git clean -ffdx"
                                   "",
                                   shell=True,
                                   stdout=DEVNULL,
                                   stderr=DEVNULL,
                                   cwd=dir_to_clean).returncode != 0:
                                aurman_error(
                                    "Directory {} could not be cleaned"
                                    "".format(
                                        Colors.BOLD(
                                            Colors.LIGHT_MAGENTA(
                                                dir_to_clean))))
                                sys.exit(1)

        sys.exit(0)

    # if user just wants to search
    if search:
        # we only need the installed system for aur queries
        if not repo:
            try:
                installed_system = System(System.get_installed_packages())
            except InvalidInput:
                sys.exit(1)
        else:
            installed_system = None

        # start search
        try:
            search_and_print(search, installed_system, str(pacman_args), repo,
                             aur)
        except InvalidInput:
            sys.exit(1)

        sys.exit(0)

    # groups are for pacman
    groups_chosen = []
    if not aur:
        groups = pacman("-Sg", True, sudo=False)
        for name in packages_of_user_names[:]:
            if name in groups:
                groups_chosen.append(name)
                packages_of_user_names.remove(name)

    # pacman call in the beginning of the routine
    if not aur \
            and (sysupgrade and (not do_everything or pacman_args.refresh) or groups_chosen):
        if not sudo_acquired:
            acquire_sudo()
            sudo_acquired = True
        pacman_called = True
        pacman_args_copy = deepcopy(pacman_args)
        pacman_args_copy.targets = groups_chosen
        # aurman handles the update
        if do_everything:
            pacman_args_copy.sysupgrade = False
        # ignore packages from other sources for sysupgrade
        try:
            packages_from_other_sources_ret = packages_from_other_sources()
        except InvalidInput:
            sys.exit(1)
        names_to_ignore = packages_from_other_sources_ret[0]
        for name_to_ignore in packages_from_other_sources_ret[1]:
            names_to_ignore.add(name_to_ignore)
        for already_ignored in pacman_args_copy.ignore:
            names_to_ignore |= set(already_ignored.split(","))
        if names_to_ignore:
            pacman_args_copy.ignore = [",".join(names_to_ignore)]
        try:
            pacman(str(pacman_args_copy), False)
        except InvalidInput:
            sys.exit(1)

    # nothing to do for us
    if not sysupgrade and not packages_of_user_names:
        sys.exit(0)

    # delete -u --sysupgrade -y --refresh from parsed args
    # not needed anymore
    pacman_args.sysupgrade = False
    pacman_args.refresh = False

    # one status message
    if pacman_called:
        aurman_status("initializing {}...".format(Colors.BOLD("aurman")), True)
    else:
        aurman_status("initializing {}...".format(Colors.BOLD("aurman")),
                      False)

    # analyzing installed packages
    try:
        installed_system = System(System.get_installed_packages())
    except InvalidInput:
        sys.exit(1)

    packages_to_show = [
        package for package in installed_system.not_repo_not_aur_packages_list
        if package.name not in concrete_no_notification_packages
    ]
    if packages_to_show and not no_notification_unknown_packages:
        aurman_status(
            "the following packages are neither in known repos nor in the aur")
        for package in packages_to_show:
            aurman_note("{}".format(Colors.BOLD(
                Colors.LIGHT_MAGENTA(package))))

    # fetching upstream repo packages...
    try:
        upstream_system = System(System.get_repo_packages())
    except InvalidInput:
        sys.exit(1)

    # fetching needed aur packages
    if not repo:
        upstream_system.append_packages_by_name(packages_of_user_names)
        # fetch info for all installed aur packages, too
        names_of_installed_aur_packages = [
            package.name for package in installed_system.aur_packages_list
        ]
        names_of_installed_aur_packages.extend(
            [package.name for package in installed_system.devel_packages_list])
        upstream_system.append_packages_by_name(
            names_of_installed_aur_packages)

    # remove known repo packages in case of --aur
    if aur:
        for package in upstream_system.repo_packages_list:
            del upstream_system.all_packages_dict[package.name]
        upstream_system = System(
            list(upstream_system.all_packages_dict.values()))

    # sanitize user input
    try:
        sanitized_names = upstream_system.sanitize_user_input(
            packages_of_user_names)
        sanitized_not_to_be_removed = installed_system.sanitize_user_input(
            not_remove)
    except InvalidInput:
        sys.exit(1)

    # names to not be removed must be also known on the upstream system,
    # otherwise aurman solving cannot handle this case.
    for name in sanitized_not_to_be_removed:
        if name not in upstream_system.all_packages_dict:
            aurman_error(
                "Packages you want to be not removed must be aur or repo packages.\n"
                "   {} is not known.".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA(name))))
            sys.exit(1)

    # for dep solving not to be removed has to be treated as wanted to install
    sanitized_names |= sanitized_not_to_be_removed

    # fetching ignored packages
    ignored_packages_names = Package.get_ignored_packages_names(
        pacman_args.ignore, pacman_args.ignoregroup, upstream_system)
    # explicitly typed in names will not be ignored
    ignored_packages_names -= sanitized_names
    for ignored_packages_name in ignored_packages_names:
        if ignored_packages_name in upstream_system.all_packages_dict:
            if ignored_packages_name in installed_system.all_packages_dict:
                aurman_note("{} {} package {}".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                    Colors.BOLD(Colors.LIGHT_CYAN("installed")),
                    Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                upstream_system.all_packages_dict[
                    ignored_packages_name] = installed_system.all_packages_dict[
                        ignored_packages_name]
            else:
                aurman_note("{} {} package {}".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                    Colors.BOLD(Colors.LIGHT_BLUE("upstream ")),
                    Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                del upstream_system.all_packages_dict[ignored_packages_name]

    # recreating upstream system
    if ignored_packages_names:
        upstream_system = System(
            list(upstream_system.all_packages_dict.values()))

    # if user entered --devel and not --repo, fetch all needed pkgbuilds etc. for the devel packages
    if devel and not repo:
        aurman_status(
            "looking for new pkgbuilds of devel packages and fetch them...")
        for package in upstream_system.devel_packages_list:
            package.fetch_pkgbuild()
        try:
            for package in upstream_system.devel_packages_list:
                package.show_pkgbuild(noedit, show_changes, pgp_fetch,
                                      keyserver, always_edit)
        except InvalidInput:
            sys.exit(1)
        for package in upstream_system.devel_packages_list:
            package.get_devel_version()

    # checking which packages need to be installed
    if not needed:
        concrete_packages_to_install = [
            upstream_system.all_packages_dict[name] for name in sanitized_names
        ]
    else:
        possible_packages = [
            upstream_system.all_packages_dict[name] for name in sanitized_names
        ]
        concrete_packages_to_install = []
        for package in possible_packages:
            if package.name in installed_system.all_packages_dict:
                installed_package = installed_system.all_packages_dict[
                    package.name]
                if not version_comparison(installed_package.version, "=",
                                          package.version):
                    concrete_packages_to_install.append(package)
            else:
                concrete_packages_to_install.append(package)

    # in case of sysupgrade fetch all installed packages, of which newer versions are available
    if sysupgrade:
        installed_packages = []
        if not repo:
            installed_packages.extend(
                [package for package in installed_system.aur_packages_list])
            installed_packages.extend(
                [package for package in installed_system.devel_packages_list])
        if not aur:
            installed_packages.extend(
                [package for package in installed_system.repo_packages_list])
        for package in installed_packages:
            # must not be that we have not received the upstream information
            assert package.name in upstream_system.all_packages_dict
            upstream_package = upstream_system.all_packages_dict[package.name]
            # normal sysupgrade
            if not sysupgrade_force:
                if version_comparison(upstream_package.version, ">",
                                      package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)
            # sysupgrade with downgrades
            else:
                if not version_comparison(upstream_package.version, "=",
                                          package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)

    aurman_status("calculating solutions...")
    if only_unfulfilled_deps:
        solutions = Package.dep_solving(concrete_packages_to_install,
                                        installed_system, upstream_system)
    else:
        solutions = Package.dep_solving(concrete_packages_to_install, System(
            ()), upstream_system)

    # validates the found solutions and lets the user choose one of them, if there are more than one valid solutions
    try:
        chosen_solution = installed_system.validate_and_choose_solution(
            solutions, concrete_packages_to_install)
    except InvalidInput:
        aurman_error("we could not find a solution")
        aurman_error(
            "if you think that there should be one, rerun aurman with the --deep_search flag"
        )
        sys.exit(1)

    # needed because deep_search ignores installed packages
    if not only_unfulfilled_deps:
        pacman_args.needed = True

    # solution contains no packages
    if not chosen_solution:
        aurman_note("nothing to do... everything is up to date")
        sys.exit(0)

    try:
        installed_system.show_solution_differences_to_user(
            chosen_solution, upstream_system, noconfirm,
            not only_unfulfilled_deps, solution_way)
    except InvalidInput:
        sys.exit(1)

    if not repo:
        aurman_status("looking for new pkgbuilds and fetch them...")
        for package in chosen_solution:
            if package.type_of is PossibleTypes.REPO_PACKAGE \
                    or devel and package.type_of is PossibleTypes.DEVEL_PACKAGE:
                continue
            package.fetch_pkgbuild()
        try:
            for package in chosen_solution:
                if package.type_of is PossibleTypes.REPO_PACKAGE \
                        or devel and package.type_of is PossibleTypes.DEVEL_PACKAGE:
                    continue
                package.show_pkgbuild(noedit, show_changes, pgp_fetch,
                                      keyserver, always_edit)
        except InvalidInput:
            sys.exit(1)

    # install packages
    if not sudo_acquired:
        acquire_sudo()
        sudo_acquired = True

    # repo packages to install from other sources
    repo_packages_dict = packages_from_other_sources()[1]

    # generate pacman args for the aur packages
    pacman_args_copy = deepcopy(pacman_args)
    pacman_args_copy.operation = PacmanOperations.UPGRADE
    pacman_args_copy.targets = []

    args_for_explicit = str(pacman_args_copy)
    pacman_args_copy.asdeps = True
    pacman_args_copy.asexplicit = False
    args_for_dependency = str(pacman_args_copy)

    # calc chunks to install
    solution_packages_chunks = System.calc_install_chunks(chosen_solution)

    # install the chunks
    for package_chunk in solution_packages_chunks:
        # repo chunk
        if package_chunk[0].type_of is PossibleTypes.REPO_PACKAGE:
            # container for explicit repo deps
            as_explicit_container = set()
            for package in package_chunk:
                if package.name in sanitized_names and package.name not in sanitized_not_to_be_removed \
                        or ((package.name in installed_system.all_packages_dict)
                            and (installed_system.all_packages_dict[package.name].install_reason == 'explicit')):
                    as_explicit_container.add(package.name)

            pacman_args_copy = deepcopy(pacman_args)
            pacman_args_copy.targets = [
                package.name for package in package_chunk
                if package.name not in repo_packages_dict
            ]

            pacman_args_copy.targets.extend([
                "{}/".format(repo_packages_dict[package.name]) + package.name
                for package in package_chunk
                if package.name in repo_packages_dict
            ])
            pacman_args_copy.asdeps = True
            pacman_args_copy.asexplicit = False
            try:
                pacman(str(pacman_args_copy), False)
            except InvalidInput:
                sys.exit(1)

            if as_explicit_container:
                pacman("-D --asexplicit {}".format(
                    " ".join(as_explicit_container)),
                       True,
                       sudo=True)
        # aur chunks always consist of one package
        else:
            package = package_chunk[0]
            try:
                package.build()
                if package.name in sanitized_names and package.name not in sanitized_not_to_be_removed \
                        or ((package.name in installed_system.all_packages_dict)
                            and (installed_system.all_packages_dict[package.name].install_reason == 'explicit')):
                    package.install(args_for_explicit)
                else:
                    package.install(args_for_dependency)
            except InvalidInput:
                sys.exit(1)
Example #10
0
 def __repr__(self):
     return "{}\n{}".format(
         Colors.BOLD(self.head),
         ''.join(["\n    {}".format(child) for child in self.children]))
Example #11
0

# aurman help
aurman_help = Help([])

# usage
usage_title = "Usage"
usage = "aurman <operation> [options] [targets]\n    see also https://www.archlinux.org/pacman/pacman.8.html"
aurman_help.points.append(HelpPoint(usage_title, (usage, )))

# description
description_title = "Description"
description = "aurman is meant as a {}. " \
              "All pacman operations are supported,\n    " \
              "but calling aurman with an operation besides " \
              "{} or {} will {}.".format(Colors.BOLD("pacman wrapper"),
                                         Colors.BOLD(Colors.LIGHT_GREEN("--sync")),
                                         Colors.BOLD(Colors.LIGHT_GREEN("-S")),
                                         Colors.BOLD("just pass the arguments to pacman"))
aurman_help.points.append(HelpPoint(description_title, (description, )))

# native pacman options
native = "the following native pacman options for " \
         "{} or {} will be forwarded to pacman".format(Colors.LIGHT_GREEN("--sync"), Colors.LIGHT_GREEN("-S"))
native_points = []
aurman_help.points.append(HelpPoint(native, native_points))

native_points.append(
    HelpOption([
        "-r", "--root"
    ], "Specify an alternative database location (a typical default is /var/lib/pacman)"
Example #12
0
def process(args):
    try:
        read_config()  # read config - available via AurmanConfig.aurman_config
    except InvalidInput:
        sys.exit(1)

    if os.getuid() == 0:
        aurman_error("Do not run aurman with sudo")
        sys.exit(1)

    # parse parameters of user
    pacman_args = parse_parameters(args)

    if pacman_args.operation is PacmanOperations.HELP:
        show_help()

    if pacman_args.operation is not PacmanOperations.SYNC or pacman_args.invalid_args:
        sys.exit(1)

    # -S or --sync
    Package.optimistic_versioning = pacman_args.optimistic_versioning \
                                    or 'miscellaneous' in AurmanConfig.aurman_config \
                                    and 'optimistic_versioning' \
                                    in AurmanConfig.aurman_config['miscellaneous']  # if --optimistic_versioning
    Package.ignore_versioning = pacman_args.ignore_versioning \
                                or 'miscellaneous' in AurmanConfig.aurman_config \
                                and 'ignore_versioning' \
                                in AurmanConfig.aurman_config['miscellaneous']  # if --ignore_versioning
    packages_of_user_names = list(
        set(pacman_args.targets
            ))  # targets of the aurman command without duplicates
    sysupgrade = pacman_args.sysupgrade  # if -u or --sysupgrade
    sysupgrade_force = sysupgrade and not isinstance(
        sysupgrade, bool)  # if -u -u or --sysupgrade --sysupgrade

    # packages to not notify about being unknown in either repos or the aur
    # global
    no_notification_unknown_packages = 'miscellaneous' in AurmanConfig.aurman_config and \
                                       'no_notification_unknown_packages' in AurmanConfig.aurman_config['miscellaneous']
    # single packages
    if 'no_notification_unknown_packages' in AurmanConfig.aurman_config:
        concrete_no_notification_packages = set([
            package_name for package_name in
            AurmanConfig.aurman_config['no_notification_unknown_packages']
        ])
    else:
        concrete_no_notification_packages = set()

    # nothing to do for us
    if not sysupgrade and not packages_of_user_names:
        sys.exit(1)

    needed = pacman_args.needed  # if --needed
    devel = pacman_args.devel  # if --devel
    only_unfulfilled_deps = not pacman_args.deep_search  # if not --deep_search

    not_remove = pacman_args.holdpkg  # list containing the specified packages for --holdpkg
    # if --holdpkg_conf append holdpkg from pacman.conf
    if pacman_args.holdpkg_conf:
        not_remove.extend(
            PacmanConfig(conf="/etc/pacman.conf").options['HoldPkg'])
    # remove duplicates
    not_remove = list(set(not_remove))

    aur = pacman_args.aur  # do only aur things
    repo = pacman_args.repo  # do only repo things
    rebuild = pacman_args.rebuild  # if --rebuild
    # if to pass -A to makepkg
    ignore_arch = 'miscellaneous' in AurmanConfig.aurman_config and \
                  'ignore_arch' in AurmanConfig.aurman_config['miscellaneous']

    if repo and aur:
        aurman_error("--repo and --aur is not what you want")
        sys.exit(1)

    if pacman_args.domain:
        AurVars.aur_domain = pacman_args.domain[0]

    # change aur rpc timeout if set by the user
    if 'miscellaneous' in AurmanConfig.aurman_config \
            and 'aur_timeout' in AurmanConfig.aurman_config['miscellaneous']:
        AurVars.aur_timeout = int(
            AurmanConfig.aurman_config['miscellaneous']['aur_timeout'])

    # analyzing installed packages
    try:
        installed_system = System(System.get_installed_packages())
    except InvalidInput:
        sys.exit(1)

    # print unknown packages for the user
    packages_not_show_names = set()
    not_repo_not_aur_packages_names = [
        package.name
        for package in installed_system.not_repo_not_aur_packages_list
    ]
    for possible_glob in concrete_no_notification_packages:
        packages_not_show_names |= set(
            fnmatch.filter(not_repo_not_aur_packages_names, possible_glob))

    packages_to_show = [
        package for package in installed_system.not_repo_not_aur_packages_list
        if package.name not in packages_not_show_names
    ]

    if packages_to_show and not no_notification_unknown_packages:
        if not pacman_args.show_unknown:
            logging.debug(
                "the following packages are neither in known repos nor in the aur"
            )
            for package in packages_to_show:
                logging.debug("{}".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA(package))))
        else:
            print("\n".join([package.name for package in packages_to_show]))

    if pacman_args.show_unknown:
        sys.exit(0)

    # fetching upstream repo packages...
    try:
        upstream_system = System(System.get_repo_packages())
    except InvalidInput:
        sys.exit(1)

    # fetching needed aur packages
    if not repo:
        upstream_system.append_packages_by_name(packages_of_user_names)
        # fetch info for all installed aur packages, too
        names_of_installed_aur_packages = [
            package.name for package in installed_system.aur_packages_list
        ]
        names_of_installed_aur_packages.extend(
            [package.name for package in installed_system.devel_packages_list])
        upstream_system.append_packages_by_name(
            names_of_installed_aur_packages)

    # remove known repo packages in case of --aur
    if aur:
        for package in upstream_system.repo_packages_list:
            del upstream_system.all_packages_dict[package.name]
        upstream_system = System(
            list(upstream_system.all_packages_dict.values()))

    # sanitize user input
    sanitized_names = sanitize_user_input(packages_of_user_names,
                                          upstream_system)
    sanitized_not_to_be_removed = sanitize_user_input(not_remove,
                                                      installed_system)

    # names to not be removed must be also known on the upstream system,
    # otherwise aurman solving cannot handle this case.
    for name in sanitized_not_to_be_removed:
        if name not in upstream_system.all_packages_dict:
            aurman_error(
                "Packages you want to be not removed must be aur or repo packages.\n"
                "   {} is not known.".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA(name))))
            sys.exit(1)

    # for dep solving not to be removed has to be treated as wanted to install
    sanitized_names |= sanitized_not_to_be_removed

    # fetching ignored packages
    ignored_packages_names = Package.get_ignored_packages_names(
        pacman_args.ignore, pacman_args.ignoregroup, upstream_system,
        installed_system, True)
    # explicitly typed in names will not be ignored
    ignored_packages_names -= sanitized_names
    for ignored_packages_name in ignored_packages_names:
        if ignored_packages_name in upstream_system.all_packages_dict:
            if ignored_packages_name in installed_system.all_packages_dict:
                logging.debug("{} {} package {}".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                    Colors.BOLD(Colors.LIGHT_CYAN("installed")),
                    Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                upstream_system.all_packages_dict[
                    ignored_packages_name] = installed_system.all_packages_dict[
                        ignored_packages_name]
            else:
                logging.debug("{} {} package {}".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                    Colors.BOLD(Colors.LIGHT_BLUE("upstream ")),
                    Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

                del upstream_system.all_packages_dict[ignored_packages_name]
        elif ignored_packages_name in installed_system.all_packages_dict:
            logging.debug("{} {} package {}".format(
                Colors.BOLD(Colors.LIGHT_MAGENTA("Ignoring")),
                Colors.BOLD(Colors.LIGHT_CYAN("installed")),
                Colors.BOLD(Colors.LIGHT_MAGENTA(ignored_packages_name))))

    # recreating upstream system
    if ignored_packages_names:
        upstream_system = System(
            list(upstream_system.all_packages_dict.values()))

    # if user entered --devel and not --repo, fetch all current versions of devel packages
    if devel and not repo:
        for package in upstream_system.devel_packages_list:
            package_dir = os.path.join(Package.cache_dir, package.pkgbase)
            if not os.path.isdir(package_dir):
                aurman_error("Package dir of {} not found".format(
                    Colors.BOLD(Colors.LIGHT_MAGENTA(package.name))))
                sys.exit(1)
            if not ignore_arch:
                makepkg(["-odc"], True, package_dir)
            else:
                makepkg(["-odcA"], True, package_dir)

            package.version = package.version_from_srcinfo()

    # checking which packages need to be installed
    if not needed:
        concrete_packages_to_install = [
            upstream_system.all_packages_dict[name] for name in sanitized_names
        ]
    else:
        possible_packages = [
            upstream_system.all_packages_dict[name] for name in sanitized_names
        ]
        concrete_packages_to_install = []
        for package in possible_packages:
            if package.name in installed_system.all_packages_dict:
                installed_package = installed_system.all_packages_dict[
                    package.name]
                if not version_comparison(installed_package.version, "=",
                                          package.version):
                    concrete_packages_to_install.append(package)
            else:
                concrete_packages_to_install.append(package)

    # dict for package replacements.
    # replacing packages names as keys, packages names to be replaced as values
    replaces_dict: Dict[str, str] = {}

    # in case of sysupgrade fetch all installed packages, of which newer versions are available
    if sysupgrade:
        installed_packages = []
        if not repo:
            installed_packages.extend(
                [package for package in installed_system.aur_packages_list])
            installed_packages.extend(
                [package for package in installed_system.devel_packages_list])
        if not aur:
            installed_packages.extend(
                [package for package in installed_system.repo_packages_list])
        for package in installed_packages:
            # must not be that we have not received the upstream information
            assert package.name in upstream_system.all_packages_dict
            upstream_package = upstream_system.all_packages_dict[package.name]
            # normal sysupgrade
            if not sysupgrade_force:
                if version_comparison(upstream_package.version, ">",
                                      package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)
            # sysupgrade with downgrades
            else:
                if not version_comparison(upstream_package.version, "=",
                                          package.version):
                    if upstream_package not in concrete_packages_to_install:
                        concrete_packages_to_install.append(upstream_package)

        # ignoring versioning has to be deactivated while checking for replaces
        ignore_versioning_copy = Package.ignore_versioning
        Package.ignore_versioning = False

        # fetch packages to replace
        for possible_replacing_package in upstream_system.repo_packages_list:
            for replaces in possible_replacing_package.replaces:
                replace_name = strip_versioning_from_name(replaces)
                installed_to_replace = [
                    package
                    for package in installed_system.provided_by(replaces)
                    if package.name == replace_name
                ]
                if installed_to_replace:
                    assert len(installed_to_replace) == 1
                    package_to_replace = installed_to_replace[0]
                    # do not let packages replaces itself, e.g. mesa replaces "ati-dri" and provides "ati-dri"
                    if possible_replacing_package.name not in ignored_packages_names \
                            and package_to_replace.name not in ignored_packages_names \
                            and possible_replacing_package.name != package_to_replace.name:

                        replaces_dict[possible_replacing_package.
                                      name] = package_to_replace.name
                        if possible_replacing_package not in concrete_packages_to_install:
                            concrete_packages_to_install.append(
                                possible_replacing_package)

                        if package_to_replace.name in upstream_system.all_packages_dict \
                                and upstream_system.all_packages_dict[package_to_replace.name] \
                                in concrete_packages_to_install:
                            concrete_packages_to_install.remove(
                                upstream_system.all_packages_dict[
                                    package_to_replace.name])

        # reset ignoring of versioning
        Package.ignore_versioning = ignore_versioning_copy

    # chunk and sort packages
    concrete_packages_to_install_repo = [
        package for package in concrete_packages_to_install
        if package.type_of is PossibleTypes.REPO_PACKAGE
    ]
    concrete_packages_to_install_aur = [
        package for package in concrete_packages_to_install
        if package.type_of is not PossibleTypes.REPO_PACKAGE
    ]

    # if not --rebuild, handle repo packages first
    if not rebuild:
        concrete_packages_to_install = group_by_function_sort_by_deps(
            concrete_packages_to_install_repo,
            lambda pkg: pkg.pkgbase) + group_by_function_sort_by_deps(
                concrete_packages_to_install_aur, lambda pkg: pkg.pkgbase)
    # if --rebuild, aur packages may be in front of repo packages
    else:
        concrete_packages_to_install = group_by_function_sort_by_deps(
            concrete_packages_to_install_repo +
            concrete_packages_to_install_aur, lambda pkg: pkg.pkgbase)

    # calc solutions
    if only_unfulfilled_deps:
        if not rebuild:
            solutions = Package.dep_solving(concrete_packages_to_install,
                                            installed_system, upstream_system)
        # if --rebuild, assume that the packages to rebuild are not installed, to ensure to correct order of rebuilding
        else:
            installed_system_no_rebuild_packages = System([
                package
                for package in installed_system.all_packages_dict.values()
                if package.name not in sanitized_names
            ])
            solutions = Package.dep_solving(
                concrete_packages_to_install,
                installed_system_no_rebuild_packages, upstream_system)
    else:
        solutions = Package.dep_solving(concrete_packages_to_install, System(
            ()), upstream_system)

    # fetch valid solutions
    sol_tuples = installed_system.validate_solutions(
        solutions, concrete_packages_to_install)
    valid_solutions = [sol_tuple[1] for sol_tuple in sol_tuples]
    if not valid_solutions:
        aurman_error("we could not find a solution")
        aurman_error(
            "if you think that there should be one, rerun aurman with the --deep_search flag"
        )
        sys.exit(1)

    print(
        json.dumps([
            valid_solutions,
            installed_system.differences_between_systems(
                [sol_tuple[0] for sol_tuple in sol_tuples])
        ],
                   cls=SolutionEncoder,
                   indent=4))
Example #13
0

# aurman help
aurman_help = Help([])

# usage
usage_title = "Usage"
usage = "aurman <operation> [options] [targets]\n    see also https://www.archlinux.org/pacman/pacman.8.html"
aurman_help.points.append(HelpPoint(usage_title, (usage, )))

# description
description_title = "Description"
description = "aurman is meant as a {}. " \
              "All pacman operations are supported,\n    " \
              "but calling aurman with an operation besides " \
              "{} or {} will {}.".format(Colors.BOLD("pacman wrapper"),
                                         Colors.BOLD(Colors.LIGHT_GREEN("--sync")),
                                         Colors.BOLD(Colors.LIGHT_GREEN("-S")),
                                         Colors.BOLD("just pass the arguments to pacman"))
aurman_help.points.append(HelpPoint(description_title, (description, )))

# native pacman options
native = "the following native pacman options for " \
         "{} or {} will be forwarded to pacman".format(Colors.LIGHT_GREEN("--sync"), Colors.LIGHT_GREEN("-S"))
native_points = []
aurman_help.points.append(HelpPoint(native, native_points))

native_points.append(
    HelpOption([
        "-r", "--root"
    ], "Specify an alternative database location (a typical default is /var/lib/pacman)"