librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 307 95b6bcadd6c4
child 368 ea743486ba6f
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
krh@248
     1
/*
krh@248
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
krh@248
     3
 * Copyright (C) 2008  Red Hat, Inc
krh@248
     4
 *
krh@248
     5
 * This program is free software; you can redistribute it and/or modify
krh@248
     6
 * it under the terms of the GNU General Public License as published by
krh@248
     7
 * the Free Software Foundation; either version 2 of the License, or
krh@248
     8
 * (at your option) any later version.
krh@248
     9
 *
krh@248
    10
 * This program is distributed in the hope that it will be useful,
krh@248
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
krh@248
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
krh@248
    13
 * GNU General Public License for more details.
krh@248
    14
 *
krh@248
    15
 * You should have received a copy of the GNU General Public License along
krh@248
    16
 * with this program; if not, write to the Free Software Foundation, Inc.,
krh@248
    17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
krh@248
    18
 */
krh@248
    19
krh@248
    20
#define _GNU_SOURCE
krh@248
    21
krh@248
    22
#include <stdlib.h>
krh@248
    23
#include <stddef.h>
krh@248
    24
#include <stdint.h>
krh@248
    25
#include <stdio.h>
krh@248
    26
#include <string.h>
krh@248
    27
#include <sys/types.h>
krh@248
    28
#include <sys/stat.h>
krh@248
    29
#include <unistd.h>
krh@248
    30
#include <fcntl.h>
krh@248
    31
#include <errno.h>
krh@248
    32
#include <ctype.h>
krh@248
    33
#include <fnmatch.h>
richard@301
    34
#include <assert.h>
krh@248
    35
krh@248
    36
#include "razor-internal.h"
krh@248
    37
#include "razor.h"
krh@248
    38
krh@248
    39
static int
krh@248
    40
provider_satisfies_requirement(struct razor_property *provider,
krh@248
    41
			       const char *provider_strings,
krh@248
    42
			       uint32_t flags,
krh@248
    43
			       const char *required)
krh@248
    44
{
krh@248
    45
	int cmp, len;
krh@248
    46
	const char *provided = &provider_strings[provider->version];
krh@248
    47
krh@248
    48
	if (!*required)
krh@248
    49
		return 1;
krh@248
    50
	if (!*provided) {
krh@248
    51
		if (flags & RAZOR_PROPERTY_LESS)
krh@248
    52
			return 0;
krh@248
    53
		else
krh@248
    54
			return 1;
krh@248
    55
	}
krh@248
    56
krh@248
    57
	cmp = razor_versioncmp(provided, required);
krh@248
    58
krh@248
    59
	switch (flags & RAZOR_PROPERTY_RELATION_MASK) {
krh@248
    60
	case RAZOR_PROPERTY_LESS:
krh@248
    61
		return cmp < 0;
krh@248
    62
krh@248
    63
	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
krh@248
    64
		if (cmp <= 0)
krh@248
    65
			return 1;
krh@248
    66
		/* fall through: FIXME, make sure this is correct */
krh@248
    67
krh@248
    68
	case RAZOR_PROPERTY_EQUAL:
krh@248
    69
		if (cmp == 0)
krh@248
    70
			return 1;
krh@248
    71
krh@248
    72
		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
krh@248
    73
		len = strlen(required);
krh@248
    74
		if (!strncmp(required, provided, len) && provided[len] == '-')
krh@248
    75
			return 1;
krh@248
    76
		return 0;
krh@248
    77
krh@248
    78
	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
krh@248
    79
		return cmp >= 0;
krh@248
    80
krh@248
    81
	case RAZOR_PROPERTY_GREATER:
krh@248
    82
		return cmp > 0;
krh@248
    83
	}
krh@248
    84
krh@248
    85
	/* shouldn't happen */
krh@248
    86
	return 0;
krh@248
    87
}
krh@248
    88
krh@248
    89
#define TRANS_PACKAGE_PRESENT		1
krh@248
    90
#define TRANS_PACKAGE_UPDATE		2
krh@248
    91
#define TRANS_PROPERTY_SATISFIED	0x80000000
krh@248
    92
krh@248
    93
struct transaction_set {
krh@248
    94
	struct razor_set *set;
krh@248
    95
	uint32_t *packages;
krh@248
    96
	uint32_t *properties;
krh@248
    97
};
krh@248
    98
krh@248
    99
struct razor_transaction {
krh@248
   100
	int package_count, errors;
krh@248
   101
	struct transaction_set system, upstream;
krh@248
   102
	int changes;
krh@248
   103
};
krh@248
   104
krh@248
   105
static void
krh@248
   106
transaction_set_init(struct transaction_set *ts, struct razor_set *set)
krh@248
   107
{
krh@248
   108
	int count;
krh@248
   109
krh@248
   110
	ts->set = set;
krh@248
   111
	count = set->packages.size / sizeof (struct razor_package);
krh@248
   112
	ts->packages = zalloc(count * sizeof *ts->packages);
krh@248
   113
	count = set->properties.size / sizeof (struct razor_property);
krh@248
   114
	ts->properties = zalloc(count * sizeof *ts->properties);
krh@248
   115
}
krh@248
   116
krh@248
   117
static void
krh@248
   118
transaction_set_release(struct transaction_set *ts)
krh@248
   119
{
krh@248
   120
	free(ts->packages);
krh@248
   121
	free(ts->properties);
krh@248
   122
}
krh@248
   123
krh@248
   124
static void
krh@248
   125
transaction_set_install_package(struct transaction_set *ts,
krh@248
   126
				struct razor_package *package)
krh@248
   127
{
krh@248
   128
	struct razor_package *pkgs;
krh@248
   129
	struct list *prop;
krh@248
   130
	int i;
krh@248
   131
krh@248
   132
	pkgs = ts->set->packages.data;
krh@248
   133
	i = package - pkgs;
krh@248
   134
	if (ts->packages[i] == TRANS_PACKAGE_PRESENT)
krh@248
   135
		return;
krh@248
   136
krh@248
   137
	ts->packages[i] = TRANS_PACKAGE_PRESENT;
krh@248
   138
krh@248
   139
	prop = list_first(&package->properties, &ts->set->property_pool);
krh@248
   140
	while (prop) {
krh@248
   141
		ts->properties[prop->data]++;
krh@248
   142
		prop = list_next(prop);
krh@248
   143
	}
krh@248
   144
}
krh@248
   145
krh@248
   146
static void
krh@248
   147
transaction_set_remove_package(struct transaction_set *ts,
krh@248
   148
			       struct razor_package *package)
krh@248
   149
{
krh@248
   150
	struct razor_package *pkgs;
krh@248
   151
	struct list *prop;
krh@248
   152
	int i;
krh@248
   153
krh@248
   154
	pkgs = ts->set->packages.data;
krh@248
   155
	i = package - pkgs;
krh@248
   156
	if (ts->packages[i] == 0)
krh@248
   157
		return;
krh@248
   158
krh@248
   159
	ts->packages[i] = 0;
krh@248
   160
krh@248
   161
	prop = list_first(&package->properties, &ts->set->property_pool);
krh@248
   162
	while (prop) {
krh@248
   163
		ts->properties[prop->data]--;
krh@248
   164
		prop = list_next(prop);
krh@248
   165
	}
krh@248
   166
}
krh@248
   167
krh@269
   168
RAZOR_EXPORT struct razor_transaction *
krh@248
   169
razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
krh@248
   170
{
krh@248
   171
	struct razor_transaction *trans;
krh@248
   172
	struct razor_package *p, *spkgs, *pend;
krh@248
   173
krh@248
   174
	trans = zalloc(sizeof *trans);
krh@248
   175
	transaction_set_init(&trans->system, system);
krh@248
   176
	transaction_set_init(&trans->upstream, upstream);
krh@248
   177
krh@248
   178
	spkgs = trans->system.set->packages.data;
krh@248
   179
	pend = trans->system.set->packages.data +
krh@248
   180
		trans->system.set->packages.size;
krh@248
   181
	for (p = spkgs; p < pend; p++)
krh@248
   182
		transaction_set_install_package(&trans->system, p);
krh@248
   183
krh@248
   184
	return trans;
krh@248
   185
}
krh@248
   186
krh@269
   187
RAZOR_EXPORT void
krh@248
   188
razor_transaction_install_package(struct razor_transaction *trans,
krh@248
   189
				  struct razor_package *package)
krh@248
   190
{
richard@301
   191
	assert (trans != NULL);
richard@301
   192
	assert (package != NULL);
richard@301
   193
krh@248
   194
	transaction_set_install_package(&trans->upstream, package);
krh@248
   195
	trans->changes++;
krh@248
   196
}
krh@248
   197
krh@269
   198
RAZOR_EXPORT void
krh@248
   199
razor_transaction_remove_package(struct razor_transaction *trans,
krh@248
   200
				 struct razor_package *package)
krh@248
   201
{
richard@301
   202
	assert (trans != NULL);
richard@301
   203
	assert (package != NULL);
richard@301
   204
krh@248
   205
	transaction_set_remove_package(&trans->system, package);
krh@248
   206
	trans->changes++;
krh@248
   207
}
krh@248
   208
krh@269
   209
RAZOR_EXPORT void
krh@248
   210
razor_transaction_update_package(struct razor_transaction *trans,
krh@248
   211
				  struct razor_package *package)
krh@248
   212
{
krh@248
   213
	struct razor_package *spkgs, *upkgs, *end;
krh@248
   214
richard@301
   215
	assert (trans != NULL);
richard@301
   216
	assert (package != NULL);
richard@301
   217
krh@248
   218
	spkgs = trans->system.set->packages.data;
krh@248
   219
	upkgs = trans->upstream.set->packages.data;
krh@248
   220
	end = trans->system.set->packages.data +
krh@248
   221
		trans->system.set->packages.size;
krh@248
   222
	if (spkgs <= package && package < end)
krh@248
   223
		trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
krh@248
   224
	else
krh@248
   225
		trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
krh@248
   226
}
krh@248
   227
krh@248
   228
struct prop_iter {
krh@248
   229
	struct razor_property *p, *start, *end;
krh@248
   230
	const char *pool;
krh@248
   231
	uint32_t *present;
krh@248
   232
};
krh@248
   233
krh@248
   234
static void
krh@248
   235
prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
krh@248
   236
{
krh@248
   237
	pi->p = ts->set->properties.data;
krh@248
   238
	pi->start = ts->set->properties.data;
krh@248
   239
	pi->end = ts->set->properties.data + ts->set->properties.size;
krh@248
   240
	pi->pool = ts->set->string_pool.data;
krh@248
   241
	pi->present = ts->properties;
krh@248
   242
}
krh@248
   243
krh@248
   244
static int
krh@248
   245
prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p)
krh@248
   246
{
krh@248
   247
	while (pi->p < pi->end) {
krh@248
   248
		if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
krh@248
   249
		    (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) {
krh@248
   250
			*p = pi->p++;
krh@248
   251
			return 1;
krh@248
   252
		}
krh@248
   253
		pi->p++;
krh@248
   254
	}
krh@248
   255
krh@248
   256
	return 0;
krh@248
   257
}
krh@248
   258
krh@248
   259
static struct razor_property *
krh@248
   260
prop_iter_seek_to(struct prop_iter *pi,
krh@248
   261
		  uint32_t flags, const char *match)
krh@248
   262
{
krh@248
   263
	uint32_t name;
krh@248
   264
krh@248
   265
	while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
krh@248
   266
		pi->p++;
krh@248
   267
krh@248
   268
	if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
krh@248
   269
		return NULL;
krh@248
   270
krh@248
   271
	name = pi->p->name;
krh@248
   272
	while (pi->p < pi->end &&
krh@248
   273
	       pi->p->name == name &&
krh@248
   274
	       (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags)
krh@248
   275
		pi->p++;
krh@248
   276
krh@248
   277
	if (pi->p == pi->end || pi->p->name != name)
krh@248
   278
		return NULL;
krh@248
   279
krh@248
   280
	return pi->p;
krh@248
   281
}
krh@248
   282
krh@248
   283
/* Remove packages from set that provide any of the matching (same
krh@248
   284
 * name and type) providers from ppi onwards that match the
krh@248
   285
 * requirement that rpi points to. */
krh@248
   286
static void
krh@248
   287
remove_matching_providers(struct razor_transaction *trans,
krh@248
   288
			  struct prop_iter *ppi,
krh@248
   289
			  uint32_t flags,
krh@248
   290
			  const char *version)
krh@248
   291
{
krh@248
   292
	struct razor_property *p;
krh@248
   293
	struct razor_package *pkg, *pkgs;
krh@248
   294
	struct razor_package_iterator pkg_iter;
krh@248
   295
	struct razor_set *set;
richard@302
   296
	const char *n, *v;
krh@248
   297
	uint32_t type;
krh@248
   298
krh@248
   299
	if (ppi->present == trans->system.properties)
krh@248
   300
		set = trans->system.set;
krh@248
   301
	else
krh@248
   302
		set = trans->upstream.set;
krh@248
   303
krh@248
   304
	pkgs = (struct razor_package *) set->packages.data;
krh@248
   305
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   306
	for (p = ppi->p;
krh@248
   307
	     p < ppi->end &&
krh@248
   308
	     p->name == ppi->p->name &&
krh@248
   309
	     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
krh@248
   310
	     p++) {
krh@248
   311
		if (!ppi->present[p - ppi->start])
krh@248
   312
			continue;
krh@248
   313
		if (!provider_satisfies_requirement(p, ppi->pool,
krh@248
   314
						    flags, version))
krh@248
   315
			continue;
krh@248
   316
krh@248
   317
		razor_package_iterator_init_for_property(&pkg_iter, set, p);
richard@302
   318
		while (razor_package_iterator_next(&pkg_iter, &pkg,
richard@302
   319
						   RAZOR_DETAIL_NAME, &n,
richard@307
   320
						   RAZOR_DETAIL_VERSION, &v,
richard@307
   321
						   RAZOR_DETAIL_LAST)) {
krh@248
   322
			fprintf(stderr, "removing %s-%s\n", n, v);
krh@248
   323
			razor_transaction_remove_package(trans, pkg);
krh@248
   324
		}
krh@248
   325
	}
krh@248
   326
}
krh@248
   327
krh@248
   328
static void
krh@248
   329
flag_matching_providers(struct razor_transaction *trans,
krh@248
   330
			struct prop_iter *ppi,
krh@248
   331
			struct razor_property *r,
krh@248
   332
			struct prop_iter *rpi,
krh@248
   333
			unsigned int flag)
krh@248
   334
{
krh@248
   335
	struct razor_property *p;
krh@248
   336
	struct razor_package *pkg, *pkgs;
krh@248
   337
	struct razor_package_iterator pkg_iter;
krh@248
   338
	struct razor_set *set;
richard@302
   339
	const char *name, *version;
krh@248
   340
	uint32_t *flags, type;
krh@248
   341
krh@248
   342
	if (ppi->present == trans->system.properties) {
krh@248
   343
		set = trans->system.set;
krh@248
   344
		flags = trans->system.packages;
krh@248
   345
	} else {
krh@248
   346
		set = trans->upstream.set;
krh@248
   347
		flags = trans->upstream.packages;
krh@248
   348
	}
krh@248
   349
krh@248
   350
	pkgs = (struct razor_package *) set->packages.data;
krh@248
   351
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   352
	for (p = ppi->p;
krh@248
   353
	     p < ppi->end &&
krh@248
   354
		     p->name == ppi->p->name &&
krh@248
   355
		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
krh@248
   356
	     p++) {
krh@248
   357
		if (!ppi->present[p - ppi->start])
krh@248
   358
			continue;
krh@248
   359
		if (!provider_satisfies_requirement(p, ppi->pool,
krh@248
   360
						    r->flags,
krh@248
   361
						    &rpi->pool[r->version]))
krh@248
   362
			continue;
krh@248
   363
krh@248
   364
		razor_package_iterator_init_for_property(&pkg_iter, set, p);
krh@248
   365
		while (razor_package_iterator_next(&pkg_iter, &pkg,
richard@302
   366
						   RAZOR_DETAIL_NAME, &name,
richard@307
   367
						   RAZOR_DETAIL_VERSION, &version,
richard@307
   368
						   RAZOR_DETAIL_LAST)) {
krh@248
   369
krh@248
   370
			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
krh@248
   371
				name, version,
krh@248
   372
				ppi->pool + p->name,
krh@248
   373
				rpi->pool + r->name,
krh@248
   374
				rpi->pool + r->version);
krh@248
   375
			flags[pkg - pkgs] |= flag;
krh@248
   376
		}
krh@248
   377
	}
krh@248
   378
}
krh@248
   379
krh@248
   380
static struct razor_package *
krh@248
   381
pick_matching_provider(struct razor_set *set,
krh@248
   382
		       struct prop_iter *ppi,
krh@248
   383
		       uint32_t flags,
krh@248
   384
		       const char *version)
krh@248
   385
{
krh@248
   386
	struct razor_property *p;
krh@248
   387
	struct razor_package *pkgs;
krh@248
   388
	struct list *i;
krh@248
   389
	uint32_t type;
krh@248
   390
krh@248
   391
	/* This is where we decide which pkgs to pull in to satisfy a
krh@248
   392
	 * requirement.  There may be several different providers
krh@248
   393
	 * (different versions) and each version of a provider may
krh@248
   394
	 * come from a number of packages.  We pick the first package
krh@248
   395
	 * from the first provider that matches. */
krh@248
   396
krh@248
   397
	pkgs = set->packages.data;
krh@248
   398
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   399
	for (p = ppi->p;
krh@248
   400
	     p < ppi->end &&
krh@248
   401
		     p->name == ppi->p->name &&
krh@248
   402
		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
krh@248
   403
		     ppi->present[p - ppi->start] == 0;
krh@248
   404
	     p++) {
krh@248
   405
		if (!provider_satisfies_requirement(p, ppi->pool,
krh@248
   406
						    flags, version))
krh@248
   407
			continue;
krh@248
   408
krh@248
   409
		i = list_first(&p->packages, &set->package_pool);
krh@248
   410
krh@248
   411
		return &pkgs[i->data];
krh@248
   412
	}
krh@248
   413
krh@248
   414
	return NULL;
krh@248
   415
}
krh@248
   416
krh@248
   417
static void
krh@248
   418
remove_obsoleted_packages(struct razor_transaction *trans)
krh@248
   419
{
krh@248
   420
	struct razor_property *up;
krh@248
   421
	struct razor_package *spkgs;
krh@248
   422
	struct prop_iter spi, upi;
krh@248
   423
krh@248
   424
	spkgs = trans->system.set->packages.data;
krh@248
   425
	prop_iter_init(&spi, &trans->system);
krh@248
   426
	prop_iter_init(&upi, &trans->upstream);
krh@248
   427
krh@248
   428
	while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
krh@248
   429
		if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
krh@248
   430
				       &upi.pool[up->name]))
krh@248
   431
			continue;
krh@248
   432
		remove_matching_providers(trans, &spi, up->flags,
krh@248
   433
					  &upi.pool[up->version]);
krh@248
   434
	}
krh@248
   435
}
krh@248
   436
krh@248
   437
static int
krh@248
   438
any_provider_satisfies_requirement(struct prop_iter *ppi,
krh@248
   439
				   uint32_t flags,
krh@248
   440
				   const char *version)
krh@248
   441
{
krh@248
   442
	struct razor_property *p;
krh@248
   443
	uint32_t type;
krh@248
   444
krh@248
   445
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   446
	for (p = ppi->p;
krh@248
   447
	     p < ppi->end &&
krh@248
   448
		     p->name == ppi->p->name &&
krh@248
   449
		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
krh@248
   450
	     p++) {
krh@248
   451
		if (ppi->present[p - ppi->start] > 0 &&
krh@248
   452
		    provider_satisfies_requirement(p, ppi->pool,
krh@248
   453
						   flags, version))
krh@248
   454
			return 1;
krh@248
   455
	}
krh@248
   456
krh@248
   457
	return 0;
krh@248
   458
}
krh@248
   459
krh@248
   460
static void
krh@248
   461
clear_requires_flags(struct transaction_set *ts)
krh@248
   462
{
krh@248
   463
	struct razor_property *p;
krh@248
   464
	const char *pool;
krh@248
   465
	int i, count;
krh@248
   466
krh@248
   467
	count = ts->set->properties.size / sizeof *p;
krh@248
   468
	p = ts->set->properties.data;
krh@248
   469
	pool = ts->set->string_pool.data;
krh@248
   470
	for (i = 0; i < count; i++) {
krh@248
   471
		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
krh@248
   472
		if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
krh@248
   473
			ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
krh@248
   474
	}
krh@248
   475
}
krh@248
   476
krh@248
   477
static void
krh@248
   478
mark_satisfied_requires(struct razor_transaction *trans,
krh@248
   479
			struct transaction_set *rts,
krh@248
   480
			struct transaction_set *pts)
krh@248
   481
{
krh@248
   482
	struct prop_iter rpi, ppi;
krh@248
   483
	struct razor_property *rp;
krh@248
   484
krh@248
   485
	prop_iter_init(&rpi, rts);
krh@248
   486
	prop_iter_init(&ppi, pts);
krh@248
   487
krh@248
   488
	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   489
		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
krh@248
   490
				       &rpi.pool[rp->name]))
krh@248
   491
			continue;
krh@248
   492
krh@248
   493
		if (any_provider_satisfies_requirement(&ppi, rp->flags,
krh@248
   494
						       &rpi.pool[rp->version]))
krh@248
   495
			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
krh@248
   496
	}
krh@248
   497
}
krh@248
   498
krh@248
   499
static void
krh@248
   500
mark_all_satisfied_requires(struct razor_transaction *trans)
krh@248
   501
{
krh@248
   502
	clear_requires_flags(&trans->system);
krh@248
   503
	clear_requires_flags(&trans->upstream);
krh@248
   504
	mark_satisfied_requires(trans, &trans->system, &trans->system);
krh@248
   505
	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
krh@248
   506
	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
krh@248
   507
	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
krh@248
   508
}
krh@248
   509
krh@248
   510
static void
krh@248
   511
update_unsatisfied_packages(struct razor_transaction *trans)
krh@248
   512
{
krh@248
   513
	struct razor_package *spkgs, *pkg;
krh@248
   514
	struct razor_property *sp;
krh@248
   515
	struct prop_iter spi;
krh@248
   516
	struct razor_package_iterator pkg_iter;
richard@302
   517
	const char *name;
krh@248
   518
krh@248
   519
	spkgs = trans->system.set->packages.data;
krh@248
   520
	prop_iter_init(&spi, &trans->system);
krh@248
   521
krh@248
   522
	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
krh@248
   523
		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
krh@248
   524
			continue;
krh@248
   525
krh@248
   526
		razor_package_iterator_init_for_property(&pkg_iter,
krh@248
   527
							 trans->system.set,
krh@248
   528
							 sp);
krh@248
   529
		while (razor_package_iterator_next(&pkg_iter, &pkg,
richard@307
   530
						   RAZOR_DETAIL_NAME, &name,
richard@307
   531
						   RAZOR_DETAIL_LAST)) {
krh@248
   532
			fprintf(stderr, "updating %s because %s %s %s "
krh@248
   533
				"isn't satisfied\n",
krh@248
   534
				name, spi.pool + sp->name,
krh@248
   535
				razor_property_relation_to_string(sp),
krh@248
   536
				spi.pool + sp->version);
krh@248
   537
			trans->system.packages[pkg - spkgs] |=
krh@248
   538
				TRANS_PACKAGE_UPDATE;
krh@248
   539
		}
krh@248
   540
	}
krh@248
   541
}
krh@248
   542
krh@269
   543
RAZOR_EXPORT void
krh@248
   544
razor_transaction_update_all(struct razor_transaction *trans)
krh@248
   545
{
krh@248
   546
	struct razor_package *p;
krh@248
   547
	int i, count;
krh@248
   548
richard@301
   549
	assert (trans != NULL);
richard@301
   550
krh@248
   551
	count = trans->system.set->packages.size / sizeof *p;
krh@248
   552
	for (i = 0; i < count; i++)
krh@248
   553
		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
krh@248
   554
}
krh@248
   555
krh@248
   556
static void
krh@248
   557
update_conflicted_packages(struct razor_transaction *trans)
krh@248
   558
{
krh@248
   559
	struct razor_package *pkg, *spkgs;
krh@248
   560
	struct razor_property *up, *sp;
krh@248
   561
	struct prop_iter spi, upi;
krh@248
   562
	struct razor_package_iterator pkg_iter;
richard@302
   563
	const char *name, *version;
krh@248
   564
krh@248
   565
	spkgs = trans->system.set->packages.data;
krh@248
   566
	prop_iter_init(&spi, &trans->system);
krh@248
   567
	prop_iter_init(&upi, &trans->upstream);
krh@248
   568
krh@248
   569
	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
krh@248
   570
		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
krh@248
   571
				       &spi.pool[sp->name]))
krh@248
   572
			continue;
krh@248
   573
krh@248
   574
		if (!any_provider_satisfies_requirement(&upi, sp->flags,
krh@248
   575
							&spi.pool[sp->version]))
krh@248
   576
			continue;
krh@248
   577
krh@248
   578
		razor_package_iterator_init_for_property(&pkg_iter,
krh@248
   579
							 trans->system.set,
krh@248
   580
							 sp);
krh@248
   581
		while (razor_package_iterator_next(&pkg_iter, &pkg,
richard@302
   582
						   RAZOR_DETAIL_NAME, &name,
richard@307
   583
						   RAZOR_DETAIL_VERSION, &version,
richard@307
   584
						   RAZOR_DETAIL_LAST)) {
jbowes@286
   585
			fprintf(stderr, "updating %s %s because it "
jbowes@286
   586
				"conflicts with %s\n",
krh@248
   587
				name, version, spi.pool + sp->name);
krh@248
   588
			trans->system.packages[pkg - spkgs] |=
krh@248
   589
				TRANS_PACKAGE_UPDATE;
krh@248
   590
		}
krh@248
   591
	}
krh@248
   592
krh@248
   593
	prop_iter_init(&spi, &trans->system);
krh@248
   594
	prop_iter_init(&upi, &trans->upstream);
krh@248
   595
krh@248
   596
	while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
krh@248
   597
		sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
krh@248
   598
				       &upi.pool[upi.p->name]);
krh@248
   599
krh@248
   600
		if (sp)
krh@248
   601
			flag_matching_providers(trans, &spi, up, &upi,
krh@248
   602
						TRANS_PACKAGE_UPDATE);
krh@248
   603
	}
krh@248
   604
}
krh@248
   605
krh@248
   606
static void
krh@248
   607
pull_in_requirements(struct razor_transaction *trans,
krh@248
   608
		     struct prop_iter *rpi, struct prop_iter *ppi)
krh@248
   609
{
krh@248
   610
	struct razor_property *rp, *pp;
krh@248
   611
	struct razor_package *pkg, *upkgs;
krh@248
   612
krh@248
   613
	upkgs = trans->upstream.set->packages.data;
krh@248
   614
	while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   615
		if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
krh@248
   616
			continue;
krh@248
   617
krh@248
   618
		pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
krh@248
   619
				       &rpi->pool[rp->name]);
krh@248
   620
		if (pp == NULL)
krh@248
   621
			continue;
krh@248
   622
		pkg = pick_matching_provider(trans->upstream.set,
krh@248
   623
					     ppi, rp->flags,
krh@248
   624
					     &rpi->pool[rp->version]);
krh@248
   625
		if (pkg == NULL)
krh@248
   626
			continue;
krh@248
   627
krh@248
   628
		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
krh@248
   629
krh@257
   630
		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
krh@248
   631
			"to satisfy %s %s %s\n",
krh@248
   632
			ppi->pool + pkg->name,
krh@257
   633
			ppi->pool + pkg->version,
krh@257
   634
			ppi->pool + pkg->arch,
krh@248
   635
			ppi->pool + pp->name,
krh@248
   636
			razor_property_relation_to_string(pp),
krh@248
   637
			ppi->pool + pp->version,
krh@248
   638
			&rpi->pool[rp->name],
krh@248
   639
			razor_property_relation_to_string(rp),
krh@248
   640
			&rpi->pool[rp->version]);
krh@248
   641
krh@248
   642
		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
krh@248
   643
	}
krh@248
   644
}
krh@248
   645
krh@248
   646
static void
krh@248
   647
pull_in_all_requirements(struct razor_transaction *trans)
krh@248
   648
{
krh@248
   649
	struct prop_iter rpi, ppi;
krh@248
   650
krh@248
   651
	prop_iter_init(&rpi, &trans->system);
krh@248
   652
	prop_iter_init(&ppi, &trans->upstream);
krh@248
   653
	pull_in_requirements(trans, &rpi, &ppi);
krh@248
   654
krh@248
   655
	prop_iter_init(&rpi, &trans->upstream);
krh@248
   656
	prop_iter_init(&ppi, &trans->upstream);
krh@248
   657
	pull_in_requirements(trans, &rpi, &ppi);
krh@248
   658
}
krh@248
   659
krh@248
   660
static void
krh@248
   661
flush_scheduled_system_updates(struct razor_transaction *trans)
krh@248
   662
{
krh@248
   663
 	struct razor_package_iterator *pi;
krh@248
   664
 	struct razor_package *p, *pkg, *spkgs;
krh@248
   665
	struct prop_iter ppi;
richard@302
   666
	const char *name, *version;
krh@248
   667
krh@248
   668
	spkgs = trans->system.set->packages.data;
krh@248
   669
	pi = razor_package_iterator_create(trans->system.set);
krh@248
   670
	prop_iter_init(&ppi, &trans->upstream);
krh@248
   671
richard@302
   672
	while (razor_package_iterator_next(pi, &p,
richard@302
   673
					   RAZOR_DETAIL_NAME, &name,
richard@307
   674
					   RAZOR_DETAIL_VERSION, &version,
richard@307
   675
					   RAZOR_DETAIL_LAST)) {
krh@248
   676
		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
krh@248
   677
			continue;
krh@248
   678
krh@248
   679
		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
krh@248
   680
			continue;
krh@248
   681
krh@248
   682
		pkg = pick_matching_provider(trans->upstream.set, &ppi,
krh@248
   683
					     RAZOR_PROPERTY_GREATER, version);
krh@248
   684
		if (pkg == NULL)
krh@248
   685
			continue;
krh@248
   686
krh@248
   687
		fprintf(stderr, "updating %s-%s to %s-%s\n",
krh@248
   688
			name, version,
krh@248
   689
			&ppi.pool[pkg->name], &ppi.pool[pkg->version]);
krh@248
   690
krh@248
   691
		razor_transaction_remove_package(trans, p);
krh@248
   692
		razor_transaction_install_package(trans, pkg);
krh@248
   693
	}
krh@248
   694
krh@248
   695
	razor_package_iterator_destroy(pi);
krh@248
   696
}
krh@248
   697
krh@248
   698
static void
krh@248
   699
flush_scheduled_upstream_updates(struct razor_transaction *trans)
krh@248
   700
{
krh@248
   701
 	struct razor_package_iterator *pi;
krh@248
   702
 	struct razor_package *p, *upkgs;
krh@248
   703
	struct prop_iter spi;
richard@302
   704
	const char *name, *version;
krh@248
   705
krh@248
   706
	upkgs = trans->upstream.set->packages.data;
krh@248
   707
	pi = razor_package_iterator_create(trans->upstream.set);
krh@248
   708
	prop_iter_init(&spi, &trans->system);
krh@248
   709
richard@302
   710
	while (razor_package_iterator_next(pi, &p,
richard@302
   711
					   RAZOR_DETAIL_NAME, &name,
richard@307
   712
					   RAZOR_DETAIL_VERSION, &version,
richard@307
   713
					   RAZOR_DETAIL_LAST)) {
krh@248
   714
		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
krh@248
   715
			continue;
krh@248
   716
krh@248
   717
		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
krh@248
   718
			remove_matching_providers(trans,
krh@248
   719
						  &spi,
krh@248
   720
						  RAZOR_PROPERTY_LESS,
krh@248
   721
						  version);
krh@248
   722
		razor_transaction_install_package(trans, p);
krh@248
   723
		fprintf(stderr, "installing %s-%s\n", name, version);
krh@248
   724
	}
krh@248
   725
}
krh@248
   726
krh@269
   727
RAZOR_EXPORT int
krh@248
   728
razor_transaction_resolve(struct razor_transaction *trans)
krh@248
   729
{
krh@248
   730
	int last = 0;
krh@248
   731
krh@248
   732
	flush_scheduled_system_updates(trans);
krh@248
   733
	flush_scheduled_upstream_updates(trans);
krh@248
   734
krh@248
   735
	while (last < trans->changes) {
krh@248
   736
		last = trans->changes;
krh@248
   737
		remove_obsoleted_packages(trans);
krh@248
   738
		mark_all_satisfied_requires(trans);
krh@248
   739
		update_unsatisfied_packages(trans);
krh@248
   740
		update_conflicted_packages(trans);
krh@248
   741
		pull_in_all_requirements(trans);
krh@248
   742
		flush_scheduled_system_updates(trans);
krh@248
   743
		flush_scheduled_upstream_updates(trans);
krh@248
   744
	}
krh@248
   745
krh@248
   746
	return trans->changes;
krh@248
   747
}
krh@248
   748
krh@248
   749
static void
krh@248
   750
describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
krh@248
   751
{
krh@248
   752
	struct razor_package_iterator pi;
krh@248
   753
	struct razor_package *pkg;
krh@248
   754
	const char *name, *version, *arch, *pool;
krh@248
   755
krh@248
   756
	pool = set->string_pool.data;
krh@248
   757
	if (pool[rp->version] == '\0') {
krh@248
   758
		razor_package_iterator_init_for_property(&pi, set, rp);
krh@248
   759
		while (razor_package_iterator_next(&pi, &pkg,
richard@302
   760
						   RAZOR_DETAIL_NAME, &name,
richard@302
   761
						   RAZOR_DETAIL_VERSION, &version,
richard@307
   762
						   RAZOR_DETAIL_ARCH, &arch,
richard@307
   763
						   RAZOR_DETAIL_LAST))
krh@248
   764
			fprintf(stderr, "%s is needed by %s-%s.%s\n",
krh@248
   765
				&pool[rp->name],
krh@248
   766
				name, version, arch);
krh@248
   767
	} else {
krh@248
   768
		razor_package_iterator_init_for_property(&pi, set, rp);
krh@248
   769
		while (razor_package_iterator_next(&pi, &pkg,
richard@302
   770
						   RAZOR_DETAIL_NAME, &name,
richard@302
   771
						   RAZOR_DETAIL_VERSION, &version,
richard@307
   772
						   RAZOR_DETAIL_ARCH, &arch,
richard@307
   773
						   RAZOR_DETAIL_LAST))
krh@248
   774
			fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
krh@248
   775
				&pool[rp->name],
krh@248
   776
				razor_property_relation_to_string(rp),
krh@248
   777
				&pool[rp->version],
krh@248
   778
				name, version, arch);
krh@248
   779
	}
krh@248
   780
}
krh@248
   781
krh@269
   782
RAZOR_EXPORT int
krh@248
   783
razor_transaction_describe(struct razor_transaction *trans)
krh@248
   784
{
krh@248
   785
	struct prop_iter rpi;
krh@248
   786
	struct razor_property *rp;
krh@248
   787
	int unsatisfied;
krh@248
   788
krh@248
   789
	flush_scheduled_system_updates(trans);
krh@248
   790
	flush_scheduled_upstream_updates(trans);
krh@248
   791
	mark_all_satisfied_requires(trans);
krh@248
   792
krh@248
   793
	unsatisfied = 0;
krh@248
   794
	prop_iter_init(&rpi, &trans->system);
krh@248
   795
	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   796
		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
krh@248
   797
			describe_unsatisfied(trans->system.set, rp);
krh@248
   798
		        unsatisfied++;
krh@248
   799
		}
krh@248
   800
	}
krh@248
   801
krh@248
   802
	prop_iter_init(&rpi, &trans->upstream);
krh@248
   803
	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   804
		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
krh@248
   805
			describe_unsatisfied(trans->upstream.set, rp);
krh@248
   806
			unsatisfied++;
krh@248
   807
		}
krh@248
   808
	}
krh@248
   809
krh@248
   810
	return unsatisfied;
krh@248
   811
}
krh@248
   812
krh@269
   813
RAZOR_EXPORT int
krh@248
   814
razor_transaction_unsatisfied_property(struct razor_transaction *trans,
krh@248
   815
				       const char *name,
krh@248
   816
				       uint32_t flags,
krh@248
   817
				       const char *version)
krh@248
   818
{
krh@248
   819
	struct prop_iter pi;
krh@248
   820
	struct razor_property *p;
krh@248
   821
krh@248
   822
	prop_iter_init(&pi, &trans->system);
jbowes@284
   823
	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
krh@248
   824
		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
krh@248
   825
		    p->flags == flags &&
krh@248
   826
		    strcmp(&pi.pool[p->name], name) == 0 &&
krh@248
   827
		    strcmp(&pi.pool[p->version], version) == 0)
krh@248
   828
krh@248
   829
			return 1;
krh@248
   830
	}
krh@248
   831
krh@248
   832
	prop_iter_init(&pi, &trans->upstream);
jbowes@284
   833
	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
krh@248
   834
		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
krh@248
   835
		    p->flags == flags &&
krh@248
   836
		    strcmp(&pi.pool[p->name], name) == 0 &&
krh@248
   837
		    strcmp(&pi.pool[p->version], version) == 0)
krh@248
   838
krh@248
   839
			return 1;
krh@248
   840
	}
krh@248
   841
krh@248
   842
	return 0;
krh@248
   843
}
krh@248
   844
krh@269
   845
RAZOR_EXPORT struct razor_set *
krh@248
   846
razor_transaction_finish(struct razor_transaction *trans)
krh@248
   847
{
krh@248
   848
	struct razor_merger *merger;
krh@248
   849
	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
krh@248
   850
	char *upool, *spool;
krh@248
   851
	int cmp;
krh@248
   852
krh@248
   853
	s = trans->system.set->packages.data;
krh@248
   854
	spkgs = trans->system.set->packages.data;
krh@248
   855
	send = trans->system.set->packages.data +
krh@248
   856
		trans->system.set->packages.size;
krh@248
   857
	spool = trans->system.set->string_pool.data;
krh@248
   858
krh@248
   859
	u = trans->upstream.set->packages.data;
krh@248
   860
	upkgs = trans->upstream.set->packages.data;
krh@248
   861
	uend = trans->upstream.set->packages.data +
krh@248
   862
		trans->upstream.set->packages.size;
krh@248
   863
	upool = trans->upstream.set->string_pool.data;
krh@248
   864
krh@248
   865
	merger = razor_merger_create(trans->system.set, trans->upstream.set);
krh@248
   866
	while (s < send || u < uend) {
krh@248
   867
		if (s < send && u < uend)
krh@248
   868
			cmp = strcmp(&spool[s->name], &upool[u->name]);
krh@248
   869
		else if (s < send)
krh@248
   870
			cmp = -1;
krh@248
   871
		else
krh@248
   872
			cmp = 1;
krh@248
   873
krh@248
   874
		if (cmp < 0) {
krh@248
   875
			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   876
				razor_merger_add_package(merger, s);
krh@248
   877
			s++;
krh@248
   878
		} else if (cmp == 0) {
krh@248
   879
			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   880
				razor_merger_add_package(merger, s);
krh@248
   881
			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   882
				razor_merger_add_package(merger, u);
krh@248
   883
krh@248
   884
			s++;
krh@248
   885
			u++;
krh@248
   886
		} else {
krh@248
   887
			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   888
				razor_merger_add_package(merger, u);
krh@248
   889
			u++;
krh@248
   890
		}
krh@248
   891
	}
krh@248
   892
krh@248
   893
	razor_transaction_destroy(trans);
krh@248
   894
krh@248
   895
	return razor_merger_finish(merger);
krh@248
   896
}
krh@248
   897
krh@269
   898
RAZOR_EXPORT void
krh@248
   899
razor_transaction_destroy(struct razor_transaction *trans)
krh@248
   900
{
richard@301
   901
	assert (trans != NULL);
richard@301
   902
krh@248
   903
	transaction_set_release(&trans->system);
krh@248
   904
	transaction_set_release(&trans->upstream);
krh@248
   905
	free(trans);
krh@248
   906
}