Rewrite depsolver to use a series of passes over all packages.
The big change is that we follow one step of the depedency chain for
each package to resolve in each iteration, and repeat until there are
no more possible moves. In contrast the old depsolver would try to
follow the dependency chain completely for one package at a time.
This new approach is simpler and faster, and at the same time more
roboust. Instead of knowing how one newly installed package may
affect other packages (obsoleting, pulling in new packages etc), the
new algorithm just looks at the total list of requires, provides,
obsoletes and conflicts after installing new 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>
37 #include "razor-internal.h"
40 struct razor_set_section {
46 struct razor_set_header {
49 struct razor_set_section sections[0];
52 #define RAZOR_MAGIC 0x7a7a7a7a
53 #define RAZOR_VERSION 1
55 #define RAZOR_STRING_POOL 0
56 #define RAZOR_PACKAGES 1
57 #define RAZOR_PROPERTIES 2
59 #define RAZOR_PACKAGE_POOL 4
60 #define RAZOR_PROPERTY_POOL 5
61 #define RAZOR_FILE_POOL 6
63 struct razor_package {
68 struct list_head properties;
69 struct list_head files;
72 struct razor_property {
75 enum razor_property_type type : 2;
76 enum razor_version_relation relation : 32;
78 struct list_head packages;
85 struct list_head packages;
88 #define RAZOR_ENTRY_LAST 0x80
91 struct array string_pool;
92 struct array packages;
93 struct array properties;
95 struct array package_pool;
96 struct array property_pool;
97 struct array file_pool;
98 struct razor_set_header *header;
101 struct import_entry {
106 struct import_directory {
107 uint32_t name, count;
109 struct array packages;
110 struct import_directory *last;
113 struct razor_importer {
114 struct razor_set *set;
115 struct hashtable table;
116 struct razor_package *package;
117 struct array properties;
119 struct array file_requires;
133 struct razor_set_section razor_sections[] = {
134 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
135 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
136 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
137 { RAZOR_FILES, offsetof(struct razor_set, files) },
138 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
139 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
140 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
144 razor_set_create(void)
146 struct razor_set *set;
147 struct razor_entry *e;
150 set = zalloc(sizeof *set);
152 e = array_add(&set->files, sizeof *e);
153 empty = array_add(&set->string_pool, 1);
156 e->flags = RAZOR_ENTRY_LAST;
158 list_set_empty(&e->packages);
164 razor_set_open(const char *filename)
166 struct razor_set *set;
167 struct razor_set_section *s;
172 set = zalloc(sizeof *set);
173 fd = open(filename, O_RDONLY);
174 if (fstat(fd, &stat) < 0)
176 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
177 if (set->header == MAP_FAILED) {
182 for (s = set->header->sections; ~s->type; s++) {
183 if (s->type >= ARRAY_SIZE(razor_sections))
185 if (s->type != razor_sections[s->type].type)
187 array = (void *) set + razor_sections[s->type].offset;
188 array->data = (void *) set->header + s->offset;
189 array->size = s->size;
190 array->alloc = s->size;
198 razor_set_destroy(struct razor_set *set)
205 for (i = 0; set->header->sections[i].type; i++)
207 size = set->header->sections[i].type;
208 munmap(set->header, size);
210 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
211 a = (void *) set + razor_sections[i].offset;
220 razor_set_write_to_fd(struct razor_set *set, int fd)
223 struct razor_set_header *header = (struct razor_set_header *) data;
228 memset(data, 0, sizeof data);
229 header->magic = RAZOR_MAGIC;
230 header->version = RAZOR_VERSION;
231 offset = sizeof data;
233 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
234 if (razor_sections[i].type != i)
236 a = (void *) set + razor_sections[i].offset;
237 header->sections[i].type = i;
238 header->sections[i].offset = offset;
239 header->sections[i].size = a->size;
240 offset += ALIGN(a->size, 4096);
243 header->sections[i].type = ~0;
244 header->sections[i].offset = 0;
245 header->sections[i].size = 0;
247 razor_write(fd, data, sizeof data);
248 memset(data, 0, sizeof data);
249 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
250 if (razor_sections[i].type != i)
252 a = (void *) set + razor_sections[i].offset;
253 razor_write(fd, a->data, a->size);
254 razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
261 razor_set_write(struct razor_set *set, const char *filename)
265 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
269 status = razor_set_write_to_fd(set, fd);
279 razor_build_evr(char *evr_buf, int size, const char *epoch,
280 const char *version, const char *release)
284 if (!version || !*version) {
289 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
290 len = snprintf(evr_buf, size, "%s:", epoch);
294 len = snprintf(evr_buf, size, "%s", version);
297 if (release && *release)
298 snprintf(evr_buf, size, "-%s", release);
302 razor_importer_begin_package(struct razor_importer *importer,
307 struct razor_package *p;
309 p = array_add(&importer->set->packages, sizeof *p);
310 p->name = hashtable_tokenize(&importer->table, name);
312 p->version = hashtable_tokenize(&importer->table, version);
313 p->arch = hashtable_tokenize(&importer->table, arch);
315 importer->package = p;
316 array_init(&importer->properties);
320 razor_importer_finish_package(struct razor_importer *importer)
322 list_set_array(&importer->package->properties,
323 &importer->set->property_pool,
324 &importer->properties,
327 array_release(&importer->properties);
331 razor_importer_add_property(struct razor_importer *importer,
333 enum razor_version_relation relation,
335 enum razor_property_type type)
337 struct razor_property *p;
340 p = array_add(&importer->set->properties, sizeof *p);
341 p->name = hashtable_tokenize(&importer->table, name);
344 p->relation = relation;
345 p->version = hashtable_tokenize(&importer->table, version);
346 list_set_ptr(&p->packages, importer->package -
347 (struct razor_package *) importer->set->packages.data);
349 r = array_add(&importer->properties, sizeof *r);
350 *r = p - (struct razor_property *) importer->set->properties.data;
352 if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') {
353 r = array_add(&importer->file_requires, sizeof *r);
359 razor_importer_add_file(struct razor_importer *importer, const char *name)
361 struct import_entry *e;
363 e = array_add(&importer->files, sizeof *e);
365 e->package = importer->package -
366 (struct razor_package *) importer->set->packages.data;
367 e->name = strdup(name);
370 struct razor_importer *
371 razor_importer_new(void)
373 struct razor_importer *importer;
375 importer = zalloc(sizeof *importer);
376 importer->set = razor_set_create();
377 hashtable_init(&importer->table, &importer->set->string_pool);
382 /* Destroy an importer without creating the set. */
384 razor_importer_destroy(struct razor_importer *importer)
386 /* FIXME: write this */
390 versioncmp(const char *s1, const char *s2)
396 n1 = strtol(s1, (char **) &p1, 10);
397 n2 = strtol(s2, (char **) &p2, 10);
399 /* Epoch; if one but not the other has an epoch set, default
400 * the epoch-less version to 0. */
401 res = (*p1 == ':') - (*p2 == ':');
406 } else if (res > 0) {
419 if (isdigit(*p1) && isdigit(*p2))
420 return versioncmp(p1, p2);
427 compare_packages(const void *p1, const void *p2, void *data)
429 const struct razor_package *pkg1 = p1, *pkg2 = p2;
430 struct razor_set *set = data;
431 char *pool = set->string_pool.data;
433 /* FIXME: what if the flags are different? */
434 if (pkg1->name == pkg2->name)
435 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
437 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
441 compare_properties(const void *p1, const void *p2, void *data)
443 const struct razor_property *prop1 = p1, *prop2 = p2;
444 struct razor_set *set = data;
445 char *pool = set->string_pool.data;
447 if (prop1->name != prop2->name)
448 return strcmp(&pool[prop1->name], &pool[prop2->name]);
449 else if (prop1->type != prop2->type)
450 return prop1->type - prop2->type;
451 else if (prop1->relation != prop2->relation)
452 return prop1->relation - prop2->relation;
454 return versioncmp(&pool[prop1->version], &pool[prop2->version]);
458 uniqueify_properties(struct razor_set *set)
460 struct razor_property *rp, *up, *rp_end;
461 struct array *pkgs, *p;
463 uint32_t *map, *rmap;
464 int i, count, unique;
466 count = set->properties.size / sizeof(struct razor_property);
467 map = razor_qsort_with_data(set->properties.data,
469 sizeof(struct razor_property),
473 rp_end = set->properties.data + set->properties.size;
474 rmap = malloc(count * sizeof *map);
475 pkgs = zalloc(count * sizeof *pkgs);
476 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
477 if (rp->name != up->name || rp->type != up->type ||
478 rp->relation != up->relation || rp->version != up->version) {
483 up->relation = rp->relation;
484 up->version = rp->version;
487 unique = up - (struct razor_property *) set->properties.data;
488 rmap[map[i]] = unique;
489 r = array_add(&pkgs[unique], sizeof *r);
496 set->properties.size = (void *) up - set->properties.data;
498 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
499 list_set_array(&rp->packages, &set->package_pool, p, 0);
509 compare_filenames(const void *p1, const void *p2, void *data)
511 const struct import_entry *e1 = p1;
512 const struct import_entry *e2 = p2;
513 const char *n1 = e1->name;
514 const char *n2 = e2->name;
516 /* Need to make sure that the contents of a directory
517 * are sorted immediately after it. So "foo/bar" has to
518 * sort before "foo.conf"
520 * FIXME: this is about 60% slower than strcmp
524 return *n2 == '/' ? 1 : -1;
526 return *n1 == '/' ? -1 : 1;
539 count_entries(struct import_directory *d)
541 struct import_directory *p, *end;
544 end = d->files.data + d->files.size;
548 d->count += p->count + 1;
554 serialize_files(struct razor_set *set,
555 struct import_directory *d, struct array *array)
557 struct import_directory *p, *end;
558 struct razor_entry *e = NULL;
562 end = d->files.data + d->files.size;
563 s = array->size / sizeof *e + d->files.size / sizeof *p;
565 e = array_add(array, sizeof *e);
568 e->start = p->count > 0 ? s : 0;
571 list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
572 array_release(&p->packages);
576 e->flags |= RAZOR_ENTRY_LAST;
579 end = d->files.data + d->files.size;
581 serialize_files(set, p, array);
587 remap_property_package_links(struct array *properties, uint32_t *rmap)
589 struct razor_property *p, *end;
591 end = properties->data + properties->size;
592 for (p = properties->data; p < end; p++)
593 list_remap_head(&p->packages, rmap);
597 build_file_tree(struct razor_importer *importer)
599 int count, i, length;
600 struct import_entry *filenames;
604 struct import_directory *d, root;
605 struct razor_entry *e;
607 count = importer->files.size / sizeof (struct import_entry);
608 razor_qsort_with_data(importer->files.data,
610 sizeof (struct import_entry),
614 root.name = hashtable_tokenize(&importer->table, "");
615 array_init(&root.files);
616 array_init(&root.packages);
619 filenames = importer->files.data;
620 for (i = 0; i < count; i++) {
621 f = filenames[i].name;
628 end = strchr(f, '/');
632 memcpy(dirname, f, length);
633 dirname[length] ='\0';
634 name = hashtable_tokenize(&importer->table, dirname);
635 if (d->last == NULL || d->last->name != name) {
636 d->last = array_add(&d->files, sizeof *d);
637 d->last->name = name;
638 d->last->last = NULL;
639 array_init(&d->last->files);
640 array_init(&d->last->packages);
648 r = array_add(&d->packages, sizeof *r);
649 *r = filenames[i].package;
650 free(filenames[i].name);
653 count_entries(&root);
654 e = importer->set->files.data;
656 e->flags = RAZOR_ENTRY_LAST;
657 e->start = importer->files.size ? 1 : 0;
658 list_set_empty(&e->packages);
660 serialize_files(importer->set, &root, &importer->set->files);
662 array_release(&importer->files);
665 static struct razor_entry *
666 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern);
669 list_to_array(struct list *list, struct array *array)
674 item = array_add(array, sizeof *item);
676 list = list_next(list);
681 compare_file_requires(const void *p1, const void *p2, void *data)
683 uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
684 const char *pool = data;
686 return strcmp(&pool[*f1], &pool[*f2]);
690 find_file_provides(struct razor_importer *importer)
692 struct razor_property *prop;
693 struct razor_entry *top, *entry;
694 struct razor_package *packages;
695 struct array pkgprops;
697 uint32_t *req, *req_start, *req_end;
698 uint32_t *map, *newprop;
701 pool = importer->set->string_pool.data;
702 packages = importer->set->packages.data;
703 top = importer->set->files.data;
705 req = req_start = importer->file_requires.data;
706 req_end = importer->file_requires.data + importer->file_requires.size;
707 map = razor_qsort_with_data(req, req_end - req, sizeof *req,
708 compare_file_requires, pool);
711 for (req = req_start; req < req_end; req++) {
712 if (req > req_start && req[0] == req[-1])
714 entry = find_entry(importer->set, top, &pool[*req]);
718 for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
719 prop = array_add(&importer->set->properties, sizeof *prop);
721 prop->type = RAZOR_PROPERTY_PROVIDES;
722 prop->relation = RAZOR_VERSION_EQUAL;
723 prop->version = hashtable_tokenize(&importer->table, "");
724 list_set_ptr(&prop->packages, pkg->data);
726 /* Update property list of pkg */
727 array_init(&pkgprops);
728 list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
729 newprop = array_add(&pkgprops, sizeof *newprop);
730 *newprop = prop - (struct razor_property *)importer->set->properties.data;
731 list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
732 array_release(&pkgprops);
736 array_release(&importer->file_requires);
740 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
742 struct razor_package *p, *packages;
744 struct razor_entry *e, *end;
749 count = set->packages.size / sizeof *p;
750 pkgs = zalloc(count * sizeof *pkgs);
752 end = set->files.data + set->files.size;
753 for (e = set->files.data; e < end; e++) {
754 list_remap_head(&e->packages, rmap);
755 r = list_first(&e->packages, &set->package_pool);
757 q = array_add(&pkgs[r->data], sizeof *q);
758 *q = e - (struct razor_entry *) set->files.data;
763 packages = set->packages.data;
764 for (i = 0; i < count; i++) {
765 list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
766 array_release(&pkgs[i]);
772 razor_importer_finish(struct razor_importer *importer)
774 struct razor_set *set;
775 uint32_t *map, *rmap;
778 build_file_tree(importer);
779 find_file_provides(importer);
781 map = uniqueify_properties(importer->set);
782 list_remap_pool(&importer->set->property_pool, map);
785 count = importer->set->packages.size / sizeof(struct razor_package);
786 map = razor_qsort_with_data(importer->set->packages.data,
788 sizeof(struct razor_package),
792 rmap = malloc(count * sizeof *rmap);
793 for (i = 0; i < count; i++)
797 list_remap_pool(&importer->set->package_pool, rmap);
798 build_package_file_lists(importer->set, rmap);
799 remap_property_package_links(&importer->set->properties, rmap);
803 hashtable_release(&importer->table);
809 struct razor_package_iterator {
810 struct razor_set *set;
811 struct razor_package *package, *end;
816 static struct razor_package_iterator *
817 razor_package_iterator_create_with_index(struct razor_set *set,
820 struct razor_package_iterator *pi;
822 pi = zalloc(sizeof *pi);
829 struct razor_package_iterator *
830 razor_package_iterator_create(struct razor_set *set)
832 struct razor_package_iterator *pi;
834 pi = zalloc(sizeof *pi);
836 pi->end = set->packages.data + set->packages.size;
837 pi->package = set->packages.data;
843 razor_package_iterator_init_for_property(struct razor_package_iterator *pi,
844 struct razor_set *set,
845 struct razor_property *property)
847 memset(pi, 0, sizeof *pi);
849 pi->index = list_first(&property->packages, &set->package_pool);
852 struct razor_package_iterator *
853 razor_package_iterator_create_for_property(struct razor_set *set,
854 struct razor_property *property)
858 index = list_first(&property->packages, &set->package_pool);
859 return razor_package_iterator_create_with_index(set, index);
863 razor_package_iterator_next(struct razor_package_iterator *pi,
864 struct razor_package **package,
866 const char **version,
871 struct razor_package *p, *packages;
876 } else if (pi->index) {
877 packages = pi->set->packages.data;
878 p = &packages[pi->index->data];
879 pi->index = list_next(pi->index);
885 pool = pi->set->string_pool.data;
887 *name = &pool[p->name];
888 *version = &pool[p->version];
889 *arch = &pool[p->arch];
898 razor_package_iterator_destroy(struct razor_package_iterator *pi)
906 struct razor_package *
907 razor_set_get_package(struct razor_set *set, const char *package)
909 struct razor_package_iterator *pi;
910 struct razor_package *p;
911 const char *name, *version, *arch;
913 pi = razor_package_iterator_create(set);
914 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
915 if (strcmp(package, name) == 0)
918 razor_package_iterator_destroy(pi);
923 struct razor_property_iterator {
924 struct razor_set *set;
925 struct razor_property *property, *end;
929 struct razor_property_iterator *
930 razor_property_iterator_create(struct razor_set *set,
931 struct razor_package *package)
933 struct razor_property_iterator *pi;
935 pi = zalloc(sizeof *pi);
939 pi->index = list_first(&package->properties,
940 &set->property_pool);
942 pi->property = set->properties.data;
943 pi->end = set->properties.data + set->properties.size;
950 razor_property_iterator_next(struct razor_property_iterator *pi,
951 struct razor_property **property,
953 enum razor_version_relation *relation,
954 const char **version,
955 enum razor_property_type *type)
959 struct razor_property *p, *properties;
964 } else if (pi->index) {
965 properties = pi->set->properties.data;
966 p = &properties[pi->index->data];
967 pi->index = list_next(pi->index);
973 pool = pi->set->string_pool.data;
975 *name = &pool[p->name];
976 *relation = p->relation;
977 *version = &pool[p->version];
987 razor_property_iterator_destroy(struct razor_property_iterator *pi)
992 static struct razor_entry *
993 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
995 struct razor_entry *e;
996 const char *n, *pool = set->string_pool.data;
999 e = (struct razor_entry *) set->files.data + dir->start;
1002 if (strcmp(pattern + 1, n) == 0)
1005 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
1006 pattern[len + 1] == '/') {
1007 return find_entry(set, e, pattern + len + 1);
1009 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1015 list_dir(struct razor_set *set, struct razor_entry *dir,
1016 char *prefix, const char *pattern)
1018 struct razor_entry *e;
1019 const char *n, *pool = set->string_pool.data;
1021 e = (struct razor_entry *) set->files.data + dir->start;
1024 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
1026 printf("%s/%s\n", prefix, n);
1028 char *sub = prefix + strlen (prefix);
1030 strcpy (sub + 1, n);
1031 list_dir(set, e, prefix, pattern);
1034 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1038 razor_set_list_files(struct razor_set *set, const char *pattern)
1040 struct razor_entry *e;
1041 char buffer[512], *p, *base;
1043 if (pattern == NULL || !strcmp (pattern, "/")) {
1045 list_dir(set, set->files.data, buffer, NULL);
1049 strcpy(buffer, pattern);
1050 e = find_entry(set, set->files.data, buffer);
1051 if (e && e->start > 0) {
1054 p = strrchr(buffer, '/');
1062 e = find_entry(set, set->files.data, buffer);
1064 list_dir(set, e, buffer, base);
1067 struct razor_package_iterator *
1068 razor_package_iterator_create_for_file(struct razor_set *set,
1069 const char *filename)
1071 struct razor_entry *entry;
1074 entry = find_entry(set, set->files.data, filename);
1078 index = list_first(&entry->packages, &set->package_pool);
1079 return razor_package_iterator_create_with_index(set, index);
1082 static struct list *
1083 list_package_files(struct razor_set *set, struct list *r,
1084 struct razor_entry *dir, uint32_t end,
1087 struct razor_entry *e, *f, *entries;
1088 uint32_t next, file;
1092 entries = (struct razor_entry *) set->files.data;
1093 pool = set->string_pool.data;
1095 e = entries + dir->start;
1097 if (entries + r->data == e) {
1098 printf("%s/%s\n", prefix, pool + e->name);
1105 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1107 e = entries + dir->start;
1112 if (e->flags & RAZOR_ENTRY_LAST)
1116 while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
1125 if (e->start <= file && file < next) {
1126 len = strlen(prefix);
1128 strcpy(prefix + len + 1, pool + e->name);
1129 r = list_package_files(set, r, e, next, prefix);
1132 } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
1138 razor_set_list_package_files(struct razor_set *set, const char *name)
1140 struct razor_package *package;
1145 package = razor_set_get_package(set, name);
1147 r = list_first(&package->files, &set->file_pool);
1148 end = set->files.size / sizeof (struct razor_entry);
1150 list_package_files(set, r, set->files.data, end, buffer);
1153 #define UPSTREAM_SOURCE 0x80
1156 struct razor_set *set;
1157 uint32_t *property_map;
1161 struct razor_merger {
1162 struct razor_set *set;
1163 struct hashtable table;
1164 struct source source1;
1165 struct source source2;
1168 static struct razor_merger *
1169 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
1171 struct razor_merger *merger;
1175 merger = zalloc(sizeof *merger);
1176 merger->set = razor_set_create();
1177 hashtable_init(&merger->table, &merger->set->string_pool);
1179 merger->source1.set = set1;
1180 count = set1->properties.size / sizeof (struct razor_property);
1181 size = count * sizeof merger->source1.property_map[0];
1182 merger->source1.property_map = zalloc(size);
1183 count = set1->files.size / sizeof (struct razor_entry);
1184 size = count * sizeof merger->source1.file_map[0];
1185 merger->source1.file_map = zalloc(size);
1187 merger->source2.set = set2;
1188 count = set2->properties.size / sizeof (struct razor_property);
1189 size = count * sizeof merger->source2.property_map[0];
1190 merger->source2.property_map = zalloc(size);
1191 count = set2->files.size / sizeof (struct razor_entry);
1192 size = count * sizeof merger->source2.file_map[0];
1193 merger->source2.file_map = zalloc(size);
1199 razor_merger_add_package(struct razor_merger *merger,
1200 struct razor_package *package)
1204 struct razor_package *p;
1205 struct razor_set *set1;
1206 struct source *source;
1209 set1 = merger->source1.set;
1210 if (set1->packages.data <= (void *) package &&
1211 (void *) package < set1->packages.data + set1->packages.size) {
1212 source = &merger->source1;
1215 source = &merger->source2;
1216 flags = UPSTREAM_SOURCE;
1219 pool = source->set->string_pool.data;
1220 p = array_add(&merger->set->packages, sizeof *p);
1221 p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
1223 p->version = hashtable_tokenize(&merger->table,
1224 &pool[package->version]);
1225 p->arch = hashtable_tokenize(&merger->table,
1226 &pool[package->arch]);
1228 p->properties = package->properties;
1229 r = list_first(&package->properties, &source->set->property_pool);
1231 source->property_map[r->data] = 1;
1235 p->files = package->files;
1236 r = list_first(&package->files, &source->set->file_pool);
1238 source->file_map[r->data] = 1;
1244 add_property(struct razor_merger *merger,
1245 const char *name, enum razor_version_relation relation,
1246 const char *version, int type)
1248 struct razor_property *p;
1250 p = array_add(&merger->set->properties, sizeof *p);
1251 p->name = hashtable_tokenize(&merger->table, name);
1254 p->relation = relation;
1255 p->version = hashtable_tokenize(&merger->table, version);
1257 return p - (struct razor_property *) merger->set->properties.data;
1261 merge_properties(struct razor_merger *merger)
1263 struct razor_property *p1, *p2;
1264 struct razor_set *set1, *set2;
1265 uint32_t *map1, *map2;
1266 int i, j, cmp, count1, count2;
1267 char *pool1, *pool2;
1269 set1 = merger->source1.set;
1270 set2 = merger->source2.set;
1271 map1 = merger->source1.property_map;
1272 map2 = merger->source2.property_map;
1276 pool1 = set1->string_pool.data;
1277 pool2 = set2->string_pool.data;
1279 count1 = set1->properties.size / sizeof *p1;
1280 count2 = set2->properties.size / sizeof *p2;
1281 while (i < count1 || j < count2) {
1282 if (i < count1 && map1[i] == 0) {
1286 if (j < count2 && map2[j] == 0) {
1290 p1 = (struct razor_property *) set1->properties.data + i;
1291 p2 = (struct razor_property *) set2->properties.data + j;
1292 if (i < count1 && j < count2)
1293 cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
1294 else if (i < count1)
1299 cmp = p1->type - p2->type;
1301 cmp = p1->relation - p2->relation;
1303 cmp = versioncmp(&pool1[p1->version],
1304 &pool2[p2->version]);
1306 map1[i++] = add_property(merger,
1309 &pool1[p1->version],
1311 } else if (cmp > 0) {
1312 map2[j++] = add_property(merger,
1315 &pool2[p2->version],
1318 map1[i++] = map2[j++] = add_property(merger,
1321 &pool1[p1->version],
1328 emit_properties(struct list_head *properties, struct array *source_pool,
1329 uint32_t *map, struct array *pool)
1334 r = pool->size / sizeof *q;
1335 p = list_first(properties, source_pool);
1337 q = array_add(pool, sizeof *q);
1338 q->data = map[p->data];
1339 q->flags = p->flags;
1343 list_set_ptr(properties, r);
1347 add_file(struct razor_merger *merger, const char *name)
1349 struct razor_entry *e;
1351 e = array_add(&merger->set->files, sizeof *e);
1352 e->name = hashtable_tokenize(&merger->table, name);
1356 return e - (struct razor_entry *)merger->set->files.data;
1361 fix_file_map(uint32_t *map,
1362 struct razor_entry *files,
1363 struct razor_entry *top)
1371 fix_file_map(map, files, &files[e]);
1374 } while (!(files[e++].flags & RAZOR_ENTRY_LAST));
1377 map[top - files] = 1;
1381 struct merge_directory {
1382 uint32_t merged, dir1, dir2;
1386 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
1388 struct razor_entry *root1, *root2, *mroot, *e1, *e2;
1389 struct razor_set *set1, *set2;
1390 struct array merge_stack;
1391 struct merge_directory *child_md, *end_md;
1392 uint32_t *map1, *map2, start, last;
1394 char *pool1, *pool2;
1396 set1 = merger->source1.set;
1397 set2 = merger->source2.set;
1398 map1 = merger->source1.file_map;
1399 map2 = merger->source2.file_map;
1400 pool1 = set1->string_pool.data;
1401 pool2 = set2->string_pool.data;
1402 root1 = (struct razor_entry *) set1->files.data;
1403 root2 = (struct razor_entry *) set2->files.data;
1405 array_init(&merge_stack);
1407 start = merger->set->files.size / sizeof (struct razor_entry);
1409 e1 = md->dir1 ? root1 + md->dir1 : NULL;
1410 e2 = md->dir2 ? root2 + md->dir2 : NULL;
1412 if (!e2 && !map1[e1 - root1]) {
1413 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1417 if (!e1 && !map2[e2 - root2]) {
1418 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1422 if (e1 && !map1[e1 - root1] &&
1423 e2 && !map1[e2 - root2]) {
1424 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1426 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1436 cmp = strcmp (&pool1[e1->name],
1441 if (map1[e1 - root1]) {
1442 map1[e1 - root1] = last =
1443 add_file(merger, &pool1[e1->name]);
1445 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1446 child_md->merged = last;
1447 child_md->dir1 = e1->start;
1451 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1453 } else if (cmp > 0) {
1454 if (map2[e2 - root2]) {
1455 map2[e2 - root2] = last =
1456 add_file(merger, &pool2[e2->name]);
1458 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1459 child_md->merged = last;
1461 child_md->dir2 = e2->start;
1464 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1467 map1[e1 - root1] = map2[e2- root2] = last =
1468 add_file(merger, &pool1[e1->name]);
1469 if (e1->start || e2->start) {
1470 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1471 child_md->merged = last;
1472 child_md->dir1 = e1->start;
1473 child_md->dir2 = e2->start;
1475 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1477 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1482 mroot = (struct razor_entry *)merger->set->files.data;
1484 mroot[last].flags = RAZOR_ENTRY_LAST;
1485 mroot[md->merged].start = start;
1487 mroot[md->merged].start = 0;
1489 end_md = merge_stack.data + merge_stack.size;
1490 for (child_md = merge_stack.data; child_md < end_md; child_md++)
1491 merge_one_directory(merger, child_md);
1492 array_release(&merge_stack);
1496 merge_files(struct razor_merger *merger)
1498 struct razor_entry *root;
1499 struct merge_directory md;
1500 uint32_t *map1, *map2;
1502 map1 = merger->source1.file_map;
1503 map2 = merger->source2.file_map;
1507 if (merger->source1.set->files.size) {
1508 root = (struct razor_entry *) merger->source1.set->files.data;
1510 fix_file_map(map1, root, root);
1511 md.dir1 = root->start;
1515 if (merger->source2.set->files.size) {
1516 root = (struct razor_entry *) merger->source2.set->files.data;
1518 fix_file_map(map2, root, root);
1519 md.dir2 = root->start;
1523 merge_one_directory(merger, &md);
1527 emit_files(struct list_head *files, struct array *source_pool,
1528 uint32_t *map, struct array *pool)
1533 r = pool->size / sizeof *q;
1534 p = list_first(files, source_pool);
1536 q = array_add(pool, sizeof *q);
1537 q->data = map[p->data];
1538 q->flags = p->flags;
1542 list_set_ptr(files, r);
1545 /* Rebuild property->packages maps. We can't just remap these, as a
1546 * property may have lost or gained a number of packages. Allocate an
1547 * array per property and loop through the packages and add them to
1548 * the arrays for their properties. */
1550 rebuild_property_package_lists(struct razor_set *set)
1552 struct array *pkgs, *a;
1553 struct razor_package *pkg, *pkg_end;
1554 struct razor_property *prop, *prop_end;
1559 count = set->properties.size / sizeof (struct razor_property);
1560 pkgs = zalloc(count * sizeof *pkgs);
1561 pkg_end = set->packages.data + set->packages.size;
1563 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1564 r = list_first(&pkg->properties, &set->property_pool);
1566 q = array_add(&pkgs[r->data], sizeof *q);
1567 *q = pkg - (struct razor_package *) set->packages.data;
1572 prop_end = set->properties.data + set->properties.size;
1574 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
1575 list_set_array(&prop->packages, &set->package_pool, a, 0);
1582 rebuild_file_package_lists(struct razor_set *set)
1584 struct array *pkgs, *a;
1585 struct razor_package *pkg, *pkg_end;
1586 struct razor_entry *entry, *entry_end;
1591 count = set->files.size / sizeof (struct razor_entry);
1592 pkgs = zalloc(count * sizeof *pkgs);
1593 pkg_end = set->packages.data + set->packages.size;
1595 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1596 r = list_first(&pkg->files, &set->file_pool);
1598 q = array_add(&pkgs[r->data], sizeof *q);
1599 *q = pkg - (struct razor_package *) set->packages.data;
1604 entry_end = set->files.data + set->files.size;
1606 for (entry = set->files.data; entry < entry_end; entry++, a++) {
1607 list_set_array(&entry->packages, &set->package_pool, a, 0);
1613 static struct razor_set *
1614 razor_merger_finish(struct razor_merger *merger)
1616 struct razor_set *result;
1617 struct razor_package *p, *pend;
1619 /* As we built the package list, we filled out a bitvector of
1620 * the properties that are referenced by the packages in the
1621 * new set. Now we do a parallel loop through the properties
1622 * and emit those marked in the bit vector to the new set. In
1623 * the process, we update the bit vector to actually map from
1624 * indices in the old property list to indices in the new
1625 * property list for both sets. */
1627 merge_properties(merger);
1628 merge_files(merger);
1630 /* Now we loop through the packages again and emit the
1631 * property lists, remapped to point to the new properties. */
1633 pend = merger->set->packages.data + merger->set->packages.size;
1634 for (p = merger->set->packages.data; p < pend; p++) {
1637 if (p->flags & UPSTREAM_SOURCE)
1638 src = &merger->source2;
1640 src = &merger->source1;
1642 emit_properties(&p->properties,
1643 &src->set->property_pool,
1645 &merger->set->property_pool);
1646 emit_files(&p->files,
1647 &src->set->file_pool,
1649 &merger->set->file_pool);
1650 p->flags &= ~UPSTREAM_SOURCE;
1653 rebuild_property_package_lists(merger->set);
1654 rebuild_file_package_lists(merger->set);
1656 result = merger->set;
1657 hashtable_release(&merger->table);
1663 /* The diff order matters. We should sort the packages so that a
1664 * REMOVE of a package comes before the INSTALL, and so that all
1665 * requires for a package have been installed before the package.
1669 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1670 razor_package_callback_t callback, void *data)
1672 struct razor_package_iterator *pi1, *pi2;
1673 struct razor_package *p1, *p2;
1674 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
1677 pi1 = razor_package_iterator_create(set);
1678 pi2 = razor_package_iterator_create(upstream);
1680 razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
1681 razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
1685 res = strcmp(name1, name2);
1687 res = versioncmp(version1, version2);
1692 if (p2 == NULL || res < 0)
1693 callback(name1, version1, NULL, arch1, data);
1694 else if (p1 == NULL || res > 0)
1695 callback(name2, NULL, version2, arch2, data);
1697 if (p1 != NULL && res <= 0)
1698 razor_package_iterator_next(pi1, &p1,
1699 &name1, &version1, &arch1);
1700 if (p2 != NULL && res >= 0)
1701 razor_package_iterator_next(pi2, &p2,
1702 &name2, &version2, &arch2);
1705 razor_package_iterator_destroy(pi1);
1706 razor_package_iterator_destroy(pi2);
1710 provider_satisfies_requirement(struct razor_property *provider,
1711 const char *provider_strings,
1712 enum razor_version_relation relation,
1713 const char *required)
1716 const char *provided = &provider_strings[provider->version];
1721 if (relation >= RAZOR_VERSION_EQUAL)
1727 cmp = versioncmp(provided, required);
1730 case RAZOR_VERSION_LESS:
1733 case RAZOR_VERSION_LESS_OR_EQUAL:
1736 /* fall through: FIXME, make sure this is correct */
1738 case RAZOR_VERSION_EQUAL:
1742 /* "foo == 1.1" is satisfied by "foo 1.1-2" */
1743 len = strlen(required);
1744 if (!strncmp(required, provided, len) && provided[len] == '-')
1748 case RAZOR_VERSION_GREATER_OR_EQUAL:
1751 case RAZOR_VERSION_GREATER:
1755 /* shouldn't happen */
1759 #define TRANS_PACKAGE_PRESENT 1
1760 #define TRANS_PACKAGE_UPDATE 2
1761 #define TRANS_PROPERTY_SATISFIED 0x80000000
1763 struct transaction_set {
1764 struct razor_set *set;
1766 uint32_t *properties;
1769 struct razor_transaction {
1770 int package_count, errors;
1771 struct transaction_set system, upstream;
1776 transaction_set_init(struct transaction_set *ts, struct razor_set *set)
1781 count = set->packages.size / sizeof (struct razor_package);
1782 ts->packages = zalloc(count * sizeof *ts->packages);
1783 count = set->properties.size / sizeof (struct razor_property);
1784 ts->properties = zalloc(count * sizeof *ts->properties);
1788 transaction_set_release(struct transaction_set *ts)
1791 free(ts->properties);
1795 transaction_set_install_package(struct transaction_set *ts,
1796 struct razor_package *package)
1798 struct razor_package *pkgs;
1802 pkgs = ts->set->packages.data;
1804 if (ts->packages[i] == TRANS_PACKAGE_PRESENT)
1807 ts->packages[i] = TRANS_PACKAGE_PRESENT;
1809 prop = list_first(&package->properties, &ts->set->property_pool);
1811 ts->properties[prop->data]++;
1812 prop = list_next(prop);
1817 transaction_set_remove_package(struct transaction_set *ts,
1818 struct razor_package *package)
1820 struct razor_package *pkgs;
1824 pkgs = ts->set->packages.data;
1826 if (ts->packages[i] == 0)
1829 ts->packages[i] = 0;
1831 prop = list_first(&package->properties, &ts->set->property_pool);
1833 ts->properties[prop->data]--;
1834 prop = list_next(prop);
1838 struct razor_transaction *
1839 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
1841 struct razor_transaction *trans;
1842 struct razor_package *p, *spkgs, *pend;
1844 trans = zalloc(sizeof *trans);
1845 transaction_set_init(&trans->system, system);
1846 transaction_set_init(&trans->upstream, upstream);
1848 spkgs = trans->system.set->packages.data;
1849 pend = trans->system.set->packages.data +
1850 trans->system.set->packages.size;
1851 for (p = spkgs; p < pend; p++)
1852 transaction_set_install_package(&trans->system, p);
1858 razor_transaction_install_package(struct razor_transaction *trans,
1859 struct razor_package *package)
1861 transaction_set_install_package(&trans->upstream, package);
1866 razor_transaction_remove_package(struct razor_transaction *trans,
1867 struct razor_package *package)
1869 transaction_set_remove_package(&trans->system, package);
1874 razor_transaction_update_package(struct razor_transaction *trans,
1875 struct razor_package *package)
1877 struct razor_package *spkgs;
1879 spkgs = trans->system.set->packages.data;
1880 trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
1884 struct razor_property *p, *start, *end;
1890 prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
1892 pi->p = ts->set->properties.data;
1893 pi->start = ts->set->properties.data;
1894 pi->end = ts->set->properties.data + ts->set->properties.size;
1895 pi->pool = ts->set->string_pool.data;
1896 pi->present = ts->properties;
1900 prop_iter_next(struct prop_iter *pi,
1901 enum razor_property_type type, struct razor_property **p)
1903 while (pi->p < pi->end) {
1904 if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
1905 pi->p->type == type) {
1915 static struct razor_property *
1916 prop_iter_seek_to(struct prop_iter *pi,
1917 enum razor_property_type type, const char *match)
1921 while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
1924 if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
1928 while (pi->p < pi->end &&
1929 pi->p->name == name &&
1930 pi->p->type != type)
1933 if (pi->p == pi->end || pi->p->name != name)
1939 /* Remove packages from set that provide any of the matching (same
1940 * name and type) providers from ppi onwards that match the
1941 * requirement that rpi points to. */
1943 remove_matching_providers(struct razor_transaction *trans,
1944 struct prop_iter *ppi,
1945 enum razor_version_relation relation,
1946 const char *version)
1948 struct razor_property *p;
1949 struct razor_package *pkg, *pkgs;
1950 struct razor_package_iterator pkg_iter;
1951 struct razor_set *set;
1952 const char *n, *v, *a;
1954 if (ppi->present == trans->system.properties)
1955 set = trans->system.set;
1957 set = trans->upstream.set;
1959 pkgs = (struct razor_package *) set->packages.data;
1962 p->name == ppi->p->name &&
1963 p->type == ppi->p->type;
1965 if (!ppi->present[p - ppi->start])
1967 if (!provider_satisfies_requirement(p, ppi->pool,
1971 razor_package_iterator_init_for_property(&pkg_iter, set, p);
1972 while (razor_package_iterator_next(&pkg_iter,
1973 &pkg, &n, &v, &a)) {
1974 fprintf(stderr, "removing %s-%s\n", n, v);
1975 razor_transaction_remove_package(trans, pkg);
1981 flag_matching_providers(struct razor_transaction *trans,
1982 struct prop_iter *ppi,
1983 struct razor_property *r,
1984 struct prop_iter *rpi,
1987 struct razor_property *p;
1988 struct razor_package *pkg, *pkgs;
1989 struct razor_package_iterator pkg_iter;
1990 struct razor_set *set;
1991 const char *name, *version, *arch;
1994 if (ppi->present == trans->system.properties) {
1995 set = trans->system.set;
1996 flags = trans->system.packages;
1998 set = trans->upstream.set;
1999 flags = trans->upstream.packages;
2002 pkgs = (struct razor_package *) set->packages.data;
2005 p->name == ppi->p->name &&
2006 p->type == ppi->p->type;
2008 if (!ppi->present[p - ppi->start])
2010 if (!provider_satisfies_requirement(p, ppi->pool,
2012 &rpi->pool[r->version]))
2015 razor_package_iterator_init_for_property(&pkg_iter, set, p);
2016 while (razor_package_iterator_next(&pkg_iter, &pkg,
2017 &name, &version, &arch)) {
2019 fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
2021 ppi->pool + p->name,
2022 rpi->pool + r->name,
2023 rpi->pool + r->version);
2024 flags[pkg - pkgs] |= flag;
2029 static struct razor_package *
2030 pick_matching_provider(struct razor_set *set,
2031 struct prop_iter *ppi,
2032 enum razor_version_relation relation,
2033 const char *version)
2035 struct razor_property *p;
2036 struct razor_package *pkgs;
2039 /* This is where we decide which pkgs to pull in to satisfy a
2040 * requirement. There may be several different providers
2041 * (different versions) and each version of a provider may
2042 * come from a number of packages. We pick the first package
2043 * from the first provider that matches. */
2045 pkgs = set->packages.data;
2048 p->name == ppi->p->name &&
2049 p->type == ppi->p->type &&
2050 ppi->present[p - ppi->start] == 0;
2052 if (!provider_satisfies_requirement(p, ppi->pool,
2056 i = list_first(&p->packages, &set->package_pool);
2058 return &pkgs[i->data];
2065 remove_obsoleted_packages(struct razor_transaction *trans)
2067 struct razor_property *up;
2068 struct razor_package *spkgs;
2069 struct prop_iter spi, upi;
2071 spkgs = trans->system.set->packages.data;
2072 prop_iter_init(&spi, &trans->system);
2073 prop_iter_init(&upi, &trans->upstream);
2075 while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
2076 if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
2077 &upi.pool[up->name]))
2079 remove_matching_providers(trans, &spi, up->relation,
2080 &upi.pool[up->version]);
2085 any_provider_satisfies_requirement(struct prop_iter *ppi,
2086 enum razor_version_relation relation,
2087 const char *version)
2089 struct razor_property *p;
2093 p->name == ppi->p->name &&
2094 p->type == ppi->p->type;
2096 if (ppi->present[p - ppi->start] > 0 &&
2097 provider_satisfies_requirement(p, ppi->pool,
2106 clear_requires_flags(struct transaction_set *ts)
2108 struct razor_property *p;
2112 count = ts->set->properties.size / sizeof *p;
2113 p = ts->set->properties.data;
2114 pool = ts->set->string_pool.data;
2115 for (i = 0; i < count; i++) {
2116 ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
2117 if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
2118 ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
2123 mark_satisfied_requires(struct razor_transaction *trans,
2124 struct transaction_set *rts,
2125 struct transaction_set *pts)
2127 struct prop_iter rpi, ppi;
2128 struct razor_property *rp;
2130 prop_iter_init(&rpi, rts);
2131 prop_iter_init(&ppi, pts);
2133 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2134 if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
2135 &rpi.pool[rp->name]))
2138 if (any_provider_satisfies_requirement(&ppi, rp->relation,
2139 &rpi.pool[rp->version]))
2140 rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
2144 static const char *relation_string[] = { "<", "<=", "=", ">=", ">" };
2147 mark_all_satisfied_requires(struct razor_transaction *trans)
2149 struct razor_property *sp;
2150 struct prop_iter spi;
2152 clear_requires_flags(&trans->system);
2153 clear_requires_flags(&trans->upstream);
2154 mark_satisfied_requires(trans, &trans->system, &trans->system);
2155 mark_satisfied_requires(trans, &trans->system, &trans->upstream);
2156 mark_satisfied_requires(trans, &trans->upstream, &trans->system);
2157 mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
2159 prop_iter_init(&spi, &trans->system);
2160 while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
2161 if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
2163 fprintf(stderr, "unsatisfied system requires: %s %s %s\n",
2164 spi.pool + sp->name,
2165 relation_string[sp->relation],
2166 spi.pool + sp->version);
2169 prop_iter_init(&spi, &trans->upstream);
2170 while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
2171 if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
2173 fprintf(stderr, "unsatisfied upstream requires: %s %s %s\n",
2174 spi.pool + sp->name,
2175 relation_string[sp->relation],
2176 spi.pool + sp->version);
2181 update_unsatisfied_packages(struct razor_transaction *trans)
2183 struct razor_package *spkgs, *pkg;
2184 struct razor_property *sp;
2185 struct prop_iter spi;
2186 struct razor_package_iterator pkg_iter;
2187 const char *name, *version, *arch;
2189 spkgs = trans->system.set->packages.data;
2190 prop_iter_init(&spi, &trans->system);
2192 while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
2193 if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
2196 razor_package_iterator_init_for_property(&pkg_iter,
2199 while (razor_package_iterator_next(&pkg_iter, &pkg,
2200 &name, &version, &arch)) {
2201 fprintf(stderr, "updating %s because %s %s %s "
2202 "isn't satisfied\n",
2203 name, spi.pool + sp->name,
2204 relation_string[sp->relation],
2205 spi.pool + sp->version);
2206 trans->system.packages[pkg - spkgs] |=
2207 TRANS_PACKAGE_UPDATE;
2213 razor_transaction_update_all(struct razor_transaction *trans)
2215 struct razor_package *p;
2218 count = trans->system.set->packages.size / sizeof *p;
2219 for (i = 0; i < count; i++)
2220 trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
2224 update_conflicted_packages(struct razor_transaction *trans)
2226 struct razor_package *pkg, *spkgs;
2227 struct razor_property *up, *sp;
2228 struct prop_iter spi, upi;
2229 struct razor_package_iterator pkg_iter;
2230 const char *name, *version, *arch;
2232 spkgs = trans->system.set->packages.data;
2233 prop_iter_init(&spi, &trans->system);
2234 prop_iter_init(&upi, &trans->upstream);
2236 while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
2237 if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
2238 &spi.pool[sp->name]))
2241 if (!any_provider_satisfies_requirement(&upi, sp->relation,
2242 &spi.pool[sp->version]))
2245 razor_package_iterator_init_for_property(&pkg_iter,
2248 while (razor_package_iterator_next(&pkg_iter, &pkg,
2249 &name, &version, &arch)) {
2250 fprintf(stderr, "updating %s %s because it conflicts with %s",
2251 name, version, spi.pool + sp->name);
2252 trans->system.packages[pkg - spkgs] |=
2253 TRANS_PACKAGE_UPDATE;
2257 prop_iter_init(&spi, &trans->system);
2258 prop_iter_init(&upi, &trans->upstream);
2260 while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
2261 sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
2262 &upi.pool[upi.p->name]);
2265 flag_matching_providers(trans, &spi, up, &upi,
2266 TRANS_PACKAGE_UPDATE);
2271 pull_in_requirements(struct razor_transaction *trans,
2272 struct prop_iter *rpi, struct prop_iter *ppi)
2274 struct razor_property *rp, *pp;
2275 struct razor_package *pkg, *upkgs;
2277 upkgs = trans->upstream.set->packages.data;
2278 while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2279 if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
2282 pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
2283 &rpi->pool[rp->name]);
2286 pkg = pick_matching_provider(trans->upstream.set,
2288 &rpi->pool[rp->version]);
2292 rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
2294 fprintf(stderr, "pulling in %s which provides %s %s %s "
2295 "to satisfy %s %s %s\n",
2296 ppi->pool + pkg->name,
2297 ppi->pool + pp->name,
2298 relation_string[pp->relation],
2299 ppi->pool + pp->version,
2300 &rpi->pool[rp->name],
2301 relation_string[rp->relation],
2302 &rpi->pool[rp->version]);
2304 trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
2309 pull_in_all_requirements(struct razor_transaction *trans)
2311 struct prop_iter rpi, ppi;
2312 struct razor_property *rp;
2314 prop_iter_init(&rpi, &trans->system);
2315 prop_iter_init(&ppi, &trans->upstream);
2316 pull_in_requirements(trans, &rpi, &ppi);
2318 prop_iter_init(&rpi, &trans->upstream);
2319 prop_iter_init(&ppi, &trans->upstream);
2320 pull_in_requirements(trans, &rpi, &ppi);
2322 prop_iter_init(&rpi, &trans->system);
2323 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2324 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED))
2325 fprintf(stderr, "could not satisfy req %s %s %s\n",
2326 &rpi.pool[rp->name],
2327 relation_string[rp->relation],
2328 &rpi.pool[rp->version]);
2331 prop_iter_init(&rpi, &trans->upstream);
2332 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2333 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED))
2334 fprintf(stderr, "could not satisfy req %s %s %s\n",
2335 &rpi.pool[rp->name],
2336 relation_string[rp->relation],
2337 &rpi.pool[rp->version]);
2342 flush_scheduled_system_updates(struct razor_transaction *trans)
2344 struct razor_package_iterator *pi;
2345 struct razor_package *p, *pkg, *spkgs;
2346 struct prop_iter ppi;
2347 const char *name, *version, *arch;
2349 spkgs = trans->system.set->packages.data;
2350 pi = razor_package_iterator_create(trans->system.set);
2351 prop_iter_init(&ppi, &trans->upstream);
2353 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
2354 if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
2357 if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name)) {
2358 fprintf(stderr, "nothing provides %s\n", name);
2362 pkg = pick_matching_provider(trans->upstream.set, &ppi,
2363 RAZOR_VERSION_GREATER, version);
2366 "no newer version of %s available\n", name);
2370 fprintf(stderr, "updating %s from %s to %s\n",
2371 name, version, &ppi.pool[pkg->version]);
2373 razor_transaction_remove_package(trans, p);
2374 razor_transaction_install_package(trans, pkg);
2377 razor_package_iterator_destroy(pi);
2381 flush_scheduled_upstream_updates(struct razor_transaction *trans)
2383 struct razor_package_iterator *pi;
2384 struct razor_package *p, *upkgs;
2385 struct prop_iter spi;
2386 const char *name, *version, *arch;
2388 upkgs = trans->upstream.set->packages.data;
2389 pi = razor_package_iterator_create(trans->upstream.set);
2390 prop_iter_init(&spi, &trans->system);
2392 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
2393 if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
2396 if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
2398 remove_matching_providers(trans, &spi,
2399 RAZOR_VERSION_LESS, version);
2400 razor_transaction_install_package(trans, p);
2401 fprintf(stderr, "installing %s-%s\n", name, version);
2406 razor_transaction_resolve(struct razor_transaction *trans)
2410 flush_scheduled_system_updates(trans);
2412 while (last < trans->changes) {
2413 last = trans->changes;
2414 remove_obsoleted_packages(trans);
2415 mark_all_satisfied_requires(trans);
2416 update_unsatisfied_packages(trans);
2417 update_conflicted_packages(trans);
2418 pull_in_all_requirements(trans);
2419 flush_scheduled_system_updates(trans);
2420 flush_scheduled_upstream_updates(trans);
2423 return trans->changes;
2427 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
2429 enum razor_version_relation rel,
2430 const char *version,
2431 enum razor_property_type type)
2433 struct prop_iter pi;
2434 struct razor_property *p;
2436 prop_iter_init(&pi, &trans->system);
2437 while (prop_iter_next(&pi, type, &p)) {
2438 if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
2439 p->relation == rel &&
2440 strcmp(&pi.pool[p->name], name) == 0 &&
2441 strcmp(&pi.pool[p->version], version) == 0)
2446 prop_iter_init(&pi, &trans->upstream);
2447 while (prop_iter_next(&pi, type, &p)) {
2448 if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
2449 p->relation == rel &&
2450 strcmp(&pi.pool[p->name], name) == 0 &&
2451 strcmp(&pi.pool[p->version], version) == 0)
2460 razor_transaction_finish(struct razor_transaction *trans)
2462 struct razor_merger *merger;
2463 struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
2464 char *upool, *spool;
2467 s = trans->system.set->packages.data;
2468 spkgs = trans->system.set->packages.data;
2469 send = trans->system.set->packages.data +
2470 trans->system.set->packages.size;
2471 spool = trans->system.set->string_pool.data;
2473 u = trans->upstream.set->packages.data;
2474 upkgs = trans->upstream.set->packages.data;
2475 uend = trans->upstream.set->packages.data +
2476 trans->upstream.set->packages.size;
2477 upool = trans->upstream.set->string_pool.data;
2479 merger = razor_merger_create(trans->system.set, trans->upstream.set);
2480 while (s < send || u < uend) {
2481 if (s < send && u < uend)
2482 cmp = strcmp(&spool[s->name], &upool[u->name]);
2489 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
2490 razor_merger_add_package(merger, s);
2492 } else if (cmp == 0) {
2493 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
2494 razor_merger_add_package(merger, s);
2495 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
2496 razor_merger_add_package(merger, u);
2501 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
2502 razor_merger_add_package(merger, u);
2507 razor_transaction_destroy(trans);
2509 return razor_merger_finish(merger);
2513 razor_transaction_destroy(struct razor_transaction *trans)
2515 transaction_set_release(&trans->system);
2516 transaction_set_release(&trans->upstream);
2519 /* FIXME: free upstream if it was created as an empty set */
2522 struct razor_package_query {
2523 struct razor_set *set;
2528 struct razor_package_query *
2529 razor_package_query_create(struct razor_set *set)
2531 struct razor_package_query *pq;
2534 pq = zalloc(sizeof *pq);
2536 count = set->packages.size / sizeof(struct razor_package);
2537 pq->vector = zalloc(count * sizeof(char));
2543 razor_package_query_add_package(struct razor_package_query *pq,
2544 struct razor_package *p)
2546 struct razor_package *packages;
2548 packages = pq->set->packages.data;
2549 pq->count += pq->vector[p - packages] ^ 1;
2550 pq->vector[p - packages] = 1;
2554 razor_package_query_add_iterator(struct razor_package_query *pq,
2555 struct razor_package_iterator *pi)
2557 struct razor_package *packages, *p;
2558 const char *name, *version, *arch;
2560 packages = pq->set->packages.data;
2561 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
2562 pq->count += pq->vector[p - packages] ^ 1;
2563 pq->vector[p - packages] = 1;
2567 struct razor_package_iterator *
2568 razor_package_query_finish(struct razor_package_query *pq)
2570 struct razor_package_iterator *pi;
2571 struct razor_set *set;
2576 count = set->packages.size / sizeof(struct razor_package);
2577 index = zalloc(pq->count * sizeof *index);
2579 for (i = 0, j = 0; i < count; i++) {
2584 if (j == pq->count - 1)
2585 index[j].flags = 0x80;
2591 pi = razor_package_iterator_create_with_index(set, index);