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