Add API for retrieving repository ContentRevision and ContentIdentifier (Fate#316160)
[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/sat/Pool.h"
26
27 using std::endl;
28
29 ///////////////////////////////////////////////////////////////////
30 namespace zypp
31 { /////////////////////////////////////////////////////////////////
32
33     const Repository Repository::noRepository;
34
35     const std::string & Repository::systemRepoAlias()
36     { return sat::detail::PoolImpl::systemRepoAlias(); }
37
38     /////////////////////////////////////////////////////////////////
39
40     ::_Repo * Repository::get() const
41     { return myPool().getRepo( _id ); }
42
43 #define NO_REPOSITORY_RETURN( VAL ) \
44     ::_Repo * _repo( get() ); \
45     if ( ! _repo ) return VAL
46
47 #define NO_REPOSITORY_THROW( VAL ) \
48     ::_Repo * _repo( get() ); \
49     if ( ! _repo ) ZYPP_THROW( VAL )
50
51     bool Repository::isSystemRepo() const
52     {
53         NO_REPOSITORY_RETURN( false );
54         return myPool().isSystemRepo( _repo );
55     }
56
57     std::string Repository::alias() const
58     {
59       NO_REPOSITORY_RETURN( std::string() );
60       if ( ! _repo->name )
61         return std::string();
62       return _repo->name;
63     }
64
65     std::string Repository::name() const
66     { return info().name(); }
67
68     int Repository::satInternalPriority() const
69     {
70       NO_REPOSITORY_RETURN( INT_MIN );
71       return _repo->priority;
72     }
73
74     int Repository::satInternalSubPriority() const
75     {
76       NO_REPOSITORY_RETURN( INT_MIN );
77       return _repo->subpriority;
78     }
79
80     Repository::ContentRevision contentRevision() const
81     {
82       NO_REPOSITORY_RETURN( ContentRevision() );
83       sat::LookupRepoAttr q( sat::SolvAttr::repositoryRevision, *this );
84       return q.empty() ? std::string() : q.begin().asString();
85     }
86
87     Repository::ContentIdentifier Repository::contentIdentifier() const
88     {
89       NO_REPOSITORY_RETURN( ContentIdentifier() );
90       sat::LookupRepoAttr q( sat::SolvAttr::repositoryRepoid, *this );
91       return q.empty() ? std::string() : q.begin().asString();
92     }
93
94     zypp::Date Repository::generatedTimestamp() const
95     {
96       NO_REPOSITORY_RETURN( 0 );
97       sat::LookupRepoAttr q( sat::SolvAttr::repositoryTimestamp, *this );
98       return( q.empty() ? 0 : q.begin().asUnsigned() );
99     }
100
101     zypp::Date Repository::suggestedExpirationTimestamp() const
102     {
103       NO_REPOSITORY_RETURN( 0 );
104       Date generated = generatedTimestamp();
105       if ( ! generated )
106         return 0; // do not calculate over a missing generated timestamp
107
108       sat::LookupRepoAttr q( sat::SolvAttr::repositoryExpire, *this );
109       if ( q.empty() )
110         return 0;
111
112       return generated + Date(q.begin().asUnsigned());
113     }
114
115     Repository::Keywords Repository::keywords() const
116     {
117       NO_REPOSITORY_RETURN( Keywords() );
118       return Keywords( sat::SolvAttr::repositoryKeywords, *this, sat::LookupAttr::REPO_ATTR );
119     }
120
121     bool Repository::hasKeyword( const std::string & val_r ) const
122     {
123       for ( const auto & val : keywords() )
124         if ( val == val_r )
125           return true;
126       return false;
127     }
128
129     bool Repository::maybeOutdated() const
130     {
131       NO_REPOSITORY_RETURN( false );
132       // system repo is not mirrored
133       if ( isSystemRepo() )
134         return false;
135
136       Date suggested = suggestedExpirationTimestamp();
137
138       // if no data, don't suggest
139       if ( ! suggested )
140         return false;
141
142       return suggestedExpirationTimestamp() < Date::now();
143     }
144
145     bool Repository::providesUpdatesFor( const std::string &key ) const
146     {
147       NO_REPOSITORY_RETURN( false );
148
149       for_( it,
150             updatesProductBegin(),
151             updatesProductEnd() )
152       {
153         // FIXME implement real CPE matching here
154         // someday
155         if ( key == it.cpeId() )
156           return true;
157       }
158
159       return false;
160     }
161
162     bool Repository::isUpdateRepo() const
163     {
164       NO_REPOSITORY_RETURN( false );
165       return ( updatesProductBegin() != updatesProductEnd() );
166     }
167
168     bool Repository::solvablesEmpty() const
169     {
170       NO_REPOSITORY_RETURN( true );
171       return !_repo->nsolvables;
172     }
173
174     Repository::size_type Repository::solvablesSize() const
175     {
176       NO_REPOSITORY_RETURN( 0 );
177       return _repo->nsolvables;
178     }
179
180     Repository::SolvableIterator Repository::solvablesBegin() const
181     {
182       NO_REPOSITORY_RETURN( make_filter_iterator( detail::ByRepository( *this ),
183                             sat::detail::SolvableIterator(),
184                             sat::detail::SolvableIterator() ) );
185       return make_filter_iterator( detail::ByRepository( *this ),
186                                    sat::detail::SolvableIterator(_repo->start),
187                                    sat::detail::SolvableIterator(_repo->end) );
188     }
189
190     Repository::SolvableIterator Repository::solvablesEnd() const
191     {
192       NO_REPOSITORY_RETURN( make_filter_iterator( detail::ByRepository( *this ),
193                             sat::detail::SolvableIterator(),
194                             sat::detail::SolvableIterator() ) );
195       return make_filter_iterator(detail::ByRepository( *this ),
196                                   sat::detail::SolvableIterator(_repo->end),
197                                   sat::detail::SolvableIterator(_repo->end) );
198     }
199
200     Repository::ProductInfoIterator Repository::compatibleWithProductBegin() const
201     {
202       NO_REPOSITORY_RETURN( ProductInfoIterator() );
203       return ProductInfoIterator( sat::SolvAttr::repositoryDistros, *this );
204     }
205
206     Repository::ProductInfoIterator Repository::compatibleWithProductEnd() const
207     {
208       return ProductInfoIterator();
209     }
210
211     Repository::ProductInfoIterator Repository::updatesProductBegin() const
212     {
213       NO_REPOSITORY_RETURN( ProductInfoIterator() );
214       return ProductInfoIterator( sat::SolvAttr::repositoryUpdates, *this );
215     }
216
217     Repository::ProductInfoIterator Repository::updatesProductEnd() const
218     {
219       return ProductInfoIterator();
220     }
221
222     RepoInfo Repository::info() const
223     {
224       NO_REPOSITORY_RETURN( RepoInfo() );
225       return myPool().repoInfo( _repo );
226     }
227
228     void Repository::setInfo( const RepoInfo & info_r )
229     {
230         NO_REPOSITORY_THROW( Exception( "Can't set RepoInfo for norepo." ) );
231         if ( info_r.alias() != alias() )
232         {
233             ZYPP_THROW( Exception( str::form( "RepoInfo alias (%s) does not match repository alias (%s)",
234                                               info_r.alias().c_str(), alias().c_str() ) ) );
235         }
236         myPool().setRepoInfo( _repo, info_r );
237         MIL << *this << endl;
238     }
239
240     void Repository::clearInfo()
241     {
242         NO_REPOSITORY_RETURN();
243         myPool().setRepoInfo( _repo, RepoInfo() );
244     }
245
246     void Repository::eraseFromPool()
247     {
248         NO_REPOSITORY_RETURN();
249         MIL << *this << " removed from pool" << endl;
250         myPool()._deleteRepo( _repo );
251         _id = sat::detail::noRepoId;
252     }
253
254     Repository Repository::nextInPool() const
255     {
256       NO_REPOSITORY_RETURN( noRepository );
257       for_( it, sat::Pool::instance().reposBegin(), sat::Pool::instance().reposEnd() )
258       {
259         if ( *it == *this )
260         {
261           if ( ++it != _for_end )
262             return *it;
263           break;
264         }
265       }
266       return noRepository;
267     }
268
269     void Repository::addSolv( const Pathname & file_r )
270     {
271       NO_REPOSITORY_THROW( Exception( "Can't add solvables to norepo." ) );
272
273       AutoDispose<FILE*> file( ::fopen( file_r.c_str(), "re" ), ::fclose );
274       if ( file == NULL )
275       {
276         file.resetDispose();
277         ZYPP_THROW( Exception( "Can't open solv-file: "+file_r.asString() ) );
278       }
279
280       if ( myPool()._addSolv( _repo, file ) != 0 )
281       {
282         ZYPP_THROW( Exception( "Error reading solv-file: "+file_r.asString() ) );
283       }
284
285       MIL << *this << " after adding " << file_r << endl;
286     }
287
288     void Repository::addHelix( const Pathname & file_r )
289     {
290       NO_REPOSITORY_THROW( Exception( "Can't add solvables to norepo." ) );
291
292       std::string command( file_r.extension() == ".gz" ? "zcat " : "cat " );
293       command += file_r.asString();
294
295       AutoDispose<FILE*> file( ::popen( command.c_str(), "re" ), ::pclose );
296       if ( file == NULL )
297       {
298         file.resetDispose();
299         ZYPP_THROW( Exception( "Can't open helix-file: "+file_r.asString() ) );
300       }
301
302       if ( myPool()._addHelix( _repo, file ) != 0 )
303       {
304         ZYPP_THROW( Exception( "Error reading helix-file: "+file_r.asString() ) );
305       }
306
307       MIL << *this << " after adding " << file_r << endl;
308     }
309
310     sat::detail::SolvableIdType Repository::addSolvables( unsigned count_r )
311     {
312         NO_REPOSITORY_THROW( Exception( "Can't add solvables to norepo.") );
313         return myPool()._addSolvables( _repo, count_r );
314     }
315
316     /******************************************************************
317      **
318      ** FUNCTION NAME : operator<<
319      ** FUNCTION TYPE : std::ostream &
320      */
321     std::ostream & operator<<( std::ostream & str, const Repository & obj )
322     {
323         if ( ! obj )
324             return str << "noRepository";
325
326         return str << "sat::repo(" << obj.alias() << ")"
327                    << "{"
328                    << "prio " << obj.get()->priority << '.' << obj.get()->subpriority
329                    << ", size " << obj.solvablesSize()
330                    << "}";
331     }
332
333     std::ostream & dumpAsXmlOn( std::ostream & str, const Repository & obj )
334     {
335       return xmlout::node( str, "repository", {
336         { "alias", obj.name() },
337         { "name", obj.alias() }
338       } );
339     }
340
341     //////////////////////////////////////////////////////////////////
342     namespace detail
343     {
344       void RepositoryIterator::increment()
345       {
346         if ( base() )
347         {
348           ::_Pool * satpool = sat::Pool::instance().get();
349           do {
350             ++base_reference();
351           } while ( base() < satpool->repos+satpool->nrepos && !*base() );
352         }
353       }
354     } // namespace detail
355     //////////////////////////////////////////////////////////////////
356
357     ///////////////////////////////////////////////////////////////////
358     //
359     // Repository::ProductInfoIterator
360     //
361     ///////////////////////////////////////////////////////////////////
362
363     Repository::ProductInfoIterator::ProductInfoIterator( sat::SolvAttr attr_r, Repository repo_r )
364     { base_reference() = sat::LookupRepoAttr( attr_r, repo_r ).begin(); }
365
366     std::string Repository::ProductInfoIterator::label() const
367     { return base_reference().subFind( sat::SolvAttr::repositoryProductLabel ).asString(); }
368
369     std::string Repository::ProductInfoIterator::cpeId() const
370     { return base_reference().subFind( sat::SolvAttr::repositoryProductCpeid ).asString(); }
371
372     /////////////////////////////////////////////////////////////////
373 } // namespace zypp
374 ///////////////////////////////////////////////////////////////////