librazor/importer.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 21:56:43 2008 -0400 (2008-06-20)
changeset 254 ccb1c11968ab
parent 248 057933050c42
child 257 0c3db660514d
permissions -rw-r--r--
Introduce install/remove iterators.

These iterator constructors lets you pass in two sets and creates
an iterator for the packages to remove or the packages to install.
The iterators will step through the packages in a sequence that respects
the pre, post, preun and postun modifiers.

Right now, the install order isn't actually implemented, this patch just
implements the API changes and updates the applications.
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@248
   138
	else
krh@248
   139
		return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@248
   140
}
krh@248
   141
krh@248
   142
static uint32_t *
krh@248
   143
uniqueify_properties(struct razor_set *set)
krh@248
   144
{
krh@248
   145
	struct razor_property *rp, *up, *rp_end;
krh@248
   146
	struct array *pkgs, *p;
krh@248
   147
	struct list_head *r;
krh@248
   148
	uint32_t *map, *rmap;
krh@248
   149
	int i, count, unique;
krh@248
   150
krh@248
   151
	count = set->properties.size / sizeof(struct razor_property);
krh@248
   152
	map = razor_qsort_with_data(set->properties.data,
krh@248
   153
				    count,
krh@248
   154
				    sizeof(struct razor_property),
krh@248
   155
				    compare_properties,
krh@248
   156
				    set);
krh@248
   157
krh@248
   158
	rp_end = set->properties.data + set->properties.size;
krh@248
   159
	rmap = malloc(count * sizeof *map);
krh@248
   160
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   161
	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
krh@248
   162
		if (rp->name != up->name ||
krh@248
   163
		    rp->flags != up->flags ||
krh@248
   164
		    rp->version != up->version) {
krh@248
   165
			up++;
krh@248
   166
			up->name = rp->name;
krh@248
   167
			up->flags = rp->flags;
krh@248
   168
			up->version = rp->version;
krh@248
   169
		}
krh@248
   170
krh@248
   171
		unique = up - (struct razor_property *) set->properties.data;
krh@248
   172
		rmap[map[i]] = unique;
krh@248
   173
		r = array_add(&pkgs[unique], sizeof *r);
krh@248
   174
		*r = rp->packages;
krh@248
   175
	}
krh@248
   176
	free(map);
krh@248
   177
krh@248
   178
	if (up != rp)
krh@248
   179
		up++;
krh@248
   180
	set->properties.size = (void *) up - set->properties.data;
krh@248
   181
	rp_end = up;
krh@248
   182
	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
krh@248
   183
		list_set_array(&rp->packages, &set->package_pool, p, 0);
krh@248
   184
		array_release(p);
krh@248
   185
	}
krh@248
   186
krh@248
   187
	free(pkgs);
krh@248
   188
krh@248
   189
	return rmap;
krh@248
   190
}
krh@248
   191
krh@248
   192
static int
krh@248
   193
compare_filenames(const void *p1, const void *p2, void *data)
krh@248
   194
{
krh@248
   195
	const struct import_entry *e1 = p1;
krh@248
   196
	const struct import_entry *e2 = p2;
krh@248
   197
	const char *n1 = e1->name;
krh@248
   198
	const char *n2 = e2->name;
krh@248
   199
krh@248
   200
	/* Need to make sure that the contents of a directory
krh@248
   201
	 * are sorted immediately after it. So "foo/bar" has to
krh@248
   202
	 * sort before "foo.conf"
krh@248
   203
	 *
krh@248
   204
	 * FIXME: this is about 60% slower than strcmp
krh@248
   205
	 */
krh@248
   206
	while (*n1 && *n2) {
krh@248
   207
		if (*n1 < *n2)
krh@248
   208
			return *n2 == '/' ? 1 : -1;
krh@248
   209
		else if (*n1 > *n2)
krh@248
   210
			return *n1 == '/' ? -1 : 1;
krh@248
   211
		n1++;
krh@248
   212
		n2++;
krh@248
   213
	}
krh@248
   214
	if (*n1)
krh@248
   215
		return 1;
krh@248
   216
	else if (*n2)
krh@248
   217
		return -1;
krh@248
   218
	else
krh@248
   219
		return 0;
krh@248
   220
}
krh@248
   221
krh@248
   222
static void
krh@248
   223
count_entries(struct import_directory *d)
krh@248
   224
{
krh@248
   225
	struct import_directory *p, *end;
krh@248
   226
krh@248
   227
	p = d->files.data;
krh@248
   228
	end = d->files.data + d->files.size;
krh@248
   229
	d->count = 0;
krh@248
   230
	while (p < end) {
krh@248
   231
		count_entries(p);
krh@248
   232
		d->count += p->count + 1;
krh@248
   233
		p++;
krh@248
   234
	}
krh@248
   235
}
krh@248
   236
krh@248
   237
static void
krh@248
   238
serialize_files(struct razor_set *set,
krh@248
   239
		struct import_directory *d, struct array *array)
krh@248
   240
{
krh@248
   241
	struct import_directory *p, *end;
krh@248
   242
	struct razor_entry *e = NULL;
krh@248
   243
	uint32_t s;
krh@248
   244
krh@248
   245
	p = d->files.data;
krh@248
   246
	end = d->files.data + d->files.size;
krh@248
   247
	s = array->size / sizeof *e + d->files.size / sizeof *p;
krh@248
   248
	while (p < end) {
krh@248
   249
		e = array_add(array, sizeof *e);
krh@248
   250
		e->name = p->name;
krh@248
   251
		e->flags = 0;
krh@248
   252
		e->start = p->count > 0 ? s : 0;
krh@248
   253
		s += p->count;
krh@248
   254
krh@248
   255
		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
krh@248
   256
		array_release(&p->packages);
krh@248
   257
		p++;
krh@248
   258
	}
krh@248
   259
	if (e != NULL)
krh@248
   260
		e->flags |= RAZOR_ENTRY_LAST;
krh@248
   261
krh@248
   262
	p = d->files.data;
krh@248
   263
	end = d->files.data + d->files.size;
krh@248
   264
	while (p < end) {
krh@248
   265
		serialize_files(set, p, array);
krh@248
   266
		p++;
krh@248
   267
	}
krh@248
   268
}
krh@248
   269
krh@248
   270
static void
krh@248
   271
remap_property_package_links(struct array *properties, uint32_t *rmap)
krh@248
   272
{
krh@248
   273
	struct razor_property *p, *end;
krh@248
   274
krh@248
   275
	end = properties->data + properties->size;
krh@248
   276
	for (p = properties->data; p < end; p++)
krh@248
   277
		list_remap_head(&p->packages, rmap);
krh@248
   278
}
krh@248
   279
krh@248
   280
static void
krh@248
   281
build_file_tree(struct razor_importer *importer)
krh@248
   282
{
krh@248
   283
	int count, i, length;
krh@248
   284
	struct import_entry *filenames;
krh@248
   285
	char *f, *end;
krh@248
   286
	uint32_t name, *r;
krh@248
   287
	char dirname[256];
krh@248
   288
	struct import_directory *d, root;
krh@248
   289
	struct razor_entry *e;
krh@248
   290
krh@248
   291
	count = importer->files.size / sizeof (struct import_entry);
krh@248
   292
	razor_qsort_with_data(importer->files.data,
krh@248
   293
			      count,
krh@248
   294
			      sizeof (struct import_entry),
krh@248
   295
			      compare_filenames,
krh@248
   296
			      NULL);
krh@248
   297
krh@248
   298
	root.name = hashtable_tokenize(&importer->table, "");
krh@248
   299
	array_init(&root.files);
krh@248
   300
	array_init(&root.packages);
krh@248
   301
	root.last = NULL;
krh@248
   302
krh@248
   303
	filenames = importer->files.data;
krh@248
   304
	for (i = 0; i < count; i++) {
krh@248
   305
		f = filenames[i].name;
krh@248
   306
		if (*f != '/')
krh@248
   307
			continue;
krh@248
   308
		f++;
krh@248
   309
krh@248
   310
		d = &root;
krh@248
   311
		while (*f) {
krh@248
   312
			end = strchr(f, '/');
krh@248
   313
			if (end == NULL)
krh@248
   314
				end = f + strlen(f);
krh@248
   315
			length = end - f;
krh@248
   316
			memcpy(dirname, f, length);
krh@248
   317
			dirname[length] ='\0';
krh@248
   318
			name = hashtable_tokenize(&importer->table, dirname);
krh@248
   319
			if (d->last == NULL || d->last->name != name) {
krh@248
   320
				d->last = array_add(&d->files, sizeof *d);
krh@248
   321
				d->last->name = name;
krh@248
   322
				d->last->last = NULL;
krh@248
   323
				array_init(&d->last->files);
krh@248
   324
				array_init(&d->last->packages);
krh@248
   325
			}
krh@248
   326
			d = d->last;
krh@248
   327
			f = end + 1;
krh@248
   328
			if (*end == '\0')
krh@248
   329
				break;
krh@248
   330
		}
krh@248
   331
krh@248
   332
		r = array_add(&d->packages, sizeof *r);
krh@248
   333
		*r = filenames[i].package;
krh@248
   334
		free(filenames[i].name);
krh@248
   335
	}
krh@248
   336
krh@248
   337
	count_entries(&root);
krh@248
   338
	e = importer->set->files.data;
krh@248
   339
	e->name = root.name;
krh@248
   340
	e->flags = RAZOR_ENTRY_LAST;
krh@248
   341
	e->start = importer->files.size ? 1 : 0;
krh@248
   342
	list_set_empty(&e->packages);
krh@248
   343
krh@248
   344
	serialize_files(importer->set, &root, &importer->set->files);
krh@248
   345
krh@248
   346
	array_release(&importer->files);
krh@248
   347
}
krh@248
   348
krh@248
   349
static void
krh@248
   350
list_to_array(struct list *list, struct array *array)
krh@248
   351
{
krh@248
   352
	uint32_t *item;
krh@248
   353
krh@248
   354
	while (list) {
krh@248
   355
		 item = array_add(array, sizeof *item);
krh@248
   356
		 *item = list->data;
krh@248
   357
		 list = list_next(list);
krh@248
   358
	}
krh@248
   359
}
krh@248
   360
krh@248
   361
static int
krh@248
   362
compare_file_requires(const void *p1, const void *p2, void *data)
krh@248
   363
{
krh@248
   364
	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
krh@248
   365
	const char *pool = data;
krh@248
   366
krh@248
   367
	return strcmp(&pool[*f1], &pool[*f2]);
krh@248
   368
}
krh@248
   369
krh@248
   370
static void
krh@248
   371
find_file_provides(struct razor_importer *importer)
krh@248
   372
{
krh@248
   373
	struct razor_property *prop;
krh@248
   374
	struct razor_entry *top, *entry;
krh@248
   375
	struct razor_package *packages;
krh@248
   376
	struct array pkgprops;
krh@248
   377
	struct list *pkg;
krh@248
   378
	uint32_t *req, *req_start, *req_end;
krh@248
   379
	uint32_t *map, *newprop;
krh@248
   380
	char *pool;
krh@248
   381
krh@248
   382
	pool = importer->set->string_pool.data;
krh@248
   383
	packages = importer->set->packages.data;
krh@248
   384
	top = importer->set->files.data;
krh@248
   385
krh@248
   386
	req = req_start = importer->file_requires.data;
krh@248
   387
	req_end = importer->file_requires.data + importer->file_requires.size;
krh@248
   388
	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
krh@248
   389
				    compare_file_requires, pool);
krh@248
   390
	free(map);
krh@248
   391
krh@248
   392
	for (req = req_start; req < req_end; req++) {
krh@248
   393
		if (req > req_start && req[0] == req[-1])
krh@248
   394
			continue;
krh@248
   395
		entry = razor_set_find_entry(importer->set, top, &pool[*req]);
krh@248
   396
		if (!entry)
krh@248
   397
			continue;
krh@248
   398
krh@248
   399
		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
krh@248
   400
			prop = array_add(&importer->set->properties, sizeof *prop);
krh@248
   401
			prop->name = *req;
krh@248
   402
			prop->flags =
krh@248
   403
				RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
krh@248
   404
			prop->version = hashtable_tokenize(&importer->table, "");
krh@248
   405
			list_set_ptr(&prop->packages, pkg->data);
krh@248
   406
krh@248
   407
			/* Update property list of pkg */
krh@248
   408
			array_init(&pkgprops);
krh@248
   409
			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
krh@248
   410
			newprop = array_add(&pkgprops, sizeof *newprop);
krh@248
   411
			*newprop = prop - (struct razor_property *)importer->set->properties.data;
krh@248
   412
			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
krh@248
   413
			array_release(&pkgprops);
krh@248
   414
		}
krh@248
   415
	}
krh@248
   416
krh@248
   417
	array_release(&importer->file_requires);
krh@248
   418
}
krh@248
   419
krh@248
   420
static void
krh@248
   421
build_package_file_lists(struct razor_set *set, uint32_t *rmap)
krh@248
   422
{
krh@248
   423
	struct razor_package *p, *packages;
krh@248
   424
	struct array *pkgs;
krh@248
   425
	struct razor_entry *e, *end;
krh@248
   426
	struct list *r;
krh@248
   427
	uint32_t *q;
krh@248
   428
	int i, count;
krh@248
   429
krh@248
   430
	count = set->packages.size / sizeof *p;
krh@248
   431
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   432
krh@248
   433
	end = set->files.data + set->files.size;
krh@248
   434
	for (e = set->files.data; e < end; e++) {
krh@248
   435
		list_remap_head(&e->packages, rmap);
krh@248
   436
		r = list_first(&e->packages, &set->package_pool);
krh@248
   437
		while (r) {
krh@248
   438
			q = array_add(&pkgs[r->data], sizeof *q);
krh@248
   439
			*q = e - (struct razor_entry *) set->files.data;
krh@248
   440
			r = list_next(r);
krh@248
   441
		}
krh@248
   442
	}
krh@248
   443
krh@248
   444
	packages = set->packages.data;
krh@248
   445
	for (i = 0; i < count; i++) {
krh@248
   446
		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
krh@248
   447
		array_release(&pkgs[i]);
krh@248
   448
	}
krh@248
   449
	free(pkgs);
krh@248
   450
}
krh@248
   451
krh@248
   452
struct razor_set *
krh@248
   453
razor_importer_finish(struct razor_importer *importer)
krh@248
   454
{
krh@248
   455
	struct razor_set *set;
krh@248
   456
	uint32_t *map, *rmap;
krh@248
   457
	int i, count;
krh@248
   458
krh@248
   459
	build_file_tree(importer);
krh@248
   460
	find_file_provides(importer);
krh@248
   461
krh@248
   462
	map = uniqueify_properties(importer->set);
krh@248
   463
	list_remap_pool(&importer->set->property_pool, map);
krh@248
   464
	free(map);
krh@248
   465
krh@248
   466
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@248
   467
	map = razor_qsort_with_data(importer->set->packages.data,
krh@248
   468
				    count,
krh@248
   469
				    sizeof(struct razor_package),
krh@248
   470
				    compare_packages,
krh@248
   471
				    importer->set);
krh@248
   472
krh@248
   473
	rmap = malloc(count * sizeof *rmap);
krh@248
   474
	for (i = 0; i < count; i++)
krh@248
   475
		rmap[map[i]] = i;
krh@248
   476
	free(map);
krh@248
   477
krh@248
   478
	list_remap_pool(&importer->set->package_pool, rmap);
krh@248
   479
	build_package_file_lists(importer->set, rmap);
krh@248
   480
	remap_property_package_links(&importer->set->properties, rmap);
krh@248
   481
	free(rmap);
krh@248
   482
krh@248
   483
	set = importer->set;
krh@248
   484
	hashtable_release(&importer->table);
krh@248
   485
	free(importer);
krh@248
   486
krh@248
   487
	return set;
krh@248
   488
}