When uniquifying properties, also sort them on the owning package.
This ensures that whenever two packages provide or (or require, obsolete
or conflict) the same property, they appear in the same order in the
propertys list of packages.
2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "razor-internal.h"
27 razor_importer_begin_package(struct razor_importer *importer,
32 struct razor_package *p;
34 p = array_add(&importer->set->packages, sizeof *p);
35 p->name = hashtable_tokenize(&importer->table, name);
37 p->version = hashtable_tokenize(&importer->table, version);
38 p->arch = hashtable_tokenize(&importer->table, arch);
40 importer->package = p;
41 array_init(&importer->properties);
46 razor_importer_finish_package(struct razor_importer *importer)
48 list_set_array(&importer->package->properties,
49 &importer->set->property_pool,
50 &importer->properties,
53 array_release(&importer->properties);
57 razor_importer_add_property(struct razor_importer *importer,
62 struct razor_property *p;
65 p = array_add(&importer->set->properties, sizeof *p);
66 p->name = hashtable_tokenize(&importer->table, name);
68 p->version = hashtable_tokenize(&importer->table, version);
69 list_set_ptr(&p->packages, importer->package -
70 (struct razor_package *) importer->set->packages.data);
72 r = array_add(&importer->properties, sizeof *r);
73 *r = p - (struct razor_property *) importer->set->properties.data;
75 if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
77 r = array_add(&importer->file_requires, sizeof *r);
83 razor_importer_add_file(struct razor_importer *importer, const char *name)
85 struct import_entry *e;
87 e = array_add(&importer->files, sizeof *e);
89 e->package = importer->package -
90 (struct razor_package *) importer->set->packages.data;
91 e->name = strdup(name);
94 struct razor_importer *
95 razor_importer_create(void)
97 struct razor_importer *importer;
99 importer = zalloc(sizeof *importer);
100 importer->set = razor_set_create();
101 hashtable_init(&importer->table, &importer->set->string_pool);
106 /* Destroy an importer without creating the set. */
108 razor_importer_destroy(struct razor_importer *importer)
110 /* FIXME: write this */
114 compare_packages(const void *p1, const void *p2, void *data)
116 const struct razor_package *pkg1 = p1, *pkg2 = p2;
117 struct razor_set *set = data;
118 char *pool = set->string_pool.data;
120 /* FIXME: what if the flags are different? */
121 if (pkg1->name == pkg2->name)
122 return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
124 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
128 compare_properties(const void *p1, const void *p2, void *data)
130 const struct razor_property *prop1 = p1, *prop2 = p2;
131 struct razor_set *set = data;
132 char *pool = set->string_pool.data;
134 if (prop1->name != prop2->name)
135 return strcmp(&pool[prop1->name], &pool[prop2->name]);
136 else if (prop1->flags != prop2->flags)
137 return prop1->flags - prop2->flags;
138 else if (prop1->version != prop2->version)
139 return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
141 return prop1->packages.list_ptr - prop2->packages.list_ptr;
145 uniqueify_properties(struct razor_set *set)
147 struct razor_property *rp, *up, *rp_end;
148 struct array *pkgs, *p;
150 uint32_t *map, *rmap;
151 int i, count, unique;
153 count = set->properties.size / sizeof(struct razor_property);
154 map = razor_qsort_with_data(set->properties.data,
156 sizeof(struct razor_property),
160 rp_end = set->properties.data + set->properties.size;
161 rmap = malloc(count * sizeof *map);
162 pkgs = zalloc(count * sizeof *pkgs);
163 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
164 if (rp->name != up->name ||
165 rp->flags != up->flags ||
166 rp->version != up->version) {
169 up->flags = rp->flags;
170 up->version = rp->version;
173 unique = up - (struct razor_property *) set->properties.data;
174 rmap[map[i]] = unique;
175 r = array_add(&pkgs[unique], sizeof *r);
182 set->properties.size = (void *) up - set->properties.data;
184 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
185 list_set_array(&rp->packages, &set->package_pool, p, 0);
195 compare_filenames(const void *p1, const void *p2, void *data)
197 const struct import_entry *e1 = p1;
198 const struct import_entry *e2 = p2;
199 const char *n1 = e1->name;
200 const char *n2 = e2->name;
202 /* Need to make sure that the contents of a directory
203 * are sorted immediately after it. So "foo/bar" has to
204 * sort before "foo.conf"
206 * FIXME: this is about 60% slower than strcmp
210 return *n2 == '/' ? 1 : -1;
212 return *n1 == '/' ? -1 : 1;
225 count_entries(struct import_directory *d)
227 struct import_directory *p, *end;
230 end = d->files.data + d->files.size;
234 d->count += p->count + 1;
240 serialize_files(struct razor_set *set,
241 struct import_directory *d, struct array *array)
243 struct import_directory *p, *end;
244 struct razor_entry *e = NULL;
248 end = d->files.data + d->files.size;
249 s = array->size / sizeof *e + d->files.size / sizeof *p;
251 e = array_add(array, sizeof *e);
254 e->start = p->count > 0 ? s : 0;
257 list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
258 array_release(&p->packages);
262 e->flags |= RAZOR_ENTRY_LAST;
265 end = d->files.data + d->files.size;
267 serialize_files(set, p, array);
273 remap_property_package_links(struct array *properties, uint32_t *rmap)
275 struct razor_property *p, *end;
277 end = properties->data + properties->size;
278 for (p = properties->data; p < end; p++)
279 list_remap_head(&p->packages, rmap);
283 build_file_tree(struct razor_importer *importer)
285 int count, i, length;
286 struct import_entry *filenames;
290 struct import_directory *d, root;
291 struct razor_entry *e;
293 count = importer->files.size / sizeof (struct import_entry);
294 razor_qsort_with_data(importer->files.data,
296 sizeof (struct import_entry),
300 root.name = hashtable_tokenize(&importer->table, "");
301 array_init(&root.files);
302 array_init(&root.packages);
305 filenames = importer->files.data;
306 for (i = 0; i < count; i++) {
307 f = filenames[i].name;
314 end = strchr(f, '/');
318 memcpy(dirname, f, length);
319 dirname[length] ='\0';
320 name = hashtable_tokenize(&importer->table, dirname);
321 if (d->last == NULL || d->last->name != name) {
322 d->last = array_add(&d->files, sizeof *d);
323 d->last->name = name;
324 d->last->last = NULL;
325 array_init(&d->last->files);
326 array_init(&d->last->packages);
334 r = array_add(&d->packages, sizeof *r);
335 *r = filenames[i].package;
336 free(filenames[i].name);
339 count_entries(&root);
340 e = importer->set->files.data;
342 e->flags = RAZOR_ENTRY_LAST;
343 e->start = importer->files.size ? 1 : 0;
344 list_set_empty(&e->packages);
346 serialize_files(importer->set, &root, &importer->set->files);
348 array_release(&importer->files);
352 list_to_array(struct list *list, struct array *array)
357 item = array_add(array, sizeof *item);
359 list = list_next(list);
364 compare_file_requires(const void *p1, const void *p2, void *data)
366 uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
367 const char *pool = data;
369 return strcmp(&pool[*f1], &pool[*f2]);
373 find_file_provides(struct razor_importer *importer)
375 struct razor_property *prop;
376 struct razor_entry *top, *entry;
377 struct razor_package *packages;
378 struct array pkgprops;
380 uint32_t *req, *req_start, *req_end;
381 uint32_t *map, *newprop;
384 pool = importer->set->string_pool.data;
385 packages = importer->set->packages.data;
386 top = importer->set->files.data;
388 req = req_start = importer->file_requires.data;
389 req_end = importer->file_requires.data + importer->file_requires.size;
390 map = razor_qsort_with_data(req, req_end - req, sizeof *req,
391 compare_file_requires, pool);
394 for (req = req_start; req < req_end; req++) {
395 if (req > req_start && req[0] == req[-1])
397 entry = razor_set_find_entry(importer->set, top, &pool[*req]);
401 for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
402 prop = array_add(&importer->set->properties, sizeof *prop);
405 RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
406 prop->version = hashtable_tokenize(&importer->table, "");
407 list_set_ptr(&prop->packages, pkg->data);
409 /* Update property list of pkg */
410 array_init(&pkgprops);
411 list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
412 newprop = array_add(&pkgprops, sizeof *newprop);
413 *newprop = prop - (struct razor_property *)importer->set->properties.data;
414 list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
415 array_release(&pkgprops);
419 array_release(&importer->file_requires);
423 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
425 struct razor_package *p, *packages;
427 struct razor_entry *e, *end;
432 count = set->packages.size / sizeof *p;
433 pkgs = zalloc(count * sizeof *pkgs);
435 end = set->files.data + set->files.size;
436 for (e = set->files.data; e < end; e++) {
437 list_remap_head(&e->packages, rmap);
438 r = list_first(&e->packages, &set->package_pool);
440 q = array_add(&pkgs[r->data], sizeof *q);
441 *q = e - (struct razor_entry *) set->files.data;
446 packages = set->packages.data;
447 for (i = 0; i < count; i++) {
448 list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
449 array_release(&pkgs[i]);
455 razor_importer_finish(struct razor_importer *importer)
457 struct razor_set *set;
458 uint32_t *map, *rmap;
461 build_file_tree(importer);
462 find_file_provides(importer);
464 map = uniqueify_properties(importer->set);
465 list_remap_pool(&importer->set->property_pool, map);
468 count = importer->set->packages.size / sizeof(struct razor_package);
469 map = razor_qsort_with_data(importer->set->packages.data,
471 sizeof(struct razor_package),
475 rmap = malloc(count * sizeof *rmap);
476 for (i = 0; i < count; i++)
480 list_remap_pool(&importer->set->package_pool, rmap);
481 build_package_file_lists(importer->set, rmap);
482 remap_property_package_links(&importer->set->properties, rmap);
486 hashtable_release(&importer->table);