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