Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / repo / RepoMirrorList.cc
index 965e1d8..5477838 100644 (file)
@@ -29,124 +29,145 @@ namespace zypp
   namespace repo
   { /////////////////////////////////////////////////////////////////
 
-    RepoMirrorList::RepoMirrorList( const Url &url, const Pathname &metadatapath )
+    ///////////////////////////////////////////////////////////////////
+    namespace
     {
-      std::vector<Url> my_urls;
-      Pathname tmpfile, cachefile;
-
-      if ( url.asString().find("/metalink") != string::npos )
-        cachefile = metadatapath / "mirrorlist.xml";
-      else
-        cachefile = metadatapath / "mirrorlist.txt";
-        //cachefile = ZConfig::instance().repoMetadataPath() / Pathname(escaped_alias) / "mirrorlist.txt";
-
-      zypp::filesystem::PathInfo cacheinfo (cachefile);
-
-      if ( !cacheinfo.isFile() || cacheinfo.mtime() < time(NULL) - (long) ZConfig::instance().repo_refresh_delay() * 60 )
+      ///////////////////////////////////////////////////////////////////
+      /// \class RepoMirrorListTempProvider
+      /// \brief Provide access to downloaded mirror list (in temp space)
+      /// \ingroup g_RAII
+      ///
+      /// Tempspace (and mirror list) are deleted when provider goes out
+      /// of scope.
+      struct RepoMirrorListTempProvider
       {
-        Pathname filepath (url.getPathName());
-        Url abs_url (url);
-
-        DBG << "Getting MirrorList from URL: " << abs_url << endl;
-
-        abs_url.setPathName("");
-        abs_url.setQueryParam("mediahandler", "curl");
-
-        MediaSetAccess access (abs_url);
-        tmpfile = access.provideFile(filepath);
-
-        zypp::filesystem::copy(tmpfile, cachefile);
+       RepoMirrorListTempProvider()
+       {}
+       RepoMirrorListTempProvider( const Pathname & localfile_r )
+       : _localfile( localfile_r )
+       {}
+       RepoMirrorListTempProvider( const Url & url_r )
+       {
+         Url abs_url( url_r );
+         abs_url.setPathName( "/" );
+         abs_url.setQueryParam( "mediahandler", "curl" );
+         _access.reset( new MediaSetAccess( abs_url ) );
+         _localfile = _access->provideFile( url_r.getPathName() );
+       }
+
+       const Pathname & localfile() const
+       { return _localfile; }
+
+      private:
+       shared_ptr<MediaSetAccess> _access;
+       Pathname _localfile;
+      };
+      ///////////////////////////////////////////////////////////////////
+
+      inline std::vector<Url> RepoMirrorListParseXML( const Pathname &tmpfile )
+      {
+       InputStream tmpfstream (tmpfile);
+       media::MetaLinkParser metalink;
+       metalink.parse(tmpfstream);
+       return metalink.getUrls();
       }
 
-      if ( url.asString().find("/metalink") != string::npos )
+      inline std::vector<Url> RepoMirrorListParseTXT( const Pathname &tmpfile )
       {
-        my_urls = parseXML(cachefile);
+       InputStream tmpfstream (tmpfile);
+       std::vector<Url> my_urls;
+       string tmpurl;
+       while (getline(tmpfstream.stream(), tmpurl))
+       {
+         if ( tmpurl[0] == '#' )
+           continue;
+         try {
+           my_urls.push_back(Url(tmpurl));
+         }
+         catch (...)
+         {;}   // ignore malformed urls
+       }
+       return my_urls;
       }
-      else
+
+      /** Parse a local mirrorlist \a listfile_r and return usable URLs */
+      inline std::vector<Url> RepoMirrorListParse( const Url & url_r, const Pathname & listfile_r, bool mirrorListForceMetalink_r )
       {
-        my_urls = parseTXT(cachefile);
+       USR << url_r << " " << listfile_r << endl;
+
+       std::vector<Url> mirrorurls;
+       if ( mirrorListForceMetalink_r || url_r.asString().find( "/metalink" ) != string::npos )
+         mirrorurls = RepoMirrorListParseXML( listfile_r );
+       else
+         mirrorurls = RepoMirrorListParseTXT( listfile_r );
+
+
+       std::vector<Url> ret;
+       for ( auto & murl : mirrorurls )
+       {
+         if ( murl.getScheme() != "rsync" )
+         {
+           size_t delpos = murl.getPathName().find("repodata/repomd.xml");
+           if( delpos != string::npos )
+           {
+             murl.setPathName( murl.getPathName().erase(delpos)  );
+           }
+           ret.push_back( murl );
+
+           if ( ret.size() >= 4 )      // why 4?
+             break;
+         }
+       }
+       return ret;
       }
 
-      setUrls( my_urls );
-      if( urls.empty() )
-        zypp::filesystem::unlink(cachefile);
-    }
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
 
-    RepoMirrorList::RepoMirrorList( const Url &url )
+    RepoMirrorList::RepoMirrorList( const Url & url_r, const Pathname & metadatapath_r, bool mirrorListForceMetalink_r )
     {
-      std::vector<Url> my_urls;
-      Pathname tmpfile;
-
-      Pathname filepath (url.getPathName());
-      Url abs_url (url);
-
-      DBG << "Getting MirrorList from URL: " << abs_url << endl;
-
-      abs_url.setPathName("");
-      abs_url.setQueryParam("mediahandler", "curl");
-
-      MediaSetAccess access (abs_url);
-      tmpfile = access.provideFile(filepath);
-
-      if ( url.asString().find("/metalink") != string::npos )
+      if ( url_r.getScheme() == "file" )
       {
-        my_urls = parseXML(tmpfile);
+       // never cache for local mirrorlist
+       _urls = RepoMirrorListParse( url_r, url_r.getPathName(), mirrorListForceMetalink_r );
       }
-      else
+      else if ( ! PathInfo( metadatapath_r).isDir() )
       {
-        my_urls = parseTXT(tmpfile);
+       // no cachedir
+       RepoMirrorListTempProvider provider( url_r );   // RAII: lifetime of any downloaded files
+       _urls = RepoMirrorListParse( url_r, provider.localfile(), mirrorListForceMetalink_r );
       }
-
-      setUrls( my_urls );
-    }
-
-    void RepoMirrorList::setUrls( std::vector<Url> my_urls )
-    {
-      int valid_urls = 0;
-      for (std::vector<Url>::iterator it = my_urls.begin() ; it != my_urls.end() and valid_urls < 4 ; ++it)
-      {
-        if ( it->getScheme() != "rsync" )
-        {
-          size_t delpos = it->getPathName().find("repodata/repomd.xml");
-          if( delpos != string::npos )
-          {
-            it->setPathName( it->getPathName().erase(delpos)  );
-          }
-          urls.push_back(*it);
-          ++valid_urls;
-        }
-      }
-    }
-
-    std::vector<Url> RepoMirrorList::parseXML( const Pathname &tmpfile ) const
-    {
-      InputStream tmpfstream (tmpfile);
-      media::MetaLinkParser metalink;
-      metalink.parse(tmpfstream);
-      return metalink.getUrls();
-    }
-
-    std::vector<Url> RepoMirrorList::parseTXT( const Pathname &tmpfile ) const
-    {
-      InputStream tmpfstream (tmpfile);
-      std::vector<Url> my_urls;
-      string tmpurl;
-      while (getline(tmpfstream.stream(), tmpurl))
+      else
       {
-        my_urls.push_back(Url(tmpurl));
+       // have cachedir
+       Pathname cachefile( metadatapath_r );
+       if ( mirrorListForceMetalink_r || url_r.asString().find( "/metalink" ) != string::npos )
+         cachefile /= "mirrorlist.xml";
+       else
+         cachefile /= "mirrorlist.txt";
+
+       zypp::filesystem::PathInfo cacheinfo( cachefile );
+       if ( !cacheinfo.isFile() || cacheinfo.mtime() < time(NULL) - (long) ZConfig::instance().repo_refresh_delay() * 60 )
+       {
+         DBG << "Getting MirrorList from URL: " << url_r << endl;
+         RepoMirrorListTempProvider provider( url_r ); // RAII: lifetime of downloaded file
+
+         // Create directory, if not existing
+         DBG << "Copy MirrorList file to " << cachefile << endl;
+         zypp::filesystem::assert_dir( metadatapath_r );
+         zypp::filesystem::hardlinkCopy( provider.localfile(), cachefile );
+       }
+
+       _urls = RepoMirrorListParse( url_r, cachefile, mirrorListForceMetalink_r );
+       if( _urls.empty() )
+       {
+         DBG << "Removing Cachefile as it contains no URLs" << endl;
+         zypp::filesystem::unlink( cachefile );
+       }
       }
-      return my_urls;
-    }
-    
-    std::vector<Url> RepoMirrorList::getUrls() const
-    {
-      return urls;
     }
 
-    RepoMirrorList::~RepoMirrorList()
-    {}
-
-   /////////////////////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////
   } // namespace repo
   ///////////////////////////////////////////////////////////////////
   /////////////////////////////////////////////////////////////////