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.
21 #include "razor-internal.h"
24 #define UPSTREAM_SOURCE 0x80
27 struct razor_set *set;
28 uint32_t *property_map;
33 struct razor_set *set;
34 struct hashtable table;
35 struct source source1;
36 struct source source2;
40 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
42 struct razor_merger *merger;
46 merger = zalloc(sizeof *merger);
47 merger->set = razor_set_create();
48 hashtable_init(&merger->table, &merger->set->string_pool);
50 merger->source1.set = set1;
51 count = set1->properties.size / sizeof (struct razor_property);
52 size = count * sizeof merger->source1.property_map[0];
53 merger->source1.property_map = zalloc(size);
54 count = set1->files.size / sizeof (struct razor_entry);
55 size = count * sizeof merger->source1.file_map[0];
56 merger->source1.file_map = zalloc(size);
58 merger->source2.set = set2;
59 count = set2->properties.size / sizeof (struct razor_property);
60 size = count * sizeof merger->source2.property_map[0];
61 merger->source2.property_map = zalloc(size);
62 count = set2->files.size / sizeof (struct razor_entry);
63 size = count * sizeof merger->source2.file_map[0];
64 merger->source2.file_map = zalloc(size);
70 razor_merger_add_package(struct razor_merger *merger,
71 struct razor_package *package)
75 struct razor_package *p;
76 struct razor_set *set1;
77 struct source *source;
80 set1 = merger->source1.set;
81 if (set1->packages.data <= (void *) package &&
82 (void *) package < set1->packages.data + set1->packages.size) {
83 source = &merger->source1;
86 source = &merger->source2;
87 flags = UPSTREAM_SOURCE;
90 pool = source->set->string_pool.data;
91 p = array_add(&merger->set->packages, sizeof *p);
92 p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
94 p->version = hashtable_tokenize(&merger->table,
95 &pool[package->version]);
96 p->arch = hashtable_tokenize(&merger->table,
97 &pool[package->arch]);
99 p->properties = package->properties;
100 r = list_first(&package->properties, &source->set->property_pool);
102 source->property_map[r->data] = 1;
106 p->files = package->files;
107 r = list_first(&package->files, &source->set->file_pool);
109 source->file_map[r->data] = 1;
115 add_property(struct razor_merger *merger,
116 const char *name, uint32_t flags, const char *version)
118 struct razor_property *p;
120 p = array_add(&merger->set->properties, sizeof *p);
121 p->name = hashtable_tokenize(&merger->table, name);
123 p->version = hashtable_tokenize(&merger->table, version);
125 return p - (struct razor_property *) merger->set->properties.data;
129 merge_properties(struct razor_merger *merger)
131 struct razor_property *p1, *p2;
132 struct razor_set *set1, *set2;
133 uint32_t *map1, *map2;
134 int i, j, cmp, count1, count2;
137 set1 = merger->source1.set;
138 set2 = merger->source2.set;
139 map1 = merger->source1.property_map;
140 map2 = merger->source2.property_map;
144 pool1 = set1->string_pool.data;
145 pool2 = set2->string_pool.data;
147 count1 = set1->properties.size / sizeof *p1;
148 count2 = set2->properties.size / sizeof *p2;
149 while (i < count1 || j < count2) {
150 if (i < count1 && map1[i] == 0) {
154 if (j < count2 && map2[j] == 0) {
158 p1 = (struct razor_property *) set1->properties.data + i;
159 p2 = (struct razor_property *) set2->properties.data + j;
160 if (i < count1 && j < count2)
161 cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
167 cmp = p1->flags - p2->flags;
169 cmp = razor_versioncmp(&pool1[p1->version],
170 &pool2[p2->version]);
172 map1[i++] = add_property(merger,
175 &pool1[p1->version]);
176 } else if (cmp > 0) {
177 map2[j++] = add_property(merger,
180 &pool2[p2->version]);
182 map1[i++] = map2[j++] =
186 &pool1[p1->version]);
192 emit_properties(struct list_head *properties, struct array *source_pool,
193 uint32_t *map, struct array *pool)
198 r = pool->size / sizeof *q;
199 p = list_first(properties, source_pool);
201 q = array_add(pool, sizeof *q);
202 q->data = map[p->data];
207 list_set_ptr(properties, r);
211 add_file(struct razor_merger *merger, const char *name)
213 struct razor_entry *e;
215 e = array_add(&merger->set->files, sizeof *e);
216 e->name = hashtable_tokenize(&merger->table, name);
220 return e - (struct razor_entry *)merger->set->files.data;
225 fix_file_map(uint32_t *map,
226 struct razor_entry *files,
227 struct razor_entry *top)
235 fix_file_map(map, files, &files[e]);
238 } while (!(files[e++].flags & RAZOR_ENTRY_LAST));
241 map[top - files] = 1;
245 struct merge_directory {
246 uint32_t merged, dir1, dir2;
250 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
252 struct razor_entry *root1, *root2, *mroot, *e1, *e2;
253 struct razor_set *set1, *set2;
254 struct array merge_stack;
255 struct merge_directory *child_md, *end_md;
256 uint32_t *map1, *map2, start, last;
260 set1 = merger->source1.set;
261 set2 = merger->source2.set;
262 map1 = merger->source1.file_map;
263 map2 = merger->source2.file_map;
264 pool1 = set1->string_pool.data;
265 pool2 = set2->string_pool.data;
266 root1 = (struct razor_entry *) set1->files.data;
267 root2 = (struct razor_entry *) set2->files.data;
269 array_init(&merge_stack);
271 start = merger->set->files.size / sizeof (struct razor_entry);
273 e1 = md->dir1 ? root1 + md->dir1 : NULL;
274 e2 = md->dir2 ? root2 + md->dir2 : NULL;
276 if (!e2 && !map1[e1 - root1]) {
277 if ((e1++)->flags & RAZOR_ENTRY_LAST)
281 if (!e1 && !map2[e2 - root2]) {
282 if ((e2++)->flags & RAZOR_ENTRY_LAST)
286 if (e1 && !map1[e1 - root1] &&
287 e2 && !map1[e2 - root2]) {
288 if ((e1++)->flags & RAZOR_ENTRY_LAST)
290 if ((e2++)->flags & RAZOR_ENTRY_LAST)
300 cmp = strcmp (&pool1[e1->name],
305 if (map1[e1 - root1]) {
306 map1[e1 - root1] = last =
307 add_file(merger, &pool1[e1->name]);
309 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
310 child_md->merged = last;
311 child_md->dir1 = e1->start;
315 if ((e1++)->flags & RAZOR_ENTRY_LAST)
317 } else if (cmp > 0) {
318 if (map2[e2 - root2]) {
319 map2[e2 - root2] = last =
320 add_file(merger, &pool2[e2->name]);
322 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
323 child_md->merged = last;
325 child_md->dir2 = e2->start;
328 if ((e2++)->flags & RAZOR_ENTRY_LAST)
331 map1[e1 - root1] = map2[e2- root2] = last =
332 add_file(merger, &pool1[e1->name]);
333 if (e1->start || e2->start) {
334 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
335 child_md->merged = last;
336 child_md->dir1 = e1->start;
337 child_md->dir2 = e2->start;
339 if ((e1++)->flags & RAZOR_ENTRY_LAST)
341 if ((e2++)->flags & RAZOR_ENTRY_LAST)
346 mroot = (struct razor_entry *)merger->set->files.data;
348 mroot[last].flags = RAZOR_ENTRY_LAST;
349 mroot[md->merged].start = start;
351 mroot[md->merged].start = 0;
353 end_md = merge_stack.data + merge_stack.size;
354 for (child_md = merge_stack.data; child_md < end_md; child_md++)
355 merge_one_directory(merger, child_md);
356 array_release(&merge_stack);
360 merge_files(struct razor_merger *merger)
362 struct razor_entry *root;
363 struct merge_directory md;
364 uint32_t *map1, *map2;
366 map1 = merger->source1.file_map;
367 map2 = merger->source2.file_map;
371 if (merger->source1.set->files.size) {
372 root = (struct razor_entry *) merger->source1.set->files.data;
374 fix_file_map(map1, root, root);
375 md.dir1 = root->start;
379 if (merger->source2.set->files.size) {
380 root = (struct razor_entry *) merger->source2.set->files.data;
382 fix_file_map(map2, root, root);
383 md.dir2 = root->start;
387 merge_one_directory(merger, &md);
391 emit_files(struct list_head *files, struct array *source_pool,
392 uint32_t *map, struct array *pool)
397 r = pool->size / sizeof *q;
398 p = list_first(files, source_pool);
400 q = array_add(pool, sizeof *q);
401 q->data = map[p->data];
406 list_set_ptr(files, r);
409 /* Rebuild property->packages maps. We can't just remap these, as a
410 * property may have lost or gained a number of packages. Allocate an
411 * array per property and loop through the packages and add them to
412 * the arrays for their properties. */
414 rebuild_property_package_lists(struct razor_set *set)
416 struct array *pkgs, *a;
417 struct razor_package *pkg, *pkg_end;
418 struct razor_property *prop, *prop_end;
423 count = set->properties.size / sizeof (struct razor_property);
424 pkgs = zalloc(count * sizeof *pkgs);
425 pkg_end = set->packages.data + set->packages.size;
427 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
428 r = list_first(&pkg->properties, &set->property_pool);
430 q = array_add(&pkgs[r->data], sizeof *q);
431 *q = pkg - (struct razor_package *) set->packages.data;
436 prop_end = set->properties.data + set->properties.size;
438 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
439 list_set_array(&prop->packages, &set->package_pool, a, 0);
446 rebuild_file_package_lists(struct razor_set *set)
448 struct array *pkgs, *a;
449 struct razor_package *pkg, *pkg_end;
450 struct razor_entry *entry, *entry_end;
455 count = set->files.size / sizeof (struct razor_entry);
456 pkgs = zalloc(count * sizeof *pkgs);
457 pkg_end = set->packages.data + set->packages.size;
459 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
460 r = list_first(&pkg->files, &set->file_pool);
462 q = array_add(&pkgs[r->data], sizeof *q);
463 *q = pkg - (struct razor_package *) set->packages.data;
468 entry_end = set->files.data + set->files.size;
470 for (entry = set->files.data; entry < entry_end; entry++, a++) {
471 list_set_array(&entry->packages, &set->package_pool, a, 0);
478 razor_merger_finish(struct razor_merger *merger)
480 struct razor_set *result;
481 struct razor_package *p, *pend;
483 /* As we built the package list, we filled out a bitvector of
484 * the properties that are referenced by the packages in the
485 * new set. Now we do a parallel loop through the properties
486 * and emit those marked in the bit vector to the new set. In
487 * the process, we update the bit vector to actually map from
488 * indices in the old property list to indices in the new
489 * property list for both sets. */
491 merge_properties(merger);
494 /* Now we loop through the packages again and emit the
495 * property lists, remapped to point to the new properties. */
497 pend = merger->set->packages.data + merger->set->packages.size;
498 for (p = merger->set->packages.data; p < pend; p++) {
501 if (p->flags & UPSTREAM_SOURCE)
502 src = &merger->source2;
504 src = &merger->source1;
506 emit_properties(&p->properties,
507 &src->set->property_pool,
509 &merger->set->property_pool);
510 emit_files(&p->files,
511 &src->set->file_pool,
513 &merger->set->file_pool);
514 p->flags &= ~UPSTREAM_SOURCE;
517 rebuild_property_package_lists(merger->set);
518 rebuild_file_package_lists(merger->set);
520 result = merger->set;
521 hashtable_release(&merger->table);