diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index ba7a81d788..835c1a7553 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -101,6 +101,7 @@ PRIVATE_SYSTEM_LIBS = libfluidsynth.so libilmimf.so liblpsolve55.so + libpackage-add-on-libsolv.so libroot-addon-icu.so ; SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h index d52d73905c..97cee58a15 100644 --- a/headers/os/package/solver/Solver.h +++ b/headers/os/package/solver/Solver.h @@ -13,30 +13,42 @@ namespace BPackageKit { class BSolverPackageSpecifierList; +class BSolverProblem; class BSolverRepository; +class BSolverResult; class BSolver { public: - BSolver(); - ~BSolver(); + virtual ~BSolver(); - status_t Init(); + static status_t Create(BSolver*& _solver); - status_t AddRepository(BSolverRepository* repository); + virtual status_t Init() = 0; - status_t Install( + virtual status_t AddRepository( + BSolverRepository* repository) = 0; + + virtual status_t Install( const BSolverPackageSpecifierList& - packages); + packages) = 0; -private: - class Implementation; + bool HasProblems() const + { return CountProblems() > 0; } + virtual int32 CountProblems() const = 0; + virtual BSolverProblem* ProblemAt(int32 index) const = 0; -private: - Implementation* fImplementation; + virtual status_t GetResult(BSolverResult& _result) = 0; + +protected: + BSolver(); }; +// function exported by the libsolv based add-on +extern "C" BSolver* create_solver(); + + } // namespace BPackageKit diff --git a/headers/os/package/solver/SolverPackage.h b/headers/os/package/solver/SolverPackage.h new file mode 100644 index 0000000000..94e52a90ce --- /dev/null +++ b/headers/os/package/solver/SolverPackage.h @@ -0,0 +1,42 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__SOLVER_PACKAGE_H_ +#define _PACKAGE__SOLVER_PACKAGE_H_ + + +#include + + +namespace BPackageKit { + + +class BSolverRepository; + + +class BSolverPackage { +public: + BSolverPackage(BSolverRepository* repository, + const BPackageInfo& packageInfo); + BSolverPackage(const BSolverPackage& other); + ~BSolverPackage(); + + BSolverRepository* Repository() const; + const BPackageInfo& Info() const; + + BString Name() const; + BString VersionedName() const; + + BSolverPackage& operator=(const BSolverPackage& other); + +private: + BSolverRepository* fRepository; + BPackageInfo fInfo; +}; + + +} // namespace BPackageKit + + +#endif // _PACKAGE__SOLVER_PACKAGE_H_ diff --git a/headers/os/package/solver/SolverPackageSpecifierList.h b/headers/os/package/solver/SolverPackageSpecifierList.h index 0557dec065..7a2bf581e1 100644 --- a/headers/os/package/solver/SolverPackageSpecifierList.h +++ b/headers/os/package/solver/SolverPackageSpecifierList.h @@ -28,6 +28,7 @@ public: bool AppendSpecifier( const BSolverPackageSpecifier& specifier); + void MakeEmpty(); BSolverPackageSpecifierList& operator=( const BSolverPackageSpecifierList& other); diff --git a/headers/os/package/solver/SolverProblem.h b/headers/os/package/solver/SolverProblem.h new file mode 100644 index 0000000000..f660837fbf --- /dev/null +++ b/headers/os/package/solver/SolverProblem.h @@ -0,0 +1,69 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__SOLVER_PROBLEM_H_ +#define _PACKAGE__SOLVER_PROBLEM_H_ + + +#include + + +namespace BPackageKit { + + +class BSolverPackage; + + +class BSolverProblem { +public: + enum BType { + B_UNSPECIFIED, + B_NOT_IN_DISTUPGRADE_REPOSITORY, + B_INFERIOR_ARCHITECTURE, + B_INSTALLED_PACKAGE_PROBLEM, + B_CONFLICTING_REQUESTS, + B_REQUESTED_RESOLVABLE_NOT_PROVIDED, + B_REQUESTED_RESOLVABLE_PROVIDED_BY_SYSTEM, + B_DEPENDENCY_PROBLEM, + B_PACKAGE_NOT_INSTALLABLE, + B_DEPENDENCY_NOT_PROVIDED, + B_PACKAGE_NAME_CLASH, + B_PACKAGE_CONFLICT, + B_PACKAGE_OBSOLETES_RESOLVABLE, + B_INSTALLED_PACKAGE_OBSOLETES_RESOLVABLE, + B_PACKAGE_IMPLICITLY_OBSOLETES_RESOLVABLE, + B_DEPENDENCY_NOT_INSTALLABLE, + B_SELF_CONFLICT + }; + +public: + BSolverProblem(BType type, + BSolverPackage* sourcePackage, + BSolverPackage* targetPackage = NULL); + BSolverProblem(BType type, + BSolverPackage* sourcePackage, + BSolverPackage* targetPackage, + const BPackageResolvableExpression& + dependency); + ~BSolverProblem(); + + BType Type() const; + BSolverPackage* SourcePackage() const; + BSolverPackage* TargetPackage() const; + const BPackageResolvableExpression& Dependency() const; + + BString ToString() const; + +private: + BType fType; + BSolverPackage* fSourcePackage; + BSolverPackage* fTargetPackage; + BPackageResolvableExpression fDependency; +}; + + +} // namespace BPackageKit + + +#endif // _PACKAGE__SOLVER_PROBLEM_H_ diff --git a/headers/os/package/solver/SolverRepository.h b/headers/os/package/solver/SolverRepository.h index 579512dda0..187a3db95a 100644 --- a/headers/os/package/solver/SolverRepository.h +++ b/headers/os/package/solver/SolverRepository.h @@ -6,6 +6,7 @@ #define _PACKAGE__SOLVER_REPOSITORY_H_ +#include #include #include #include @@ -16,6 +17,7 @@ namespace BPackageKit { class BPackageInfo; class BRepositoryConfig; +class BSolverPackage; class BSolverRepository { @@ -45,21 +47,27 @@ public: status_t InitCheck(); bool IsInstalled() const; + void SetInstalled(bool isInstalled); BString Name() const; uint8 Priority() const; + bool IsEmpty() const; + int32 CountPackages() const; + BSolverPackage* PackageAt(int32 index) const; + status_t AddPackage(const BPackageInfo& info); status_t AddPackages( BPackageInstallationLocation location); - Iterator GetIterator() const; +private: + typedef BObjectList PackageList; private: BString fName; uint8 fPriority; bool fIsInstalled; - BPackageInfoSet fPackages; + PackageList fPackages; }; diff --git a/headers/os/package/solver/SolverResult.h b/headers/os/package/solver/SolverResult.h new file mode 100644 index 0000000000..c14b691649 --- /dev/null +++ b/headers/os/package/solver/SolverResult.h @@ -0,0 +1,67 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__SOLVER_RESULT_H_ +#define _PACKAGE__SOLVER_RESULT_H_ + + +#include + + +namespace BPackageKit { + + +class BSolverPackage; + + +class BSolverResultElement { +public: + enum BType { + B_TYPE_INSTALL, + B_TYPE_UNINSTALL + }; + +public: + BSolverResultElement(BType type, + BSolverPackage* package); + BSolverResultElement( + const BSolverResultElement& other); + ~BSolverResultElement(); + + BType Type() const; + BSolverPackage* Package() const; + + BSolverResultElement& operator=(const BSolverResultElement& other); + +private: + BType fType; + BSolverPackage* fPackage; +}; + + +class BSolverResult { +public: + BSolverResult(); + ~BSolverResult(); + + bool IsEmpty() const; + int32 CountElements() const; + const BSolverResultElement* ElementAt(int32 index) const; + + void MakeEmpty(); + bool AppendElement( + const BSolverResultElement& element); + +private: + typedef BObjectList ElementList; + +private: + ElementList fElements; +}; + + +} // namespace BPackageKit + + +#endif // _PACKAGE__SOLVER_RESULT_H_ diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index 5059d6f193..6eb0ac4468 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -7,6 +7,7 @@ UsePrivateHeaders shared ; SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package solver ] ; HPKG_SOURCES = AttributeDataReader.cpp @@ -76,6 +77,14 @@ SharedLibrary libpackage.so NoErrorOutput.cpp StandardErrorOutput.cpp + # solver + Solver.cpp + SolverPackage.cpp + SolverPackageSpecifier.cpp + SolverPackageSpecifierList.cpp + SolverProblem.cpp + SolverRepository.cpp + SolverResult.cpp : libshared.a be z $(TARGET_LIBSTDC++) ; diff --git a/src/kits/package/solver/Jamfile b/src/kits/package/solver/Jamfile index 06ea5a5db2..5109fad226 100644 --- a/src/kits/package/solver/Jamfile +++ b/src/kits/package/solver/Jamfile @@ -1,23 +1,20 @@ SubDir HAIKU_TOP src kits package solver ; -UsePrivateHeaders shared ; - -# TODO: Add properly to BuildFeatures and remove here! -HAIKU_LIBSOLV_INSTALL_DIR ?= /Transfer/ports/libsolv-install/boot/common ; -HAIKU_LIBSOLV_HEADERS ?= $(HAIKU_LIBSOLV_INSTALL_DIR)/include ; -HAIKU_LIBSOLV_LIBS ?= $(HAIKU_LIBSOLV_INSTALL_DIR)/lib/libsolv.so - $(HAIKU_LIBSOLV_INSTALL_DIR)/lib/libsolvext.so ; +# add-on implementing a libsolv based BSolver SubDirSysHdrs $(HAIKU_LIBSOLV_HEADERS) ; SubDirHdrs $(HAIKU_LIBSOLV_HEADERS)/solv ; +UsePrivateHeaders shared ; -SharedLibrary libpackage_solver.so + +SharedLibrary libpackage-add-on-libsolv.so : - Solver.cpp - SolverPackageSpecifier.cpp - SolverPackageSpecifierList.cpp - SolverRepository.cpp + LibsolvSolver.cpp : package $(HAIKU_LIBSOLV_LIBS) be $(TARGET_LIBSTDC++) ; + + +Includes [ FGristFiles LibsolvSolver.cpp ] + : $(HAIKU_LIBSOLV_HEADERS_DEPENDENCY) ; diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp new file mode 100644 index 0000000000..19aa15b3b4 --- /dev/null +++ b/src/kits/package/solver/LibsolvSolver.cpp @@ -0,0 +1,619 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include "LibsolvSolver.h" + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +// TODO: libsolv doesn't have any helpful out-of-memory handling. It just just +// abort()s. Obviously that isn't good behavior for a library. + + +BSolver* +BPackageKit::create_solver() +{ + return new(std::nothrow) LibsolvSolver; +} + + +struct LibsolvSolver::SolvQueue : Queue { + SolvQueue() + { + queue_init(this); + } + + ~SolvQueue() + { + queue_free(this); + } +}; + + +struct LibsolvSolver::RepositoryInfo { + RepositoryInfo(BSolverRepository* repository) + : + fRepository(repository), + fSolvRepo(NULL) + { + } + + BSolverRepository* Repository() const + { + return fRepository; + } + + Repo* SolvRepo() + { + return fSolvRepo; + } + + void SetSolvRepo(Repo* repo) + { + fSolvRepo = repo; + } + +private: + BSolverRepository* fRepository; + Repo* fSolvRepo; +}; + + +// #pragma mark - LibsolvSolver + + +LibsolvSolver::LibsolvSolver() + : + fPool(NULL), + fSolver(NULL), + fRepositoryInfos(10, true), + fInstalledRepository(NULL), + fProblems(10, true) +{ +} + + +LibsolvSolver::~LibsolvSolver() +{ + _Cleanup(); +} + + +status_t +LibsolvSolver::Init() +{ + _Cleanup(); + + fPool = pool_create(); + + // Set the system architecture. We use what uname() returns unless we're on + // x86 gcc2. + { + const char* arch; + #ifdef __HAIKU_ARCH_X86 + #if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2 + arch = "x86_gcc2"; + #else + arch = "x86"; + #endif + #else + struct utsname info; + if (uname(&info) != 0) + return errno; + arch = info.machine; + #endif + + pool_setarchpolicy(fPool, arch); + } + + return B_OK; +} + + +status_t +LibsolvSolver::AddRepository(BSolverRepository* repository) +{ + if (repository == NULL || repository->InitCheck() != B_OK) + return B_BAD_VALUE; + + // If the repository represents installed packages, check, if we already + // have such a repository. + if (repository->IsInstalled() && fInstalledRepository != NULL) + return B_BAD_VALUE; + + // add the repository info + RepositoryInfo* info = new(std::nothrow) RepositoryInfo(repository); + if (info == NULL) + return B_NO_MEMORY; + + if (!fRepositoryInfos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + + if (repository->IsInstalled()) + fInstalledRepository = info; + + return B_OK; +} + + +status_t +LibsolvSolver::Install(const BSolverPackageSpecifierList& packages) +{ + if (packages.IsEmpty()) + return B_BAD_VALUE; + +// TODO: Clean up first? + + // add repositories to pool + status_t error = _AddRepositories(); + if (error != B_OK) + return error; + + // prepare pool for solving + pool_createwhatprovides(fPool); + + // add the packages to install to the job queue + SolvQueue jobs; + + int32 packageCount = packages.CountSpecifiers(); + for (int32 i = 0; i < packageCount; i++) { + const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i); + + // find matching packages + SolvQueue matchingPackages; + + int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB + | SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL; +// TODO: All flags needed/useful? + /*int matchFlags =*/ selection_make(fPool, &matchingPackages, + specifier.Expression().Name(), flags); +// TODO: Don't just match the name, but also the version, if given! + if (matchingPackages.count == 0) + return B_NAME_NOT_FOUND; + + // restrict to the matching repository + if (BSolverRepository* repository = specifier.Repository()) { + RepositoryInfo* repositoryInfo = _GetRepositoryInfo(repository); + if (repositoryInfo == NULL) + return B_BAD_VALUE; + + SolvQueue repoFilter; + queue_push2(&repoFilter, + SOLVER_SOLVABLE_REPO/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/, + repositoryInfo->SolvRepo()->repoid); + + selection_filter(fPool, &matchingPackages, &repoFilter); + + if (matchingPackages.count == 0) + return B_NAME_NOT_FOUND; + } + + for (int j = 0; j < matchingPackages.count; j++) + queue_push(&jobs, matchingPackages.elements[j]); + } + + // add solver mode to job queue elements + int solverMode = SOLVER_INSTALL; + for (int i = 0; i < jobs.count; i += 2) { + jobs.elements[i] |= solverMode; +// if (cleandeps) +// jobs.elements[i] |= SOLVER_CLEANDEPS; +// if (forcebest) +// jobs.elements[i] |= SOLVER_FORCEBEST; + } + + // create the solver and solve + fSolver = solver_create(fPool); + solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1); + solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1); + + // get the problems (if any) + fProblems.MakeEmpty(); + + int problemCount = solver_solve(fSolver, &jobs); + for (Id problemId = 1; problemId <= problemCount; problemId++) { + error = _AddProblem(problemId); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +int32 +LibsolvSolver::CountProblems() const +{ + return fProblems.CountItems(); +} + + +BSolverProblem* +LibsolvSolver::ProblemAt(int32 index) const +{ + return fProblems.ItemAt(index); +} + + +status_t +LibsolvSolver::GetResult(BSolverResult& _result) +{ + if (HasProblems()) + return B_BAD_VALUE; + + _result.MakeEmpty(); + + Transaction* transaction = solver_create_transaction(fSolver); + CObjectDeleter transactionDeleter(transaction, + &transaction_free); + + if (transaction->steps.count == 0) + return B_OK; + + // Get the packages that end up in the installation. The result queue + // contains newPackageCount new packages to install first, followed by the + // kept packages. + SolvQueue installedPackages; + int newPackageCount = transaction_installedresult(transaction, + &installedPackages); + + transaction_order(transaction, 0); + + for (int i = 0; i < transaction->steps.count; i++) { + Id solvableId = transaction->steps.elements[i]; + Solvable* solvable = pool_id2solvable(fPool, solvableId); + switch (transaction_type(transaction, solvableId, + SOLVER_TRANSACTION_RPM_ONLY)) { + case SOLVER_TRANSACTION_ERASE: + { + BSolverPackage* package = _GetPackage(solvable); + if (package == NULL) + return B_ERROR; + + status_t error = _result.AppendElement( + BSolverResultElement(BSolverResultElement::B_TYPE_UNINSTALL, + package)); + if (error != B_OK) + return error; + break; + } + + case SOLVER_TRANSACTION_INSTALL: + case SOLVER_TRANSACTION_MULTIINSTALL: + { + // check, if it really is a new package +// TODO: Is this check really necessary? + bool foundPackage = false; + for (int j = 0; j < newPackageCount; j++) { + if (installedPackages.elements[j] == solvableId) { + foundPackage = true; + break; + } + } + + if (!foundPackage) + continue; + + BSolverPackage* package = _GetPackage(solvable); + if (package == NULL) + return B_ERROR; + + if (!_result.AppendElement( + BSolverResultElement( + BSolverResultElement::B_TYPE_INSTALL, package))) { + return B_NO_MEMORY; + } + break; + } + + default: + break; + } + } + + return B_OK; +} + + +void +LibsolvSolver::_Cleanup() +{ + fProblems.MakeEmpty(); + fSolvablePackages.clear(); + fInstalledRepository = NULL; + fRepositoryInfos.MakeEmpty(); + + if (fSolver != NULL) { + solver_free(fSolver); + fSolver = NULL; + } + + if (fPool != NULL) { + pool_free(fPool); + fPool = NULL; + } +} + + +status_t +LibsolvSolver::_AddRepositories() +{ + int32 repositoryCount = fRepositoryInfos.CountItems(); + for (int32 i = 0; i < repositoryCount; i++) { + RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i); + BSolverRepository* repository = repositoryInfo->Repository(); + Repo* repo = repo_create(fPool, repository->Name()); + repositoryInfo->SetSolvRepo(repo); + + repo->priority = 256 - repository->Priority(); + repo->appdata = (void*)repositoryInfo; + + int32 packageCount = repository->CountPackages(); + for (int32 k = 0; k < packageCount; k++) { + BSolverPackage* package = repository->PackageAt(k); + Id solvableId = repo_add_haiku_package_info(repo, package->Info(), + REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE); + Solvable* solvable = pool_id2solvable(fPool, solvableId); + + try { + fSolvablePackages[solvable] = package; + } catch (std::bad_alloc&) { + return B_NO_MEMORY; + } + } + + repo_internalize(repo); + + if (repository->IsInstalled()) + pool_set_installed(fPool, repo); + } + + return B_OK; +} + + +LibsolvSolver::RepositoryInfo* +LibsolvSolver::_GetRepositoryInfo(BSolverRepository* repository) const +{ + int32 repositoryCount = fRepositoryInfos.CountItems(); + for (int32 i = 0; i < repositoryCount; i++) { + RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i); + if (repository == repositoryInfo->Repository()) + return repositoryInfo; + } + + return NULL; +} + + +BSolverPackage* +LibsolvSolver::_GetPackage(Solvable* solvable) const +{ + SolvableMap::const_iterator it = fSolvablePackages.find(solvable); + return it != fSolvablePackages.end() ? it->second : NULL; +} + + +BSolverPackage* +LibsolvSolver::_GetPackage(Id solvableId) const +{ + Solvable* solvable = pool_id2solvable(fPool, solvableId); + return solvable != NULL ? _GetPackage(solvable) : NULL; +} + + +status_t +LibsolvSolver::_AddProblem(Id problemId) +{ + enum { + NEED_SOURCE = 0x1, + NEED_TARGET = 0x2, + NEED_DEPENDENCY = 0x4 + }; + + Id ruleId = solver_findproblemrule(fSolver, problemId); + Id sourceId; + Id targetId; + Id dependencyId; + BSolverProblem::BType problemType = BSolverProblem::B_UNSPECIFIED; + uint32 needed = 0; + + switch (solver_ruleinfo(fSolver, ruleId, &sourceId, &targetId, + &dependencyId)) { + case SOLVER_RULE_DISTUPGRADE: + problemType = BSolverProblem::B_NOT_IN_DISTUPGRADE_REPOSITORY; + needed = NEED_SOURCE; + break; + case SOLVER_RULE_INFARCH: + problemType = BSolverProblem::B_INFERIOR_ARCHITECTURE; + needed = NEED_SOURCE; + break; + case SOLVER_RULE_UPDATE: + problemType = BSolverProblem::B_INSTALLED_PACKAGE_PROBLEM; + needed = NEED_SOURCE; + break; + case SOLVER_RULE_JOB: + problemType = BSolverProblem::B_CONFLICTING_REQUESTS; + break; + case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP: + problemType = BSolverProblem::B_REQUESTED_RESOLVABLE_NOT_PROVIDED; + needed = NEED_DEPENDENCY; + break; + case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: + problemType + = BSolverProblem::B_REQUESTED_RESOLVABLE_PROVIDED_BY_SYSTEM; + needed = NEED_DEPENDENCY; + break; + case SOLVER_RULE_RPM: + problemType = BSolverProblem::B_DEPENDENCY_PROBLEM; + break; + case SOLVER_RULE_RPM_NOT_INSTALLABLE: + problemType = BSolverProblem::B_PACKAGE_NOT_INSTALLABLE; + needed = NEED_SOURCE; + break; + case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP: + problemType = BSolverProblem::B_DEPENDENCY_NOT_PROVIDED; + needed = NEED_SOURCE | NEED_DEPENDENCY; + break; + case SOLVER_RULE_RPM_SAME_NAME: + problemType = BSolverProblem::B_PACKAGE_NAME_CLASH; + needed = NEED_SOURCE | NEED_TARGET; + break; + case SOLVER_RULE_RPM_PACKAGE_CONFLICT: + problemType = BSolverProblem::B_PACKAGE_CONFLICT; + needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY; + break; + case SOLVER_RULE_RPM_PACKAGE_OBSOLETES: + problemType = BSolverProblem::B_PACKAGE_OBSOLETES_RESOLVABLE; + needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY; + break; + case SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES: + problemType + = BSolverProblem::B_INSTALLED_PACKAGE_OBSOLETES_RESOLVABLE; + needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY; + break; + case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES: + problemType + = BSolverProblem::B_PACKAGE_IMPLICITLY_OBSOLETES_RESOLVABLE; + needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY; + break; + case SOLVER_RULE_RPM_PACKAGE_REQUIRES: + problemType = BSolverProblem::B_DEPENDENCY_NOT_INSTALLABLE; + needed = NEED_SOURCE | NEED_DEPENDENCY; + break; + case SOLVER_RULE_RPM_SELF_CONFLICT: + problemType = BSolverProblem::B_SELF_CONFLICT; + needed = NEED_SOURCE | NEED_DEPENDENCY; + break; + case SOLVER_RULE_UNKNOWN: + case SOLVER_RULE_FEATURE: + case SOLVER_RULE_LEARNT: + case SOLVER_RULE_CHOICE: + case SOLVER_RULE_BEST: + problemType = BSolverProblem::B_UNSPECIFIED; + break; + } + + BSolverPackage* sourcePackage = NULL; + if ((needed & NEED_SOURCE) != 0) { + sourcePackage = _GetPackage(sourceId); + if (sourcePackage == NULL) + return B_ERROR; + } + + BSolverPackage* targetPackage = NULL; + if ((needed & NEED_TARGET) != 0) { + targetPackage = _GetPackage(targetId); + if (targetPackage == NULL) + return B_ERROR; + } + + BPackageResolvableExpression dependency; + if ((needed & NEED_DEPENDENCY) != 0) { + status_t error = _GetResolvableExpression(dependencyId, dependency); + if (error != B_OK) + return error; + } + + BSolverProblem* problem = new(std::nothrow) BSolverProblem(problemType, + sourcePackage, targetPackage, dependency); + if (problem == NULL || !fProblems.AddItem(problem)) { + delete problem; + return B_NO_MEMORY; + } + + return B_OK; +} + + +status_t +LibsolvSolver::_GetResolvableExpression(Id id, + BPackageResolvableExpression& _expression) const +{ + // Try to translate the libsolv ID to a resolvable expression. Generally + // that doesn't work, since libsolv is more expressive, but all the stuff + // we feed libsolv we should be able to translate back. + + if (!ISRELDEP(id)) { + // just a string + _expression.SetTo(pool_id2str(fPool, id)); + return B_OK; + } + + // a composite -- analyze it + Reldep* reldep = GETRELDEP(fPool, id); + + // No support for more than one level, so both name and evr must be strings. + if (ISRELDEP(reldep->name) || ISRELDEP(reldep->evr)) + return B_NOT_SUPPORTED; + + const char* name = pool_id2str(fPool, reldep->name); + const char* versionString = pool_id2str(fPool, reldep->evr); + if (name == NULL || versionString == NULL) + return B_NOT_SUPPORTED; + + // get the operator -- we don't support all libsolv supports + BPackageResolvableOperator op; + switch (reldep->flags) { + case 1: + op = B_PACKAGE_RESOLVABLE_OP_GREATER; + break; + case 2: + op = B_PACKAGE_RESOLVABLE_OP_EQUAL; + break; + case 3: + op = B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL; + break; + case 4: + op = B_PACKAGE_RESOLVABLE_OP_LESS; + break; + case 5: + op = B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL; + break; + case 6: + op = B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL; + break; + default: + return B_NOT_SUPPORTED; + } + + // get the version (cut off the empty epoch) + if (versionString[0] == ':') + versionString++; + + BPackageVersion version; + status_t error = version.SetTo(versionString, true); + if (error != B_OK) + return error == B_BAD_DATA ? B_NOT_SUPPORTED : error; + + _expression.SetTo(name, op, version); + return B_OK; +} diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h new file mode 100644 index 0000000000..1f4c30198e --- /dev/null +++ b/src/kits/package/solver/LibsolvSolver.h @@ -0,0 +1,77 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef HAIKU_LIBSOLV_SOLVER_H +#define HAIKU_LIBSOLV_SOLVER_H + + +#include + +#include +#include + +#include +#include + + +using namespace BPackageKit; + + +namespace BPackageKit { + class BPackageResolvableExpression; + class BSolverPackage; +} + + +class LibsolvSolver : public BSolver { +public: + LibsolvSolver(); + virtual ~LibsolvSolver(); + + virtual status_t Init(); + + virtual status_t AddRepository(BSolverRepository* repository); + + virtual status_t Install( + const BSolverPackageSpecifierList& + packages); + + virtual int32 CountProblems() const; + virtual BSolverProblem* ProblemAt(int32 index) const; + + virtual status_t GetResult(BSolverResult& _result); + +private: + struct SolvQueue; + struct RepositoryInfo; + + typedef BObjectList RepositoryInfoList; + typedef BObjectList ProblemList; + typedef std::map SolvableMap; + +private: + void _Cleanup(); + + status_t _AddRepositories(); + RepositoryInfo* _GetRepositoryInfo( + BSolverRepository* repository) const; + BSolverPackage* _GetPackage(Solvable* solvable) const; + BSolverPackage* _GetPackage(Id solvableId) const; + + status_t _AddProblem(Id problemId); + status_t _GetResolvableExpression(Id id, + BPackageResolvableExpression& _expression) + const; + +private: + Pool* fPool; + Solver* fSolver; + RepositoryInfoList fRepositoryInfos; + RepositoryInfo* fInstalledRepository; + SolvableMap fSolvablePackages; + ProblemList fProblems; +}; + + +#endif // HAIKU_LIBSOLV_SOLVER_H diff --git a/src/kits/package/solver/Solver.cpp b/src/kits/package/solver/Solver.cpp index 10ff02d2d4..52f2ba691c 100644 --- a/src/kits/package/solver/Solver.cpp +++ b/src/kits/package/solver/Solver.cpp @@ -9,348 +9,62 @@ #include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -// TODO: libsolv doesn't have any helpful out-of-memory handling. It just just -// abort()s. Obviously that isn't good behavior for a library. +#include +#include namespace BPackageKit { -// #pragma mark - BSolver::Implementation +typedef BSolver* CreateSolverFunction(); +static CreateSolverFunction* sCreateSolver = NULL; + +static pthread_once_t sLoadLibsolvSolverAddOnInitOnce = PTHREAD_ONCE_INIT; -class BSolver::Implementation { -public: - Implementation(); - ~Implementation(); +static void +load_libsolv_solver_add_on() +{ + void* imageHandle = dlopen("libpackage-add-on-libsolv.so", 0); + if (imageHandle == NULL) + return; - status_t Init(); - - status_t AddRepository(BSolverRepository* repository); - - status_t Install( - const BSolverPackageSpecifierList& - packages); - -private: - struct SolvQueue; - struct RepositoryInfo; - - typedef BObjectList RepositoryInfoList; - -private: - status_t _AddRepositories(); - RepositoryInfo* _GetRepositoryInfo( - BSolverRepository* repository) const; - -private: - Pool* fPool; - RepositoryInfoList fRepositoryInfos; - RepositoryInfo* fInstalledRepository; -}; - - -struct BSolver::Implementation::SolvQueue : Queue { - SolvQueue() - { - queue_init(this); - } - - ~SolvQueue() - { - queue_free(this); - } -}; - - -struct BSolver::Implementation::RepositoryInfo { - RepositoryInfo(BSolverRepository* repository) - : - fRepository(repository), - fSolvRepo(NULL) - { - } - - BSolverRepository* Repository() const - { - return fRepository; - } - - Repo* SolvRepo() - { - return fSolvRepo; - } - - void SetSolvRepo(Repo* repo) - { - fSolvRepo = repo; - } - -private: - BSolverRepository* fRepository; - Repo* fSolvRepo; -}; - - -// #pragma mark - BSolver + sCreateSolver = (CreateSolverFunction*)dlsym(imageHandle, "create_solver"); + if (sCreateSolver == NULL) + dlclose(imageHandle); +} BSolver::BSolver() - : - fImplementation(new(std::nothrow) Implementation) { } BSolver::~BSolver() { - delete fImplementation; } -status_t -BSolver::Init() +/*static*/ status_t +BSolver::Create(BSolver*& _solver) { - return fImplementation != NULL ? fImplementation->Init() : B_NO_MEMORY; -} + pthread_once(&sLoadLibsolvSolverAddOnInitOnce, &load_libsolv_solver_add_on); + if (sCreateSolver == NULL) + return B_NOT_SUPPORTED; - -status_t -BSolver::AddRepository(BSolverRepository* repository) -{ - return fImplementation != NULL - ? fImplementation->AddRepository(repository) : B_NO_MEMORY; -} - - -status_t -BSolver::Install(const BSolverPackageSpecifierList& packages) -{ - return fImplementation != NULL - ? fImplementation->Install(packages) : B_NO_MEMORY; -} - - -// #pragma mark - BSolver::Implementation - - -BSolver::Implementation::Implementation() - : - fPool(NULL), - fRepositoryInfos(), - fInstalledRepository(NULL) -{ -} - - -BSolver::Implementation::~Implementation() -{ - if (fPool != NULL) - pool_free(fPool); -} - - -status_t -BSolver::Implementation::Init() -{ - // already initialized? - if (fPool != NULL) - return B_BAD_VALUE; - - fPool = pool_create(); - - // Set the system architecture. We use what uname() returns unless we're on - // x86 gcc2. - { - const char* arch; - #ifdef __HAIKU_ARCH_X86 - #if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2 - arch = "x86_gcc2"; - #else - arch = "x86"; - #endif - #else - struct utsname info; - if (uname(&info) != 0) - return errno; - arch = info.machine; - #endif - - pool_setarchpolicy(fPool, arch); - } - - return B_OK; -} - - -status_t -BSolver::Implementation::AddRepository(BSolverRepository* repository) -{ - if (repository == NULL || repository->InitCheck() != B_OK) - return B_BAD_VALUE; - - // If the repository represents installed packages, check, if we already - // have such a repository. - if (repository->IsInstalled() && fInstalledRepository != NULL) - return B_BAD_VALUE; - - // add the repository info - RepositoryInfo* info = new(std::nothrow) RepositoryInfo(repository); - if (info == NULL) + BSolver* solver = sCreateSolver(); + if (solver == NULL) return B_NO_MEMORY; - if (!fRepositoryInfos.AddItem(info)) { - delete info; - return B_NO_MEMORY; - } - - if (repository->IsInstalled()) - fInstalledRepository = info; - - return B_OK; -} - - -status_t -BSolver::Implementation::Install(const BSolverPackageSpecifierList& packages) -{ - if (packages.IsEmpty()) - return B_BAD_VALUE; - -// TODO: Clean up first? - - // add repositories to pool - status_t error = _AddRepositories(); - if (error != B_OK) + status_t error = solver->Init(); + if (error != B_OK) { + delete solver; return error; - - // prepare pool for solving - pool_createwhatprovides(fPool); - - // add the packages to install to the job queue - SolvQueue jobs; - - int32 packageCount = packages.CountSpecifiers(); - for (int32 i = 0; i < packageCount; i++) { - const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i); - - // find matching packages - SolvQueue matchingPackages; - - int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB - | SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL; -// TODO: All flags needed/useful? - /*int matchFlags =*/ selection_make(fPool, &matchingPackages, - specifier.Expression().Name(), flags); -// TODO: Don't just match the name, but also the version, if given! - if (matchingPackages.count == 0) - return B_NAME_NOT_FOUND; - - // restrict to the matching repository - if (BSolverRepository* repository = specifier.Repository()) { - RepositoryInfo* repositoryInfo = _GetRepositoryInfo(repository); - if (repositoryInfo == NULL) - return B_BAD_VALUE; - - SolvQueue repoFilter; - queue_push2(&repoFilter, - SOLVER_SOLVABLE_REPO/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/, - repositoryInfo->SolvRepo()->repoid); - - selection_filter(fPool, &matchingPackages, &repoFilter); - - if (matchingPackages.count == 0) - return B_NAME_NOT_FOUND; - } - - for (int j = 0; j < matchingPackages.count; j++) - queue_push(&jobs, matchingPackages.elements[j]); - } - - // add solver mode to job queue elements - int solverMode = SOLVER_INSTALL; - for (int i = 0; i < jobs.count; i += 2) { - jobs.elements[i] |= solverMode; -// if (cleandeps) -// jobs.elements[i] |= SOLVER_CLEANDEPS; -// if (forcebest) -// jobs.elements[i] |= SOLVER_FORCEBEST; - } - - // create the solver and solve - Solver* solver = solver_create(fPool); - solver_set_flag(solver, SOLVER_FLAG_SPLITPROVIDES, 1); - solver_set_flag(solver, SOLVER_FLAG_BEST_OBEY_POLICY, 1); - - int problemCount = solver_solve(solver, &jobs); - solver_free(solver); - -// TODO: Problem support! - return problemCount == 0 ? B_OK : B_BAD_VALUE; -} - - -status_t -BSolver::Implementation::_AddRepositories() -{ - if (fInstalledRepository == NULL) - return B_BAD_VALUE; - - int32 repositoryCount = fRepositoryInfos.CountItems(); - for (int32 i = 0; i < repositoryCount; i++) { - RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i); - BSolverRepository* repository = repositoryInfo->Repository(); - Repo* repo = repo_create(fPool, repository->Name()); - repositoryInfo->SetSolvRepo(repo); - - repo->priority = 256 - repository->Priority(); - repo->appdata = (void*)repositoryInfo; - - BRepositoryCache::Iterator it = repository->GetIterator(); - while (const BPackageInfo* packageInfo = it.Next()) { - repo_add_haiku_package_info(repo, *packageInfo, - REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE); - } - - repo_internalize(repo); - - if (repository->IsInstalled()) - pool_set_installed(fPool, repo); } + _solver = solver; return B_OK; } -BSolver::Implementation::RepositoryInfo* -BSolver::Implementation::_GetRepositoryInfo(BSolverRepository* repository) const -{ - int32 repositoryCount = fRepositoryInfos.CountItems(); - for (int32 i = 0; i < repositoryCount; i++) { - RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i); - if (repository == repositoryInfo->Repository()) - return repositoryInfo; - } - - return NULL; -} - - } // namespace BPackageKit diff --git a/src/kits/package/solver/SolverPackage.cpp b/src/kits/package/solver/SolverPackage.cpp new file mode 100644 index 0000000000..23dfba75ea --- /dev/null +++ b/src/kits/package/solver/SolverPackage.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include + + +namespace BPackageKit { + + +BSolverPackage::BSolverPackage(BSolverRepository* repository, + const BPackageInfo& packageInfo) + : + fRepository(repository), + fInfo(packageInfo) +{ +} + + +BSolverPackage::BSolverPackage(const BSolverPackage& other) + : + fRepository(other.fRepository), + fInfo(other.fInfo) +{ +} + + +BSolverPackage::~BSolverPackage() +{ +} + + +BSolverRepository* +BSolverPackage::Repository() const +{ + return fRepository; +} + + +const BPackageInfo& +BSolverPackage::Info() const +{ + return fInfo; +} + + +BString +BSolverPackage::Name() const +{ + return fInfo.Name(); +} + + +BString +BSolverPackage::VersionedName() const +{ + if (fInfo.Version().InitCheck() != B_OK) + return Name(); + BString result = Name(); + return result << '-' << fInfo.Version().ToString(); +} + + +BSolverPackage& +BSolverPackage::operator=(const BSolverPackage& other) +{ + fRepository = other.fRepository; + fInfo = other.fInfo; + return *this; +} + + +} // namespace BPackageKit diff --git a/src/kits/package/solver/SolverPackageSpecifierList.cpp b/src/kits/package/solver/SolverPackageSpecifierList.cpp index b15c776a5f..6544179079 100644 --- a/src/kits/package/solver/SolverPackageSpecifierList.cpp +++ b/src/kits/package/solver/SolverPackageSpecifierList.cpp @@ -101,6 +101,13 @@ BSolverPackageSpecifierList::AppendSpecifier( } +void +BSolverPackageSpecifierList::MakeEmpty() +{ + fSpecifiers->clear(); +} + + BSolverPackageSpecifierList& BSolverPackageSpecifierList::operator=(const BSolverPackageSpecifierList& other) { diff --git a/src/kits/package/solver/SolverProblem.cpp b/src/kits/package/solver/SolverProblem.cpp new file mode 100644 index 0000000000..034f3d2ad6 --- /dev/null +++ b/src/kits/package/solver/SolverProblem.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include + +#include + +#include + + +static const char* const kToStringTexts[] = { + "unspecified problem", + "%source% does not belong to a distupgrade repository", + "%source% has inferior architecture", + "problem with installed package %source%", + "conflicting requests", + "nothing provides requested %dependency%", + "%dependency% is provided by the system", + "dependency problem", + "package %source% is not installable", + "nothing provides %dependency% needed by %source%", + "cannot install both %source% and %target%", + "package %source% conflicts with %dependency% provided by %target%", + "package %source% obsoletes %dependency% provided by %target%", + "installed package %source% obsoletes %dependency% provided by %target%", + "package %source% implicitly obsoletes %dependency% provided by %target%", + "package %source% requires %dependency%, but none of the providers can be " + "installed", + "package %source% conflicts with %dependency% provided by itself" +}; + + +namespace BPackageKit { + + +BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage, + BSolverPackage* targetPackage) + : + fType(type), + fSourcePackage(sourcePackage), + fTargetPackage(targetPackage), + fDependency() +{ +} + + +BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage, + BSolverPackage* targetPackage, + const BPackageResolvableExpression& dependency) + : + fType(type), + fSourcePackage(sourcePackage), + fTargetPackage(targetPackage), + fDependency(dependency) +{ +} + + +BSolverProblem::~BSolverProblem() +{ +} + + +BSolverProblem::BType +BSolverProblem::Type() const +{ + return fType; +} + + +BSolverPackage* +BSolverProblem::SourcePackage() const +{ + return fSourcePackage; +} + + +BSolverPackage* +BSolverProblem::TargetPackage() const +{ + return fTargetPackage; +} + + +const BPackageResolvableExpression& +BSolverProblem::Dependency() const +{ + return fDependency; +} + + +BString +BSolverProblem::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("%dependency%", + fDependency.InitCheck() == B_OK + ? fDependency.ToString().String() : "?"); +} + + +} // namespace BPackageKit diff --git a/src/kits/package/solver/SolverRepository.cpp b/src/kits/package/solver/SolverRepository.cpp index 93c2f78707..d3bd4dd141 100644 --- a/src/kits/package/solver/SolverRepository.cpp +++ b/src/kits/package/solver/SolverRepository.cpp @@ -13,6 +13,10 @@ #include #include #include +#include + + +static const int32 kInitialPackageListSize = 40; namespace BPackageKit { @@ -23,7 +27,7 @@ BSolverRepository::BSolverRepository() fName(), fPriority(0), fIsInstalled(false), - fPackages() + fPackages(kInitialPackageListSize, true) { } @@ -33,7 +37,7 @@ BSolverRepository::BSolverRepository(const BString& name) fName(), fPriority(0), fIsInstalled(false), - fPackages() + fPackages(kInitialPackageListSize, true) { SetTo(name); } @@ -44,7 +48,7 @@ BSolverRepository::BSolverRepository(BPackageInstallationLocation location) fName(), fPriority(0), fIsInstalled(false), - fPackages() + fPackages(kInitialPackageListSize, true) { SetTo(location); } @@ -55,7 +59,7 @@ BSolverRepository::BSolverRepository(BAllInstallationLocations) fName(), fPriority(0), fIsInstalled(false), - fPackages() + fPackages(kInitialPackageListSize, true) { SetTo(B_ALL_INSTALLATION_LOCATIONS); } @@ -66,7 +70,7 @@ BSolverRepository::BSolverRepository(const BRepositoryConfig& config) fName(), fPriority(0), fIsInstalled(false), - fPackages() + fPackages(kInitialPackageListSize, true) { SetTo(config); } @@ -184,6 +188,13 @@ BSolverRepository::IsInstalled() const } +void +BSolverRepository::SetInstalled(bool isInstalled) +{ + fIsInstalled = isInstalled; +} + + BString BSolverRepository::Name() const { @@ -198,10 +209,37 @@ BSolverRepository::Priority() const } +bool +BSolverRepository::IsEmpty() const +{ + return fPackages.IsEmpty(); +} + + +int32 +BSolverRepository::CountPackages() const +{ + return fPackages.CountItems(); +} + + +BSolverPackage* +BSolverRepository::PackageAt(int32 index) const +{ + return fPackages.ItemAt(index); +} + + status_t BSolverRepository::AddPackage(const BPackageInfo& info) { - return fPackages.AddInfo(info); + BSolverPackage* package = new(std::nothrow) BSolverPackage(this, info); + if (package == NULL || !fPackages.AddItem(package)) { + delete package; + return B_NO_MEMORY; + } + + return B_OK; } @@ -216,7 +254,7 @@ BSolverRepository::AddPackages(BPackageInstallationLocation location) BRepositoryCache::Iterator it = packageInfos.GetIterator(); while (const BPackageInfo* packageInfo = it.Next()) { - error = fPackages.AddInfo(*packageInfo); + error = AddPackage(*packageInfo); if (error != B_OK) return error; } @@ -225,11 +263,4 @@ BSolverRepository::AddPackages(BPackageInstallationLocation location) } -BSolverRepository::Iterator -BSolverRepository::GetIterator() const -{ - return fPackages.GetIterator(); -} - - } // namespace BPackageKit diff --git a/src/kits/package/solver/SolverResult.cpp b/src/kits/package/solver/SolverResult.cpp new file mode 100644 index 0000000000..581233969a --- /dev/null +++ b/src/kits/package/solver/SolverResult.cpp @@ -0,0 +1,120 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include + + +namespace BPackageKit { + + +// #pragma mark - BSolverResultElement + + +BSolverResultElement::BSolverResultElement(BType type, BSolverPackage* package) + : + fType(type), + fPackage(package) +{ +} + + +BSolverResultElement::BSolverResultElement(const BSolverResultElement& other) + : + fType(other.fType), + fPackage(other.fPackage) +{ +} + + +BSolverResultElement::~BSolverResultElement() +{ +} + + +BSolverResultElement::BType +BSolverResultElement::Type() const +{ + return fType; +} + + +BSolverPackage* +BSolverResultElement::Package() const +{ + return fPackage; +} + + +BSolverResultElement& +BSolverResultElement::operator=(const BSolverResultElement& other) +{ + fType = other.fType; + fPackage = other.fPackage; + return *this; +} + + +// #pragma mark - BSolverResult + + +BSolverResult::BSolverResult() + : + fElements(20, true) +{ +} + + +BSolverResult::~BSolverResult() +{ +} + + +bool +BSolverResult::IsEmpty() const +{ + return fElements.IsEmpty(); +} + + +int32 +BSolverResult::CountElements() const +{ + return fElements.CountItems(); +} + + +const BSolverResultElement* +BSolverResult::ElementAt(int32 index) const +{ + return fElements.ItemAt(index); +} + + +void +BSolverResult::MakeEmpty() +{ + fElements.MakeEmpty(); +} + + +bool +BSolverResult::AppendElement(const BSolverResultElement& element) +{ + BSolverResultElement* newElement + = new(std::nothrow) BSolverResultElement(element); + if (newElement == NULL || !fElements.AddItem(newElement)) { + delete newElement; + return false; + } + + return true; +} + + +} // namespace BPackageKit