razor.c
author Kristian H?gsberg <krh@redhat.com>
Mon Jun 09 12:47:37 2008 -0400 (2008-06-09)
changeset 230 c1e2aed8dd07
parent 220 1fcb5c23034a
child 237 715b18dc94f3
permissions -rw-r--r--
Rewrite depsolver to use a series of passes over all packages.

The big change is that we follow one step of the depedency chain for
each package to resolve in each iteration, and repeat until there are
no more possible moves. In contrast the old depsolver would try to
follow the dependency chain completely for one package at a time.

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