Imported Upstream version 0.6.29
[platform/upstream/libsolv.git] / tools / common_write.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 #include <sys/types.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "pool.h"
14 #include "repo.h"
15 #include "repo_write.h"
16 #include "common_write.h"
17 #include "solvversion.h"
18
19 /* toolversion history
20  * 1.0: initial tool version
21  * 1.1: changed PRODUCT_ENDOFLIFE parsing
22 */
23
24 static Id verticals[] = {
25   SOLVABLE_AUTHORS,
26   SOLVABLE_DESCRIPTION,
27   SOLVABLE_MESSAGEDEL,
28   SOLVABLE_MESSAGEINS,
29   SOLVABLE_EULA,
30   SOLVABLE_DISKUSAGE,
31   SOLVABLE_FILELIST,
32   SOLVABLE_CHANGELOG_AUTHOR,
33   SOLVABLE_CHANGELOG_TEXT,
34   0
35 };
36
37 static char *languagetags[] = {
38   "solvable:summary:",
39   "solvable:description:",
40   "solvable:messageins:",
41   "solvable:messagedel:",
42   "solvable:eula:",
43   0
44 };
45
46 static int test_separate = 0;
47
48 struct keyfilter_data {
49   char **languages;
50   int nlanguages;
51   int haveaddedfileprovides;
52   int haveexternal;
53 };
54
55 static int
56 keyfilter_solv(Repo *data, Repokey *key, void *kfdata)
57 {
58   struct keyfilter_data *kd = kfdata;
59   int i;
60   const char *keyname;
61
62   if (test_separate && key->storage != KEY_STORAGE_SOLVABLE)
63     return KEY_STORAGE_DROPPED;
64   if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
65     return KEY_STORAGE_DROPPED;
66   if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
67     return KEY_STORAGE_DROPPED;
68   for (i = 0; verticals[i]; i++)
69     if (key->name == verticals[i])
70       return KEY_STORAGE_VERTICAL_OFFSET;
71   keyname = pool_id2str(data->pool, key->name);
72   for (i = 0; languagetags[i] != 0; i++)
73     if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
74       return KEY_STORAGE_VERTICAL_OFFSET;
75   return KEY_STORAGE_INCORE;
76 }
77
78 static int
79 keyfilter_attr(Repo *data, Repokey *key, void *kfdata)
80 {
81   int i;
82   const char *keyname;
83   if (key->storage == KEY_STORAGE_SOLVABLE)
84     return KEY_STORAGE_DROPPED;
85   /* those must only be in the main solv file */
86   if (key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_TOOLVERSION)
87     return KEY_STORAGE_DROPPED;
88   for (i = 0; verticals[i]; i++)
89     if (key->name == verticals[i])
90       return KEY_STORAGE_VERTICAL_OFFSET;
91   keyname = pool_id2str(data->pool, key->name);
92   for (i = 0; languagetags[i] != 0; i++)
93     if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
94       return KEY_STORAGE_VERTICAL_OFFSET;
95   return KEY_STORAGE_INCORE;
96 }
97
98 static int
99 keyfilter_language(Repo *repo, Repokey *key, void *kfdata)
100 {
101   Pool *pool = repo->pool;
102   const char *name, *p;
103   char *lang = kfdata;
104   int i;
105
106   name = pool_id2str(repo->pool, key->name);
107   p = strrchr(name, ':');
108   if (!p || strcmp(p + 1, lang) != 0)
109     return KEY_STORAGE_DROPPED;
110   for (i = 0; verticals[i]; i++)
111     {
112       const char *vname = pool_id2str(pool, verticals[i]);
113       if (!strncmp(name, vname, p - name) && vname[p - name] == 0)
114         return KEY_STORAGE_VERTICAL_OFFSET;
115     }
116   return KEY_STORAGE_INCORE;
117 }
118
119 static int
120 keyfilter_DU(Repo *repo, Repokey *key, void *kfdata)
121 {
122   int i;
123   if (key->name != SOLVABLE_DISKUSAGE)
124     return KEY_STORAGE_DROPPED;
125   for (i = 0; verticals[i]; i++)
126     if (key->name == verticals[i])
127       return KEY_STORAGE_VERTICAL_OFFSET;
128   return KEY_STORAGE_INCORE;
129 }
130
131 static int
132 keyfilter_FL(Repo *repo, Repokey *key, void *kfdata)
133 {
134   int i;
135   if (key->name != SOLVABLE_FILELIST)
136     return KEY_STORAGE_DROPPED;
137   for (i = 0; verticals[i]; i++)
138     if (key->name == verticals[i])
139       return KEY_STORAGE_VERTICAL_OFFSET;
140   return KEY_STORAGE_INCORE;
141 }
142
143 static int
144 keyfilter_other(Repo *repo, Repokey *key, void *kfdata)
145 {
146   const char *name, *p;
147   struct keyfilter_data *kd = kfdata;
148   int i;
149
150   if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
151     return KEY_STORAGE_DROPPED;
152   if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
153     return KEY_STORAGE_DROPPED;
154
155   if (key->name == SOLVABLE_FILELIST || key->name == SOLVABLE_DISKUSAGE)
156     return KEY_STORAGE_DROPPED;
157
158   name = pool_id2str(repo->pool, key->name);
159   p = strrchr(name, ':');
160   if (p)
161     {
162       for (i = 0; i < kd->nlanguages; i++)
163         if (!strcmp(p + 1, kd->languages[i]))
164           return KEY_STORAGE_DROPPED;
165     }
166   for (i = 0; verticals[i]; i++)
167     if (key->name == verticals[i])
168       return KEY_STORAGE_VERTICAL_OFFSET;
169   return KEY_STORAGE_INCORE;
170 }
171
172 /*
173  * Write <repo> to stdout
174  * If <attrname> is given, write attributes to <attrname>
175  * If <basename> is given, split attributes
176  */
177
178 #define REPODATAFILE_BLOCK 15
179
180 static void
181 write_info(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Repodata *info, const char *location)
182 {
183   Id h;
184   Queue keyq;
185
186   queue_init(&keyq);
187   if (repo_write_filtered(repo, fp, keyfilter, kfdata, &keyq) != 0)
188     {
189       fprintf(stderr, "repo_write failed\n");
190       exit(1);
191     }
192   h = repodata_new_handle(info);
193   if (keyq.count)
194     repodata_set_idarray(info, h, REPOSITORY_KEYS, &keyq);
195   queue_free(&keyq);
196   repodata_set_str(info, h, REPOSITORY_LOCATION, location);
197   repodata_add_flexarray(info, SOLVID_META, REPOSITORY_EXTERNAL, h);
198 }
199
200 void
201 tool_write(Repo *repo, const char *basename, const char *attrname)
202 {
203   Repodata *data;
204   Repodata *info = 0;
205   Repokey *key;
206   char **languages = 0;
207   int nlanguages = 0;
208   int i, j, k, l;
209   struct keyfilter_data kd;
210   Queue addedfileprovides;
211
212   memset(&kd, 0, sizeof(kd));
213   info = repo_add_repodata(repo, 0);
214   repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION);
215   queue_init(&addedfileprovides);
216   pool_addfileprovides_queue(repo->pool, &addedfileprovides, 0);
217   if (addedfileprovides.count)
218     {
219       kd.haveaddedfileprovides = 1;
220       repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides);
221     }
222   queue_free(&addedfileprovides);
223
224   pool_freeidhashes(repo->pool);        /* free some mem */
225
226   if (basename)
227     {
228       char fn[4096];
229       FILE *fp;
230       int has_DU = 0;
231       int has_FL = 0;
232
233       /* find languages and other info */
234       FOR_REPODATAS(repo, i, data)
235         {
236           for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++)
237             {
238               const char *keyname = pool_id2str(repo->pool, key->name);
239               if (key->name == SOLVABLE_DISKUSAGE)
240                 has_DU = 1;
241               if (key->name == SOLVABLE_FILELIST)
242                 has_FL = 1;
243               for (k = 0; languagetags[k] != 0; k++)
244                 if (!strncmp(keyname, languagetags[k], strlen(languagetags[k])))
245                   break;
246               if (!languagetags[k])
247                 continue;
248               l = strlen(languagetags[k]);
249               if (strlen(keyname + l) > 5)
250                 continue;
251               for (k = 0; k < nlanguages; k++)
252                 if (!strcmp(languages[k], keyname + l))
253                   break;
254               if (k < nlanguages)
255                 continue;
256               languages = solv_realloc2(languages, nlanguages + 1, sizeof(char *));
257               languages[nlanguages++] = strdup(keyname + l);
258             }
259         }
260       /* write language subfiles */
261       for (i = 0; i < nlanguages; i++)
262         {
263           sprintf(fn, "%s.%s.solv", basename, languages[i]);
264           if (!(fp = fopen(fn, "w")))
265             {
266               perror(fn);
267               exit(1);
268             }
269           write_info(repo, fp, keyfilter_language, languages[i], info, fn);
270           fclose(fp);
271           kd.haveexternal = 1;
272         }
273       /* write DU subfile */
274       if (has_DU)
275         {
276           sprintf(fn, "%s.DU.solv", basename);
277           if (!(fp = fopen(fn, "w")))
278             {
279               perror(fn);
280               exit(1);
281             }
282           write_info(repo, fp, keyfilter_DU, 0, info, fn);
283           fclose(fp);
284           kd.haveexternal = 1;
285         }
286       /* write filelist */
287       if (has_FL)
288         {
289           sprintf(fn, "%s.FL.solv", basename);
290           if (!(fp = fopen(fn, "w")))
291             {
292               perror(fn);
293               exit(1);
294             }
295           write_info(repo, fp, keyfilter_FL, 0, info, fn);
296           fclose(fp);
297           kd.haveexternal = 1;
298         }
299       /* write everything else */
300       sprintf(fn, "%s.solv", basename);
301       if (!(fp = fopen(fn, "w")))
302         {
303           perror(fn);
304           exit(1);
305         }
306       kd.languages = languages;
307       kd.nlanguages = nlanguages;
308       repodata_internalize(info);
309       if (repo_write_filtered(repo, fp, keyfilter_other, &kd, 0) != 0)
310         {
311           fprintf(stderr, "repo_write failed\n");
312           exit(1);
313         }
314       if (fclose(fp) != 0)
315         {
316           perror("fclose");
317           exit(1);
318         }
319       for (i = 0; i < nlanguages; i++)
320         free(languages[i]);
321       solv_free(languages);
322       repodata_free(info);
323     }
324   if (attrname)
325     {
326       FILE *fp;
327       test_separate = 1;
328       fp = fopen(attrname, "w");
329       write_info(repo, fp, keyfilter_attr, 0, info, attrname);
330       fclose(fp);
331       kd.haveexternal = 1;
332     }
333   repodata_internalize(info);
334   if (repo_write_filtered(repo, stdout, keyfilter_solv, &kd, 0) != 0)
335     {
336       fprintf(stderr, "repo_write failed\n");
337       exit(1);
338     }
339   repodata_free(info);
340 }