From 3ac0de3b1fac18912d6cb7758b502468e3802ee9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 21 Apr 2013 12:31:29 +0200 Subject: [PATCH] pkgman: Refactoring -> PackageManager Move common and reusable functionality from "search" and "install" to new PackageManager class. --- src/bin/pkgman/Jamfile | 1 + src/bin/pkgman/PackageManager.cpp | 396 +++++++++++++++++++++++++++++ src/bin/pkgman/PackageManager.h | 94 +++++++ src/bin/pkgman/command_install.cpp | 339 +----------------------- src/bin/pkgman/command_search.cpp | 75 +----- 5 files changed, 505 insertions(+), 400 deletions(-) create mode 100644 src/bin/pkgman/PackageManager.cpp create mode 100644 src/bin/pkgman/PackageManager.h diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile index cb8328a9f2..4669d214f2 100644 --- a/src/bin/pkgman/Jamfile +++ b/src/bin/pkgman/Jamfile @@ -14,6 +14,7 @@ BinCommand pkgman : DecisionProvider.cpp JobStateListener.cpp PackageInfoErrorListener.cpp + PackageManager.cpp pkgman.cpp RepositoryBuilder.cpp : diff --git a/src/bin/pkgman/PackageManager.cpp b/src/bin/pkgman/PackageManager.cpp new file mode 100644 index 0000000000..e099995bfc --- /dev/null +++ b/src/bin/pkgman/PackageManager.cpp @@ -0,0 +1,396 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include "PackageManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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(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"); + } +} diff --git a/src/bin/pkgman/PackageManager.h b/src/bin/pkgman/PackageManager.h new file mode 100644 index 0000000000..7a8ebd050c --- /dev/null +++ b/src/bin/pkgman/PackageManager.h @@ -0,0 +1,94 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ +#ifndef PACKAGE_MANAGER_H +#define PACKAGE_MANAGER_H + + +#include +#include +#include +#include +#include +#include +#include + +#include "DecisionProvider.h" +#include "JobStateListener.h" + + +using namespace BPackageKit; + + +class PackageManager { +public: + struct Repository; + typedef BObjectList 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& InstalledRepositories() const + { return fInstalledRepositories; } + const RepositoryList& OtherRepositories() const + { return fOtherRepositories; } + + void Install(const char* const* packages, + int packageCount); + +private: + typedef BObjectList PackageList; + +private: + void _HandleProblems(); + void _AnalyzeResult(); + void _PrintResult(); + void _ApplyPackageChanges(); + +private: + BPackageInstallationLocation fLocation; + BSolver* fSolver; + BSolverRepository fSystemRepository; + BSolverRepository fCommonRepository; + BSolverRepository fHomeRepository; + BObjectList 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 diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp index 1bcbeff777..da9c77ff1a 100644 --- a/src/bin/pkgman/command_install.cpp +++ b/src/bin/pkgman/command_install.cpp @@ -7,31 +7,13 @@ */ -#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - #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 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 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 packagesToActivate; - BObjectList 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(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; } diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp index f65db3eefc..9d2a72b6c0 100644 --- a/src/bin/pkgman/command_search.cpp +++ b/src/bin/pkgman/command_search.cpp @@ -14,14 +14,13 @@ #include #include -#include -#include +#include -#include +#include #include "Command.h" +#include "PackageManager.h" #include "pkgman.h" -#include "RepositoryBuilder.h" // TODO: internationalization! @@ -32,9 +31,6 @@ using namespace BPackageKit; -typedef std::map PackagePathMap; - - static const char* const kShortUsage = " %command% \n" " Searches for packages matching .\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 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 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",