pkgman: Refactoring -> PackageManager

Move common and reusable functionality from "search" and "install" to
new PackageManager class.
This commit is contained in:
Ingo Weinhold
2013-04-21 12:31:29 +02:00
parent c128275ede
commit 3ac0de3b1f
5 changed files with 505 additions and 400 deletions
+1
View File
@@ -14,6 +14,7 @@ BinCommand pkgman :
DecisionProvider.cpp
JobStateListener.cpp
PackageInfoErrorListener.cpp
PackageManager.cpp
pkgman.cpp
RepositoryBuilder.cpp
:
+396
View File
@@ -0,0 +1,396 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <[email protected]>
*/
#include "PackageManager.h"
#include <Directory.h>
#include <package/DownloadFileRequest.h>
#include <package/PackageRoster.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/solver/SolverPackage.h>
#include <package/solver/SolverPackageSpecifier.h>
#include <package/solver/SolverPackageSpecifierList.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverProblemSolution.h>
#include <package/solver/SolverResult.h>
#include <package/ActivationTransaction.h>
#include <package/DaemonClient.h>
#include "pkgman.h"
#include "RepositoryBuilder.h"
using namespace BPackageKit::BPrivate;
// #pragma mark - Repository
PackageManager::Repository::Repository()
:
BSolverRepository()
{
}
status_t
PackageManager::Repository::Init(BPackageRoster& roster, BContext& context,
const char* name)
{
// get the repository config
status_t error = roster.GetRepositoryConfig(name, &fConfig);
if (error != B_OK)
return error;
// refresh
BRefreshRepositoryRequest refreshRequest(context, fConfig);
error = refreshRequest.Process();
if (error != B_OK) {
WARN(error, "refreshing repository \"%s\" failed", name);
return B_OK;
}
// re-get the config
return roster.GetRepositoryConfig(name, &fConfig);
}
const BRepositoryConfig&
PackageManager::Repository::Config() const
{
return fConfig;
}
// #pragma mark - Solver
PackageManager::PackageManager(BPackageInstallationLocation location,
bool addInstalledRepositories, bool addOtherRepositories)
:
fLocation(location),
fSolver(NULL),
fSystemRepository(),
fCommonRepository(),
fHomeRepository(),
fInstalledRepositories(10),
fOtherRepositories(10, true),
fDecisionProvider(),
fJobStateListener(),
fContext(fDecisionProvider, fJobStateListener)
{
// create the solver
status_t error = BSolver::Create(fSolver);
if (error != B_OK)
DIE(error, "failed to create solver");
// add installation location repositories
if (addInstalledRepositories) {
// We add only the repository of our actual installation location as the
// "installed" repository. The repositories for the more general
// installation locations are added as regular repositories, but with
// better priorities than the actual (remote) repositories. This
// prevents the solver from showing conflicts when a package in a more
// specific installation location overrides a package in a more general
// one. Instead any requirement that is already installed in a more
// general installation location will turn up as to be installed as
// well. But we can easily filter those out.
RepositoryBuilder(fSystemRepository, "system")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
.AddToSolver(fSolver, false);
fSystemRepository.SetPriority(-1);
bool installInHome = location == B_PACKAGE_INSTALLATION_LOCATION_HOME;
RepositoryBuilder(fCommonRepository, "common")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
.AddToSolver(fSolver, !installInHome);
if (!fInstalledRepositories.AddItem(&fSystemRepository)
|| !fInstalledRepositories.AddItem(&fCommonRepository)) {
DIE(B_NO_MEMORY, "failed to add installed repositories to list");
}
if (installInHome) {
fCommonRepository.SetPriority(-2);
RepositoryBuilder(fHomeRepository, "home")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
.AddToSolver(fSolver, true);
if (!fInstalledRepositories.AddItem(&fHomeRepository))
DIE(B_NO_MEMORY, "failed to add home repository to list");
}
}
// add other repositories
if (addOtherRepositories) {
BPackageRoster roster;
BStringList repositoryNames;
error = roster.GetRepositoryNames(repositoryNames);
if (error != B_OK)
WARN(error, "failed to get repository names");
int32 repositoryNameCount = repositoryNames.CountStrings();
for (int32 i = 0; i < repositoryNameCount; i++) {
Repository* repository = new(std::nothrow) Repository;
if (repository == NULL || !fOtherRepositories.AddItem(repository))
DIE(B_NO_MEMORY, "failed to create/add repository object");
const BString& name = repositoryNames.StringAt(i);
error = repository->Init(roster, fContext, name);
if (error != B_OK) {
WARN(error,
"failed to get config for repository \"%s\". Skipping.",
name.String());
fOtherRepositories.RemoveItem(repository, true);
continue;
}
RepositoryBuilder(*repository, repository->Config())
.AddToSolver(fSolver, false);
}
}
}
PackageManager::~PackageManager()
{
}
void
PackageManager::Install(const char* const* packages, int packageCount)
{
// solve
BSolverPackageSpecifierList packagesToInstall;
for (int i = 0; i < packageCount; i++) {
if (!packagesToInstall.AppendSpecifier(packages[i]))
DIE(B_NO_MEMORY, "failed to add specified package");
}
const BSolverPackageSpecifier* unmatchedSpecifier;
status_t error = fSolver->Install(packagesToInstall, &unmatchedSpecifier);
if (error != B_OK) {
if (unmatchedSpecifier != NULL) {
DIE(error, "failed to find a match for \"%s\"",
unmatchedSpecifier->SelectString().String());
} else
DIE(error, "failed to compute packages to install");
}
_HandleProblems();
// install/uninstall packages
_AnalyzeResult();
_PrintResult();
_ApplyPackageChanges();
}
void
PackageManager::_HandleProblems()
{
while (fSolver->HasProblems()) {
printf("Encountered problems:\n");
int32 problemCount = fSolver->CountProblems();
for (int32 i = 0; i < problemCount; i++) {
// print problem and possible solutions
BSolverProblem* problem = fSolver->ProblemAt(i);
printf("problem %" B_PRId32 ": %s\n", i + 1,
problem->ToString().String());
int32 solutionCount = problem->CountSolutions();
for (int32 k = 0; k < solutionCount; k++) {
const BSolverProblemSolution* solution = problem->SolutionAt(k);
printf(" solution %" B_PRId32 ":\n", k + 1);
int32 elementCount = solution->CountElements();
for (int32 l = 0; l < elementCount; l++) {
const BSolverProblemSolutionElement* element
= solution->ElementAt(l);
printf(" - %s\n", element->ToString().String());
}
}
// let the user choose a solution
printf("Please select a solution, skip the problem for now or "
"quit.\n");
for (;;) {
if (solutionCount > 1)
printf("select [1...%" B_PRId32 "/s/q]: ", solutionCount);
else
printf("select [1/s/q]: ");
char buffer[32];
if (fgets(buffer, sizeof(buffer), stdin) == NULL
|| strcmp(buffer, "q\n") == 0) {
exit(1);
}
if (strcmp(buffer, "s\n") == 0)
break;
char* end;
long selected = strtol(buffer, &end, 0);
if (end == buffer || *end != '\n' || selected < 1
|| selected > solutionCount) {
printf("*** invalid input\n");
continue;
}
status_t error = fSolver->SelectProblemSolution(problem,
problem->SolutionAt(selected - 1));
if (error != B_OK)
DIE(error, "failed to set solution");
break;
}
}
status_t error = fSolver->SolveAgain();
if (error != B_OK)
DIE(error, "failed to compute packages to install");
}
}
void
PackageManager::_AnalyzeResult()
{
BSolverResult result;
status_t error = fSolver->GetResult(result);
if (error != B_OK)
DIE(error, "failed to compute packages to install");
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
i++) {
BSolverPackage* package = element->Package();
switch (element->Type()) {
case BSolverResultElement::B_TYPE_INSTALL:
if (!fInstalledRepositories.HasItem(package->Repository())) {
if (!fPackagesToActivate.AddItem(package))
DIE(B_NO_MEMORY, "failed to add package to activate");
}
break;
case BSolverResultElement::B_TYPE_UNINSTALL:
if (!fPackagesToDeactivate.AddItem(package))
DIE(B_NO_MEMORY, "failed to add package to deactivate");
break;
}
}
if (fPackagesToActivate.IsEmpty() && fPackagesToDeactivate.IsEmpty()) {
printf("Nothing to do.\n");
exit(0);
}
}
void
PackageManager::_PrintResult()
{
printf("The following changes will be made:\n");
for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i);
i++) {
printf(" install package %s from repository %s\n",
package->Info().CanonicalFileName().String(),
package->Repository()->Name().String());
}
for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
i++) {
printf(" uninstall package %s\n", package->VersionedName().String());
}
// TODO: Print file/download sizes. Unfortunately our package infos don't
// contain the file size. Which is probably correct. The file size (and possibly
// other information) should, however, be provided by the repository cache in
// some way. Extend BPackageInfo? Create a BPackageFileInfo?
if (!fDecisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n",
"y")) {
exit(1);
}
}
void
PackageManager::_ApplyPackageChanges()
{
// create an activation transaction
BDaemonClient daemonClient;
BActivationTransaction transaction;
BDirectory transactionDirectory;
status_t error = daemonClient.CreateTransaction(fLocation, transaction,
transactionDirectory);
if (error != B_OK)
DIE(error, "failed to create transaction");
// download the new packages and prepare the transaction
for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i);
i++) {
// get package URL and target entry
Repository* repository
= static_cast<Repository*>(package->Repository());
BString url = repository->Config().BaseURL();
BString fileName(package->Info().CanonicalFileName());
if (fileName.IsEmpty())
DIE(B_NO_MEMORY, "failed to allocate file name");
url << '/' << fileName;
BEntry entry;
error = entry.SetTo(&transactionDirectory, fileName);
if (error != B_OK)
DIE(error, "failed to create package entry");
// download the package
DownloadFileRequest downloadRequest(fContext, url, entry,
package->Info().Checksum());
error = downloadRequest.Process();
if (error != B_OK)
DIE(error, "failed to download package");
// add package to transaction
if (!transaction.AddPackageToActivate(
package->Info().CanonicalFileName())) {
DIE(B_NO_MEMORY,
"failed to add package to activate to transaction");
}
}
for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
i++) {
// add package to transaction
if (!transaction.AddPackageToDeactivate(
package->Info().CanonicalFileName())) {
DIE(B_NO_MEMORY,
"failed to add package to deactivate to transaction");
}
}
// commit the transaction
BDaemonClient::BCommitTransactionResult transactionResult;
error = daemonClient.CommitTransaction(transaction, transactionResult);
if (error != B_OK) {
fprintf(stderr, "*** failed to commit transaction: %s\n",
transactionResult.FullErrorMessage().String());
exit(1);
}
printf("Installation done. Old activation state backed up in \"%s\"\n",
transactionResult.OldStateDirectory().String());
printf("Cleaning up ...\n");
BEntry transactionDirectoryEntry;
if ((error = transactionDirectory.GetEntry(&transactionDirectoryEntry))
!= B_OK
|| (error = transactionDirectoryEntry.Remove()) != B_OK) {
WARN(error, "failed to remove transaction directory");
}
}
+94
View File
@@ -0,0 +1,94 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <[email protected]>
*/
#ifndef PACKAGE_MANAGER_H
#define PACKAGE_MANAGER_H
#include <ObjectList.h>
#include <package/Context.h>
#include <package/PackageDefs.h>
#include <package/PackageRoster.h>
#include <package/RepositoryConfig.h>
#include <package/solver/Solver.h>
#include <package/solver/SolverRepository.h>
#include "DecisionProvider.h"
#include "JobStateListener.h"
using namespace BPackageKit;
class PackageManager {
public:
struct Repository;
typedef BObjectList<Repository> RepositoryList;
public:
PackageManager(
BPackageInstallationLocation location,
bool addInstalledRepositories,
bool addOtherRepositories);
~PackageManager();
BSolver* Solver() const
{ return fSolver; }
const BSolverRepository* SystemRepository() const
{ return &fSystemRepository; }
const BSolverRepository* CommonRepository() const
{ return &fCommonRepository; }
const BSolverRepository* HomeRepository() const
{ return &fHomeRepository; }
const BObjectList<BSolverRepository>& InstalledRepositories() const
{ return fInstalledRepositories; }
const RepositoryList& OtherRepositories() const
{ return fOtherRepositories; }
void Install(const char* const* packages,
int packageCount);
private:
typedef BObjectList<BSolverPackage> PackageList;
private:
void _HandleProblems();
void _AnalyzeResult();
void _PrintResult();
void _ApplyPackageChanges();
private:
BPackageInstallationLocation fLocation;
BSolver* fSolver;
BSolverRepository fSystemRepository;
BSolverRepository fCommonRepository;
BSolverRepository fHomeRepository;
BObjectList<BSolverRepository> fInstalledRepositories;
RepositoryList fOtherRepositories;
DecisionProvider fDecisionProvider;
JobStateListener fJobStateListener;
BContext fContext;
PackageList fPackagesToActivate;
PackageList fPackagesToDeactivate;
};
struct PackageManager::Repository : public BSolverRepository {
Repository();
status_t Init(BPackageRoster& roster, BContext& context,
const char* name);
const BRepositoryConfig& Config() const;
private:
BRepositoryConfig fConfig;
};
#endif // PACKAGE_MANAGER_H
+4 -335
View File
@@ -7,31 +7,13 @@
*/
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <Directory.h>
#include <package/DownloadFileRequest.h>
#include <package/PackageRoster.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/RepositoryConfig.h>
#include <package/solver/SolverPackageSpecifier.h>
#include <package/solver/SolverPackageSpecifierList.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverProblemSolution.h>
#include <package/solver/SolverResult.h>
#include <AutoDeleter.h>
#include <package/ActivationTransaction.h>
#include <package/DaemonClient.h>
#include "Command.h"
#include "DecisionProvider.h"
#include "JobStateListener.h"
#include "pkgman.h"
#include "RepositoryBuilder.h"
#include "PackageManager.h"
// TODO: internationalization!
@@ -59,42 +41,6 @@ static const char* const kLongUsage =
DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage)
struct Repository : public BSolverRepository {
Repository()
:
BSolverRepository()
{
}
status_t Init(BPackageRoster& roster, BContext& context, const char* name)
{
// get the repository config
status_t error = roster.GetRepositoryConfig(name, &fConfig);
if (error != B_OK)
return error;
// refresh
BRefreshRepositoryRequest refreshRequest(context, fConfig);
error = refreshRequest.Process();
if (error != B_OK) {
WARN(error, "refreshing repository \"%s\" failed", name);
return B_OK;
}
// re-get the config
return roster.GetRepositoryConfig(name, &fConfig);
}
const BRepositoryConfig& Config() const
{
return fConfig;
}
private:
BRepositoryConfig fConfig;
};
int
InstallCommand::Execute(int argc, const char* const* argv)
{
@@ -134,289 +80,12 @@ InstallCommand::Execute(int argc, const char* const* argv)
int packageCount = argc - optind;
const char* const* packages = argv + optind;
// create the solver
BSolver* solver;
status_t error = BSolver::Create(solver);
if (error != B_OK)
DIE(error, "failed to create solver");
// add repositories
// We add only the repository of our actual installation location as the
// "installed" repository. The repositories for the more general
// installation locations are added as regular repositories, but with better
// priorities than the actual (remote) repositories. This prevents the solver
// from showing conflicts when a package in a more specific installation
// location overrides a package in a more general one. Instead any
// requirement that is already installed in a more general installation
// location will turn up as to be installed as well. But we can easily
// filter those out.
BSolverRepository systemRepository;
RepositoryBuilder(systemRepository, "system")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
.AddToSolver(solver, false);
systemRepository.SetPriority(-1);
BSolverRepository commonRepository;
RepositoryBuilder(commonRepository, "common")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
.AddToSolver(solver, !installInHome);
BObjectList<BSolverRepository> installedRepositories(10);
if (!installedRepositories.AddItem(&systemRepository)
|| !installedRepositories.AddItem(&commonRepository)) {
DIE(B_NO_MEMORY, "failed to add installed repositories to list");
}
BSolverRepository homeRepository;
if (installInHome) {
commonRepository.SetPriority(-2);
RepositoryBuilder(homeRepository, "home")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
.AddToSolver(solver, true);
if (!installedRepositories.AddItem(&homeRepository))
DIE(B_NO_MEMORY, "failed to add home repository to list");
}
// other repositories
DecisionProvider decisionProvider;
JobStateListener listener;
BContext context(decisionProvider, listener);
BObjectList<Repository> otherRepositories(10, true);
BPackageRoster roster;
BStringList repositoryNames;
error = roster.GetRepositoryNames(repositoryNames);
if (error != B_OK)
WARN(error, "failed to get repository names");
int32 repositoryNameCount = repositoryNames.CountStrings();
for (int32 i = 0; i < repositoryNameCount; i++) {
Repository* repository = new(std::nothrow) Repository;
if (repository == NULL || !otherRepositories.AddItem(repository))
DIE(B_NO_MEMORY, "failed to create/add repository object");
const BString& name = repositoryNames.StringAt(i);
error = repository->Init(roster, context, name);
if (error != B_OK) {
WARN(error, "failed to get config for repository \"%s\". Skipping.",
name.String());
otherRepositories.RemoveItem(repository, true);
continue;
}
RepositoryBuilder(*repository, repository->Config())
.AddToSolver(solver, false);
}
// solve
BSolverPackageSpecifierList packagesToInstall;
for (int i = 0; i < packageCount; i++) {
if (!packagesToInstall.AppendSpecifier(packages[i]))
DIE(B_NO_MEMORY, "failed to add specified package");
}
const BSolverPackageSpecifier* unmatchedSpecifier;
error = solver->Install(packagesToInstall, &unmatchedSpecifier);
if (error != B_OK) {
if (unmatchedSpecifier != NULL) {
DIE(error, "failed to find a match for \"%s\"",
unmatchedSpecifier->SelectString().String());
} else
DIE(error, "failed to compute packages to install");
}
// deal with problems
while (solver->HasProblems()) {
printf("Encountered problems:\n");
int32 problemCount = solver->CountProblems();
for (int32 i = 0; i < problemCount; i++) {
// print problem and possible solutions
BSolverProblem* problem = solver->ProblemAt(i);
printf("problem %" B_PRId32 ": %s\n", i + 1,
problem->ToString().String());
int32 solutionCount = problem->CountSolutions();
for (int32 k = 0; k < solutionCount; k++) {
const BSolverProblemSolution* solution = problem->SolutionAt(k);
printf(" solution %" B_PRId32 ":\n", k + 1);
int32 elementCount = solution->CountElements();
for (int32 l = 0; l < elementCount; l++) {
const BSolverProblemSolutionElement* element
= solution->ElementAt(l);
printf(" - %s\n", element->ToString().String());
}
}
// let the user choose a solution
printf("Please select a solution, skip the problem for now or "
"quit.\n");
for (;;) {
if (solutionCount > 1)
printf("select [1...%" B_PRId32 "/s/q]: ", solutionCount);
else
printf("select [1/s/q]: ");
char buffer[32];
if (fgets(buffer, sizeof(buffer), stdin) == NULL
|| strcmp(buffer, "q\n") == 0) {
exit(1);
}
if (strcmp(buffer, "s\n") == 0)
break;
char* end;
long selected = strtol(buffer, &end, 0);
if (end == buffer || *end != '\n' || selected < 1
|| selected > solutionCount) {
printf("*** invalid input\n");
continue;
}
error = solver->SelectProblemSolution(problem,
problem->SolutionAt(selected - 1));
if (error != B_OK)
DIE(error, "failed to set solution");
break;
}
}
error = solver->SolveAgain();
if (error != B_OK)
DIE(error, "failed to compute packages to install");
}
// print result
BSolverResult result;
error = solver->GetResult(result);
if (error != B_OK)
DIE(error, "failed to compute packages to install");
BObjectList<BSolverPackage> packagesToActivate;
BObjectList<BSolverPackage> packagesToDeactivate;
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
i++) {
BSolverPackage* package = element->Package();
switch (element->Type()) {
case BSolverResultElement::B_TYPE_INSTALL:
if (!installedRepositories.HasItem(package->Repository())) {
if (!packagesToActivate.AddItem(package))
DIE(B_NO_MEMORY, "failed to add package to activate");
}
break;
case BSolverResultElement::B_TYPE_UNINSTALL:
if (!packagesToDeactivate.AddItem(package))
DIE(B_NO_MEMORY, "failed to add package to deactivate");
break;
}
}
if (packagesToActivate.IsEmpty() && packagesToDeactivate.IsEmpty()) {
printf("Nothing to do.\n");
exit(0);
}
printf("The following changes will be made:\n");
for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
i++) {
printf(" install package %s from repository %s\n",
package->Info().CanonicalFileName().String(),
package->Repository()->Name().String());
}
for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
i++) {
printf(" uninstall package %s\n", package->VersionedName().String());
}
// TODO: Print file/download sizes. Unfortunately our package infos don't
// contain the file size. Which is probably correct. The file size (and possibly
// other information) should, however, be provided by the repository cache in
// some way. Extend BPackageInfo? Create a BPackageFileInfo?
if (!decisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n",
"y")) {
return 1;
}
// create an activation transaction
BDaemonClient daemonClient;
// perform the installation
BPackageInstallationLocation location = installInHome
? B_PACKAGE_INSTALLATION_LOCATION_HOME
: B_PACKAGE_INSTALLATION_LOCATION_COMMON;
BActivationTransaction transaction;
BDirectory transactionDirectory;
error = daemonClient.CreateTransaction(location, transaction,
transactionDirectory);
if (error != B_OK)
DIE(error, "failed to create transaction");
// download the new packages and prepare the transaction
for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
i++) {
// get package URL and target entry
Repository* repository
= static_cast<Repository*>(package->Repository());
BString url = repository->Config().BaseURL();
BString fileName(package->Info().CanonicalFileName());
if (fileName.IsEmpty())
DIE(B_NO_MEMORY, "failed to allocate file name");
url << '/' << fileName;
BEntry entry;
error = entry.SetTo(&transactionDirectory, fileName);
if (error != B_OK)
DIE(error, "failed to create package entry");
// download the package
DownloadFileRequest downloadRequest(context, url, entry,
package->Info().Checksum());
error = downloadRequest.Process();
if (error != B_OK)
DIE(error, "failed to download package");
// add package to transaction
if (!transaction.AddPackageToActivate(
package->Info().CanonicalFileName())) {
DIE(B_NO_MEMORY,
"failed to add package to activate to transaction");
}
}
for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
i++) {
// add package to transaction
if (!transaction.AddPackageToDeactivate(
package->Info().CanonicalFileName())) {
DIE(B_NO_MEMORY,
"failed to add package to deactivate to transaction");
}
}
// commit the transaction
BDaemonClient::BCommitTransactionResult transactionResult;
error = daemonClient.CommitTransaction(transaction, transactionResult);
if (error != B_OK) {
fprintf(stderr, "*** failed to commit transaction: %s\n",
transactionResult.FullErrorMessage().String());
exit(1);
}
printf("Installation done. Old activation state backed up in \"%s\"\n",
transactionResult.OldStateDirectory().String());
printf("Cleaning up ...\n");
BEntry transactionDirectoryEntry;
if ((error = transactionDirectory.GetEntry(&transactionDirectoryEntry))
!= B_OK
|| (error = transactionDirectoryEntry.Remove()) != B_OK) {
WARN(error, "failed to remove transaction directory");
}
PackageManager packageManager(location, true, true);
packageManager.Install(packages, packageCount);
return 0;
}
+10 -65
View File
@@ -14,14 +14,13 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include <package/PackageRoster.h>
#include <package/RepositoryConfig.h>
#include <algorithm>
#include <AutoDeleter.h>
#include <package/solver/SolverPackage.h>
#include "Command.h"
#include "PackageManager.h"
#include "pkgman.h"
#include "RepositoryBuilder.h"
// TODO: internationalization!
@@ -32,9 +31,6 @@
using namespace BPackageKit;
typedef std::map<BSolverPackage*, BString> PackagePathMap;
static const char* const kShortUsage =
" %command% <search-string>\n"
" Searches for packages matching <search-string>.\n";
@@ -113,64 +109,13 @@ SearchCommand::Execute(int argc, const char* const* argv)
const char* searchString = argv[optind++];
// create the solver
BSolver* solver;
status_t error = BSolver::Create(solver);
if (error != B_OK)
DIE(error, "failed to create solver");
// add repositories
// installed
BSolverRepository systemRepository;
BSolverRepository commonRepository;
BSolverRepository homeRepository;
if (!uninstalledOnly) {
RepositoryBuilder(systemRepository, "system")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
.AddToSolver(solver, false);
RepositoryBuilder(commonRepository, "common")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
.AddToSolver(solver, false);
// RepositoryBuilder(homeRepository, "home")
// .AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
// .AddToSolver(solver, false);
}
// not installed
BObjectList<BSolverRepository> uninstalledRepositories(10, true);
if (!installedOnly) {
BPackageRoster roster;
BStringList repositoryNames;
error = roster.GetRepositoryNames(repositoryNames);
if (error != B_OK)
WARN(error, "failed to get repository names");
int32 repositoryNameCount = repositoryNames.CountStrings();
for (int32 i = 0; i < repositoryNameCount; i++) {
const BString& name = repositoryNames.StringAt(i);
BRepositoryConfig config;
error = roster.GetRepositoryConfig(name, &config);
if (error != B_OK) {
WARN(error, "failed to get config for repository \"%s\". "
"Skipping.", name.String());
continue;
}
BSolverRepository* repository = new(std::nothrow) BSolverRepository;
if (repository == NULL
|| !uninstalledRepositories.AddItem(repository)) {
DIE(B_NO_MEMORY, "out of memory");
}
RepositoryBuilder(*repository, config)
.AddToSolver(solver, false);
}
}
PackageManager packageManager(B_PACKAGE_INSTALLATION_LOCATION_COMMON,
!uninstalledOnly, !installedOnly);
// TODO: Use B_PACKAGE_INSTALLATION_LOCATION_HOME once we actually mount it.
// search
BObjectList<BSolverPackage> packages;
error = solver->FindPackages(searchString,
status_t error = packageManager.Solver()->FindPackages(searchString,
BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME
| BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION
| BSolver::B_FIND_IN_PROVIDES,
@@ -230,11 +175,11 @@ SearchCommand::Execute(int argc, const char* const* argv)
BSolverPackage* package = packages.ItemAt(i);
const char* installed = "";
if (package->Repository() == &systemRepository)
if (package->Repository() == packageManager.SystemRepository())
installed = "system";
else if (package->Repository() == &commonRepository)
else if (package->Repository() == packageManager.CommonRepository())
installed = "common";
else if (package->Repository() == &homeRepository)
else if (package->Repository() == packageManager.HomeRepository())
installed = "home";
printf("%-*s %-*s %-*.*s\n",