Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
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;
370 uint32_t name, *r, s;
371 char rootname[256], dirname[256];
372 struct import_directory *d, *last_root;
374 struct razor_entry *e;
376 count = importer->files.size / sizeof (struct import_entry);
377 filenames = importer->files.data;
378 razor_qsort_with_data(filenames,
380 sizeof (struct import_entry),
387 for (i = 0; i < count; i++) {
388 f = filenames[i].name;
391 end = strchr(f, '/');
395 memcpy(dirname, f, length);
396 dirname[length] = '\0';
397 name = hashtable_tokenize(&importer->file_table,
400 if (!last_root || last_root->name != name) {
401 d = array_add(&roots, sizeof *d);
404 array_init(&d->files);
405 array_init(&d->packages);
410 if (!d->last || d->last->name != name) {
411 d->last = array_add(&d->files,
413 d->last->name = name;
414 d->last->last = NULL;
415 array_init(&d->last->files);
416 array_init(&d->last->packages);
425 r = array_add(&d->packages, sizeof *r);
426 *r = filenames[i].package;
427 free(filenames[i].name);
430 count = roots.size / sizeof (struct import_directory);
433 for (i = 0; i < count; i++) {
436 e = array_add(&importer->set->files, sizeof *e);
438 e = importer->set->files.data;
441 e->start = d->count > 0 ? s : 0;
443 list_set_empty(&e->packages);
447 e->flags |= RAZOR_ENTRY_LAST;
450 for (i = 0; i < count; i++) {
451 serialize_files(importer->set, d, &importer->set->files);
455 array_release(&importer->files);
456 array_release(&roots);
460 list_to_array(struct list *list, struct array *array)
465 item = array_add(array, sizeof *item);
467 list = list_next(list);
472 compare_file_requires(const void *p1, const void *p2, void *data)
474 uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
475 const char *pool = data;
477 return strcmp(&pool[*f1], &pool[*f2]);
481 find_file_provides(struct razor_importer *importer)
483 struct razor_property *prop;
484 struct razor_entry *top, *entry;
485 struct razor_package *packages;
486 struct array pkgprops;
488 uint32_t *req, *req_start, *req_end;
489 uint32_t *map, *newprop;
492 pool = importer->set->string_pool.data;
493 packages = importer->set->packages.data;
494 top = importer->set->files.data;
496 req = req_start = importer->file_requires.data;
497 req_end = importer->file_requires.data + importer->file_requires.size;
498 map = razor_qsort_with_data(req, req_end - req, sizeof *req,
499 compare_file_requires, pool);
502 for (req = req_start; req < req_end; req++) {
503 if (req > req_start && req[0] == req[-1])
505 entry = razor_set_find_entry(importer->set, top, &pool[*req]);
509 for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
510 prop = array_add(&importer->set->properties, sizeof *prop);
513 RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
514 prop->version = hashtable_tokenize(&importer->table, "");
515 list_set_ptr(&prop->packages, pkg->data);
517 /* Update property list of pkg */
518 array_init(&pkgprops);
519 list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
520 newprop = array_add(&pkgprops, sizeof *newprop);
521 *newprop = prop - (struct razor_property *)importer->set->properties.data;
522 list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
523 array_release(&pkgprops);
527 array_release(&importer->file_requires);
531 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
533 struct razor_package *p, *packages;
535 struct razor_entry *e, *end;
540 count = set->packages.size / sizeof *p;
541 pkgs = zalloc(count * sizeof *pkgs);
543 end = set->files.data + set->files.size;
544 for (e = set->files.data; e < end; e++) {
545 list_remap_head(&e->packages, rmap);
546 r = list_first(&e->packages, &set->package_pool);
548 q = array_add(&pkgs[r->data], sizeof *q);
549 *q = e - (struct razor_entry *) set->files.data;
554 packages = set->packages.data;
555 for (i = 0; i < count; i++) {
556 list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
557 array_release(&pkgs[i]);
563 * razor_importer_finish:
564 * @importer: the %razor_importer
566 * Finish importing packages and create the package set. This sorts
567 * and indexes all the packages, properties and files in the importer
568 * and creates a new %razor_set. After creating the new package set,
569 * the importer is destroyed.
571 * Returns: the new %razor_set
573 RAZOR_EXPORT struct razor_set *
574 razor_importer_finish(struct razor_importer *importer)
576 struct razor_set *set;
577 uint32_t *map, *rmap;
580 build_file_tree(importer);
581 find_file_provides(importer);
583 map = uniqueify_properties(importer->set);
584 list_remap_pool(&importer->set->property_pool, map);
587 count = importer->set->packages.size / sizeof(struct razor_package);
588 map = razor_qsort_with_data(importer->set->packages.data,
590 sizeof(struct razor_package),
594 rmap = malloc(count * sizeof *rmap);
595 for (i = 0; i < count; i++)
599 list_remap_pool(&importer->set->package_pool, rmap);
600 build_package_file_lists(importer->set, rmap);
601 remap_property_package_links(&importer->set->properties, rmap);
605 hashtable_release(&importer->table);
606 hashtable_release(&importer->details_table);
607 hashtable_release(&importer->file_table);