ADD_DEFINITIONS( -DFEDORA )
ENDIF ( FEDORA)
+IF ( DEBIAN )
+MESSAGE(STATUS "Building for Debian")
+ADD_DEFINITIONS( -DDEBIAN -DDEBIAN_SEMANTICS)
+ENDIF ( DEBIAN )
+
IF ( MULTI_SEMANTICS )
MESSAGE(STATUS "Enabling multi dist support")
ADD_DEFINITIONS( -DMULTI_SEMANTICS)
ENDIF ( MULTI_SEMANTICS )
+IF ( NOT DEBIAN )
FIND_LIBRARY(RPMDB_LIBRARY NAMES rpmdb)
IF ( NOT RPMDB_LIBRARY )
FIND_LIBRARY(RPMDB_LIBRARY NAMES rpm)
ENDIF( NOT RPMDB_LIBRARY )
+FIND_LIBRARY(RPMIO_LIBRARY NAMES rpmio)
+IF ( RPMIO_LIBRARY )
+SET( RPMDB_LIBRARY ${RPMIO_LIBRARY} ${RPMDB_LIBRARY} )
+ENDIF ( RPMIO_LIBRARY )
+IF ( FEDORA )
+FIND_LIBRARY(DB_LIBRARY NAMES db)
+IF ( DB_LIBRARY )
+SET( RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY} )
+ENDIF ( DB_LIBRARY )
+ENDIF ( FEDORA )
+ENDIF ( NOT DEBIAN )
SET( PACKAGE "satsolver" )
SET( VERSION "${LIBSATSOLVER_MAJOR}.${LIBSATSOLVER_MINOR}.${LIBSATSOLVER_PATCH}" )
#
SET(LIBSATSOLVER_MAJOR "0")
-SET(LIBSATSOLVER_MINOR "14")
-SET(LIBSATSOLVER_PATCH "16")
+SET(LIBSATSOLVER_MINOR "16")
+SET(LIBSATSOLVER_PATCH "1")
-# last released 0.14.16
+# last released 0.16.0
ADD_EXECUTABLE(solv solv.c)
+IF ( DEBIAN )
+TARGET_LINK_LIBRARIES(solv satsolverext satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
+ELSE ( DEBIAN )
TARGET_LINK_LIBRARIES(solv satsolverext satsolver ${RPMDB_LIBRARY} ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
+ENDIF ( DEBIAN )
install(TARGETS
solv
/* solv, a little software installer demoing the sat solver library */
-/* things available in the library but missing from solv:
+/* things it does:
+ * - understands globs for package names / dependencies
+ * - understands .arch suffix
+ * - installation of commandline packages
+ * - repository data caching
+ * - on demand loading of secondary repository data
+ * - gpg and checksum verification
+ * - file conflicts
+ * - deltarpm support
+ * - fastestmirror implementation
+ *
+ * things available in the library but missing from solv:
* - vendor policy loading
* - soft locks file handling
* - multi version handling
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
+#include <sys/dir.h>
+#include <sys/stat.h>
#include <sys/socket.h>
#include <netdb.h>
#include "repo_solv.h"
#include "repo_write.h"
+#ifndef DEBIAN
#include "repo_rpmdb.h"
+#else
+#include "repo_deb.h"
+#endif
#include "repo_products.h"
#include "repo_rpmmd.h"
#include "repo_susetags.h"
int priority;
int keeppackages;
int metadata_expire;
+ char **components;
+ int ncomponents;
unsigned char cookie[32];
unsigned char extcookie[32];
#define TYPE_SUSETAGS 1
#define TYPE_RPMMD 2
#define TYPE_PLAINDIR 3
+#define TYPE_DEBIAN 4
static int
read_repoinfos_sort(const void *ap, const void *bp)
return strcmp(a->alias, b->alias);
}
+#ifndef DEBIAN
+
struct repoinfo *
read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
{
}
while ((ent = readdir(dir)) != 0)
{
+ if (ent->d_name[0] == '.')
+ continue;
l = strlen(ent->d_name);
if (l < 6 || rdlen + 2 + l >= sizeof(buf) || strcmp(ent->d_name + l - 5, ".repo") != 0)
continue;
return repoinfos;
}
+#else
+
+struct repoinfo *
+read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
+{
+ FILE *fp;
+ char buf[4096];
+ char buf2[4096];
+ int l;
+ char *kp, *url, *distro;
+ struct repoinfo *repoinfos = 0, *cinfo;
+ int nrepoinfos = 0;
+ DIR *dir = 0;
+ struct dirent *ent;
+
+ fp = fopen("/etc/apt/sources.list", "r");
+ while (1)
+ {
+ if (!fp)
+ {
+ if (!dir)
+ {
+ dir = opendir("/etc/apt/sources.list.d");
+ if (!dir)
+ break;
+ }
+ if ((ent = readdir(dir)) == 0)
+ {
+ closedir(dir);
+ break;
+ }
+ if (ent->d_name[0] == '.')
+ continue;
+ l = strlen(ent->d_name);
+ if (l < 5 || strcmp(ent->d_name + l - 5, ".list") != 0)
+ continue;
+ snprintf(buf, sizeof(buf), "%s/%s", "/etc/apt/sources.list.d", ent->d_name);
+ if (!(fp = fopen(buf, "r")))
+ continue;
+ }
+ while(fgets(buf2, sizeof(buf2), fp))
+ {
+ l = strlen(buf2);
+ if (l == 0)
+ continue;
+ while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t'))
+ buf2[--l] = 0;
+ kp = buf2;
+ while (*kp == ' ' || *kp == '\t')
+ kp++;
+ if (!*kp || *kp == '#')
+ continue;
+ if (strncmp(kp, "deb", 3) != 0)
+ continue;
+ kp += 3;
+ if (*kp != ' ' && *kp != '\t')
+ continue;
+ while (*kp == ' ' || *kp == '\t')
+ kp++;
+ if (!*kp)
+ continue;
+ url = kp;
+ while (*kp && *kp != ' ' && *kp != '\t')
+ kp++;
+ if (*kp)
+ *kp++ = 0;
+ while (*kp == ' ' || *kp == '\t')
+ kp++;
+ if (!*kp)
+ continue;
+ distro = kp;
+ while (*kp && *kp != ' ' && *kp != '\t')
+ kp++;
+ if (*kp)
+ *kp++ = 0;
+ while (*kp == ' ' || *kp == '\t')
+ kp++;
+ if (!*kp)
+ continue;
+ repoinfos = sat_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
+ cinfo = repoinfos + nrepoinfos++;
+ memset(cinfo, 0, sizeof(*cinfo));
+ cinfo->baseurl = strdup(url);
+ cinfo->alias = sat_dupjoin(url, "/", distro);
+ cinfo->name = strdup(distro);
+ cinfo->type = TYPE_DEBIAN;
+ cinfo->enabled = 1;
+ cinfo->autorefresh = 1;
+ cinfo->repo_gpgcheck = 1;
+ cinfo->metadata_expire = METADATA_EXPIRE;
+ while (*kp)
+ {
+ char *compo;
+ while (*kp == ' ' || *kp == '\t')
+ kp++;
+ if (!*kp)
+ break;
+ compo = kp;
+ while (*kp && *kp != ' ' && *kp != '\t')
+ kp++;
+ if (*kp)
+ *kp++ = 0;
+ cinfo->components = sat_extend(cinfo->components, cinfo->ncomponents, 1, sizeof(*cinfo->components), 15);
+ cinfo->components[cinfo->ncomponents++] = strdup(compo);
+ }
+ }
+ fclose(fp);
+ fp = 0;
+ }
+ qsort(repoinfos, nrepoinfos, sizeof(*repoinfos), read_repoinfos_sort);
+ *nrepoinfosp = nrepoinfos;
+ return repoinfos;
+}
+
+#endif
+
void
free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos)
{
- int i;
+ int i, j;
for (i = 0; i < nrepoinfos; i++)
{
struct repoinfo *cinfo = repoinfos + i;
sat_free(cinfo->metalink);
sat_free(cinfo->mirrorlist);
sat_free(cinfo->baseurl);
+ for (j = 0; j < cinfo->ncomponents; j++)
+ sat_free(cinfo->components[j]);
+ sat_free(cinfo->components);
}
sat_free(repoinfos);
}
return fdopen(fd, "r");
}
+#ifndef DEBIAN
+
static void
cleanupgpg(char *gpgdir)
{
return r == 0 ? 1 : 0;
}
+#else
+
+int
+checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
+{
+ char cmd[256];
+ int r;
+
+ snprintf(cmd, sizeof(cmd), "gpgv -q --keyring /etc/apt/trusted.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", fileno(sigfp), fileno(fp));
+ fcntl(fileno(fp), F_SETFD, 0); /* clear CLOEXEC */
+ fcntl(fileno(sigfp), F_SETFD, 0); /* clear CLOEXEC */
+ r = system(cmd);
+ fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
+ fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC);
+ return r == 0 ? 1 : 0;
+}
+
+#endif
+
#define CHKSUM_IDENT "1.1"
void
flags = 0;
if (repoext)
- flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
- if (repoext && strcmp(repoext, "DL") != 0)
- flags |= REPO_LOCALPOOL; /* no local pool for DL so that we can compare IDs */
+ {
+ flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
+ if (strcmp(repoext, "DL") != 0)
+ flags |= REPO_LOCALPOOL; /* no local pool for DL so that we can compare IDs */
+ }
if (repo_add_solv_flags(repo, fp, flags))
{
read_sigs()
{
Pool *sigpool = pool_create();
+#ifndef DEBIAN
Repo *repo = repo_create(sigpool, "rpmdbkeys");
repo_add_rpmdb_pubkeys(repo, 0, 0);
+#endif
return sigpool;
}
static unsigned char installedcookie[32];
+#ifdef DEBIAN
+void
+repo_add_debdb(Repo *repo, int flags)
+{
+ FILE *fp;
+ if ((fp = fopen("/var/lib/dpkg/status", "r")) == 0)
+ {
+ perror("/var/lib/dpkg/status");
+ exit(1);
+ }
+ repo_add_debpackages(repo, fp, flags);
+ fclose(fp);
+}
+
+static int
+hexstr2bytes(unsigned char *buf, const char *str, int buflen)
+{
+ int i;
+ for (i = 0; i < buflen; i++)
+ {
+#define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
+ : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
+ : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
+ : -1)
+ int v = c2h(*str);
+ str++;
+ if (v < 0)
+ return 0;
+ buf[i] = v;
+ v = c2h(*str);
+ str++;
+ if (v < 0)
+ return 0;
+ buf[i] = (buf[i] << 4) | v;
+#undef c2h
+ }
+ return buflen;
+}
+
+const char *
+debian_find_component(struct repoinfo *cinfo, FILE *fp, char *comp, const unsigned char **chksump, Id *chksumtypep)
+{
+ char buf[4096];
+ Id chksumtype;
+ unsigned char *chksum;
+ Id curchksumtype;
+ int l, compl;
+ char *ch, *fn, *bp;
+ char *filename;
+ static char *basearch;
+ char *binarydir;
+ int lbinarydir;
+
+ if (!basearch)
+ {
+ struct utsname un;
+ if (uname(&un))
+ {
+ perror("uname");
+ exit(1);
+ }
+ basearch = strdup(un.machine);
+ if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86"))
+ basearch[1] = '3';
+ }
+ binarydir = sat_dupjoin("binary-", basearch, "/");
+ lbinarydir = strlen(binarydir);
+ compl = strlen(comp);
+ rewind(fp);
+ curchksumtype = 0;
+ filename = 0;
+ chksum = sat_malloc(32);
+ chksumtype = 0;
+ while(fgets(buf, sizeof(buf), fp))
+ {
+ l = strlen(buf);
+ if (l == 0)
+ continue;
+ while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+ buf[--l] = 0;
+ if (!strncasecmp(buf, "MD5Sum:", 7))
+ {
+ curchksumtype = REPOKEY_TYPE_MD5;
+ continue;
+ }
+ if (!strncasecmp(buf, "SHA1:", 5))
+ {
+ curchksumtype = REPOKEY_TYPE_SHA1;
+ continue;
+ }
+ if (!strncasecmp(buf, "SHA256:", 7))
+ {
+ curchksumtype = REPOKEY_TYPE_SHA256;
+ continue;
+ }
+ if (!curchksumtype)
+ continue;
+ bp = buf;
+ if (*bp++ != ' ')
+ {
+ curchksumtype = 0;
+ continue;
+ }
+ ch = bp;
+ while (*bp && *bp != ' ' && *bp != '\t')
+ bp++;
+ if (!*bp)
+ continue;
+ *bp++ = 0;
+ while (*bp == ' ' || *bp == '\t')
+ bp++;
+ while (*bp && *bp != ' ' && *bp != '\t')
+ bp++;
+ if (!*bp)
+ continue;
+ while (*bp == ' ' || *bp == '\t')
+ bp++;
+ fn = bp;
+ if (strncmp(fn, comp, compl) != 0 || fn[compl] != '/')
+ continue;
+ bp += compl + 1;
+ if (strncmp(bp, binarydir, lbinarydir))
+ continue;
+ bp += lbinarydir;
+ if (!strcmp(bp, "Packages") || !strcmp(bp, "Packages.gz"))
+ {
+ if (filename && !strcmp(bp, "Packages"))
+ continue;
+ if (chksumtype && sat_chksum_len(chksumtype) > sat_chksum_len(curchksumtype))
+ continue;
+ if (!hexstr2bytes(chksum, ch, sat_chksum_len(curchksumtype)))
+ continue;
+ sat_free(filename);
+ filename = strdup(fn);
+ chksumtype = curchksumtype;
+ }
+ }
+ free(binarydir);
+ if (filename)
+ {
+ fn = sat_dupjoin("/", filename, 0);
+ sat_free(filename);
+ filename = sat_dupjoin("dists/", cinfo->name, fn);
+ sat_free(fn);
+ }
+ if (!chksumtype)
+ chksum = sat_free(chksum);
+ *chksump = chksum;
+ *chksumtypep = chksumtype;
+ return filename;
+}
+#endif
+
void
read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
{
Repodata *data;
int badchecksum;
int dorefresh;
+#ifdef DEBIAN
+ FILE *fpr;
+ int j;
+#endif
repo = repo_create(pool, "@System");
+#ifndef DEBIAN
printf("rpm database:");
if (stat("/var/lib/rpm/Packages", &stb))
memset(&stb, 0, sizeof(&stb));
+#else
+ printf("dpgk database:");
+ if (stat("/var/lib/dpkg/status", &stb))
+ memset(&stb, 0, sizeof(&stb));
+#endif
calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, installedcookie);
if (usecachedrepo(repo, 0, installedcookie, 0))
printf(" cached\n");
else
{
+#ifndef DEBIAN
FILE *ofp;
- printf(" reading\n");
int done = 0;
+#endif
+ printf(" reading\n");
#ifdef PRODUCTS_PATH
repo_add_products(repo, PRODUCTS_PATH, 0, REPO_NO_INTERNALIZE);
#endif
+#ifndef DEBIAN
if ((ofp = fopen(calccachepath(repo, 0), "r")) != 0)
{
Repo *ref = repo_create(pool, "@System.old");
}
if (!done)
repo_add_rpmdb(repo, 0, 0, REPO_REUSE_REPODATA);
+#else
+ repo_add_debdb(repo, REPO_REUSE_REPODATA);
+#endif
writecachedrepo(repo, 0, 0, installedcookie);
}
pool_set_installed(pool, repo);
writecachedrepo(repo, 0, 0, cinfo->cookie);
repodata_create_stubs(repo_last_repodata(repo));
break;
+
+#ifdef DEBIAN
+ case TYPE_DEBIAN:
+ printf("debian repo '%s':", cinfo->alias);
+ fflush(stdout);
+ filename = sat_dupjoin("dists/", cinfo->name, "/Release");
+ if ((fpr = curlfopen(cinfo, filename, 0, 0, 0, 0)) == 0)
+ {
+ printf(" no Release file, skipped\n");
+ repo_free(repo, 1);
+ cinfo->repo = 0;
+ free((char *)filename);
+ break;
+ }
+ sat_free((char *)filename);
+ if (cinfo->repo_gpgcheck)
+ {
+ filename = sat_dupjoin("dists/", cinfo->name, "/Release.gpg");
+ sigfp = curlfopen(cinfo, filename, 0, 0, 0, 0);
+ sat_free((char *)filename);
+ if (!sigfp)
+ {
+ printf(" unsigned, skipped\n");
+ fclose(fpr);
+ break;
+ }
+ if (!sigpool)
+ sigpool = read_sigs();
+ if (!checksig(sigpool, fpr, sigfp))
+ {
+ printf(" checksig failed, skipped\n");
+ fclose(sigfp);
+ fclose(fpr);
+ break;
+ }
+ fclose(sigfp);
+ }
+ calc_checksum_fp(fpr, REPOKEY_TYPE_SHA256, cinfo->cookie);
+ if (usecachedrepo(repo, 0, cinfo->cookie, 1))
+ {
+ printf(" cached\n");
+ fclose(fpr);
+ break;
+ }
+ printf(" fetching\n");
+ for (j = 0; j < cinfo->ncomponents; j++)
+ {
+ if (!(filename = debian_find_component(cinfo, fpr, cinfo->components[j], &filechksum, &filechksumtype)))
+ {
+ printf("[component %s not found]\n", cinfo->components[j]);
+ continue;
+ }
+ if ((fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0)
+ {
+ repo_add_debpackages(repo, fp, 0);
+ fclose(fp);
+ }
+ sat_free((char *)filechksum);
+ sat_free((char *)filename);
+ }
+ fclose(fpr);
+ if (!badchecksum)
+ writecachedrepo(repo, 0, 0, cinfo->cookie);
+ break;
+#endif
+
default:
printf("unsupported repo '%s': skipped\n", cinfo->alias);
repo_free(repo, 1);
return id;
}
+
+#define DEPGLOB_NAME 1
+#define DEPGLOB_DEP 2
+#define DEPGLOB_NAMEDEP 3
+
int
-depglob(Pool *pool, char *name, Queue *job)
+depglob(Pool *pool, char *name, Queue *job, int what)
{
Id p, pp;
Id id = str2id(pool, name, 0);
{
Solvable *s = pool->solvables + p;
match = 1;
- if (s->name == id)
+ if (s->name == id && (what & DEPGLOB_NAME) != 0)
{
queue_push2(job, SOLVER_SOLVABLE_NAME, id);
return 1;
}
if (match)
{
- printf("[using capability match for '%s']\n", name);
+ if (what == DEPGLOB_NAMEDEP)
+ printf("[using capability match for '%s']\n", name);
queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
return 1;
}
if (strpbrk(name, "[*?") == 0)
return 0;
- /* looks like a name glob. hard work. */
- for (p = 1; p < pool->nsolvables; p++)
+ if ((what & DEPGLOB_NAME) != 0)
{
- Solvable *s = pool->solvables + p;
- if (!s->repo || !pool_installable(pool, s))
- continue;
- id = s->name;
- if (fnmatch(name, id2str(pool, id), 0) == 0)
+ /* looks like a name glob. hard work. */
+ for (p = 1; p < pool->nsolvables; p++)
{
- for (i = 0; i < job->count; i += 2)
- if (job->elements[i] == SOLVER_SOLVABLE_NAME && job->elements[i + 1] == id)
- break;
- if (i == job->count)
- queue_push2(job, SOLVER_SOLVABLE_NAME, id);
- match = 1;
+ Solvable *s = pool->solvables + p;
+ if (!s->repo || !pool_installable(pool, s))
+ continue;
+ id = s->name;
+ if (fnmatch(name, id2str(pool, id), 0) == 0)
+ {
+ for (i = 0; i < job->count; i += 2)
+ if (job->elements[i] == SOLVER_SOLVABLE_NAME && job->elements[i + 1] == id)
+ break;
+ if (i == job->count)
+ queue_push2(job, SOLVER_SOLVABLE_NAME, id);
+ match = 1;
+ }
}
+ if (match)
+ return 1;
}
- if (match)
- return 1;
- /* looks like a dep glob. really hard work. */
- for (id = 1; id < pool->ss.nstrings; id++)
+ if ((what & DEPGLOB_DEP))
{
- if (!pool->whatprovides[id])
- continue;
- if (fnmatch(name, id2str(pool, id), 0) == 0)
+ /* looks like a dep glob. really hard work. */
+ for (id = 1; id < pool->ss.nstrings; id++)
{
- if (!match)
- printf("[using capability match for '%s']\n", name);
- for (i = 0; i < job->count; i += 2)
- if (job->elements[i] == SOLVER_SOLVABLE_PROVIDES && job->elements[i + 1] == id)
- break;
- if (i == job->count)
- queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
- match = 1;
+ if (!pool->whatprovides[id])
+ continue;
+ if (fnmatch(name, id2str(pool, id), 0) == 0)
+ {
+ if (!match && what == DEPGLOB_NAMEDEP)
+ printf("[using capability match for '%s']\n", name);
+ for (i = 0; i < job->count; i += 2)
+ if (job->elements[i] == SOLVER_SOLVABLE_PROVIDES && job->elements[i + 1] == id)
+ break;
+ if (i == job->count)
+ queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
+ match = 1;
+ }
}
+ if (match)
+ return 1;
}
- if (match)
- return 1;
return 0;
}
-void
-addrelation(Pool *pool, Queue *job, int flags, Id evr)
-{
- int i;
- for (i = 0; i < job->count; i += 2)
- {
- if (job->elements[i] != SOLVER_SOLVABLE_NAME && job->elements[i] != SOLVER_SOLVABLE_PROVIDES)
- continue;
- job->elements[i + 1] = rel2id(pool, job->elements[i + 1], evr, flags, 1);
- }
-}
-
int
-limitevr(Pool *pool, char *evr, Queue *job, Id archid)
+limitrelation(Pool *pool, Queue *job, int flags, Id evr)
{
- Queue mq;
- Id p, pp, evrid;
- int matched = 0;
int i, j;
- Solvable *s;
- const char *sevr;
-
- queue_init(&mq);
- for (i = 0; i < job->count; i += 2)
+ Id p, pp;
+ for (i = j = 0; i < job->count; i += 2)
{
- queue_empty(&mq);
- FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
+ Id select = job->elements[i] & SOLVER_SELECTMASK;
+ if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES)
{
- s = pool_id2solvable(pool, p);
- if (archid && s->arch != archid)
- continue;
- sevr = id2str(pool, s->evr);
- if (!strchr(evr, ':') && strchr(sevr, ':'))
- sevr = strchr(sevr, ':') + 1;
- if (evrcmp_str(pool, sevr, evr, EVRCMP_MATCH) == 0)
- queue_push(&mq, p);
+ fprintf(stderr, "limitrelation only works on name/provides jobs\n");
+ exit(1);
}
- if (mq.count)
- {
- if (!matched && i)
- {
- queue_deleten(job, 0, i);
- i = 0;
- }
- matched = 1;
- /* if all solvables have the same evr */
- s = pool_id2solvable(pool, mq.elements[0]);
- evrid = s->evr;
- for (j = 0; j < mq.count; j++)
- {
- s = pool_id2solvable(pool, mq.elements[j]);
- if (s->evr != evrid)
- break;
- }
- if (j == mq.count && j > 1)
- {
- prune_to_best_arch(pool, &mq);
- // prune_to_highest_prio(pool, &mq);
- mq.count = 1;
- }
- if (mq.count > 1)
- {
- job->elements[i] = SOLVER_SOLVABLE_ONE_OF;
- job->elements[i + 1] = pool_queuetowhatprovides(pool, &mq);
- }
+ job->elements[i + 1] = rel2id(pool, job->elements[i + 1], evr, flags, 1);
+ if (flags == REL_ARCH)
+ job->elements[i] |= SOLVER_SETARCH;
+ if (flags == REL_EQ && select == SOLVER_SOLVABLE_NAME && job->elements[i])
+ {
+#ifndef DEBIAN
+ const char *evrstr = id2str(pool, evr);
+ if (!strchr(evrstr, '-'))
+ job->elements[i] |= SOLVER_SETEV;
else
- {
- job->elements[i] = SOLVER_SOLVABLE;
- job->elements[i + 1] = mq.elements[0];
- }
+#endif
+ job->elements[i] |= SOLVER_SETEVR;
}
- else if (matched)
+ /* make sure we still have matches */
+ FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
+ break;
+ if (p)
{
- queue_deleten(job, i, 2);
- i -= 2;
+ job->elements[j] = job->elements[i];
+ job->elements[j + 1] = job->elements[i + 1];
+ j += 2;
}
}
- queue_free(&mq);
- if (matched)
- return 1;
- if (!archid)
+ queue_truncate(job, j);
+ return j / 2;
+}
+
+int
+limitrelation_arch(Pool *pool, Queue *job, int flags, char *evr)
+{
+ char *r;
+ Id archid;
+ if ((r = strrchr(evr, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
{
- char *r;
- if ((r = strrchr(evr, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
- {
- *r = 0;
- if (limitevr(pool, evr, job, archid))
- {
- *r = '.';
- return 1;
- }
- *r = '.';
- }
+ *r = 0;
+ limitrelation(pool, job, REL_ARCH, archid);
+ limitrelation(pool, job, flags, str2id(pool, evr, 1));
+ *r = '.';
}
- return 0;
+ else
+ limitrelation(pool, job, flags, str2id(pool, evr, 1));
+ return job->count / 2;
}
int
{
Queue mq;
Id p, pp;
- int matched = 0;
- int i;
+ int i, j;
Solvable *s;
queue_init(&mq);
- for (i = 0; i < job->count; i += 2)
+ for (i = j = 0; i < job->count; i += 2)
{
queue_empty(&mq);
FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
}
if (mq.count)
{
- if (!matched && i)
- {
- queue_deleten(job, 0, i);
- i = 0;
- }
- matched = 1;
- if (mq.count > 1)
+ /* here we assume that repo == vendor, so we also set SOLVER_SETVENDOR */
+ if (mq.count == 1)
{
- job->elements[i] = SOLVER_SOLVABLE_ONE_OF;
- job->elements[i + 1] = pool_queuetowhatprovides(pool, &mq);
+ job->elements[j] = SOLVER_SOLVABLE | (job->elements[i] & SOLVER_SETMASK) | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_NOAUTOSET;
+ job->elements[j + 1] = mq.elements[0];
}
else
{
- job->elements[i] = SOLVER_SOLVABLE;
- job->elements[i + 1] = mq.elements[0];
+ job->elements[j] = SOLVER_SOLVABLE_ONE_OF | (job->elements[i] & SOLVER_SETMASK) | SOLVER_SETVENDOR | SOLVER_SETREPO;
+ job->elements[j + 1] = pool_queuetowhatprovides(pool, &mq);
}
- }
- else if (matched)
- {
- queue_deleten(job, i, 2);
- i -= 2;
+ j += 2;
}
}
+ queue_truncate(job, j);
queue_free(&mq);
- return matched;
+ return j / 2;
}
-void
+int
mkselect(Pool *pool, int mode, char *name, Queue *job)
{
char *r, *r2;
if (*name == '/')
{
Dataiterator di;
+ int type = strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
Queue q;
- int match = 0;
-
queue_init(&q);
- dataiterator_init(&di, pool, mode == SOLVER_ERASE ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, SEARCH_STRING|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
+ dataiterator_init(&di, pool, mode == SOLVER_ERASE ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
while (dataiterator_step(&di))
{
Solvable *s = pool->solvables + di.solvid;
if (q.count)
{
printf("[using file list match for '%s']\n", name);
- match = 1;
if (q.count > 1)
queue_push2(job, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
else
- queue_push2(job, SOLVER_SOLVABLE, q.elements[0]);
+ queue_push2(job, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
+ queue_free(&q);
+ return job->count / 2;
}
- queue_free(&q);
- if (match)
- return;
}
if ((r = strpbrk(name, "<=>")) != 0)
{
/* relation case, support:
* depglob rel
- * depglob.rpm rel
+ * depglob.arch rel
*/
int rflags = 0;
int nend = r - name;
+ char oldnend;
for (; *r; r++)
{
if (*r == '<')
r++;
while (nend && (name[nend - 1] == ' ' || name[nend -1 ] == '\t'))
nend--;
- name[nend] = 0;
if (!*name || !*r)
{
fprintf(stderr, "bad relation\n");
exit(1);
}
- if (depglob(pool, name, job))
+ oldnend = name[nend];
+ name[nend] = 0;
+ if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
{
- addrelation(pool, job, rflags, str2id(pool, r, 1));
- return;
+ name[nend] = oldnend;
+ limitrelation(pool, job, rflags, str2id(pool, r, 1));
+ return job->count / 2;
}
if ((r2 = strrchr(name, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
{
*r2 = 0;
- if (depglob(pool, name, job))
+ if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
{
+ name[nend] = oldnend;
*r2 = '.';
- addrelation(pool, job, REL_ARCH, archid);
- addrelation(pool, job, rflags, str2id(pool, r, 1));
- return;
+ limitrelation(pool, job, REL_ARCH, archid);
+ limitrelation(pool, job, rflags, str2id(pool, r, 1));
+ return job->count / 2;
}
*r2 = '.';
}
+ name[nend] = oldnend;
}
else
{
/* no relation case, support:
* depglob
* depglob.arch
- * depglob-version-release
- * depglob-version-release.arch
+ * nameglob-version
+ * nameglob-version.arch
+ * nameglob-version-release
+ * nameglob-version-release.arch
*/
- if (depglob(pool, name, job))
- return;
- archid = 0;
+ if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
+ return job->count / 2;
if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
{
*r = 0;
- if (depglob(pool, name, job))
+ if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
{
*r = '.';
- addrelation(pool, job, REL_ARCH, archid);
- return;
+ limitrelation(pool, job, REL_ARCH, archid);
+ return job->count / 2;
}
*r = '.';
}
if ((r = strrchr(name, '-')) != 0)
{
*r = 0;
- if (depglob(pool, name, job))
+ if (depglob(pool, name, job, DEPGLOB_NAME))
{
/* have just the version */
+ limitrelation_arch(pool, job, REL_EQ, r + 1);
*r = '-';
- if (limitevr(pool, r + 1, job, 0))
- return;
+ return job->count / 2;
}
if ((r2 = strrchr(name, '-')) != 0)
{
*r = '-';
*r2 = 0;
- if (depglob(pool, name, job))
+ r = r2;
+ if (depglob(pool, name, job, DEPGLOB_NAME))
{
- *r2 = '-';
- if (limitevr(pool, r2 + 1, job, 0))
- return;
+ /* have version-release */
+ limitrelation_arch(pool, job, REL_EQ, r + 1);
+ *r = '-';
+ return job->count / 2;
}
- *r2 = '-';
}
*r = '-';
}
}
- fprintf(stderr, "nothing matches '%s'\n", name);
- exit(1);
+ return 0;
}
}
}
+#ifndef DEBIAN
+
struct fcstate {
FILE **newpkgsfps;
Queue *checkq;
return rpm_byfp(fp, solvable2str(pool, s), &fcstate->rpmdbstate);
}
+
void
runrpm(const char *arg, const char *name, int dupfd3)
{
}
}
+#endif
+
+#ifdef DEBIAN
+
+void
+rundpkg(const char *arg, const char *name, int dupfd3)
+{
+ pid_t pid;
+ int status;
+
+ if ((pid = fork()) == (pid_t)-1)
+ {
+ perror("fork");
+ exit(1);
+ }
+ if (pid == 0)
+ {
+ if (dupfd3 != -1 && dupfd3 != 3)
+ {
+ dup2(dupfd3, 3);
+ close(dupfd3);
+ }
+ if (dupfd3 != -1)
+ fcntl(3, F_SETFD, 0); /* clear CLOEXEC */
+ if (strcmp(arg, "--install") == 0)
+ execlp("dpkg", "dpkg", "--install", "--force", "all", name, (char *)0);
+ else
+ execlp("dpkg", "dpkg", "--remove", "--force", "all", name, (char *)0);
+ perror("dpkg");
+ _exit(0);
+ }
+ while (waitpid(pid, &status, 0) != pid)
+ ;
+ if (status)
+ {
+ printf("dpkg failed\n");
+ exit(1);
+ }
+}
+
+#endif
+
static Id
nscallback(Pool *pool, void *data, Id name, Id evr)
{
#define MODE_INFO 7
#define MODE_REPOLIST 8
#define MODE_SEARCH 9
+#define MODE_ERASECLEAN 10
void
usage(int r)
char inbuf[128], *ip;
int allpkgs = 0;
FILE **newpkgsfps;
- struct fcstate fcstate;
Id *addedfileprovides = 0;
Id repofilter = 0;
mainmode = MODE_ERASE;
mode = SOLVER_ERASE;
}
+ else if (!strcmp(argv[0], "eraseclean") || !strcmp(argv[0], "rmclean"))
+ {
+ mainmode = MODE_ERASECLEAN;
+ mode = SOLVER_ERASE;
+ }
else if (!strcmp(argv[0], "list"))
{
mainmode = MODE_LIST;
{
int l;
l = strlen(argv[i]);
+#ifndef DEBIAN
if (l <= 4 || strcmp(argv[i] + l - 4, ".rpm"))
continue;
+#else
+ if (l <= 4 || strcmp(argv[i] + l - 4, ".deb"))
+ continue;
+#endif
if (access(argv[i], R_OK))
{
perror(argv[i]);
commandlinepkgs = sat_calloc(argc, sizeof(Id));
if (!commandlinerepo)
commandlinerepo = repo_create(pool, "@commandline");
+#ifndef DEBIAN
repo_add_rpms(commandlinerepo, (const char **)argv + i, 1, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
+#else
+ repo_add_debs(commandlinerepo, (const char **)argv + i, 1, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
+#endif
commandlinepkgs[i] = commandlinerepo->end - 1;
}
if (commandlinerepo)
continue;
}
queue_init(&job2);
- mkselect(pool, mode, argv[i], &job2);
+ if (!mkselect(pool, mode, argv[i], &job2))
+ {
+ fprintf(stderr, "nothing matches '%s'\n", argv[i]);
+ exit(1);
+ }
if (repofilter && !limitrepo(pool, repofilter, &job2))
{
fprintf(stderr, "nothing in repo matches '%s'\n", argv[i]);
Solvable *s = pool_id2solvable(pool, p);
if (mainmode == MODE_INFO)
{
+ const char *str;
printf("Name: %s\n", solvable2str(pool, s));
printf("Repo: %s\n", s->repo->name);
printf("Summary: %s\n", solvable_lookup_str(s, SOLVABLE_SUMMARY));
- printf("Url: %s\n", solvable_lookup_str(s, SOLVABLE_URL));
- printf("License: %s\n", solvable_lookup_str(s, SOLVABLE_LICENSE));
+ str = solvable_lookup_str(s, SOLVABLE_URL);
+ if (str)
+ printf("Url: %s\n", str);
+ str = solvable_lookup_str(s, SOLVABLE_LICENSE);
+ if (str)
+ printf("License: %s\n", str);
printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION));
printf("\n");
}
}
}
job.elements[i] |= mode;
+ if (mainmode == MODE_ERASECLEAN)
+ job.elements[i] |= SOLVER_CLEANDEPS;
}
if (mainmode == MODE_DISTUPGRADE && allpkgs && repofilter)
addsoftlocks(pool, &job);
#endif
+#ifndef DEBIAN
rerunsolver:
+#endif
for (;;)
{
Id problem, solution;
solv->allowarchchange = 1;
solv->allowvendorchange = 1;
}
- if (mainmode == MODE_ERASE)
+ if (mainmode == MODE_ERASE || mainmode == MODE_ERASECLEAN)
solv->allowuninstall = 1; /* don't nag */
solver_solve(solv, &job);
if (!trans->steps.count)
{
printf("Nothing to do.\n");
+ solver_free(solv);
+ queue_free(&job);
+ pool_free(pool);
+ free_repoinfos(repoinfos, nrepoinfos);
+ sat_free(commandlinepkgs);
+#ifdef FEDORA
+ yum_substitute(pool, 0);
+#endif
exit(1);
}
printf("\n");
printf("Transaction summary:\n\n");
solver_printtransaction(solv);
-#ifndef FEDORA
+#if !defined(FEDORA) && !defined(DEBIAN)
if (1)
{
DUChanges duc[4];
if (!yesno("OK to continue (y/n)? "))
{
printf("Abort.\n");
+ solver_free(solv);
+ queue_free(&job);
+ pool_free(pool);
+ free_repoinfos(repoinfos, nrepoinfos);
+ sat_free(commandlinepkgs);
+#ifdef FEDORA
+ yum_substitute(pool, 0);
+#endif
exit(1);
}
putchar('\n');
}
+#ifndef DEBIAN
if (newpkgs)
{
Queue conflicts;
+ struct fcstate fcstate;
printf("Searching for file conflicts\n");
queue_init(&conflicts);
}
queue_free(&conflicts);
}
+#endif
printf("Committing transaction:\n\n");
transaction_order(trans, 0);
for (i = 0; i < trans->steps.count; i++)
{
+#ifndef DEBIAN
const char *evr, *evrp, *nvra;
+#endif
Solvable *s;
int j;
FILE *fp;
{
case SOLVER_TRANSACTION_ERASE:
printf("erase %s\n", solvid2str(pool, p));
+#ifndef DEBIAN
if (!s->repo->rpmdbid || !s->repo->rpmdbid[p - s->repo->start])
continue;
/* strip epoch from evr */
evr = evrp + 1;
nvra = pool_tmpjoin(pool, id2str(pool, s->name), "-", evr);
nvra = pool_tmpjoin(pool, nvra, ".", id2str(pool, s->arch));
- runrpm("-e", nvra, -1); /* to bad that --querybynumber doesn't work */
+ runrpm("-e", nvra, -1); /* too bad that --querybynumber doesn't work */
+#else
+ rundpkg("--remove", id2str(pool, s->name), 0);
+#endif
break;
case SOLVER_TRANSACTION_INSTALL:
case SOLVER_TRANSACTION_MULTIINSTALL:
continue;
rewind(fp);
lseek(fileno(fp), 0, SEEK_SET);
+#ifndef DEBIAN
runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp));
+#else
+ rundpkg("--install", "/dev/fd/3", fileno(fp));
+#endif
fclose(fp);
newpkgsfps[j] = 0;
break;
SET(libsatsolverext_SRCS
- pool_fileconflicts.c repo_content.c repo_deltainfoxml.c repo_helix.c repo_products.c
- repo_releasefile_products.c repo_repomdxml.c repo_rpmdb.c repo_rpmmd.c
+ repo_content.c repo_deltainfoxml.c repo_helix.c repo_products.c
+ repo_releasefile_products.c repo_repomdxml.c repo_rpmmd.c
repo_susetags.c repo_updateinfoxml.c repo_write.c repo_zyppdb.c
repo_deb.c)
+IF ( NOT DEBIAN )
+SET(libsatsolverext_SRCS
+ ${libsatsolverext_SRCS} pool_fileconflicts.c repo_rpmdb.c)
+ENDIF (NOT DEBIAN)
ADD_LIBRARY(satsolverext STATIC ${libsatsolverext_SRCS})
char *p, *q, *end, *tag;
int x, l;
int havesource = 0;
+ char checksum[32 * 2 + 1];
+ Id checksumtype = 0;
p = control;
while (*p)
if (!strcasecmp(tag, "enhances"))
s->enhances = makedeps(repo, q, s->enhances, 0);
break;
+ case 'F' << 8 | 'I':
+ if (!strcasecmp(tag, "filename"))
+ repodata_set_location(data, s - pool->solvables, 0, 0, q);
+ break;
case 'H' << 8 | 'O':
if (!strcasecmp(tag, "homepage"))
repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
if (!strcasecmp(tag, "installed-size"))
repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, atoi(q));
break;
+ case 'M' << 8 | 'D':
+ if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
+ {
+ strcpy(checksum, q);
+ checksumtype = REPOKEY_TYPE_MD5;
+ }
+ break;
case 'P' << 8 | 'A':
if (!strcasecmp(tag, "package"))
s->name = str2id(pool, q, 1);
else if (!strcasecmp(tag, "recommends"))
s->recommends = makedeps(repo, q, s->recommends, 0);
break;
+ case 'S' << 8 | 'H':
+ if (!strcasecmp(tag, "sha1") && checksumtype != REPOKEY_TYPE_SHA256 && strlen(q) == 20 * 2)
+ {
+ strcpy(checksum, q);
+ checksumtype = REPOKEY_TYPE_SHA1;
+ }
+ else if (!strcasecmp(tag, "sha256") && strlen(q) == 32 * 2)
+ {
+ strcpy(checksum, q);
+ checksumtype = REPOKEY_TYPE_SHA256;
+ }
+ break;
case 'S' << 8 | 'O':
if (!strcasecmp(tag, "source"))
{
break;
}
}
+ if (checksumtype)
+ repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
if (!s->arch)
s->arch = ARCH_ALL;
if (!s->evr)
s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
if (s->name && !havesource)
repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+ if (s->obsoletes)
+ {
+ /* obsoletes only count when the packages also conflict */
+ int i, j, k;
+ Id d;
+ for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
+ {
+ if (s->conflicts)
+ {
+ for (k = s->conflicts; repo->idarraydata[k] != 0; k++)
+ if (repo->idarraydata[k] == d)
+ break;
+ if (repo->idarraydata[k])
+ {
+ repo->idarraydata[j++] = d;
+ }
+ }
+ }
+ repo->idarraydata[j] = 0;
+ }
}
void
STATE_RELEASE, // 5
STATE_ARCH, // 6
STATE_SUMMARY, // 7
+ STATE_SHORTSUMMARY,
STATE_DESCRIPTION, // 8
STATE_UPDATEREPOKEY, // 9 should go away
STATE_CPEID, // 9
{ STATE_PRODUCT, "arch", STATE_ARCH, 1 },
{ STATE_PRODUCT, "productline", STATE_PRODUCTLINE, 1 },
{ STATE_PRODUCT, "summary", STATE_SUMMARY, 1 },
+ { STATE_PRODUCT, "shortsummary", STATE_SHORTSUMMARY, 1 },
{ STATE_PRODUCT, "description", STATE_DESCRIPTION, 1 },
{ STATE_PRODUCT, "register", STATE_REGISTER, 0 },
{ STATE_PRODUCT, "urls", STATE_URLS, 0 },
repodata_set_str(pd->data, pd->handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), pd->content);
pd->tmplang = sat_free((void *)pd->tmplang);
break;
+ case STATE_SHORTSUMMARY:
+ repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, pd->content);
+ break;
case STATE_DESCRIPTION:
repodata_set_str(pd->data, pd->handle, langtag(pd, SOLVABLE_DESCRIPTION, pd->tmplang), pd->content );
pd->tmplang = sat_free((void *)pd->tmplang);
join_freemem();
return;
}
-
+
/* code11 didn't work, try -release files parsing */
fullpath = root ? join2(root, "", "/etc") : "/etc";
dir = opendir(fullpath);
Id htype = 0;
#endif
// printf("V3 signature packet\n");
+ if (l < 17)
+ continue;
if (p[2] != 0x10 && p[2] != 0x11 && p[2] != 0x12 && p[2] != 0x13 && p[2] != 0x1f)
continue;
if (!memcmp(keyid, p + 6, 8))
unsigned char issuer[8];
// printf("V4 signature packet\n");
+ if (l < 6)
+ continue;
if (p[1] != 0x10 && p[1] != 0x11 && p[1] != 0x12 && p[1] != 0x13 && p[1] != 0x1f)
continue;
haveissuer = 0;
q = p + 4;
for (j = 0; q && j < 2; j++)
{
+ if (q + 2 > p + l)
+ {
+ q = 0;
+ break;
+ }
ql = q[0] << 8 | q[1];
q += 2;
+ if (q + ql > p + l)
+ {
+ q = 0;
+ break;
+ }
while (ql)
{
int sl;
*/
#define _GNU_SOURCE
+#define _XOPEN_SOURCE /* glibc2 needs this */
#include <sys/types.h>
#include <limits.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <expat.h>
+#include <time.h>
#include "pool.h"
#include "repo.h"
};
/*
+ * Convert date strings ("1287746075" or "2010-10-22 13:14:35")
+ * to timestamp.
+ */
+static time_t
+datestr2timestamp(const char *date)
+{
+ if (!date)
+ return 0;
+
+ if (strlen(date) == strspn(date, "0123456789"))
+ return atoi(date);
+
+ struct tm tm;
+ memset(&tm, 0, sizeof(tm));
+ if (!strptime(date, "%F%T", &tm))
+ return 0;
+ return timegm(&tm);
+}
+
+/*
* if we have seen a <filename>...
* inside of <package>...
- *
+ *
*
* If not, we must insert an empty filename to UPDATE_COLLECTION_FILENAME
* at </package> in order to keep all UPDATE_COLLECTION_* arrays in sync
else if (!strcmp(*atts, "version"))
version = atts[1];
}
-
+
solvable = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
pd->datanum = pd->solvable - pool->solvables;
-
+
solvable->vendor = str2id(pool, from, 1);
solvable->evr = str2id(pool, version, 1);
solvable->arch = ARCH_NOARCH;
}
if (date)
{
- if (strlen(date) == strspn(date, "0123456789"))
- repodata_set_num(pd->data, pd->datanum, SOLVABLE_BUILDTIME, atoi(date));
- else
- {
- /* FIXME: must convert to interger! */
- repodata_set_str(pd->data, pd->datanum, SOLVABLE_BUILDTIME, date);
- }
+ repodata_set_num(pd->data, pd->datanum, SOLVABLE_BUILDTIME, datestr2timestamp(date));
}
}
break;
/* <collection short="F8" */
case STATE_COLLECTION:
break;
- /* <name>Fedora 8</name> */
+ /* <name>Fedora 8</name> */
case STATE_NAME:
break;
/* <package arch="ppc64" name="imlib-debuginfo" release="6.fc8"
* src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm"
* version="1.9.15">
- *
+ *
*
* -> patch.conflicts: {name} < {version}.{release}
*/
repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
break;
}
- /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
+ /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
/* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
case STATE_FILENAME:
break;
*/
case STATE_DESCRIPTION:
repodata_set_str(pd->data, pd->datanum, SOLVABLE_DESCRIPTION, pd->content);
- break;
+ break;
/*
* <message>Warning! ...</message>
*/
repodata_add_flexarray(pd->data, pd->datanum, UPDATE_COLLECTION, pd->collhandle);
pd->collhandle = 0;
break;
- /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
+ /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
/* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
case STATE_FILENAME:
repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, pd->content);
-------------------------------------------------------------------
+Fri Oct 22 15:51:11 CEST 2010 - ma@suse.de
+
+- updateinfoxml: Correctly parse 'issued date' field.
+- 0.16.1
+
+-------------------------------------------------------------------
+Thu Sep 9 17:30:36 CEST 2010 - mls@suse.de
+
+- bump version to 0.16 to make it different from code11_3 branch
+- 0.16.0
+
+-------------------------------------------------------------------
+Mon Sep 6 13:50:02 UTC 2010 - dmacvicar@novell.com
+
+- ruby bindings: fix bugs regarding include path loading
+ (was hardcoded) and refactor the way the library path is defined
+ (only once in a helper)
+
+-------------------------------------------------------------------
+Mon Sep 6 12:38:21 UTC 2010 - dmacvicar@novell.com
+
+- SLE10SP3 also has vendor_ruby
+
+-------------------------------------------------------------------
+Wed Aug 18 14:11:08 UTC 2010 - kkaempf@novell.com
+
+- refactor ruby-satsolver, pure-Ruby extensions added
+- 0.15.1
+
+-------------------------------------------------------------------
+Thu May 6 17:39:20 CEST 2010 - mls@suse.de
+
+- fix bug in cleandeps code
+- bump version to 0.15 to make it different from code11_2 branch
+- 0.15.0
+
+-------------------------------------------------------------------
+Tue Mar 23 17:24:46 CET 2010 - ma@suse.de
+
+- Parse an installed products <shortsummary> tag [bnc#586303]
+
+-------------------------------------------------------------------
+Mon Mar 22 18:45:42 CET 2010 - mls@suse.de
+
+- dataiterator: reset parent when jumping to a solvid [bnc#589640]
+- 0.14.17
+
+-------------------------------------------------------------------
Thu Mar 11 22:13:26 CET 2010 - ma@suse.de
- parse global repository ids. [bnc#377568]
+%if 0%{?fedora_version}
+%{!?ruby_sitelib: %global ruby_sitelib %(ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"] ')}
+%{!?ruby_sitearch: %global ruby_sitearch %(ruby -rrbconfig -e 'puts Config::CONFIG["sitearchdir"] ')}
+%endif
+
Name: libsatsolver
Version: @VERSION@
Release: 1
%files -n ruby-satsolver
%defattr(-,root,root,-)
%if 0%{?suse_version}
-%if 0%{?suse_version} < 1100
+%if 0%{?suse_version} < 1010
%dir %{_libdir}/ruby/site_ruby/%{rb_ver}/%{rb_arch}
+%dir %{_libdir}/ruby/site_ruby/%{rb_ver}/satsolver
+%{_libdir}/ruby/site_ruby/%{rb_ver}/satsolver/*.rb
+%{_libdir}/ruby/site_ruby/%{rb_ver}/satsolver.rb
%{_libdir}/ruby/site_ruby/%{rb_ver}/%{rb_arch}/satsolver.so
%else
+%dir %{_libdir}/ruby/vendor_ruby/%{rb_ver}/satsolver
+%{_libdir}/ruby/vendor_ruby/%{rb_ver}/satsolver/*.rb
+%{_libdir}/ruby/vendor_ruby/%{rb_ver}/satsolver.rb
%{_libdir}/ruby/vendor_ruby/%{rb_ver}/%{rb_arch}/satsolver.so
%endif
%endif
%if 0%{?mandriva_version}
+%dir %{ruby_sitelibdir}/satsolver
+%{ruby_sitelibdir}/satsolver/*.rb
+%{ruby_sitelibdir}/satsolver.rb
%{ruby_sitearchdir}/satsolver.so
%endif
%if 0%{?fedora_version}
+%dir %{ruby_sitelib}/satsolver
+%{ruby_sitelib}/satsolver.rb
+%{ruby_sitelib}/satsolver/*.rb
%{ruby_sitearch}/satsolver.so
%endif
%doc bindings/ruby/html
if (r1 && !r2)
return 1;
}
+ if (mode == EVRCMP_COMPARE_EVONLY)
+ return 0;
if (r1 && r2)
{
if (s1 != ++r1 && s2 != ++r2)
#include "pooltypes.h"
-#define EVRCMP_COMPARE 0
-#define EVRCMP_MATCH_RELEASE 1
-#define EVRCMP_MATCH 2
+#define EVRCMP_COMPARE 0
+#define EVRCMP_MATCH_RELEASE 1
+#define EVRCMP_MATCH 2
+#define EVRCMP_COMPARE_EVONLY 3
extern int vercmp(const char *s1, const char *q1, const char *s2, const char *q2);
extern int evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode);
/*-----------------------------------------------------------------*/
/*
- * prep for prune_best_version_arch
+ * prep for prune_best_version
* sort by name
*/
plist->count = j;
}
+static void
+prune_to_highest_prio_per_name(Pool *pool, Queue *plist)
+{
+ Queue pq;
+ int i, j, k;
+ Id name;
+
+ queue_init(&pq);
+ sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
+ queue_push(&pq, plist->elements[0]);
+ name = pool->solvables[pq.elements[0]].name;
+ for (i = 1, j = 0; i < plist->count; i++)
+ {
+ if (pool->solvables[plist->elements[i]].name != name)
+ {
+ if (pq.count > 2)
+ prune_to_highest_prio(pool, &pq);
+ for (k = 0; k < pq.count; k++)
+ plist->elements[j++] = pq.elements[k];
+ queue_empty(&pq);
+ queue_push(&pq, plist->elements[i]);
+ name = pool->solvables[pq.elements[0]].name;
+ }
+ }
+ if (pq.count > 2)
+ prune_to_highest_prio(pool, &pq);
+ for (k = 0; k < pq.count; k++)
+ plist->elements[j++] = pq.elements[k];
+ queue_free(&pq);
+ plist->count = j;
+}
+
/*
* prune to recommended/suggested packages.
}
/*
- * prune_to_best_version
- *
- * sort list of packages (given through plist) by name and evr
- * return result through plist
+ * remove entries from plist that are obsoleted by other entries
+ * with different name.
+ * plist should be sorted in some way.
*/
-void
-prune_to_best_version(Pool *pool, Queue *plist)
+static void
+prune_obsoleted(Pool *pool, Queue *plist)
{
- Id best;
int i, j;
Solvable *s;
- if (plist->count < 2) /* no need to prune for a single entry */
- return;
- POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
-
- /* sort by name first, prefer installed */
- sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
-
- /* delete obsoleted. hmm, looks expensive! */
/* FIXME maybe also check provides depending on noupdateprovide? */
/* FIXME do not prune cycles */
for (i = 0; i < plist->count; i++)
continue;
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
continue;
+ /* hmm, expensive. should use hash if plist is big */
for (j = 0; j < plist->count; j++)
{
if (i == j)
if (plist->elements[i])
plist->elements[j++] = plist->elements[i];
plist->count = j;
+}
+
+/*
+ * prune_to_best_version
+ *
+ * sort list of packages (given through plist) by name and evr
+ * return result through plist
+ */
+void
+prune_to_best_version(Pool *pool, Queue *plist)
+{
+ int i, j;
+ Solvable *s, *best;
+
+ if (plist->count < 2) /* no need to prune for a single entry */
+ return;
+ POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
+
+ /* sort by name first, prefer installed */
+ sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
/* now find best 'per name' */
best = 0;
solvable2str(pool, s),
(pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
- if (!best) /* if no best yet, the current is best */
+ if (!best) /* if no best yet, the current is best */
{
- best = plist->elements[i];
+ best = s;
continue;
}
- /* name switch: re-init */
- if (pool->solvables[best].name != s->name) /* new name */
+ /* name switch: finish group, re-init */
+ if (best->name != s->name) /* new name */
{
- plist->elements[j++] = best; /* move old best to front */
- best = plist->elements[i]; /* take current as new best */
+ plist->elements[j++] = best - pool->solvables; /* move old best to front */
+ best = s; /* take current as new best */
continue;
}
- if (pool->solvables[best].evr != s->evr) /* compare evr */
+ if (best->evr != s->evr) /* compare evr */
{
- if (evrcmp(pool, pool->solvables[best].evr, s->evr, EVRCMP_COMPARE) < 0)
- best = plist->elements[i];
+ if (evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) < 0)
+ best = s;
}
}
-
- if (!best)
- best = plist->elements[0];
-
- plist->elements[j++] = best;
+ plist->elements[j++] = best - pool->solvables; /* finish last group */
plist->count = j;
+
+ /* we reduced the list to one package per name, now look at
+ * package obsoletes */
+ if (plist->count > 1)
+ prune_obsoleted(pool, plist);
}
prune_to_best_version(pool, plist);
}
+/* installed packages involed in a dup operation can only be kept
+* if they are identical to a non-installed one */
+static void
+prune_installed_dup_packages(Solver *solv, Queue *plist)
+{
+ Pool *pool = solv->pool;
+ int i, j, k;
+
+ for (i = j = 0; i < plist->count; i++)
+ {
+ Id p = plist->elements[i];
+ Solvable *s = pool->solvables + p;
+ if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))))
+ {
+ for (k = 0; k < plist->count; k++)
+ {
+ Solvable *s2 = pool->solvables + plist->elements[k];
+ if (s2->repo != pool->installed && solvable_identical(s, s2))
+ break;
+ }
+ if (k == plist->count)
+ continue; /* no identical package found, ignore installed package */
+ }
+ plist->elements[j++] = p;
+ }
+ if (j)
+ plist->count = j;
+}
+/*
+ * POLICY_MODE_CHOOSE: default, do all pruning steps
+ * POLICY_MODE_RECOMMEND: leave out prune_to_recommended
+ * POLICY_MODE_SUGGEST: leave out prune_to_recommended, do prio pruning just per name
+ */
void
policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
{
Pool *pool = solv->pool;
- if (plist->count > 1 && mode != POLICY_MODE_SUGGEST)
- prune_to_highest_prio(pool, plist);
+ if (plist->count > 1)
+ {
+ if (mode != POLICY_MODE_SUGGEST)
+ prune_to_highest_prio(pool, plist);
+ else
+ prune_to_highest_prio_per_name(pool, plist);
+ /* installed dup packages need special treatment as prio pruning
+ * does not prune installed packages */
+ if (plist->count > 1 && pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size))
+ prune_installed_dup_packages(solv, plist);
+ }
if (plist->count > 1 && mode == POLICY_MODE_CHOOSE)
prune_to_recommended(solv, plist);
prune_best_arch_name_version(solv, pool, plist);
return 1; /* no class matches */
}
+/* check if it is illegal to replace installed
+ * package "is" with package "s" (which must obsolete "is")
+ */
+int
+policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore)
+{
+ Pool *pool = solv->pool;
+ int ret = 0;
+ if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !solv->allowdowngrade)
+ {
+ if (is->name == s->name && evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0)
+ ret |= POLICY_ILLEGAL_DOWNGRADE;
+ }
+ if (!(ignore & POLICY_ILLEGAL_ARCHCHANGE) && !solv->allowarchchange)
+ {
+ if (is->arch != s->arch && policy_illegal_archchange(solv, s, is))
+ ret |= POLICY_ILLEGAL_ARCHCHANGE;
+ }
+ if (!(ignore & POLICY_ILLEGAL_VENDORCHANGE) && !solv->allowvendorchange)
+ {
+ if (is->vendor != s->vendor && policy_illegal_vendorchange(solv, s, is))
+ ret |= POLICY_ILLEGAL_VENDORCHANGE;
+ }
+ return ret;
+}
/*-------------------------------------------------------------------
*
* candidates : List of candidates (This list depends on other
* restrictions like architecture and vendor policies too)
*/
+
+#define POLICY_ILLEGAL_DOWNGRADE 1
+#define POLICY_ILLEGAL_ARCHCHANGE 2
+#define POLICY_ILLEGAL_VENDORCHANGE 4
+
extern void policy_filter_unwanted(Solver *solv, Queue *plist, int mode);
extern int policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2);
extern int policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2);
+extern int policy_is_illegal(Solver *solv, Solvable *s1, Solvable *s2, int ignore);
extern void policy_findupdatepackages(Solver *solv,
Solvable *s,
Queue *qs,
queue_init(&pool->vendormap);
pool->debugmask = SAT_DEBUG_RESULT; /* FIXME */
+#ifdef FEDORA
+ pool->obsoleteusescolors = 1;
+#endif
+#ifdef DEBIAN
+ pool->allowselfconflicts = 1;
+# ifdef MULTI_SEMANTICS
+ pool->disttype = DISTTYPE_DEB;
+# endif
+#endif
return pool;
}
return 0;
}
-/* match two dependencies */
+/* match (flags, evr) against provider (pflags, pevr) */
+static inline int
+pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr)
+{
+ if (!pflags || !flags || pflags >= 8 || flags >= 8)
+ return 0;
+ if (flags == 7 || pflags == 7)
+ return 1; /* rel provides every version */
+ if ((pflags & flags & 5) != 0)
+ return 1; /* both rels show in the same direction */
+ if (pevr == evr)
+ {
+ if ((pflags & flags & 2) != 0)
+ return 1; /* both have '=', match */
+ }
+ else
+ {
+ int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
+ if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)))) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* match two dependencies (d1 = provider) */
int
pool_match_dep(Pool *pool, Id d1, Id d2)
{
Reldep *rd1, *rd2;
- int pflags, flags;
if (d1 == d2)
return 1;
return pool_match_dep(pool, rd1->name, d2);
}
rd2 = GETRELDEP(pool, d2);
+ /* first match name */
if (!pool_match_dep(pool, rd1->name, rd2->name))
return 0;
- pflags = rd1->flags;
- flags = rd2->flags;
- if (!pflags || !flags || pflags >= 8 || flags >= 8)
- return 0;
- if (flags == 7 || pflags == 7)
- return 1;
- if ((pflags & flags & 5) != 0)
- return 1;
- if (rd1->evr == rd2->evr)
- {
- if ((pflags & flags & 2) != 0)
- return 1;
- }
- else
- {
- int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
- if ((f & (1 << (1 + evrcmp(pool, rd1->evr, rd2->evr, EVRCMP_DEPCMP)))) != 0)
- return 1;
- }
- return 0;
+ /* name matches, check flags and evr */
+ return pool_match_flags_evr(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
}
/*
Id evr = rd->evr;
int flags = rd->flags;
Id pid, *pidp;
- Id p, wp, *pp, *pp2, *pp3;
+ Id p, *pp;
d = GETRELID(d);
queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
- switch (flags)
+
+ if (flags >= 8)
{
- case REL_AND:
- case REL_WITH:
- pp = pool_whatprovides_ptr(pool, name);
- pp2 = pool_whatprovides_ptr(pool, evr);
- while ((p = *pp++) != 0)
- {
- for (pp3 = pp2; *pp3;)
- if (*pp3++ == p)
- {
- queue_push(&plist, p);
- break;
- }
- }
- break;
- case REL_OR:
- pp = pool_whatprovides_ptr(pool, name);
- while ((p = *pp++) != 0)
- queue_push(&plist, p);
- pp = pool_whatprovides_ptr(pool, evr);
- while ((p = *pp++) != 0)
- queue_pushunique(&plist, p);
- break;
- case REL_NAMESPACE:
- if (name == NAMESPACE_OTHERPROVIDERS)
- {
- wp = pool_whatprovides(pool, evr);
- pool->whatprovides_rel[d] = wp;
- return wp;
- }
- if (pool->nscallback)
+ /* special relation */
+ Id wp = 0;
+ Id *pp2, *pp3;
+
+ switch (flags)
{
- /* ask callback which packages provide the dependency
- * 0: none
- * 1: the system (aka SYSTEMSOLVABLE)
- * >1: a set of packages, stored as offset on whatprovidesdata
- */
- p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
- if (p > 1)
+ case REL_AND:
+ case REL_WITH:
+ wp = pool_whatprovides(pool, name);
+ pp2 = pool_whatprovides_ptr(pool, evr);
+ pp = pool->whatprovidesdata + wp;
+ while ((p = *pp++) != 0)
{
- queue_free(&plist);
- pool->whatprovides_rel[d] = p;
- return p;
+ for (pp3 = pp2; *pp3; pp3++)
+ if (*pp3 == p)
+ break;
+ if (*pp3)
+ queue_push(&plist, p); /* found it */
+ else
+ wp = 0;
}
- if (p == 1)
- queue_push(&plist, SYSTEMSOLVABLE);
- }
- break;
- case REL_ARCH:
- /* small hack: make it possible to match <pkg>.src
- * we have to iterate over the solvables as src packages do not
- * provide anything, thus they are not indexed in our
- * whatprovides hash */
- if (evr == ARCH_SRC)
- {
- Solvable *s;
- for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
+ break;
+ case REL_OR:
+ wp = pool_whatprovides(pool, name);
+ pp = pool->whatprovidesdata + wp;
+ if (!*pp)
+ wp = pool_whatprovides(pool, evr);
+ else
+ {
+ int cnt;
+ while ((p = *pp++) != 0)
+ queue_push(&plist, p);
+ cnt = plist.count;
+ pp = pool_whatprovides_ptr(pool, evr);
+ while ((p = *pp++) != 0)
+ queue_pushunique(&plist, p);
+ if (plist.count != cnt)
+ wp = 0;
+ }
+ break;
+ case REL_NAMESPACE:
+ if (name == NAMESPACE_OTHERPROVIDERS)
+ {
+ wp = pool_whatprovides(pool, evr);
+ break;
+ }
+ if (pool->nscallback)
+ {
+ /* ask callback which packages provide the dependency
+ * 0: none
+ * 1: the system (aka SYSTEMSOLVABLE)
+ * >1: set of packages, stored as offset on whatprovidesdata
+ */
+ p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
+ if (p > 1)
+ wp = p;
+ if (p == 1)
+ queue_push(&plist, SYSTEMSOLVABLE);
+ }
+ break;
+ case REL_ARCH:
+ /* small hack: make it possible to match <pkg>.src
+ * we have to iterate over the solvables as src packages do not
+ * provide anything, thus they are not indexed in our
+ * whatprovides hash */
+ if (evr == ARCH_SRC)
{
- if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+ Solvable *s;
+ for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
+ {
+ if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+ continue;
+ if (pool_match_nevr(pool, s, name))
+ queue_push(&plist, p);
+ }
+ break;
+ }
+ wp = pool_whatprovides(pool, name);
+ pp = pool->whatprovidesdata + wp;
+ while ((p = *pp++) != 0)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->arch == evr)
+ queue_push(&plist, p);
+ else
+ wp = 0;
+ }
+ break;
+ case REL_FILECONFLICT:
+ pp = pool_whatprovides_ptr(pool, name);
+ while ((p = *pp++) != 0)
+ {
+ Id origd = MAKERELDEP(d);
+ Solvable *s = pool->solvables + p;
+ if (!s->provides)
continue;
- if (pool_match_nevr(pool, s, name))
+ pidp = s->repo->idarraydata + s->provides;
+ while ((pid = *pidp++) != 0)
+ if (pid == origd)
+ break;
+ if (pid)
queue_push(&plist, p);
}
break;
- }
- wp = pool_whatprovides(pool, name);
- pp = pool->whatprovidesdata + wp;
- while ((p = *pp++) != 0)
- {
- Solvable *s = pool->solvables + p;
- if (s->arch == evr)
- queue_push(&plist, p);
- else
- wp = 0;
+ default:
+ break;
}
if (wp)
{
- /* all solvables match, no need to create a new list */
+ /* we can reuse an existing entry */
+ queue_free(&plist);
pool->whatprovides_rel[d] = wp;
return wp;
}
- break;
- case REL_FILECONFLICT:
- pp = pool_whatprovides_ptr(pool, name);
- while ((p = *pp++) != 0)
- {
- Id origd = MAKERELDEP(d);
- Solvable *s = pool->solvables + p;
- if (!s->provides)
- continue;
- pidp = s->repo->idarraydata + s->provides;
- while ((pid = *pidp++) != 0)
- if (pid == origd)
- break;
- if (pid)
- queue_push(&plist, p);
- }
- break;
- default:
- break;
}
-
- /* convert to whatprovides id */
+ else if (flags)
+ {
+ /* simple version comparison relation */
#if 0
- POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
+ POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
#endif
- if (flags && flags < 8)
- {
pp = pool_whatprovides_ptr(pool, name);
while (ISRELDEP(name))
{
while ((p = *pp++) != 0)
{
Solvable *s = pool->solvables + p;
-#if 0
- POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, s->name));
-#endif
if (!s->provides)
{
/* no provides - check nevr */
pidp = s->repo->idarraydata + s->provides;
while ((pid = *pidp++) != 0)
{
- int pflags;
- Id pevr;
-
if (pid == name)
{
#if defined(MULTI_SEMANTICS)
prd = GETRELDEP(pool, pid);
if (prd->name != name)
continue; /* wrong provides name */
- /* right package, both deps are rels */
- pflags = prd->flags;
- if (!pflags)
- continue;
- if (flags == 7 || pflags == 7)
- break; /* included */
- if ((pflags & flags & 5) != 0)
- break; /* same direction, match */
- pevr = prd->evr;
- if (pevr == evr)
- {
- if ((pflags & flags & 2) != 0)
- break; /* both have =, match */
- }
- else
- {
- int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
- if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)))) != 0)
- break;
- }
+ /* right package, both deps are rels. check flags/evr */
+ if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
+ break; /* matches */
}
if (!pid)
- continue; /* no rel match */
+ continue; /* none of the providers matched */
queue_push(&plist, p);
}
/* make our system solvable provide all unknown rpmlib() stuff */
int obsoleteusesprovides; /* true: obsoletes are matched against provides, not names */
int implicitobsoleteusesprovides; /* true: implicit obsoletes due to same name are matched against provides, not names */
int obsoleteusescolors; /* true: obsoletes check arch color */
+ int noinstalledobsoletes; /* true: ignore obsoletes of installed packages */
int novirtualconflicts; /* true: conflicts on names, not on provides */
int allowselfconflicts; /* true: packages which conflict with itself are installable */
#ifdef MULTI_SEMANTICS
"ia64", "ia64:i686:i586:i486:i386",
"ppc64", "ppc64:ppc",
"ppc", "ppc",
+ "armv7l", "armv7l:armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
"armv6l", "armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
"armv5tejl", "armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
"armv5tel", "armv5tel:armv5l:armv4tl:armv4l:armv3l",
rr = solv->rules + solv->featurerules + (why - solv->updaterules);
if (!rr->p)
rr = solv->rules + why;
- if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0)
+ if (solv->dupmap_all && solv->rules[why].p != p && solv->decisionmap[p] > 0)
{
/* distupgrade case, allow to keep old package */
queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
convertsolution(solv, solution.elements[j], &solv->solutions);
if (solv->solutions.count == solstart + 1)
{
- solv->solutions.count--;
- if (!essentialok && i + 1 == problem.count && !nsol)
+ solv->solutions.count--; /* this one did not work out */
+ if (nsol || i + 1 < problem.count)
+ continue; /* got one or still hope */
+ if (!essentialok)
{
/* nothing found, start over */
+ POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "nothing found, re-run with essentialok = 1\n");
essentialok = 1;
i = -1;
+ continue;
+ }
+ /* this is bad, we found no solution */
+ /* for now just offer a rule */
+ POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "nothing found, already did essentialok, fake it\n");
+ queue_push(&solv->solutions, 0);
+ for (j = 0; j < problem.count; j++)
+ {
+ queue_empty(&solution);
+ queue_push(&solution, problem.elements[j]);
+ convertsolution(solv, solution.elements[j], &solv->solutions);
+ if (solv->solutions.count > solstart + 1)
+ break;
+ }
+ if (solv->solutions.count == solstart + 1)
+ {
+ solv->solutions.count--;
+ continue; /* sorry */
}
- continue;
}
/* patch in number of solution elements */
solv->solutions.elements[solstart] = (solv->solutions.count - (solstart + 1)) / 2;
static inline Repo *pool_id2repo(Pool *pool, Id repoid)
{
- return pool->repos[repoid - 1];
+ return repoid ? pool->repos[repoid - 1] : 0;
}
static inline int pool_installable(const Pool *pool, Solvable *s)
Repodata *data = di->data;
if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
- if (!di->matcher.match || (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING || !repodata_filelistfilter_matches(di->data, di->matcher.match))
+ if (!di->matcher.match
+ || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
+ && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
+ || !repodata_filelistfilter_matches(di->data, di->matcher.match))
needcomplete = 1;
if (data->state != REPODATA_AVAILABLE)
return needcomplete ? 1 : 0;
dataiterator_skip_solvable(Dataiterator *di)
{
di->nparents = 0;
+ di->kv.parent = 0;
di->rootlevel = 0;
di->keyname = di->keynames[0];
di->state = di_nextsolvable;
dataiterator_skip_repo(Dataiterator *di)
{
di->nparents = 0;
+ di->kv.parent = 0;
di->rootlevel = 0;
di->keyname = di->keynames[0];
di->state = di_nextrepo;
dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
{
di->nparents = 0;
+ di->kv.parent = 0;
di->rootlevel = 0;
di->keyname = di->keynames[0];
if (solvid == SOLVID_POS)
dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
{
di->nparents = 0;
+ di->kv.parent = 0;
di->rootlevel = 0;
di->repo = repo;
di->repoid = -1;
#include <string.h>
#include <unistd.h>
#include <assert.h>
+#include <fcntl.h>
#include <time.h>
#include "repo.h"
store->pagefd = dup(fileno(fp));
if (store->pagefd == -1)
can_seek = 0;
+ else
+ fcntl(store->pagefd, F_SETFD, FD_CLOEXEC);
#ifdef DEBUG_PAGING
fprintf(stderr, "can %sseek\n", can_seek ? "" : "NOT ");
#include "pool.h"
#include "poolarch.h"
#include "util.h"
+#include "evr.h"
#include "policy.h"
#include "solverdebug.h"
#define RULES_BLOCK 63
static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
+static void solver_createcleandepsmap(Solver *solv);
/*-------------------------------------------------------------------
* Check if dependency is possible
/*
* special multiversion patch conflict handling:
- * a patch conflict is also satisfied, if some other
+ * a patch conflict is also satisfied if some other
* version with the same name/arch that doesn't conflict
- * get's installed. The generated rule is thus:
+ * gets installed. The generated rule is thus:
* -patch|-cpack|opack1|opack2|...
*/
static Id
dontfix = 0;
if (installed /* Installed system available */
- && !solv->fixsystem /* NOT repair errors in rpm dependency graph */
&& s->repo == installed /* solvable is installed */
- && (!solv->fixmap.size || !MAPTST(&solv->fixmap, n - installed->start)))
+ && !solv->fixmap_all /* NOT repair errors in rpm dependency graph */
+ && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
{
dontfix = 1; /* dont care about broken rpm deps */
}
}
/*-----------------------------------------
- * check obsoletes if not installed
- * (only installation will trigger the obsoletes in rpm)
+ * check obsoletes and implicit obsoletes of a package
+ * if ignoreinstalledsobsoletes is not set, we're also checking
+ * obsoletes of installed packages (like newer rpm versions)
*/
- if (!installed || pool->solvables[n].repo != installed)
- { /* not installed */
+ if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
+ {
int noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, n);
+ int isinstalled = (installed && s->repo == installed);
if (s->obsoletes && !noobs)
{
obsp = s->repo->idarraydata + s->obsoletes;
FOR_PROVIDES(p, pp, obs)
{
Solvable *ps = pool->solvables + p;
+ if (p == n)
+ continue;
+ if (isinstalled && dontfix && ps->repo == installed)
+ continue; /* don't repair installed/installed problems */
if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
&& !pool_match_nevr(pool, ps, obs))
continue;
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
continue;
- addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
+ if (!isinstalled)
+ addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
+ else
+ addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES, obs);
}
}
}
- FOR_PROVIDES(p, pp, s->name)
+ /* check implicit obsoletes
+ * for installed packages we only need to check installed/installed problems (and
+ * only when dontfix is not set), as the others are picked up when looking at the
+ * uninstalled package.
+ */
+ if (!isinstalled || !dontfix)
{
- Solvable *ps = pool->solvables + p;
- /* we still obsolete packages with same nevra, like rpm does */
- /* (actually, rpm mixes those packages. yuck...) */
- if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
- continue;
- if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
- continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- if (s->name == ps->name)
- addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
- else
- addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ Solvable *ps = pool->solvables + p;
+ if (p == n)
+ continue;
+ if (isinstalled && ps->repo != installed)
+ continue;
+ /* we still obsolete packages with same nevra, like rpm does */
+ /* (actually, rpm mixes those packages. yuck...) */
+ if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
+ continue;
+ if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ if (s->name == ps->name)
+ addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
+ else
+ addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
+ }
}
}
queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
p = s - pool->solvables;
/* find update candidates for 's' */
- if (solv->distupgrade)
+ if (solv->dupmap_all)
p = finddistupgradepackages(solv, s, &qs, allow_all);
else
policy_findupdatepackages(solv, s, &qs, allow_all);
- if (!allow_all && !solv->distupgrade && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+ if (!allow_all && !solv->dupmap_all && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
addduppackages(solv, s, &qs);
if (!allow_all && qs.count && solv->noobsoletes.size)
}
if (j < qs.count)
{
- if (d && solv->updatesystem && solv->installed && s->repo == solv->installed)
+ if (d && solv->installed && s->repo == solv->installed &&
+ (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, s - pool->solvables - solv->installed->start))))
{
if (!solv->multiversionupdaters)
solv->multiversionupdaters = sat_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
solv->multiversionupdaters[s - pool->solvables - solv->installed->start] = d;
}
- if (j == 0 && p == -SYSTEMSOLVABLE && solv->distupgrade)
+ if (j == 0 && p == -SYSTEMSOLVABLE && solv->dupmap_all)
{
queue_push(&solv->orphaned, s - pool->solvables); /* treat as orphaned */
j = qs.count;
a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
if (a != 1 && pool->installed && ps->repo == pool->installed)
{
- if (!solv->distupgrade)
+ if (!solv->dupmap_all && !(solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
queue_pushunique(&allowedarchs, ps->arch); /* also ok to keep this architecture */
continue; /* ignore installed solvables when calculating the best arch */
}
solver_freedupmaps(Solver *solv)
{
map_free(&solv->dupmap);
- map_free(&solv->dupinvolvedmap);
+ /* we no longer free solv->dupinvolvedmap as we need it in
+ * policy's priority pruning code. sigh. */
}
void
Id select, p, pp;
Repo *installed;
Solvable *s;
- int i;
+ int i, j, set, qstart, pass;
+ Map omap;
installed = solv->installed;
select = how & SOLVER_SELECTMASK;
switch (how & SOLVER_JOBMASK)
{
case SOLVER_INSTALL:
- if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && solv->infarchrules != solv->infarchrules_end && ISRELDEP(what))
+ set = how & SOLVER_SETMASK;
+ if (!(set & SOLVER_NOAUTOSET))
{
- Reldep *rd = GETRELDEP(pool, what);
- if (rd->flags == REL_ARCH)
+ /* automatically add set bits by analysing the job */
+ if (select == SOLVER_SOLVABLE)
+ set |= SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
+ else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
+ {
+ Reldep *rd = GETRELDEP(pool, what);
+ if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
+ {
+#if !defined(DEBIAN_SEMANTICS)
+ const char *evr = id2str(pool, rd->evr);
+ if (strchr(evr, '-'))
+ set |= SOLVER_SETEVR;
+ else
+ set |= SOLVER_SETEV;
+#else
+ set |= SOLVER_SETEVR;
+#endif
+ }
+ if (rd->flags <= 7 && ISRELDEP(rd->name))
+ rd = GETRELDEP(pool, rd->name);
+ if (rd->flags == REL_ARCH)
+ set |= SOLVER_SETARCH;
+ }
+ }
+ else
+ set &= ~SOLVER_NOAUTOSET;
+ if (!set)
+ return;
+ if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
+ {
+ if (select == SOLVER_SOLVABLE)
+ queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
+ else
{
int qcnt = q->count;
FOR_JOB_SELECT(p, pp, select, what)
break;
if (i < q->count)
continue;
- queue_push(q, DISABLE_INFARCH);
- queue_push(q, s->name);
+ queue_push2(q, DISABLE_INFARCH, s->name);
}
}
}
- if (select != SOLVER_SOLVABLE)
- break;
- s = pool->solvables + what;
- if (solv->infarchrules != solv->infarchrules_end)
+ if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
{
- queue_push(q, DISABLE_INFARCH);
- queue_push(q, s->name);
- }
- if (solv->duprules != solv->duprules_end)
- {
- queue_push(q, DISABLE_DUP);
- queue_push(q, s->name);
+ if (select == SOLVER_SOLVABLE)
+ queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
+ else
+ {
+ int qcnt = q->count;
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ s = pool->solvables + p;
+ /* unify names */
+ for (i = qcnt; i < q->count; i += 2)
+ if (q->elements[i + 1] == s->name)
+ break;
+ if (i < q->count)
+ continue;
+ queue_push2(q, DISABLE_DUP, s->name);
+ }
+ }
}
if (!installed)
return;
- if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what))
+ /* now the hard part: disable some update rules */
+
+ /* first check if we have noobs or installed packages in the job */
+ FOR_JOB_SELECT(p, pp, select, what)
{
- /* XXX: remove if we always do distupgrade with DUP rules */
- if (solv->distupgrade && s->repo == installed)
+ if (pool->solvables[p].repo == installed)
{
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, what);
+ if (select == SOLVER_SOLVABLE)
+ queue_push2(q, DISABLE_UPDATE, what);
return;
}
- return;
- }
- if (s->repo == installed)
- {
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, what);
- return;
+ if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
+ return;
}
- if (s->obsoletes)
+
+ /* all job packages obsolete */
+ qstart = q->count;
+ pass = 0;
+ memset(&omap, 0, sizeof(omap));
+ FOR_JOB_SELECT(p, pp, select, what)
{
- Id obs, *obsp;
- obsp = s->repo->idarraydata + s->obsoletes;
- while ((obs = *obsp++) != 0)
- FOR_PROVIDES(p, pp, obs)
- {
- Solvable *ps = pool->solvables + p;
- if (ps->repo != installed)
- continue;
- if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
- continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, p);
- }
+ Id p2, pp2;
+
+ if (pass == 1)
+ map_grow(&omap, installed->end - installed->start);
+ s = pool->solvables + p;
+ if (s->obsoletes)
+ {
+ Id obs, *obsp;
+ obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ FOR_PROVIDES(p2, pp2, obs)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (ps->repo != installed)
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ if (pass)
+ MAPSET(&omap, p2 - installed->start);
+ else
+ queue_push2(q, DISABLE_UPDATE, p2);
+ }
+ }
+ FOR_PROVIDES(p2, pp2, s->name)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (ps->repo != installed)
+ continue;
+ if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ if (pass)
+ MAPSET(&omap, p2 - installed->start);
+ else
+ queue_push2(q, DISABLE_UPDATE, p2);
+ }
+ if (pass)
+ {
+ for (i = j = qstart; i < q->count; i += 2)
+ {
+ if (MAPTST(&omap, q->elements[i + 1] - installed->start))
+ {
+ MAPCLR(&omap, q->elements[i + 1] - installed->start);
+ q->elements[j + 1] = q->elements[i + 1];
+ j += 2;
+ }
+ }
+ queue_truncate(q, j);
+ }
+ if (q->count == qstart)
+ break;
+ pass++;
}
- FOR_PROVIDES(p, pp, s->name)
+ if (omap.size)
+ map_free(&omap);
+
+ if (qstart == q->count)
+ return; /* nothing to prune */
+ if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
+ return; /* all is set */
+
+ /* now that we know which installed packages are obsoleted check each of them */
+ for (i = j = qstart; i < q->count; i += 2)
{
- Solvable *ps = pool->solvables + p;
- if (ps->repo != installed)
- continue;
- if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
- continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, p);
+ Solvable *is = pool->solvables + q->elements[i + 1];
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ int illegal = 0;
+ s = pool->solvables + p;
+ if ((set & SOLVER_SETEVR) != 0)
+ illegal |= POLICY_ILLEGAL_DOWNGRADE; /* ignore */
+ if ((set & SOLVER_SETARCH) != 0)
+ illegal |= POLICY_ILLEGAL_ARCHCHANGE; /* ignore */
+ if ((set & SOLVER_SETVENDOR) != 0)
+ illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
+ illegal = policy_is_illegal(solv, is, s, illegal);
+ if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
+ {
+ /* it's ok if the EV is different */
+ if (evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
+ illegal = 0;
+ }
+ if (illegal)
+ break;
+ }
+ if (!p)
+ {
+ /* no package conflicts with the update rule */
+ /* thus keep the DISABLE_UPDATE */
+ q->elements[j + 1] = q->elements[i + 1];
+ j += 2;
+ }
}
+ queue_truncate(q, j);
return;
+
case SOLVER_ERASE:
if (!installed)
break;
FOR_JOB_SELECT(p, pp, select, what)
if (pool->solvables[p].repo == installed)
- {
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, p);
- }
+ queue_push2(q, DISABLE_UPDATE, p);
return;
default:
return;
lastjob = j;
jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
}
+ if (solv->cleandepsmap.size)
+ {
+ solver_createcleandepsmap(solv);
+ for (i = solv->installed->start; i < solv->installed->end; i++)
+ if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
+ queue_push2(&allq, DISABLE_UPDATE, i);
+ }
MAPZERO(&solv->noupdate);
for (i = 0; i < allq.count; i += 2)
{
lastjob = j;
jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
}
+ if (solv->cleandepsmap.size)
+ {
+ solver_createcleandepsmap(solv);
+ for (i = solv->installed->start; i < solv->installed->end; i++)
+ if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
+ queue_push2(&allq, DISABLE_UPDATE, i);
+ }
for (j = 0; j < q.count; j += 2)
{
Id type = q.elements[j], arg = q.elements[j + 1];
}
void
-addchoicerules(Solver *solv)
+solver_addchoicerules(Solver *solv)
{
Pool *pool = solv->pool;
Map m, mneg;
if (p2)
{
/* found installed package p2 that we can update to p */
- if (!solv->allowarchchange && s->arch != s2->arch && policy_illegal_archchange(solv, s, s2))
- continue;
- if (!solv->allowvendorchange && s->vendor != s2->vendor && policy_illegal_vendorchange(solv, s, s2))
- continue;
if (MAPTST(&mneg, p))
continue;
+ if (policy_is_illegal(solv, s2, s, 0))
+ continue;
queue_push(&qi, p2);
queue_push(&q, p);
continue;
if (obs)
{
/* found installed package p2 that we can update to p */
- if (!solv->allowarchchange && s->arch != s2->arch && policy_illegal_archchange(solv, s, s2))
- continue;
- if (!solv->allowvendorchange && s->vendor != s2->vendor && policy_illegal_vendorchange(solv, s, s2))
- continue;
if (MAPTST(&mneg, p))
continue;
+ if (policy_is_illegal(solv, s2, s, 0))
+ continue;
queue_push(&qi, p2);
queue_push(&q, p);
continue;
/* called when a choice rule is disabled by analyze_unsolvable. We also
* have to disable all other choice rules so that the best packages get
* picked */
-
void
-disablechoicerules(Solver *solv, Rule *r)
+solver_disablechoicerules(Solver *solv, Rule *r)
{
Id rid, p, *pp;
Pool *pool = solv->pool;
}
}
+static void solver_createcleandepsmap(Solver *solv)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ Queue *job = &solv->job;
+ Map userinstalled;
+ Map im;
+ Map installedm;
+ Rule *r;
+ Id rid, how, what, select;
+ Id p, pp, ip, *jp;
+ Id req, *reqp, sup, *supp;
+ Solvable *s;
+ Queue iq;
+ int i;
+
+ map_init(&userinstalled, installed->end - installed->start);
+ map_init(&im, pool->nsolvables);
+ map_init(&installedm, pool->nsolvables);
+ map_empty(&solv->cleandepsmap);
+ queue_init(&iq);
+
+ for (i = 0; i < job->count; i += 2)
+ {
+ how = job->elements[i];
+ if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+ {
+ what = job->elements[i + 1];
+ select = how & SOLVER_SELECTMASK;
+ FOR_JOB_SELECT(p, pp, select, what)
+ if (pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ }
+ }
+ /* add all positive elements (e.g. locks) to "userinstalled" */
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->d < 0)
+ continue;
+ FOR_RULELITERALS(p, jp, r)
+ if (p > 0 && pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ }
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->p >= 0 || r->d != 0)
+ continue; /* disabled or not erase */
+ p = -r->p;
+ if (pool->solvables[p].repo != installed)
+ continue;
+ MAPCLR(&userinstalled, p - installed->start);
+ i = solv->ruletojob.elements[rid - solv->jobrules];
+ how = job->elements[i];
+ if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
+ queue_push(&iq, p);
+ }
+ for (p = installed->start; p < installed->end; p++)
+ {
+ if (pool->solvables[p].repo != installed)
+ continue;
+ MAPSET(&installedm, p);
+ MAPSET(&im, p);
+ }
+
+ while (iq.count)
+ {
+ ip = queue_shift(&iq);
+ s = pool->solvables + ip;
+ if (!MAPTST(&im, ip))
+ continue;
+ if (!MAPTST(&installedm, ip))
+ continue;
+ if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
+ continue;
+ MAPCLR(&im, ip);
+#ifdef CLEANDEPSDEBUG
+ printf("hello %s\n", solvable2str(pool, s));
+#endif
+ if (s->requires)
+ {
+ reqp = s->repo->idarraydata + s->requires;
+ while ((req = *reqp++) != 0)
+ {
+ if (req == SOLVABLE_PREREQMARKER)
+ continue;
+#if 0
+ /* count number of installed packages that match */
+ count = 0;
+ FOR_PROVIDES(p, pp, req)
+ if (MAPTST(&installedm, p))
+ count++;
+ if (count > 1)
+ continue;
+#endif
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (MAPTST(&im, p))
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (s->recommends)
+ {
+ reqp = s->repo->idarraydata + s->recommends;
+ while ((req = *reqp++) != 0)
+ {
+#if 0
+ count = 0;
+ FOR_PROVIDES(p, pp, req)
+ if (MAPTST(&installedm, p))
+ count++;
+ if (count > 1)
+ continue;
+#endif
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (MAPTST(&im, p))
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (!iq.count)
+ {
+ /* supplements pass */
+ for (ip = solv->installed->start; ip < solv->installed->end; ip++)
+ {
+ if (!MAPTST(&installedm, ip))
+ continue;
+ s = pool->solvables + ip;
+ if (!s->supplements)
+ continue;
+ if (!MAPTST(&im, ip))
+ continue;
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
+ break;
+ /* no longer supplemented, also erase */
+ if (sup)
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s supplemented\n", solvid2str(pool, ip));
+#endif
+ queue_push(&iq, ip);
+ }
+ }
+ }
+ }
+
+ /* turn userinstalled into remove set for pruning */
+ map_empty(&userinstalled);
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->p >= 0 || r->d != 0)
+ continue; /* disabled or not erase */
+ p = -r->p;
+ MAPCLR(&im, p);
+ if (pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ }
+ for (p = installed->start; p < installed->end; p++)
+ if (MAPTST(&im, p))
+ queue_push(&iq, p);
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->d < 0)
+ continue;
+ FOR_RULELITERALS(p, jp, r)
+ if (p > 0)
+ queue_push(&iq, p);
+ }
+ /* also put directly addressed packages on the install queue
+ * so we can mark patterns as installed */
+ for (i = 0; i < job->count; i += 2)
+ {
+ how = job->elements[i];
+ if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+ {
+ what = job->elements[i + 1];
+ select = how & SOLVER_SELECTMASK;
+ if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
+ queue_push(&iq, what);
+ }
+ }
+ while (iq.count)
+ {
+ ip = queue_shift(&iq);
+ s = pool->solvables + ip;
+#ifdef CLEANDEPSDEBUG
+ printf("bye %s\n", solvable2str(pool, s));
+#endif
+ if (s->requires)
+ {
+ reqp = s->repo->idarraydata + s->requires;
+ while ((req = *reqp++) != 0)
+ {
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (!MAPTST(&im, p) && MAPTST(&installedm, p))
+ {
+ if (p == ip)
+ continue;
+ if (MAPTST(&userinstalled, p - installed->start))
+ continue;
+#ifdef CLEANDEPSDEBUG
+ printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ MAPSET(&im, p);
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (s->recommends)
+ {
+ reqp = s->repo->idarraydata + s->recommends;
+ while ((req = *reqp++) != 0)
+ {
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (!MAPTST(&im, p) && MAPTST(&installedm, p))
+ {
+ if (p == ip)
+ continue;
+ if (MAPTST(&userinstalled, p - installed->start))
+ continue;
+#ifdef CLEANDEPSDEBUG
+ printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ MAPSET(&im, p);
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (!iq.count)
+ {
+ /* supplements pass */
+ for (ip = installed->start; ip < installed->end; ip++)
+ {
+ if (!MAPTST(&installedm, ip))
+ continue;
+ if (MAPTST(&userinstalled, ip - installed->start))
+ continue;
+ s = pool->solvables + ip;
+ if (!s->supplements)
+ continue;
+ if (MAPTST(&im, ip) || !MAPTST(&installedm, ip))
+ continue;
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (dep_possible(solv, sup, &im))
+ break;
+ if (sup)
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s supplemented\n", solvid2str(pool, ip));
+#endif
+ MAPSET(&im, ip);
+ queue_push(&iq, ip);
+ }
+ }
+ }
+ }
+
+ queue_free(&iq);
+ for (p = installed->start; p < installed->end; p++)
+ {
+ if (pool->solvables[p].repo != installed)
+ continue;
+ if (!MAPTST(&im, p))
+ MAPSET(&solv->cleandepsmap, p - installed->start);
+ }
+ map_free(&im);
+ map_free(&installedm);
+ map_free(&userinstalled);
+}
+
+
/* EOF */
SOLVER_RULE_RPM_SAME_NAME,
SOLVER_RULE_RPM_PACKAGE_OBSOLETES,
SOLVER_RULE_RPM_IMPLICIT_OBSOLETES,
+ SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES,
SOLVER_RULE_UPDATE = 0x200,
SOLVER_RULE_FEATURE = 0x300,
SOLVER_RULE_JOB = 0x400,
int solver_allruleinfos(struct _Solver *solv, Id rid, Queue *rq);
SolverRuleinfo solver_ruleinfo(struct _Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
+/* misc functions */
+void solver_addchoicerules(struct _Solver *solv);
+void solver_disablechoicerules(struct _Solver *solv, Rule *r);
#ifdef __cplusplus
}
solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
{
if (!s->repo)
- return 0;
+ return notfound;
return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
}
rq1 = rq2 = 0;
if (s1->requires)
for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
- rq1 ^= *reqp++;
+ rq1 ^= *reqp;
if (s2->requires)
for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
- rq2 ^= *reqp++;
+ rq2 ^= *reqp;
if (rq1 != rq2)
return 0;
}
if (lastweak)
{
Id v;
- extern void disablechoicerules(Solver *solv, Rule *r);
/* disable last weak rule */
solv->problems.count = oldproblemcount;
solv->learnt_pool.count = oldlearntpoolcount;
POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "disabling ");
solver_printruleclass(solv, SAT_DEBUG_UNSOLVABLE, solv->rules + lastweak);
if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
- disablechoicerules(solv, solv->rules + lastweak);
+ solver_disablechoicerules(solv, solv->rules + lastweak);
solver_disableproblem(solv, v);
if (v < 0)
solver_reenablepolicyrules(solv, -(v + 1));
map_free(&solv->dupmap);
map_free(&solv->dupinvolvedmap);
map_free(&solv->droporphanedmap);
+ map_free(&solv->cleandepsmap);
sat_free(solv->decisionmap);
sat_free(solv->rules);
if (l || !dq.count)
continue;
/* prune to installed if not updating */
- if (!solv->updatesystem && solv->installed && dq.count > 1)
+ if (dq.count > 1 && solv->installed && !solv->updatemap_all)
{
int j, k;
for (j = k = 0; j < dq.count; j++)
{
Solvable *s = pool->solvables + dq.elements[j];
if (s->repo == solv->installed)
- dq.elements[k++] = dq.elements[j];
+ {
+ dq.elements[k++] = dq.elements[j];
+ if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start))
+ {
+ k = 0; /* package wants to be updated, do not prune */
+ break;
+ }
+ }
}
if (k)
dq.count = k;
if (solv->decisionmap[i] > 0)
continue;
- /* XXX: noupdate check is probably no longer needed, as all jobs should
- * already be satisfied */
- if (MAPTST(&solv->noupdate, i - installed->start))
- continue;
if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
continue; /* updates first */
r = solv->rules + solv->updaterules + (i - installed->start);
if (!rr->p)
continue; /* orpaned package */
+ /* XXX: noupdate check is probably no longer needed, as all jobs should
+ * already be satisfied */
+ /* Actually we currently still need it because of erase jobs */
+ /* if noupdate is set we do not look at update candidates */
queue_empty(&dq);
- if (solv->decisionmap[i] < 0 || solv->updatesystem || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i)
+ if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i))
{
if (solv->noobsoletes.size && solv->multiversionupdaters
&& (d = solv->multiversionupdaters[i - installed->start]) != 0)
if (solv->decisionmap[i] == 0)
{
olevel = level;
- POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
- level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
+ if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
+ {
+ POOL_DEBUG(SAT_DEBUG_POLICY, "cleandeps erasing %s\n", solvid2str(pool, i));
+ level = setpropagatelearn(solv, level, -i, disablerules, 0);
+ }
+ else
+ {
+ POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
+ level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
+ }
if (level == 0)
{
queue_free(&dq);
}
}
- if (solv->distupgrade && solv->installed)
+ if (solv->dupmap_all && solv->installed)
{
int installedone = 0;
if (solv->decisionmap[p])
continue; /* already decided */
olevel = level;
- if (solv->distupgrade_removeunsupported)
+ if (solv->droporphanedmap_all)
continue;
if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
continue;
}
/*
+ * add a rule created by a job, record job number and weak flag
+ */
+static inline void
+solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
+{
+ solver_addrule(solv, p, d);
+ queue_push(&solv->ruletojob, job);
+ if (weak)
+ queue_push(&solv->weakruleq, solv->nrules - 1);
+}
+
+/*
*
* solve job queue
*
queue_free(&solv->job);
queue_init_clone(&solv->job, job);
+ /* initialize with legacy values */
+ solv->fixmap_all = solv->fixsystem;
+ solv->updatemap_all = solv->updatesystem;
+ solv->droporphanedmap_all = solv->distupgrade_removeunsupported;
+ solv->dupmap_all = solv->distupgrade;
+
/*
* create basic rule set of all involved packages
* use addedmap bitmap to make sure we don't create rules twice
*/
if (installed)
{
- /* check for verify jobs */
+ /* check for update/verify jobs as they need to be known early */
for (i = 0; i < job->count; i += 2)
{
how = job->elements[i];
switch (how & SOLVER_JOBMASK)
{
case SOLVER_VERIFY:
+ if (select == SOLVER_SOLVABLE_ALL)
+ solv->fixmap_all = 1;
FOR_JOB_SELECT(p, pp, select, what)
{
s = pool->solvables + p;
MAPSET(&solv->fixmap, p - solv->installed->start);
}
break;
+ case SOLVER_UPDATE:
+ if (select == SOLVER_SOLVABLE_ALL)
+ solv->updatemap_all = 1;
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ s = pool->solvables + p;
+ if (!solv->installed || s->repo != solv->installed)
+ continue;
+ if (!solv->updatemap.size)
+ map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
+ MAPSET(&solv->updatemap, p - solv->installed->start);
+ }
+ break;
default:
break;
}
}
break;
case SOLVER_DISTUPGRADE:
- if (!solv->distupgrade)
+ if (select == SOLVER_SOLVABLE_ALL)
+ {
+ solv->dupmap_all = 1;
+ solv->updatemap_all = 1;
+ }
+ if (!solv->dupmap_all)
hasdupjob = 1;
break;
default:
queue_push(&solv->orphaned, i);
if (!r->p)
{
- assert(solv->distupgrade && !sr->p);
+ assert(solv->dupmap_all && !sr->p);
continue;
}
if (!solver_samerule(solv, r, sr))
switch (how & SOLVER_JOBMASK)
{
case SOLVER_INSTALL:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
if (select == SOLVER_SOLVABLE)
{
p = what;
p = queue_shift(&q); /* get first candidate */
d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q); /* internalize */
}
- solver_addrule(solv, p, d); /* add install rule */
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
+ solver_addjobrule(solv, p, d, i, weak);
break;
case SOLVER_ERASE:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
+ if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && solv->installed)
+ map_grow(&solv->cleandepsmap, solv->installed->end - solv->installed->start);
if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
{
/* special case for "erase a specific solvable": we also
* erase all other solvables with that name, so that they
* don't get picked up as replacement */
+ /* XXX: look also at packages that obsolete this package? */
name = pool->solvables[what].name;
FOR_PROVIDES(p, pp, name)
{
/* keep installcandidates of other jobs */
if (MAPTST(&installcandidatemap, p))
continue;
- solver_addrule(solv, -p, 0); /* remove by Id */
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
+ solver_addjobrule(solv, -p, 0, i, weak); /* remove by id */
}
}
FOR_JOB_SELECT(p, pp, select, what)
- {
- solver_addrule(solv, -p, 0);
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
- }
+ solver_addjobrule(solv, -p, 0, i, weak);
break;
case SOLVER_UPDATE:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
- FOR_JOB_SELECT(p, pp, select, what)
- {
- s = pool->solvables + p;
- if (!solv->installed || s->repo != solv->installed)
- continue;
- if (!solv->updatemap.size)
- map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
- MAPSET(&solv->updatemap, p - solv->installed->start);
- }
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
break;
case SOLVER_VERIFY:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
break;
case SOLVER_WEAKENDEPS:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
if (select != SOLVER_SOLVABLE)
break;
s = pool->solvables + what;
weaken_solvable_deps(solv, what);
break;
case SOLVER_NOOBSOLETES:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
break;
case SOLVER_LOCK:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
FOR_JOB_SELECT(p, pp, select, what)
{
s = pool->solvables + p;
- if (installed && s->repo == installed)
- solver_addrule(solv, p, 0);
- else
- solver_addrule(solv, -p, 0);
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
+ solver_addjobrule(solv, installed && s->repo == installed ? p : -p, 0, i, weak);
}
break;
case SOLVER_DISTUPGRADE:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
break;
case SOLVER_DROP_ORPHANED:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
+ if (select == SOLVER_SOLVABLE_ALL)
+ solv->droporphanedmap_all = 1;
FOR_JOB_SELECT(p, pp, select, what)
{
s = pool->solvables + p;
MAPSET(&solv->droporphanedmap, p - installed->start);
}
break;
+ case SOLVER_USERINSTALLED:
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
+ break;
default:
POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
break;
solv->duprules = solv->duprules_end = solv->nrules;
if (1)
- {
- extern void addchoicerules(Solver *solv);
- addchoicerules(solv);
- }
+ solver_addchoicerules(solv);
else
solv->choicerules = solv->choicerules_end = solv->nrules;
map_free(&installedmap);
}
-
-#if 0
-#define FIND_INVOLVED_DEBUG 0
-void
-solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
-{
- Pool *pool = solv->pool;
- Map im;
- Map installedm;
- Solvable *s;
- Queue iq;
- Queue installedq_internal;
- Id tp, ip, p, pp, req, *reqp, sup, *supp;
- int i, count;
-
- tp = ts - pool->solvables;
- queue_init(&iq);
- queue_init(&installedq_internal);
- map_init(&im, pool->nsolvables);
- map_init(&installedm, pool->nsolvables);
-
- if (!installedq)
- {
- installedq = &installedq_internal;
- if (solv->installed)
- {
- for (ip = solv->installed->start; ip < solv->installed->end; ip++)
- {
- s = pool->solvables + ip;
- if (s->repo != solv->installed)
- continue;
- queue_push(installedq, ip);
- }
- }
- }
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- MAPSET(&installedm, ip);
- MAPSET(&im, ip);
- }
-
- queue_push(&iq, ts - pool->solvables);
- while (iq.count)
- {
- ip = queue_shift(&iq);
- if (!MAPTST(&im, ip))
- continue;
- if (!MAPTST(&installedm, ip))
- continue;
- MAPCLR(&im, ip);
- s = pool->solvables + ip;
-#if FIND_INVOLVED_DEBUG
- printf("hello %s\n", solvable2str(pool, s));
-#endif
- if (s->requires)
- {
- reqp = s->repo->idarraydata + s->requires;
- while ((req = *reqp++) != 0)
- {
- if (req == SOLVABLE_PREREQMARKER)
- continue;
- /* count number of installed packages that match */
- count = 0;
- FOR_PROVIDES(p, pp, req)
- if (MAPTST(&installedm, p))
- count++;
- if (count > 1)
- continue;
- FOR_PROVIDES(p, pp, req)
- {
- if (MAPTST(&im, p))
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- queue_push(&iq, p);
- }
- }
- }
- }
- if (s->recommends)
- {
- reqp = s->repo->idarraydata + s->recommends;
- while ((req = *reqp++) != 0)
- {
- count = 0;
- FOR_PROVIDES(p, pp, req)
- if (MAPTST(&installedm, p))
- count++;
- if (count > 1)
- continue;
- FOR_PROVIDES(p, pp, req)
- {
- if (MAPTST(&im, p))
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- queue_push(&iq, p);
- }
- }
- }
- }
- if (!iq.count)
- {
- /* supplements pass */
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- s = pool->solvables + ip;
- if (!s->supplements)
- continue;
- if (!MAPTST(&im, ip))
- continue;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
- break;
- /* no longer supplemented, also erase */
- if (sup)
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s supplemented\n", solvid2str(pool, ip));
-#endif
- queue_push(&iq, ip);
- }
- }
- }
- }
-
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- if (MAPTST(&im, ip))
- queue_push(&iq, ip);
- }
-
- while (iq.count)
- {
- ip = queue_shift(&iq);
- if (!MAPTST(&installedm, ip))
- continue;
- s = pool->solvables + ip;
-#if FIND_INVOLVED_DEBUG
- printf("bye %s\n", solvable2str(pool, s));
-#endif
- if (s->requires)
- {
- reqp = s->repo->idarraydata + s->requires;
- while ((req = *reqp++) != 0)
- {
- FOR_PROVIDES(p, pp, req)
- {
- if (!MAPTST(&im, p))
- {
- if (p == tp)
- continue;
-#if FIND_INVOLVED_DEBUG
- printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- MAPSET(&im, p);
- queue_push(&iq, p);
- }
- }
- }
- }
- if (s->recommends)
- {
- reqp = s->repo->idarraydata + s->recommends;
- while ((req = *reqp++) != 0)
- {
- FOR_PROVIDES(p, pp, req)
- {
- if (!MAPTST(&im, p))
- {
- if (p == tp)
- continue;
-#if FIND_INVOLVED_DEBUG
- printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- MAPSET(&im, p);
- queue_push(&iq, p);
- }
- }
- }
- }
- if (!iq.count)
- {
- /* supplements pass */
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- if (ip == tp)
- continue;
- s = pool->solvables + ip;
- if (!s->supplements)
- continue;
- if (MAPTST(&im, ip))
- continue;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &im))
- break;
- if (sup)
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s supplemented\n", solvid2str(pool, ip));
-#endif
- MAPSET(&im, ip);
- queue_push(&iq, ip);
- }
- }
- }
- }
-
- queue_free(&iq);
-
- /* convert map into result */
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- if (MAPTST(&im, ip))
- continue;
- if (ip == ts - pool->solvables)
- continue;
- queue_push(q, ip);
- }
- map_free(&im);
- map_free(&installedm);
- queue_free(&installedq_internal);
-}
-#endif
-
Map noupdate; /* don't try to update these
installed solvables */
- Map noobsoletes; /* ignore obsoletes for these
- (multiinstall) */
+ Map noobsoletes; /* ignore obsoletes for these (multiinstall) */
- Map updatemap; /* bring those installed packages to the newest version */
- Map fixmap; /* fix those packages */
+ Map updatemap; /* bring these installed packages to the newest version */
+ int updatemap_all; /* bring all packages to the newest version */
+
+ Map fixmap; /* fix these packages */
+ int fixmap_all; /* fix all packages */
Queue weakruleq; /* index into 'rules' for weak ones */
Map weakrulemap; /* map rule# to '1' for weak rules, 1..learntrules */
Queue covenantq; /* Covenants honored by this solver (generic locks) */
- Map dupmap; /* packages from dup repos */
+ Map dupmap; /* dup these packages*/
+ int dupmap_all; /* dup all packages */
Map dupinvolvedmap; /* packages involved in dup process */
+
Map droporphanedmap; /* packages to drop in dup mode */
+ int droporphanedmap_all;
+
+ Map cleandepsmap; /* try to drop these packages as of cleandeps erases */
Queue *ruleinfoq; /* tmp space for solver_ruleinfo() */
} Solver;
#define SOLVER_SOLVABLE_PROVIDES 0x03
#define SOLVER_SOLVABLE_ONE_OF 0x04
#define SOLVER_SOLVABLE_REPO 0x05
+#define SOLVER_SOLVABLE_ALL 0x06
#define SOLVER_SELECTMASK 0xff
#define SOLVER_DISTUPGRADE 0x0700
#define SOLVER_VERIFY 0x0800
#define SOLVER_DROP_ORPHANED 0x0900
+#define SOLVER_USERINSTALLED 0x0a00
#define SOLVER_JOBMASK 0xff00
#define SOLVER_WEAK 0x010000
#define SOLVER_ESSENTIAL 0x020000
+#define SOLVER_CLEANDEPS 0x040000
+
+#define SOLVER_SETEV 0x01000000
+#define SOLVER_SETEVR 0x02000000
+#define SOLVER_SETARCH 0x04000000
+#define SOLVER_SETVENDOR 0x08000000
+#define SOLVER_SETREPO 0x10000000
+#define SOLVER_NOAUTOSET 0x20000000
+
+#define SOLVER_SETMASK 0x2f000000
/* old API compatibility, do not use in new code */
#if 1
l = r->p; l; l = (dp != &r->w2 + 1 ? *dp++ : 0))
/* iterate over all packages selected by a job */
-#define FOR_JOB_SELECT(p, pp, select, what) \
- if (select == SOLVER_SOLVABLE_REPO) \
- p = pp = 0; \
- else for (pp = (select == SOLVER_SOLVABLE ? 0 : \
- select == SOLVER_SOLVABLE_ONE_OF ? what : \
- pool_whatprovides(pool, what)), \
+#define FOR_JOB_SELECT(p, pp, select, what) \
+ if (select == SOLVER_SOLVABLE_REPO || select == SOLVER_SOLVABLE_ALL) \
+ p = pp = 0; \
+ else for (pp = (select == SOLVER_SOLVABLE ? 0 : \
+ select == SOLVER_SOLVABLE_ONE_OF ? what : \
+ pool_whatprovides(pool, what)), \
p = (select == SOLVER_SOLVABLE ? what : pool->whatprovidesdata[pp++]) ; p ; p = pool->whatprovidesdata[pp++]) \
if (select != SOLVER_SOLVABLE_NAME || pool_match_nevr(pool, pool->solvables + p, what))
queue_free(&pkgs);
}
-void
-solver_printprobleminfo(Solver *solv, Id problem)
+static void
+solver_printproblemruleinfo(Solver *solv, Id probr)
{
Pool *pool = solv->pool;
- Id probr;
Id dep, source, target;
- probr = solver_findproblemrule(solv, problem);
switch (solver_ruleinfo(solv, probr, &source, &target, &dep))
{
case SOLVER_RULE_DISTUPGRADE:
case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
return;
+ case SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES:
+ POOL_DEBUG(SAT_DEBUG_RESULT, "installed package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
+ return;
case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES:
POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
return;
}
void
+solver_printprobleminfo(Solver *solv, Id problem)
+{
+ solver_printproblemruleinfo(solv, solver_findproblemrule(solv, problem));
+}
+
+void
+solver_printcompleteprobleminfo(Solver *solv, Id problem)
+{
+ Queue q;
+ Id probr;
+ int i, nobad = 0;
+
+ queue_init(&q);
+ solver_findallproblemrules(solv, problem, &q);
+ for (i = 0; i < q.count; i++)
+ {
+ probr = q.elements[i];
+ if (!(probr >= solv->updaterules && probr < solv->updaterules_end) && !(probr >= solv->jobrules && probr < solv->jobrules_end))
+ {
+ nobad = 1;
+ break;
+ }
+ }
+ for (i = 0; i < q.count; i++)
+ {
+ probr = q.elements[i];
+ if (nobad && ((probr >= solv->updaterules && probr < solv->updaterules_end) || (probr >= solv->jobrules && probr < solv->jobrules_end)))
+ continue;
+ solver_printproblemruleinfo(solv, probr);
+ }
+ queue_free(&q);
+}
+
+void
solver_printsolution(Solver *solv, Id problem, Id solution)
{
Pool *pool = solv->pool;
if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
POOL_DEBUG(SAT_DEBUG_RESULT, " - do not keep %s installed\n", solvid2str(pool, what));
else if (select == SOLVER_SOLVABLE_PROVIDES)
- POOL_DEBUG(SAT_DEBUG_RESULT, " - do not install a solvable %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - do not install a solvable %s\n", solver_select2str(pool, select, what));
else
- POOL_DEBUG(SAT_DEBUG_RESULT, " - do not install %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - do not install %s\n", solver_select2str(pool, select, what));
break;
case SOLVER_ERASE:
if (select == SOLVER_SOLVABLE && !(solv->installed && pool->solvables[what].repo == solv->installed))
POOL_DEBUG(SAT_DEBUG_RESULT, " - do not forbid installation of %s\n", solvid2str(pool, what));
else if (select == SOLVER_SOLVABLE_PROVIDES)
- POOL_DEBUG(SAT_DEBUG_RESULT, " - do not deinstall all solvables %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - do not deinstall all solvables %s\n", solver_select2str(pool, select, what));
else
- POOL_DEBUG(SAT_DEBUG_RESULT, " - do not deinstall %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - do not deinstall %s\n", solver_select2str(pool, select, what));
break;
case SOLVER_UPDATE:
- POOL_DEBUG(SAT_DEBUG_RESULT, " - do not install most recent version of %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - do not install most recent version of %s\n", solver_select2str(pool, select, what));
break;
case SOLVER_LOCK:
- POOL_DEBUG(SAT_DEBUG_RESULT, " - do not lock %s\n", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - do not lock %s\n", solver_select2str(pool, select, what));
break;
default:
POOL_DEBUG(SAT_DEBUG_RESULT, " - do something different\n");
/* policy, replace p with rp */
s = pool->solvables + p;
sd = rp ? pool->solvables + rp : 0;
- if (s == sd && solv->distupgrade)
+ if (sd)
{
- POOL_DEBUG(SAT_DEBUG_RESULT, " - keep obsolete %s\n", solvable2str(pool, s));
- }
- else if (sd)
- {
- int gotone = 0;
- if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr, EVRCMP_MATCH_RELEASE) > 0)
- {
- POOL_DEBUG(SAT_DEBUG_RESULT, " - allow downgrade of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
- gotone = 1;
- }
- if (!solv->allowarchchange && s->name == sd->name && s->arch != sd->arch && policy_illegal_archchange(solv, s, sd))
- {
- POOL_DEBUG(SAT_DEBUG_RESULT, " - allow architecture change of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
- gotone = 1;
- }
- if (!solv->allowvendorchange && s->name == sd->name && s->vendor != sd->vendor && policy_illegal_vendorchange(solv, s, sd))
+ int illegal = policy_is_illegal(solv, s, sd, 0);
+ if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0)
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - allow downgrade of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
+ if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0)
+ POOL_DEBUG(SAT_DEBUG_RESULT, " - allow architecture change of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
+ if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0)
{
if (sd->vendor)
POOL_DEBUG(SAT_DEBUG_RESULT, " - allow vendor change from '%s' (%s) to '%s' (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), id2str(pool, sd->vendor), solvable2str(pool, sd));
else
POOL_DEBUG(SAT_DEBUG_RESULT, " - allow vendor change from '%s' (%s) to no vendor (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), solvable2str(pool, sd));
- gotone = 1;
}
- if (!gotone)
+ if (!illegal)
POOL_DEBUG(SAT_DEBUG_RESULT, " - allow replacement of %s with %s\n", solvable2str(pool, s), solvable2str(pool, sd));
}
else
{
POOL_DEBUG(SAT_DEBUG_RESULT, " - allow deinstallation of %s\n", solvable2str(pool, s));
}
-
}
}
}
pcnt++;
POOL_DEBUG(SAT_DEBUG_RESULT, "Problem %d:\n", pcnt);
POOL_DEBUG(SAT_DEBUG_RESULT, "====================================\n");
+#if 1
solver_printprobleminfo(solv, problem);
+#else
+ solver_printcompleteprobleminfo(solv, problem);
+#endif
POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
solution = 0;
while ((solution = solver_next_solution(solv, problem, solution)) != 0)
}
const char *
-solver_select2str(Solver *solv, Id select, Id what)
+solver_select2str(Pool *pool, Id select, Id what)
{
- Pool *pool = solv->pool;
const char *s;
char *b;
if (select == SOLVER_SOLVABLE)
sprintf(b, "repo #%d", what);
return b;
}
+ if (select == SOLVER_SOLVABLE_ALL)
+ return "all packages";
return "unknown job select";
}
extern void solver_printdecisions(Solver *solv);
extern void solver_printtransaction(Solver *solv);
extern void solver_printprobleminfo(Solver *solv, Id problem);
+extern void solver_printcompleteprobleminfo(Solver *solv, Id problem);
extern void solver_printsolution(Solver *solv, Id problem, Id solution);
extern void solver_printallsolutions(Solver *solv);
extern void solver_printtrivial(Solver *solv);
-extern const char *solver_select2str(Solver *solv, Id select, Id what);
+
+extern const char *solver_select2str(Pool *pool, Id select, Id what);
#endif /* SATSOLVER_SOLVERDEBUG_H */
ADD_LIBRARY(toolstuff STATIC common_write.c)
+IF ( NOT DEBIAN )
ADD_EXECUTABLE(rpmdb2solv rpmdb2solv.c)
TARGET_LINK_LIBRARIES(rpmdb2solv toolstuff satsolverext satsolver ${RPMDB_LIBRARY} ${EXPAT_LIBRARY})
ADD_EXECUTABLE(rpms2solv rpms2solv.c)
TARGET_LINK_LIBRARIES(rpms2solv toolstuff satsolverext satsolver ${RPMDB_LIBRARY})
+ADD_EXECUTABLE(findfileconflicts findfileconflicts.c)
+TARGET_LINK_LIBRARIES(findfileconflicts satsolverext satsolver ${RPMDB_LIBRARY})
+
+ENDIF ( NOT DEBIAN )
+
ADD_EXECUTABLE(rpmmd2solv rpmmd2solv.c)
TARGET_LINK_LIBRARIES(rpmmd2solv toolstuff satsolverext satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
ADD_EXECUTABLE(mergesolv mergesolv.c )
TARGET_LINK_LIBRARIES(mergesolv toolstuff satsolverext satsolver)
-ADD_EXECUTABLE(findfileconflicts findfileconflicts.c)
-TARGET_LINK_LIBRARIES(findfileconflicts satsolverext satsolver ${RPMDB_LIBRARY})
-
install(TARGETS
mergesolv
dumpsolv
susetags2solv
helix2solv
rpmmd2solv
- rpmdb2solv
- rpms2solv
updateinfoxml2solv
deltainfoxml2solv
repomdxml2solv
DESTINATION ${BIN_INSTALL_DIR})
+IF ( NOT DEBIAN )
+install(TARGETS
+ rpmdb2solv
+ rpms2solv
+ DESTINATION ${BIN_INSTALL_DIR})
+ENDIF ( NOT DEBIAN )
+
install(PROGRAMS
repo2solv.sh
DESTINATION ${BIN_INSTALL_DIR})
#include "pool.h"
#include "poolarch.h"
#include "repo_solv.h"
+#ifndef DEBIAN
#include "repo_susetags.h"
#include "repo_rpmmd.h"
+#else
+#include "repo_deb.h"
+#endif
#include "solver.h"
static ssize_t
void
usage(char** argv)
{
- printf("Usage:\n%s: <arch> repo [--nocheck repo]...\n", argv[0]);
+ printf("Usage:\n%s: <arch> [options..] repo [--nocheck repo]...\n"
+ "\t--exclude <pattern>\twhitespace-separated list of (sub-)"
+ "packagenames to ignore\n"
+ "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n"
+ , argv[0]);
exit(1);
}
exit(1);
}
Repo *repo = repo_create(pool, argv[i]);
+#ifndef DEBIAN
if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
{
repo_add_susetags(repo, fp, 0, 0, 0);
{
repo_add_rpmmd(repo, fp, 0, 0);
}
+#else
+ if (l >= 8 && !strcmp(argv[i] + l - 8, "Packages"))
+ {
+ repo_add_debpackages(repo, fp, 0);
+ }
+ else if (l >= 11 && !strcmp(argv[i] + l - 11, "Packages.gz"))
+ {
+ repo_add_debpackages(repo, fp, 0);
+ }
+#endif
else if (repo_add_solv(repo, fp))
{
fprintf(stderr, "could not add repo %s\n", argv[i]);
rpmid = str2id(pool, "rpm", 0);
rpmarch = str2id(pool, arch, 0);
rpmrel = 0;
+#ifndef DEBIAN
if (rpmid && rpmarch)
{
for (p = 1; p < pool->nsolvables; p++)
if (p < pool->nsolvables)
rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
}
+#endif
queue_init(&job);
queue_init(&rids);
usage(char** argv)
{
- printf("%s: <arch> <patchnameprefix> [repos] [--updaterepos] [repos]...\n"
+ printf("%s: <arch> <patchnameprefix> [--install-available] [repos] [--updaterepos] [repos]...\n"
+ "\t --install-available: installation repository is available during update\n"
"\t repos: repository ending in\n"
"\t\tpackages, packages.gz, primary.xml.gz, updateinfo.xml.gz or .solv\n",
argv[0]);
exit(1);
}
+typedef struct {
+ int updatestart;
+ int shown;
+ int status;
+ int install_available;
+ Repo *repo;
+ Repo *instrepo;
+} context_t;
+
+#define SHOW_PATCH(c) if (!(c)->shown++) printf("%s:\n", solvable2str(pool, s));
+#define PERF_DEBUGGING 0
+
+static Pool *pool;
+
+void
+test_all_old_patches_included(context_t *c, Id pid)
+{
+ Id p, pp;
+ Id con, *conp;
+ Solvable *s = pool->solvables + pid;
+ /* Test 1: are all old patches included */
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ Solvable *s2 = pool->solvables + p;
+ Id con2, *conp2;
+
+ if (!s2->conflicts)
+ continue;
+ if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
+ continue;
+ conp2 = s2->repo->idarraydata + s2->conflicts;
+ while ((con2 = *conp2++) != 0)
+ {
+ Reldep *rd2, *rd;
+ if (!ISRELDEP(con2))
+ continue;
+ rd2 = GETRELDEP(pool, con2);
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ if (!ISRELDEP(con))
+ continue;
+ rd = GETRELDEP(pool, con);
+ if (rd->name == rd2->name)
+ break;
+ }
+ if (!con)
+ {
+ SHOW_PATCH(c);
+ printf(" %s contained %s\n", solvable2str(pool, s2), dep2str(pool, rd2->name));
+ }
+ else
+ {
+ if (evrcmp(pool, rd->evr, rd2->evr, EVRCMP_COMPARE) < 0)
+ {
+ SHOW_PATCH(c);
+ printf(" %s required newer version %s-%s of %s-%s\n",
+ solvable2str(pool, s2), dep2str(pool, rd2->name), dep2str(pool, rd2->evr),
+ dep2str(pool, rd->name), dep2str(pool, rd->evr));
+ }
+ }
+
+ }
+ }
+}
+
+void
+test_all_packages_installable(context_t *c, Id pid)
+{
+ Solver *solv;
+ Queue job;
+ Id p, pp;
+ Id con, *conp;
+ unsigned int now, solver_runs;
+ int i;
+ Solvable *s = pool->solvables + pid;
+
+ queue_init(&job);
+
+ now = sat_timems(0);
+ solver_runs = 0;
+
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ FOR_PROVIDES(p, pp, con)
+ {
+ queue_empty(&job);
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, p);
+
+ /* also set up some minimal system */
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+ queue_push(&job, str2id(pool, "rpm", 1));
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+ queue_push(&job, str2id(pool, "aaa_base", 1));
+
+ solv = solver_create(pool);
+ solv->dontinstallrecommended = 0;
+ ++solver_runs;
+ solver_solve(solv, &job);
+ if (solv->problems.count)
+ {
+ c->status = 1;
+ printf("error installing original package\n");
+ showproblems(solv, s, 0, 0);
+ }
+ toinst(solv, c->repo, c->instrepo);
+ solver_free(solv);
+
+#if 0
+ dump_instrepo(instrepo, pool);
+
+#endif
+ if (!c->install_available)
+ {
+ queue_empty(&job);
+ for (i = 1; i < c->updatestart; i++)
+ {
+ if (pool->solvables[i].repo != c->repo || i == pid)
+ continue;
+ queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+ queue_push(&job, i);
+ }
+ }
+ queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+ queue_push(&job, pid);
+ solv = solver_create(pool);
+ /*solv->dontinstallrecommended = 1;*/
+ ++solver_runs;
+ solver_solve(solv, &job);
+ if (solv->problems.count)
+ {
+ c->status = 1;
+ showproblems(solv, s, 0, 0);
+ }
+ frominst(solv, c->repo, c->instrepo);
+ solver_free(solv);
+ }
+ }
+
+ if (PERF_DEBUGGING)
+ printf(" test_all_packages_installable took %d ms in %d runs\n", sat_timems(now), solver_runs);
+}
+
+void
+test_can_upgrade_all_packages(context_t *c, Id pid)
+{
+ Solver *solv;
+ Id p;
+ Id con, *conp;
+ Queue job;
+ Queue cand;
+ Queue badguys;
+ int i, j;
+ unsigned int now, solver_runs;
+ Solvable *s = pool->solvables + pid;
+
+ queue_init(&job);
+ queue_init(&cand);
+ queue_init(&badguys);
+
+ now = sat_timems(0);
+ solver_runs = 0;
+
+ /* Test 3: can we upgrade all packages? */
+ for (p = 1; p < pool->nsolvables; p++)
+ {
+ Solvable *s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if (strchr(id2str(pool, s->name), ':'))
+ continue; /* only packages, please */
+ if (!pool_installable(pool, s))
+ continue;
+ queue_push(&cand, p);
+ }
+ while (cand.count)
+ {
+ solv = solver_create(pool);
+ queue_empty(&job);
+ for (i = 0; i < badguys.count; i++)
+ {
+ queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, badguys.elements[i]);
+ }
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+ queue_push(&job, con);
+ }
+ for (i = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, p);
+ }
+ ++solver_runs;
+ solver_solve(solv, &job);
+#if 0
+ solver_printdecisions(solv);
+#endif
+ /* put packages into installed repo and prune them from cand */
+ toinst(solv, c->repo, c->instrepo);
+ for (i = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ if (p > 0 && solv->decisionmap[p] > 0)
+ cand.elements[i] = -p; /* drop candidate */
+ }
+ solver_free(solv);
+
+ /* now the interesting part: test patch */
+ queue_empty(&job);
+ if (!c->install_available)
+ {
+ for (i = 1; i < c->updatestart; i++)
+ {
+ if (pool->solvables[i].repo != c->repo || i == pid)
+ continue;
+ queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+ queue_push(&job, i);
+ }
+ }
+ queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+ queue_push(&job, pid);
+ solv = solver_create(pool);
+ solv->dontinstallrecommended = 1;
+ ++solver_runs;
+ solver_solve(solv, &job);
+
+ if (solv->problems.count)
+ {
+ c->status = 1;
+ showproblems(solv, s, &cand, &badguys);
+ }
+ frominst(solv, c->repo, c->instrepo);
+ solver_free(solv);
+ /* now drop all negative elements from cand */
+ for (i = j = 0; i < cand.count; i++)
+ {
+ if (cand.elements[i] < 0)
+ continue;
+ cand.elements[j++] = cand.elements[i];
+ }
+ if (i == j)
+ break; /* no progress */
+ cand.count = j;
+ }
+ if (PERF_DEBUGGING)
+ printf(" test_can_upgrade_all_packages took %d ms in %d runs\n", sat_timems(now), solver_runs);
+}
+
+void
+test_no_ga_package_fulfills_dependency(context_t *c, Id pid)
+{
+ Id con, *conp;
+ Solvable *s = pool->solvables + pid;
+
+ /* Test 4: no GA package fulfills patch dependency */
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ Reldep *rd;
+ Id rp, rpp;
+
+ if (!ISRELDEP(con))
+ continue;
+ rd = GETRELDEP(pool, con);
+ FOR_PROVIDES(rp, rpp, rd->name)
+ {
+ Solvable *s2 = pool_id2solvable(pool, rp);
+ if (rp < c->updatestart
+ && evrcmp(pool, rd->evr, s2->evr, EVRCMP_COMPARE) < 0
+ && pool_match_nevr_rel(pool, s2, rd->name)
+ )
+ {
+ SHOW_PATCH(c);
+ printf(" conflict %s < %s satisfied by non-updated package %s\n",
+ dep2str(pool, rd->name), dep2str(pool, rd->evr), solvable2str(pool, s2));
+ break;
+ }
+ }
+ }
+}
+
int
main(int argc, char **argv)
{
- Pool *pool;
char *arch, *mypatch;
const char *pname;
int l;
FILE *fp;
- int i, j;
- Queue job;
- Queue cand;
- Queue badguys;
+ int i;
Id pid, p, pp;
- Id con, *conp;
- Solver *solv;
- Repo *repo, *instrepo;
- int status = 0;
int tests = 0;
- int updatestart = 0;
+ context_t c;
+
+ c.install_available = 0;
+ c.updatestart = 0;
+ c.status = 0;
if (argc <= 3)
usage(argv);
mypatch = argv[2];
- repo = repo_create(pool, 0);
- instrepo = repo_create(pool, 0);
+ c.repo = repo_create(pool, 0);
+ c.instrepo = repo_create(pool, 0);
for (i = 3; i < argc; i++)
{
if (!strcmp(argv[i], "--updaterepos"))
{
- updatestart = pool->nsolvables;
+ c.updatestart = pool->nsolvables;
continue;
}
+
+ if (!strcmp(argv[i], "--install-available"))
+ {
+ c.install_available = 1;
+ continue;
+ }
+
l = strlen(argv[i]);
if (!strcmp(argv[i], "-"))
fp = stdin;
}
if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
{
- repo_add_susetags(repo, fp, 0, 0, 0);
+ repo_add_susetags(c.repo, fp, 0, 0, 0);
}
else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
{
- repo_add_susetags(repo, fp, 0, 0, 0);
+ repo_add_susetags(c.repo, fp, 0, 0, 0);
}
else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
{
- repo_add_rpmmd(repo, fp, 0, 0);
+ repo_add_rpmmd(c.repo, fp, 0, 0);
}
else if (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz"))
{
- repo_add_updateinfoxml(repo, fp, 0);
+ repo_add_updateinfoxml(c.repo, fp, 0);
}
- else if (repo_add_solv(repo, fp))
+ else if (repo_add_solv(c.repo, fp))
{
fprintf(stderr, "could not add repo %s\n", argv[i]);
exit(1);
pool_addfileprovides(pool);
/* bad hack ahead: clone repo */
- instrepo->idarraydata = repo->idarraydata;
- instrepo->idarraysize = repo->idarraysize;
- instrepo->start = repo->start;
- instrepo->end = repo->end;
- instrepo->nsolvables = repo->nsolvables; /* sic! */
- instrepo->lastoff = repo->lastoff; /* sic! */
- pool_set_installed(pool, instrepo);
+ c.instrepo->idarraydata = c.repo->idarraydata;
+ c.instrepo->idarraysize = c.repo->idarraysize;
+ c.instrepo->start = c.repo->start;
+ c.instrepo->end = c.repo->end;
+ c.instrepo->nsolvables = c.repo->nsolvables; /* sic! */
+ c.instrepo->lastoff = c.repo->lastoff; /* sic! */
+ pool_set_installed(pool, c.instrepo);
pool_createwhatprovides(pool);
- queue_init(&job);
- queue_init(&cand);
- queue_init(&badguys);
-
for (pid = 1; pid < pool->nsolvables; pid++)
{
- int shown = 0;
-#define SHOW_PATCH() if (!shown++) printf("%s:\n", solvable2str(pool, s));
+ c.shown = 0;
Solvable *s = pool->solvables + pid;
if (!s->repo)
continue;
printf("testing patch %s-%s\n", pname + 6, id2str(pool, s->evr));
#endif
- if (1) {
-
- /* Test 1: are all old patches included */
- FOR_PROVIDES(p, pp, s->name)
- {
- Solvable *s2 = pool->solvables + p;
- Id con2, *conp2;
-
- if (!s2->conflicts)
- continue;
- if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
- continue;
- conp2 = s2->repo->idarraydata + s2->conflicts;
- while ((con2 = *conp2++) != 0)
- {
- Reldep *rd2, *rd;
- if (!ISRELDEP(con2))
- continue;
- rd2 = GETRELDEP(pool, con2);
- conp = s->repo->idarraydata + s->conflicts;
- while ((con = *conp++) != 0)
- {
- if (!ISRELDEP(con))
- continue;
- rd = GETRELDEP(pool, con);
- if (rd->name == rd2->name)
- break;
- }
- if (!con)
- {
- SHOW_PATCH();
- printf(" %s contained %s\n", solvable2str(pool, s2), dep2str(pool, rd2->name));
- }
- else
- {
- if (evrcmp(pool, rd->evr, rd2->evr, EVRCMP_COMPARE) < 0)
- {
- SHOW_PATCH();
- printf(" %s required newer version %s-%s of %s-%s\n",
- solvable2str(pool, s2), dep2str(pool, rd2->name), dep2str(pool, rd2->evr),
- dep2str(pool, rd->name), dep2str(pool, rd->evr));
- }
- }
-
- }
- }
- }
-
- if (1) {
- /* Test 2: are the packages installable */
- conp = s->repo->idarraydata + s->conflicts;
- while ((con = *conp++) != 0)
- {
- FOR_PROVIDES(p, pp, con)
- {
- queue_empty(&job);
- queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
- queue_push(&job, p);
-
- /* also set up some minimal system */
- queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
- queue_push(&job, str2id(pool, "rpm", 1));
- queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
- queue_push(&job, str2id(pool, "aaa_base", 1));
-
- solv = solver_create(pool);
- solv->dontinstallrecommended = 0;
- solver_solve(solv, &job);
- if (solv->problems.count)
- {
- status = 1;
- printf("error installing original package\n");
- showproblems(solv, s, 0, 0);
- }
- toinst(solv, repo, instrepo);
- solver_free(solv);
-
-#if 0
- dump_instrepo(instrepo, pool);
-
-#endif
-#if 1
- queue_empty(&job);
- for (i = 1; i < updatestart; i++)
- {
- if (pool->solvables[i].repo != repo || i == pid)
- continue;
- queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
- queue_push(&job, i);
- }
- queue_push(&job, SOLVER_INSTALL_SOLVABLE);
- queue_push(&job, pid);
- solv = solver_create(pool);
- /*solv->dontinstallrecommended = 1;*/
- solver_solve(solv, &job);
- if (solv->problems.count)
- {
- status = 1;
- showproblems(solv, s, 0, 0);
- }
- frominst(solv, repo, instrepo);
- solver_free(solv);
-#endif
- }
- }
- }
-
- if (1) {
-
- /* Test 3: can we upgrade all packages? */
- queue_empty(&cand);
- queue_empty(&badguys);
- for (p = 1; p < pool->nsolvables; p++)
- {
- Solvable *s = pool->solvables + p;
- if (!s->repo)
- continue;
- if (strchr(id2str(pool, s->name), ':'))
- continue; /* only packages, please */
- if (!pool_installable(pool, s))
- continue;
- queue_push(&cand, p);
- }
- while (cand.count)
- {
- solv = solver_create(pool);
- queue_empty(&job);
- for (i = 0; i < badguys.count; i++)
- {
- queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
- queue_push(&job, badguys.elements[i]);
- }
- conp = s->repo->idarraydata + s->conflicts;
- while ((con = *conp++) != 0)
- {
- queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
- queue_push(&job, con);
- }
- for (i = 0; i < cand.count; i++)
- {
- p = cand.elements[i];
- queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
- queue_push(&job, p);
- }
- solver_solve(solv, &job);
-#if 0
- solver_printdecisions(solv);
-#endif
- /* put packages into installed repo and prune them from cand */
- toinst(solv, repo, instrepo);
- for (i = 0; i < cand.count; i++)
- {
- p = cand.elements[i];
- if (p > 0 && solv->decisionmap[p] > 0)
- cand.elements[i] = -p; /* drop candidate */
- }
- solver_free(solv);
-
- /* now the interesting part: test patch */
- queue_empty(&job);
-#if 0
- for (i = 1; i < updatestart; i++)
- {
- if (pool->solvables[i].repo != repo || i == pid)
- continue;
- queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
- queue_push(&job, i);
- }
-#endif
- queue_push(&job, SOLVER_INSTALL_SOLVABLE);
- queue_push(&job, pid);
- solv = solver_create(pool);
- solv->dontinstallrecommended = 1;
- solver_solve(solv, &job);
-
- if (solv->problems.count)
- {
- status = 1;
- showproblems(solv, s, &cand, &badguys);
- }
- frominst(solv, repo, instrepo);
- solver_free(solv);
- /* now drop all negative elements from cand */
- for (i = j = 0; i < cand.count; i++)
- {
- if (cand.elements[i] < 0)
- continue;
- cand.elements[j++] = cand.elements[i];
- }
- if (i == j)
- break; /* no progress */
- cand.count = j;
- }
- }
-
- if (1)
- {
- /* Test 4: no GA package fulfills patch dependency */
- conp = s->repo->idarraydata + s->conflicts;
- while ((con = *conp++) != 0)
- {
- Reldep *rd;
- Id rp, rpp;
-
- if (!ISRELDEP(con))
- continue;
- rd = GETRELDEP(pool, con);
- FOR_PROVIDES(rp, rpp, rd->name)
- {
- Solvable *s2 = pool_id2solvable(pool, rp);
- if (rp < updatestart
- && evrcmp(pool, rd->evr, s2->evr, EVRCMP_COMPARE) < 0
- && pool_match_nevr_rel(pool, s2, rd->name)
- )
- {
- SHOW_PATCH();
- printf(" conflict %s < %s satisfied by non-updated package %s\n",
- dep2str(pool, rd->name), dep2str(pool, rd->evr), solvable2str(pool, s2));
- break;
- }
- }
- }
- }
+ test_all_old_patches_included(&c, pid);
+ test_all_packages_installable(&c, pid);
+ test_can_upgrade_all_packages(&c, pid);
+ test_no_ga_package_fulfills_dependency(&c, pid);
}
- exit(status);
+ exit(c.status);
}
case $1 in
*.gz) gzip -dc "$1" ;;
*.bz2) bzip2 -dc "$1" ;;
+ *.lzma) lzma -dc "$1" ;;
+ *.xz) xz -dc "$1" ;;
*) cat "$1" ;;
esac
}
+susetags_findfile_cat() {
+ if test -s "$1.xz" ; then
+ xz -dc "$1.xz"
+ elif test -s "$1.lzma" ; then
+ lzma -dc "$1.lzma"
+ elif test -s "$1.bz2" ; then
+ bzip2 -dc "$1.bz2"
+ elif test -s "$1.gz" ; then
+ gzip -dc "$1.gz"
+ elif test -s "$1" ; then
+ cat "$1"
+ fi
+}
+
# signal an error if there is a problem
set -e
cd ${DESCR} || exit 2
(
# First packages
- if test -s packages.gz; then
- gzip -dc packages.gz
- elif test -s packages.bz2; then
- bzip2 -dc packages.bz2
- elif test -s packages; then
- cat packages
- fi
+ susetags_findfile_cat packages
# DU
- if test -s packages.DU.gz; then
- gzip -dc packages.DU.gz
- elif test -s packages.DU.bz2; then
- bzip2 -dc packages.DU.bz2
- elif test -s packages.DU; then
- cat packages.DU
- fi
+ susetags_findfile_cat packages.DU
# Now default language
- if test -s packages.en.gz; then
- gzip -dc packages.en.gz
- elif test -s packages.en.bz2; then
- bzip2 -dc packages.en.bz2
- elif test -s packages.en; then
- cat packages.en
- fi
+ susetags_findfile_cat packages.en
# Now patterns. Not simply those files matching *.pat{,.gz,bz2},
# but only those mentioned in the file 'patterns'
- if test -f patterns; then
+ if test -f patterns ; then
for i in `cat patterns`; do
- test -s "$i" || continue
- case $i in
- *.gz) gzip -dc "$i" ;;
- *.bz2) bzip2 -dc "$i" ;;
- *) cat "$i" ;;
- esac
+ if test -s "$i" ; then
+ repomd_decompress "$i"
+ fi
done
fi
# Now all other packages.{lang}. Needs to come last as it switches
# languages for all following susetags files
- for i in packages.*; do
+ for i in packages.* ; do
case $i in
- *.gz) name="${i%.gz}" ; prog="gzip -dc" ;;
- *.bz2) name="${i%.bz2}" ; prog="bzip2 -dc" ;;
- *) name="$i"; prog=cat ;;
+ *.gz|*.bz2|*.xz|*.lzma) name="${i%.*}" ;;
+ *) name="$i" ;;
esac
case $name in
# ignore files we handled already
*)
suff=${name#packages.}
echo "=Lan: $suff"
- $prog "$i" ;;
+ repomd_decompress "$i"
esac
done
if (contentfile)
{
- FILE *fp = fopen (contentfile, "r");
+ FILE *fp = fopen(contentfile, "r");
if (!fp)
{
perror(contentfile);
}
repo_add_content(repo, fp, REPO_REUSE_REPODATA);
defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
+ fclose(fp);
}
if (attrname)