2 * Copyright 2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Ingo Weinhold <ingo_weinhold@gmx.de>
10 #include "LibsolvSolver.h"
13 #include <sys/utsname.h>
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.
42 BPackageKit::create_solver()
44 return new(std::nothrow
) LibsolvSolver
;
48 struct LibsolvSolver::SolvQueue
: Queue
{
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
);
70 dataiterator_free(this);
75 struct LibsolvSolver::RepositoryInfo
{
76 RepositoryInfo(BSolverRepository
* repository
)
78 fRepository(repository
),
80 fChangeCount(repository
->ChangeCount())
84 BSolverRepository
* Repository() const
94 void SetSolvRepo(Repo
* repo
)
99 bool HasChanged() const
101 return fChangeCount
!= fRepository
->ChangeCount() || fSolvRepo
== NULL
;
106 fChangeCount
= fRepository
->ChangeCount();
110 BSolverRepository
* fRepository
;
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
),
123 fSelectedSolution(NULL
)
132 const Solution
* SelectedSolution() const
134 return fSelectedSolution
;
137 void SetSelectedSolution(const Solution
* solution
)
139 fSelectedSolution
= solution
;
144 const Solution
* fSelectedSolution
;
148 struct LibsolvSolver::Solution
: public BSolverProblemSolution
{
149 Solution(::Id id
, LibsolvSolver::Problem
* problem
)
151 BSolverProblemSolution(),
162 LibsolvSolver::Problem
* Problem() const
169 LibsolvSolver::Problem
* fProblem
;
173 // #pragma mark - LibsolvSolver
176 LibsolvSolver::LibsolvSolver()
181 fRepositoryInfos(10, true),
182 fInstalledRepository(NULL
),
191 LibsolvSolver::~LibsolvSolver()
198 LibsolvSolver::Init()
202 // We do all initialization lazily.
208 LibsolvSolver::SetDebugLevel(int32 level
)
213 pool_setdebuglevel(fPool
, fDebugLevel
);
218 LibsolvSolver::AddRepository(BSolverRepository
* repository
)
220 if (repository
== NULL
|| repository
->InitCheck() != B_OK
)
223 // If the repository represents installed packages, check, if we already
224 // have such a repository.
225 if (repository
->IsInstalled() && _InstalledRepository() != NULL
)
228 // add the repository info
229 RepositoryInfo
* info
= new(std::nothrow
) RepositoryInfo(repository
);
233 if (!fRepositoryInfos
.AddItem(info
)) {
243 LibsolvSolver::FindPackages(const char* searchString
, uint32 flags
,
244 BObjectList
<BSolverPackage
>& _packages
)
246 // add repositories to pool
247 status_t error
= _AddRepositories();
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
);
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
);
309 LibsolvSolver::FindPackages(const BSolverPackageSpecifierList
& packages
,
310 uint32 flags
, BObjectList
<BSolverPackage
>& _packages
,
311 const BSolverPackageSpecifier
** _unmatched
)
313 if (_unmatched
!= NULL
)
316 if ((flags
& B_FIND_INSTALLED_ONLY
) != 0 && _InstalledRepository() == NULL
)
319 // add repositories to pool
320 status_t error
= _AddRepositories();
324 error
= _InitJobQueue();
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);
334 return _GetFoundPackages(*fJobs
, flags
, _packages
);
339 LibsolvSolver::Install(const BSolverPackageSpecifierList
& packages
,
340 const BSolverPackageSpecifier
** _unmatched
)
342 if (_unmatched
!= NULL
)
345 if (packages
.IsEmpty())
348 // add repositories to pool
349 status_t error
= _AddRepositories();
353 // add the packages to install to the job queue
354 error
= _InitJobQueue();
358 error
= _AddSpecifiedPackages(packages
, _unmatched
, 0);
362 // set jobs' solver mode and solve
363 _SetJobsSolverMode(SOLVER_INSTALL
);
371 LibsolvSolver::Uninstall(const BSolverPackageSpecifierList
& packages
,
372 const BSolverPackageSpecifier
** _unmatched
)
374 if (_unmatched
!= NULL
)
377 if (_InstalledRepository() == NULL
|| packages
.IsEmpty())
380 // add repositories to pool
381 status_t error
= _AddRepositories();
385 // add the packages to uninstall to the job queue
386 error
= _InitJobQueue();
390 error
= _AddSpecifiedPackages(packages
, _unmatched
,
391 SELECTION_INSTALLED_ONLY
);
395 // set jobs' solver mode and solve
396 _SetJobsSolverMode(SOLVER_ERASE
);
399 solver_set_flag(fSolver
, SOLVER_FLAG_ALLOW_UNINSTALL
, 1);
405 LibsolvSolver::Update(const BSolverPackageSpecifierList
& packages
,
406 bool installNotYetInstalled
, const BSolverPackageSpecifier
** _unmatched
)
408 if (_unmatched
!= NULL
)
411 // add repositories to pool
412 status_t error
= _AddRepositories();
416 // add the packages to update to the job queue -- if none are specified,
418 error
= _InitJobQueue();
422 if (packages
.IsEmpty()) {
423 queue_push2(fJobs
, SOLVER_SOLVABLE_ALL
, 0);
425 error
= _AddSpecifiedPackages(packages
, _unmatched
, 0);
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
;
450 LibsolvSolver::FullSync()
452 // add repositories to pool
453 status_t error
= _AddRepositories();
457 // Init the job queue and specify that all packages shall be updated.
458 error
= _InitJobQueue();
462 queue_push2(fJobs
, SOLVER_SOLVABLE_ALL
, 0);
464 // set jobs' solver mode and solve
465 _SetJobsSolverMode(SOLVER_DISTUPGRADE
);
473 LibsolvSolver::VerifyInstallation(uint32 flags
)
475 if (_InstalledRepository() == NULL
)
478 // add repositories to pool
479 status_t error
= _AddRepositories();
483 // add the verify job to the job queue
484 error
= _InitJobQueue();
488 queue_push2(fJobs
, SOLVER_SOLVABLE_ALL
, 0);
490 // set jobs' solver mode and solve
491 _SetJobsSolverMode(SOLVER_VERIFY
);
494 if ((flags
& B_VERIFY_ALLOW_UNINSTALL
) != 0)
495 solver_set_flag(fSolver
, SOLVER_FLAG_ALLOW_UNINSTALL
, 1);
501 LibsolvSolver::SelectProblemSolution(BSolverProblem
* _problem
,
502 const BSolverProblemSolution
* _solution
)
504 if (_problem
== NULL
)
507 Problem
* problem
= static_cast<Problem
*>(_problem
);
508 if (_solution
== NULL
) {
509 problem
->SetSelectedSolution(NULL
);
513 const Solution
* solution
= static_cast<const Solution
*>(_solution
);
514 if (solution
->Problem() != problem
)
517 problem
->SetSelectedSolution(solution
);
523 LibsolvSolver::SolveAgain()
525 if (fSolver
== NULL
|| fJobs
== NULL
)
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
);
541 LibsolvSolver::CountProblems() const
543 return fProblems
.CountItems();
548 LibsolvSolver::ProblemAt(int32 index
) const
550 return fProblems
.ItemAt(index
);
555 LibsolvSolver::GetResult(BSolverResult
& _result
)
557 if (fSolver
== NULL
|| HasProblems())
562 Transaction
* transaction
= solver_create_transaction(fSolver
);
563 CObjectDeleter
<Transaction
> transactionDeleter(transaction
,
566 if (transaction
->steps
.count
== 0)
569 transaction_order(transaction
, 0);
571 for (int i
= 0; i
< transaction
->steps
.count
; i
++) {
572 Id solvableId
= transaction
->steps
.elements
[i
];
574 && fPool
->solvables
[solvableId
].repo
== fPool
->installed
) {
575 BSolverPackage
* package
= _GetPackage(solvableId
);
579 if (!_result
.AppendElement(
580 BSolverResultElement(
581 BSolverResultElement::B_TYPE_UNINSTALL
, package
))) {
585 BSolverPackage
* package
= _GetPackage(solvableId
);
589 if (!_result
.AppendElement(
590 BSolverResultElement(
591 BSolverResultElement::B_TYPE_INSTALL
, package
))) {
602 LibsolvSolver::_InitPool()
606 fPool
= pool_create();
608 pool_setdebuglevel(fPool
, fDebugLevel
);
610 // Set the system architecture. We use what uname() returns unless we're on
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
623 if (uname(&info
) != 0)
628 arch
= HAIKU_PACKAGING_ARCH
;
631 pool_setarchpolicy(fPool
, arch
);
639 LibsolvSolver::_InitJobQueue()
643 fJobs
= new(std::nothrow
) SolvQueue
;
644 return fJobs
!= NULL
? B_OK
: B_NO_MEMORY
;;
649 LibsolvSolver::_InitSolver()
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);
660 LibsolvSolver::_Cleanup()
664 fInstalledRepository
= NULL
;
665 fRepositoryInfos
.MakeEmpty();
671 LibsolvSolver::_CleanupPool()
673 // clean up jobs and solver data
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
);
693 LibsolvSolver::_CleanupJobQueue()
703 LibsolvSolver::_CleanupSolver()
705 fProblems
.MakeEmpty();
707 if (fSolver
!= NULL
) {
708 solver_free(fSolver
);
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())
729 LibsolvSolver::_AddRepositories()
731 if (fPool
!= NULL
&& !_HaveRepositoriesChanged())
734 // something has changed -- re-create the pool
735 status_t error
= _InitPool();
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
);
758 fSolvablePackages
[solvableId
] = package
;
759 fPackageSolvables
[package
] = solvableId
;
760 } catch (std::bad_alloc
&) {
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
);
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
;
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
;
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;
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
:
838 case BSolverPackageSpecifier::B_PACKAGE
:
840 BSolverPackage
* package
= specifier
.Package();
843 || (solvableId
= _GetSolvable(package
)) == 0) {
847 queue_push2(fJobs
, SOLVER_SOLVABLE
, solvableId
);
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
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.
868 // restrict to the matching repository
869 if (BSolverRepository
* repository
= specifier
.Repository()) {
870 RepositoryInfo
* repositoryInfo
871 = _GetRepositoryInfo(repository
);
872 if (repositoryInfo
== NULL
)
875 SolvQueue repoFilter
;
876 queue_push2(&repoFilter
,
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
;
888 for (int j
= 0; j
< matchingPackages
.count
; j
++)
889 queue_push(fJobs
, matchingPackages
.elements
[j
]);
899 LibsolvSolver::_AddProblem(Id problemId
)
904 NEED_DEPENDENCY
= 0x4
907 Id ruleId
= solver_findproblemrule(fSolver
, problemId
);
911 BSolverProblem::BType problemType
= BSolverProblem::B_UNSPECIFIED
;
914 switch (solver_ruleinfo(fSolver
, ruleId
, &sourceId
, &targetId
,
916 case SOLVER_RULE_DISTUPGRADE
:
917 problemType
= BSolverProblem::B_NOT_IN_DISTUPGRADE_REPOSITORY
;
918 needed
= NEED_SOURCE
;
920 case SOLVER_RULE_INFARCH
:
921 problemType
= BSolverProblem::B_INFERIOR_ARCHITECTURE
;
922 needed
= NEED_SOURCE
;
924 case SOLVER_RULE_UPDATE
:
925 problemType
= BSolverProblem::B_INSTALLED_PACKAGE_PROBLEM
;
926 needed
= NEED_SOURCE
;
928 case SOLVER_RULE_JOB
:
929 problemType
= BSolverProblem::B_CONFLICTING_REQUESTS
;
931 case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP
:
932 problemType
= BSolverProblem::B_REQUESTED_RESOLVABLE_NOT_PROVIDED
;
933 needed
= NEED_DEPENDENCY
;
935 case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM
:
937 = BSolverProblem::B_REQUESTED_RESOLVABLE_PROVIDED_BY_SYSTEM
;
938 needed
= NEED_DEPENDENCY
;
940 case SOLVER_RULE_RPM
:
941 problemType
= BSolverProblem::B_DEPENDENCY_PROBLEM
;
943 case SOLVER_RULE_RPM_NOT_INSTALLABLE
:
944 problemType
= BSolverProblem::B_PACKAGE_NOT_INSTALLABLE
;
945 needed
= NEED_SOURCE
;
947 case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP
:
948 problemType
= BSolverProblem::B_DEPENDENCY_NOT_PROVIDED
;
949 needed
= NEED_SOURCE
| NEED_DEPENDENCY
;
951 case SOLVER_RULE_RPM_SAME_NAME
:
952 problemType
= BSolverProblem::B_PACKAGE_NAME_CLASH
;
953 needed
= NEED_SOURCE
| NEED_TARGET
;
955 case SOLVER_RULE_RPM_PACKAGE_CONFLICT
:
956 problemType
= BSolverProblem::B_PACKAGE_CONFLICT
;
957 needed
= NEED_SOURCE
| NEED_TARGET
| NEED_DEPENDENCY
;
959 case SOLVER_RULE_RPM_PACKAGE_OBSOLETES
:
960 problemType
= BSolverProblem::B_PACKAGE_OBSOLETES_RESOLVABLE
;
961 needed
= NEED_SOURCE
| NEED_TARGET
| NEED_DEPENDENCY
;
963 case SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES
:
965 = BSolverProblem::B_INSTALLED_PACKAGE_OBSOLETES_RESOLVABLE
;
966 needed
= NEED_SOURCE
| NEED_TARGET
| NEED_DEPENDENCY
;
968 case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES
:
970 = BSolverProblem::B_PACKAGE_IMPLICITLY_OBSOLETES_RESOLVABLE
;
971 needed
= NEED_SOURCE
| NEED_TARGET
| NEED_DEPENDENCY
;
973 case SOLVER_RULE_RPM_PACKAGE_REQUIRES
:
974 problemType
= BSolverProblem::B_DEPENDENCY_NOT_INSTALLABLE
;
975 needed
= NEED_SOURCE
| NEED_DEPENDENCY
;
977 case SOLVER_RULE_RPM_SELF_CONFLICT
:
978 problemType
= BSolverProblem::B_SELF_CONFLICT
;
979 needed
= NEED_SOURCE
| NEED_DEPENDENCY
;
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
;
990 BSolverPackage
* sourcePackage
= NULL
;
991 if ((needed
& NEED_SOURCE
) != 0) {
992 sourcePackage
= _GetPackage(sourceId
);
993 if (sourcePackage
== NULL
)
997 BSolverPackage
* targetPackage
= NULL
;
998 if ((needed
& NEED_TARGET
) != 0) {
999 targetPackage
= _GetPackage(targetId
);
1000 if (targetPackage
== NULL
)
1004 BPackageResolvableExpression dependency
;
1005 if ((needed
& NEED_DEPENDENCY
) != 0) {
1006 status_t error
= _GetResolvableExpression(dependencyId
, dependency
);
1011 Problem
* problem
= new(std::nothrow
) Problem(problemId
, problemType
,
1012 sourcePackage
, targetPackage
, dependency
);
1013 if (problem
== NULL
|| !fProblems
.AddItem(problem
)) {
1018 int solutionCount
= solver_solution_count(fSolver
, problemId
);
1019 for (Id solutionId
= 1; solutionId
<= solutionCount
; solutionId
++) {
1020 status_t error
= _AddSolution(problem
, solutionId
);
1030 LibsolvSolver::_AddSolution(Problem
* problem
, Id solutionId
)
1032 Solution
* solution
= new(std::nothrow
) Solution(solutionId
, problem
);
1033 if (solution
== NULL
|| !problem
->AppendSolution(solution
)) {
1042 elementId
= solver_next_solutionelement(fSolver
, problem
->Id(),
1043 solutionId
, elementId
, &sourceId
, &targetId
);
1047 status_t error
= _AddSolutionElement(solution
, sourceId
, targetId
);
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
,
1080 return _AddSolutionElement(solution
,
1081 Element::B_DONT_INSTALL
, 0, 0,
1082 solver_select2str(fPool
, select
, what
));
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
));
1101 return _AddSolutionElement(solution
,
1102 Element::B_DONT_INSTALL_MOST_RECENT
, 0, 0,
1103 solver_select2str(fPool
, select
, what
));
1106 return _AddSolutionElement(solution
, Element::B_DONT_LOCK
, 0, 0,
1107 solver_select2str(fPool
, select
, what
));
1110 return _AddSolutionElement(solution
, Element::B_UNSPECIFIED
, 0,
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
,
1122 ? Element::B_KEEP_INFERIOR_ARCHITECTURE
1123 : Element::B_INSTALL_INFERIOR_ARCHITECTURE
,
1127 if (sourceId
== SOLVER_SOLUTION_DISTUPGRADE
) {
1128 return _AddSolutionElement(solution
,
1130 ? Element::B_KEEP_EXCLUDED
: Element::B_INSTALL_EXCLUDED
,
1134 if (sourceId
== SOLVER_SOLUTION_BEST
) {
1135 return _AddSolutionElement(solution
,
1136 targetInstalled
? Element::B_KEEP_OLD
: Element::B_INSTALL_OLD
,
1140 // replace source with target
1141 Solvable
* source
= fPool
->solvables
+ sourceId
;
1142 if (target
== NULL
) {
1143 return _AddSolutionElement(solution
, Element::B_ALLOW_DEINSTALLATION
,
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
);
1155 if ((illegalMask
& POLICY_ILLEGAL_NAMECHANGE
) != 0) {
1156 status_t error
= _AddSolutionElement(solution
,
1157 Element::B_ALLOW_NAME_CHANGE
, sourceId
, targetId
, NULL
);
1162 if ((illegalMask
& POLICY_ILLEGAL_ARCHCHANGE
) != 0) {
1163 status_t error
= _AddSolutionElement(solution
,
1164 Element::B_ALLOW_ARCHITECTURE_CHANGE
, sourceId
, targetId
, NULL
);
1169 if ((illegalMask
& POLICY_ILLEGAL_VENDORCHANGE
) != 0) {
1170 status_t error
= _AddSolutionElement(solution
,
1171 Element::B_ALLOW_VENDOR_CHANGE
, sourceId
, targetId
, NULL
);
1176 if (illegalMask
== 0) {
1177 return _AddSolutionElement(solution
, Element::B_ALLOW_REPLACEMENT
,
1178 sourceId
, targetId
, NULL
);
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
)
1197 BSolverPackage
* targetPackage
= NULL
;
1198 if (targetSolvableId
!= 0) {
1199 targetPackage
= _GetPackage(targetSolvableId
);
1200 if (targetPackage
== NULL
)
1205 if (selectionString
!= NULL
&& selectionString
[0] != '\0') {
1206 selection
= selectionString
;
1207 if (selection
.IsEmpty())
1211 if (!solution
->AppendElement(BSolverProblemSolutionElement(
1212 type
, sourcePackage
, targetPackage
, selection
))) {
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
)) {
1230 _expression
.SetTo(pool_id2str(fPool
, id
));
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
) {
1250 op
= B_PACKAGE_RESOLVABLE_OP_GREATER
;
1253 op
= B_PACKAGE_RESOLVABLE_OP_EQUAL
;
1256 op
= B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL
;
1259 op
= B_PACKAGE_RESOLVABLE_OP_LESS
;
1262 op
= B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL
;
1265 op
= B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL
;
1268 return B_NOT_SUPPORTED
;
1271 // get the version (cut off the empty epoch)
1272 if (versionString
[0] == ':')
1275 BPackageVersion version
;
1276 status_t error
= version
.SetTo(versionString
, true);
1278 return error
== B_BAD_DATA
? B_NOT_SUPPORTED
: error
;
1280 _expression
.SetTo(name
, op
, version
);
1286 LibsolvSolver::_GetFoundPackages(SolvQueue
& selection
, uint32 flags
,
1287 BObjectList
<BSolverPackage
>& _packages
)
1290 SolvQueue solvables
;
1291 selection_solvables(fPool
, &selection
, &solvables
);
1294 for (int i
= 0; i
< solvables
.count
; i
++) {
1295 BSolverPackage
* package
= _GetPackage(solvables
.elements
[i
]);
1296 if (package
== NULL
)
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()) {
1306 if (!_packages
.AddItem(package
))
1315 LibsolvSolver::_Solve()
1317 if (fJobs
== NULL
|| fSolver
== NULL
)
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
);
1336 LibsolvSolver::_SetJobsSolverMode(int solverMode
)
1338 for (int i
= 0; i
< fJobs
->count
; i
+= 2)
1339 fJobs
->elements
[i
] |= solverMode
;