- get missing translations from other solvables
[platform/upstream/libsolv.git] / src / solvable.c
1 /*
2  * Copyright (c) 2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solvable.c
10  *
11  * set/retrieve data from solvables
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <unistd.h>
18 #include <string.h>
19
20 #include "pool.h"
21 #include "repo.h"
22 #include "util.h"
23
24 const char *
25 solvable2str(Pool *pool, Solvable *s)
26 {
27   const char *n, *e, *a;
28   char *p;
29   n = id2str(pool, s->name);
30   e = id2str(pool, s->evr);
31   a = id2str(pool, s->arch);
32   p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
33   sprintf(p, "%s-%s.%s", n, e, a);
34   return p;
35 }
36
37 Id
38 solvable_lookup_id(Solvable *s, Id keyname)
39 {
40   if (!s->repo)
41     return 0;
42   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
43 }
44
45 int
46 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
47 {
48   Dataiterator di;
49   int found = 0;
50
51   queue_empty(q);
52   if (!s->repo)
53     return 0;
54   dataiterator_init(&di, s->repo->pool, s->repo, s - s->repo->pool->solvables, keyname, 0, SEARCH_ARRAYSENTINEL);
55   while (dataiterator_step(&di))
56     {
57       if (di.key->type != REPOKEY_TYPE_IDARRAY && di.key->type != REPOKEY_TYPE_REL_IDARRAY)
58         continue;
59       found = 1;
60       if (di.kv.eof)
61         break;
62       queue_push(q, di.kv.id);
63     }
64   dataiterator_free(&di);
65   return found;
66 }
67
68 const char *
69 solvable_lookup_str(Solvable *s, Id keyname)
70 {
71   if (!s->repo)
72     return 0;
73   return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
74 }
75
76 const char *
77 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname)
78 {
79   Pool *pool;
80   const char *str, *basestr;
81   Id p, pp;
82   Solvable *s2;
83   int pass;
84
85   if (!s->repo)
86     return 0;
87   pool = s->repo->pool;
88   str = solvable_lookup_str(s, keyname);
89   if (str || keyname == basekeyname)
90     return str;
91   basestr = solvable_lookup_str(s, basekeyname);
92   if (!basestr)
93     return 0;
94   /* search for a solvable with same name and same base that has the
95    * translation */
96   if (!pool->whatprovides)
97     return 0;
98   /* we do this in two passes, first same vendor, then all other vendors */
99   for (pass = 0; pass < 2; pass++)
100     {
101       FOR_PROVIDES(p, pp, s->name)
102         {
103           s2 = pool->solvables + p;
104           if (s2->name != s->name)
105             continue;
106           if ((s->vendor == s2->vendor) != (pass == 0))
107             continue;
108           str = solvable_lookup_str(s2, basekeyname);
109           if (!str || strcmp(str, basestr))
110             continue;
111           str = solvable_lookup_str(s2, keyname);
112           if (str)
113             return str;
114         }
115     }
116   return 0;
117 }
118
119 const char *
120 solvable_lookup_str_poollang(Solvable *s, Id keyname)
121 {
122   Pool *pool;
123   int i, cols;
124   const char *str;
125   Id *row;
126
127   if (!s->repo)
128     return 0;
129   pool = s->repo->pool;
130   if (!pool->nlanguages)
131     return solvable_lookup_str(s, keyname);
132   cols = pool->nlanguages + 1;
133   if (!pool->languagecache)
134     {
135       pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
136       pool->languagecacheother = 0;
137     }
138   if (keyname >= ID_NUM_INTERNAL)
139     {
140       row = pool->languagecache + ID_NUM_INTERNAL * cols;
141       for (i = 0; i < pool->languagecacheother; i++, row += cols)
142         if (*row == keyname)
143           break;
144       if (i >= pool->languagecacheother)
145         {
146           pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
147           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
148           *row = keyname;
149         }
150     }
151   else
152     row = pool->languagecache + keyname * cols;
153   row++;        /* skip keyname */
154   for (i = 0; i < pool->nlanguages; i++, row++)
155     {
156       if (!*row)
157         {
158           char *p;
159           const char *kn;
160
161           kn = id2str(pool, keyname);
162           p = sat_malloc(strlen(kn) + strlen(pool->languages[i]) + 2);
163           sprintf(p, "%s:%s", kn, pool->languages[i]);
164           *row = str2id(pool, p, 1);
165           sat_free(p);
166         }
167       str = solvable_lookup_str_base(s, *row, keyname);
168       if (str)
169         return str;
170     }
171   return solvable_lookup_str(s, keyname);
172 }
173
174 const char *
175 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang)
176 {
177   if (s->repo)
178     {
179       const char *str;
180       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
181       if (id && (str = solvable_lookup_str_base(s, id, keyname)) != 0)
182         return str;
183     }
184   return solvable_lookup_str(s, keyname);
185 }
186
187 unsigned int
188 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
189 {
190   if (!s->repo)
191     return 0;
192   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
193 }
194
195 int
196 solvable_lookup_void(Solvable *s, Id keyname)
197 {
198   if (!s->repo)
199     return 0;
200   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
201 }
202
203 int
204 solvable_lookup_bool(Solvable *s, Id keyname)
205 {
206   Repo *repo = s->repo;
207   Pool *pool;
208   Repodata *data;
209   int i, j, n;
210
211   if (!repo)
212     return 0;
213   pool = repo->pool;
214   n = s - pool->solvables;
215   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
216     {
217       if (n < data->start || n >= data->end)
218         continue;
219       /* there are two ways of storing a bool, as num == 1 or void */
220       for (j = 1; j < data->nkeys; j++)
221         {
222           if (data->keys[j].name == keyname
223               && (data->keys[j].type == REPOKEY_TYPE_U32
224                   || data->keys[j].type == REPOKEY_TYPE_NUM
225                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT
226                   || data->keys[j].type == REPOKEY_TYPE_VOID))
227             {
228               unsigned int value;
229               if (repodata_lookup_num(data, n, keyname, &value))
230                 return value == 1;
231               if (repodata_lookup_void(data, n, keyname))
232                 return 1;
233             }
234         }
235     }
236   return 0;
237 }
238
239 const unsigned char *
240 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
241 {
242   Repo *repo = s->repo;
243
244   if (!repo)
245     {
246       *typep = 0;
247       return 0;
248     }
249   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
250 }
251
252 const char *
253 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
254 {
255   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
256   /* we need the repodata just as a reference for a pool */
257   return chk ? repodata_chk2str(s->repo->repodata, *typep, chk) : 0;
258 }
259
260 static inline const char *
261 evrid2vrstr(Pool *pool, Id evrid)
262 {
263   const char *p, *evr = id2str(pool, evrid);
264   if (!evr)
265     return evr;
266   for (p = evr; *p >= '0' && *p <= '9'; p++)
267     ;
268   return p != evr && *p == ':' ? p + 1 : evr;
269 }
270
271 char *
272 solvable_get_location(Solvable *s, unsigned int *medianrp)
273 {
274   Pool *pool;
275   int l = 0;
276   char *loc;
277   const char *mediadir, *mediafile;
278
279   *medianrp = 0;
280   if (!s->repo)
281     return 0;
282   pool = s->repo->pool;
283   *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
284   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
285     mediadir = id2str(pool, s->arch);
286   else
287     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
288   if (mediadir)
289     l = strlen(mediadir) + 1;
290   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
291     {
292       const char *name, *evr, *arch;
293       name = id2str(pool, s->name);
294       evr = evrid2vrstr(pool, s->evr);
295       arch = id2str(pool, s->arch);
296       /* name-vr.arch.rpm */
297       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
298       if (mediadir)
299         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
300       else
301         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
302     }
303   else
304     {
305       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
306       if (!mediafile)
307         return 0;
308       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
309       if (mediadir)
310         sprintf(loc, "%s/%s", mediadir, mediafile);
311       else
312         strcpy(loc, mediafile);
313     }
314   return loc;
315 }
316
317 /*****************************************************************************/
318
319 static inline Id dep2name(Pool *pool, Id dep)
320 {
321   while (ISRELDEP(dep))
322     {
323       Reldep *rd = rd = GETRELDEP(pool, dep);
324       dep = rd->name;
325     }
326   return dep;
327 }
328
329 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
330 {
331   Id p, pp;
332   FOR_PROVIDES(p, pp, dep)
333     {
334       if (p == SYSTEMSOLVABLE)
335         return -1;
336       if (MAPTST(installed, p))
337         return 1;
338     }
339   return 0;
340 }
341
342 /*
343  * solvable_trivial_installable_map - anwers is a solvable is installable
344  * without any other installs/deinstalls.
345  * The packages considered to be installed are provided via the
346  * installedmap bitmap. A additional "conflictsmap" bitmap providing
347  * information about the conflicts of the installed packages can be
348  * used for extra speed up. Provide a NULL pointer if you do not
349  * have this information.
350  * Both maps can be created with pool_create_state_maps() or
351  * solver_create_state_maps().
352  *
353  * returns:
354  * 1:  solvable is installable without any other package changes
355  * 0:  solvable is not installable
356  * -1: solvable is installable, but doesn't constrain any installed packages
357  */
358 int
359 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
360 {
361   Pool *pool = s->repo->pool;
362   Solvable *s2;
363   Id p, pp, *dp;
364   Id *reqp, req;
365   Id *conp, con;
366   Id *obsp, obs;
367   int r, interesting = 0;
368
369   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
370     return 0;
371   if (s->requires)
372     {
373       reqp = s->repo->idarraydata + s->requires;
374       while ((req = *reqp++) != 0)
375         {
376           if (req == SOLVABLE_PREREQMARKER)
377             continue;
378           r = providedbyinstalled(pool, installedmap, req);
379           if (!r)
380             return 0;
381           if (r > 0)
382             interesting = 1;
383         }
384     }
385   if (s->conflicts)
386     {
387       conp = s->repo->idarraydata + s->conflicts;
388       while ((con = *conp++) != 0)
389         {
390           if (providedbyinstalled(pool, installedmap, con))
391             return 0;
392           if (!interesting && ISRELDEP(con))
393             {
394               con = dep2name(pool, con);
395               if (providedbyinstalled(pool, installedmap, con))
396                 interesting = 1;
397             }
398         }
399     }
400   if (s->repo)
401     {
402       Repo *installed = 0;
403       if (s->obsoletes && s->repo != installed)
404         {
405           obsp = s->repo->idarraydata + s->obsoletes;
406           while ((obs = *obsp++) != 0)
407             {
408               if (providedbyinstalled(pool, installedmap, obs))
409                 return 0;
410             }
411         }
412       if (s->repo != installed)
413         {
414           FOR_PROVIDES(p, pp, s->name)
415             {
416               s2 = pool->solvables + p;
417               if (s2->repo == installed && s2->name == s->name)
418                 return 0;
419             }
420         }
421     }
422   if (!conflictsmap)
423     {
424       int i;
425
426       p = s - pool->solvables;
427       for (i = 1; i < pool->nsolvables; i++)
428         {
429           if (!MAPTST(installedmap, i))
430             continue;
431           s2 = pool->solvables + i;
432           if (!s2->conflicts)
433             continue;
434           conp = s2->repo->idarraydata + s2->conflicts;
435           while ((con = *conp++) != 0)
436             {
437               dp = pool_whatprovides_ptr(pool, con);
438               for (; *dp; dp++)
439                 if (*dp == p)
440                   return 0;
441             }
442         }
443      }
444   return interesting ? 1 : -1;
445 }
446
447 /*
448  * different interface for solvable_trivial_installable_map, where
449  * the information about the installed packages is provided
450  * by a queue.
451  */
452 int
453 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
454 {
455   Pool *pool = s->repo->pool;
456   int i;
457   Id p;
458   Map installedmap;
459   int r;
460
461   map_init(&installedmap, pool->nsolvables);
462   for (i = 0; i < installed->count; i++)
463     {
464       p = installed->elements[i];
465       if (p > 0)                /* makes it work with decisionq */
466         MAPSET(&installedmap, p);
467     }
468   r = solvable_trivial_installable_map(s, &installedmap, 0);
469   map_free(&installedmap);
470   return r;
471 }
472
473 /*
474  * different interface for solvable_trivial_installable_map, where
475  * the information about the installed packages is provided
476  * by a repo containing the installed solvables.
477  */
478 int
479 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
480 {
481   Pool *pool = s->repo->pool;
482   Id p;
483   Solvable *s2;
484   Map installedmap;
485   int r;
486
487   map_init(&installedmap, pool->nsolvables);
488   FOR_REPO_SOLVABLES(installed, p, s2)
489     MAPSET(&installedmap, p);
490   r = solvable_trivial_installable_map(s, &installedmap, 0);
491   map_free(&installedmap);
492   return r;
493 }
494
495
496 /*****************************************************************************/
497
498 /*
499  * Create maps containing the state of each solvable. Input is a "installed" queue,
500  * it contains all solvable ids that are considered to be installed.
501  * 
502  * The created maps can be used for solvable_trivial_installable_map(),
503  * pool_calc_duchanges(), pool_calc_installsizechange().
504  *
505  */
506 void
507 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
508 {
509   int i;
510   Solvable *s;
511   Id p, *dp;
512   Id *conp, con;
513
514   map_init(installedmap, pool->nsolvables);
515   if (conflictsmap)
516     map_init(conflictsmap, pool->nsolvables);
517   for (i = 0; i < installed->count; i++)
518     {
519       p = installed->elements[i];
520       if (p <= 0)       /* makes it work with decisionq */
521         continue;
522       MAPSET(installedmap, p);
523       if (!conflictsmap)
524         continue;
525       s = pool->solvables + p;
526       if (!s->conflicts)
527         continue;
528       conp = s->repo->idarraydata + s->conflicts;
529       while ((con = *conp++) != 0)
530         {
531           dp = pool_whatprovides_ptr(pool, con);
532           for (; *dp; dp++)
533             MAPSET(conflictsmap, *dp);
534         }
535     }
536 }
537
538 /* Tests if two solvables have identical content. Currently
539  * both solvables need to come from the same pool */
540
541 int
542 solvable_identical(Solvable *s1, Solvable *s2)
543 {
544   unsigned int bt1, bt2;
545   Id rq1, rq2;
546   Id *reqp;
547
548   if (s1->name != s2->name)
549     return 0;
550   if (s1->arch != s2->arch)
551     return 0;
552   if (s1->evr != s2->evr)
553     return 0;
554   /* map missing vendor to empty string */
555   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
556     return 0;
557
558   /* looking good, try some fancier stuff */
559   /* might also look up the package checksum here */
560   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
561   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
562   if (bt1 && bt2)
563     {
564       if (bt1 != bt2)
565         return 0;
566     }
567   else
568     {
569       /* look at requires in a last attempt to find recompiled packages */
570       rq1 = rq2 = 0;
571       if (s1->requires)
572         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
573           rq1 ^= *reqp++;
574       if (s2->requires)
575         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
576           rq2 ^= *reqp++;
577       if (rq1 != rq2)
578          return 0;
579     }
580   return 1;
581 }
582
583 /* return the self provide dependency of a solvable */
584 Id
585 solvable_selfprovidedep(Solvable *s)
586 {
587   Pool *pool;
588   Reldep *rd;
589   Id prov, *provp;
590
591   if (!s->repo)
592     return s->name;
593   pool = s->repo->pool;
594   if (s->provides)
595     {
596       provp = s->repo->idarraydata + s->provides;
597       while ((prov = *provp++) != 0)
598         {
599           if (!ISRELDEP(prov))
600             continue;
601           rd = GETRELDEP(pool, prov);
602           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
603             return prov;
604         }
605     }
606   return rel2id(pool, s->name, s->evr, REL_EQ, 1);
607 }