b841f255a546f2475ad568ce04205da8671f49fd
[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 <boost/iterator.hpp>
19
20 #include "zypp/base/PtrTypes.h"
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/RepoStatus.h"
27 #include "zypp/ProgressData.h"
28
29 ///////////////////////////////////////////////////////////////////
30 namespace zypp
31 { /////////////////////////////////////////////////////////////////
32   class ServiceInfo; //predef
33
34    /**
35     * Parses \a repo_file and returns a list of \ref RepoInfo objects
36     * corresponding to repositories found within the file.
37     *
38     * \param repo_file Valid URL of the repo file.
39     * \return found list<RepoInfo>
40     *
41     * \throws MediaException If the access to the url fails
42     * \throws ParseException If the file parsing fails
43     * \throws Exception On other errors.
44     */
45    std::list<RepoInfo> readRepoFile(const Url & repo_file);
46
47   /**
48    * Repo manager settings.
49    * Settings default to ZYpp global settings.
50    */
51   struct RepoManagerOptions
52   {
53     /** Default ctor following \ref ZConfig global settings.
54      * If an optional \c root_r directory is given, all paths  will
55      * be prefixed accordingly.
56      * \code
57      *    root_r\repoCachePath
58      *          \repoRawCachePath
59      *          \repoSolvCachePath
60      *          \repoPackagesCachePath
61      *          \knownReposPath
62      * \endcode
63      */
64     RepoManagerOptions( const Pathname & root_r = Pathname() );
65
66     /** Test setup adjusting all paths to be located below one \c root_r directory.
67      * \code
68      *    root_r\          - repoCachePath
69      *          \raw       - repoRawCachePath
70      *          \solv      - repoSolvCachePath
71      *          \packages  - repoPackagesCachePath
72      *          \repos.d   - knownReposPath
73      * \endcode
74      */
75     static RepoManagerOptions makeTestSetup( const Pathname & root_r );
76
77     Pathname repoCachePath;
78     Pathname repoRawCachePath;
79     Pathname repoSolvCachePath;
80     Pathname repoPackagesCachePath;
81     Pathname knownReposPath;
82     Pathname knownServicesPath;
83     bool probe;
84     /**
85      * Target distro ID to be used when refreshing repo index services.
86      * Repositories not maching this ID will be skipped/removed.
87      *
88      * The value is initialized upon construction to
89      * \ref Target::targetDistribution() if the Target is already initialized,
90      * otherwise the value is initially empty.
91      *
92      * If empty, no repositories contained in the index will be skipped.
93      */
94     std::string servicesTargetDistro;
95   };
96
97
98
99   /**
100    * \short creates and provides information about known sources.
101    *
102    */
103   class RepoManager
104   {
105     friend std::ostream & operator<<( std::ostream & str, const RepoManager & obj );
106
107   public:
108     /** Implementation  */
109     class Impl;
110
111     /** service typedefs */
112     typedef std::set<ServiceInfo> ServiceSet;
113     typedef ServiceSet::const_iterator ServiceConstIterator;
114     typedef ServiceSet::size_type ServiceSizeType;
115
116     /** RepoInfo typedefs */
117     typedef std::set<RepoInfo> RepoSet;
118     typedef RepoSet::const_iterator RepoConstIterator;
119     typedef RepoSet::size_type RepoSizeType;
120
121   public:
122    RepoManager( const RepoManagerOptions &options = RepoManagerOptions() );
123    /** Dtor */
124     ~RepoManager();
125
126     enum RawMetadataRefreshPolicy
127     {
128       RefreshIfNeeded,
129       RefreshForced,
130       RefreshIfNeededIgnoreDelay
131     };
132
133     enum CacheBuildPolicy
134     {
135       BuildIfNeeded,
136       BuildForced
137     };
138
139     enum RepoRemovePolicy
140     {
141
142     };
143
144    /**
145     * \short List known repositories.
146     *
147     * The known repositories are read from
148     * \ref RepoManagerOptions::knownReposPath passed on the Ctor.
149     * Which defaults to ZYpp global settings.
150     * \deprecated use iterator instead which read only one time directory
151     * \return found list<RepoInfo>
152     */
153    ZYPP_DEPRECATED 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     * \short Probe repo metadata type.
362     *
363     * \todo FIXME Should this be private?
364     */
365    repo::RepoType probe( const Url &url ) const;
366
367
368    /**
369     * \short Adds a repository to the list of known repositories.
370     *
371     *
372     *
373     * \throws repo::RepoAlreadyExistsException If the repo clash some
374     *         unique attribute like alias
375     * \throws RepoUnknownType
376     *         If RepoManagerOptions::probe is true
377     *         and repository type can't be determined.
378     * \throws RepoException
379     *         If RepoManagerOptions::probe is true and access to the url fails.
380     * \throws Exception On other errors.
381     */
382    void addRepository( const RepoInfo &info,
383                        const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
384
385    /**
386     * \short Adds repositores from a repo file to the list of known repositories.
387     * \param url Url of the repo file
388     *
389     * \throws repo::RepoAlreadyExistsException If the repo clash some
390     *         unique attribute like alias
391     * \throws MediaException If the access to the url fails
392     * \throws ParseException If the file parsing fails
393     * \throws RepoUnknownType If repository type can't be determined
394     * \throws RepoException ON other repository related errors
395     * \throws Exception On other errors.
396     */
397     void addRepositories( const Url &url,
398                          const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
399     /**
400      * \short Remove the best matching repository from known repos list
401      *
402      * \throws RepoNotFoundException If no repo match
403      */
404     void removeRepository( const RepoInfo & info,
405                            const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
406
407     /**
408      * \short Modify repository attributes
409      *
410      * \throws RepoAlreadyExistsException if the alias specified in newinfo
411      *         is already used by another repository
412      * \throws RepoNotFoundException If no repo match
413      * \throws ParseException If the file parsing fails
414      * \throws Exception On other errors.
415      */
416     void modifyRepository( const std::string &alias,
417                            const RepoInfo & newinfo,
418                            const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
419
420     /**
421      * \short Find a matching repository info
422      *
423      * \note if multiple repositories incorrectly share the
424      * same alias, the first one found will be returned.
425      *
426      * \param alias Repository alias
427      * \param progressrcv Progress reporting function
428      * \return RepoInfo of the found repository
429      * \throws RepoNotFoundException If no repo match the alias
430      * \throws ParseException If the file parsing fails
431      * \throws Exception On other errors.
432      */
433     RepoInfo getRepositoryInfo( const std::string &alias,
434                                 const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
435
436     /**
437      * \short Find repository info by URL.
438      *
439      * \param url URL to find.
440      * \param urlview url::ViewOption to influence URL matching.
441      * \param progressrcv Progress receiver function.
442      * \return RepoInfo of the found repository.
443      *
444      * \note if multpile repositories incorrectly share the
445      * same URL, the first one found will be returned.
446      *
447      * \note the string representation of the URLs are compared.
448      *       The \a urlview can be used to influence which
449              parts of the URL are to be compared.
450      *
451      * \throws RepoNotFoundException If no repo match
452      * \throws ParseException If the file parsing fails
453      * \throws Exception On other errors.
454      */
455     RepoInfo getRepositoryInfo( const Url & url,
456                                 const url::ViewOption & urlview = url::ViewOption::DEFAULTS,
457                                 const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
458
459     /**
460      * Adds new service by it's alias and url
461      *
462      * \param alias unique identifier of the service
463      * \param url url to service
464      *
465      * \throws FIXME RepoAlreadyExistException and as reponame is service name
466      */
467     void addService( const std::string & alias, const Url& url );
468
469     /**
470      * Adds new service
471      *
472      * \param service service info
473      *
474      * \throws FIXME RepoAlreadyExistException and as reponame is service name
475      */
476     void addService( const ServiceInfo & service );
477
478     /**
479      * Removes service specified by its name
480      *
481      * \param alias unique indientifier of the service to remove
482      *
483      * \throws RepoException if service is not found or file with ServiceInfo cannot be deleted
484      * \throws Exception if file contain more services and rewrite file failed
485      */
486     void removeService( const std::string & alias );
487
488     void removeService( const ServiceInfo & service );
489
490     /**
491      * Gets true if no service is in RepoManager (so no one in specified location)
492      *
493      * \return true if any ServiceInfo is in RepoManager
494      */
495     bool serviceEmpty() const;
496
497     /**
498      * Gets count of service in RepoManager (in specified location)
499      *
500      * \return count of service
501      */
502     ServiceSizeType serviceSize() const;
503
504     /**
505      * Iterator to first service in internal storage.
506      * \note Iterator is immutable, so you cannot change pointed ServiceInfo
507      * \return Iterator to first service
508      */
509     ServiceConstIterator serviceBegin() const;
510
511     /**
512      * Iterator to place behind last service in internal storage.
513      * \return iterator to end
514      */
515     ServiceConstIterator serviceEnd() const;
516
517     /**
518      * Finds ServiceInfo by alias or return noService
519      *
520      * \param alias unique identifier of service
521      * \return information about service
522      */
523     ServiceInfo getService( const std::string & alias ) const;
524
525     /**
526      * Refreshes all enabled services.
527      * 
528      * \see refreshService(ServiceInfo)
529      */
530     void refreshServices();
531
532     /**
533      * Refresh specific service.
534      * 
535      * \param name service structure
536      * \throws MediaException If there's a problem downloading the repo index file.
537      */
538     void refreshService( const ServiceInfo & service );
539
540     /**
541      * Modifies service file (rewrites it with new values) and underlying
542      * repositories if needed.
543      * 
544      * Modifications of a service can lead to rewrite of all .repo files of
545      * contained repositories. Particularily, disabling a service (changing
546      * ServiceInfo::enabled() from true to false) will disable all contained
547      * repositories. Renaming of a service will modify the "service" key
548      * of all contained repositories.
549      *
550      * \param oldAlias Old alias of the service
551      * \param service ServiceInfo object containing new data
552      *
553      * \throws RepoException if sservice with oldAlias is not known
554      * \throws Exception if have problems with files
555      */
556     void modifyService(const std::string & oldAlias, const ServiceInfo & service);
557
558   private:
559     /**
560      * Functor thats filter RepoInfo by service which belongs to.
561      */
562     struct MatchServiceAlias
563     {
564       private:
565         std::string alias;
566       public:
567         MatchServiceAlias( const std::string & alias_ ) : alias(alias_) {}
568         bool match( const RepoInfo & info ) { return info.service() == alias; }
569     };
570
571   public:
572
573     /**
574      * fill to output iterator repositories in service name. This output iterator can perform
575      * any action on with Repo or service Container, because it is sets and it isn't dynamic recreate.
576      *
577      * \note Don't use this function with RepoManager::removeRepository(), it will lead to segfaults
578      *       due to invalidated internal iterators. FIXME can this be solved (using STL) so that this
579      *       warning would not be needed?
580      *
581      * \param alias service alias
582      * \param out output iterator which get all the repositories belonging to
583      *   specified service
584      *
585      * example how set priority for each RepoInfo in this service:
586      * \code
587      * //functor
588      * class ChangePriority
589      * {
590      * private:
591      *   int priority;
592      * public:
593      *   ChangePriority(int prio) : priority(prio) {}
594      *   // missing rewrite priority back via RepoManager::modifyRepo
595      *   void doIt( RepoInfo info ) { info.setPriority(priority); } 
596      * }
597      *
598      * //somewhere in code
599      * ChangePriority changer(10);
600      * getRepositoriesInService(name,
601      *   boost::make_function_output_iterator(
602      *     bind(&ChangePriority::doIt, &changer, _1)));
603      * \endcode
604      */
605     template<typename OutputIterator>
606     void getRepositoriesInService( const std::string & alias,
607                                    OutputIterator out ) const
608     {
609       MatchServiceAlias filter(alias);
610
611       std::copy(
612         boost::make_filter_iterator(
613           bind(&MatchServiceAlias::match, filter, _1), repoBegin(), repoEnd()),
614         boost::make_filter_iterator(
615           bind(&MatchServiceAlias::match, filter, _1), repoEnd(), repoEnd()),
616         out);
617     }
618
619   protected:
620     RepoStatus rawMetadataStatus( const RepoInfo &info );
621     void setCacheStatus( const RepoInfo &info, const RepoStatus &status );
622
623     /**
624      * Update timestamp of repository index file for the specified repository \a info.
625      * Used in \ref checkIfToRefreshMetadata() for repo.refresh.delay feature.
626      */
627     void touchIndexFile(const RepoInfo & info);
628
629   public:
630
631   private:
632     /** Pointer to implementation */
633     RWCOW_pointer<Impl> _pimpl;
634   };
635   ///////////////////////////////////////////////////////////////////
636
637   /** \relates RepoManager Stream output */
638   std::ostream & operator<<( std::ostream & str, const RepoManager & obj );
639
640   /////////////////////////////////////////////////////////////////
641 } // namespace zypp
642 ///////////////////////////////////////////////////////////////////
643 #endif // ZYPP2_REPOMANAGER_H