bnc #446170 - path and url in add_on_products.xml is evaluated wrong
[platform/upstream/libzypp.git] / zypp / repo / susetags / Downloader.cc
1
2 #include <iostream>
3 #include <fstream>
4
5 #include "zypp/base/Logger.h"
6 #include "zypp/base/String.h"
7 #include "zypp/OnMediaLocation.h"
8 #include "zypp/MediaSetAccess.h"
9 #include "zypp/Fetcher.h"
10 #include "zypp/Locale.h"
11 #include "zypp/ZConfig.h"
12 #include "zypp/repo/MediaInfoDownloader.h"
13 #include "zypp/repo/susetags/Downloader.h"
14 #include "zypp/parser/ParseException.h"
15 #include "zypp/parser/susetags/RepoIndex.h"
16 #include "zypp/base/UserRequestException.h"
17 #include "zypp/KeyContext.h" // for SignatureFileChecker
18
19 using namespace std;
20 using namespace zypp::parser;
21 using namespace zypp::parser::susetags;
22
23 namespace zypp
24 {
25 namespace repo
26 {
27 namespace susetags
28 {
29
30 Downloader::Downloader( const RepoInfo &repoinfo )
31   : repo::Downloader(repoinfo)
32 {
33 }
34
35 RepoStatus Downloader::status( MediaSetAccess &media )
36 {
37   Pathname content = media.provideFile( repoInfo().path() + "/content");
38   // the media.1 is always in the root of the media, not like the content
39   // file which is in the path() location
40   Pathname mediafile = media.provideFile( "/media.1/media" );
41
42   return RepoStatus(content) && RepoStatus(mediafile);
43 }
44
45 void Downloader::download( MediaSetAccess &media,
46                            const Pathname &dest_dir,
47                            const ProgressData::ReceiverFnc & progress )
48 {
49   downloadMediaInfo( dest_dir, media );
50
51   SignatureFileChecker sigchecker/*(repoInfo().name())*/;
52
53   Pathname sig = repoInfo().path() + "/content.asc";
54   if ( media.doesFileExist(sig) )
55   {
56     this->enqueue( OnMediaLocation( sig, 1 ) );
57     this->start( dest_dir, media );
58     this->reset();
59
60     sigchecker = SignatureFileChecker( dest_dir + sig/*, repoInfo().name() */);
61   }
62
63   Pathname key = repoInfo().path() + "/content.key";
64   if ( media.doesFileExist(key) )
65   {
66     KeyContext context;
67     context.setRepoInfo(repoInfo());
68     this->enqueue( OnMediaLocation( key, 1 ) );
69     this->start( dest_dir, media );
70     this->reset();
71     sigchecker.addPublicKey(dest_dir + key, context);
72   }
73
74   if ( ! repoInfo().gpgCheck() )
75   {
76     WAR << "Signature checking disabled in config of repository " << repoInfo().alias() << endl;
77   }
78   this->enqueue( OnMediaLocation( repoInfo().path() + "/content", 1 ),
79                  repoInfo().gpgCheck() ? FileChecker(sigchecker) : FileChecker(NullFileChecker()) );
80   this->start( dest_dir, media );
81   this->reset();
82
83   Pathname descr_dir;
84
85   // Content file first to get the repoindex
86   {
87     Pathname inputfile( dest_dir +  repoInfo().path() + "/content" );
88     ContentFileReader content;
89     content.setRepoIndexConsumer( bind( &Downloader::consumeIndex, this, _1 ) );
90     content.parse( inputfile );
91   }
92   if ( ! _repoindex )
93   {
94     ZYPP_THROW( ParseException( (dest_dir+repoInfo().path()).asString() + ": " + "No repository index in content file." ) );
95   }
96   MIL << "RepoIndex: " << _repoindex << endl;
97   if ( _repoindex->metaFileChecksums.empty() )
98   {
99     ZYPP_THROW( ParseException( (dest_dir+repoInfo().path()).asString() + ": " + "No metadata checksums in content file." ) );
100   }
101   if ( _repoindex->signingKeys.empty() )
102   {
103     WAR << "No signing keys defined." << endl;
104   }
105
106   // Prepare parsing
107   descr_dir = _repoindex->descrdir; // path below reporoot
108   //_datadir  = _repoIndex->datadir;  // path below reporoot
109
110
111   for_( it, _repoindex->metaFileChecksums.begin(), _repoindex->metaFileChecksums.end() )
112   {
113     // omit unwanted translations
114     if ( str::hasPrefix( it->first, "packages" ) )
115     {
116       std::string rest( str::stripPrefix( it->first, "packages" ) );
117       if ( ! (   rest.empty()
118               || rest == ".DU"
119               || rest == ".en"
120               || rest == ".gz"
121               || rest == ".DU.gz"
122               || rest == ".en.gz" ) )
123       {
124         // Not 100% correct as we take each fallback of textLocale
125         Locale toParse( ZConfig::instance().textLocale() );
126         while ( toParse != Locale::noCode )
127         {
128           if ( rest == ("."+toParse.code()) || (rest == ("."+toParse.code()+".gz")) )
129             break;
130           toParse = toParse.fallback();
131         }
132         if ( toParse == Locale::noCode )
133         {
134           // discard
135           continue;
136         }
137       }
138     }
139     else if ( it->first == "patterns.pat"
140               || it->first == "patterns.pat.gz" )
141     {
142       // take all patterns in one go
143     }
144     else if ( str::endsWith( it->first, ".pat" )
145               || str::endsWith( it->first, ".pat.gz" ) )
146     {
147
148       // *** see also zypp/parser/susetags/RepoParser.cc ***
149
150       // omit unwanted patterns, see https://bugzilla.novell.com/show_bug.cgi?id=298716
151       // expect "<name>.<arch>.pat[.gz]", <name> might contain additional dots
152       // split at dots, take .pat or .pat.gz into account
153
154       std::vector<std::string> patparts;
155       unsigned archpos = 2;
156       // expect "<name>.<arch>.pat[.gz]", <name> might contain additional dots
157       unsigned count = str::split( it->first, std::back_inserter(patparts), "." );
158       if ( patparts[count-1] == "gz" )
159           archpos++;
160
161       if ( count > archpos )
162       {
163         try                             // might by an invalid architecture
164         {
165           Arch patarch( patparts[count-archpos] );
166           if ( !patarch.compatibleWith( ZConfig::instance().systemArchitecture() ) )
167           {
168             // discard, if not compatible
169             MIL << "Discarding pattern " << it->first << endl;
170             continue;
171           }
172         }
173         catch ( const Exception & excpt )
174         {
175           WAR << "Pattern file name does not contain recognizable architecture: " << it->first << endl;
176           // keep .pat file if it doesn't contain an recognizable arch
177         }
178       }
179     }
180     MIL << "adding job " << it->first << endl;
181     OnMediaLocation location( repoInfo().path() + descr_dir + it->first, 1 );
182     location.setChecksum( it->second );
183     this->enqueueDigested(location);
184   }
185
186   for_( it, _repoindex->mediaFileChecksums.begin(), _repoindex->mediaFileChecksums.end() )
187   {
188     // Repo adopts license files listed in HASH
189     if ( it->first != "license.tar.gz" )
190       continue;
191
192     MIL << "adding job " << it->first << endl;
193     OnMediaLocation location( repoInfo().path() + it->first, 1 );
194     location.setChecksum( it->second );
195     this->enqueueDigested(location);
196   }
197
198   for_( it, _repoindex->signingKeys.begin(),_repoindex->signingKeys.end() )
199   {
200     MIL << "adding job " << it->first << endl;
201     OnMediaLocation location( repoInfo().path() + it->first, 1 );
202     location.setChecksum( it->second );
203     this->enqueueDigested(location);
204   }
205
206   this->start( dest_dir, media );
207 }
208
209 void Downloader::consumeIndex( const RepoIndex_Ptr & data_r )
210 {
211   MIL << "Consuming repo index" << endl;
212   _repoindex = data_r;
213 }
214
215 }// ns susetags
216 }// ns source
217 } // ns zypp