librazor/importer.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 21:56:43 2008 -0400 (2008-06-20)
changeset 254 ccb1c11968ab
parent 248 057933050c42
child 257 0c3db660514d
permissions -rw-r--r--
Introduce install/remove iterators.

These iterator constructors lets you pass in two sets and creates
an iterator for the packages to remove or the packages to install.
The iterators will step through the packages in a sequence that respects
the pre, post, preun and postun modifiers.

Right now, the install order isn't actually implemented, this patch just
implements the API changes and updates the applications.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #define _GNU_SOURCE
    21 
    22 #include <string.h>
    23 #include "razor-internal.h"
    24 #include "razor.h"
    25 
    26 void
    27 razor_importer_begin_package(struct razor_importer *importer,
    28 			     const char *name,
    29 			     const char *version,
    30 			     const char *arch)
    31 {
    32 	struct razor_package *p;
    33 
    34 	p = array_add(&importer->set->packages, sizeof *p);
    35 	p->name = hashtable_tokenize(&importer->table, name);
    36 	p->flags = 0;
    37 	p->version = hashtable_tokenize(&importer->table, version);
    38 	p->arch = hashtable_tokenize(&importer->table, arch);
    39 
    40 	importer->package = p;
    41 	array_init(&importer->properties);
    42 }
    43 
    44 
    45 void
    46 razor_importer_finish_package(struct razor_importer *importer)
    47 {
    48 	list_set_array(&importer->package->properties,
    49 		       &importer->set->property_pool,
    50 		       &importer->properties,
    51 		       1);
    52 
    53 	array_release(&importer->properties);
    54 }
    55 
    56 void
    57 razor_importer_add_property(struct razor_importer *importer,
    58 			    const char *name,
    59 			    uint32_t flags,
    60 			    const char *version)
    61 {
    62 	struct razor_property *p;
    63 	uint32_t *r;
    64 
    65 	p = array_add(&importer->set->properties, sizeof *p);
    66 	p->name = hashtable_tokenize(&importer->table, name);
    67 	p->flags = flags;
    68 	p->version = hashtable_tokenize(&importer->table, version);
    69 	list_set_ptr(&p->packages, importer->package -
    70 		     (struct razor_package *) importer->set->packages.data);
    71 
    72 	r = array_add(&importer->properties, sizeof *r);
    73 	*r = p - (struct razor_property *) importer->set->properties.data;
    74 
    75 	if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
    76 	    *name == '/') {
    77 		r = array_add(&importer->file_requires, sizeof *r);
    78 		*r = p->name;
    79 	}
    80 }
    81 
    82 void
    83 razor_importer_add_file(struct razor_importer *importer, const char *name)
    84 {
    85 	struct import_entry *e;
    86 
    87 	e = array_add(&importer->files, sizeof *e);
    88 
    89 	e->package = importer->package -
    90 		(struct razor_package *) importer->set->packages.data;
    91 	e->name = strdup(name);
    92 }
    93 
    94 struct razor_importer *
    95 razor_importer_create(void)
    96 {
    97 	struct razor_importer *importer;
    98 
    99 	importer = zalloc(sizeof *importer);
   100 	importer->set = razor_set_create();
   101 	hashtable_init(&importer->table, &importer->set->string_pool);
   102 
   103 	return importer;
   104 }
   105 
   106 /* Destroy an importer without creating the set. */
   107 void
   108 razor_importer_destroy(struct razor_importer *importer)
   109 {
   110 	/* FIXME: write this */
   111 }
   112 
   113 static int
   114 compare_packages(const void *p1, const void *p2, void *data)
   115 {
   116 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   117 	struct razor_set *set = data;
   118 	char *pool = set->string_pool.data;
   119 
   120 	/* FIXME: what if the flags are different? */
   121 	if (pkg1->name == pkg2->name)
   122 		return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
   123 	else
   124 		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   125 }
   126 
   127 static int
   128 compare_properties(const void *p1, const void *p2, void *data)
   129 {
   130 	const struct razor_property *prop1 = p1, *prop2 = p2;
   131 	struct razor_set *set = data;
   132 	char *pool = set->string_pool.data;
   133 
   134 	if (prop1->name != prop2->name)
   135 		return strcmp(&pool[prop1->name], &pool[prop2->name]);
   136 	else if (prop1->flags != prop2->flags)
   137 		return prop1->flags - prop2->flags;
   138 	else
   139 		return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
   140 }
   141 
   142 static uint32_t *
   143 uniqueify_properties(struct razor_set *set)
   144 {
   145 	struct razor_property *rp, *up, *rp_end;
   146 	struct array *pkgs, *p;
   147 	struct list_head *r;
   148 	uint32_t *map, *rmap;
   149 	int i, count, unique;
   150 
   151 	count = set->properties.size / sizeof(struct razor_property);
   152 	map = razor_qsort_with_data(set->properties.data,
   153 				    count,
   154 				    sizeof(struct razor_property),
   155 				    compare_properties,
   156 				    set);
   157 
   158 	rp_end = set->properties.data + set->properties.size;
   159 	rmap = malloc(count * sizeof *map);
   160 	pkgs = zalloc(count * sizeof *pkgs);
   161 	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
   162 		if (rp->name != up->name ||
   163 		    rp->flags != up->flags ||
   164 		    rp->version != up->version) {
   165 			up++;
   166 			up->name = rp->name;
   167 			up->flags = rp->flags;
   168 			up->version = rp->version;
   169 		}
   170 
   171 		unique = up - (struct razor_property *) set->properties.data;
   172 		rmap[map[i]] = unique;
   173 		r = array_add(&pkgs[unique], sizeof *r);
   174 		*r = rp->packages;
   175 	}
   176 	free(map);
   177 
   178 	if (up != rp)
   179 		up++;
   180 	set->properties.size = (void *) up - set->properties.data;
   181 	rp_end = up;
   182 	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
   183 		list_set_array(&rp->packages, &set->package_pool, p, 0);
   184 		array_release(p);
   185 	}
   186 
   187 	free(pkgs);
   188 
   189 	return rmap;
   190 }
   191 
   192 static int
   193 compare_filenames(const void *p1, const void *p2, void *data)
   194 {
   195 	const struct import_entry *e1 = p1;
   196 	const struct import_entry *e2 = p2;
   197 	const char *n1 = e1->name;
   198 	const char *n2 = e2->name;
   199 
   200 	/* Need to make sure that the contents of a directory
   201 	 * are sorted immediately after it. So "foo/bar" has to
   202 	 * sort before "foo.conf"
   203 	 *
   204 	 * FIXME: this is about 60% slower than strcmp
   205 	 */
   206 	while (*n1 && *n2) {
   207 		if (*n1 < *n2)
   208 			return *n2 == '/' ? 1 : -1;
   209 		else if (*n1 > *n2)
   210 			return *n1 == '/' ? -1 : 1;
   211 		n1++;
   212 		n2++;
   213 	}
   214 	if (*n1)
   215 		return 1;
   216 	else if (*n2)
   217 		return -1;
   218 	else
   219 		return 0;
   220 }
   221 
   222 static void
   223 count_entries(struct import_directory *d)
   224 {
   225 	struct import_directory *p, *end;
   226 
   227 	p = d->files.data;
   228 	end = d->files.data + d->files.size;
   229 	d->count = 0;
   230 	while (p < end) {
   231 		count_entries(p);
   232 		d->count += p->count + 1;
   233 		p++;
   234 	}
   235 }
   236 
   237 static void
   238 serialize_files(struct razor_set *set,
   239 		struct import_directory *d, struct array *array)
   240 {
   241 	struct import_directory *p, *end;
   242 	struct razor_entry *e = NULL;
   243 	uint32_t s;
   244 
   245 	p = d->files.data;
   246 	end = d->files.data + d->files.size;
   247 	s = array->size / sizeof *e + d->files.size / sizeof *p;
   248 	while (p < end) {
   249 		e = array_add(array, sizeof *e);
   250 		e->name = p->name;
   251 		e->flags = 0;
   252 		e->start = p->count > 0 ? s : 0;
   253 		s += p->count;
   254 
   255 		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
   256 		array_release(&p->packages);
   257 		p++;
   258 	}
   259 	if (e != NULL)
   260 		e->flags |= RAZOR_ENTRY_LAST;
   261 
   262 	p = d->files.data;
   263 	end = d->files.data + d->files.size;
   264 	while (p < end) {
   265 		serialize_files(set, p, array);
   266 		p++;
   267 	}
   268 }
   269 
   270 static void
   271 remap_property_package_links(struct array *properties, uint32_t *rmap)
   272 {
   273 	struct razor_property *p, *end;
   274 
   275 	end = properties->data + properties->size;
   276 	for (p = properties->data; p < end; p++)
   277 		list_remap_head(&p->packages, rmap);
   278 }
   279 
   280 static void
   281 build_file_tree(struct razor_importer *importer)
   282 {
   283 	int count, i, length;
   284 	struct import_entry *filenames;
   285 	char *f, *end;
   286 	uint32_t name, *r;
   287 	char dirname[256];
   288 	struct import_directory *d, root;
   289 	struct razor_entry *e;
   290 
   291 	count = importer->files.size / sizeof (struct import_entry);
   292 	razor_qsort_with_data(importer->files.data,
   293 			      count,
   294 			      sizeof (struct import_entry),
   295 			      compare_filenames,
   296 			      NULL);
   297 
   298 	root.name = hashtable_tokenize(&importer->table, "");
   299 	array_init(&root.files);
   300 	array_init(&root.packages);
   301 	root.last = NULL;
   302 
   303 	filenames = importer->files.data;
   304 	for (i = 0; i < count; i++) {
   305 		f = filenames[i].name;
   306 		if (*f != '/')
   307 			continue;
   308 		f++;
   309 
   310 		d = &root;
   311 		while (*f) {
   312 			end = strchr(f, '/');
   313 			if (end == NULL)
   314 				end = f + strlen(f);
   315 			length = end - f;
   316 			memcpy(dirname, f, length);
   317 			dirname[length] ='\0';
   318 			name = hashtable_tokenize(&importer->table, dirname);
   319 			if (d->last == NULL || d->last->name != name) {
   320 				d->last = array_add(&d->files, sizeof *d);
   321 				d->last->name = name;
   322 				d->last->last = NULL;
   323 				array_init(&d->last->files);
   324 				array_init(&d->last->packages);
   325 			}
   326 			d = d->last;
   327 			f = end + 1;
   328 			if (*end == '\0')
   329 				break;
   330 		}
   331 
   332 		r = array_add(&d->packages, sizeof *r);
   333 		*r = filenames[i].package;
   334 		free(filenames[i].name);
   335 	}
   336 
   337 	count_entries(&root);
   338 	e = importer->set->files.data;
   339 	e->name = root.name;
   340 	e->flags = RAZOR_ENTRY_LAST;
   341 	e->start = importer->files.size ? 1 : 0;
   342 	list_set_empty(&e->packages);
   343 
   344 	serialize_files(importer->set, &root, &importer->set->files);
   345 
   346 	array_release(&importer->files);
   347 }
   348 
   349 static void
   350 list_to_array(struct list *list, struct array *array)
   351 {
   352 	uint32_t *item;
   353 
   354 	while (list) {
   355 		 item = array_add(array, sizeof *item);
   356 		 *item = list->data;
   357 		 list = list_next(list);
   358 	}
   359 }
   360 
   361 static int
   362 compare_file_requires(const void *p1, const void *p2, void *data)
   363 {
   364 	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
   365 	const char *pool = data;
   366 
   367 	return strcmp(&pool[*f1], &pool[*f2]);
   368 }
   369 
   370 static void
   371 find_file_provides(struct razor_importer *importer)
   372 {
   373 	struct razor_property *prop;
   374 	struct razor_entry *top, *entry;
   375 	struct razor_package *packages;
   376 	struct array pkgprops;
   377 	struct list *pkg;
   378 	uint32_t *req, *req_start, *req_end;
   379 	uint32_t *map, *newprop;
   380 	char *pool;
   381 
   382 	pool = importer->set->string_pool.data;
   383 	packages = importer->set->packages.data;
   384 	top = importer->set->files.data;
   385 
   386 	req = req_start = importer->file_requires.data;
   387 	req_end = importer->file_requires.data + importer->file_requires.size;
   388 	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
   389 				    compare_file_requires, pool);
   390 	free(map);
   391 
   392 	for (req = req_start; req < req_end; req++) {
   393 		if (req > req_start && req[0] == req[-1])
   394 			continue;
   395 		entry = razor_set_find_entry(importer->set, top, &pool[*req]);
   396 		if (!entry)
   397 			continue;
   398 
   399 		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
   400 			prop = array_add(&importer->set->properties, sizeof *prop);
   401 			prop->name = *req;
   402 			prop->flags =
   403 				RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
   404 			prop->version = hashtable_tokenize(&importer->table, "");
   405 			list_set_ptr(&prop->packages, pkg->data);
   406 
   407 			/* Update property list of pkg */
   408 			array_init(&pkgprops);
   409 			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
   410 			newprop = array_add(&pkgprops, sizeof *newprop);
   411 			*newprop = prop - (struct razor_property *)importer->set->properties.data;
   412 			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
   413 			array_release(&pkgprops);
   414 		}
   415 	}
   416 
   417 	array_release(&importer->file_requires);
   418 }
   419 
   420 static void
   421 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
   422 {
   423 	struct razor_package *p, *packages;
   424 	struct array *pkgs;
   425 	struct razor_entry *e, *end;
   426 	struct list *r;
   427 	uint32_t *q;
   428 	int i, count;
   429 
   430 	count = set->packages.size / sizeof *p;
   431 	pkgs = zalloc(count * sizeof *pkgs);
   432 
   433 	end = set->files.data + set->files.size;
   434 	for (e = set->files.data; e < end; e++) {
   435 		list_remap_head(&e->packages, rmap);
   436 		r = list_first(&e->packages, &set->package_pool);
   437 		while (r) {
   438 			q = array_add(&pkgs[r->data], sizeof *q);
   439 			*q = e - (struct razor_entry *) set->files.data;
   440 			r = list_next(r);
   441 		}
   442 	}
   443 
   444 	packages = set->packages.data;
   445 	for (i = 0; i < count; i++) {
   446 		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
   447 		array_release(&pkgs[i]);
   448 	}
   449 	free(pkgs);
   450 }
   451 
   452 struct razor_set *
   453 razor_importer_finish(struct razor_importer *importer)
   454 {
   455 	struct razor_set *set;
   456 	uint32_t *map, *rmap;
   457 	int i, count;
   458 
   459 	build_file_tree(importer);
   460 	find_file_provides(importer);
   461 
   462 	map = uniqueify_properties(importer->set);
   463 	list_remap_pool(&importer->set->property_pool, map);
   464 	free(map);
   465 
   466 	count = importer->set->packages.size / sizeof(struct razor_package);
   467 	map = razor_qsort_with_data(importer->set->packages.data,
   468 				    count,
   469 				    sizeof(struct razor_package),
   470 				    compare_packages,
   471 				    importer->set);
   472 
   473 	rmap = malloc(count * sizeof *rmap);
   474 	for (i = 0; i < count; i++)
   475 		rmap[map[i]] = i;
   476 	free(map);
   477 
   478 	list_remap_pool(&importer->set->package_pool, rmap);
   479 	build_package_file_lists(importer->set, rmap);
   480 	remap_property_package_links(&importer->set->properties, rmap);
   481 	free(rmap);
   482 
   483 	set = importer->set;
   484 	hashtable_release(&importer->table);
   485 	free(importer);
   486 
   487 	return set;
   488 }