librazor/importer.c
author James Bowes <jbowes@redhat.com>
Wed Jun 25 21:11:33 2008 -0400 (2008-06-25)
changeset 285 264c878c62d1
parent 264 634e54ca476c
child 309 a69289c9080c
permissions -rw-r--r--
Update gitignore files for docs and test-driver
krh@248
     1
/*
krh@248
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
krh@248
     3
 * Copyright (C) 2008  Red Hat, Inc
krh@248
     4
 *
krh@248
     5
 * This program is free software; you can redistribute it and/or modify
krh@248
     6
 * it under the terms of the GNU General Public License as published by
krh@248
     7
 * the Free Software Foundation; either version 2 of the License, or
krh@248
     8
 * (at your option) any later version.
krh@248
     9
 *
krh@248
    10
 * This program is distributed in the hope that it will be useful,
krh@248
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
krh@248
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
krh@248
    13
 * GNU General Public License for more details.
krh@248
    14
 *
krh@248
    15
 * You should have received a copy of the GNU General Public License along
krh@248
    16
 * with this program; if not, write to the Free Software Foundation, Inc.,
krh@248
    17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
krh@248
    18
 */
krh@248
    19
krh@248
    20
#define _GNU_SOURCE
krh@248
    21
krh@248
    22
#include <string.h>
krh@248
    23
#include "razor-internal.h"
krh@248
    24
#include "razor.h"
krh@248
    25
krh@269
    26
RAZOR_EXPORT void
krh@248
    27
razor_importer_begin_package(struct razor_importer *importer,
krh@248
    28
			     const char *name,
krh@248
    29
			     const char *version,
krh@248
    30
			     const char *arch)
krh@248
    31
{
krh@248
    32
	struct razor_package *p;
krh@248
    33
krh@248
    34
	p = array_add(&importer->set->packages, sizeof *p);
krh@248
    35
	p->name = hashtable_tokenize(&importer->table, name);
krh@248
    36
	p->flags = 0;
krh@248
    37
	p->version = hashtable_tokenize(&importer->table, version);
krh@248
    38
	p->arch = hashtable_tokenize(&importer->table, arch);
krh@248
    39
krh@248
    40
	importer->package = p;
krh@248
    41
	array_init(&importer->properties);
krh@248
    42
}
krh@248
    43
krh@248
    44
krh@269
    45
RAZOR_EXPORT void
krh@248
    46
razor_importer_finish_package(struct razor_importer *importer)
krh@248
    47
{
krh@248
    48
	list_set_array(&importer->package->properties,
krh@248
    49
		       &importer->set->property_pool,
krh@248
    50
		       &importer->properties,
krh@248
    51
		       1);
krh@248
    52
krh@248
    53
	array_release(&importer->properties);
krh@248
    54
}
krh@248
    55
krh@269
    56
RAZOR_EXPORT void
jbowes@258
    57
razor_importer_add_details(struct razor_importer *importer,
jbowes@258
    58
			   const char *summary,
jbowes@258
    59
			   const char *description,
jbowes@258
    60
			   const char *url,
jbowes@258
    61
			   const char *license)
jbowes@258
    62
{
jbowes@258
    63
	importer->package->summary = hashtable_tokenize(&importer->details_table, summary);
jbowes@258
    64
	importer->package->description = hashtable_tokenize(&importer->details_table, description);
jbowes@258
    65
	importer->package->url = hashtable_tokenize(&importer->details_table, url);
jbowes@258
    66
	importer->package->license = hashtable_tokenize(&importer->details_table, license);
jbowes@258
    67
}
jbowes@258
    68
krh@269
    69
RAZOR_EXPORT void
krh@248
    70
razor_importer_add_property(struct razor_importer *importer,
krh@248
    71
			    const char *name,
krh@248
    72
			    uint32_t flags,
krh@248
    73
			    const char *version)
krh@248
    74
{
krh@248
    75
	struct razor_property *p;
krh@248
    76
	uint32_t *r;
krh@248
    77
krh@248
    78
	p = array_add(&importer->set->properties, sizeof *p);
krh@248
    79
	p->name = hashtable_tokenize(&importer->table, name);
krh@248
    80
	p->flags = flags;
krh@248
    81
	p->version = hashtable_tokenize(&importer->table, version);
krh@248
    82
	list_set_ptr(&p->packages, importer->package -
krh@248
    83
		     (struct razor_package *) importer->set->packages.data);
krh@248
    84
krh@248
    85
	r = array_add(&importer->properties, sizeof *r);
krh@248
    86
	*r = p - (struct razor_property *) importer->set->properties.data;
krh@248
    87
krh@248
    88
	if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
krh@248
    89
	    *name == '/') {
krh@248
    90
		r = array_add(&importer->file_requires, sizeof *r);
krh@248
    91
		*r = p->name;
krh@248
    92
	}
krh@248
    93
}
krh@248
    94
krh@269
    95
RAZOR_EXPORT void
krh@248
    96
razor_importer_add_file(struct razor_importer *importer, const char *name)
krh@248
    97
{
krh@248
    98
	struct import_entry *e;
krh@248
    99
krh@248
   100
	e = array_add(&importer->files, sizeof *e);
krh@248
   101
krh@248
   102
	e->package = importer->package -
krh@248
   103
		(struct razor_package *) importer->set->packages.data;
krh@248
   104
	e->name = strdup(name);
krh@248
   105
}
krh@248
   106
krh@269
   107
RAZOR_EXPORT struct razor_importer *
krh@249
   108
razor_importer_create(void)
krh@248
   109
{
krh@248
   110
	struct razor_importer *importer;
krh@248
   111
krh@248
   112
	importer = zalloc(sizeof *importer);
krh@248
   113
	importer->set = razor_set_create();
krh@248
   114
	hashtable_init(&importer->table, &importer->set->string_pool);
jbowes@258
   115
	hashtable_init(&importer->details_table,
jbowes@258
   116
		       &importer->set->details_string_pool);
jbowes@258
   117
	hashtable_init(&importer->file_table,
jbowes@258
   118
		       &importer->set->file_string_pool);
krh@248
   119
krh@248
   120
	return importer;
krh@248
   121
}
krh@248
   122
krh@248
   123
/* Destroy an importer without creating the set. */
krh@269
   124
RAZOR_EXPORT void
krh@248
   125
razor_importer_destroy(struct razor_importer *importer)
krh@248
   126
{
krh@248
   127
	/* FIXME: write this */
krh@248
   128
}
krh@248
   129
krh@248
   130
static int
krh@248
   131
compare_packages(const void *p1, const void *p2, void *data)
krh@248
   132
{
krh@248
   133
	const struct razor_package *pkg1 = p1, *pkg2 = p2;
krh@248
   134
	struct razor_set *set = data;
krh@248
   135
	char *pool = set->string_pool.data;
krh@248
   136
krh@248
   137
	/* FIXME: what if the flags are different? */
krh@248
   138
	if (pkg1->name == pkg2->name)
krh@248
   139
		return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
krh@248
   140
	else
krh@248
   141
		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
krh@248
   142
}
krh@248
   143
krh@248
   144
static int
krh@248
   145
compare_properties(const void *p1, const void *p2, void *data)
krh@248
   146
{
krh@248
   147
	const struct razor_property *prop1 = p1, *prop2 = p2;
krh@248
   148
	struct razor_set *set = data;
krh@248
   149
	char *pool = set->string_pool.data;
krh@248
   150
krh@248
   151
	if (prop1->name != prop2->name)
krh@248
   152
		return strcmp(&pool[prop1->name], &pool[prop2->name]);
krh@248
   153
	else if (prop1->flags != prop2->flags)
krh@248
   154
		return prop1->flags - prop2->flags;
krh@257
   155
	else if (prop1->version != prop2->version)
krh@257
   156
		return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@248
   157
	else
krh@257
   158
		return prop1->packages.list_ptr - prop2->packages.list_ptr;
krh@248
   159
}
krh@248
   160
krh@248
   161
static uint32_t *
krh@248
   162
uniqueify_properties(struct razor_set *set)
krh@248
   163
{
krh@248
   164
	struct razor_property *rp, *up, *rp_end;
krh@248
   165
	struct array *pkgs, *p;
krh@248
   166
	struct list_head *r;
krh@248
   167
	uint32_t *map, *rmap;
krh@248
   168
	int i, count, unique;
krh@248
   169
krh@248
   170
	count = set->properties.size / sizeof(struct razor_property);
krh@248
   171
	map = razor_qsort_with_data(set->properties.data,
krh@248
   172
				    count,
krh@248
   173
				    sizeof(struct razor_property),
krh@248
   174
				    compare_properties,
krh@248
   175
				    set);
krh@248
   176
krh@248
   177
	rp_end = set->properties.data + set->properties.size;
krh@248
   178
	rmap = malloc(count * sizeof *map);
krh@248
   179
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   180
	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
krh@248
   181
		if (rp->name != up->name ||
krh@248
   182
		    rp->flags != up->flags ||
krh@248
   183
		    rp->version != up->version) {
krh@248
   184
			up++;
krh@248
   185
			up->name = rp->name;
krh@248
   186
			up->flags = rp->flags;
krh@248
   187
			up->version = rp->version;
krh@248
   188
		}
krh@248
   189
krh@248
   190
		unique = up - (struct razor_property *) set->properties.data;
krh@248
   191
		rmap[map[i]] = unique;
krh@248
   192
		r = array_add(&pkgs[unique], sizeof *r);
krh@248
   193
		*r = rp->packages;
krh@248
   194
	}
krh@248
   195
	free(map);
krh@248
   196
krh@248
   197
	if (up != rp)
krh@248
   198
		up++;
krh@248
   199
	set->properties.size = (void *) up - set->properties.data;
krh@248
   200
	rp_end = up;
krh@248
   201
	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
krh@248
   202
		list_set_array(&rp->packages, &set->package_pool, p, 0);
krh@248
   203
		array_release(p);
krh@248
   204
	}
krh@248
   205
krh@248
   206
	free(pkgs);
krh@248
   207
krh@248
   208
	return rmap;
krh@248
   209
}
krh@248
   210
krh@248
   211
static int
krh@248
   212
compare_filenames(const void *p1, const void *p2, void *data)
krh@248
   213
{
krh@248
   214
	const struct import_entry *e1 = p1;
krh@248
   215
	const struct import_entry *e2 = p2;
krh@248
   216
	const char *n1 = e1->name;
krh@248
   217
	const char *n2 = e2->name;
krh@248
   218
krh@248
   219
	/* Need to make sure that the contents of a directory
krh@248
   220
	 * are sorted immediately after it. So "foo/bar" has to
krh@248
   221
	 * sort before "foo.conf"
krh@248
   222
	 *
krh@248
   223
	 * FIXME: this is about 60% slower than strcmp
krh@248
   224
	 */
krh@248
   225
	while (*n1 && *n2) {
krh@248
   226
		if (*n1 < *n2)
krh@248
   227
			return *n2 == '/' ? 1 : -1;
krh@248
   228
		else if (*n1 > *n2)
krh@248
   229
			return *n1 == '/' ? -1 : 1;
krh@248
   230
		n1++;
krh@248
   231
		n2++;
krh@248
   232
	}
krh@248
   233
	if (*n1)
krh@248
   234
		return 1;
krh@248
   235
	else if (*n2)
krh@248
   236
		return -1;
krh@248
   237
	else
krh@248
   238
		return 0;
krh@248
   239
}
krh@248
   240
krh@248
   241
static void
krh@248
   242
count_entries(struct import_directory *d)
krh@248
   243
{
krh@248
   244
	struct import_directory *p, *end;
krh@248
   245
krh@248
   246
	p = d->files.data;
krh@248
   247
	end = d->files.data + d->files.size;
krh@248
   248
	d->count = 0;
krh@248
   249
	while (p < end) {
krh@248
   250
		count_entries(p);
krh@248
   251
		d->count += p->count + 1;
krh@248
   252
		p++;
krh@248
   253
	}
krh@248
   254
}
krh@248
   255
krh@248
   256
static void
krh@248
   257
serialize_files(struct razor_set *set,
krh@248
   258
		struct import_directory *d, struct array *array)
krh@248
   259
{
krh@248
   260
	struct import_directory *p, *end;
krh@248
   261
	struct razor_entry *e = NULL;
krh@248
   262
	uint32_t s;
krh@248
   263
krh@248
   264
	p = d->files.data;
krh@248
   265
	end = d->files.data + d->files.size;
krh@248
   266
	s = array->size / sizeof *e + d->files.size / sizeof *p;
krh@248
   267
	while (p < end) {
krh@248
   268
		e = array_add(array, sizeof *e);
krh@248
   269
		e->name = p->name;
krh@248
   270
		e->flags = 0;
krh@248
   271
		e->start = p->count > 0 ? s : 0;
krh@248
   272
		s += p->count;
krh@248
   273
krh@248
   274
		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
krh@248
   275
		array_release(&p->packages);
krh@248
   276
		p++;
krh@248
   277
	}
krh@248
   278
	if (e != NULL)
krh@248
   279
		e->flags |= RAZOR_ENTRY_LAST;
krh@248
   280
krh@248
   281
	p = d->files.data;
krh@248
   282
	end = d->files.data + d->files.size;
krh@248
   283
	while (p < end) {
krh@248
   284
		serialize_files(set, p, array);
krh@248
   285
		p++;
krh@248
   286
	}
krh@248
   287
}
krh@248
   288
krh@248
   289
static void
krh@248
   290
remap_property_package_links(struct array *properties, uint32_t *rmap)
krh@248
   291
{
krh@248
   292
	struct razor_property *p, *end;
krh@248
   293
krh@248
   294
	end = properties->data + properties->size;
krh@248
   295
	for (p = properties->data; p < end; p++)
krh@248
   296
		list_remap_head(&p->packages, rmap);
krh@248
   297
}
krh@248
   298
krh@248
   299
static void
krh@248
   300
build_file_tree(struct razor_importer *importer)
krh@248
   301
{
krh@248
   302
	int count, i, length;
krh@248
   303
	struct import_entry *filenames;
krh@248
   304
	char *f, *end;
krh@248
   305
	uint32_t name, *r;
krh@248
   306
	char dirname[256];
krh@248
   307
	struct import_directory *d, root;
krh@248
   308
	struct razor_entry *e;
krh@248
   309
krh@248
   310
	count = importer->files.size / sizeof (struct import_entry);
krh@248
   311
	razor_qsort_with_data(importer->files.data,
krh@248
   312
			      count,
krh@248
   313
			      sizeof (struct import_entry),
krh@248
   314
			      compare_filenames,
krh@248
   315
			      NULL);
krh@248
   316
jbowes@264
   317
	root.name = hashtable_tokenize(&importer->file_table, "");
krh@248
   318
	array_init(&root.files);
krh@248
   319
	array_init(&root.packages);
krh@248
   320
	root.last = NULL;
krh@248
   321
krh@248
   322
	filenames = importer->files.data;
krh@248
   323
	for (i = 0; i < count; i++) {
krh@248
   324
		f = filenames[i].name;
krh@248
   325
		if (*f != '/')
krh@248
   326
			continue;
krh@248
   327
		f++;
krh@248
   328
krh@248
   329
		d = &root;
krh@248
   330
		while (*f) {
krh@248
   331
			end = strchr(f, '/');
krh@248
   332
			if (end == NULL)
krh@248
   333
				end = f + strlen(f);
krh@248
   334
			length = end - f;
krh@248
   335
			memcpy(dirname, f, length);
krh@248
   336
			dirname[length] ='\0';
jbowes@264
   337
			name = hashtable_tokenize(&importer->file_table,
jbowes@264
   338
						  dirname);
krh@248
   339
			if (d->last == NULL || d->last->name != name) {
krh@248
   340
				d->last = array_add(&d->files, sizeof *d);
krh@248
   341
				d->last->name = name;
krh@248
   342
				d->last->last = NULL;
krh@248
   343
				array_init(&d->last->files);
krh@248
   344
				array_init(&d->last->packages);
krh@248
   345
			}
krh@248
   346
			d = d->last;
krh@248
   347
			f = end + 1;
krh@248
   348
			if (*end == '\0')
krh@248
   349
				break;
krh@248
   350
		}
krh@248
   351
krh@248
   352
		r = array_add(&d->packages, sizeof *r);
krh@248
   353
		*r = filenames[i].package;
krh@248
   354
		free(filenames[i].name);
krh@248
   355
	}
krh@248
   356
krh@248
   357
	count_entries(&root);
krh@248
   358
	e = importer->set->files.data;
krh@248
   359
	e->name = root.name;
krh@248
   360
	e->flags = RAZOR_ENTRY_LAST;
krh@248
   361
	e->start = importer->files.size ? 1 : 0;
krh@248
   362
	list_set_empty(&e->packages);
krh@248
   363
krh@248
   364
	serialize_files(importer->set, &root, &importer->set->files);
krh@248
   365
krh@248
   366
	array_release(&importer->files);
krh@248
   367
}
krh@248
   368
krh@248
   369
static void
krh@248
   370
list_to_array(struct list *list, struct array *array)
krh@248
   371
{
krh@248
   372
	uint32_t *item;
krh@248
   373
krh@248
   374
	while (list) {
krh@248
   375
		 item = array_add(array, sizeof *item);
krh@248
   376
		 *item = list->data;
krh@248
   377
		 list = list_next(list);
krh@248
   378
	}
krh@248
   379
}
krh@248
   380
krh@248
   381
static int
krh@248
   382
compare_file_requires(const void *p1, const void *p2, void *data)
krh@248
   383
{
krh@248
   384
	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
krh@248
   385
	const char *pool = data;
krh@248
   386
krh@248
   387
	return strcmp(&pool[*f1], &pool[*f2]);
krh@248
   388
}
krh@248
   389
krh@248
   390
static void
krh@248
   391
find_file_provides(struct razor_importer *importer)
krh@248
   392
{
krh@248
   393
	struct razor_property *prop;
krh@248
   394
	struct razor_entry *top, *entry;
krh@248
   395
	struct razor_package *packages;
krh@248
   396
	struct array pkgprops;
krh@248
   397
	struct list *pkg;
krh@248
   398
	uint32_t *req, *req_start, *req_end;
krh@248
   399
	uint32_t *map, *newprop;
krh@248
   400
	char *pool;
krh@248
   401
krh@248
   402
	pool = importer->set->string_pool.data;
krh@248
   403
	packages = importer->set->packages.data;
krh@248
   404
	top = importer->set->files.data;
krh@248
   405
krh@248
   406
	req = req_start = importer->file_requires.data;
krh@248
   407
	req_end = importer->file_requires.data + importer->file_requires.size;
krh@248
   408
	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
krh@248
   409
				    compare_file_requires, pool);
krh@248
   410
	free(map);
krh@248
   411
krh@248
   412
	for (req = req_start; req < req_end; req++) {
krh@248
   413
		if (req > req_start && req[0] == req[-1])
krh@248
   414
			continue;
krh@248
   415
		entry = razor_set_find_entry(importer->set, top, &pool[*req]);
krh@248
   416
		if (!entry)
krh@248
   417
			continue;
krh@248
   418
krh@248
   419
		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
krh@248
   420
			prop = array_add(&importer->set->properties, sizeof *prop);
krh@248
   421
			prop->name = *req;
krh@248
   422
			prop->flags =
krh@248
   423
				RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
krh@248
   424
			prop->version = hashtable_tokenize(&importer->table, "");
krh@248
   425
			list_set_ptr(&prop->packages, pkg->data);
krh@248
   426
krh@248
   427
			/* Update property list of pkg */
krh@248
   428
			array_init(&pkgprops);
krh@248
   429
			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
krh@248
   430
			newprop = array_add(&pkgprops, sizeof *newprop);
krh@248
   431
			*newprop = prop - (struct razor_property *)importer->set->properties.data;
krh@248
   432
			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
krh@248
   433
			array_release(&pkgprops);
krh@248
   434
		}
krh@248
   435
	}
krh@248
   436
krh@248
   437
	array_release(&importer->file_requires);
krh@248
   438
}
krh@248
   439
krh@248
   440
static void
krh@248
   441
build_package_file_lists(struct razor_set *set, uint32_t *rmap)
krh@248
   442
{
krh@248
   443
	struct razor_package *p, *packages;
krh@248
   444
	struct array *pkgs;
krh@248
   445
	struct razor_entry *e, *end;
krh@248
   446
	struct list *r;
krh@248
   447
	uint32_t *q;
krh@248
   448
	int i, count;
krh@248
   449
krh@248
   450
	count = set->packages.size / sizeof *p;
krh@248
   451
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   452
krh@248
   453
	end = set->files.data + set->files.size;
krh@248
   454
	for (e = set->files.data; e < end; e++) {
krh@248
   455
		list_remap_head(&e->packages, rmap);
krh@248
   456
		r = list_first(&e->packages, &set->package_pool);
krh@248
   457
		while (r) {
krh@248
   458
			q = array_add(&pkgs[r->data], sizeof *q);
krh@248
   459
			*q = e - (struct razor_entry *) set->files.data;
krh@248
   460
			r = list_next(r);
krh@248
   461
		}
krh@248
   462
	}
krh@248
   463
krh@248
   464
	packages = set->packages.data;
krh@248
   465
	for (i = 0; i < count; i++) {
krh@248
   466
		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
krh@248
   467
		array_release(&pkgs[i]);
krh@248
   468
	}
krh@248
   469
	free(pkgs);
krh@248
   470
}
krh@248
   471
krh@269
   472
RAZOR_EXPORT struct razor_set *
krh@248
   473
razor_importer_finish(struct razor_importer *importer)
krh@248
   474
{
krh@248
   475
	struct razor_set *set;
krh@248
   476
	uint32_t *map, *rmap;
krh@248
   477
	int i, count;
krh@248
   478
krh@248
   479
	build_file_tree(importer);
krh@248
   480
	find_file_provides(importer);
krh@248
   481
krh@248
   482
	map = uniqueify_properties(importer->set);
krh@248
   483
	list_remap_pool(&importer->set->property_pool, map);
krh@248
   484
	free(map);
krh@248
   485
krh@248
   486
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@248
   487
	map = razor_qsort_with_data(importer->set->packages.data,
krh@248
   488
				    count,
krh@248
   489
				    sizeof(struct razor_package),
krh@248
   490
				    compare_packages,
krh@248
   491
				    importer->set);
krh@248
   492
krh@248
   493
	rmap = malloc(count * sizeof *rmap);
krh@248
   494
	for (i = 0; i < count; i++)
krh@248
   495
		rmap[map[i]] = i;
krh@248
   496
	free(map);
krh@248
   497
krh@248
   498
	list_remap_pool(&importer->set->package_pool, rmap);
krh@248
   499
	build_package_file_lists(importer->set, rmap);
krh@248
   500
	remap_property_package_links(&importer->set->properties, rmap);
krh@248
   501
	free(rmap);
krh@248
   502
krh@248
   503
	set = importer->set;
krh@248
   504
	hashtable_release(&importer->table);
jbowes@264
   505
	hashtable_release(&importer->details_table);
jbowes@264
   506
	hashtable_release(&importer->file_table);
krh@248
   507
	free(importer);
krh@248
   508
krh@248
   509
	return set;
krh@248
   510
}