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