1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
11 #include <solv/solvversion.h>
12 #include "zypp/base/String.h"
13 #include "zypp/base/LogTools.h"
14 #include "zypp/base/Function.h"
15 #include "zypp/ZConfig.h"
17 #include "Downloader.h"
18 #include "zypp/repo/MediaInfoDownloader.h"
19 #include "zypp/base/UserRequestException.h"
20 #include "zypp/parser/xml/Reader.h"
21 #include "zypp/parser/yum/RepomdFileReader.h"
23 using namespace zypp::xml;
24 using namespace zypp::parser::yum;
32 ///////////////////////////////////////////////////////////////////
35 inline OnMediaLocation loc_with_path_prefix( OnMediaLocation loc_r, const Pathname & prefix_r )
37 if ( ! prefix_r.empty() && prefix_r != "/" )
38 loc_r.changeFilename( prefix_r / loc_r.filename() );
42 // search old repository file to run the delta algorithm on
43 Pathname search_deltafile( const Pathname & dir, const Pathname & file )
46 if ( ! PathInfo(dir).isDir() )
49 // Strip the checksum preceding the file stem so we can look for an
50 // old *-primary.xml which may contain some reusable blocks.
51 std::string base { file.basename() };
52 size_t hypoff = base.find( "-" );
53 if ( hypoff != std::string::npos )
54 base.replace( 0, hypoff + 1, "" );
56 std::list<std::string> retlist;
57 if ( ! filesystem::readdir( retlist, dir, false ) )
59 for ( const auto & fn : retlist )
61 if ( str::endsWith( fn, base ) )
68 ///////////////////////////////////////////////////////////////////
70 ///////////////////////////////////////////////////////////////////
71 /// \class Downloader::Impl
72 /// \brief Helper filtering the files offered by a RepomdFileReader
74 /// Clumsy construct; basically an Impl class for Downloader, maintained
75 /// in Downloader::download only while parsing a repomd.xml.
78 /// type_db (sqlite, ignored by zypp)
79 /// type_zck (zchunk, preferred)
82 ///////////////////////////////////////////////////////////////////
83 struct Downloader::Impl
88 Impl( Downloader & downloader_r, MediaSetAccess & media_r, const Pathname & destDir_r )
89 : _downloader { downloader_r }
91 , _destDir { destDir_r }
93 addWantedLocale( ZConfig::instance().textLocale() );
94 for ( const Locale & it : ZConfig::instance().repoRefreshLocales() )
95 addWantedLocale( it );
98 /** The callback invoked by the RepomdFileReader.
99 * It's a pity, but in the presence of separate "type" and "type_zck" entries,
100 * we have to scan the whole file before deciding what to download....
102 bool operator()( const OnMediaLocation & loc_r, const std::string & typestr_r )
104 if ( str::endsWith( typestr_r, "_db" ) )
105 return true; // skip sqlitedb
107 bool zchk { str::endsWith( typestr_r, "_zck" ) };
108 #ifdef LIBSOLVEXT_FEATURE_ZSTD_COMPRESSION
109 const std::string & basetype { zchk ? typestr_r.substr( 0, typestr_r.size()-4 ) : typestr_r };
112 return true; // skip zchunk if not supported by libsolv
113 const std::string & basetype { typestr_r };
116 // filter well known resource types
117 if ( basetype == "other" || basetype == "filelists" )
118 return true; // skip it
120 // filter localized susedata
121 if ( str::startsWith( basetype, "susedata." ) )
124 if ( ! wantLocale( Locale(basetype.c_str()+9) ) )
125 return true; // skip it
128 // may take it... (prefer zchnk)
129 if ( zchk || !_wantedFiles.count( basetype ) )
130 _wantedFiles[basetype] = loc_r;
137 // schedule fileS for download
138 for ( const auto & el : _wantedFiles )
140 const OnMediaLocation & loc { el.second };
141 const OnMediaLocation & loc_with_path { loc_with_path_prefix( loc, _downloader.repoInfo().path() ) };
142 _downloader.enqueueDigested( loc_with_path, FileChecker(), search_deltafile( deltaDir()/"repodata", loc.filename() ) );
147 const Pathname & deltaDir() const
148 { return _downloader._deltaDir; }
150 bool wantLocale( const Locale & locale_r ) const
151 { return _wantedLocales.count( locale_r ); }
153 void addWantedLocale( Locale locale_r )
157 _wantedLocales.insert( locale_r );
158 locale_r = locale_r.fallback();
163 Downloader & _downloader;
164 MediaSetAccess & _media;
165 const Pathname & _destDir;
167 LocaleSet _wantedLocales; ///< Locales do download
168 std::map<std::string,OnMediaLocation> _wantedFiles;
171 ///////////////////////////////////////////////////////////////////
175 ///////////////////////////////////////////////////////////////////
177 Downloader::Downloader( const RepoInfo & info_r, const Pathname & deltaDir_r )
178 : repo::Downloader { info_r}
179 , _deltaDir { deltaDir_r }
182 void Downloader::download( MediaSetAccess & media_r, const Pathname & destDir_r, const ProgressData::ReceiverFnc & progress_r )
184 downloadMediaInfo( destDir_r, media_r );
186 Pathname masterIndex { repoInfo().path() / "/repodata/repomd.xml" };
187 defaultDownloadMasterIndex( media_r, destDir_r, masterIndex );
190 Impl pimpl( *this, media_r, destDir_r );
191 RepomdFileReader( destDir_r / masterIndex, std::ref(pimpl) );
195 start( destDir_r, media_r );
198 RepoStatus Downloader::status( MediaSetAccess & media_r )
200 RepoStatus ret { media_r.provideOptionalFile( repoInfo().path() / "/repodata/repomd.xml" ) };
201 if ( !ret.empty() ) // else: mandatory master index is missing
202 ret = ret && RepoStatus( media_r.provideOptionalFile( "/media.1/media" ) );
203 // else: mandatory master index is missing -> stay empty