Esempio n. 1
0
 def find_conditional_versions(self, **kwargs):
     package_id = kwargs.get("package_id", None)
     target = kwargs.get("target", None)
     results = self.database.find_conditional_versions(package_id, target)
     result_objs = PackageItem()
     for result in results:
         result_obj = LCollect()
         result_obj.package_id = result[0]
         result_obj.target = result[1]
         result_obj.decision_point = pickle.loads(str(result[2]))
         result_objs.append(result_obj)
         del result_obj
     return result_objs
Esempio n. 2
0
    def create_operation_plan(self):
        '''Resolve dependencies and prepares a convenient operation plan'''
        single_packages = PackageItem()
        for package in self.packages:
            self.parent_package = package
            self.current_package = None
            self.package_heap[package.id] = package
            dependencies = []
            package_dependencies = self.collect_dependencies(package)
            if not package_dependencies:
                single_packages.add(package)
                continue
            # Create a list that consists of parent and child items
            for dependency in package_dependencies:
                dependency.parent = package.category+"/"+package.name+"/"+package.slot
                dependencies.append((package.id, dependency))
            while True:
                buff = []
                for parent, dependency in dependencies:
                    self.current_package = dependency
                    self.parent_package = None
                    self.package_query.append((dependency.id, parent))
                    if dependency.id in self.processed:
                        if self.processed[dependency.id] == self.package_options.get(dependency.id, None):
                            # This package was processed and it has no option changes
                            continue

                    # Keep the package options to prevent extra transaction
                    self.processed[dependency.id] = self.package_options.get(dependency.id, None)

                    # Keep the package information for the next operations.
                    # We don't want to create a new transaction for it.
                    self.package_heap[dependency.id] = dependency

                    # Get its dependencies
                    package_collection = self.collect_dependencies(dependency)
                    if not package_collection:
                        # The item has no dependency
                        continue
                    # Create a list that consists of parent and child items
                    for item in package_collection:
                        item.parent = package.category+"/"+package.name+"/"+package.slot
                        buff.append((dependency.id, item))
                if not buff:
                    # End of the node
                    break
                dependencies = buff

        try:
            # Sort packages for building operation
            plan = sorter.topsort(self.package_query)
        except sorter.CycleError as err:
            answer, num_parents, children = err
            out.brightred("Circular dependency detected:\n")
            for items in sorter.find_cycles(parent_children=children):
                for item in items:
                    package = self.repodb.find_package(package_id=item).get(0)
                    out.write(package.repo+"/"+package.category+"/"+package.name+"-"\
                            +package.version+":"+package.slot+"  ")
            out.write("\n")
            raise DependencyError

        # This part detects inline option conflicts
        removed = {}
        option_conflict = set()
        for package_id in self.inline_option_targets:
            for target in self.inline_option_targets[package_id]:
                for option in self.inline_option_targets[package_id][target]:
                    if option.startswith("-"):
                        if option in removed:
                            removed[option].add((package_id, target))
                        else:
                            removed[option] = set([(package_id, target)])
                    else:
                        if "-"+option in removed:
                            for (my_pkg_id, my_target)  in removed["-"+option]:
                                if my_target == target:
                                    option_conflict.add((my_target, \
                                            self.package_heap[package_id], \
                                            self.package_heap[my_pkg_id],\
                                            option))
        if option_conflict:
            out.error("option conflict detected:\n")
            for (pkg, add, remove, option)in option_conflict:
                out.error(out.color(option, "red")+" option on "+pkg+"\n")
                out.warn("%s/%s/%s/%s adds the option." % (add.repo, add.category, \
                        add.name, add.version))
                out.warn("%s/%s/%s/%s removes the option." % (remove.repo, remove.category, \
                        remove.name, remove.version))
            lpms.terminate()

        self.conditional_versions = {}
        for (key, values) in self.conditional_packages.items():
            for value in values:
                target_package = self.package_heap[key]
                my_item = {
                            "type": value["type"],
                            "version": value["version"],
                            "target": target_package.category+"/"+target_package.name+\
                                    "/"+target_package.slot,
                }
                if not value["owner_id"] in self.conditional_versions:
                    self.conditional_versions[value["owner_id"]] = [my_item]
                else:
                    self.conditional_versions[value["owner_id"]].append(my_item)

        # TODO: I think I must use most professional way for ignore-depends feature.
        if lpms.getopt("--ignore-deps"):
            result = LCollect()
            result.packages = self.packages
            result.dependencies = self.package_dependencies
            result.options = self.package_options
            result.inline_option_targets = self.inline_option_targets
            result.conditional_versions = self.conditional_versions
            result.conflicts = self.conflicts
            return result

        # Workaround for postmerge dependencies
        for (id_dependency, id_package) in self.postmerge_dependencies:
            plan.remove(id_dependency)
            plan.insert(plan.index(id_package)+1, id_dependency)

        final_plan = PackageItem()
        required_package_ids = [package.id for package in self.packages]
        for package_id in plan:
            package = self.package_heap[package_id]
            continue_conditional = False
            # If a package has a conditional decision point,
            # we should consider the condition
            if package.id not in self.conditional_packages:
                for c_package_id in self.conditional_packages:
                    c_package = self.package_heap[c_package_id]
                    if package.pk == c_package.pk:
                        continue_conditional = True
                        if package_id in required_package_ids:
                            final_plan.add_by_pk(c_package)
                            break
                if package_id in required_package_ids:
                    if continue_conditional is False:
                        final_plan.add_by_pk(package)
            if continue_conditional:
                continue
            installed_package = self.instdb.find_package(
                    package_category=package.category,
                    package_name=package.name,
                    package_slot=package.slot
            )
            if installed_package:
                if package.id in self.inline_options:
                    if installed_package.get(0).applied_options is None:
                        final_plan.add_by_pk(package)
                        continue
                    continue_inline = False
                    for inline_option in self.inline_options[package.id]:
                        if not inline_option in installed_package.get(0).applied_options:
                            final_plan.add_by_pk(package)
                            continue_inline = True
                            break
                    if continue_inline:
                        continue
                try:
                    conditional_versions_query = self.instdb.find_conditional_versions(
                            target=package.category+"/"+package.name+"/"+package.slot)
                    if conditional_versions_query:
                        for item in conditional_versions_query:
                            item.decision_point["package_id"]=item.package_id
                            if package.id in self.conditional_packages:
                                if not item.decision_point in self.conditional_packages[package.id]:
                                    self.conditional_packages[package.id].append(item.decision_point)
                            else:
                                self.conditional_packages[package.id] = [item.decision_point]
                    if package.id in self.conditional_packages:
                        decision_points = self.conditional_packages[package.id]
                        for decision_point in decision_points:
                            comparison = utils.vercmp(installed_package.get(0).version, \
                                        decision_point["version"])
                            if decision_point["type"] == ">=":
                                if self.handle_condition_conflict(decision_point, final_plan, \
                                        package.pk, ("<", ">"), (0, 1)) is False:
                                    continue
                                if not comparison in (1, 0) or package.id in required_package_ids:
                                    final_plan.add_by_pk(package)
                            elif decision_point["type"] == "<":
                                if self.handle_condition_conflict(decision_point, final_plan, \
                                        package.pk, (">", "<"), (0, -1)) is False:
                                    continue
                                if comparison != -1:
                                    final_plan.add_by_pk(package)
                            elif decision_point["type"] == ">":
                                if self.handle_condition_conflict(decision_point, final_plan, \
                                        package.pk, ("<", ">"), (0, 1)) is False:
                                    continue
                                if comparison != 1 or package.id in required_package_ids:
                                    final_plan.add_by_pk(package)
                            elif decision_point["type"] == "<=":
                                if self.handle_condition_conflict(decision_point, final_plan, \
                                        package.pk, (">", "<"), (0, -1)) is False:
                                    continue
                                if not comparison in (-1, 0) or package.id in required_package_ids:
                                    final_plan.add_by_pk(package)
                            elif decision_point["type"] == "==":
                                if comparison != 0 or package.id in required_package_ids:
                                    final_plan.add_by_pk(package)
                except ConditionConflict:
                    if not "owner_package" in decision_point:
                        conflict_package = self.instdb.find_package(package_id=\
                                decision_point["package_id"]).get(0)
                        decision_point["owner_package"] = conflict_package.repo+"/"+ \
                        conflict_package.category+"/"+ \
                        conflict_package.name+"/"+ \
                        conflict_package.version

                    out.error("while selecting a convenient version of %s, a conflict detected:\n" % \
                            out.color(package.pk, "red"))
                    out.notify(decision_point["owner_package"]+" wants "+\
                            decision_point["type"]+decision_point["version"])
                    out.notify(self.conflict_point["owner_package"]+" wants "+\
                            self.conflict_point["type"]+self.conflict_point["version"])
                    lpms.terminate("\nplease contact the package maintainers.")

                # Use new options if the package is effected
                if self.use_new_options and not package in final_plan:
                    if package.id in self.package_options:
                        for option in self.package_options[package.id]:
                            if not option in installed_package.get(0).applied_options:
                                final_plan.add_by_pk(package)
                                break
            else:
                final_plan.add_by_pk(package)

        # Oh my god! Some packages have no dependency.
        if single_packages:
            for single_package in single_packages:
                for item_id in plan:
                    if self.package_heap[item_id].pk == single_package.pk:
                        single_packages.remove(single_package)
                        break
            for single_package in single_packages:
                final_plan.insert_into(0, single_package)

        # Create LCollect object to manage package dependency data
        operation_plan = LCollect()
        operation_plan.packages = final_plan
        operation_plan.dependencies = self.package_dependencies
        operation_plan.options = self.package_options
        operation_plan.inline_option_targets = self.inline_option_targets
        operation_plan.conditional_versions = self.conditional_versions
        operation_plan.conflicts = self.conflicts
        return operation_plan
Esempio n. 3
0
    def find_package(self, **kwargs):
        results = PackageItem()
        added_packages = []
        object_items = {
            'metadata_keys': {
                0: 'id',
                1: 'repo',
                2: 'category',
                3: 'name',
                4: 'version',
                5: 'slot',
                6: 'arch',
            },
            'dependency_keys': {
                7: 'options',
                8: 'optional_depends_build',
                9: 'optional_depends_runtime',
                10: 'optional_depends_postmerge',
                11: 'optional_depends_conflict',
                12: 'static_depends_build',
                13: 'static_depends_runtime',
                14: 'static_depends_postmerge',
                15: 'static_depends_conflict'
            }
        }

        # Set the keywords
        name = kwargs.get("package_name", None)
        p_id = kwargs.get("package_id", None)
        if p_id is None and name is None:
            raise DatabaseAPIError("you must give package_name parameter.")
        repo = kwargs.get("package_repo", None)
        category = kwargs.get("package_category", None)
        version = kwargs.get("package_version", None)
        slot = kwargs.get("package_slot", None)
        available_arches = kwargs.get("available_arches", None)

        # Get the package query
        package_query = self.database.find_package(
            package_id=p_id,
            package_repo=repo,
            package_category=category,
            package_name=name,
            package_version=version,
            package_slot=slot,
            package_available_arches=available_arches,
        )

        # Create a LCollect object
        pkg_obj = LCollect()

        # Add the packages to the object
        for package in package_query:
            # [0] => repo, [1] => category [2] => name, [3] => version, [6] => arch
            if not (package[1], package[2], package[3], package[4],
                    package[6]) in added_packages:
                added_packages.append((package[1], package[2], package[3],
                                       package[4], package[6]))
            else:
                continue
            for index, item in object_items['metadata_keys'].iteritems():
                setattr(pkg_obj, item, package[index])

            for index, item in object_items['dependency_keys'].iteritems():
                setattr(pkg_obj, item, pickle.loads(str(package[index])))

            pkg_obj.pk = pkg_obj.category + "/" + pkg_obj.name + "/" + pkg_obj.slot
            results.add(pkg_obj)

            # Delete the object to prevent overrides
            del pkg_obj
            # Create it again
            pkg_obj = LCollect()

        return results