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