librazor/transaction.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 23:13:09 2008 -0400 (2008-06-20)
changeset 257 0c3db660514d
parent 248 057933050c42
child 269 03fc85294bc9
permissions -rw-r--r--
When uniquifying properties, also sort them on the owning package.

This ensures that whenever two packages provide or (or require, obsolete
or conflict) the same property, they appear in the same order in the
propertys list of packages.
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>
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@248
   168
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@248
   187
void
krh@248
   188
razor_transaction_install_package(struct razor_transaction *trans,
krh@248
   189
				  struct razor_package *package)
krh@248
   190
{
krh@248
   191
	transaction_set_install_package(&trans->upstream, package);
krh@248
   192
	trans->changes++;
krh@248
   193
}
krh@248
   194
krh@248
   195
void
krh@248
   196
razor_transaction_remove_package(struct razor_transaction *trans,
krh@248
   197
				 struct razor_package *package)
krh@248
   198
{
krh@248
   199
	transaction_set_remove_package(&trans->system, package);
krh@248
   200
	trans->changes++;
krh@248
   201
}
krh@248
   202
krh@248
   203
void
krh@248
   204
razor_transaction_update_package(struct razor_transaction *trans,
krh@248
   205
				  struct razor_package *package)
krh@248
   206
{
krh@248
   207
	struct razor_package *spkgs, *upkgs, *end;
krh@248
   208
krh@248
   209
	spkgs = trans->system.set->packages.data;
krh@248
   210
	upkgs = trans->upstream.set->packages.data;
krh@248
   211
	end = trans->system.set->packages.data +
krh@248
   212
		trans->system.set->packages.size;
krh@248
   213
	if (spkgs <= package && package < end)
krh@248
   214
		trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
krh@248
   215
	else
krh@248
   216
		trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
krh@248
   217
}
krh@248
   218
krh@248
   219
struct prop_iter {
krh@248
   220
	struct razor_property *p, *start, *end;
krh@248
   221
	const char *pool;
krh@248
   222
	uint32_t *present;
krh@248
   223
};
krh@248
   224
krh@248
   225
static void
krh@248
   226
prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
krh@248
   227
{
krh@248
   228
	pi->p = ts->set->properties.data;
krh@248
   229
	pi->start = ts->set->properties.data;
krh@248
   230
	pi->end = ts->set->properties.data + ts->set->properties.size;
krh@248
   231
	pi->pool = ts->set->string_pool.data;
krh@248
   232
	pi->present = ts->properties;
krh@248
   233
}
krh@248
   234
krh@248
   235
static int
krh@248
   236
prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p)
krh@248
   237
{
krh@248
   238
	while (pi->p < pi->end) {
krh@248
   239
		if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
krh@248
   240
		    (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) {
krh@248
   241
			*p = pi->p++;
krh@248
   242
			return 1;
krh@248
   243
		}
krh@248
   244
		pi->p++;
krh@248
   245
	}
krh@248
   246
krh@248
   247
	return 0;
krh@248
   248
}
krh@248
   249
krh@248
   250
static struct razor_property *
krh@248
   251
prop_iter_seek_to(struct prop_iter *pi,
krh@248
   252
		  uint32_t flags, const char *match)
krh@248
   253
{
krh@248
   254
	uint32_t name;
krh@248
   255
krh@248
   256
	while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
krh@248
   257
		pi->p++;
krh@248
   258
krh@248
   259
	if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
krh@248
   260
		return NULL;
krh@248
   261
krh@248
   262
	name = pi->p->name;
krh@248
   263
	while (pi->p < pi->end &&
krh@248
   264
	       pi->p->name == name &&
krh@248
   265
	       (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags)
krh@248
   266
		pi->p++;
krh@248
   267
krh@248
   268
	if (pi->p == pi->end || pi->p->name != name)
krh@248
   269
		return NULL;
krh@248
   270
krh@248
   271
	return pi->p;
krh@248
   272
}
krh@248
   273
krh@248
   274
/* Remove packages from set that provide any of the matching (same
krh@248
   275
 * name and type) providers from ppi onwards that match the
krh@248
   276
 * requirement that rpi points to. */
krh@248
   277
static void
krh@248
   278
remove_matching_providers(struct razor_transaction *trans,
krh@248
   279
			  struct prop_iter *ppi,
krh@248
   280
			  uint32_t flags,
krh@248
   281
			  const char *version)
krh@248
   282
{
krh@248
   283
	struct razor_property *p;
krh@248
   284
	struct razor_package *pkg, *pkgs;
krh@248
   285
	struct razor_package_iterator pkg_iter;
krh@248
   286
	struct razor_set *set;
krh@248
   287
	const char *n, *v, *a;
krh@248
   288
	uint32_t type;
krh@248
   289
krh@248
   290
	if (ppi->present == trans->system.properties)
krh@248
   291
		set = trans->system.set;
krh@248
   292
	else
krh@248
   293
		set = trans->upstream.set;
krh@248
   294
krh@248
   295
	pkgs = (struct razor_package *) set->packages.data;
krh@248
   296
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   297
	for (p = ppi->p;
krh@248
   298
	     p < ppi->end &&
krh@248
   299
	     p->name == ppi->p->name &&
krh@248
   300
	     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
krh@248
   301
	     p++) {
krh@248
   302
		if (!ppi->present[p - ppi->start])
krh@248
   303
			continue;
krh@248
   304
		if (!provider_satisfies_requirement(p, ppi->pool,
krh@248
   305
						    flags, version))
krh@248
   306
			continue;
krh@248
   307
krh@248
   308
		razor_package_iterator_init_for_property(&pkg_iter, set, p);
krh@248
   309
		while (razor_package_iterator_next(&pkg_iter,
krh@248
   310
						   &pkg, &n, &v, &a)) {
krh@248
   311
			fprintf(stderr, "removing %s-%s\n", n, v);
krh@248
   312
			razor_transaction_remove_package(trans, pkg);
krh@248
   313
		}
krh@248
   314
	}
krh@248
   315
}
krh@248
   316
krh@248
   317
static void
krh@248
   318
flag_matching_providers(struct razor_transaction *trans,
krh@248
   319
			struct prop_iter *ppi,
krh@248
   320
			struct razor_property *r,
krh@248
   321
			struct prop_iter *rpi,
krh@248
   322
			unsigned int flag)
krh@248
   323
{
krh@248
   324
	struct razor_property *p;
krh@248
   325
	struct razor_package *pkg, *pkgs;
krh@248
   326
	struct razor_package_iterator pkg_iter;
krh@248
   327
	struct razor_set *set;
krh@248
   328
	const char *name, *version, *arch;
krh@248
   329
	uint32_t *flags, type;
krh@248
   330
krh@248
   331
	if (ppi->present == trans->system.properties) {
krh@248
   332
		set = trans->system.set;
krh@248
   333
		flags = trans->system.packages;
krh@248
   334
	} else {
krh@248
   335
		set = trans->upstream.set;
krh@248
   336
		flags = trans->upstream.packages;
krh@248
   337
	}
krh@248
   338
krh@248
   339
	pkgs = (struct razor_package *) set->packages.data;
krh@248
   340
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   341
	for (p = ppi->p;
krh@248
   342
	     p < ppi->end &&
krh@248
   343
		     p->name == ppi->p->name &&
krh@248
   344
		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
krh@248
   345
	     p++) {
krh@248
   346
		if (!ppi->present[p - ppi->start])
krh@248
   347
			continue;
krh@248
   348
		if (!provider_satisfies_requirement(p, ppi->pool,
krh@248
   349
						    r->flags,
krh@248
   350
						    &rpi->pool[r->version]))
krh@248
   351
			continue;
krh@248
   352
krh@248
   353
		razor_package_iterator_init_for_property(&pkg_iter, set, p);
krh@248
   354
		while (razor_package_iterator_next(&pkg_iter, &pkg,
krh@248
   355
						   &name, &version, &arch)) {
krh@248
   356
krh@248
   357
			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
krh@248
   358
				name, version,
krh@248
   359
				ppi->pool + p->name,
krh@248
   360
				rpi->pool + r->name,
krh@248
   361
				rpi->pool + r->version);
krh@248
   362
			flags[pkg - pkgs] |= flag;
krh@248
   363
		}
krh@248
   364
	}
krh@248
   365
}
krh@248
   366
krh@248
   367
static struct razor_package *
krh@248
   368
pick_matching_provider(struct razor_set *set,
krh@248
   369
		       struct prop_iter *ppi,
krh@248
   370
		       uint32_t flags,
krh@248
   371
		       const char *version)
krh@248
   372
{
krh@248
   373
	struct razor_property *p;
krh@248
   374
	struct razor_package *pkgs;
krh@248
   375
	struct list *i;
krh@248
   376
	uint32_t type;
krh@248
   377
krh@248
   378
	/* This is where we decide which pkgs to pull in to satisfy a
krh@248
   379
	 * requirement.  There may be several different providers
krh@248
   380
	 * (different versions) and each version of a provider may
krh@248
   381
	 * come from a number of packages.  We pick the first package
krh@248
   382
	 * from the first provider that matches. */
krh@248
   383
krh@248
   384
	pkgs = set->packages.data;
krh@248
   385
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   386
	for (p = ppi->p;
krh@248
   387
	     p < ppi->end &&
krh@248
   388
		     p->name == ppi->p->name &&
krh@248
   389
		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
krh@248
   390
		     ppi->present[p - ppi->start] == 0;
krh@248
   391
	     p++) {
krh@248
   392
		if (!provider_satisfies_requirement(p, ppi->pool,
krh@248
   393
						    flags, version))
krh@248
   394
			continue;
krh@248
   395
krh@248
   396
		i = list_first(&p->packages, &set->package_pool);
krh@248
   397
krh@248
   398
		return &pkgs[i->data];
krh@248
   399
	}
krh@248
   400
krh@248
   401
	return NULL;
krh@248
   402
}
krh@248
   403
krh@248
   404
static void
krh@248
   405
remove_obsoleted_packages(struct razor_transaction *trans)
krh@248
   406
{
krh@248
   407
	struct razor_property *up;
krh@248
   408
	struct razor_package *spkgs;
krh@248
   409
	struct prop_iter spi, upi;
krh@248
   410
krh@248
   411
	spkgs = trans->system.set->packages.data;
krh@248
   412
	prop_iter_init(&spi, &trans->system);
krh@248
   413
	prop_iter_init(&upi, &trans->upstream);
krh@248
   414
krh@248
   415
	while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
krh@248
   416
		if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
krh@248
   417
				       &upi.pool[up->name]))
krh@248
   418
			continue;
krh@248
   419
		remove_matching_providers(trans, &spi, up->flags,
krh@248
   420
					  &upi.pool[up->version]);
krh@248
   421
	}
krh@248
   422
}
krh@248
   423
krh@248
   424
static int
krh@248
   425
any_provider_satisfies_requirement(struct prop_iter *ppi,
krh@248
   426
				   uint32_t flags,
krh@248
   427
				   const char *version)
krh@248
   428
{
krh@248
   429
	struct razor_property *p;
krh@248
   430
	uint32_t type;
krh@248
   431
krh@248
   432
	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
krh@248
   433
	for (p = ppi->p;
krh@248
   434
	     p < ppi->end &&
krh@248
   435
		     p->name == ppi->p->name &&
krh@248
   436
		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
krh@248
   437
	     p++) {
krh@248
   438
		if (ppi->present[p - ppi->start] > 0 &&
krh@248
   439
		    provider_satisfies_requirement(p, ppi->pool,
krh@248
   440
						   flags, version))
krh@248
   441
			return 1;
krh@248
   442
	}
krh@248
   443
krh@248
   444
	return 0;
krh@248
   445
}
krh@248
   446
krh@248
   447
static void
krh@248
   448
clear_requires_flags(struct transaction_set *ts)
krh@248
   449
{
krh@248
   450
	struct razor_property *p;
krh@248
   451
	const char *pool;
krh@248
   452
	int i, count;
krh@248
   453
krh@248
   454
	count = ts->set->properties.size / sizeof *p;
krh@248
   455
	p = ts->set->properties.data;
krh@248
   456
	pool = ts->set->string_pool.data;
krh@248
   457
	for (i = 0; i < count; i++) {
krh@248
   458
		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
krh@248
   459
		if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
krh@248
   460
			ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
krh@248
   461
	}
krh@248
   462
}
krh@248
   463
krh@248
   464
const char *
krh@248
   465
razor_property_relation_to_string(struct razor_property *p)
krh@248
   466
{
krh@248
   467
	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
krh@248
   468
	case RAZOR_PROPERTY_LESS:
krh@248
   469
		return "<";
krh@248
   470
krh@248
   471
	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
krh@248
   472
		return "<=";
krh@248
   473
krh@248
   474
	case RAZOR_PROPERTY_EQUAL:
krh@248
   475
		return "=";
krh@248
   476
krh@248
   477
	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
krh@248
   478
		return ">=";
krh@248
   479
krh@248
   480
	case RAZOR_PROPERTY_GREATER:
krh@248
   481
		return ">";
krh@248
   482
krh@248
   483
	default:
krh@248
   484
		return "?";
krh@248
   485
	}
krh@248
   486
}
krh@248
   487
krh@248
   488
const char *
krh@248
   489
razor_property_type_to_string(struct razor_property *p)
krh@248
   490
{
krh@248
   491
	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
krh@248
   492
	case RAZOR_PROPERTY_REQUIRES:
krh@248
   493
		return "requires";
krh@248
   494
	case RAZOR_PROPERTY_PROVIDES:
krh@248
   495
		return "provides";
krh@248
   496
	case RAZOR_PROPERTY_CONFLICTS:
krh@248
   497
		return "conflicts";
krh@248
   498
	case RAZOR_PROPERTY_OBSOLETES:
krh@248
   499
		return "obsoletes";
krh@248
   500
	default:
krh@248
   501
		return NULL;
krh@248
   502
	}
krh@248
   503
}
krh@248
   504
krh@248
   505
static void
krh@248
   506
mark_satisfied_requires(struct razor_transaction *trans,
krh@248
   507
			struct transaction_set *rts,
krh@248
   508
			struct transaction_set *pts)
krh@248
   509
{
krh@248
   510
	struct prop_iter rpi, ppi;
krh@248
   511
	struct razor_property *rp;
krh@248
   512
krh@248
   513
	prop_iter_init(&rpi, rts);
krh@248
   514
	prop_iter_init(&ppi, pts);
krh@248
   515
krh@248
   516
	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   517
		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
krh@248
   518
				       &rpi.pool[rp->name]))
krh@248
   519
			continue;
krh@248
   520
krh@248
   521
		if (any_provider_satisfies_requirement(&ppi, rp->flags,
krh@248
   522
						       &rpi.pool[rp->version]))
krh@248
   523
			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
krh@248
   524
	}
krh@248
   525
}
krh@248
   526
krh@248
   527
static void
krh@248
   528
mark_all_satisfied_requires(struct razor_transaction *trans)
krh@248
   529
{
krh@248
   530
	clear_requires_flags(&trans->system);
krh@248
   531
	clear_requires_flags(&trans->upstream);
krh@248
   532
	mark_satisfied_requires(trans, &trans->system, &trans->system);
krh@248
   533
	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
krh@248
   534
	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
krh@248
   535
	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
krh@248
   536
}
krh@248
   537
krh@248
   538
static void
krh@248
   539
update_unsatisfied_packages(struct razor_transaction *trans)
krh@248
   540
{
krh@248
   541
	struct razor_package *spkgs, *pkg;
krh@248
   542
	struct razor_property *sp;
krh@248
   543
	struct prop_iter spi;
krh@248
   544
	struct razor_package_iterator pkg_iter;
krh@248
   545
	const char *name, *version, *arch;
krh@248
   546
krh@248
   547
	spkgs = trans->system.set->packages.data;
krh@248
   548
	prop_iter_init(&spi, &trans->system);
krh@248
   549
krh@248
   550
	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
krh@248
   551
		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
krh@248
   552
			continue;
krh@248
   553
krh@248
   554
		razor_package_iterator_init_for_property(&pkg_iter,
krh@248
   555
							 trans->system.set,
krh@248
   556
							 sp);
krh@248
   557
		while (razor_package_iterator_next(&pkg_iter, &pkg,
krh@248
   558
						   &name, &version, &arch)) {
krh@248
   559
			fprintf(stderr, "updating %s because %s %s %s "
krh@248
   560
				"isn't satisfied\n",
krh@248
   561
				name, spi.pool + sp->name,
krh@248
   562
				razor_property_relation_to_string(sp),
krh@248
   563
				spi.pool + sp->version);
krh@248
   564
			trans->system.packages[pkg - spkgs] |=
krh@248
   565
				TRANS_PACKAGE_UPDATE;
krh@248
   566
		}
krh@248
   567
	}
krh@248
   568
}
krh@248
   569
krh@248
   570
void
krh@248
   571
razor_transaction_update_all(struct razor_transaction *trans)
krh@248
   572
{
krh@248
   573
	struct razor_package *p;
krh@248
   574
	int i, count;
krh@248
   575
krh@248
   576
	count = trans->system.set->packages.size / sizeof *p;
krh@248
   577
	for (i = 0; i < count; i++)
krh@248
   578
		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
krh@248
   579
}
krh@248
   580
krh@248
   581
static void
krh@248
   582
update_conflicted_packages(struct razor_transaction *trans)
krh@248
   583
{
krh@248
   584
	struct razor_package *pkg, *spkgs;
krh@248
   585
	struct razor_property *up, *sp;
krh@248
   586
	struct prop_iter spi, upi;
krh@248
   587
	struct razor_package_iterator pkg_iter;
krh@248
   588
	const char *name, *version, *arch;
krh@248
   589
krh@248
   590
	spkgs = trans->system.set->packages.data;
krh@248
   591
	prop_iter_init(&spi, &trans->system);
krh@248
   592
	prop_iter_init(&upi, &trans->upstream);
krh@248
   593
krh@248
   594
	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
krh@248
   595
		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
krh@248
   596
				       &spi.pool[sp->name]))
krh@248
   597
			continue;
krh@248
   598
krh@248
   599
		if (!any_provider_satisfies_requirement(&upi, sp->flags,
krh@248
   600
							&spi.pool[sp->version]))
krh@248
   601
			continue;
krh@248
   602
krh@248
   603
		razor_package_iterator_init_for_property(&pkg_iter,
krh@248
   604
							 trans->system.set,
krh@248
   605
							 sp);
krh@248
   606
		while (razor_package_iterator_next(&pkg_iter, &pkg,
krh@248
   607
						   &name, &version, &arch)) {
krh@248
   608
			fprintf(stderr, "updating %s %s because it conflicts with %s",
krh@248
   609
				name, version, spi.pool + sp->name);
krh@248
   610
			trans->system.packages[pkg - spkgs] |=
krh@248
   611
				TRANS_PACKAGE_UPDATE;
krh@248
   612
		}
krh@248
   613
	}
krh@248
   614
krh@248
   615
	prop_iter_init(&spi, &trans->system);
krh@248
   616
	prop_iter_init(&upi, &trans->upstream);
krh@248
   617
krh@248
   618
	while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
krh@248
   619
		sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
krh@248
   620
				       &upi.pool[upi.p->name]);
krh@248
   621
krh@248
   622
		if (sp)
krh@248
   623
			flag_matching_providers(trans, &spi, up, &upi,
krh@248
   624
						TRANS_PACKAGE_UPDATE);
krh@248
   625
	}
krh@248
   626
}
krh@248
   627
krh@248
   628
static void
krh@248
   629
pull_in_requirements(struct razor_transaction *trans,
krh@248
   630
		     struct prop_iter *rpi, struct prop_iter *ppi)
krh@248
   631
{
krh@248
   632
	struct razor_property *rp, *pp;
krh@248
   633
	struct razor_package *pkg, *upkgs;
krh@248
   634
krh@248
   635
	upkgs = trans->upstream.set->packages.data;
krh@248
   636
	while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   637
		if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
krh@248
   638
			continue;
krh@248
   639
krh@248
   640
		pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
krh@248
   641
				       &rpi->pool[rp->name]);
krh@248
   642
		if (pp == NULL)
krh@248
   643
			continue;
krh@248
   644
		pkg = pick_matching_provider(trans->upstream.set,
krh@248
   645
					     ppi, rp->flags,
krh@248
   646
					     &rpi->pool[rp->version]);
krh@248
   647
		if (pkg == NULL)
krh@248
   648
			continue;
krh@248
   649
krh@248
   650
		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
krh@248
   651
krh@257
   652
		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
krh@248
   653
			"to satisfy %s %s %s\n",
krh@248
   654
			ppi->pool + pkg->name,
krh@257
   655
			ppi->pool + pkg->version,
krh@257
   656
			ppi->pool + pkg->arch,
krh@248
   657
			ppi->pool + pp->name,
krh@248
   658
			razor_property_relation_to_string(pp),
krh@248
   659
			ppi->pool + pp->version,
krh@248
   660
			&rpi->pool[rp->name],
krh@248
   661
			razor_property_relation_to_string(rp),
krh@248
   662
			&rpi->pool[rp->version]);
krh@248
   663
krh@248
   664
		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
krh@248
   665
	}
krh@248
   666
}
krh@248
   667
krh@248
   668
static void
krh@248
   669
pull_in_all_requirements(struct razor_transaction *trans)
krh@248
   670
{
krh@248
   671
	struct prop_iter rpi, ppi;
krh@248
   672
krh@248
   673
	prop_iter_init(&rpi, &trans->system);
krh@248
   674
	prop_iter_init(&ppi, &trans->upstream);
krh@248
   675
	pull_in_requirements(trans, &rpi, &ppi);
krh@248
   676
krh@248
   677
	prop_iter_init(&rpi, &trans->upstream);
krh@248
   678
	prop_iter_init(&ppi, &trans->upstream);
krh@248
   679
	pull_in_requirements(trans, &rpi, &ppi);
krh@248
   680
}
krh@248
   681
krh@248
   682
static void
krh@248
   683
flush_scheduled_system_updates(struct razor_transaction *trans)
krh@248
   684
{
krh@248
   685
 	struct razor_package_iterator *pi;
krh@248
   686
 	struct razor_package *p, *pkg, *spkgs;
krh@248
   687
	struct prop_iter ppi;
krh@248
   688
	const char *name, *version, *arch;
krh@248
   689
krh@248
   690
	spkgs = trans->system.set->packages.data;
krh@248
   691
	pi = razor_package_iterator_create(trans->system.set);
krh@248
   692
	prop_iter_init(&ppi, &trans->upstream);
krh@248
   693
krh@248
   694
	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
krh@248
   695
		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
krh@248
   696
			continue;
krh@248
   697
krh@248
   698
		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
krh@248
   699
			continue;
krh@248
   700
krh@248
   701
		pkg = pick_matching_provider(trans->upstream.set, &ppi,
krh@248
   702
					     RAZOR_PROPERTY_GREATER, version);
krh@248
   703
		if (pkg == NULL)
krh@248
   704
			continue;
krh@248
   705
krh@248
   706
		fprintf(stderr, "updating %s-%s to %s-%s\n",
krh@248
   707
			name, version,
krh@248
   708
			&ppi.pool[pkg->name], &ppi.pool[pkg->version]);
krh@248
   709
krh@248
   710
		razor_transaction_remove_package(trans, p);
krh@248
   711
		razor_transaction_install_package(trans, pkg);
krh@248
   712
	}
krh@248
   713
krh@248
   714
	razor_package_iterator_destroy(pi);
krh@248
   715
}
krh@248
   716
krh@248
   717
static void
krh@248
   718
flush_scheduled_upstream_updates(struct razor_transaction *trans)
krh@248
   719
{
krh@248
   720
 	struct razor_package_iterator *pi;
krh@248
   721
 	struct razor_package *p, *upkgs;
krh@248
   722
	struct prop_iter spi;
krh@248
   723
	const char *name, *version, *arch;
krh@248
   724
krh@248
   725
	upkgs = trans->upstream.set->packages.data;
krh@248
   726
	pi = razor_package_iterator_create(trans->upstream.set);
krh@248
   727
	prop_iter_init(&spi, &trans->system);
krh@248
   728
krh@248
   729
	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
krh@248
   730
		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
krh@248
   731
			continue;
krh@248
   732
krh@248
   733
		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
krh@248
   734
			remove_matching_providers(trans,
krh@248
   735
						  &spi,
krh@248
   736
						  RAZOR_PROPERTY_LESS,
krh@248
   737
						  version);
krh@248
   738
		razor_transaction_install_package(trans, p);
krh@248
   739
		fprintf(stderr, "installing %s-%s\n", name, version);
krh@248
   740
	}
krh@248
   741
}
krh@248
   742
krh@248
   743
int
krh@248
   744
razor_transaction_resolve(struct razor_transaction *trans)
krh@248
   745
{
krh@248
   746
	int last = 0;
krh@248
   747
krh@248
   748
	flush_scheduled_system_updates(trans);
krh@248
   749
	flush_scheduled_upstream_updates(trans);
krh@248
   750
krh@248
   751
	while (last < trans->changes) {
krh@248
   752
		last = trans->changes;
krh@248
   753
		remove_obsoleted_packages(trans);
krh@248
   754
		mark_all_satisfied_requires(trans);
krh@248
   755
		update_unsatisfied_packages(trans);
krh@248
   756
		update_conflicted_packages(trans);
krh@248
   757
		pull_in_all_requirements(trans);
krh@248
   758
		flush_scheduled_system_updates(trans);
krh@248
   759
		flush_scheduled_upstream_updates(trans);
krh@248
   760
	}
krh@248
   761
krh@248
   762
	return trans->changes;
krh@248
   763
}
krh@248
   764
krh@248
   765
static void
krh@248
   766
describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
krh@248
   767
{
krh@248
   768
	struct razor_package_iterator pi;
krh@248
   769
	struct razor_package *pkg;
krh@248
   770
	const char *name, *version, *arch, *pool;
krh@248
   771
krh@248
   772
	pool = set->string_pool.data;
krh@248
   773
	if (pool[rp->version] == '\0') {
krh@248
   774
		razor_package_iterator_init_for_property(&pi, set, rp);
krh@248
   775
		while (razor_package_iterator_next(&pi, &pkg,
krh@248
   776
						   &name, &version, &arch))
krh@248
   777
			fprintf(stderr, "%s is needed by %s-%s.%s\n",
krh@248
   778
				&pool[rp->name],
krh@248
   779
				name, version, arch);
krh@248
   780
	} else {
krh@248
   781
		razor_package_iterator_init_for_property(&pi, set, rp);
krh@248
   782
		while (razor_package_iterator_next(&pi, &pkg,
krh@248
   783
						   &name, &version, &arch))
krh@248
   784
			fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
krh@248
   785
				&pool[rp->name],
krh@248
   786
				razor_property_relation_to_string(rp),
krh@248
   787
				&pool[rp->version],
krh@248
   788
				name, version, arch);
krh@248
   789
	}
krh@248
   790
}
krh@248
   791
krh@248
   792
int
krh@248
   793
razor_transaction_describe(struct razor_transaction *trans)
krh@248
   794
{
krh@248
   795
	struct prop_iter rpi;
krh@248
   796
	struct razor_property *rp;
krh@248
   797
	int unsatisfied;
krh@248
   798
krh@248
   799
	flush_scheduled_system_updates(trans);
krh@248
   800
	flush_scheduled_upstream_updates(trans);
krh@248
   801
	mark_all_satisfied_requires(trans);
krh@248
   802
krh@248
   803
	unsatisfied = 0;
krh@248
   804
	prop_iter_init(&rpi, &trans->system);
krh@248
   805
	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   806
		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
krh@248
   807
			describe_unsatisfied(trans->system.set, rp);
krh@248
   808
		        unsatisfied++;
krh@248
   809
		}
krh@248
   810
	}
krh@248
   811
krh@248
   812
	prop_iter_init(&rpi, &trans->upstream);
krh@248
   813
	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
krh@248
   814
		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
krh@248
   815
			describe_unsatisfied(trans->upstream.set, rp);
krh@248
   816
			unsatisfied++;
krh@248
   817
		}
krh@248
   818
	}
krh@248
   819
krh@248
   820
	return unsatisfied;
krh@248
   821
}
krh@248
   822
krh@248
   823
int
krh@248
   824
razor_transaction_unsatisfied_property(struct razor_transaction *trans,
krh@248
   825
				       const char *name,
krh@248
   826
				       uint32_t flags,
krh@248
   827
				       const char *version)
krh@248
   828
{
krh@248
   829
	struct prop_iter pi;
krh@248
   830
	struct razor_property *p;
krh@248
   831
krh@248
   832
	prop_iter_init(&pi, &trans->system);
krh@248
   833
	while (prop_iter_next(&pi, flags, &p)) {
krh@248
   834
		if (!(trans->system.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
	prop_iter_init(&pi, &trans->upstream);
krh@248
   843
	while (prop_iter_next(&pi, flags, &p)) {
krh@248
   844
		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
krh@248
   845
		    p->flags == flags &&
krh@248
   846
		    strcmp(&pi.pool[p->name], name) == 0 &&
krh@248
   847
		    strcmp(&pi.pool[p->version], version) == 0)
krh@248
   848
krh@248
   849
			return 1;
krh@248
   850
	}
krh@248
   851
krh@248
   852
	return 0;
krh@248
   853
}
krh@248
   854
krh@248
   855
struct razor_set *
krh@248
   856
razor_transaction_finish(struct razor_transaction *trans)
krh@248
   857
{
krh@248
   858
	struct razor_merger *merger;
krh@248
   859
	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
krh@248
   860
	char *upool, *spool;
krh@248
   861
	int cmp;
krh@248
   862
krh@248
   863
	s = trans->system.set->packages.data;
krh@248
   864
	spkgs = trans->system.set->packages.data;
krh@248
   865
	send = trans->system.set->packages.data +
krh@248
   866
		trans->system.set->packages.size;
krh@248
   867
	spool = trans->system.set->string_pool.data;
krh@248
   868
krh@248
   869
	u = trans->upstream.set->packages.data;
krh@248
   870
	upkgs = trans->upstream.set->packages.data;
krh@248
   871
	uend = trans->upstream.set->packages.data +
krh@248
   872
		trans->upstream.set->packages.size;
krh@248
   873
	upool = trans->upstream.set->string_pool.data;
krh@248
   874
krh@248
   875
	merger = razor_merger_create(trans->system.set, trans->upstream.set);
krh@248
   876
	while (s < send || u < uend) {
krh@248
   877
		if (s < send && u < uend)
krh@248
   878
			cmp = strcmp(&spool[s->name], &upool[u->name]);
krh@248
   879
		else if (s < send)
krh@248
   880
			cmp = -1;
krh@248
   881
		else
krh@248
   882
			cmp = 1;
krh@248
   883
krh@248
   884
		if (cmp < 0) {
krh@248
   885
			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   886
				razor_merger_add_package(merger, s);
krh@248
   887
			s++;
krh@248
   888
		} else if (cmp == 0) {
krh@248
   889
			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   890
				razor_merger_add_package(merger, s);
krh@248
   891
			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   892
				razor_merger_add_package(merger, u);
krh@248
   893
krh@248
   894
			s++;
krh@248
   895
			u++;
krh@248
   896
		} else {
krh@248
   897
			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
krh@248
   898
				razor_merger_add_package(merger, u);
krh@248
   899
			u++;
krh@248
   900
		}
krh@248
   901
	}
krh@248
   902
krh@248
   903
	razor_transaction_destroy(trans);
krh@248
   904
krh@248
   905
	return razor_merger_finish(merger);
krh@248
   906
}
krh@248
   907
krh@248
   908
void
krh@248
   909
razor_transaction_destroy(struct razor_transaction *trans)
krh@248
   910
{
krh@248
   911
	transaction_set_release(&trans->system);
krh@248
   912
	transaction_set_release(&trans->upstream);
krh@248
   913
	free(trans);
krh@248
   914
}