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