diff --git a/headers/private/package/manager/PackageManager.h b/headers/private/package/manager/PackageManager.h index a693f08ffe..d5c9b567c9 100644 --- a/headers/private/package/manager/PackageManager.h +++ b/headers/private/package/manager/PackageManager.h @@ -10,6 +10,9 @@ #define _PACKAGE__MANAGER__PRIVATE__PACKAGE_MANAGER_H_ +#include +#include + #include #include #include @@ -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 PackagePathMap; +private: + PackagePathMap fPackagePaths; +}; + + +class BPackageManager::InstalledRepository : public LocalRepository { public: typedef BObjectList 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); diff --git a/src/kits/package/manager/PackageManager.cpp b/src/kits/package/manager/PackageManager.cpp index c24125e807..44044d224e 100644 --- a/src/kits/package/manager/PackageManager.cpp +++ b/src/kits/package/manager/PackageManager.cpp @@ -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(package->Repository()); - if (remoteRepository == NULL) { - // clone the existing package (unless already present) - if (package->Repository() != &installationRepository) { - _ClonePackageFile( - dynamic_cast(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(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) {