Implement a lookupLocation function. The location is stored in a clever
[platform/upstream/libzypp.git] / zypp / sat / Solvable.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/sat/Solvable.cc
10  *
11 */
12 #include <iostream>
13
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Gettext.h"
16 #include "zypp/base/Exception.h"
17
18 #include "zypp/sat/detail/PoolImpl.h"
19 #include "zypp/sat/Solvable.h"
20 #include "zypp/sat/Repo.h"
21
22 using std::endl;
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 { /////////////////////////////////////////////////////////////////
27   ///////////////////////////////////////////////////////////////////
28   namespace sat
29   { /////////////////////////////////////////////////////////////////
30
31     const Solvable Solvable::nosolvable;
32
33     /////////////////////////////////////////////////////////////////
34
35     ::_Solvable * Solvable::get() const
36     { return myPool().getSolvable( _id ); }
37
38 #define NO_SOLVABLE_RETURN( VAL ) \
39     ::_Solvable * _solvable( get() ); \
40     if ( ! _solvable ) return VAL
41
42     Solvable Solvable::nextInPool() const
43     { return Solvable( myPool().getNextId( _id ) ); }
44
45     Solvable Solvable::nextInRepo() const
46     {
47       NO_SOLVABLE_RETURN( nosolvable );
48       for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
49       {
50         ::_Solvable * nextS( myPool().getSolvable( next ) );
51         if ( nextS && nextS->repo == _solvable->repo )
52         {
53           return Solvable( next );
54         }
55       }
56       return nosolvable;
57     }
58
59     Repo Solvable::repo() const
60     {
61       NO_SOLVABLE_RETURN( Repo::norepo );
62       return Repo( _solvable->repo );
63     }
64
65     bool Solvable::isSystem() const
66     { return repo().isSystemRepo(); }
67
68     IdString Solvable::ident() const
69     {
70       NO_SOLVABLE_RETURN( IdString() );
71       return IdString( _solvable->name );
72     }
73
74     std::string Solvable::lookupStrAttribute( const SolvAttr &attr ) const
75     {
76       const char *s = repo_lookup_str(this->get(), attr.idStr().id());
77       return s ? s : std::string();
78     }
79
80     unsigned Solvable::lookupNumAttribute( const SolvAttr &attr ) const
81     {
82       return repo_lookup_num(this->get(), attr.idStr().id());
83     }
84
85     struct LocCallback
86     {
87       unsigned medianr;
88       const char *mediadir;
89       const char *mediafile;
90       int trivial;
91     };
92
93     static int
94     location_cb (void *vcbdata, ::Solvable *s, ::Repodata *data, ::Repokey *key, ::KeyValue *kv)
95     {
96       LocCallback *lc = (LocCallback *)vcbdata;
97       switch (key->type)
98       {
99         case TYPE_ID:
100           if (key->name == SolvAttr::mediadir.idStr().id())
101           {
102             if (data->localpool)
103               lc->mediadir = stringpool_id2str(&data->spool, kv->id);
104             else
105               lc->mediadir = id2str(data->repo->pool, kv->id);
106           }
107           break;
108         case TYPE_STR:
109           if (key->name == SolvAttr::mediafile.idStr().id())
110             lc->mediafile = kv->str;
111           break;
112         case TYPE_VOID:
113           if (key->name == SolvAttr::mediafile.idStr().id())
114             lc->trivial = 1;
115           break;
116         case TYPE_CONSTANT:
117           if (key->name == SolvAttr::medianr.idStr().id())
118             lc->medianr = kv->num;
119           break;
120       }
121       /* continue walking */
122       return 0;
123     }
124
125     std::string Solvable::lookupLocation(unsigned &medianr) const
126     {
127       NO_SOLVABLE_RETURN( std::string() );
128       ::Repo *repo = _solvable->repo;
129       ::Pool *pool = repo->pool;
130       Id sid = _solvable - pool->solvables;
131       ::Repodata *data;
132       unsigned i;
133       LocCallback lc;
134       lc.medianr = 1;
135       lc.mediadir = 0;
136       lc.mediafile = 0;
137       lc.trivial = 0;
138       for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
139       {
140         if (data->state == REPODATA_STUB || data->state == REPODATA_ERROR)
141           continue;
142         if (sid < data->start || sid >= data->end)
143           continue;
144         repodata_search(data, sid - data->start, 0, location_cb, &lc);
145       }
146       medianr = lc.medianr;
147       std::string ret;
148       if (lc.mediadir)
149         ret += std::string( lc.mediadir ) + "/";
150       if (!lc.trivial)
151         {
152           if (lc.mediafile)
153             ret += lc.mediafile;
154           return ret;
155         }
156       /* Trivial means that we can construct the rpm name from our
157          solvable data, as name-evr.arch.rpm .  */
158       /* If we haven't seen an explicit dirname, then prepend the arch as
159          directory.  */
160       if (!lc.mediadir)
161         ret += IdString(_solvable->arch).asString() + "/";
162       ret += IdString(_solvable->name).asString();
163       ret += '-';
164       ret += IdString(_solvable->evr).asString();
165       ret += '.';
166       ret += IdString(_solvable->arch).asString();
167       ret += ".rpm";
168       return ret;
169     }
170
171     ResKind Solvable::kind() const
172     {
173       NO_SOLVABLE_RETURN( ResKind() );
174       // detect srcpackages by 'arch'
175       switch ( _solvable->arch )
176       {
177         case ARCH_SRC:
178         case ARCH_NOSRC:
179           return ResKind::srcpackage;
180           break;
181       }
182
183       const char * ident = IdString( _solvable->name ).c_str();
184       const char * sep = ::strchr( ident, ':' );
185
186       // no ':' in package names (hopefully)
187       if ( ! sep )
188         return ResKind::package;
189
190       // quick check for well known kinds
191       if ( sep-ident >= 4 )
192       {
193         switch ( ident[3] )
194         {
195 #define OUTS(K,S) if ( ::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
196           //             ----v
197           case 'c': OUTS( patch, 5 );       break;
198           case 'd': OUTS( product, 7 );     break;
199           case 'i': OUTS( script, 6 );      break;
200           case 'k': OUTS( package, 7 );     break;
201           case 'm': OUTS( atom, 4 );        break;
202           case 'p': OUTS( srcpackage, 10 ); break;
203           case 's': OUTS( message, 7 );     break;
204           case 't': OUTS( pattern, 7 );     break;
205 #undef OUTS
206         }
207       }
208
209       // an unknown kind
210       return ResKind( std::string( ident, sep-ident ) );
211     }
212
213     bool Solvable::isKind( const ResKind & kind_r ) const
214     {
215       NO_SOLVABLE_RETURN( false );
216
217       // detect srcpackages by 'arch'
218       if ( kind_r == ResKind::srcpackage )
219       {
220         return( _solvable->arch == ARCH_SRC || _solvable->arch == ARCH_NOSRC );
221       }
222
223       // no ':' in package names (hopefully)
224       const char * ident = IdString( _solvable->name ).c_str();
225       if ( kind_r == ResKind::package )
226       {
227         return( ::strchr( ident, ':' ) == 0 );
228       }
229
230       // look for a 'kind:' prefix
231       const char * kind = kind_r.c_str();
232       unsigned     ksize = ::strlen( kind );
233       return( ::strncmp( ident, kind, ksize ) == 0
234               && ident[ksize] == ':' );
235     }
236
237     std::string Solvable::name() const
238     {
239       NO_SOLVABLE_RETURN( std::string() );
240       const char * ident = IdString( _solvable->name ).c_str();
241       const char * sep = ::strchr( ident, ':' );
242       return( sep ? sep+1 : ident );
243     }
244
245     Edition Solvable::edition() const
246     {
247       NO_SOLVABLE_RETURN( Edition() );
248       return Edition( _solvable->evr );
249     }
250
251     Arch Solvable::arch() const
252     {
253       NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
254       switch ( _solvable->arch )
255       {
256         case ARCH_SRC:
257         case ARCH_NOSRC:
258           return Arch_noarch; //ArchId( ARCH_NOARCH );
259           break;
260       }
261       return Arch( IdString(_solvable->arch).asString() );
262       //return ArchId( _solvable->arch );
263     }
264
265     IdString Solvable::vendor() const
266     {
267       NO_SOLVABLE_RETURN( IdString() );
268       return IdString( _solvable->vendor );
269     }
270
271     Capabilities Solvable::operator[]( Dep which_r ) const
272     {
273       NO_SOLVABLE_RETURN( Capabilities() );
274       ::Offset offs = 0;
275       switch( which_r.inSwitch() )
276       {
277         case Dep::PROVIDES_e:    offs = _solvable->provides;    break;
278         case Dep::REQUIRES_e:    offs = _solvable->requires;    break;
279         case Dep::CONFLICTS_e:   offs = _solvable->conflicts;   break;
280         case Dep::OBSOLETES_e:   offs = _solvable->obsoletes;   break;
281         case Dep::RECOMMENDS_e:  offs = _solvable->recommends;  break;
282         case Dep::SUGGESTS_e:    offs = _solvable->suggests;    break;
283         case Dep::FRESHENS_e:    offs = _solvable->freshens;    break;
284         case Dep::ENHANCES_e:    offs = _solvable->enhances;    break;
285         case Dep::SUPPLEMENTS_e: offs = _solvable->supplements; break;
286
287         case Dep::PREREQUIRES_e:
288           // prerequires are a subset of requires
289           if ( (offs = _solvable->requires) )
290             return Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker );
291           else
292             return Capabilities();
293           break;
294       }
295
296       return offs ? Capabilities( _solvable->repo->idarraydata + offs )
297                   : Capabilities();
298     }
299
300     /******************************************************************
301     **
302     **  FUNCTION NAME : operator<<
303     **  FUNCTION TYPE : std::ostream &
304     */
305     std::ostream & operator<<( std::ostream & str, const Solvable & obj )
306     {
307       if ( ! obj )
308         return str << "sat::solvable()";
309
310       return str << "sat::solvable(" << obj.id() << "|"
311           << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
312           << '-' << obj.edition() << '.' << obj.arch() << "){"
313           << obj.repo().name() << "}";
314     }
315
316     /******************************************************************
317     **
318     **  FUNCTION NAME : dumpOn
319     **  FUNCTION TYPE : std::ostream &
320     */
321     std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
322     {
323       str << obj;
324       if ( obj )
325       {
326 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
327         OUTS(PROVIDES);
328         OUTS(PREREQUIRES);
329         OUTS(REQUIRES);
330         OUTS(CONFLICTS);
331         OUTS(OBSOLETES);
332         OUTS(RECOMMENDS);
333         OUTS(SUGGESTS);
334         OUTS(FRESHENS);
335         OUTS(ENHANCES);
336         OUTS(SUPPLEMENTS);
337 #undef OUTS
338       }
339       return str;
340     }
341
342     /////////////////////////////////////////////////////////////////
343   } // namespace sat
344   ///////////////////////////////////////////////////////////////////
345   /////////////////////////////////////////////////////////////////
346 } // namespace zypp
347 ///////////////////////////////////////////////////////////////////