Rewrite depsolver to use a series of passes over all packages.
The big change is that we follow one step of the depedency chain for
each package to resolve in each iteration, and repeat until there are
no more possible moves. In contrast the old depsolver would try to
follow the dependency chain completely for one package at a time.
This new approach is simpler and faster, and at the same time more
roboust. Instead of knowing how one newly installed package may
affect other packages (obsoleting, pulling in new packages etc), the
new algorithm just looks at the total list of requires, provides,
obsoletes and conflicts after installing new packages.
2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 /* Import a yum filelist as a razor package set. */
38 YUM_STATE_PACKAGE_NAME,
39 YUM_STATE_PACKAGE_ARCH,
49 XML_Parser primary_parser;
50 XML_Parser filelists_parser;
51 XML_Parser current_parser;
53 struct razor_importer *importer;
54 struct import_property_context *current_property_context;
55 char name[256], arch[64], buffer[512], *p;
60 static enum razor_version_relation
61 yum_to_razor_flags (const char *flags)
65 return RAZOR_VERSION_EQUAL;
67 if (flags[0] == 'L') {
69 return RAZOR_VERSION_LESS;
71 return RAZOR_VERSION_LESS_OR_EQUAL;
72 } else if (flags[0] == 'G') {
74 return RAZOR_VERSION_GREATER;
76 return RAZOR_VERSION_GREATER_OR_EQUAL;
78 return RAZOR_VERSION_EQUAL;
82 yum_primary_start_element(void *data, const char *name, const char **atts)
84 struct yum_context *ctx = data;
85 const char *n, *epoch, *version, *release, *flags;
89 if (strcmp(name, "name") == 0) {
90 ctx->state = YUM_STATE_PACKAGE_NAME;
92 } else if (strcmp(name, "arch") == 0) {
93 ctx->state = YUM_STATE_PACKAGE_ARCH;
95 } else if (strcmp(name, "version") == 0) {
99 for (i = 0; atts[i]; i += 2) {
100 if (strcmp(atts[i], "epoch") == 0)
102 else if (strcmp(atts[i], "ver") == 0)
103 version = atts[i + 1];
104 else if (strcmp(atts[i], "rel") == 0)
105 release = atts[i + 1];
107 if (version == NULL || release == NULL) {
108 fprintf(stderr, "invalid version tag, "
109 "missing version or release attribute\n");
113 razor_build_evr(buffer, sizeof buffer, epoch, version, release);
114 razor_importer_begin_package(ctx->importer,
115 ctx->name, buffer, ctx->arch);
116 } else if (strcmp(name, "checksum") == 0) {
118 ctx->state = YUM_STATE_CHECKSUM;
119 } else if (strcmp(name, "rpm:requires") == 0) {
120 ctx->state = YUM_STATE_REQUIRES;
121 } else if (strcmp(name, "rpm:provides") == 0) {
122 ctx->state = YUM_STATE_PROVIDES;
123 } else if (strcmp(name, "rpm:obsoletes") == 0) {
124 ctx->state = YUM_STATE_OBSOLETES;
125 } else if (strcmp(name, "rpm:conflicts") == 0) {
126 ctx->state = YUM_STATE_CONFLICTS;
127 } else if (strcmp(name, "rpm:entry") == 0 &&
128 ctx->state != YUM_STATE_BEGIN) {
134 for (i = 0; atts[i]; i += 2) {
135 if (strcmp(atts[i], "name") == 0)
137 else if (strcmp(atts[i], "epoch") == 0)
139 else if (strcmp(atts[i], "ver") == 0)
140 version = atts[i + 1];
141 else if (strcmp(atts[i], "rel") == 0)
142 release = atts[i + 1];
143 else if (strcmp(atts[i], "flags") == 0)
148 fprintf(stderr, "invalid rpm:entry, "
149 "missing name or version attributes\n");
153 razor_build_evr(buffer, sizeof buffer, epoch, version, release);
154 switch (ctx->state) {
155 case YUM_STATE_REQUIRES:
156 razor_importer_add_property(ctx->importer, n,
157 yum_to_razor_flags (flags),
159 RAZOR_PROPERTY_REQUIRES);
161 case YUM_STATE_PROVIDES:
162 razor_importer_add_property(ctx->importer, n,
163 yum_to_razor_flags (flags),
165 RAZOR_PROPERTY_PROVIDES);
167 case YUM_STATE_OBSOLETES:
168 razor_importer_add_property(ctx->importer, n,
169 yum_to_razor_flags (flags),
171 RAZOR_PROPERTY_OBSOLETES);
173 case YUM_STATE_CONFLICTS:
174 razor_importer_add_property(ctx->importer, n,
175 yum_to_razor_flags (flags),
177 RAZOR_PROPERTY_CONFLICTS);
184 yum_primary_end_element (void *data, const char *name)
186 struct yum_context *ctx = data;
188 switch (ctx->state) {
189 case YUM_STATE_PACKAGE_NAME:
190 case YUM_STATE_PACKAGE_ARCH:
191 case YUM_STATE_CHECKSUM:
193 ctx->state = YUM_STATE_BEGIN;
197 if (strcmp(name, "package") == 0) {
198 XML_StopParser(ctx->current_parser, XML_TRUE);
199 ctx->current_parser = ctx->filelists_parser;
204 yum_character_data (void *data, const XML_Char *s, int len)
206 struct yum_context *ctx = data;
208 switch (ctx->state) {
209 case YUM_STATE_PACKAGE_NAME:
210 case YUM_STATE_PACKAGE_ARCH:
211 case YUM_STATE_CHECKSUM:
213 memcpy(ctx->p, s, len);
221 yum_filelists_start_element(void *data, const char *name, const char **atts)
223 struct yum_context *ctx = data;
224 const char *pkg, *pkgid;
227 if (strcmp(name, "package") == 0) {
230 for (i = 0; atts[i]; i += 2) {
231 if (strcmp(atts[i], "name") == 0)
233 else if (strcmp(atts[i], "pkgid") == 0)
236 if (strcmp(pkgid, ctx->pkgid) != 0)
237 fprintf(stderr, "primary.xml and filelists.xml "
238 "mismatch for %s: %s vs %s",
239 pkg, pkgid, ctx->pkgid);
240 } else if (strcmp(name, "file") == 0) {
241 ctx->state = YUM_STATE_FILE;
242 ctx->p = ctx->buffer;
248 yum_filelists_end_element (void *data, const char *name)
250 struct yum_context *ctx = data;
252 ctx->state = YUM_STATE_BEGIN;
253 if (strcmp(name, "package") == 0) {
254 XML_StopParser(ctx->current_parser, XML_TRUE);
255 ctx->current_parser = ctx->primary_parser;
256 razor_importer_finish_package(ctx->importer);
257 } else if (strcmp(name, "file") == 0)
258 razor_importer_add_file(ctx->importer, ctx->buffer);
262 #define XML_BUFFER_SIZE 4096
265 razor_set_create_from_yum(void)
267 struct yum_context ctx;
270 gzFile primary, filelists;
271 XML_ParsingStatus status;
273 ctx.importer = razor_importer_new();
274 ctx.state = YUM_STATE_BEGIN;
276 ctx.primary_parser = XML_ParserCreate(NULL);
277 XML_SetUserData(ctx.primary_parser, &ctx);
278 XML_SetElementHandler(ctx.primary_parser,
279 yum_primary_start_element,
280 yum_primary_end_element);
281 XML_SetCharacterDataHandler(ctx.primary_parser,
284 ctx.filelists_parser = XML_ParserCreate(NULL);
285 XML_SetUserData(ctx.filelists_parser, &ctx);
286 XML_SetElementHandler(ctx.filelists_parser,
287 yum_filelists_start_element,
288 yum_filelists_end_element);
289 XML_SetCharacterDataHandler(ctx.filelists_parser,
292 primary = gzopen("primary.xml.gz", "rb");
295 filelists = gzopen("filelists.xml.gz", "rb");
296 if (filelists == NULL)
299 ctx.current_parser = ctx.primary_parser;
302 XML_GetParsingStatus(ctx.current_parser, &status);
303 switch (status.parsing) {
305 ret = XML_ResumeParser(ctx.current_parser);
308 case XML_INITIALIZED:
309 buf = XML_GetBuffer(ctx.current_parser,
311 if (ctx.current_parser == ctx.primary_parser)
312 len = gzread(primary, buf, XML_BUFFER_SIZE);
314 len = gzread(filelists, buf, XML_BUFFER_SIZE);
317 "couldn't read input: %s\n",
322 XML_ParseBuffer(ctx.current_parser, len, len == 0);
327 } while (status.parsing != XML_FINISHED);
330 XML_ParserFree(ctx.primary_parser);
331 XML_ParserFree(ctx.filelists_parser);
336 return razor_importer_finish(ctx.importer);