Introduce install/remove iterators.
These iterator constructors lets you pass in two sets and creates
an iterator for the packages to remove or the packages to install.
The iterators will step through the packages in a sequence that respects
the pre, post, preun and postun modifiers.
Right now, the install order isn't actually implemented, this patch just
implements the API changes and updates the applications.
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 which provides %s %s %s "
653 "to satisfy %s %s %s\n",
654 ppi->pool + pkg->name,
655 ppi->pool + pp->name,
656 razor_property_relation_to_string(pp),
657 ppi->pool + pp->version,
658 &rpi->pool[rp->name],
659 razor_property_relation_to_string(rp),
660 &rpi->pool[rp->version]);
662 trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
667 pull_in_all_requirements(struct razor_transaction *trans)
669 struct prop_iter rpi, ppi;
671 prop_iter_init(&rpi, &trans->system);
672 prop_iter_init(&ppi, &trans->upstream);
673 pull_in_requirements(trans, &rpi, &ppi);
675 prop_iter_init(&rpi, &trans->upstream);
676 prop_iter_init(&ppi, &trans->upstream);
677 pull_in_requirements(trans, &rpi, &ppi);
681 flush_scheduled_system_updates(struct razor_transaction *trans)
683 struct razor_package_iterator *pi;
684 struct razor_package *p, *pkg, *spkgs;
685 struct prop_iter ppi;
686 const char *name, *version, *arch;
688 spkgs = trans->system.set->packages.data;
689 pi = razor_package_iterator_create(trans->system.set);
690 prop_iter_init(&ppi, &trans->upstream);
692 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
693 if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
696 if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
699 pkg = pick_matching_provider(trans->upstream.set, &ppi,
700 RAZOR_PROPERTY_GREATER, version);
704 fprintf(stderr, "updating %s-%s to %s-%s\n",
706 &ppi.pool[pkg->name], &ppi.pool[pkg->version]);
708 razor_transaction_remove_package(trans, p);
709 razor_transaction_install_package(trans, pkg);
712 razor_package_iterator_destroy(pi);
716 flush_scheduled_upstream_updates(struct razor_transaction *trans)
718 struct razor_package_iterator *pi;
719 struct razor_package *p, *upkgs;
720 struct prop_iter spi;
721 const char *name, *version, *arch;
723 upkgs = trans->upstream.set->packages.data;
724 pi = razor_package_iterator_create(trans->upstream.set);
725 prop_iter_init(&spi, &trans->system);
727 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
728 if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
731 if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
732 remove_matching_providers(trans,
736 razor_transaction_install_package(trans, p);
737 fprintf(stderr, "installing %s-%s\n", name, version);
742 razor_transaction_resolve(struct razor_transaction *trans)
746 flush_scheduled_system_updates(trans);
747 flush_scheduled_upstream_updates(trans);
749 while (last < trans->changes) {
750 last = trans->changes;
751 remove_obsoleted_packages(trans);
752 mark_all_satisfied_requires(trans);
753 update_unsatisfied_packages(trans);
754 update_conflicted_packages(trans);
755 pull_in_all_requirements(trans);
756 flush_scheduled_system_updates(trans);
757 flush_scheduled_upstream_updates(trans);
760 return trans->changes;
764 describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
766 struct razor_package_iterator pi;
767 struct razor_package *pkg;
768 const char *name, *version, *arch, *pool;
770 pool = set->string_pool.data;
771 if (pool[rp->version] == '\0') {
772 razor_package_iterator_init_for_property(&pi, set, rp);
773 while (razor_package_iterator_next(&pi, &pkg,
774 &name, &version, &arch))
775 fprintf(stderr, "%s is needed by %s-%s.%s\n",
777 name, version, arch);
779 razor_package_iterator_init_for_property(&pi, set, rp);
780 while (razor_package_iterator_next(&pi, &pkg,
781 &name, &version, &arch))
782 fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
784 razor_property_relation_to_string(rp),
786 name, version, arch);
791 razor_transaction_describe(struct razor_transaction *trans)
793 struct prop_iter rpi;
794 struct razor_property *rp;
797 flush_scheduled_system_updates(trans);
798 flush_scheduled_upstream_updates(trans);
799 mark_all_satisfied_requires(trans);
802 prop_iter_init(&rpi, &trans->system);
803 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
804 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
805 describe_unsatisfied(trans->system.set, rp);
810 prop_iter_init(&rpi, &trans->upstream);
811 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
812 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
813 describe_unsatisfied(trans->upstream.set, rp);
822 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
828 struct razor_property *p;
830 prop_iter_init(&pi, &trans->system);
831 while (prop_iter_next(&pi, flags, &p)) {
832 if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
834 strcmp(&pi.pool[p->name], name) == 0 &&
835 strcmp(&pi.pool[p->version], version) == 0)
840 prop_iter_init(&pi, &trans->upstream);
841 while (prop_iter_next(&pi, flags, &p)) {
842 if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
844 strcmp(&pi.pool[p->name], name) == 0 &&
845 strcmp(&pi.pool[p->version], version) == 0)
854 razor_transaction_finish(struct razor_transaction *trans)
856 struct razor_merger *merger;
857 struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
861 s = trans->system.set->packages.data;
862 spkgs = trans->system.set->packages.data;
863 send = trans->system.set->packages.data +
864 trans->system.set->packages.size;
865 spool = trans->system.set->string_pool.data;
867 u = trans->upstream.set->packages.data;
868 upkgs = trans->upstream.set->packages.data;
869 uend = trans->upstream.set->packages.data +
870 trans->upstream.set->packages.size;
871 upool = trans->upstream.set->string_pool.data;
873 merger = razor_merger_create(trans->system.set, trans->upstream.set);
874 while (s < send || u < uend) {
875 if (s < send && u < uend)
876 cmp = strcmp(&spool[s->name], &upool[u->name]);
883 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
884 razor_merger_add_package(merger, s);
886 } else if (cmp == 0) {
887 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
888 razor_merger_add_package(merger, s);
889 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
890 razor_merger_add_package(merger, u);
895 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
896 razor_merger_add_package(merger, u);
901 razor_transaction_destroy(trans);
903 return razor_merger_finish(merger);
907 razor_transaction_destroy(struct razor_transaction *trans)
909 transaction_set_release(&trans->system);
910 transaction_set_release(&trans->upstream);