753b86c8609e21618ea8cd1e6caef954e5ae2d67
[platform/upstream/libsolv.git] / tools / susetags2solv.c
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #define _GNU_SOURCE
9
10 #include <sys/types.h>
11 #include <limits.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <dirent.h>
17 #include <zlib.h>
18 #include <getopt.h>
19
20 #include "pool.h"
21 #include "repo.h"
22 #include "repo_susetags.h"
23 #include "repo_content.h"
24 #include "common_write.h"
25
26 static void
27 usage(int status)
28 {
29   fprintf(stderr, "\nUsage:\n"
30           "susetags2solv [-b <base>][-c <content>][-d <descrdir>][-h][-k][-n <name>]\n"
31           "  reads a 'susetags' repository from <stdin> and writes a .solv file to <stdout>\n"
32           "  -b <base>: save as multiple files starting with <base>\n"
33           "  -c <contentfile> : parse given contentfile (for product information)\n"
34           "  -d <descrdir> : do not read from stdin, but use data in descrdir\n"
35           "  -h : print help & exit\n"
36           "  -k : don't mix kinds (experimental!)\n"
37           "  -n <name>: save attributes as <name>.attr\n"
38          );
39    exit(status);
40 }
41
42 static ssize_t
43 cookie_gzread(void *cookie, char *buf, size_t nbytes)
44 {
45   return gzread((gzFile *)cookie, buf, nbytes);
46 }
47
48 static int
49 cookie_gzclose(void *cookie)
50 {
51   return gzclose((gzFile *)cookie);
52 }
53
54 FILE *
55 myfopen(const char *fn)
56 {
57   cookie_io_functions_t cio;
58   char *suf;
59   gzFile *gzf;
60
61   if (!fn)
62     return 0;
63   suf = strrchr(fn, '.');
64   if (!suf || strcmp(suf, ".gz") != 0)
65     return fopen(fn, "r");
66   gzf = gzopen(fn, "r");
67   if (!gzf)
68     return 0;
69   memset(&cio, 0, sizeof(cio));
70   cio.read = cookie_gzread;
71   cio.close = cookie_gzclose;
72   return  fopencookie(gzf, "r", cio);
73 }
74
75 /* content file query */
76 static void
77 doquery(Pool *pool, Repo *repo, const char *arg)
78 {
79   char qbuf[256];
80   const char *str;
81   Id id;
82
83   snprintf(qbuf, sizeof(qbuf), "susetags:%s", arg);
84   id = str2id(pool, qbuf, 0);
85   if (!id)
86     return;
87   str = repo_lookup_str(repo, SOLVID_META, id);
88   if (str)
89     printf("%s\n", str);
90 }
91
92 int
93 main(int argc, char **argv)
94 {
95   const char *contentfile = 0;
96   const char *attrname = 0;
97   const char *descrdir = 0;
98   const char *basefile = 0;
99   const char *query = 0;
100   Id defvendor = 0;
101   int flags = 0;
102   int c;
103
104   while ((c = getopt(argc, argv, "hkn:c:d:b:q:")) >= 0)
105     {
106       switch (c)
107         {
108         case 'h':
109           usage(0);
110           break;
111         case 'k':
112           flags |= SUSETAGS_KINDS_SEPARATELY;   /* do not use! */
113           break;
114         case 'n':
115           attrname = optarg;
116           break;
117         case 'c':
118           contentfile = optarg;
119           break;
120         case 'd':
121           descrdir = optarg;
122           break;
123         case 'b':
124           basefile = optarg;
125           break;
126         case 'q':
127           query = optarg;
128           break;
129         default:
130           usage(1);
131           break;
132         }
133     }
134   Pool *pool = pool_create();
135   Repo *repo = repo_create(pool, "<susetags>");
136
137   repo_add_repodata(repo, 0);
138
139   if (contentfile)
140     {
141       FILE *fp = fopen (contentfile, "r");
142       if (!fp)
143         {
144           perror(contentfile);
145           exit(1);
146         }
147       repo_add_content(repo, fp, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
148       if (repo->start < repo->end)
149         if (!strncmp(id2str(pool, pool->solvables[repo->start].name), "product:", 8))
150           defvendor = pool->solvables[repo->start].vendor;
151       fclose(fp);
152     }
153
154   if (attrname)
155     {
156       /* ensure '.attr' suffix */
157       const char *dot = strrchr(attrname, '.');
158       if (!dot || strcmp(dot, ".attr"))
159       {
160         int len = strlen (attrname);
161         char *newname = (char *)malloc(len + 6); /* alloc for <attrname>+'.attr'+'\0' */
162         strcpy (newname, attrname);
163         strcpy (newname+len, ".attr");
164         attrname = newname;
165       }
166     }
167
168   /*
169    * descrdir path given, open files and read from there
170    */
171   
172   if (descrdir)
173     {
174       char *fnp;
175       int ndirs, i;
176       struct dirent **files;
177
178       ndirs = scandir(descrdir, &files, 0, alphasort);
179       if (ndirs < 0)
180         {
181           perror(descrdir);
182           exit(1);
183         }
184
185       /* bring packages to front */
186       for (i = 0; i < ndirs; i++)
187         {
188           char *fn = files[i]->d_name;
189           if (!strcmp(fn, "packages") || !strcmp(fn, "packages.gz"))
190             break;
191         }
192       if (i == ndirs)
193         {
194           fprintf(stderr, "found no packages file\n");
195           exit(1);
196         }
197       if (i)
198         {
199           struct dirent *de = files[i];
200           memmove(files + 1, files, i * sizeof(de));
201           files[0] = de;
202         }
203
204       fnp = sat_malloc(strlen(descrdir) + 128);
205       for (i = 0; i < ndirs; i++)
206         {
207           char *fn = files[i]->d_name;
208
209           if (!strcmp(fn, "packages") || !strcmp(fn, "packages.gz"))
210             {
211               sprintf(fnp, "%s/%s", descrdir, fn);
212               FILE *fp = myfopen(fnp);
213               if (!fp)
214                 {
215                   perror(fn);
216                   exit(1);
217                 }
218               repo_add_susetags(repo, fp, defvendor, 0, flags | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
219               fclose(fp);
220             }
221           else if (!strcmp(fn, "packages.DU") || !strcmp(fn, "packages.DU.gz"))
222             {
223               sprintf(fnp, "%s/%s", descrdir, fn);
224               FILE *fp = myfopen(fnp);
225               if (!fp)
226                 {
227                   perror(fn);
228                   exit(1);
229                 }
230               repo_add_susetags(repo, fp, defvendor, 0, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
231               fclose(fp);
232             }
233           else if (!strcmp(fn, "packages.FL") || !strcmp(fn, "packages.FL.gz"))
234             {
235 #if 0
236               sprintf(fnp, "%s/%s", descrdir, fn);
237               FILE *fp = myfopen(fnp);
238               if (!fp)
239                 {
240                   perror(fn);
241                   exit(1);
242                 }
243               repo_add_susetags(repo, fp, defvendor, 0, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
244               fclose(fp);
245 #else
246               /* ignore for now. reactivate when filters work */
247               continue;
248 #endif
249             }
250           else if (!strncmp(fn, "packages.", 9))
251             {
252               char lang[6];
253               char *p;
254               sprintf(fnp, "%s/%s", descrdir, fn);
255               p = strrchr(fnp, '.');
256               if (p && !strcmp(p, ".gz"))
257                 {
258                   *p = 0;
259                   p = strrchr(fnp, '.');
260                 }
261               if (!p || !p[1] || strlen(p + 1) > 5)
262                 continue;
263               strcpy(lang, p + 1);
264               sprintf(fnp, "%s/%s", descrdir, fn);
265               FILE *fp = myfopen(fnp);
266               if (!fp)
267                 {
268                   perror(fn);
269                   exit(1);
270                 }
271               repo_add_susetags(repo, fp, defvendor, lang, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
272               fclose(fp);
273             }
274         }
275       for (i = 0; i < ndirs; i++)
276         free(files[i]);
277       free(files);
278       free(fnp);
279       repo_internalize(repo);
280     }
281   else
282     /* read data from stdin */
283     repo_add_susetags(repo, stdin, defvendor, 0, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
284   repo_internalize(repo);
285
286   if (query)
287     doquery(pool, repo, query);
288   else
289     tool_write(repo, basefile, attrname);
290   pool_free(pool);
291   exit(0);
292 }