diff options
author | Richard Hughes <rhughes@redhat.com> | 2008-06-16 14:43:03 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2008-06-16 15:40:30 -0400 |
commit | e967bfd71a068d6c3f5831cfa93de92d78136065 (patch) | |
tree | 80484292b4f3e4877853bf14acb7d15e5cbf108f /src | |
parent | 614b267207d0caf51c33d5c3e7036195aa0624c4 (diff) |
Autoconfify razor.
Diffstat (limited to 'src')
-rw-r--r-- | src/.gitignore | 5 | ||||
-rw-r--r-- | src/Makefile.am | 26 | ||||
-rw-r--r-- | src/import-rpmdb.c | 157 | ||||
-rw-r--r-- | src/import-yum.c | 337 | ||||
-rw-r--r-- | src/main.c | 804 | ||||
-rw-r--r-- | src/rpm.c | 897 | ||||
-rw-r--r-- | src/test-driver.c | 458 | ||||
-rw-r--r-- | src/test.xml | 858 |
8 files changed, 3542 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..25f606c --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,5 @@ +.deps +.libs +razor +rpm-razor + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..58f7788 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = \ + $(CURL_CFLAGS) \ + $(EXPAT_CFLAGS) \ + $(RPM_CFLAGS) \ + -I$(top_builddir)/src -I$(top_srcdir)/src \ + -I$(top_srcdir)/librazor \ + -DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \ + -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + -DPACKAGE_BIN_DIR=\""$(bindir)"\" \ + -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \ + -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" + +bin_PROGRAMS = razor rpm + +razor_SOURCES = main.c import-rpmdb.c import-yum.c +razor_LDADD = $(RPM_LIBS) $(EXPAT_LIBS) $(CURL_LIBS) $(top_builddir)/librazor/librazor.la + +rpm_SOURCES = rpm.c +rpm_LDADD = $(top_builddir)/librazor/librazor.la + +clean-local : + rm -f *~ + diff --git a/src/import-rpmdb.c b/src/import-rpmdb.c new file mode 100644 index 0000000..ddfed9e --- /dev/null +++ b/src/import-rpmdb.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stddef.h> +#include <string.h> +#include <fcntl.h> +#include <rpm/rpmlib.h> +#include <rpm/rpmdb.h> + +#include "razor.h" + +union rpm_entry { + void *p; + char *string; + char **list; + uint_32 *flags; + uint_32 integer; +}; + +static enum razor_version_relation +rpm_to_razor_flags (uint_32 flags) +{ + switch (flags & (RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_GREATER)) { + case RPMSENSE_LESS: + return RAZOR_VERSION_LESS; + case RPMSENSE_LESS|RPMSENSE_EQUAL: + return RAZOR_VERSION_LESS_OR_EQUAL; + case RPMSENSE_EQUAL: + return RAZOR_VERSION_EQUAL; + case RPMSENSE_GREATER|RPMSENSE_EQUAL: + return RAZOR_VERSION_GREATER_OR_EQUAL; + case RPMSENSE_GREATER: + return RAZOR_VERSION_GREATER; + } + + /* FIXME? */ + return RAZOR_VERSION_EQUAL; +} + +static void +add_properties(struct razor_importer *importer, + enum razor_property_type property_type, + Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag) +{ + union rpm_entry names, versions, flags; + int_32 i, type, count; + + headerGetEntry(h, name_tag, &type, &names.p, &count); + headerGetEntry(h, version_tag, &type, &versions.p, &count); + headerGetEntry(h, flags_tag, &type, &flags.p, &count); + + for (i = 0; i < count; i++) + razor_importer_add_property(importer, + names.list[i], + rpm_to_razor_flags (flags.flags[i]), + versions.list[i], + property_type); +} + +struct razor_set * +razor_set_create_from_rpmdb(void) +{ + struct razor_importer *importer; + rpmdbMatchIterator iter; + Header h; + int_32 type, count, i; + union rpm_entry name, epoch, version, release, arch; + union rpm_entry basenames, dirnames, dirindexes; + char filename[PATH_MAX], evr[128], buf[16]; + rpmdb db; + + rpmReadConfigFiles(NULL, NULL); + + if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) { + fprintf(stderr, "cannot open rpm database\n"); + exit(1); + } + + importer = razor_importer_new(); + + iter = rpmdbInitIterator(db, 0, NULL, 0); + while (h = rpmdbNextIterator(iter), h != NULL) { + headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count); + headerGetEntry(h, RPMTAG_EPOCH, &type, &epoch.p, &count); + headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count); + headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count); + headerGetEntry(h, RPMTAG_ARCH, &type, &arch.p, &count); + + if (epoch.flags != NULL) { + snprintf(buf, sizeof buf, "%u", *epoch.flags); + razor_build_evr(evr, sizeof evr, + buf, version.string, release.string); + } else { + razor_build_evr(evr, sizeof evr, + NULL, version.string, release.string); + } + + razor_importer_begin_package(importer, + name.string, evr, arch.string); + + add_properties(importer, RAZOR_PROPERTY_REQUIRES, h, + RPMTAG_REQUIRENAME, + RPMTAG_REQUIREVERSION, + RPMTAG_REQUIREFLAGS); + + add_properties(importer, RAZOR_PROPERTY_PROVIDES, h, + RPMTAG_PROVIDENAME, + RPMTAG_PROVIDEVERSION, + RPMTAG_PROVIDEFLAGS); + + add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h, + RPMTAG_OBSOLETENAME, + RPMTAG_OBSOLETEVERSION, + RPMTAG_OBSOLETEFLAGS); + + add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h, + RPMTAG_CONFLICTNAME, + RPMTAG_CONFLICTVERSION, + RPMTAG_CONFLICTFLAGS); + + headerGetEntry(h, RPMTAG_BASENAMES, &type, + &basenames.p, &count); + headerGetEntry(h, RPMTAG_DIRNAMES, &type, + &dirnames.p, &count); + headerGetEntry(h, RPMTAG_DIRINDEXES, &type, + &dirindexes.p, &count); + for (i = 0; i < count; i++) { + snprintf(filename, sizeof filename, "%s%s", + dirnames.list[dirindexes.flags[i]], + basenames.list[i]); + razor_importer_add_file(importer, filename); + } + + razor_importer_finish_package(importer); + } + + rpmdbClose(db); + + return razor_importer_finish(importer); +} diff --git a/src/import-yum.c b/src/import-yum.c new file mode 100644 index 0000000..c461a15 --- /dev/null +++ b/src/import-yum.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE + +#include <string.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <expat.h> +#include <zlib.h> +#include "razor.h" + +/* Import a yum filelist as a razor package set. */ + +enum { + YUM_STATE_BEGIN, + YUM_STATE_PACKAGE_NAME, + YUM_STATE_PACKAGE_ARCH, + YUM_STATE_CHECKSUM, + YUM_STATE_REQUIRES, + YUM_STATE_PROVIDES, + YUM_STATE_OBSOLETES, + YUM_STATE_CONFLICTS, + YUM_STATE_FILE +}; + +struct yum_context { + XML_Parser primary_parser; + XML_Parser filelists_parser; + XML_Parser current_parser; + + struct razor_importer *importer; + struct import_property_context *current_property_context; + char name[256], arch[64], buffer[512], *p; + char pkgid[128]; + int state; +}; + +static enum razor_version_relation +yum_to_razor_flags (const char *flags) +{ + /* FIXME? */ + if (!flags) + return RAZOR_VERSION_EQUAL; + + if (flags[0] == 'L') { + if (flags[1] == 'T') + return RAZOR_VERSION_LESS; + else + return RAZOR_VERSION_LESS_OR_EQUAL; + } else if (flags[0] == 'G') { + if (flags[1] == 'T') + return RAZOR_VERSION_GREATER; + else + return RAZOR_VERSION_GREATER_OR_EQUAL; + } else + return RAZOR_VERSION_EQUAL; +} + +static void +yum_primary_start_element(void *data, const char *name, const char **atts) +{ + struct yum_context *ctx = data; + const char *n, *epoch, *version, *release, *flags; + char buffer[128]; + int i; + + if (strcmp(name, "name") == 0) { + ctx->state = YUM_STATE_PACKAGE_NAME; + ctx->p = ctx->name; + } else if (strcmp(name, "arch") == 0) { + ctx->state = YUM_STATE_PACKAGE_ARCH; + ctx->p = ctx->arch; + } else if (strcmp(name, "version") == 0) { + epoch = NULL; + version = NULL; + release = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "epoch") == 0) + epoch = atts[i + 1]; + else if (strcmp(atts[i], "ver") == 0) + version = atts[i + 1]; + else if (strcmp(atts[i], "rel") == 0) + release = atts[i + 1]; + } + if (version == NULL || release == NULL) { + fprintf(stderr, "invalid version tag, " + "missing version or release attribute\n"); + return; + } + + razor_build_evr(buffer, sizeof buffer, epoch, version, release); + razor_importer_begin_package(ctx->importer, + ctx->name, buffer, ctx->arch); + } else if (strcmp(name, "checksum") == 0) { + ctx->p = ctx->pkgid; + ctx->state = YUM_STATE_CHECKSUM; + } else if (strcmp(name, "rpm:requires") == 0) { + ctx->state = YUM_STATE_REQUIRES; + } else if (strcmp(name, "rpm:provides") == 0) { + ctx->state = YUM_STATE_PROVIDES; + } else if (strcmp(name, "rpm:obsoletes") == 0) { + ctx->state = YUM_STATE_OBSOLETES; + } else if (strcmp(name, "rpm:conflicts") == 0) { + ctx->state = YUM_STATE_CONFLICTS; + } else if (strcmp(name, "rpm:entry") == 0 && + ctx->state != YUM_STATE_BEGIN) { + n = NULL; + epoch = NULL; + version = NULL; + release = NULL; + flags = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "name") == 0) + n = atts[i + 1]; + else if (strcmp(atts[i], "epoch") == 0) + epoch = atts[i + 1]; + else if (strcmp(atts[i], "ver") == 0) + version = atts[i + 1]; + else if (strcmp(atts[i], "rel") == 0) + release = atts[i + 1]; + else if (strcmp(atts[i], "flags") == 0) + flags = atts[i + 1]; + } + + if (n == NULL) { + fprintf(stderr, "invalid rpm:entry, " + "missing name or version attributes\n"); + return; + } + + razor_build_evr(buffer, sizeof buffer, epoch, version, release); + switch (ctx->state) { + case YUM_STATE_REQUIRES: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_REQUIRES); + break; + case YUM_STATE_PROVIDES: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_PROVIDES); + break; + case YUM_STATE_OBSOLETES: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_OBSOLETES); + break; + case YUM_STATE_CONFLICTS: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_CONFLICTS); + break; + } + } +} + +static void +yum_primary_end_element (void *data, const char *name) +{ + struct yum_context *ctx = data; + + switch (ctx->state) { + case YUM_STATE_PACKAGE_NAME: + case YUM_STATE_PACKAGE_ARCH: + case YUM_STATE_CHECKSUM: + case YUM_STATE_FILE: + ctx->state = YUM_STATE_BEGIN; + break; + } + + if (strcmp(name, "package") == 0) { + XML_StopParser(ctx->current_parser, XML_TRUE); + ctx->current_parser = ctx->filelists_parser; + } +} + +static void +yum_character_data (void *data, const XML_Char *s, int len) +{ + struct yum_context *ctx = data; + + switch (ctx->state) { + case YUM_STATE_PACKAGE_NAME: + case YUM_STATE_PACKAGE_ARCH: + case YUM_STATE_CHECKSUM: + case YUM_STATE_FILE: + memcpy(ctx->p, s, len); + ctx->p += len; + *ctx->p = '\0'; + break; + } +} + +static void +yum_filelists_start_element(void *data, const char *name, const char **atts) +{ + struct yum_context *ctx = data; + const char *pkg, *pkgid; + int i; + + if (strcmp(name, "package") == 0) { + pkg = NULL; + pkgid = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "name") == 0) + pkg = atts[i + 1]; + else if (strcmp(atts[i], "pkgid") == 0) + pkgid = atts[i + 1]; + } + if (strcmp(pkgid, ctx->pkgid) != 0) + fprintf(stderr, "primary.xml and filelists.xml " + "mismatch for %s: %s vs %s", + pkg, pkgid, ctx->pkgid); + } else if (strcmp(name, "file") == 0) { + ctx->state = YUM_STATE_FILE; + ctx->p = ctx->buffer; + } +} + + +static void +yum_filelists_end_element (void *data, const char *name) +{ + struct yum_context *ctx = data; + + ctx->state = YUM_STATE_BEGIN; + if (strcmp(name, "package") == 0) { + XML_StopParser(ctx->current_parser, XML_TRUE); + ctx->current_parser = ctx->primary_parser; + razor_importer_finish_package(ctx->importer); + } else if (strcmp(name, "file") == 0) + razor_importer_add_file(ctx->importer, ctx->buffer); + +} + +#define XML_BUFFER_SIZE 4096 + +struct razor_set * +razor_set_create_from_yum(void) +{ + struct yum_context ctx; + void *buf; + int len, ret; + gzFile primary, filelists; + XML_ParsingStatus status; + + ctx.importer = razor_importer_new(); + ctx.state = YUM_STATE_BEGIN; + + ctx.primary_parser = XML_ParserCreate(NULL); + XML_SetUserData(ctx.primary_parser, &ctx); + XML_SetElementHandler(ctx.primary_parser, + yum_primary_start_element, + yum_primary_end_element); + XML_SetCharacterDataHandler(ctx.primary_parser, + yum_character_data); + + ctx.filelists_parser = XML_ParserCreate(NULL); + XML_SetUserData(ctx.filelists_parser, &ctx); + XML_SetElementHandler(ctx.filelists_parser, + yum_filelists_start_element, + yum_filelists_end_element); + XML_SetCharacterDataHandler(ctx.filelists_parser, + yum_character_data); + + primary = gzopen("primary.xml.gz", "rb"); + if (primary == NULL) + return NULL; + filelists = gzopen("filelists.xml.gz", "rb"); + if (filelists == NULL) + return NULL; + + ctx.current_parser = ctx.primary_parser; + + do { + XML_GetParsingStatus(ctx.current_parser, &status); + switch (status.parsing) { + case XML_SUSPENDED: + ret = XML_ResumeParser(ctx.current_parser); + break; + case XML_PARSING: + case XML_INITIALIZED: + buf = XML_GetBuffer(ctx.current_parser, + XML_BUFFER_SIZE); + if (ctx.current_parser == ctx.primary_parser) + len = gzread(primary, buf, XML_BUFFER_SIZE); + else + len = gzread(filelists, buf, XML_BUFFER_SIZE); + if (len < 0) { + fprintf(stderr, + "couldn't read input: %s\n", + strerror(errno)); + return NULL; + } + + XML_ParseBuffer(ctx.current_parser, len, len == 0); + break; + case XML_FINISHED: + break; + } + } while (status.parsing != XML_FINISHED); + + + XML_ParserFree(ctx.primary_parser); + XML_ParserFree(ctx.filelists_parser); + + gzclose(primary); + gzclose(filelists); + + return razor_importer_finish(ctx.importer); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..772231b --- /dev/null +++ b/src/main.c @@ -0,0 +1,804 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <curl/curl.h> +#include <fnmatch.h> +#include <errno.h> +#include "razor.h" + +static const char system_repo_filename[] = "system.repo"; +static const char next_repo_filename[] = "system-next.repo"; +static const char rawhide_repo_filename[] = "rawhide.repo"; +static const char updated_repo_filename[] = "system-updated.repo"; +static const char install_root[] = "install"; +static const char *repo_filename = system_repo_filename; +static const char *yum_url; + +static int +command_list(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *pattern, *name, *version, *arch; + int only_names = 0, i = 0; + + if (i < argc && strcmp(argv[i], "--only-names") == 0) { + only_names = 1; + i++; + } + + pattern = argv[i]; + set = razor_set_open(repo_filename); + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) != 0) + continue; + + if (only_names) + printf("%s\n", name); + else + printf("%s-%s.%s\n", name, version, arch); + } + razor_package_iterator_destroy(pi); + razor_set_destroy(set); + + return 0; +} + +static int +list_properties(const char *package_name, + enum razor_property_type required_type) +{ + static const char *relation_string[] = { "<", "<=", "=", ">=", ">" }; + struct razor_set *set; + struct razor_property *property; + struct razor_package *package; + struct razor_property_iterator *pi; + const char *name, *version; + enum razor_property_type type; + enum razor_version_relation relation; + + set = razor_set_open(repo_filename); + if (package_name) + package = razor_set_get_package(set, package_name); + else + package = NULL; + + pi = razor_property_iterator_create(set, package); + while (razor_property_iterator_next(pi, &property, + &name, &relation, &version, + &type)) { + if (type != required_type) + continue; + if (version[0] == '\0') + printf("%s\n", name); + else + printf("%s %s %s\n", name, + relation_string[relation], version); + } + razor_property_iterator_destroy(pi); + + razor_set_destroy(set); + + return 0; +} + +static int +command_list_requires(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES); +} + +static int +command_list_provides(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES); +} + +static int +command_list_obsoletes(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES); +} + +static int +command_list_conflicts(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS); +} + +static int +command_list_files(int argc, const char *argv[]) +{ + struct razor_set *set; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + razor_set_list_files(set, argv[0]); + razor_set_destroy(set); + + return 0; +} + +static int +command_list_file_packages(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + + pi = razor_package_iterator_create_for_file(set, argv[0]); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) + printf("%s-%s\n", name, version); + razor_package_iterator_destroy(pi); + + razor_set_destroy(set); + + return 0; +} + +static int +command_list_package_files(int argc, const char *argv[]) +{ + struct razor_set *set; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + razor_set_list_package_files(set, argv[0]); + razor_set_destroy(set); + + return 0; +} + +static void +list_packages_for_property(struct razor_set *set, + struct razor_property *property) +{ + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + pi = razor_package_iterator_create_for_property(set, property); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) + printf("%s-%s.%s\n", name, version, arch); + razor_package_iterator_destroy(pi); +} + +static int +list_property_packages(const char *ref_name, + const char *ref_version, + enum razor_property_type ref_type) +{ + struct razor_set *set; + struct razor_property *property; + struct razor_property_iterator *pi; + const char *name, *version; + enum razor_property_type type; + enum razor_version_relation relation; + + if (ref_name == NULL) + return 0; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + + pi = razor_property_iterator_create(set, NULL); + while (razor_property_iterator_next(pi, &property, + &name, &relation, &version, + &type)) { + if (strcmp(ref_name, name) != 0) + continue; + if (ref_version && relation == RAZOR_VERSION_EQUAL && + strcmp(ref_version, version) != 0) + continue; + if (ref_type != type) + continue; + + list_packages_for_property(set, property); + } + razor_property_iterator_destroy(pi); + + return 0; +} + +static int +command_what_requires(int argc, const char *argv[]) +{ + return list_property_packages(argv[0], argv[1], + RAZOR_PROPERTY_REQUIRES); +} + +static int +command_what_provides(int argc, const char *argv[]) +{ + return list_property_packages(argv[0], argv[1], + RAZOR_PROPERTY_PROVIDES); +} + +static int +show_progress(void *clientp, + double dltotal, double dlnow, double ultotal, double ulnow) +{ + const char *file = clientp; + + if (!dlnow < dltotal) + fprintf(stderr, "\rdownloading %s, %dkB/%dkB", + file, (int) dlnow / 1024, (int) dltotal / 1024); + + return 0; +} + +static int +download_if_missing(const char *url, const char *file) +{ + CURL *curl; + struct stat buf; + char error[256]; + FILE *fp; + CURLcode res; + long response; + + curl = curl_easy_init(); + if (curl == NULL) + return 1; + + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file); + + if (stat(file, &buf) < 0) { + fp = fopen(file, "w"); + if (fp == NULL) { + fprintf(stderr, + "failed to open %s for writing\n", file); + return -1; + } + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + curl_easy_setopt(curl, CURLOPT_URL, url); + res = curl_easy_perform(curl); + fclose(fp); + if (res != CURLE_OK) { + fprintf(stderr, "curl error: %s\n", error); + unlink(file); + return -1; + } + res = curl_easy_getinfo(curl, + CURLINFO_RESPONSE_CODE, &response); + if (res != CURLE_OK) { + fprintf(stderr, "curl error: %s\n", error); + unlink(file); + return -1; + } + if (response != 200) { + fprintf(stderr, " - failed %ld\n", response); + unlink(file); + return -1; + } + fprintf(stderr, "\n"); + } + + curl_easy_cleanup(curl); + + return 0; +} + +#define YUM_URL "http://download.fedora.redhat.com" \ + "/pub/fedora/linux/development/i386/os" + +static int +command_import_yum(int argc, const char *argv[]) +{ + struct razor_set *set; + char buffer[512]; + + printf("downloading from %s.\n", yum_url); + snprintf(buffer, sizeof buffer, + "%s/repodata/primary.xml.gz", yum_url); + if (download_if_missing(buffer, "primary.xml.gz") < 0) + return -1; + snprintf(buffer, sizeof buffer, + "%s/repodata/filelists.xml.gz", yum_url); + if (download_if_missing(buffer, "filelists.xml.gz") < 0) + return -1; + + set = razor_set_create_from_yum(); + if (set == NULL) + return 1; + razor_set_write(set, rawhide_repo_filename); + razor_set_destroy(set); + printf("wrote %s\n", rawhide_repo_filename); + + return 0; +} + +static int +command_import_rpmdb(int argc, const char *argv[]) +{ + struct razor_set *set; + + set = razor_set_create_from_rpmdb(); + if (set == NULL) + return 1; + razor_set_write(set, repo_filename); + razor_set_destroy(set); + printf("wrote %s\n", repo_filename); + + return 0; +} + +static int +mark_packages_for_update(struct razor_transaction *trans, + struct razor_set *set, const char *pattern) +{ + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + int matches = 0; + + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) == 0) { + razor_transaction_update_package(trans, package); + matches++; + } + } + razor_package_iterator_destroy(pi); + + return matches; +} + +static int +mark_packages_for_removal(struct razor_transaction *trans, + struct razor_set *set, const char *pattern) +{ + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + int matches = 0; + + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) == 0) { + razor_transaction_remove_package(trans, package); + matches++; + } + } + razor_package_iterator_destroy(pi); + + return matches; +} + +static int +command_update(int argc, const char *argv[]) +{ + struct razor_set *set, *upstream; + struct razor_transaction *trans; + int i, errors; + + set = razor_set_open(repo_filename); + upstream = razor_set_open(rawhide_repo_filename); + if (set == NULL || upstream == NULL) + return 1; + + trans = razor_transaction_create(set, upstream); + if (argc == 0) + razor_transaction_update_all(trans); + for (i = 0; i < argc; i++) { + if (mark_packages_for_update(trans, set, argv[i]) == 0) { + fprintf(stderr, "no match for %s\n", argv[i]); + return 1; + } + } + + errors = razor_transaction_resolve(trans); + if (errors) + return 1; + + set = razor_transaction_finish(trans); + razor_set_write(set, updated_repo_filename); + razor_set_destroy(set); + razor_set_destroy(upstream); + printf("wrote system-updated.repo\n"); + + return 0; +} + +static int +command_remove(int argc, const char *argv[]) +{ + struct razor_set *set, *upstream; + struct razor_transaction *trans; + int i, errors; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + + upstream = razor_set_create(); + trans = razor_transaction_create(set, upstream); + for (i = 0; i < argc; i++) { + if (mark_packages_for_removal(trans, set, argv[i]) == 0) { + fprintf(stderr, "no match for %s\n", argv[i]); + return 1; + } + } + + errors = razor_transaction_resolve(trans); + if (errors) + return 1; + + set = razor_transaction_finish(trans); + razor_set_write(set, updated_repo_filename); + razor_set_destroy(set); + razor_set_destroy(upstream); + printf("wrote system-updated.repo\n"); + + return 0; +} + +static void +print_diff(const char *name, + const char *old_version, const char *new_version, const char *arch, + void *data) +{ + if (old_version) + printf("removing %s %s\n", name, old_version); + else + printf("install %s %s\n", name, new_version); +} + +static int +command_diff(int argc, const char *argv[]) +{ + struct razor_set *set, *updated; + + set = razor_set_open(repo_filename); + updated = razor_set_open(updated_repo_filename); + if (set == NULL || updated == NULL) + return 1; + + razor_set_diff(set, updated, print_diff, NULL); + + razor_set_destroy(set); + razor_set_destroy(updated); + + return 0; +} + +static int +command_import_rpms(int argc, const char *argv[]) +{ + DIR *dir; + struct dirent *de; + struct razor_importer *importer; + struct razor_set *set; + struct razor_rpm *rpm; + int len; + char filename[256]; + const char *dirname = argv[0]; + + if (dirname == NULL) { + fprintf(stderr, "usage: razor import-rpms DIR\n"); + return -1; + } + + dir = opendir(dirname); + if (dir == NULL) { + fprintf(stderr, "couldn't read dir %s\n", dirname); + return -1; + } + + importer = razor_importer_new(); + + while (de = readdir(dir), de != NULL) { + len = strlen(de->d_name); + if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0) + continue; + snprintf(filename, sizeof filename, + "%s/%s", dirname, de->d_name); + rpm = razor_rpm_open(filename); + if (rpm == NULL) { + fprintf(stderr, + "failed to open rpm \"%s\"\n", filename); + continue; + } + if (razor_importer_add_rpm(importer, rpm)) { + fprintf(stderr, "couldn't import %s\n", filename); + break; + } + razor_rpm_close(rpm); + } + + if (de != NULL) { + razor_importer_destroy(importer); + return -1; + } + + set = razor_importer_finish(importer); + + razor_set_write(set, repo_filename); + razor_set_destroy(set); + printf("wrote %s\n", repo_filename); + + return 0; +} + +static void +download_package(const char *name, + const char *old_version, + const char *new_version, + const char *arch, + void *data) +{ + char file[PATH_MAX], url[256]; + const char *v; + int *errors = data; + + if (old_version) + return; + + /* Skip epoch */ + v = strchr(new_version, ':'); + if (v != NULL) + v = v + 1; + else + v = new_version; + + snprintf(url, sizeof url, + "%s/Packages/%s-%s.%s.rpm", yum_url, name, v, arch); + snprintf(file, sizeof file, + "rpms/%s-%s.%s.rpm", name, v, arch); + if (download_if_missing(url, file) < 0) + (*errors)++; +} + +static void +install_package(const char *name, + const char *old_version, + const char *new_version, + const char *arch, + void *data) +{ + const char *v, *root = data; + char file[PATH_MAX]; + struct razor_rpm *rpm; + + if (old_version) { + printf("removing %s %s not handled\n", name, old_version); + return; + } + + /* Skip epoch */ + v = strchr(new_version, ':'); + if (v != NULL) + v = v + 1; + else + v = new_version; + + printf("install %s %s\n", name, v); + snprintf(file, sizeof file, "rpms/%s-%s.%s.rpm", name, v, arch); + + rpm = razor_rpm_open(file); + if (rpm == NULL) { + fprintf(stderr, "failed to open rpm %s\n", file); + return; + } + if (razor_rpm_install(rpm, root) < 0) { + fprintf(stderr, + "failed to install rpm %s\n", file); + return; + } + razor_rpm_close(rpm); +} + +static int +command_install(int argc, const char *argv[]) +{ + struct razor_root *root; + struct razor_set *upstream, *next; + struct razor_transaction *trans; + int i = 0, errors, dependencies = 1; + + if (i < argc && strcmp(argv[i], "--no-dependencies") == 0) { + dependencies = 0; + i++; + } + + root = razor_root_open(install_root, RAZOR_ROOT_OPEN_WRITE); + upstream = razor_set_open(rawhide_repo_filename); + trans = razor_root_create_transaction(root, upstream); + + for (; i < argc; i++) { + if (mark_packages_for_update(trans, upstream, argv[i]) == 0) { + fprintf(stderr, "no package matched %s\n", argv[i]); + razor_root_close(root); + return 1; + } + } + + if (dependencies) { + errors = razor_transaction_resolve(trans); + if (errors) { + razor_root_close(root); + return 1; + } + } + + next = razor_transaction_finish(trans); + + razor_root_update(root, next); + + if (mkdir("rpms", 0777) && errno != EEXIST) { + fprintf(stderr, "failed to create rpms directory.\n"); + razor_root_close(root); + return 1; + } + + razor_root_diff(root, download_package, &errors); + if (errors > 0) { + fprintf(stderr, "failed to download %d packages\n", errors); + razor_root_close(root); + return 1; + } + + /* FIXME: We need to figure out the right install order here, + * so the post and pre scripts can run. */ + razor_root_diff(root, install_package, (void *) root); + + razor_set_destroy(next); + razor_set_destroy(upstream); + + return razor_root_commit(root); +} + +static int +command_init(int argc, const char *argv[]) +{ + return razor_root_create(install_root); +} + +static int +command_download(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *pattern = argv[0], *name, *version, *arch; + char url[256], file[256]; + int matches = 0; + + if (mkdir("rpms", 0777) && errno != EEXIST) { + fprintf(stderr, "failed to create rpms directory.\n"); + return 1; + } + + set = razor_set_open(rawhide_repo_filename); + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) != 0) + continue; + + matches++; + snprintf(url, sizeof url, + "%s/Packages/%s-%s.%s.rpm", + yum_url, name, version, arch); + snprintf(file, sizeof file, + "rpms/%s-%s.%s.rpm", name, version, arch); + download_if_missing(url, file); + } + razor_package_iterator_destroy(pi); + razor_set_destroy(set); + + if (matches == 0) + fprintf(stderr, "no packages matched \"%s\"\n", pattern); + else if (matches == 1) + fprintf(stderr, "downloaded 1 package\n"); + else + fprintf(stderr, "downloaded %d packages\n", matches); + + return 0; +} + +static struct { + const char *name; + const char *description; + int (*func)(int argc, const char *argv[]); +} razor_commands[] = { + { "list", "list all packages", command_list }, + { "list-requires", "list all requires for the given package", command_list_requires }, + { "list-provides", "list all provides for the given package", command_list_provides }, + { "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes }, + { "list-conflicts", "list all conflicts for the given package", command_list_conflicts }, + { "list-files", "list files for package set", command_list_files }, + { "list-file-packages", "list packages owning file", command_list_file_packages }, + { "list-package-files", "list files in package", command_list_package_files }, + { "what-requires", "list the packages that have the given requires", command_what_requires }, + { "what-provides", "list the packages that have the given provides", command_what_provides }, + { "import-yum", "import yum metadata files", command_import_yum }, + { "import-rpmdb", "import the system rpm database", command_import_rpmdb }, + { "import-rpms", "import rpms from the given directory", command_import_rpms }, + { "update", "update all or specified packages", command_update }, + { "remove", "remove specified packages", command_remove }, + { "diff", "show diff between two package sets", command_diff }, + { "install", "install rpm", command_install }, + { "init", "init razor root", command_init }, + { "download", "download packages", command_download } +}; + +static int +usage(void) +{ + int i; + + printf("usage:\n"); + for (i = 0; i < ARRAY_SIZE(razor_commands); i++) + printf(" %-20s%s\n", + razor_commands[i].name, razor_commands[i].description); + + return 1; +} + +int +main(int argc, const char *argv[]) +{ + char *repo; + int i; + + repo = getenv("RAZOR_REPO"); + if (repo != NULL) + repo_filename = repo; + + yum_url = getenv("YUM_URL"); + if (yum_url == NULL) + yum_url = YUM_URL; + + if (argc < 2) + return usage(); + + for (i = 0; i < ARRAY_SIZE(razor_commands); i++) + if (strcmp(razor_commands[i].name, argv[1]) == 0) + return razor_commands[i].func(argc - 2, argv + 2); + + return usage(); +} diff --git a/src/rpm.c b/src/rpm.c new file mode 100644 index 0000000..6a3ea80 --- /dev/null +++ b/src/rpm.c @@ -0,0 +1,897 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <dirent.h> +#include "razor.h" + +enum option_type { + OPTION_LAST, + OPTION_GROUP, + OPTION_BOOL, + OPTION_STRING +}; + +struct option { + enum option_type type; + const char *name; + char short_name; + const char *arg_name; + const char *description; + void *data; +}; + +/* A note about all these options: rpm allows options to mean + * different things depending on what other options are present on the + * command line. For example, if -q or --query is present, -i no + * longer means install, but info. The way we handle this is by + * setting all the options that may match (ie if -i is given we set + * install and info), and then look at the relevent one depending on + * what else in on the command line. */ + +static int option_all, option_whatrequires, option_whatprovides; +static int option_package; + +static const struct option query_options[] = { + { OPTION_BOOL, "configfiles", 'c', NULL, "list all configuration files", NULL }, + { OPTION_BOOL, "docfiles", 'd', NULL, "list all documentation files", NULL }, + { OPTION_BOOL, "dump", 0, NULL, "dump basic file information", NULL }, + { OPTION_BOOL, "list", 0, NULL, "list files in package", NULL }, + { OPTION_STRING, "queryformat", 0, "QUERYFORMAT", "use the following query format", NULL }, + { OPTION_BOOL, "state", 's', NULL, "display the states of the listed files", NULL }, + { OPTION_BOOL, "all", 'a', NULL, "query/verify all packages", &option_all }, + { OPTION_BOOL, "file", 'f', NULL, "query/verify package(s) owning file", NULL }, + { OPTION_BOOL, "group", 'g', NULL, "query/verify package(s) in group", NULL }, + { OPTION_BOOL, "package", 'p', NULL, "query/verify a package file", &option_package }, + { OPTION_BOOL, "ftswalk", 'W', NULL, "query/verify package(s) from TOP file tree walk", NULL }, + { OPTION_BOOL, "pkgid", 0, NULL, "query/verify package(s) with package identifier", NULL }, + { OPTION_BOOL, "hdrid", 0, NULL, "query/verify package(s) with header identifier", NULL }, + { OPTION_BOOL, "fileid", 0, NULL, "query/verify package(s) with file identifier", NULL }, + { OPTION_BOOL, "specfile", 0, NULL, "query a spec file", NULL, }, + { OPTION_BOOL, "triggeredby", 0, NULL, "query the package(s) triggered by the package", NULL }, + { OPTION_BOOL, "whatrequires", 0, NULL, "query/verify the package(s) which require a dependency", &option_whatrequires }, + { OPTION_BOOL, "whatprovides", 0, NULL, "query/verify the package(s) which provide a dependency", &option_whatprovides }, + { OPTION_BOOL, "nomanifest", 0, NULL, "do not process non-package files as manifests", NULL }, + { } +}; + +static int option_nodeps; + +static const struct option verify_options[] = { + { OPTION_BOOL, "nomd5", 0, NULL, "don't verify MD5 digest of files", NULL }, + { OPTION_BOOL, "nofiles", 0, NULL, "don't verify files in package", NULL }, + { OPTION_BOOL, "nodeps", 0, NULL, "don't verify package dependencies", &option_nodeps }, + { OPTION_BOOL, "noscript", 0, NULL, "don't execute verify script(s)", NULL, }, + { OPTION_BOOL, "all", 'a', NULL, "query/verify all packages", &option_all }, + { OPTION_BOOL, "file", 'f', NULL, "query/verify package(s) owning file", NULL }, + { OPTION_BOOL, "group", 'g', NULL, "query/verify package(s) in group", NULL }, + { OPTION_BOOL, "package", 'p', NULL, "query/verify a package file", &option_package }, + { OPTION_BOOL, "ftswalk", 'W', NULL, "query/verify package(s) from TOP file tree walk", NULL }, + { OPTION_BOOL, "pkgid", 0, NULL, "query/verify package(s) with package identifier", NULL }, + { OPTION_BOOL, "hdrid", 0, NULL, "query/verify package(s) with header identifier", NULL }, + { OPTION_BOOL, "fileid", 0, NULL, "query/verify package(s) with file identifier", NULL }, + { OPTION_BOOL, "specfile", 0, NULL, "query a spec file", NULL }, + { OPTION_BOOL, "triggeredby", 0, NULL, "query the package(s) triggered by the package", NULL }, + { OPTION_BOOL, "whatrequires", 0, NULL, "query/verify the package(s) which require a dependency", &option_whatrequires }, + { OPTION_BOOL, "whatprovides", 0, NULL, "query/verify the package(s) which provide a dependency", &option_whatprovides }, + { OPTION_BOOL, "nomanifest", 0, NULL, "do not process non-package files as manifests", NULL }, + { } +}; + +static const struct option ftw_options[] = { + { OPTION_BOOL, "comfollow", 0, NULL, "FTS_COMFOLLOW: follow command line symlinks", NULL }, + { OPTION_BOOL, "logical", 0, NULL, "FTS_LOGICAL: logical walk", NULL }, + { OPTION_BOOL, "nochdir", 0, NULL, "FTS_NOCHDIR: don't change directories", NULL }, + { OPTION_BOOL, "nostat", 0, NULL, "FTS_NOSTAT: don't get stat info", NULL }, + { OPTION_BOOL, "physical", 0, NULL, "FTS_PHYSICAL: physical walk", NULL }, + { OPTION_BOOL, "seedot", 0, NULL, "FTS_SEEDOT: return dot and dot-dot", NULL }, + { OPTION_BOOL, "xdev", 0, NULL, "FTS_XDEV: don't cross devices", NULL }, + { OPTION_BOOL, "whiteout", 0, NULL, "FTS_WHITEOUT: return whiteout information", NULL }, + { } +}; + +static const struct option signature_options[] = { + { OPTION_BOOL, "addsign", 0, NULL, "sign package(s) (identical to --resign)", NULL, }, + { OPTION_BOOL, "checksig", 'K', NULL, "verify package signature(s)", NULL, }, + { OPTION_BOOL, "delsign", 0, NULL, "delete package signatures", NULL, }, + { OPTION_BOOL, "import", 0, NULL, "import an armored public key", NULL, }, + { OPTION_BOOL, "resign", 0, NULL, "sign package(s) (identical to --addsign)", NULL, }, + { OPTION_BOOL, "nodigest", 0, NULL, "don't verify package digest(s)", NULL, }, + { OPTION_BOOL, "nosignature", 0, NULL, "don't verify package signature(s)", NULL }, + { } +}; + +static int option_initdb; + +static const struct option database_options[] = { + { OPTION_BOOL, "initdb", 0, NULL, "initialize database", &option_initdb }, + { OPTION_BOOL, "rebuilddb", 0, NULL, "rebuild database inverted lists from installed package headers", NULL }, + { } +}; + +static int option_erase, option_install, option_upgrade, option_justdb; +static int option_test; + +static const struct option install_options[] = { + { OPTION_BOOL, "aid", 0, NULL, "add suggested packages to transaction", NULL, }, + { OPTION_BOOL, "allfiles", 0, NULL, "install all files, even configurations which might otherwise be skipped", NULL, }, + { OPTION_BOOL, "allmatches", 0, NULL, "remove all packages which match <package> (normally an error is generated if <package> specified multiple packages)", NULL, }, + { OPTION_BOOL, "badreloc", 0, NULL, "relocate files in non-relocatable package", NULL }, + { OPTION_BOOL, "erase", 'e', "<package>", "erase (uninstall) package", &option_erase }, + { OPTION_BOOL, "excludedocs", 0, NULL, "do not install documentation", NULL, }, + { OPTION_BOOL, "excludepath", 0, "<path>", "skip files with leading component <path> ", NULL, }, + { OPTION_BOOL, "fileconflicts", 0, NULL, "detect file conflicts between packages", NULL, }, + { OPTION_BOOL, "force", 0, NULL, "short hand for --replacepkgs --replacefiles", NULL }, + { OPTION_BOOL, "freshen", 'F', "<packagefile>+", "upgrade package(s) if already installed", NULL }, + { OPTION_BOOL, "hash", 'h', NULL, "print hash marks as package installs (good with -v)", NULL }, + { OPTION_BOOL, "ignorearch", 0, NULL, "don't verify package architecture", NULL, }, + { OPTION_BOOL, "ignoreos", 0, NULL, "don't verify package operating system", NULL, }, + { OPTION_BOOL, "ignoresize", 0, NULL, "don't check disk space before installing", NULL }, + { OPTION_BOOL, "install", 'i', NULL, "install package(s)", &option_install }, + { OPTION_BOOL, "justdb", 0, NULL, "update the database, but do not modify the filesystem", &option_justdb, }, + { OPTION_BOOL, "nodeps", 0, NULL, "do not verify package dependencies", &option_nodeps, }, + { OPTION_BOOL, "nomd5", 0, NULL, "don't verify MD5 digest of files", NULL, }, + { OPTION_BOOL, "nocontexts", 0, NULL, "don't install file security contexts", NULL, }, + { OPTION_BOOL, "noorder", 0, NULL, "do not reorder package installation to satisfy dependencies", NULL, }, + { OPTION_BOOL, "nosuggest", 0, NULL, "do not suggest missing dependency resolution(s)", NULL, }, + { OPTION_BOOL, "noscripts", 0, NULL, "do not execute package scriptlet(s)", NULL, }, + { OPTION_BOOL, "notriggers", 0, NULL, "do not execute any scriptlet(s) triggered by this package", NULL, }, + { OPTION_BOOL, "oldpackage", 0, NULL, "upgrade to an old version of the package (--force on upgrades does this automatically)", NULL }, + { OPTION_BOOL, "percent", 0, NULL, "print percentages as package installs", NULL, }, + { OPTION_STRING, "prefix", 0, "<dir>", "relocate the package to <dir>, if relocatable", NULL, }, + { OPTION_STRING, "relocate", 0, "<old>=<new>", "relocate files from path <old> to <new>", NULL, }, + { OPTION_BOOL, "repackage", 0, NULL, "save erased package files by repackaging", NULL, }, + { OPTION_BOOL, "replacefiles", 0, NULL, "ignore file conflicts between packages", NULL, }, + { OPTION_BOOL, "replacepkgs", 0, NULL, "reinstall if the package is already present", NULL, }, + { OPTION_BOOL, "test", 0, NULL, "don't install, but tell if it would work or not", &option_test }, + { OPTION_BOOL, "upgrade", 'U', "<packagefile>+", "upgrade package(s)", &option_upgrade }, + { } +}; + +static int option_version; +static const char *option_root = "install"; + +static const struct option common_options[] = { + { OPTION_STRING, "define", 'D', "MACRO EXPR", "define MACRO with value EXPR", NULL, }, + { OPTION_STRING, "eval", 'E', "EXPR", "print macro expansion of EXPR", NULL }, + { OPTION_STRING, "macros", 0, "<FILE:...>", "read <FILE:...> instead of default file(s)", NULL }, + { OPTION_BOOL, "nodigest", 0, NULL, "don't verify package digest(s)", NULL, }, + { OPTION_BOOL, "nosignature", 0, NULL, "don't verify package signature(s)", NULL, }, + { OPTION_STRING, "rcfile", 0, "<FILE:...>", "read <FILE:...> instead of default file(s)", NULL }, + { OPTION_STRING, "root", 'r', "ROOT", "use ROOT as top level directory (default: \"/\")", &option_root }, + { OPTION_BOOL, "querytags", 0, NULL, "display known query tags", NULL, }, + { OPTION_BOOL, "showrc", 0, NULL, "display final rpmrc and macro configuration", NULL, }, + { OPTION_BOOL, "quiet", 0, NULL, "provide less detailed output", NULL }, + { OPTION_BOOL, "verbose", 'v', NULL, "provide more detailed output", NULL }, + { OPTION_BOOL, "version", 0, NULL, "print the version of rpm being used", &option_version }, + { } +}; + +static int option_conflicts, option_obsoletes, option_requires; +static int option_provides, option_info, option_changelog; + +static const struct option alias_options[] = { + { OPTION_BOOL, "scripts", 0, NULL, "list install/erase scriptlets from package(s)", NULL, }, + { OPTION_BOOL, "setperms", 0, NULL, "set permissions of files in a package", NULL, }, + { OPTION_BOOL, "setugids", 0, NULL, "set user/group ownership of files in a package", NULL, }, + { OPTION_BOOL, "conflicts", 0, NULL, "list capabilities this package conflicts with", &option_conflicts, }, + { OPTION_BOOL, "obsoletes", 0, NULL, "list other packages removed by installing this package", &option_obsoletes, }, + { OPTION_BOOL, "provides", 0, NULL, "list capabilities that this package provides", &option_provides, }, + { OPTION_BOOL, "requires", 0, NULL, "list capabilities required by package(s)", &option_requires, }, + { OPTION_BOOL, "info", 'i', NULL, "list descriptive information from package(s)", &option_info, }, + { OPTION_BOOL, "changelog", 0, NULL, "list change logs for this package", &option_changelog, }, + { OPTION_BOOL, "xml", 0, NULL, "list metadata in xml", NULL, }, + { OPTION_BOOL, "triggers", 0, NULL, "list trigger scriptlets from package(s)", NULL, }, + { OPTION_BOOL, "last", 0, NULL, "list package(s) by install time, most recent first", NULL, }, + { OPTION_BOOL, "dupes", 0, NULL, "list duplicated packages", NULL, }, + { OPTION_BOOL, "filesbypkg", 0, NULL, "list all files from each package", NULL, }, + { OPTION_BOOL, "fileclass", 0, NULL, "list file names with classes", NULL, }, + { OPTION_BOOL, "filecolor", 0, NULL, "list file names with colors", NULL, }, + { OPTION_BOOL, "filecontext", 0, NULL, "list file names with security context from header", NULL, }, + { OPTION_BOOL, "fscontext", 0, NULL, "list file names with security context from file system", NULL, }, + { OPTION_BOOL, "recontext", 0, NULL, "list file names with security context from policy RE", NULL, }, + { OPTION_BOOL, "fileprovide", 0, NULL, "list file names with provides", NULL, }, + { OPTION_BOOL, "filerequire", 0, NULL, "list file names with requires", NULL, }, + { OPTION_BOOL, "redhatprovides", 0, NULL, "find package name that contains a provided capability (needs rpmdb-redhat package installed)", NULL, }, + { OPTION_BOOL, "redhatrequires", 0, NULL, "find package name that contains a required capability (needs rpmdb-redhat package installed)", NULL, }, + { OPTION_STRING, "buildpolicy", 0, "<policy>", "set buildroot <policy> (e.g. compress man pages)", NULL, }, + { OPTION_BOOL, "with", 0, "<option>", "enable configure <option> for build", NULL, }, + { OPTION_BOOL, "without", 0, "<option>", "disable configure <option> for build", NULL }, + { } +}; + +static int option_help, option_usage; + +static const struct option help_options[] = { + { OPTION_BOOL, "help", '?', NULL, "Show this help message", &option_help }, + { OPTION_BOOL, "usage", 0, NULL, "Display brief usage message", &option_usage}, + { } +}; + +static int option_query, option_verify; + +static const struct option rpm_options[] = { + { OPTION_BOOL, "query", 'q', NULL, "Query rpm database", &option_query }, + { OPTION_BOOL, "verify", 'V', NULL, "Verify rpm database", &option_verify }, + { OPTION_GROUP, NULL, 0, NULL, "Query options (with -q or --query):", &query_options }, + { OPTION_GROUP, NULL, 0, NULL, "Verify options (with -V or --verify):", &verify_options }, + { OPTION_GROUP, NULL, 0, NULL, "File tree walk options (with --ftswalk):", &ftw_options }, + { OPTION_GROUP, NULL, 0, NULL, "Signature options:", &signature_options }, + { OPTION_GROUP, NULL, 0, NULL, "Database options:", &database_options }, + { OPTION_GROUP, NULL, 0, NULL, "Install/Upgrade/Erase options:", &install_options }, + { OPTION_GROUP, NULL, 0, NULL, "Common options for all rpm modes and executables:", &common_options }, + { OPTION_GROUP, NULL, 0, NULL, "Options implemented via popt alias/exec:", &alias_options }, + { OPTION_GROUP, NULL, 0, NULL, "Help options", &help_options }, + { } +}; + +static const char system_repo_filename[] = "system.repo"; +static const char *repo_filename = system_repo_filename; + +static void +command_initdb(int argc, const char *argv[]) +{ + razor_root_create(option_root); +} + +static struct razor_property * +add_property_packages(struct razor_set *set, + struct razor_package_query *query, + const char *ref_name, + const char *ref_version, + enum razor_property_type ref_type) +{ + struct razor_property *property; + struct razor_property_iterator *pi; + struct razor_package_iterator *pkgi; + const char *name, *version; + enum razor_property_type type; + enum razor_version_relation relation; + + pi = razor_property_iterator_create(set, NULL); + while (razor_property_iterator_next(pi, &property, &name, + &relation, &version, &type)) { + if (strcmp(ref_name, name) != 0) + continue; + if (ref_version && relation == RAZOR_VERSION_EQUAL && + strcmp(ref_version, version) != 0) + continue; + if (ref_type != type) + continue; + + pkgi = razor_package_iterator_create_for_property(set, + property); + razor_package_query_add_iterator(query, pkgi); + razor_package_iterator_destroy(pkgi); + } + razor_property_iterator_destroy(pi); + + return property; +} + +static int +strcmpp(const void *p1, const void *p2) +{ + return strcmp(*(char * const *) p1, *(char * const *) p2); +} + +static void +add_command_line_packages(struct razor_set *set, + struct razor_package_query *query, + int argc, const char **argv) +{ + struct razor_package *package; + struct razor_package_iterator *pi; + const char *name, *version, *arch; + int i, cmp, errors; + + qsort(argv, argc, sizeof(*argv), strcmpp); + i = 0; + errors = 0; + + pi = razor_package_iterator_create(set); + + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + while (cmp = strcmp(argv[i], name), cmp < 0 && i < argc) { + fprintf(stderr, "error: package %s is not installed\n", + argv[i]); + errors++; + i++; + } + + if (cmp == 0) { + razor_package_query_add_package(query, package); + i++; + } + } + + razor_package_iterator_destroy(pi); + + if (errors) + exit(1); +} + +static struct razor_package_iterator * +get_query_packages(struct razor_set *set, int argc, const char *argv[]) +{ + struct razor_package_query *query; + struct razor_package_iterator *pi; + int i; + + if (option_all + option_whatprovides + option_whatrequires > 1) { + printf("only one type of query/verify " + "may be performed at a time\n"); + exit(1); + } + + query = razor_package_query_create(set); + + if (option_all) { + pi = razor_package_iterator_create(set); + razor_package_query_add_iterator(query, pi); + razor_package_iterator_destroy(pi); + } else if (option_whatrequires) { + for (i = 0; i < argc; i++) + add_property_packages(set, query, + argv[i], NULL, + RAZOR_PROPERTY_REQUIRES); + } else if (option_whatprovides) { + for (i = 0; i < argc; i++) + add_property_packages(set, query, + argv[i], NULL, + RAZOR_PROPERTY_PROVIDES); + } else if (argc > 0) { + add_command_line_packages(set, query, argc, argv); + } else { + printf("no arguments given for query/verify\n"); + exit(1); + } + + return razor_package_query_finish(query); +} + +static const char *relation_string[] = { "<", "<=", "=", ">=", ">" }; + +static void +print_package_properties(struct razor_set *set, + struct razor_package *package, + enum razor_property_type ref_type) +{ + struct razor_property *property; + struct razor_property_iterator *pi; + const char *name, *version; + enum razor_property_type type; + enum razor_version_relation relation; + + pi = razor_property_iterator_create(set, package); + while (razor_property_iterator_next(pi, &property, + &name, &relation, &version, + &type)) { + if (type != ref_type) + continue; + if (version[0] == '\0') + printf("%s\n", name); + else + printf("%s %s %s\n", name, + relation_string[relation], version); + } + razor_property_iterator_destroy(pi); +} + +static void +print_package_info(struct razor_set *set, struct razor_package *package) +{ + printf("FIXME: Package info not tracked.\n"); +} + +static void +print_package_changelog(struct razor_set *set, struct razor_package *package) +{ + printf("FIXME: Package changelog not tracked.\n"); +} + +static struct razor_set * +create_set_from_command_line(int argc, const char *argv[]) +{ + struct razor_importer *importer; + struct razor_rpm *rpm; + int i; + + importer = razor_importer_new(); + + for (i = 0; i < argc; i++) { + rpm = razor_rpm_open(argv[i]); + if (rpm == NULL) + continue; + if (razor_importer_add_rpm(importer, rpm)) + printf("couldn't import %s\n", argv[i]); + + razor_rpm_close(rpm); + } + + return razor_importer_finish(importer); +} + +static void +command_query(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + if (option_package) { + set = create_set_from_command_line(argc, argv); + argc = 0; + option_all = 1; + } else { + set = razor_root_open_read_only(option_root); + } + + pi = get_query_packages(set, argc, argv); + + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (option_conflicts) + print_package_properties(set, package, + RAZOR_PROPERTY_CONFLICTS); + if (option_obsoletes) + print_package_properties(set, package, + RAZOR_PROPERTY_OBSOLETES); + if (option_requires) + print_package_properties(set, package, + RAZOR_PROPERTY_REQUIRES); + if (option_provides) + print_package_properties(set, package, + RAZOR_PROPERTY_PROVIDES); + if (option_info) + print_package_info(set, package); + if (option_changelog) + print_package_changelog(set, package); + + if (option_conflicts + option_obsoletes + + option_requires + option_provides + + option_info + option_changelog == 0) + printf("%s-%s.%s\n", name, version, arch); + } + + razor_package_iterator_destroy(pi); + + razor_set_destroy(set); + + return; +} + +static void +command_verify(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + if (option_package) { + set = create_set_from_command_line(argc, argv); + argc = 0; + option_all = 1; + } else { + set = razor_root_open_read_only(option_root); + } + + pi = get_query_packages(set, argc, argv); + + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + printf("verify %s-%s.%s - not implemented\n", + name, version, arch); + } + + razor_package_iterator_destroy(pi); +} + +static void +remove_package(const char *name, + const char *old_version, const char *new_version, + const char *arch, void *data) +{ + if (old_version) + printf("remove %s-%s.%s\n", name, old_version, arch); +} + +static void +command_erase(int argc, const char *argv[]) +{ + struct razor_set *set, *upstream, *next; + struct razor_transaction *trans; + struct razor_package_query *query; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + if (argc == 0) { + printf("no packages given for erase\n"); + exit(1); + } + + set = razor_set_open(repo_filename); + upstream = razor_set_create(); + + trans = razor_transaction_create(set, upstream); + + query = razor_package_query_create(set); + add_command_line_packages(set, query, argc, argv); + + pi = razor_package_query_finish(query); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) + razor_transaction_remove_package(trans, package); + razor_package_iterator_destroy(pi); + + if (!option_nodeps && razor_transaction_describe(trans) > 0) { + printf("unsatisfied dependencies.\n"); + exit(1); + } + + if (option_test) + exit(0); + + next = razor_transaction_finish(trans); + + if (!option_justdb) + razor_set_diff(set, next, remove_package, NULL); + + razor_set_destroy(set); + razor_set_destroy(upstream); + + razor_set_destroy(next); +} + +static void +install_package(const char *name, + const char *old_version, const char *new_version, + const char *arch, void *data) +{ + if (new_version) + printf("install %s-%s.%s\n", name, new_version, arch); +} + +static void +command_install(int argc, const char *argv[]) +{ + struct razor_set *set, *upstream, *next; + struct razor_transaction *trans; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + if (argc == 0) { + printf("no packages given for install\n"); + exit(1); + } + + set = razor_set_open(repo_filename); + upstream = create_set_from_command_line(argc, argv); + + trans = razor_transaction_create(set, upstream); + + pi = razor_package_iterator_create(upstream); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) + razor_transaction_install_package(trans, package); + razor_package_iterator_destroy(pi); + + if (!option_nodeps && razor_transaction_describe(trans) > 0) { + printf("unsatisfied dependencies.\n"); + exit(1); + } + + if (option_test) + exit(0); + + next = razor_transaction_finish(trans); + + if (!option_justdb) + razor_set_diff(set, next, install_package, NULL); + + razor_set_destroy(set); + razor_set_destroy(upstream); + + razor_set_destroy(next); +} + +static void +update_package(const char *name, + const char *old_version, const char *new_version, + const char *arch, void *data) +{ + if (old_version) + printf("remove %s-%s.%s\n", name, old_version, arch); + if (new_version) + printf("install %s-%s.%s\n", name, new_version, arch); +} + +static void +command_update(int argc, const char *argv[]) +{ + struct razor_set *set, *upstream, *next; + struct razor_transaction *trans; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + if (argc == 0) { + printf("no packages given for update\n"); + exit(1); + } + + set = razor_set_open(repo_filename); + upstream = create_set_from_command_line(argc, argv); + + trans = razor_transaction_create(set, upstream); + + pi = razor_package_iterator_create(upstream); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) + razor_transaction_update_package(trans, package); + razor_package_iterator_destroy(pi); + + if (!option_nodeps && razor_transaction_describe(trans) > 0) { + printf("unsatisfied dependencies.\n"); + exit(1); + } + + if (option_test) + exit(0); + + next = razor_transaction_finish(trans); + + if (!option_justdb) + razor_set_diff(set, next, update_package, NULL); + + razor_set_destroy(set); + razor_set_destroy(upstream); + + razor_set_destroy(next); +} + +static int +for_each_option(const struct option *options, + const char *name, char short_name, + void (*fn)(const struct option *o, + const char *name, char short_name, + void *data), void *data) +{ + int i, count = 0; + + for (i = 0; options[i].type != OPTION_LAST; i++) { + switch (options[i].type) { + case OPTION_GROUP: + count += for_each_option(options[i].data, + name, short_name, fn, data); + break; + + case OPTION_BOOL: + case OPTION_STRING: + if (name && strcmp(options[i].name, name) == 0) { + fn(&options[i], name, 0, data); + count++; + break; + } + + if (short_name && + short_name == options[i].short_name) { + fn(&options[i], NULL, short_name, data); + count++; + break; + } + break; + + case OPTION_LAST: + break; + } + } + + return count; +} + +static void +handle_option(const struct option *o, + const char *name, char short_name, void *data) +{ + if (o->data == NULL) { + if (name) + printf("option --%s not supported\n", name); + else + printf("option -%c not supported\n", short_name); + return; + } + + switch (o->type) { + case OPTION_BOOL: + *(int *) o->data = 1; + break; + + case OPTION_STRING: + *(const char **) o->data = name + strlen(o->name) + 1; + break; + + case OPTION_LAST: + case OPTION_GROUP: + /* Shouldn't happen. */ + break; + } +} + +static int +parse_options(const struct option *options, int argc, const char **argv) +{ + int i, j, k; + + for (i = 1, j = 0; i < argc; i++) { + if (argv[i][0] != '-') { + argv[j++] = argv[i]; + continue; + } + + if (argv[i][1] == '-') { + if (for_each_option(options, &argv[i][2], 0, + handle_option, NULL) == 0) { + printf("unknown option: %s\n", argv[i]); + exit(1); + } + continue; + } + + for (k = 1; argv[i][k]; k++) { + if (for_each_option(options, NULL, argv[i][k], + handle_option, NULL) == 0) { + printf("unknown option: -%c\n", argv[i][k]); + exit(1); + } + } + } + + return j; +} + +static void +print_options_help(const struct option *options) +{ + int i; + + for (i = 0; options[i].type != OPTION_LAST; i++) { + switch (options[i].type) { + case OPTION_GROUP: + printf("%s\n", options[i].description); + print_options_help(options[i].data); + printf("\n"); + break; + + case OPTION_BOOL: + case OPTION_STRING: + printf(" "); + if (options[i].short_name) + printf("-%c", options[i].short_name); + if (options[i].short_name && options[i].name) + printf(", "); + if (options[i].name) + printf("--%s", options[i].name); + if (options[i].arg_name) + printf("=%s", options[i].arg_name); + if (options[i].description) + printf("\t\t%s", options[i].description); + printf("\n"); + break; + + case OPTION_LAST: + break; + } + } +} + +static void +print_options_usage(const struct option *options) +{ + int i; + + for (i = 0; options[i].type != OPTION_LAST; i++) { + switch (options[i].type) { + case OPTION_GROUP: + print_options_usage(options[i].data); + break; + + case OPTION_BOOL: + printf("["); + if (options[i].short_name) + printf("-%c", options[i].short_name); + if (options[i].short_name && options[i].name) + printf("|"); + if (options[i].name) + printf("--%s", options[i].name); + printf("] "); + break; + + case OPTION_STRING: + printf("["); + if (options[i].short_name) + printf("-%c", options[i].short_name); + if (options[i].short_name && options[i].name) + printf("|"); + if (options[i].name) + printf("--%s", options[i].name); + if (options[i].arg_name) + printf("=%s", options[i].arg_name); + printf("] "); + break; + + + break; + + case OPTION_LAST: + break; + } + } +} + +int +main(int argc, const char *argv[]) +{ + argc = parse_options(rpm_options, argc, argv); + + if (option_version) { + printf("razor rpm version hoopla.\n"); + exit(0); + } + + if (option_help) { + printf("Usage: rpm [OPTION...]\n"); + print_options_help(rpm_options); + exit(0); + } + + if (option_usage) { + printf("Usage: rpm [OPTION...]\n"); + print_options_usage(rpm_options); + printf("\n"); + exit(0); + } + + if (option_initdb) { + command_initdb(argc, argv); + } else if (option_verify) { + command_verify(argc, argv); + } else if (option_query) { + command_query(argc, argv); + } else if (option_install) { + command_install(argc, argv); + } else if (option_upgrade) { + command_update(argc, argv); + } else if (option_erase) { + command_erase(argc, argv); + } else { + print_options_usage(rpm_options); + printf("\n"); + exit(0); + } + + return 0; +} diff --git a/src/test-driver.c b/src/test-driver.c new file mode 100644 index 0000000..876d248 --- /dev/null +++ b/src/test-driver.c @@ -0,0 +1,458 @@ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <expat.h> + +#include "razor.h" + +#define XML_BUFFER_SIZE 4096 + +static void +parse_xml_file(const char *filename, + XML_StartElementHandler start, + XML_EndElementHandler end, + void *data) +{ + XML_Parser parser; + char *buffer; + int fd, len, err; + + parser = XML_ParserCreate(NULL); + XML_SetElementHandler(parser, start, end); + XML_SetUserData(parser, data); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "failed to open %s: %m\n", filename); + exit(-1); + } + + while (1) { + buffer = XML_GetBuffer(parser, XML_BUFFER_SIZE); + len = read(fd, buffer, XML_BUFFER_SIZE); + if (len == 0) + break; + err = XML_ParseBuffer(parser, len, len == 0); + if (err == XML_STATUS_ERROR) { + fprintf(stderr, "parse error at line %lu:\n%s\n", + XML_GetCurrentLineNumber(parser), + XML_ErrorString(XML_GetErrorCode(parser))); + exit(-1); + } + } + + if (fd < 0) { + fprintf(stderr, "read: %m\n"); + exit(-1); + } + + close(fd); +} + +struct test_context { + struct razor_set *system_set, *repo_set, *result_set; + + struct razor_importer *importer; + struct razor_set **importer_set; + + struct razor_transaction *trans; + + char *install_pkgs[3], *remove_pkgs[3]; + int n_install_pkgs, n_remove_pkgs; + + int unsat; + int in_result; + + int debug, errors; +}; + +static void +get_atts(const char **atts, ...) +{ + va_list ap; + const char *name, **ptr; + int i; + + va_start(ap, atts); + while (name = va_arg(ap, const char *), name != NULL) { + ptr = va_arg(ap, const char **); + *ptr = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], name) == 0) + *ptr = atts[i + 1]; + } + } + va_end(ap); +} + +static enum razor_version_relation +parse_relation (const char *rel_str) +{ + if (!rel_str) + return -1; + if (rel_str[0] == 'L') + return rel_str[1] == 'E' ? RAZOR_VERSION_LESS_OR_EQUAL : RAZOR_VERSION_LESS; + else if (rel_str[0] == 'G') + return rel_str[1] == 'E' ? RAZOR_VERSION_GREATER_OR_EQUAL : RAZOR_VERSION_GREATER; + else if (rel_str[0] == 'E' || rel_str[1] == 'Q') + return RAZOR_VERSION_EQUAL; + else + return -1; +} + +static void +start_test(struct test_context *ctx, const char **atts) +{ + const char *name = NULL; + + get_atts(atts, "name", &name, NULL); + if (!name) { + fprintf(stderr, "Test with no name\n"); + exit(1); + } + printf("%s\n", name); +} + +static void +end_test(struct test_context *ctx) +{ + if (ctx->system_set) { + razor_set_destroy(ctx->system_set); + ctx->system_set = NULL; + } + if (ctx->repo_set) { + razor_set_destroy(ctx->repo_set); + ctx->repo_set = NULL; + } + if (ctx->result_set) { + razor_set_destroy(ctx->result_set); + ctx->result_set = NULL; + } + if (ctx->trans) { + razor_transaction_destroy(ctx->trans); + ctx->trans = NULL; + } +} + +static void +start_set(struct test_context *ctx, const char **atts) +{ + const char *name = NULL; + + ctx->importer = razor_importer_new(); + get_atts(atts, "name", &name, NULL); + if (!name) + ctx->importer_set = &ctx->result_set; + else if (!strcmp(name, "system")) + ctx->importer_set = &ctx->system_set; + else if (!strcmp(name, "repo")) + ctx->importer_set = &ctx->repo_set; + else { + fprintf(stderr, " bad set name '%s'\n", name); + exit(1); + } +} + +static void +end_set(struct test_context *ctx) +{ + *ctx->importer_set = razor_importer_finish(ctx->importer); + ctx->importer = NULL; +} + +static void +start_package(struct test_context *ctx, const char **atts) +{ + const char *name = NULL, *version = NULL, *arch = NULL; + + get_atts(atts, "name", &name, + "version", &version, + "arch", &arch, + NULL); + + if (!name) { + fprintf(stderr, " package with no name\n"); + exit(1); + } + + razor_importer_begin_package(ctx->importer, name, version, arch); + razor_importer_add_property(ctx->importer, name, + RAZOR_VERSION_EQUAL, version, + RAZOR_PROPERTY_PROVIDES); +} + +static void +end_package(struct test_context *ctx) +{ + razor_importer_finish_package(ctx->importer); +} + +static void +add_property(struct test_context *ctx, enum razor_property_type type, const char *name, enum razor_version_relation rel, const char *version) +{ + razor_importer_add_property(ctx->importer, name, + rel, version, type); +} + +static void +check_unsatisfiable_property(struct test_context *ctx, + enum razor_property_type type, + const char *name, + enum razor_version_relation rel, + const char *version) +{ + static const char *relation_string[] = { "<", "<=", "=", ">=", ">" }; + + if (!version) + version = ""; + + if (razor_transaction_unsatisfied_property(ctx->trans, + name, rel, version, type)) + return; + + fprintf(stderr, " didn't get unsatisfiable '%s %s %s'\n", + name, relation_string[rel], version); + ctx->errors++; +} + +static void +start_property(struct test_context *ctx, enum razor_property_type type, const char **atts) +{ + const char *name = NULL, *rel_str = NULL, *version = NULL; + enum razor_version_relation rel; + + get_atts(atts, "name", &name, "relation", &rel_str, "version", &version, NULL); + if (name == NULL) { + fprintf(stderr, " no name specified for property\n"); + exit(1); + } + if (version) { + rel = parse_relation(rel_str); + if (rel == -1) { + fprintf(stderr, " bad or missing version relation for property %s\n", name); + exit(1); + } + } else + rel = RAZOR_VERSION_EQUAL; + + if (ctx->unsat) + check_unsatisfiable_property(ctx, type, name, rel, version); + else + add_property(ctx, type, name, rel, version); +} + +static void +start_transaction(struct test_context *ctx, const char **atts) +{ + ctx->n_install_pkgs = 0; + ctx->n_remove_pkgs = 0; +} + +static void +end_transaction(struct test_context *ctx) +{ + struct razor_package *pkg; + int errors, i; + + ctx->trans = razor_transaction_create(ctx->system_set, ctx->repo_set); + for (i = 0; i < ctx->n_install_pkgs; i++) { + pkg = razor_set_get_package(ctx->repo_set, + ctx->install_pkgs[i]); + razor_transaction_install_package(ctx->trans, pkg); + } + for (i = 0; i < ctx->n_remove_pkgs; i++) { + pkg = razor_set_get_package(ctx->repo_set, + ctx->remove_pkgs[i]); + razor_transaction_remove_package(ctx->trans, pkg); + } + + errors = razor_transaction_resolve(ctx->trans); + printf("\n"); + + while (ctx->n_install_pkgs--) + free(ctx->install_pkgs[ctx->n_install_pkgs]); + while (ctx->n_remove_pkgs--) + free(ctx->remove_pkgs[ctx->n_remove_pkgs]); + + if (!errors) { + struct razor_set *new; + new = razor_transaction_finish(ctx->trans); + ctx->system_set = new; + } +} + +static void +start_install_or_update(struct test_context *ctx, const char **atts) +{ + const char *name = NULL; + + get_atts(atts, "name", &name, NULL); + if (!name) { + fprintf(stderr, " install/update with no name\n"); + exit(1); + } + + ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name); +} + +static void +start_remove(struct test_context *ctx, const char **atts) +{ + const char *name = NULL; + + get_atts(atts, "name", &name, NULL); + if (!name) { + fprintf(stderr, " remove with no name\n"); + exit(1); + } + + ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name); +} + +static void +start_result(struct test_context *ctx, const char **atts) +{ + ctx->in_result = 1; +} + +static void +diff_callback(const char *name, + const char *old_version, + const char *new_version, + const char *arch, + void *data) +{ + struct test_context *ctx = data; + + ctx->errors++; + if (old_version) { + fprintf(stderr, " result set should not contain %s %s\n", + name, old_version); + } else { + fprintf(stderr, " result set should contain %s %s\n", + name, new_version); + } +} + +static void +end_result(struct test_context *ctx) +{ + ctx->in_result = 0; + + if (ctx->result_set) { + if (!ctx->system_set) + ctx->system_set = razor_set_create(); + razor_set_diff(ctx->system_set, ctx->result_set, + diff_callback, ctx); + } +} + +static void +start_unsatisfiable(struct test_context *ctx, const char **atts) +{ + if (ctx->result_set) { + fprintf(stderr, "Expected to fail, but didn't\n"); + exit(1); + } + + ctx->unsat = 1; +} + +static void +end_unsatisfiable(struct test_context *ctx) +{ + ctx->unsat = 0; +} + +static void +start_test_element(void *data, const char *element, const char **atts) +{ + struct test_context *ctx = data; + + if (strcmp(element, "tests") == 0) { + ; + } else if (strcmp(element, "test") == 0) { + start_test(ctx, atts); + } else if (strcmp(element, "set") == 0) { + start_set(ctx, atts); + } else if (strcmp(element, "transaction") == 0) { + start_transaction(ctx, atts); + } else if (strcmp(element, "install") == 0) { + start_install_or_update(ctx, atts); + } else if (strcmp(element, "install") == 0) { + start_install_or_update(ctx, atts); + } else if (strcmp(element, "remove") == 0) { + start_remove(ctx, atts); + } else if (strcmp(element, "result") == 0) { + start_result(ctx, atts); + } else if (strcmp(element, "unsatisfiable") == 0) { + start_unsatisfiable(ctx, atts); + } else if (strcmp(element, "package") == 0) { + start_package(ctx, atts); + } else if (strcmp(element, "requires") == 0) { + start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts); + } else if (strcmp(element, "provides") == 0) { + start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts); + } else if (strcmp(element, "conflicts") == 0) { + start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts); + } else if (strcmp(element, "obsoletes") == 0) { + start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts); + } else { + fprintf(stderr, "Unrecognized element '%s'\n", element); + exit(1); + } +} + +static void +end_test_element (void *data, const char *element) +{ + struct test_context *ctx = data; + + if (strcmp(element, "test") == 0) { + end_test(ctx); + } else if (strcmp(element, "set") == 0) { + end_set(ctx); + } else if (strcmp(element, "package") == 0) { + end_package(ctx); + } else if (strcmp(element, "transaction") == 0) { + end_transaction(ctx); + } else if (strcmp(element, "result") == 0) { + end_result(ctx); + } else if (strcmp(element, "unsatisfiable") == 0) { + end_unsatisfiable(ctx); + } +} + +int main(int argc, char *argv[]) +{ + struct test_context ctx; + const char *test_file; + + memset(&ctx, 0, sizeof ctx); + + if (argc > 3) { + fprintf(stderr, "usage: %s [-d] [TESTS-FILE]\n", argv[0]); + exit(-1); + } + + if (argc >= 2 && !strcmp (argv[1], "-d")) { + ctx.debug = 1; + argc--; + argv++; + } + if (argc == 2) + test_file = argv[1]; + else + test_file = "test.xml"; + + parse_xml_file(test_file, start_test_element, end_test_element, &ctx); + + if (ctx.errors) { + fprintf(stderr, "\n%d errors\n", ctx.errors); + return 1; + } else + return 0; +} diff --git a/src/test.xml b/src/test.xml new file mode 100644 index 0000000..f24cf96 --- /dev/null +++ b/src/test.xml @@ -0,0 +1,858 @@ +<tests> + + <test name="testEmpty"> + <set name="system"/> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + <remove name="zsh"/> + </transaction> + <result> + <set/> + </result> + </test> + + <test name="testInstallSinglePackageNoRequires"> + <set name="system"/> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireNotProvided"> + <set name="system"/> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zip"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireInstalled"> + <set name="system"> + <package name="zip" version="1-1" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1-1" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireInstalledRequireNotProvided"> + <set name="system"> + <package name="zip" version="1-2" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + <!-- This may be a bug in the python test: it looks + like they meant to have zip require zap, not zsh. + But the install succeeds if you do that... + --> + <requires name="zap"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zap"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireInstalledRequireInstall"> + <set name="system"> + <package name="zip" version="1-3" arch="i386"> + <requires name="zap"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + </package> + <package name="zap" version="1-2" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + <install name="zap"/> + </transaction> + <result> + <set> + <package name="zap" version="1-2" arch="i386"/> + <package name="zip" version="1-3" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer1NotProvided"> + <set name="system"> + <package name="zip" version="1.0-2" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="1.3-2"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zip" relation="EQ" version="1.3-2"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer1Installed"> + <set name="system"> + <package name="zip" version="1.3-2" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="1.3-2"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1.3-2" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer2NotProvided"> + <set name="system"> + <package name="zip" version="1.3-2" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zip" relation="EQ" version="1.3-4"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer2Installed"> + <set name="system"> + <package name="zip" version="1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1.3-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer3NotProvided"> + <set name="system"> + <package name="zip" version="0:1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="GE" version="1:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zip" relation="GE" version="1:1.3-4"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer3Installed"> + <set name="system"> + <package name="zip" version="2:1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="GE" version="2:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="2:1.3-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer4NotProvided"> + <set name="system"> + <package name="zip" version="2:1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="LT" version="2:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zip" relation="LT" version="2:1.3-4"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer4_1Installed"> + <set name="system"> + <package name="zip" version="2:1.0-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="LT" version="2:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="2:1.0-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer4_2Installed"> + <set name="system"> + <package name="zip" version="2:1.3-3" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="LT" version="2:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="2:1.3-3" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer4_3Installed"> + <set name="system"> + <package name="zip" version="1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="LT" version="2:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1.3-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer4_4Installed"> + <set name="system"> + <package name="zip" version="1:1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="LT" version="2:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1:1.3-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireVer4_5Installed"> + <set name="system"> + <package name="zip" version="2:0.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="LT" version="2:1.3-4"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="2:0.3-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireXtraBadVer"> + <set name="system"> + <package name="zip" version="2:1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="2:1.3-4"/> + <requires name="zap" relation="EQ" version="2:1.3-4"/> + </package> + <package name="zap" version="0:1.3-4" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zap" relation="EQ" version="2:1.3-4"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireXtra"> + <set name="system"> + <package name="zip" version="2:1.3-4" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="2:1.3-4"/> + <requires name="zap" relation="EQ" version="4:2.6-8"/> + </package> + <package name="zap" version="4:2.6-8" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zap" version="4:2.6-8" arch="i386"/> + <package name="zip" version="2:1.3-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireInstalledRequireXtra"> + <set name="system"> + <package name="zip" version="2:1.3-4" arch="i386"> + <requires name="zap" relation="EQ" version="4:2.6-8"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="2:1.3-4"/> + </package> + <!-- This may be a bug in the python test; it doesn't + actually matter whether or not zap is available + --> + <package name="zap" version="4:2.6-8" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="2:1.3-4" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireUpgradeRequireXtraErr"> + <set name="system"> + <package name="zip" version="2:1.3-4" arch="i386"> + <requires name="zap" relation="EQ" version="2:1.3-3"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="4:2.6-8"/> + </package> + <package name="zip" version="4:2.6-8" arch="i386"> + <requires name="zap" relation="EQ" version="2:1.3-4"/> + </package> + <package name="zap" version="2:1.3-4" arch="i386"> + <requires name="zsh" relation="EQ" version="2:4-8"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <unsatisfiable> + <requires name="zsh" relation="EQ" version="2:4-8"/> + </unsatisfiable> + </result> + </test> + + <test name="testInstallSinglePackageRequireUpgradeRequireXtraOk"> + <set name="system"> + <package name="zip" version="2:1.3-4" arch="i386"> + <requires name="zap" relation="EQ" version="2:1.3-3"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="4:2.6-8"/> + </package> + <package name="zip" version="4:2.6-8" arch="i386"> + <requires name="zap" relation="EQ" version="2:1.3-4"/> + </package> + <package name="zap" version="2:1.3-4" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zap" version="2:1.3-4" arch="i386"/> + <package name="zip" version="4:2.6-8" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireMultiXtra"> + <set name="system"/> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip" relation="EQ" version="4:2.6-8"/> + </package> + <package name="zip" version="4:2.6-8" arch="i386"> + <requires name="zap" relation="EQ" version="2:1.3-4"/> + </package> + <package name="zap" version="2:1.3-4" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zap" version="2:1.3-4" arch="i386"/> + <package name="zip" version="4:2.6-8" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireInstalledMultiLib"> + <set name="system"> + <package name="zip" version="1-3" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-1" arch="x86_64"> + <requires name="zip"/> + </package> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1-3" arch="i386"/> + <package name="zsh" version="1-1" arch="x86_64"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireXtra1MultiLib"> + <set name="system"/> + <set name="repo"> + <package name="zsh" version="1-1" arch="x86_64"> + <requires name="zip"/> + </package> + <package name="zip" version="1-3" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1-3" arch="i386"/> + <package name="zsh" version="1-1" arch="x86_64"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireXtra2_64MultiLib"> + <set name="system"/> + <set name="repo"> + <package name="zsh" version="1-1" arch="x86_64"> + <requires name="zip"/> + </package> + <package name="zip" version="1-3" arch="i386"/> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zsh" version="1-1" arch="x86_64"/> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + </result> + </test> + + <test name="testInstallSinglePackageRequireXtra2_32MultiLib"> + <set name="system"/> + <set name="repo"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + </package> + <package name="zip" version="1-3" arch="i386"/> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1-3" arch="i386"/> + <package name="zsh" version="1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateSinglePackage"> + <set name="system"> + <package name="zsh" version="1-1" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-3" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zsh" version="1-3" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateForDependency"> + <set name="system"> + <package name="zip" version="0:1-1" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="0:1-1" arch="i386"> + <requires name="zip" relation="EQ" version="0:2-1"/> + </package> + <package name="zip" version="0:2-1" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="0:2-1" arch="i386"/> + <package name="zsh" version="0:1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateSplitPackage"> + <set name="system"> + <package name="zip" version="0:1-1" arch="i386"> + <provides name="libzip" relation="EQ" version="0:1-1"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="0:1-1" arch="i386"> + <requires name="libzip" relation="EQ" version="0:2-1"/> + </package> + <package name="zip" version="0:2-1" arch="i386"> + <requires name="zip-libs" relation="EQ" version="0:2-1"/> + </package> + <package name="zip-libs" version="0:2-1" arch="i386"> + <provides name="libzip" relation="EQ" version="0:2-1"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="0:1-1" arch="i386"/> + <package name="zip-libs" version="0:2-1" arch="i386"/> + <package name="zsh" version="0:1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateSinglePackageNewRequires"> + <set name="system"> + <package name="zsh" version="1-1" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-3" arch="i386"> + <requires name="zip"/> + </package> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zsh" version="1-3" arch="i386"/> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + </result> + </test> + + <test name="testUpdateSinglePackageOldRequires"> + <set name="system"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + </package> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + <set name="repo"> + <package name="zsh" version="1-3" arch="i386"> + <requires name="zip"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1-3" arch="x86_64"/> + <package name="zsh" version="1-3" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateSinglePackageOldRequiresGone"> + <set name="system"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + </package> + <package name="zip" version="1-3" arch="x86_64"/> + </set> + <set name="repo"> + <package name="zsh" version="1-3" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="1-3" arch="x86_64"/> + <package name="zsh" version="1-3" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateSinglePackageObsoletesOldRequirement"> + <set name="system"> + <package name="zsh" version="1-1" arch="i386"> + <requires name="zip"/> + </package> + <package name="zip" version="1-1" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="1-3" arch="i386"> + <!-- depsolvetests.py actually adds the obsoletes + to the installed zsh rather than the new zsh, + but I'm assuming that's a bug --> + <obsoletes name="zip"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zsh" version="1-3" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateForConflict"> + <set name="system"> + <package name="zip" version="0:1-1" arch="i386"/> + </set> + <set name="repo"> + <package name="zsh" version="0:1-1" arch="i386"> + <conflicts name="zip" relation="LE" version="0:1-1"/> + </package> + <package name="zip" version="0:2-1" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="0:2-1" arch="i386"/> + <package name="zsh" version="0:1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateForConflict2"> + <set name="system"> + <package name="zip" version="0:1-1" arch="i386"> + <conflicts name="zsh" relation="LE" version="0:1-1"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="0:1-1" arch="i386"/> + <package name="zip" version="0:2-1" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zsh" version="0:1-1" arch="i386"/> + <package name="zip" version="0:2-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateForConflictProvide"> + <set name="system"> + <package name="zip" version="0:1-1" arch="i386"> + <provides name="zippy" relation="EQ" version="0:1-1"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="0:1-1" arch="i386"> + <conflicts name="zippy" relation="LE" version="0:1-1"/> + </package> + <package name="zip" version="0:2-1" arch="i386"/> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="0:2-1" arch="i386"/> + <package name="zsh" version="0:1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testUpdateForConflictProvide2"> + <set name="system"> + <package name="zip" version="0:1-1" arch="i386"> + <conflicts name="zippy" relation="GT" version="0:1-1"/> + <conflicts name="zippy" relation="LT" version="0:1-1"/> + </package> + </set> + <set name="repo"> + <package name="zsh" version="0:1-1" arch="i386"> + <provides name="zippy" relation="EQ" version="0:2-1"/> + </package> + <package name="zip" version="0:2-1" arch="i386"> + <conflicts name="zippy" relation="GT" version="0:2-1"/> + <conflicts name="zippy" relation="LT" version="0:2-1"/> + </package> + </set> + <transaction> + <install name="zsh"/> + </transaction> + <result> + <set> + <package name="zip" version="0:2-1" arch="i386"/> + <package name="zsh" version="0:1-1" arch="i386"/> + </set> + </result> + </test> + + <test name="testEraseSinglePackage"> + <set name="system"> + <package name="zsh" version="0:1-1" arch="i386"/> + </set> + <set name="repo"/> + <transaction> + <remove name="zsh"/> + </transaction> + <result> + <set/> + </result> + </test> + + <test name="testEraseSinglePackageRequiredByOneInstalled"> + <set name="system"> + <package name="zippy" version="0:1-1" arch="i386"> + <requires name="zsh"/> + </package> + <package name="zsh" version="0:1-1" arch="i386"/> + </set> + <set name="repo"/> + <transaction> + <remove name="zsh"/> + </transaction> + <result> + <set/> + </result> + </test> +</tests> |