- use FOR_REPODATAS macro
[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, *keyarray = 0;
180   int i;
181
182   repo_write(repo, fp, keyfilter, kfdata, &keyarray);
183   h = repodata_new_handle(info);
184   if (keyarray)
185     {
186       for (i = 0; keyarray[i]; i++)
187         repodata_add_idarray(info, h, REPOSITORY_KEYS, keyarray[i]);
188     }
189   sat_free(keyarray);
190   repodata_set_str(info, h, REPOSITORY_LOCATION, location);
191   repodata_add_flexarray(info, SOLVID_META, REPOSITORY_EXTERNAL, h);
192 }
193
194 int
195 tool_write(Repo *repo, const char *basename, const char *attrname)
196 {
197   Repodata *data;
198   Repodata *info = 0;
199   Repokey *key;
200   char **languages = 0;
201   int nlanguages = 0;
202   int i, j, k, l;
203   Id *addedfileprovides = 0;
204   struct keyfilter_data kd;
205
206   memset(&kd, 0, sizeof(kd));
207   info = repo_add_repodata(repo, 0);
208   repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION);
209   pool_addfileprovides_ids(repo->pool, 0, &addedfileprovides);
210   if (addedfileprovides && *addedfileprovides)
211     {
212       kd.haveaddedfileprovides = 1;
213       for (i = 0; addedfileprovides[i]; i++)
214         repodata_add_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[i]);
215     }
216   sat_free(addedfileprovides);
217
218   pool_freeidhashes(repo->pool);        /* free some mem */
219
220   if (basename)
221     {
222       char fn[4096];
223       FILE *fp;
224       int has_DU = 0;
225       int has_FL = 0;
226
227       /* find languages and other info */
228       FOR_REPODATAS(repo, i, data)
229         {
230           for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++)
231             {
232               const char *keyname = pool_id2str(repo->pool, key->name);
233               if (key->name == SOLVABLE_DISKUSAGE)
234                 has_DU = 1;
235               if (key->name == SOLVABLE_FILELIST)
236                 has_FL = 1;
237               for (k = 0; languagetags[k] != 0; k++)
238                 if (!strncmp(keyname, languagetags[k], strlen(languagetags[k])))
239                   break;
240               if (!languagetags[k])
241                 continue;
242               l = strlen(languagetags[k]);
243               if (strlen(keyname + l) > 5)
244                 continue;
245               for (k = 0; k < nlanguages; k++)
246                 if (!strcmp(languages[k], keyname + l))
247                   break;
248               if (k < nlanguages)
249                 continue;
250               languages = sat_realloc2(languages, nlanguages + 1, sizeof(char *));
251               languages[nlanguages++] = strdup(keyname + l);
252             }
253         }
254       /* write language subfiles */
255       for (i = 0; i < nlanguages; i++)
256         {
257           sprintf(fn, "%s.%s.solv", basename, languages[i]);
258           if (!(fp = fopen(fn, "w")))
259             {
260               perror(fn);
261               exit(1);
262             }
263           write_info(repo, fp, keyfilter_language, languages[i], info, fn);
264           fclose(fp);
265           kd.haveexternal = 1;
266         }
267       /* write DU subfile */
268       if (has_DU)
269         {
270           sprintf(fn, "%s.DU.solv", basename);
271           if (!(fp = fopen(fn, "w")))
272             {
273               perror(fn);
274               exit(1);
275             }
276           write_info(repo, fp, keyfilter_DU, 0, info, fn);
277           fclose(fp);
278           kd.haveexternal = 1;
279         }
280       /* write filelist */
281       if (has_FL)
282         {
283           sprintf(fn, "%s.FL.solv", basename);
284           if (!(fp = fopen(fn, "w")))
285             {
286               perror(fn);
287               exit(1);
288             }
289           write_info(repo, fp, keyfilter_FL, 0, info, fn);
290           fclose(fp);
291           kd.haveexternal = 1;
292         }
293       /* write everything else */
294       sprintf(fn, "%s.solv", basename);
295       if (!(fp = fopen(fn, "w")))
296         {
297           perror(fn);
298           exit(1);
299         }
300       kd.languages = languages;
301       kd.nlanguages = nlanguages;
302       repodata_internalize(info);
303       repo_write(repo, fp, keyfilter_other, &kd, 0);
304       fclose(fp);
305       for (i = 0; i < nlanguages; i++)
306         free(languages[i]);
307       sat_free(languages);
308       repodata_free(info);
309       return 0;
310     }
311   if (attrname)
312     {
313       test_separate = 1;
314       FILE *fp = fopen(attrname, "w");
315       write_info(repo, fp, keyfilter_attr, 0, info, attrname);
316       fclose(fp);
317       kd.haveexternal = 1;
318     }
319   repodata_internalize(info);
320   repo_write(repo, stdout, keyfilter_solv, &kd, 0);
321   repodata_free(info);
322   return 0;
323 }