main.c
author Kristian H?gsberg <krh@redhat.com>
Mon Jun 09 12:47:37 2008 -0400 (2008-06-09)
changeset 230 c1e2aed8dd07
parent 212 e8f493d8ff9a
child 231 fef9808171ff
permissions -rw-r--r--
Rewrite depsolver to use a series of passes over all packages.

The big change is that we follow one step of the depedency chain for
each package to resolve in each iteration, and repeat until there are
no more possible moves. In contrast the old depsolver would try to
follow the dependency chain completely for one package at a time.

This new approach is simpler and faster, and at the same time more
roboust. Instead of knowing how one newly installed package may
affect other packages (obsoleting, pulling in new packages etc), the
new algorithm just looks at the total list of requires, provides,
obsoletes and conflicts after installing new packages.
krh@212
     1
/*
krh@212
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
krh@212
     3
 * Copyright (C) 2008  Red Hat, Inc
krh@212
     4
 *
krh@212
     5
 * This program is free software; you can redistribute it and/or modify
krh@212
     6
 * it under the terms of the GNU General Public License as published by
krh@212
     7
 * the Free Software Foundation; either version 2 of the License, or
krh@212
     8
 * (at your option) any later version.
krh@212
     9
 *
krh@212
    10
 * This program is distributed in the hope that it will be useful,
krh@212
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
krh@212
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
krh@212
    13
 * GNU General Public License for more details.
krh@212
    14
 *
krh@212
    15
 * You should have received a copy of the GNU General Public License along
krh@212
    16
 * with this program; if not, write to the Free Software Foundation, Inc.,
krh@212
    17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
krh@212
    18
 */
krh@212
    19
krh@43
    20
#include <stdlib.h>
krh@43
    21
#include <stddef.h>
krh@43
    22
#include <stdio.h>
krh@186
    23
#include <stdint.h>
krh@43
    24
#include <string.h>
krh@72
    25
#include <sys/stat.h>
krh@43
    26
#include <unistd.h>
krh@197
    27
#include <fcntl.h>
krh@75
    28
#include <dirent.h>
krh@71
    29
#include <curl/curl.h>
krh@94
    30
#include <fnmatch.h>
krh@206
    31
#include <errno.h>
krh@43
    32
#include "razor.h"
krh@151
    33
#include "razor-internal.h"
krh@43
    34
krh@152
    35
static const char system_repo_filename[] = "system.repo";
krh@171
    36
static const char next_repo_filename[] = "system-next.repo";
krh@152
    37
static const char rawhide_repo_filename[] = "rawhide.repo";
krh@152
    38
static const char updated_repo_filename[] = "system-updated.repo";
krh@152
    39
static const char razor_root_path[] = "/var/lib/razor";
krh@152
    40
static const char root[] = "install";
krh@152
    41
static const char *repo_filename = system_repo_filename;
krh@43
    42
krh@43
    43
static int
krh@43
    44
command_list(int argc, const char *argv[])
krh@43
    45
{
krh@43
    46
	struct razor_set *set;
krh@92
    47
	struct razor_package_iterator *pi;
krh@92
    48
	struct razor_package *package;
krh@192
    49
	const char *pattern, *name, *version, *arch;
krh@187
    50
	int only_names = 0, i = 0;
krh@43
    51
krh@193
    52
	if (i < argc && strcmp(argv[i], "--only-names") == 0) {
krh@187
    53
		only_names = 1;
krh@187
    54
		i++;
krh@187
    55
	}
krh@187
    56
krh@187
    57
	pattern = argv[i];
krh@43
    58
	set = razor_set_open(repo_filename);
krh@92
    59
	pi = razor_package_iterator_create(set);
krh@192
    60
	while (razor_package_iterator_next(pi, &package,
krh@192
    61
					   &name, &version, &arch)) {
krh@92
    62
		if (pattern && fnmatch(pattern, name, 0) != 0)
krh@92
    63
			continue;
krh@92
    64
krh@187
    65
		if (only_names)
krh@187
    66
			printf("%s\n", name);
krh@187
    67
		else
krh@192
    68
			printf("%s-%s.%s\n", name, version, arch);
krh@92
    69
	}
krh@92
    70
	razor_package_iterator_destroy(pi);
krh@92
    71
	razor_set_destroy(set);
krh@92
    72
krh@92
    73
	return 0;
krh@92
    74
}
krh@92
    75
krh@92
    76
static int
krh@92
    77
list_properties(const char *package_name,
krh@92
    78
		enum razor_property_type required_type)
krh@92
    79
{
krh@230
    80
	static const char *relation_string[] = { "<", "<=", "=", ">=", ">" };
krh@92
    81
	struct razor_set *set;
krh@92
    82
	struct razor_property *property;
krh@92
    83
	struct razor_package *package;
krh@92
    84
	struct razor_property_iterator *pi;
krh@92
    85
	const char *name, *version;
krh@92
    86
	enum razor_property_type type;
danw@109
    87
	enum razor_version_relation relation;
krh@92
    88
krh@92
    89
	set = razor_set_open(repo_filename);
krh@92
    90
	if (package_name)
krh@92
    91
		package = razor_set_get_package(set, package_name);
krh@92
    92
	else
krh@92
    93
		package = NULL;
krh@92
    94
krh@92
    95
	pi = razor_property_iterator_create(set, package);
krh@92
    96
	while (razor_property_iterator_next(pi, &property,
danw@109
    97
					    &name, &relation, &version,
danw@109
    98
					    &type)) {
krh@92
    99
		if (type != required_type)
krh@92
   100
			continue;
krh@92
   101
		if (version[0] == '\0')
krh@92
   102
			printf("%s\n", name);
krh@92
   103
		else
danw@137
   104
			printf("%s %s %s\n", name,
krh@230
   105
			       relation_string[relation], version);
krh@92
   106
	}
krh@92
   107
	razor_property_iterator_destroy(pi);
krh@92
   108
krh@43
   109
	razor_set_destroy(set);
krh@43
   110
krh@43
   111
	return 0;
krh@43
   112
}
krh@43
   113
krh@43
   114
static int
krh@43
   115
command_list_requires(int argc, const char *argv[])
krh@43
   116
{
krh@92
   117
	return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES);
krh@43
   118
}
krh@43
   119
krh@43
   120
static int
krh@43
   121
command_list_provides(int argc, const char *argv[])
krh@43
   122
{
krh@92
   123
	return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES);
krh@43
   124
}
krh@43
   125
krh@43
   126
static int
krh@67
   127
command_list_obsoletes(int argc, const char *argv[])
krh@67
   128
{
krh@92
   129
	return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES);
krh@67
   130
}
krh@67
   131
krh@67
   132
static int
krh@67
   133
command_list_conflicts(int argc, const char *argv[])
krh@67
   134
{
krh@92
   135
	return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS);
krh@67
   136
}
krh@67
   137
krh@67
   138
static int
krh@48
   139
command_list_files(int argc, const char *argv[])
krh@48
   140
{
krh@48
   141
	struct razor_set *set;
krh@48
   142
krh@48
   143
	set = razor_set_open(repo_filename);
krh@48
   144
	if (set == NULL)
krh@48
   145
		return 1;
krh@49
   146
	razor_set_list_files(set, argv[0]);
krh@48
   147
	razor_set_destroy(set);
krh@48
   148
krh@48
   149
	return 0;
krh@48
   150
}
krh@48
   151
krh@48
   152
static int
krh@52
   153
command_list_file_packages(int argc, const char *argv[])
krh@52
   154
{
krh@52
   155
	struct razor_set *set;
krh@102
   156
	struct razor_package_iterator *pi;
krh@102
   157
	struct razor_package *package;
krh@192
   158
	const char *name, *version, *arch;
krh@52
   159
krh@52
   160
	set = razor_set_open(repo_filename);
krh@52
   161
	if (set == NULL)
krh@52
   162
		return 1;
krh@102
   163
krh@102
   164
	pi = razor_package_iterator_create_for_file(set, argv[0]);
krh@192
   165
	while (razor_package_iterator_next(pi, &package,
krh@192
   166
					   &name, &version, &arch))
krh@102
   167
		printf("%s-%s\n", name, version);
krh@102
   168
	razor_package_iterator_destroy(pi);
krh@102
   169
krh@52
   170
	razor_set_destroy(set);
krh@52
   171
krh@52
   172
	return 0;
krh@52
   173
}
krh@52
   174
krh@56
   175
static int
krh@56
   176
command_list_package_files(int argc, const char *argv[])
krh@56
   177
{
krh@56
   178
	struct razor_set *set;
krh@56
   179
krh@56
   180
	set = razor_set_open(repo_filename);
krh@56
   181
	if (set == NULL)
krh@56
   182
		return 1;
krh@56
   183
	razor_set_list_package_files(set, argv[0]);
krh@56
   184
	razor_set_destroy(set);
krh@56
   185
krh@56
   186
	return 0;
krh@56
   187
}
krh@52
   188
krh@101
   189
static void
krh@101
   190
list_packages_for_property(struct razor_set *set,
krh@101
   191
			   struct razor_property *property)
krh@101
   192
{
krh@101
   193
	struct razor_package_iterator *pi;
krh@101
   194
	struct razor_package *package;
krh@192
   195
	const char *name, *version, *arch;
krh@101
   196
krh@101
   197
	pi = razor_package_iterator_create_for_property(set, property);
krh@192
   198
	while (razor_package_iterator_next(pi, &package,
krh@192
   199
					   &name, &version, &arch))
krh@192
   200
		printf("%s-%s.%s\n", name, version, arch);
krh@101
   201
	razor_package_iterator_destroy(pi);
krh@101
   202
}
krh@101
   203
krh@52
   204
static int
krh@100
   205
list_property_packages(const char *ref_name,
krh@100
   206
		       const char *ref_version,
krh@100
   207
		       enum razor_property_type ref_type)
krh@43
   208
{
krh@43
   209
	struct razor_set *set;
krh@100
   210
	struct razor_property *property;
krh@100
   211
	struct razor_property_iterator *pi;
krh@100
   212
	const char *name, *version;
krh@100
   213
	enum razor_property_type type;
danw@109
   214
	enum razor_version_relation relation;
krh@100
   215
krh@100
   216
	if (ref_name == NULL)
krh@100
   217
		return 0;
krh@43
   218
krh@43
   219
	set = razor_set_open(repo_filename);
krh@100
   220
	if (set == NULL)
krh@100
   221
		return 1;
krh@100
   222
krh@100
   223
	pi = razor_property_iterator_create(set, NULL);
krh@100
   224
	while (razor_property_iterator_next(pi, &property,
danw@109
   225
					    &name, &relation, &version,
danw@109
   226
					    &type)) {
krh@100
   227
		if (strcmp(ref_name, name) != 0)
krh@100
   228
			continue;
danw@109
   229
		if (ref_version && relation == RAZOR_VERSION_EQUAL &&
danw@109
   230
		    strcmp(ref_version, version) != 0)
krh@100
   231
			continue;
krh@100
   232
		if (ref_type != type)
krh@100
   233
			continue;
krh@100
   234
krh@101
   235
		list_packages_for_property(set, property);
krh@100
   236
	}
krh@100
   237
	razor_property_iterator_destroy(pi);
krh@43
   238
krh@43
   239
	return 0;
krh@43
   240
}
krh@43
   241
krh@43
   242
static int
krh@100
   243
command_what_requires(int argc, const char *argv[])
krh@100
   244
{
krh@100
   245
	return list_property_packages(argv[0], argv[1],
krh@100
   246
				      RAZOR_PROPERTY_REQUIRES);
krh@100
   247
}
krh@100
   248
krh@100
   249
static int
krh@43
   250
command_what_provides(int argc, const char *argv[])
krh@43
   251
{
krh@100
   252
	return list_property_packages(argv[0], argv[1],
krh@100
   253
				      RAZOR_PROPERTY_PROVIDES);
krh@43
   254
}
krh@43
   255
krh@73
   256
static int
krh@73
   257
show_progress(void *clientp,
krh@73
   258
	      double dltotal, double dlnow, double ultotal, double ulnow)
krh@73
   259
{
krh@73
   260
	const char *file = clientp;
krh@73
   261
krh@73
   262
	if (!dlnow < dltotal)
krh@73
   263
		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
krh@73
   264
			file, (int) dlnow / 1024, (int) dltotal / 1024);
krh@73
   265
krh@73
   266
	return 0;
krh@73
   267
}
krh@73
   268
krh@73
   269
static int
krh@194
   270
download_if_missing(const char *url, const char *file)
krh@73
   271
{
krh@194
   272
	CURL *curl;
krh@73
   273
	struct stat buf;
krh@73
   274
	char error[256];
krh@73
   275
	FILE *fp;
krh@73
   276
	CURLcode res;
krh@204
   277
	long response;
krh@73
   278
krh@194
   279
	curl = curl_easy_init();
krh@194
   280
	if (curl == NULL)
krh@194
   281
		return 1;
krh@194
   282
krh@73
   283
	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
krh@73
   284
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
krh@73
   285
	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
krh@73
   286
	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
krh@73
   287
krh@73
   288
	if (stat(file, &buf) < 0) {
krh@73
   289
		fp = fopen(file, "w");
krh@207
   290
		if (fp == NULL) {
krh@207
   291
			fprintf(stderr,
krh@207
   292
				"failed to open %s for writing\n", file);
krh@207
   293
			return -1;
krh@207
   294
		}
krh@73
   295
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
krh@187
   296
		curl_easy_setopt(curl, CURLOPT_URL, url);
krh@73
   297
		res = curl_easy_perform(curl);
krh@73
   298
		fclose(fp);
krh@73
   299
		if (res != CURLE_OK) {
krh@73
   300
			fprintf(stderr, "curl error: %s\n", error);
krh@73
   301
			unlink(file);
krh@73
   302
			return -1;
krh@73
   303
		}
krh@204
   304
		res = curl_easy_getinfo(curl,
krh@204
   305
					CURLINFO_RESPONSE_CODE, &response);
krh@204
   306
		if (res != CURLE_OK) {
krh@204
   307
			fprintf(stderr, "curl error: %s\n", error);
krh@204
   308
                        unlink(file);
krh@204
   309
                        return -1;
krh@204
   310
		}
krh@204
   311
		if (response != 200) {
krh@204
   312
			fprintf(stderr, " - failed %ld\n", response);
krh@204
   313
                        unlink(file);
krh@204
   314
                        return -1;
krh@204
   315
		}
krh@188
   316
		fprintf(stderr, "\n");
krh@73
   317
	}
krh@73
   318
krh@194
   319
	curl_easy_cleanup(curl);
krh@194
   320
krh@73
   321
	return 0;
krh@73
   322
}
krh@73
   323
krh@71
   324
#define REPO_URL "http://download.fedora.redhat.com" \
krh@187
   325
	"/pub/fedora/linux/development/i386/os"
krh@71
   326
krh@43
   327
static int
krh@43
   328
command_import_yum(int argc, const char *argv[])
krh@43
   329
{
krh@43
   330
	struct razor_set *set;
krh@71
   331
krh@194
   332
	if (download_if_missing(REPO_URL "/repodata/primary.xml.gz",
krh@187
   333
				"primary.xml.gz") < 0)
krh@73
   334
		return -1;
krh@194
   335
	if (download_if_missing(REPO_URL "/repodata/filelists.xml.gz",
krh@187
   336
				"filelists.xml.gz") < 0)
krh@73
   337
		return -1;
krh@43
   338
krh@70
   339
	set = razor_set_create_from_yum();
krh@43
   340
	if (set == NULL)
krh@43
   341
		return 1;
krh@43
   342
	razor_set_write(set, rawhide_repo_filename);
krh@43
   343
	razor_set_destroy(set);
krh@43
   344
	printf("wrote %s\n", rawhide_repo_filename);
krh@43
   345
krh@43
   346
	return 0;
krh@43
   347
}
krh@43
   348
krh@43
   349
static int
krh@43
   350
command_import_rpmdb(int argc, const char *argv[])
krh@43
   351
{
krh@43
   352
	struct razor_set *set;
krh@43
   353
krh@43
   354
	set = razor_set_create_from_rpmdb();
krh@43
   355
	if (set == NULL)
krh@43
   356
		return 1;
krh@43
   357
	razor_set_write(set, repo_filename);
krh@43
   358
	razor_set_destroy(set);
krh@43
   359
	printf("wrote %s\n", repo_filename);
krh@43
   360
krh@43
   361
	return 0;
krh@43
   362
}
krh@43
   363
krh@43
   364
static int
krh@208
   365
mark_packages_for_update(struct razor_transaction *trans,
krh@208
   366
			 struct razor_set *set, const char *pattern)
krh@208
   367
{
krh@208
   368
	struct razor_package_iterator *pi;
krh@208
   369
	struct razor_package *package;
krh@208
   370
	const char *name, *version, *arch;
krh@208
   371
	int matches = 0;
krh@208
   372
krh@208
   373
	pi = razor_package_iterator_create(set);
krh@208
   374
	while (razor_package_iterator_next(pi, &package,
krh@208
   375
					   &name, &version, &arch)) {
krh@208
   376
		if (pattern && fnmatch(pattern, name, 0) == 0) {
krh@230
   377
			razor_transaction_update_package(trans, package);
krh@208
   378
			matches++;
krh@208
   379
		}
krh@208
   380
	}
krh@208
   381
	razor_package_iterator_destroy(pi);
krh@208
   382
krh@208
   383
	return matches;
krh@208
   384
}
krh@208
   385
krh@208
   386
static int
krh@208
   387
mark_packages_for_removal(struct razor_transaction *trans,
krh@208
   388
			  struct razor_set *set, const char *pattern)
krh@208
   389
{
krh@208
   390
	struct razor_package_iterator *pi;
krh@208
   391
	struct razor_package *package;
krh@208
   392
	const char *name, *version, *arch;
krh@208
   393
	int matches = 0;
krh@208
   394
krh@208
   395
	pi = razor_package_iterator_create(set);
krh@208
   396
	while (razor_package_iterator_next(pi, &package,
krh@208
   397
					   &name, &version, &arch)) {
krh@208
   398
		if (pattern && fnmatch(pattern, name, 0) == 0) {
krh@208
   399
			razor_transaction_remove_package(trans, package);
krh@208
   400
			matches++;
krh@208
   401
		}
krh@208
   402
	}
krh@208
   403
	razor_package_iterator_destroy(pi);
krh@208
   404
krh@208
   405
	return matches;
krh@208
   406
}
krh@208
   407
krh@208
   408
static int
krh@43
   409
command_update(int argc, const char *argv[])
krh@43
   410
{
krh@43
   411
	struct razor_set *set, *upstream;
danw@137
   412
	struct razor_transaction *trans;
krh@208
   413
	int i, errors;
krh@43
   414
krh@43
   415
	set = razor_set_open(repo_filename);
krh@43
   416
	upstream = razor_set_open(rawhide_repo_filename);
krh@43
   417
	if (set == NULL || upstream == NULL)
krh@43
   418
		return 1;
krh@208
   419
krh@208
   420
	trans = razor_transaction_create(set, upstream);
krh@208
   421
	if (argc == 0)
krh@208
   422
		razor_transaction_update_all(trans);
krh@208
   423
	for (i = 0; i < argc; i++) {
krh@230
   424
		if (mark_packages_for_update(trans, set, argv[i]) == 0) {
krh@208
   425
			fprintf(stderr, "no match for %s\n", argv[i]);
krh@208
   426
			return 1;
krh@208
   427
		}
krh@208
   428
	}
krh@208
   429
		
krh@210
   430
	errors = razor_transaction_resolve(trans);
krh@190
   431
	if (errors)
danw@137
   432
		return 1;
danw@137
   433
krh@196
   434
	set = razor_transaction_finish(trans);
krh@44
   435
	razor_set_write(set, updated_repo_filename);
krh@43
   436
	razor_set_destroy(set);
krh@43
   437
	razor_set_destroy(upstream);
krh@43
   438
	printf("wrote system-updated.repo\n");
krh@43
   439
krh@43
   440
	return 0;
krh@43
   441
}
krh@43
   442
danw@129
   443
static int
danw@129
   444
command_remove(int argc, const char *argv[])
danw@129
   445
{
danw@129
   446
	struct razor_set *set;
danw@137
   447
	struct razor_transaction *trans;
krh@208
   448
	int i, errors;
danw@129
   449
danw@129
   450
	set = razor_set_open(repo_filename);
danw@129
   451
	if (set == NULL)
danw@129
   452
		return 1;
krh@208
   453
krh@208
   454
	trans = razor_transaction_create(set, NULL);
krh@208
   455
	for (i = 0; i < argc; i++) {
krh@208
   456
		if (mark_packages_for_removal(trans, set, argv[i]) == 0) {
krh@208
   457
			fprintf(stderr, "no match for %s\n", argv[i]);
krh@208
   458
			return 1;
krh@208
   459
		}
krh@208
   460
	}
krh@208
   461
krh@210
   462
	errors = razor_transaction_resolve(trans);
krh@190
   463
	if (errors)
danw@137
   464
		return 1;
danw@137
   465
krh@196
   466
	set = razor_transaction_finish(trans);
danw@129
   467
	razor_set_write(set, updated_repo_filename);
danw@129
   468
	razor_set_destroy(set);
danw@129
   469
	printf("wrote system-updated.repo\n");
danw@129
   470
danw@129
   471
	return 0;
danw@129
   472
}
danw@129
   473
krh@44
   474
static void
krh@44
   475
print_diff(const char *name,
krh@192
   476
	   const char *old_version, const char *new_version, const char *arch,
krh@192
   477
	   void *data)
krh@44
   478
{
krh@44
   479
	if (old_version)
krh@44
   480
		printf("removing %s %s\n", name, old_version);
krh@44
   481
	else
krh@44
   482
		printf("install %s %s\n", name, new_version);
krh@44
   483
}
krh@44
   484
krh@44
   485
static int
krh@44
   486
command_diff(int argc, const char *argv[])
krh@44
   487
{
krh@44
   488
	struct razor_set *set, *updated;
krh@44
   489
krh@44
   490
	set = razor_set_open(repo_filename);
krh@44
   491
	updated = razor_set_open(updated_repo_filename);
krh@44
   492
	if (set == NULL || updated == NULL)
krh@44
   493
		return 1;
krh@44
   494
krh@44
   495
	razor_set_diff(set, updated, print_diff, NULL);	
krh@44
   496
krh@44
   497
	razor_set_destroy(set);
krh@44
   498
	razor_set_destroy(updated);
krh@44
   499
krh@44
   500
	return 0;
krh@44
   501
}
krh@44
   502
krh@74
   503
static int
krh@75
   504
command_import_rpms(int argc, const char *argv[])
krh@74
   505
{
krh@75
   506
	DIR *dir;
krh@75
   507
	struct dirent *de;
krh@75
   508
	struct razor_importer *importer;
krh@75
   509
	struct razor_set *set;
krh@77
   510
	struct razor_rpm *rpm;
krh@75
   511
	int len;
krh@75
   512
	char filename[256];
krh@75
   513
	const char *dirname = argv[0];
krh@75
   514
krh@75
   515
	if (dirname == NULL) {
krh@75
   516
		fprintf(stderr, "usage: razor import-rpms DIR\n");
krh@75
   517
		return -1;
krh@75
   518
	}
krh@75
   519
krh@75
   520
	dir = opendir(dirname);
krh@75
   521
	if (dir == NULL) {
krh@75
   522
		fprintf(stderr, "couldn't read dir %s\n", dirname);
krh@75
   523
		return -1;
krh@75
   524
	}
krh@75
   525
krh@75
   526
	importer = razor_importer_new();
krh@75
   527
krh@75
   528
	while (de = readdir(dir), de != NULL) {
krh@75
   529
		len = strlen(de->d_name);
krh@75
   530
		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
krh@75
   531
		    continue;
krh@75
   532
		snprintf(filename, sizeof filename,
krh@75
   533
			 "%s/%s", dirname, de->d_name);
krh@77
   534
		rpm = razor_rpm_open(filename);
krh@77
   535
		if (rpm == NULL) {
krh@77
   536
			fprintf(stderr,
krh@77
   537
				"failed to open rpm \"%s\"\n", filename);
krh@77
   538
			continue;
krh@77
   539
		}
krh@77
   540
		if (razor_importer_add_rpm(importer, rpm)) {
krh@75
   541
			fprintf(stderr, "couldn't import %s\n", filename);
krh@75
   542
			break;
krh@75
   543
		}
krh@77
   544
		razor_rpm_close(rpm);
krh@75
   545
	}
krh@75
   546
krh@75
   547
	if (de != NULL) {
krh@75
   548
		razor_importer_destroy(importer);
krh@75
   549
		return -1;
krh@75
   550
	}
krh@75
   551
krh@75
   552
	set = razor_importer_finish(importer);
krh@75
   553
krh@75
   554
	razor_set_write(set, repo_filename);
krh@75
   555
	razor_set_destroy(set);
krh@75
   556
	printf("wrote %s\n", repo_filename);
krh@74
   557
krh@74
   558
	return 0;
krh@74
   559
}
krh@74
   560
krh@194
   561
static void
krh@194
   562
download_package(const char *name,
krh@194
   563
		 const char *old_version,
krh@194
   564
		 const char *new_version,
krh@194
   565
		 const char *arch,
krh@194
   566
		 void *data)
krh@152
   567
{
krh@194
   568
	char file[PATH_MAX], url[256];
krh@201
   569
	const char *v;
krh@204
   570
	int *errors = data;
krh@194
   571
krh@194
   572
	if (old_version)
krh@194
   573
		return;
krh@194
   574
krh@201
   575
	/* Skip epoch */
krh@201
   576
	v = strchr(new_version, ':');
krh@201
   577
	if (v != NULL)
krh@201
   578
		v = v + 1;
krh@201
   579
	else
krh@201
   580
		v = new_version;
krh@201
   581
krh@194
   582
	snprintf(url, sizeof url,
krh@201
   583
		 REPO_URL "/Packages/%s-%s.%s.rpm", name, v, arch);
krh@194
   584
	snprintf(file, sizeof file,
krh@201
   585
		 "rpms/%s-%s.%s.rpm", name, v, arch);
krh@194
   586
	if (download_if_missing(url, file) < 0)
krh@204
   587
		(*errors)++;
krh@194
   588
}
krh@194
   589
krh@194
   590
static void
krh@194
   591
install_package(const char *name,
krh@194
   592
		const char *old_version,
krh@194
   593
		const char *new_version,
krh@194
   594
		const char *arch,
krh@194
   595
		void *data)
krh@194
   596
{
krh@201
   597
	const char *v, *root = data;
krh@194
   598
	char file[PATH_MAX];
krh@152
   599
	struct razor_rpm *rpm;
krh@152
   600
krh@194
   601
	if (old_version) {
krh@194
   602
		printf("removing %s %s not handled\n", name, old_version);
krh@194
   603
		return;
krh@152
   604
	}
krh@152
   605
krh@201
   606
	/* Skip epoch */
krh@201
   607
	v = strchr(new_version, ':');
krh@201
   608
	if (v != NULL)
krh@201
   609
		v = v + 1;
krh@201
   610
	else
krh@201
   611
		v = new_version;
krh@201
   612
krh@201
   613
	printf("install %s %s\n", name, v);
krh@201
   614
	snprintf(file, sizeof file, "rpms/%s-%s.%s.rpm", name, v, arch);
krh@152
   615
krh@194
   616
 	rpm = razor_rpm_open(file);
krh@194
   617
	if (rpm == NULL) {
krh@194
   618
		fprintf(stderr, "failed to open rpm %s\n", file);
krh@194
   619
		return;
krh@194
   620
	}
krh@194
   621
	if (razor_rpm_install(rpm, root) < 0) {
krh@194
   622
		fprintf(stderr,
krh@194
   623
			"failed to install rpm %s\n", file);
krh@194
   624
		return;
krh@194
   625
	}
krh@194
   626
	razor_rpm_close(rpm);
krh@152
   627
}
krh@151
   628
krh@77
   629
static int
krh@77
   630
command_install(int argc, const char *argv[])
krh@77
   631
{
krh@171
   632
	struct razor_set *system, *upstream, *next;
krh@152
   633
	struct razor_transaction *trans;
krh@194
   634
	char path[PATH_MAX], new_path[PATH_MAX];
krh@210
   635
	int i = 0, errors, fd, dependencies = 1;
krh@210
   636
krh@210
   637
	if (i < argc && strcmp(argv[i], "--no-dependencies") == 0) {
krh@210
   638
		dependencies = 0;
krh@210
   639
		i++;
krh@210
   640
	}
krh@197
   641
krh@197
   642
	/* Create the new next repo file up front to ensure exclusive
krh@197
   643
	 * access. */
krh@197
   644
	snprintf(new_path, sizeof new_path,
krh@197
   645
		 "%s%s/%s", root, razor_root_path, next_repo_filename);
krh@197
   646
	fd = open(new_path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666);
krh@197
   647
	if (fd < 0) {
krh@197
   648
		fprintf(stderr, "failed to get lock file, "
krh@197
   649
			"maybe previous operation crashed?\n");
krh@197
   650
krh@197
   651
		/* FIXME: Use fcntl advisory locking to figure out
krh@197
   652
		 * whether previous operation crashed or is still in
krh@197
   653
		 * progress. */
krh@197
   654
krh@197
   655
		return -1;
krh@197
   656
	}
krh@151
   657
krh@194
   658
	upstream = razor_set_open(rawhide_repo_filename);
krh@152
   659
	snprintf(path, sizeof path,
krh@152
   660
		 "%s%s/%s", root, razor_root_path, system_repo_filename);
krh@152
   661
	system = razor_set_open(path);
krh@197
   662
	if (system == NULL || upstream == NULL) {
krh@197
   663
		unlink(new_path);
krh@194
   664
		return 1;
krh@197
   665
	}
krh@208
   666
	trans = razor_transaction_create(system, upstream);
krh@210
   667
	for (; i < argc; i++) {
krh@208
   668
		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
krh@208
   669
			fprintf(stderr, "no package matched %s\n", argv[i]);
krh@208
   670
			unlink(new_path);
krh@208
   671
			return 1;
krh@208
   672
		}
krh@208
   673
	}
krh@208
   674
krh@210
   675
	if (dependencies) {
krh@210
   676
		errors = razor_transaction_resolve(trans);
krh@210
   677
		if (errors) {
krh@210
   678
			unlink(new_path);
krh@210
   679
			return 1;
krh@210
   680
		}
krh@197
   681
	}
krh@152
   682
krh@196
   683
	next = razor_transaction_finish(trans);
krh@152
   684
krh@197
   685
	razor_set_write_to_fd(next, fd);
krh@194
   686
	printf("wrote %s\n", new_path);
krh@194
   687
krh@206
   688
	if (mkdir("rpms", 0777) && errno != EEXIST) {
krh@206
   689
		fprintf(stderr, "failed to create rpms directory.\n");
krh@206
   690
		return 1;
krh@206
   691
	}
krh@206
   692
krh@204
   693
	razor_set_diff(system, next, download_package, &errors);
krh@204
   694
	if (errors > 0) {
krh@204
   695
		fprintf(stderr, "failed to download %d packages\n", errors);
krh@204
   696
		unlink(new_path);
krh@204
   697
                return 1;
krh@204
   698
        }
krh@194
   699
krh@200
   700
	/* FIXME: We need to figure out the right install order here,
krh@200
   701
	 * so the post and pre scripts can run. */
krh@194
   702
	razor_set_diff(system, next, install_package, (void *) root);
krh@171
   703
krh@171
   704
	razor_set_destroy(next);
krh@171
   705
	razor_set_destroy(system);
krh@171
   706
	razor_set_destroy(upstream);
krh@171
   707
krh@171
   708
	/* Make it so. */
krh@171
   709
	rename(new_path, path);
krh@171
   710
	printf("renamed %s to %s\n", new_path, path);
krh@171
   711
krh@151
   712
	return 0;
krh@151
   713
}
krh@151
   714
krh@151
   715
static int
krh@151
   716
command_init(int argc, const char *argv[])
krh@151
   717
{
krh@77
   718
	struct stat buf;
krh@151
   719
	struct razor_set *set;
krh@151
   720
	char path[PATH_MAX];
krh@77
   721
krh@77
   722
	if (stat(root, &buf) < 0) {
krh@77
   723
		if (mkdir(root, 0777) < 0) {
krh@77
   724
			fprintf(stderr,
krh@77
   725
				"could not create install root \"%s\"\n",
krh@77
   726
				root);
krh@77
   727
			return -1;
krh@77
   728
		}
krh@77
   729
		fprintf(stderr, "created install root \"%s\"\n", root);
krh@77
   730
	} else if (!S_ISDIR(buf.st_mode)) {
krh@77
   731
		fprintf(stderr,
krh@77
   732
			"install root \"%s\" exists, but is not a directory\n",
krh@77
   733
			root);
krh@77
   734
		return -1;
krh@77
   735
	}
krh@77
   736
krh@211
   737
	snprintf(path, sizeof path, "%s/%s",
krh@211
   738
		 razor_root_path, system_repo_filename);
krh@211
   739
	if (razor_create_dir(root, path) < 0) {
krh@151
   740
		fprintf(stderr, "could not create %s%s\n",
krh@151
   741
			root, razor_root_path);
krh@77
   742
		return -1;
krh@77
   743
	}
krh@151
   744
krh@151
   745
	set = razor_set_create();
krh@151
   746
	snprintf(path, sizeof path, "%s%s/%s",
krh@152
   747
		 root, razor_root_path, system_repo_filename);
krh@151
   748
	if (razor_set_write(set, path) < 0) {
krh@151
   749
		fprintf(stderr, "could not write initial package set\n");
krh@77
   750
		return -1;
krh@77
   751
	}
krh@151
   752
	razor_set_destroy(set);
krh@77
   753
krh@77
   754
	return 0;
krh@77
   755
}
krh@77
   756
krh@187
   757
static int
krh@187
   758
command_download(int argc, const char *argv[])
krh@187
   759
{
krh@187
   760
	struct razor_set *set;
krh@187
   761
	struct razor_package_iterator *pi;
krh@187
   762
	struct razor_package *package;
krh@192
   763
	const char *pattern = argv[0], *name, *version, *arch;
krh@187
   764
	char url[256], file[256];
krh@203
   765
	int matches = 0;
krh@187
   766
krh@206
   767
	if (mkdir("rpms", 0777) && errno != EEXIST) {
krh@206
   768
		fprintf(stderr, "failed to create rpms directory.\n");
krh@206
   769
		return 1;
krh@206
   770
	}
krh@206
   771
krh@187
   772
	set = razor_set_open(rawhide_repo_filename);
krh@187
   773
	pi = razor_package_iterator_create(set);
krh@192
   774
	while (razor_package_iterator_next(pi, &package,
krh@192
   775
					   &name, &version, &arch)) {
krh@187
   776
		if (pattern && fnmatch(pattern, name, 0) != 0)
krh@187
   777
			continue;
krh@187
   778
krh@203
   779
		matches++;
krh@187
   780
		snprintf(url, sizeof url,
krh@203
   781
			 REPO_URL "/Packages/%s-%s.%s.rpm",
krh@203
   782
			 name, version, arch);
krh@187
   783
		snprintf(file, sizeof file,
krh@203
   784
			 "rpms/%s-%s.%s.rpm", name, version, arch);
krh@204
   785
		download_if_missing(url, file);
krh@187
   786
	}
krh@187
   787
	razor_package_iterator_destroy(pi);
krh@187
   788
	razor_set_destroy(set);
krh@187
   789
krh@203
   790
	if (matches == 0)
krh@203
   791
		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
krh@203
   792
	else if (matches == 1)
krh@203
   793
		fprintf(stderr, "downloaded 1 package\n");
krh@203
   794
	else
krh@205
   795
		fprintf(stderr, "downloaded %d packages\n", matches);
krh@203
   796
krh@187
   797
	return 0;
krh@187
   798
}
krh@187
   799
krh@43
   800
static struct {
krh@43
   801
	const char *name;
krh@43
   802
	const char *description;
krh@43
   803
	int (*func)(int argc, const char *argv[]);
krh@43
   804
} razor_commands[] = {
krh@43
   805
	{ "list", "list all packages", command_list },
krh@67
   806
	{ "list-requires", "list all requires for the given package", command_list_requires },
krh@75
   807
	{ "list-provides", "list all provides for the given package", command_list_provides },
krh@75
   808
	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
krh@75
   809
	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
krh@48
   810
	{ "list-files", "list files for package set", command_list_files },
krh@52
   811
	{ "list-file-packages", "list packages owning file", command_list_file_packages },
krh@56
   812
	{ "list-package-files", "list files in package", command_list_package_files },
krh@43
   813
	{ "what-requires", "list the packages that have the given requires", command_what_requires },
krh@43
   814
	{ "what-provides", "list the packages that have the given provides", command_what_provides },
krh@75
   815
	{ "import-yum", "import yum metadata files", command_import_yum },
krh@43
   816
	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
krh@75
   817
	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
krh@44
   818
	{ "update", "update all or specified packages", command_update },
danw@129
   819
	{ "remove", "remove specified packages", command_remove },
krh@77
   820
	{ "diff", "show diff between two package sets", command_diff },
krh@151
   821
	{ "install", "install rpm", command_install },
krh@187
   822
	{ "init", "init razor root", command_init },
krh@187
   823
	{ "download", "download packages", command_download }
krh@43
   824
};
krh@43
   825
krh@43
   826
static int
krh@43
   827
usage(void)
krh@43
   828
{
krh@43
   829
	int i;
krh@43
   830
krh@43
   831
	printf("usage:\n");
krh@43
   832
	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
krh@43
   833
		printf("  %-20s%s\n",
krh@43
   834
		       razor_commands[i].name, razor_commands[i].description);
krh@43
   835
krh@43
   836
	return 1;
krh@43
   837
}
krh@43
   838
krh@43
   839
int
krh@43
   840
main(int argc, const char *argv[])
krh@43
   841
{
krh@43
   842
	char *repo;
krh@43
   843
	int i;
krh@43
   844
krh@43
   845
	repo = getenv("RAZOR_REPO");
krh@43
   846
	if (repo != NULL)
krh@43
   847
		repo_filename = repo;
krh@43
   848
krh@43
   849
	if (argc < 2)
krh@43
   850
		return usage();
krh@43
   851
krh@43
   852
	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
krh@43
   853
		if (strcmp(razor_commands[i].name, argv[1]) == 0)
krh@43
   854
			return razor_commands[i].func(argc - 2, argv + 2);
krh@43
   855
krh@43
   856
	return usage();
krh@43
   857
}