btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / servers / package / PackageManager.cpp
blobeaaece08e0bfca6029007467609cb05bd4220837
1 /*
2 * Copyright 2013-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "PackageManager.h"
9 #include <Catalog.h>
10 #include <Notification.h>
11 #include <package/DownloadFileRequest.h>
12 #include <package/RefreshRepositoryRequest.h>
13 #include <package/solver/SolverPackage.h>
14 #include <package/solver/SolverPackageSpecifierList.h>
15 #include <package/solver/SolverProblem.h>
16 #include <package/solver/SolverProblemSolution.h>
18 #include <AutoDeleter.h>
19 #include <package/manager/Exceptions.h>
20 #include <package/manager/RepositoryBuilder.h>
21 #include <Server.h>
23 #include "ProblemWindow.h"
24 #include "ResultWindow.h"
25 #include "Root.h"
26 #include "Volume.h"
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "PackageManager"
31 using BPackageKit::BManager::BPrivate::BAbortedByUserException;
32 using BPackageKit::BManager::BPrivate::BFatalErrorException;
33 using BPackageKit::BManager::BPrivate::BRepositoryBuilder;
36 PackageManager::PackageManager(Root* root, Volume* volume)
38 BPackageManager(volume->Location(), this, this),
39 BPackageManager::UserInteractionHandler(),
40 fRoot(root),
41 fVolume(volume),
42 fSolverPackages(),
43 fPackagesAddedByUser(),
44 fPackagesRemovedByUser(),
45 fProblemWindow(NULL)
50 PackageManager::~PackageManager()
52 if (fProblemWindow != NULL)
53 fProblemWindow->PostMessage(B_QUIT_REQUESTED);
57 void
58 PackageManager::HandleUserChanges()
60 const PackageSet& packagesToActivate = fVolume->PackagesToBeActivated();
61 const PackageSet& packagesToDeactivate = fVolume->PackagesToBeDeactivated();
63 if (packagesToActivate.empty() && packagesToDeactivate.empty())
64 return;
66 if (packagesToActivate.empty()) {
67 // only packages removed -- use uninstall mode
68 Init(B_ADD_INSTALLED_REPOSITORIES);
70 BSolverPackageSpecifierList packagesToUninstall;
71 for (PackageSet::const_iterator it = packagesToDeactivate.begin();
72 it != packagesToDeactivate.end(); ++it) {
73 BSolverPackage* solverPackage = _SolverPackageFor(*it);
74 if (solverPackage == NULL)
75 continue;
77 if (!packagesToUninstall.AppendSpecifier(solverPackage))
78 throw std::bad_alloc();
79 fPackagesRemovedByUser.insert(solverPackage);
82 if (fPackagesRemovedByUser.empty())
83 return;
85 Uninstall(packagesToUninstall);
86 } else {
87 // packages added and (possibly) remove -- manually add/remove those
88 // from the repository and use verify mode
89 Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
90 | B_REFRESH_REPOSITORIES);
92 // disable and remove uninstalled packages
93 InstalledRepository& repository = InstallationRepository();
94 for (PackageSet::const_iterator it = packagesToDeactivate.begin();
95 it != packagesToDeactivate.end(); ++it) {
96 BSolverPackage* solverPackage = _SolverPackageFor(*it);
97 if (solverPackage == NULL)
98 continue;
100 repository.DisablePackage(solverPackage);
101 if (!repository.PackagesToDeactivate().AddItem(solverPackage))
102 throw std::bad_alloc();
103 fPackagesRemovedByUser.insert(solverPackage);
106 // add new packages
107 BRepositoryBuilder repositoryBuilder(repository);
108 for (PackageSet::const_iterator it = packagesToActivate.begin();
109 it != packagesToActivate.end(); ++it) {
110 Package* package = *it;
111 BSolverPackage* solverPackage;
112 repositoryBuilder.AddPackage(package->Info(), NULL, &solverPackage);
113 fSolverPackages[package] = solverPackage;
114 if (!repository.PackagesToActivate().AddItem(solverPackage))
115 throw std::bad_alloc();
116 fPackagesAddedByUser.insert(solverPackage);
119 if (fPackagesRemovedByUser.empty() && fPackagesAddedByUser.empty())
120 return;
122 // TODO: When packages are moved out of the packages directory, we can't create
123 // a complete "old-state" directory.
125 VerifyInstallation();
130 void
131 PackageManager::InitInstalledRepository(InstalledRepository& repository)
133 const char* name = repository.InitialName();
134 BRepositoryBuilder repositoryBuilder(repository, name);
136 if (Volume* volume = fRoot->GetVolume(repository.Location())) {
137 for (PackageFileNameHashTable::Iterator it
138 = volume->PackagesByFileNameIterator(); it.HasNext();) {
139 Package* package = it.Next();
140 if (package->IsActive()) {
141 BSolverPackage* solverPackage;
142 repositoryBuilder.AddPackage(package->Info(), NULL,
143 &solverPackage);
144 fSolverPackages[package] = solverPackage;
151 void
152 PackageManager::ResultComputed(InstalledRepository& repository)
154 // Normalize the result, i.e. remove the packages added by the user which
155 // have been removed again in the problem resolution process, and vice
156 // versa.
157 if (repository.Location() != fVolume->Location())
158 return;
160 PackageList& packagesToActivate = repository.PackagesToActivate();
161 PackageList& packagesToDeactivate = repository.PackagesToDeactivate();
163 for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
164 i++) {
165 if (fPackagesAddedByUser.erase(package) == 0)
166 continue;
168 for (SolverPackageMap::iterator it = fSolverPackages.begin();
169 it != fSolverPackages.end(); ++it) {
170 if (it->second == package) {
171 fSolverPackages.erase(it);
172 break;
176 repository.EnablePackage(package);
177 packagesToDeactivate.RemoveItemAt(i--);
178 packagesToActivate.RemoveItem(package);
179 repository.DeletePackage(package);
182 for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
183 i++) {
184 if (fPackagesRemovedByUser.erase(package) == 0)
185 continue;
187 repository.EnablePackage(package);
188 packagesToActivate.RemoveItemAt(i--);
189 packagesToDeactivate.RemoveItem(package);
191 // Note: We keep the package activated, but nonetheless it is gone,
192 // since the user has removed it from the packages directory. So unless
193 // the user moves it back, we won't find it upon next reboot.
194 // TODO: We probable even run into trouble when the user moves in a
195 // replacement afterward.
200 status_t
201 PackageManager::PrepareTransaction(Transaction& transaction)
203 Volume* volume = fRoot->GetVolume(transaction.Repository().Location());
204 if (volume == NULL)
205 return B_BAD_VALUE;
207 return volume->CreateTransaction(transaction.Repository().Location(),
208 transaction.ActivationTransaction(),
209 transaction.TransactionDirectory());
213 status_t
214 PackageManager::CommitTransaction(Transaction& transaction,
215 BCommitTransactionResult& _result)
217 Volume* volume = fRoot->GetVolume(transaction.Repository().Location());
218 if (volume == NULL)
219 return B_BAD_VALUE;
221 // Get the packages that have already been added to/removed from the
222 // packages directory and thus need to be handled specially by
223 // Volume::CommitTransaction().
224 PackageSet packagesAlreadyAdded;
225 PackageSet packagesAlreadyRemoved;
226 if (volume == fVolume) {
227 const PackageSet& packagesToActivate = volume->PackagesToBeActivated();
228 for (PackageSet::const_iterator it = packagesToActivate.begin();
229 it != packagesToActivate.end(); ++it) {
230 Package* package = *it;
231 if (fPackagesAddedByUser.find(_SolverPackageFor(package))
232 != fPackagesAddedByUser.end()) {
233 packagesAlreadyAdded.insert(package);
237 const PackageSet& packagesToDeactivate
238 = volume->PackagesToBeDeactivated();
239 for (PackageSet::const_iterator it = packagesToDeactivate.begin();
240 it != packagesToDeactivate.end(); ++it) {
241 Package* package = *it;
242 if (fPackagesRemovedByUser.find(_SolverPackageFor(package))
243 != fPackagesRemovedByUser.end()) {
244 packagesAlreadyRemoved.insert(package);
249 volume->CommitTransaction(transaction.ActivationTransaction(),
250 packagesAlreadyAdded, packagesAlreadyRemoved, _result);
251 return B_OK;
255 void
256 PackageManager::HandleProblems()
258 _InitGui();
260 if (fProblemWindow == NULL)
261 fProblemWindow = new ProblemWindow;
263 if (!fProblemWindow->Go(fSolver, fPackagesAddedByUser,
264 fPackagesRemovedByUser)) {
265 throw BAbortedByUserException();
270 void
271 PackageManager::ConfirmChanges(bool fromMostSpecific)
273 // Check whether there are any changes other than those made by the user.
274 _InitGui();
275 ResultWindow* window = new ResultWindow;
276 ObjectDeleter<ResultWindow> windowDeleter(window);
278 bool hasOtherChanges = false;
279 int32 count = fInstalledRepositories.CountItems();
280 if (fromMostSpecific) {
281 for (int32 i = count - 1; i >= 0; i--)
282 hasOtherChanges
283 |= _AddResults(*fInstalledRepositories.ItemAt(i), window);
284 } else {
285 for (int32 i = 0; i < count; i++)
286 hasOtherChanges
287 |= _AddResults(*fInstalledRepositories.ItemAt(i), window);
290 if (!hasOtherChanges)
291 return;
293 // show the window
294 if (windowDeleter.Detach()->Go() == 0)
295 throw BAbortedByUserException();
299 void
300 PackageManager::Warn(status_t error, const char* format, ...)
302 va_list args;
303 va_start(args, format);
304 BString message;
305 message.SetToFormatVarArgs(format, args);
306 va_end(args);
308 if (error != B_OK)
309 message << BString().SetToFormat(": %s", strerror(error));
311 BNotification notification(B_ERROR_NOTIFICATION);
312 notification.SetGroup(B_TRANSLATE("Package daemon"));
313 notification.SetTitle(B_TRANSLATE("Warning"));
314 notification.SetContent(message);
315 notification.Send();
319 void
320 PackageManager::ProgressPackageDownloadStarted(const char* packageName)
325 void
326 PackageManager::ProgressPackageDownloadActive(const char* packageName,
327 float completionPercentage, off_t bytes, off_t totalBytes)
332 void
333 PackageManager::ProgressPackageDownloadComplete(const char* packageName)
338 void
339 PackageManager::ProgressPackageChecksumStarted(const char* title)
344 void
345 PackageManager::ProgressPackageChecksumComplete(const char* title)
350 void
351 PackageManager::ProgressStartApplyingChanges(InstalledRepository& repository)
356 void
357 PackageManager::ProgressTransactionCommitted(InstalledRepository& repository,
358 const BCommitTransactionResult& result)
363 void
364 PackageManager::ProgressApplyingChangesDone(InstalledRepository& repository)
369 void
370 PackageManager::JobFailed(BSupportKit::BJob* job)
372 // TODO:...
376 void
377 PackageManager::JobAborted(BSupportKit::BJob* job)
379 // TODO:...
383 bool
384 PackageManager::_AddResults(InstalledRepository& repository,
385 ResultWindow* window)
387 if (!repository.HasChanges())
388 return false;
390 return window->AddLocationChanges(repository.Name(),
391 repository.PackagesToActivate(), fPackagesAddedByUser,
392 repository.PackagesToDeactivate(), fPackagesRemovedByUser);
396 BSolverPackage*
397 PackageManager::_SolverPackageFor(Package* package) const
399 SolverPackageMap::const_iterator it = fSolverPackages.find(package);
400 return it != fSolverPackages.end() ? it->second : NULL;
404 void
405 PackageManager::_InitGui()
407 BServer* server = dynamic_cast<BServer*>(be_app);
408 if (server == NULL || server->InitGUIContext() != B_OK)
409 throw BFatalErrorException("failed to initialize the GUI");