btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / package / solver / LibsolvSolver.cpp
blobc8bd1673956e1815e944c810710b12835cf6204e
1 /*
2 * Copyright 2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold <ingo_weinhold@gmx.de>
7 */
10 #include "LibsolvSolver.h"
12 #include <errno.h>
13 #include <sys/utsname.h>
15 #include <new>
17 #include <solv/policy.h>
18 #include <solv/poolarch.h>
19 #include <solv/repo.h>
20 #include <solv/repo_haiku.h>
21 #include <solv/selection.h>
22 #include <solv/solverdebug.h>
24 #include <package/PackageResolvableExpression.h>
25 #include <package/RepositoryCache.h>
26 #include <package/solver/SolverPackage.h>
27 #include <package/solver/SolverPackageSpecifier.h>
28 #include <package/solver/SolverPackageSpecifierList.h>
29 #include <package/solver/SolverProblem.h>
30 #include <package/solver/SolverRepository.h>
31 #include <package/solver/SolverResult.h>
33 #include <AutoDeleter.h>
34 #include <ObjectList.h>
37 // TODO: libsolv doesn't have any helpful out-of-memory handling. It just just
38 // abort()s. Obviously that isn't good behavior for a library.
41 BSolver*
42 BPackageKit::create_solver()
44 return new(std::nothrow) LibsolvSolver;
48 struct LibsolvSolver::SolvQueue : Queue {
49 SolvQueue()
51 queue_init(this);
54 ~SolvQueue()
56 queue_free(this);
61 struct LibsolvSolver::SolvDataIterator : Dataiterator {
62 SolvDataIterator(Pool* pool, Repo* repo, Id solvableId, Id keyname,
63 const char* match, int flags)
65 dataiterator_init(this, pool, repo, solvableId, keyname, match, flags);
68 ~SolvDataIterator()
70 dataiterator_free(this);
75 struct LibsolvSolver::RepositoryInfo {
76 RepositoryInfo(BSolverRepository* repository)
78 fRepository(repository),
79 fSolvRepo(NULL),
80 fChangeCount(repository->ChangeCount())
84 BSolverRepository* Repository() const
86 return fRepository;
89 Repo* SolvRepo()
91 return fSolvRepo;
94 void SetSolvRepo(Repo* repo)
96 fSolvRepo = repo;
99 bool HasChanged() const
101 return fChangeCount != fRepository->ChangeCount() || fSolvRepo == NULL;
104 void SetUnchanged()
106 fChangeCount = fRepository->ChangeCount();
109 private:
110 BSolverRepository* fRepository;
111 Repo* fSolvRepo;
112 uint64 fChangeCount;
116 struct LibsolvSolver::Problem : public BSolverProblem {
117 Problem(::Id id, BType type, BSolverPackage* sourcePackage,
118 BSolverPackage* targetPackage,
119 const BPackageResolvableExpression& dependency)
121 BSolverProblem(type, sourcePackage, targetPackage, dependency),
122 fId(id),
123 fSelectedSolution(NULL)
127 ::Id Id() const
129 return fId;
132 const Solution* SelectedSolution() const
134 return fSelectedSolution;
137 void SetSelectedSolution(const Solution* solution)
139 fSelectedSolution = solution;
142 private:
143 ::Id fId;
144 const Solution* fSelectedSolution;
148 struct LibsolvSolver::Solution : public BSolverProblemSolution {
149 Solution(::Id id, LibsolvSolver::Problem* problem)
151 BSolverProblemSolution(),
152 fId(id),
153 fProblem(problem)
157 ::Id Id() const
159 return fId;
162 LibsolvSolver::Problem* Problem() const
164 return fProblem;
167 private:
168 ::Id fId;
169 LibsolvSolver::Problem* fProblem;
173 // #pragma mark - LibsolvSolver
176 LibsolvSolver::LibsolvSolver()
178 fPool(NULL),
179 fSolver(NULL),
180 fJobs(NULL),
181 fRepositoryInfos(10, true),
182 fInstalledRepository(NULL),
183 fSolvablePackages(),
184 fPackageSolvables(),
185 fProblems(10, true),
186 fDebugLevel(0)
191 LibsolvSolver::~LibsolvSolver()
193 _Cleanup();
197 status_t
198 LibsolvSolver::Init()
200 _Cleanup();
202 // We do all initialization lazily.
203 return B_OK;
207 void
208 LibsolvSolver::SetDebugLevel(int32 level)
210 fDebugLevel = level;
212 if (fPool != NULL)
213 pool_setdebuglevel(fPool, fDebugLevel);
217 status_t
218 LibsolvSolver::AddRepository(BSolverRepository* repository)
220 if (repository == NULL || repository->InitCheck() != B_OK)
221 return B_BAD_VALUE;
223 // If the repository represents installed packages, check, if we already
224 // have such a repository.
225 if (repository->IsInstalled() && _InstalledRepository() != NULL)
226 return B_BAD_VALUE;
228 // add the repository info
229 RepositoryInfo* info = new(std::nothrow) RepositoryInfo(repository);
230 if (info == NULL)
231 return B_NO_MEMORY;
233 if (!fRepositoryInfos.AddItem(info)) {
234 delete info;
235 return B_NO_MEMORY;
238 return B_OK;
242 status_t
243 LibsolvSolver::FindPackages(const char* searchString, uint32 flags,
244 BObjectList<BSolverPackage>& _packages)
246 // add repositories to pool
247 status_t error = _AddRepositories();
248 if (error != B_OK)
249 return error;
251 // create data iterator
252 int iteratorFlags = SEARCH_SUBSTRING;
253 if ((flags & B_FIND_CASE_INSENSITIVE) != 0)
254 iteratorFlags |= SEARCH_NOCASE;
256 SolvDataIterator iterator(fPool, 0, 0, 0, searchString, iteratorFlags);
257 SolvQueue selection;
259 // search package names
260 if ((flags & B_FIND_IN_NAME) != 0) {
261 dataiterator_set_keyname(&iterator, SOLVABLE_NAME);
262 dataiterator_set_search(&iterator, 0, 0);
264 while (dataiterator_step(&iterator))
265 queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
268 // search package summaries
269 if ((flags & B_FIND_IN_SUMMARY) != 0) {
270 dataiterator_set_keyname(&iterator, SOLVABLE_SUMMARY);
271 dataiterator_set_search(&iterator, 0, 0);
273 while (dataiterator_step(&iterator))
274 queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
277 // search package description
278 if ((flags & B_FIND_IN_DESCRIPTION) != 0) {
279 dataiterator_set_keyname(&iterator, SOLVABLE_DESCRIPTION);
280 dataiterator_set_search(&iterator, 0, 0);
282 while (dataiterator_step(&iterator))
283 queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
286 // search package provides
287 if ((flags & B_FIND_IN_PROVIDES) != 0) {
288 dataiterator_set_keyname(&iterator, SOLVABLE_PROVIDES);
289 dataiterator_set_search(&iterator, 0, 0);
291 while (dataiterator_step(&iterator))
292 queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
295 // search package requires
296 if ((flags & B_FIND_IN_REQUIRES) != 0) {
297 dataiterator_set_keyname(&iterator, SOLVABLE_REQUIRES);
298 dataiterator_set_search(&iterator, 0, 0);
300 while (dataiterator_step(&iterator))
301 queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
304 return _GetFoundPackages(selection, flags, _packages);
308 status_t
309 LibsolvSolver::FindPackages(const BSolverPackageSpecifierList& packages,
310 uint32 flags, BObjectList<BSolverPackage>& _packages,
311 const BSolverPackageSpecifier** _unmatched)
313 if (_unmatched != NULL)
314 *_unmatched = NULL;
316 if ((flags & B_FIND_INSTALLED_ONLY) != 0 && _InstalledRepository() == NULL)
317 return B_BAD_VALUE;
319 // add repositories to pool
320 status_t error = _AddRepositories();
321 if (error != B_OK)
322 return error;
324 error = _InitJobQueue();
325 if (error != B_OK)
326 return error;
328 // add the package specifies to the job queue
329 error = _AddSpecifiedPackages(packages, _unmatched,
330 (flags & B_FIND_INSTALLED_ONLY) != 0 ? SELECTION_INSTALLED_ONLY : 0);
331 if (error != B_OK)
332 return error;
334 return _GetFoundPackages(*fJobs, flags, _packages);
338 status_t
339 LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
340 const BSolverPackageSpecifier** _unmatched)
342 if (_unmatched != NULL)
343 *_unmatched = NULL;
345 if (packages.IsEmpty())
346 return B_BAD_VALUE;
348 // add repositories to pool
349 status_t error = _AddRepositories();
350 if (error != B_OK)
351 return error;
353 // add the packages to install to the job queue
354 error = _InitJobQueue();
355 if (error != B_OK)
356 return error;
358 error = _AddSpecifiedPackages(packages, _unmatched, 0);
359 if (error != B_OK)
360 return error;
362 // set jobs' solver mode and solve
363 _SetJobsSolverMode(SOLVER_INSTALL);
365 _InitSolver();
366 return _Solve();
370 status_t
371 LibsolvSolver::Uninstall(const BSolverPackageSpecifierList& packages,
372 const BSolverPackageSpecifier** _unmatched)
374 if (_unmatched != NULL)
375 *_unmatched = NULL;
377 if (_InstalledRepository() == NULL || packages.IsEmpty())
378 return B_BAD_VALUE;
380 // add repositories to pool
381 status_t error = _AddRepositories();
382 if (error != B_OK)
383 return error;
385 // add the packages to uninstall to the job queue
386 error = _InitJobQueue();
387 if (error != B_OK)
388 return error;
390 error = _AddSpecifiedPackages(packages, _unmatched,
391 SELECTION_INSTALLED_ONLY);
392 if (error != B_OK)
393 return error;
395 // set jobs' solver mode and solve
396 _SetJobsSolverMode(SOLVER_ERASE);
398 _InitSolver();
399 solver_set_flag(fSolver, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
400 return _Solve();
404 status_t
405 LibsolvSolver::Update(const BSolverPackageSpecifierList& packages,
406 bool installNotYetInstalled, const BSolverPackageSpecifier** _unmatched)
408 if (_unmatched != NULL)
409 *_unmatched = NULL;
411 // add repositories to pool
412 status_t error = _AddRepositories();
413 if (error != B_OK)
414 return error;
416 // add the packages to update to the job queue -- if none are specified,
417 // update all
418 error = _InitJobQueue();
419 if (error != B_OK)
420 return error;
422 if (packages.IsEmpty()) {
423 queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
424 } else {
425 error = _AddSpecifiedPackages(packages, _unmatched, 0);
426 if (error != B_OK)
427 return error;
430 // set jobs' solver mode and solve
431 _SetJobsSolverMode(SOLVER_UPDATE);
433 if (installNotYetInstalled) {
434 for (int i = 0; i < fJobs->count; i += 2) {
435 // change solver mode to SOLVER_INSTALL for empty update jobs
436 if (pool_isemptyupdatejob(fPool, fJobs->elements[i],
437 fJobs->elements[i + 1])) {
438 fJobs->elements[i] &= ~SOLVER_JOBMASK;
439 fJobs->elements[i] |= SOLVER_INSTALL;
444 _InitSolver();
445 return _Solve();
449 status_t
450 LibsolvSolver::FullSync()
452 // add repositories to pool
453 status_t error = _AddRepositories();
454 if (error != B_OK)
455 return error;
457 // Init the job queue and specify that all packages shall be updated.
458 error = _InitJobQueue();
459 if (error != B_OK)
460 return error;
462 queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
464 // set jobs' solver mode and solve
465 _SetJobsSolverMode(SOLVER_DISTUPGRADE);
467 _InitSolver();
468 return _Solve();
472 status_t
473 LibsolvSolver::VerifyInstallation(uint32 flags)
475 if (_InstalledRepository() == NULL)
476 return B_BAD_VALUE;
478 // add repositories to pool
479 status_t error = _AddRepositories();
480 if (error != B_OK)
481 return error;
483 // add the verify job to the job queue
484 error = _InitJobQueue();
485 if (error != B_OK)
486 return error;
488 queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
490 // set jobs' solver mode and solve
491 _SetJobsSolverMode(SOLVER_VERIFY);
493 _InitSolver();
494 if ((flags & B_VERIFY_ALLOW_UNINSTALL) != 0)
495 solver_set_flag(fSolver, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
496 return _Solve();
500 status_t
501 LibsolvSolver::SelectProblemSolution(BSolverProblem* _problem,
502 const BSolverProblemSolution* _solution)
504 if (_problem == NULL)
505 return B_BAD_VALUE;
507 Problem* problem = static_cast<Problem*>(_problem);
508 if (_solution == NULL) {
509 problem->SetSelectedSolution(NULL);
510 return B_OK;
513 const Solution* solution = static_cast<const Solution*>(_solution);
514 if (solution->Problem() != problem)
515 return B_BAD_VALUE;
517 problem->SetSelectedSolution(solution);
518 return B_OK;
522 status_t
523 LibsolvSolver::SolveAgain()
525 if (fSolver == NULL || fJobs == NULL)
526 return B_BAD_VALUE;
528 // iterate through all problems and propagate the selected solutions
529 int32 problemCount = fProblems.CountItems();
530 for (int32 i = 0; i < problemCount; i++) {
531 Problem* problem = fProblems.ItemAt(i);
532 if (const Solution* solution = problem->SelectedSolution())
533 solver_take_solution(fSolver, problem->Id(), solution->Id(), fJobs);
536 return _Solve();
540 int32
541 LibsolvSolver::CountProblems() const
543 return fProblems.CountItems();
547 BSolverProblem*
548 LibsolvSolver::ProblemAt(int32 index) const
550 return fProblems.ItemAt(index);
554 status_t
555 LibsolvSolver::GetResult(BSolverResult& _result)
557 if (fSolver == NULL || HasProblems())
558 return B_BAD_VALUE;
560 _result.MakeEmpty();
562 Transaction* transaction = solver_create_transaction(fSolver);
563 CObjectDeleter<Transaction> transactionDeleter(transaction,
564 &transaction_free);
566 if (transaction->steps.count == 0)
567 return B_OK;
569 transaction_order(transaction, 0);
571 for (int i = 0; i < transaction->steps.count; i++) {
572 Id solvableId = transaction->steps.elements[i];
573 if (fPool->installed
574 && fPool->solvables[solvableId].repo == fPool->installed) {
575 BSolverPackage* package = _GetPackage(solvableId);
576 if (package == NULL)
577 return B_ERROR;
579 if (!_result.AppendElement(
580 BSolverResultElement(
581 BSolverResultElement::B_TYPE_UNINSTALL, package))) {
582 return B_NO_MEMORY;
584 } else {
585 BSolverPackage* package = _GetPackage(solvableId);
586 if (package == NULL)
587 return B_ERROR;
589 if (!_result.AppendElement(
590 BSolverResultElement(
591 BSolverResultElement::B_TYPE_INSTALL, package))) {
592 return B_NO_MEMORY;
597 return B_OK;
601 status_t
602 LibsolvSolver::_InitPool()
604 _CleanupPool();
606 fPool = pool_create();
608 pool_setdebuglevel(fPool, fDebugLevel);
610 // Set the system architecture. We use what uname() returns unless we're on
611 // x86 gcc2.
613 const char* arch;
614 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
615 #ifdef __HAIKU_ARCH_X86
616 #if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2
617 arch = "x86_gcc2";
618 #else
619 arch = "x86";
620 #endif
621 #else
622 struct utsname info;
623 if (uname(&info) != 0)
624 return errno;
625 arch = info.machine;
626 #endif
627 #else
628 arch = HAIKU_PACKAGING_ARCH;
629 #endif
631 pool_setarchpolicy(fPool, arch);
634 return B_OK;
638 status_t
639 LibsolvSolver::_InitJobQueue()
641 _CleanupJobQueue();
643 fJobs = new(std::nothrow) SolvQueue;
644 return fJobs != NULL ? B_OK : B_NO_MEMORY;;
648 void
649 LibsolvSolver::_InitSolver()
651 _CleanupSolver();
653 fSolver = solver_create(fPool);
654 solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
655 solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
659 void
660 LibsolvSolver::_Cleanup()
662 _CleanupPool();
664 fInstalledRepository = NULL;
665 fRepositoryInfos.MakeEmpty();
670 void
671 LibsolvSolver::_CleanupPool()
673 // clean up jobs and solver data
674 _CleanupJobQueue();
676 // clean up our data structures that depend on/refer to libsolv pool data
677 fSolvablePackages.clear();
678 fPackageSolvables.clear();
680 int32 repositoryCount = fRepositoryInfos.CountItems();
681 for (int32 i = 0; i < repositoryCount; i++)
682 fRepositoryInfos.ItemAt(i)->SetSolvRepo(NULL);
684 // delete the pool
685 if (fPool != NULL) {
686 pool_free(fPool);
687 fPool = NULL;
692 void
693 LibsolvSolver::_CleanupJobQueue()
695 _CleanupSolver();
697 delete fJobs;
698 fJobs = NULL;
702 void
703 LibsolvSolver::_CleanupSolver()
705 fProblems.MakeEmpty();
707 if (fSolver != NULL) {
708 solver_free(fSolver);
709 fSolver = NULL;
714 bool
715 LibsolvSolver::_HaveRepositoriesChanged() const
717 int32 repositoryCount = fRepositoryInfos.CountItems();
718 for (int32 i = 0; i < repositoryCount; i++) {
719 RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
720 if (repositoryInfo->HasChanged())
721 return true;
724 return false;
728 status_t
729 LibsolvSolver::_AddRepositories()
731 if (fPool != NULL && !_HaveRepositoriesChanged())
732 return B_OK;
734 // something has changed -- re-create the pool
735 status_t error = _InitPool();
736 if (error != B_OK)
737 return error;
739 fInstalledRepository = NULL;
741 int32 repositoryCount = fRepositoryInfos.CountItems();
742 for (int32 i = 0; i < repositoryCount; i++) {
743 RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
744 BSolverRepository* repository = repositoryInfo->Repository();
745 Repo* repo = repo_create(fPool, repository->Name());
746 repositoryInfo->SetSolvRepo(repo);
748 repo->priority = -1 - repository->Priority();
749 repo->appdata = (void*)repositoryInfo;
751 int32 packageCount = repository->CountPackages();
752 for (int32 k = 0; k < packageCount; k++) {
753 BSolverPackage* package = repository->PackageAt(k);
754 Id solvableId = repo_add_haiku_package_info(repo, package->Info(),
755 REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
757 try {
758 fSolvablePackages[solvableId] = package;
759 fPackageSolvables[package] = solvableId;
760 } catch (std::bad_alloc&) {
761 return B_NO_MEMORY;
765 repo_internalize(repo);
767 if (repository->IsInstalled()) {
768 fInstalledRepository = repositoryInfo;
769 pool_set_installed(fPool, repo);
772 repositoryInfo->SetUnchanged();
775 // create "provides" lookup
776 pool_createwhatprovides(fPool);
778 return B_OK;
782 LibsolvSolver::RepositoryInfo*
783 LibsolvSolver::_InstalledRepository() const
785 int32 repositoryCount = fRepositoryInfos.CountItems();
786 for (int32 i = 0; i < repositoryCount; i++) {
787 RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
788 if (repositoryInfo->Repository()->IsInstalled())
789 return repositoryInfo;
792 return NULL;
796 LibsolvSolver::RepositoryInfo*
797 LibsolvSolver::_GetRepositoryInfo(BSolverRepository* repository) const
799 int32 repositoryCount = fRepositoryInfos.CountItems();
800 for (int32 i = 0; i < repositoryCount; i++) {
801 RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
802 if (repository == repositoryInfo->Repository())
803 return repositoryInfo;
806 return NULL;
810 BSolverPackage*
811 LibsolvSolver::_GetPackage(Id solvableId) const
813 SolvableMap::const_iterator it = fSolvablePackages.find(solvableId);
814 return it != fSolvablePackages.end() ? it->second : NULL;
819 LibsolvSolver::_GetSolvable(BSolverPackage* package) const
821 PackageMap::const_iterator it = fPackageSolvables.find(package);
822 return it != fPackageSolvables.end() ? it->second : 0;
826 status_t
827 LibsolvSolver::_AddSpecifiedPackages(
828 const BSolverPackageSpecifierList& packages,
829 const BSolverPackageSpecifier** _unmatched, int additionalFlags)
831 int32 packageCount = packages.CountSpecifiers();
832 for (int32 i = 0; i < packageCount; i++) {
833 const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
834 switch (specifier.Type()) {
835 case BSolverPackageSpecifier::B_UNSPECIFIED:
836 return B_BAD_VALUE;
838 case BSolverPackageSpecifier::B_PACKAGE:
840 BSolverPackage* package = specifier.Package();
841 Id solvableId;
842 if (package == NULL
843 || (solvableId = _GetSolvable(package)) == 0) {
844 return B_BAD_VALUE;
847 queue_push2(fJobs, SOLVER_SOLVABLE, solvableId);
848 break;
851 case BSolverPackageSpecifier::B_SELECT_STRING:
853 // find matching packages
854 SolvQueue matchingPackages;
856 int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
857 | SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL
858 | additionalFlags;
859 /*int matchFlags =*/ selection_make(fPool, &matchingPackages,
860 specifier.SelectString().String(), flags);
861 if (matchingPackages.count == 0) {
862 if (_unmatched != NULL)
863 *_unmatched = &specifier;
864 return B_NAME_NOT_FOUND;
866 // TODO: We might want to add support for restricting to certain repositories.
867 #if 0
868 // restrict to the matching repository
869 if (BSolverRepository* repository = specifier.Repository()) {
870 RepositoryInfo* repositoryInfo
871 = _GetRepositoryInfo(repository);
872 if (repositoryInfo == NULL)
873 return B_BAD_VALUE;
875 SolvQueue repoFilter;
876 queue_push2(&repoFilter,
877 SOLVER_SOLVABLE_REPO
878 /* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
879 repositoryInfo->SolvRepo()->repoid);
881 selection_filter(fPool, &matchingPackages, &repoFilter);
883 if (matchingPackages.count == 0)
884 return B_NAME_NOT_FOUND;
886 #endif
888 for (int j = 0; j < matchingPackages.count; j++)
889 queue_push(fJobs, matchingPackages.elements[j]);
894 return B_OK;
898 status_t
899 LibsolvSolver::_AddProblem(Id problemId)
901 enum {
902 NEED_SOURCE = 0x1,
903 NEED_TARGET = 0x2,
904 NEED_DEPENDENCY = 0x4
907 Id ruleId = solver_findproblemrule(fSolver, problemId);
908 Id sourceId;
909 Id targetId;
910 Id dependencyId;
911 BSolverProblem::BType problemType = BSolverProblem::B_UNSPECIFIED;
912 uint32 needed = 0;
914 switch (solver_ruleinfo(fSolver, ruleId, &sourceId, &targetId,
915 &dependencyId)) {
916 case SOLVER_RULE_DISTUPGRADE:
917 problemType = BSolverProblem::B_NOT_IN_DISTUPGRADE_REPOSITORY;
918 needed = NEED_SOURCE;
919 break;
920 case SOLVER_RULE_INFARCH:
921 problemType = BSolverProblem::B_INFERIOR_ARCHITECTURE;
922 needed = NEED_SOURCE;
923 break;
924 case SOLVER_RULE_UPDATE:
925 problemType = BSolverProblem::B_INSTALLED_PACKAGE_PROBLEM;
926 needed = NEED_SOURCE;
927 break;
928 case SOLVER_RULE_JOB:
929 problemType = BSolverProblem::B_CONFLICTING_REQUESTS;
930 break;
931 case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
932 problemType = BSolverProblem::B_REQUESTED_RESOLVABLE_NOT_PROVIDED;
933 needed = NEED_DEPENDENCY;
934 break;
935 case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
936 problemType
937 = BSolverProblem::B_REQUESTED_RESOLVABLE_PROVIDED_BY_SYSTEM;
938 needed = NEED_DEPENDENCY;
939 break;
940 case SOLVER_RULE_RPM:
941 problemType = BSolverProblem::B_DEPENDENCY_PROBLEM;
942 break;
943 case SOLVER_RULE_RPM_NOT_INSTALLABLE:
944 problemType = BSolverProblem::B_PACKAGE_NOT_INSTALLABLE;
945 needed = NEED_SOURCE;
946 break;
947 case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
948 problemType = BSolverProblem::B_DEPENDENCY_NOT_PROVIDED;
949 needed = NEED_SOURCE | NEED_DEPENDENCY;
950 break;
951 case SOLVER_RULE_RPM_SAME_NAME:
952 problemType = BSolverProblem::B_PACKAGE_NAME_CLASH;
953 needed = NEED_SOURCE | NEED_TARGET;
954 break;
955 case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
956 problemType = BSolverProblem::B_PACKAGE_CONFLICT;
957 needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
958 break;
959 case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
960 problemType = BSolverProblem::B_PACKAGE_OBSOLETES_RESOLVABLE;
961 needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
962 break;
963 case SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES:
964 problemType
965 = BSolverProblem::B_INSTALLED_PACKAGE_OBSOLETES_RESOLVABLE;
966 needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
967 break;
968 case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES:
969 problemType
970 = BSolverProblem::B_PACKAGE_IMPLICITLY_OBSOLETES_RESOLVABLE;
971 needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
972 break;
973 case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
974 problemType = BSolverProblem::B_DEPENDENCY_NOT_INSTALLABLE;
975 needed = NEED_SOURCE | NEED_DEPENDENCY;
976 break;
977 case SOLVER_RULE_RPM_SELF_CONFLICT:
978 problemType = BSolverProblem::B_SELF_CONFLICT;
979 needed = NEED_SOURCE | NEED_DEPENDENCY;
980 break;
981 case SOLVER_RULE_UNKNOWN:
982 case SOLVER_RULE_FEATURE:
983 case SOLVER_RULE_LEARNT:
984 case SOLVER_RULE_CHOICE:
985 case SOLVER_RULE_BEST:
986 problemType = BSolverProblem::B_UNSPECIFIED;
987 break;
990 BSolverPackage* sourcePackage = NULL;
991 if ((needed & NEED_SOURCE) != 0) {
992 sourcePackage = _GetPackage(sourceId);
993 if (sourcePackage == NULL)
994 return B_ERROR;
997 BSolverPackage* targetPackage = NULL;
998 if ((needed & NEED_TARGET) != 0) {
999 targetPackage = _GetPackage(targetId);
1000 if (targetPackage == NULL)
1001 return B_ERROR;
1004 BPackageResolvableExpression dependency;
1005 if ((needed & NEED_DEPENDENCY) != 0) {
1006 status_t error = _GetResolvableExpression(dependencyId, dependency);
1007 if (error != B_OK)
1008 return error;
1011 Problem* problem = new(std::nothrow) Problem(problemId, problemType,
1012 sourcePackage, targetPackage, dependency);
1013 if (problem == NULL || !fProblems.AddItem(problem)) {
1014 delete problem;
1015 return B_NO_MEMORY;
1018 int solutionCount = solver_solution_count(fSolver, problemId);
1019 for (Id solutionId = 1; solutionId <= solutionCount; solutionId++) {
1020 status_t error = _AddSolution(problem, solutionId);
1021 if (error != B_OK)
1022 return error;
1025 return B_OK;
1029 status_t
1030 LibsolvSolver::_AddSolution(Problem* problem, Id solutionId)
1032 Solution* solution = new(std::nothrow) Solution(solutionId, problem);
1033 if (solution == NULL || !problem->AppendSolution(solution)) {
1034 delete solution;
1035 return B_NO_MEMORY;
1038 Id elementId = 0;
1039 for (;;) {
1040 Id sourceId;
1041 Id targetId;
1042 elementId = solver_next_solutionelement(fSolver, problem->Id(),
1043 solutionId, elementId, &sourceId, &targetId);
1044 if (elementId == 0)
1045 break;
1047 status_t error = _AddSolutionElement(solution, sourceId, targetId);
1048 if (error != B_OK)
1049 return error;
1052 return B_OK;
1056 status_t
1057 LibsolvSolver::_AddSolutionElement(Solution* solution, Id sourceId, Id targetId)
1059 typedef BSolverProblemSolutionElement Element;
1061 if (sourceId == SOLVER_SOLUTION_JOB
1062 || sourceId == SOLVER_SOLUTION_POOLJOB) {
1063 // targetId is an index into the job queue
1064 if (sourceId == SOLVER_SOLUTION_JOB)
1065 targetId += fSolver->pooljobcnt;
1067 Id how = fSolver->job.elements[targetId - 1];
1068 Id what = fSolver->job.elements[targetId];
1069 Id select = how & SOLVER_SELECTMASK;
1071 switch (how & SOLVER_JOBMASK) {
1072 case SOLVER_INSTALL:
1073 if (select == SOLVER_SOLVABLE && fInstalledRepository != NULL
1074 && fPool->solvables[what].repo
1075 == fInstalledRepository->SolvRepo()) {
1076 return _AddSolutionElement(solution, Element::B_DONT_KEEP,
1077 what, 0, NULL);
1080 return _AddSolutionElement(solution,
1081 Element::B_DONT_INSTALL, 0, 0,
1082 solver_select2str(fPool, select, what));
1084 case SOLVER_ERASE:
1086 if (select == SOLVER_SOLVABLE
1087 && (fInstalledRepository == NULL
1088 || fPool->solvables[what].repo
1089 != fInstalledRepository->SolvRepo())) {
1090 return _AddSolutionElement(solution,
1091 Element::B_DONT_FORBID_INSTALLATION, what, 0, NULL);
1094 Element::BType type = select == SOLVER_SOLVABLE_PROVIDES
1095 ? Element::B_DONT_DEINSTALL_ALL : Element::B_DONT_DEINSTALL;
1096 return _AddSolutionElement(solution, type, 0, 0,
1097 solver_select2str(fPool, select, what));
1100 case SOLVER_UPDATE:
1101 return _AddSolutionElement(solution,
1102 Element::B_DONT_INSTALL_MOST_RECENT, 0, 0,
1103 solver_select2str(fPool, select, what));
1105 case SOLVER_LOCK:
1106 return _AddSolutionElement(solution, Element::B_DONT_LOCK, 0, 0,
1107 solver_select2str(fPool, select, what));
1109 default:
1110 return _AddSolutionElement(solution, Element::B_UNSPECIFIED, 0,
1111 0, NULL);
1115 Solvable* target = targetId != 0 ? fPool->solvables + targetId : NULL;
1116 bool targetInstalled = target != NULL && fInstalledRepository
1117 && target->repo == fInstalledRepository->SolvRepo();
1119 if (sourceId == SOLVER_SOLUTION_INFARCH) {
1120 return _AddSolutionElement(solution,
1121 targetInstalled
1122 ? Element::B_KEEP_INFERIOR_ARCHITECTURE
1123 : Element::B_INSTALL_INFERIOR_ARCHITECTURE,
1124 targetId, 0, NULL);
1127 if (sourceId == SOLVER_SOLUTION_DISTUPGRADE) {
1128 return _AddSolutionElement(solution,
1129 targetInstalled
1130 ? Element::B_KEEP_EXCLUDED : Element::B_INSTALL_EXCLUDED,
1131 targetId, 0, NULL);
1134 if (sourceId == SOLVER_SOLUTION_BEST) {
1135 return _AddSolutionElement(solution,
1136 targetInstalled ? Element::B_KEEP_OLD : Element::B_INSTALL_OLD,
1137 targetId, 0, NULL);
1140 // replace source with target
1141 Solvable* source = fPool->solvables + sourceId;
1142 if (target == NULL) {
1143 return _AddSolutionElement(solution, Element::B_ALLOW_DEINSTALLATION,
1144 sourceId, 0, NULL);
1147 int illegalMask = policy_is_illegal(fSolver, source, target, 0);
1148 if ((illegalMask & POLICY_ILLEGAL_DOWNGRADE) != 0) {
1149 status_t error = _AddSolutionElement(solution,
1150 Element::B_ALLOW_DOWNGRADE, sourceId, targetId, NULL);
1151 if (error != B_OK)
1152 return error;
1155 if ((illegalMask & POLICY_ILLEGAL_NAMECHANGE) != 0) {
1156 status_t error = _AddSolutionElement(solution,
1157 Element::B_ALLOW_NAME_CHANGE, sourceId, targetId, NULL);
1158 if (error != B_OK)
1159 return error;
1162 if ((illegalMask & POLICY_ILLEGAL_ARCHCHANGE) != 0) {
1163 status_t error = _AddSolutionElement(solution,
1164 Element::B_ALLOW_ARCHITECTURE_CHANGE, sourceId, targetId, NULL);
1165 if (error != B_OK)
1166 return error;
1169 if ((illegalMask & POLICY_ILLEGAL_VENDORCHANGE) != 0) {
1170 status_t error = _AddSolutionElement(solution,
1171 Element::B_ALLOW_VENDOR_CHANGE, sourceId, targetId, NULL);
1172 if (error != B_OK)
1173 return error;
1176 if (illegalMask == 0) {
1177 return _AddSolutionElement(solution, Element::B_ALLOW_REPLACEMENT,
1178 sourceId, targetId, NULL);
1181 return B_OK;
1185 status_t
1186 LibsolvSolver::_AddSolutionElement(Solution* solution,
1187 BSolverProblemSolutionElement::BType type, Id sourceSolvableId,
1188 Id targetSolvableId, const char* selectionString)
1190 BSolverPackage* sourcePackage = NULL;
1191 if (sourceSolvableId != 0) {
1192 sourcePackage = _GetPackage(sourceSolvableId);
1193 if (sourcePackage == NULL)
1194 return B_ERROR;
1197 BSolverPackage* targetPackage = NULL;
1198 if (targetSolvableId != 0) {
1199 targetPackage = _GetPackage(targetSolvableId);
1200 if (targetPackage == NULL)
1201 return B_ERROR;
1204 BString selection;
1205 if (selectionString != NULL && selectionString[0] != '\0') {
1206 selection = selectionString;
1207 if (selection.IsEmpty())
1208 return B_NO_MEMORY;
1211 if (!solution->AppendElement(BSolverProblemSolutionElement(
1212 type, sourcePackage, targetPackage, selection))) {
1213 return B_NO_MEMORY;
1216 return B_OK;
1220 status_t
1221 LibsolvSolver::_GetResolvableExpression(Id id,
1222 BPackageResolvableExpression& _expression) const
1224 // Try to translate the libsolv ID to a resolvable expression. Generally
1225 // that doesn't work, since libsolv is more expressive, but all the stuff
1226 // we feed libsolv we should be able to translate back.
1228 if (!ISRELDEP(id)) {
1229 // just a string
1230 _expression.SetTo(pool_id2str(fPool, id));
1231 return B_OK;
1234 // a composite -- analyze it
1235 Reldep* reldep = GETRELDEP(fPool, id);
1237 // No support for more than one level, so both name and evr must be strings.
1238 if (ISRELDEP(reldep->name) || ISRELDEP(reldep->evr))
1239 return B_NOT_SUPPORTED;
1241 const char* name = pool_id2str(fPool, reldep->name);
1242 const char* versionString = pool_id2str(fPool, reldep->evr);
1243 if (name == NULL || versionString == NULL)
1244 return B_NOT_SUPPORTED;
1246 // get the operator -- we don't support all libsolv supports
1247 BPackageResolvableOperator op;
1248 switch (reldep->flags) {
1249 case 1:
1250 op = B_PACKAGE_RESOLVABLE_OP_GREATER;
1251 break;
1252 case 2:
1253 op = B_PACKAGE_RESOLVABLE_OP_EQUAL;
1254 break;
1255 case 3:
1256 op = B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL;
1257 break;
1258 case 4:
1259 op = B_PACKAGE_RESOLVABLE_OP_LESS;
1260 break;
1261 case 5:
1262 op = B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL;
1263 break;
1264 case 6:
1265 op = B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL;
1266 break;
1267 default:
1268 return B_NOT_SUPPORTED;
1271 // get the version (cut off the empty epoch)
1272 if (versionString[0] == ':')
1273 versionString++;
1275 BPackageVersion version;
1276 status_t error = version.SetTo(versionString, true);
1277 if (error != B_OK)
1278 return error == B_BAD_DATA ? B_NOT_SUPPORTED : error;
1280 _expression.SetTo(name, op, version);
1281 return B_OK;
1285 status_t
1286 LibsolvSolver::_GetFoundPackages(SolvQueue& selection, uint32 flags,
1287 BObjectList<BSolverPackage>& _packages)
1289 // get solvables
1290 SolvQueue solvables;
1291 selection_solvables(fPool, &selection, &solvables);
1293 // get packages
1294 for (int i = 0; i < solvables.count; i++) {
1295 BSolverPackage* package = _GetPackage(solvables.elements[i]);
1296 if (package == NULL)
1297 return B_ERROR;
1299 // TODO: Fix handling of SELECTION_INSTALLED_ONLY in libsolv. Despite
1300 // passing the flag, we get solvables that aren't installed.
1301 if ((flags & B_FIND_INSTALLED_ONLY) != 0
1302 && package->Repository() != fInstalledRepository->Repository()) {
1303 continue;
1306 if (!_packages.AddItem(package))
1307 return B_NO_MEMORY;
1310 return B_OK;
1314 status_t
1315 LibsolvSolver::_Solve()
1317 if (fJobs == NULL || fSolver == NULL)
1318 return B_BAD_VALUE;
1320 int problemCount = solver_solve(fSolver, fJobs);
1322 // get the problems (if any)
1323 fProblems.MakeEmpty();
1325 for (Id problemId = 1; problemId <= problemCount; problemId++) {
1326 status_t error = _AddProblem(problemId);
1327 if (error != B_OK)
1328 return error;
1331 return B_OK;
1335 void
1336 LibsolvSolver::_SetJobsSolverMode(int solverMode)
1338 for (int i = 0; i < fJobs->count; i += 2)
1339 fJobs->elements[i] |= solverMode;