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