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