201447ca12a0b55d3b4f545986468a33493e8e3b
[platform/upstream/libzypp.git] / zypp / RepoManager.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/RepoManager.h
10  *
11 */
12 #ifndef ZYPP_REPOMANAGER_H
13 #define ZYPP_REPOMANAGER_H
14
15 #include <iosfwd>
16 #include <list>
17
18 #include "zypp/base/PtrTypes.h"
19 #include "zypp/base/Iterator.h"
20
21 #include "zypp/Pathname.h"
22 #include "zypp/ZConfig.h"
23 #include "zypp/RepoInfo.h"
24 #include "zypp/repo/RepoException.h"
25 #include "zypp/repo/RepoType.h"
26 #include "zypp/repo/ServiceType.h"
27 #include "zypp/RepoStatus.h"
28 #include "zypp/ProgressData.h"
29
30 ///////////////////////////////////////////////////////////////////
31 namespace zypp
32 { /////////////////////////////////////////////////////////////////
33   class ServiceInfo; //predef
34
35    /**
36     * Parses \a repo_file and returns a list of \ref RepoInfo objects
37     * corresponding to repositories found within the file.
38     *
39     * \param repo_file Valid URL of the repo file.
40     * \return found list<RepoInfo>
41     *
42     * \throws MediaException If the access to the url fails
43     * \throws ParseException If the file parsing fails
44     * \throws Exception On other errors.
45     */
46    std::list<RepoInfo> readRepoFile(const Url & repo_file);
47
48   /**
49    * Repo manager settings.
50    * Settings default to ZYpp global settings.
51    */
52   struct RepoManagerOptions
53   {
54     /** Default ctor following \ref ZConfig global settings.
55      * If an optional \c root_r directory is given, all paths  will
56      * be prefixed accordingly.
57      * \code
58      *    root_r\repoCachePath
59      *          \repoRawCachePath
60      *          \repoSolvCachePath
61      *          \repoPackagesCachePath
62      *          \knownReposPath
63      * \endcode
64      */
65     RepoManagerOptions( const Pathname & root_r = Pathname() );
66
67     /** Test setup adjusting all paths to be located below one \c root_r directory.
68      * \code
69      *    root_r\          - repoCachePath
70      *          \raw       - repoRawCachePath
71      *          \solv      - repoSolvCachePath
72      *          \packages  - repoPackagesCachePath
73      *          \repos.d   - knownReposPath
74      * \endcode
75      */
76     static RepoManagerOptions makeTestSetup( const Pathname & root_r );
77
78     Pathname repoCachePath;
79     Pathname repoRawCachePath;
80     Pathname repoSolvCachePath;
81     Pathname repoPackagesCachePath;
82     Pathname knownReposPath;
83     Pathname knownServicesPath;
84     bool probe;
85     /**
86      * Target distro ID to be used when refreshing repo index services.
87      * Repositories not maching this ID will be skipped/removed.
88      *
89      * The value is initialized upon construction to
90      * \ref Target::targetDistribution() if the Target is already initialized,
91      * otherwise the value is initially empty.
92      *
93      * If empty, no repositories contained in the index will be skipped.
94      */
95     std::string servicesTargetDistro;
96   };
97
98
99
100   /**
101    * \short creates and provides information about known sources.
102    *
103    */
104   class RepoManager
105   {
106     friend std::ostream & operator<<( std::ostream & str, const RepoManager & obj );
107
108   public:
109     /** Implementation  */
110     class Impl;
111
112     /** ServiceInfo typedefs */
113     typedef std::set<ServiceInfo> ServiceSet;
114     typedef ServiceSet::const_iterator ServiceConstIterator;
115     typedef ServiceSet::size_type ServiceSizeType;
116
117     /** RepoInfo typedefs */
118     typedef std::set<RepoInfo> RepoSet;
119     typedef RepoSet::const_iterator RepoConstIterator;
120     typedef RepoSet::size_type RepoSizeType;
121
122   public:
123    RepoManager( const RepoManagerOptions &options = RepoManagerOptions() );
124    /** Dtor */
125     ~RepoManager();
126
127     enum RawMetadataRefreshPolicy
128     {
129       RefreshIfNeeded,
130       RefreshForced,
131       RefreshIfNeededIgnoreDelay
132     };
133
134     enum CacheBuildPolicy
135     {
136       BuildIfNeeded,
137       BuildForced
138     };
139
140     enum RepoRemovePolicy
141     {
142
143     };
144
145    /**
146     * \short List known repositories.
147     *
148     * The known repositories are read from
149     * \ref RepoManagerOptions::knownReposPath passed on the Ctor.
150     * Which defaults to ZYpp global settings.
151     * \return found list<RepoInfo>
152     */
153    std::list<RepoInfo> knownRepositories() const;
154
155    bool repoEmpty() const;
156    RepoSizeType repoSize() const;
157    RepoConstIterator repoBegin() const;
158    RepoConstIterator repoEnd() const;
159
160
161    /**
162     * \short Status of local metadata
163     */
164     RepoStatus metadataStatus( const RepoInfo &info ) const;
165
166     /**
167      * Possibly return state of checkIfRefreshMEtadata function
168      */
169     enum RefreshCheckStatus {
170       REFRESH_NEEDED,  /**< refresh is needed */
171       REPO_UP_TO_DATE, /**< repository not changed */
172       REPO_CHECK_DELAYED     /**< refresh is delayed due to settings */
173     };
174
175     /**
176      * Checks whether to refresh metadata for specified repository and url.
177      * <p>
178      * The need for refresh is evaluated according to the following conditions,
179      * in that order:
180      * <ul>
181      * <li>the refresh policy (refresh may be forced)
182      * <li>the repo.refresh.delay ZConfig value compared to the difference between
183      *   cached index file timestamp and actual time
184      * <li>the timestamp of cached repo index file compared to the remote
185      *   index file timestamp.
186      * </ul>
187      * <p>
188      * This method checks the status against the specified url only. If more
189      * baseurls are defined for in the RepoInfo, each one must be check
190      * individually. Example:
191      *
192      * <code>
193      *
194      * RepoInfo info;
195      * // try urls one by one
196      * for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin();
197      *       it != info.baseUrlsEnd(); ++it )
198      * {
199      *   try
200      *   {
201      *     // check whether to refresh metadata
202      *     // if the check fails for this url, it throws, so another url will be checked
203      *     if (checkIfToRefreshMetadata(info, *it, policy)!=RepoInfo::REFRESH_NEEDED)
204      *       return;
205      *
206      *     // do the actual refresh
207      *   }
208      *   catch (const Exception & e)
209      *   {
210      *     ZYPP_CAUGHT(e);
211      *     ERR << *it << " doesn't look good. Trying another url." << endl;
212      *   }
213      * } // for all urls
214      *
215      * handle("No more URLs.");
216      *
217      * </code>
218      *
219      * \param info
220      * \param url
221      * \param policy
222      * \return state of repository
223      * \see RefreshCheckStatus
224      * \throws RepoUnknownTypeException
225      * \throws repo::RepoNoAliasException if can't figure an alias
226      * \throws Exception on unknown error
227      *
228      */
229     RefreshCheckStatus checkIfToRefreshMetadata( const RepoInfo &info,
230                                    const Url &url,
231                                    RawMetadataRefreshPolicy policy = RefreshIfNeeded);
232
233     /**
234      * \short Path where the metadata is downloaded and kept
235      *
236      * Given a repoinfo, tells where \ref RepoManager will download
237      * and keep the raw metadata.
238      *
239      * \param info Repository information
240      *
241      * \throws repo::RepoNoAliasException if can't figure an alias
242      */
243     Pathname metadataPath( const RepoInfo &info ) const;
244
245
246     /**
247      * \short Path where the rpm packages are downloaded and kept
248      *
249      * Given a repoinfo, tells where \ref RepoProvidePackage will download
250      * and keep the .rpm files.
251      *
252      * \param info Repository information
253      *
254      * \throws repo::RepoNoAliasException if can't figure an alias
255      */
256     Pathname packagesPath( const RepoInfo &info ) const;
257
258
259    /**
260     * \short Refresh local raw cache
261     *
262     * Will try to download the metadata
263     *
264     * In case of falure the metadata remains
265     * as it was before.
266     *
267     * \throws repo::RepoNoUrlException if no urls are available.
268     * \throws repo::RepoNoAliasException if can't figure an alias
269     * \throws repo::RepoUnknownTypeException if the metadata is unknown
270     * \throws repo::RepoException if the repository is invalid
271     *         (no valid metadata found at any of baseurls)
272     */
273    void refreshMetadata( const RepoInfo &info,
274                          RawMetadataRefreshPolicy policy = RefreshIfNeeded,
275                          const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
276
277    /**
278     * \short Clean local metadata
279     *
280     * Empty local metadata.
281     *
282     * \throws repo::RepoNoAliasException if can't figure an alias
283     * \throws Exception on unknown error.
284     */
285    void cleanMetadata( const RepoInfo &info,
286                        const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
287
288    /**
289     * \short Clean local package cache
290     *
291     * Empty local directory with downloaded packages
292     *
293     * \throws repo::RepoNoAliasException if can't figure an alias
294     * \throws Exception on unknown error.
295     */
296    void cleanPackages( const RepoInfo &info,
297                        const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
298
299    /**
300     * \short Status of metadata cache
301     */
302     RepoStatus cacheStatus( const RepoInfo &info ) const;
303
304    /**
305     * \short Refresh local cache
306     *
307     * Will try to build the cache from local metadata.
308     *
309     * If the cache exists it will be overwriten.
310     *
311     * \note the local metadata must be valid.
312     *
313     * \throws repo::RepoNoAliasException if can't figure
314     *     an alias to look in cache
315     * \throws repo::RepoMetadataException if the metadata
316     *     is not enough to build a cache (empty, incorrect, or
317     *     refresh needed)
318     * \throws repo::RepoUnknownTypeException
319     * \throws parser::ParseException if parser encounters an error.
320     * \throws Exception on unknown error.
321     */
322    void buildCache( const RepoInfo &info,
323                     CacheBuildPolicy policy = BuildIfNeeded,
324                     const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
325
326    /**
327     * \short clean local cache
328     *
329     * Clean the cached version of the metadata
330     *
331     * \note the local metadata must be valid.
332     *
333     * \throws repo::RepoNoAliasException if can't figure an alias to look in cache
334     * \throws cache::CacheRecordNotFoundException if the cache could not be
335     *     cleaned because of repository record not found.
336     * \throws Exception on unknown error.
337     */
338    void cleanCache( const RepoInfo &info,
339                     const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
340
341    /**
342     * \short Whether a repository exists in cache
343     *
344     * \param RepoInfo to be checked.
345     */
346     bool isCached( const RepoInfo &info ) const;
347
348
349     /**
350     * \short Load resolvables into the pool
351     *
352     * Creating from cache requires that the repository is
353     * refreshed (metadata downloaded) and cached
354     *
355     * \throws repo::RepoNoAliasException if can't figure an alias to look in cache
356     * \throw RepoNotCachedException When the source is not cached.
357     */
358    void loadFromCache( const RepoInfo &info,
359                        const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
360
361    /**
362     * \short Probe repo metadata type.
363     */
364    repo::RepoType probe( const Url &url ) const;
365
366
367    /**
368     * \short Adds a repository to the list of known repositories.
369     *
370     *
371     *
372     * \throws repo::RepoAlreadyExistsException If the repo clash some
373     *         unique attribute like alias
374     * \throws RepoUnknownType
375     *         If RepoManagerOptions::probe is true
376     *         and repository type can't be determined.
377     * \throws RepoException
378     *         If RepoManagerOptions::probe is true and access to the url fails.
379     * \throws Exception On other errors.
380     */
381    void addRepository( const RepoInfo &info,
382                        const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
383
384    /**
385     * \short Adds repositores from a repo file to the list of known repositories.
386     * \param url Url of the repo file
387     *
388     * \throws repo::RepoAlreadyExistsException If the repo clash some
389     *         unique attribute like alias
390     * \throws MediaException If the access to the url fails
391     * \throws ParseException If the file parsing fails
392     * \throws RepoUnknownType If repository type can't be determined
393     * \throws RepoException ON other repository related errors
394     * \throws Exception On other errors.
395     */
396     void addRepositories( const Url &url,
397                          const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
398     /**
399      * \short Remove the best matching repository from known repos list
400      *
401      * \throws RepoNotFoundException If no repo match
402      */
403     void removeRepository( const RepoInfo & info,
404                            const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
405
406     /**
407      * \short Modify repository attributes
408      *
409      * \throws RepoAlreadyExistsException if the alias specified in newinfo
410      *         is already used by another repository
411      * \throws RepoNotFoundException If no repo match
412      * \throws ParseException If the file parsing fails
413      * \throws Exception On other errors.
414      */
415     void modifyRepository( const std::string &alias,
416                            const RepoInfo & newinfo,
417                            const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
418
419     /**
420      * \short Find a matching repository info
421      *
422      * \note if multiple repositories incorrectly share the
423      * same alias, the first one found will be returned.
424      *
425      * \param alias Repository alias
426      * \param progressrcv Progress reporting function
427      * \return RepoInfo of the found repository
428      * \throws RepoNotFoundException If no repo match the alias
429      * \throws ParseException If the file parsing fails
430      * \throws Exception On other errors.
431      */
432     RepoInfo getRepositoryInfo( const std::string &alias,
433                                 const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
434
435     /**
436      * \short Find repository info by URL.
437      *
438      * \param url URL to find.
439      * \param urlview url::ViewOption to influence URL matching.
440      * \param progressrcv Progress receiver function.
441      * \return RepoInfo of the found repository.
442      *
443      * \note if multpile repositories incorrectly share the
444      * same URL, the first one found will be returned.
445      *
446      * \note the string representation of the URLs are compared.
447      *       The \a urlview can be used to influence which
448              parts of the URL are to be compared.
449      *
450      * \throws RepoNotFoundException If no repo match
451      * \throws ParseException If the file parsing fails
452      * \throws Exception On other errors.
453      */
454     RepoInfo getRepositoryInfo( const Url & url,
455                                 const url::ViewOption & urlview = url::ViewOption::DEFAULTS,
456                                 const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
457
458     /**
459      * \short Probe the type or the service.
460      */
461     repo::ServiceType probeService( const Url &url ) const;
462
463     /**
464      * Adds new service by it's alias and url
465      *
466      * \param alias unique identifier of the service
467      * \param url url to service
468      *
469      * \throws FIXME RepoAlreadyExistException and as reponame is service name
470      */
471     void addService( const std::string & alias, const Url& url );
472
473     /**
474      * Adds new service
475      *
476      * \param service service info
477      *
478      * \throws FIXME RepoAlreadyExistException and as reponame is service name
479      */
480     void addService( const ServiceInfo & service );
481
482     /**
483      * Removes service specified by its name
484      *
485      * \param alias unique indientifier of the service to remove
486      *
487      * \throws RepoException if service is not found or file with ServiceInfo cannot be deleted
488      * \throws Exception if file contain more services and rewrite file failed
489      */
490     void removeService( const std::string & alias );
491
492     void removeService( const ServiceInfo & service );
493
494     /**
495      * Gets true if no service is in RepoManager (so no one in specified location)
496      *
497      * \return true if any ServiceInfo is in RepoManager
498      */
499     bool serviceEmpty() const;
500
501     /**
502      * Gets count of service in RepoManager (in specified location)
503      *
504      * \return count of service
505      */
506     ServiceSizeType serviceSize() const;
507
508     /**
509      * Iterator to first service in internal storage.
510      * \note Iterator is immutable, so you cannot change pointed ServiceInfo
511      * \return Iterator to first service
512      */
513     ServiceConstIterator serviceBegin() const;
514
515     /**
516      * Iterator to place behind last service in internal storage.
517      * \return iterator to end
518      */
519     ServiceConstIterator serviceEnd() const;
520
521     /**
522      * Finds ServiceInfo by alias or return noService
523      *
524      * \param alias unique identifier of service
525      * \return information about service
526      */
527     ServiceInfo getService( const std::string & alias ) const;
528
529     /**
530      * Refreshes all enabled services.
531      *
532      * \see refreshService(ServiceInfo)
533      */
534     void refreshServices();
535
536     /**
537      * Refresh specific service.
538      *
539      * \param name service structure
540      * \throws MediaException If there's a problem downloading the repo index file.
541      */
542     void refreshService( const ServiceInfo & service );
543
544     /**
545      * Modifies service file (rewrites it with new values) and underlying
546      * repositories if needed.
547      *
548      * Modifications of a service can lead to rewrite of all .repo files of
549      * contained repositories. Particularily, disabling a service (changing
550      * ServiceInfo::enabled() from true to false) will disable all contained
551      * repositories. Renaming of a service will modify the "service" key
552      * of all contained repositories.
553      *
554      * \param oldAlias Old alias of the service
555      * \param service ServiceInfo object containing new data
556      *
557      * \throws RepoException if sservice with oldAlias is not known
558      * \throws Exception if have problems with files
559      */
560     void modifyService(const std::string & oldAlias, const ServiceInfo & service);
561
562   private:
563     /**
564      * Functor thats filter RepoInfo by service which belongs to.
565      */
566     struct MatchServiceAlias
567     {
568       public:
569         MatchServiceAlias( const std::string & alias_ ) : alias(alias_) {}
570         bool operator()( const RepoInfo & info ) const { return info.service() == alias; }
571       private:
572         std::string alias;
573     };
574
575   public:
576
577     /**
578      * fill to output iterator repositories in service name. This output iterator can perform
579      * any action on with Repo or service Container, because it is sets and it isn't dynamic recreate.
580      *
581      * \note Don't use this function with RepoManager::removeRepository(), it will lead to segfaults
582      *       due to invalidated internal iterators. FIXME can this be solved (using STL) so that this
583      *       warning would not be needed?
584      *
585      * \param alias service alias
586      * \param out output iterator which get all the repositories belonging to
587      *   specified service
588      *
589      * example how set priority for each RepoInfo in this service:
590      * \code
591      * //functor
592      * class ChangePriority
593      * {
594      * private:
595      *   int priority;
596      * public:
597      *   ChangePriority(int prio) : priority(prio) {}
598      *   // missing rewrite priority back via RepoManager::modifyRepo
599      *   void doIt( RepoInfo info ) { info.setPriority(priority); }
600      * }
601      *
602      * //somewhere in code
603      * ChangePriority changer(10);
604      * getRepositoriesInService(name,
605      *   boost::make_function_output_iterator(
606      *     bind(&ChangePriority::doIt, &changer, _1)));
607      * \endcode
608      */
609     template<typename OutputIterator>
610     void getRepositoriesInService( const std::string & alias,
611                                    OutputIterator out ) const
612     {
613       MatchServiceAlias filter(alias);
614
615       std::copy( boost::make_filter_iterator( filter, repoBegin(), repoEnd() ),
616                  boost::make_filter_iterator( filter, repoEnd(), repoEnd() ),
617                  out);
618     }
619
620   protected:
621     RepoStatus rawMetadataStatus( const RepoInfo &info );
622     void setCacheStatus( const RepoInfo &info, const RepoStatus &status );
623
624     /**
625      * Update timestamp of repository index file for the specified repository \a info.
626      * Used in \ref checkIfToRefreshMetadata() for repo.refresh.delay feature.
627      */
628     void touchIndexFile(const RepoInfo & info);
629
630   public:
631
632   private:
633     /** Pointer to implementation */
634     RWCOW_pointer<Impl> _pimpl;
635   };
636   ///////////////////////////////////////////////////////////////////
637
638   /** \relates RepoManager Stream output */
639   std::ostream & operator<<( std::ostream & str, const RepoManager & obj );
640
641   /////////////////////////////////////////////////////////////////
642 } // namespace zypp
643 ///////////////////////////////////////////////////////////////////
644 #endif // ZYPP2_REPOMANAGER_H