Flesh out the package kit solver API quite a bit more
* Reorganize things a bit:
- BSolver is now an abstract base class.
- A libsolv based implementation, LibsolvSolver, lives in a new
add-on, which is loaded lazily.
- Get rid of libpackage_solver. Save for LibsolvSolver everything
is moved to libpackage.
- This is a nicer solution for the cyclic dependency caused by
libsolv (libsolvext to be precise) using the package kit for
reading repositories and package files.
* Add a solver result data structure and and an accessor the solver.
* Add problem reporting support to the solver. There aren't data
structures for the problem solutions yet and support for selecting
solutions and re-solving is missing as well.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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 <package/PackageInfo.h>
|
||||
|
||||
|
||||
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_
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
|
||||
bool AppendSpecifier(
|
||||
const BSolverPackageSpecifier& specifier);
|
||||
void MakeEmpty();
|
||||
|
||||
BSolverPackageSpecifierList& operator=(
|
||||
const BSolverPackageSpecifierList& other);
|
||||
|
||||
@@ -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 <package/PackageResolvableExpression.h>
|
||||
|
||||
|
||||
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_
|
||||
@@ -6,6 +6,7 @@
|
||||
#define _PACKAGE__SOLVER_REPOSITORY_H_
|
||||
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <package/PackageDefs.h>
|
||||
#include <package/PackageInfoSet.h>
|
||||
#include <String.h>
|
||||
@@ -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<BSolverPackage> PackageList;
|
||||
|
||||
private:
|
||||
BString fName;
|
||||
uint8 fPriority;
|
||||
bool fIsInstalled;
|
||||
BPackageInfoSet fPackages;
|
||||
PackageList fPackages;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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 <ObjectList.h>
|
||||
|
||||
|
||||
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<BSolverResultElement> ElementList;
|
||||
|
||||
private:
|
||||
ElementList fElements;
|
||||
};
|
||||
|
||||
|
||||
} // namespace BPackageKit
|
||||
|
||||
|
||||
#endif // _PACKAGE__SOLVER_RESULT_H_
|
||||
@@ -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++)
|
||||
;
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include "LibsolvSolver.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <solv/poolarch.h>
|
||||
#include <solv/repo.h>
|
||||
#include <solv/repo_haiku.h>
|
||||
#include <solv/selection.h>
|
||||
#include <solv/solverdebug.h>
|
||||
|
||||
#include <package/PackageResolvableExpression.h>
|
||||
#include <package/RepositoryCache.h>
|
||||
#include <package/solver/SolverPackage.h>
|
||||
#include <package/solver/SolverPackageSpecifier.h>
|
||||
#include <package/solver/SolverPackageSpecifierList.h>
|
||||
#include <package/solver/SolverProblem.h>
|
||||
#include <package/solver/SolverRepository.h>
|
||||
#include <package/solver/SolverResult.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
|
||||
// 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<Transaction> 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;
|
||||
}
|
||||
@@ -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 <map>
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <package/solver/Solver.h>
|
||||
|
||||
#include <solv/pool.h>
|
||||
#include <solv/solver.h>
|
||||
|
||||
|
||||
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<RepositoryInfo> RepositoryInfoList;
|
||||
typedef BObjectList<BSolverProblem> ProblemList;
|
||||
typedef std::map<Solvable*, BSolverPackage*> 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
|
||||
@@ -9,348 +9,62 @@
|
||||
|
||||
#include <package/solver/Solver.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <solv/pool.h>
|
||||
#include <solv/poolarch.h>
|
||||
#include <solv/repo.h>
|
||||
#include <solv/repo_haiku.h>
|
||||
#include <solv/selection.h>
|
||||
#include <solv/solver.h>
|
||||
|
||||
#include <package/RepositoryCache.h>
|
||||
#include <package/solver/SolverPackageSpecifier.h>
|
||||
#include <package/solver/SolverPackageSpecifierList.h>
|
||||
#include <package/solver/SolverRepository.h>
|
||||
|
||||
#include <ObjectList.h>
|
||||
|
||||
|
||||
// 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 <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
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<RepositoryInfo> 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
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include <package/solver/SolverPackage.h>
|
||||
|
||||
|
||||
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
|
||||
@@ -101,6 +101,13 @@ BSolverPackageSpecifierList::AppendSpecifier(
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BSolverPackageSpecifierList::MakeEmpty()
|
||||
{
|
||||
fSpecifiers->clear();
|
||||
}
|
||||
|
||||
|
||||
BSolverPackageSpecifierList&
|
||||
BSolverPackageSpecifierList::operator=(const BSolverPackageSpecifierList& other)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include <package/solver/SolverProblem.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <package/solver/SolverPackage.h>
|
||||
|
||||
|
||||
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
|
||||
@@ -13,6 +13,10 @@
|
||||
#include <package/PackageRoster.h>
|
||||
#include <package/RepositoryCache.h>
|
||||
#include <package/RepositoryConfig.h>
|
||||
#include <package/solver/SolverPackage.h>
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include <package/solver/SolverResult.h>
|
||||
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user