razor.c
changeset 137 4722cd3437cb
parent 134 a3672fc689b7
child 138 49deac048d07
     1.1 --- a/razor.c	Tue Feb 26 16:39:01 2008 -0500
     1.2 +++ b/razor.c	Fri Feb 29 11:53:15 2008 -0500
     1.3 @@ -382,7 +382,7 @@
     1.4  		__qsort_with_data(end, right, mend, ctx);
     1.5  }
     1.6  
     1.7 -uint32_t *
     1.8 +static uint32_t *
     1.9  qsort_with_data(void *base, size_t nelem, size_t size,
    1.10  		compare_with_data_func_t compare, void *data)
    1.11  {
    1.12 @@ -758,7 +758,7 @@
    1.13  	struct list *index;
    1.14  };
    1.15  
    1.16 -struct razor_package_iterator *
    1.17 +static struct razor_package_iterator *
    1.18  razor_package_iterator_create_with_index(struct razor_set *set,
    1.19  					 struct list *index)
    1.20  {
    1.21 @@ -1231,53 +1231,6 @@
    1.22  	}
    1.23  }
    1.24  
    1.25 -
    1.26 -/* Build the new package list sorted by merging the two package lists.
    1.27 - * Build new string pool as we go. */
    1.28 -static void
    1.29 -merge_packages(struct razor_merger *merger, struct array *packages)
    1.30 -{
    1.31 -	struct razor_package *upstream_packages, *p, *s, *send;
    1.32 -	struct source *source1, *source2;
    1.33 -	char *spool, *upool;
    1.34 -	uint32_t *u, *uend;
    1.35 -	int cmp;
    1.36 -
    1.37 -	source1 = &merger->source1;
    1.38 -	source2 = &merger->source2;
    1.39 -	upstream_packages = source2->set->packages.data;
    1.40 -
    1.41 -	u = packages->data;
    1.42 -	uend = packages->data + packages->size;
    1.43 -	upool = source2->set->string_pool.data;
    1.44 -
    1.45 -	s = source1->set->packages.data;
    1.46 -	send = source1->set->packages.data + source1->set->packages.size;
    1.47 -	spool = source1->set->string_pool.data;
    1.48 -
    1.49 -	while (s < send || u < uend) {
    1.50 -		p = upstream_packages + *u;
    1.51 -
    1.52 -		if (s < send && u < uend)
    1.53 -			cmp = strcmp(&spool[s->name], &upool[p->name]);
    1.54 -		else if (s < send)
    1.55 -			cmp = -1;
    1.56 -		else
    1.57 -			cmp = 1;
    1.58 -		if (cmp < 0) {
    1.59 -			add_package(merger, s, source1, 0);
    1.60 -			s++;
    1.61 -		} else if (cmp == 0) {
    1.62 -			add_package(merger, p, source2, UPSTREAM_SOURCE);
    1.63 -			s++;
    1.64 -			u++;
    1.65 -		} else {
    1.66 -			add_package(merger, p, source2, UPSTREAM_SOURCE);
    1.67 -			u++;
    1.68 -		}
    1.69 -	}
    1.70 -}
    1.71 -
    1.72  static uint32_t
    1.73  add_property(struct razor_merger *merger,
    1.74  	     const char *name, enum razor_version_relation relation,
    1.75 @@ -1648,7 +1601,7 @@
    1.76  	free(pkgs);
    1.77  }
    1.78  
    1.79 -struct razor_set *
    1.80 +static struct razor_set *
    1.81  razor_merger_finish(struct razor_merger *merger)
    1.82  {
    1.83  	struct razor_set *result;
    1.84 @@ -1698,112 +1651,58 @@
    1.85  	return result;
    1.86  }
    1.87  
    1.88 -/* Add packages from 'upstream' to 'set'.  The packages to add are
    1.89 - * specified by the 'packages' array, which is a sorted list of
    1.90 - * package indexes.  Returns a newly allocated package set.  Does not
    1.91 - * enforce validity of the resulting package set.
    1.92 - *
    1.93 - * This looks more complicated than it is.  An easy way to merge two
    1.94 - * package sets would be to just use a razor_importer, but that
    1.95 - * requires resorting, and is thus O(n log n).  We can do this in a
    1.96 - * linear sweep, but it gets a little more complicated.
    1.97 - */
    1.98 -struct razor_set *
    1.99 -razor_set_add(struct razor_set *set, struct razor_set *upstream,
   1.100 -	      struct array *packages)
   1.101 -{
   1.102 -	struct razor_merger *merger;
   1.103 -
   1.104 -	merger = razor_merger_create(set, upstream);
   1.105 -
   1.106 -	merge_packages(merger, packages);
   1.107 -
   1.108 -	return razor_merger_finish(merger);
   1.109 -}
   1.110 -
   1.111 -void
   1.112 -razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
   1.113 -		  struct razor_set *upstream, struct array *list)
   1.114 -{
   1.115 -	struct razor_property *requires, *r;
   1.116 -	struct razor_property *p, *pend;
   1.117 -	uint32_t *u, *end, *pkg;
   1.118 -	struct array *package_pool;
   1.119 -	char *pool, *upool;
   1.120 -
   1.121 -	end = unsatisfied->data + unsatisfied->size;
   1.122 -	requires = set->properties.data;
   1.123 -	pool = set->string_pool.data;
   1.124 -
   1.125 -	p = upstream->properties.data;
   1.126 -	pend = upstream->properties.data + upstream->properties.size;
   1.127 -	upool = upstream->string_pool.data;
   1.128 -	package_pool = &upstream->package_pool;
   1.129 -
   1.130 -	u = unsatisfied->data;
   1.131 -	while (u < end) {
   1.132 -		r = requires + *u;
   1.133 -
   1.134 -		while (p < pend &&
   1.135 -		       p->type != RAZOR_PROPERTY_PROVIDES &&
   1.136 -		       strcmp(&pool[r->name], &upool[p->name]) > 0)
   1.137 -			p++;
   1.138 -		/* If there is more than one version of a provides,
   1.139 -		 * seek to the end for the highest version. */
   1.140 -		while (p + 1 < pend && p->name == (p + 1)->name && p->type == (p + 1)->type)
   1.141 -			p++;
   1.142 -
   1.143 -		if (p != pend &&
   1.144 -		    p->type == RAZOR_PROPERTY_PROVIDES &&
   1.145 -		    strcmp(&pool[r->name], &upool[p->name]) == 0 &&
   1.146 -		    versioncmp(&pool[r->version], &upool[p->version]) <= 0) {
   1.147 -			pkg = array_add(list, sizeof *pkg);
   1.148 -			/* We just pull in the first package that provides */
   1.149 -			*pkg = list_first(&p->packages, package_pool)->data;
   1.150 -
   1.151 -			/* Remove this from the unsatisfied list */
   1.152 -			memmove (u, u + 1, end - (u + 1));
   1.153 -			end--;
   1.154 -		} else {
   1.155 -			/* Leave this in the unsatisfied list */
   1.156 -			u++;
   1.157 -		}
   1.158 -	}
   1.159 -	unsatisfied->size = (void *)end - unsatisfied->data;
   1.160 -}
   1.161 -
   1.162 -static void
   1.163 -find_packages(struct razor_set *set,
   1.164 -	      int count, const char **package_names, struct array *list)
   1.165 +static int
   1.166 +find_packages(struct razor_set *set, int count, const char **package_names,
   1.167 +	      struct array *package_array,
   1.168 +	      enum razor_transaction_package_state state)
   1.169  {
   1.170  	struct razor_package_iterator *pi;
   1.171  	struct razor_package *p, *packages;
   1.172  	const char *name, *version;
   1.173 -	uint32_t *r;
   1.174 -	int i;
   1.175 +	struct razor_transaction_package *tp;
   1.176 +	int i, *found, errors = 0;
   1.177  
   1.178  	packages = (struct razor_package *) set->packages.data;
   1.179  	pi = razor_package_iterator_create(set);
   1.180 +	found = zalloc(count * sizeof (int));
   1.181  
   1.182  	while (razor_package_iterator_next(pi, &p, &name, &version)) {
   1.183  		for (i = 0; i < count; i++) {
   1.184  			if (strcmp(name, package_names[i]) == 0) {
   1.185 -				r = array_add(list, sizeof *r);
   1.186 -				*r = p - packages;
   1.187 +				found[i] = 1;
   1.188 +				tp = array_add(package_array, sizeof *tp);
   1.189 +				memset(tp, 0, sizeof *tp);
   1.190 +				tp->package = p;
   1.191 +				tp->name = name;
   1.192 +				tp->version = version;
   1.193 +				tp->state = state;
   1.194  				break;
   1.195  			}
   1.196  		}
   1.197  	}
   1.198  
   1.199 +	for (i = 0; i < count; i++) {
   1.200 +		if (!found[i]) {
   1.201 +			tp = array_add(package_array, sizeof *tp);
   1.202 +			memset(tp, 0, sizeof *tp);
   1.203 +			tp->name = strdup(package_names[i]);
   1.204 +			tp->state = state | RAZOR_PACKAGE_UNAVAILABLE;
   1.205 +			errors++;
   1.206 +		}
   1.207 +	}
   1.208 +
   1.209  	razor_package_iterator_destroy(pi);
   1.210 +	free(found);
   1.211 +
   1.212 +	return errors;
   1.213  }
   1.214  
   1.215  static void
   1.216  find_all_packages(struct razor_set *set,
   1.217 -		  struct razor_set *upstream, struct array *list)
   1.218 +		  struct razor_set *upstream, struct array *package_array)
   1.219  {
   1.220 +	struct razor_transaction_package *tp;
   1.221  	struct razor_package *p, *u, *pend, *uend;
   1.222 -	uint32_t *r;
   1.223  	char *pool, *upool;
   1.224  
   1.225  	pend = set->packages.data + set->packages.size;
   1.226 @@ -1816,25 +1715,89 @@
   1.227  		while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
   1.228  			u++;
   1.229  		if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
   1.230 -			r = array_add(list, sizeof *r);
   1.231 -			*r = u - (struct razor_package *) upstream->packages.data;
   1.232 +			tp = array_add(package_array, sizeof *tp);
   1.233 +			memset(tp, 0, sizeof *tp);
   1.234 +			tp->name = &upool[u->name];
   1.235 +			tp->version = &upool[u->version];
   1.236 +			tp->state = RAZOR_PACKAGE_INSTALL;
   1.237  		}
   1.238  	}
   1.239  }
   1.240  
   1.241 +/* FIXME: wrong, need to compare names, not razor_package* */
   1.242  static int
   1.243 -find_provider(struct razor_set *set, const char *req_name,
   1.244 -	      enum razor_version_relation relation, const char *version)
   1.245 +find_transaction_package(struct array *package_array,
   1.246 +			 struct razor_package *package)
   1.247 +{
   1.248 +	struct razor_transaction_package *tps = package_array->data;
   1.249 +	int i, tpcount = package_array->size / sizeof *tps;
   1.250 +
   1.251 +	for (i = 0; i < tpcount; i++) {
   1.252 +		if (tps[i].package == package)
   1.253 +			return i;
   1.254 +	}
   1.255 +	return -1;
   1.256 +}
   1.257 +
   1.258 +static int
   1.259 +provider_satisfies_requirement(struct razor_property *provider,
   1.260 +			       const char *provider_strings,
   1.261 +			       struct razor_property *requirement,
   1.262 +			       const char *requirement_strings)
   1.263 +{
   1.264 +	int cmp, len;
   1.265 +	const char *provided = &provider_strings[provider->version];
   1.266 +	const char *required = &requirement_strings[requirement->version];
   1.267 +
   1.268 +	if (!*required)
   1.269 +		return 1;
   1.270 +
   1.271 +	cmp = versioncmp(provided, required);
   1.272 +
   1.273 +	switch (requirement->relation) {
   1.274 +	case RAZOR_VERSION_LESS:
   1.275 +		return cmp < 0;
   1.276 +
   1.277 +	case RAZOR_VERSION_LESS_OR_EQUAL:
   1.278 +		if (cmp <= 0)
   1.279 +			return 1;
   1.280 +		/* fall through: FIXME, make sure this is correct */
   1.281 +
   1.282 +	case RAZOR_VERSION_EQUAL:
   1.283 +		if (cmp == 0)
   1.284 +			return 1;
   1.285 +
   1.286 +		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
   1.287 +		len = strlen(required);
   1.288 +		if (!strncmp(required, provided, len) && provided[len] == '-')
   1.289 +			return 1;
   1.290 +		return 0;
   1.291 +
   1.292 +	case RAZOR_VERSION_GREATER_OR_EQUAL:
   1.293 +		return cmp >= 0;
   1.294 +
   1.295 +	case RAZOR_VERSION_GREATER:
   1.296 +		return cmp > 0;
   1.297 +	}
   1.298 +
   1.299 +	/* shouldn't happen */
   1.300 +	return 0;
   1.301 +}
   1.302 +
   1.303 +static int
   1.304 +find_provider(struct razor_set *set, struct razor_property *requirement,
   1.305 +	      const char *requirement_strings)
   1.306  {
   1.307  	struct razor_property *props = set->properties.data;
   1.308 -	int p, hi, lo, cmp, pkg;
   1.309 +	int p, hi, lo, cmp;
   1.310  	char *pool = set->string_pool.data;
   1.311  
   1.312  	lo = 0;
   1.313  	hi = set->properties.size / sizeof *props;
   1.314  	while (lo < hi) {
   1.315  		p = (lo + hi) / 2;
   1.316 -		cmp = strcmp(&pool[props[p].name], req_name);
   1.317 +		cmp = strcmp(&pool[props[p].name],
   1.318 +			     &requirement_strings[requirement->name]);
   1.319  		if (cmp < 0)
   1.320  			lo = p + 1;
   1.321  		else if (cmp > 0)
   1.322 @@ -1868,35 +1831,9 @@
   1.323  		return -1;
   1.324  
   1.325  	do {
   1.326 -		pkg = list_first(&props[p].packages, &set->package_pool)->data;
   1.327 -		if (!*version)
   1.328 -			return pkg;
   1.329 -
   1.330 -		cmp = versioncmp(&pool[props[p].version], version);
   1.331 -
   1.332 -		switch (relation) {
   1.333 -		case RAZOR_VERSION_EQUAL:
   1.334 -		case RAZOR_VERSION_GREATER_OR_EQUAL:
   1.335 -		case RAZOR_VERSION_GREATER:
   1.336 -			if (cmp >= 0)
   1.337 -				return pkg;
   1.338 -			else {
   1.339 -				/* If the highest version doesn't pass,
   1.340 -				 * none of the others will either.
   1.341 -				 */
   1.342 -				return -1;
   1.343 -			}
   1.344 -
   1.345 -		case RAZOR_VERSION_LESS_OR_EQUAL:
   1.346 -			if (cmp <= 0)
   1.347 -				return pkg;
   1.348 -			break;
   1.349 -
   1.350 -		case RAZOR_VERSION_LESS:
   1.351 -			if (cmp < 0)
   1.352 -				return pkg;
   1.353 -			break;
   1.354 -		}
   1.355 +		if (provider_satisfies_requirement(&props[p], pool,
   1.356 +						   requirement, requirement_strings))
   1.357 +			return list_first(&props[p].packages, &set->package_pool)->data;
   1.358  
   1.359  		p--;
   1.360  	} while (p > lo && props[p].name == props[p + 1].name &&
   1.361 @@ -1921,78 +1858,79 @@
   1.362  		if (!strncmp(&upool[prop->name], "rpmlib(", 7))
   1.363  			continue;
   1.364  
   1.365 -		if (find_provider(system, &upool[prop->name],
   1.366 -				  prop->relation, &upool[prop->version]) == -1) {
   1.367 +		if (find_provider(system, prop, upool) == -1) {
   1.368  			new = array_add(new_requires, sizeof *new);
   1.369  			*new = p->data;
   1.370  		}
   1.371  	}
   1.372  }
   1.373  
   1.374 -struct razor_set *
   1.375 -razor_set_update(struct razor_set *set, struct razor_set *upstream,
   1.376 -		 int count, const char **packages)
   1.377 +static void
   1.378 +razor_transaction_satisfy_installs(struct razor_transaction *trans,
   1.379 +				   struct array *package_array,
   1.380 +				   int start, int end)
   1.381  {
   1.382 -	struct razor_set *new_set;
   1.383 -	struct array list;
   1.384  	struct razor_package *pkgs;
   1.385 -	int update_count, u, provider, already;
   1.386 -	uint32_t *update, *new, *new_end, *required;
   1.387 +	struct razor_transaction_package *packages, *tp;
   1.388 +	int p, provider, already;
   1.389 +	uint32_t *new, *new_end;
   1.390  	struct razor_property *props, *prop_end;
   1.391  	struct array new_requires;
   1.392  	char *pool;
   1.393  
   1.394 -	pkgs = upstream->packages.data;
   1.395 -	props = upstream->properties.data;
   1.396 -	prop_end = upstream->properties.data + set->properties.size;
   1.397 -	pool = upstream->string_pool.data;
   1.398 +	pkgs = trans->upstream->packages.data;
   1.399 +	props = trans->upstream->properties.data;
   1.400 +	prop_end = trans->upstream->properties.data + trans->upstream->properties.size;
   1.401 +	pool = trans->upstream->string_pool.data;
   1.402  
   1.403 -	array_init(&list);
   1.404 -	if (count > 0)
   1.405 -		find_packages(upstream, count, packages, &list);
   1.406 -	else
   1.407 -		find_all_packages(set, upstream, &list);
   1.408 +	packages = package_array->data;
   1.409 +	for (p = start; p < end; p++) {
   1.410 +		if (packages[p].state != RAZOR_PACKAGE_INSTALL)
   1.411 +			continue;
   1.412  
   1.413 -	update = list.data;
   1.414 -	update_count = list.size / sizeof (uint32_t);
   1.415 -	u = 0;
   1.416 -	while (u < update_count) {
   1.417  		array_init(&new_requires);
   1.418 -		for (; u < update_count; u++)
   1.419 -			gather_new_requires(set, upstream, &pkgs[update[u]], &new_requires);
   1.420 +		gather_new_requires(trans->system, trans->upstream,
   1.421 +				    packages[p].package, &new_requires);
   1.422  
   1.423  		new_end = new_requires.data + new_requires.size;
   1.424  		for (new = new_requires.data; new < new_end; new++) {
   1.425 -			provider = find_provider(upstream, &pool[props[*new].name],
   1.426 -						 props[*new].relation,
   1.427 -						 &pool[props[*new].version]);
   1.428 -
   1.429  			/* FIXME */
   1.430 -			if (provider == -1)
   1.431 +			if (pool[props[*new].name] == '/')
   1.432  				continue;
   1.433  
   1.434 -			update = list.data;
   1.435 -			update_count = list.size / sizeof (uint32_t);
   1.436 -			for (already = 0; already < update_count; already++) {
   1.437 -				if (provider == update[already])
   1.438 -					break;
   1.439 -			}
   1.440 -			if (already < update_count)
   1.441 +			provider = find_provider(trans->upstream,
   1.442 +						 &props[*new], pool);
   1.443 +			already = find_transaction_package(package_array,
   1.444 +							   &pkgs[provider]);
   1.445 +			if (already != -1 &&
   1.446 +			    (packages[already].state & RAZOR_PACKAGE_INSTALL))
   1.447  				continue;
   1.448  
   1.449 -			required = array_add(&list, sizeof *required);
   1.450 -			*required = provider;
   1.451 +			tp = array_add(package_array, sizeof *tp);
   1.452 +			memset(tp, 0, sizeof *tp);
   1.453 +			tp->req_package = packages[p].name;
   1.454 +			tp->req_property = &pool[props[*new].name];
   1.455 +			tp->req_relation = props[*new].relation;
   1.456 +			tp->req_version = &pool[props[*new].version];
   1.457 +
   1.458 +			if (provider != -1) {
   1.459 +				tp->package = &pkgs[provider];
   1.460 +				tp->name = &pool[tp->package->name];
   1.461 +				tp->version = &pool[tp->package->version];
   1.462 +				if (already != -1) {
   1.463 +					tp->state = RAZOR_PACKAGE_INSTALL_BLOCKED;
   1.464 +					trans->errors++;
   1.465 +				} else
   1.466 +					tp->state = RAZOR_PACKAGE_INSTALL;
   1.467 +			} else {
   1.468 +				tp->state = RAZOR_PACKAGE_INSTALL_UNSATISFIABLE;
   1.469 +				trans->errors++;
   1.470 +			}
   1.471 +
   1.472 +			packages = package_array->data;
   1.473  		}
   1.474  		array_release(&new_requires);
   1.475 -
   1.476 -		update = list.data;
   1.477 -		update_count = list.size / sizeof (uint32_t);
   1.478  	}
   1.479 -
   1.480 -	new_set = razor_set_add(set, upstream, &list);
   1.481 -	array_release(&list);
   1.482 -	razor_set_destroy(set);
   1.483 -	return new_set;
   1.484  }
   1.485  
   1.486  /* Look through pkg's PROVIDES, and for each one that no other package
   1.487 @@ -2019,101 +1957,102 @@
   1.488  	}
   1.489  }
   1.490  
   1.491 -/* Add the index of each package required by req that isn't already in
   1.492 - * lost_requires, to lost_requires
   1.493 - */
   1.494  static void
   1.495 -gather_lost_requires(struct razor_set *set, struct razor_property *req,
   1.496 -		     struct array *lost_requires)
   1.497 +lose_requirement(struct razor_transaction *trans, struct array *package_array,
   1.498 +		 const char *req_package, struct razor_property *req,
   1.499 +		 struct razor_property *lost_provider,
   1.500 +		 struct razor_property *first_provider)
   1.501  {
   1.502 +	struct razor_property *provider, *prop_end;
   1.503 +	struct razor_package *pkgs;
   1.504 +	char *pool = trans->system->string_pool.data;
   1.505  	struct list *p;
   1.506 -	uint32_t *lost, *already_lost, *already_end;
   1.507 +	struct razor_transaction_package *tp, *packages;;
   1.508 +	int already;
   1.509  
   1.510 -	for (p = list_first(&req->packages, &set->package_pool); p; p = list_next(p)) {
   1.511 -		already_end = lost_requires->data + lost_requires->size;
   1.512 -		for (already_lost = lost_requires->data; already_lost < already_end; already_lost++) {
   1.513 -			if (*already_lost == p->data)
   1.514 -				break;
   1.515 -		}
   1.516 +	pkgs = trans->system->packages.data;
   1.517 +	prop_end = trans->system->properties.data + trans->system->properties.size;
   1.518  
   1.519 -		if (already_lost == already_end) {
   1.520 -			lost = array_add(lost_requires, sizeof *lost);
   1.521 -			*lost = p->data;
   1.522 -		}
   1.523 +	/* See if any other provider satisfies req */
   1.524 +	for (provider = first_provider;
   1.525 +	     provider < prop_end && provider->type == RAZOR_PROPERTY_PROVIDES && provider->name == lost_provider->name;
   1.526 +	     provider++) {
   1.527 +		if (provider == lost_provider)
   1.528 +			continue;
   1.529 +
   1.530 +		if (provider_satisfies_requirement(provider, pool, req, pool))
   1.531 +			return;
   1.532 +	}
   1.533 +
   1.534 +	/* Remove each of the packages requiring req */
   1.535 +	for (p = list_first(&req->packages, &trans->system->package_pool); p; p = list_next(p)) {
   1.536 +		packages = package_array->data;
   1.537 +		already = find_transaction_package(package_array, &pkgs[p->data]);
   1.538 +		if (already != -1 &&
   1.539 +		    (packages[already].state & RAZOR_PACKAGE_REMOVE))
   1.540 +			continue;
   1.541 +
   1.542 +		tp = array_add(package_array, sizeof *tp);
   1.543 +		memset(tp, 0, sizeof *tp);
   1.544 +		tp->package = &pkgs[p->data];
   1.545 +		tp->name = &pool[tp->package->name];
   1.546 +		tp->version = &pool[tp->package->version];
   1.547 +		tp->req_package = req_package;
   1.548 +		tp->req_property = &pool[req->name];
   1.549 +		tp->req_relation = req->relation;
   1.550 +		tp->req_version = &pool[req->version];
   1.551 +		if (already != -1) {
   1.552 +			tp->state = RAZOR_PACKAGE_REMOVE_BLOCKED;
   1.553 +			trans->errors++;
   1.554 +		} else
   1.555 +			tp->state = RAZOR_PACKAGE_REMOVE;
   1.556  	}
   1.557  }
   1.558  
   1.559 -static struct razor_set *
   1.560 -razor_set_remove_internal(struct razor_set *set, struct array *list)
   1.561 +static void
   1.562 +razor_transaction_satisfy_removes(struct razor_transaction *trans,
   1.563 +				  struct array *package_array,
   1.564 +				  int start, int end)
   1.565  {
   1.566 -	struct razor_set *empty, *new;
   1.567 -	struct razor_merger *merger;
   1.568 +	struct razor_transaction_package *packages;
   1.569  	struct razor_package *pkgs;
   1.570 -	int pkg_count, remove_count, p, r;
   1.571 -	uint32_t *remove, *lost, *lost_end;
   1.572 -	struct razor_property *props, *prop_end, *req;
   1.573 +	int pkg_count, r;
   1.574 +	uint32_t *lost, *lost_end;
   1.575 +	struct razor_property *props, *prop_end, *req, *first_provider;
   1.576  	struct array lost_provides;
   1.577 +	const char *req_package;
   1.578  
   1.579 -	pkgs = set->packages.data;
   1.580 -	pkg_count = set->packages.size / sizeof (struct razor_package);
   1.581 -	props = set->properties.data;
   1.582 -	prop_end = set->properties.data + set->properties.size;
   1.583 +	pkgs = trans->system->packages.data;
   1.584 +	pkg_count = trans->system->packages.size / sizeof (struct razor_package);
   1.585 +	props = trans->system->properties.data;
   1.586 +	prop_end = trans->system->properties.data + trans->system->properties.size;
   1.587  
   1.588 -	remove = list->data;
   1.589 -	remove_count = list->size / sizeof (uint32_t);
   1.590 -	r = 0;
   1.591 -	while (r < remove_count) {
   1.592 +	for (r = start; r < end; r++) {
   1.593 +		packages = package_array->data;
   1.594 +		if (packages[r].state != RAZOR_PACKAGE_REMOVE)
   1.595 +			continue;
   1.596 +
   1.597  		array_init(&lost_provides);
   1.598 -		for (; r < remove_count; r++)
   1.599 -			gather_lost_provides(set, &pkgs[remove[r]], &lost_provides);
   1.600 +		req_package = packages[r].name;
   1.601 +		gather_lost_provides(trans->system, packages[r].package,
   1.602 +				     &lost_provides);
   1.603  
   1.604  		lost_end = lost_provides.data + lost_provides.size;
   1.605  		for (lost = lost_provides.data; lost < lost_end; lost++) {
   1.606  			/* Requires FOO will appear before Provides FOO */
   1.607  			for (req = &props[*lost]; req > props && req->name == props[*lost].name && req->type != RAZOR_PROPERTY_REQUIRES; req--)
   1.608  				;
   1.609 -			/* FIXME: versioned deps... */
   1.610 +			first_provider = req + 1;
   1.611 +
   1.612  			while (req > props && req->name == props[*lost].name) {
   1.613 -				gather_lost_requires(set, req, list);
   1.614 +				lose_requirement(trans, package_array,
   1.615 +						 req_package, req,
   1.616 +						 &props[*lost], first_provider);
   1.617  				req--;
   1.618  			}
   1.619  		}
   1.620  		array_release(&lost_provides);
   1.621 -
   1.622 -		remove = list->data;
   1.623 -		remove_count = list->size / sizeof (uint32_t);
   1.624  	}
   1.625 -
   1.626 -	empty = razor_set_create();
   1.627 -	merger = razor_merger_create(set, empty);
   1.628 -
   1.629 -	for (p = 0; p < pkg_count; p++) {
   1.630 -		for (r = 0; r < remove_count; r++) {
   1.631 -			if (p == remove[r])
   1.632 -				goto skip;
   1.633 -		}
   1.634 -		add_package(merger, &pkgs[p], &merger->source1, 0);
   1.635 -	skip:
   1.636 -		;
   1.637 -	}
   1.638 -
   1.639 -	new = razor_merger_finish(merger);
   1.640 -	razor_set_destroy(empty);
   1.641 -	return new;
   1.642 -}
   1.643 -
   1.644 -struct razor_set *
   1.645 -razor_set_remove(struct razor_set *set, int count, const char **packages)
   1.646 -{
   1.647 -	struct razor_set *new;
   1.648 -	struct array list;
   1.649 -
   1.650 -	array_init(&list);
   1.651 -	find_packages(set, count, packages, &list);
   1.652 -	new = razor_set_remove_internal(set, &list);
   1.653 -	array_release(&list);
   1.654 -	razor_set_destroy(set);
   1.655 -	return new;
   1.656  }
   1.657  
   1.658  /* The diff order matters.  We should sort the packages so that a
   1.659 @@ -2161,3 +2100,258 @@
   1.660  	razor_package_iterator_destroy(pi1);
   1.661  	razor_package_iterator_destroy(pi2);
   1.662  }
   1.663 +
   1.664 +struct razor_transaction *
   1.665 +razor_transaction_create(struct razor_set *system, struct razor_set *upstream,
   1.666 +			 int update_count, const char **update_packages,
   1.667 +			 int remove_count, const char **remove_packages)
   1.668 +{
   1.669 +	struct razor_transaction *trans;
   1.670 +	struct array packages;
   1.671 +	int start, end;
   1.672 +
   1.673 +	trans = zalloc(sizeof *trans);
   1.674 +	trans->system = system;
   1.675 +	trans->upstream = upstream ? upstream : razor_set_create();
   1.676 +	array_init(&packages);
   1.677 +
   1.678 +	/* Find initial upstream packages to be installed */
   1.679 +	if (update_count > 0) {
   1.680 +		trans->errors +=
   1.681 +			find_packages(upstream, update_count, update_packages,
   1.682 +				      &packages, RAZOR_PACKAGE_INSTALL);
   1.683 +	} else if (remove_count == 0)
   1.684 +		find_all_packages(system, upstream, &packages);
   1.685 +
   1.686 +	/* Find initial installed packages to remove. */
   1.687 +	if (remove_count > 0) {
   1.688 +		trans->errors +=
   1.689 +			find_packages(system, remove_count, remove_packages,
   1.690 +				      &packages, RAZOR_PACKAGE_REMOVE);
   1.691 +	}
   1.692 +
   1.693 +	start = 0;
   1.694 +	end = packages.size / sizeof (struct razor_transaction_package);
   1.695 +
   1.696 +	while (!trans->errors && start != end) {
   1.697 +		if (upstream)
   1.698 +			razor_transaction_satisfy_installs(trans, &packages, start, end);
   1.699 +		razor_transaction_satisfy_removes(trans, &packages, start, end);
   1.700 +
   1.701 +		start = end;
   1.702 +		end = packages.size / sizeof (struct razor_transaction_package);
   1.703 +	}
   1.704 +
   1.705 +	trans->packages = packages.data;
   1.706 +	trans->package_count = packages.size / sizeof (struct razor_transaction_package);
   1.707 +	return trans;
   1.708 +}
   1.709 +
   1.710 +const char * const razor_version_relations[] = {
   1.711 +	/* same order as enum razor_version_relation */
   1.712 +	"<", "<=", "=", ">=", ">"
   1.713 +};
   1.714 +
   1.715 +void
   1.716 +razor_transaction_describe(struct razor_transaction *trans)
   1.717 +{
   1.718 +	struct razor_transaction_package *p, *pend, *tps;
   1.719 +	int errors_only = 0;
   1.720 +
   1.721 +	tps = trans->packages;
   1.722 +	pend = trans->packages + trans->package_count;
   1.723 +	for (p = trans->packages; p < pend; p++) {
   1.724 +		switch (p->state) {
   1.725 +		case RAZOR_PACKAGE_INSTALL:
   1.726 +			if (errors_only)
   1.727 +				break;
   1.728 +
   1.729 +			printf ("Installing %s %s", p->name, p->version);
   1.730 +			if (p->req_package) {
   1.731 +				printf (" for %s", p->req_package);
   1.732 +				if (*p->req_version) {
   1.733 +					printf (", which requires %s %s %s",
   1.734 +						p->req_property,
   1.735 +						razor_version_relations[p->req_relation],
   1.736 +						p->req_version);
   1.737 +				} else if (strcmp(p->req_property, p->name) != 0) {
   1.738 +					printf (", which requires %s",
   1.739 +						p->req_property);
   1.740 +				}
   1.741 +			}
   1.742 +			printf("\n");
   1.743 +			break;
   1.744 +
   1.745 +		case RAZOR_PACKAGE_INSTALL_UNAVAILABLE:
   1.746 +			if (*p->req_version && strcmp(p->req_property, p->name) == 0) {
   1.747 +				printf ("Can't find %s %s %s, which is required by %s",
   1.748 +					p->name,
   1.749 +					razor_version_relations[p->req_relation],
   1.750 +					p->req_version,
   1.751 +					p->req_package);
   1.752 +			} else {
   1.753 +				printf ("Can't find %s", p->name);
   1.754 +				if (*p->version)
   1.755 +					printf (" %s", p->version);
   1.756 +				
   1.757 +				if (p->req_package) {
   1.758 +					printf ("  which is required by %s",
   1.759 +						p->req_package);
   1.760 +					if (strcmp(p->req_property, p->name) != 0)
   1.761 +						printf (" for %s", p->req_property);
   1.762 +				}
   1.763 +			}
   1.764 +			printf("\n");
   1.765 +			errors_only = 1;
   1.766 +			break;
   1.767 +
   1.768 +		case RAZOR_PACKAGE_INSTALL_BLOCKED:
   1.769 +			printf ("Cannot install %s, which is already marked for removal but is required by %s\n", p->name, p->req_package);
   1.770 +			errors_only = 1;
   1.771 +			break;
   1.772 +
   1.773 +		case RAZOR_PACKAGE_INSTALL_UNSATISFIABLE:
   1.774 +			printf ("Cannot find package for %s", p->req_property);
   1.775 +			if (*p->req_version) {
   1.776 +				printf (" %s %s",
   1.777 +					razor_version_relations[p->req_relation],
   1.778 +					p->req_version);
   1.779 +			}
   1.780 +			printf (" which is required by %s\n",
   1.781 +				p->req_package);
   1.782 +			errors_only = 1;
   1.783 +			break;
   1.784 +
   1.785 +		case RAZOR_PACKAGE_REMOVE:
   1.786 +			if (errors_only)
   1.787 +				break;
   1.788 +			printf ("Removing %s %s", p->name, p->version);
   1.789 +			if (p->req_package) {
   1.790 +				printf (" which required %s", p->req_package);
   1.791 +				if (strcmp(p->req_property, p->req_package) != 0)
   1.792 +					printf (" for %s", p->req_property);
   1.793 +			}
   1.794 +			printf("\n");
   1.795 +			break;
   1.796 +
   1.797 +		case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED:
   1.798 +			printf ("Package %s is not installed\n", p->name);
   1.799 +			errors_only = 1;
   1.800 +			break;
   1.801 +
   1.802 +		case RAZOR_PACKAGE_REMOVE_BLOCKED:
   1.803 +			printf ("Cannot remove %s, which is marked for installation but requires %s\n", p->name, p->req_package);
   1.804 +			errors_only = 1;
   1.805 +			break;
   1.806 +
   1.807 +		default:
   1.808 +			/* Shouldn't actually happen */
   1.809 +			break;
   1.810 +		}
   1.811 +	}
   1.812 +}
   1.813 +
   1.814 +struct razor_set *
   1.815 +razor_transaction_run(struct razor_transaction *trans)
   1.816 +{
   1.817 +	struct array install_packages, remove_packages;
   1.818 +	struct razor_merger *merger;
   1.819 +	struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send;
   1.820 +	struct source *source1, *source2;
   1.821 +	char *spool, *ipool, *rpool;
   1.822 +	uint32_t *map;
   1.823 +	int p, cmp;
   1.824 +
   1.825 +	/* FIXME */
   1.826 +	if (trans->errors)
   1.827 +		return NULL;
   1.828 +
   1.829 +	/* Sort the transaction packages into two arrays */
   1.830 +	array_init(&install_packages);
   1.831 +	array_init(&remove_packages);
   1.832 +	for (p = 0; p < trans->package_count; p++) {
   1.833 +		if (trans->packages[p].state & RAZOR_PACKAGE_INSTALL)
   1.834 +			pkg = array_add(&install_packages, sizeof *pkg);
   1.835 +		else
   1.836 +			pkg = array_add(&remove_packages, sizeof *pkg);
   1.837 +		*pkg = *trans->packages[p].package;
   1.838 +	}
   1.839 +	map = qsort_with_data(install_packages.data,
   1.840 +			      install_packages.size / sizeof *pkg,
   1.841 +			      sizeof *pkg,
   1.842 +			      compare_packages,
   1.843 +			      trans->upstream);
   1.844 +	free(map);
   1.845 +	map = qsort_with_data(remove_packages.data,
   1.846 +			      remove_packages.size / sizeof *pkg,
   1.847 +			      sizeof *pkg,
   1.848 +			      compare_packages,
   1.849 +			      trans->system);
   1.850 +	free(map);
   1.851 +
   1.852 +	merger = razor_merger_create(trans->system, trans->upstream);
   1.853 +
   1.854 +	source1 = &merger->source1;
   1.855 +	source2 = &merger->source2;
   1.856 +
   1.857 +	i = install_packages.data;
   1.858 +	iend = install_packages.data + install_packages.size;
   1.859 +	ipool = trans->upstream->string_pool.data;
   1.860 +
   1.861 +	r = remove_packages.data;
   1.862 +	rend = remove_packages.data + remove_packages.size;
   1.863 +	rpool = trans->system->string_pool.data;
   1.864 +
   1.865 +	s = trans->system->packages.data;
   1.866 +	send = trans->system->packages.data + trans->system->packages.size;
   1.867 +	spool = trans->system->string_pool.data;
   1.868 +
   1.869 +	while (s < send || i < iend) {
   1.870 +		/* Check if s is being removed */
   1.871 +		if (s < send && r < rend &&
   1.872 +		    s->name == r->name && s->version && r->version) {
   1.873 +			s++;
   1.874 +			r++;
   1.875 +			continue;
   1.876 +		}
   1.877 +
   1.878 +		if (s < send && i < iend)
   1.879 +			cmp = strcmp(&spool[s->name], &ipool[i->name]);
   1.880 +		else if (s < send)
   1.881 +			cmp = -1;
   1.882 +		else
   1.883 +			cmp = 1;
   1.884 +		if (cmp < 0) {
   1.885 +			add_package(merger, s, source1, 0);
   1.886 +			s++;
   1.887 +		} else if (cmp == 0) {
   1.888 +			add_package(merger, i, source2, UPSTREAM_SOURCE);
   1.889 +			s++;
   1.890 +			i++;
   1.891 +		} else {
   1.892 +			add_package(merger, i, source2, UPSTREAM_SOURCE);
   1.893 +			i++;
   1.894 +		}
   1.895 +	}
   1.896 +
   1.897 +	array_release(&install_packages);
   1.898 +	array_release(&remove_packages);
   1.899 +
   1.900 +	return razor_merger_finish(merger);
   1.901 +}
   1.902 +
   1.903 +void
   1.904 +razor_transaction_destroy(struct razor_transaction *trans)
   1.905 +{
   1.906 +	int p;
   1.907 +
   1.908 +	for (p = 0; p < trans->package_count; p++) {
   1.909 +		if (!trans->packages[p].req_package &&
   1.910 +		    (trans->packages[p].state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE ||
   1.911 +		     trans->packages[p].state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED))
   1.912 +			free((char *)trans->packages[p].name);
   1.913 +	}
   1.914 +	free(trans);
   1.915 +
   1.916 +	/* FIXME: free upstream if it was created as an empty set */
   1.917 +}