librazor/merger.c
author J. Ali Harlow <ali@juiblex.co.uk>
Mon Jul 04 10:48:18 2016 +0100 (2016-07-04)
changeset 475 008c75a5e08d
parent 458 3f841a46eab5
permissions -rw-r--r--
Switch to a URI-based API
krh@248
     1
/*
krh@248
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
krh@248
     3
 * Copyright (C) 2008  Red Hat, Inc
ali@403
     4
 * Copyright (C) 2009-2011  J. Ali Harlow <ali@juiblex.co.uk>
krh@248
     5
 *
krh@248
     6
 * This program is free software; you can redistribute it and/or modify
krh@248
     7
 * it under the terms of the GNU General Public License as published by
krh@248
     8
 * the Free Software Foundation; either version 2 of the License, or
krh@248
     9
 * (at your option) any later version.
krh@248
    10
 *
krh@248
    11
 * This program is distributed in the hope that it will be useful,
krh@248
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
krh@248
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
krh@248
    14
 * GNU General Public License for more details.
krh@248
    15
 *
krh@248
    16
 * You should have received a copy of the GNU General Public License along
krh@248
    17
 * with this program; if not, write to the Free Software Foundation, Inc.,
krh@248
    18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
krh@248
    19
 */
krh@248
    20
ali@438
    21
#include "config.h"
krh@248
    22
#include <string.h>
ali@369
    23
#include <assert.h>
krh@248
    24
#include "razor-internal.h"
krh@248
    25
#include "razor.h"
krh@248
    26
krh@248
    27
#define UPSTREAM_SOURCE 0x80
krh@248
    28
krh@248
    29
struct source {
krh@248
    30
	struct razor_set *set;
krh@248
    31
	uint32_t *property_map;
krh@248
    32
	uint32_t *file_map;
krh@248
    33
};
krh@248
    34
krh@248
    35
struct razor_merger {
ali@369
    36
	int committed;
krh@248
    37
	struct razor_set *set;
krh@248
    38
	struct hashtable table;
ali@348
    39
	struct hashtable file_table;
ali@394
    40
	struct hashtable details_table;
krh@248
    41
	struct source source1;
krh@248
    42
	struct source source2;
krh@248
    43
};
krh@248
    44
krh@248
    45
struct razor_merger *
krh@248
    46
razor_merger_create(struct razor_set *set1, struct razor_set *set2)
krh@248
    47
{
krh@248
    48
	struct razor_merger *merger;
krh@248
    49
	int count;
krh@248
    50
	size_t size;
ali@403
    51
	uint32_t header_version;
krh@248
    52
krh@248
    53
	merger = zalloc(sizeof *merger);
krh@248
    54
	merger->set = razor_set_create();
ali@403
    55
	if (set1->packages.size) {
ali@403
    56
		header_version = razor_set_get_header_version(set1);
ali@403
    57
		if (set2->packages.size &&
ali@403
    58
		    razor_set_get_header_version(set2) > header_version)
ali@403
    59
			header_version = razor_set_get_header_version(set2);
ali@403
    60
	} else
ali@403
    61
		header_version = razor_set_get_header_version(set2);
ali@403
    62
	razor_set_set_header_version(merger->set, header_version);
krh@248
    63
	hashtable_init(&merger->table, &merger->set->string_pool);
ali@348
    64
	hashtable_init(&merger->file_table, &merger->set->file_string_pool);
ali@394
    65
	hashtable_init(&merger->details_table,
ali@394
    66
		       &merger->set->details_string_pool);
krh@248
    67
krh@248
    68
	merger->source1.set = set1;
krh@248
    69
	count = set1->properties.size / sizeof (struct razor_property);
krh@248
    70
	size = count * sizeof merger->source1.property_map[0];
krh@248
    71
	merger->source1.property_map = zalloc(size);
krh@248
    72
	count = set1->files.size / sizeof (struct razor_entry);
krh@248
    73
	size = count * sizeof merger->source1.file_map[0];
krh@248
    74
	merger->source1.file_map = zalloc(size);
krh@248
    75
krh@248
    76
	merger->source2.set = set2;
krh@248
    77
	count = set2->properties.size / sizeof (struct razor_property);
krh@248
    78
	size = count * sizeof merger->source2.property_map[0];
krh@248
    79
	merger->source2.property_map = zalloc(size);
krh@248
    80
	count = set2->files.size / sizeof (struct razor_entry);
krh@248
    81
	size = count * sizeof merger->source2.file_map[0];
krh@248
    82
	merger->source2.file_map = zalloc(size);
krh@248
    83
krh@248
    84
	return merger;
krh@248
    85
}
krh@248
    86
krh@248
    87
void
krh@248
    88
razor_merger_add_package(struct razor_merger *merger,
krh@248
    89
			 struct razor_package *package)
krh@248
    90
{
ali@394
    91
	char *pool, *details_pool, *s;
krh@248
    92
	struct list *r;
krh@248
    93
	struct razor_package *p;
krh@248
    94
	struct razor_set *set1;
krh@248
    95
	struct source *source;
ali@372
    96
	uint32_t flags, *prefix;
ali@372
    97
	struct array install_prefixes;
krh@248
    98
ali@369
    99
	assert(merger->committed == 0);
ali@369
   100
krh@248
   101
	set1 = merger->source1.set;
krh@248
   102
	if (set1->packages.data <= (void *) package &&
krh@248
   103
	    (void *) package < set1->packages.data + set1->packages.size) {
krh@248
   104
		source = &merger->source1;
krh@248
   105
		flags = 0;
krh@248
   106
	} else {
krh@248
   107
		source = &merger->source2;
krh@248
   108
		flags = UPSTREAM_SOURCE;
krh@248
   109
	}
krh@248
   110
krh@248
   111
	pool = source->set->string_pool.data;
ali@394
   112
	details_pool = source->set->details_string_pool.data;
krh@248
   113
	p = array_add(&merger->set->packages, sizeof *p);
krh@248
   114
	p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
krh@248
   115
	p->flags = flags;
krh@248
   116
	p->version = hashtable_tokenize(&merger->table,
krh@248
   117
					&pool[package->version]);
krh@248
   118
	p->arch = hashtable_tokenize(&merger->table,
krh@248
   119
				     &pool[package->arch]);
ali@395
   120
	if (source->set->details_string_pool.size) {
ali@395
   121
		p->summary = hashtable_tokenize(&merger->details_table,
ali@395
   122
						&details_pool[package->summary]);
ali@395
   123
		p->description = hashtable_tokenize(&merger->details_table,
ali@395
   124
						    &details_pool[package->description]);
ali@395
   125
		p->url = hashtable_tokenize(&merger->details_table,
ali@395
   126
					    &details_pool[package->url]);
ali@395
   127
		p->license = hashtable_tokenize(&merger->details_table,
ali@395
   128
						&details_pool[package->license]);
ali@395
   129
	} else {
ali@395
   130
		p->summary = hashtable_tokenize(&merger->details_table, "");
ali@395
   131
		p->description = hashtable_tokenize(&merger->details_table, "");
ali@395
   132
		p->url = hashtable_tokenize(&merger->details_table, "");
ali@395
   133
		p->license = hashtable_tokenize(&merger->details_table, "");
ali@395
   134
	}
krh@248
   135
krh@248
   136
	p->properties = package->properties;
krh@248
   137
	r = list_first(&package->properties, &source->set->property_pool);
krh@248
   138
	while (r) {
krh@248
   139
		source->property_map[r->data] = 1;
krh@248
   140
		r = list_next(r);
krh@248
   141
	}
krh@248
   142
krh@248
   143
	p->files = package->files;
krh@248
   144
	r = list_first(&package->files, &source->set->file_pool);
krh@248
   145
	while (r) {
krh@248
   146
		source->file_map[r->data] = 1;
krh@248
   147
		r = list_next(r);
krh@248
   148
	}
ali@369
   149
ali@372
   150
	array_init(&install_prefixes);
ali@372
   151
	r = list_first(&package->install_prefixes, &source->set->prefix_pool);
ali@372
   152
	while (r) {
ali@372
   153
		s = (char *)source->set->string_pool.data + r->data;
ali@372
   154
		prefix = array_add(&install_prefixes, sizeof *prefix);
ali@372
   155
		*prefix = hashtable_tokenize(&merger->table, s);
ali@372
   156
		r = list_next(r);
ali@372
   157
	}
ali@372
   158
	list_set_array(&p->install_prefixes, &merger->set->prefix_pool,
ali@372
   159
                       &install_prefixes, 0);
ali@372
   160
	array_release(&install_prefixes);
ali@372
   161
ali@369
   162
	p->preun.program = hashtable_tokenize(&merger->table,
ali@369
   163
					      &pool[package->preun.program]);
ali@369
   164
	p->preun.body = hashtable_tokenize(&merger->table,
ali@369
   165
					   &pool[package->preun.body]);
ali@369
   166
	p->postun.program = hashtable_tokenize(&merger->table,
ali@369
   167
					       &pool[package->postun.program]);
ali@369
   168
	p->postun.body = hashtable_tokenize(&merger->table,
ali@369
   169
					    &pool[package->postun.body]);
krh@248
   170
}
krh@248
   171
krh@248
   172
static uint32_t
krh@248
   173
add_property(struct razor_merger *merger,
krh@248
   174
	     const char *name, uint32_t flags, const char *version)
krh@248
   175
{
krh@248
   176
	struct razor_property *p;
krh@248
   177
krh@248
   178
	p = array_add(&merger->set->properties, sizeof *p);
krh@248
   179
	p->name = hashtable_tokenize(&merger->table, name);
krh@248
   180
	p->flags = flags;
krh@248
   181
	p->version = hashtable_tokenize(&merger->table, version);
krh@248
   182
krh@248
   183
	return p - (struct razor_property *) merger->set->properties.data;
krh@248
   184
}
krh@248
   185
krh@248
   186
static void
krh@248
   187
merge_properties(struct razor_merger *merger)
krh@248
   188
{
krh@248
   189
	struct razor_property *p1, *p2;
krh@248
   190
	struct razor_set *set1, *set2;
krh@248
   191
	uint32_t *map1, *map2;
krh@248
   192
	int i, j, cmp, count1, count2;
krh@248
   193
	char *pool1, *pool2;
krh@248
   194
krh@248
   195
	set1 = merger->source1.set;
krh@248
   196
	set2 = merger->source2.set;
krh@248
   197
	map1 = merger->source1.property_map;
krh@248
   198
	map2 = merger->source2.property_map;
krh@248
   199
krh@248
   200
	i = 0;
krh@248
   201
	j = 0;
krh@248
   202
	pool1 = set1->string_pool.data;
krh@248
   203
	pool2 = set2->string_pool.data;
krh@248
   204
krh@248
   205
	count1 = set1->properties.size / sizeof *p1;
krh@248
   206
	count2 = set2->properties.size / sizeof *p2;
krh@248
   207
	while (i < count1 || j < count2) {
krh@248
   208
		if (i < count1 && map1[i] == 0) {
krh@248
   209
			i++;
krh@248
   210
			continue;
krh@248
   211
		}
krh@248
   212
		if (j < count2 && map2[j] == 0) {
krh@248
   213
			j++;
krh@248
   214
			continue;
krh@248
   215
		}
krh@248
   216
		p1 = (struct razor_property *) set1->properties.data + i;
krh@248
   217
		p2 = (struct razor_property *) set2->properties.data + j;
krh@248
   218
		if (i < count1 && j < count2)
krh@248
   219
			cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
krh@248
   220
		else if (i < count1)
krh@248
   221
			cmp = -1;
krh@248
   222
		else
krh@248
   223
			cmp = 1;
krh@248
   224
		if (cmp == 0)
krh@248
   225
			cmp = p1->flags - p2->flags;
krh@248
   226
		if (cmp == 0)
krh@248
   227
			cmp = razor_versioncmp(&pool1[p1->version],
krh@248
   228
					       &pool2[p2->version]);
krh@248
   229
		if (cmp < 0) {
krh@248
   230
			map1[i++] = add_property(merger,
krh@248
   231
						 &pool1[p1->name],
krh@248
   232
						 p1->flags,
krh@248
   233
						 &pool1[p1->version]);
krh@248
   234
		} else if (cmp > 0) {
krh@248
   235
			map2[j++] = add_property(merger,
krh@248
   236
						 &pool2[p2->name],
krh@248
   237
						 p2->flags,
krh@248
   238
						 &pool2[p2->version]);
krh@248
   239
		} else  {
krh@248
   240
			map1[i++] = map2[j++] =
krh@248
   241
				add_property(merger,
krh@248
   242
					     &pool1[p1->name],
krh@248
   243
					     p1->flags,
krh@248
   244
					     &pool1[p1->version]);
krh@248
   245
		}
krh@248
   246
	}
krh@248
   247
}
krh@248
   248
krh@248
   249
static void
krh@248
   250
emit_properties(struct list_head *properties, struct array *source_pool,
krh@248
   251
		uint32_t *map, struct array *pool)
krh@248
   252
{
krh@248
   253
	uint32_t r;
krh@248
   254
	struct list *p, *q;
krh@248
   255
krh@248
   256
	r = pool->size / sizeof *q;
krh@248
   257
	p = list_first(properties, source_pool);
krh@248
   258
	while (p) {
krh@248
   259
		q = array_add(pool, sizeof *q);
krh@248
   260
		q->data = map[p->data];
krh@248
   261
		q->flags = p->flags;
krh@248
   262
		p = list_next(p);
krh@248
   263
	}
krh@248
   264
krh@248
   265
	list_set_ptr(properties, r);
krh@248
   266
}
krh@248
   267
krh@248
   268
static uint32_t
krh@248
   269
add_file(struct razor_merger *merger, const char *name)
krh@248
   270
{
krh@248
   271
	struct razor_entry *e;
krh@248
   272
krh@248
   273
	e = array_add(&merger->set->files, sizeof *e);
ali@348
   274
	e->name = hashtable_tokenize(&merger->file_table, name);
krh@248
   275
	e->flags = 0;
krh@248
   276
	e->start = 0;
krh@248
   277
krh@248
   278
	return e - (struct razor_entry *)merger->set->files.data;
krh@248
   279
}
krh@248
   280
krh@248
   281
/* FIXME. Blah */
krh@248
   282
static int
krh@248
   283
fix_file_map(uint32_t *map,
krh@248
   284
	     struct razor_entry *files,
krh@248
   285
	     struct razor_entry *top)
krh@248
   286
{
krh@248
   287
	uint32_t e;
krh@248
   288
	int found_file = 0;
krh@248
   289
ali@359
   290
	e = top - files;
krh@248
   291
	do {
ali@359
   292
		if (files[e].start &&
ali@359
   293
		    fix_file_map(map, files, &files[files[e].start]))
ali@359
   294
			map[e] = 1;
krh@248
   295
		if (map[e])
krh@248
   296
			found_file = 1;
krh@248
   297
	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
krh@248
   298
krh@248
   299
	return found_file;
krh@248
   300
}
krh@248
   301
krh@248
   302
struct merge_directory {
krh@248
   303
	uint32_t merged, dir1, dir2;
krh@248
   304
};
krh@248
   305
krh@248
   306
static void
krh@248
   307
merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
krh@248
   308
{
krh@248
   309
	struct razor_entry *root1, *root2, *mroot, *e1, *e2;
krh@248
   310
	struct razor_set *set1, *set2;
krh@248
   311
	struct array merge_stack;
krh@248
   312
	struct merge_directory *child_md, *end_md;
krh@248
   313
	uint32_t *map1, *map2, start, last;
krh@248
   314
	int cmp;
krh@248
   315
	char *pool1, *pool2;
krh@248
   316
krh@248
   317
	set1 = merger->source1.set;
krh@248
   318
	set2 = merger->source2.set;
krh@248
   319
	map1 = merger->source1.file_map;
krh@248
   320
	map2 = merger->source2.file_map;
ali@458
   321
	if (set1->file_string_pool.size)
ali@458
   322
		pool1 = set1->file_string_pool.data;
ali@458
   323
	else
ali@458
   324
		pool1 = NULL;
ali@458
   325
	if (set2->file_string_pool.size)
ali@458
   326
		pool2 = set2->file_string_pool.data;
ali@458
   327
	else
ali@458
   328
		pool2 = NULL;
krh@248
   329
	root1 = (struct razor_entry *) set1->files.data;
krh@248
   330
	root2 = (struct razor_entry *) set2->files.data;
krh@248
   331
krh@248
   332
	array_init(&merge_stack);
krh@248
   333
krh@248
   334
	start = merger->set->files.size / sizeof (struct razor_entry);
ali@359
   335
	last = 0xFFFFFFFF;
ali@359
   336
	e1 = md->dir1 != 0xFFFFFFFF ? root1 + md->dir1 : NULL;
ali@359
   337
	e2 = md->dir2 != 0xFFFFFFFF ? root2 + md->dir2 : NULL;
krh@248
   338
	while (e1 || e2) {
krh@248
   339
		if (!e2 && !map1[e1 - root1]) {
krh@248
   340
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
krh@248
   341
				e1 = NULL;
krh@248
   342
			continue;
krh@248
   343
		}
krh@248
   344
		if (!e1 && !map2[e2 - root2]) {
krh@248
   345
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
krh@248
   346
				e2 = NULL;
krh@248
   347
			continue;
krh@248
   348
		}
krh@248
   349
		if (e1 && !map1[e1 - root1] &&
krh@314
   350
		    e2 && !map2[e2 - root2]) {
krh@248
   351
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
krh@248
   352
				e1 = NULL;
krh@248
   353
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
krh@248
   354
				e2 = NULL;
krh@248
   355
			continue;
krh@248
   356
		}
krh@248
   357
ali@458
   358
		if (!e1 || !pool1)
krh@248
   359
			cmp = 1;
ali@458
   360
		else if (!e2 || !pool2)
krh@248
   361
			cmp = -1;
krh@248
   362
		else {
krh@248
   363
			cmp = strcmp (&pool1[e1->name],
krh@248
   364
				      &pool2[e2->name]);
krh@248
   365
		}
krh@248
   366
krh@248
   367
		if (cmp < 0) {
krh@248
   368
			if (map1[e1 - root1]) {
krh@248
   369
				map1[e1 - root1] = last =
krh@248
   370
					add_file(merger, &pool1[e1->name]);
krh@248
   371
				if (e1->start) {
krh@248
   372
					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
krh@248
   373
					child_md->merged = last;
krh@248
   374
					child_md->dir1 = e1->start;
ali@359
   375
					child_md->dir2 = 0xFFFFFFFF;
krh@248
   376
				}
krh@248
   377
			}
krh@248
   378
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
krh@248
   379
				e1 = NULL;
krh@248
   380
		} else if (cmp > 0) {
krh@248
   381
			if (map2[e2 - root2]) {
krh@248
   382
				map2[e2 - root2] = last =
krh@248
   383
					add_file(merger, &pool2[e2->name]);
krh@248
   384
				if (e2->start) {
krh@248
   385
					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
krh@248
   386
					child_md->merged = last;
ali@359
   387
					child_md->dir1 = 0xFFFFFFFF;
krh@248
   388
					child_md->dir2 = e2->start;
krh@248
   389
				}
krh@248
   390
			}
krh@248
   391
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
krh@248
   392
				e2 = NULL;
krh@248
   393
		} else {
krh@248
   394
			map1[e1 - root1] = map2[e2- root2] = last =
krh@248
   395
				add_file(merger, &pool1[e1->name]);
krh@248
   396
			if (e1->start || e2->start) {
krh@248
   397
				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
krh@248
   398
				child_md->merged = last;
ali@359
   399
				child_md->dir1 = e1->start ? e1->start : 0xFFFFFFFF;
ali@359
   400
				child_md->dir2 = e2->start ? e2->start : 0xFFFFFFFF;
krh@248
   401
			}
krh@248
   402
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
krh@248
   403
				e1 = NULL;
krh@248
   404
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
krh@248
   405
				e2 = NULL;
krh@248
   406
		}
krh@248
   407
	}
krh@248
   408
krh@248
   409
	mroot = (struct razor_entry *)merger->set->files.data;
ali@359
   410
	if (last != 0xFFFFFFFF) {
krh@248
   411
		mroot[last].flags = RAZOR_ENTRY_LAST;
krh@248
   412
		mroot[md->merged].start = start;
ali@359
   413
	}
krh@248
   414
krh@248
   415
	end_md = merge_stack.data + merge_stack.size;
krh@248
   416
	for (child_md = merge_stack.data; child_md < end_md; child_md++)
krh@248
   417
		merge_one_directory(merger, child_md);
krh@248
   418
	array_release(&merge_stack);
krh@248
   419
}
krh@248
   420
krh@248
   421
static void
krh@248
   422
merge_files(struct razor_merger *merger)
krh@248
   423
{
krh@248
   424
	struct razor_entry *root;
krh@248
   425
	struct merge_directory md;
krh@248
   426
	uint32_t *map1, *map2;
krh@248
   427
krh@248
   428
	map1 = merger->source1.file_map;
krh@248
   429
	map2 = merger->source2.file_map;
krh@248
   430
krh@248
   431
	md.merged = 0;
krh@248
   432
krh@248
   433
	if (merger->source1.set->files.size) {
krh@248
   434
		root = (struct razor_entry *) merger->source1.set->files.data;
krh@248
   435
		if (root->start)
krh@248
   436
			fix_file_map(map1, root, root);
krh@248
   437
		md.dir1 = 0;
ali@359
   438
	} else {
ali@359
   439
		md.dir1 = 0xFFFFFFFF;
ali@359
   440
	}
krh@248
   441
krh@248
   442
	if (merger->source2.set->files.size) {
krh@248
   443
		root = (struct razor_entry *) merger->source2.set->files.data;
krh@248
   444
		if (root->start)
krh@248
   445
			fix_file_map(map2, root, root);
krh@248
   446
		md.dir2 = 0;
ali@359
   447
	} else {
ali@359
   448
		md.dir2 = 0xFFFFFFFF;
ali@359
   449
	}
ali@359
   450
ali@359
   451
	/* Remove the unnamed root which razor_set_create() added */
ali@359
   452
	array_release(&merger->set->files);
ali@359
   453
	array_init(&merger->set->files);
krh@248
   454
krh@248
   455
	merge_one_directory(merger, &md);
krh@248
   456
}
krh@248
   457
krh@248
   458
static void
krh@248
   459
emit_files(struct list_head *files, struct array *source_pool,
krh@248
   460
	   uint32_t *map, struct array *pool)
krh@248
   461
{
krh@248
   462
	uint32_t r;
krh@248
   463
	struct list *p, *q;
krh@248
   464
krh@248
   465
	r = pool->size / sizeof *q;
krh@248
   466
	p = list_first(files, source_pool);
ali@470
   467
ali@470
   468
	if (!p)
ali@470
   469
		return;
ali@470
   470
krh@248
   471
	while (p) {
krh@248
   472
		q = array_add(pool, sizeof *q);
krh@248
   473
		q->data = map[p->data];
krh@248
   474
		q->flags = p->flags;
krh@248
   475
		p = list_next(p);
krh@248
   476
	}
krh@248
   477
krh@248
   478
	list_set_ptr(files, r);
krh@248
   479
}
krh@248
   480
krh@248
   481
/* Rebuild property->packages maps.  We can't just remap these, as a
krh@248
   482
 * property may have lost or gained a number of packages.  Allocate an
krh@248
   483
 * array per property and loop through the packages and add them to
krh@248
   484
 * the arrays for their properties. */
krh@248
   485
static void
krh@248
   486
rebuild_property_package_lists(struct razor_set *set)
krh@248
   487
{
krh@248
   488
	struct array *pkgs, *a;
krh@248
   489
	struct razor_package *pkg, *pkg_end;
krh@248
   490
	struct razor_property *prop, *prop_end;
krh@248
   491
	struct list *r;
krh@248
   492
	uint32_t *q;
krh@248
   493
	int count;
krh@248
   494
krh@248
   495
	count = set->properties.size / sizeof (struct razor_property);
krh@248
   496
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   497
	pkg_end = set->packages.data + set->packages.size;
krh@248
   498
krh@248
   499
	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
krh@248
   500
		r = list_first(&pkg->properties, &set->property_pool);
krh@248
   501
		while (r) {
krh@248
   502
			q = array_add(&pkgs[r->data], sizeof *q);
krh@248
   503
			*q = pkg - (struct razor_package *) set->packages.data;
krh@248
   504
			r = list_next(r);
krh@248
   505
		}
krh@248
   506
	}
krh@248
   507
krh@248
   508
	prop_end = set->properties.data + set->properties.size;
krh@248
   509
	a = pkgs;
krh@248
   510
	for (prop = set->properties.data; prop < prop_end; prop++, a++) {
krh@248
   511
		list_set_array(&prop->packages, &set->package_pool, a, 0);
krh@248
   512
		array_release(a);
krh@248
   513
	}
krh@248
   514
	free(pkgs);
krh@248
   515
}
krh@248
   516
krh@248
   517
static void
krh@248
   518
rebuild_file_package_lists(struct razor_set *set)
krh@248
   519
{
krh@248
   520
	struct array *pkgs, *a;
krh@248
   521
	struct razor_package *pkg, *pkg_end;
krh@248
   522
	struct razor_entry *entry, *entry_end;
krh@248
   523
	struct list *r;
krh@248
   524
	uint32_t *q;
krh@248
   525
	int count;
krh@248
   526
krh@248
   527
	count = set->files.size / sizeof (struct razor_entry);
krh@248
   528
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   529
	pkg_end = set->packages.data + set->packages.size;
krh@248
   530
krh@248
   531
	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
krh@248
   532
		r = list_first(&pkg->files, &set->file_pool);
krh@248
   533
		while (r) {
krh@248
   534
			q = array_add(&pkgs[r->data], sizeof *q);
krh@248
   535
			*q = pkg - (struct razor_package *) set->packages.data;
krh@248
   536
			r = list_next(r);
krh@248
   537
		}
krh@248
   538
	}
krh@248
   539
krh@248
   540
	entry_end = set->files.data + set->files.size;
krh@248
   541
	a = pkgs;
krh@248
   542
	for (entry = set->files.data; entry < entry_end; entry++, a++) {
krh@248
   543
		list_set_array(&entry->packages, &set->package_pool, a, 0);
krh@248
   544
		array_release(a);
krh@248
   545
	}
krh@248
   546
	free(pkgs);
krh@248
   547
}
krh@248
   548
krh@248
   549
struct razor_set *
ali@369
   550
razor_merger_commit(struct razor_merger *merger)
krh@248
   551
{
krh@248
   552
	struct razor_package *p, *pend;
krh@248
   553
krh@248
   554
	/* As we built the package list, we filled out a bitvector of
krh@248
   555
	 * the properties that are referenced by the packages in the
krh@248
   556
	 * new set.  Now we do a parallel loop through the properties
krh@248
   557
	 * and emit those marked in the bit vector to the new set.  In
krh@248
   558
	 * the process, we update the bit vector to actually map from
krh@248
   559
	 * indices in the old property list to indices in the new
krh@248
   560
	 * property list for both sets. */
krh@248
   561
krh@248
   562
	merge_properties(merger);
krh@248
   563
	merge_files(merger);
krh@248
   564
krh@248
   565
	/* Now we loop through the packages again and emit the
krh@248
   566
	 * property lists, remapped to point to the new properties. */
krh@248
   567
krh@248
   568
	pend = merger->set->packages.data + merger->set->packages.size;
krh@248
   569
	for (p = merger->set->packages.data; p < pend; p++) {
krh@248
   570
		struct source *src;
krh@248
   571
krh@248
   572
		if (p->flags & UPSTREAM_SOURCE)
krh@248
   573
			src = &merger->source2;
krh@248
   574
		else
krh@248
   575
			src = &merger->source1;
krh@248
   576
krh@248
   577
		emit_properties(&p->properties,
krh@248
   578
				&src->set->property_pool,
krh@248
   579
				src->property_map,
krh@248
   580
				&merger->set->property_pool);
krh@248
   581
		emit_files(&p->files,
krh@248
   582
			   &src->set->file_pool,
krh@248
   583
			   src->file_map,
krh@248
   584
			   &merger->set->file_pool);
krh@248
   585
		p->flags &= ~UPSTREAM_SOURCE;
krh@248
   586
	}
krh@248
   587
krh@248
   588
	rebuild_property_package_lists(merger->set);
krh@248
   589
	rebuild_file_package_lists(merger->set);
krh@248
   590
ali@369
   591
	merger->committed = 1;
ali@369
   592
ali@369
   593
	return merger->set;
ali@369
   594
}
ali@369
   595
ali@369
   596
void
ali@369
   597
razor_merger_package_add_script(struct razor_merger *merger,
ali@369
   598
				struct razor_package *package,
ali@369
   599
				enum razor_property_flags script,
ali@369
   600
				const char *program, const char *body)
ali@369
   601
{
ali@369
   602
	uint32_t p, b;
ali@369
   603
	char *pool;
ali@369
   604
	struct razor_set *set = merger->set;
ali@369
   605
	assert ((void *)package >= set->packages.data && \
ali@369
   606
	    (void *)package < set->packages.data + set->packages.size);
ali@369
   607
ali@369
   608
	p = hashtable_tokenize(&merger->table, program);
ali@369
   609
	b = hashtable_tokenize(&merger->table, body);
ali@369
   610
ali@369
   611
	pool = merger->set->string_pool.data;
ali@369
   612
ali@369
   613
	switch (script) {
ali@369
   614
	case RAZOR_PROPERTY_PREUN:
ali@403
   615
		if (package->preun.program != p) {
ali@403
   616
			assert(pool[package->preun.program] == '\0');
ali@403
   617
			package->preun.program = p;
ali@403
   618
		}
ali@403
   619
		if (package->preun.body != b) {
ali@403
   620
			assert(pool[package->preun.body] == '\0');
ali@403
   621
			package->preun.body = b;
ali@403
   622
		}
ali@369
   623
		break;
ali@369
   624
	case RAZOR_PROPERTY_POSTUN:
ali@403
   625
		if (package->postun.program != p) {
ali@403
   626
			assert(pool[package->postun.program] == '\0');
ali@403
   627
			package->postun.program = p;
ali@403
   628
		}
ali@403
   629
		if (package->postun.body != b) {
ali@403
   630
			assert(pool[package->postun.body] == '\0');
ali@403
   631
			package->postun.body = b;
ali@403
   632
		}
ali@369
   633
		break;
ali@369
   634
	default:
ali@369
   635
		break;
ali@369
   636
	}
ali@369
   637
}
ali@369
   638
ali@369
   639
void razor_merger_destroy(struct razor_merger *merger)
ali@369
   640
{
krh@248
   641
	hashtable_release(&merger->table);
ali@348
   642
	hashtable_release(&merger->file_table);
ali@394
   643
	hashtable_release(&merger->details_table);
ali@458
   644
	free(merger->source1.property_map);
ali@458
   645
	free(merger->source1.file_map);
ali@458
   646
	free(merger->source2.property_map);
ali@458
   647
	free(merger->source2.file_map);
krh@248
   648
	free(merger);
krh@248
   649
}