pkgman install: Complete basic functionality

Download package files to install from the respective repositories and
use BDaemonClient to perform the package de-/activation. Still missing
is the interactive problem solution support.
This commit is contained in:
Ingo Weinhold 2013-04-20 21:31:32 +02:00
parent 6a1430716c
commit eee120f987

View File

@ -11,8 +11,9 @@
#include <getopt.h> #include <getopt.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
//#include <sys/stat.h>
#include <Directory.h>
#include <package/DownloadFileRequest.h>
#include <package/PackageRoster.h> #include <package/PackageRoster.h>
#include <package/RepositoryConfig.h> #include <package/RepositoryConfig.h>
#include <package/solver/SolverPackageSpecifier.h> #include <package/solver/SolverPackageSpecifier.h>
@ -22,8 +23,12 @@
#include <package/solver/SolverResult.h> #include <package/solver/SolverResult.h>
#include <AutoDeleter.h> #include <AutoDeleter.h>
#include <package/ActivationTransaction.h>
#include <package/DaemonClient.h>
#include "Command.h" #include "Command.h"
#include "DecisionProvider.h"
#include "JobStateListener.h"
#include "pkgman.h" #include "pkgman.h"
#include "RepositoryBuilder.h" #include "RepositoryBuilder.h"
@ -32,6 +37,7 @@
using namespace BPackageKit; using namespace BPackageKit;
using namespace BPackageKit::BPrivate;
static const char* const kShortUsage = static const char* const kShortUsage =
@ -52,6 +58,28 @@ static const char* const kLongUsage =
DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage) DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage)
struct Repository : public BSolverRepository {
Repository()
:
BSolverRepository()
{
}
status_t Init(BPackageRoster& roster, const char* name)
{
return roster.GetRepositoryConfig(name, &fConfig);
}
const BRepositoryConfig& Config() const
{
return fConfig;
}
private:
BRepositoryConfig fConfig;
};
int int
InstallCommand::Execute(int argc, const char* const* argv) InstallCommand::Execute(int argc, const char* const* argv)
{ {
@ -121,16 +149,25 @@ InstallCommand::Execute(int argc, const char* const* argv)
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common") .AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
.AddToSolver(solver, !installInHome); .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; BSolverRepository homeRepository;
if (installInHome) { if (installInHome) {
commonRepository.SetPriority(-2); commonRepository.SetPriority(-2);
RepositoryBuilder(homeRepository, "home") RepositoryBuilder(homeRepository, "home")
.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home") .AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
.AddToSolver(solver, true); .AddToSolver(solver, true);
if (!installedRepositories.AddItem(&homeRepository))
DIE(B_NO_MEMORY, "failed to add home repository to list");
} }
// other repositories // other repositories
BObjectList<BSolverRepository> otherRepositories(10, true); BObjectList<Repository> otherRepositories(10, true);
BPackageRoster roster; BPackageRoster roster;
BStringList repositoryNames; BStringList repositoryNames;
error = roster.GetRepositoryNames(repositoryNames); error = roster.GetRepositoryNames(repositoryNames);
@ -139,20 +176,20 @@ InstallCommand::Execute(int argc, const char* const* argv)
int32 repositoryNameCount = repositoryNames.CountStrings(); int32 repositoryNameCount = repositoryNames.CountStrings();
for (int32 i = 0; i < repositoryNameCount; i++) { for (int32 i = 0; i < repositoryNameCount; i++) {
const BString& name = repositoryNames.StringAt(i); Repository* repository = new(std::nothrow) Repository;
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 || !otherRepositories.AddItem(repository)) if (repository == NULL || !otherRepositories.AddItem(repository))
DIE(B_NO_MEMORY, "out of memory"); DIE(B_NO_MEMORY, "out of memory");
RepositoryBuilder(*repository, config) const BString& name = repositoryNames.StringAt(i);
error = repository->Init(roster, 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); .AddToSolver(solver, false);
} }
@ -205,22 +242,124 @@ exit(1);
if (error != B_OK) if (error != B_OK)
DIE(error, "failed to compute packages to install"); DIE(error, "failed to compute packages to install");
printf("transaction:\n"); printf("The following changes will be made:\n");
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i); for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
i++) { i++) {
BSolverPackage* package = element->Package(); BSolverPackage* package = element->Package();
switch (element->Type()) { switch (element->Type()) {
case BSolverResultElement::B_TYPE_INSTALL: case BSolverResultElement::B_TYPE_INSTALL:
if (installedRepositories.HasItem(package->Repository()))
continue;
printf(" install package %s from repository %s\n", printf(" install package %s from repository %s\n",
package->VersionedName().String(), package->Info().CanonicalFileName().String(),
package->Repository()->Name().String()); package->Repository()->Name().String());
break; break;
case BSolverResultElement::B_TYPE_UNINSTALL: case BSolverResultElement::B_TYPE_UNINSTALL:
printf(" uninstall package %s\n", printf(" uninstall package %s\n",
package->VersionedName().String()); package->VersionedName().String());
break; break;
} }
} }
// 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?
DecisionProvider decisionProvider;
if (!decisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n",
"y")) {
return 1;
}
// create an activation transaction
BDaemonClient daemonClient;
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
JobStateListener listener;
BContext context(decisionProvider, listener);
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()))
continue;
// 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, "out of memory");
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");
}
break;
}
case BSolverResultElement::B_TYPE_UNINSTALL:
// add package to transaction
if (!transaction.AddPackageToDeactivate(
package->Info().CanonicalFileName())) {
DIE(B_NO_MEMORY,
"failed to add package to deactivate to transaction");
}
break;
}
}
// 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");
}
return 0; return 0;
} }