librazor/importer.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 23:13:09 2008 -0400 (2008-06-20)
changeset 257 0c3db660514d
parent 249 061a5b815727
child 259 5b0601d184ed
permissions -rw-r--r--
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.
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@248
    26
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@248
    45
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@248
    56
void
krh@248
    57
razor_importer_add_property(struct razor_importer *importer,
krh@248
    58
			    const char *name,
krh@248
    59
			    uint32_t flags,
krh@248
    60
			    const char *version)
krh@248
    61
{
krh@248
    62
	struct razor_property *p;
krh@248
    63
	uint32_t *r;
krh@248
    64
krh@248
    65
	p = array_add(&importer->set->properties, sizeof *p);
krh@248
    66
	p->name = hashtable_tokenize(&importer->table, name);
krh@248
    67
	p->flags = flags;
krh@248
    68
	p->version = hashtable_tokenize(&importer->table, version);
krh@248
    69
	list_set_ptr(&p->packages, importer->package -
krh@248
    70
		     (struct razor_package *) importer->set->packages.data);
krh@248
    71
krh@248
    72
	r = array_add(&importer->properties, sizeof *r);
krh@248
    73
	*r = p - (struct razor_property *) importer->set->properties.data;
krh@248
    74
krh@248
    75
	if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
krh@248
    76
	    *name == '/') {
krh@248
    77
		r = array_add(&importer->file_requires, sizeof *r);
krh@248
    78
		*r = p->name;
krh@248
    79
	}
krh@248
    80
}
krh@248
    81
krh@248
    82
void
krh@248
    83
razor_importer_add_file(struct razor_importer *importer, const char *name)
krh@248
    84
{
krh@248
    85
	struct import_entry *e;
krh@248
    86
krh@248
    87
	e = array_add(&importer->files, sizeof *e);
krh@248
    88
krh@248
    89
	e->package = importer->package -
krh@248
    90
		(struct razor_package *) importer->set->packages.data;
krh@248
    91
	e->name = strdup(name);
krh@248
    92
}
krh@248
    93
krh@248
    94
struct razor_importer *
krh@249
    95
razor_importer_create(void)
krh@248
    96
{
krh@248
    97
	struct razor_importer *importer;
krh@248
    98
krh@248
    99
	importer = zalloc(sizeof *importer);
krh@248
   100
	importer->set = razor_set_create();
krh@248
   101
	hashtable_init(&importer->table, &importer->set->string_pool);
krh@248
   102
krh@248
   103
	return importer;
krh@248
   104
}
krh@248
   105
krh@248
   106
/* Destroy an importer without creating the set. */
krh@248
   107
void
krh@248
   108
razor_importer_destroy(struct razor_importer *importer)
krh@248
   109
{
krh@248
   110
	/* FIXME: write this */
krh@248
   111
}
krh@248
   112
krh@248
   113
static int
krh@248
   114
compare_packages(const void *p1, const void *p2, void *data)
krh@248
   115
{
krh@248
   116
	const struct razor_package *pkg1 = p1, *pkg2 = p2;
krh@248
   117
	struct razor_set *set = data;
krh@248
   118
	char *pool = set->string_pool.data;
krh@248
   119
krh@248
   120
	/* FIXME: what if the flags are different? */
krh@248
   121
	if (pkg1->name == pkg2->name)
krh@248
   122
		return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
krh@248
   123
	else
krh@248
   124
		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
krh@248
   125
}
krh@248
   126
krh@248
   127
static int
krh@248
   128
compare_properties(const void *p1, const void *p2, void *data)
krh@248
   129
{
krh@248
   130
	const struct razor_property *prop1 = p1, *prop2 = p2;
krh@248
   131
	struct razor_set *set = data;
krh@248
   132
	char *pool = set->string_pool.data;
krh@248
   133
krh@248
   134
	if (prop1->name != prop2->name)
krh@248
   135
		return strcmp(&pool[prop1->name], &pool[prop2->name]);
krh@248
   136
	else if (prop1->flags != prop2->flags)
krh@248
   137
		return prop1->flags - prop2->flags;
krh@257
   138
	else if (prop1->version != prop2->version)
krh@257
   139
		return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@248
   140
	else
krh@257
   141
		return prop1->packages.list_ptr - prop2->packages.list_ptr;
krh@248
   142
}
krh@248
   143
krh@248
   144
static uint32_t *
krh@248
   145
uniqueify_properties(struct razor_set *set)
krh@248
   146
{
krh@248
   147
	struct razor_property *rp, *up, *rp_end;
krh@248
   148
	struct array *pkgs, *p;
krh@248
   149
	struct list_head *r;
krh@248
   150
	uint32_t *map, *rmap;
krh@248
   151
	int i, count, unique;
krh@248
   152
krh@248
   153
	count = set->properties.size / sizeof(struct razor_property);
krh@248
   154
	map = razor_qsort_with_data(set->properties.data,
krh@248
   155
				    count,
krh@248
   156
				    sizeof(struct razor_property),
krh@248
   157
				    compare_properties,
krh@248
   158
				    set);
krh@248
   159
krh@248
   160
	rp_end = set->properties.data + set->properties.size;
krh@248
   161
	rmap = malloc(count * sizeof *map);
krh@248
   162
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   163
	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
krh@248
   164
		if (rp->name != up->name ||
krh@248
   165
		    rp->flags != up->flags ||
krh@248
   166
		    rp->version != up->version) {
krh@248
   167
			up++;
krh@248
   168
			up->name = rp->name;
krh@248
   169
			up->flags = rp->flags;
krh@248
   170
			up->version = rp->version;
krh@248
   171
		}
krh@248
   172
krh@248
   173
		unique = up - (struct razor_property *) set->properties.data;
krh@248
   174
		rmap[map[i]] = unique;
krh@248
   175
		r = array_add(&pkgs[unique], sizeof *r);
krh@248
   176
		*r = rp->packages;
krh@248
   177
	}
krh@248
   178
	free(map);
krh@248
   179
krh@248
   180
	if (up != rp)
krh@248
   181
		up++;
krh@248
   182
	set->properties.size = (void *) up - set->properties.data;
krh@248
   183
	rp_end = up;
krh@248
   184
	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
krh@248
   185
		list_set_array(&rp->packages, &set->package_pool, p, 0);
krh@248
   186
		array_release(p);
krh@248
   187
	}
krh@248
   188
krh@248
   189
	free(pkgs);
krh@248
   190
krh@248
   191
	return rmap;
krh@248
   192
}
krh@248
   193
krh@248
   194
static int
krh@248
   195
compare_filenames(const void *p1, const void *p2, void *data)
krh@248
   196
{
krh@248
   197
	const struct import_entry *e1 = p1;
krh@248
   198
	const struct import_entry *e2 = p2;
krh@248
   199
	const char *n1 = e1->name;
krh@248
   200
	const char *n2 = e2->name;
krh@248
   201
krh@248
   202
	/* Need to make sure that the contents of a directory
krh@248
   203
	 * are sorted immediately after it. So "foo/bar" has to
krh@248
   204
	 * sort before "foo.conf"
krh@248
   205
	 *
krh@248
   206
	 * FIXME: this is about 60% slower than strcmp
krh@248
   207
	 */
krh@248
   208
	while (*n1 && *n2) {
krh@248
   209
		if (*n1 < *n2)
krh@248
   210
			return *n2 == '/' ? 1 : -1;
krh@248
   211
		else if (*n1 > *n2)
krh@248
   212
			return *n1 == '/' ? -1 : 1;
krh@248
   213
		n1++;
krh@248
   214
		n2++;
krh@248
   215
	}
krh@248
   216
	if (*n1)
krh@248
   217
		return 1;
krh@248
   218
	else if (*n2)
krh@248
   219
		return -1;
krh@248
   220
	else
krh@248
   221
		return 0;
krh@248
   222
}
krh@248
   223
krh@248
   224
static void
krh@248
   225
count_entries(struct import_directory *d)
krh@248
   226
{
krh@248
   227
	struct import_directory *p, *end;
krh@248
   228
krh@248
   229
	p = d->files.data;
krh@248
   230
	end = d->files.data + d->files.size;
krh@248
   231
	d->count = 0;
krh@248
   232
	while (p < end) {
krh@248
   233
		count_entries(p);
krh@248
   234
		d->count += p->count + 1;
krh@248
   235
		p++;
krh@248
   236
	}
krh@248
   237
}
krh@248
   238
krh@248
   239
static void
krh@248
   240
serialize_files(struct razor_set *set,
krh@248
   241
		struct import_directory *d, struct array *array)
krh@248
   242
{
krh@248
   243
	struct import_directory *p, *end;
krh@248
   244
	struct razor_entry *e = NULL;
krh@248
   245
	uint32_t s;
krh@248
   246
krh@248
   247
	p = d->files.data;
krh@248
   248
	end = d->files.data + d->files.size;
krh@248
   249
	s = array->size / sizeof *e + d->files.size / sizeof *p;
krh@248
   250
	while (p < end) {
krh@248
   251
		e = array_add(array, sizeof *e);
krh@248
   252
		e->name = p->name;
krh@248
   253
		e->flags = 0;
krh@248
   254
		e->start = p->count > 0 ? s : 0;
krh@248
   255
		s += p->count;
krh@248
   256
krh@248
   257
		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
krh@248
   258
		array_release(&p->packages);
krh@248
   259
		p++;
krh@248
   260
	}
krh@248
   261
	if (e != NULL)
krh@248
   262
		e->flags |= RAZOR_ENTRY_LAST;
krh@248
   263
krh@248
   264
	p = d->files.data;
krh@248
   265
	end = d->files.data + d->files.size;
krh@248
   266
	while (p < end) {
krh@248
   267
		serialize_files(set, p, array);
krh@248
   268
		p++;
krh@248
   269
	}
krh@248
   270
}
krh@248
   271
krh@248
   272
static void
krh@248
   273
remap_property_package_links(struct array *properties, uint32_t *rmap)
krh@248
   274
{
krh@248
   275
	struct razor_property *p, *end;
krh@248
   276
krh@248
   277
	end = properties->data + properties->size;
krh@248
   278
	for (p = properties->data; p < end; p++)
krh@248
   279
		list_remap_head(&p->packages, rmap);
krh@248
   280
}
krh@248
   281
krh@248
   282
static void
krh@248
   283
build_file_tree(struct razor_importer *importer)
krh@248
   284
{
krh@248
   285
	int count, i, length;
krh@248
   286
	struct import_entry *filenames;
krh@248
   287
	char *f, *end;
krh@248
   288
	uint32_t name, *r;
krh@248
   289
	char dirname[256];
krh@248
   290
	struct import_directory *d, root;
krh@248
   291
	struct razor_entry *e;
krh@248
   292
krh@248
   293
	count = importer->files.size / sizeof (struct import_entry);
krh@248
   294
	razor_qsort_with_data(importer->files.data,
krh@248
   295
			      count,
krh@248
   296
			      sizeof (struct import_entry),
krh@248
   297
			      compare_filenames,
krh@248
   298
			      NULL);
krh@248
   299
krh@248
   300
	root.name = hashtable_tokenize(&importer->table, "");
krh@248
   301
	array_init(&root.files);
krh@248
   302
	array_init(&root.packages);
krh@248
   303
	root.last = NULL;
krh@248
   304
krh@248
   305
	filenames = importer->files.data;
krh@248
   306
	for (i = 0; i < count; i++) {
krh@248
   307
		f = filenames[i].name;
krh@248
   308
		if (*f != '/')
krh@248
   309
			continue;
krh@248
   310
		f++;
krh@248
   311
krh@248
   312
		d = &root;
krh@248
   313
		while (*f) {
krh@248
   314
			end = strchr(f, '/');
krh@248
   315
			if (end == NULL)
krh@248
   316
				end = f + strlen(f);
krh@248
   317
			length = end - f;
krh@248
   318
			memcpy(dirname, f, length);
krh@248
   319
			dirname[length] ='\0';
krh@248
   320
			name = hashtable_tokenize(&importer->table, dirname);
krh@248
   321
			if (d->last == NULL || d->last->name != name) {
krh@248
   322
				d->last = array_add(&d->files, sizeof *d);
krh@248
   323
				d->last->name = name;
krh@248
   324
				d->last->last = NULL;
krh@248
   325
				array_init(&d->last->files);
krh@248
   326
				array_init(&d->last->packages);
krh@248
   327
			}
krh@248
   328
			d = d->last;
krh@248
   329
			f = end + 1;
krh@248
   330
			if (*end == '\0')
krh@248
   331
				break;
krh@248
   332
		}
krh@248
   333
krh@248
   334
		r = array_add(&d->packages, sizeof *r);
krh@248
   335
		*r = filenames[i].package;
krh@248
   336
		free(filenames[i].name);
krh@248
   337
	}
krh@248
   338
krh@248
   339
	count_entries(&root);
krh@248
   340
	e = importer->set->files.data;
krh@248
   341
	e->name = root.name;
krh@248
   342
	e->flags = RAZOR_ENTRY_LAST;
krh@248
   343
	e->start = importer->files.size ? 1 : 0;
krh@248
   344
	list_set_empty(&e->packages);
krh@248
   345
krh@248
   346
	serialize_files(importer->set, &root, &importer->set->files);
krh@248
   347
krh@248
   348
	array_release(&importer->files);
krh@248
   349
}
krh@248
   350
krh@248
   351
static void
krh@248
   352
list_to_array(struct list *list, struct array *array)
krh@248
   353
{
krh@248
   354
	uint32_t *item;
krh@248
   355
krh@248
   356
	while (list) {
krh@248
   357
		 item = array_add(array, sizeof *item);
krh@248
   358
		 *item = list->data;
krh@248
   359
		 list = list_next(list);
krh@248
   360
	}
krh@248
   361
}
krh@248
   362
krh@248
   363
static int
krh@248
   364
compare_file_requires(const void *p1, const void *p2, void *data)
krh@248
   365
{
krh@248
   366
	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
krh@248
   367
	const char *pool = data;
krh@248
   368
krh@248
   369
	return strcmp(&pool[*f1], &pool[*f2]);
krh@248
   370
}
krh@248
   371
krh@248
   372
static void
krh@248
   373
find_file_provides(struct razor_importer *importer)
krh@248
   374
{
krh@248
   375
	struct razor_property *prop;
krh@248
   376
	struct razor_entry *top, *entry;
krh@248
   377
	struct razor_package *packages;
krh@248
   378
	struct array pkgprops;
krh@248
   379
	struct list *pkg;
krh@248
   380
	uint32_t *req, *req_start, *req_end;
krh@248
   381
	uint32_t *map, *newprop;
krh@248
   382
	char *pool;
krh@248
   383
krh@248
   384
	pool = importer->set->string_pool.data;
krh@248
   385
	packages = importer->set->packages.data;
krh@248
   386
	top = importer->set->files.data;
krh@248
   387
krh@248
   388
	req = req_start = importer->file_requires.data;
krh@248
   389
	req_end = importer->file_requires.data + importer->file_requires.size;
krh@248
   390
	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
krh@248
   391
				    compare_file_requires, pool);
krh@248
   392
	free(map);
krh@248
   393
krh@248
   394
	for (req = req_start; req < req_end; req++) {
krh@248
   395
		if (req > req_start && req[0] == req[-1])
krh@248
   396
			continue;
krh@248
   397
		entry = razor_set_find_entry(importer->set, top, &pool[*req]);
krh@248
   398
		if (!entry)
krh@248
   399
			continue;
krh@248
   400
krh@248
   401
		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
krh@248
   402
			prop = array_add(&importer->set->properties, sizeof *prop);
krh@248
   403
			prop->name = *req;
krh@248
   404
			prop->flags =
krh@248
   405
				RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
krh@248
   406
			prop->version = hashtable_tokenize(&importer->table, "");
krh@248
   407
			list_set_ptr(&prop->packages, pkg->data);
krh@248
   408
krh@248
   409
			/* Update property list of pkg */
krh@248
   410
			array_init(&pkgprops);
krh@248
   411
			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
krh@248
   412
			newprop = array_add(&pkgprops, sizeof *newprop);
krh@248
   413
			*newprop = prop - (struct razor_property *)importer->set->properties.data;
krh@248
   414
			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
krh@248
   415
			array_release(&pkgprops);
krh@248
   416
		}
krh@248
   417
	}
krh@248
   418
krh@248
   419
	array_release(&importer->file_requires);
krh@248
   420
}
krh@248
   421
krh@248
   422
static void
krh@248
   423
build_package_file_lists(struct razor_set *set, uint32_t *rmap)
krh@248
   424
{
krh@248
   425
	struct razor_package *p, *packages;
krh@248
   426
	struct array *pkgs;
krh@248
   427
	struct razor_entry *e, *end;
krh@248
   428
	struct list *r;
krh@248
   429
	uint32_t *q;
krh@248
   430
	int i, count;
krh@248
   431
krh@248
   432
	count = set->packages.size / sizeof *p;
krh@248
   433
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   434
krh@248
   435
	end = set->files.data + set->files.size;
krh@248
   436
	for (e = set->files.data; e < end; e++) {
krh@248
   437
		list_remap_head(&e->packages, rmap);
krh@248
   438
		r = list_first(&e->packages, &set->package_pool);
krh@248
   439
		while (r) {
krh@248
   440
			q = array_add(&pkgs[r->data], sizeof *q);
krh@248
   441
			*q = e - (struct razor_entry *) set->files.data;
krh@248
   442
			r = list_next(r);
krh@248
   443
		}
krh@248
   444
	}
krh@248
   445
krh@248
   446
	packages = set->packages.data;
krh@248
   447
	for (i = 0; i < count; i++) {
krh@248
   448
		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
krh@248
   449
		array_release(&pkgs[i]);
krh@248
   450
	}
krh@248
   451
	free(pkgs);
krh@248
   452
}
krh@248
   453
krh@248
   454
struct razor_set *
krh@248
   455
razor_importer_finish(struct razor_importer *importer)
krh@248
   456
{
krh@248
   457
	struct razor_set *set;
krh@248
   458
	uint32_t *map, *rmap;
krh@248
   459
	int i, count;
krh@248
   460
krh@248
   461
	build_file_tree(importer);
krh@248
   462
	find_file_provides(importer);
krh@248
   463
krh@248
   464
	map = uniqueify_properties(importer->set);
krh@248
   465
	list_remap_pool(&importer->set->property_pool, map);
krh@248
   466
	free(map);
krh@248
   467
krh@248
   468
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@248
   469
	map = razor_qsort_with_data(importer->set->packages.data,
krh@248
   470
				    count,
krh@248
   471
				    sizeof(struct razor_package),
krh@248
   472
				    compare_packages,
krh@248
   473
				    importer->set);
krh@248
   474
krh@248
   475
	rmap = malloc(count * sizeof *rmap);
krh@248
   476
	for (i = 0; i < count; i++)
krh@248
   477
		rmap[map[i]] = i;
krh@248
   478
	free(map);
krh@248
   479
krh@248
   480
	list_remap_pool(&importer->set->package_pool, rmap);
krh@248
   481
	build_package_file_lists(importer->set, rmap);
krh@248
   482
	remap_property_package_links(&importer->set->properties, rmap);
krh@248
   483
	free(rmap);
krh@248
   484
krh@248
   485
	set = importer->set;
krh@248
   486
	hashtable_release(&importer->table);
krh@248
   487
	free(importer);
krh@248
   488
krh@248
   489
	return set;
krh@248
   490
}