Implement linear package set merger.
17 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
24 struct razor_set_section {
30 struct razor_set_header {
33 struct razor_set_section sections[0];
36 #define RAZOR_MAGIC 0x7a7a7a7a
37 #define RAZOR_VERSION 1
39 #define RAZOR_PACKAGES 0
40 #define RAZOR_REQUIRES 1
41 #define RAZOR_PROVIDES 2
42 #define RAZOR_STRING_POOL 3
43 #define RAZOR_PACKAGE_POOL 4
44 #define RAZOR_REQUIRES_POOL 5
45 #define RAZOR_PROVIDES_POOL 6
47 struct razor_package {
49 unsigned long version;
50 unsigned long requires;
51 unsigned long provides;
54 struct razor_property {
56 unsigned long version;
57 unsigned long packages;
61 struct array string_pool;
62 struct array packages;
63 struct array package_pool;
64 struct array requires;
65 struct array provides;
66 struct array requires_pool;
67 struct array provides_pool;
68 struct razor_set_header *header;
71 struct import_property_context {
76 struct razor_importer {
77 struct razor_set *set;
79 struct import_property_context requires;
80 struct import_property_context provides;
81 struct razor_package *package;
85 array_init(struct array *array)
87 memset(array, 0, sizeof *array);
91 array_release(struct array *array)
97 array_add(struct array *array, int size)
102 if (array->alloc > 0)
103 alloc = array->alloc;
107 while (alloc < array->size + size)
110 if (array->alloc < alloc) {
111 data = realloc(array->data, alloc);
115 array->alloc = alloc;
118 p = array->data + array->size;
125 write_to_fd(int fd, void *p, size_t size)
131 len = write(fd, p, rest);
151 struct razor_set_section razor_sections[] = {
152 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
153 { RAZOR_REQUIRES, offsetof(struct razor_set, requires) },
154 { RAZOR_PROVIDES, offsetof(struct razor_set, provides) },
155 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
156 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
157 { RAZOR_REQUIRES_POOL, offsetof(struct razor_set, requires_pool) },
158 { RAZOR_PROVIDES_POOL, offsetof(struct razor_set, provides_pool) },
162 razor_set_create(void)
164 return zalloc(sizeof(struct razor_set));
168 razor_set_open(const char *filename)
170 struct razor_set *set;
171 struct razor_set_section *s;
176 set = zalloc(sizeof *set);
177 fd = open(filename, O_RDONLY);
178 if (fstat(fd, &stat) < 0)
180 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
181 if (set->header == MAP_FAILED) {
186 for (s = set->header->sections; ~s->type; s++) {
187 if (s->type >= ARRAY_SIZE(razor_sections))
189 if (s->type != razor_sections[s->type].type)
191 array = (void *) set + razor_sections[s->type].offset;
192 array->data = (void *) set->header + s->offset;
193 array->size = s->size;
194 array->alloc = s->size;
202 razor_set_destroy(struct razor_set *set)
209 for (i = 0; set->header->sections[i].type; i++)
211 size = set->header->sections[i].type;
212 munmap(set->header, size);
214 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
215 a = (void *) set + razor_sections[i].offset;
224 razor_set_write(struct razor_set *set, const char *filename)
227 struct razor_set_header *header = (struct razor_set_header *) data;
229 unsigned long offset;
232 memset(data, 0, sizeof data);
233 header->magic = RAZOR_MAGIC;
234 header->version = RAZOR_VERSION;
235 offset = sizeof data;
237 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
238 if (razor_sections[i].type != i)
240 a = (void *) set + razor_sections[i].offset;
241 header->sections[i].type = i;
242 header->sections[i].offset = offset;
243 header->sections[i].size = a->size;
244 offset += (a->size + 4095) & ~4095;
247 header->sections[i].type = ~0;
248 header->sections[i].offset = 0;
249 header->sections[i].size = 0;
251 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
255 write_to_fd(fd, data, sizeof data);
256 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
257 if (razor_sections[i].type != i)
259 a = (void *) set + razor_sections[i].offset;
260 write_to_fd(fd, a->data, (a->size + 4095) & ~4095);
269 hash_string(const char *key)
272 unsigned int hash = 0;
274 for (p = key; *p; p++)
275 hash = (hash * 617) ^ *p;
281 razor_importer_lookup(struct razor_importer *importer, const char *key)
283 unsigned int mask, start, i;
287 pool = importer->set->string_pool.data;
288 mask = importer->buckets.alloc - 1;
289 start = hash_string(key) * sizeof(unsigned long);
291 for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
292 b = importer->buckets.data + ((start + i) & mask);
297 if (strcmp(key, &pool[*b]) == 0)
305 add_to_string_pool(struct razor_set *set, const char *key)
310 len = strlen(key) + 1;
311 p = array_add(&set->string_pool, len);
314 return p - (char *) set->string_pool.data;
318 add_to_property_pool(struct array *pool, struct array *properties)
322 p = array_add(properties, sizeof *p);
324 p = array_add(pool, properties->size);
325 memcpy(p, properties->data, properties->size);
327 return p - (unsigned long *) pool->data;
331 do_insert(struct razor_importer *importer, unsigned long value)
333 unsigned int mask, start, i;
337 key = (char *) importer->set->string_pool.data + value;
338 mask = importer->buckets.alloc - 1;
339 start = hash_string(key) * sizeof(unsigned long);
341 for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
342 b = importer->buckets.data + ((start + i) & mask);
351 razor_importer_insert(struct razor_importer *importer, const char *key)
353 unsigned long value, *buckets, *b, *end;
356 alloc = importer->buckets.alloc;
357 array_add(&importer->buckets, 4 * sizeof *buckets);
358 if (alloc != importer->buckets.alloc) {
359 end = importer->buckets.data + alloc;
360 memset(end, 0, importer->buckets.alloc - alloc);
361 for (b = importer->buckets.data; b < end; b++) {
365 do_insert(importer, value);
370 value = add_to_string_pool(importer->set, key);
371 do_insert (importer, value);
377 razor_importer_tokenize(struct razor_importer *importer, const char *string)
382 return razor_importer_tokenize(importer, "");
384 token = razor_importer_lookup(importer, string);
388 return razor_importer_insert(importer, string);
392 razor_importer_begin_package(struct razor_importer *importer,
393 const char *name, const char *version)
395 struct razor_package *p;
397 p = array_add(&importer->set->packages, sizeof *p);
398 p->name = razor_importer_tokenize(importer, name);
399 p->version = razor_importer_tokenize(importer, version);
401 importer->package = p;
402 array_init(&importer->requires.package);
403 array_init(&importer->provides.package);
407 razor_importer_finish_package(struct razor_importer *importer)
409 struct razor_package *p;
411 p = importer->package;
412 p->requires = add_to_property_pool(&importer->set->requires_pool,
413 &importer->requires.package);
414 p->provides = add_to_property_pool(&importer->set->provides_pool,
415 &importer->provides.package);
417 array_release(&importer->requires.package);
418 array_release(&importer->provides.package);
422 razor_importer_add_property(struct razor_importer *importer,
423 struct import_property_context *pctx,
424 const char *name, const char *version)
426 struct razor_property *p;
429 p = array_add(pctx->all, sizeof *p);
430 p->name = razor_importer_tokenize(importer, name);
431 p->version = razor_importer_tokenize(importer, version);
432 p->packages = importer->package -
433 (struct razor_package *) importer->set->packages.data;
435 r = array_add(&pctx->package, sizeof *r);
436 *r = p - (struct razor_property *) pctx->all->data;
440 razor_importer_add_requires(struct razor_importer *importer,
441 const char *name, const char *version)
443 razor_importer_add_property(importer,
444 &importer->requires, name, version);
448 razor_importer_add_provides(struct razor_importer *importer,
449 const char *name, const char *version)
451 razor_importer_add_property(importer,
452 &importer->provides, name, version);
455 struct razor_importer *
456 razor_importer_new(void)
458 struct razor_importer *importer;
460 importer = zalloc(sizeof *importer);
461 importer->set = razor_set_create();
462 importer->requires.all = &importer->set->requires;
463 importer->provides.all = &importer->set->provides;
468 typedef int (*compare_with_data_func_t)(const void *p1,
472 struct qsort_context {
474 compare_with_data_func_t compare;
479 qsort_swap(void *p1, void *p2, size_t size)
483 memcpy(buffer, p1, size);
484 memcpy(p1, p2, size);
485 memcpy(p2, buffer, size);
489 __qsort_with_data(void *base, size_t nelem, unsigned long *map,
490 struct qsort_context *ctx)
492 void *p, *start, *end, *pivot;
493 unsigned long *mp, *mstart, *mend, tmp;
494 int left, right, result;
495 size_t size = ctx->size;
499 end = base + nelem * size;
503 pivot = base + (random() % nelem) * size;
506 result = ctx->compare(p, pivot, ctx->data);
508 qsort_swap(p, start, size);
518 } else if (result == 0) {
524 qsort_swap(p, end, size);
533 left = (start - base) / size;
534 right = (base + nelem * size - end) / size;
536 __qsort_with_data(base, left, map, ctx);
538 __qsort_with_data(end, right, mend, ctx);
542 qsort_with_data(void *base, size_t nelem, size_t size,
543 compare_with_data_func_t compare, void *data)
545 struct qsort_context ctx;
550 ctx.compare = compare;
553 map = malloc(nelem * sizeof (unsigned long));
554 for (i = 0; i < nelem; i++)
557 __qsort_with_data(base, nelem, map, &ctx);
563 versioncmp(const char *s1, const char *s2)
569 n1 = strtol(s1, (char **) &p1, 0);
570 n2 = strtol(s2, (char **) &p2, 0);
572 /* Epoch; if one but not the other has an epoch set, default
573 * the epoch-less version to 0. */
574 res = (*p1 == ':') - (*p2 == ':');
579 } else if (res > 0) {
592 if (isdigit(*p1) && isdigit(*p2))
593 return versioncmp(p1, p2);
601 compare_packages(const void *p1, const void *p2, void *data)
603 const struct razor_package *pkg1 = p1, *pkg2 = p2;
604 struct razor_set *set = data;
605 char *pool = set->string_pool.data;
607 if (pkg1->name == pkg2->name)
608 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
610 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
614 compare_properties(const void *p1, const void *p2, void *data)
616 const struct razor_property *prop1 = p1, *prop2 = p2;
617 struct razor_set *set = data;
618 char *pool = set->string_pool.data;
620 if (prop1->name == prop2->name)
621 return versioncmp(&pool[prop1->version], &pool[prop2->version]);
623 return strcmp(&pool[prop1->name], &pool[prop2->name]);
626 static unsigned long *
627 uniqueify_properties(struct razor_set *set, struct array *properties)
629 struct razor_property *rp, *up, *rp_end;
630 struct array *pkgs, *p;
631 unsigned long *map, *rmap, *r;
632 int i, count, unique;
634 count = properties->size / sizeof(struct razor_property);
635 map = qsort_with_data(properties->data,
637 sizeof(struct razor_property),
641 rp_end = properties->data + properties->size;
642 rmap = malloc(count * sizeof *map);
643 pkgs = zalloc(count * sizeof *pkgs);
644 for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) {
645 if (rp->name != up->name || rp->version != up->version) {
648 up->version = rp->version;
651 unique = up - (struct razor_property *) properties->data;
652 rmap[map[i]] = unique;
653 r = array_add(&pkgs[unique], sizeof *r);
659 properties->size = (void *) up - properties->data;
661 for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) {
662 rp->packages = add_to_property_pool(&set->package_pool, p);
672 remap_links(struct array *links, unsigned long *map)
674 unsigned long *p, *end;
676 end = links->data + links->size;
677 for (p = links->data; p < end; p++)
683 razor_importer_finish(struct razor_importer *importer)
685 struct razor_set *set;
686 unsigned long *map, *rmap;
689 map = uniqueify_properties(importer->set, &importer->set->requires);
690 remap_links(&importer->set->requires_pool, map);
693 map = uniqueify_properties(importer->set, &importer->set->provides);
694 remap_links(&importer->set->provides_pool, map);
697 count = importer->set->packages.size / sizeof(struct razor_package);
698 map = qsort_with_data(importer->set->packages.data,
700 sizeof(struct razor_package),
704 rmap = malloc(count * sizeof *rmap);
705 for (i = 0; i < count; i++)
708 remap_links(&importer->set->package_pool, rmap);
713 array_release(&importer->buckets);
720 razor_set_list(struct razor_set *set)
722 struct razor_package *p, *end;
725 pool = set->string_pool.data;
726 end = set->packages.data + set->packages.size;
727 for (p = set->packages.data; p < end; p++)
728 printf("%s %s\n", &pool[p->name], &pool[p->version]);
731 struct razor_set *bsearch_set;
734 compare_package_name(const void *key, const void *data)
736 const struct razor_package *p = data;
739 pool = bsearch_set->string_pool.data;
741 return strcmp(key, &pool[p->name]);
744 struct razor_package *
745 razor_set_get_package(struct razor_set *set, const char *package)
748 return bsearch(package, set->packages.data,
749 set->packages.size / sizeof(struct razor_package),
750 sizeof(struct razor_package), compare_package_name);
754 compare_property_name(const void *key, const void *data)
756 const struct razor_property *p = data;
759 pool = bsearch_set->string_pool.data;
761 return strcmp(key, &pool[p->name]);
764 struct razor_property *
765 razor_set_get_property(struct razor_set *set,
766 struct array *properties,
767 const char *property)
769 struct razor_property *p, *start;
772 p = bsearch(property, properties->data,
773 properties->size / sizeof(struct razor_property),
774 sizeof(struct razor_property), compare_property_name);
776 start = properties->data;
777 while (p > start && (p - 1)->name == p->name)
784 razor_set_list_all_properties(struct razor_set *set, struct array *properties)
786 struct razor_property *p, *end;
789 pool = set->string_pool.data;
790 end = properties->data + properties->size;
791 for (p = properties->data; p < end; p++)
792 printf("%s %s\n", &pool[p->name], &pool[p->version]);
796 razor_set_list_requires(struct razor_set *set, const char *name)
798 struct razor_property *p, *requires;
799 struct razor_package *package;
804 package = razor_set_get_package(set, name);
805 r = (unsigned long *) set->requires_pool.data +
807 requires = set->requires.data;
808 pool = set->string_pool.data;
811 printf("%s %s\n", &pool[p->name], &pool[p->version]);
814 razor_set_list_all_properties(set, &set->requires);
818 razor_set_list_provides(struct razor_set *set, const char *name)
820 struct razor_property *p, *provides;
821 struct razor_package *package;
826 package = razor_set_get_package(set, name);
827 r = (unsigned long *) set->provides_pool.data +
829 provides = set->provides.data;
830 pool = set->string_pool.data;
833 printf("%s %s\n", &pool[p->name], &pool[p->version]);
836 razor_set_list_all_properties(set, &set->provides);
840 razor_set_list_property_packages(struct razor_set *set,
841 struct array *properties,
845 struct razor_property *property, *end;
846 struct razor_package *p, *packages;
853 property = razor_set_get_property(set, properties, name);
854 packages = set->packages.data;
855 pool = set->string_pool.data;
856 end = properties->data + properties->size;
857 while (property < end && strcmp(name, &pool[property->name]) == 0) {
858 if (version && versioncmp(version, &pool[property->version]) != 0)
860 r = (unsigned long *)
861 set->package_pool.data + property->packages;
865 &pool[p->name], &pool[p->version]);
873 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
875 struct razor_property *r, *p, *rend, *pend;
879 p = set->provides.data;
880 rend = set->requires.data + set->requires.size;
881 pend = set->provides.data + set->provides.size;
882 pool = set->string_pool.data;
884 for (r = set->requires.data; r < rend; r++) {
885 while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0)
888 /* If there is more than one version of a provides,
889 * seek to the end for the highest version. */
890 while (p + 1 < pend && p->name == (p + 1)->name)
893 /* FIXME: We need to track property flags (<, <=, =
894 * etc) to properly determine if a requires is
895 * satisfied. The current code doesn't track that the
896 * requires a = 1 isn't satisfied by a = 2 provides. */
898 if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0 ||
899 versioncmp(&pool[r->version], &pool[p->version]) > 0) {
900 /* FIXME: We ignore file requires for now. */
901 if (pool[r->name] == '/')
903 u = array_add(unsatisfied, sizeof *u);
904 *u = r - (struct razor_property *) set->requires.data;
910 razor_set_list_unsatisfied(struct razor_set *set)
912 struct array unsatisfied;
913 struct razor_property *requires, *r;
914 unsigned long *u, *end;
917 array_init(&unsatisfied);
918 razor_set_validate(set, &unsatisfied);
920 end = unsatisfied.data + unsatisfied.size;
921 requires = set->requires.data;
922 pool = set->string_pool.data;
924 for (u = unsatisfied.data; u < end; u++) {
926 printf("%s %s not satisfied\n",
927 &pool[r->name], &pool[r->version]);
930 array_release(&unsatisfied);
933 #define UPSTREAM_SOURCE 0x80000000ul
934 #define INDEX_MASK 0x00fffffful
937 struct razor_set *set;
938 unsigned long *requires_map;
939 unsigned long *provides_map;
943 prepare_source(struct source *source, struct razor_set *set)
950 count = set->requires.size / sizeof (struct razor_property);
951 size = count * sizeof *source->requires_map;
952 source->requires_map = zalloc(size);
954 count = set->provides.size / sizeof (struct razor_property);
955 size = count * sizeof *source->provides_map;
956 source->provides_map = zalloc(size);
960 add_package(struct razor_importer *importer,
961 struct razor_package *package, struct source *source,
966 struct razor_package *p;
968 pool = source->set->string_pool.data;
969 p = array_add(&importer->set->packages, sizeof *p);
970 p->name = razor_importer_tokenize(importer, &pool[package->name]);
972 p->version = razor_importer_tokenize(importer,
973 &pool[package->version]);
974 p->requires = package->requires;
975 p->provides = package->provides;
977 r = (unsigned long *)
978 source->set->requires_pool.data + package->requires;
980 source->requires_map[*r++] = 1;
982 r = (unsigned long *)
983 source->set->provides_pool.data + package->provides;
985 source->provides_map[*r++] = 1;
989 /* Build the new package list sorted by merging the two package lists.
990 * Build new string pool as we go. (for now we just re-use that part of
993 merge_packages(struct razor_importer *importer,
994 struct source *source1, struct source *source2,
995 struct array *packages)
997 struct razor_package *upstream_packages, *p, *s, *send;
999 unsigned long *u, *uend;
1002 upstream_packages = source2->set->packages.data;
1005 uend = packages->data + packages->size;
1006 upool = source2->set->string_pool.data;
1008 s = source1->set->packages.data;
1009 send = source1->set->packages.data + source1->set->packages.size;
1010 spool = source1->set->string_pool.data;
1013 p = upstream_packages + *u;
1016 cmp = strcmp(&spool[s->name], &upool[p->name]);
1017 if (u >= uend || cmp < 0) {
1018 add_package(importer, s, source1, 0);
1020 } else if (cmp == 0) {
1021 add_package(importer, p, source2, UPSTREAM_SOURCE);
1025 add_package(importer, p, source2, UPSTREAM_SOURCE);
1031 static unsigned long
1032 add_property(struct razor_importer *importer, struct array *properties,
1033 const char *name, const char *version)
1035 struct razor_property *p;
1037 p = array_add(properties, sizeof *p);
1038 p->name = razor_importer_tokenize(importer, name);
1039 p->version = razor_importer_tokenize(importer, version);
1041 return p - (struct razor_property *) properties->data;
1045 merge_properties(struct array *properties,
1046 struct razor_importer *importer,
1047 struct razor_set *set1,
1048 struct array *properties1,
1049 unsigned long *map1,
1050 struct razor_set *set2,
1051 struct array *properties2,
1052 unsigned long *map2)
1054 struct razor_property *p1, *p2;
1055 int i, j, cmp, count1, count2;
1056 char *pool1, *pool2;
1060 pool1 = set1->string_pool.data;
1061 pool2 = set2->string_pool.data;
1063 count1 = properties1->size / sizeof *p1;
1064 count2 = properties2->size / sizeof *p2;
1065 while (i < count1 || j < count2) {
1066 if (i < count1 && map1[i] == 0) {
1070 if (j < count2 && map2[j] == 0) {
1074 p1 = (struct razor_property *) properties1->data + i;
1075 p2 = (struct razor_property *) properties2->data + j;
1076 if (i < count1 && j < count2)
1077 cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
1078 else if (i < count1)
1083 cmp = versioncmp(&pool1[p1->version],
1084 &pool2[p2->version]);
1086 map1[i++] = add_property(importer,
1089 &pool1[p1->version]);
1090 } else if (cmp > 0) {
1091 map2[j++] = add_property(importer,
1094 &pool2[p2->version]);
1096 map1[i++] = map2[j++] = add_property(importer,
1099 &pool1[p1->version]);
1104 static unsigned long
1105 emit_properties(struct array *source_pool, unsigned long index,
1106 unsigned long *map, struct array *pool)
1108 unsigned long r, *p, *q;
1110 r = pool->size / sizeof *q;
1111 p = (unsigned long *) source_pool->data + index;
1113 q = array_add(pool, sizeof *q);
1117 q = array_add(pool, sizeof *q);
1123 /* Rebuild property->packages maps. We can't just remap these, as a
1124 * property may have lost or gained a number of packages. Allocate an
1125 * array per property and loop through the packages and add them to
1126 * the arrays for their properties. */
1128 rebuild_package_lists(struct razor_set *set)
1130 int requires_count, provides_count;
1131 struct array *requires_pkgs, *provides_pkgs, *a;
1132 struct razor_package *pkg, *pkg_end;
1133 struct razor_property *prop, *prop_end;
1134 unsigned long *r, *q, *rpool, *ppool;
1136 requires_count = set->requires.size / sizeof (struct razor_property);
1137 provides_count = set->provides.size / sizeof (struct razor_property);
1138 requires_pkgs = zalloc(requires_count * sizeof *requires_pkgs);
1139 provides_pkgs = zalloc(provides_count * sizeof *provides_pkgs);
1140 pkg_end = set->packages.data + set->packages.size;
1141 rpool = set->requires_pool.data;
1142 ppool = set->provides_pool.data;
1144 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1145 for (r = &rpool[pkg->requires]; *r != ~0; r++) {
1146 q = array_add(&requires_pkgs[*r], sizeof *q);
1147 *q = pkg - (struct razor_package *) set->packages.data;
1149 for (r = &ppool[pkg->provides]; *r != ~0; r++) {
1150 q = array_add(&provides_pkgs[*r], sizeof *q);
1151 *q = pkg - (struct razor_package *) set->packages.data;
1155 prop_end = set->requires.data + set->requires.size;
1157 for (prop = set->requires.data; prop < prop_end; prop++, a++) {
1158 prop->packages = add_to_property_pool(&set->requires_pool, a);
1161 free(requires_pkgs);
1163 prop_end = set->provides.data + set->provides.size;
1165 for (prop = set->provides.data; prop < prop_end; prop++, a++) {
1166 prop->packages = add_to_property_pool(&set->provides_pool, a);
1169 free(provides_pkgs);
1172 /* Add packages from 'upstream' to 'set'. The packages to add are
1173 * specified by the 'packages' array, which is a sorted list of
1174 * package indexes. Returns a newly allocated package set. Does not
1175 * enforce validity of the resulting package set.
1177 * This looks more complicated than it is. An easy way to merge two
1178 * package sets would be to just use a razor_importer, but that
1179 * requires resorting, and is thus O(n log n). We can do this in a
1180 * linear sweep, but it gets a little more complicated.
1183 razor_set_add(struct razor_set *set, struct razor_set *upstream,
1184 struct array *packages)
1186 struct razor_set *result;
1187 struct razor_importer *importer;
1188 struct razor_package *p, *pend;
1189 struct source source, upstream_source;
1191 importer = razor_importer_new();
1193 prepare_source(&upstream_source, upstream);
1194 prepare_source(&source, set);
1196 merge_packages(importer, &source, &upstream_source, packages);
1198 /* As we built the package list, we filled out a bitvector of
1199 * the properties that are referenced by the packages in the
1200 * new set. Now we do a parallel loop through the properties
1201 * and emit those marked in the bit vector to the new set. In
1202 * the process, we update the bit vector to actually map from
1203 * indices in the old property list to indices in the new
1204 * property list for both sets. */
1206 merge_properties(&importer->set->requires, importer,
1207 set, &set->requires, source.requires_map,
1208 upstream, &upstream->requires,
1209 upstream_source.requires_map);
1210 merge_properties(&importer->set->provides, importer,
1211 set, &set->provides, source.provides_map,
1212 upstream, &upstream->provides,
1213 upstream_source.provides_map);
1215 /* Now we loop through the packages again and emit the
1216 * property lists, remapped to point to the new properties. */
1218 pend = importer->set->packages.data + importer->set->packages.size;
1219 for (p = importer->set->packages.data; p < pend; p++) {
1222 if (p->name & UPSTREAM_SOURCE)
1223 src = &upstream_source;
1227 p->requires = emit_properties(&src->set->requires_pool,
1230 &importer->set->requires_pool);
1231 p->provides = emit_properties(&src->set->provides_pool,
1234 &importer->set->provides_pool);
1235 p->name &= INDEX_MASK;
1238 rebuild_package_lists(importer->set);
1240 result = importer->set;
1241 array_release(&importer->buckets);
1248 razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
1249 struct razor_set *upstream, struct array *list)
1251 struct razor_property *requires, *r;
1252 struct razor_property *p, *pend;
1253 unsigned long *u, *end, *pkg, *package_pool;
1256 end = unsatisfied->data + unsatisfied->size;
1257 requires = set->requires.data;
1258 pool = set->string_pool.data;
1260 p = upstream->provides.data;
1261 pend = upstream->provides.data + upstream->provides.size;
1262 upool = upstream->string_pool.data;
1263 package_pool = upstream->package_pool.data;
1265 for (u = unsatisfied->data; u < end; u++) {
1268 while (p < pend && strcmp(&pool[r->name], &upool[p->name]) > 0)
1270 /* If there is more than one version of a provides,
1271 * seek to the end for the highest version. */
1272 while (p + 1 < pend && p->name == (p + 1)->name)
1276 strcmp(&pool[r->name], &upool[p->name]) != 0 ||
1277 versioncmp(&pool[r->version], &upool[p->version]) > 0) {
1278 /* Do we need to track unsatisfiable requires
1279 * as we go, or should we just do a
1280 * razor_set_validate() at the end? */
1282 pkg = array_add(list, sizeof *pkg);
1283 /* We just pull in the first package that provides */
1284 *pkg = package_pool[p->packages];
1290 find_packages(struct razor_set *set,
1291 int count, const char **packages, struct array *list)
1293 struct razor_package *p;
1297 /* FIXME: Sort the packages. */
1298 for (i = 0; i < count; i++) {
1299 p = razor_set_get_package(set, packages[i]);
1300 r = array_add(list, sizeof *r);
1301 *r = p - (struct razor_package *) set->packages.data;
1306 find_all_packages(struct razor_set *set,
1307 struct razor_set *upstream, struct array *list)
1309 struct razor_package *p, *u, *pend, *uend;
1313 pend = set->packages.data + set->packages.size;
1314 pool = set->string_pool.data;
1315 u = upstream->packages.data;
1316 uend = upstream->packages.data + upstream->packages.size;
1317 upool = upstream->string_pool.data;
1319 for (p = set->packages.data; p < pend; p++) {
1320 while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
1322 if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
1323 r = array_add(list, sizeof *r);
1324 *r = u - (struct razor_package *) upstream->packages.data;
1330 razor_set_update(struct razor_set *set, struct razor_set *upstream,
1331 int count, const char **packages)
1333 struct razor_set *new;
1334 struct razor_package *p, *upackages;
1335 struct array list, unsatisfied;
1337 unsigned long *u, *end;
1342 find_packages(upstream, count, packages, &list);
1344 find_all_packages(set, upstream, &list);
1346 end = list.data + list.size;
1347 upackages = upstream->packages.data;
1348 pool = upstream->string_pool.data;
1349 for (u = list.data; u < end; u++) {
1351 printf("package %s-%s set to be updated\n",
1352 &pool[p->name], &pool[p->version]);
1354 total += list.size / sizeof *u;
1356 while (list.size > 0) {
1357 printf(" -- satisfying new requires\n");
1359 new = razor_set_add(set, upstream, &list);
1360 array_release(&list);
1361 razor_set_destroy(set);
1364 array_init(&unsatisfied);
1365 razor_set_validate(new, &unsatisfied);
1367 razor_set_satisfy(new, &unsatisfied, upstream, &list);
1368 array_release(&unsatisfied);
1370 end = list.data + list.size;
1371 upackages = upstream->packages.data;
1372 pool = upstream->string_pool.data;
1373 for (u = list.data; u < end; u++) {
1375 printf("package %s-%s set to be updated\n",
1376 &pool[p->name], &pool[p->version]);
1378 total += list.size / sizeof *u;
1381 array_release(&list);
1383 printf("total of %d packages set to be updated\n", total);
1389 razor_set_info(struct razor_set *set)
1391 unsigned int offset, size;
1394 for (i = 0; i < set->header->sections[i].type; i++) {
1395 offset = set->header->sections[i].offset;
1396 size = set->header->sections[i].size;
1398 switch (set->header->sections[i].type) {
1399 case RAZOR_PACKAGES:
1400 printf("package section:\t%dkb\n", size / 1024);
1402 case RAZOR_REQUIRES:
1403 printf("requires section:\t%dkb\n", size / 1024);
1405 case RAZOR_PROVIDES:
1406 printf("provides section:\t%dkb\n", size / 1024);
1408 case RAZOR_STRING_POOL:
1409 printf("string pool:\t\t%dkb\n", size / 1024);
1418 printf("usage: razor [ import FILES | lookup <key> | "
1419 "list | list-requires | list-provides | eat-yum | info ]\n");
1423 static const char *repo_filename = "system.repo";
1424 static const char rawhide_repo_filename[] = "rawhide.repo";
1427 main(int argc, const char *argv[])
1429 struct razor_set *set, *upstream;
1430 struct stat statbuf;
1433 repo = getenv("RAZOR_REPO");
1435 repo_filename = repo;
1439 } else if (strcmp(argv[1], "import") == 0) {
1440 if (stat("set", &statbuf) && mkdir("set", 0777)) {
1441 fprintf(stderr, "could not create directory 'set'\n");
1445 set = razor_import_rzr_files(argc - 2, argv + 2);
1447 printf("pool size: %d\n", set->string_pool.size);
1448 printf("pool allocation: %d\n", set->string_pool.alloc);
1449 printf("packages: %d\n",
1450 set->packages.size / sizeof(struct razor_package));
1451 printf("requires: %d\n",
1452 set->requires.size / sizeof(struct razor_property));
1453 printf("provides: %d\n",
1454 set->provides.size / sizeof(struct razor_property));
1456 razor_set_write(set, repo_filename);
1458 razor_set_destroy(set);
1459 } else if (strcmp(argv[1], "list") == 0) {
1460 set = razor_set_open(repo_filename);
1461 razor_set_list(set);
1462 razor_set_destroy(set);
1463 } else if (strcmp(argv[1], "list-requires") == 0) {
1464 set = razor_set_open(repo_filename);
1465 razor_set_list_requires(set, argv[2]);
1466 razor_set_destroy(set);
1467 } else if (strcmp(argv[1], "list-provides") == 0) {
1468 set = razor_set_open(repo_filename);
1469 razor_set_list_provides(set, argv[2]);
1470 razor_set_destroy(set);
1471 } else if (strcmp(argv[1], "what-requires") == 0) {
1472 set = razor_set_open(repo_filename);
1473 razor_set_list_property_packages(set, &set->requires,
1475 razor_set_destroy(set);
1476 } else if (strcmp(argv[1], "what-provides") == 0) {
1477 set = razor_set_open(repo_filename);
1478 razor_set_list_property_packages(set, &set->provides,
1480 razor_set_destroy(set);
1481 } else if (strcmp(argv[1], "info") == 0) {
1482 set = razor_set_open(repo_filename);
1483 razor_set_info(set);
1484 razor_set_destroy(set);
1485 } else if (strcmp(argv[1], "eat-yum") == 0) {
1486 set = razor_set_create_from_yum_filelist(STDIN_FILENO);
1489 razor_set_write(set, rawhide_repo_filename);
1490 razor_set_destroy(set);
1491 printf("wrote %s\n", rawhide_repo_filename);
1492 } else if (strcmp(argv[1], "import-rpmdb") == 0) {
1493 set = razor_set_create_from_rpmdb();
1496 razor_set_write(set, repo_filename);
1497 razor_set_destroy(set);
1498 printf("wrote %s\n", repo_filename);
1499 } else if (strcmp(argv[1], "validate") == 0) {
1500 set = razor_set_open(repo_filename);
1503 razor_set_list_unsatisfied(set);
1504 razor_set_destroy(set);
1505 } else if (strcmp(argv[1], "add") == 0) {
1508 set = razor_set_open(repo_filename);
1509 upstream = razor_set_open(rawhide_repo_filename);
1510 if (set == NULL || upstream == NULL)
1513 find_packages(upstream, argc - 2, argv + 2, &list);
1514 set = razor_set_add(set, upstream, &list);
1515 razor_set_write(set, "system-updated.repo");
1516 razor_set_destroy(set);
1517 printf("wrote system-updated.repo\n");
1518 } else if (strcmp(argv[1], "update") == 0) {
1519 set = razor_set_open(repo_filename);
1520 upstream = razor_set_open(rawhide_repo_filename);
1521 if (set == NULL || upstream == NULL)
1523 set = razor_set_update(set, upstream, argc - 2, argv + 2);
1524 razor_set_write(set, "system-updated.repo");
1525 razor_set_destroy(set);
1526 razor_set_destroy(upstream);
1527 printf("wrote system-updated.repo\n");