When uniquifying properties, also sort them on the owning package.
This ensures that whenever two packages provide or (or require, obsolete
or conflict) the same property, they appear in the same order in the
propertys list of packages.
2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <sys/types.h>
36 #include "razor-internal.h"
40 provider_satisfies_requirement(struct razor_property *provider,
41 const char *provider_strings,
46 const char *provided = &provider_strings[provider->version];
51 if (flags & RAZOR_PROPERTY_LESS)
57 cmp = razor_versioncmp(provided, required);
59 switch (flags & RAZOR_PROPERTY_RELATION_MASK) {
60 case RAZOR_PROPERTY_LESS:
63 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
66 /* fall through: FIXME, make sure this is correct */
68 case RAZOR_PROPERTY_EQUAL:
72 /* "foo == 1.1" is satisfied by "foo 1.1-2" */
73 len = strlen(required);
74 if (!strncmp(required, provided, len) && provided[len] == '-')
78 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
81 case RAZOR_PROPERTY_GREATER:
85 /* shouldn't happen */
89 #define TRANS_PACKAGE_PRESENT 1
90 #define TRANS_PACKAGE_UPDATE 2
91 #define TRANS_PROPERTY_SATISFIED 0x80000000
93 struct transaction_set {
94 struct razor_set *set;
99 struct razor_transaction {
100 int package_count, errors;
101 struct transaction_set system, upstream;
106 transaction_set_init(struct transaction_set *ts, struct razor_set *set)
111 count = set->packages.size / sizeof (struct razor_package);
112 ts->packages = zalloc(count * sizeof *ts->packages);
113 count = set->properties.size / sizeof (struct razor_property);
114 ts->properties = zalloc(count * sizeof *ts->properties);
118 transaction_set_release(struct transaction_set *ts)
121 free(ts->properties);
125 transaction_set_install_package(struct transaction_set *ts,
126 struct razor_package *package)
128 struct razor_package *pkgs;
132 pkgs = ts->set->packages.data;
134 if (ts->packages[i] == TRANS_PACKAGE_PRESENT)
137 ts->packages[i] = TRANS_PACKAGE_PRESENT;
139 prop = list_first(&package->properties, &ts->set->property_pool);
141 ts->properties[prop->data]++;
142 prop = list_next(prop);
147 transaction_set_remove_package(struct transaction_set *ts,
148 struct razor_package *package)
150 struct razor_package *pkgs;
154 pkgs = ts->set->packages.data;
156 if (ts->packages[i] == 0)
161 prop = list_first(&package->properties, &ts->set->property_pool);
163 ts->properties[prop->data]--;
164 prop = list_next(prop);
168 struct razor_transaction *
169 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
171 struct razor_transaction *trans;
172 struct razor_package *p, *spkgs, *pend;
174 trans = zalloc(sizeof *trans);
175 transaction_set_init(&trans->system, system);
176 transaction_set_init(&trans->upstream, upstream);
178 spkgs = trans->system.set->packages.data;
179 pend = trans->system.set->packages.data +
180 trans->system.set->packages.size;
181 for (p = spkgs; p < pend; p++)
182 transaction_set_install_package(&trans->system, p);
188 razor_transaction_install_package(struct razor_transaction *trans,
189 struct razor_package *package)
191 transaction_set_install_package(&trans->upstream, package);
196 razor_transaction_remove_package(struct razor_transaction *trans,
197 struct razor_package *package)
199 transaction_set_remove_package(&trans->system, package);
204 razor_transaction_update_package(struct razor_transaction *trans,
205 struct razor_package *package)
207 struct razor_package *spkgs, *upkgs, *end;
209 spkgs = trans->system.set->packages.data;
210 upkgs = trans->upstream.set->packages.data;
211 end = trans->system.set->packages.data +
212 trans->system.set->packages.size;
213 if (spkgs <= package && package < end)
214 trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
216 trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
220 struct razor_property *p, *start, *end;
226 prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
228 pi->p = ts->set->properties.data;
229 pi->start = ts->set->properties.data;
230 pi->end = ts->set->properties.data + ts->set->properties.size;
231 pi->pool = ts->set->string_pool.data;
232 pi->present = ts->properties;
236 prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p)
238 while (pi->p < pi->end) {
239 if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
240 (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) {
250 static struct razor_property *
251 prop_iter_seek_to(struct prop_iter *pi,
252 uint32_t flags, const char *match)
256 while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
259 if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
263 while (pi->p < pi->end &&
264 pi->p->name == name &&
265 (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags)
268 if (pi->p == pi->end || pi->p->name != name)
274 /* Remove packages from set that provide any of the matching (same
275 * name and type) providers from ppi onwards that match the
276 * requirement that rpi points to. */
278 remove_matching_providers(struct razor_transaction *trans,
279 struct prop_iter *ppi,
283 struct razor_property *p;
284 struct razor_package *pkg, *pkgs;
285 struct razor_package_iterator pkg_iter;
286 struct razor_set *set;
287 const char *n, *v, *a;
290 if (ppi->present == trans->system.properties)
291 set = trans->system.set;
293 set = trans->upstream.set;
295 pkgs = (struct razor_package *) set->packages.data;
296 type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
299 p->name == ppi->p->name &&
300 (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
302 if (!ppi->present[p - ppi->start])
304 if (!provider_satisfies_requirement(p, ppi->pool,
308 razor_package_iterator_init_for_property(&pkg_iter, set, p);
309 while (razor_package_iterator_next(&pkg_iter,
311 fprintf(stderr, "removing %s-%s\n", n, v);
312 razor_transaction_remove_package(trans, pkg);
318 flag_matching_providers(struct razor_transaction *trans,
319 struct prop_iter *ppi,
320 struct razor_property *r,
321 struct prop_iter *rpi,
324 struct razor_property *p;
325 struct razor_package *pkg, *pkgs;
326 struct razor_package_iterator pkg_iter;
327 struct razor_set *set;
328 const char *name, *version, *arch;
329 uint32_t *flags, type;
331 if (ppi->present == trans->system.properties) {
332 set = trans->system.set;
333 flags = trans->system.packages;
335 set = trans->upstream.set;
336 flags = trans->upstream.packages;
339 pkgs = (struct razor_package *) set->packages.data;
340 type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
343 p->name == ppi->p->name &&
344 (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
346 if (!ppi->present[p - ppi->start])
348 if (!provider_satisfies_requirement(p, ppi->pool,
350 &rpi->pool[r->version]))
353 razor_package_iterator_init_for_property(&pkg_iter, set, p);
354 while (razor_package_iterator_next(&pkg_iter, &pkg,
355 &name, &version, &arch)) {
357 fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
361 rpi->pool + r->version);
362 flags[pkg - pkgs] |= flag;
367 static struct razor_package *
368 pick_matching_provider(struct razor_set *set,
369 struct prop_iter *ppi,
373 struct razor_property *p;
374 struct razor_package *pkgs;
378 /* This is where we decide which pkgs to pull in to satisfy a
379 * requirement. There may be several different providers
380 * (different versions) and each version of a provider may
381 * come from a number of packages. We pick the first package
382 * from the first provider that matches. */
384 pkgs = set->packages.data;
385 type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
388 p->name == ppi->p->name &&
389 (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
390 ppi->present[p - ppi->start] == 0;
392 if (!provider_satisfies_requirement(p, ppi->pool,
396 i = list_first(&p->packages, &set->package_pool);
398 return &pkgs[i->data];
405 remove_obsoleted_packages(struct razor_transaction *trans)
407 struct razor_property *up;
408 struct razor_package *spkgs;
409 struct prop_iter spi, upi;
411 spkgs = trans->system.set->packages.data;
412 prop_iter_init(&spi, &trans->system);
413 prop_iter_init(&upi, &trans->upstream);
415 while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
416 if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
417 &upi.pool[up->name]))
419 remove_matching_providers(trans, &spi, up->flags,
420 &upi.pool[up->version]);
425 any_provider_satisfies_requirement(struct prop_iter *ppi,
429 struct razor_property *p;
432 type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
435 p->name == ppi->p->name &&
436 (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
438 if (ppi->present[p - ppi->start] > 0 &&
439 provider_satisfies_requirement(p, ppi->pool,
448 clear_requires_flags(struct transaction_set *ts)
450 struct razor_property *p;
454 count = ts->set->properties.size / sizeof *p;
455 p = ts->set->properties.data;
456 pool = ts->set->string_pool.data;
457 for (i = 0; i < count; i++) {
458 ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
459 if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
460 ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
465 razor_property_relation_to_string(struct razor_property *p)
467 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
468 case RAZOR_PROPERTY_LESS:
471 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
474 case RAZOR_PROPERTY_EQUAL:
477 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
480 case RAZOR_PROPERTY_GREATER:
489 razor_property_type_to_string(struct razor_property *p)
491 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
492 case RAZOR_PROPERTY_REQUIRES:
494 case RAZOR_PROPERTY_PROVIDES:
496 case RAZOR_PROPERTY_CONFLICTS:
498 case RAZOR_PROPERTY_OBSOLETES:
506 mark_satisfied_requires(struct razor_transaction *trans,
507 struct transaction_set *rts,
508 struct transaction_set *pts)
510 struct prop_iter rpi, ppi;
511 struct razor_property *rp;
513 prop_iter_init(&rpi, rts);
514 prop_iter_init(&ppi, pts);
516 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
517 if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
518 &rpi.pool[rp->name]))
521 if (any_provider_satisfies_requirement(&ppi, rp->flags,
522 &rpi.pool[rp->version]))
523 rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
528 mark_all_satisfied_requires(struct razor_transaction *trans)
530 clear_requires_flags(&trans->system);
531 clear_requires_flags(&trans->upstream);
532 mark_satisfied_requires(trans, &trans->system, &trans->system);
533 mark_satisfied_requires(trans, &trans->system, &trans->upstream);
534 mark_satisfied_requires(trans, &trans->upstream, &trans->system);
535 mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
539 update_unsatisfied_packages(struct razor_transaction *trans)
541 struct razor_package *spkgs, *pkg;
542 struct razor_property *sp;
543 struct prop_iter spi;
544 struct razor_package_iterator pkg_iter;
545 const char *name, *version, *arch;
547 spkgs = trans->system.set->packages.data;
548 prop_iter_init(&spi, &trans->system);
550 while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
551 if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
554 razor_package_iterator_init_for_property(&pkg_iter,
557 while (razor_package_iterator_next(&pkg_iter, &pkg,
558 &name, &version, &arch)) {
559 fprintf(stderr, "updating %s because %s %s %s "
561 name, spi.pool + sp->name,
562 razor_property_relation_to_string(sp),
563 spi.pool + sp->version);
564 trans->system.packages[pkg - spkgs] |=
565 TRANS_PACKAGE_UPDATE;
571 razor_transaction_update_all(struct razor_transaction *trans)
573 struct razor_package *p;
576 count = trans->system.set->packages.size / sizeof *p;
577 for (i = 0; i < count; i++)
578 trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
582 update_conflicted_packages(struct razor_transaction *trans)
584 struct razor_package *pkg, *spkgs;
585 struct razor_property *up, *sp;
586 struct prop_iter spi, upi;
587 struct razor_package_iterator pkg_iter;
588 const char *name, *version, *arch;
590 spkgs = trans->system.set->packages.data;
591 prop_iter_init(&spi, &trans->system);
592 prop_iter_init(&upi, &trans->upstream);
594 while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
595 if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
596 &spi.pool[sp->name]))
599 if (!any_provider_satisfies_requirement(&upi, sp->flags,
600 &spi.pool[sp->version]))
603 razor_package_iterator_init_for_property(&pkg_iter,
606 while (razor_package_iterator_next(&pkg_iter, &pkg,
607 &name, &version, &arch)) {
608 fprintf(stderr, "updating %s %s because it conflicts with %s",
609 name, version, spi.pool + sp->name);
610 trans->system.packages[pkg - spkgs] |=
611 TRANS_PACKAGE_UPDATE;
615 prop_iter_init(&spi, &trans->system);
616 prop_iter_init(&upi, &trans->upstream);
618 while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
619 sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
620 &upi.pool[upi.p->name]);
623 flag_matching_providers(trans, &spi, up, &upi,
624 TRANS_PACKAGE_UPDATE);
629 pull_in_requirements(struct razor_transaction *trans,
630 struct prop_iter *rpi, struct prop_iter *ppi)
632 struct razor_property *rp, *pp;
633 struct razor_package *pkg, *upkgs;
635 upkgs = trans->upstream.set->packages.data;
636 while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
637 if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
640 pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
641 &rpi->pool[rp->name]);
644 pkg = pick_matching_provider(trans->upstream.set,
646 &rpi->pool[rp->version]);
650 rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
652 fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
653 "to satisfy %s %s %s\n",
654 ppi->pool + pkg->name,
655 ppi->pool + pkg->version,
656 ppi->pool + pkg->arch,
657 ppi->pool + pp->name,
658 razor_property_relation_to_string(pp),
659 ppi->pool + pp->version,
660 &rpi->pool[rp->name],
661 razor_property_relation_to_string(rp),
662 &rpi->pool[rp->version]);
664 trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
669 pull_in_all_requirements(struct razor_transaction *trans)
671 struct prop_iter rpi, ppi;
673 prop_iter_init(&rpi, &trans->system);
674 prop_iter_init(&ppi, &trans->upstream);
675 pull_in_requirements(trans, &rpi, &ppi);
677 prop_iter_init(&rpi, &trans->upstream);
678 prop_iter_init(&ppi, &trans->upstream);
679 pull_in_requirements(trans, &rpi, &ppi);
683 flush_scheduled_system_updates(struct razor_transaction *trans)
685 struct razor_package_iterator *pi;
686 struct razor_package *p, *pkg, *spkgs;
687 struct prop_iter ppi;
688 const char *name, *version, *arch;
690 spkgs = trans->system.set->packages.data;
691 pi = razor_package_iterator_create(trans->system.set);
692 prop_iter_init(&ppi, &trans->upstream);
694 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
695 if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
698 if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
701 pkg = pick_matching_provider(trans->upstream.set, &ppi,
702 RAZOR_PROPERTY_GREATER, version);
706 fprintf(stderr, "updating %s-%s to %s-%s\n",
708 &ppi.pool[pkg->name], &ppi.pool[pkg->version]);
710 razor_transaction_remove_package(trans, p);
711 razor_transaction_install_package(trans, pkg);
714 razor_package_iterator_destroy(pi);
718 flush_scheduled_upstream_updates(struct razor_transaction *trans)
720 struct razor_package_iterator *pi;
721 struct razor_package *p, *upkgs;
722 struct prop_iter spi;
723 const char *name, *version, *arch;
725 upkgs = trans->upstream.set->packages.data;
726 pi = razor_package_iterator_create(trans->upstream.set);
727 prop_iter_init(&spi, &trans->system);
729 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
730 if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
733 if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
734 remove_matching_providers(trans,
738 razor_transaction_install_package(trans, p);
739 fprintf(stderr, "installing %s-%s\n", name, version);
744 razor_transaction_resolve(struct razor_transaction *trans)
748 flush_scheduled_system_updates(trans);
749 flush_scheduled_upstream_updates(trans);
751 while (last < trans->changes) {
752 last = trans->changes;
753 remove_obsoleted_packages(trans);
754 mark_all_satisfied_requires(trans);
755 update_unsatisfied_packages(trans);
756 update_conflicted_packages(trans);
757 pull_in_all_requirements(trans);
758 flush_scheduled_system_updates(trans);
759 flush_scheduled_upstream_updates(trans);
762 return trans->changes;
766 describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
768 struct razor_package_iterator pi;
769 struct razor_package *pkg;
770 const char *name, *version, *arch, *pool;
772 pool = set->string_pool.data;
773 if (pool[rp->version] == '\0') {
774 razor_package_iterator_init_for_property(&pi, set, rp);
775 while (razor_package_iterator_next(&pi, &pkg,
776 &name, &version, &arch))
777 fprintf(stderr, "%s is needed by %s-%s.%s\n",
779 name, version, arch);
781 razor_package_iterator_init_for_property(&pi, set, rp);
782 while (razor_package_iterator_next(&pi, &pkg,
783 &name, &version, &arch))
784 fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
786 razor_property_relation_to_string(rp),
788 name, version, arch);
793 razor_transaction_describe(struct razor_transaction *trans)
795 struct prop_iter rpi;
796 struct razor_property *rp;
799 flush_scheduled_system_updates(trans);
800 flush_scheduled_upstream_updates(trans);
801 mark_all_satisfied_requires(trans);
804 prop_iter_init(&rpi, &trans->system);
805 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
806 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
807 describe_unsatisfied(trans->system.set, rp);
812 prop_iter_init(&rpi, &trans->upstream);
813 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
814 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
815 describe_unsatisfied(trans->upstream.set, rp);
824 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
830 struct razor_property *p;
832 prop_iter_init(&pi, &trans->system);
833 while (prop_iter_next(&pi, flags, &p)) {
834 if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
836 strcmp(&pi.pool[p->name], name) == 0 &&
837 strcmp(&pi.pool[p->version], version) == 0)
842 prop_iter_init(&pi, &trans->upstream);
843 while (prop_iter_next(&pi, flags, &p)) {
844 if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
846 strcmp(&pi.pool[p->name], name) == 0 &&
847 strcmp(&pi.pool[p->version], version) == 0)
856 razor_transaction_finish(struct razor_transaction *trans)
858 struct razor_merger *merger;
859 struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
863 s = trans->system.set->packages.data;
864 spkgs = trans->system.set->packages.data;
865 send = trans->system.set->packages.data +
866 trans->system.set->packages.size;
867 spool = trans->system.set->string_pool.data;
869 u = trans->upstream.set->packages.data;
870 upkgs = trans->upstream.set->packages.data;
871 uend = trans->upstream.set->packages.data +
872 trans->upstream.set->packages.size;
873 upool = trans->upstream.set->string_pool.data;
875 merger = razor_merger_create(trans->system.set, trans->upstream.set);
876 while (s < send || u < uend) {
877 if (s < send && u < uend)
878 cmp = strcmp(&spool[s->name], &upool[u->name]);
885 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
886 razor_merger_add_package(merger, s);
888 } else if (cmp == 0) {
889 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
890 razor_merger_add_package(merger, s);
891 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
892 razor_merger_add_package(merger, u);
897 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
898 razor_merger_add_package(merger, u);
903 razor_transaction_destroy(trans);
905 return razor_merger_finish(merger);
909 razor_transaction_destroy(struct razor_transaction *trans)
911 transaction_set_release(&trans->system);
912 transaction_set_release(&trans->upstream);