Imported Upstream version 17.0.0
[platform/upstream/libzypp.git] / zypp / repo / yum / Downloader.cc
index a31581c..b0b8ee0 100644 (file)
@@ -9,10 +9,9 @@
 
 #include <fstream>
 #include "zypp/base/String.h"
-#include "zypp/base/Logger.h"
+#include "zypp/base/LogTools.h"
 #include "zypp/base/Function.h"
-
-#include "zypp/Date.h"
+#include "zypp/ZConfig.h"
 
 #include "zypp/parser/yum/RepomdFileReader.h"
 #include "zypp/parser/yum/PatchesFileReader.h"
@@ -32,150 +31,174 @@ namespace repo
 namespace yum
 {
 
-Downloader::Downloader( const RepoInfo &info )
-  : _info(info), _media_ptr(0L)
-{
-}
-
-Downloader::Downloader(const Pathname &path )
-{
-    RepoInfo info;
-    info.setPath(path);
-    _info = info;
-}
+Downloader::Downloader( const RepoInfo &repoinfo , const Pathname &delta_dir)
+  : repo::Downloader(repoinfo), _delta_dir(delta_dir), _media_ptr(0L)
+{}
 
 RepoStatus Downloader::status( MediaSetAccess &media )
 {
-  Pathname repomd = media.provideFile( _info.path() + "/repodata/repomd.xml");
-  return RepoStatus(repomd);
+  RepoStatus ret( media.provideFile( repoInfo().path() / "/repodata/repomd.xml" ) );
+  if ( !ret.empty() )  // else: mandatory master index is missing
+    ret = ret && RepoStatus( media.provideOptionalFile( "/media.1/media" ) );
+  // else: mandatory master index is missing -> stay empty
+  return ret;
 }
 
-static OnMediaLocation
-loc_with_path_prefix(const OnMediaLocation & loc,
-                     const Pathname & prefix)
+static OnMediaLocation loc_with_path_prefix( const OnMediaLocation & loc, const Pathname & prefix )
 {
   if (prefix.empty() || prefix == "/")
     return loc;
 
   OnMediaLocation loc_with_path(loc);
-  loc_with_path.setFilename(prefix / loc.filename());
+  loc_with_path.changeFilename(prefix / loc.filename());
   return loc_with_path;
 }
 
+// search old repository file file to run the delta algorithm on
+static Pathname search_deltafile( const Pathname & dir, const Pathname & file )
+{
+  Pathname deltafile;
+  if (!PathInfo(dir).isDir())
+    return deltafile;
+  string base = file.basename();
+  size_t hypoff = base.find("-");
+  if (hypoff != string::npos)
+    base.replace(0, hypoff + 1, "");
+  size_t basesize = base.size();
+  std::list<Pathname> retlist;
+  if (!filesystem::readdir(retlist, dir, false))
+  {
+    for_( it, retlist.begin(), retlist.end() )
+    {
+      string fn = it->asString();
+      if (fn.size() >= basesize && fn.substr(fn.size() - basesize, basesize) == base)
+       deltafile = *it;
+    }
+  }
+  return deltafile;
+}
 
-bool Downloader::patches_Callback( const OnMediaLocation &loc,
-                                   const string &id )
+bool Downloader::patches_Callback( const OnMediaLocation & loc_r, const string & id_r )
 {
-  OnMediaLocation loc_with_path(loc_with_path_prefix(loc, _info.path()));
-  MIL << id << " : " << loc_with_path << endl;
-  this->enqueueDigested(loc_with_path);
+  OnMediaLocation loc_with_path(loc_with_path_prefix(loc_r, repoInfo().path()));
+  MIL << id_r << " : " << loc_with_path << endl;
+  this->enqueueDigested(loc_with_path,  FileChecker(), search_deltafile(_delta_dir + "repodata", loc_r.filename()));
   return true;
 }
 
 
-bool Downloader::repomd_Callback( const OnMediaLocation &loc,
-                                  const ResourceType &dtype )
-{
-  OnMediaLocation loc_with_path(loc_with_path_prefix(loc, _info.path()));
-  MIL << dtype << " : " << loc_with_path << endl;
+//bool repomd_Callback2( const OnMediaLocation &loc, const ResourceType &dtype, const std::string &typestr, UserData & userData_r );
 
-  //! \todo do this through a ZConfig call so that it is always in sync with parser
-  // skip other
-  if ( dtype == ResourceType::OTHER )
-  {
-    MIL << "Skipping other.xml" << endl;
-    return true;
-  }
-  // skip filelists
-  if ( dtype == ResourceType::FILELISTS )
+///////////////////////////////////////////////////////////////////
+namespace
+{
+  ///////////////////////////////////////////////////////////////////
+  /// \class Impl
+  /// \brief Helper filtering the files offered by a RepomdFileReader
+  ///
+  /// Clumsy construct; basically an Impl class for Downloader, maintained
+  /// in Downloader::download only while parsing a repomd.xml.
+  ///
+  /// Introduced because Downloader itself lacks an Impl class, thus can't
+  /// be extended to provide more data to the callbacks without losing
+  /// binary compatibility.
+  ///////////////////////////////////////////////////////////////////
+  struct RepomdFileReaderCallback2
   {
-    MIL << "Skipping filelists.xml.gz" << endl;
-    return true;
-  }
+    RepomdFileReaderCallback2( const RepomdFileReader::ProcessResource & origCallback_r )
+    : _origCallback( origCallback_r )
+    {
+      addWantedLocale( ZConfig::instance().textLocale() );
+      for ( const Locale & it : ZConfig::instance().repoRefreshLocales() )
+       addWantedLocale( it );
+    }
+
+    /** The callback invoked by the RepomdFileReader */
+    bool repomd_Callback2( const OnMediaLocation & loc_r, const ResourceType & dtype_r, const std::string & typestr_r )
+    {
+      // filter well known resource types
+      if ( dtype_r == ResourceType::OTHER || dtype_r == ResourceType::FILELISTS )
+       return true;    // skip it
+
+      // filter custom resource types (by string)
+      if ( dtype_r == ResourceType::NONE )
+      {
+       // susedata.LANG
+       if ( str::hasPrefix( typestr_r, "susedata." ) && ! wantLocale( Locale(typestr_r.c_str()+9) ) )
+         return true;  // skip it
+      }
+
+      // take it
+      return( _origCallback ? _origCallback( loc_r, dtype_r ) : true );
+    }
+
+  private:
+    bool wantLocale( const Locale & locale_r ) const
+    { return _wantedLocales.count( locale_r ); }
+
+    void addWantedLocale( Locale locale_r )
+    {
+      while ( locale_r )
+      {
+       _wantedLocales.insert( locale_r );
+       locale_r = locale_r.fallback();
+      }
+    }
+
+  private:
+    RepomdFileReader::ProcessResource _origCallback;   ///< Original Downloader callback
+    LocaleSet _wantedLocales;                          ///< Locales do download
+
+  };
+} // namespace
+///////////////////////////////////////////////////////////////////
+
+bool Downloader::repomd_Callback( const OnMediaLocation & loc_r, const ResourceType & dtype_r )
+{
+  // NOTE: Filtering of unwanted files is done in RepomdFileReaderCallback2!
 
-  this->enqueueDigested(loc_with_path);
+  // schedule file for download
+  const OnMediaLocation & loc_with_path(loc_with_path_prefix(loc_r, repoInfo().path()));
+  this->enqueueDigested(loc_with_path, FileChecker(), search_deltafile(_delta_dir + "repodata", loc_r.filename()));
 
   // We got a patches file we need to read, to add patches listed
   // there, so we transfer what we have in the queue, and
   // queue the patches in the patches callback
-  if ( dtype == ResourceType::PATCHES )
+  if ( dtype_r == ResourceType::PATCHES )
   {
     this->start( _dest_dir, *_media_ptr );
     // now the patches.xml file must exists
-    PatchesFileReader( _dest_dir + _info.path() + loc.filename(),
+    PatchesFileReader( _dest_dir + repoInfo().path() + loc_r.filename(),
                        bind( &Downloader::patches_Callback, this, _1, _2));
   }
-
   return true;
 }
 
-void Downloader::download( MediaSetAccess &media,
-                           const Pathname &dest_dir,
-                           const ProgressData::ReceiverFnc & progressrcv )
+void Downloader::download( MediaSetAccess & media, const Pathname & dest_dir, const ProgressData::ReceiverFnc & progressrcv )
 {
-  Pathname repomdpath =  _info.path() + "/repodata/repomd.xml";
-  Pathname keypath =  _info.path() + "/repodata/repomd.xml.key";
-  Pathname sigpath =  _info.path() + "/repodata/repomd.xml.asc";
-
-  _media_ptr = (&media);
-
-  ProgressData progress;
-  progress.sendTo(progressrcv);
-  progress.toMin();
+  downloadMediaInfo( dest_dir, media );
 
-  //downloadMediaInfo( dest_dir, _media );
+  Pathname masterIndex( repoInfo().path() / "/repodata/repomd.xml" );
+  defaultDownloadMasterIndex( media, dest_dir, masterIndex );
 
+  // init the data stored in Downloader itself
+  _media_ptr = (&media);
   _dest_dir = dest_dir;
 
-  SignatureFileChecker sigchecker(_info.name());
-
-  if ( _media_ptr->doesFileExist(sigpath) )
-  {
-      this->enqueue( OnMediaLocation(sigpath,1).setOptional(true) );
-     this->start( dest_dir, *_media_ptr);
-     this->reset();
-     sigchecker = SignatureFileChecker(dest_dir + sigpath, _info.name());
-  }
-
-
-  if ( _media_ptr->doesFileExist(keypath) )
-  {
-      this->enqueue( OnMediaLocation(keypath,1).setOptional(true) );
-    this->start( dest_dir, *_media_ptr);
-    this->reset();
-    sigchecker.addPublicKey(dest_dir + keypath);
-  }
-
-
-  this->start( dest_dir, *_media_ptr );
-
-  if ( ! progress.tick() )
-    ZYPP_THROW(AbortRequestException());
-
-  if ( ! _info.gpgCheck() )
-  {
-    WAR << "Signature checking disabled in config of repository " << _info.alias() << endl;
-  }
-  this->enqueue( OnMediaLocation(repomdpath,1),
-                 _info.gpgCheck() ? FileChecker(sigchecker) : FileChecker(NullFileChecker()) );
-  this->start( dest_dir, *_media_ptr);
-
-  if ( ! progress.tick() )
-        ZYPP_THROW(AbortRequestException());
-
-  this->reset();
+  // init the extended data
+  RepomdFileReaderCallback2 pimpl( bind(&Downloader::repomd_Callback, this, _1, _2) );
 
-  Reader reader( dest_dir + _info.path() + "/repodata/repomd.xml" );
-  RepomdFileReader( dest_dir + _info.path() + "/repodata/repomd.xml", bind( &Downloader::repomd_Callback, this, _1, _2));
+  // setup parser
+  RepomdFileReader( dest_dir / masterIndex,
+                   RepomdFileReader::ProcessResource2( bind(&RepomdFileReaderCallback2::repomd_Callback2, &pimpl, _1, _2, _3) ) );
 
   // ready, go!
-  this->start( dest_dir, *_media_ptr);
-  progress.toMax();
+  start( dest_dir, media );
 }
 
-}// ns yum
-}// ns source
-} // ns zypp
+} // namespace yum
+} // namespace repo
+} // namespace zypp