Refactor reusable pkgman code into libpackage
* Move RepositoryBuilder class to libpackage and add B* prefix to name. * Pull BPackageManager class out of PackageManager and move to libpackage. The base class is customizable via three handler objects responsible for transaction handling, request execution, respectively user interaction. * Reorganize _ApplyPackageChanges(): Now we first prepare the transactions for all affected installation locations (downloading files etc.) and then commit them.
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
#include <../private/package/manager/Exceptions.h>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include <../private/package/manager/RepositoryBuilder.h>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef _PACKAGE__MANAGER__PRIVATE__EXCEPTIONS_H_
|
||||||
|
#define _PACKAGE__MANAGER__PRIVATE__EXCEPTIONS_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <package/Context.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPackageKit {
|
||||||
|
|
||||||
|
namespace BManager {
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
class BException {
|
||||||
|
public:
|
||||||
|
BException();
|
||||||
|
BException(const BString& message);
|
||||||
|
|
||||||
|
const BString& Message() const
|
||||||
|
{ return fMessage; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BString fMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BFatalErrorException : public BException {
|
||||||
|
public:
|
||||||
|
BFatalErrorException();
|
||||||
|
BFatalErrorException(const char* format, ...);
|
||||||
|
BFatalErrorException(status_t error,
|
||||||
|
const char* format, ...);
|
||||||
|
|
||||||
|
const BString& Details() const
|
||||||
|
{ return fDetails; }
|
||||||
|
BFatalErrorException& SetDetails(const BString& details);
|
||||||
|
|
||||||
|
status_t Error() const
|
||||||
|
{ return fError; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fDetails;
|
||||||
|
status_t fError;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BAbortedByUserException : public BException {
|
||||||
|
public:
|
||||||
|
BAbortedByUserException();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BNothingToDoException : public BException {
|
||||||
|
public:
|
||||||
|
BNothingToDoException();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
} // namespace BManager
|
||||||
|
|
||||||
|
} // namespace BPackageKit
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _PACKAGE__MANAGER__PRIVATE__EXCEPTIONS_H_
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef _PACKAGE__MANAGER__PRIVATE__PACKAGE_MANAGER_H_
|
||||||
|
#define _PACKAGE__MANAGER__PRIVATE__PACKAGE_MANAGER_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <Directory.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 <package/ActivationTransaction.h>
|
||||||
|
#include <package/DaemonClient.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPackageKit {
|
||||||
|
|
||||||
|
namespace BManager {
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
using namespace BPackageKit::BPrivate;
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager {
|
||||||
|
public:
|
||||||
|
class RemoteRepository;
|
||||||
|
class InstalledRepository;
|
||||||
|
class Transaction;
|
||||||
|
class TransactionHandler;
|
||||||
|
class DaemonClientTransactionHandler;
|
||||||
|
class UserInteractionHandler;
|
||||||
|
class RequestHandler;
|
||||||
|
|
||||||
|
typedef BObjectList<RemoteRepository> RemoteRepositoryList;
|
||||||
|
typedef BObjectList<InstalledRepository> InstalledRepositoryList;
|
||||||
|
typedef BObjectList<BSolverPackage> PackageList;
|
||||||
|
typedef BObjectList<Transaction> TransactionList;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
B_ADD_INSTALLED_REPOSITORIES = 0x01,
|
||||||
|
B_ADD_REMOTE_REPOSITORIES = 0x02,
|
||||||
|
B_REFRESH_REPOSITORIES = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
BPackageManager(
|
||||||
|
BPackageInstallationLocation location);
|
||||||
|
~BPackageManager();
|
||||||
|
|
||||||
|
void Init(uint32 flags);
|
||||||
|
|
||||||
|
BSolver* Solver() const
|
||||||
|
{ return fSolver; }
|
||||||
|
|
||||||
|
const InstalledRepository* SystemRepository() const
|
||||||
|
{ return fSystemRepository; }
|
||||||
|
const InstalledRepository* CommonRepository() const
|
||||||
|
{ return fCommonRepository; }
|
||||||
|
const InstalledRepository* HomeRepository() const
|
||||||
|
{ return fHomeRepository; }
|
||||||
|
const InstalledRepositoryList& InstalledRepositories() const
|
||||||
|
{ return fInstalledRepositories; }
|
||||||
|
const RemoteRepositoryList& OtherRepositories() const
|
||||||
|
{ return fOtherRepositories; }
|
||||||
|
|
||||||
|
void Install(const char* const* packages,
|
||||||
|
int packageCount);
|
||||||
|
void Uninstall(const char* const* packages,
|
||||||
|
int packageCount);
|
||||||
|
void Update(const char* const* packages,
|
||||||
|
int packageCount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _HandleProblems();
|
||||||
|
void _AnalyzeResult();
|
||||||
|
void _ConfirmChanges(bool fromMostSpecific = false);
|
||||||
|
void _ApplyPackageChanges(
|
||||||
|
bool fromMostSpecific = false);
|
||||||
|
void _PreparePackageChanges(
|
||||||
|
InstalledRepository&
|
||||||
|
installationRepository);
|
||||||
|
void _CommitPackageChanges(Transaction& transaction);
|
||||||
|
|
||||||
|
void _ClonePackageFile(
|
||||||
|
InstalledRepository* repository,
|
||||||
|
const BString& fileName,
|
||||||
|
const BEntry& entry);
|
||||||
|
int32 _FindBasePackage(const PackageList& packages,
|
||||||
|
const BPackageInfo& info);
|
||||||
|
|
||||||
|
InstalledRepository& _InstallationRepository();
|
||||||
|
|
||||||
|
void _AddInstalledRepository(
|
||||||
|
InstalledRepository* repository);
|
||||||
|
void _AddRemoteRepository(BPackageRoster& roster,
|
||||||
|
const char* name, bool refresh);
|
||||||
|
status_t _GetRepositoryConfig(BPackageRoster& roster,
|
||||||
|
const char* name, bool refresh,
|
||||||
|
BRepositoryConfig& _config);
|
||||||
|
|
||||||
|
bool _NextSpecificInstallationLocation();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BPackageInstallationLocation fLocation;
|
||||||
|
BSolver* fSolver;
|
||||||
|
InstalledRepository* fSystemRepository;
|
||||||
|
InstalledRepository* fCommonRepository;
|
||||||
|
InstalledRepository* fHomeRepository;
|
||||||
|
InstalledRepositoryList fInstalledRepositories;
|
||||||
|
RemoteRepositoryList fOtherRepositories;
|
||||||
|
TransactionList fTransactions;
|
||||||
|
|
||||||
|
// must be set by the derived class
|
||||||
|
TransactionHandler* fTransactionHandler;
|
||||||
|
RequestHandler* fRequestHandler;
|
||||||
|
UserInteractionHandler* fUserInteractionHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager::RemoteRepository : public BSolverRepository {
|
||||||
|
public:
|
||||||
|
RemoteRepository(
|
||||||
|
const BRepositoryConfig& config);
|
||||||
|
|
||||||
|
const BRepositoryConfig& Config() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BRepositoryConfig fConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager::InstalledRepository : public BSolverRepository {
|
||||||
|
public:
|
||||||
|
typedef BObjectList<BSolverPackage> PackageList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InstalledRepository(const char* name,
|
||||||
|
BPackageInstallationLocation location,
|
||||||
|
int32 priority);
|
||||||
|
|
||||||
|
BPackageInstallationLocation Location() const
|
||||||
|
{ return fLocation; }
|
||||||
|
const char* InitialName() const
|
||||||
|
{ return fInitialName; }
|
||||||
|
int32 InitialPriority() const
|
||||||
|
{ return fInitialPriority; }
|
||||||
|
|
||||||
|
void DisablePackage(BSolverPackage* package);
|
||||||
|
|
||||||
|
PackageList& PackagesToActivate()
|
||||||
|
{ return fPackagesToActivate; }
|
||||||
|
PackageList& PackagesToDeactivate()
|
||||||
|
{ return fPackagesToDeactivate; }
|
||||||
|
|
||||||
|
bool HasChanges() const;
|
||||||
|
void ApplyChanges();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageList fDisabledPackages;
|
||||||
|
PackageList fPackagesToActivate;
|
||||||
|
PackageList fPackagesToDeactivate;
|
||||||
|
const char* fInitialName;
|
||||||
|
BPackageInstallationLocation fLocation;
|
||||||
|
int32 fInitialPriority;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager::Transaction {
|
||||||
|
public:
|
||||||
|
Transaction(InstalledRepository& repository);
|
||||||
|
~Transaction();
|
||||||
|
|
||||||
|
InstalledRepository& Repository()
|
||||||
|
{ return fRepository; }
|
||||||
|
BActivationTransaction& ActivationTransaction()
|
||||||
|
{ return fTransaction; }
|
||||||
|
BDirectory& TransactionDirectory()
|
||||||
|
{ return fTransactionDirectory; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
InstalledRepository& fRepository;
|
||||||
|
BActivationTransaction fTransaction;
|
||||||
|
BDirectory fTransactionDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager::TransactionHandler {
|
||||||
|
public:
|
||||||
|
virtual ~TransactionHandler();
|
||||||
|
|
||||||
|
virtual status_t PrepareTransaction(Transaction& transaction)
|
||||||
|
= 0;
|
||||||
|
virtual status_t CommitTransaction(Transaction& transaction,
|
||||||
|
BDaemonClient::BCommitTransactionResult&
|
||||||
|
_result) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager::DaemonClientTransactionHandler
|
||||||
|
: public TransactionHandler {
|
||||||
|
public:
|
||||||
|
DaemonClientTransactionHandler();
|
||||||
|
virtual ~DaemonClientTransactionHandler();
|
||||||
|
|
||||||
|
virtual status_t PrepareTransaction(Transaction& transaction);
|
||||||
|
virtual status_t CommitTransaction(Transaction& transaction,
|
||||||
|
BDaemonClient::BCommitTransactionResult&
|
||||||
|
_result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BDaemonClient fDaemonClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager::RequestHandler {
|
||||||
|
public:
|
||||||
|
virtual ~RequestHandler();
|
||||||
|
|
||||||
|
virtual status_t RefreshRepository(
|
||||||
|
const BRepositoryConfig& repoConfig) = 0;
|
||||||
|
virtual status_t DownloadPackage(const BString& fileURL,
|
||||||
|
const BEntry& targetEntry,
|
||||||
|
const BString& checksum) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BPackageManager::UserInteractionHandler {
|
||||||
|
public:
|
||||||
|
virtual ~UserInteractionHandler();
|
||||||
|
|
||||||
|
virtual void HandleProblems() = 0;
|
||||||
|
virtual void ConfirmChanges(bool fromMostSpecific) = 0;
|
||||||
|
|
||||||
|
virtual void Warn(status_t error, const char* format, ...)
|
||||||
|
= 0;
|
||||||
|
virtual void ProgressStartApplyingChanges(
|
||||||
|
InstalledRepository& repository) = 0;
|
||||||
|
virtual void ProgressTransactionCommitted(
|
||||||
|
InstalledRepository& repository,
|
||||||
|
const char* transactionDirectoryName) = 0;
|
||||||
|
virtual void ProgressApplyingChangesDone(
|
||||||
|
InstalledRepository& repository) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
} // namespace BManager
|
||||||
|
|
||||||
|
} // namespace BPackageKit
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _PACKAGE__MANAGER__PRIVATE__PACKAGE_MANAGER_H_
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef _PACKAGE__MANAGER__PRIVATE__REPOSITORY_BUILDER_H_
|
||||||
|
#define _PACKAGE__MANAGER__PRIVATE__REPOSITORY_BUILDER_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <package/PackageInfo.h>
|
||||||
|
#include <package/solver/Solver.h>
|
||||||
|
#include <package/solver/SolverPackage.h>
|
||||||
|
#include <package/solver/SolverRepository.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPackageKit {
|
||||||
|
|
||||||
|
namespace BManager {
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::map<BSolverPackage*, BString> BPackagePathMap;
|
||||||
|
|
||||||
|
|
||||||
|
class BRepositoryBuilder {
|
||||||
|
public:
|
||||||
|
BRepositoryBuilder(
|
||||||
|
BSolverRepository& repository,
|
||||||
|
const BString& name,
|
||||||
|
const BString& errorName = BString());
|
||||||
|
BRepositoryBuilder(
|
||||||
|
BSolverRepository& repository,
|
||||||
|
const BRepositoryConfig& config);
|
||||||
|
BRepositoryBuilder(
|
||||||
|
BSolverRepository& repository,
|
||||||
|
const BRepositoryCache& cache,
|
||||||
|
const BString& errorName = BString());
|
||||||
|
|
||||||
|
BRepositoryBuilder& SetPackagePathMap(
|
||||||
|
BPackagePathMap* packagePaths);
|
||||||
|
|
||||||
|
BRepositoryBuilder& AddPackage(const BPackageInfo& info,
|
||||||
|
const char* packageErrorName = NULL,
|
||||||
|
BSolverPackage** _package = NULL);
|
||||||
|
BRepositoryBuilder& AddPackage(const char* path,
|
||||||
|
BSolverPackage** _package = NULL);
|
||||||
|
BRepositoryBuilder& AddPackages(
|
||||||
|
BPackageInstallationLocation location,
|
||||||
|
const char* locationErrorName);
|
||||||
|
BRepositoryBuilder& AddPackagesDirectory(const char* path);
|
||||||
|
|
||||||
|
BRepositoryBuilder& AddToSolver(BSolver* solver,
|
||||||
|
bool isInstalled = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BSolverRepository& fRepository;
|
||||||
|
BString fErrorName;
|
||||||
|
BPackagePathMap* fPackagePaths;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
} // namespace BManager
|
||||||
|
|
||||||
|
} // namespace BPackageKit
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _PACKAGE__MANAGER__PRIVATE__REPOSITORY_BUILDER_H_
|
||||||
@@ -15,10 +15,8 @@ BinCommand pkgman :
|
|||||||
command_uninstall.cpp
|
command_uninstall.cpp
|
||||||
DecisionProvider.cpp
|
DecisionProvider.cpp
|
||||||
JobStateListener.cpp
|
JobStateListener.cpp
|
||||||
PackageInfoErrorListener.cpp
|
|
||||||
PackageManager.cpp
|
PackageManager.cpp
|
||||||
pkgman.cpp
|
pkgman.cpp
|
||||||
RepositoryBuilder.cpp
|
|
||||||
:
|
:
|
||||||
package be
|
package be
|
||||||
$(TARGET_LIBSUPC++) $(TARGET_LIBSTDC++)
|
$(TARGET_LIBSUPC++) $(TARGET_LIBSTDC++)
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Ingo Weinhold <[email protected]>
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "PackageInfoErrorListener.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
PackageInfoErrorListener::PackageInfoErrorListener(const BString& errorContext)
|
|
||||||
:
|
|
||||||
fErrorContext(errorContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageInfoErrorListener::OnError(const BString& message, int line, int column)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
|
|
||||||
fErrorContext.String(), line, column, message.String());
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Ingo Weinhold <[email protected]>
|
|
||||||
*/
|
|
||||||
#ifndef PACKAGE_INFO_ERROR_LISTENER_H
|
|
||||||
#define PACKAGE_INFO_ERROR_LISTENER_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <package/PackageInfo.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace BPackageKit;
|
|
||||||
|
|
||||||
|
|
||||||
class PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
|
|
||||||
public:
|
|
||||||
PackageInfoErrorListener(
|
|
||||||
const BString& errorContext);
|
|
||||||
|
|
||||||
virtual void OnError(const BString& message, int line,
|
|
||||||
int column);
|
|
||||||
|
|
||||||
private:
|
|
||||||
BString fErrorContext;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // PACKAGE_INFO_ERROR_LISTENER_H
|
|
||||||
+110
-698
@@ -9,516 +9,119 @@
|
|||||||
|
|
||||||
#include "PackageManager.h"
|
#include "PackageManager.h"
|
||||||
|
|
||||||
#include <Directory.h>
|
|
||||||
#include <package/DownloadFileRequest.h>
|
#include <package/DownloadFileRequest.h>
|
||||||
#include <package/PackageRoster.h>
|
|
||||||
#include <package/RefreshRepositoryRequest.h>
|
#include <package/RefreshRepositoryRequest.h>
|
||||||
#include <package/solver/SolverPackage.h>
|
#include <package/solver/SolverPackage.h>
|
||||||
#include <package/solver/SolverPackageSpecifier.h>
|
|
||||||
#include <package/solver/SolverPackageSpecifierList.h>
|
|
||||||
#include <package/solver/SolverProblem.h>
|
#include <package/solver/SolverProblem.h>
|
||||||
#include <package/solver/SolverProblemSolution.h>
|
#include <package/solver/SolverProblemSolution.h>
|
||||||
#include <package/solver/SolverResult.h>
|
|
||||||
|
|
||||||
#include <CopyEngine.h>
|
|
||||||
#include <package/ActivationTransaction.h>
|
|
||||||
#include <package/DaemonClient.h>
|
|
||||||
|
|
||||||
#include "pkgman.h"
|
#include "pkgman.h"
|
||||||
#include "RepositoryBuilder.h"
|
|
||||||
|
|
||||||
|
|
||||||
using namespace BPackageKit::BPrivate;
|
using namespace BPackageKit::BPrivate;
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - RemoteRepository
|
PackageManager::PackageManager(BPackageInstallationLocation location)
|
||||||
|
|
||||||
|
|
||||||
PackageManager::RemoteRepository::RemoteRepository()
|
|
||||||
:
|
:
|
||||||
BSolverRepository()
|
BPackageManager(location),
|
||||||
{
|
BPackageManager::UserInteractionHandler(),
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
PackageManager::RemoteRepository::Init(BPackageRoster& roster,
|
|
||||||
BContext& context, const char* name, bool refresh)
|
|
||||||
{
|
|
||||||
// get the repository config
|
|
||||||
status_t error = roster.GetRepositoryConfig(name, &fConfig);
|
|
||||||
if (error != B_OK)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
// refresh
|
|
||||||
if (!refresh)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
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::RemoteRepository::Config() const
|
|
||||||
{
|
|
||||||
return fConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - InstalledRepository
|
|
||||||
|
|
||||||
|
|
||||||
PackageManager::InstalledRepository::InstalledRepository(const char* name,
|
|
||||||
BPackageInstallationLocation location, int32 priority)
|
|
||||||
:
|
|
||||||
BSolverRepository(),
|
|
||||||
fDisabledPackages(10, true),
|
|
||||||
fPackagesToActivate(),
|
|
||||||
fPackagesToDeactivate(),
|
|
||||||
fInitialName(name),
|
|
||||||
fLocation(location),
|
|
||||||
fInitialPriority(priority)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::InstalledRepository::DisablePackage(BSolverPackage* package)
|
|
||||||
{
|
|
||||||
if (fDisabledPackages.HasItem(package)) {
|
|
||||||
fprintf(stderr, "*** package %s already disabled\n",
|
|
||||||
package->VersionedName().String());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (package->Repository() != this) {
|
|
||||||
fprintf(stderr, "*** package %s not in repository %s\n",
|
|
||||||
package->VersionedName().String(), Name().String());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// move to disabled list
|
|
||||||
if (!fDisabledPackages.AddItem(package))
|
|
||||||
DIE(B_NO_MEMORY, "failed to add package to list");
|
|
||||||
|
|
||||||
RemovePackage(package);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
PackageManager::InstalledRepository::HasChanges() const
|
|
||||||
{
|
|
||||||
return !fPackagesToActivate.IsEmpty() || !fPackagesToDeactivate.IsEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::InstalledRepository::ApplyChanges()
|
|
||||||
{
|
|
||||||
// disable packages to deactivate
|
|
||||||
for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
|
|
||||||
i++) {
|
|
||||||
if (!fDisabledPackages.HasItem(package))
|
|
||||||
DisablePackage(package);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add packages to activate
|
|
||||||
for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i);
|
|
||||||
i++) {
|
|
||||||
status_t error = AddPackage(package->Info());
|
|
||||||
if (error != B_OK) {
|
|
||||||
DIE(error, "failed to add package %s to %s repository",
|
|
||||||
package->Name().String(),
|
|
||||||
Name().String());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Solver
|
|
||||||
|
|
||||||
|
|
||||||
PackageManager::PackageManager(BPackageInstallationLocation location,
|
|
||||||
uint32 flags)
|
|
||||||
:
|
|
||||||
fLocation(location),
|
|
||||||
fSolver(NULL),
|
|
||||||
fSystemRepository(new (std::nothrow) InstalledRepository("system",
|
|
||||||
B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, -1)),
|
|
||||||
fCommonRepository(new (std::nothrow) InstalledRepository("common",
|
|
||||||
B_PACKAGE_INSTALLATION_LOCATION_COMMON, -2)),
|
|
||||||
fHomeRepository(new (std::nothrow) InstalledRepository("home",
|
|
||||||
B_PACKAGE_INSTALLATION_LOCATION_HOME, -3)),
|
|
||||||
fInstalledRepositories(10),
|
|
||||||
fOtherRepositories(10, true),
|
|
||||||
fDecisionProvider(),
|
fDecisionProvider(),
|
||||||
fJobStateListener(JobStateListener::EXIT_ON_ABORT),
|
fJobStateListener(JobStateListener::EXIT_ON_ABORT),
|
||||||
fContext(fDecisionProvider, fJobStateListener)
|
fContext(fDecisionProvider, fJobStateListener),
|
||||||
|
fDaemonClientTransactionHandler()
|
||||||
{
|
{
|
||||||
// create the solver
|
fTransactionHandler = &fDaemonClientTransactionHandler;
|
||||||
status_t error = BSolver::Create(fSolver);
|
fRequestHandler = this;
|
||||||
if (error != B_OK)
|
fUserInteractionHandler = this;
|
||||||
DIE(error, "failed to create solver");
|
|
||||||
|
|
||||||
if (fSystemRepository == NULL || fCommonRepository == NULL
|
|
||||||
|| fHomeRepository == NULL) {
|
|
||||||
DIE(B_NO_MEMORY, "failed to create repositories");
|
|
||||||
}
|
|
||||||
|
|
||||||
// add installation location repositories
|
|
||||||
if ((flags & ADD_INSTALLED_REPOSITORIES) != 0) {
|
|
||||||
// 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.
|
|
||||||
_AddInstalledRepository(fSystemRepository);
|
|
||||||
|
|
||||||
if (!fSystemRepository->IsInstalled()) {
|
|
||||||
_AddInstalledRepository(fCommonRepository);
|
|
||||||
|
|
||||||
if (!fCommonRepository->IsInstalled())
|
|
||||||
_AddInstalledRepository(fHomeRepository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add other repositories
|
|
||||||
if ((flags & ADD_REMOTE_REPOSITORIES) != 0) {
|
|
||||||
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++) {
|
|
||||||
RemoteRepository* repository = new(std::nothrow) RemoteRepository;
|
|
||||||
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,
|
|
||||||
(flags & REFRESH_REPOSITORIES) != 0);
|
|
||||||
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()
|
PackageManager::~PackageManager()
|
||||||
{
|
{
|
||||||
delete fSystemRepository;
|
}
|
||||||
delete fCommonRepository;
|
|
||||||
delete fHomeRepository;
|
|
||||||
|
status_t
|
||||||
|
PackageManager::RefreshRepository(const BRepositoryConfig& repoConfig)
|
||||||
|
{
|
||||||
|
return BRefreshRepositoryRequest(fContext, repoConfig).Process();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
PackageManager::DownloadPackage(const BString& fileURL,
|
||||||
|
const BEntry& targetEntry, const BString& checksum)
|
||||||
|
{
|
||||||
|
return DownloadFileRequest(fContext, fileURL, targetEntry, checksum)
|
||||||
|
.Process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PackageManager::Install(const char* const* packages, int packageCount)
|
PackageManager::HandleProblems()
|
||||||
{
|
{
|
||||||
// solve
|
printf("Encountered problems:\n");
|
||||||
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;
|
int32 problemCount = fSolver->CountProblems();
|
||||||
status_t error = fSolver->Install(packagesToInstall, &unmatchedSpecifier);
|
for (int32 i = 0; i < problemCount; i++) {
|
||||||
if (error != B_OK) {
|
// print problem and possible solutions
|
||||||
if (unmatchedSpecifier != NULL) {
|
BSolverProblem* problem = fSolver->ProblemAt(i);
|
||||||
DIE(error, "failed to find a match for \"%s\"",
|
printf("problem %" B_PRId32 ": %s\n", i + 1,
|
||||||
unmatchedSpecifier->SelectString().String());
|
problem->ToString().String());
|
||||||
} else
|
|
||||||
DIE(error, "failed to compute packages to install");
|
|
||||||
}
|
|
||||||
|
|
||||||
_HandleProblems();
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// install/uninstall packages
|
// let the user choose a solution
|
||||||
_AnalyzeResult();
|
printf("Please select a solution, skip the problem for now or quit.\n");
|
||||||
_PrintResult();
|
for (;;) {
|
||||||
_ApplyPackageChanges();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
if (strcmp(buffer, "s\n") == 0)
|
||||||
PackageManager::Uninstall(const char* const* packages, int packageCount)
|
break;
|
||||||
{
|
|
||||||
// find the packages that match the specification
|
|
||||||
BSolverPackageSpecifierList packagesToUninstall;
|
|
||||||
for (int i = 0; i < packageCount; i++) {
|
|
||||||
if (!packagesToUninstall.AppendSpecifier(packages[i]))
|
|
||||||
DIE(B_NO_MEMORY, "failed to add specified package");
|
|
||||||
}
|
|
||||||
|
|
||||||
const BSolverPackageSpecifier* unmatchedSpecifier;
|
char* end;
|
||||||
PackageList foundPackages;
|
long selected = strtol(buffer, &end, 0);
|
||||||
status_t error = fSolver->FindPackages(packagesToUninstall,
|
if (end == buffer || *end != '\n' || selected < 1
|
||||||
BSolver::B_FIND_INSTALLED_ONLY, foundPackages, &unmatchedSpecifier);
|
|| selected > solutionCount) {
|
||||||
if (error != B_OK) {
|
printf("*** invalid input\n");
|
||||||
if (unmatchedSpecifier != NULL) {
|
|
||||||
DIE(error, "failed to find a match for \"%s\"",
|
|
||||||
unmatchedSpecifier->SelectString().String());
|
|
||||||
} else
|
|
||||||
DIE(error, "failed to compute packages to uninstall");
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the inverse base package closure for the found packages
|
|
||||||
// TODO: Optimize!
|
|
||||||
InstalledRepository& installationRepository = _InstallationRepository();
|
|
||||||
bool foundAnotherPackage;
|
|
||||||
do {
|
|
||||||
foundAnotherPackage = false;
|
|
||||||
int32 count = installationRepository.CountPackages();
|
|
||||||
for (int32 i = 0; i < count; i++) {
|
|
||||||
BSolverPackage* package = installationRepository.PackageAt(i);
|
|
||||||
if (foundPackages.HasItem(package))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (_FindBasePackage(foundPackages, package->Info()) >= 0) {
|
|
||||||
foundPackages.AddItem(package);
|
|
||||||
foundAnotherPackage = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (foundAnotherPackage);
|
|
||||||
|
|
||||||
// remove the packages from the repository
|
|
||||||
for (int32 i = 0; BSolverPackage* package = foundPackages.ItemAt(i); i++)
|
|
||||||
installationRepository.DisablePackage(package);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
error = fSolver->VerifyInstallation(BSolver::B_VERIFY_ALLOW_UNINSTALL);
|
|
||||||
if (error != B_OK)
|
|
||||||
DIE(error, "failed to compute packages to uninstall");
|
|
||||||
|
|
||||||
_HandleProblems();
|
|
||||||
|
|
||||||
// (virtually) apply the result to this repository
|
|
||||||
_AnalyzeResult();
|
|
||||||
|
|
||||||
for (int32 i = foundPackages.CountItems() - 1; i >= 0; i--) {
|
|
||||||
if (!installationRepository.PackagesToDeactivate()
|
|
||||||
.AddItem(foundPackages.ItemAt(i))) {
|
|
||||||
DIE(B_NO_MEMORY, "failed to add package to uninstall");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
installationRepository.ApplyChanges();
|
|
||||||
|
|
||||||
// verify the next specific respository
|
|
||||||
if (!_NextSpecificInstallationLocation())
|
|
||||||
break;
|
|
||||||
|
|
||||||
foundPackages.MakeEmpty();
|
|
||||||
|
|
||||||
// NOTE: In theory, after verifying a more specific location, it would
|
|
||||||
// be more correct to compute the inverse base package closure for the
|
|
||||||
// packages we need to uninstall and (if anything changed) verify again.
|
|
||||||
// In practice, however, base packages are always required with an exact
|
|
||||||
// version (ATM). If that base package still exist in a more general
|
|
||||||
// location (the only reason why the package requiring the base package
|
|
||||||
// wouldn't be marked to be uninstalled as well) there shouldn't have
|
|
||||||
// been any reason to remove it from the more specific location in the
|
|
||||||
// first place.
|
|
||||||
}
|
|
||||||
|
|
||||||
_PrintResult(true);
|
|
||||||
_ApplyPackageChanges(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::Update(const char* const* packages, int packageCount)
|
|
||||||
{
|
|
||||||
// solve
|
|
||||||
BSolverPackageSpecifierList packagesToUpdate;
|
|
||||||
for (int i = 0; i < packageCount; i++) {
|
|
||||||
if (!packagesToUpdate.AppendSpecifier(packages[i]))
|
|
||||||
DIE(B_NO_MEMORY, "failed to add specified package");
|
|
||||||
}
|
|
||||||
|
|
||||||
const BSolverPackageSpecifier* unmatchedSpecifier;
|
|
||||||
status_t error = fSolver->Update(packagesToUpdate, true,
|
|
||||||
&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 update");
|
|
||||||
}
|
|
||||||
|
|
||||||
_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
|
status_t error = fSolver->SelectProblemSolution(problem,
|
||||||
printf("Please select a solution, skip the problem for now or "
|
problem->SolutionAt(selected - 1));
|
||||||
"quit.\n");
|
if (error != B_OK)
|
||||||
for (;;) {
|
DIE(error, "failed to set solution");
|
||||||
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 recompute packages to un/-install");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::_AnalyzeResult()
|
|
||||||
{
|
|
||||||
BSolverResult result;
|
|
||||||
status_t error = fSolver->GetResult(result);
|
|
||||||
if (error != B_OK)
|
|
||||||
DIE(error, "failed to compute packages to un/-install");
|
|
||||||
|
|
||||||
InstalledRepository& installationRepository = _InstallationRepository();
|
|
||||||
PackageList& packagesToActivate
|
|
||||||
= installationRepository.PackagesToActivate();
|
|
||||||
PackageList& packagesToDeactivate
|
|
||||||
= installationRepository.PackagesToDeactivate();
|
|
||||||
|
|
||||||
PackageList potentialBasePackages;
|
|
||||||
|
|
||||||
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
|
|
||||||
i++) {
|
|
||||||
BSolverPackage* package = element->Package();
|
|
||||||
|
|
||||||
switch (element->Type()) {
|
|
||||||
case BSolverResultElement::B_TYPE_INSTALL:
|
|
||||||
{
|
|
||||||
PackageList& packageList
|
|
||||||
= dynamic_cast<InstalledRepository*>(package->Repository())
|
|
||||||
!= NULL
|
|
||||||
? potentialBasePackages
|
|
||||||
: packagesToActivate;
|
|
||||||
if (!packageList.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure base packages are installed in the same location.
|
|
||||||
for (int32 i = 0; i < packagesToActivate.CountItems(); i++) {
|
|
||||||
BSolverPackage* package = packagesToActivate.ItemAt(i);
|
|
||||||
int32 index = _FindBasePackage(potentialBasePackages, package->Info());
|
|
||||||
if (index < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
BSolverPackage* basePackage = potentialBasePackages.RemoveItemAt(index);
|
|
||||||
if (!packagesToActivate.AddItem(basePackage))
|
|
||||||
DIE(B_NO_MEMORY, "failed to add package to activate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::_PrintResult(bool fromMostSpecific)
|
|
||||||
{
|
|
||||||
// check, if there are any changes at all
|
|
||||||
int32 count = fInstalledRepositories.CountItems();
|
|
||||||
bool hasChanges = false;
|
|
||||||
for (int32 i = 0; i < count; i++) {
|
|
||||||
if (fInstalledRepositories.ItemAt(i)->HasChanges()) {
|
|
||||||
hasChanges = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasChanges) {
|
|
||||||
printf("Nothing to do.\n");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageManager::ConfirmChanges(bool fromMostSpecific)
|
||||||
|
{
|
||||||
printf("The following changes will be made:\n");
|
printf("The following changes will be made:\n");
|
||||||
|
|
||||||
|
int32 count = fInstalledRepositories.CountItems();
|
||||||
if (fromMostSpecific) {
|
if (fromMostSpecific) {
|
||||||
for (int32 i = count - 1; i >= 0; i--)
|
for (int32 i = count - 1; i >= 0; i--)
|
||||||
_PrintResult(*fInstalledRepositories.ItemAt(i));
|
_PrintResult(*fInstalledRepositories.ItemAt(i));
|
||||||
@@ -534,6 +137,45 @@ PackageManager::_PrintResult(bool fromMostSpecific)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageManager::Warn(status_t error, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vfprintf(stderr, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (error == B_OK)
|
||||||
|
printf("\n");
|
||||||
|
else
|
||||||
|
printf(": %s\n", strerror(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageManager::ProgressStartApplyingChanges(InstalledRepository& repository)
|
||||||
|
{
|
||||||
|
printf("[%s] Applying changes ...\n", repository.Name().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageManager::ProgressTransactionCommitted(InstalledRepository& repository,
|
||||||
|
const char* transactionDirectoryName)
|
||||||
|
{
|
||||||
|
printf("[%s] Changes applied. Old activation state backed up in \"%s\"\n",
|
||||||
|
repository.Name().String(), transactionDirectoryName);
|
||||||
|
printf("[%s] Cleaning up ...\n", repository.Name().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageManager::ProgressApplyingChangesDone(InstalledRepository& repository)
|
||||||
|
{
|
||||||
|
printf("[%s] Done.\n", repository.Name().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PackageManager::_PrintResult(InstalledRepository& installationRepository)
|
PackageManager::_PrintResult(InstalledRepository& installationRepository)
|
||||||
{
|
{
|
||||||
@@ -563,233 +205,3 @@ PackageManager::_PrintResult(InstalledRepository& installationRepository)
|
|||||||
// other information) should, however, be provided by the repository cache in
|
// other information) should, however, be provided by the repository cache in
|
||||||
// some way. Extend BPackageInfo? Create a BPackageFileInfo?
|
// some way. Extend BPackageInfo? Create a BPackageFileInfo?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::_ApplyPackageChanges(bool fromMostSpecific)
|
|
||||||
{
|
|
||||||
int32 count = fInstalledRepositories.CountItems();
|
|
||||||
if (fromMostSpecific) {
|
|
||||||
for (int32 i = count - 1; i >= 0; i--)
|
|
||||||
_ApplyPackageChanges(*fInstalledRepositories.ItemAt(i));
|
|
||||||
} else {
|
|
||||||
for (int32 i = 0; i < count; i++)
|
|
||||||
_ApplyPackageChanges(*fInstalledRepositories.ItemAt(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::_ApplyPackageChanges(
|
|
||||||
InstalledRepository& installationRepository)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!installationRepository.HasChanges())
|
|
||||||
return;
|
|
||||||
|
|
||||||
PackageList& packagesToActivate
|
|
||||||
= installationRepository.PackagesToActivate();
|
|
||||||
PackageList& packagesToDeactivate
|
|
||||||
= installationRepository.PackagesToDeactivate();
|
|
||||||
|
|
||||||
// create an activation transaction
|
|
||||||
BDaemonClient daemonClient;
|
|
||||||
BActivationTransaction transaction;
|
|
||||||
BDirectory transactionDirectory;
|
|
||||||
status_t error = daemonClient.CreateTransaction(
|
|
||||||
installationRepository.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
|
|
||||||
|
|
||||||
BString fileName(package->Info().FileName());
|
|
||||||
if (fileName.IsEmpty())
|
|
||||||
DIE(B_NO_MEMORY, "failed to allocate file name");
|
|
||||||
|
|
||||||
BEntry entry;
|
|
||||||
error = entry.SetTo(&transactionDirectory, fileName);
|
|
||||||
if (error != B_OK)
|
|
||||||
DIE(error, "failed to create package entry");
|
|
||||||
|
|
||||||
RemoteRepository* remoteRepository
|
|
||||||
= dynamic_cast<RemoteRepository*>(package->Repository());
|
|
||||||
if (remoteRepository == NULL) {
|
|
||||||
// clone the existing package
|
|
||||||
_ClonePackageFile(
|
|
||||||
dynamic_cast<InstalledRepository*>(package->Repository()),
|
|
||||||
fileName, entry);
|
|
||||||
} else {
|
|
||||||
// download the package
|
|
||||||
BString url = remoteRepository->Config().PackagesURL();
|
|
||||||
url << '/' << fileName;
|
|
||||||
|
|
||||||
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(fileName)) {
|
|
||||||
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().FileName())) {
|
|
||||||
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("Changes applied in \"%s\". Old activation state backed up in "
|
|
||||||
"\"%s\"\n", installationRepository.Name().String(),
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::_ClonePackageFile(InstalledRepository* repository,
|
|
||||||
const BString& fileName, const BEntry& entry) const
|
|
||||||
{
|
|
||||||
// get the source and destination file paths
|
|
||||||
directory_which packagesWhich;
|
|
||||||
if (repository == fSystemRepository) {
|
|
||||||
packagesWhich = B_SYSTEM_PACKAGES_DIRECTORY;
|
|
||||||
} else if (repository == fCommonRepository) {
|
|
||||||
packagesWhich = B_COMMON_PACKAGES_DIRECTORY;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "*** don't know packages directory path for "
|
|
||||||
"installation location \"%s\"", repository->Name().String());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
BPath destinationPath;
|
|
||||||
error = entry.GetPath(&destinationPath);
|
|
||||||
if (error != B_OK) {
|
|
||||||
DIE(error, "failed to entry path of package file to install \"%s\"",
|
|
||||||
fileName.String());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the package. Ideally we would just hard-link it, but BFS doesn't
|
|
||||||
// support that.
|
|
||||||
error = BCopyEngine().CopyEntry(sourcePath.Path(), destinationPath.Path());
|
|
||||||
if (error != B_OK)
|
|
||||||
DIE(error, "failed to copy package file \"%s\"", sourcePath.Path());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
PackageManager::_FindBasePackage(const PackageList& packages,
|
|
||||||
const BPackageInfo& info) const
|
|
||||||
{
|
|
||||||
if (info.BasePackage().IsEmpty())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// find the requirement matching the base package
|
|
||||||
BPackageResolvableExpression* basePackage = NULL;
|
|
||||||
int32 count = info.RequiresList().CountItems();
|
|
||||||
for (int32 i = 0; i < count; i++) {
|
|
||||||
BPackageResolvableExpression* requires = info.RequiresList().ItemAt(i);
|
|
||||||
if (requires->Name() == info.BasePackage()) {
|
|
||||||
basePackage = requires;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (basePackage == NULL) {
|
|
||||||
printf("warning: package %s-%s doesn't have a matching requires for "
|
|
||||||
"its base package \"%s\"\n", info.Name().String(),
|
|
||||||
info.Version().ToString().String(), info.BasePackage().String());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the first package matching the base package requires
|
|
||||||
count = packages.CountItems();
|
|
||||||
for (int32 i = 0; i < count; i++) {
|
|
||||||
BSolverPackage* package = packages.ItemAt(i);
|
|
||||||
if (package->Name() == basePackage->Name()
|
|
||||||
&& package->Info().Matches(*basePackage)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PackageManager::InstalledRepository&
|
|
||||||
PackageManager::_InstallationRepository()
|
|
||||||
{
|
|
||||||
if (fInstalledRepositories.IsEmpty())
|
|
||||||
DIE(B_ERROR, "no installation repository");
|
|
||||||
|
|
||||||
return *fInstalledRepositories.LastItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PackageManager::_AddInstalledRepository(InstalledRepository* repository)
|
|
||||||
{
|
|
||||||
const char* name = repository->InitialName();
|
|
||||||
RepositoryBuilder(*repository, name)
|
|
||||||
.AddPackages(repository->Location(), name)
|
|
||||||
.AddToSolver(fSolver, repository->Location() == fLocation);
|
|
||||||
repository->SetPriority(repository->InitialPriority());
|
|
||||||
|
|
||||||
if (!fInstalledRepositories.AddItem(repository))
|
|
||||||
DIE(B_NO_MEMORY, "failed to add %s repository to list", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
PackageManager::_NextSpecificInstallationLocation()
|
|
||||||
{
|
|
||||||
if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) {
|
|
||||||
fLocation = B_PACKAGE_INSTALLATION_LOCATION_COMMON;
|
|
||||||
fSystemRepository->SetInstalled(false);
|
|
||||||
_AddInstalledRepository(fCommonRepository);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_COMMON) {
|
|
||||||
fLocation = B_PACKAGE_INSTALLATION_LOCATION_HOME;
|
|
||||||
fCommonRepository->SetInstalled(false);
|
|
||||||
_AddInstalledRepository(fHomeRepository);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
+32
-125
@@ -9,151 +9,58 @@
|
|||||||
#define PACKAGE_MANAGER_H
|
#define PACKAGE_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
#include <ObjectList.h>
|
#include <package/DaemonClient.h>
|
||||||
#include <package/Context.h>
|
#include <package/manager/PackageManager.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 "DecisionProvider.h"
|
||||||
#include "JobStateListener.h"
|
#include "JobStateListener.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace BPackageKit;
|
using namespace BPackageKit;
|
||||||
|
using BPackageKit::BPrivate::BDaemonClient;
|
||||||
|
using BManager::BPrivate::BPackageManager;
|
||||||
|
|
||||||
|
|
||||||
class PackageManager {
|
class PackageManager : public BPackageManager,
|
||||||
public:
|
private BPackageManager::RequestHandler,
|
||||||
struct RemoteRepository;
|
private BPackageManager::UserInteractionHandler {
|
||||||
struct InstalledRepository;
|
|
||||||
typedef BObjectList<RemoteRepository> RemoteRepositoryList;
|
|
||||||
typedef BObjectList<InstalledRepository> InstalledRepositoryList;
|
|
||||||
typedef BObjectList<BSolverPackage> PackageList;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ADD_INSTALLED_REPOSITORIES = 0x01,
|
|
||||||
ADD_REMOTE_REPOSITORIES = 0x02,
|
|
||||||
REFRESH_REPOSITORIES = 0x04,
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PackageManager(
|
PackageManager(
|
||||||
BPackageInstallationLocation location,
|
BPackageInstallationLocation location);
|
||||||
uint32 flags);
|
|
||||||
~PackageManager();
|
~PackageManager();
|
||||||
|
|
||||||
BSolver* Solver() const
|
private:
|
||||||
{ return fSolver; }
|
// RequestHandler
|
||||||
|
virtual status_t RefreshRepository(
|
||||||
const InstalledRepository* SystemRepository() const
|
const BRepositoryConfig& repoConfig);
|
||||||
{ return fSystemRepository; }
|
virtual status_t DownloadPackage(const BString& fileURL,
|
||||||
const InstalledRepository* CommonRepository() const
|
const BEntry& targetEntry,
|
||||||
{ return fCommonRepository; }
|
const BString& checksum);
|
||||||
const InstalledRepository* HomeRepository() const
|
|
||||||
{ return fHomeRepository; }
|
|
||||||
const InstalledRepositoryList& InstalledRepositories() const
|
|
||||||
{ return fInstalledRepositories; }
|
|
||||||
const RemoteRepositoryList& OtherRepositories() const
|
|
||||||
{ return fOtherRepositories; }
|
|
||||||
|
|
||||||
void Install(const char* const* packages,
|
|
||||||
int packageCount);
|
|
||||||
void Uninstall(const char* const* packages,
|
|
||||||
int packageCount);
|
|
||||||
void Update(const char* const* packages,
|
|
||||||
int packageCount);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _HandleProblems();
|
// UserInteractionHandler
|
||||||
void _AnalyzeResult();
|
virtual void HandleProblems();
|
||||||
void _PrintResult(bool fromMostSpecific = false);
|
virtual void ConfirmChanges(bool fromMostSpecific);
|
||||||
void _PrintResult(
|
|
||||||
InstalledRepository&
|
|
||||||
installationRepository);
|
|
||||||
void _ApplyPackageChanges(
|
|
||||||
bool fromMostSpecific = false);
|
|
||||||
void _ApplyPackageChanges(
|
|
||||||
InstalledRepository&
|
|
||||||
installationRepository);
|
|
||||||
|
|
||||||
void _ClonePackageFile(
|
virtual void Warn(status_t error, const char* format, ...);
|
||||||
InstalledRepository* repository,
|
virtual void ProgressStartApplyingChanges(
|
||||||
const BString& fileName,
|
InstalledRepository& repository);
|
||||||
const BEntry& entry) const;
|
virtual void ProgressTransactionCommitted(
|
||||||
int32 _FindBasePackage(const PackageList& packages,
|
InstalledRepository& repository,
|
||||||
const BPackageInfo& info) const;
|
const char* transactionDirectoryName);
|
||||||
|
virtual void ProgressApplyingChangesDone(
|
||||||
InstalledRepository& _InstallationRepository();
|
InstalledRepository& repository);
|
||||||
|
|
||||||
void _AddInstalledRepository(
|
private:
|
||||||
InstalledRepository* repository);
|
void _PrintResult(InstalledRepository&
|
||||||
bool _NextSpecificInstallationLocation();
|
installationRepository);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BPackageInstallationLocation fLocation;
|
|
||||||
BSolver* fSolver;
|
|
||||||
InstalledRepository* fSystemRepository;
|
|
||||||
InstalledRepository* fCommonRepository;
|
|
||||||
InstalledRepository* fHomeRepository;
|
|
||||||
InstalledRepositoryList fInstalledRepositories;
|
|
||||||
RemoteRepositoryList fOtherRepositories;
|
|
||||||
DecisionProvider fDecisionProvider;
|
DecisionProvider fDecisionProvider;
|
||||||
JobStateListener fJobStateListener;
|
JobStateListener fJobStateListener;
|
||||||
BContext fContext;
|
BContext fContext;
|
||||||
PackageList fPackagesToActivate;
|
BPackageManager::DaemonClientTransactionHandler
|
||||||
PackageList fPackagesToDeactivate;
|
fDaemonClientTransactionHandler;
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PackageManager::RemoteRepository : public BSolverRepository {
|
|
||||||
public:
|
|
||||||
RemoteRepository();
|
|
||||||
|
|
||||||
status_t Init(BPackageRoster& roster, BContext& context,
|
|
||||||
const char* name, bool refresh);
|
|
||||||
|
|
||||||
const BRepositoryConfig& Config() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
BRepositoryConfig fConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PackageManager::InstalledRepository : public BSolverRepository {
|
|
||||||
public:
|
|
||||||
typedef BObjectList<BSolverPackage> PackageList;
|
|
||||||
|
|
||||||
public:
|
|
||||||
InstalledRepository(const char* name,
|
|
||||||
BPackageInstallationLocation location,
|
|
||||||
int32 priority);
|
|
||||||
|
|
||||||
BPackageInstallationLocation Location() const
|
|
||||||
{ return fLocation; }
|
|
||||||
const char* InitialName() const
|
|
||||||
{ return fInitialName; }
|
|
||||||
int32 InitialPriority() const
|
|
||||||
{ return fInitialPriority; }
|
|
||||||
|
|
||||||
void DisablePackage(BSolverPackage* package);
|
|
||||||
|
|
||||||
PackageList& PackagesToActivate()
|
|
||||||
{ return fPackagesToActivate; }
|
|
||||||
PackageList& PackagesToDeactivate()
|
|
||||||
{ return fPackagesToDeactivate; }
|
|
||||||
|
|
||||||
bool HasChanges() const;
|
|
||||||
void ApplyChanges();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PackageList fDisabledPackages;
|
|
||||||
PackageList fPackagesToActivate;
|
|
||||||
PackageList fPackagesToDeactivate;
|
|
||||||
const char* fInitialName;
|
|
||||||
BPackageInstallationLocation fLocation;
|
|
||||||
int32 fInitialPriority;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Ingo Weinhold <[email protected]>
|
|
||||||
*/
|
|
||||||
#ifndef REPOSITORY_BUILDER_H
|
|
||||||
#define REPOSITORY_BUILDER_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <package/PackageInfo.h>
|
|
||||||
#include <package/solver/Solver.h>
|
|
||||||
#include <package/solver/SolverPackage.h>
|
|
||||||
#include <package/solver/SolverRepository.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace BPackageKit;
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<BSolverPackage*, BString> PackagePathMap;
|
|
||||||
|
|
||||||
|
|
||||||
class RepositoryBuilder {
|
|
||||||
private:
|
|
||||||
typedef RepositoryBuilder Builder;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RepositoryBuilder(BSolverRepository& repository,
|
|
||||||
const BString& name,
|
|
||||||
const BString& errorName = BString());
|
|
||||||
RepositoryBuilder(BSolverRepository& repository,
|
|
||||||
const BRepositoryConfig& config);
|
|
||||||
RepositoryBuilder(BSolverRepository& repository,
|
|
||||||
const BRepositoryCache& cache,
|
|
||||||
const BString& errorName = BString());
|
|
||||||
|
|
||||||
RepositoryBuilder& SetPackagePathMap(PackagePathMap* packagePaths);
|
|
||||||
|
|
||||||
RepositoryBuilder& AddPackage(const BPackageInfo& info,
|
|
||||||
const char* packageErrorName = NULL,
|
|
||||||
BSolverPackage** _package = NULL);
|
|
||||||
RepositoryBuilder& AddPackage(const char* path,
|
|
||||||
BSolverPackage** _package = NULL);
|
|
||||||
RepositoryBuilder& AddPackages(
|
|
||||||
BPackageInstallationLocation location,
|
|
||||||
const char* locationErrorName);
|
|
||||||
RepositoryBuilder& AddPackagesDirectory(const char* path);
|
|
||||||
|
|
||||||
RepositoryBuilder& AddToSolver(BSolver* solver,
|
|
||||||
bool isInstalled = false);
|
|
||||||
|
|
||||||
private:
|
|
||||||
BSolverRepository& fRepository;
|
|
||||||
BString fErrorName;
|
|
||||||
PackagePathMap* fPackagePaths;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // REPOSITORY_BUILDER_H
|
|
||||||
@@ -91,10 +91,7 @@ InstallCommand::Execute(int argc, const char* const* argv)
|
|||||||
const char* const* packages = argv + optind;
|
const char* const* packages = argv + optind;
|
||||||
|
|
||||||
// perform the installation
|
// perform the installation
|
||||||
PackageManager packageManager(location,
|
PackageManager packageManager(location);
|
||||||
PackageManager::ADD_INSTALLED_REPOSITORIES
|
|
||||||
| PackageManager::ADD_REMOTE_REPOSITORIES
|
|
||||||
| PackageManager::REFRESH_REPOSITORIES);
|
|
||||||
packageManager.Install(packages, packageCount);
|
packageManager.Install(packages, packageCount);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <package/manager/RepositoryBuilder.h>
|
||||||
#include <package/solver/SolverPackageSpecifier.h>
|
#include <package/solver/SolverPackageSpecifier.h>
|
||||||
#include <package/solver/SolverPackageSpecifierList.h>
|
#include <package/solver/SolverPackageSpecifierList.h>
|
||||||
#include <package/solver/SolverProblem.h>
|
#include <package/solver/SolverProblem.h>
|
||||||
@@ -22,13 +23,14 @@
|
|||||||
|
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
#include "pkgman.h"
|
#include "pkgman.h"
|
||||||
#include "RepositoryBuilder.h"
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: internationalization!
|
// TODO: internationalization!
|
||||||
|
|
||||||
|
|
||||||
using namespace BPackageKit;
|
using namespace BPackageKit;
|
||||||
|
using BManager::BPrivate::BPackagePathMap;
|
||||||
|
using BManager::BPrivate::BRepositoryBuilder;
|
||||||
|
|
||||||
|
|
||||||
static const char* const kShortUsage =
|
static const char* const kShortUsage =
|
||||||
@@ -77,7 +79,7 @@ check_problems(BSolver* solver, const char* errorContext)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
verify_result(const BSolverResult& result,
|
verify_result(const BSolverResult& result,
|
||||||
const PackagePathMap& specifiedPackagePaths)
|
const BPackagePathMap& specifiedPackagePaths)
|
||||||
{
|
{
|
||||||
// create the solver
|
// create the solver
|
||||||
BSolver* solver;
|
BSolver* solver;
|
||||||
@@ -88,7 +90,7 @@ verify_result(const BSolverResult& result,
|
|||||||
// Add an installation repository and add all of the result packages save
|
// Add an installation repository and add all of the result packages save
|
||||||
// the specified packages.
|
// the specified packages.
|
||||||
BSolverRepository installation;
|
BSolverRepository installation;
|
||||||
RepositoryBuilder installationBuilder(installation, "installation");
|
BRepositoryBuilder installationBuilder(installation, "installation");
|
||||||
|
|
||||||
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
|
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
|
||||||
i++) {
|
i++) {
|
||||||
@@ -160,7 +162,7 @@ ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
|
|||||||
DIE(error, "failed to create solver");
|
DIE(error, "failed to create solver");
|
||||||
|
|
||||||
// add repositories
|
// add repositories
|
||||||
PackagePathMap packagePaths;
|
BPackagePathMap packagePaths;
|
||||||
BObjectList<BSolverRepository> repositories(10, true);
|
BObjectList<BSolverRepository> repositories(10, true);
|
||||||
int32 repositoryIndex = 0;
|
int32 repositoryIndex = 0;
|
||||||
for (int i = 0; i < repositoryDirectoryCount; i++, repositoryIndex++) {
|
for (int i = 0; i < repositoryDirectoryCount; i++, repositoryIndex++) {
|
||||||
@@ -180,17 +182,18 @@ ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RepositoryBuilder(*repository, BString("repository") << repositoryIndex)
|
BRepositoryBuilder(*repository,
|
||||||
|
BString("repository") << repositoryIndex)
|
||||||
.SetPackagePathMap(&packagePaths)
|
.SetPackagePathMap(&packagePaths)
|
||||||
.AddPackagesDirectory(directoryPath)
|
.AddPackagesDirectory(directoryPath)
|
||||||
.AddToSolver(solver);
|
.AddToSolver(solver);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a repository with only the specified packages
|
// add a repository with only the specified packages
|
||||||
PackagePathMap specifiedPackagePaths;
|
BPackagePathMap specifiedPackagePaths;
|
||||||
BSolverRepository dummyRepository;
|
BSolverRepository dummyRepository;
|
||||||
{
|
{
|
||||||
RepositoryBuilder builder(dummyRepository, "dummy",
|
BRepositoryBuilder builder(dummyRepository, "dummy",
|
||||||
"specified packages");
|
"specified packages");
|
||||||
builder.SetPackagePathMap(&specifiedPackagePaths);
|
builder.SetPackagePathMap(&specifiedPackagePaths);
|
||||||
|
|
||||||
@@ -202,7 +205,7 @@ ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
|
|||||||
|
|
||||||
// resolve
|
// resolve
|
||||||
BSolverPackageSpecifierList packagesToInstall;
|
BSolverPackageSpecifierList packagesToInstall;
|
||||||
for (PackagePathMap::const_iterator it = specifiedPackagePaths.begin();
|
for (BPackagePathMap::const_iterator it = specifiedPackagePaths.begin();
|
||||||
it != specifiedPackagePaths.end(); ++it) {
|
it != specifiedPackagePaths.end(); ++it) {
|
||||||
if (!packagesToInstall.AppendSpecifier(it->first))
|
if (!packagesToInstall.AppendSpecifier(it->first))
|
||||||
DIE(B_NO_MEMORY, "failed to add specified package");
|
DIE(B_NO_MEMORY, "failed to add specified package");
|
||||||
@@ -231,7 +234,7 @@ ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// resolve and print the path
|
// resolve and print the path
|
||||||
PackagePathMap::const_iterator it = packagePaths.find(package);
|
BPackagePathMap::const_iterator it = packagePaths.find(package);
|
||||||
if (it == packagePaths.end()) {
|
if (it == packagePaths.end()) {
|
||||||
DIE(B_ERROR, "ugh, no package %p (%s-%s) not in package path map",
|
DIE(B_ERROR, "ugh, no package %p (%s-%s) not in package path map",
|
||||||
package, package->Info().Name().String(),
|
package, package->Info().Name().String(),
|
||||||
|
|||||||
@@ -119,9 +119,10 @@ SearchCommand::Execute(int argc, const char* const* argv)
|
|||||||
const char* searchString = listAll ? "" : argv[optind++];
|
const char* searchString = listAll ? "" : argv[optind++];
|
||||||
|
|
||||||
// create the solver
|
// create the solver
|
||||||
PackageManager packageManager(B_PACKAGE_INSTALLATION_LOCATION_HOME,
|
PackageManager packageManager(B_PACKAGE_INSTALLATION_LOCATION_HOME);
|
||||||
(!uninstalledOnly ? PackageManager::ADD_INSTALLED_REPOSITORIES : 0)
|
packageManager.Init(
|
||||||
| (!installedOnly ? PackageManager::ADD_REMOTE_REPOSITORIES : 0));
|
(!uninstalledOnly ? PackageManager::B_ADD_INSTALLED_REPOSITORIES : 0)
|
||||||
|
| (!installedOnly ? PackageManager::B_ADD_REMOTE_REPOSITORIES : 0));
|
||||||
|
|
||||||
// search
|
// search
|
||||||
BObjectList<BSolverPackage> packages;
|
BObjectList<BSolverPackage> packages;
|
||||||
|
|||||||
@@ -91,8 +91,7 @@ UninstallCommand::Execute(int argc, const char* const* argv)
|
|||||||
const char* const* packages = argv + optind;
|
const char* const* packages = argv + optind;
|
||||||
|
|
||||||
// perform the installation
|
// perform the installation
|
||||||
PackageManager packageManager(location,
|
PackageManager packageManager(location);
|
||||||
PackageManager::ADD_INSTALLED_REPOSITORIES);
|
|
||||||
packageManager.Uninstall(packages, packageCount);
|
packageManager.Uninstall(packages, packageCount);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -89,10 +89,7 @@ UpdateCommand::Execute(int argc, const char* const* argv)
|
|||||||
const char* const* packages = argv + optind;
|
const char* const* packages = argv + optind;
|
||||||
|
|
||||||
// perform the update
|
// perform the update
|
||||||
PackageManager packageManager(location,
|
PackageManager packageManager(location);
|
||||||
PackageManager::ADD_INSTALLED_REPOSITORIES
|
|
||||||
| PackageManager::ADD_REMOTE_REPOSITORIES
|
|
||||||
| PackageManager::REFRESH_REPOSITORIES);
|
|
||||||
packageManager.Update(packages, packageCount);
|
packageManager.Update(packages, packageCount);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -11,9 +11,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <package/manager/Exceptions.h>
|
||||||
|
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace BPackageKit::BManager::BPrivate;
|
||||||
|
|
||||||
|
|
||||||
extern const char* __progname;
|
extern const char* __progname;
|
||||||
const char* kProgramName = __progname;
|
const char* kProgramName = __progname;
|
||||||
|
|
||||||
@@ -85,5 +90,25 @@ main(int argc, const char* const* argv)
|
|||||||
if (commands.CountItems() != 1)
|
if (commands.CountItems() != 1)
|
||||||
print_usage_and_exit(true);
|
print_usage_and_exit(true);
|
||||||
|
|
||||||
return commands.ItemAt(0)->Execute(argc - 1, argv + 1);
|
try {
|
||||||
|
return commands.ItemAt(0)->Execute(argc - 1, argv + 1);
|
||||||
|
} catch (BNothingToDoException&) {
|
||||||
|
fprintf(stderr, "Nothing to do.\n");
|
||||||
|
return 0;
|
||||||
|
} catch (std::bad_alloc&) {
|
||||||
|
fprintf(stderr, "Out of memory!\n");
|
||||||
|
return 1;
|
||||||
|
} catch (BFatalErrorException& exception) {
|
||||||
|
if (!exception.Details().IsEmpty())
|
||||||
|
fprintf(stderr, "%s", exception.Details().String());
|
||||||
|
if (exception.Error() == B_OK) {
|
||||||
|
fprintf(stderr, "*** %s\n", exception.Message().String());
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "*** %s: %s\n", exception.Message().String(),
|
||||||
|
strerror(exception.Error()));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
} catch (BAbortedByUserException&) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ UsePrivateBuildHeaders kernel package shared storage ;
|
|||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg v1 ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg v1 ] ;
|
||||||
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package manager ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package solver ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package solver ] ;
|
||||||
|
|
||||||
USES_BE_API on libpackage_build.so = true ;
|
USES_BE_API on libpackage_build.so = true ;
|
||||||
@@ -116,6 +117,10 @@ BuildPlatformSharedLibrary libpackage_build.so
|
|||||||
NoErrorOutput.cpp
|
NoErrorOutput.cpp
|
||||||
StandardErrorOutput.cpp
|
StandardErrorOutput.cpp
|
||||||
|
|
||||||
|
# manager
|
||||||
|
Exceptions.cpp
|
||||||
|
RepositoryBuilder.cpp
|
||||||
|
|
||||||
# solver
|
# solver
|
||||||
Solver.cpp
|
Solver.cpp
|
||||||
SolverPackage.cpp
|
SolverPackage.cpp
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
|
|
||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg v1 ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg v1 ] ;
|
||||||
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package manager ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package solver ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package solver ] ;
|
||||||
|
|
||||||
Includes [ FGristFiles $(HPKG_SOURCES) ]
|
Includes [ FGristFiles $(HPKG_SOURCES) ]
|
||||||
@@ -112,6 +113,11 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
NoErrorOutput.cpp
|
NoErrorOutput.cpp
|
||||||
StandardErrorOutput.cpp
|
StandardErrorOutput.cpp
|
||||||
|
|
||||||
|
# manager
|
||||||
|
Exceptions.cpp
|
||||||
|
PackageManager.cpp
|
||||||
|
RepositoryBuilder.cpp
|
||||||
|
|
||||||
# solver
|
# solver
|
||||||
Solver.cpp
|
Solver.cpp
|
||||||
SolverPackage.cpp
|
SolverPackage.cpp
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <package/manager/Exceptions.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPackageKit {
|
||||||
|
|
||||||
|
namespace BManager {
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BException
|
||||||
|
|
||||||
|
|
||||||
|
BException::BException()
|
||||||
|
:
|
||||||
|
fMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BException::BException(const BString& message)
|
||||||
|
:
|
||||||
|
fMessage(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BFatalErrorException
|
||||||
|
|
||||||
|
|
||||||
|
BFatalErrorException::BFatalErrorException()
|
||||||
|
:
|
||||||
|
BException(),
|
||||||
|
fDetails(),
|
||||||
|
fError(B_OK)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BFatalErrorException::BFatalErrorException(const char* format, ...)
|
||||||
|
:
|
||||||
|
BException(),
|
||||||
|
fDetails(),
|
||||||
|
fError(B_OK)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
fMessage.SetToFormatVarArgs(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BFatalErrorException::BFatalErrorException(status_t error, const char* format,
|
||||||
|
...)
|
||||||
|
:
|
||||||
|
BException(),
|
||||||
|
fDetails(),
|
||||||
|
fError(error)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
fMessage.SetToFormatVarArgs(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BFatalErrorException&
|
||||||
|
BFatalErrorException::SetDetails(const BString& details)
|
||||||
|
{
|
||||||
|
fDetails = details;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BAbortedByUserException
|
||||||
|
|
||||||
|
|
||||||
|
BAbortedByUserException::BAbortedByUserException()
|
||||||
|
:
|
||||||
|
BException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BNothingToDoException
|
||||||
|
|
||||||
|
|
||||||
|
BNothingToDoException::BNothingToDoException()
|
||||||
|
:
|
||||||
|
BException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
} // namespace BManager
|
||||||
|
|
||||||
|
} // namespace BPackageKit
|
||||||
@@ -0,0 +1,824 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <package/manager/PackageManager.h>
|
||||||
|
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <package/PackageRoster.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 <CopyEngine.h>
|
||||||
|
#include <package/ActivationTransaction.h>
|
||||||
|
#include <package/DaemonClient.h>
|
||||||
|
#include <package/manager/RepositoryBuilder.h>
|
||||||
|
|
||||||
|
#include "PackageManagerUtils.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPackageKit {
|
||||||
|
|
||||||
|
namespace BManager {
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BPackageManager
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::BPackageManager(BPackageInstallationLocation location)
|
||||||
|
:
|
||||||
|
fLocation(location),
|
||||||
|
fSolver(NULL),
|
||||||
|
fSystemRepository(new (std::nothrow) InstalledRepository("system",
|
||||||
|
B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, -1)),
|
||||||
|
fCommonRepository(new (std::nothrow) InstalledRepository("common",
|
||||||
|
B_PACKAGE_INSTALLATION_LOCATION_COMMON, -2)),
|
||||||
|
fHomeRepository(new (std::nothrow) InstalledRepository("home",
|
||||||
|
B_PACKAGE_INSTALLATION_LOCATION_HOME, -3)),
|
||||||
|
fInstalledRepositories(10),
|
||||||
|
fOtherRepositories(10, true),
|
||||||
|
fTransactions(5, true),
|
||||||
|
fTransactionHandler(NULL),
|
||||||
|
fRequestHandler(NULL),
|
||||||
|
fUserInteractionHandler(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::~BPackageManager()
|
||||||
|
{
|
||||||
|
delete fSolver;
|
||||||
|
delete fSystemRepository;
|
||||||
|
delete fCommonRepository;
|
||||||
|
delete fHomeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::Init(uint32 flags)
|
||||||
|
{
|
||||||
|
if (fSolver != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create the solver
|
||||||
|
status_t error = BSolver::Create(fSolver);
|
||||||
|
if (error != B_OK)
|
||||||
|
DIE(error, "failed to create solver");
|
||||||
|
|
||||||
|
if (fSystemRepository == NULL || fCommonRepository == NULL
|
||||||
|
|| fHomeRepository == NULL) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add installation location repositories
|
||||||
|
if ((flags & B_ADD_INSTALLED_REPOSITORIES) != 0) {
|
||||||
|
// 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.
|
||||||
|
_AddInstalledRepository(fSystemRepository);
|
||||||
|
|
||||||
|
if (!fSystemRepository->IsInstalled()) {
|
||||||
|
_AddInstalledRepository(fCommonRepository);
|
||||||
|
|
||||||
|
if (!fCommonRepository->IsInstalled())
|
||||||
|
_AddInstalledRepository(fHomeRepository);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add other repositories
|
||||||
|
if ((flags & B_ADD_REMOTE_REPOSITORIES) != 0) {
|
||||||
|
BPackageRoster roster;
|
||||||
|
BStringList repositoryNames;
|
||||||
|
error = roster.GetRepositoryNames(repositoryNames);
|
||||||
|
if (error != B_OK) {
|
||||||
|
fUserInteractionHandler->Warn(error,
|
||||||
|
"failed to get repository names");
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 repositoryNameCount = repositoryNames.CountStrings();
|
||||||
|
for (int32 i = 0; i < repositoryNameCount; i++) {
|
||||||
|
_AddRemoteRepository(roster, repositoryNames.StringAt(i),
|
||||||
|
(flags & B_REFRESH_REPOSITORIES) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::Install(const char* const* packages, int packageCount)
|
||||||
|
{
|
||||||
|
Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
|
||||||
|
| B_REFRESH_REPOSITORIES);
|
||||||
|
|
||||||
|
// solve
|
||||||
|
BSolverPackageSpecifierList packagesToInstall;
|
||||||
|
for (int i = 0; i < packageCount; i++) {
|
||||||
|
if (!packagesToInstall.AppendSpecifier(packages[i]))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
_ConfirmChanges();
|
||||||
|
_ApplyPackageChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::Uninstall(const char* const* packages, int packageCount)
|
||||||
|
{
|
||||||
|
Init(B_ADD_INSTALLED_REPOSITORIES);
|
||||||
|
|
||||||
|
// find the packages that match the specification
|
||||||
|
BSolverPackageSpecifierList packagesToUninstall;
|
||||||
|
for (int i = 0; i < packageCount; i++) {
|
||||||
|
if (!packagesToUninstall.AppendSpecifier(packages[i]))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
const BSolverPackageSpecifier* unmatchedSpecifier;
|
||||||
|
PackageList foundPackages;
|
||||||
|
status_t error = fSolver->FindPackages(packagesToUninstall,
|
||||||
|
BSolver::B_FIND_INSTALLED_ONLY, foundPackages, &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 uninstall");
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the inverse base package closure for the found packages
|
||||||
|
// TODO: Optimize!
|
||||||
|
InstalledRepository& installationRepository = _InstallationRepository();
|
||||||
|
bool foundAnotherPackage;
|
||||||
|
do {
|
||||||
|
foundAnotherPackage = false;
|
||||||
|
int32 count = installationRepository.CountPackages();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BSolverPackage* package = installationRepository.PackageAt(i);
|
||||||
|
if (foundPackages.HasItem(package))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_FindBasePackage(foundPackages, package->Info()) >= 0) {
|
||||||
|
foundPackages.AddItem(package);
|
||||||
|
foundAnotherPackage = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (foundAnotherPackage);
|
||||||
|
|
||||||
|
// remove the packages from the repository
|
||||||
|
for (int32 i = 0; BSolverPackage* package = foundPackages.ItemAt(i); i++)
|
||||||
|
installationRepository.DisablePackage(package);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
error = fSolver->VerifyInstallation(BSolver::B_VERIFY_ALLOW_UNINSTALL);
|
||||||
|
if (error != B_OK)
|
||||||
|
DIE(error, "failed to compute packages to uninstall");
|
||||||
|
|
||||||
|
_HandleProblems();
|
||||||
|
|
||||||
|
// (virtually) apply the result to this repository
|
||||||
|
_AnalyzeResult();
|
||||||
|
|
||||||
|
for (int32 i = foundPackages.CountItems() - 1; i >= 0; i--) {
|
||||||
|
if (!installationRepository.PackagesToDeactivate()
|
||||||
|
.AddItem(foundPackages.ItemAt(i))) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
installationRepository.ApplyChanges();
|
||||||
|
|
||||||
|
// verify the next specific respository
|
||||||
|
if (!_NextSpecificInstallationLocation())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foundPackages.MakeEmpty();
|
||||||
|
|
||||||
|
// NOTE: In theory, after verifying a more specific location, it would
|
||||||
|
// be more correct to compute the inverse base package closure for the
|
||||||
|
// packages we need to uninstall and (if anything changed) verify again.
|
||||||
|
// In practice, however, base packages are always required with an exact
|
||||||
|
// version (ATM). If that base package still exist in a more general
|
||||||
|
// location (the only reason why the package requiring the base package
|
||||||
|
// wouldn't be marked to be uninstalled as well) there shouldn't have
|
||||||
|
// been any reason to remove it from the more specific location in the
|
||||||
|
// first place.
|
||||||
|
}
|
||||||
|
|
||||||
|
_ConfirmChanges(true);
|
||||||
|
_ApplyPackageChanges(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::Update(const char* const* packages, int packageCount)
|
||||||
|
{
|
||||||
|
Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
|
||||||
|
| B_REFRESH_REPOSITORIES);
|
||||||
|
|
||||||
|
// solve
|
||||||
|
BSolverPackageSpecifierList packagesToUpdate;
|
||||||
|
for (int i = 0; i < packageCount; i++) {
|
||||||
|
if (!packagesToUpdate.AppendSpecifier(packages[i]))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
const BSolverPackageSpecifier* unmatchedSpecifier;
|
||||||
|
status_t error = fSolver->Update(packagesToUpdate, true,
|
||||||
|
&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 update");
|
||||||
|
}
|
||||||
|
|
||||||
|
_HandleProblems();
|
||||||
|
|
||||||
|
// install/uninstall packages
|
||||||
|
_AnalyzeResult();
|
||||||
|
_ConfirmChanges();
|
||||||
|
_ApplyPackageChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_HandleProblems()
|
||||||
|
{
|
||||||
|
while (fSolver->HasProblems()) {
|
||||||
|
fUserInteractionHandler->HandleProblems();
|
||||||
|
|
||||||
|
status_t error = fSolver->SolveAgain();
|
||||||
|
if (error != B_OK)
|
||||||
|
DIE(error, "failed to recompute packages to un/-install");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_AnalyzeResult()
|
||||||
|
{
|
||||||
|
BSolverResult result;
|
||||||
|
status_t error = fSolver->GetResult(result);
|
||||||
|
if (error != B_OK)
|
||||||
|
DIE(error, "failed to compute packages to un/-install");
|
||||||
|
|
||||||
|
InstalledRepository& installationRepository = _InstallationRepository();
|
||||||
|
PackageList& packagesToActivate
|
||||||
|
= installationRepository.PackagesToActivate();
|
||||||
|
PackageList& packagesToDeactivate
|
||||||
|
= installationRepository.PackagesToDeactivate();
|
||||||
|
|
||||||
|
PackageList potentialBasePackages;
|
||||||
|
|
||||||
|
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
|
||||||
|
i++) {
|
||||||
|
BSolverPackage* package = element->Package();
|
||||||
|
|
||||||
|
switch (element->Type()) {
|
||||||
|
case BSolverResultElement::B_TYPE_INSTALL:
|
||||||
|
{
|
||||||
|
PackageList& packageList
|
||||||
|
= dynamic_cast<InstalledRepository*>(package->Repository())
|
||||||
|
!= NULL
|
||||||
|
? potentialBasePackages
|
||||||
|
: packagesToActivate;
|
||||||
|
if (!packageList.AddItem(package))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BSolverResultElement::B_TYPE_UNINSTALL:
|
||||||
|
if (!packagesToDeactivate.AddItem(package))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure base packages are installed in the same location.
|
||||||
|
for (int32 i = 0; i < packagesToActivate.CountItems(); i++) {
|
||||||
|
BSolverPackage* package = packagesToActivate.ItemAt(i);
|
||||||
|
int32 index = _FindBasePackage(potentialBasePackages, package->Info());
|
||||||
|
if (index < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BSolverPackage* basePackage = potentialBasePackages.RemoveItemAt(index);
|
||||||
|
if (!packagesToActivate.AddItem(basePackage))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_ConfirmChanges(bool fromMostSpecific)
|
||||||
|
{
|
||||||
|
// check, if there are any changes at all
|
||||||
|
int32 count = fInstalledRepositories.CountItems();
|
||||||
|
bool hasChanges = false;
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
if (fInstalledRepositories.ItemAt(i)->HasChanges()) {
|
||||||
|
hasChanges = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasChanges)
|
||||||
|
throw BNothingToDoException();
|
||||||
|
|
||||||
|
fUserInteractionHandler->ConfirmChanges(fromMostSpecific);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_ApplyPackageChanges(bool fromMostSpecific)
|
||||||
|
{
|
||||||
|
int32 count = fInstalledRepositories.CountItems();
|
||||||
|
if (fromMostSpecific) {
|
||||||
|
for (int32 i = count - 1; i >= 0; i--)
|
||||||
|
_PreparePackageChanges(*fInstalledRepositories.ItemAt(i));
|
||||||
|
} else {
|
||||||
|
for (int32 i = 0; i < count; i++)
|
||||||
|
_PreparePackageChanges(*fInstalledRepositories.ItemAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 i = 0; Transaction* transaction = fTransactions.ItemAt(i); i++)
|
||||||
|
_CommitPackageChanges(*transaction);
|
||||||
|
|
||||||
|
// TODO: Clean up the transaction directories on error!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_PreparePackageChanges(
|
||||||
|
InstalledRepository& installationRepository)
|
||||||
|
{
|
||||||
|
if (!installationRepository.HasChanges())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PackageList& packagesToActivate
|
||||||
|
= installationRepository.PackagesToActivate();
|
||||||
|
PackageList& packagesToDeactivate
|
||||||
|
= installationRepository.PackagesToDeactivate();
|
||||||
|
|
||||||
|
// create the transaction
|
||||||
|
Transaction* transaction = new Transaction(installationRepository);
|
||||||
|
if (!fTransactions.AddItem(transaction)) {
|
||||||
|
delete transaction;
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t error = fTransactionHandler->PrepareTransaction(*transaction);
|
||||||
|
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
|
||||||
|
|
||||||
|
BString fileName(package->Info().FileName());
|
||||||
|
if (fileName.IsEmpty())
|
||||||
|
throw std::bad_alloc();
|
||||||
|
|
||||||
|
BEntry entry;
|
||||||
|
error = entry.SetTo(&transaction->TransactionDirectory(), fileName);
|
||||||
|
if (error != B_OK)
|
||||||
|
DIE(error, "failed to create package entry");
|
||||||
|
|
||||||
|
RemoteRepository* remoteRepository
|
||||||
|
= dynamic_cast<RemoteRepository*>(package->Repository());
|
||||||
|
if (remoteRepository == NULL) {
|
||||||
|
// clone the existing package
|
||||||
|
_ClonePackageFile(
|
||||||
|
dynamic_cast<InstalledRepository*>(package->Repository()),
|
||||||
|
fileName, entry);
|
||||||
|
} else {
|
||||||
|
// download the package
|
||||||
|
BString url = remoteRepository->Config().PackagesURL();
|
||||||
|
url << '/' << fileName;
|
||||||
|
|
||||||
|
status_t error = fRequestHandler->DownloadPackage(url, entry,
|
||||||
|
package->Info().Checksum());
|
||||||
|
if (error != B_OK)
|
||||||
|
DIE(error, "failed to download package");
|
||||||
|
}
|
||||||
|
|
||||||
|
// add package to transaction
|
||||||
|
if (!transaction->ActivationTransaction().AddPackageToActivate(
|
||||||
|
fileName)) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
|
||||||
|
i++) {
|
||||||
|
// add package to transaction
|
||||||
|
if (!transaction->ActivationTransaction().AddPackageToDeactivate(
|
||||||
|
package->Info().FileName())) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_CommitPackageChanges(Transaction& transaction)
|
||||||
|
{
|
||||||
|
InstalledRepository& installationRepository = transaction.Repository();
|
||||||
|
|
||||||
|
fUserInteractionHandler->ProgressStartApplyingChanges(
|
||||||
|
installationRepository);
|
||||||
|
|
||||||
|
// commit the transaction
|
||||||
|
BDaemonClient::BCommitTransactionResult transactionResult;
|
||||||
|
status_t error = fTransactionHandler->CommitTransaction(transaction,
|
||||||
|
transactionResult);
|
||||||
|
if (error != B_OK) {
|
||||||
|
DIE("failed to commit transaction: %s",
|
||||||
|
transactionResult.FullErrorMessage().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
fUserInteractionHandler->ProgressTransactionCommitted(
|
||||||
|
installationRepository, transactionResult.OldStateDirectory());
|
||||||
|
|
||||||
|
BEntry transactionDirectoryEntry;
|
||||||
|
if ((error = transaction.TransactionDirectory()
|
||||||
|
.GetEntry(&transactionDirectoryEntry)) != B_OK
|
||||||
|
|| (error = transactionDirectoryEntry.Remove()) != B_OK) {
|
||||||
|
fUserInteractionHandler->Warn(error,
|
||||||
|
"failed to remove transaction directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
fUserInteractionHandler->ProgressApplyingChangesDone(
|
||||||
|
installationRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_ClonePackageFile(InstalledRepository* repository,
|
||||||
|
const BString& fileName, const BEntry& entry)
|
||||||
|
{
|
||||||
|
// get the source and destination file paths
|
||||||
|
directory_which packagesWhich;
|
||||||
|
if (repository == fSystemRepository) {
|
||||||
|
packagesWhich = B_SYSTEM_PACKAGES_DIRECTORY;
|
||||||
|
} else if (repository == fCommonRepository) {
|
||||||
|
packagesWhich = B_COMMON_PACKAGES_DIRECTORY;
|
||||||
|
} else {
|
||||||
|
DIE("don't know packages directory path for installation location "
|
||||||
|
"\"%s\"", repository->Name().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
BPath destinationPath;
|
||||||
|
error = entry.GetPath(&destinationPath);
|
||||||
|
if (error != B_OK) {
|
||||||
|
DIE(error, "failed to entry path of package file to install \"%s\"",
|
||||||
|
fileName.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the package. Ideally we would just hard-link it, but BFS doesn't
|
||||||
|
// support that.
|
||||||
|
error = BCopyEngine().CopyEntry(sourcePath.Path(), destinationPath.Path());
|
||||||
|
if (error != B_OK)
|
||||||
|
DIE(error, "failed to copy package file \"%s\"", sourcePath.Path());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BPackageManager::_FindBasePackage(const PackageList& packages,
|
||||||
|
const BPackageInfo& info)
|
||||||
|
{
|
||||||
|
if (info.BasePackage().IsEmpty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// find the requirement matching the base package
|
||||||
|
BPackageResolvableExpression* basePackage = NULL;
|
||||||
|
int32 count = info.RequiresList().CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BPackageResolvableExpression* requires = info.RequiresList().ItemAt(i);
|
||||||
|
if (requires->Name() == info.BasePackage()) {
|
||||||
|
basePackage = requires;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basePackage == NULL) {
|
||||||
|
fUserInteractionHandler->Warn(B_OK, "package %s-%s doesn't have a "
|
||||||
|
"matching requires for its base package \"%s\"",
|
||||||
|
info.Name().String(), info.Version().ToString().String(),
|
||||||
|
info.BasePackage().String());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the first package matching the base package requires
|
||||||
|
count = packages.CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BSolverPackage* package = packages.ItemAt(i);
|
||||||
|
if (package->Name() == basePackage->Name()
|
||||||
|
&& package->Info().Matches(*basePackage)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::InstalledRepository&
|
||||||
|
BPackageManager::_InstallationRepository()
|
||||||
|
{
|
||||||
|
if (fInstalledRepositories.IsEmpty())
|
||||||
|
DIE("no installation repository");
|
||||||
|
|
||||||
|
return *fInstalledRepositories.LastItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_AddInstalledRepository(InstalledRepository* repository)
|
||||||
|
{
|
||||||
|
const char* name = repository->InitialName();
|
||||||
|
BRepositoryBuilder(*repository, name)
|
||||||
|
.AddPackages(repository->Location(), name)
|
||||||
|
.AddToSolver(fSolver, repository->Location() == fLocation);
|
||||||
|
repository->SetPriority(repository->InitialPriority());
|
||||||
|
|
||||||
|
if (!fInstalledRepositories.AddItem(repository))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::_AddRemoteRepository(BPackageRoster& roster, const char* name,
|
||||||
|
bool refresh)
|
||||||
|
{
|
||||||
|
BRepositoryConfig config;
|
||||||
|
status_t error = _GetRepositoryConfig(roster, name, refresh, config);
|
||||||
|
if (error != B_OK) {
|
||||||
|
fUserInteractionHandler->Warn(error,
|
||||||
|
"failed to get config for repository \"%s\". Skipping.", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteRepository* repository = new RemoteRepository(config);
|
||||||
|
if (!fOtherRepositories.AddItem(repository)) {
|
||||||
|
delete repository;
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
BRepositoryBuilder(*repository, repository->Config())
|
||||||
|
.AddToSolver(fSolver, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPackageManager::_GetRepositoryConfig(BPackageRoster& roster, const char* name,
|
||||||
|
bool refresh, BRepositoryConfig& _config)
|
||||||
|
{
|
||||||
|
// get the repository config
|
||||||
|
status_t error = roster.GetRepositoryConfig(name, &_config);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// refresh
|
||||||
|
if (!refresh)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
error = fRequestHandler->RefreshRepository(_config);
|
||||||
|
if (error != B_OK) {
|
||||||
|
fUserInteractionHandler->Warn(error,
|
||||||
|
"refreshing repository \"%s\" failed", name);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-get the config
|
||||||
|
return roster.GetRepositoryConfig(name, &_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BPackageManager::_NextSpecificInstallationLocation()
|
||||||
|
{
|
||||||
|
if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) {
|
||||||
|
fLocation = B_PACKAGE_INSTALLATION_LOCATION_COMMON;
|
||||||
|
fSystemRepository->SetInstalled(false);
|
||||||
|
_AddInstalledRepository(fCommonRepository);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_COMMON) {
|
||||||
|
fLocation = B_PACKAGE_INSTALLATION_LOCATION_HOME;
|
||||||
|
fCommonRepository->SetInstalled(false);
|
||||||
|
_AddInstalledRepository(fHomeRepository);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - RemoteRepository
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::RemoteRepository::RemoteRepository(
|
||||||
|
const BRepositoryConfig& config)
|
||||||
|
:
|
||||||
|
BSolverRepository(),
|
||||||
|
fConfig(config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BRepositoryConfig&
|
||||||
|
BPackageManager::RemoteRepository::Config() const
|
||||||
|
{
|
||||||
|
return fConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - InstalledRepository
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::InstalledRepository::InstalledRepository(const char* name,
|
||||||
|
BPackageInstallationLocation location, int32 priority)
|
||||||
|
:
|
||||||
|
BSolverRepository(),
|
||||||
|
fDisabledPackages(10, true),
|
||||||
|
fPackagesToActivate(),
|
||||||
|
fPackagesToDeactivate(),
|
||||||
|
fInitialName(name),
|
||||||
|
fLocation(location),
|
||||||
|
fInitialPriority(priority)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::InstalledRepository::DisablePackage(BSolverPackage* package)
|
||||||
|
{
|
||||||
|
if (fDisabledPackages.HasItem(package))
|
||||||
|
DIE("package %s already disabled", package->VersionedName().String());
|
||||||
|
|
||||||
|
if (package->Repository() != this) {
|
||||||
|
DIE("package %s not in repository %s",
|
||||||
|
package->VersionedName().String(), Name().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
// move to disabled list
|
||||||
|
if (!fDisabledPackages.AddItem(package))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
|
||||||
|
RemovePackage(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BPackageManager::InstalledRepository::HasChanges() const
|
||||||
|
{
|
||||||
|
return !fPackagesToActivate.IsEmpty() || !fPackagesToDeactivate.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageManager::InstalledRepository::ApplyChanges()
|
||||||
|
{
|
||||||
|
// disable packages to deactivate
|
||||||
|
for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
|
||||||
|
i++) {
|
||||||
|
if (!fDisabledPackages.HasItem(package))
|
||||||
|
DisablePackage(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add packages to activate
|
||||||
|
for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i);
|
||||||
|
i++) {
|
||||||
|
status_t error = AddPackage(package->Info());
|
||||||
|
if (error != B_OK) {
|
||||||
|
DIE(error, "failed to add package %s to %s repository",
|
||||||
|
package->Name().String(), Name().String());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Transaction
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::Transaction::Transaction(InstalledRepository& repository)
|
||||||
|
:
|
||||||
|
fRepository(repository),
|
||||||
|
fTransaction(),
|
||||||
|
fTransactionDirectory()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::Transaction::~Transaction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TransactionHandler
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::TransactionHandler::~TransactionHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DaemonClientTransactionHandler
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::DaemonClientTransactionHandler
|
||||||
|
::DaemonClientTransactionHandler()
|
||||||
|
:
|
||||||
|
fDaemonClient()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::DaemonClientTransactionHandler
|
||||||
|
::~DaemonClientTransactionHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPackageManager::DaemonClientTransactionHandler::PrepareTransaction(
|
||||||
|
Transaction& transaction)
|
||||||
|
{
|
||||||
|
return fDaemonClient.CreateTransaction(transaction.Repository().Location(),
|
||||||
|
transaction.ActivationTransaction(),
|
||||||
|
transaction.TransactionDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPackageManager::DaemonClientTransactionHandler::CommitTransaction(
|
||||||
|
Transaction& transaction, BDaemonClient::BCommitTransactionResult& _result)
|
||||||
|
{
|
||||||
|
return fDaemonClient.CommitTransaction(transaction.ActivationTransaction(),
|
||||||
|
_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - RequestHandler
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::RequestHandler::~RequestHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - UserInteractionHandler
|
||||||
|
|
||||||
|
|
||||||
|
BPackageManager::UserInteractionHandler::~UserInteractionHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
} // namespace BManager
|
||||||
|
|
||||||
|
} // namespace BPackageKit
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef PACKAGE_MANAGER_UTILS_H
|
||||||
|
#define PACKAGE_MANAGER_UTILS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <package/manager/Exceptions.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define DIE(...) \
|
||||||
|
do { \
|
||||||
|
throw BFatalErrorException(__VA_ARGS__); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#define DIE_DETAILS(details, ...) \
|
||||||
|
do { \
|
||||||
|
throw BFatalErrorException(__VA_ARGS__).SetDetails(details); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#endif // PACKAGE_MANAGER_UTILS_H
|
||||||
+65
-22
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "RepositoryBuilder.h"
|
#include <package/manager/RepositoryBuilder.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@@ -18,11 +18,46 @@
|
|||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
#include "PackageInfoErrorListener.h"
|
#include "PackageManagerUtils.h"
|
||||||
#include "pkgman.h"
|
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
|
namespace BPackageKit {
|
||||||
|
|
||||||
|
namespace BManager {
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
class PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
|
||||||
|
public:
|
||||||
|
PackageInfoErrorListener(const char* context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnError(const BString& message, int line, int column)
|
||||||
|
{
|
||||||
|
fErrors << BString().SetToFormat("%s: parse error in line %d:%d: %s\n",
|
||||||
|
fContext, line, column, message.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
const BString& Errors() const
|
||||||
|
{
|
||||||
|
return fErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* fContext;
|
||||||
|
BString fErrors;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository,
|
||||||
const BString& name, const BString& errorName)
|
const BString& name, const BString& errorName)
|
||||||
:
|
:
|
||||||
fRepository(repository),
|
fRepository(repository),
|
||||||
@@ -35,7 +70,7 @@ RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
|
BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository,
|
||||||
const BRepositoryConfig& config)
|
const BRepositoryConfig& config)
|
||||||
:
|
:
|
||||||
fRepository(repository),
|
fRepository(repository),
|
||||||
@@ -48,7 +83,7 @@ RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
|
BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository,
|
||||||
const BRepositoryCache& cache, const BString& errorName)
|
const BRepositoryCache& cache, const BString& errorName)
|
||||||
:
|
:
|
||||||
fRepository(repository),
|
fRepository(repository),
|
||||||
@@ -62,16 +97,16 @@ RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder&
|
BRepositoryBuilder&
|
||||||
RepositoryBuilder::SetPackagePathMap(PackagePathMap* packagePaths)
|
BRepositoryBuilder::SetPackagePathMap(BPackagePathMap* packagePaths)
|
||||||
{
|
{
|
||||||
fPackagePaths = packagePaths;
|
fPackagePaths = packagePaths;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder&
|
BRepositoryBuilder&
|
||||||
RepositoryBuilder::AddPackage(const BPackageInfo& info,
|
BRepositoryBuilder::AddPackage(const BPackageInfo& info,
|
||||||
const char* packageErrorName, BSolverPackage** _package)
|
const char* packageErrorName, BSolverPackage** _package)
|
||||||
{
|
{
|
||||||
status_t error = fRepository.AddPackage(info, _package);
|
status_t error = fRepository.AddPackage(info, _package);
|
||||||
@@ -86,27 +121,28 @@ RepositoryBuilder::AddPackage(const BPackageInfo& info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder&
|
BRepositoryBuilder&
|
||||||
RepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
|
BRepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
|
||||||
{
|
{
|
||||||
// read a package info from the (HPKG or package info) file
|
// read a package info from the (HPKG or package info) file
|
||||||
BPackageInfo packageInfo;
|
BPackageInfo packageInfo;
|
||||||
|
|
||||||
size_t pathLength = strlen(path);
|
size_t pathLength = strlen(path);
|
||||||
status_t error;
|
status_t error;
|
||||||
|
PackageInfoErrorListener errorListener(path);
|
||||||
if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
|
if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
|
||||||
// a package file
|
// a package file
|
||||||
error = packageInfo.ReadFromPackageFile(path);
|
error = packageInfo.ReadFromPackageFile(path);
|
||||||
} else {
|
} else {
|
||||||
// a package info file (supposedly)
|
// a package info file (supposedly)
|
||||||
PackageInfoErrorListener errorListener(
|
|
||||||
"Error: failed to read package info");
|
|
||||||
error = packageInfo.ReadFromConfigFile(BEntry(path, true),
|
error = packageInfo.ReadFromConfigFile(BEntry(path, true),
|
||||||
&errorListener);
|
&errorListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error != B_OK)
|
if (error != B_OK) {
|
||||||
DIE(error, "failed to read package info from \"%s\"", path);
|
DIE_DETAILS(errorListener.Errors(), error,
|
||||||
|
"failed to read package info from \"%s\"", path);
|
||||||
|
}
|
||||||
|
|
||||||
// add the package
|
// add the package
|
||||||
BSolverPackage* package;
|
BSolverPackage* package;
|
||||||
@@ -123,8 +159,8 @@ RepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder&
|
BRepositoryBuilder&
|
||||||
RepositoryBuilder::AddPackages(BPackageInstallationLocation location,
|
BRepositoryBuilder::AddPackages(BPackageInstallationLocation location,
|
||||||
const char* locationErrorName)
|
const char* locationErrorName)
|
||||||
{
|
{
|
||||||
status_t error = fRepository.AddPackages(location);
|
status_t error = fRepository.AddPackages(location);
|
||||||
@@ -136,8 +172,8 @@ RepositoryBuilder::AddPackages(BPackageInstallationLocation location,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder&
|
BRepositoryBuilder&
|
||||||
RepositoryBuilder::AddPackagesDirectory(const char* path)
|
BRepositoryBuilder::AddPackagesDirectory(const char* path)
|
||||||
{
|
{
|
||||||
// open directory
|
// open directory
|
||||||
DIR* dir = opendir(path);
|
DIR* dir = opendir(path);
|
||||||
@@ -172,8 +208,8 @@ RepositoryBuilder::AddPackagesDirectory(const char* path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RepositoryBuilder&
|
BRepositoryBuilder&
|
||||||
RepositoryBuilder::AddToSolver(BSolver* solver, bool isInstalled)
|
BRepositoryBuilder::AddToSolver(BSolver* solver, bool isInstalled)
|
||||||
{
|
{
|
||||||
fRepository.SetInstalled(isInstalled);
|
fRepository.SetInstalled(isInstalled);
|
||||||
|
|
||||||
@@ -184,3 +220,10 @@ RepositoryBuilder::AddToSolver(BSolver* solver, bool isInstalled)
|
|||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
} // namespace BManager
|
||||||
|
|
||||||
|
} // namespace BPackageKit
|
||||||
@@ -8,10 +8,6 @@ USES_BE_API on <build>get_package_dependencies = true ;
|
|||||||
|
|
||||||
BuildPlatformMain <build>get_package_dependencies :
|
BuildPlatformMain <build>get_package_dependencies :
|
||||||
get_package_dependencies.cpp
|
get_package_dependencies.cpp
|
||||||
|
|
||||||
# pkgman sources
|
|
||||||
PackageInfoErrorListener.cpp
|
|
||||||
RepositoryBuilder.cpp
|
|
||||||
:
|
:
|
||||||
libpackage-add-on-libsolv_build.so
|
libpackage-add-on-libsolv_build.so
|
||||||
libsolvext_build.so libsolv_build.so
|
libsolvext_build.so libsolv_build.so
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <package/RepositoryCache.h>
|
#include <package/RepositoryCache.h>
|
||||||
|
#include <package/manager/RepositoryBuilder.h>
|
||||||
#include <package/solver/Solver.h>
|
#include <package/solver/Solver.h>
|
||||||
#include <package/solver/SolverPackageSpecifier.h>
|
#include <package/solver/SolverPackageSpecifier.h>
|
||||||
#include <package/solver/SolverPackageSpecifierList.h>
|
#include <package/solver/SolverPackageSpecifierList.h>
|
||||||
@@ -22,13 +23,22 @@
|
|||||||
#include <package/solver/SolverRepository.h>
|
#include <package/solver/SolverRepository.h>
|
||||||
#include <package/solver/SolverResult.h>
|
#include <package/solver/SolverResult.h>
|
||||||
|
|
||||||
#include "pkgman.h"
|
|
||||||
#include "RepositoryBuilder.h"
|
using namespace BPackageKit;
|
||||||
|
using namespace BPackageKit::BManager::BPrivate;
|
||||||
|
|
||||||
|
|
||||||
static const char* sProgramName = "get_package_dependencies";
|
static const char* sProgramName = "get_package_dependencies";
|
||||||
|
|
||||||
|
|
||||||
|
#define DIE(result, msg...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "*** " msg); \
|
||||||
|
fprintf(stderr, " : %s\n", strerror(result)); \
|
||||||
|
exit(5); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
print_usage_and_exit(bool error)
|
print_usage_and_exit(bool error)
|
||||||
{
|
{
|
||||||
@@ -74,7 +84,7 @@ main(int argc, const char* const* argv)
|
|||||||
// add the "installed" repository with the given packages
|
// add the "installed" repository with the given packages
|
||||||
BSolverRepository installedRepository;
|
BSolverRepository installedRepository;
|
||||||
{
|
{
|
||||||
RepositoryBuilder installedRepositoryBuilder(installedRepository,
|
BRepositoryBuilder installedRepositoryBuilder(installedRepository,
|
||||||
"installed");
|
"installed");
|
||||||
for (int i = 0; i < packageCount; i++)
|
for (int i = 0; i < packageCount; i++)
|
||||||
installedRepositoryBuilder.AddPackage(packages[i]);
|
installedRepositoryBuilder.AddPackage(packages[i]);
|
||||||
@@ -89,7 +99,7 @@ main(int argc, const char* const* argv)
|
|||||||
error = cache.SetTo(repositories[i]);
|
error = cache.SetTo(repositories[i]);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
DIE(error, "failed to read repository file '%s'", repositories[i]);
|
DIE(error, "failed to read repository file '%s'", repositories[i]);
|
||||||
RepositoryBuilder(*repository, cache)
|
BRepositoryBuilder(*repository, cache)
|
||||||
.AddToSolver(solver, false);
|
.AddToSolver(solver, false);
|
||||||
repositoryInfos[repository] = cache.Info();
|
repositoryInfos[repository] = cache.Info();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user