1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
11 #include "zypp/base/String.h"
12 #include "zypp/base/LogTools.h"
13 #include "zypp/base/Function.h"
14 #include "zypp/ZConfig.h"
16 #include "zypp/parser/yum/RepomdFileReader.h"
17 #include "zypp/parser/yum/PatchesFileReader.h"
18 #include "Downloader.h"
19 #include "zypp/repo/MediaInfoDownloader.h"
20 #include "zypp/base/UserRequestException.h"
21 #include "zypp/parser/xml/Reader.h"
24 using namespace zypp::xml;
25 using namespace zypp::parser::yum;
34 Downloader::Downloader( const RepoInfo &repoinfo , const Pathname &delta_dir)
35 : repo::Downloader(repoinfo), _delta_dir(delta_dir), _media_ptr(0L)
38 RepoStatus Downloader::status( MediaSetAccess &media )
40 RepoStatus ret( media.provideFile( repoInfo().path() / "/repodata/repomd.xml" ) );
41 if ( !ret.empty() ) // else: mandatory master index is missing
42 ret = ret && RepoStatus( media.provideOptionalFile( "/media.1/media" ) );
43 // else: mandatory master index is missing -> stay empty
47 static OnMediaLocation loc_with_path_prefix( const OnMediaLocation & loc, const Pathname & prefix )
49 if (prefix.empty() || prefix == "/")
52 OnMediaLocation loc_with_path(loc);
53 loc_with_path.changeFilename(prefix / loc.filename());
57 // search old repository file file to run the delta algorithm on
58 static Pathname search_deltafile( const Pathname & dir, const Pathname & file )
61 if (!PathInfo(dir).isDir())
63 string base = file.basename();
64 size_t hypoff = base.find("-");
65 if (hypoff != string::npos)
66 base.replace(0, hypoff + 1, "");
67 size_t basesize = base.size();
68 std::list<Pathname> retlist;
69 if (!filesystem::readdir(retlist, dir, false))
71 for_( it, retlist.begin(), retlist.end() )
73 string fn = it->asString();
74 if (fn.size() >= basesize && fn.substr(fn.size() - basesize, basesize) == base)
81 bool Downloader::patches_Callback( const OnMediaLocation & loc_r, const string & id_r )
83 OnMediaLocation loc_with_path(loc_with_path_prefix(loc_r, repoInfo().path()));
84 MIL << id_r << " : " << loc_with_path << endl;
85 this->enqueueDigested(loc_with_path, FileChecker(), search_deltafile(_delta_dir + "repodata", loc_r.filename()));
90 //bool repomd_Callback2( const OnMediaLocation &loc, const ResourceType &dtype, const std::string &typestr, UserData & userData_r );
92 ///////////////////////////////////////////////////////////////////
95 ///////////////////////////////////////////////////////////////////
97 /// \brief Helper filtering the files offered by a RepomdFileReader
99 /// Clumsy construct; basically an Impl class for Downloader, maintained
100 /// in Downloader::download only while parsing a repomd.xml.
102 /// Introduced because Downloader itself lacks an Impl class, thus can't
103 /// be extended to provide more data to the callbacks without losing
104 /// binary compatibility.
105 ///////////////////////////////////////////////////////////////////
106 struct RepomdFileReaderCallback2
108 RepomdFileReaderCallback2( const RepomdFileReader::ProcessResource & origCallback_r )
109 : _origCallback( origCallback_r )
111 addWantedLocale( ZConfig::instance().textLocale() );
112 for ( const Locale & it : ZConfig::instance().repoRefreshLocales() )
113 addWantedLocale( it );
116 /** The callback invoked by the RepomdFileReader */
117 bool repomd_Callback2( const OnMediaLocation & loc_r, const ResourceType & dtype_r, const std::string & typestr_r )
119 // filter well known resource types
120 if ( dtype_r == ResourceType::OTHER || dtype_r == ResourceType::FILELISTS )
121 return true; // skip it
123 // filter custom resource types (by string)
124 if ( dtype_r == ResourceType::NONE )
127 if ( str::hasPrefix( typestr_r, "susedata." ) && ! wantLocale( Locale(typestr_r.c_str()+9) ) )
128 return true; // skip it
132 return( _origCallback ? _origCallback( loc_r, dtype_r ) : true );
136 bool wantLocale( const Locale & locale_r ) const
137 { return _wantedLocales.count( locale_r ); }
139 void addWantedLocale( Locale locale_r )
143 _wantedLocales.insert( locale_r );
144 locale_r = locale_r.fallback();
149 RepomdFileReader::ProcessResource _origCallback; ///< Original Downloader callback
150 LocaleSet _wantedLocales; ///< Locales do download
154 ///////////////////////////////////////////////////////////////////
156 bool Downloader::repomd_Callback( const OnMediaLocation & loc_r, const ResourceType & dtype_r )
158 // NOTE: Filtering of unwanted files is done in RepomdFileReaderCallback2!
160 // schedule file for download
161 const OnMediaLocation & loc_with_path(loc_with_path_prefix(loc_r, repoInfo().path()));
162 this->enqueueDigested(loc_with_path, FileChecker(), search_deltafile(_delta_dir + "repodata", loc_r.filename()));
164 // We got a patches file we need to read, to add patches listed
165 // there, so we transfer what we have in the queue, and
166 // queue the patches in the patches callback
167 if ( dtype_r == ResourceType::PATCHES )
169 this->start( _dest_dir, *_media_ptr );
170 // now the patches.xml file must exists
171 PatchesFileReader( _dest_dir + repoInfo().path() + loc_r.filename(),
172 bind( &Downloader::patches_Callback, this, _1, _2));
177 void Downloader::download( MediaSetAccess & media, const Pathname & dest_dir, const ProgressData::ReceiverFnc & progressrcv )
179 downloadMediaInfo( dest_dir, media );
181 Pathname masterIndex( repoInfo().path() / "/repodata/repomd.xml" );
182 defaultDownloadMasterIndex( media, dest_dir, masterIndex );
184 // init the data stored in Downloader itself
185 _media_ptr = (&media);
186 _dest_dir = dest_dir;
188 // init the extended data
189 RepomdFileReaderCallback2 pimpl( bind(&Downloader::repomd_Callback, this, _1, _2) );
192 RepomdFileReader( dest_dir / masterIndex,
193 RepomdFileReader::ProcessResource2( bind(&RepomdFileReaderCallback2::repomd_Callback2, &pimpl, _1, _2, _3) ) );
196 start( dest_dir, media );