From 0d8901de92af4d0337a2410badcae82aeeec4ae9 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Mon, 3 Mar 2008 17:11:40 +0000 Subject: [PATCH] - add '-d' option to susetags2solv, reads all packages files - add '-b' option to susetags2solv and rpmdb2solv - both options currently a bit experimental --- tools/CMakeLists.txt | 2 +- tools/common_write.c | 260 ++++++++++++++++++++++++++++++++++++++++---------- tools/repo_susetags.c | 47 +++++++-- tools/repo_susetags.h | 3 +- tools/rpmdb2solv.c | 16 +++- tools/susetags2solv.c | 193 ++++++++++++++++++++++++++++--------- 6 files changed, 410 insertions(+), 111 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5485737..14658e4 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -24,7 +24,7 @@ TARGET_LINK_LIBRARIES( helix2solv satsolver ${EXPAT_LIBRARY}) SET(susetags2solv_REPOS susetags2solv.c repo_susetags.h repo_susetags.c repo_content.c repo_write.c common_write.c) ADD_EXECUTABLE( susetags2solv ${susetags2solv_REPOS} ) -TARGET_LINK_LIBRARIES( susetags2solv satsolver) +TARGET_LINK_LIBRARIES( susetags2solv satsolver ${ZLIB_LIBRARY}) SET(patchxml2solv_REPOS patchxml2solv.c repo_patchxml.h repo_patchxml.c repo_write.c common_write.c) ADD_EXECUTABLE( patchxml2solv ${patchxml2solv_REPOS} ) diff --git a/tools/common_write.c b/tools/common_write.c index 01fdda7..89d117a 100644 --- a/tools/common_write.c +++ b/tools/common_write.c @@ -17,94 +17,254 @@ #include "repo_write.h" #include "common_write.h" -static char *verticals[] = { - "authors", - "description", - "messagedel", - "messageins", - "eula", - "diskusage", - "filelist", +static Id verticals[] = { + SOLVABLE_AUTHORS, + SOLVABLE_DESCRIPTION, + SOLVABLE_MESSAGEDEL, + SOLVABLE_MESSAGEINS, + SOLVABLE_EULA, + SOLVABLE_DISKUSAGE, + SOLVABLE_FILELIST, 0 }; -static unsigned char *filter; -static int nfilter; - -static void -create_filter(Pool *pool) -{ - char **s; - Id id; - for (s = verticals; *s; s++) - { - id = str2id(pool, *s, 1); - if (id >= nfilter) - { - filter = sat_realloc(filter, id + 16); - memset(filter + nfilter, 0, id + 16 - nfilter); - nfilter = id + 16; - } - filter[id] = 1; - } -} +static char *languagetags[] = { + "solvable:summary:", + "solvable:description:", + "solvable:messageins:", + "solvable:messagedel:", + 0 +}; static int test_separate = 0; static int keyfilter_solv(Repo *data, Repokey *key, void *kfdata) { + int i; if (test_separate && key->storage != KEY_STORAGE_SOLVABLE) return KEY_STORAGE_DROPPED; - if (key->name < nfilter && filter[key->name]) - return KEY_STORAGE_VERTICAL_OFFSET; + for (i = 0; verticals[i]; i++) + if (key->name == verticals[i]) + return KEY_STORAGE_VERTICAL_OFFSET; return KEY_STORAGE_INCORE; } static int keyfilter_attr(Repo *data, Repokey *key, void *kfdata) { + int i; if (key->storage == KEY_STORAGE_SOLVABLE) return KEY_STORAGE_DROPPED; - if (key->name < nfilter && filter[key->name]) - return KEY_STORAGE_VERTICAL_OFFSET; + for (i = 0; verticals[i]; i++) + if (key->name == verticals[i]) + return KEY_STORAGE_VERTICAL_OFFSET; + return KEY_STORAGE_INCORE; +} + +static int +keyfilter_language(Repo *repo, Repokey *key, void *kfdata) +{ + const char *name, *p; + char *lang = kfdata, *bname; + int i; + Id id; + + name = id2str(repo->pool, key->name); + p = strrchr(name, ':'); + if (!p || strcmp(p + 1, lang) != 0) + return KEY_STORAGE_DROPPED; + /* find base name id */ + bname = strdup(name); + bname[p - name] = 0; + id = str2id(repo->pool, bname, 1); + for (i = 0; verticals[i]; i++) + if (id == verticals[i]) + return KEY_STORAGE_VERTICAL_OFFSET; + return KEY_STORAGE_INCORE; +} + +static int +keyfilter_DU(Repo *repo, Repokey *key, void *kfdata) +{ + int i; + if (key->name != SOLVABLE_DISKUSAGE) + return KEY_STORAGE_DROPPED; + for (i = 0; verticals[i]; i++) + if (key->name == verticals[i]) + return KEY_STORAGE_VERTICAL_OFFSET; + return KEY_STORAGE_INCORE; +} + +static int +keyfilter_FL(Repo *repo, Repokey *key, void *kfdata) +{ + int i; + if (key->name != SOLVABLE_FILELIST) + return KEY_STORAGE_DROPPED; + for (i = 0; verticals[i]; i++) + if (key->name == verticals[i]) + return KEY_STORAGE_VERTICAL_OFFSET; + return KEY_STORAGE_INCORE; +} + +struct keyfilter_other_data { + char **languages; + int nlanguages; +}; + +static int +keyfilter_other(Repo *repo, Repokey *key, void *kfdata) +{ + const char *name, *p; + struct keyfilter_other_data *kd = kfdata; + int i; + + if (key->name == SOLVABLE_FILELIST || key->name == SOLVABLE_DISKUSAGE) + return KEY_STORAGE_DROPPED; + name = id2str(repo->pool, key->name); + p = strrchr(name, ':'); + if (p) + { + for (i = 0; i < kd->nlanguages; i++) + if (!strcmp(p + 1, kd->languages[i])) + return KEY_STORAGE_DROPPED; + } + for (i = 0; verticals[i]; i++) + if (key->name == verticals[i]) + return KEY_STORAGE_VERTICAL_OFFSET; return KEY_STORAGE_INCORE; } /* * Write to stdout * If is given, write attributes to + * If is given, split attributes */ int tool_write(Repo *repo, const char *basename, const char *attrname) { - Pool *pool = repo->pool; - Repodatafile fileinfoa[1]; - Repodatafile *fileinfo = 0; - int nsubfiles = 0; + Repodata *data; + Repokey *key; + Repodatafile *fileinfos = 0; + int nfileinfos = 0; + char **languages = 0; + int nlanguages = 0; + int i, j, k, l; + + if (basename) + { + struct keyfilter_other_data kd; + char fn[4096]; + FILE *fp; + int has_DU = 0; + int has_FL = 0; - create_filter(pool); - memset (fileinfoa, 0, sizeof fileinfoa); + /* find languages and other info */ + for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) + { + for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++) + { + const char *keyname = id2str(repo->pool, key->name); + if (key->name == SOLVABLE_DISKUSAGE) + has_DU = 1; + if (key->name == SOLVABLE_FILELIST) + has_FL = 1; + for (k = 0; languagetags[k] != 0; k++) + if (!strncmp(keyname, languagetags[k], strlen(languagetags[k]))) + break; + if (!languagetags[k]) + continue; + l = strlen(languagetags[k]); + if (strlen(keyname + l) > 5) + continue; + for (k = 0; k < nlanguages; k++) + if (!strcmp(languages[k], keyname + l)) + break; + if (k < nlanguages) + continue; + languages = sat_realloc2(languages, nlanguages + 1, sizeof(char *)); + languages[nlanguages++] = strdup(keyname + l); + } + } + fileinfos = sat_calloc(nlanguages + 2, sizeof(Repodatafile)); + /* write language subfiles */ + for (i = 0; i < nlanguages; i++) + { + sprintf(fn, "%s.%s.solv", basename, languages[i]); + if (!(fp = fopen(fn, "w"))) + { + perror(fn); + exit(1); + } + repo_write(repo, fp, keyfilter_language, languages[i], fileinfos + nfileinfos, 0); + fileinfos[nfileinfos++].location = strdup(fn); + fclose(fp); + } + /* write DU subfile */ + if (has_DU) + { + sprintf(fn, "%s.DU.solv", basename); + if (!(fp = fopen(fn, "w"))) + { + perror(fn); + exit(1); + } + repo_write(repo, fp, keyfilter_DU, 0, fileinfos + nfileinfos, 0); + fileinfos[nfileinfos++].location = strdup(fn); + fclose(fp); + } + /* write filelist */ + if (has_FL) + { + sprintf(fn, "%s.FL.solv", basename); + if (!(fp = fopen(fn, "w"))) + { + perror(fn); + exit(1); + } + repo_write(repo, fp, keyfilter_FL, 0, fileinfos + nfileinfos, 0); + fileinfos[nfileinfos++].location = strdup(fn); + fclose(fp); + } + /* write everything else */ + sprintf(fn, "%s.solv", basename); + if (!(fp = fopen(fn, "w"))) + { + perror(fn); + exit(1); + } + kd.languages = languages; + kd.nlanguages = nlanguages; + repo_write(repo, fp, keyfilter_other, &kd, fileinfos, nfileinfos); + fclose(fp); + for (i = 0; i < nlanguages; i++) + free(languages[i]); + sat_free(languages); + for (i = 0; i < nfileinfos; i++) + { + sat_free(fileinfos[i].location); + sat_free(fileinfos[i].keys); + } + sat_free(fileinfos); + exit(0); + } if (attrname) { + fileinfos = sat_calloc(1, sizeof(Repodatafile)); test_separate = 1; - fileinfo = fileinfoa; FILE *fp = fopen (attrname, "w"); - repo_write(repo, fp, keyfilter_attr, 0, fileinfo, 0); + repo_write(repo, fp, keyfilter_attr, 0, fileinfos + nfileinfos++, 0); + fileinfos[nfileinfos - 1].location = strdup(attrname); fclose(fp); - fileinfo->location = strdup(attrname); - fileinfo++; - - nsubfiles = fileinfo - fileinfoa; - fileinfo = fileinfoa; } - repo_write(repo, stdout, keyfilter_solv, 0, fileinfo, nsubfiles); - if (fileinfo) + repo_write(repo, stdout, keyfilter_solv, 0, fileinfos, nfileinfos); + if (fileinfos) { - free(fileinfo->location); - free(fileinfo->keys); + free(fileinfos[0].location); + free(fileinfos[0].keys); + free(fileinfos); } - sat_free(filter); return 0; } diff --git a/tools/repo_susetags.c b/tools/repo_susetags.c index 0c5b76d..8057797 100644 --- a/tools/repo_susetags.c +++ b/tools/repo_susetags.c @@ -27,6 +27,7 @@ struct parsedata { int nshare; Id (*dirs)[3]; // dirid, size, nfiles int ndirs; + Id langcache[ID_NUM_INTERNAL]; }; static char *flagtab[] = { @@ -38,6 +39,26 @@ static char *flagtab[] = { "<=" }; + +static Id +langtag(struct parsedata *pd, Id tag, const char *language) +{ + char *p; + const char *tagname; + + if (!language || tag >= ID_NUM_INTERNAL) + return tag; + if (!pd->langcache[tag]) + { + tagname = id2str(pd->repo->pool, tag); + p = sat_malloc(strlen(tagname) + strlen(language) + 2); + sprintf(p, "%s:%s", tagname, language); + pd->langcache[tag] = str2id(pd->repo->pool, p, 1); + sat_free(p); + } + return pd->langcache[tag]; +} + /* * adddep * create and add dependency @@ -238,7 +259,7 @@ commit_diskusage (struct parsedata *pd, unsigned entry) /* 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); + 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 @@ -334,7 +355,7 @@ tag_from_string (char *cs) */ void -repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int flags) +repo_add_susetags(Repo *repo, FILE *fp, Id vendor, const char *language, int flags) { Pool *pool = repo->pool; char *line, *linep; @@ -348,7 +369,14 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int flags) struct parsedata pd; Repodata *data = 0; - data = repo_add_repodata(repo); + if ((flags & SUSETAGS_EXTEND) && repo->nrepodata) + { + /* use last repodata */ + data = repo->repodata + repo->nrepodata - 1; + indesc = 1; + } + if (!data) + data = repo_add_repodata(repo); memset(&pd, 0, sizeof(pd)); line = malloc(1024); @@ -562,7 +590,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int flags) solvables. */ if (indesc >= 2 && !s) { - fprintf (stderr, "Huh?\n"); + fprintf (stderr, "Huh %s?\n", line); continue; } switch (tag) @@ -686,19 +714,19 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int flags) repodata_set_str(data, last_found_pack, SOLVABLE_AUTHORS, line + 6); continue; case CTAG('=', 'S', 'u', 'm'): - repodata_set_str(data, last_found_pack, SOLVABLE_SUMMARY, line + 6); + repodata_set_str(data, last_found_pack, langtag(&pd, SOLVABLE_SUMMARY, language), line + 6); continue; case CTAG('=', 'D', 'e', 's'): - repodata_set_str(data, last_found_pack, SOLVABLE_DESCRIPTION, line + 6); + repodata_set_str(data, last_found_pack, langtag(&pd, SOLVABLE_DESCRIPTION, language), line + 6); continue; case CTAG('=', 'E', 'u', 'l'): - repodata_set_str(data, last_found_pack, SOLVABLE_EULA, line + 6); + repodata_set_str(data, last_found_pack, langtag(&pd, SOLVABLE_EULA, language), line + 6); continue; case CTAG('=', 'I', 'n', 's'): - repodata_set_str(data, last_found_pack, SOLVABLE_MESSAGEINS, line + 6); + repodata_set_str(data, last_found_pack, langtag(&pd, SOLVABLE_MESSAGEINS, language), line + 6); continue; case CTAG('=', 'D', 'e', 'l'): - repodata_set_str(data, last_found_pack, SOLVABLE_MESSAGEDEL, line + 6); + repodata_set_str(data, last_found_pack, langtag(&pd, SOLVABLE_MESSAGEDEL, language), line + 6); continue; case CTAG('=', 'V', 'i', 's'): { @@ -792,3 +820,4 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int flags) free(pd.common.tmp); free(line); } + diff --git a/tools/repo_susetags.h b/tools/repo_susetags.h index 4c6c8d4..880844a 100644 --- a/tools/repo_susetags.h +++ b/tools/repo_susetags.h @@ -10,5 +10,6 @@ */ #define SUSETAGS_KINDS_SEPARATELY 1 +#define SUSETAGS_EXTEND 2 -extern void repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int flags); +extern void repo_add_susetags(Repo *repo, FILE *fp, Id vendor, const char *language, int flags); diff --git a/tools/rpmdb2solv.c b/tools/rpmdb2solv.c index e818e11..81d58bd 100644 --- a/tools/rpmdb2solv.c +++ b/tools/rpmdb2solv.c @@ -31,13 +31,19 @@ main(int argc, char **argv) Repo *repo, *ref = 0; FILE *fp; Pool *refpool; - int g; + int c; const char *root = "/"; + const char *basefile = 0; - while ((g = getopt (argc, argv, "r:")) >= 0) - switch (g) + while ((c = getopt (argc, argv, "b:r:")) >= 0) + switch (c) { - case 'r': root = optarg; break; + case 'r': + root = optarg; + break; + case 'b': + basefile = optarg; + break; default: exit(1); } @@ -66,7 +72,7 @@ main(int argc, char **argv) ref = 0; } - tool_write(repo, 0, 0); + tool_write(repo, basefile, 0); pool_free(pool); exit(0); diff --git a/tools/susetags2solv.c b/tools/susetags2solv.c index 8f71a41..aa9e069 100644 --- a/tools/susetags2solv.c +++ b/tools/susetags2solv.c @@ -5,12 +5,16 @@ * for further information */ +#define _GNU_SOURCE + #include #include #include #include #include #include +#include +#include #include "pool.h" #include "repo.h" @@ -19,19 +23,52 @@ #include "common_write.h" static void -usage(const char *err) +usage(int status) { - if (err) - fprintf(stderr, "\n** Error:\n %s\n", err); fprintf(stderr, "\nUsage:\n" "susetags2solv [-a][-s][-c ][-h]\n" " reads a 'susetags' repository from and writes a .solv file to \n" " -c : parse given contentfile (for product information)\n" + " -d : do not read from stdin, but use data in descrdir\n" " -h : print help & exit\n" " -k : don't mix kinds (experimental!)\n" + " -b : save fas multiple files starting with \n" " -n : save attributes as .attr\n" ); - exit(0); + exit(status); +} + +static ssize_t +cookie_gzread(void *cookie, char *buf, size_t nbytes) +{ + return gzread((gzFile *)cookie, buf, nbytes); +} + +static int +cookie_gzclose(void *cookie) +{ + return gzclose((gzFile *)cookie); +} + +FILE * +myfopen(const char *fn) +{ + cookie_io_functions_t cio; + char *suf; + gzFile *gzf; + + if (!fn) + return 0; + suf = strrchr(fn, '.'); + if (!suf || strcmp(suf, ".gz") != 0) + return fopen(fn, "r"); + gzf = gzopen(fn, "r"); + if (!gzf) + return 0; + memset(&cio, 0, sizeof(cio)); + cio.read = cookie_gzread; + cio.close = cookie_gzclose; + return fopencookie(gzf, "r", cio); } int @@ -39,54 +76,48 @@ main(int argc, char **argv) { const char *contentfile = 0; const char *attrname = 0; + const char *descrdir = 0; + const char *basefile = 0; Id vendor = 0; int flags = 0; - argv++; - argc--; - while (argc--) + int c; + + while ((c = getopt(argc, argv, "hkn:c:d:b:")) >= 0) { - const char *s = argv[0]; - if (*s++ == '-') - while (*s) - switch (*s++) - { - case 'h': usage(NULL); break; - case 'n': - if (argc) - { - attrname = argv[1]; - argv++; - argc--; - } - else - usage("argument required for '-n'"); - break; - case 'c': - if (argc) - { - contentfile = argv[1]; - argv++; - argc--; - } - else - usage("argument required for '-c'"); - break; - case 'k': - flags |= SUSETAGS_KINDS_SEPARATELY; - break; - default : break; - } - argv++; + switch (c) + { + case 'h': + usage(0); + break; + case 'k': + flags |= SUSETAGS_KINDS_SEPARATELY; /* do not use! */ + break; + case 'n': + attrname = optarg; + break; + case 'c': + contentfile = optarg; + break; + case 'd': + descrdir = optarg; + break; + case 'b': + basefile = optarg; + break; + default: + usage(1); + break; + } } Pool *pool = pool_create(); - Repo *repo = repo_create(pool, ""); + Repo *repo = repo_create(pool, ""); if (contentfile) { FILE *fp = fopen (contentfile, "r"); if (!fp) { - perror("opening content file"); - exit (1); + perror(contentfile); + exit(1); } repo_add_content(repo, fp); if (!strncmp (id2str(pool, pool->solvables[repo->start].name), "product:", 8)) @@ -100,14 +131,86 @@ main(int argc, char **argv) if (!dot || strcmp(dot, ".attr")) { int len = strlen (attrname); - char *newname = (char *)malloc (len + 6); /* alloc for +'.attr'+'\0' */ + char *newname = (char *)malloc(len + 6); /* alloc for +'.attr'+'\0' */ strcpy (newname, attrname); strcpy (newname+len, ".attr"); attrname = newname; } } - repo_add_susetags(repo, stdin, vendor, flags); - tool_write(repo, 0, attrname); + + if (descrdir) + { + char *fnp; + int ndirs, i; + struct dirent **files; + + ndirs = scandir(descrdir, &files, 0, alphasort); + if (ndirs < 0) + { + perror(descrdir); + exit(1); + } + fnp = sat_malloc(strlen(descrdir) + 128); + for (i = 0; i < ndirs; i++) + { + char *fn = files[i]->d_name; + + if (!strcmp(fn, "packages") || !strcmp(fn, "packages.gz")) + { + sprintf(fnp, "%s/%s", descrdir, fn); + FILE *fp = myfopen(fnp); + if (!fp) + { + perror(fn); + exit(1); + } + repo_add_susetags(repo, fp, vendor, 0, flags); + fclose(fp); + } + else if (!strcmp(fn, "packages.DU") || !strcmp(fn, "packages.DU.gz")) + { + sprintf(fnp, "%s/%s", descrdir, fn); + FILE *fp = myfopen(fnp); + if (!fp) + { + perror(fn); + exit(1); + } + repo_add_susetags(repo, fp, vendor, 0, flags | SUSETAGS_EXTEND); + fclose(fp); + } + else if (!strncmp(fn, "packages.", 9)) + { + char lang[6]; + char *p; + sprintf(fnp, "%s/%s", descrdir, fn); + p = strrchr(fn, '.'); + if (p && !strcmp(p, ".gz")) + { + *p = 0; + p = strrchr(fn, '.'); + } + if (!p || !p[1] || strlen(p + 1) > 5) + continue; + strcpy(lang, p + 1); + sprintf(fnp, "%s/%s", descrdir, fn); + FILE *fp = myfopen(fnp); + if (!fp) + { + perror(fn); + exit(1); + } + repo_add_susetags(repo, fp, vendor, lang, flags | SUSETAGS_EXTEND); + fclose(fp); + } + } + free(files); + free(fnp); + } + else + repo_add_susetags(repo, stdin, vendor, 0, flags); + + tool_write(repo, basefile, attrname); pool_free(pool); exit(0); } -- 2.7.4