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