BPackageManager: Support installing/updating local package files
* The Install() and Update() versions that take a const char* array now check whether a string looks like a path to a local package file. If so, they use that file instead of interpreting the string as a search string. * Extend the repository hierarchy. There's now a LocalRepository base class from which InstalledRepository and the new MiscLocalRepository derive. The latter is instantiated once and collects all package files specified by path.
This commit is contained in:
@@ -10,6 +10,9 @@
|
||||
#define _PACKAGE__MANAGER__PRIVATE__PACKAGE_MANAGER_H_
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <ObjectList.h>
|
||||
#include <package/Context.h>
|
||||
@@ -42,6 +45,8 @@ using BPackageKit::BPrivate::BDaemonClient;
|
||||
class BPackageManager : protected BJobStateListener {
|
||||
public:
|
||||
class RemoteRepository;
|
||||
class LocalRepository;
|
||||
class MiscLocalRepository;
|
||||
class InstalledRepository;
|
||||
class Transaction;
|
||||
class InstallationInterface;
|
||||
@@ -126,8 +131,8 @@ private:
|
||||
void _CommitPackageChanges(Transaction& transaction);
|
||||
|
||||
void _ClonePackageFile(
|
||||
InstalledRepository* repository,
|
||||
const BString& fileName,
|
||||
LocalRepository* repository,
|
||||
BSolverPackage* package,
|
||||
const BEntry& entry);
|
||||
int32 _FindBasePackage(const PackageList& packages,
|
||||
const BPackageInfo& info);
|
||||
@@ -140,6 +145,13 @@ private:
|
||||
const BRepositoryConfig& config,
|
||||
bool refresh, BRepositoryCache& _cache);
|
||||
|
||||
void _AddPackageSpecifiers(
|
||||
const char* const* searchStrings,
|
||||
int searchStringCount,
|
||||
BSolverPackageSpecifierList& specifierList);
|
||||
bool _IsLocalPackage(const char* fileName);
|
||||
BSolverPackage* _AddLocalPackage(const char* fileName);
|
||||
|
||||
bool _NextSpecificInstallationLocation();
|
||||
|
||||
protected:
|
||||
@@ -149,6 +161,7 @@ protected:
|
||||
InstalledRepository* fHomeRepository;
|
||||
InstalledRepositoryList fInstalledRepositories;
|
||||
RemoteRepositoryList fOtherRepositories;
|
||||
MiscLocalRepository* fLocalRepository;
|
||||
TransactionList fTransactions;
|
||||
|
||||
// must be set by the derived class
|
||||
@@ -169,7 +182,33 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class BPackageManager::InstalledRepository : public BSolverRepository {
|
||||
class BPackageManager::LocalRepository : public BSolverRepository {
|
||||
public:
|
||||
LocalRepository();
|
||||
LocalRepository(const BString& name);
|
||||
|
||||
virtual void GetPackagePath(BSolverPackage* package,
|
||||
BPath& _path) = 0;
|
||||
};
|
||||
|
||||
|
||||
class BPackageManager::MiscLocalRepository : public LocalRepository {
|
||||
public:
|
||||
MiscLocalRepository();
|
||||
|
||||
BSolverPackage* AddLocalPackage(const char* fileName);
|
||||
|
||||
virtual void GetPackagePath(BSolverPackage* package,
|
||||
BPath& _path);
|
||||
|
||||
private:
|
||||
typedef std::map<BSolverPackage*, std::string> PackagePathMap;
|
||||
private:
|
||||
PackagePathMap fPackagePaths;
|
||||
};
|
||||
|
||||
|
||||
class BPackageManager::InstalledRepository : public LocalRepository {
|
||||
public:
|
||||
typedef BObjectList<BSolverPackage> PackageList;
|
||||
|
||||
@@ -185,6 +224,9 @@ public:
|
||||
int32 InitialPriority() const
|
||||
{ return fInitialPriority; }
|
||||
|
||||
virtual void GetPackagePath(BSolverPackage* package,
|
||||
BPath& _path);
|
||||
|
||||
void DisablePackage(BSolverPackage* package);
|
||||
// throws, if already disabled
|
||||
bool EnablePackage(BSolverPackage* package);
|
||||
|
||||
@@ -59,6 +59,7 @@ BPackageManager::BPackageManager(BPackageInstallationLocation location,
|
||||
B_PACKAGE_INSTALLATION_LOCATION_HOME, -3)),
|
||||
fInstalledRepositories(10),
|
||||
fOtherRepositories(10, true),
|
||||
fLocalRepository(NULL),
|
||||
fTransactions(5, true),
|
||||
fInstallationInterface(installationInterface),
|
||||
fUserInteractionHandler(userInteractionHandler)
|
||||
@@ -71,6 +72,7 @@ BPackageManager::~BPackageManager()
|
||||
delete fSolver;
|
||||
delete fSystemRepository;
|
||||
delete fHomeRepository;
|
||||
delete fLocalRepository;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +90,9 @@ BPackageManager::Init(uint32 flags)
|
||||
if (fSystemRepository == NULL || fHomeRepository == NULL)
|
||||
throw std::bad_alloc();
|
||||
|
||||
if (fLocalRepository != NULL)
|
||||
BRepositoryBuilder(*fLocalRepository).AddToSolver(fSolver, false);
|
||||
|
||||
// add installation location repositories
|
||||
if ((flags & B_ADD_INSTALLED_REPOSITORIES) != 0) {
|
||||
// We add only the repository of our actual installation location as the
|
||||
@@ -128,8 +133,7 @@ void
|
||||
BPackageManager::Install(const char* const* packages, int packageCount)
|
||||
{
|
||||
BSolverPackageSpecifierList packagesToInstall;
|
||||
if (!packagesToInstall.AppendSpecifiers(packages, packageCount))
|
||||
throw std::bad_alloc();
|
||||
_AddPackageSpecifiers(packages, packageCount, packagesToInstall);
|
||||
Install(packagesToInstall);
|
||||
}
|
||||
|
||||
@@ -256,8 +260,7 @@ void
|
||||
BPackageManager::Update(const char* const* packages, int packageCount)
|
||||
{
|
||||
BSolverPackageSpecifierList packagesToUpdate;
|
||||
if (!packagesToUpdate.AppendSpecifiers(packages, packageCount))
|
||||
throw std::bad_alloc();
|
||||
_AddPackageSpecifiers(packages, packageCount, packagesToUpdate);
|
||||
Update(packagesToUpdate);
|
||||
}
|
||||
|
||||
@@ -532,14 +535,7 @@ BPackageManager::_PreparePackageChanges(
|
||||
|
||||
RemoteRepository* remoteRepository
|
||||
= dynamic_cast<RemoteRepository*>(package->Repository());
|
||||
if (remoteRepository == NULL) {
|
||||
// clone the existing package (unless already present)
|
||||
if (package->Repository() != &installationRepository) {
|
||||
_ClonePackageFile(
|
||||
dynamic_cast<InstalledRepository*>(package->Repository()),
|
||||
fileName, entry);
|
||||
}
|
||||
} else {
|
||||
if (remoteRepository != NULL) {
|
||||
// download the package
|
||||
BString url = remoteRepository->Config().PackagesURL();
|
||||
url << '/' << fileName;
|
||||
@@ -548,6 +544,15 @@ BPackageManager::_PreparePackageChanges(
|
||||
package->Info().Checksum());
|
||||
if (error != B_OK)
|
||||
DIE(error, "failed to download package");
|
||||
} else if (package->Repository() != &installationRepository) {
|
||||
// clone the existing package
|
||||
LocalRepository* localRepository
|
||||
= dynamic_cast<LocalRepository*>(package->Repository());
|
||||
if (localRepository == NULL) {
|
||||
DIE("internal error: repository %s is not a local repository",
|
||||
package->Repository()->Name().String());
|
||||
}
|
||||
_ClonePackageFile(localRepository, package, entry);
|
||||
}
|
||||
|
||||
// add package to transaction
|
||||
@@ -602,30 +607,18 @@ BPackageManager::_CommitPackageChanges(Transaction& transaction)
|
||||
|
||||
|
||||
void
|
||||
BPackageManager::_ClonePackageFile(InstalledRepository* repository,
|
||||
const BString& fileName, const BEntry& entry)
|
||||
BPackageManager::_ClonePackageFile(LocalRepository* repository,
|
||||
BSolverPackage* package, const BEntry& entry)
|
||||
{
|
||||
// get the source and destination file paths
|
||||
directory_which packagesWhich;
|
||||
if (repository == fSystemRepository) {
|
||||
packagesWhich = B_SYSTEM_PACKAGES_DIRECTORY;
|
||||
} else {
|
||||
DIE("don't know packages directory path for installation location "
|
||||
"\"%s\"", repository->Name().String());
|
||||
}
|
||||
|
||||
// get source and destination path
|
||||
BPath sourcePath;
|
||||
status_t error = find_directory(packagesWhich, &sourcePath);
|
||||
if (error != B_OK || (error = sourcePath.Append(fileName)) != B_OK) {
|
||||
DIE(error, "failed to get path of package file \"%s\" in installation "
|
||||
"location \"%s\"", fileName.String(), repository->Name().String());
|
||||
}
|
||||
repository->GetPackagePath(package, sourcePath);
|
||||
|
||||
BPath destinationPath;
|
||||
error = entry.GetPath(&destinationPath);
|
||||
status_t error = entry.GetPath(&destinationPath);
|
||||
if (error != B_OK) {
|
||||
DIE(error, "failed to entry path of package file to install \"%s\"",
|
||||
fileName.String());
|
||||
package->Info().FileName().String());
|
||||
}
|
||||
|
||||
// Copy the package. Ideally we would just hard-link it, but BFS doesn't
|
||||
@@ -738,6 +731,46 @@ BPackageManager::_GetRepositoryCache(BPackageRoster& roster,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPackageManager::_AddPackageSpecifiers(const char* const* searchStrings,
|
||||
int searchStringCount, BSolverPackageSpecifierList& specifierList)
|
||||
{
|
||||
for (int i = 0; i < searchStringCount; i++) {
|
||||
const char* searchString = searchStrings[i];
|
||||
if (_IsLocalPackage(searchString)) {
|
||||
BSolverPackage* package = _AddLocalPackage(searchString);
|
||||
if (!specifierList.AppendSpecifier(package))
|
||||
throw std::bad_alloc();
|
||||
} else {
|
||||
if (!specifierList.AppendSpecifier(searchString))
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BPackageManager::_IsLocalPackage(const char* fileName)
|
||||
{
|
||||
// Simple heuristic: fileName contains ".hpkg" and there's actually a file
|
||||
// it refers to.
|
||||
struct stat st;
|
||||
return strstr(fileName, ".hpkg") != NULL && stat(fileName, &st) == 0
|
||||
&& S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
|
||||
BSolverPackage*
|
||||
BPackageManager::_AddLocalPackage(const char* fileName)
|
||||
{
|
||||
// We need a local repository.
|
||||
if (fLocalRepository == NULL)
|
||||
fLocalRepository = new MiscLocalRepository;
|
||||
|
||||
return fLocalRepository->AddLocalPackage(fileName);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BPackageManager::_NextSpecificInstallationLocation()
|
||||
{
|
||||
@@ -791,13 +824,70 @@ BPackageManager::RemoteRepository::Config() const
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - LocalRepository
|
||||
|
||||
|
||||
BPackageManager::LocalRepository::LocalRepository()
|
||||
:
|
||||
BSolverRepository()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BPackageManager::LocalRepository::LocalRepository(const BString& name)
|
||||
:
|
||||
BSolverRepository(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - MiscLocalRepository
|
||||
|
||||
|
||||
BPackageManager::MiscLocalRepository::MiscLocalRepository()
|
||||
:
|
||||
LocalRepository("local"),
|
||||
fPackagePaths()
|
||||
{
|
||||
SetPriority(-127);
|
||||
}
|
||||
|
||||
|
||||
BSolverPackage*
|
||||
BPackageManager::MiscLocalRepository::AddLocalPackage(const char* fileName)
|
||||
{
|
||||
BSolverPackage* package;
|
||||
BRepositoryBuilder(*this).AddPackage(fileName, &package);
|
||||
|
||||
fPackagePaths[package] = fileName;
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPackageManager::MiscLocalRepository::GetPackagePath(BSolverPackage* package,
|
||||
BPath& _path)
|
||||
{
|
||||
PackagePathMap::const_iterator it = fPackagePaths.find(package);
|
||||
if (it == fPackagePaths.end()) {
|
||||
DIE("package %s not in local repository",
|
||||
package->VersionedName().String());
|
||||
}
|
||||
|
||||
status_t error = _path.SetTo(it->second.c_str());
|
||||
if (error != B_OK)
|
||||
DIE(error, "failed to init package path %s", it->second.c_str());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - InstalledRepository
|
||||
|
||||
|
||||
BPackageManager::InstalledRepository::InstalledRepository(const char* name,
|
||||
BPackageInstallationLocation location, int32 priority)
|
||||
:
|
||||
BSolverRepository(),
|
||||
LocalRepository(),
|
||||
fDisabledPackages(10, true),
|
||||
fPackagesToActivate(),
|
||||
fPackagesToDeactivate(),
|
||||
@@ -808,6 +898,32 @@ BPackageManager::InstalledRepository::InstalledRepository(const char* name,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPackageManager::InstalledRepository::GetPackagePath(BSolverPackage* package,
|
||||
BPath& _path)
|
||||
{
|
||||
directory_which packagesWhich;
|
||||
switch (fLocation) {
|
||||
case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
|
||||
packagesWhich = B_SYSTEM_PACKAGES_DIRECTORY;
|
||||
break;
|
||||
case B_PACKAGE_INSTALLATION_LOCATION_HOME:
|
||||
packagesWhich = B_USER_PACKAGES_DIRECTORY;
|
||||
break;
|
||||
default:
|
||||
DIE("don't know packages directory path for installation location "
|
||||
"\"%s\"", Name().String());
|
||||
}
|
||||
|
||||
BString fileName(package->Info().FileName());
|
||||
status_t error = find_directory(packagesWhich, &_path);
|
||||
if (error != B_OK || (error = _path.Append(fileName)) != B_OK) {
|
||||
DIE(error, "failed to get path of package file \"%s\" in installation "
|
||||
"location \"%s\"", fileName.String(), Name().String());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPackageManager::InstalledRepository::DisablePackage(BSolverPackage* package)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user