예제 #1
0
파일: resolve.py 프로젝트: ARF1/conda
    def solve(self, specs, installed=[], update_deps=True, returnall=False,
              guess=True, minimal_hint=False):
        try:
            stdoutlog.info("Solving package specifications: ")
            res = self.explicit(specs)
            if res is not None:
                return res

            # If update_deps=True, set the target package in MatchSpec so that
            # the solver can minimize the version change. If update_deps=False,
            # fix the version and build so that no change is possible.
            len0 = len(specs)
            specs = list(map(MatchSpec, specs))
            snames = {s.name for s in specs}
            for pkg in installed:
                name, version, build = self.package_triple(pkg)
                if pkg not in self.index:
                    self.index[pkg] = {
                        'name':name, 'version':version,
                        'build':build, 'build_number':0
                    }
                    self.groups.setdefault(name,[]).append(pkg)
                if name in snames:
                    continue
                if update_deps:
                    spec = MatchSpec(name, target=pkg)
                else:
                    spec = MatchSpec('%s %s %s'%(name,version,build))
                specs.append(spec)
                snames.add(spec)
            dotlog.debug("Solving for %s" % specs)

            try:
                dists, specs = self.get_dists(specs)
            except NoPackagesFound:
                raise

            # Clear out our caches to reduce memory usage before the solve
            self.find_matches_.clear()
            self.ms_depends_.clear()

            # Check if satisfiable
            dotlog.debug('Checking satisfiability')
            groups = build_groups(dists)
            m, v, w = self.build_vw(groups)
            clauses = list(self.gen_clauses(v, groups, specs))
            solution = sat(clauses)
            if not solution:
                if guess:
                    if minimal_hint:
                        stderrlog.info('\nError: Unsatisfiable package '
                            'specifications.\nGenerating minimal hint: \n')
                        sys.exit(self.minimal_unsatisfiable_subset(clauses, v, w))
                    else:
                        stderrlog.info('\nError: Unsatisfiable package '
                            'specifications.\nGenerating hint: \n')
                        sys.exit(self.guess_bad_solve(specs))
                raise RuntimeError("Unsatisfiable package specifications")

            eq_version = self.generate_version_eq(v, groups, specs[:len0], majoronly=True)
            clauses, solution, obj1 = optimize(eq_version, clauses, solution)
            dotlog.debug('Requested version metric: %d'%obj1)

            eq_features, n0 = self.generate_feature_eq(v, groups, specs)
            clauses, solution, obj = optimize(eq_features, clauses, solution)
            dotlog.debug('Feature count metric: %d'%(obj+n0))

            eq_version2 = self.generate_version_eq(v, groups, specs, majoronly=False)
            clauses, solution, obj2 = optimize(eq_version2, clauses, solution)
            dotlog.debug('Total version metric: %d'%obj2)

            eq_version3 = self.generate_package_count(v, groups, specs)
            clauses, solution, obj3 = optimize(eq_version3, clauses, solution)
            dotlog.debug('Weak dependency metric: %d'%obj3)

            dotlog.debug('Final metrics: (%d,%d,%d,%d)'%(
                (n0+evaluate_eq(eq_features,solution),
                    evaluate_eq(eq_version,solution),
                    evaluate_eq(eq_version2,solution),
                    evaluate_eq(eq_version3,solution))))

            solution = [s for s in solution if 0 < s <= m]

            dotlog.debug('Looking for alternate solutions')
            solutions = [solution]
            nsol = 1
            while True:
                nclause = tuple(-q for q in solution if 0 < q <= m)
                clauses.append(nclause)
                solution = sat(clauses)
                if solution is None:
                    break
                solution = [s for s in solution if 0 < s <= m]
                nsol += 1
                if nsol > 10:
                    dotlog.debug('Too many solutions; terminating')
                    break
                solutions.append(solution)

            psolutions = [set(w[lit] for lit in sol if 0 < lit <= m and '@' not in w[lit]) for sol in solutions]
            if nsol > 1:
                stdoutlog.info(
                    '\nWarning: %s possible package resolutions (only showing differing packages):\n' %
                    ('>10' if nsol > 10 else nsol))
                common  = set.intersection(*psolutions)
                for sol in psolutions:
                    stdoutlog.info('\t%s,\n' % sorted(sol - common))

            if obj1 > 0 or obj2 > 0 or (obj3 > 0 and any(i>1 for i,_ in eq_version3)):
                log.debug("Older versions in the solution(s):")
                for sol in solutions:
                    v = ([(i, w[j]) for i, j in eq_version if j in sol] +
                         [(i, w[j]) for i, j in eq_version2 if j in sol] +
                         [(i, w[j]) for i, j in eq_version3 if i>1 and j in sol])
                    log.debug(v)
            stdoutlog.info('\n')
            return list(map(sorted, psolutions)) if returnall else sorted(psolutions[0])
        except:
            stdoutlog.info('\n')
            raise
예제 #2
0
    def solve(self, specs, installed=[], update_deps=True, returnall=False,
              guess=True, minimal_hint=False):
        try:
            stdoutlog.info("Solving package specifications: ")
            res = self.explicit(specs)
            if res is not None:
                return res

            # If update_deps=True, set the target package in MatchSpec so that
            # the solver can minimize the version change. If update_deps=False,
            # fix the version and build so that no change is possible.
            len0 = len(specs)
            specs = list(map(MatchSpec, specs))
            snames = {s.name for s in specs}
            for pkg in installed:
                name, version, build = self.package_triple(pkg)
                if pkg not in self.index:
                    self.index[pkg] = {
                        'name':name, 'version':version,
                        'build':build, 'build_number':0
                    }
                    self.groups.setdefault(name,[]).append(pkg)
                if name in snames:
                    continue
                if update_deps:
                    spec = MatchSpec(name, target=pkg)
                else:
                    spec = MatchSpec('%s %s %s'%(name,version,build))
                specs.append(spec)
                snames.add(spec)
            dotlog.debug("Solving for %s" % specs)

            try:
                dists, specs = self.get_dists(specs)
            except NoPackagesFound:
                raise

            # Clear out our caches to reduce memory usage before the solve
            self.find_matches_.clear()
            self.ms_depends_.clear()

            # Check if satisfiable
            dotlog.debug('Checking satisfiability')
            groups = build_groups(dists)
            m, v, w = self.build_vw(groups)
            clauses = list(self.gen_clauses(v, groups, specs))
            solution = sat(clauses)
            if not solution:
                if guess:
                    if minimal_hint:
                        stderrlog.info('\nError: Unsatisfiable package '
                            'specifications.\nGenerating minimal hint: \n')
                        sys.exit(self.minimal_unsatisfiable_subset(clauses, v, w))
                    else:
                        stderrlog.info('\nError: Unsatisfiable package '
                            'specifications.\nGenerating hint: \n')
                        sys.exit(self.guess_bad_solve(specs))
                raise RuntimeError("Unsatisfiable package specifications")

            eq_version = self.generate_version_eq(v, groups, specs[:len0], majoronly=True)
            clauses, solution, obj1 = optimize(eq_version, clauses, solution)
            dotlog.debug('Requested version metric: %d'%obj1)

            eq_features, n0 = self.generate_feature_eq(v, groups, specs)
            clauses, solution, obj = optimize(eq_features, clauses, solution)
            dotlog.debug('Feature count metric: %d'%(obj+n0))

            eq_version2 = self.generate_version_eq(v, groups, specs, majoronly=False)
            clauses, solution, obj2 = optimize(eq_version2, clauses, solution)
            dotlog.debug('Total version metric: %d'%obj2)

            eq_version3 = self.generate_package_count(v, groups, specs)
            clauses, solution, obj3 = optimize(eq_version3, clauses, solution)
            dotlog.debug('Weak dependency metric: %d'%obj3)

            dotlog.debug('Final metrics: (%d,%d,%d,%d)'%(
                (n0+evaluate_eq(eq_features,solution),
                    evaluate_eq(eq_version,solution),
                    evaluate_eq(eq_version2,solution),
                    evaluate_eq(eq_version3,solution))))

            solution = [s for s in solution if 0 < s <= m]

            dotlog.debug('Looking for alternate solutions')
            solutions = [solution]
            nsol = 1
            while True:
                nclause = tuple(-q for q in solution if 0 < q <= m)
                clauses.append(nclause)
                solution = sat(clauses)
                if solution is None:
                    break
                solution = [s for s in solution if 0 < s <= m]
                nsol += 1
                if nsol > 10:
                    dotlog.debug('Too many solutions; terminating')
                    break
                solutions.append(solution)

            psolutions = [set(w[lit] for lit in sol if 0 < lit <= m and '@' not in w[lit]) for sol in solutions]
            if nsol > 1:
                stdoutlog.info(
                    '\nWarning: %s possible package resolutions (only showing differing packages):\n' %
                    ('>10' if nsol > 10 else nsol))
                common  = set.intersection(*psolutions)
                for sol in psolutions:
                    stdoutlog.info('\t%s,\n' % sorted(sol - common))

            if obj1 > 0 or obj2 > 0 or (obj3 > 0 and any(i>1 for i,_ in eq_version3)):
                log.debug("Older versions in the solution(s):")
                for sol in solutions:
                    v = ([(i, w[j]) for i, j in eq_version if j in sol] +
                         [(i, w[j]) for i, j in eq_version2 if j in sol] +
                         [(i, w[j]) for i, j in eq_version3 if i>1 and j in sol])
                    log.debug(v)
            stdoutlog.info('\n')
            return list(map(sorted, psolutions)) if returnall else sorted(psolutions[0])
        except:
            stdoutlog.info('\n')
            raise