razor.c
author Kristian H?gsberg <krh@redhat.com>
Thu Sep 20 14:21:28 2007 -0400 (2007-09-20)
changeset 37 094daff9a8dc
parent 36 266dba01582d
child 38 88f3ec190a3f
permissions -rw-r--r--
Implement the rest of package updating.
krh@15
     1
#define _GNU_SOURCE
krh@15
     2
krh@0
     3
#include <stdlib.h>
krh@19
     4
#include <stddef.h>
krh@0
     5
#include <stdio.h>
krh@0
     6
#include <string.h>
krh@0
     7
#include <sys/types.h>
krh@0
     8
#include <sys/stat.h>
krh@0
     9
#include <sys/mman.h>
krh@0
    10
#include <unistd.h>
krh@0
    11
#include <fcntl.h>
krh@15
    12
#include <errno.h>
krh@35
    13
#include <ctype.h>
krh@0
    14
krh@27
    15
#include "razor.h"
krh@6
    16
krh@30
    17
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
krh@30
    18
krh@30
    19
struct array {
krh@30
    20
	void *data;
krh@30
    21
	int size, alloc;
krh@30
    22
};
krh@30
    23
krh@30
    24
struct razor_set_section {
krh@30
    25
	unsigned int type;
krh@30
    26
	unsigned int offset;
krh@30
    27
	unsigned int size;
krh@30
    28
};
krh@30
    29
krh@30
    30
struct razor_set_header {
krh@30
    31
	unsigned int magic;
krh@30
    32
	unsigned int version;
krh@30
    33
	struct razor_set_section sections[0];
krh@30
    34
};
krh@30
    35
krh@30
    36
#define RAZOR_MAGIC 0x7a7a7a7a
krh@30
    37
#define RAZOR_VERSION 1
krh@30
    38
krh@30
    39
#define RAZOR_PACKAGES 0
krh@30
    40
#define RAZOR_REQUIRES 1
krh@30
    41
#define RAZOR_PROVIDES 2
krh@30
    42
#define RAZOR_STRING_POOL 3
krh@30
    43
#define RAZOR_PROPERTY_POOL 4
krh@30
    44
krh@30
    45
struct razor_package {
krh@30
    46
	unsigned long name;
krh@30
    47
	unsigned long version;
krh@30
    48
	unsigned long requires;
krh@30
    49
	unsigned long provides;
krh@30
    50
};
krh@30
    51
krh@30
    52
struct razor_property {
krh@30
    53
	unsigned long name;
krh@30
    54
	unsigned long version;
krh@30
    55
	unsigned long packages;
krh@30
    56
};
krh@30
    57
krh@30
    58
struct razor_set {
krh@30
    59
	struct array string_pool;
krh@30
    60
	struct array property_pool;
krh@30
    61
 	struct array packages;
krh@30
    62
 	struct array requires;
krh@30
    63
 	struct array provides;
krh@30
    64
	struct razor_set_header *header;
krh@30
    65
};
krh@30
    66
krh@30
    67
struct import_property_context {
krh@30
    68
	struct array *all;
krh@30
    69
	struct array package;
krh@30
    70
};
krh@30
    71
krh@30
    72
struct razor_importer {
krh@30
    73
	struct razor_set *set;
krh@32
    74
	struct array buckets;
krh@30
    75
	struct import_property_context requires;
krh@30
    76
	struct import_property_context provides;
krh@30
    77
	struct razor_package *package;
krh@30
    78
	unsigned long *requires_map;
krh@30
    79
	unsigned long *provides_map;
krh@30
    80
};
krh@30
    81
krh@13
    82
static void
krh@13
    83
array_init(struct array *array)
krh@13
    84
{
krh@13
    85
	memset(array, 0, sizeof *array);
krh@13
    86
}
krh@13
    87
krh@13
    88
static void
krh@13
    89
array_release(struct array *array)
krh@13
    90
{
krh@13
    91
	free(array->data);
krh@13
    92
}
krh@13
    93
krh@6
    94
static void *
krh@6
    95
array_add(struct array *array, int size)
krh@6
    96
{
krh@6
    97
	int alloc;
krh@6
    98
	void *data, *p;
krh@6
    99
krh@6
   100
	if (array->alloc > 0)
krh@6
   101
		alloc = array->alloc;
krh@6
   102
	else
krh@10
   103
		alloc = 16;
krh@6
   104
krh@6
   105
	while (alloc < array->size + size)
krh@6
   106
		alloc *= 2;
krh@6
   107
krh@6
   108
	if (array->alloc < alloc) {
krh@6
   109
		data = realloc(array->data, alloc);
krh@6
   110
		if (data == NULL)
krh@6
   111
			return 0;
krh@6
   112
		array->data = data;
krh@6
   113
		array->alloc = alloc;
krh@6
   114
	}
krh@6
   115
krh@6
   116
	p = array->data + array->size;
krh@6
   117
	array->size += size;
krh@6
   118
krh@6
   119
	return p;
krh@6
   120
}
krh@6
   121
krh@0
   122
static int
krh@0
   123
write_to_fd(int fd, void *p, size_t size)
krh@0
   124
{
krh@0
   125
	int rest, len;
krh@0
   126
krh@0
   127
	rest = size;
krh@0
   128
	while (rest > 0) {
krh@0
   129
		len = write(fd, p, rest);
krh@0
   130
		if (len < 0)
krh@0
   131
			return -1;
krh@0
   132
		rest -= len;
krh@0
   133
	}
krh@0
   134
krh@0
   135
	return 0;
krh@0
   136
}
krh@0
   137
krh@0
   138
static void *
krh@0
   139
zalloc(size_t size)
krh@0
   140
{
krh@0
   141
	void *p;
krh@0
   142
krh@0
   143
	p = malloc(size);
krh@0
   144
	memset(p, 0, size);
krh@0
   145
krh@0
   146
	return p;
krh@0
   147
}
krh@0
   148
krh@19
   149
struct razor_set_section razor_sections[] = {
krh@19
   150
	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
krh@19
   151
	{ RAZOR_REQUIRES,	offsetof(struct razor_set, requires) },
krh@19
   152
	{ RAZOR_PROVIDES,	offsetof(struct razor_set, provides) },
krh@19
   153
	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
krh@19
   154
	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
krh@19
   155
};
krh@19
   156
krh@4
   157
struct razor_set *
krh@4
   158
razor_set_create(void)
krh@0
   159
{
krh@18
   160
	return zalloc(sizeof(struct razor_set));
krh@0
   161
}
krh@0
   162
krh@4
   163
struct razor_set *
krh@4
   164
razor_set_open(const char *filename)
krh@0
   165
{
krh@4
   166
	struct razor_set *set;
krh@19
   167
	struct razor_set_section *s;
krh@0
   168
	struct stat stat;
krh@19
   169
	struct array *array;
krh@19
   170
	int fd;
krh@0
   171
krh@4
   172
	set = zalloc(sizeof *set);
krh@0
   173
	fd = open(filename, O_RDONLY);
krh@0
   174
	if (fstat(fd, &stat) < 0)
krh@0
   175
		return NULL;
krh@4
   176
	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
krh@4
   177
	if (set->header == MAP_FAILED) {
krh@4
   178
		free(set);
krh@0
   179
		return NULL;
krh@0
   180
	}
krh@0
   181
krh@19
   182
	for (s = set->header->sections; ~s->type; s++) {
krh@19
   183
		if (s->type >= ARRAY_SIZE(razor_sections))
krh@19
   184
			continue;
krh@19
   185
		if (s->type != razor_sections[s->type].type)
krh@19
   186
			continue;
krh@19
   187
		array = (void *) set + razor_sections[s->type].offset;
krh@19
   188
		array->data = (void *) set->header + s->offset;
krh@19
   189
		array->size = s->size;
krh@19
   190
		array->alloc = s->size;
krh@0
   191
	}
krh@0
   192
	close(fd);
krh@0
   193
krh@4
   194
	return set;
krh@0
   195
}
krh@0
   196
krh@0
   197
void
krh@4
   198
razor_set_destroy(struct razor_set *set)
krh@0
   199
{
krh@0
   200
	unsigned int size;
krh@19
   201
	struct array *a;
krh@0
   202
	int i;
krh@0
   203
krh@4
   204
	if (set->header) {
krh@4
   205
		for (i = 0; set->header->sections[i].type; i++)
krh@0
   206
			;
krh@4
   207
		size = set->header->sections[i].type;
krh@4
   208
		munmap(set->header, size);
krh@0
   209
	} else {
krh@19
   210
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   211
			a = (void *) set + razor_sections[i].offset;
krh@19
   212
			free(a->data);
krh@19
   213
		}
krh@0
   214
	}
krh@0
   215
krh@4
   216
	free(set);
krh@0
   217
}
krh@0
   218
krh@0
   219
static int
krh@4
   220
razor_set_write(struct razor_set *set, const char *filename)
krh@0
   221
{
krh@0
   222
	char data[4096];
krh@4
   223
	struct razor_set_header *header = (struct razor_set_header *) data;
krh@19
   224
	struct array *a;
krh@17
   225
	unsigned long offset;
krh@17
   226
	int i, fd;
krh@0
   227
krh@0
   228
	memset(data, 0, sizeof data);
krh@4
   229
	header->magic = RAZOR_MAGIC;
krh@4
   230
	header->version = RAZOR_VERSION;
krh@17
   231
	offset = sizeof data;
krh@0
   232
krh@19
   233
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   234
		if (razor_sections[i].type != i)
krh@19
   235
			continue;
krh@19
   236
		a = (void *) set + razor_sections[i].offset;
krh@19
   237
		header->sections[i].type = i;
krh@17
   238
		header->sections[i].offset = offset;
krh@19
   239
		header->sections[i].size = a->size;
krh@19
   240
		offset += (a->size + 4095) & ~4095;
krh@17
   241
	}
krh@0
   242
krh@19
   243
	header->sections[i].type = ~0;
krh@17
   244
	header->sections[i].offset = 0;
krh@17
   245
	header->sections[i].size = 0;
krh@10
   246
krh@0
   247
	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
krh@0
   248
	if (fd < 0)
krh@0
   249
		return -1;
krh@0
   250
krh@0
   251
	write_to_fd(fd, data, sizeof data);
krh@19
   252
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   253
		if (razor_sections[i].type != i)
krh@19
   254
			continue;
krh@19
   255
		a = (void *) set + razor_sections[i].offset;
krh@19
   256
		write_to_fd(fd, a->data, (a->size + 4095) & ~4095);
krh@19
   257
	}
krh@17
   258
krh@17
   259
	close(fd);
krh@0
   260
krh@0
   261
	return 0;
krh@0
   262
}
krh@0
   263
krh@0
   264
static unsigned int
krh@0
   265
hash_string(const char *key)
krh@0
   266
{
krh@0
   267
	const char *p;
krh@0
   268
	unsigned int hash = 0;
krh@0
   269
krh@0
   270
	for (p = key; *p; p++)
krh@9
   271
		hash = (hash * 617) ^ *p;
krh@0
   272
krh@0
   273
	return hash;
krh@0
   274
}
krh@0
   275
krh@32
   276
static unsigned long
krh@32
   277
razor_importer_lookup(struct razor_importer *importer, const char *key)
krh@0
   278
{
krh@6
   279
	unsigned int mask, start, i;
krh@6
   280
	unsigned long *b;
krh@6
   281
	char *pool;
krh@0
   282
krh@32
   283
	pool = importer->set->string_pool.data;
krh@32
   284
	mask = importer->buckets.alloc - 1;
krh@6
   285
	start = hash_string(key) * sizeof(unsigned long);
krh@0
   286
krh@32
   287
	for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
krh@32
   288
		b = importer->buckets.data + ((start + i) & mask);
krh@6
   289
krh@6
   290
		if (*b == 0)
krh@0
   291
			return 0;
krh@0
   292
krh@6
   293
		if (strcmp(key, &pool[*b]) == 0)
krh@6
   294
			return *b;
krh@6
   295
	}
krh@0
   296
krh@0
   297
	return 0;
krh@0
   298
}
krh@0
   299
krh@0
   300
static unsigned long
krh@4
   301
add_to_string_pool(struct razor_set *set, const char *key)
krh@0
   302
{
krh@6
   303
	int len;
krh@6
   304
	char *p;
krh@0
   305
krh@0
   306
	len = strlen(key) + 1;
krh@6
   307
	p = array_add(&set->string_pool, len);
krh@6
   308
	memcpy(p, key, len);
krh@0
   309
krh@6
   310
	return p - (char *) set->string_pool.data;
krh@0
   311
}
krh@0
   312
krh@10
   313
static unsigned long
krh@10
   314
add_to_property_pool(struct razor_set *set, struct array *properties)
krh@10
   315
{
krh@10
   316
	unsigned long  *p;
krh@10
   317
krh@10
   318
	p = array_add(properties, sizeof *p);
krh@18
   319
	*p = ~0ul;
krh@10
   320
	p = array_add(&set->property_pool, properties->size);
krh@10
   321
	memcpy(p, properties->data, properties->size);
krh@10
   322
krh@10
   323
	return p - (unsigned long *) set->property_pool.data;
krh@10
   324
}
krh@10
   325
krh@0
   326
static void
krh@32
   327
do_insert(struct razor_importer *importer, unsigned long value)
krh@0
   328
{
krh@6
   329
	unsigned int mask, start, i;
krh@6
   330
	unsigned long *b;
krh@0
   331
	const char *key;
krh@0
   332
krh@32
   333
	key = (char *) importer->set->string_pool.data + value;
krh@32
   334
	mask = importer->buckets.alloc - 1;
krh@6
   335
	start = hash_string(key) * sizeof(unsigned long);
krh@6
   336
krh@32
   337
	for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
krh@32
   338
		b = importer->buckets.data + ((start + i) & mask);
krh@6
   339
		if (*b == 0) {
krh@6
   340
			*b = value;
krh@0
   341
			break;
krh@0
   342
		}
krh@6
   343
	}
krh@0
   344
}
krh@0
   345
krh@32
   346
static unsigned long
krh@32
   347
razor_importer_insert(struct razor_importer *importer, const char *key)
krh@0
   348
{
krh@6
   349
	unsigned long value, *buckets, *b, *end;
krh@6
   350
	int alloc;
krh@0
   351
krh@32
   352
	alloc = importer->buckets.alloc;
krh@32
   353
	array_add(&importer->buckets, 4 * sizeof *buckets);
krh@32
   354
	if (alloc != importer->buckets.alloc) {
krh@32
   355
		end = importer->buckets.data + alloc;
krh@32
   356
		memset(end, 0, importer->buckets.alloc - alloc);
krh@32
   357
		for (b = importer->buckets.data; b < end; b++) {
krh@6
   358
			value = *b;
krh@6
   359
			if (value != 0) {
krh@6
   360
				*b = 0;
krh@32
   361
				do_insert(importer, value);
krh@6
   362
			}
krh@0
   363
		}
krh@0
   364
	}
krh@0
   365
krh@32
   366
	value = add_to_string_pool(importer->set, key);
krh@32
   367
	do_insert (importer, value);
krh@0
   368
krh@0
   369
	return value;
krh@0
   370
}
krh@0
   371
krh@30
   372
static unsigned long
krh@32
   373
razor_importer_tokenize(struct razor_importer *importer, const char *string)
krh@0
   374
{
krh@0
   375
	unsigned long token;
krh@0
   376
krh@13
   377
	if (string == NULL)
krh@32
   378
		return razor_importer_tokenize(importer, "");
krh@13
   379
krh@32
   380
	token = razor_importer_lookup(importer, string);
krh@0
   381
	if (token != 0)
krh@0
   382
		return token;
krh@0
   383
krh@32
   384
	return razor_importer_insert(importer, string);
krh@0
   385
}
krh@0
   386
krh@27
   387
void
krh@30
   388
razor_importer_begin_package(struct razor_importer *importer,
krh@30
   389
			     const char *name, const char *version)
krh@13
   390
{
krh@25
   391
	struct razor_package *p;
krh@13
   392
krh@30
   393
	p = array_add(&importer->set->packages, sizeof *p);
krh@32
   394
	p->name = razor_importer_tokenize(importer, name);
krh@32
   395
	p->version = razor_importer_tokenize(importer, version);
krh@13
   396
krh@30
   397
	importer->package = p;
krh@30
   398
	array_init(&importer->requires.package);
krh@30
   399
	array_init(&importer->provides.package);
krh@13
   400
}
krh@13
   401
krh@13
   402
void
krh@30
   403
razor_importer_finish_package(struct razor_importer *importer)
krh@13
   404
{
krh@25
   405
	struct razor_package *p;
krh@13
   406
krh@30
   407
	p = importer->package;
krh@30
   408
	p->requires = add_to_property_pool(importer->set,
krh@30
   409
					   &importer->requires.package);
krh@30
   410
	p->provides = add_to_property_pool(importer->set,
krh@30
   411
					   &importer->provides.package);
krh@13
   412
krh@30
   413
	array_release(&importer->requires.package);
krh@30
   414
	array_release(&importer->provides.package);
krh@13
   415
}
krh@13
   416
krh@30
   417
static void
krh@30
   418
razor_importer_add_property(struct razor_importer *importer,
krh@13
   419
			    struct import_property_context *pctx,
krh@13
   420
			    const char *name, const char *version)
krh@13
   421
{
krh@25
   422
	struct razor_property *p;
krh@13
   423
	unsigned long *r;
krh@13
   424
krh@25
   425
	p = array_add(pctx->all, sizeof *p);
krh@32
   426
	p->name = razor_importer_tokenize(importer, name);
krh@32
   427
	p->version = razor_importer_tokenize(importer, version);
krh@30
   428
	p->packages = importer->package -
krh@30
   429
		(struct razor_package *) importer->set->packages.data;
krh@13
   430
krh@13
   431
	r = array_add(&pctx->package, sizeof *r);
krh@25
   432
	*r = p - (struct razor_property *) pctx->all->data;
krh@13
   433
}
krh@13
   434
krh@27
   435
void
krh@30
   436
razor_importer_add_requires(struct razor_importer *importer,
krh@30
   437
			    const char *name, const char *version)
krh@9
   438
{
krh@30
   439
	razor_importer_add_property(importer,
krh@30
   440
				    &importer->requires, name, version);
krh@30
   441
}
krh@30
   442
krh@30
   443
void
krh@30
   444
razor_importer_add_provides(struct razor_importer *importer,
krh@30
   445
			    const char *name, const char *version)
krh@30
   446
{
krh@30
   447
	razor_importer_add_property(importer,
krh@30
   448
				    &importer->provides, name, version);
krh@30
   449
}
krh@30
   450
krh@30
   451
struct razor_importer *
krh@30
   452
razor_importer_new(void)
krh@30
   453
{
krh@30
   454
	struct razor_importer *importer;
krh@30
   455
krh@30
   456
	importer = zalloc(sizeof *importer);
krh@30
   457
	importer->set = razor_set_create();
krh@30
   458
	importer->requires.all = &importer->set->requires;
krh@30
   459
	importer->provides.all = &importer->set->provides;
krh@30
   460
krh@30
   461
	return importer;
krh@9
   462
}
krh@9
   463
krh@22
   464
typedef int (*compare_with_data_func_t)(const void *p1,
krh@22
   465
					const void *p,
krh@22
   466
					void *data);
krh@22
   467
krh@25
   468
struct qsort_context {
krh@25
   469
	size_t size;
krh@25
   470
	compare_with_data_func_t compare;
krh@25
   471
	void *data;
krh@25
   472
};
krh@25
   473
krh@22
   474
static void
krh@22
   475
qsort_swap(void *p1, void *p2, size_t size)
krh@22
   476
{
krh@22
   477
	char buffer[size];
krh@22
   478
krh@22
   479
	memcpy(buffer, p1, size);
krh@22
   480
	memcpy(p1, p2, size);
krh@22
   481
	memcpy(p2, buffer, size);
krh@22
   482
}
krh@22
   483
krh@25
   484
static void
krh@25
   485
__qsort_with_data(void *base, size_t nelem, unsigned long *map,
krh@25
   486
		  struct qsort_context *ctx)
krh@22
   487
{
krh@22
   488
	void *p, *start, *end, *pivot;
krh@25
   489
	unsigned long *mp, *mstart, *mend, tmp;
krh@22
   490
	int left, right, result;
krh@25
   491
	size_t size = ctx->size;
krh@22
   492
krh@22
   493
	p = base;
krh@22
   494
	start = base;
krh@22
   495
	end = base + nelem * size;
krh@25
   496
	mp = map;
krh@25
   497
	mstart = map;
krh@25
   498
	mend = map + nelem;
krh@22
   499
	pivot = base + (random() % nelem) * size;
krh@25
   500
krh@22
   501
	while (p < end) {
krh@25
   502
		result = ctx->compare(p, pivot, ctx->data);
krh@22
   503
		if (result < 0) {
krh@22
   504
			qsort_swap(p, start, size);
krh@25
   505
			tmp = *mp;
krh@25
   506
			*mp = *mstart;
krh@25
   507
			*mstart = tmp;
krh@22
   508
			if (start == pivot)
krh@22
   509
				pivot = p;
krh@22
   510
			start += size;
krh@25
   511
			mstart++;
krh@22
   512
			p += size;
krh@29
   513
			mp++;
krh@22
   514
		} else if (result == 0) {
krh@22
   515
			p += size;
krh@25
   516
			mp++;
krh@22
   517
		} else {
krh@22
   518
 			end -= size;
krh@25
   519
			mend--;
krh@22
   520
			qsort_swap(p, end, size);
krh@25
   521
			tmp = *mp;
krh@29
   522
			*mp = *mend;
krh@29
   523
			*mend = tmp;
krh@22
   524
			if (end == pivot)
krh@22
   525
				pivot = p;
krh@22
   526
		}
krh@22
   527
	}
krh@22
   528
krh@22
   529
	left = (start - base) / size;
krh@22
   530
	right = (base + nelem * size - end) / size;
krh@22
   531
	if (left > 1)
krh@25
   532
		__qsort_with_data(base, left, map, ctx);
krh@22
   533
	if (right > 1)
krh@25
   534
		__qsort_with_data(end, right, mend, ctx);
krh@25
   535
}
krh@25
   536
krh@25
   537
unsigned long *
krh@25
   538
qsort_with_data(void *base, size_t nelem, size_t size,
krh@25
   539
		compare_with_data_func_t compare, void *data)
krh@25
   540
{
krh@25
   541
	struct qsort_context ctx;
krh@25
   542
	unsigned long *map;
krh@25
   543
	int i;
krh@25
   544
krh@25
   545
	ctx.size = size;
krh@25
   546
	ctx.compare = compare;
krh@25
   547
	ctx.data = data;
krh@25
   548
krh@25
   549
	map = malloc(nelem * sizeof (unsigned long));
krh@25
   550
	for (i = 0; i < nelem; i++)
krh@25
   551
		map[i] = i;
krh@25
   552
krh@25
   553
	__qsort_with_data(base, nelem, map, &ctx);
krh@25
   554
krh@25
   555
	return map;
krh@22
   556
}
krh@9
   557
krh@9
   558
static int
krh@35
   559
versioncmp(const char *s1, const char *s2)
krh@35
   560
{
krh@35
   561
	const char *p1, *p2;
krh@35
   562
	long n1, n2;
krh@35
   563
	int res;
krh@35
   564
krh@35
   565
	n1 = strtol(s1, (char **) &p1, 0);
krh@35
   566
	n2 = strtol(s2, (char **) &p2, 0);
krh@35
   567
krh@35
   568
	/* Epoch; if one but not the other has an epoch set, default
krh@35
   569
	 * the epoch-less version to 0. */
krh@35
   570
	res = (*p1 == ':') - (*p2 == ':');
krh@35
   571
	if (res < 0) {
krh@35
   572
		n1 = 0;
krh@35
   573
		p1 = s1;
krh@35
   574
		p2++;
krh@35
   575
	} else if (res > 0) {
krh@35
   576
		p1++;
krh@35
   577
		n2 = 0;
krh@35
   578
		p2 = s2;
krh@35
   579
	}
krh@35
   580
krh@35
   581
	if (n1 != n2)
krh@35
   582
		return n1 - n2;
krh@35
   583
	while (*p1 && *p2) {
krh@35
   584
		if (*p1 != *p2)
krh@35
   585
			return *p1 - *p2;
krh@35
   586
		p1++;
krh@35
   587
		p2++;
krh@35
   588
		if (isdigit(*p1) && isdigit(*p2))
krh@35
   589
			return versioncmp(p1, p2);
krh@35
   590
	}
krh@35
   591
krh@35
   592
	return *p1 - *p2;
krh@35
   593
}
krh@35
   594
krh@35
   595
krh@35
   596
static int
krh@22
   597
compare_packages(const void *p1, const void *p2, void *data)
krh@9
   598
{
krh@25
   599
	const struct razor_package *pkg1 = p1, *pkg2 = p2;
krh@22
   600
	struct razor_set *set = data;
krh@22
   601
	char *pool = set->string_pool.data;
krh@9
   602
krh@23
   603
	if (pkg1->name == pkg2->name)
krh@35
   604
		return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
krh@23
   605
	else
krh@23
   606
		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
krh@9
   607
}
krh@9
   608
krh@9
   609
static int
krh@22
   610
compare_properties(const void *p1, const void *p2, void *data)
krh@9
   611
{
krh@25
   612
	const struct razor_property *prop1 = p1, *prop2 = p2;
krh@22
   613
	struct razor_set *set = data;
krh@22
   614
	char *pool = set->string_pool.data;
krh@9
   615
krh@23
   616
	if (prop1->name == prop2->name)
krh@35
   617
		return versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@12
   618
	else
krh@23
   619
		return strcmp(&pool[prop1->name], &pool[prop2->name]);
krh@9
   620
}
krh@9
   621
krh@10
   622
static unsigned long *
krh@25
   623
uniqueify_properties(struct razor_set *set, struct array *properties)
krh@9
   624
{
krh@25
   625
	struct razor_property *rp, *up, *rp_end;
krh@18
   626
	struct array *pkgs, *p;
krh@25
   627
	unsigned long *map, *rmap, *r;
krh@18
   628
	int i, count, unique;
krh@9
   629
krh@25
   630
	count = properties->size / sizeof(struct razor_property);
krh@25
   631
	map = qsort_with_data(properties->data,
krh@25
   632
			      count,
krh@25
   633
			      sizeof(struct razor_property),
krh@25
   634
			      compare_properties,
krh@25
   635
			      set);
krh@9
   636
krh@25
   637
	rp_end = properties->data + properties->size;
krh@25
   638
	rmap = malloc(count * sizeof *map);
krh@25
   639
	pkgs = zalloc(count * sizeof *pkgs);
krh@25
   640
	for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) {
krh@25
   641
		if (rp->name != up->name || rp->version != up->version) {
krh@25
   642
			up++;
krh@25
   643
			up->name = rp->name;
krh@25
   644
			up->version = rp->version;
krh@10
   645
		}
krh@25
   646
krh@25
   647
		unique = up - (struct razor_property *) properties->data;
krh@25
   648
		rmap[map[i]] = unique;
krh@25
   649
		r = array_add(&pkgs[unique], sizeof *r);
krh@25
   650
		*r = rp->packages;
krh@10
   651
	}
krh@25
   652
	free(map);
krh@9
   653
krh@25
   654
	up++;
krh@25
   655
	properties->size = (void *) up - properties->data;
krh@25
   656
	rp_end = up;
krh@25
   657
	for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) {
krh@25
   658
		rp->packages = add_to_property_pool(set, p);
krh@25
   659
		array_release(p);
krh@18
   660
	}
krh@18
   661
krh@18
   662
	free(pkgs);
krh@18
   663
krh@25
   664
	return rmap;
krh@10
   665
}
krh@10
   666
krh@10
   667
static void
krh@30
   668
remap_package_links(struct razor_importer *importer)
krh@10
   669
{
krh@25
   670
	struct razor_package *p, *end;
krh@10
   671
	unsigned long *pool, *r;
krh@10
   672
krh@30
   673
	pool = importer->set->property_pool.data;
krh@30
   674
	end = importer->set->packages.data + importer->set->packages.size;
krh@30
   675
	for (p = importer->set->packages.data; p < end; p++) {
krh@18
   676
		for (r = &pool[p->requires]; ~*r; r++)
krh@30
   677
			*r = importer->requires_map[*r];
krh@18
   678
		for (r = &pool[p->provides]; ~*r; r++)
krh@30
   679
			*r = importer->provides_map[*r];
krh@9
   680
	}
krh@18
   681
}
krh@10
   682
krh@18
   683
static void
krh@30
   684
remap_property_links(struct razor_importer *importer, unsigned long *map)
krh@18
   685
{
krh@18
   686
	struct razor_property *p, *end;
krh@25
   687
	struct razor_package *rp;
krh@25
   688
	unsigned long *pool, *r, *rmap;
krh@18
   689
	int i, count;
krh@18
   690
krh@30
   691
	pool = importer->set->property_pool.data;
krh@30
   692
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@25
   693
	rmap = malloc(count * sizeof *map);
krh@30
   694
	rp = importer->set->packages.data;
krh@18
   695
	for (i = 0; i < count; i++)
krh@25
   696
		rmap[map[i]] = i;
krh@18
   697
krh@18
   698
	/* FIXME: This will break if we implement package list sharing
krh@18
   699
	 * for all properties, since we'll remap those lists more than
krh@18
   700
	 * once. We should just have a separate pool for property
krh@18
   701
	 * lists and a separate pool for package lists and remap it as
krh@18
   702
	 * a flat pool.  Right now, as property lists and package
krh@18
   703
	 * lists are mixed, we can't do that. */
krh@18
   704
krh@30
   705
	end = importer->set->requires.data + importer->set->requires.size;
krh@30
   706
	for (p = importer->set->requires.data; p < end; p++)
krh@18
   707
		for (r = &pool[p->packages]; ~*r; r++)
krh@25
   708
			*r = rmap[*r];
krh@18
   709
krh@30
   710
	end = importer->set->provides.data + importer->set->provides.size;
krh@30
   711
	for (p = importer->set->provides.data; p < end; p++)
krh@18
   712
		for (r = &pool[p->packages]; ~*r; r++)
krh@25
   713
			*r = rmap[*r];
krh@18
   714
krh@25
   715
	free(rmap);
krh@9
   716
}
krh@9
   717
krh@27
   718
struct razor_set *
krh@30
   719
razor_importer_finish(struct razor_importer *importer)
krh@9
   720
{
krh@30
   721
	struct razor_set *set;
krh@25
   722
	unsigned long *map;
krh@25
   723
	int count;
krh@18
   724
krh@30
   725
	importer->requires_map = uniqueify_properties(importer->set,
krh@30
   726
						      importer->requires.all);
krh@30
   727
	importer->provides_map = uniqueify_properties(importer->set,
krh@30
   728
						      importer->provides.all);
krh@30
   729
	remap_package_links(importer);
krh@30
   730
	free(importer->requires_map);
krh@30
   731
	free(importer->provides_map);
krh@25
   732
krh@30
   733
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@30
   734
	map = qsort_with_data(importer->set->packages.data,
krh@25
   735
			      count,
krh@25
   736
			      sizeof(struct razor_package),
krh@25
   737
			      compare_packages,
krh@30
   738
			      importer->set);
krh@30
   739
	remap_property_links(importer, map);
krh@25
   740
	free(map);
krh@13
   741
krh@30
   742
	set = importer->set;
krh@32
   743
	array_release(&importer->buckets);
krh@30
   744
	free(importer);
krh@30
   745
krh@30
   746
	return set;
krh@9
   747
}
krh@9
   748
krh@0
   749
void
krh@4
   750
razor_set_list(struct razor_set *set)
krh@3
   751
{
krh@6
   752
	struct razor_package *p, *end;
krh@6
   753
	char *pool;
krh@3
   754
krh@6
   755
	pool = set->string_pool.data;
krh@6
   756
	end = set->packages.data + set->packages.size;
krh@14
   757
	for (p = set->packages.data; p < end; p++)
krh@6
   758
		printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@3
   759
}
krh@3
   760
krh@16
   761
struct razor_set *bsearch_set;
krh@16
   762
krh@16
   763
static int
krh@16
   764
compare_package_name(const void *key, const void *data)
krh@16
   765
{
krh@16
   766
	const struct razor_package *p = data;
krh@16
   767
	char *pool;
krh@16
   768
krh@16
   769
	pool = bsearch_set->string_pool.data;
krh@16
   770
krh@16
   771
	return strcmp(key, &pool[p->name]);
krh@16
   772
}
krh@16
   773
krh@10
   774
struct razor_package *
krh@10
   775
razor_set_get_package(struct razor_set *set, const char *package)
krh@10
   776
{
krh@16
   777
	bsearch_set = set;
krh@16
   778
	return bsearch(package, set->packages.data,
krh@16
   779
		       set->packages.size / sizeof(struct razor_package),
krh@16
   780
		       sizeof(struct razor_package), compare_package_name);
krh@10
   781
}
krh@10
   782
krh@18
   783
static int
krh@18
   784
compare_property_name(const void *key, const void *data)
krh@18
   785
{
krh@18
   786
	const struct razor_property *p = data;
krh@18
   787
	char *pool;
krh@18
   788
krh@18
   789
	pool = bsearch_set->string_pool.data;
krh@18
   790
krh@18
   791
	return strcmp(key, &pool[p->name]);
krh@18
   792
}
krh@18
   793
krh@18
   794
struct razor_property *
krh@18
   795
razor_set_get_property(struct razor_set *set,
krh@18
   796
		       struct array *properties,
krh@18
   797
		       const char *property)
krh@18
   798
{
krh@18
   799
	struct razor_property *p, *start;
krh@18
   800
krh@18
   801
	bsearch_set = set;
krh@18
   802
	p = bsearch(property, properties->data,
krh@18
   803
		    properties->size / sizeof(struct razor_property),
krh@18
   804
		    sizeof(struct razor_property), compare_property_name);
krh@18
   805
krh@18
   806
	start = properties->data;
krh@18
   807
	while (p > start && (p - 1)->name == p->name)
krh@18
   808
		p--;
krh@18
   809
krh@18
   810
	return p;
krh@18
   811
}
krh@18
   812
krh@10
   813
static void
krh@10
   814
razor_set_list_all_properties(struct razor_set *set, struct array *properties)
krh@8
   815
{
krh@8
   816
	struct razor_property *p, *end;
krh@8
   817
	char *pool;
krh@8
   818
krh@8
   819
	pool = set->string_pool.data;
krh@10
   820
	end = properties->data + properties->size;
krh@14
   821
	for (p = properties->data; p < end; p++)
krh@8
   822
		printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@8
   823
}
krh@8
   824
krh@8
   825
void
krh@10
   826
razor_set_list_requires(struct razor_set *set, const char *name)
krh@7
   827
{
krh@10
   828
	struct razor_property *p, *requires;
krh@10
   829
	struct razor_package *package;
krh@10
   830
	unsigned long *r;
krh@7
   831
	char *pool;
krh@7
   832
krh@10
   833
	if (name) {
krh@10
   834
		package = razor_set_get_package(set, name);
krh@10
   835
		r = (unsigned long *) set->property_pool.data +
krh@10
   836
			package->requires;
krh@10
   837
		requires = set->requires.data;
krh@10
   838
		pool = set->string_pool.data;
krh@18
   839
		while (~*r) {
krh@10
   840
			p = &requires[*r++];
krh@10
   841
			printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@10
   842
		}
krh@10
   843
	} else
krh@10
   844
		razor_set_list_all_properties(set, &set->requires);
krh@10
   845
}
krh@10
   846
krh@10
   847
void
krh@10
   848
razor_set_list_provides(struct razor_set *set, const char *name)
krh@10
   849
{
krh@10
   850
	struct razor_property *p, *provides;
krh@10
   851
	struct razor_package *package;
krh@10
   852
	unsigned long *r;
krh@10
   853
	char *pool;
krh@10
   854
krh@10
   855
	if (name) {
krh@10
   856
		package = razor_set_get_package(set, name);
krh@10
   857
		r = (unsigned long *) set->property_pool.data +
krh@10
   858
			package->provides;
krh@10
   859
		provides = set->provides.data;
krh@10
   860
		pool = set->string_pool.data;
krh@18
   861
		while (~*r) {
krh@10
   862
			p = &provides[*r++];
krh@10
   863
			printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@10
   864
		}
krh@10
   865
	} else 
krh@10
   866
		razor_set_list_all_properties(set, &set->provides);
krh@7
   867
}
krh@7
   868
krh@7
   869
void
krh@18
   870
razor_set_list_property_packages(struct razor_set *set,
krh@18
   871
				 struct array *properties,
krh@20
   872
				 const char *name,
krh@20
   873
				 const char *version)
krh@18
   874
{
krh@18
   875
	struct razor_property *property, *end;
krh@18
   876
	struct razor_package *p, *packages;
krh@18
   877
	unsigned long *r;
krh@18
   878
	char *pool;
krh@18
   879
krh@18
   880
	if (name == NULL)
krh@18
   881
		return;
krh@18
   882
krh@18
   883
	property = razor_set_get_property(set, properties, name);
krh@18
   884
	packages = set->packages.data;
krh@18
   885
	pool = set->string_pool.data;
krh@18
   886
	end = properties->data + properties->size;
krh@18
   887
	while (property < end && strcmp(name, &pool[property->name]) == 0) {
krh@35
   888
		if (version && versioncmp(version, &pool[property->version]) != 0)
krh@20
   889
			goto next;
krh@18
   890
		r = (unsigned long *)
krh@18
   891
			set->property_pool.data + property->packages;
krh@18
   892
		while (~*r) {
krh@18
   893
			p = &packages[*r++];
krh@18
   894
			printf("%s %s\n",
krh@18
   895
			       &pool[p->name], &pool[p->version]);
krh@18
   896
		}
krh@20
   897
	next:
krh@18
   898
		property++;
krh@18
   899
	}
krh@18
   900
}
krh@18
   901
krh@18
   902
void
krh@21
   903
razor_set_validate(struct razor_set *set, struct array *unsatisfied)
krh@21
   904
{
krh@21
   905
	struct razor_property *r, *p, *rend, *pend;
krh@21
   906
	unsigned long *u;
krh@21
   907
	char *pool;
krh@21
   908
krh@21
   909
	p = set->provides.data;
krh@21
   910
	rend = set->requires.data + set->requires.size;
krh@21
   911
	pend = set->provides.data + set->provides.size;
krh@21
   912
	pool = set->string_pool.data;
krh@21
   913
	
krh@35
   914
	for (r = set->requires.data; r < rend; r++) {
krh@21
   915
		while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0)
krh@21
   916
			p++;
krh@37
   917
krh@35
   918
		/* If there is more than one version of a provides,
krh@35
   919
		 * seek to the end for the highest version. */
krh@35
   920
		while (p + 1 < pend && p->name == (p + 1)->name)
krh@35
   921
			p++;
krh@37
   922
krh@37
   923
		/* FIXME: We need to track property flags (<, <=, =
krh@37
   924
		 * etc) to properly determine if a requires is
krh@37
   925
		 * satisfied.  The current code doesn't track that the
krh@37
   926
		 * requires a = 1 isn't satisfied by a = 2 provides. */
krh@37
   927
krh@35
   928
		if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0 ||
krh@35
   929
		    versioncmp(&pool[r->version], &pool[p->version]) > 0) {
krh@35
   930
			/* FIXME: We ignore file requires for now. */
krh@35
   931
			if (pool[r->name] == '/')
krh@35
   932
				continue;
krh@21
   933
			u = array_add(unsatisfied, sizeof *u);
krh@21
   934
			*u = r - (struct razor_property *) set->requires.data;
krh@21
   935
		}
krh@21
   936
	}
krh@21
   937
}
krh@21
   938
krh@21
   939
void
krh@21
   940
razor_set_list_unsatisfied(struct razor_set *set)
krh@21
   941
{
krh@21
   942
	struct array unsatisfied;
krh@21
   943
	struct razor_property *requires, *r;
krh@21
   944
	unsigned long *u, *end;
krh@21
   945
	char *pool;
krh@21
   946
krh@21
   947
	array_init(&unsatisfied);
krh@21
   948
	razor_set_validate(set, &unsatisfied);
krh@21
   949
krh@21
   950
	end = unsatisfied.data + unsatisfied.size;
krh@21
   951
	requires = set->requires.data;
krh@21
   952
	pool = set->string_pool.data;
krh@21
   953
krh@21
   954
	for (u = unsatisfied.data; u < end; u++) {
krh@21
   955
		r = requires + *u;
krh@21
   956
		printf("%s %s not satisfied\n",
krh@21
   957
		       &pool[r->name], &pool[r->version]);
krh@21
   958
	}
krh@21
   959
krh@21
   960
	array_release(&unsatisfied);
krh@21
   961
}
krh@21
   962
krh@33
   963
static void
krh@33
   964
add_package(struct razor_importer *importer,
krh@33
   965
	    struct razor_package *package, struct razor_set *set)
krh@33
   966
{
krh@33
   967
	char *pool;
krh@33
   968
	unsigned long *r;
krh@33
   969
	struct razor_property *p, *properties;
krh@33
   970
krh@33
   971
	pool = set->string_pool.data;
krh@33
   972
	razor_importer_begin_package(importer,
krh@33
   973
				     &pool[package->name],
krh@33
   974
				     &pool[package->version]);
krh@33
   975
krh@33
   976
	r = (unsigned long *) set->property_pool.data + package->requires;
krh@33
   977
	properties = set->requires.data;
krh@33
   978
	while (~*r) {
krh@33
   979
		p = &properties[*r++];
krh@33
   980
		razor_importer_add_requires(importer,
krh@33
   981
					    &pool[p->name], &pool[p->version]);
krh@33
   982
	}
krh@33
   983
krh@33
   984
	r = (unsigned long *) set->property_pool.data + package->provides;
krh@33
   985
	properties = set->provides.data;
krh@33
   986
	while (~*r) {
krh@33
   987
		p = &properties[*r++];
krh@33
   988
		razor_importer_add_provides(importer,
krh@33
   989
					    &pool[p->name], &pool[p->version]);
krh@33
   990
	}
krh@33
   991
krh@33
   992
	razor_importer_finish_package(importer);
krh@33
   993
}
krh@33
   994
krh@33
   995
/* Add packages from 'upstream' to 'set'.  The packages to add are
krh@33
   996
 * specified by the 'packages' array, which is a sorted list of
krh@33
   997
 * package indexes.  Returns a newly allocated package set.  Does not
krh@33
   998
 * enforce validity of the resulting package set. */
krh@33
   999
krh@36
  1000
/* FIXME: We can do this in a linear sweep instead of using an
krh@36
  1001
 * importer and the sorting that incurs: build the new package list
krh@36
  1002
 * sorted, build up a map from package index in old set to package
krh@36
  1003
 * index in new set for both sets. ~0 means 'not in new set'.  build
krh@36
  1004
 * new string pool as we go, probably just re-use that part of the
krh@36
  1005
 * importer.  as we build the package list, fill out a bitvector of
krh@36
  1006
 * the properties that are referenced by the pacakges in the new
krh@36
  1007
 * set. then do a parallel loop through the properties and emit them
krh@36
  1008
 * to the new set and build a map from indices in the old set to
krh@36
  1009
 * indices in the new set. then loop through the packages again and
krh@36
  1010
 * emit the property lists. */
krh@36
  1011
krh@33
  1012
struct razor_set *
krh@33
  1013
razor_set_add(struct razor_set *set, struct razor_set *upstream,
krh@33
  1014
	      struct array *packages)
krh@33
  1015
{
krh@33
  1016
	struct razor_importer *importer;
krh@33
  1017
	struct razor_package *upstream_packages, *p, *s, *send;
krh@33
  1018
	char *spool, *upool;
krh@33
  1019
	unsigned long *u, *uend;
krh@33
  1020
	int cmp;
krh@33
  1021
krh@33
  1022
	importer = razor_importer_new();
krh@33
  1023
	upstream_packages = upstream->packages.data;
krh@33
  1024
	u = packages->data;
krh@33
  1025
	uend = packages->data + packages->size;
krh@33
  1026
	upool = upstream->string_pool.data;
krh@33
  1027
	s = set->packages.data;
krh@33
  1028
	send = set->packages.data + set->packages.size;
krh@33
  1029
	spool = set->string_pool.data;
krh@33
  1030
krh@33
  1031
	while (s < send) {
krh@33
  1032
		p = upstream_packages + *u;
krh@37
  1033
		if (u < uend)
krh@37
  1034
			cmp = strcmp(&spool[s->name], &upool[p->name]);
krh@37
  1035
		if (u >= uend || cmp < 0) {
krh@33
  1036
			add_package(importer, s, set);
krh@33
  1037
			s++;
krh@33
  1038
		} else if (cmp == 0) {
krh@33
  1039
			add_package(importer, p, upstream);
krh@33
  1040
			s++;
krh@33
  1041
			u++;
krh@33
  1042
		} else {
krh@33
  1043
			add_package(importer, p, upstream);
krh@33
  1044
			u++;
krh@33
  1045
		}
krh@33
  1046
	}
krh@33
  1047
krh@33
  1048
	return razor_importer_finish(importer);
krh@33
  1049
}
krh@33
  1050
krh@37
  1051
void
krh@37
  1052
razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
krh@37
  1053
		  struct razor_set *upstream, struct array *list)
krh@37
  1054
{
krh@37
  1055
	struct razor_property *requires, *r;
krh@37
  1056
	struct razor_property *p, *pend;
krh@37
  1057
	unsigned long *u, *end, *pkg, *property_pool;
krh@37
  1058
	char *pool, *upool;
krh@37
  1059
krh@37
  1060
	end = unsatisfied->data + unsatisfied->size;
krh@37
  1061
	requires = set->requires.data;
krh@37
  1062
	pool = set->string_pool.data;
krh@37
  1063
krh@37
  1064
	p = upstream->provides.data;
krh@37
  1065
	pend = upstream->provides.data + upstream->provides.size;
krh@37
  1066
	upool = upstream->string_pool.data;
krh@37
  1067
	property_pool = upstream->property_pool.data;
krh@37
  1068
krh@37
  1069
	for (u = unsatisfied->data; u < end; u++) {
krh@37
  1070
		r = requires + *u;
krh@37
  1071
krh@37
  1072
		while (p < pend && strcmp(&pool[r->name], &upool[p->name]) > 0)
krh@37
  1073
			p++;
krh@37
  1074
		/* If there is more than one version of a provides,
krh@37
  1075
		 * seek to the end for the highest version. */
krh@37
  1076
		while (p + 1 < pend && p->name == (p + 1)->name)
krh@37
  1077
			p++;
krh@37
  1078
krh@37
  1079
		if (p == pend ||
krh@37
  1080
		    strcmp(&pool[r->name], &upool[p->name]) != 0 ||
krh@37
  1081
		    versioncmp(&pool[r->version], &upool[p->version]) > 0) {
krh@37
  1082
			/* Do we need to track unsatisfiable requires
krh@37
  1083
			 * as we go, or should we just do a
krh@37
  1084
			 * razor_set_validate() at the end? */
krh@37
  1085
		} else {
krh@37
  1086
			pkg = array_add(list, sizeof *pkg);
krh@37
  1087
			/* We just pull in the first package that provides */
krh@37
  1088
			*pkg = property_pool[p->packages];
krh@37
  1089
		}
krh@37
  1090
	}	
krh@37
  1091
}
krh@37
  1092
krh@33
  1093
struct razor_set *
krh@33
  1094
razor_set_update(struct razor_set *set, struct razor_set *upstream,
krh@33
  1095
		 int count, const char **packages)
krh@33
  1096
{
krh@37
  1097
	struct razor_set *new;
krh@37
  1098
	struct razor_package *p, *upackages;
krh@37
  1099
	struct array list, unsatisfied;
krh@37
  1100
	char *pool;
krh@37
  1101
	unsigned long *r, *u, *end;
krh@33
  1102
	int i;
krh@33
  1103
krh@33
  1104
	array_init(&list);
krh@33
  1105
	for (i = 0; i < count; i++) {
krh@33
  1106
		p = razor_set_get_package(upstream, packages[i]);
krh@33
  1107
		r = array_add(&list, sizeof *r);
krh@33
  1108
		*r = p - (struct razor_package *) upstream->packages.data;
krh@33
  1109
	}
krh@33
  1110
krh@37
  1111
	end = list.data + list.size;
krh@37
  1112
	upackages = upstream->packages.data;
krh@37
  1113
	pool = upstream->string_pool.data;
krh@37
  1114
	for (u = list.data; u < end; u++) {
krh@37
  1115
		p = upackages + *u;
krh@37
  1116
		printf("package %s-%s set to be updated\n",
krh@37
  1117
		       &pool[p->name], &pool[p->version]);
krh@37
  1118
	}
krh@37
  1119
krh@37
  1120
	while (list.size > 0) {
krh@37
  1121
		printf(" -- satisfying new requires\n");
krh@37
  1122
krh@37
  1123
		new = razor_set_add(set, upstream, &list);
krh@37
  1124
		array_release(&list);
krh@37
  1125
		razor_set_destroy(set);
krh@37
  1126
		set = new;
krh@37
  1127
krh@37
  1128
		array_init(&unsatisfied);
krh@37
  1129
		razor_set_validate(new, &unsatisfied);
krh@37
  1130
		array_init(&list);
krh@37
  1131
		razor_set_satisfy(new, &unsatisfied, upstream, &list);
krh@37
  1132
		array_release(&unsatisfied);
krh@37
  1133
krh@37
  1134
		end = list.data + list.size;
krh@37
  1135
		upackages = upstream->packages.data;
krh@37
  1136
		pool = upstream->string_pool.data;
krh@37
  1137
		for (u = list.data; u < end; u++) {
krh@37
  1138
			p = upackages + *u;
krh@37
  1139
			printf("package %s-%s set to be updated\n",
krh@37
  1140
			       &pool[p->name], &pool[p->version]);
krh@37
  1141
		}
krh@37
  1142
	}
krh@37
  1143
krh@37
  1144
	array_release(&list);
krh@37
  1145
krh@37
  1146
	return set;
krh@33
  1147
}
krh@33
  1148
krh@21
  1149
void
krh@4
  1150
razor_set_info(struct razor_set *set)
krh@3
  1151
{
krh@3
  1152
	unsigned int offset, size;
krh@3
  1153
	int i;
krh@3
  1154
krh@4
  1155
	for (i = 0; i < set->header->sections[i].type; i++) {
krh@4
  1156
		offset = set->header->sections[i].offset;
krh@18
  1157
		size = set->header->sections[i].size;
krh@3
  1158
krh@4
  1159
		switch (set->header->sections[i].type) {
krh@4
  1160
		case RAZOR_PACKAGES:
krh@3
  1161
			printf("package section:\t%dkb\n", size / 1024);
krh@3
  1162
			break;
krh@8
  1163
		case RAZOR_REQUIRES:
krh@8
  1164
			printf("requires section:\t%dkb\n", size / 1024);
krh@8
  1165
			break;
krh@7
  1166
		case RAZOR_PROVIDES:
krh@7
  1167
			printf("provides section:\t%dkb\n", size / 1024);
krh@7
  1168
			break;
krh@19
  1169
		case RAZOR_STRING_POOL:
krh@19
  1170
			printf("string pool:\t\t%dkb\n", size / 1024);
krh@19
  1171
			break;
krh@19
  1172
		case RAZOR_PROPERTY_POOL:
krh@18
  1173
			printf("properties section:\t%dkb\n", size / 1024);
krh@18
  1174
			break;
krh@3
  1175
		}
krh@3
  1176
	}
krh@0
  1177
}
krh@0
  1178
krh@0
  1179
static int
krh@0
  1180
usage(void)
krh@0
  1181
{
krh@7
  1182
	printf("usage: razor [ import FILES | lookup <key> | "
krh@15
  1183
	       "list | list-requires | list-provides | eat-yum | info ]\n");
krh@0
  1184
	exit(1);
krh@0
  1185
}
krh@0
  1186
krh@15
  1187
static const char *repo_filename = "system.repo";
krh@15
  1188
static const char rawhide_repo_filename[] = "rawhide.repo";
krh@0
  1189
krh@0
  1190
int
krh@27
  1191
main(int argc, const char *argv[])
krh@0
  1192
{
krh@37
  1193
	struct razor_set *set, *upstream;
krh@0
  1194
	struct stat statbuf;
krh@15
  1195
	char *repo;
krh@15
  1196
krh@15
  1197
	repo = getenv("RAZOR_REPO");
krh@15
  1198
	if (repo != NULL)
krh@15
  1199
		repo_filename = repo;
krh@0
  1200
krh@3
  1201
	if (argc < 2) {
krh@0
  1202
		usage();
krh@0
  1203
	} else if (strcmp(argv[1], "import") == 0) {
krh@0
  1204
		if (stat("set", &statbuf) && mkdir("set", 0777)) {
krh@0
  1205
			fprintf(stderr, "could not create directory 'set'\n");
krh@0
  1206
			exit(-1);
krh@0
  1207
		}
krh@0
  1208
			
krh@27
  1209
		set = razor_import_rzr_files(argc - 2, argv + 2);
krh@6
  1210
krh@6
  1211
		printf("pool size: %d\n", set->string_pool.size);
krh@6
  1212
		printf("pool allocation: %d\n", set->string_pool.alloc);
krh@7
  1213
		printf("packages: %d\n",
krh@7
  1214
		       set->packages.size / sizeof(struct razor_package));
krh@8
  1215
		printf("requires: %d\n",
krh@8
  1216
		       set->requires.size / sizeof(struct razor_property));
krh@7
  1217
		printf("provides: %d\n",
krh@8
  1218
		       set->provides.size / sizeof(struct razor_property));
krh@0
  1219
krh@4
  1220
		razor_set_write(set, repo_filename);
krh@0
  1221
krh@4
  1222
		razor_set_destroy(set);
krh@3
  1223
	} else if (strcmp(argv[1], "list") == 0) {
krh@4
  1224
		set = razor_set_open(repo_filename);
krh@4
  1225
		razor_set_list(set);
krh@4
  1226
		razor_set_destroy(set);
krh@8
  1227
	} else if (strcmp(argv[1], "list-requires") == 0) {
krh@8
  1228
		set = razor_set_open(repo_filename);
krh@10
  1229
		razor_set_list_requires(set, argv[2]);
krh@8
  1230
		razor_set_destroy(set);
krh@7
  1231
	} else if (strcmp(argv[1], "list-provides") == 0) {
krh@7
  1232
		set = razor_set_open(repo_filename);
krh@10
  1233
		razor_set_list_provides(set, argv[2]);
krh@7
  1234
		razor_set_destroy(set);
krh@18
  1235
	} else if (strcmp(argv[1], "what-requires") == 0) {
krh@18
  1236
		set = razor_set_open(repo_filename);
krh@20
  1237
		razor_set_list_property_packages(set, &set->requires,
krh@20
  1238
						 argv[2], argv[3]);
krh@18
  1239
		razor_set_destroy(set);
krh@18
  1240
	} else if (strcmp(argv[1], "what-provides") == 0) {
krh@18
  1241
		set = razor_set_open(repo_filename);
krh@20
  1242
		razor_set_list_property_packages(set, &set->provides,
krh@20
  1243
						 argv[2], argv[3]);
krh@18
  1244
		razor_set_destroy(set);
krh@3
  1245
	} else if (strcmp(argv[1], "info") == 0) {
krh@4
  1246
		set = razor_set_open(repo_filename);
krh@4
  1247
		razor_set_info(set);
krh@4
  1248
		razor_set_destroy(set);
krh@15
  1249
	} else if (strcmp(argv[1], "eat-yum") == 0) {
krh@15
  1250
		set = razor_set_create_from_yum_filelist(STDIN_FILENO);
krh@15
  1251
		if (set == NULL)
krh@15
  1252
			return 1;
krh@15
  1253
		razor_set_write(set, rawhide_repo_filename);
krh@15
  1254
		razor_set_destroy(set);
krh@18
  1255
		printf("wrote %s\n", rawhide_repo_filename);
krh@28
  1256
	} else if (strcmp(argv[1], "import-rpmdb") == 0) {
krh@28
  1257
		set = razor_set_create_from_rpmdb();
krh@28
  1258
		if (set == NULL)
krh@28
  1259
			return 1;
krh@28
  1260
		razor_set_write(set, repo_filename);
krh@28
  1261
		razor_set_destroy(set);
krh@28
  1262
		printf("wrote %s\n", repo_filename);
krh@21
  1263
	} else if (strcmp(argv[1], "validate") == 0) {
krh@21
  1264
		set = razor_set_open(repo_filename);
krh@21
  1265
		if (set == NULL)
krh@21
  1266
			return 1;
krh@21
  1267
		razor_set_list_unsatisfied(set);
krh@21
  1268
		razor_set_destroy(set);
krh@33
  1269
	} else if (strcmp(argv[1], "update") == 0) {
krh@33
  1270
		set = razor_set_open(repo_filename);
krh@33
  1271
		upstream = razor_set_open(rawhide_repo_filename);
krh@33
  1272
		if (set == NULL || upstream == NULL)
krh@33
  1273
			return 1;
krh@37
  1274
		set = razor_set_update(set, upstream, argc - 2, argv + 2);
krh@37
  1275
		razor_set_write(set, "system-updated.repo");
krh@33
  1276
		razor_set_destroy(set);
krh@33
  1277
		razor_set_destroy(upstream);
krh@37
  1278
		printf("wrote system-updated.repo\n");
krh@0
  1279
	} else {
krh@0
  1280
		usage();
krh@0
  1281
	}
krh@0
  1282
krh@0
  1283
	return 0;
krh@0
  1284
}