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