Imported Upstream version 17.23.5
[platform/upstream/libzypp.git] / zypp / repo / RepoMirrorList.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/repo/RepoMirrorList.cc
10  *
11 */
12
13 #include <iostream>
14 #include <vector>
15 #include <time.h>
16 #include <zypp/repo/RepoMirrorList.h>
17 #include <zypp/media/MetaLinkParser.h>
18 #include <zypp/MediaSetAccess.h>
19 #include <zypp/base/LogTools.h>
20 #include <zypp/ZConfig.h>
21 #include <zypp/PathInfo.h>
22
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 { /////////////////////////////////////////////////////////////////
27   ///////////////////////////////////////////////////////////////////
28   namespace repo
29   { /////////////////////////////////////////////////////////////////
30
31     ///////////////////////////////////////////////////////////////////
32     namespace
33     {
34       ///////////////////////////////////////////////////////////////////
35       /// \class RepoMirrorListTempProvider
36       /// \brief Provide access to downloaded mirror list (in temp space)
37       /// \ingroup g_RAII
38       ///
39       /// Tempspace (and mirror list) are deleted when provider goes out
40       /// of scope.
41       struct RepoMirrorListTempProvider
42       {
43         RepoMirrorListTempProvider()
44         {}
45         RepoMirrorListTempProvider( const Pathname & localfile_r )
46         : _localfile( localfile_r )
47         {}
48         RepoMirrorListTempProvider( const Url & url_r )
49         {
50           Url abs_url( url_r );
51           abs_url.setPathName( "/" );
52           abs_url.setQueryParam( "mediahandler", "curl" );
53           _access.reset( new MediaSetAccess( abs_url ) );
54           _localfile = _access->provideFile( url_r.getPathName() );
55         }
56
57         const Pathname & localfile() const
58         { return _localfile; }
59
60       private:
61         shared_ptr<MediaSetAccess> _access;
62         Pathname _localfile;
63       };
64       ///////////////////////////////////////////////////////////////////
65
66       inline std::vector<Url> RepoMirrorListParseXML( const Pathname &tmpfile )
67       {
68         InputStream tmpfstream (tmpfile);
69         media::MetaLinkParser metalink;
70         metalink.parse(tmpfstream);
71         return metalink.getUrls();
72       }
73
74       inline std::vector<Url> RepoMirrorListParseTXT( const Pathname &tmpfile )
75       {
76         InputStream tmpfstream (tmpfile);
77         std::vector<Url> my_urls;
78         std::string tmpurl;
79         while (getline(tmpfstream.stream(), tmpurl))
80         {
81           if ( tmpurl[0] == '#' )
82             continue;
83           try {
84             my_urls.push_back(Url(tmpurl));
85           }
86           catch (...)
87           {;}   // ignore malformed urls
88         }
89         return my_urls;
90       }
91
92       /** Parse a local mirrorlist \a listfile_r and return usable URLs */
93       inline std::vector<Url> RepoMirrorListParse( const Url & url_r, const Pathname & listfile_r, bool mirrorListForceMetalink_r )
94       {
95         USR << url_r << " " << listfile_r << endl;
96
97         std::vector<Url> mirrorurls;
98         if ( mirrorListForceMetalink_r || url_r.asString().find( "/metalink" ) != std::string::npos )
99           mirrorurls = RepoMirrorListParseXML( listfile_r );
100         else
101           mirrorurls = RepoMirrorListParseTXT( listfile_r );
102
103
104         std::vector<Url> ret;
105         for ( auto & murl : mirrorurls )
106         {
107           if ( murl.getScheme() != "rsync" )
108           {
109             size_t delpos = murl.getPathName().find("repodata/repomd.xml");
110             if( delpos != std::string::npos )
111             {
112               murl.setPathName( murl.getPathName().erase(delpos)  );
113             }
114             ret.push_back( murl );
115
116             if ( ret.size() >= 4 )      // why 4?
117               break;
118           }
119         }
120         return ret;
121       }
122
123     } // namespace
124     ///////////////////////////////////////////////////////////////////
125
126     RepoMirrorList::RepoMirrorList( const Url & url_r, const Pathname & metadatapath_r, bool mirrorListForceMetalink_r )
127     {
128       if ( url_r.getScheme() == "file" )
129       {
130         // never cache for local mirrorlist
131         _urls = RepoMirrorListParse( url_r, url_r.getPathName(), mirrorListForceMetalink_r );
132       }
133       else if ( ! PathInfo( metadatapath_r).isDir() )
134       {
135         // no cachedir
136         RepoMirrorListTempProvider provider( url_r );   // RAII: lifetime of any downloaded files
137         _urls = RepoMirrorListParse( url_r, provider.localfile(), mirrorListForceMetalink_r );
138       }
139       else
140       {
141         // have cachedir
142         Pathname cachefile( metadatapath_r );
143         if ( mirrorListForceMetalink_r || url_r.asString().find( "/metalink" ) != std::string::npos )
144           cachefile /= "mirrorlist.xml";
145         else
146           cachefile /= "mirrorlist.txt";
147
148         zypp::filesystem::PathInfo cacheinfo( cachefile );
149         if ( !cacheinfo.isFile() || cacheinfo.mtime() < time(NULL) - (long) ZConfig::instance().repo_refresh_delay() * 60 )
150         {
151           DBG << "Getting MirrorList from URL: " << url_r << endl;
152           RepoMirrorListTempProvider provider( url_r ); // RAII: lifetime of downloaded file
153
154           // Create directory, if not existing
155           DBG << "Copy MirrorList file to " << cachefile << endl;
156           zypp::filesystem::assert_dir( metadatapath_r );
157           zypp::filesystem::hardlinkCopy( provider.localfile(), cachefile );
158         }
159
160         _urls = RepoMirrorListParse( url_r, cachefile, mirrorListForceMetalink_r );
161         if( _urls.empty() )
162         {
163           DBG << "Removing Cachefile as it contains no URLs" << endl;
164           zypp::filesystem::unlink( cachefile );
165         }
166       }
167     }
168
169     /////////////////////////////////////////////////////////////////
170   } // namespace repo
171   ///////////////////////////////////////////////////////////////////
172   /////////////////////////////////////////////////////////////////
173 } // namespace zypp
174 ///////////////////////////////////////////////////////////////////