From 5e01af3199254d0f5fd666b32b073a5283230021 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 9 Apr 2013 17:24:27 +0200 Subject: [PATCH] package kit: Add data structures for problem solutions ... and add the problem solutions in LibsolvSolver. --- headers/os/package/solver/SolverProblem.h | 12 + .../os/package/solver/SolverProblemSolution.h | 90 +++++++ src/kits/package/Jamfile | 1 + src/kits/package/solver/LibsolvSolver.cpp | 242 +++++++++++++++++- src/kits/package/solver/LibsolvSolver.h | 13 +- src/kits/package/solver/SolverProblem.cpp | 30 ++- .../package/solver/SolverProblemSolution.cpp | 157 ++++++++++++ 7 files changed, 539 insertions(+), 6 deletions(-) create mode 100644 headers/os/package/solver/SolverProblemSolution.h create mode 100644 src/kits/package/solver/SolverProblemSolution.cpp diff --git a/headers/os/package/solver/SolverProblem.h b/headers/os/package/solver/SolverProblem.h index f660837fbf..4cd6df8668 100644 --- a/headers/os/package/solver/SolverProblem.h +++ b/headers/os/package/solver/SolverProblem.h @@ -6,6 +6,7 @@ #define _PACKAGE__SOLVER_PROBLEM_H_ +#include #include @@ -13,6 +14,7 @@ namespace BPackageKit { class BSolverPackage; +class BSolverProblemSolution; class BSolverProblem { @@ -53,13 +55,23 @@ public: BSolverPackage* TargetPackage() const; const BPackageResolvableExpression& Dependency() const; + int32 CountSolutions() const; + const BSolverProblemSolution* SolutionAt(int32 index) const; + + bool AppendSolution( + BSolverProblemSolution* solution); + BString ToString() const; +private: + typedef BObjectList SolutionList; + private: BType fType; BSolverPackage* fSourcePackage; BSolverPackage* fTargetPackage; BPackageResolvableExpression fDependency; + SolutionList fSolutions; }; diff --git a/headers/os/package/solver/SolverProblemSolution.h b/headers/os/package/solver/SolverProblemSolution.h new file mode 100644 index 0000000000..767611d14f --- /dev/null +++ b/headers/os/package/solver/SolverProblemSolution.h @@ -0,0 +1,90 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__SOLVER_PROBLEM_SOLUTION_H_ +#define _PACKAGE__SOLVER_PROBLEM_SOLUTION_H_ + + +#include +#include + + +namespace BPackageKit { + + +class BSolverPackage; + + +class BSolverProblemSolutionElement { +public: + enum BType { + B_UNSPECIFIED, + B_DONT_KEEP, + B_DONT_INSTALL, + B_DONT_INSTALL_MOST_RECENT, + B_DONT_FORBID_INSTALLATION, + B_DONT_DEINSTALL, + B_DONT_DEINSTALL_ALL, + B_DONT_LOCK, + B_KEEP_INFERIOR_ARCHITECTURE, + B_KEEP_EXCLUDED, + B_KEEP_OLD, + B_INSTALL_INFERIOR_ARCHITECTURE, + B_INSTALL_EXCLUDED, + B_INSTALL_OLD, + B_ALLOW_DOWNGRADE, + B_ALLOW_NAME_CHANGE, + B_ALLOW_ARCHITECTURE_CHANGE, + B_ALLOW_VENDOR_CHANGE, + B_ALLOW_REPLACEMENT, + B_ALLOW_DEINSTALLATION + }; + +public: + BSolverProblemSolutionElement(BType type, + BSolverPackage* sourcePackage, + BSolverPackage* targetPackage, + const BString& selection); + ~BSolverProblemSolutionElement(); + + BType Type() const; + BSolverPackage* SourcePackage() const; + BSolverPackage* TargetPackage() const; + const BString& Selection() const; + + BString ToString() const; + +private: + BType fType; + BSolverPackage* fSourcePackage; + BSolverPackage* fTargetPackage; + BString fSelection; +}; + + +class BSolverProblemSolution { +public: + typedef BSolverProblemSolutionElement Element; + +public: + BSolverProblemSolution(); + ~BSolverProblemSolution(); + + int32 CountElements() const; + const Element* ElementAt(int32 index) const; + + bool AppendElement(const Element& element); + +private: + typedef BObjectList ElementList; + +private: + ElementList fElements; +}; + + +} // namespace BPackageKit + + +#endif // _PACKAGE__SOLVER_PROBLEM_SOLUTION_H_ diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index 6eb0ac4468..338aceedf7 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -83,6 +83,7 @@ SharedLibrary libpackage.so SolverPackageSpecifier.cpp SolverPackageSpecifierList.cpp SolverProblem.cpp + SolverProblemSolution.cpp SolverRepository.cpp SolverResult.cpp : diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp index c12e8456f6..7e2a0769cd 100644 --- a/src/kits/package/solver/LibsolvSolver.cpp +++ b/src/kits/package/solver/LibsolvSolver.cpp @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -85,6 +86,46 @@ private: }; +struct LibsolvSolver::Problem : public BSolverProblem { + Problem(::Id id, BType type, BSolverPackage* sourcePackage, + BSolverPackage* targetPackage, + const BPackageResolvableExpression& dependency) + : + BSolverProblem(type, sourcePackage, targetPackage, dependency), + fId(id) + { + } + + ::Id Id() const + { + return fId; + } + +private: + ::Id fId; +}; + + +struct LibsolvSolver::Solution : public BSolverProblemSolution { + Solution(::Id id, Problem* problem) + : + BSolverProblemSolution(), + fId(id), + fProblem(problem) + { + } + + ::Id Id() const + { + return fId; + } + +private: + ::Id fId; + Problem* fProblem; +}; + + // #pragma mark - LibsolvSolver @@ -546,13 +587,212 @@ LibsolvSolver::_AddProblem(Id problemId) return error; } - BSolverProblem* problem = new(std::nothrow) BSolverProblem(problemType, + Problem* problem = new(std::nothrow) Problem(problemId, problemType, sourcePackage, targetPackage, dependency); if (problem == NULL || !fProblems.AddItem(problem)) { delete problem; return B_NO_MEMORY; } + int solutionCount = solver_solution_count(fSolver, problemId); + for (Id solutionId = 1; solutionId <= solutionCount; solutionId++) { + status_t error = _AddSolution(problem, solutionId); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +status_t +LibsolvSolver::_AddSolution(Problem* problem, Id solutionId) +{ + Solution* solution = new(std::nothrow) Solution(solutionId, problem); + if (solution == NULL || !problem->AppendSolution(solution)) { + delete solution; + return B_NO_MEMORY; + } + + Id elementId = 0; + for (;;) { + Id sourceId; + Id targetId; + elementId = solver_next_solutionelement(fSolver, problem->Id(), + solutionId, elementId, &sourceId, &targetId); + if (elementId == 0) + break; + + status_t error = _AddSolutionElement(solution, sourceId, targetId); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +status_t +LibsolvSolver::_AddSolutionElement(Solution* solution, Id sourceId, Id targetId) +{ + typedef BSolverProblemSolutionElement Element; + + if (sourceId == SOLVER_SOLUTION_JOB + || sourceId == SOLVER_SOLUTION_POOLJOB) { + // targetId is an index into the job queue + if (sourceId == SOLVER_SOLUTION_JOB) + targetId += fSolver->pooljobcnt; + + Id how = fSolver->job.elements[targetId - 1]; + Id what = fSolver->job.elements[targetId]; + Id select = how & SOLVER_SELECTMASK; + + switch (how & SOLVER_JOBMASK) { + case SOLVER_INSTALL: + if (select == SOLVER_SOLVABLE && fInstalledRepository != NULL + && fPool->solvables[what].repo + == fInstalledRepository->SolvRepo()) { + return _AddSolutionElement(solution, Element::B_DONT_KEEP, + fPool->solvables + what, NULL, NULL); + } + + return _AddSolutionElement(solution, + Element::B_DONT_INSTALL, NULL, NULL, + solver_select2str(fPool, select, what)); + + case SOLVER_ERASE: + { + if (select == SOLVER_SOLVABLE + && (fInstalledRepository == NULL + || fPool->solvables[what].repo + != fInstalledRepository->SolvRepo())) { + return _AddSolutionElement(solution, + Element::B_DONT_FORBID_INSTALLATION, + fPool->solvables + what, NULL, NULL); + } + + Element::BType type = select == SOLVER_SOLVABLE_PROVIDES + ? Element::B_DONT_DEINSTALL_ALL : Element::B_DONT_DEINSTALL; + return _AddSolutionElement(solution, type, NULL, NULL, + solver_select2str(fPool, select, what)); + } + + case SOLVER_UPDATE: + return _AddSolutionElement(solution, + Element::B_DONT_INSTALL_MOST_RECENT, NULL, NULL, + solver_select2str(fPool, select, what)); + + case SOLVER_LOCK: + return _AddSolutionElement(solution, Element::B_DONT_LOCK, NULL, + NULL, solver_select2str(fPool, select, what)); + + default: + return _AddSolutionElement(solution, Element::B_UNSPECIFIED, + NULL, NULL, NULL); + } + } + + Solvable* target = targetId != 0 ? fPool->solvables + targetId : NULL; + bool targetInstalled = target && fInstalledRepository + && target->repo == fInstalledRepository->SolvRepo(); + + if (sourceId == SOLVER_SOLUTION_INFARCH) { + return _AddSolutionElement(solution, + targetInstalled + ? Element::B_KEEP_INFERIOR_ARCHITECTURE + : Element::B_INSTALL_INFERIOR_ARCHITECTURE, + target, NULL, NULL); + } + + if (sourceId == SOLVER_SOLUTION_DISTUPGRADE) { + return _AddSolutionElement(solution, + targetInstalled + ? Element::B_KEEP_EXCLUDED : Element::B_INSTALL_EXCLUDED, + target, NULL, NULL); + } + + if (sourceId == SOLVER_SOLUTION_BEST) { + return _AddSolutionElement(solution, + targetInstalled ? Element::B_KEEP_OLD : Element::B_INSTALL_OLD, + target, NULL, NULL); + } + + // replace source with target + Solvable* source = fPool->solvables + sourceId; + if (target == NULL) { + return _AddSolutionElement(solution, Element::B_ALLOW_DEINSTALLATION, + source, NULL, NULL); + } + + int illegalMask = policy_is_illegal(fSolver, source, target, 0); + if ((illegalMask & POLICY_ILLEGAL_DOWNGRADE) != 0) { + status_t error = _AddSolutionElement(solution, + Element::B_ALLOW_DOWNGRADE, source, target, NULL); + if (error != B_OK) + return error; + } + + if ((illegalMask & POLICY_ILLEGAL_NAMECHANGE) != 0) { + status_t error = _AddSolutionElement(solution, + Element::B_ALLOW_NAME_CHANGE, source, target, NULL); + if (error != B_OK) + return error; + } + + if ((illegalMask & POLICY_ILLEGAL_ARCHCHANGE) != 0) { + status_t error = _AddSolutionElement(solution, + Element::B_ALLOW_ARCHITECTURE_CHANGE, source, target, NULL); + if (error != B_OK) + return error; + } + + if ((illegalMask & POLICY_ILLEGAL_VENDORCHANGE) != 0) { + status_t error = _AddSolutionElement(solution, + Element::B_ALLOW_VENDOR_CHANGE, source, target, NULL); + if (error != B_OK) + return error; + } + + if (illegalMask == 0) { + return _AddSolutionElement(solution, Element::B_ALLOW_REPLACEMENT, + source, target, NULL); + } + + return B_OK; +} + + +status_t +LibsolvSolver::_AddSolutionElement(Solution* solution, + BSolverProblemSolutionElement::BType type, Solvable* sourceSolvable, + Solvable* targetSolvable, const char* selectionString) +{ + BSolverPackage* sourcePackage = NULL; + if (sourceSolvable != NULL) { + sourcePackage = _GetPackage(sourceSolvable); + if (sourcePackage == NULL) + return B_ERROR; + } + + BSolverPackage* targetPackage = NULL; + if (targetSolvable != NULL) { + targetPackage = _GetPackage(targetSolvable); + if (targetPackage == NULL) + return B_ERROR; + } + + BString selection; + if (selectionString != NULL && selectionString[0] != '\0') { + selection = selectionString; + if (selection.IsEmpty()) + return B_NO_MEMORY; + } + + if (!solution->AppendElement(BSolverProblemSolutionElement( + type, sourcePackage, targetPackage, selection))) { + return B_NO_MEMORY; + } + return B_OK; } diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h index e31eeadca2..5eb4acbb71 100644 --- a/src/kits/package/solver/LibsolvSolver.h +++ b/src/kits/package/solver/LibsolvSolver.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -46,9 +47,11 @@ public: private: struct SolvQueue; struct RepositoryInfo; + struct Problem; + struct Solution; typedef BObjectList RepositoryInfoList; - typedef BObjectList ProblemList; + typedef BObjectList ProblemList; typedef std::map SolvableMap; private: @@ -61,6 +64,14 @@ private: BSolverPackage* _GetPackage(Id solvableId) const; status_t _AddProblem(Id problemId); + status_t _AddSolution(Problem* problem, Id solutionId); + status_t _AddSolutionElement(Solution* solution, + Id sourceId, Id targetId); + status_t _AddSolutionElement(Solution* solution, + BSolverProblemSolutionElement::BType type, + Solvable* sourceSolvable, + Solvable* targetSolvable, + const char* selectionString); status_t _GetResolvableExpression(Id id, BPackageResolvableExpression& _expression) const; diff --git a/src/kits/package/solver/SolverProblem.cpp b/src/kits/package/solver/SolverProblem.cpp index 034f3d2ad6..e0adce076d 100644 --- a/src/kits/package/solver/SolverProblem.cpp +++ b/src/kits/package/solver/SolverProblem.cpp @@ -9,9 +9,8 @@ #include -#include - #include +#include static const char* const kToStringTexts[] = { @@ -45,7 +44,8 @@ BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage, fType(type), fSourcePackage(sourcePackage), fTargetPackage(targetPackage), - fDependency() + fDependency(), + fSolutions(10, true) { } @@ -57,7 +57,8 @@ BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage, fType(type), fSourcePackage(sourcePackage), fTargetPackage(targetPackage), - fDependency(dependency) + fDependency(dependency), + fSolutions(10, true) { } @@ -95,6 +96,27 @@ BSolverProblem::Dependency() const } +int32 +BSolverProblem::CountSolutions() const +{ + return fSolutions.CountItems(); +} + + +const BSolverProblemSolution* +BSolverProblem::SolutionAt(int32 index) const +{ + return fSolutions.ItemAt(index); +} + + +bool +BSolverProblem::AppendSolution(BSolverProblemSolution* solution) +{ + return fSolutions.AddItem(solution); +} + + BString BSolverProblem::ToString() const { diff --git a/src/kits/package/solver/SolverProblemSolution.cpp b/src/kits/package/solver/SolverProblemSolution.cpp new file mode 100644 index 0000000000..4b6f55f5e9 --- /dev/null +++ b/src/kits/package/solver/SolverProblemSolution.cpp @@ -0,0 +1,157 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include + +#include + + +static const char* const kToStringTexts[] = { + "do something", + "do not keep %source% installed", + "do not install \"%selection%\"", + "do not install the most recent version of \"%selection%\"", + "do not forbid installation of %source%", + "do not deinstall \"%selection%\"", + "do not deinstall all resolvables \"%s\"", + "do not lock \"%selection%\"", + "keep %source% despite its inferior architecture", + "keep %source% from excluded repository", + "keep old %source%", + "install %source% despite its inferior architecture", + "install %source% from excluded repository", + "install %s despite its old version", + "allow downgrade of %source% to %target%", + "allow name change of %source% to %target%", + "allow architecture change of %source% to %target%", + "allow vendor change from \"%sourceVendor%\" (%source%) to " + "\"%targetVendor%\" (%target%)", + "allow replacement of %source% with %target%", + "allow deinstallation of %source%" +}; + + +namespace BPackageKit { + + +// #pragma mark - BSolverProblemSolutionElement + + +BSolverProblemSolutionElement::BSolverProblemSolutionElement(BType type, + BSolverPackage* sourcePackage, BSolverPackage* targetPackage, + const BString& selection) + : + fType(type), + fSourcePackage(sourcePackage), + fTargetPackage(targetPackage), + fSelection(selection) +{ +} + + +BSolverProblemSolutionElement::~BSolverProblemSolutionElement() +{ +} + + +BSolverProblemSolutionElement::BType +BSolverProblemSolutionElement::Type() const +{ + return fType; +} + + +BSolverPackage* +BSolverProblemSolutionElement::SourcePackage() const +{ + return fSourcePackage; +} + + +BSolverPackage* +BSolverProblemSolutionElement::TargetPackage() const +{ + return fTargetPackage; +} + + +const BString& +BSolverProblemSolutionElement::Selection() const +{ + return fSelection; +} + + +BString +BSolverProblemSolutionElement::ToString() const +{ + size_t index = fType; + if (index >= sizeof(kToStringTexts) / sizeof(kToStringTexts[0])) + index = 0; + + return BString(kToStringTexts[index]) + .ReplaceAll("%source%", + fSourcePackage != NULL + ? fSourcePackage->VersionedName().String() : "?") + .ReplaceAll("%target%", + fTargetPackage != NULL + ? fTargetPackage->VersionedName().String() : "?") + .ReplaceAll("%selection%", fSelection) + .ReplaceAll("%sourceVendor%", + fSourcePackage != NULL + ? fSourcePackage->Info().Vendor().String() : "?") + .ReplaceAll("%targetVendor%", + fTargetPackage != NULL + ? fTargetPackage->Info().Vendor().String() : "?"); +} + + +// #pragma mark - BSolverProblemSolution + + +BSolverProblemSolution::BSolverProblemSolution() + : + fElements(10, true) +{ +} + + +BSolverProblemSolution::~BSolverProblemSolution() +{ +} + + +int32 +BSolverProblemSolution::CountElements() const +{ + return fElements.CountItems(); +} + + +const BSolverProblemSolution::Element* +BSolverProblemSolution::ElementAt(int32 index) const +{ + return fElements.ItemAt(index); +} + + +bool +BSolverProblemSolution::AppendElement(const Element& element) +{ + Element* newElement = new(std::nothrow) Element(element); + if (newElement == NULL || !fElements.AddItem(newElement)) { + delete newElement; + return false; + } + + return true; +} + + +} // namespace BPackageKit