rename selection_make_deps to selection_make_matchdeps, add marker support
[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 #include "policy.h"
24 #include "poolvendor.h"
25 #include "chksum.h"
26
27 const char *
28 pool_solvable2str(Pool *pool, Solvable *s)
29 {
30   const char *n, *e, *a;
31   int nl, el, al;
32   char *p;
33   n = pool_id2str(pool, s->name);
34   e = pool_id2str(pool, s->evr);
35   /* XXX: may want to skip the epoch here */
36   a = pool_id2str(pool, s->arch);
37   nl = strlen(n);
38   el = strlen(e);
39   al = strlen(a);
40   if (pool->havedistepoch)
41     {
42       /* strip the distepoch from the evr */
43       const char *de = strrchr(e, '-');
44       if (de && (de = strchr(de, ':')) != 0)
45         el = de - e;
46     }
47   p = pool_alloctmpspace(pool, nl + el + al + 3);
48   strcpy(p, n);
49   if (el)
50     {
51       p[nl++] = '-';
52       strncpy(p + nl, e, el);
53     }
54   if (al)
55     {
56       p[nl + el] = pool->disttype == DISTTYPE_HAIKU ? '-' : '.';
57       strcpy(p + nl + el + 1, a);
58     }
59   return p;
60 }
61
62 Id
63 solvable_lookup_type(Solvable *s, Id keyname)
64 {
65   if (!s->repo)
66     return 0;
67   return repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname);
68 }
69
70 Id
71 solvable_lookup_id(Solvable *s, Id keyname)
72 {
73   if (!s->repo)
74     return 0;
75   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
76 }
77
78 int
79 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
80 {
81   if (!s->repo)
82     {
83       queue_empty(q);
84       return 0;
85     }
86   return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
87 }
88
89 int
90 solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
91 {
92   if (!s->repo)
93     {
94       queue_empty(q);
95       return 0;
96     }
97   return repo_lookup_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
98 }
99
100 static const char *
101 solvable_lookup_str_joinarray(Solvable *s, Id keyname, const char *joinstr)
102 {
103   Queue q;
104   Id qbuf[10];
105   char *str = 0;
106
107   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
108   if (solvable_lookup_idarray(s, keyname, &q) && q.count)
109     {
110       Pool *pool = s->repo->pool;
111       int i;
112       str = pool_tmpjoin(pool, pool_id2str(pool, q.elements[0]), 0, 0);
113       for (i = 1; i < q.count; i++)
114         str = pool_tmpappend(pool, str, joinstr, pool_id2str(pool, q.elements[i]));
115     }
116   queue_free(&q);
117   return str;
118 }
119
120 const char *
121 solvable_lookup_str(Solvable *s, Id keyname)
122 {
123   const char *str;
124   if (!s->repo)
125     return 0;
126   str = repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
127   if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP))
128     str = solvable_lookup_str_joinarray(s, keyname, ", ");
129   return str;
130 }
131
132 static const char *
133 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
134 {
135   Pool *pool;
136   const char *str, *basestr;
137   Id p, pp;
138   Solvable *s2;
139   int pass;
140
141   if (!s->repo)
142     return 0;
143   pool = s->repo->pool;
144   str = solvable_lookup_str(s, keyname);
145   if (str || keyname == basekeyname)
146     return str;
147   basestr = solvable_lookup_str(s, basekeyname);
148   if (!basestr)
149     return 0;
150   /* search for a solvable with same name and same base that has the
151    * translation */
152   if (!pool->whatprovides)
153     return usebase ? basestr : 0;
154   /* we do this in two passes, first same vendor, then all other vendors */
155   for (pass = 0; pass < 2; pass++)
156     {
157       FOR_PROVIDES(p, pp, s->name)
158         {
159           s2 = pool->solvables + p;
160           if (s2->name != s->name)
161             continue;
162           if ((s->vendor == s2->vendor) != (pass == 0))
163             continue;
164           str = solvable_lookup_str(s2, basekeyname);
165           if (!str || strcmp(str, basestr))
166             continue;
167           str = solvable_lookup_str(s2, keyname);
168           if (str)
169             return str;
170         }
171     }
172   return usebase ? basestr : 0;
173 }
174
175 const char *
176 solvable_lookup_str_poollang(Solvable *s, Id keyname)
177 {
178   Pool *pool;
179   int i, cols;
180   const char *str;
181   Id *row;
182
183   if (!s->repo)
184     return 0;
185   pool = s->repo->pool;
186   if (!pool->nlanguages)
187     return solvable_lookup_str(s, keyname);
188   cols = pool->nlanguages + 1;
189   if (!pool->languagecache)
190     {
191       pool->languagecache = solv_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
192       pool->languagecacheother = 0;
193     }
194   if (keyname >= ID_NUM_INTERNAL)
195     {
196       row = pool->languagecache + ID_NUM_INTERNAL * cols;
197       for (i = 0; i < pool->languagecacheother; i++, row += cols)
198         if (*row == keyname)
199           break;
200       if (i >= pool->languagecacheother)
201         {
202           pool->languagecache = solv_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
203           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
204           *row = keyname;
205         }
206     }
207   else
208     row = pool->languagecache + keyname * cols;
209   row++;        /* skip keyname */
210   for (i = 0; i < pool->nlanguages; i++, row++)
211     {
212       if (!*row)
213         *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
214       str = solvable_lookup_str_base(s, *row, keyname, 0);
215       if (str)
216         return str;
217     }
218   return solvable_lookup_str(s, keyname);
219 }
220
221 const char *
222 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
223 {
224   if (s->repo)
225     {
226       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
227       if (id)
228         return solvable_lookup_str_base(s, id, keyname, usebase);
229       if (!usebase)
230         return 0;
231     }
232   return solvable_lookup_str(s, keyname);
233 }
234
235 unsigned long long
236 solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound)
237 {
238   if (!s->repo)
239     return notfound;
240   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
241 }
242
243 unsigned int
244 solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound)
245 {
246   unsigned long long size;
247   if (!s->repo)
248     return notfound;
249   size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10);
250   return (unsigned int)((size + 1023) >> 10);
251 }
252
253 int
254 solvable_lookup_void(Solvable *s, Id keyname)
255 {
256   if (!s->repo)
257     return 0;
258   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
259 }
260
261 int
262 solvable_lookup_bool(Solvable *s, Id keyname)
263 {
264   if (!s->repo)
265     return 0;
266   /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
267   if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
268     return 1;
269   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
270 }
271
272 const unsigned char *
273 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
274 {
275   Repo *repo = s->repo;
276
277   if (!repo)
278     {
279       *typep = 0;
280       return 0;
281     }
282   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
283 }
284
285 const char *
286 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
287 {
288   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
289   return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0;
290 }
291
292 static inline const char *
293 evrid2vrstr(Pool *pool, Id evrid)
294 {
295   const char *p, *evr = pool_id2str(pool, evrid);
296   if (!evr)
297     return evr;
298   for (p = evr; *p >= '0' && *p <= '9'; p++)
299     ;
300   return p != evr && *p == ':' && p[1] ? p + 1 : evr;
301 }
302
303 const char *
304 solvable_lookup_location(Solvable *s, unsigned int *medianrp)
305 {
306   Pool *pool;
307   int l = 0;
308   char *loc;
309   const char *mediadir, *mediafile;
310
311   if (medianrp)
312     *medianrp = 0;
313   if (!s->repo)
314     return 0;
315   pool = s->repo->pool;
316   if (medianrp)
317     *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 0);
318   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
319     mediadir = pool_id2str(pool, s->arch);
320   else
321     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
322   if (mediadir)
323     l = strlen(mediadir) + 1;
324   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
325     {
326       const char *name, *evr, *arch;
327       name = pool_id2str(pool, s->name);
328       evr = evrid2vrstr(pool, s->evr);
329       arch = pool_id2str(pool, s->arch);
330       /* name-vr.arch.rpm */
331       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
332       if (mediadir)
333         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
334       else
335         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
336     }
337   else
338     {
339       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
340       if (!mediafile)
341         return 0;
342       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
343       if (mediadir)
344         sprintf(loc, "%s/%s", mediadir, mediafile);
345       else
346         strcpy(loc, mediafile);
347     }
348   return loc;
349 }
350
351 const char *
352 solvable_get_location(Solvable *s, unsigned int *medianrp)
353 {
354   const char *loc = solvable_lookup_location(s, medianrp);
355   if (medianrp && *medianrp == 0)
356     *medianrp = 1;      /* compat, to be removed */
357   return loc;
358 }
359
360 const char *
361 solvable_lookup_sourcepkg(Solvable *s)
362 {
363   Pool *pool;
364   const char *evr, *name;
365   Id archid;
366
367   if (!s->repo)
368     return 0;
369   pool = s->repo->pool;
370   if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
371     name = pool_id2str(pool, s->name);
372   else
373     name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
374   if (!name)
375     return 0;
376   archid = solvable_lookup_id(s, SOLVABLE_SOURCEARCH);
377   if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
378     evr = evrid2vrstr(pool, s->evr);
379   else
380     evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
381   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
382     {
383       char *str;
384       str = pool_tmpjoin(pool, name, evr ? "-" : 0, evr);
385       str = pool_tmpappend(pool, str, ".", pool_id2str(pool, archid));
386       return pool_tmpappend(pool, str, ".rpm", 0);
387     }
388   else 
389     return name;        /* FIXME */
390 }
391
392
393 /*****************************************************************************/
394
395 static inline Id dep2name(Pool *pool, Id dep)
396 {
397   while (ISRELDEP(dep))
398     {
399       Reldep *rd = rd = GETRELDEP(pool, dep);
400       dep = rd->name;
401     }
402   return dep;
403 }
404
405 static int providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con) 
406 {
407   Id p, pp;
408   Solvable *sn = pool->solvables + n; 
409
410   FOR_PROVIDES(p, pp, sn->name)
411     {    
412       Solvable *s = pool->solvables + p; 
413       if (s->name != sn->name || s->arch != sn->arch)
414         continue;
415       if (!MAPTST(installed, p))
416         continue;
417       if (pool_match_nevr(pool, pool->solvables + p, con))
418         continue;
419       return 1;         /* found installed package that doesn't conflict */
420     }    
421   return 0;
422 }
423
424 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *multiversionmap)
425 {
426   Id p, pp;
427   FOR_PROVIDES(p, pp, dep)
428     {
429       if (p == SYSTEMSOLVABLE)
430         return -1;
431       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
432         continue;
433       if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
434         if (providedbyinstalled_multiversion(pool, installed, p, dep))
435           continue;
436       if (MAPTST(installed, p))
437         return 1;
438     }
439   return 0;
440 }
441
442 /*
443  * solvable_trivial_installable_map - anwers is a solvable is installable
444  * without any other installs/deinstalls.
445  * The packages considered to be installed are provided via the
446  * installedmap bitmap. A additional "conflictsmap" bitmap providing
447  * information about the conflicts of the installed packages can be
448  * used for extra speed up. Provide a NULL pointer if you do not
449  * have this information.
450  * Both maps can be created with pool_create_state_maps() or
451  * solver_create_state_maps().
452  *
453  * returns:
454  * 1:  solvable is installable without any other package changes
455  * 0:  solvable is not installable
456  * -1: solvable is installable, but doesn't constrain any installed packages
457  */
458 int
459 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap)
460 {
461   Pool *pool = s->repo->pool;
462   Solvable *s2;
463   Id p, *dp;
464   Id *reqp, req;
465   Id *conp, con;
466   int r, interesting = 0;
467
468   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
469     return 0;
470   if (s->requires)
471     {
472       reqp = s->repo->idarraydata + s->requires;
473       while ((req = *reqp++) != 0)
474         {
475           if (req == SOLVABLE_PREREQMARKER)
476             continue;
477           r = providedbyinstalled(pool, installedmap, req, 0, 0);
478           if (!r)
479             return 0;
480           if (r > 0)
481             interesting = 1;
482         }
483     }
484   if (s->conflicts)
485     {
486       int ispatch = 0;
487
488       if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
489         ispatch = 1;
490       conp = s->repo->idarraydata + s->conflicts;
491       while ((con = *conp++) != 0)
492         {
493           if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
494             {
495               if (ispatch && solvable_is_irrelevant_patch(s, installedmap))
496                 return -1;
497               return 0;
498             }
499           if (!interesting && ISRELDEP(con))
500             {
501               con = dep2name(pool, con);
502               if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
503                 interesting = 1;
504             }
505         }
506       if (ispatch && interesting && solvable_is_irrelevant_patch(s, installedmap))
507         interesting = 0;
508     }
509 #if 0
510   if (s->repo)
511     {
512       Id *obsp, obs;
513       Repo *installed = 0;
514       if (s->obsoletes && s->repo != installed)
515         {
516           obsp = s->repo->idarraydata + s->obsoletes;
517           while ((obs = *obsp++) != 0)
518             {
519               if (providedbyinstalled(pool, installedmap, obs, 0, 0))
520                 return 0;
521             }
522         }
523       if (s->repo != installed)
524         {
525           Id pp;
526           FOR_PROVIDES(p, pp, s->name)
527             {
528               s2 = pool->solvables + p;
529               if (s2->repo == installed && s2->name == s->name)
530                 return 0;
531             }
532         }
533     }
534 #endif
535   if (!conflictsmap)
536     {
537       int i;
538
539       p = s - pool->solvables;
540       for (i = 1; i < pool->nsolvables; i++)
541         {
542           if (!MAPTST(installedmap, i))
543             continue;
544           s2 = pool->solvables + i;
545           if (!s2->conflicts)
546             continue;
547           conp = s2->repo->idarraydata + s2->conflicts;
548           while ((con = *conp++) != 0)
549             {
550               dp = pool_whatprovides_ptr(pool, con);
551               for (; *dp; dp++)
552                 if (*dp == p)
553                   return 0;
554             }
555         }
556      }
557   return interesting ? 1 : -1;
558 }
559
560 /*
561  * different interface for solvable_trivial_installable_map, where
562  * the information about the installed packages is provided
563  * by a queue.
564  */
565 int
566 solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap)
567 {
568   Pool *pool = s->repo->pool;
569   int i;
570   Id p;
571   Map installedmap;
572   int r;
573
574   map_init(&installedmap, pool->nsolvables);
575   for (i = 0; i < installed->count; i++)
576     {
577       p = installed->elements[i];
578       if (p > 0)                /* makes it work with decisionq */
579         MAPSET(&installedmap, p);
580     }
581   r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
582   map_free(&installedmap);
583   return r;
584 }
585
586 /*
587  * different interface for solvable_trivial_installable_map, where
588  * the information about the installed packages is provided
589  * by a repo containing the installed solvables.
590  */
591 int
592 solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *multiversionmap)
593 {
594   Pool *pool = s->repo->pool;
595   Id p;
596   Solvable *s2;
597   Map installedmap;
598   int r;
599
600   map_init(&installedmap, pool->nsolvables);
601   FOR_REPO_SOLVABLES(installed, p, s2)
602     MAPSET(&installedmap, p);
603   r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
604   map_free(&installedmap);
605   return r;
606 }
607
608 /* FIXME: this mirrors policy_illegal_vendorchange */
609 static int
610 pool_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2)
611 {
612   Id v1, v2; 
613   Id vendormask1, vendormask2;
614
615   if (pool->custom_vendorcheck)
616     return pool->custom_vendorcheck(pool, s1, s2);
617   /* treat a missing vendor as empty string */
618   v1 = s1->vendor ? s1->vendor : ID_EMPTY;
619   v2 = s2->vendor ? s2->vendor : ID_EMPTY;
620   if (v1 == v2) 
621     return 0;
622   vendormask1 = pool_vendor2mask(pool, v1);
623   if (!vendormask1)
624     return 1;   /* can't match */
625   vendormask2 = pool_vendor2mask(pool, v2);
626   if ((vendormask1 & vendormask2) != 0)
627     return 0;
628   return 1;     /* no class matches */
629 }
630
631 /* check if this patch is relevant according to the vendor. To bad that patches
632  * don't have a vendor, so we need to do some careful repo testing. */
633 int
634 solvable_is_irrelevant_patch(Solvable *s, Map *installedmap)
635 {
636   Pool *pool = s->repo->pool;
637   Id con, *conp;
638   int hadpatchpackage = 0;
639
640   if (!s->conflicts)
641     return 0;
642   conp = s->repo->idarraydata + s->conflicts;
643   while ((con = *conp++) != 0)
644     {
645       Reldep *rd;
646       Id p, pp, p2, pp2;
647       if (!ISRELDEP(con))
648         continue;
649       rd = GETRELDEP(pool, con);
650       if (rd->flags != REL_LT)
651         continue;
652       FOR_PROVIDES(p, pp, con)
653         {
654           Solvable *si;
655           if (!MAPTST(installedmap, p))
656             continue;
657           si = pool->solvables + p;
658           if (!pool_match_nevr(pool, si, con))
659             continue;
660           FOR_PROVIDES(p2, pp2, rd->name)
661             {
662               Solvable *s2 = pool->solvables + p2;
663               if (!pool_match_nevr(pool, s2, rd->name))
664                 continue;
665               if (pool_match_nevr(pool, s2, con))
666                 continue;       /* does not fulfill patch */
667               if (s2->repo == s->repo)
668                 {
669                   hadpatchpackage = 1;
670                   /* ok, we have a package from the patch repo that solves the conflict. check vendor */
671                   if (si->vendor == s2->vendor)
672                     return 0;
673                   if (!pool_illegal_vendorchange(pool, si, s2))
674                     return 0;
675                   /* vendor change was illegal, ignore conflict */
676                 }
677             }
678         }
679     }
680   /* if we didn't find a patchpackage don't claim that the patch is irrelevant */
681   if (!hadpatchpackage)
682     return 0;
683   return 1;
684 }
685
686 /*****************************************************************************/
687
688 /*
689  * Create maps containing the state of each solvable. Input is a "installed" queue,
690  * it contains all solvable ids that are considered to be installed.
691  * 
692  * The created maps can be used for solvable_trivial_installable_map(),
693  * pool_calc_duchanges(), pool_calc_installsizechange().
694  *
695  */
696 void
697 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
698 {
699   int i;
700   Solvable *s;
701   Id p, *dp;
702   Id *conp, con;
703
704   map_init(installedmap, pool->nsolvables);
705   if (conflictsmap)
706     map_init(conflictsmap, pool->nsolvables);
707   for (i = 0; i < installed->count; i++)
708     {
709       p = installed->elements[i];
710       if (p <= 0)       /* makes it work with decisionq */
711         continue;
712       MAPSET(installedmap, p);
713       if (!conflictsmap)
714         continue;
715       s = pool->solvables + p;
716       if (!s->conflicts)
717         continue;
718       conp = s->repo->idarraydata + s->conflicts;
719       while ((con = *conp++) != 0)
720         {
721           dp = pool_whatprovides_ptr(pool, con);
722           for (; *dp; dp++)
723             MAPSET(conflictsmap, *dp);
724         }
725     }
726 }
727
728 /* Tests if two solvables have identical content. Currently
729  * both solvables need to come from the same pool
730  */
731 int
732 solvable_identical(Solvable *s1, Solvable *s2)
733 {
734   unsigned int bt1, bt2;
735   Id rq1, rq2;
736   Id *reqp;
737
738   if (s1->name != s2->name)
739     return 0;
740   if (s1->arch != s2->arch)
741     return 0;
742   if (s1->evr != s2->evr)
743     return 0;
744   /* map missing vendor to empty string */
745   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
746     return 0;
747
748   /* looking good, try some fancier stuff */
749   /* might also look up the package checksum here */
750   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
751   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
752   if (bt1 && bt2)
753     {
754       if (bt1 != bt2)
755         return 0;
756     }
757   else
758     {
759       /* look at requires in a last attempt to find recompiled packages */
760       rq1 = rq2 = 0;
761       if (s1->requires)
762         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
763           rq1 ^= *reqp;
764       if (s2->requires)
765         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
766           rq2 ^= *reqp;
767       if (rq1 != rq2)
768          return 0;
769     }
770   return 1;
771 }
772
773 /* return the self provide dependency of a solvable */
774 Id
775 solvable_selfprovidedep(Solvable *s)
776 {
777   Pool *pool;
778   Reldep *rd;
779   Id prov, *provp;
780
781   if (!s->repo)
782     return s->name;
783   pool = s->repo->pool;
784   if (s->provides)
785     {
786       provp = s->repo->idarraydata + s->provides;
787       while ((prov = *provp++) != 0)
788         {
789           if (!ISRELDEP(prov))
790             continue;
791           rd = GETRELDEP(pool, prov);
792           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
793             return prov;
794         }
795     }
796   return pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
797 }
798
799 /* setter functions, simply call the repo variants */
800 void
801 solvable_set_id(Solvable *s, Id keyname, Id id)
802 {
803   repo_set_id(s->repo, s - s->repo->pool->solvables, keyname, id);
804 }
805
806 void
807 solvable_set_num(Solvable *s, Id keyname, unsigned long long num)
808 {
809   repo_set_num(s->repo, s - s->repo->pool->solvables, keyname, num);
810 }
811
812 void
813 solvable_set_str(Solvable *s, Id keyname, const char *str)
814 {
815   repo_set_str(s->repo, s - s->repo->pool->solvables, keyname, str);
816 }
817
818 void
819 solvable_set_poolstr(Solvable *s, Id keyname, const char *str)
820 {
821   repo_set_poolstr(s->repo, s - s->repo->pool->solvables, keyname, str);
822 }
823
824 void
825 solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str)
826 {
827   repo_add_poolstr_array(s->repo, s - s->repo->pool->solvables, keyname, str);
828 }
829
830 void
831 solvable_add_idarray(Solvable *s, Id keyname, Id id)
832 {
833   repo_add_idarray(s->repo, s - s->repo->pool->solvables, keyname, id);
834 }
835
836 void
837 solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker)
838 {
839   repo_add_deparray(s->repo, s - s->repo->pool->solvables, keyname, dep, marker);
840 }
841
842 void
843 solvable_set_idarray(Solvable *s, Id keyname, Queue *q)
844 {
845   repo_set_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
846 }
847
848 void
849 solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
850 {
851   repo_set_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
852 }
853
854 void
855 solvable_unset(Solvable *s, Id keyname)
856 {
857   repo_unset(s->repo, s - s->repo->pool->solvables, keyname);
858 }
859
860 /* return true if a dependency intersects dep in the keyname array */
861 int
862 solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker)
863 {
864   int i;
865   Pool *pool = s->repo->pool;
866   Queue q;
867   queue_init(&q);
868   solvable_lookup_deparray(s, keyname, &q, marker);
869   for (i = 0; i < q.count; i++)
870     if (pool_match_dep(pool, q.elements[i], dep))
871       break;
872   i = i == q.count ? 0 : 1;
873   queue_free(&q);
874   return i;
875 }