main.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 12:45:08 2008 -0500 (2008-02-29)
changeset 138 49deac048d07
parent 129 d221757574c1
child 151 ae6ceb604f54
permissions -rw-r--r--
implement file dependencies for installs

removes are trickier because there are no backlinks from the files array
the properties array, so there's currently no way to efficiently determine
what packages are affected by the removal of a particular file
     1 #include <stdlib.h>
     2 #include <stddef.h>
     3 #include <stdio.h>
     4 #include <string.h>
     5 #include <sys/types.h>
     6 #include <sys/stat.h>
     7 #include <unistd.h>
     8 #include <dirent.h>
     9 #include <curl/curl.h>
    10 #include <fnmatch.h>
    11 #include "razor.h"
    12 
    13 static const char *repo_filename = "system.repo";
    14 static const char *rawhide_repo_filename = "rawhide.repo";
    15 static const char *updated_repo_filename = "system-updated.repo";
    16 
    17 static int
    18 command_list(int argc, const char *argv[])
    19 {
    20 	struct razor_set *set;
    21 	struct razor_package_iterator *pi;
    22 	struct razor_package *package;
    23 	const char *pattern = argv[0], *name, *version;
    24 
    25 	set = razor_set_open(repo_filename);
    26 	pi = razor_package_iterator_create(set);
    27 	while (razor_package_iterator_next(pi, &package, &name, &version)) {
    28 		if (pattern && fnmatch(pattern, name, 0) != 0)
    29 			continue;
    30 
    31 		printf("%s-%s\n", name, version);
    32 	}
    33 	razor_package_iterator_destroy(pi);
    34 	razor_set_destroy(set);
    35 
    36 	return 0;
    37 }
    38 
    39 static int
    40 list_properties(const char *package_name,
    41 		enum razor_property_type required_type)
    42 {
    43 	struct razor_set *set;
    44 	struct razor_property *property;
    45 	struct razor_package *package;
    46 	struct razor_property_iterator *pi;
    47 	const char *name, *version;
    48 	enum razor_property_type type;
    49 	enum razor_version_relation relation;
    50 
    51 	set = razor_set_open(repo_filename);
    52 	if (package_name)
    53 		package = razor_set_get_package(set, package_name);
    54 	else
    55 		package = NULL;
    56 
    57 	pi = razor_property_iterator_create(set, package);
    58 	while (razor_property_iterator_next(pi, &property,
    59 					    &name, &relation, &version,
    60 					    &type)) {
    61 		if (type != required_type)
    62 			continue;
    63 		if (version[0] == '\0')
    64 			printf("%s\n", name);
    65 		else
    66 			printf("%s %s %s\n", name,
    67 			       razor_version_relations[relation], version);
    68 	}
    69 	razor_property_iterator_destroy(pi);
    70 
    71 	razor_set_destroy(set);
    72 
    73 	return 0;
    74 }
    75 
    76 static int
    77 command_list_requires(int argc, const char *argv[])
    78 {
    79 	return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES);
    80 }
    81 
    82 static int
    83 command_list_provides(int argc, const char *argv[])
    84 {
    85 	return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES);
    86 }
    87 
    88 static int
    89 command_list_obsoletes(int argc, const char *argv[])
    90 {
    91 	return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES);
    92 }
    93 
    94 static int
    95 command_list_conflicts(int argc, const char *argv[])
    96 {
    97 	return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS);
    98 }
    99 
   100 static int
   101 command_list_files(int argc, const char *argv[])
   102 {
   103 	struct razor_set *set;
   104 
   105 	set = razor_set_open(repo_filename);
   106 	if (set == NULL)
   107 		return 1;
   108 	razor_set_list_files(set, argv[0]);
   109 	razor_set_destroy(set);
   110 
   111 	return 0;
   112 }
   113 
   114 static int
   115 command_list_file_packages(int argc, const char *argv[])
   116 {
   117 	struct razor_set *set;
   118 	struct razor_package_iterator *pi;
   119 	struct razor_package *package;
   120 	const char *name, *version;
   121 
   122 	set = razor_set_open(repo_filename);
   123 	if (set == NULL)
   124 		return 1;
   125 
   126 	pi = razor_package_iterator_create_for_file(set, argv[0]);
   127 	while (razor_package_iterator_next(pi, &package, &name, &version))
   128 		printf("%s-%s\n", name, version);
   129 	razor_package_iterator_destroy(pi);
   130 
   131 	razor_set_destroy(set);
   132 
   133 	return 0;
   134 }
   135 
   136 static int
   137 command_list_package_files(int argc, const char *argv[])
   138 {
   139 	struct razor_set *set;
   140 
   141 	set = razor_set_open(repo_filename);
   142 	if (set == NULL)
   143 		return 1;
   144 	razor_set_list_package_files(set, argv[0]);
   145 	razor_set_destroy(set);
   146 
   147 	return 0;
   148 }
   149 
   150 static void
   151 list_packages_for_property(struct razor_set *set,
   152 			   struct razor_property *property)
   153 {
   154 	struct razor_package_iterator *pi;
   155 	struct razor_package *package;
   156 	const char *name, *version;
   157 
   158 	pi = razor_package_iterator_create_for_property(set, property);
   159 	while (razor_package_iterator_next(pi, &package, &name, &version))
   160 		printf("%s-%s\n", name, version);
   161 	razor_package_iterator_destroy(pi);
   162 }
   163 
   164 static int
   165 list_property_packages(const char *ref_name,
   166 		       const char *ref_version,
   167 		       enum razor_property_type ref_type)
   168 {
   169 	struct razor_set *set;
   170 	struct razor_property *property;
   171 	struct razor_property_iterator *pi;
   172 	const char *name, *version;
   173 	enum razor_property_type type;
   174 	enum razor_version_relation relation;
   175 
   176 	if (ref_name == NULL)
   177 		return 0;
   178 
   179 	set = razor_set_open(repo_filename);
   180 	if (set == NULL)
   181 		return 1;
   182 
   183 	pi = razor_property_iterator_create(set, NULL);
   184 	while (razor_property_iterator_next(pi, &property,
   185 					    &name, &relation, &version,
   186 					    &type)) {
   187 		if (strcmp(ref_name, name) != 0)
   188 			continue;
   189 		if (ref_version && relation == RAZOR_VERSION_EQUAL &&
   190 		    strcmp(ref_version, version) != 0)
   191 			continue;
   192 		if (ref_type != type)
   193 			continue;
   194 
   195 		list_packages_for_property(set, property);
   196 	}
   197 	razor_property_iterator_destroy(pi);
   198 
   199 	return 0;
   200 }
   201 
   202 static int
   203 command_what_requires(int argc, const char *argv[])
   204 {
   205 	return list_property_packages(argv[0], argv[1],
   206 				      RAZOR_PROPERTY_REQUIRES);
   207 }
   208 
   209 static int
   210 command_what_provides(int argc, const char *argv[])
   211 {
   212 	return list_property_packages(argv[0], argv[1],
   213 				      RAZOR_PROPERTY_PROVIDES);
   214 }
   215 
   216 static int
   217 show_progress(void *clientp,
   218 	      double dltotal, double dlnow, double ultotal, double ulnow)
   219 {
   220 	const char *file = clientp;
   221 
   222 	if (!dlnow < dltotal)
   223 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   224 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   225 	else
   226 		fprintf(stderr, "\n");
   227 
   228 	return 0;
   229 }
   230 
   231 static int
   232 download_if_missing(CURL *curl, const char *url, const char *file)
   233 {
   234 	struct stat buf;
   235 	char error[256];
   236 	FILE *fp;
   237 	CURLcode res;
   238 	char buffer[256];
   239 
   240 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   241 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   242 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   243 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   244 
   245 	if (stat(file, &buf) < 0) {
   246 		fp = fopen(file, "w");
   247 		snprintf(buffer, sizeof buffer, "%s/%s", url, file);
   248 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   249 		curl_easy_setopt(curl, CURLOPT_URL, buffer);
   250 		res = curl_easy_perform(curl);
   251 		fclose(fp);
   252 		if (res != CURLE_OK) {
   253 			fprintf(stderr, "curl error: %s\n", error);
   254 			unlink(file);
   255 			return -1;
   256 		}
   257 	}
   258 
   259 	return 0;
   260 }
   261 
   262 #define REPO_URL "http://download.fedora.redhat.com" \
   263 	"/pub/fedora/linux/development/i386/os/repodata"
   264 
   265 static int
   266 command_import_yum(int argc, const char *argv[])
   267 {
   268 	struct razor_set *set;
   269 	CURL *curl;
   270 
   271 	curl = curl_easy_init();
   272 	if (curl == NULL)
   273 		return 1;
   274 
   275 	if (download_if_missing(curl, REPO_URL, "primary.xml.gz") < 0)
   276 		return -1;
   277 	if (download_if_missing(curl, REPO_URL, "filelists.xml.gz") < 0)
   278 		return -1;
   279 	curl_easy_cleanup(curl);
   280 
   281 	set = razor_set_create_from_yum();
   282 	if (set == NULL)
   283 		return 1;
   284 	razor_set_write(set, rawhide_repo_filename);
   285 	razor_set_destroy(set);
   286 	printf("wrote %s\n", rawhide_repo_filename);
   287 
   288 	return 0;
   289 }
   290 
   291 static int
   292 command_import_rpmdb(int argc, const char *argv[])
   293 {
   294 	struct razor_set *set;
   295 
   296 	set = razor_set_create_from_rpmdb();
   297 	if (set == NULL)
   298 		return 1;
   299 	razor_set_write(set, repo_filename);
   300 	razor_set_destroy(set);
   301 	printf("wrote %s\n", repo_filename);
   302 
   303 	return 0;
   304 }
   305 
   306 static int
   307 command_validate(int argc, const char *argv[])
   308 {
   309 	struct razor_set *set;
   310 
   311 	set = razor_set_open(repo_filename);
   312 	if (set == NULL)
   313 		return 1;
   314 	razor_set_list_unsatisfied(set);
   315 	razor_set_destroy(set);
   316 
   317 	return 0;
   318 }
   319 
   320 static int
   321 command_update(int argc, const char *argv[])
   322 {
   323 	struct razor_set *set, *upstream;
   324 	struct razor_transaction *trans;
   325 
   326 	set = razor_set_open(repo_filename);
   327 	upstream = razor_set_open(rawhide_repo_filename);
   328 	if (set == NULL || upstream == NULL)
   329 		return 1;
   330 	trans = razor_transaction_create(set, upstream, argc, argv, 0, NULL);
   331 	razor_transaction_describe(trans);
   332 	if (trans->errors)
   333 		return 1;
   334 
   335 	set = razor_transaction_run(trans);
   336 	razor_transaction_destroy(trans);
   337 	razor_set_write(set, updated_repo_filename);
   338 	razor_set_destroy(set);
   339 	razor_set_destroy(upstream);
   340 	printf("wrote system-updated.repo\n");
   341 
   342 	return 0;
   343 }
   344 
   345 static int
   346 command_remove(int argc, const char *argv[])
   347 {
   348 	struct razor_set *set;
   349 	struct razor_transaction *trans;
   350 
   351 	set = razor_set_open(repo_filename);
   352 	if (set == NULL)
   353 		return 1;
   354 	trans = razor_transaction_create(set, NULL, 0, NULL, argc, argv);
   355 	razor_transaction_describe(trans);
   356 	if (trans->errors)
   357 		return 1;
   358 
   359 	set = razor_transaction_run(trans);
   360 	razor_transaction_destroy(trans);
   361 	razor_set_write(set, updated_repo_filename);
   362 	razor_set_destroy(set);
   363 	printf("wrote system-updated.repo\n");
   364 
   365 	return 0;
   366 }
   367 
   368 static void
   369 print_diff(const char *name,
   370 	   const char *old_version, const char *new_version, void *data)
   371 {
   372 	if (old_version)
   373 		printf("removing %s %s\n", name, old_version);
   374 	else
   375 		printf("install %s %s\n", name, new_version);
   376 }
   377 
   378 static int
   379 command_diff(int argc, const char *argv[])
   380 {
   381 	struct razor_set *set, *updated;
   382 
   383 	set = razor_set_open(repo_filename);
   384 	updated = razor_set_open(updated_repo_filename);
   385 	if (set == NULL || updated == NULL)
   386 		return 1;
   387 
   388 	razor_set_diff(set, updated, print_diff, NULL);	
   389 
   390 	razor_set_destroy(set);
   391 	razor_set_destroy(updated);
   392 
   393 	return 0;
   394 }
   395 
   396 static int
   397 command_import_rpms(int argc, const char *argv[])
   398 {
   399 	DIR *dir;
   400 	struct dirent *de;
   401 	struct razor_importer *importer;
   402 	struct razor_set *set;
   403 	struct razor_rpm *rpm;
   404 	int len;
   405 	char filename[256];
   406 	const char *dirname = argv[0];
   407 
   408 	if (dirname == NULL) {
   409 		fprintf(stderr, "usage: razor import-rpms DIR\n");
   410 		return -1;
   411 	}
   412 
   413 	dir = opendir(dirname);
   414 	if (dir == NULL) {
   415 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   416 		return -1;
   417 	}
   418 
   419 	importer = razor_importer_new();
   420 
   421 	while (de = readdir(dir), de != NULL) {
   422 		len = strlen(de->d_name);
   423 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   424 		    continue;
   425 		snprintf(filename, sizeof filename,
   426 			 "%s/%s", dirname, de->d_name);
   427 		rpm = razor_rpm_open(filename);
   428 		if (rpm == NULL) {
   429 			fprintf(stderr,
   430 				"failed to open rpm \"%s\"\n", filename);
   431 			continue;
   432 		}
   433 		if (razor_importer_add_rpm(importer, rpm)) {
   434 			fprintf(stderr, "couldn't import %s\n", filename);
   435 			break;
   436 		}
   437 		razor_rpm_close(rpm);
   438 	}
   439 
   440 	if (de != NULL) {
   441 		razor_importer_destroy(importer);
   442 		return -1;
   443 	}
   444 
   445 	set = razor_importer_finish(importer);
   446 
   447 	razor_set_write(set, repo_filename);
   448 	razor_set_destroy(set);
   449 	printf("wrote %s\n", repo_filename);
   450 
   451 	return 0;
   452 }
   453 
   454 static int
   455 command_install(int argc, const char *argv[])
   456 {
   457 	struct razor_rpm *rpm;
   458 	const char *filename = argv[0];
   459 	struct stat buf;
   460 	const char root[] = "install";
   461 
   462 	if (stat(root, &buf) < 0) {
   463 		if (mkdir(root, 0777) < 0) {
   464 			fprintf(stderr,
   465 				"could not create install root \"%s\"\n",
   466 				root);
   467 			return -1;
   468 		}
   469 		fprintf(stderr, "created install root \"%s\"\n", root);
   470 	} else if (!S_ISDIR(buf.st_mode)) {
   471 		fprintf(stderr,
   472 			"install root \"%s\" exists, but is not a directory\n",
   473 			root);
   474 		return -1;
   475 	}
   476 
   477 	rpm = razor_rpm_open(filename);
   478 	if (rpm == NULL) {
   479 		fprintf(stderr, "failed to open rpm %s\n", filename);
   480 		return -1;
   481 	}
   482 	if (razor_rpm_install(rpm, root) < 0) {
   483 		fprintf(stderr, "failed to install rpm %s\n", filename);
   484 		return -1;
   485 	}
   486 	
   487 	razor_rpm_close(rpm);
   488 
   489 	return 0;
   490 }
   491 
   492 static struct {
   493 	const char *name;
   494 	const char *description;
   495 	int (*func)(int argc, const char *argv[]);
   496 } razor_commands[] = {
   497 	{ "list", "list all packages", command_list },
   498 	{ "list-requires", "list all requires for the given package", command_list_requires },
   499 	{ "list-provides", "list all provides for the given package", command_list_provides },
   500 	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
   501 	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
   502 	{ "list-files", "list files for package set", command_list_files },
   503 	{ "list-file-packages", "list packages owning file", command_list_file_packages },
   504 	{ "list-package-files", "list files in package", command_list_package_files },
   505 	{ "what-requires", "list the packages that have the given requires", command_what_requires },
   506 	{ "what-provides", "list the packages that have the given provides", command_what_provides },
   507 	{ "import-yum", "import yum metadata files", command_import_yum },
   508 	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
   509 	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
   510 	{ "validate", "validate a package set", command_validate },
   511 	{ "update", "update all or specified packages", command_update },
   512 	{ "remove", "remove specified packages", command_remove },
   513 	{ "diff", "show diff between two package sets", command_diff },
   514 	{ "install", "install rpm", command_install }
   515 };
   516 
   517 static int
   518 usage(void)
   519 {
   520 	int i;
   521 
   522 	printf("usage:\n");
   523 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
   524 		printf("  %-20s%s\n",
   525 		       razor_commands[i].name, razor_commands[i].description);
   526 
   527 	return 1;
   528 }
   529 
   530 int
   531 main(int argc, const char *argv[])
   532 {
   533 	char *repo;
   534 	int i;
   535 
   536 	repo = getenv("RAZOR_REPO");
   537 	if (repo != NULL)
   538 		repo_filename = repo;
   539 
   540 	if (argc < 2)
   541 		return usage();
   542 
   543 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
   544 		if (strcmp(razor_commands[i].name, argv[1]) == 0)
   545 			return razor_commands[i].func(argc - 2, argv + 2);
   546 
   547 	return usage();
   548 }