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} )
#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 <repo> to stdout
* If <attrname> is given, write attributes to <attrname>
+ * If <basename> 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;
}
int nshare;
Id (*dirs)[3]; // dirid, size, nfiles
int ndirs;
+ Id langcache[ID_NUM_INTERNAL];
};
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
/* 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
*/
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;
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);
solvables. */
if (indesc >= 2 && !s)
{
- fprintf (stderr, "Huh?\n");
+ fprintf (stderr, "Huh %s?\n", line);
continue;
}
switch (tag)
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'):
{
free(pd.common.tmp);
free(line);
}
+
*/
#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);
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);
}
ref = 0;
}
- tool_write(repo, 0, 0);
+ tool_write(repo, basefile, 0);
pool_free(pool);
exit(0);
* for further information
*/
+#define _GNU_SOURCE
+
#include <sys/types.h>
#include <limits.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <dirent.h>
+#include <zlib.h>
#include "pool.h"
#include "repo.h"
#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 <content>][-h]\n"
" reads a 'susetags' repository from <stdin> and writes a .solv file to <stdout>\n"
" -c <contentfile> : parse given contentfile (for product information)\n"
+ " -d <descrdir> : do not read from stdin, but use data in descrdir\n"
" -h : print help & exit\n"
" -k : don't mix kinds (experimental!)\n"
+ " -b <base>: save fas multiple files starting with <base>\n"
" -n <name>: save attributes as <name>.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
{
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, "<stdin>");
+ Repo *repo = repo_create(pool, "<susetags>");
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))
if (!dot || strcmp(dot, ".attr"))
{
int len = strlen (attrname);
- char *newname = (char *)malloc (len + 6); /* alloc for <attrname>+'.attr'+'\0' */
+ char *newname = (char *)malloc(len + 6); /* alloc for <attrname>+'.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);
}