razor.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 12:45:08 2008 -0500 (2008-02-29)
changeset 138 49deac048d07
parent 137 4722cd3437cb
child 139 a416240614e3
permissions -rw-r--r--
implement file dependencies for installs

removes are trickier because there are no backlinks from the files array
the properties array, so there's currently no way to efficiently determine
what packages are affected by the removal of a particular file
krh@15
     1
#define _GNU_SOURCE
krh@15
     2
krh@0
     3
#include <stdlib.h>
krh@19
     4
#include <stddef.h>
danw@108
     5
#include <stdint.h>
krh@0
     6
#include <stdio.h>
krh@0
     7
#include <string.h>
krh@0
     8
#include <sys/types.h>
krh@0
     9
#include <sys/stat.h>
krh@0
    10
#include <sys/mman.h>
krh@0
    11
#include <unistd.h>
krh@0
    12
#include <fcntl.h>
krh@15
    13
#include <errno.h>
krh@35
    14
#include <ctype.h>
krh@54
    15
#include <fnmatch.h>
krh@0
    16
krh@27
    17
#include "razor.h"
krh@91
    18
#include "razor-internal.h"
danw@115
    19
#include "types.h"
krh@30
    20
krh@30
    21
struct razor_set_section {
danw@108
    22
	uint32_t type;
danw@108
    23
	uint32_t offset;
danw@108
    24
	uint32_t size;
krh@30
    25
};
krh@30
    26
krh@30
    27
struct razor_set_header {
danw@108
    28
	uint32_t magic;
danw@108
    29
	uint32_t version;
krh@30
    30
	struct razor_set_section sections[0];
krh@30
    31
};
krh@30
    32
krh@30
    33
#define RAZOR_MAGIC 0x7a7a7a7a
krh@30
    34
#define RAZOR_VERSION 1
krh@30
    35
krh@66
    36
#define RAZOR_STRING_POOL	0
krh@66
    37
#define RAZOR_PACKAGES		1
krh@66
    38
#define RAZOR_PROPERTIES	2
krh@66
    39
#define RAZOR_FILES		3
krh@66
    40
#define RAZOR_PACKAGE_POOL	4
krh@66
    41
#define RAZOR_PROPERTY_POOL	5
krh@66
    42
#define RAZOR_FILE_POOL		6
krh@30
    43
krh@30
    44
struct razor_package {
danw@120
    45
	uint name  : 24;
danw@120
    46
	uint flags : 8;
danw@108
    47
	uint32_t version;
danw@117
    48
	struct list_head properties;
danw@117
    49
	struct list_head files;
krh@30
    50
};
krh@30
    51
krh@30
    52
struct razor_property {
danw@119
    53
	uint name  : 24;
danw@119
    54
	uint flags : 6;
danw@119
    55
	uint type  : 2;
danw@109
    56
	uint32_t relation;
danw@108
    57
	uint32_t version;
danw@117
    58
	struct list_head packages;
krh@30
    59
};
krh@30
    60
krh@48
    61
struct razor_entry {
danw@120
    62
	uint name  : 24;
danw@120
    63
	uint flags : 8;
danw@108
    64
	uint32_t start;
danw@117
    65
	struct list_head packages;
krh@48
    66
};
krh@48
    67
danw@120
    68
#define RAZOR_ENTRY_LAST	0x80
danw@120
    69
krh@30
    70
struct razor_set {
krh@30
    71
	struct array string_pool;
krh@30
    72
 	struct array packages;
krh@66
    73
 	struct array properties;
krh@56
    74
 	struct array files;
krh@56
    75
	struct array package_pool;
krh@66
    76
 	struct array property_pool;
krh@56
    77
 	struct array file_pool;
krh@30
    78
	struct razor_set_header *header;
krh@30
    79
};
krh@30
    80
krh@52
    81
struct import_entry {
danw@108
    82
	uint32_t package;
krh@52
    83
	char *name;
krh@52
    84
};
krh@52
    85
krh@52
    86
struct import_directory {
danw@108
    87
	uint32_t name, count;
krh@52
    88
	struct array files;
krh@52
    89
	struct array packages;
krh@52
    90
	struct import_directory *last;
krh@52
    91
};
krh@52
    92
krh@30
    93
struct razor_importer {
krh@30
    94
	struct razor_set *set;
krh@78
    95
	struct hashtable table;
krh@30
    96
	struct razor_package *package;
krh@66
    97
	struct array properties;
krh@48
    98
	struct array files;
krh@30
    99
};
krh@30
   100
krh@0
   101
static void *
krh@0
   102
zalloc(size_t size)
krh@0
   103
{
krh@0
   104
	void *p;
krh@0
   105
krh@0
   106
	p = malloc(size);
krh@0
   107
	memset(p, 0, size);
krh@0
   108
krh@0
   109
	return p;
krh@0
   110
}
krh@0
   111
krh@19
   112
struct razor_set_section razor_sections[] = {
krh@56
   113
	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
krh@19
   114
	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
krh@66
   115
	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
krh@56
   116
	{ RAZOR_FILES,		offsetof(struct razor_set, files) },
krh@39
   117
	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
krh@66
   118
	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
krh@56
   119
	{ RAZOR_FILE_POOL,	offsetof(struct razor_set, file_pool) },
krh@19
   120
};
krh@19
   121
krh@4
   122
struct razor_set *
krh@4
   123
razor_set_create(void)
krh@0
   124
{
krh@18
   125
	return zalloc(sizeof(struct razor_set));
krh@0
   126
}
krh@0
   127
krh@4
   128
struct razor_set *
krh@4
   129
razor_set_open(const char *filename)
krh@0
   130
{
krh@4
   131
	struct razor_set *set;
krh@19
   132
	struct razor_set_section *s;
krh@0
   133
	struct stat stat;
krh@19
   134
	struct array *array;
krh@19
   135
	int fd;
krh@0
   136
krh@4
   137
	set = zalloc(sizeof *set);
krh@0
   138
	fd = open(filename, O_RDONLY);
krh@0
   139
	if (fstat(fd, &stat) < 0)
krh@0
   140
		return NULL;
krh@4
   141
	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
krh@4
   142
	if (set->header == MAP_FAILED) {
krh@4
   143
		free(set);
krh@0
   144
		return NULL;
krh@0
   145
	}
krh@0
   146
krh@19
   147
	for (s = set->header->sections; ~s->type; s++) {
krh@19
   148
		if (s->type >= ARRAY_SIZE(razor_sections))
krh@19
   149
			continue;
krh@19
   150
		if (s->type != razor_sections[s->type].type)
krh@19
   151
			continue;
krh@19
   152
		array = (void *) set + razor_sections[s->type].offset;
krh@19
   153
		array->data = (void *) set->header + s->offset;
krh@19
   154
		array->size = s->size;
krh@19
   155
		array->alloc = s->size;
krh@0
   156
	}
krh@0
   157
	close(fd);
krh@0
   158
krh@4
   159
	return set;
krh@0
   160
}
krh@0
   161
krh@0
   162
void
krh@4
   163
razor_set_destroy(struct razor_set *set)
krh@0
   164
{
krh@0
   165
	unsigned int size;
krh@19
   166
	struct array *a;
krh@0
   167
	int i;
krh@0
   168
krh@4
   169
	if (set->header) {
krh@4
   170
		for (i = 0; set->header->sections[i].type; i++)
krh@0
   171
			;
krh@4
   172
		size = set->header->sections[i].type;
krh@4
   173
		munmap(set->header, size);
krh@0
   174
	} else {
krh@19
   175
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   176
			a = (void *) set + razor_sections[i].offset;
krh@19
   177
			free(a->data);
krh@19
   178
		}
krh@0
   179
	}
krh@0
   180
krh@4
   181
	free(set);
krh@0
   182
}
krh@0
   183
krh@43
   184
int
krh@4
   185
razor_set_write(struct razor_set *set, const char *filename)
krh@0
   186
{
krh@0
   187
	char data[4096];
krh@4
   188
	struct razor_set_header *header = (struct razor_set_header *) data;
krh@19
   189
	struct array *a;
danw@108
   190
	uint32_t offset;
krh@17
   191
	int i, fd;
krh@0
   192
krh@0
   193
	memset(data, 0, sizeof data);
krh@4
   194
	header->magic = RAZOR_MAGIC;
krh@4
   195
	header->version = RAZOR_VERSION;
krh@17
   196
	offset = sizeof data;
krh@0
   197
krh@19
   198
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   199
		if (razor_sections[i].type != i)
krh@19
   200
			continue;
krh@19
   201
		a = (void *) set + razor_sections[i].offset;
krh@19
   202
		header->sections[i].type = i;
krh@17
   203
		header->sections[i].offset = offset;
krh@19
   204
		header->sections[i].size = a->size;
krh@91
   205
		offset += ALIGN(a->size, 4096);
krh@17
   206
	}
krh@0
   207
krh@19
   208
	header->sections[i].type = ~0;
krh@17
   209
	header->sections[i].offset = 0;
krh@17
   210
	header->sections[i].size = 0;
krh@10
   211
krh@0
   212
	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
krh@0
   213
	if (fd < 0)
krh@0
   214
		return -1;
krh@0
   215
krh@91
   216
	razor_write(fd, data, sizeof data);
danw@113
   217
	memset(data, 0, sizeof data);
krh@19
   218
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   219
		if (razor_sections[i].type != i)
krh@19
   220
			continue;
krh@19
   221
		a = (void *) set + razor_sections[i].offset;
danw@113
   222
		razor_write(fd, a->data, a->size);
danw@113
   223
		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
krh@19
   224
	}
krh@17
   225
krh@17
   226
	close(fd);
krh@0
   227
krh@0
   228
	return 0;
krh@0
   229
}
krh@0
   230
krh@27
   231
void
krh@30
   232
razor_importer_begin_package(struct razor_importer *importer,
krh@30
   233
			     const char *name, const char *version)
krh@13
   234
{
krh@25
   235
	struct razor_package *p;
krh@13
   236
krh@30
   237
	p = array_add(&importer->set->packages, sizeof *p);
krh@95
   238
	p->name = hashtable_tokenize(&importer->table, name);
danw@120
   239
	p->flags = 0;
krh@95
   240
	p->version = hashtable_tokenize(&importer->table, version);
krh@13
   241
krh@30
   242
	importer->package = p;
krh@66
   243
	array_init(&importer->properties);
krh@13
   244
}
krh@13
   245
krh@13
   246
void
krh@30
   247
razor_importer_finish_package(struct razor_importer *importer)
krh@13
   248
{
danw@117
   249
	list_set_array(&importer->package->properties,
danw@117
   250
		       &importer->set->property_pool,
danw@124
   251
		       &importer->properties,
danw@124
   252
		       1);
krh@13
   253
krh@66
   254
	array_release(&importer->properties);
krh@13
   255
}
krh@13
   256
krh@66
   257
void
krh@30
   258
razor_importer_add_property(struct razor_importer *importer,
danw@109
   259
			    const char *name,
danw@109
   260
			    enum razor_version_relation relation,
danw@109
   261
			    const char *version,
krh@66
   262
			    enum razor_property_type type)
krh@13
   263
{
krh@25
   264
	struct razor_property *p;
danw@108
   265
	uint32_t *r;
krh@13
   266
krh@66
   267
	p = array_add(&importer->set->properties, sizeof *p);
danw@119
   268
	p->name = hashtable_tokenize(&importer->table, name);
danw@119
   269
	p->flags = 0;
danw@119
   270
	p->type = type;
danw@109
   271
	p->relation = relation;
krh@95
   272
	p->version = hashtable_tokenize(&importer->table, version);
danw@117
   273
	list_set_ptr(&p->packages, importer->package -
danw@117
   274
		     (struct razor_package *) importer->set->packages.data);
krh@13
   275
krh@66
   276
	r = array_add(&importer->properties, sizeof *r);
krh@66
   277
	*r = p - (struct razor_property *) importer->set->properties.data;
krh@30
   278
}
krh@30
   279
krh@46
   280
void
krh@46
   281
razor_importer_add_file(struct razor_importer *importer, const char *name)
krh@46
   282
{
krh@52
   283
	struct import_entry *e;
krh@48
   284
krh@52
   285
	e = array_add(&importer->files, sizeof *e);
krh@52
   286
krh@52
   287
	e->package = importer->package -
krh@52
   288
		(struct razor_package *) importer->set->packages.data;
krh@52
   289
	e->name = strdup(name);
krh@46
   290
}
krh@46
   291
krh@30
   292
struct razor_importer *
krh@30
   293
razor_importer_new(void)
krh@30
   294
{
krh@30
   295
	struct razor_importer *importer;
krh@30
   296
krh@30
   297
	importer = zalloc(sizeof *importer);
krh@30
   298
	importer->set = razor_set_create();
krh@78
   299
	hashtable_init(&importer->table, &importer->set->string_pool);
krh@30
   300
krh@30
   301
	return importer;
krh@9
   302
}
krh@9
   303
krh@75
   304
/* Destroy an importer without creating the set. */
krh@75
   305
void
krh@75
   306
razor_importer_destroy(struct razor_importer *importer)
krh@75
   307
{
krh@75
   308
	/* FIXME: write this */
krh@75
   309
}
krh@75
   310
krh@75
   311
krh@22
   312
typedef int (*compare_with_data_func_t)(const void *p1,
krh@22
   313
					const void *p,
krh@22
   314
					void *data);
krh@22
   315
krh@25
   316
struct qsort_context {
krh@25
   317
	size_t size;
krh@25
   318
	compare_with_data_func_t compare;
krh@25
   319
	void *data;
krh@25
   320
};
krh@25
   321
krh@22
   322
static void
krh@22
   323
qsort_swap(void *p1, void *p2, size_t size)
krh@22
   324
{
krh@22
   325
	char buffer[size];
krh@22
   326
krh@22
   327
	memcpy(buffer, p1, size);
krh@22
   328
	memcpy(p1, p2, size);
krh@22
   329
	memcpy(p2, buffer, size);
krh@22
   330
}
krh@22
   331
krh@25
   332
static void
danw@108
   333
__qsort_with_data(void *base, size_t nelem, uint32_t *map,
krh@25
   334
		  struct qsort_context *ctx)
krh@22
   335
{
krh@22
   336
	void *p, *start, *end, *pivot;
danw@108
   337
	uint32_t *mp, *mstart, *mend, tmp;
krh@22
   338
	int left, right, result;
krh@25
   339
	size_t size = ctx->size;
krh@22
   340
krh@22
   341
	p = base;
krh@22
   342
	start = base;
krh@22
   343
	end = base + nelem * size;
krh@25
   344
	mp = map;
krh@25
   345
	mstart = map;
krh@25
   346
	mend = map + nelem;
krh@22
   347
	pivot = base + (random() % nelem) * size;
krh@25
   348
krh@22
   349
	while (p < end) {
krh@25
   350
		result = ctx->compare(p, pivot, ctx->data);
krh@22
   351
		if (result < 0) {
krh@22
   352
			qsort_swap(p, start, size);
krh@25
   353
			tmp = *mp;
krh@25
   354
			*mp = *mstart;
krh@25
   355
			*mstart = tmp;
krh@22
   356
			if (start == pivot)
krh@22
   357
				pivot = p;
krh@22
   358
			start += size;
krh@25
   359
			mstart++;
krh@22
   360
			p += size;
krh@29
   361
			mp++;
krh@22
   362
		} else if (result == 0) {
krh@22
   363
			p += size;
krh@25
   364
			mp++;
krh@22
   365
		} else {
krh@22
   366
 			end -= size;
krh@25
   367
			mend--;
krh@22
   368
			qsort_swap(p, end, size);
krh@25
   369
			tmp = *mp;
krh@29
   370
			*mp = *mend;
krh@29
   371
			*mend = tmp;
krh@22
   372
			if (end == pivot)
krh@22
   373
				pivot = p;
krh@22
   374
		}
krh@22
   375
	}
krh@22
   376
krh@22
   377
	left = (start - base) / size;
krh@22
   378
	right = (base + nelem * size - end) / size;
krh@22
   379
	if (left > 1)
krh@25
   380
		__qsort_with_data(base, left, map, ctx);
krh@22
   381
	if (right > 1)
krh@25
   382
		__qsort_with_data(end, right, mend, ctx);
krh@25
   383
}
krh@25
   384
danw@137
   385
static uint32_t *
krh@25
   386
qsort_with_data(void *base, size_t nelem, size_t size,
krh@25
   387
		compare_with_data_func_t compare, void *data)
krh@25
   388
{
krh@25
   389
	struct qsort_context ctx;
danw@108
   390
	uint32_t *map;
krh@25
   391
	int i;
krh@25
   392
krh@75
   393
	if (nelem == 0)
krh@75
   394
		return NULL;
krh@75
   395
krh@25
   396
	ctx.size = size;
krh@25
   397
	ctx.compare = compare;
krh@25
   398
	ctx.data = data;
krh@25
   399
danw@108
   400
	map = malloc(nelem * sizeof (uint32_t));
krh@25
   401
	for (i = 0; i < nelem; i++)
krh@25
   402
		map[i] = i;
krh@25
   403
krh@25
   404
	__qsort_with_data(base, nelem, map, &ctx);
krh@25
   405
krh@25
   406
	return map;
krh@22
   407
}
krh@9
   408
krh@9
   409
static int
krh@35
   410
versioncmp(const char *s1, const char *s2)
krh@35
   411
{
krh@35
   412
	const char *p1, *p2;
krh@35
   413
	long n1, n2;
krh@35
   414
	int res;
krh@35
   415
krh@35
   416
	n1 = strtol(s1, (char **) &p1, 0);
krh@35
   417
	n2 = strtol(s2, (char **) &p2, 0);
krh@35
   418
krh@35
   419
	/* Epoch; if one but not the other has an epoch set, default
krh@35
   420
	 * the epoch-less version to 0. */
krh@35
   421
	res = (*p1 == ':') - (*p2 == ':');
krh@35
   422
	if (res < 0) {
krh@35
   423
		n1 = 0;
krh@35
   424
		p1 = s1;
krh@35
   425
		p2++;
krh@35
   426
	} else if (res > 0) {
krh@35
   427
		p1++;
krh@35
   428
		n2 = 0;
krh@35
   429
		p2 = s2;
krh@35
   430
	}
krh@35
   431
krh@35
   432
	if (n1 != n2)
krh@35
   433
		return n1 - n2;
krh@35
   434
	while (*p1 && *p2) {
krh@35
   435
		if (*p1 != *p2)
krh@35
   436
			return *p1 - *p2;
krh@35
   437
		p1++;
krh@35
   438
		p2++;
krh@35
   439
		if (isdigit(*p1) && isdigit(*p2))
krh@35
   440
			return versioncmp(p1, p2);
krh@35
   441
	}
krh@35
   442
krh@35
   443
	return *p1 - *p2;
krh@35
   444
}
krh@35
   445
krh@35
   446
static int
krh@22
   447
compare_packages(const void *p1, const void *p2, void *data)
krh@9
   448
{
krh@25
   449
	const struct razor_package *pkg1 = p1, *pkg2 = p2;
krh@22
   450
	struct razor_set *set = data;
krh@22
   451
	char *pool = set->string_pool.data;
krh@9
   452
danw@120
   453
	/* FIXME: what if the flags are different? */
krh@23
   454
	if (pkg1->name == pkg2->name)
krh@35
   455
		return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
krh@23
   456
	else
krh@23
   457
		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
krh@9
   458
}
krh@9
   459
krh@9
   460
static int
krh@22
   461
compare_properties(const void *p1, const void *p2, void *data)
krh@9
   462
{
krh@25
   463
	const struct razor_property *prop1 = p1, *prop2 = p2;
krh@22
   464
	struct razor_set *set = data;
krh@22
   465
	char *pool = set->string_pool.data;
krh@9
   466
danw@119
   467
	if (prop1->name != prop2->name) 
danw@119
   468
		return strcmp(&pool[prop1->name], &pool[prop2->name]);
danw@119
   469
	else if (prop1->type != prop2->type)
danw@119
   470
		return prop1->type - prop2->type;
danw@119
   471
	else if (prop1->relation != prop2->relation)
danw@119
   472
		return prop1->relation - prop2->relation;
krh@12
   473
	else
danw@119
   474
		return versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@9
   475
}
krh@9
   476
danw@108
   477
static uint32_t *
krh@66
   478
uniqueify_properties(struct razor_set *set)
krh@9
   479
{
krh@25
   480
	struct razor_property *rp, *up, *rp_end;
krh@18
   481
	struct array *pkgs, *p;
danw@117
   482
	struct list_head *r;
danw@117
   483
	uint32_t *map, *rmap;
krh@18
   484
	int i, count, unique;
krh@9
   485
krh@66
   486
	count = set->properties.size / sizeof(struct razor_property);
krh@66
   487
	map = qsort_with_data(set->properties.data,
krh@25
   488
			      count,
krh@25
   489
			      sizeof(struct razor_property),
krh@25
   490
			      compare_properties,
krh@25
   491
			      set);
krh@9
   492
krh@66
   493
	rp_end = set->properties.data + set->properties.size;
krh@25
   494
	rmap = malloc(count * sizeof *map);
krh@25
   495
	pkgs = zalloc(count * sizeof *pkgs);
krh@66
   496
	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
danw@119
   497
		if (rp->name != up->name || rp->type != up->type ||
danw@119
   498
		    rp->relation != up->relation || rp->version != up->version) {
krh@25
   499
			up++;
krh@25
   500
			up->name = rp->name;
danw@119
   501
			up->flags = 0;
danw@119
   502
			up->type = rp->type;
danw@109
   503
			up->relation = rp->relation;
krh@25
   504
			up->version = rp->version;
krh@10
   505
		}
krh@25
   506
krh@66
   507
		unique = up - (struct razor_property *) set->properties.data;
krh@25
   508
		rmap[map[i]] = unique;
krh@25
   509
		r = array_add(&pkgs[unique], sizeof *r);
krh@25
   510
		*r = rp->packages;
krh@10
   511
	}
krh@25
   512
	free(map);
krh@9
   513
danw@124
   514
	if (up != rp)
danw@124
   515
		up++;
krh@66
   516
	set->properties.size = (void *) up - set->properties.data;
krh@25
   517
	rp_end = up;
krh@66
   518
	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
danw@124
   519
		list_set_array(&rp->packages, &set->package_pool, p, 0);
krh@25
   520
		array_release(p);
krh@18
   521
	}
krh@18
   522
krh@18
   523
	free(pkgs);
krh@18
   524
krh@25
   525
	return rmap;
krh@10
   526
}
krh@10
   527
krh@48
   528
static int
krh@48
   529
compare_filenames(const void *p1, const void *p2, void *data)
krh@48
   530
{
krh@52
   531
	const struct import_entry *e1 = p1;
krh@52
   532
	const struct import_entry *e2 = p2;
danw@126
   533
	const char *n1 = e1->name;
danw@126
   534
	const char *n2 = e2->name;
krh@48
   535
danw@126
   536
	/* Need to make sure that the contents of a directory
danw@126
   537
	 * are sorted immediately after it. So "foo/bar" has to
danw@126
   538
	 * sort before "foo.conf"
danw@126
   539
	 *
danw@126
   540
	 * FIXME: this is about 60% slower than strcmp
danw@126
   541
	 */
danw@126
   542
	while (*n1 && *n2) {
danw@126
   543
		if (*n1 < *n2)
danw@126
   544
			return *n2 == '/' ? 1 : -1;
danw@126
   545
		else if (*n1 > *n2)
danw@126
   546
			return *n1 == '/' ? -1 : 1;
danw@126
   547
		n1++;
danw@126
   548
		n2++;
danw@126
   549
	}
danw@126
   550
	if (*n1)
danw@126
   551
		return 1;
danw@126
   552
	else if (*n2)
danw@126
   553
		return -1;
danw@126
   554
	else
danw@126
   555
		return 0;
krh@48
   556
}
krh@48
   557
krh@48
   558
static void
krh@52
   559
count_entries(struct import_directory *d)
krh@48
   560
{
krh@52
   561
	struct import_directory *p, *end;
krh@48
   562
krh@48
   563
	p = d->files.data;
krh@48
   564
	end = d->files.data + d->files.size;
krh@48
   565
	d->count = 0;
krh@48
   566
	while (p < end) {
krh@48
   567
		count_entries(p);
krh@48
   568
		d->count += p->count + 1;
krh@48
   569
		p++;
krh@48
   570
	}		
krh@48
   571
}
krh@48
   572
krh@48
   573
static void
krh@52
   574
serialize_files(struct razor_set *set,
krh@52
   575
		struct import_directory *d, struct array *array)
krh@48
   576
{
krh@52
   577
	struct import_directory *p, *end;
krh@56
   578
	struct razor_entry *e = NULL;
danw@114
   579
	uint32_t s;
krh@48
   580
krh@48
   581
	p = d->files.data;
krh@48
   582
	end = d->files.data + d->files.size;
krh@48
   583
	s = array->size / sizeof *e + d->files.size / sizeof *p;
krh@48
   584
	while (p < end) {
krh@48
   585
		e = array_add(array, sizeof *e);
krh@48
   586
		e->name = p->name;
danw@120
   587
		e->flags = 0;
krh@56
   588
		e->start = p->count > 0 ? s : 0;
krh@48
   589
		s += p->count;
krh@60
   590
danw@124
   591
		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
krh@52
   592
		array_release(&p->packages);
krh@48
   593
		p++;
krh@48
   594
	}		
krh@56
   595
	if (e != NULL)
danw@120
   596
		e->flags |= RAZOR_ENTRY_LAST;
krh@48
   597
krh@48
   598
	p = d->files.data;
krh@48
   599
	end = d->files.data + d->files.size;
krh@48
   600
	while (p < end) {
krh@52
   601
		serialize_files(set, p, array);
krh@48
   602
		p++;
krh@48
   603
	}
krh@48
   604
}
krh@48
   605
krh@48
   606
static void
danw@108
   607
remap_property_package_links(struct array *properties, uint32_t *rmap)
krh@61
   608
{
krh@61
   609
	struct razor_property *p, *end;
krh@61
   610
krh@61
   611
	end = properties->data + properties->size;
krh@61
   612
	for (p = properties->data; p < end; p++)
danw@117
   613
		list_remap_head(&p->packages, rmap);
krh@61
   614
}
krh@61
   615
krh@61
   616
static void
krh@48
   617
build_file_tree(struct razor_importer *importer)
krh@48
   618
{
krh@48
   619
	int count, i, length;
krh@52
   620
	struct import_entry *filenames;
krh@52
   621
	char *f, *end;
danw@108
   622
	uint32_t name, *r;
krh@48
   623
	char dirname[256];
krh@52
   624
	struct import_directory *d, root;
krh@48
   625
	struct razor_entry *e;
krh@48
   626
krh@52
   627
	count = importer->files.size / sizeof (struct import_entry);
krh@48
   628
	qsort_with_data(importer->files.data,
krh@48
   629
			count,
krh@52
   630
			sizeof (struct import_entry),
krh@48
   631
			compare_filenames,
krh@48
   632
			NULL);
krh@48
   633
krh@95
   634
	root.name = hashtable_tokenize(&importer->table, "");
krh@48
   635
	array_init(&root.files);
krh@52
   636
	array_init(&root.packages);
krh@48
   637
	root.last = NULL;
krh@48
   638
krh@48
   639
	filenames = importer->files.data;
krh@48
   640
	for (i = 0; i < count; i++) {
krh@52
   641
		f = filenames[i].name;
krh@48
   642
		if (*f != '/')
krh@48
   643
			continue;
krh@57
   644
		f++;
krh@48
   645
krh@48
   646
		d = &root;
krh@48
   647
		while (*f) {
krh@57
   648
			end = strchr(f, '/');
krh@48
   649
			if (end == NULL)
krh@48
   650
				end = f + strlen(f);
krh@57
   651
			length = end - f;
krh@57
   652
			memcpy(dirname, f, length);
krh@48
   653
			dirname[length] ='\0';
krh@95
   654
			name = hashtable_tokenize(&importer->table, dirname);
krh@48
   655
			if (d->last == NULL || d->last->name != name) {
krh@48
   656
				d->last = array_add(&d->files, sizeof *d);
krh@48
   657
				d->last->name = name;
krh@48
   658
				d->last->last = NULL;
krh@48
   659
				array_init(&d->last->files);
krh@52
   660
				array_init(&d->last->packages);
krh@48
   661
			}
krh@48
   662
			d = d->last;				
krh@57
   663
			f = end + 1;
krh@57
   664
			if (*end == '\0')
krh@57
   665
				break;
krh@48
   666
		}
krh@48
   667
krh@52
   668
		r = array_add(&d->packages, sizeof *r);
krh@52
   669
		*r = filenames[i].package;
krh@52
   670
		free(filenames[i].name);
krh@48
   671
	}
krh@48
   672
krh@48
   673
	count_entries(&root);
krh@56
   674
	array_init(&importer->set->files);
krh@48
   675
krh@56
   676
	e = array_add(&importer->set->files, sizeof *e);
danw@120
   677
	e->name = root.name;
danw@120
   678
	e->flags = RAZOR_ENTRY_LAST;
danw@129
   679
	e->start = importer->files.size ? 1 : 0;
danw@117
   680
	list_set_empty(&e->packages);
krh@48
   681
krh@56
   682
	serialize_files(importer->set, &root, &importer->set->files);
krh@48
   683
krh@48
   684
	array_release(&importer->files);
krh@48
   685
}
krh@48
   686
krh@56
   687
static void
danw@108
   688
build_package_file_lists(struct razor_set *set, uint32_t *rmap)
krh@54
   689
{
krh@56
   690
	struct razor_package *p, *packages;
krh@56
   691
	struct array *pkgs;
krh@54
   692
	struct razor_entry *e, *end;
danw@117
   693
	struct list *r;
danw@117
   694
	uint32_t *q;
krh@56
   695
	int i, count;
krh@54
   696
krh@56
   697
	count = set->packages.size / sizeof *p;
krh@56
   698
	pkgs = zalloc(count * sizeof *pkgs);
krh@54
   699
krh@56
   700
	end = set->files.data + set->files.size;
krh@92
   701
	for (e = set->files.data; e < end; e++) {
danw@117
   702
		list_remap_head(&e->packages, rmap);
danw@116
   703
		r = list_first(&e->packages, &set->package_pool);
danw@116
   704
		while (r) {
danw@117
   705
			q = array_add(&pkgs[r->data], sizeof *q);
krh@56
   706
			*q = e - (struct razor_entry *) set->files.data;
danw@116
   707
			r = list_next(r);
krh@54
   708
		}
krh@54
   709
	}
krh@54
   710
krh@56
   711
	packages = set->packages.data;
krh@56
   712
	for (i = 0; i < count; i++) {
danw@124
   713
		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
krh@56
   714
		array_release(&pkgs[i]);
krh@48
   715
	}
krh@56
   716
	free(pkgs);
krh@52
   717
}
krh@52
   718
krh@27
   719
struct razor_set *
krh@30
   720
razor_importer_finish(struct razor_importer *importer)
krh@9
   721
{
krh@30
   722
	struct razor_set *set;
danw@108
   723
	uint32_t *map, *rmap;
krh@39
   724
	int i, count;
krh@18
   725
krh@66
   726
	map = uniqueify_properties(importer->set);
danw@116
   727
	list_remap_pool(&importer->set->property_pool, map);
krh@39
   728
	free(map);
krh@25
   729
krh@30
   730
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@30
   731
	map = qsort_with_data(importer->set->packages.data,
krh@25
   732
			      count,
krh@25
   733
			      sizeof(struct razor_package),
krh@25
   734
			      compare_packages,
krh@30
   735
			      importer->set);
krh@39
   736
krh@39
   737
	rmap = malloc(count * sizeof *rmap);
krh@39
   738
	for (i = 0; i < count; i++)
krh@39
   739
		rmap[map[i]] = i;
krh@25
   740
	free(map);
krh@13
   741
krh@48
   742
	build_file_tree(importer);
danw@116
   743
	list_remap_pool(&importer->set->package_pool, rmap);
krh@60
   744
	build_package_file_lists(importer->set, rmap);
krh@66
   745
	remap_property_package_links(&importer->set->properties, rmap);
krh@52
   746
	free(rmap);
krh@48
   747
krh@30
   748
	set = importer->set;
krh@78
   749
	hashtable_release(&importer->table);
krh@30
   750
	free(importer);
krh@30
   751
krh@30
   752
	return set;
krh@9
   753
}
krh@9
   754
krh@92
   755
struct razor_package_iterator {
krh@92
   756
	struct razor_set *set;
krh@92
   757
	struct razor_package *package, *end;
danw@117
   758
	struct list *index;
krh@92
   759
};
krh@92
   760
danw@137
   761
static struct razor_package_iterator *
krh@101
   762
razor_package_iterator_create_with_index(struct razor_set *set,
danw@117
   763
					 struct list *index)
krh@3
   764
{
krh@92
   765
	struct razor_package_iterator *pi;
krh@92
   766
krh@92
   767
	pi = zalloc(sizeof *pi);
krh@92
   768
	pi->set = set;
krh@101
   769
	pi->index = index;
krh@92
   770
krh@92
   771
	return pi;
krh@92
   772
}
krh@92
   773
krh@101
   774
struct razor_package_iterator *
krh@101
   775
razor_package_iterator_create(struct razor_set *set)
krh@101
   776
{
danw@116
   777
	struct razor_package_iterator *pi;
danw@116
   778
danw@116
   779
	pi = zalloc(sizeof *pi);
danw@116
   780
	pi->set = set;
danw@116
   781
	pi->end = set->packages.data + set->packages.size;
danw@116
   782
	pi->package = set->packages.data;
danw@116
   783
danw@116
   784
	return pi;
krh@101
   785
}
krh@101
   786
krh@101
   787
struct razor_package_iterator *
krh@101
   788
razor_package_iterator_create_for_property(struct razor_set *set,
krh@101
   789
					   struct razor_property *property)
krh@101
   790
{
danw@117
   791
	struct list *index;
krh@101
   792
danw@116
   793
	index = list_first(&property->packages, &set->package_pool);
krh@101
   794
	return razor_package_iterator_create_with_index(set, index);
krh@101
   795
}
krh@101
   796
krh@92
   797
int
krh@92
   798
razor_package_iterator_next(struct razor_package_iterator *pi,
krh@92
   799
			    struct razor_package **package,
krh@92
   800
			    const char **name, const char **version)
krh@92
   801
{
krh@6
   802
	char *pool;
krh@101
   803
	int valid;
krh@101
   804
	struct razor_package *p, *packages;
krh@3
   805
danw@116
   806
	if (pi->package) {
krh@101
   807
		p = pi->package++;
krh@101
   808
		valid = p < pi->end;
danw@116
   809
	} else if (pi->index) {
danw@116
   810
		packages = pi->set->packages.data;
danw@117
   811
		p = &packages[pi->index->data];
danw@116
   812
		pi->index = list_next(pi->index);
danw@116
   813
		valid = 1;
danw@116
   814
	} else
danw@116
   815
		valid = 0;
krh@92
   816
krh@101
   817
	if (valid) {
krh@101
   818
		pool = pi->set->string_pool.data;
krh@101
   819
		*package = p;
danw@120
   820
		*name = &pool[p->name];
krh@101
   821
		*version = &pool[p->version];
krh@101
   822
	} else {
krh@101
   823
		*package = NULL;
krh@101
   824
	}
krh@101
   825
krh@101
   826
	return valid;
krh@92
   827
}
krh@92
   828
krh@92
   829
void
krh@92
   830
razor_package_iterator_destroy(struct razor_package_iterator *pi)
krh@92
   831
{
krh@92
   832
	free(pi);
krh@3
   833
}
krh@3
   834
krh@10
   835
struct razor_package *
krh@10
   836
razor_set_get_package(struct razor_set *set, const char *package)
krh@10
   837
{
krh@97
   838
	struct razor_package_iterator *pi;
krh@97
   839
	struct razor_package *p;
krh@97
   840
	const char *name, *version;
krh@97
   841
krh@97
   842
	pi = razor_package_iterator_create(set);
krh@97
   843
	while (razor_package_iterator_next(pi, &p, &name, &version)) {
krh@97
   844
		if (strcmp(package, name) == 0)
krh@97
   845
			break;
krh@97
   846
	}
krh@97
   847
	razor_package_iterator_destroy(pi);
krh@97
   848
krh@97
   849
	return p;
krh@10
   850
}
krh@10
   851
krh@92
   852
struct razor_property_iterator {
krh@92
   853
	struct razor_set *set;
krh@92
   854
	struct razor_property *property, *end;
danw@117
   855
	struct list *index;
krh@92
   856
};
krh@92
   857
krh@92
   858
struct razor_property_iterator *
krh@92
   859
razor_property_iterator_create(struct razor_set *set,
krh@92
   860
			       struct razor_package *package)
krh@92
   861
{
krh@92
   862
	struct razor_property_iterator *pi;
krh@92
   863
krh@92
   864
	pi = zalloc(sizeof *pi);
krh@92
   865
	pi->set = set;
krh@98
   866
danw@116
   867
	if (package) {
danw@117
   868
		pi->index = list_first(&package->properties,
danw@117
   869
				       &set->property_pool);
danw@116
   870
	} else {
danw@116
   871
		pi->property = set->properties.data;
danw@116
   872
		pi->end = set->properties.data + set->properties.size;
danw@116
   873
	}
krh@92
   874
krh@92
   875
	return pi;
krh@92
   876
}
krh@92
   877
krh@92
   878
int
krh@92
   879
razor_property_iterator_next(struct razor_property_iterator *pi,
krh@92
   880
			     struct razor_property **property,
danw@109
   881
			     const char **name,
danw@109
   882
			     enum razor_version_relation *relation,
danw@109
   883
			     const char **version,
krh@92
   884
			     enum razor_property_type *type)
krh@92
   885
{
krh@92
   886
	char *pool;
krh@92
   887
	int valid;
krh@92
   888
	struct razor_property *p, *properties;
krh@92
   889
danw@116
   890
	if (pi->property) {
krh@92
   891
		p = pi->property++;
krh@92
   892
		valid = p < pi->end;
danw@116
   893
	} else if (pi->index) {
danw@116
   894
		properties = pi->set->properties.data;
danw@117
   895
		p = &properties[pi->index->data];
danw@116
   896
		pi->index = list_next(pi->index);
danw@116
   897
		valid = 1;
danw@116
   898
	} else
danw@116
   899
		valid = 0;
krh@92
   900
krh@96
   901
	if (valid) {
krh@96
   902
		pool = pi->set->string_pool.data;
krh@96
   903
		*property = p;
danw@119
   904
		*name = &pool[p->name];
danw@109
   905
		*relation = p->relation;
krh@96
   906
		*version = &pool[p->version];
danw@119
   907
		*type = p->type;
krh@96
   908
	} else {
krh@96
   909
		*property = NULL;
krh@96
   910
	}
krh@92
   911
krh@92
   912
	return valid;
krh@92
   913
}
krh@92
   914
krh@66
   915
void
krh@92
   916
razor_property_iterator_destroy(struct razor_property_iterator *pi)
krh@8
   917
{
krh@92
   918
	free(pi);
krh@10
   919
}
krh@10
   920
krh@56
   921
static struct razor_entry *
krh@56
   922
find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
krh@56
   923
{
krh@56
   924
	struct razor_entry *e;
krh@56
   925
	const char *n, *pool = set->string_pool.data;
krh@56
   926
	int len;
krh@56
   927
krh@56
   928
	e = (struct razor_entry *) set->files.data + dir->start;
krh@56
   929
	do {
danw@120
   930
		n = pool + e->name;
krh@56
   931
		if (strcmp(pattern + 1, n) == 0)
krh@56
   932
			return e;
krh@57
   933
		len = strlen(n);
krh@56
   934
		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
krh@56
   935
		    pattern[len + 1] == '/') {
krh@56
   936
			return find_entry(set, e, pattern + len + 1);
krh@56
   937
		}
danw@120
   938
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
krh@56
   939
krh@56
   940
	return NULL;
krh@56
   941
}
krh@56
   942
krh@56
   943
static void
krh@56
   944
list_dir(struct razor_set *set, struct razor_entry *dir,
danw@127
   945
	 char *prefix, const char *pattern)
krh@56
   946
{
krh@56
   947
	struct razor_entry *e;
krh@56
   948
	const char *n, *pool = set->string_pool.data;
krh@56
   949
krh@56
   950
	e = (struct razor_entry *) set->files.data + dir->start;
krh@56
   951
	do {
danw@120
   952
		n = pool + e->name;
krh@56
   953
		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
krh@56
   954
			continue;
danw@127
   955
		printf("%s/%s\n", prefix, n);
danw@127
   956
		if (e->start) {
danw@127
   957
			char *sub = prefix + strlen (prefix);
danw@127
   958
			*sub = '/';
danw@127
   959
			strcpy (sub + 1, n);
danw@127
   960
			list_dir(set, e, prefix, pattern);
danw@127
   961
			*sub = '\0';
danw@127
   962
		}
danw@120
   963
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
krh@56
   964
}
krh@56
   965
krh@56
   966
void
krh@56
   967
razor_set_list_files(struct razor_set *set, const char *pattern)
krh@56
   968
{
krh@56
   969
	struct razor_entry *e;
krh@56
   970
	char buffer[512], *p, *base;
krh@56
   971
danw@127
   972
	if (pattern == NULL || !strcmp (pattern, "/")) {
danw@127
   973
		buffer[0] = '\0';
danw@127
   974
		list_dir(set, set->files.data, buffer, NULL);
danw@127
   975
		return;
danw@127
   976
	}
krh@56
   977
krh@56
   978
	strcpy(buffer, pattern);
krh@56
   979
	e = find_entry(set, set->files.data, buffer);
krh@56
   980
	if (e && e->start > 0) {
krh@56
   981
		base = NULL;
krh@56
   982
	} else {
krh@56
   983
		p = strrchr(buffer, '/');
krh@56
   984
		if (p) {
krh@56
   985
			*p = '\0';
krh@56
   986
			base = p + 1;
krh@56
   987
		} else {
krh@56
   988
			base = NULL;
krh@56
   989
		}
krh@56
   990
	}
krh@56
   991
	e = find_entry(set, set->files.data, buffer);
krh@56
   992
	if (e->start != 0)
krh@56
   993
		list_dir(set, e, buffer, base);
krh@56
   994
}
krh@56
   995
krh@102
   996
struct razor_package_iterator *
krh@102
   997
razor_package_iterator_create_for_file(struct razor_set *set,
krh@102
   998
				       const char *filename)
krh@56
   999
{
krh@102
  1000
	struct razor_entry *entry;
danw@117
  1001
	struct list *index;
krh@56
  1002
krh@102
  1003
	entry = find_entry(set, set->files.data, filename);
krh@102
  1004
	if (entry == NULL)
krh@102
  1005
		return NULL;
krh@56
  1006
	
danw@116
  1007
	index = list_first(&entry->packages, &set->package_pool);
krh@102
  1008
	return razor_package_iterator_create_with_index(set, index);
krh@56
  1009
}
krh@56
  1010
danw@117
  1011
static struct list *
danw@117
  1012
list_package_files(struct razor_set *set, struct list *r,
danw@108
  1013
		   struct razor_entry *dir, uint32_t end,
krh@56
  1014
		   char *prefix)
krh@56
  1015
{
krh@56
  1016
	struct razor_entry *e, *f, *entries;
danw@108
  1017
	uint32_t next, file;
krh@56
  1018
	char *pool;
krh@56
  1019
	int len;
krh@56
  1020
	
krh@56
  1021
	entries = (struct razor_entry *) set->files.data;
krh@56
  1022
	pool = set->string_pool.data;
krh@56
  1023
krh@56
  1024
	e = entries + dir->start;
krh@56
  1025
	do {
danw@117
  1026
		if (entries + r->data == e) {
danw@120
  1027
			printf("%s/%s\n", prefix, pool + e->name);
danw@116
  1028
			r = list_next(r);
danw@116
  1029
			if (!r)
krh@83
  1030
				return NULL;
danw@117
  1031
			if (r->data >= end)
krh@83
  1032
				return r;
krh@56
  1033
		}
danw@120
  1034
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
krh@56
  1035
krh@56
  1036
	e = entries + dir->start;
krh@56
  1037
	do {
krh@56
  1038
		if (e->start == 0)
krh@56
  1039
			continue;
krh@56
  1040
danw@120
  1041
		if (e->flags & RAZOR_ENTRY_LAST)
krh@56
  1042
			next = end;
krh@56
  1043
		else {
krh@56
  1044
			f = e + 1; 
danw@120
  1045
			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
krh@56
  1046
				f++;
krh@56
  1047
			if (f->start == 0)
krh@56
  1048
				next = end;
krh@56
  1049
			else
krh@56
  1050
				next = f->start;
krh@56
  1051
		}
krh@56
  1052
danw@117
  1053
		file = r->data;
krh@83
  1054
		if (e->start <= file && file < next) {
krh@56
  1055
			len = strlen(prefix);
krh@56
  1056
			prefix[len] = '/';
danw@120
  1057
			strcpy(prefix + len + 1, pool + e->name);
krh@56
  1058
			r = list_package_files(set, r, e, next, prefix);
krh@56
  1059
			prefix[len] = '\0';
krh@56
  1060
		}
danw@120
  1061
	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
krh@56
  1062
krh@56
  1063
	return r;
krh@56
  1064
}
krh@56
  1065
krh@56
  1066
void
krh@56
  1067
razor_set_list_package_files(struct razor_set *set, const char *name)
krh@56
  1068
{
krh@56
  1069
	struct razor_package *package;
danw@117
  1070
	struct list *r;
danw@117
  1071
	uint32_t end;
krh@56
  1072
	char buffer[512];
krh@56
  1073
krh@56
  1074
	package = razor_set_get_package(set, name);
krh@56
  1075
danw@116
  1076
	r = list_first(&package->files, &set->file_pool);
krh@56
  1077
	end = set->files.size / sizeof (struct razor_entry);
krh@56
  1078
	buffer[0] = '\0';
krh@56
  1079
	list_package_files(set, r, set->files.data, end, buffer);
krh@56
  1080
}
krh@56
  1081
krh@43
  1082
static void
krh@21
  1083
razor_set_validate(struct razor_set *set, struct array *unsatisfied)
krh@21
  1084
{
krh@66
  1085
	struct razor_property *r, *p, *end;
danw@108
  1086
	uint32_t *u;
krh@21
  1087
	char *pool;
krh@21
  1088
krh@66
  1089
	end = set->properties.data + set->properties.size;
krh@21
  1090
	pool = set->string_pool.data;
krh@21
  1091
	
krh@66
  1092
	for (r = set->properties.data, p = r; r < end; r++) {
danw@119
  1093
		if (r->type != RAZOR_PROPERTY_REQUIRES)
krh@66
  1094
			continue;
krh@66
  1095
danw@129
  1096
		p = r;
danw@129
  1097
		while (p < end && p->name == r->name &&
danw@129
  1098
		       p->type == r->type)
danw@129
  1099
			p++;
krh@37
  1100
krh@35
  1101
		/* If there is more than one version of a provides,
krh@35
  1102
		 * seek to the end for the highest version. */
krh@66
  1103
		/* FIXME: This doesn't work if we have a series of
krh@66
  1104
		 * requires a = 1, provides a = 1, requires a = 2,
krh@66
  1105
		 * provides a = 2, as the kernel and kernel-devel
krh@66
  1106
		 * does.*/
danw@119
  1107
		while (p + 1 < end && p->name == (p + 1)->name &&
danw@119
  1108
		       p->type == (p + 1)->type)
krh@35
  1109
			p++;
krh@37
  1110
krh@37
  1111
		/* FIXME: We need to track property flags (<, <=, =
krh@37
  1112
		 * etc) to properly determine if a requires is
krh@37
  1113
		 * satisfied.  The current code doesn't track that the
krh@37
  1114
		 * requires a = 1 isn't satisfied by a = 2 provides. */
krh@37
  1115
krh@66
  1116
		if (p == end ||
danw@119
  1117
		    p->type != RAZOR_PROPERTY_PROVIDES ||
danw@119
  1118
		    r->name != p->name ||
krh@35
  1119
		    versioncmp(&pool[r->version], &pool[p->version]) > 0) {
krh@35
  1120
			/* FIXME: We ignore file requires for now. */
danw@119
  1121
			if (pool[r->name] == '/')
krh@35
  1122
				continue;
krh@21
  1123
			u = array_add(unsatisfied, sizeof *u);
krh@66
  1124
			*u = r - (struct razor_property *) set->properties.data;
krh@21
  1125
		}
krh@21
  1126
	}
krh@21
  1127
}
krh@21
  1128
krh@21
  1129
void
krh@21
  1130
razor_set_list_unsatisfied(struct razor_set *set)
krh@21
  1131
{
krh@21
  1132
	struct array unsatisfied;
krh@66
  1133
	struct razor_property *properties, *r;
danw@108
  1134
	uint32_t *u, *end;
krh@21
  1135
	char *pool;
krh@21
  1136
krh@21
  1137
	array_init(&unsatisfied);
krh@21
  1138
	razor_set_validate(set, &unsatisfied);
krh@21
  1139
krh@21
  1140
	end = unsatisfied.data + unsatisfied.size;
krh@66
  1141
	properties = set->properties.data;
krh@21
  1142
	pool = set->string_pool.data;
krh@21
  1143
krh@21
  1144
	for (u = unsatisfied.data; u < end; u++) {
krh@66
  1145
		r = properties + *u;
krh@66
  1146
		if (pool[r->version] == '\0')
krh@66
  1147
			printf("%ss not satisfied\n",
danw@119
  1148
			       &pool[r->name]);
krh@66
  1149
		else
krh@66
  1150
			printf("%s-%s not satisfied\n",
danw@119
  1151
			       &pool[r->name],
krh@66
  1152
			       &pool[r->version]);
krh@21
  1153
	}
krh@21
  1154
krh@21
  1155
	array_release(&unsatisfied);
krh@21
  1156
}
krh@21
  1157
danw@120
  1158
#define UPSTREAM_SOURCE 0x80
krh@41
  1159
krh@41
  1160
struct source {
krh@41
  1161
	struct razor_set *set;
danw@108
  1162
	uint32_t *property_map;
danw@127
  1163
	uint32_t *file_map;
krh@41
  1164
};
krh@41
  1165
krh@79
  1166
struct razor_merger {
krh@79
  1167
	struct razor_set *set;
krh@79
  1168
	struct hashtable table;
krh@79
  1169
	struct source source1;
krh@79
  1170
	struct source source2;
krh@79
  1171
};
krh@79
  1172
krh@79
  1173
static struct razor_merger *
krh@79
  1174
razor_merger_create(struct razor_set *set1, struct razor_set *set2)
krh@41
  1175
{
krh@79
  1176
	struct razor_merger *merger;
krh@41
  1177
	int count;
krh@41
  1178
	size_t size;
krh@41
  1179
krh@79
  1180
	merger = zalloc(sizeof *merger);
krh@79
  1181
	merger->set = razor_set_create();
krh@79
  1182
	hashtable_init(&merger->table, &merger->set->string_pool);
krh@41
  1183
danw@127
  1184
	merger->source1.set = set1;
krh@79
  1185
	count = set1->properties.size / sizeof (struct razor_property);
krh@79
  1186
	size = count * sizeof merger->source1.property_map[0];
krh@79
  1187
	merger->source1.property_map = zalloc(size);
danw@127
  1188
	count = set1->files.size / sizeof (struct razor_entry);
danw@127
  1189
	size = count * sizeof merger->source1.file_map[0];
danw@127
  1190
	merger->source1.file_map = zalloc(size);
krh@79
  1191
danw@127
  1192
	merger->source2.set = set2;
krh@79
  1193
	count = set2->properties.size / sizeof (struct razor_property);
krh@79
  1194
	size = count * sizeof merger->source2.property_map[0];
krh@79
  1195
	merger->source2.property_map = zalloc(size);
danw@127
  1196
	count = set2->files.size / sizeof (struct razor_entry);
danw@127
  1197
	size = count * sizeof merger->source2.file_map[0];
danw@127
  1198
	merger->source2.file_map = zalloc(size);
krh@79
  1199
krh@79
  1200
	return merger;
krh@41
  1201
}
krh@41
  1202
krh@33
  1203
static void
krh@79
  1204
add_package(struct razor_merger *merger,
krh@41
  1205
	    struct razor_package *package, struct source *source,
danw@108
  1206
	    uint32_t flags)
krh@33
  1207
{
krh@33
  1208
	char *pool;
danw@117
  1209
	struct list *r;
krh@41
  1210
	struct razor_package *p;
krh@33
  1211
krh@41
  1212
	pool = source->set->string_pool.data;
krh@79
  1213
	p = array_add(&merger->set->packages, sizeof *p);
krh@79
  1214
	p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
danw@120
  1215
	p->flags = flags;
krh@79
  1216
	p->version = hashtable_tokenize(&merger->table,
krh@79
  1217
					&pool[package->version]);
danw@127
  1218
krh@66
  1219
	p->properties = package->properties;
danw@116
  1220
	r = list_first(&package->properties, &source->set->property_pool);
danw@116
  1221
	while (r) {
danw@117
  1222
		source->property_map[r->data] = 1;
danw@116
  1223
		r = list_next(r);
krh@64
  1224
	}
danw@127
  1225
danw@127
  1226
	p->files = package->files;
danw@127
  1227
	r = list_first(&package->files, &source->set->file_pool);
danw@127
  1228
	while (r) {
danw@127
  1229
		source->file_map[r->data] = 1;
danw@127
  1230
		r = list_next(r);
danw@127
  1231
	}
krh@41
  1232
}
krh@41
  1233
danw@108
  1234
static uint32_t
krh@79
  1235
add_property(struct razor_merger *merger,
danw@109
  1236
	     const char *name, enum razor_version_relation relation,
danw@109
  1237
	     const char *version, int type)
krh@41
  1238
{
krh@41
  1239
	struct razor_property *p;
krh@41
  1240
krh@79
  1241
	p = array_add(&merger->set->properties, sizeof *p);
danw@119
  1242
	p->name = hashtable_tokenize(&merger->table, name);
danw@119
  1243
	p->flags = 0;
danw@119
  1244
	p->type = type;
danw@109
  1245
	p->relation = relation;
krh@79
  1246
	p->version = hashtable_tokenize(&merger->table, version);
krh@41
  1247
krh@79
  1248
	return p - (struct razor_property *) merger->set->properties.data;
krh@41
  1249
}
krh@41
  1250
krh@41
  1251
static void
krh@79
  1252
merge_properties(struct razor_merger *merger)
krh@41
  1253
{
krh@41
  1254
	struct razor_property *p1, *p2;
krh@79
  1255
	struct razor_set *set1, *set2;
danw@108
  1256
	uint32_t *map1, *map2;
krh@41
  1257
	int i, j, cmp, count1, count2;
krh@41
  1258
	char *pool1, *pool2;
krh@41
  1259
krh@79
  1260
	set1 = merger->source1.set;
krh@79
  1261
	set2 = merger->source2.set;
krh@79
  1262
	map1 = merger->source1.property_map;
krh@79
  1263
	map2 = merger->source2.property_map;
krh@79
  1264
krh@41
  1265
	i = 0;
krh@41
  1266
	j = 0;
krh@41
  1267
	pool1 = set1->string_pool.data;
krh@41
  1268
	pool2 = set2->string_pool.data;
krh@41
  1269
krh@66
  1270
	count1 = set1->properties.size / sizeof *p1;
krh@66
  1271
	count2 = set2->properties.size / sizeof *p2;
krh@41
  1272
	while (i < count1 || j < count2) {
krh@41
  1273
		if (i < count1 && map1[i] == 0) {
krh@41
  1274
			i++;
krh@41
  1275
			continue;
krh@41
  1276
		}
krh@41
  1277
		if (j < count2 && map2[j] == 0) {
krh@41
  1278
			j++;
krh@41
  1279
			continue;
krh@41
  1280
		}
krh@66
  1281
		p1 = (struct razor_property *) set1->properties.data + i;
krh@66
  1282
		p2 = (struct razor_property *) set2->properties.data + j;
krh@41
  1283
		if (i < count1 && j < count2)
danw@119
  1284
			cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
krh@41
  1285
		else if (i < count1)
krh@41
  1286
			cmp = -1;
krh@41
  1287
		else
krh@41
  1288
			cmp = 1;
krh@41
  1289
		if (cmp == 0)
danw@121
  1290
			cmp = p1->type - p2->type;
danw@121
  1291
		if (cmp == 0)
danw@109
  1292
			cmp = p1->relation - p2->relation;
danw@109
  1293
		if (cmp == 0)
krh@41
  1294
			cmp = versioncmp(&pool1[p1->version],
krh@41
  1295
					 &pool2[p2->version]);
krh@41
  1296
		if (cmp < 0) {
krh@79
  1297
			map1[i++] = add_property(merger,
danw@119
  1298
						 &pool1[p1->name],
danw@109
  1299
						 p1->relation,
krh@69
  1300
						 &pool1[p1->version],
danw@119
  1301
						 p1->type);
krh@41
  1302
		} else if (cmp > 0) {
krh@79
  1303
			map2[j++] = add_property(merger,
danw@119
  1304
						 &pool2[p2->name],
danw@109
  1305
						 p2->relation,
krh@69
  1306
						 &pool2[p2->version],
danw@119
  1307
						 p2->type);
krh@41
  1308
		} else  {
krh@79
  1309
			map1[i++] = map2[j++] = add_property(merger,
danw@119
  1310
							     &pool1[p1->name],
danw@109
  1311
							     p1->relation,
krh@69
  1312
							     &pool1[p1->version],
danw@119
  1313
							     p1->type);
krh@41
  1314
		}
krh@41
  1315
	}
krh@41
  1316
}
krh@41
  1317
danw@116
  1318
static void
danw@117
  1319
emit_properties(struct list_head *properties, struct array *source_pool,
danw@108
  1320
		uint32_t *map, struct array *pool)
krh@41
  1321
{
danw@117
  1322
	uint32_t r;
danw@117
  1323
	struct list *p, *q;
krh@41
  1324
krh@41
  1325
	r = pool->size / sizeof *q;
danw@116
  1326
	p = list_first(properties, source_pool);
danw@116
  1327
	while (p) {
krh@41
  1328
		q = array_add(pool, sizeof *q);
danw@117
  1329
		q->data = map[p->data];
danw@117
  1330
		q->flags = p->flags;
danw@116
  1331
		p = list_next(p);
krh@33
  1332
	}
krh@33
  1333
danw@117
  1334
	list_set_ptr(properties, r);
krh@41
  1335
}
danw@127
  1336
danw@127
  1337
static uint32_t
danw@127
  1338
add_file(struct razor_merger *merger, const char *name)
danw@127
  1339
{
danw@127
  1340
	struct razor_entry *e;
danw@127
  1341
danw@127
  1342
	e = array_add(&merger->set->files, sizeof *e);
danw@127
  1343
	e->name = hashtable_tokenize(&merger->table, name);
danw@127
  1344
	e->flags = 0;
danw@127
  1345
	e->start = 0;
danw@127
  1346
danw@127
  1347
	return e - (struct razor_entry *)merger->set->files.data;
danw@127
  1348
}
danw@127
  1349
danw@129
  1350
/* FIXME. Blah */
danw@127
  1351
static int
danw@127
  1352
fix_file_map(uint32_t *map,
danw@127
  1353
	     struct razor_entry *files,
danw@127
  1354
	     struct razor_entry *top)
danw@127
  1355
{
danw@127
  1356
	uint32_t e;
danw@127
  1357
	int found_file = 0;
danw@127
  1358
danw@127
  1359
	e = top->start;
danw@127
  1360
	do {
danw@127
  1361
		if (files[e].start)
danw@127
  1362
			fix_file_map(map, files, &files[e]);
danw@127
  1363
		if (map[e])
danw@127
  1364
			found_file = 1;
danw@127
  1365
	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
danw@127
  1366
danw@127
  1367
	if (found_file)
danw@127
  1368
		map[top - files] = 1;
danw@127
  1369
	return found_file;
danw@127
  1370
}
danw@127
  1371
danw@127
  1372
struct merge_directory {
danw@127
  1373
	uint32_t merged, dir1, dir2;
danw@127
  1374
};
danw@127
  1375
danw@127
  1376
static void
danw@127
  1377
merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
danw@127
  1378
{
danw@127
  1379
	struct razor_entry *root1, *root2, *mroot, *e1, *e2;
danw@127
  1380
	struct razor_set *set1, *set2;
danw@127
  1381
	struct array merge_stack;
danw@127
  1382
	struct merge_directory *child_md, *end_md;
danw@127
  1383
	uint32_t *map1, *map2, start, last;
danw@127
  1384
	int cmp;
danw@127
  1385
	char *pool1, *pool2;
danw@127
  1386
danw@127
  1387
	set1 = merger->source1.set;
danw@127
  1388
	set2 = merger->source2.set;
danw@127
  1389
	map1 = merger->source1.file_map;
danw@127
  1390
	map2 = merger->source2.file_map;
danw@127
  1391
	pool1 = set1->string_pool.data;
danw@127
  1392
	pool2 = set2->string_pool.data;
danw@127
  1393
	root1 = (struct razor_entry *) set1->files.data;
danw@127
  1394
	root2 = (struct razor_entry *) set2->files.data;
danw@127
  1395
danw@127
  1396
	array_init(&merge_stack);
danw@127
  1397
danw@127
  1398
	start = merger->set->files.size / sizeof (struct razor_entry);
danw@127
  1399
	last = 0;
danw@127
  1400
	e1 = md->dir1 ? root1 + md->dir1 : NULL;
danw@127
  1401
	e2 = md->dir2 ? root2 + md->dir2 : NULL;
danw@127
  1402
	while (e1 || e2) {
danw@127
  1403
		if (!e2 && !map1[e1 - root1]) {
danw@127
  1404
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1405
				e1 = NULL;
danw@127
  1406
			continue;
danw@127
  1407
		}
danw@127
  1408
		if (!e1 && !map2[e2 - root2]) {
danw@127
  1409
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1410
				e2 = NULL;
danw@127
  1411
			continue;
danw@127
  1412
		}
danw@127
  1413
		if (e1 && !map1[e1 - root1] &&
danw@127
  1414
		    e2 && !map1[e2 - root2]) {
danw@127
  1415
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1416
				e1 = NULL;
danw@127
  1417
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1418
				e2 = NULL;
danw@127
  1419
			continue;
danw@127
  1420
		}
danw@127
  1421
danw@127
  1422
		if (!e1)
danw@127
  1423
			cmp = 1;
danw@127
  1424
		else if (!e2)
danw@127
  1425
			cmp = -1;
danw@127
  1426
		else {
danw@127
  1427
			cmp = strcmp (&pool1[e1->name],
danw@127
  1428
				      &pool2[e2->name]);
danw@127
  1429
		}
danw@127
  1430
danw@127
  1431
		if (cmp < 0) {
danw@127
  1432
			if (map1[e1 - root1]) {
danw@127
  1433
				map1[e1 - root1] = last =
danw@127
  1434
					add_file(merger, &pool1[e1->name]);
danw@127
  1435
				if (e1->start) {
danw@127
  1436
					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
danw@127
  1437
					child_md->merged = last;
danw@127
  1438
					child_md->dir1 = e1->start;
danw@127
  1439
					child_md->dir2 = 0;
danw@127
  1440
				}
danw@127
  1441
			}
danw@127
  1442
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1443
				e1 = NULL;
danw@127
  1444
		} else if (cmp > 0) {
danw@127
  1445
			if (map2[e2 - root2]) {
danw@127
  1446
				map2[e2 - root2] = last =
danw@127
  1447
					add_file(merger, &pool2[e2->name]);
danw@127
  1448
				if (e2->start) {
danw@127
  1449
					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
danw@127
  1450
					child_md->merged = last;
danw@127
  1451
					child_md->dir1 = 0;
danw@127
  1452
					child_md->dir2 = e2->start;
danw@127
  1453
				}
danw@127
  1454
			}
danw@127
  1455
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1456
				e2 = NULL;
danw@127
  1457
		} else {
danw@127
  1458
			map1[e1 - root1] = map2[e2- root2] = last =
danw@127
  1459
				add_file(merger, &pool1[e1->name]);
danw@127
  1460
			if (e1->start || e2->start) {
danw@127
  1461
				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
danw@127
  1462
				child_md->merged = last;
danw@127
  1463
				child_md->dir1 = e1->start;
danw@127
  1464
				child_md->dir2 = e2->start;
danw@127
  1465
			}
danw@127
  1466
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1467
				e1 = NULL;
danw@127
  1468
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1469
				e2 = NULL;
danw@127
  1470
		}
danw@127
  1471
	}
danw@127
  1472
danw@127
  1473
	mroot = (struct razor_entry *)merger->set->files.data;
danw@127
  1474
	if (last) {
danw@127
  1475
		mroot[last].flags = RAZOR_ENTRY_LAST;
danw@127
  1476
		mroot[md->merged].start = start;
danw@127
  1477
	} else
danw@127
  1478
		mroot[md->merged].start = 0;
danw@127
  1479
danw@127
  1480
	end_md = merge_stack.data + merge_stack.size;
danw@127
  1481
	for (child_md = merge_stack.data; child_md < end_md; child_md++)
danw@127
  1482
		merge_one_directory(merger, child_md);
danw@127
  1483
	array_release(&merge_stack);
danw@127
  1484
}
danw@127
  1485
danw@127
  1486
static void
danw@127
  1487
merge_files(struct razor_merger *merger)
danw@127
  1488
{
danw@129
  1489
	struct razor_entry *root;
danw@127
  1490
	struct merge_directory md;
danw@127
  1491
	uint32_t *map1, *map2;
danw@127
  1492
danw@127
  1493
	map1 = merger->source1.file_map;
danw@127
  1494
	map2 = merger->source2.file_map;
danw@127
  1495
danw@127
  1496
	md.merged = add_file(merger, "");
danw@129
  1497
danw@129
  1498
	if (merger->source1.set->files.size) {
danw@129
  1499
		root = (struct razor_entry *) merger->source1.set->files.data;
danw@129
  1500
		if (root->start)
danw@129
  1501
			fix_file_map(map1, root, root);
danw@129
  1502
		md.dir1 = root->start;
danw@129
  1503
	} else
danw@129
  1504
		md.dir1 = 0;
danw@129
  1505
danw@129
  1506
	if (merger->source2.set->files.size) {
danw@129
  1507
		root = (struct razor_entry *) merger->source2.set->files.data;
danw@129
  1508
		if (root->start)
danw@129
  1509
			fix_file_map(map2, root, root);
danw@129
  1510
		md.dir2 = root->start;
danw@129
  1511
	} else
danw@129
  1512
		md.dir2 = 0;
danw@129
  1513
danw@127
  1514
	merge_one_directory(merger, &md);
danw@127
  1515
}
danw@127
  1516
danw@127
  1517
static void
danw@127
  1518
emit_files(struct list_head *files, struct array *source_pool,
danw@127
  1519
	   uint32_t *map, struct array *pool)
danw@127
  1520
{
danw@127
  1521
	uint32_t r;
danw@127
  1522
	struct list *p, *q;
danw@127
  1523
danw@127
  1524
	r = pool->size / sizeof *q;
danw@127
  1525
	p = list_first(files, source_pool);
danw@127
  1526
	while (p) {
danw@127
  1527
		q = array_add(pool, sizeof *q);
danw@127
  1528
		q->data = map[p->data];
danw@127
  1529
		q->flags = p->flags;
danw@127
  1530
		p = list_next(p);
danw@127
  1531
	}
danw@127
  1532
danw@127
  1533
	list_set_ptr(files, r);
danw@127
  1534
}
danw@127
  1535
krh@41
  1536
/* Rebuild property->packages maps.  We can't just remap these, as a
krh@41
  1537
 * property may have lost or gained a number of packages.  Allocate an
krh@41
  1538
 * array per property and loop through the packages and add them to
krh@41
  1539
 * the arrays for their properties. */
krh@41
  1540
static void
danw@127
  1541
rebuild_property_package_lists(struct razor_set *set)
krh@41
  1542
{
krh@66
  1543
	struct array *pkgs, *a;
krh@41
  1544
	struct razor_package *pkg, *pkg_end;
krh@41
  1545
	struct razor_property *prop, *prop_end;
danw@117
  1546
	struct list *r;
danw@117
  1547
	uint32_t *q;
krh@66
  1548
	int count;
krh@41
  1549
krh@66
  1550
	count = set->properties.size / sizeof (struct razor_property);
krh@66
  1551
	pkgs = zalloc(count * sizeof *pkgs);
krh@41
  1552
	pkg_end = set->packages.data + set->packages.size;
krh@41
  1553
krh@41
  1554
	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
danw@128
  1555
		r = list_first(&pkg->properties, &set->property_pool);
danw@116
  1556
		while (r) {
danw@117
  1557
			q = array_add(&pkgs[r->data], sizeof *q);
krh@41
  1558
			*q = pkg - (struct razor_package *) set->packages.data;
danw@116
  1559
			r = list_next(r);
krh@41
  1560
		}
krh@33
  1561
	}
krh@33
  1562
krh@66
  1563
	prop_end = set->properties.data + set->properties.size;
krh@66
  1564
	a = pkgs;
krh@66
  1565
	for (prop = set->properties.data; prop < prop_end; prop++, a++) {
danw@128
  1566
		list_set_array(&prop->packages, &set->package_pool, a, 0);
krh@41
  1567
		array_release(a);
krh@41
  1568
	}
krh@66
  1569
	free(pkgs);
krh@33
  1570
}
krh@33
  1571
danw@127
  1572
static void
danw@127
  1573
rebuild_file_package_lists(struct razor_set *set)
danw@127
  1574
{
danw@127
  1575
	struct array *pkgs, *a;
danw@127
  1576
	struct razor_package *pkg, *pkg_end;
danw@127
  1577
	struct razor_entry *entry, *entry_end;
danw@127
  1578
	struct list *r;
danw@127
  1579
	uint32_t *q;
danw@127
  1580
	int count;
danw@127
  1581
danw@127
  1582
	count = set->files.size / sizeof (struct razor_entry);
danw@127
  1583
	pkgs = zalloc(count * sizeof *pkgs);
danw@127
  1584
	pkg_end = set->packages.data + set->packages.size;
danw@127
  1585
danw@127
  1586
	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
danw@128
  1587
		r = list_first(&pkg->files, &set->file_pool);
danw@127
  1588
		while (r) {
danw@127
  1589
			q = array_add(&pkgs[r->data], sizeof *q);
danw@127
  1590
			*q = pkg - (struct razor_package *) set->packages.data;
danw@127
  1591
			r = list_next(r);
danw@127
  1592
		}
danw@127
  1593
	}
danw@127
  1594
danw@127
  1595
	entry_end = set->files.data + set->files.size;
danw@127
  1596
	a = pkgs;
danw@127
  1597
	for (entry = set->files.data; entry < entry_end; entry++, a++) {
danw@128
  1598
		list_set_array(&entry->packages, &set->package_pool, a, 0);
danw@127
  1599
		array_release(a);
danw@127
  1600
	}
danw@127
  1601
	free(pkgs);
danw@127
  1602
}
danw@127
  1603
danw@137
  1604
static struct razor_set *
krh@79
  1605
razor_merger_finish(struct razor_merger *merger)
krh@79
  1606
{
krh@79
  1607
	struct razor_set *result;
krh@41
  1608
	struct razor_package *p, *pend;
krh@33
  1609
krh@41
  1610
	/* As we built the package list, we filled out a bitvector of
krh@41
  1611
	 * the properties that are referenced by the packages in the
krh@41
  1612
	 * new set.  Now we do a parallel loop through the properties
krh@41
  1613
	 * and emit those marked in the bit vector to the new set.  In
krh@41
  1614
	 * the process, we update the bit vector to actually map from
krh@41
  1615
	 * indices in the old property list to indices in the new
krh@41
  1616
	 * property list for both sets. */
krh@41
  1617
krh@79
  1618
	merge_properties(merger);
danw@127
  1619
	merge_files(merger);
krh@41
  1620
krh@41
  1621
	/* Now we loop through the packages again and emit the
krh@41
  1622
	 * property lists, remapped to point to the new properties. */
krh@41
  1623
krh@79
  1624
	pend = merger->set->packages.data + merger->set->packages.size;
krh@79
  1625
	for (p = merger->set->packages.data; p < pend; p++) {
krh@41
  1626
		struct source *src;
krh@41
  1627
danw@120
  1628
		if (p->flags & UPSTREAM_SOURCE)
krh@79
  1629
			src = &merger->source2;
krh@41
  1630
		else
krh@79
  1631
			src = &merger->source1;
krh@41
  1632
danw@116
  1633
		emit_properties(&p->properties,
danw@116
  1634
				&src->set->property_pool,
danw@116
  1635
				src->property_map,
danw@116
  1636
				&merger->set->property_pool);
danw@127
  1637
		emit_files(&p->files,
danw@127
  1638
			   &src->set->file_pool,
danw@127
  1639
			   src->file_map,
danw@127
  1640
			   &merger->set->file_pool);
danw@120
  1641
		p->flags &= ~UPSTREAM_SOURCE;
krh@33
  1642
	}
krh@33
  1643
danw@127
  1644
	rebuild_property_package_lists(merger->set);
danw@127
  1645
	rebuild_file_package_lists(merger->set);
krh@41
  1646
danw@129
  1647
	result = merger->set;
danw@129
  1648
	hashtable_release(&merger->table);
danw@129
  1649
	free(merger);
danw@129
  1650
danw@129
  1651
	return result;
danw@129
  1652
}
danw@129
  1653
danw@137
  1654
static int
danw@137
  1655
find_packages(struct razor_set *set, int count, const char **package_names,
danw@137
  1656
	      struct array *package_array,
danw@137
  1657
	      enum razor_transaction_package_state state)
krh@38
  1658
{
krh@105
  1659
	struct razor_package_iterator *pi;
krh@105
  1660
	struct razor_package *p, *packages;
krh@105
  1661
	const char *name, *version;
danw@137
  1662
	struct razor_transaction_package *tp;
danw@137
  1663
	int i, *found, errors = 0;
krh@38
  1664
krh@105
  1665
	packages = (struct razor_package *) set->packages.data;
krh@105
  1666
	pi = razor_package_iterator_create(set);
danw@137
  1667
	found = zalloc(count * sizeof (int));
krh@105
  1668
krh@105
  1669
	while (razor_package_iterator_next(pi, &p, &name, &version)) {
krh@105
  1670
		for (i = 0; i < count; i++) {
krh@105
  1671
			if (strcmp(name, package_names[i]) == 0) {
danw@137
  1672
				found[i] = 1;
danw@137
  1673
				tp = array_add(package_array, sizeof *tp);
danw@137
  1674
				memset(tp, 0, sizeof *tp);
danw@137
  1675
				tp->package = p;
danw@137
  1676
				tp->name = name;
danw@137
  1677
				tp->version = version;
danw@137
  1678
				tp->state = state;
krh@105
  1679
				break;
krh@105
  1680
			}
krh@105
  1681
		}
krh@38
  1682
	}
krh@105
  1683
danw@137
  1684
	for (i = 0; i < count; i++) {
danw@137
  1685
		if (!found[i]) {
danw@137
  1686
			tp = array_add(package_array, sizeof *tp);
danw@137
  1687
			memset(tp, 0, sizeof *tp);
danw@137
  1688
			tp->name = strdup(package_names[i]);
danw@137
  1689
			tp->state = state | RAZOR_PACKAGE_UNAVAILABLE;
danw@137
  1690
			errors++;
danw@137
  1691
		}
danw@137
  1692
	}
danw@137
  1693
krh@105
  1694
	razor_package_iterator_destroy(pi);
danw@137
  1695
	free(found);
danw@137
  1696
danw@137
  1697
	return errors;
krh@38
  1698
}
krh@38
  1699
krh@38
  1700
static void
krh@38
  1701
find_all_packages(struct razor_set *set,
danw@137
  1702
		  struct razor_set *upstream, struct array *package_array)
krh@38
  1703
{
danw@137
  1704
	struct razor_transaction_package *tp;
krh@38
  1705
	struct razor_package *p, *u, *pend, *uend;
krh@38
  1706
	char *pool, *upool;
krh@38
  1707
krh@38
  1708
	pend = set->packages.data + set->packages.size;
krh@38
  1709
	pool = set->string_pool.data;
krh@38
  1710
	u = upstream->packages.data;
krh@38
  1711
	uend = upstream->packages.data + upstream->packages.size;
krh@38
  1712
	upool = upstream->string_pool.data;
krh@38
  1713
krh@38
  1714
	for (p = set->packages.data; p < pend; p++) {
krh@38
  1715
		while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
krh@38
  1716
			u++;
krh@38
  1717
		if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
danw@137
  1718
			tp = array_add(package_array, sizeof *tp);
danw@137
  1719
			memset(tp, 0, sizeof *tp);
danw@137
  1720
			tp->name = &upool[u->name];
danw@137
  1721
			tp->version = &upool[u->version];
danw@137
  1722
			tp->state = RAZOR_PACKAGE_INSTALL;
krh@38
  1723
		}
krh@38
  1724
	}
krh@38
  1725
}
krh@38
  1726
danw@137
  1727
/* FIXME: wrong, need to compare names, not razor_package* */
danw@134
  1728
static int
danw@137
  1729
find_transaction_package(struct array *package_array,
danw@137
  1730
			 struct razor_package *package)
danw@137
  1731
{
danw@137
  1732
	struct razor_transaction_package *tps = package_array->data;
danw@137
  1733
	int i, tpcount = package_array->size / sizeof *tps;
danw@137
  1734
danw@137
  1735
	for (i = 0; i < tpcount; i++) {
danw@137
  1736
		if (tps[i].package == package)
danw@137
  1737
			return i;
danw@137
  1738
	}
danw@137
  1739
	return -1;
danw@137
  1740
}
danw@137
  1741
danw@137
  1742
static int
danw@137
  1743
provider_satisfies_requirement(struct razor_property *provider,
danw@137
  1744
			       const char *provider_strings,
danw@137
  1745
			       struct razor_property *requirement,
danw@137
  1746
			       const char *requirement_strings)
danw@137
  1747
{
danw@137
  1748
	int cmp, len;
danw@137
  1749
	const char *provided = &provider_strings[provider->version];
danw@137
  1750
	const char *required = &requirement_strings[requirement->version];
danw@137
  1751
danw@137
  1752
	if (!*required)
danw@137
  1753
		return 1;
danw@137
  1754
danw@137
  1755
	cmp = versioncmp(provided, required);
danw@137
  1756
danw@137
  1757
	switch (requirement->relation) {
danw@137
  1758
	case RAZOR_VERSION_LESS:
danw@137
  1759
		return cmp < 0;
danw@137
  1760
danw@137
  1761
	case RAZOR_VERSION_LESS_OR_EQUAL:
danw@137
  1762
		if (cmp <= 0)
danw@137
  1763
			return 1;
danw@137
  1764
		/* fall through: FIXME, make sure this is correct */
danw@137
  1765
danw@137
  1766
	case RAZOR_VERSION_EQUAL:
danw@137
  1767
		if (cmp == 0)
danw@137
  1768
			return 1;
danw@137
  1769
danw@137
  1770
		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
danw@137
  1771
		len = strlen(required);
danw@137
  1772
		if (!strncmp(required, provided, len) && provided[len] == '-')
danw@137
  1773
			return 1;
danw@137
  1774
		return 0;
danw@137
  1775
danw@137
  1776
	case RAZOR_VERSION_GREATER_OR_EQUAL:
danw@137
  1777
		return cmp >= 0;
danw@137
  1778
danw@137
  1779
	case RAZOR_VERSION_GREATER:
danw@137
  1780
		return cmp > 0;
danw@137
  1781
	}
danw@137
  1782
danw@137
  1783
	/* shouldn't happen */
danw@137
  1784
	return 0;
danw@137
  1785
}
danw@137
  1786
danw@137
  1787
static int
danw@138
  1788
find_property_provider(struct razor_set *set,
danw@138
  1789
		       struct razor_property *requirement,
danw@138
  1790
		       const char *requirement_strings)
danw@134
  1791
{
danw@134
  1792
	struct razor_property *props = set->properties.data;
danw@137
  1793
	int p, hi, lo, cmp;
danw@134
  1794
	char *pool = set->string_pool.data;
danw@134
  1795
danw@134
  1796
	lo = 0;
danw@134
  1797
	hi = set->properties.size / sizeof *props;
danw@134
  1798
	while (lo < hi) {
danw@134
  1799
		p = (lo + hi) / 2;
danw@137
  1800
		cmp = strcmp(&pool[props[p].name],
danw@137
  1801
			     &requirement_strings[requirement->name]);
danw@134
  1802
		if (cmp < 0)
danw@134
  1803
			lo = p + 1;
danw@134
  1804
		else if (cmp > 0)
danw@134
  1805
			hi = p;
danw@134
  1806
		else
danw@134
  1807
			break;
danw@134
  1808
	}
danw@134
  1809
	if (lo >= hi)
danw@134
  1810
		return -1;
danw@134
  1811
danw@134
  1812
	/* Seek to the last (ie, highest version number) PROVIDES
danw@134
  1813
	 * entry for this name.
danw@134
  1814
	 */
danw@134
  1815
	if (props[p].type < RAZOR_PROPERTY_PROVIDES) {
danw@134
  1816
		while (p < hi &&
danw@134
  1817
		       props[p].type != RAZOR_PROPERTY_PROVIDES &&
danw@134
  1818
		       props[p + 1].name == props[p].name)
danw@134
  1819
			p++;
danw@134
  1820
	} else if (props[p].type > RAZOR_PROPERTY_PROVIDES) {
danw@134
  1821
		while (p > lo &&
danw@134
  1822
		       props[p].type != RAZOR_PROPERTY_PROVIDES &&
danw@134
  1823
		       props[p - 1].name == props[p].name)
danw@134
  1824
			p--;
danw@134
  1825
	}
danw@134
  1826
	while (p < hi &&
danw@134
  1827
	       props[p + 1].type == RAZOR_PROPERTY_PROVIDES &&
danw@134
  1828
	       props[p + 1].name == props[p].name)
danw@134
  1829
		p++;
danw@134
  1830
danw@134
  1831
	if (props[p].type != RAZOR_PROPERTY_PROVIDES)
danw@134
  1832
		return -1;
danw@134
  1833
danw@134
  1834
	do {
danw@137
  1835
		if (provider_satisfies_requirement(&props[p], pool,
danw@137
  1836
						   requirement, requirement_strings))
danw@137
  1837
			return list_first(&props[p].packages, &set->package_pool)->data;
danw@134
  1838
danw@134
  1839
		p--;
danw@134
  1840
	} while (p > lo && props[p].name == props[p + 1].name &&
danw@134
  1841
		 props[p].type == RAZOR_PROPERTY_PROVIDES);
danw@134
  1842
danw@134
  1843
	return -1;
danw@134
  1844
}
danw@134
  1845
danw@138
  1846
static int
danw@138
  1847
find_file_provider(struct razor_set *set, const char *filename)
danw@138
  1848
{
danw@138
  1849
	struct razor_entry *entry;
danw@138
  1850
danw@138
  1851
	entry = find_entry(set, set->files.data, filename);
danw@138
  1852
	if (entry)
danw@138
  1853
		return list_first(&entry->packages, &set->package_pool)->data;
danw@138
  1854
	else
danw@138
  1855
		return -1;
danw@138
  1856
}
danw@138
  1857
danw@138
  1858
static int
danw@138
  1859
find_provider(struct razor_set *set, struct razor_property *requirement,
danw@138
  1860
	      const char *requirement_strings)
danw@138
  1861
{
danw@138
  1862
	const char *name = &requirement_strings[requirement->name];
danw@138
  1863
	if (*name == '/')
danw@138
  1864
		return find_file_provider(set, name);
danw@138
  1865
	else
danw@138
  1866
		return find_property_provider(set, requirement, requirement_strings);
danw@138
  1867
}
danw@138
  1868
danw@131
  1869
static void
danw@134
  1870
gather_new_requires(struct razor_set *system, struct razor_set *upstream,
danw@134
  1871
		    struct razor_package *pkg, struct array *new_requires)
danw@131
  1872
{
danw@134
  1873
	struct razor_property *uprops = upstream->properties.data, *prop;
danw@134
  1874
	char *upool = upstream->string_pool.data;
danw@134
  1875
	struct list *p;
danw@134
  1876
	uint32_t *new;
danw@131
  1877
danw@134
  1878
	for (p = list_first(&pkg->properties, &upstream->property_pool); p; p = list_next(p)) {
danw@134
  1879
		prop = &uprops[p->data];
danw@134
  1880
		if (prop->type != RAZOR_PROPERTY_REQUIRES)
danw@134
  1881
			continue;
danw@134
  1882
		if (!strncmp(&upool[prop->name], "rpmlib(", 7))
danw@134
  1883
			continue;
danw@131
  1884
danw@137
  1885
		if (find_provider(system, prop, upool) == -1) {
danw@134
  1886
			new = array_add(new_requires, sizeof *new);
danw@134
  1887
			*new = p->data;
danw@131
  1888
		}
danw@131
  1889
	}
danw@131
  1890
}
danw@131
  1891
danw@137
  1892
static void
danw@137
  1893
razor_transaction_satisfy_installs(struct razor_transaction *trans,
danw@137
  1894
				   struct array *package_array,
danw@137
  1895
				   int start, int end)
krh@33
  1896
{
danw@134
  1897
	struct razor_package *pkgs;
danw@137
  1898
	struct razor_transaction_package *packages, *tp;
danw@137
  1899
	int p, provider, already;
danw@137
  1900
	uint32_t *new, *new_end;
danw@134
  1901
	struct razor_property *props, *prop_end;
danw@134
  1902
	struct array new_requires;
danw@134
  1903
	char *pool;
danw@134
  1904
danw@137
  1905
	pkgs = trans->upstream->packages.data;
danw@137
  1906
	props = trans->upstream->properties.data;
danw@137
  1907
	prop_end = trans->upstream->properties.data + trans->upstream->properties.size;
danw@137
  1908
	pool = trans->upstream->string_pool.data;
krh@33
  1909
danw@137
  1910
	packages = package_array->data;
danw@137
  1911
	for (p = start; p < end; p++) {
danw@137
  1912
		if (packages[p].state != RAZOR_PACKAGE_INSTALL)
danw@137
  1913
			continue;
krh@33
  1914
danw@134
  1915
		array_init(&new_requires);
danw@137
  1916
		gather_new_requires(trans->system, trans->upstream,
danw@137
  1917
				    packages[p].package, &new_requires);
danw@131
  1918
danw@134
  1919
		new_end = new_requires.data + new_requires.size;
danw@134
  1920
		for (new = new_requires.data; new < new_end; new++) {
danw@137
  1921
			provider = find_provider(trans->upstream,
danw@137
  1922
						 &props[*new], pool);
danw@137
  1923
			already = find_transaction_package(package_array,
danw@137
  1924
							   &pkgs[provider]);
danw@137
  1925
			if (already != -1 &&
danw@137
  1926
			    (packages[already].state & RAZOR_PACKAGE_INSTALL))
danw@134
  1927
				continue;
danw@131
  1928
danw@137
  1929
			tp = array_add(package_array, sizeof *tp);
danw@137
  1930
			memset(tp, 0, sizeof *tp);
danw@137
  1931
			tp->req_package = packages[p].name;
danw@137
  1932
			tp->req_property = &pool[props[*new].name];
danw@137
  1933
			tp->req_relation = props[*new].relation;
danw@137
  1934
			tp->req_version = &pool[props[*new].version];
danw@137
  1935
danw@137
  1936
			if (provider != -1) {
danw@137
  1937
				tp->package = &pkgs[provider];
danw@137
  1938
				tp->name = &pool[tp->package->name];
danw@137
  1939
				tp->version = &pool[tp->package->version];
danw@137
  1940
				if (already != -1) {
danw@137
  1941
					tp->state = RAZOR_PACKAGE_INSTALL_BLOCKED;
danw@137
  1942
					trans->errors++;
danw@137
  1943
				} else
danw@137
  1944
					tp->state = RAZOR_PACKAGE_INSTALL;
danw@137
  1945
			} else {
danw@137
  1946
				tp->state = RAZOR_PACKAGE_INSTALL_UNSATISFIABLE;
danw@137
  1947
				trans->errors++;
danw@137
  1948
			}
danw@137
  1949
danw@137
  1950
			packages = package_array->data;
danw@131
  1951
		}
danw@134
  1952
		array_release(&new_requires);
krh@37
  1953
	}
krh@33
  1954
}
krh@33
  1955
danw@130
  1956
/* Look through pkg's PROVIDES, and for each one that no other package
danw@130
  1957
 * provides, add its property index to lost_provides.
danw@130
  1958
 */
danw@130
  1959
static void
danw@130
  1960
gather_lost_provides(struct razor_set *set, struct razor_package *pkg,
danw@130
  1961
		     struct array *lost_provides)
danw@130
  1962
{
danw@130
  1963
	struct razor_property *props = set->properties.data, *prop;
danw@130
  1964
	struct list *p, *providers;
danw@130
  1965
	uint32_t *lost;
danw@130
  1966
danw@130
  1967
	for (p = list_first(&pkg->properties, &set->property_pool); p; p = list_next(p)) {
danw@130
  1968
		prop = &props[p->data];
danw@130
  1969
		if (prop->type != RAZOR_PROPERTY_PROVIDES)
danw@130
  1970
			continue;
danw@130
  1971
danw@130
  1972
		providers = list_first(&prop->packages, &set->package_pool);
danw@130
  1973
		if (providers && !list_next(providers)) {
danw@130
  1974
			lost = array_add(lost_provides, sizeof *lost);
danw@130
  1975
			*lost = p->data;
danw@130
  1976
		}
danw@130
  1977
	}
danw@130
  1978
}
danw@130
  1979
danw@130
  1980
static void
danw@137
  1981
lose_requirement(struct razor_transaction *trans, struct array *package_array,
danw@137
  1982
		 const char *req_package, struct razor_property *req,
danw@137
  1983
		 struct razor_property *lost_provider,
danw@137
  1984
		 struct razor_property *first_provider)
danw@130
  1985
{
danw@137
  1986
	struct razor_property *provider, *prop_end;
danw@137
  1987
	struct razor_package *pkgs;
danw@137
  1988
	char *pool = trans->system->string_pool.data;
danw@130
  1989
	struct list *p;
danw@137
  1990
	struct razor_transaction_package *tp, *packages;;
danw@137
  1991
	int already;
danw@130
  1992
danw@137
  1993
	pkgs = trans->system->packages.data;
danw@137
  1994
	prop_end = trans->system->properties.data + trans->system->properties.size;
danw@130
  1995
danw@137
  1996
	/* See if any other provider satisfies req */
danw@137
  1997
	for (provider = first_provider;
danw@137
  1998
	     provider < prop_end && provider->type == RAZOR_PROPERTY_PROVIDES && provider->name == lost_provider->name;
danw@137
  1999
	     provider++) {
danw@137
  2000
		if (provider == lost_provider)
danw@137
  2001
			continue;
danw@137
  2002
danw@137
  2003
		if (provider_satisfies_requirement(provider, pool, req, pool))
danw@137
  2004
			return;
danw@137
  2005
	}
danw@137
  2006
danw@137
  2007
	/* Remove each of the packages requiring req */
danw@137
  2008
	for (p = list_first(&req->packages, &trans->system->package_pool); p; p = list_next(p)) {
danw@137
  2009
		packages = package_array->data;
danw@137
  2010
		already = find_transaction_package(package_array, &pkgs[p->data]);
danw@137
  2011
		if (already != -1 &&
danw@137
  2012
		    (packages[already].state & RAZOR_PACKAGE_REMOVE))
danw@137
  2013
			continue;
danw@137
  2014
danw@137
  2015
		tp = array_add(package_array, sizeof *tp);
danw@137
  2016
		memset(tp, 0, sizeof *tp);
danw@137
  2017
		tp->package = &pkgs[p->data];
danw@137
  2018
		tp->name = &pool[tp->package->name];
danw@137
  2019
		tp->version = &pool[tp->package->version];
danw@137
  2020
		tp->req_package = req_package;
danw@137
  2021
		tp->req_property = &pool[req->name];
danw@137
  2022
		tp->req_relation = req->relation;
danw@137
  2023
		tp->req_version = &pool[req->version];
danw@137
  2024
		if (already != -1) {
danw@137
  2025
			tp->state = RAZOR_PACKAGE_REMOVE_BLOCKED;
danw@137
  2026
			trans->errors++;
danw@137
  2027
		} else
danw@137
  2028
			tp->state = RAZOR_PACKAGE_REMOVE;
danw@130
  2029
	}
danw@130
  2030
}
danw@130
  2031
danw@137
  2032
static void
danw@137
  2033
razor_transaction_satisfy_removes(struct razor_transaction *trans,
danw@137
  2034
				  struct array *package_array,
danw@137
  2035
				  int start, int end)
danw@129
  2036
{
danw@137
  2037
	struct razor_transaction_package *packages;
danw@129
  2038
	struct razor_package *pkgs;
danw@137
  2039
	int pkg_count, r;
danw@137
  2040
	uint32_t *lost, *lost_end;
danw@137
  2041
	struct razor_property *props, *prop_end, *req, *first_provider;
danw@130
  2042
	struct array lost_provides;
danw@137
  2043
	const char *req_package;
danw@129
  2044
danw@137
  2045
	pkgs = trans->system->packages.data;
danw@137
  2046
	pkg_count = trans->system->packages.size / sizeof (struct razor_package);
danw@137
  2047
	props = trans->system->properties.data;
danw@137
  2048
	prop_end = trans->system->properties.data + trans->system->properties.size;
danw@130
  2049
danw@137
  2050
	for (r = start; r < end; r++) {
danw@137
  2051
		packages = package_array->data;
danw@137
  2052
		if (packages[r].state != RAZOR_PACKAGE_REMOVE)
danw@137
  2053
			continue;
danw@137
  2054
danw@130
  2055
		array_init(&lost_provides);
danw@137
  2056
		req_package = packages[r].name;
danw@137
  2057
		gather_lost_provides(trans->system, packages[r].package,
danw@137
  2058
				     &lost_provides);
danw@130
  2059
danw@130
  2060
		lost_end = lost_provides.data + lost_provides.size;
danw@130
  2061
		for (lost = lost_provides.data; lost < lost_end; lost++) {
danw@130
  2062
			/* Requires FOO will appear before Provides FOO */
danw@130
  2063
			for (req = &props[*lost]; req > props && req->name == props[*lost].name && req->type != RAZOR_PROPERTY_REQUIRES; req--)
danw@130
  2064
				;
danw@137
  2065
			first_provider = req + 1;
danw@137
  2066
danw@130
  2067
			while (req > props && req->name == props[*lost].name) {
danw@137
  2068
				lose_requirement(trans, package_array,
danw@137
  2069
						 req_package, req,
danw@137
  2070
						 &props[*lost], first_provider);
danw@130
  2071
				req--;
danw@130
  2072
			}
danw@130
  2073
		}
danw@130
  2074
		array_release(&lost_provides);
danw@130
  2075
	}
danw@129
  2076
}
danw@129
  2077
krh@44
  2078
/* The diff order matters.  We should sort the packages so that a
krh@44
  2079
 * REMOVE of a package comes before the INSTALL, and so that all
krh@44
  2080
 * requires for a package have been installed before the package.
krh@44
  2081
 **/
krh@44
  2082
krh@44
  2083
void
krh@44
  2084
razor_set_diff(struct razor_set *set, struct razor_set *upstream,
krh@44
  2085
	       razor_package_callback_t callback, void *data)
krh@44
  2086
{
krh@103
  2087
	struct razor_package_iterator *pi1, *pi2;
krh@103
  2088
	struct razor_package *p1, *p2;
krh@103
  2089
	const char *name1, *name2, *version1, *version2;
krh@106
  2090
	int res;
krh@44
  2091
krh@103
  2092
	pi1 = razor_package_iterator_create(set);
krh@103
  2093
	pi2 = razor_package_iterator_create(upstream);
krh@44
  2094
krh@103
  2095
	razor_package_iterator_next(pi1, &p1, &name1, &version1);
krh@103
  2096
	razor_package_iterator_next(pi2, &p2, &name2, &version2);
krh@44
  2097
krh@103
  2098
	while (p1 || p2) {
krh@103
  2099
		if (p1 && p2) {
krh@103
  2100
			res = strcmp(name1, name2);
krh@44
  2101
			if (res == 0)
krh@103
  2102
				res = versioncmp(version1, version2);
krh@106
  2103
		} else {
krh@106
  2104
			res = 0;
krh@44
  2105
		}
krh@44
  2106
krh@103
  2107
		if (p2 == NULL || res < 0)
krh@103
  2108
			callback(name1, version1, NULL, data);
krh@103
  2109
		else if (p1 == NULL || res > 0)
krh@103
  2110
			callback(name2, NULL, version2, data);
krh@103
  2111
krh@103
  2112
		if (p1 != NULL && res <= 0)
krh@103
  2113
			razor_package_iterator_next(pi1, &p1,
krh@103
  2114
						    &name1, &version1);
krh@103
  2115
		if (p2 != NULL && res >= 0)
krh@103
  2116
			razor_package_iterator_next(pi2, &p2,
krh@103
  2117
						    &name2, &version2);
krh@44
  2118
	}
krh@103
  2119
krh@103
  2120
	razor_package_iterator_destroy(pi1);
krh@103
  2121
	razor_package_iterator_destroy(pi2);
krh@44
  2122
}
danw@137
  2123
danw@137
  2124
struct razor_transaction *
danw@137
  2125
razor_transaction_create(struct razor_set *system, struct razor_set *upstream,
danw@137
  2126
			 int update_count, const char **update_packages,
danw@137
  2127
			 int remove_count, const char **remove_packages)
danw@137
  2128
{
danw@137
  2129
	struct razor_transaction *trans;
danw@137
  2130
	struct array packages;
danw@137
  2131
	int start, end;
danw@137
  2132
danw@137
  2133
	trans = zalloc(sizeof *trans);
danw@137
  2134
	trans->system = system;
danw@137
  2135
	trans->upstream = upstream ? upstream : razor_set_create();
danw@137
  2136
	array_init(&packages);
danw@137
  2137
danw@137
  2138
	/* Find initial upstream packages to be installed */
danw@137
  2139
	if (update_count > 0) {
danw@137
  2140
		trans->errors +=
danw@137
  2141
			find_packages(upstream, update_count, update_packages,
danw@137
  2142
				      &packages, RAZOR_PACKAGE_INSTALL);
danw@137
  2143
	} else if (remove_count == 0)
danw@137
  2144
		find_all_packages(system, upstream, &packages);
danw@137
  2145
danw@137
  2146
	/* Find initial installed packages to remove. */
danw@137
  2147
	if (remove_count > 0) {
danw@137
  2148
		trans->errors +=
danw@137
  2149
			find_packages(system, remove_count, remove_packages,
danw@137
  2150
				      &packages, RAZOR_PACKAGE_REMOVE);
danw@137
  2151
	}
danw@137
  2152
danw@137
  2153
	start = 0;
danw@137
  2154
	end = packages.size / sizeof (struct razor_transaction_package);
danw@137
  2155
danw@137
  2156
	while (!trans->errors && start != end) {
danw@137
  2157
		if (upstream)
danw@137
  2158
			razor_transaction_satisfy_installs(trans, &packages, start, end);
danw@137
  2159
		razor_transaction_satisfy_removes(trans, &packages, start, end);
danw@137
  2160
danw@137
  2161
		start = end;
danw@137
  2162
		end = packages.size / sizeof (struct razor_transaction_package);
danw@137
  2163
	}
danw@137
  2164
danw@137
  2165
	trans->packages = packages.data;
danw@137
  2166
	trans->package_count = packages.size / sizeof (struct razor_transaction_package);
danw@137
  2167
	return trans;
danw@137
  2168
}
danw@137
  2169
danw@137
  2170
const char * const razor_version_relations[] = {
danw@137
  2171
	/* same order as enum razor_version_relation */
danw@137
  2172
	"<", "<=", "=", ">=", ">"
danw@137
  2173
};
danw@137
  2174
danw@137
  2175
void
danw@137
  2176
razor_transaction_describe(struct razor_transaction *trans)
danw@137
  2177
{
danw@137
  2178
	struct razor_transaction_package *p, *pend, *tps;
danw@137
  2179
	int errors_only = 0;
danw@137
  2180
danw@137
  2181
	tps = trans->packages;
danw@137
  2182
	pend = trans->packages + trans->package_count;
danw@137
  2183
	for (p = trans->packages; p < pend; p++) {
danw@137
  2184
		switch (p->state) {
danw@137
  2185
		case RAZOR_PACKAGE_INSTALL:
danw@137
  2186
			if (errors_only)
danw@137
  2187
				break;
danw@137
  2188
danw@137
  2189
			printf ("Installing %s %s", p->name, p->version);
danw@137
  2190
			if (p->req_package) {
danw@137
  2191
				printf (" for %s", p->req_package);
danw@137
  2192
				if (*p->req_version) {
danw@137
  2193
					printf (", which requires %s %s %s",
danw@137
  2194
						p->req_property,
danw@137
  2195
						razor_version_relations[p->req_relation],
danw@137
  2196
						p->req_version);
danw@137
  2197
				} else if (strcmp(p->req_property, p->name) != 0) {
danw@137
  2198
					printf (", which requires %s",
danw@137
  2199
						p->req_property);
danw@137
  2200
				}
danw@137
  2201
			}
danw@137
  2202
			printf("\n");
danw@137
  2203
			break;
danw@137
  2204
danw@137
  2205
		case RAZOR_PACKAGE_INSTALL_UNAVAILABLE:
danw@137
  2206
			if (*p->req_version && strcmp(p->req_property, p->name) == 0) {
danw@137
  2207
				printf ("Can't find %s %s %s, which is required by %s",
danw@137
  2208
					p->name,
danw@137
  2209
					razor_version_relations[p->req_relation],
danw@137
  2210
					p->req_version,
danw@137
  2211
					p->req_package);
danw@137
  2212
			} else {
danw@137
  2213
				printf ("Can't find %s", p->name);
danw@137
  2214
				if (*p->version)
danw@137
  2215
					printf (" %s", p->version);
danw@137
  2216
				
danw@137
  2217
				if (p->req_package) {
danw@137
  2218
					printf ("  which is required by %s",
danw@137
  2219
						p->req_package);
danw@137
  2220
					if (strcmp(p->req_property, p->name) != 0)
danw@137
  2221
						printf (" for %s", p->req_property);
danw@137
  2222
				}
danw@137
  2223
			}
danw@137
  2224
			printf("\n");
danw@137
  2225
			errors_only = 1;
danw@137
  2226
			break;
danw@137
  2227
danw@137
  2228
		case RAZOR_PACKAGE_INSTALL_BLOCKED:
danw@137
  2229
			printf ("Cannot install %s, which is already marked for removal but is required by %s\n", p->name, p->req_package);
danw@137
  2230
			errors_only = 1;
danw@137
  2231
			break;
danw@137
  2232
danw@137
  2233
		case RAZOR_PACKAGE_INSTALL_UNSATISFIABLE:
danw@137
  2234
			printf ("Cannot find package for %s", p->req_property);
danw@137
  2235
			if (*p->req_version) {
danw@137
  2236
				printf (" %s %s",
danw@137
  2237
					razor_version_relations[p->req_relation],
danw@137
  2238
					p->req_version);
danw@137
  2239
			}
danw@137
  2240
			printf (" which is required by %s\n",
danw@137
  2241
				p->req_package);
danw@137
  2242
			errors_only = 1;
danw@137
  2243
			break;
danw@137
  2244
danw@137
  2245
		case RAZOR_PACKAGE_REMOVE:
danw@137
  2246
			if (errors_only)
danw@137
  2247
				break;
danw@137
  2248
			printf ("Removing %s %s", p->name, p->version);
danw@137
  2249
			if (p->req_package) {
danw@137
  2250
				printf (" which required %s", p->req_package);
danw@137
  2251
				if (strcmp(p->req_property, p->req_package) != 0)
danw@137
  2252
					printf (" for %s", p->req_property);
danw@137
  2253
			}
danw@137
  2254
			printf("\n");
danw@137
  2255
			break;
danw@137
  2256
danw@137
  2257
		case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED:
danw@137
  2258
			printf ("Package %s is not installed\n", p->name);
danw@137
  2259
			errors_only = 1;
danw@137
  2260
			break;
danw@137
  2261
danw@137
  2262
		case RAZOR_PACKAGE_REMOVE_BLOCKED:
danw@137
  2263
			printf ("Cannot remove %s, which is marked for installation but requires %s\n", p->name, p->req_package);
danw@137
  2264
			errors_only = 1;
danw@137
  2265
			break;
danw@137
  2266
danw@137
  2267
		default:
danw@137
  2268
			/* Shouldn't actually happen */
danw@137
  2269
			break;
danw@137
  2270
		}
danw@137
  2271
	}
danw@137
  2272
}
danw@137
  2273
danw@137
  2274
struct razor_set *
danw@137
  2275
razor_transaction_run(struct razor_transaction *trans)
danw@137
  2276
{
danw@137
  2277
	struct array install_packages, remove_packages;
danw@137
  2278
	struct razor_merger *merger;
danw@137
  2279
	struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send;
danw@137
  2280
	struct source *source1, *source2;
danw@137
  2281
	char *spool, *ipool, *rpool;
danw@137
  2282
	uint32_t *map;
danw@137
  2283
	int p, cmp;
danw@137
  2284
danw@137
  2285
	/* FIXME */
danw@137
  2286
	if (trans->errors)
danw@137
  2287
		return NULL;
danw@137
  2288
danw@137
  2289
	/* Sort the transaction packages into two arrays */
danw@137
  2290
	array_init(&install_packages);
danw@137
  2291
	array_init(&remove_packages);
danw@137
  2292
	for (p = 0; p < trans->package_count; p++) {
danw@137
  2293
		if (trans->packages[p].state & RAZOR_PACKAGE_INSTALL)
danw@137
  2294
			pkg = array_add(&install_packages, sizeof *pkg);
danw@137
  2295
		else
danw@137
  2296
			pkg = array_add(&remove_packages, sizeof *pkg);
danw@137
  2297
		*pkg = *trans->packages[p].package;
danw@137
  2298
	}
danw@137
  2299
	map = qsort_with_data(install_packages.data,
danw@137
  2300
			      install_packages.size / sizeof *pkg,
danw@137
  2301
			      sizeof *pkg,
danw@137
  2302
			      compare_packages,
danw@137
  2303
			      trans->upstream);
danw@137
  2304
	free(map);
danw@137
  2305
	map = qsort_with_data(remove_packages.data,
danw@137
  2306
			      remove_packages.size / sizeof *pkg,
danw@137
  2307
			      sizeof *pkg,
danw@137
  2308
			      compare_packages,
danw@137
  2309
			      trans->system);
danw@137
  2310
	free(map);
danw@137
  2311
danw@137
  2312
	merger = razor_merger_create(trans->system, trans->upstream);
danw@137
  2313
danw@137
  2314
	source1 = &merger->source1;
danw@137
  2315
	source2 = &merger->source2;
danw@137
  2316
danw@137
  2317
	i = install_packages.data;
danw@137
  2318
	iend = install_packages.data + install_packages.size;
danw@137
  2319
	ipool = trans->upstream->string_pool.data;
danw@137
  2320
danw@137
  2321
	r = remove_packages.data;
danw@137
  2322
	rend = remove_packages.data + remove_packages.size;
danw@137
  2323
	rpool = trans->system->string_pool.data;
danw@137
  2324
danw@137
  2325
	s = trans->system->packages.data;
danw@137
  2326
	send = trans->system->packages.data + trans->system->packages.size;
danw@137
  2327
	spool = trans->system->string_pool.data;
danw@137
  2328
danw@137
  2329
	while (s < send || i < iend) {
danw@137
  2330
		/* Check if s is being removed */
danw@137
  2331
		if (s < send && r < rend &&
danw@137
  2332
		    s->name == r->name && s->version && r->version) {
danw@137
  2333
			s++;
danw@137
  2334
			r++;
danw@137
  2335
			continue;
danw@137
  2336
		}
danw@137
  2337
danw@137
  2338
		if (s < send && i < iend)
danw@137
  2339
			cmp = strcmp(&spool[s->name], &ipool[i->name]);
danw@137
  2340
		else if (s < send)
danw@137
  2341
			cmp = -1;
danw@137
  2342
		else
danw@137
  2343
			cmp = 1;
danw@137
  2344
		if (cmp < 0) {
danw@137
  2345
			add_package(merger, s, source1, 0);
danw@137
  2346
			s++;
danw@137
  2347
		} else if (cmp == 0) {
danw@137
  2348
			add_package(merger, i, source2, UPSTREAM_SOURCE);
danw@137
  2349
			s++;
danw@137
  2350
			i++;
danw@137
  2351
		} else {
danw@137
  2352
			add_package(merger, i, source2, UPSTREAM_SOURCE);
danw@137
  2353
			i++;
danw@137
  2354
		}
danw@137
  2355
	}
danw@137
  2356
danw@137
  2357
	array_release(&install_packages);
danw@137
  2358
	array_release(&remove_packages);
danw@137
  2359
danw@137
  2360
	return razor_merger_finish(merger);
danw@137
  2361
}
danw@137
  2362
danw@137
  2363
void
danw@137
  2364
razor_transaction_destroy(struct razor_transaction *trans)
danw@137
  2365
{
danw@137
  2366
	int p;
danw@137
  2367
danw@137
  2368
	for (p = 0; p < trans->package_count; p++) {
danw@137
  2369
		if (!trans->packages[p].req_package &&
danw@137
  2370
		    (trans->packages[p].state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE ||
danw@137
  2371
		     trans->packages[p].state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED))
danw@137
  2372
			free((char *)trans->packages[p].name);
danw@137
  2373
	}
danw@137
  2374
	free(trans);
danw@137
  2375
danw@137
  2376
	/* FIXME: free upstream if it was created as an empty set */
danw@137
  2377
}