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