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 Pathname repomd = media.provideFile( repoInfo().path() + "/repodata/repomd.xml");
41 return RepoStatus(repomd);
44 static OnMediaLocation loc_with_path_prefix( const OnMediaLocation & loc, const Pathname & prefix )
46 if (prefix.empty() || prefix == "/")
49 OnMediaLocation loc_with_path(loc);
50 loc_with_path.changeFilename(prefix / loc.filename());
54 // search old repository file file to run the delta algorithm on
55 static Pathname search_deltafile( const Pathname & dir, const Pathname & file )
58 if (!PathInfo(dir).isDir())
60 string base = file.basename();
61 size_t hypoff = base.find("-");
62 if (hypoff != string::npos)
63 base.replace(0, hypoff + 1, "");
64 size_t basesize = base.size();
65 std::list<Pathname> retlist;
66 if (!filesystem::readdir(retlist, dir, false))
68 for_( it, retlist.begin(), retlist.end() )
70 string fn = it->asString();
71 if (fn.size() >= basesize && fn.substr(fn.size() - basesize, basesize) == base)
78 bool Downloader::patches_Callback( const OnMediaLocation & loc_r, const string & id_r )
80 OnMediaLocation loc_with_path(loc_with_path_prefix(loc_r, repoInfo().path()));
81 MIL << id_r << " : " << loc_with_path << endl;
82 this->enqueueDigested(loc_with_path, FileChecker(), search_deltafile(_delta_dir + "repodata", loc_r.filename()));
87 //bool repomd_Callback2( const OnMediaLocation &loc, const ResourceType &dtype, const std::string &typestr, UserData & userData_r );
89 ///////////////////////////////////////////////////////////////////
92 ///////////////////////////////////////////////////////////////////
94 /// \brief Helper filtering the files offered by a RepomdFileReader
96 /// Clumsy construct; basically an Impl class for Downloader, maintained
97 /// in Downloader::download only while parsing a repomd.xml.
99 /// Introduced because Downloader itself lacks an Impl class, thus can't
100 /// be extended to provide more data to the callbacks without losing
101 /// binary compatibility.
102 ///////////////////////////////////////////////////////////////////
103 struct RepomdFileReaderCallback2
105 RepomdFileReaderCallback2( const RepomdFileReader::ProcessResource & origCallback_r )
106 : _origCallback( origCallback_r )
108 addWantedLocale( ZConfig::instance().textLocale() );
109 for ( const Locale & it : ZConfig::instance().repoRefreshLocales() )
110 addWantedLocale( it );
113 /** The callback invoked by the RepomdFileReader */
114 bool repomd_Callback2( const OnMediaLocation & loc_r, const ResourceType & dtype_r, const std::string & typestr_r )
116 // filter well known resource types
117 if ( dtype_r == ResourceType::OTHER || dtype_r == ResourceType::FILELISTS )
118 return true; // skip it
120 // filter custom resource types (by string)
121 if ( dtype_r == ResourceType::NONE )
124 if ( str::hasPrefix( typestr_r, "susedata." ) && ! wantLocale( Locale(typestr_r.c_str()+9) ) )
125 return true; // skip it
129 return( _origCallback ? _origCallback( loc_r, dtype_r ) : true );
133 bool wantLocale( const Locale & locale_r ) const
134 { return _wantedLocales.count( locale_r ); }
136 void addWantedLocale( Locale locale_r )
140 _wantedLocales.insert( locale_r );
141 locale_r = locale_r.fallback();
146 RepomdFileReader::ProcessResource _origCallback; ///< Original Downloader callback
147 LocaleSet _wantedLocales; ///< Locales do download
151 ///////////////////////////////////////////////////////////////////
153 bool Downloader::repomd_Callback( const OnMediaLocation & loc_r, const ResourceType & dtype_r )
155 // NOTE: Filtering of unwanted files is done in RepomdFileReaderCallback2!
157 // schedule file for download
158 const OnMediaLocation & loc_with_path(loc_with_path_prefix(loc_r, repoInfo().path()));
159 this->enqueueDigested(loc_with_path, FileChecker(), search_deltafile(_delta_dir + "repodata", loc_r.filename()));
161 // We got a patches file we need to read, to add patches listed
162 // there, so we transfer what we have in the queue, and
163 // queue the patches in the patches callback
164 if ( dtype_r == ResourceType::PATCHES )
166 this->start( _dest_dir, *_media_ptr );
167 // now the patches.xml file must exists
168 PatchesFileReader( _dest_dir + repoInfo().path() + loc_r.filename(),
169 bind( &Downloader::patches_Callback, this, _1, _2));
174 void Downloader::download( MediaSetAccess & media, const Pathname & dest_dir, const ProgressData::ReceiverFnc & progressrcv )
176 Pathname masterIndex( repoInfo().path() / "/repodata/repomd.xml" );
177 defaultDownloadMasterIndex( media, dest_dir, masterIndex );
179 // init the data stored in Downloader itself
180 _media_ptr = (&media);
181 _dest_dir = dest_dir;
183 // init the extended data
184 RepomdFileReaderCallback2 pimpl( bind(&Downloader::repomd_Callback, this, _1, _2) );
187 RepomdFileReader( dest_dir / masterIndex,
188 RepomdFileReader::ProcessResource2( bind(&RepomdFileReaderCallback2::repomd_Callback2, &pimpl, _1, _2, _3) ) );
191 start( dest_dir, media );