librazor/transaction.c
author James Bowes <jbowes@redhat.com>
Wed Jul 09 10:11:13 2008 -0400 (2008-07-09)
changeset 318 829d6711b316
parent 304 bf23ba00db03
child 331 890a49fb2c71
permissions -rw-r--r--
Use strings to identify section types in the on-disk repo format.

Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).

This will allow for razor files to contain arbitrary sections.

For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".

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