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