Use strings to identify section types in the on-disk repo format.
Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).
This will allow for razor files to contain arbitrary sections.
For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".
committer: Kristian H?gsberg <krh@redhat.com>
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_create:
29 * Create a new %razor_importer.
31 * Returns: the new %razor_importer.
33 RAZOR_EXPORT struct razor_importer *
34 razor_importer_create(void)
36 struct razor_importer *importer;
38 importer = zalloc(sizeof *importer);
39 importer->set = razor_set_create();
40 hashtable_init(&importer->table, &importer->set->string_pool);
41 hashtable_init(&importer->details_table,
42 &importer->set->details_string_pool);
43 hashtable_init(&importer->file_table,
44 &importer->set->file_string_pool);
50 * razor_importer_destroy:
51 * @importer: the %razor_importer
53 * Destroy an importer without creating a %razor_set. Normally,
54 * %razor_importer_finish will create a new %razor_set and destroy the
55 * importer. If the import must be aborted without creating the set,
56 * just destroy the import using this function.
59 razor_importer_destroy(struct razor_importer *importer)
61 /* FIXME: write this */
66 * razor_importer_begin_package:
67 * @importer: the %razor_importer
68 * @name: the name of the new package
69 * @version: the version of the new package
70 * @arch: the architechture of the new package.
72 * Begin describing a new package to the importer. This creates a new
73 * package and sets the %name, %version and %arch. Subsequent calls
74 * to %razor_importer_add_details, %razor_importer_add_property and
75 * %razor_importer_add_file further describe this package and
76 * %razor_importer_finish_package marks the end of meta data for this
80 razor_importer_begin_package(struct razor_importer *importer,
85 struct razor_package *p;
87 p = array_add(&importer->set->packages, sizeof *p);
88 p->name = hashtable_tokenize(&importer->table, name);
90 p->version = hashtable_tokenize(&importer->table, version);
91 p->arch = hashtable_tokenize(&importer->table, arch);
93 importer->package = p;
94 array_init(&importer->properties);
98 * razor_importer_finish_package:
99 * @importer: the %razor_importer
101 * Tells the importer that the current package is complete.
104 razor_importer_finish_package(struct razor_importer *importer)
106 list_set_array(&importer->package->properties,
107 &importer->set->property_pool,
108 &importer->properties,
111 array_release(&importer->properties);
115 * razor_importer_add_details:
116 * @importer: the %razor_importer
117 * @summary: the package summary
118 * @description: the package description
119 * @url: the package url
120 * @license: the package license
122 * Provide additional information for the current package.
125 razor_importer_add_details(struct razor_importer *importer,
127 const char *description,
131 importer->package->summary = hashtable_tokenize(&importer->details_table, summary);
132 importer->package->description = hashtable_tokenize(&importer->details_table, description);
133 importer->package->url = hashtable_tokenize(&importer->details_table, url);
134 importer->package->license = hashtable_tokenize(&importer->details_table, license);
138 * razor_importer_add_property:
139 * @importer: the %razor_importer
140 * @name: name of the property
141 * @flags: property flags
142 * @version: version of the property or %NULL
144 * Add a property for the current package. The %flags parameter
145 * determines the type of the property and optionally the relation to
146 * the specified version and the availability constraint. See
147 * %razor_property_flags for further information about the flag
151 razor_importer_add_property(struct razor_importer *importer,
156 struct razor_property *p;
159 p = array_add(&importer->set->properties, sizeof *p);
160 p->name = hashtable_tokenize(&importer->table, name);
162 p->version = hashtable_tokenize(&importer->table, version);
163 list_set_ptr(&p->packages, importer->package -
164 (struct razor_package *) importer->set->packages.data);
166 r = array_add(&importer->properties, sizeof *r);
167 *r = p - (struct razor_property *) importer->set->properties.data;
169 if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
171 r = array_add(&importer->file_requires, sizeof *r);
177 * razor_importer_add_file:
178 * @importer: the %razor_importer
179 * @name: name of the file
181 * Add a file to the current package.
184 razor_importer_add_file(struct razor_importer *importer, const char *name)
186 struct import_entry *e;
188 e = array_add(&importer->files, sizeof *e);
190 e->package = importer->package -
191 (struct razor_package *) importer->set->packages.data;
192 e->name = strdup(name);
196 compare_packages(const void *p1, const void *p2, void *data)
198 const struct razor_package *pkg1 = p1, *pkg2 = p2;
199 struct razor_set *set = data;
200 char *pool = set->string_pool.data;
202 /* FIXME: what if the flags are different? */
203 if (pkg1->name == pkg2->name)
204 return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
206 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
210 compare_properties(const void *p1, const void *p2, void *data)
212 const struct razor_property *prop1 = p1, *prop2 = p2;
213 struct razor_set *set = data;
214 char *pool = set->string_pool.data;
216 if (prop1->name != prop2->name)
217 return strcmp(&pool[prop1->name], &pool[prop2->name]);
218 else if (prop1->flags != prop2->flags)
219 return prop1->flags - prop2->flags;
220 else if (prop1->version != prop2->version)
221 return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
223 return prop1->packages.list_ptr - prop2->packages.list_ptr;
227 uniqueify_properties(struct razor_set *set)
229 struct razor_property *rp, *up, *rp_end;
230 struct array *pkgs, *p;
232 uint32_t *map, *rmap;
233 int i, count, unique;
235 count = set->properties.size / sizeof(struct razor_property);
236 map = razor_qsort_with_data(set->properties.data,
238 sizeof(struct razor_property),
242 rp_end = set->properties.data + set->properties.size;
243 rmap = malloc(count * sizeof *map);
244 pkgs = zalloc(count * sizeof *pkgs);
245 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
246 if (rp->name != up->name ||
247 rp->flags != up->flags ||
248 rp->version != up->version) {
251 up->flags = rp->flags;
252 up->version = rp->version;
255 unique = up - (struct razor_property *) set->properties.data;
256 rmap[map[i]] = unique;
257 r = array_add(&pkgs[unique], sizeof *r);
264 set->properties.size = (void *) up - set->properties.data;
266 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
267 list_set_array(&rp->packages, &set->package_pool, p, 0);
277 compare_filenames(const void *p1, const void *p2, void *data)
279 const struct import_entry *e1 = p1;
280 const struct import_entry *e2 = p2;
281 const char *n1 = e1->name;
282 const char *n2 = e2->name;
284 /* Need to make sure that the contents of a directory
285 * are sorted immediately after it. So "foo/bar" has to
286 * sort before "foo.conf"
288 * FIXME: this is about 60% slower than strcmp
292 return *n2 == '/' ? 1 : -1;
294 return *n1 == '/' ? -1 : 1;
307 count_entries(struct import_directory *d)
309 struct import_directory *p, *end;
312 end = d->files.data + d->files.size;
316 d->count += p->count + 1;
322 serialize_files(struct razor_set *set,
323 struct import_directory *d, struct array *array)
325 struct import_directory *p, *end;
326 struct razor_entry *e = NULL;
330 end = d->files.data + d->files.size;
331 s = array->size / sizeof *e + d->files.size / sizeof *p;
333 e = array_add(array, sizeof *e);
336 e->start = p->count > 0 ? s : 0;
339 list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
340 array_release(&p->packages);
344 e->flags |= RAZOR_ENTRY_LAST;
347 end = d->files.data + d->files.size;
349 serialize_files(set, p, array);
355 remap_property_package_links(struct array *properties, uint32_t *rmap)
357 struct razor_property *p, *end;
359 end = properties->data + properties->size;
360 for (p = properties->data; p < end; p++)
361 list_remap_head(&p->packages, rmap);
365 build_file_tree(struct razor_importer *importer)
367 int count, i, length;
368 struct import_entry *filenames;
372 struct import_directory *d, root;
373 struct razor_entry *e;
375 count = importer->files.size / sizeof (struct import_entry);
376 razor_qsort_with_data(importer->files.data,
378 sizeof (struct import_entry),
382 root.name = hashtable_tokenize(&importer->file_table, "");
383 array_init(&root.files);
384 array_init(&root.packages);
387 filenames = importer->files.data;
388 for (i = 0; i < count; i++) {
389 f = filenames[i].name;
396 end = strchr(f, '/');
400 memcpy(dirname, f, length);
401 dirname[length] ='\0';
402 name = hashtable_tokenize(&importer->file_table,
404 if (d->last == NULL || d->last->name != name) {
405 d->last = array_add(&d->files, sizeof *d);
406 d->last->name = name;
407 d->last->last = NULL;
408 array_init(&d->last->files);
409 array_init(&d->last->packages);
417 r = array_add(&d->packages, sizeof *r);
418 *r = filenames[i].package;
419 free(filenames[i].name);
422 count_entries(&root);
423 e = importer->set->files.data;
425 e->flags = RAZOR_ENTRY_LAST;
426 e->start = importer->files.size ? 1 : 0;
427 list_set_empty(&e->packages);
429 serialize_files(importer->set, &root, &importer->set->files);
431 array_release(&importer->files);
435 list_to_array(struct list *list, struct array *array)
440 item = array_add(array, sizeof *item);
442 list = list_next(list);
447 compare_file_requires(const void *p1, const void *p2, void *data)
449 uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
450 const char *pool = data;
452 return strcmp(&pool[*f1], &pool[*f2]);
456 find_file_provides(struct razor_importer *importer)
458 struct razor_property *prop;
459 struct razor_entry *top, *entry;
460 struct razor_package *packages;
461 struct array pkgprops;
463 uint32_t *req, *req_start, *req_end;
464 uint32_t *map, *newprop;
467 pool = importer->set->string_pool.data;
468 packages = importer->set->packages.data;
469 top = importer->set->files.data;
471 req = req_start = importer->file_requires.data;
472 req_end = importer->file_requires.data + importer->file_requires.size;
473 map = razor_qsort_with_data(req, req_end - req, sizeof *req,
474 compare_file_requires, pool);
477 for (req = req_start; req < req_end; req++) {
478 if (req > req_start && req[0] == req[-1])
480 entry = razor_set_find_entry(importer->set, top, &pool[*req]);
484 for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
485 prop = array_add(&importer->set->properties, sizeof *prop);
488 RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
489 prop->version = hashtable_tokenize(&importer->table, "");
490 list_set_ptr(&prop->packages, pkg->data);
492 /* Update property list of pkg */
493 array_init(&pkgprops);
494 list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
495 newprop = array_add(&pkgprops, sizeof *newprop);
496 *newprop = prop - (struct razor_property *)importer->set->properties.data;
497 list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
498 array_release(&pkgprops);
502 array_release(&importer->file_requires);
506 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
508 struct razor_package *p, *packages;
510 struct razor_entry *e, *end;
515 count = set->packages.size / sizeof *p;
516 pkgs = zalloc(count * sizeof *pkgs);
518 end = set->files.data + set->files.size;
519 for (e = set->files.data; e < end; e++) {
520 list_remap_head(&e->packages, rmap);
521 r = list_first(&e->packages, &set->package_pool);
523 q = array_add(&pkgs[r->data], sizeof *q);
524 *q = e - (struct razor_entry *) set->files.data;
529 packages = set->packages.data;
530 for (i = 0; i < count; i++) {
531 list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
532 array_release(&pkgs[i]);
538 * razor_importer_finish:
539 * @importer: the %razor_importer
541 * Finish importing packages and create the package set. This sorts
542 * and indexes all the packages, properties and files in the importer
543 * and creates a new %razor_set. After creating the new package set,
544 * the importer is destroyed.
546 * Returns: the new %razor_set
548 RAZOR_EXPORT struct razor_set *
549 razor_importer_finish(struct razor_importer *importer)
551 struct razor_set *set;
552 uint32_t *map, *rmap;
555 build_file_tree(importer);
556 find_file_provides(importer);
558 map = uniqueify_properties(importer->set);
559 list_remap_pool(&importer->set->property_pool, map);
562 count = importer->set->packages.size / sizeof(struct razor_package);
563 map = razor_qsort_with_data(importer->set->packages.data,
565 sizeof(struct razor_package),
569 rmap = malloc(count * sizeof *rmap);
570 for (i = 0; i < count; i++)
574 list_remap_pool(&importer->set->package_pool, rmap);
575 build_package_file_lists(importer->set, rmap);
576 remap_property_package_links(&importer->set->properties, rmap);
580 hashtable_release(&importer->table);
581 hashtable_release(&importer->details_table);
582 hashtable_release(&importer->file_table);