X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tools%2Frepo_rpmmd.c;h=44ab8eee32c979345eb61a89346682fae714d42f;hb=d4a38c4b2394d728afd0344f5b03b173123278ef;hp=fc90a04839931004deb377b744919f2b7dd3a107;hpb=e29179ffd572cfed83aefcf47a3815db6e259e90;p=platform%2Fupstream%2Flibsolv.git diff --git a/tools/repo_rpmmd.c b/tools/repo_rpmmd.c index fc90a04..44ab8ee 100644 --- a/tools/repo_rpmmd.c +++ b/tools/repo_rpmmd.c @@ -15,17 +15,16 @@ #include "pool.h" #include "repo.h" +#define DISABLE_SPLIT #include "tools_util.h" #include "repo_rpmmd.h" enum state { STATE_START, - STATE_METADATA, + STATE_SOLVABLE, - STATE_PRODUCT, - STATE_PATTERN, - STATE_PATCH, + STATE_NAME, STATE_ARCH, STATE_VERSION, @@ -39,6 +38,9 @@ enum state { /* resobject attributes */ STATE_SUMMARY, STATE_DESCRIPTION, + STATE_DISTRIBUTION, + STATE_PACKAGER, + STATE_URL, STATE_INSNOTIFY, STATE_DELNOTIFY, STATE_VENDOR, @@ -47,14 +49,21 @@ enum state { STATE_DOWNLOADSIZE, STATE_INSTALLTIME, STATE_INSTALLONLY, - + + /* Novell/SUSE extended attributes */ + STATE_EULA, + STATE_KEYWORD, + STATE_DISKUSAGE, + STATE_DIRS, + STATE_DIR, + /* patch */ STATE_ID, STATE_TIMESTAMP, STATE_AFFECTSPKG, STATE_REBOOTNEEDED, - // xml store pattern attributes + // pattern attributes STATE_CATEGORY, /* pattern and patches */ STATE_SCRIPT, STATE_ICON, @@ -64,13 +73,15 @@ enum state { /* product */ STATE_SHORTNAME, - STATE_DISTNAME, - STATE_DISTEDITION, + STATE_DISTNAME, // obsolete + STATE_DISTEDITION, // obsolete STATE_SOURCE, + STATE_TYPE, STATE_RELNOTESURL, + STATE_UPDATEURL, + STATE_OPTIONALURL, + STATE_FLAG, - STATE_FORMAT, - /* rpm-md dependencies inside the format tag */ STATE_PROVIDES, @@ -82,18 +93,8 @@ enum state { STATE_SUGGESTS, STATE_ENHANCES, STATE_FRESHENS, - - STATE_CAPS_FORMAT, - STATE_CAPS_VENDOR, - STATE_CAPS_PROVIDES, - STATE_CAPS_REQUIRES, - STATE_CAPS_OBSOLETES, - STATE_CAPS_CONFLICTS, - STATE_CAPS_RECOMMENDS, - STATE_CAPS_SUPPLEMENTS, - STATE_CAPS_SUGGESTS, - STATE_CAPS_ENHANCES, - STATE_CAPS_FRESHENS, + STATE_SOURCERPM, + STATE_HEADERRANGE, STATE_PROVIDESENTRY, STATE_REQUIRESENTRY, @@ -105,16 +106,6 @@ enum state { STATE_ENHANCESENTRY, STATE_FRESHENSENTRY, - STATE_CAP_FRESHENS, - STATE_CAP_PROVIDES, - STATE_CAP_REQUIRES, - STATE_CAP_OBSOLETES, - STATE_CAP_CONFLICTS, - STATE_CAP_SUGGESTS, - STATE_CAP_RECOMMENDS, - STATE_CAP_SUPPLEMENTS, - STATE_CAP_ENHANCES, - STATE_FILE, // general @@ -129,14 +120,20 @@ struct stateswitch { }; static struct stateswitch stateswitches[] = { + /** fake tag used to enclose 2 different xml files in one **/ + { STATE_START, "rpmmd", STATE_START, 0 }, + + /** tags for different package data, we just ignore the tag **/ + { STATE_START, "metadata", STATE_START, 0 }, + { STATE_START, "otherdata", STATE_START, 0 }, + { STATE_START, "diskusagedata", STATE_START, 0 }, + { STATE_START, "susedata", STATE_START, 0 }, { STATE_START, "product", STATE_SOLVABLE, 0 }, { STATE_START, "pattern", STATE_SOLVABLE, 0 }, { STATE_START, "patch", STATE_SOLVABLE, 0 }, + { STATE_START, "package", STATE_SOLVABLE, 0 }, - { STATE_START, "metadata", STATE_METADATA, 0 }, - { STATE_METADATA, "package", STATE_SOLVABLE, 0 }, - { STATE_SOLVABLE, "name", STATE_NAME, 1 }, { STATE_SOLVABLE, "arch", STATE_ARCH, 1 }, { STATE_SOLVABLE, "version", STATE_VERSION, 0 }, @@ -144,66 +141,65 @@ static struct stateswitch stateswitches[] = { // package attributes rpm-md { STATE_SOLVABLE, "location", STATE_LOCATION, 0 }, { STATE_SOLVABLE, "checksum", STATE_CHECKSUM, 1 }, - + /* resobject attributes */ - { STATE_SOLVABLE, "summary", STATE_SUMMARY, 1 }, - { STATE_SOLVABLE, "description", STATE_DESCRIPTION, 1 }, + { STATE_SOLVABLE, "summary", STATE_SUMMARY, 1 }, + { STATE_SOLVABLE, "description", STATE_DESCRIPTION, 1 }, + { STATE_SOLVABLE, "distribution", STATE_DISTRIBUTION, 1 }, + { STATE_SOLVABLE, "url", STATE_URL, 1 }, + { STATE_SOLVABLE, "packager", STATE_PACKAGER, 1 }, //{ STATE_SOLVABLE, "???", STATE_INSNOTIFY, 1 }, //{ STATE_SOLVABLE, "??", STATE_DELNOTIFY, 1 }, - { STATE_SOLVABLE, "vendor", STATE_VENDOR, 1 }, - { STATE_SOLVABLE, "size", STATE_SIZE, 0 }, + { STATE_SOLVABLE, "vendor", STATE_VENDOR, 1 }, + { STATE_SOLVABLE, "size", STATE_SIZE, 0 }, { STATE_SOLVABLE, "archive-size", STATE_DOWNLOADSIZE, 1 }, - { STATE_SOLVABLE, "install-time", STATE_INSTALLTIME, 1 }, - { STATE_SOLVABLE, "install-only", STATE_INSTALLONLY, 1 }, - { STATE_SOLVABLE, "time", STATE_TIME, 0 }, - - // xml store pattern attributes - { STATE_SOLVABLE, "script", STATE_SCRIPT, 1 }, - { STATE_SOLVABLE, "icon", STATE_ICON, 1 }, - { STATE_SOLVABLE, "uservisible", STATE_USERVISIBLE, 1 }, - { STATE_SOLVABLE, "category", STATE_CATEGORY, 1 }, - { STATE_SOLVABLE, "default", STATE_DEFAULT, 1 }, - { STATE_SOLVABLE, "install-time", STATE_INSTALL_TIME, 1 }, - - { STATE_SOLVABLE, "format", STATE_FORMAT, 0 }, - - /* those are used in libzypp xml store */ - { STATE_SOLVABLE, "obsoletes", STATE_CAPS_OBSOLETES , 0 }, - { STATE_SOLVABLE, "conflicts", STATE_CAPS_CONFLICTS , 0 }, - { STATE_SOLVABLE, "recommends", STATE_CAPS_RECOMMENDS , 0 }, - { STATE_SOLVABLE, "supplements", STATE_CAPS_SUPPLEMENTS, 0 }, - { STATE_SOLVABLE, "suggests", STATE_CAPS_SUGGESTS, 0 }, - { STATE_SOLVABLE, "enhances", STATE_CAPS_ENHANCES, 0 }, - { STATE_SOLVABLE, "freshens", STATE_CAPS_FRESHENS, 0 }, - { STATE_SOLVABLE, "provides", STATE_CAPS_PROVIDES, 0 }, - { STATE_SOLVABLE, "requires", STATE_CAPS_REQUIRES, 0 }, - - { STATE_CAPS_PROVIDES, "capability", STATE_CAP_PROVIDES, 1 }, - { STATE_CAPS_REQUIRES, "capability", STATE_CAP_REQUIRES, 1 }, - { STATE_CAPS_OBSOLETES, "capability", STATE_CAP_OBSOLETES, 1 }, - { STATE_CAPS_CONFLICTS, "capability", STATE_CAP_CONFLICTS, 1 }, - { STATE_CAPS_RECOMMENDS, "capability", STATE_CAP_RECOMMENDS, 1 }, - { STATE_CAPS_SUPPLEMENTS, "capability", STATE_CAP_SUPPLEMENTS, 1 }, - { STATE_CAPS_SUGGESTS, "capability", STATE_CAP_SUGGESTS, 1 }, - { STATE_CAPS_ENHANCES, "capability", STATE_CAP_ENHANCES, 1 }, - { STATE_CAPS_FRESHENS, "capability", STATE_CAP_FRESHENS, 1 }, - - { STATE_FORMAT, "rpm:vendor", STATE_VENDOR, 1 }, - { STATE_FORMAT, "rpm:group", STATE_RPM_GROUP, 1 }, - { STATE_FORMAT, "rpm:license", STATE_RPM_LICENSE, 1 }, - - /* rpm-md dependencies */ - { STATE_FORMAT, "rpm:provides", STATE_PROVIDES, 0 }, - { STATE_FORMAT, "rpm:requires", STATE_REQUIRES, 0 }, - { STATE_FORMAT, "rpm:obsoletes", STATE_OBSOLETES , 0 }, - { STATE_FORMAT, "rpm:conflicts", STATE_CONFLICTS , 0 }, - { STATE_FORMAT, "rpm:recommends", STATE_RECOMMENDS , 0 }, - { STATE_FORMAT, "rpm:supplements", STATE_SUPPLEMENTS, 0 }, - { STATE_FORMAT, "rpm:suggests", STATE_SUGGESTS, 0 }, - { STATE_FORMAT, "rpm:enhances", STATE_ENHANCES, 0 }, - { STATE_FORMAT, "rpm:freshens", STATE_FRESHENS, 0 }, - { STATE_FORMAT, "file", STATE_FILE, 1 }, + { STATE_SOLVABLE, "install-time", STATE_INSTALLTIME, 1 }, + { STATE_SOLVABLE, "install-only", STATE_INSTALLONLY, 1 }, + { STATE_SOLVABLE, "time", STATE_TIME, 0 }, + + /* extended Novell/SUSE attributes (susedata.xml) */ + { STATE_SOLVABLE, "eula", STATE_EULA, 1 }, + { STATE_SOLVABLE, "keyword", STATE_KEYWORD, 1 }, + { STATE_SOLVABLE, "diskusage", STATE_DISKUSAGE, 0 }, + + // pattern attribute + { STATE_SOLVABLE, "script", STATE_SCRIPT, 1 }, + { STATE_SOLVABLE, "icon", STATE_ICON, 1 }, + { STATE_SOLVABLE, "uservisible", STATE_USERVISIBLE, 1 }, + { STATE_SOLVABLE, "category", STATE_CATEGORY, 1 }, + { STATE_SOLVABLE, "default", STATE_DEFAULT, 1 }, + { STATE_SOLVABLE, "install-time", STATE_INSTALL_TIME, 1 }, + + /* product attributes */ + /* note the product type is an attribute */ + { STATE_SOLVABLE, "release-notes-url", STATE_RELNOTESURL, 1 }, + { STATE_SOLVABLE, "update-url", STATE_UPDATEURL, 1 }, + { STATE_SOLVABLE, "optional-url", STATE_OPTIONALURL, 1 }, + { STATE_SOLVABLE, "flag", STATE_FLAG, 1 }, + + { STATE_SOLVABLE, "rpm:vendor", STATE_VENDOR, 1 }, + { STATE_SOLVABLE, "rpm:group", STATE_RPM_GROUP, 1 }, + { STATE_SOLVABLE, "rpm:license", STATE_RPM_LICENSE, 1 }, + + /* rpm-md dependencies */ + { STATE_SOLVABLE, "rpm:provides", STATE_PROVIDES, 0 }, + { STATE_SOLVABLE, "rpm:requires", STATE_REQUIRES, 0 }, + { STATE_SOLVABLE, "rpm:obsoletes", STATE_OBSOLETES, 0 }, + { STATE_SOLVABLE, "rpm:conflicts", STATE_CONFLICTS, 0 }, + { STATE_SOLVABLE, "rpm:recommends", STATE_RECOMMENDS , 0 }, + { STATE_SOLVABLE, "rpm:supplements", STATE_SUPPLEMENTS, 0 }, + { STATE_SOLVABLE, "rpm:suggests", STATE_SUGGESTS, 0 }, + { STATE_SOLVABLE, "rpm:enhances", STATE_ENHANCES, 0 }, + { STATE_SOLVABLE, "rpm:freshens", STATE_FRESHENS, 0 }, + { STATE_SOLVABLE, "rpm:sourcerpm", STATE_SOURCERPM, 1 }, + { STATE_SOLVABLE, "rpm:header-range", STATE_HEADERRANGE, 0 }, + { STATE_SOLVABLE, "file", STATE_FILE, 1 }, + + /* extended Novell/SUSE diskusage attributes (susedata.xml) */ + { STATE_DISKUSAGE, "dirs", STATE_DIRS, 0 }, + { STATE_DIRS, "dir", STATE_DIR, 0 }, + { STATE_PROVIDES, "rpm:entry", STATE_PROVIDESENTRY, 0 }, { STATE_REQUIRES, "rpm:entry", STATE_REQUIRESENTRY, 0 }, { STATE_OBSOLETES, "rpm:entry", STATE_OBSOLETESENTRY, 0 }, @@ -213,9 +209,15 @@ static struct stateswitch stateswitches[] = { { STATE_SUGGESTS, "rpm:entry", STATE_SUGGESTSENTRY, 0 }, { STATE_ENHANCES, "rpm:entry", STATE_ENHANCESENTRY, 0 }, { STATE_FRESHENS, "rpm:entry", STATE_FRESHENSENTRY, 0 }, + { NUMSTATES} }; +/* maxmum initial size of + the checksum cache */ +#define MAX_CSCACHE 32768 +#define CSREALLOC_STEP 1024 + struct parsedata { struct parsedata_common common; char *kind; @@ -227,69 +229,119 @@ struct parsedata { int acontent; int docontent; Solvable *solvable; + Offset freshens; struct stateswitch *swtab[NUMSTATES]; enum state sbtab[NUMSTATES]; - const char *lang; + /* temporal to store attribute tag language */ + const char *tmplang; const char *capkind; // used to store tmp attributes // while the tag ends const char *tmpattr; Repodata *data; -}; + Id handle; + XML_Parser *parser; + Id (*dirs)[3]; // dirid, size, nfiles + int ndirs; + Id langcache[ID_NUM_INTERNAL]; + /** system language */ + const char *language; -static char *flagtabnum[] = { - ">", - "=", - ">=", - "<", - "!=", - "<=", + /** Hash to maps checksums to solv */ + Stringpool cspool; + /** Cache of known checksums to solvable id */ + Id *cscache; + /* the current longest index in the table */ + int ncscache; }; -/** - * adds plain dependencies, that is strings like "foo > 2.0" - * which are used in libzypp xml store, not in rpm-md. - */ -static unsigned int -adddepplain(Pool *pool, struct parsedata_common *pd, unsigned int olddeps, char *line, Id marker, const char *kind) +static Id +langtag(struct parsedata *pd, Id tag, const char *language) { - int i, flags; - Id id, evrid; - char *sp[4]; + if (language && !language[0]) + language = 0; + if (!language || tag >= ID_NUM_INTERNAL) + return pool_id2langid(pd->common.repo->pool, tag, language, 1); + return pool_id2langid(pd->common.repo->pool, tag, language, 1); + if (!pd->langcache[tag]) + pd->langcache[tag] = pool_id2langid(pd->common.repo->pool, tag, language, 1); + return pd->langcache[tag]; +} + +static int +id3_cmp (const void *v1, const void *v2) +{ + Id *i1 = (Id*)v1; + Id *i2 = (Id*)v2; + return i1[0] - i2[0]; +} - i = split(line, sp, 4); - if (i != 1 && i != 3) +static void +commit_diskusage (struct parsedata *pd, unsigned handle) +{ + unsigned i; + Dirpool *dp = &pd->data->dirpool; + /* Now sort in dirid order. This ensures that parents come before + their children. */ + if (pd->ndirs > 1) + qsort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp); + /* Substract leaf numbers from all parents to make the numbers + non-cumulative. This must be done post-order (i.e. all leafs + adjusted before parents). We ensure this by starting at the end of + the array moving to the start, hence seeing leafs before parents. */ + for (i = pd->ndirs; i--;) { - fprintf(stderr, "Bad dependency line: %s\n", line); - exit(1); + unsigned p = dirpool_parent(dp, pd->dirs[i][0]); + unsigned j = i; + for (; p; p = dirpool_parent(dp, p)) + { + for (; j--;) + if (pd->dirs[j][0] == p) + break; + if (j < pd->ndirs) + { + if (pd->dirs[j][1] < pd->dirs[i][1]) + pd->dirs[j][1] = 0; + else + pd->dirs[j][1] -= pd->dirs[i][1]; + if (pd->dirs[j][2] < pd->dirs[i][2]) + pd->dirs[j][2] = 0; + else + pd->dirs[j][2] -= pd->dirs[i][2]; + } + else + /* Haven't found this parent in the list, look further if + we maybe find the parents parent. */ + j = i; + } } - if (kind) - id = str2id(pool, join2(kind, ":", sp[0]), 1); - else - id = str2id(pool, sp[0], 1); - if (i == 3) +#if 0 + char sbuf[1024]; + char *buf = sbuf; + unsigned slen = sizeof (sbuf); + for (i = 0; i < pd->ndirs; i++) { - evrid = makeevr(pool, sp[2]); - for (flags = 0; flags < 6; flags++) - if (!strcmp(sp[1], flagtabnum[flags])) - break; - if (flags == 6) - { - if ( !strcmp(sp[1], "==")) - { - flags = 1; - } - else - { - fprintf(stderr, "Unknown relation '%s'\n", sp[1]); - exit(1); - } - } - id = rel2id(pool, id, evrid, flags + 1, 1); + dir2str (attr, pd->dirs[i][0], &buf, &slen); + fprintf (stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf); } - return repo_addid_dep(pd->repo, olddeps, id, marker); + if (buf != sbuf) + free (buf); +#endif + for (i = 0; i < pd->ndirs; i++) + if (pd->dirs[i][1] || pd->dirs[i][2]) + { + repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]); + } + pd->ndirs = 0; } + +/* + * makeevr_atts + * parse 'epoch', 'ver' and 'rel', return evr Id + * + */ + static Id makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) { @@ -355,7 +407,17 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) return str2id(pool, pd->content, 1); } -static const char * + +/* + * find_attr + * find value for xml attribute + * I: txt, name of attribute + * I: atts, list of key/value attributes + * O: pointer to value of matching key, or NULL + * + */ + +static inline const char * find_attr(const char *txt, const char **atts) { for (; *atts; atts += 2) @@ -366,6 +428,11 @@ find_attr(const char *txt, const char **atts) return 0; } + +/* + * dependency relations + */ + static char *flagtab[] = { "GT", "EQ", @@ -375,6 +442,13 @@ static char *flagtab[] = { "LE" }; + +/* + * adddep + * parse attributes to reldep Id + * + */ + static unsigned int adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, int isreq) { @@ -407,8 +481,8 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts pd->content = sat_realloc(pd->content, l + 256); pd->acontent = l + 256; } - sprintf(pd->content, "%s:%s", k, n); - name = str2id(pool, pd->content, 1); + sprintf(pd->content, "%s:%s", k, n); + name = str2id(pool, pd->content, 1); } else name = str2id(pool, (char *)n, 1); @@ -430,35 +504,41 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts return repo_addid_dep(pd->common.repo, olddeps, id, marker); } + +/* + * set_desciption_author + * + */ + static void -set_desciption_author(Repodata *data, Id entry, char *str) +set_desciption_author(Repodata *data, Id handle, char *str) { char *aut, *p; if (!str || !*str) return; for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++) - if (!strncmp(aut, "\nAuthors:\n--------\n", 19)) + if (!strncmp(aut, "\nAuthors:\n--------\n", 19)) break; if (aut) { /* oh my, found SUSE special author section */ - int l = aut - str; - str[l] = 0; + int l = aut - str; + str[l] = 0; while (l > 0 && str[l - 1] == '\n') - str[--l] = 0; + str[--l] = 0; if (l) - repodata_set_str(data, entry, id_description, str); + repodata_set_str(data, handle, SOLVABLE_DESCRIPTION, str); p = aut + 19; aut = str; /* copy over */ while (*p == ' ' || *p == '\n') p++; - while (*p) + while (*p) { if (*p == '\n') { *aut++ = *p++; - while (*p == ' ') + while (*p == ' ') p++; continue; } @@ -466,14 +546,74 @@ set_desciption_author(Repodata *data, Id entry, char *str) } while (aut != str && aut[-1] == '\n') aut--; - *aut = 0; + *aut = 0; if (*str) - repodata_set_str(data, entry, id_authors, str); + repodata_set_str(data, handle, SOLVABLE_AUTHORS, str); } else if (*str) - repodata_set_str(data, entry, id_description, str); + repodata_set_str(data, handle, SOLVABLE_DESCRIPTION, str); } + +/* + * set_sourcerpm + * + */ + +static void +set_sourcerpm(Repodata *data, Solvable *s, Id handle, char *sourcerpm) +{ + const char *p, *sevr, *sarch, *name, *evr; + Pool *pool; + + p = strrchr(sourcerpm, '.'); + if (!p || strcmp(p, ".rpm") != 0) + return; + p--; + while (p > sourcerpm && *p != '.') + p--; + if (*p != '.' || p == sourcerpm) + return; + sarch = p-- + 1; + while (p > sourcerpm && *p != '-') + p--; + if (*p != '-' || p == sourcerpm) + return; + p--; + while (p > sourcerpm && *p != '-') + p--; + if (*p != '-' || p == sourcerpm) + return; + sevr = p + 1; + pool = s->repo->pool; + name = id2str(pool, s->name); + evr = id2str(pool, s->evr); + if (!strcmp(sarch, "src.rpm")) + repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_SRC); + else if (!strcmp(sarch, "nosrc.rpm")) + repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_NOSRC); + else + repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, strn2id(pool, sarch, strlen(sarch) - 4, 1)); + if (!strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0) + repodata_set_void(data, handle, SOLVABLE_SOURCEEVR); + else + repodata_set_id(data, handle, SOLVABLE_SOURCEEVR, strn2id(pool, sevr, sarch - sevr - 1, 1)); + if (!strncmp(sourcerpm, name, sevr - sourcerpm - 1) && name[sevr - sourcerpm - + 1] == 0) + repodata_set_void(data, handle, SOLVABLE_SOURCENAME); + else + repodata_set_id(data, handle, SOLVABLE_SOURCENAME, strn2id(pool, sourcerpm, sevr - sourcerpm - 1, 1)); +} + +/*-----------------------------------------------*/ +/* XML callbacks */ + +/* + * startElement + * XML callback + * + */ + static void XMLCALL startElement(void *userData, const char *name, const char **atts) { @@ -483,14 +623,26 @@ startElement(void *userData, const char *name, const char **atts) Solvable *s = pd->solvable; struct stateswitch *sw; const char *str; - Id entry = s ? (s - pool->solvables) - pd->data->start : 0; + Id handle = pd->handle; + + // fprintf(stderr, "into %s, from %d, depth %d, statedepth %d\n", name, pd->state, pd->depth, pd->statedepth); if (pd->depth != pd->statedepth) { pd->depth++; return; } + + if (pd->state == STATE_START && !strcmp(name, "patterns")) + return; + //if (pd->state == STATE_START && !strcmp(name, "metadata")) + // return; + if (pd->state == STATE_SOLVABLE && !strcmp(name, "format")) + return; + pd->depth++; + if (!pd->swtab[pd->state]) + return; for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) if (!strcmp(sw->ename, name)) break; @@ -516,124 +668,188 @@ startElement(void *userData, const char *name, const char **atts) pd->kind = "product"; else if (name[2] == 't' && name[3] == 'c') pd->kind = "patch"; - - pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->common.repo)); - repodata_extend(pd->data, pd->solvable - pool->solvables); + + /* to support extension metadata files like others.xml which + have the following structure: + + + + ... + + we need to check if the pkgid is there and if it matches + an already seen package, that means we don't need to create + a new solvable but just append the attributes to the existing + one. + */ + const char *pkgid; + if ((pkgid = find_attr("pkgid", atts)) != NULL) + { + // look at the checksum cache + Id index = stringpool_str2id(&pd->cspool, pkgid, 0); + if (!index || index >= pd->ncscache || !pd->cscache[index]) + { + fprintf(stderr, "error, the repository specifies extra information about package with checksum '%s', which does not exist in the repository.\n", pkgid); + exit(1); + } + pd->solvable = pool_id2solvable(pool, pd->cscache[index]); + } + else + { + /* this is a new package */ + pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->common.repo)); + pd->freshens = 0; + } + pd->handle = pd->solvable - pool->solvables; #if 0 fprintf(stderr, "package #%d\n", pd->solvable - pool->solvables); #endif + break; case STATE_VERSION: s->evr = makeevr_atts(pool, pd, atts); break; - case STATE_CAPS_PROVIDES: case STATE_PROVIDES: s->provides = 0; break; case STATE_PROVIDESENTRY: s->provides = adddep(pool, pd, s->provides, atts, 0); break; - case STATE_CAPS_REQUIRES: case STATE_REQUIRES: s->requires = 0; break; case STATE_REQUIRESENTRY: s->requires = adddep(pool, pd, s->requires, atts, 1); break; - case STATE_CAPS_OBSOLETES: case STATE_OBSOLETES: s->obsoletes = 0; break; case STATE_OBSOLETESENTRY: s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0); break; - case STATE_CAPS_CONFLICTS: case STATE_CONFLICTS: s->conflicts = 0; break; case STATE_CONFLICTSENTRY: s->conflicts = adddep(pool, pd, s->conflicts, atts, 0); break; - case STATE_CAPS_RECOMMENDS: case STATE_RECOMMENDS: s->recommends = 0; break; case STATE_RECOMMENDSENTRY: s->recommends = adddep(pool, pd, s->recommends, atts, 0); break; - case STATE_CAPS_SUPPLEMENTS: case STATE_SUPPLEMENTS: s->supplements= 0; break; case STATE_SUPPLEMENTSENTRY: s->supplements = adddep(pool, pd, s->supplements, atts, 0); break; - case STATE_CAPS_SUGGESTS: case STATE_SUGGESTS: s->suggests = 0; break; case STATE_SUGGESTSENTRY: s->suggests = adddep(pool, pd, s->suggests, atts, 0); break; - case STATE_CAPS_ENHANCES: case STATE_ENHANCES: s->enhances = 0; break; case STATE_ENHANCESENTRY: s->enhances = adddep(pool, pd, s->enhances, atts, 0); break; - case STATE_CAPS_FRESHENS: case STATE_FRESHENS: - s->freshens = 0; + pd->freshens = 0; break; case STATE_FRESHENSENTRY: - s->freshens = adddep(pool, pd, s->freshens, atts, 0); - break; - case STATE_CAP_PROVIDES: - case STATE_CAP_REQUIRES: - case STATE_CAP_OBSOLETES: - case STATE_CAP_CONFLICTS: - case STATE_CAP_RECOMMENDS: - case STATE_CAP_SUPPLEMENTS: - case STATE_CAP_SUGGESTS: - case STATE_CAP_ENHANCES: - case STATE_CAP_FRESHENS: - pd->capkind = find_attr("kind", atts); - //fprintf(stderr,"capkind es: %s\n", pd->capkind); + pd->freshens = adddep(pool, pd, pd->freshens, atts, 0); break; case STATE_SUMMARY: case STATE_DESCRIPTION: - pd->lang = find_attr("lang", atts); + pd->tmplang = find_attr("lang", atts); break; case STATE_LOCATION: str = find_attr("href", atts); if (str) - repodata_set_str(pd->data, entry, id_mediafile, str); + repodata_set_location(pd->data, handle, 0, 0, str); break; case STATE_CHECKSUM: pd->tmpattr = find_attr("type", atts); break; case STATE_TIME: { - unsigned t; + unsigned int t; str = find_attr("build", atts); if (str && (t = atoi(str)) != 0) - repodata_set_num(pd->data, entry, id_time, t); + repodata_set_num(pd->data, handle, SOLVABLE_BUILDTIME, t); break; } case STATE_SIZE: { - unsigned k; + unsigned int k; str = find_attr("installed", atts); if (str && (k = atoi(str)) != 0) - repodata_set_num(pd->data, entry, id_installsize, (k + 1023) / 1024); + repodata_set_num(pd->data, handle, SOLVABLE_INSTALLSIZE, (k + 1023) / 1024); /* XXX the "package" attribute gives the size of the rpm file, i.e. the download size. Except on packman, there it seems to be something else entirely, it has a value near to the other two values, as if the rpm is uncompressed. */ str = find_attr("package", atts); if (str && (k = atoi(str)) != 0) - repodata_set_num(pd->data, entry, id_downloadsize, (k + 1023) / 1024); + repodata_set_num(pd->data, handle, SOLVABLE_DOWNLOADSIZE, (k + 1023) / 1024); + break; + } + case STATE_HEADERRANGE: + { + unsigned int end; + str = find_attr("end", atts); + if (str && (end = atoi(str)) != 0) + repodata_set_num(pd->data, handle, SOLVABLE_HEADEREND, end); + } + /* + + + + + + + + + + */ + case STATE_DISKUSAGE: + { + /* Really, do nothing, wat for tag */ + break; + } + case STATE_DIR: + { + long filesz = 0, filenum = 0; + unsigned dirid; + if ( (str = find_attr("name", atts)) ) + { + dirid = repodata_str2dir(pd->data, str, 1); + } + else + { + fprintf( stderr, " tag without 'name' attribute, atts = %p, *atts = %p\n", atts, *atts); + break; + } + if ( (str = find_attr("size", atts)) ) + { + filesz = strtol (str, 0, 0); + } + if ( (str = find_attr("count", atts)) ) + { + filenum = strtol (str, 0, 0); + } + pd->dirs = sat_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31); + pd->dirs[pd->ndirs][0] = dirid; + pd->dirs[pd->ndirs][1] = filesz; + pd->dirs[pd->ndirs][2] = filenum; + pd->ndirs++; break; } default: @@ -641,6 +857,13 @@ startElement(void *userData, const char *name, const char **atts) } } + +/* + * endElement + * XML callback + * + */ + static void XMLCALL endElement(void *userData, const char *name) { @@ -649,7 +872,7 @@ endElement(void *userData, const char *name) Pool *pool = pd->common.pool; Solvable *s = pd->solvable; Repo *repo = pd->common.repo; - Id entry = s ? (s - pool->solvables) - pd->data->start : 0; + Id handle = pd->handle; Id id; char *p; @@ -659,18 +882,29 @@ endElement(void *userData, const char *name) // printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); return; } + + /* ignore patterns & metadata */ + if (pd->state == STATE_START && !strcmp(name, "patterns")) + return; + //if (pd->state == STATE_START && !strcmp(name, "metadata")) + // return; + if (pd->state == STATE_SOLVABLE && !strcmp(name, "format")) + return; + pd->depth--; pd->statedepth--; switch (pd->state) { - case STATE_PATTERN: - case STATE_PRODUCT: case STATE_SOLVABLE: if (!s->arch) s->arch = ARCH_NOARCH; + if (!s->evr) + s->evr = ID_EMPTY; /* some patterns have this */ if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - s->supplements = repo_fix_legacy(repo, s->provides, s->supplements); + s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, pd->freshens); + s->conflicts = repo_fix_conflicts(repo, s->conflicts); + pd->freshens = 0; pd->kind = 0; break; case STATE_NAME: @@ -686,69 +920,135 @@ endElement(void *userData, const char *name) s->vendor = str2id(pool, pd->content, 1); break; case STATE_RPM_GROUP: - repodata_set_poolstr(pd->data, entry, id_group, pd->content); + repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, pd->content); break; case STATE_RPM_LICENSE: - repodata_set_poolstr(pd->data, entry, id_license, pd->content); + repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, pd->content); break; + case STATE_CHECKSUM: + { + int l; + Id type, index; + if (!strcasecmp (pd->tmpattr, "sha") || !strcasecmp (pd->tmpattr, "sha1")) + l = SIZEOF_SHA1 * 2, type = REPOKEY_TYPE_SHA1; + else if (!strcasecmp (pd->tmpattr, "md5")) + l = SIZEOF_MD5 * 2, type = REPOKEY_TYPE_MD5; + else + { + fprintf(stderr, "Unknown checksum type: %d: %s\n", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), pd->tmpattr); + exit(1); + } + if (strlen(pd->content) != l) + { + fprintf(stderr, "Invalid checksum length: %d: for %s\n", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), pd->tmpattr); + exit(1); + } + repodata_set_checksum(pd->data, handle, SOLVABLE_CHECKSUM, type, pd->content); + /* we save the checksum to solvable id relationship for extended + metadata */ + index = stringpool_str2id(&pd->cspool, pd->content, 1 /* create it */); + if (index >= pd->ncscache) + { + pd->cscache = sat_zextend(pd->cscache, pd->ncscache, index + 1 - pd->ncscache, sizeof(Id), 255); + pd->ncscache = index + 1; + } + /* add the checksum to the cache */ + pd->cscache[index] = s - pool->solvables; + break; + } case STATE_FILE: #if 0 id = str2id(pool, pd->content, 1); s->provides = repo_addid_dep(repo, s->provides, id, SOLVABLE_FILEMARKER); #endif - if ((p = strrchr(pd->content, '/')) != 0) { - *p++ = 0; - id = repodata_str2dir(pd->data, pd->content, 1); - } else { - id = 1; - p = pd->content; - } - repodata_add_dirstr(pd->data, entry, id_filelist, id, p); + if ((p = strrchr(pd->content, '/')) != 0) + { + *p++ = 0; + id = repodata_str2dir(pd->data, pd->content, 1); + } + else + { + p = pd->content; + id = 0; + } + if (!id) + id = repodata_str2dir(pd->data, "/", 1); + repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, id, p); break; - // xml store capabilities - case STATE_CAP_PROVIDES: - s->provides = adddepplain(pool, &pd->common, s->provides, pd->content, 0, pd->capkind); + case STATE_SUMMARY: + pd->tmplang = 0; + repodata_set_str(pd->data, handle, SOLVABLE_SUMMARY, pd->content); break; - case STATE_CAP_REQUIRES: - s->requires = adddepplain(pool, &pd->common, s->requires, pd->content, 0, pd->capkind); + case STATE_DESCRIPTION: + pd->tmplang = 0; + set_desciption_author(pd->data, handle, pd->content); break; - case STATE_CAP_OBSOLETES: - s->obsoletes = adddepplain(pool, &pd->common, s->obsoletes, pd->content, 0, pd->capkind); + case STATE_DISTRIBUTION: + repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, pd->content); + break; + case STATE_URL: + if (pd->content[0]) + repodata_set_str(pd->data, handle, SOLVABLE_URL, pd->content); break; - case STATE_CAP_CONFLICTS: - s->conflicts = adddepplain(pool, &pd->common, s->conflicts, pd->content, 0, pd->capkind); + case STATE_PACKAGER: + if (pd->content[0]) + repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, pd->content); break; - case STATE_CAP_RECOMMENDS: - s->recommends = adddepplain(pool, &pd->common, s->recommends, pd->content, 0, pd->capkind); + case STATE_SOURCERPM: + set_sourcerpm(pd->data, s, handle, pd->content); break; - case STATE_CAP_SUPPLEMENTS: - s->supplements = adddepplain(pool, &pd->common, s->supplements, pd->content, 0, pd->capkind); + case STATE_RELNOTESURL: + if (pd->content[0]) + { + repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, pd->content); + repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, str2id(pool, "releasenotes", 1)); + } break; - case STATE_CAP_SUGGESTS: - s->suggests = adddepplain(pool, &pd->common, s->suggests, pd->content, 0, pd->capkind); + case STATE_UPDATEURL: + if (pd->content[0]) + { + repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, pd->content); + repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, str2id(pool, "update", 1)); + } break; - case STATE_CAP_ENHANCES: - s->enhances = adddepplain(pool, &pd->common, s->enhances, pd->content, 0, pd->capkind); + case STATE_OPTIONALURL: + if (pd->content[0]) + { + repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, pd->content); + repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, str2id(pool, "optional", 1)); + } break; - case STATE_CAP_FRESHENS: - s->freshens = adddepplain(pool, &pd->common, s->freshens, pd->content, 0, pd->capkind); + case STATE_FLAG: + if (pd->content[0]) + repodata_set_poolstr(pd->data, handle, PRODUCT_FLAGS, pd->content); break; - case STATE_SUMMARY: - pd->lang = 0; - repodata_set_str(pd->data, entry, id_summary, pd->content); + case STATE_EULA: + if (pd->content[0]) + repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->language), pd->content); break; - case STATE_DESCRIPTION: - pd->lang = 0; - set_desciption_author(pd->data, entry, pd->content); + case STATE_KEYWORD: + if (pd->content[0]) + repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, pd->content); + break; + case STATE_DISKUSAGE: + if (pd->ndirs) + commit_diskusage (pd, pd->handle); break; default: break; } pd->state = pd->sbtab[pd->state]; pd->docontent = 0; - //fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); + // fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); } + +/* + * characterData + * XML callback + * + */ + static void XMLCALL characterData(void *userData, const XML_Char *s, int len) { @@ -772,16 +1072,33 @@ characterData(void *userData, const XML_Char *s, int len) } +/*-----------------------------------------------*/ +/* 'main' */ + #define BUFF_SIZE 8192 +/* + * repo_add_rpmmd + * parse rpm-md metadata (primary, others) + * + */ + void -repo_add_rpmmd(Repo *repo, FILE *fp, int flags) +repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags) { Pool *pool = repo->pool; struct parsedata pd; char buf[BUFF_SIZE]; int i, l; struct stateswitch *sw; + Repodata *data; + unsigned int now; + + now = sat_timems(0); + if (!(flags & REPO_REUSE_REPODATA)) + data = repo_add_repodata(repo, 0); + else + data = repo_last_repodata(repo); memset(&pd, 0, sizeof(pd)); for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) @@ -793,8 +1110,7 @@ repo_add_rpmmd(Repo *repo, FILE *fp, int flags) pd.common.pool = pool; pd.common.repo = repo; - pd.data = repo_add_repodata(repo); - init_attr_ids(pool); + pd.data = data; pd.content = sat_malloc(256); pd.acontent = 256; @@ -802,8 +1118,16 @@ repo_add_rpmmd(Repo *repo, FILE *fp, int flags) pd.common.tmp = 0; pd.common.tmpl = 0; pd.kind = 0; + pd.language = language; + + /* initialize the string pool where we will store + the package checksums we know about, to get an Id + we can use in a cache */ + stringpool_init_empty(&pd.cspool); + XML_Parser parser = XML_ParserCreate(NULL); XML_SetUserData(parser, &pd); + pd.parser = &parser; XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, characterData); for (;;) @@ -818,8 +1142,13 @@ repo_add_rpmmd(Repo *repo, FILE *fp, int flags) break; } XML_ParserFree(parser); - - if (pd.data) - repodata_internalize(pd.data); sat_free(pd.content); + join_freemem(); + stringpool_free(&pd.cspool); + sat_free(pd.cscache); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + POOL_DEBUG(SAT_DEBUG_STATS, "repo_add_rpmmd took %d ms\n", sat_timems(now)); + POOL_DEBUG(SAT_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables); + POOL_DEBUG(SAT_DEBUG_STATS, "repo memory used: %ld K incore, %ld K idarray\n", (unsigned long)data->incoredatalen/1024, (unsigned long)repo->idarraysize / (1024/sizeof(Id))); }