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