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