Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / Repository.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/sat/Repository.cc
10  *
11 */
12 #include <climits>
13 #include <iostream>
14
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/Gettext.h"
17 #include "zypp/base/Exception.h"
18 #include "zypp/base/Xml.h"
19
20 #include "zypp/AutoDispose.h"
21 #include "zypp/Pathname.h"
22
23 #include "zypp/sat/detail/PoolImpl.h"
24 #include "zypp/Repository.h"
25 #include "zypp/ResPool.h"
26 #include "zypp/Product.h"
27 #include "zypp/sat/Pool.h"
28
29 using std::endl;
30
31 ///////////////////////////////////////////////////////////////////
32 namespace zypp
33 { /////////////////////////////////////////////////////////////////
34
35     const Repository Repository::noRepository;
36
37     const std::string & Repository::systemRepoAlias()
38     { return sat::detail::PoolImpl::systemRepoAlias(); }
39
40     /////////////////////////////////////////////////////////////////
41
42     ::_Repo * Repository::get() const
43     { return myPool().getRepo( _id ); }
44
45 #define NO_REPOSITORY_RETURN( VAL ) \
46     ::_Repo * _repo( get() ); \
47     if ( ! _repo ) return VAL
48
49 #define NO_REPOSITORY_THROW( VAL ) \
50     ::_Repo * _repo( get() ); \
51     if ( ! _repo ) ZYPP_THROW( VAL )
52
53     bool Repository::isSystemRepo() const
54     {
55         NO_REPOSITORY_RETURN( false );
56         return myPool().isSystemRepo( _repo );
57     }
58
59     std::string Repository::alias() const
60     {
61       NO_REPOSITORY_RETURN( std::string() );
62       if ( ! _repo->name )
63         return std::string();
64       return _repo->name;
65     }
66
67     std::string Repository::name() const
68     { return info().name(); }
69
70     std::string Repository::label() const
71     { return info().label(); }
72
73     int Repository::satInternalPriority() const
74     {
75       NO_REPOSITORY_RETURN( INT_MIN );
76       return _repo->priority;
77     }
78
79     int Repository::satInternalSubPriority() const
80     {
81       NO_REPOSITORY_RETURN( INT_MIN );
82       return _repo->subpriority;
83     }
84
85     Repository::ContentRevision Repository::contentRevision() const
86     {
87       NO_REPOSITORY_RETURN( ContentRevision() );
88       sat::LookupRepoAttr q( sat::SolvAttr::repositoryRevision, *this );
89       return q.empty() ? std::string() : q.begin().asString();
90     }
91
92     Repository::ContentIdentifier Repository::contentIdentifier() const
93     {
94       NO_REPOSITORY_RETURN( ContentIdentifier() );
95       sat::LookupRepoAttr q( sat::SolvAttr::repositoryRepoid, *this );
96       return q.empty() ? std::string() : q.begin().asString();
97     }
98
99     bool Repository::hasContentIdentifier( const ContentIdentifier & id_r ) const
100     {
101       NO_REPOSITORY_RETURN( false );
102       sat::LookupRepoAttr q( sat::SolvAttr::repositoryRepoid, *this );
103       for_( it, q.begin(), q.end() )
104         if ( it.asString() == id_r )
105           return true;
106       return false;
107     }
108
109     zypp::Date Repository::generatedTimestamp() const
110     {
111       NO_REPOSITORY_RETURN( 0 );
112       sat::LookupRepoAttr q( sat::SolvAttr::repositoryTimestamp, *this );
113       return( q.empty() ? 0 : q.begin().asUnsigned() );
114     }
115
116     zypp::Date Repository::suggestedExpirationTimestamp() const
117     {
118       NO_REPOSITORY_RETURN( 0 );
119       Date generated = generatedTimestamp();
120       if ( ! generated )
121         return 0; // do not calculate over a missing generated timestamp
122
123       sat::LookupRepoAttr q( sat::SolvAttr::repositoryExpire, *this );
124       if ( q.empty() )
125         return 0;
126
127       return generated + Date(q.begin().asUnsigned());
128     }
129
130     Repository::Keywords Repository::keywords() const
131     {
132       NO_REPOSITORY_RETURN( Keywords() );
133       return Keywords( sat::SolvAttr::repositoryKeywords, *this, sat::LookupAttr::REPO_ATTR );
134     }
135
136     bool Repository::hasKeyword( const std::string & val_r ) const
137     {
138       for ( const auto & val : keywords() )
139         if ( val == val_r )
140           return true;
141       return false;
142     }
143
144     bool Repository::maybeOutdated() const
145     {
146       NO_REPOSITORY_RETURN( false );
147       // system repo is not mirrored
148       if ( isSystemRepo() )
149         return false;
150
151       Date suggested = suggestedExpirationTimestamp();
152
153       // if no data, don't suggest
154       if ( ! suggested )
155         return false;
156
157       return suggestedExpirationTimestamp() < Date::now();
158     }
159
160     bool Repository::providesUpdatesFor( const CpeId & cpeid_r ) const
161     {
162       NO_REPOSITORY_RETURN( false );
163       if ( ! cpeid_r )
164         return false;   // filter queries/products without CpeId, as an empty CpeId matches ANYthing.
165
166       // check in repository metadata
167       for_( it, updatesProductBegin(), updatesProductEnd() )
168       {
169         if ( compare( cpeid_r, it.cpeId(), SetRelation::subset ) )
170           return true;
171       }
172
173       // check whether known products refer to this as update repo
174       sat::LookupRepoAttr myIds( sat::SolvAttr::repositoryRepoid, *this );      // usually just one, but...
175       if ( ! myIds.empty() )
176       {
177         const ResPool & pool( ResPool::instance() );
178         for_( it, pool.byKindBegin<Product>(), pool.byKindEnd<Product>() )
179         {
180           Product::constPtr prod( (*it)->asKind<Product>() );
181           if ( compare( cpeid_r, prod->cpeId(), SetRelation::superset ) )
182           {
183             for_( myId, myIds.begin(), myIds.end() )
184             {
185               if ( prod->hasUpdateContentIdentifier( myId.asString() ) )
186                 return true;
187             }
188           }
189         }
190       }
191       return false;
192     }
193
194     bool Repository::isUpdateRepo() const
195     {
196       NO_REPOSITORY_RETURN( false );
197
198       // check in repository metadata
199       if ( updatesProductBegin() != updatesProductEnd() )
200         return true;
201
202       // check whether known products refer to this as update repo
203       sat::LookupRepoAttr myIds( sat::SolvAttr::repositoryRepoid, *this );      // usually just one, but...
204       if ( ! myIds.empty() )
205       {
206         const ResPool & pool( ResPool::instance() );
207         for_( it, pool.byKindBegin<Product>(), pool.byKindEnd<Product>() )
208         {
209           for_( myId, myIds.begin(), myIds.end() )
210           {
211             if ( (*it)->asKind<Product>()->hasUpdateContentIdentifier( myId.asString() ) )
212               return true;
213           }
214         }
215       }
216       return false;
217     }
218
219     bool Repository::solvablesEmpty() const
220     {
221       NO_REPOSITORY_RETURN( true );
222       return !_repo->nsolvables;
223     }
224
225     Repository::size_type Repository::solvablesSize() const
226     {
227       NO_REPOSITORY_RETURN( 0 );
228       return _repo->nsolvables;
229     }
230
231     Repository::SolvableIterator Repository::solvablesBegin() const
232     {
233       NO_REPOSITORY_RETURN( make_filter_iterator( detail::ByRepository( *this ),
234                             sat::detail::SolvableIterator(),
235                             sat::detail::SolvableIterator() ) );
236       return make_filter_iterator( detail::ByRepository( *this ),
237                                    sat::detail::SolvableIterator(_repo->start),
238                                    sat::detail::SolvableIterator(_repo->end) );
239     }
240
241     Repository::SolvableIterator Repository::solvablesEnd() const
242     {
243       NO_REPOSITORY_RETURN( make_filter_iterator( detail::ByRepository( *this ),
244                             sat::detail::SolvableIterator(),
245                             sat::detail::SolvableIterator() ) );
246       return make_filter_iterator(detail::ByRepository( *this ),
247                                   sat::detail::SolvableIterator(_repo->end),
248                                   sat::detail::SolvableIterator(_repo->end) );
249     }
250
251     Repository::ProductInfoIterator Repository::compatibleWithProductBegin() const
252     {
253       NO_REPOSITORY_RETURN( ProductInfoIterator() );
254       return ProductInfoIterator( sat::SolvAttr::repositoryDistros, *this );
255     }
256
257     Repository::ProductInfoIterator Repository::compatibleWithProductEnd() const
258     {
259       return ProductInfoIterator();
260     }
261
262     Repository::ProductInfoIterator Repository::updatesProductBegin() const
263     {
264       NO_REPOSITORY_RETURN( ProductInfoIterator() );
265       return ProductInfoIterator( sat::SolvAttr::repositoryUpdates, *this );
266     }
267
268     Repository::ProductInfoIterator Repository::updatesProductEnd() const
269     {
270       return ProductInfoIterator();
271     }
272
273     RepoInfo Repository::info() const
274     {
275       NO_REPOSITORY_RETURN( RepoInfo() );
276       return myPool().repoInfo( _repo );
277     }
278
279     void Repository::setInfo( const RepoInfo & info_r )
280     {
281         NO_REPOSITORY_THROW( Exception( "Can't set RepoInfo for norepo." ) );
282         if ( info_r.alias() != alias() )
283         {
284             ZYPP_THROW( Exception( str::form( "RepoInfo alias (%s) does not match repository alias (%s)",
285                                               info_r.alias().c_str(), alias().c_str() ) ) );
286         }
287         myPool().setRepoInfo( _repo, info_r );
288         MIL << *this << endl;
289     }
290
291     void Repository::clearInfo()
292     {
293         NO_REPOSITORY_RETURN();
294         myPool().setRepoInfo( _repo, RepoInfo() );
295     }
296
297     void Repository::eraseFromPool()
298     {
299         NO_REPOSITORY_RETURN();
300         MIL << *this << " removed from pool" << endl;
301         myPool()._deleteRepo( _repo );
302         _id = sat::detail::noRepoId;
303     }
304
305     Repository Repository::nextInPool() const
306     {
307       NO_REPOSITORY_RETURN( noRepository );
308       for_( it, sat::Pool::instance().reposBegin(), sat::Pool::instance().reposEnd() )
309       {
310         if ( *it == *this )
311         {
312           if ( ++it != _for_end )
313             return *it;
314           break;
315         }
316       }
317       return noRepository;
318     }
319
320     void Repository::addSolv( const Pathname & file_r )
321     {
322       NO_REPOSITORY_THROW( Exception( "Can't add solvables to norepo." ) );
323
324       AutoDispose<FILE*> file( ::fopen( file_r.c_str(), "re" ), ::fclose );
325       if ( file == NULL )
326       {
327         file.resetDispose();
328         ZYPP_THROW( Exception( "Can't open solv-file: "+file_r.asString() ) );
329       }
330
331       if ( myPool()._addSolv( _repo, file ) != 0 )
332       {
333         ZYPP_THROW( Exception( "Error reading solv-file: "+file_r.asString() ) );
334       }
335
336       MIL << *this << " after adding " << file_r << endl;
337     }
338
339     void Repository::addHelix( const Pathname & file_r )
340     {
341       NO_REPOSITORY_THROW( Exception( "Can't add solvables to norepo." ) );
342
343       std::string command( file_r.extension() == ".gz" ? "zcat " : "cat " );
344       command += file_r.asString();
345
346       AutoDispose<FILE*> file( ::popen( command.c_str(), "re" ), ::pclose );
347       if ( file == NULL )
348       {
349         file.resetDispose();
350         ZYPP_THROW( Exception( "Can't open helix-file: "+file_r.asString() ) );
351       }
352
353       if ( myPool()._addHelix( _repo, file ) != 0 )
354       {
355         ZYPP_THROW( Exception( "Error reading helix-file: "+file_r.asString() ) );
356       }
357
358       MIL << *this << " after adding " << file_r << endl;
359     }
360
361     sat::detail::SolvableIdType Repository::addSolvables( unsigned count_r )
362     {
363         NO_REPOSITORY_THROW( Exception( "Can't add solvables to norepo.") );
364         return myPool()._addSolvables( _repo, count_r );
365     }
366
367     /******************************************************************
368      **
369      ** FUNCTION NAME : operator<<
370      ** FUNCTION TYPE : std::ostream &
371      */
372     std::ostream & operator<<( std::ostream & str, const Repository & obj )
373     {
374         if ( ! obj )
375             return str << "noRepository";
376
377         return str << "sat::repo(" << obj.alias() << ")"
378                    << "{"
379                    << "prio " << obj.get()->priority << '.' << obj.get()->subpriority
380                    << ", size " << obj.solvablesSize()
381                    << "}";
382     }
383
384     std::ostream & dumpAsXmlOn( std::ostream & str, const Repository & obj )
385     {
386       return xmlout::node( str, "repository", {
387         { "name", obj.name() },
388         { "alias", obj.alias() }
389       } );
390     }
391
392     //////////////////////////////////////////////////////////////////
393     namespace detail
394     {
395       void RepositoryIterator::increment()
396       {
397         if ( base() )
398         {
399           ::_Pool * satpool = sat::Pool::instance().get();
400           do {
401             ++base_reference();
402           } while ( base() < satpool->repos+satpool->nrepos && !*base() );
403         }
404       }
405     } // namespace detail
406     //////////////////////////////////////////////////////////////////
407
408     ///////////////////////////////////////////////////////////////////
409     //
410     // Repository::ProductInfoIterator
411     //
412     ///////////////////////////////////////////////////////////////////
413
414     Repository::ProductInfoIterator::ProductInfoIterator( sat::SolvAttr attr_r, Repository repo_r )
415     { base_reference() = sat::LookupRepoAttr( attr_r, repo_r ).begin(); }
416
417     std::string Repository::ProductInfoIterator::label() const
418     { return base_reference().subFind( sat::SolvAttr::repositoryProductLabel ).asString(); }
419
420     CpeId Repository::ProductInfoIterator::cpeId() const
421     { return CpeId( base_reference().subFind( sat::SolvAttr::repositoryProductCpeid ).asString(), CpeId::noThrow ); }
422
423     /////////////////////////////////////////////////////////////////
424 } // namespace zypp
425 ///////////////////////////////////////////////////////////////////