libzypp 17.37.17
RepoindexFileReader.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12#include <iostream>
13#include <unordered_map>
14
15#include <zypp/base/String.h>
16#include <zypp/base/Logger.h>
17#include <zypp/base/Gettext.h>
18#include <utility>
19#include <zypp-core/base/InputStream>
20#include <zypp-core/base/DefaultIntegral>
21
22#include <zypp/Pathname.h>
23
25#include <zypp-core/parser/ParseException>
26
27#include <zypp/RepoInfo.h>
28
30
31
32#undef ZYPP_BASE_LOGGER_LOGGROUP
33#define ZYPP_BASE_LOGGER_LOGGROUP "parser"
34
35using std::endl;
36
37namespace zypp
38{
39 namespace parser
40 {
41 using xml::Reader;
42 using xml::XmlString;
43
45 namespace
46 {
47 class VarReplacer : private base::NonCopyable
48 {
49 public:
51 void setGlobalVar( const std::string & key_r, const std::string & val_r )
52 { _global[key_r] = replace( val_r ); }
53
55 void setSectionVar( const std::string & key_r, const std::string & val_r )
56 { _section[key_r] = replace( val_r ); }
57
59 void clearSectionVars()
60 { _section.clear(); }
61
62 std::string replace( const std::string & val_r ) const
63 {
64 std::string::size_type vbeg = val_r.find( "%{", 0 );
65 if ( vbeg == std::string::npos )
66 return val_r;
67
68 str::Str ret;
69 std::string::size_type cbeg = 0;
70 for( ; vbeg != std::string::npos; vbeg = val_r.find( "%{", vbeg ) )
71 {
72 std::string::size_type nbeg = vbeg+2;
73 std::string::size_type nend = val_r.find( '}', nbeg );
74 if ( nend == std::string::npos )
75 {
76 WAR << "Incomplete variable in '" << val_r << "'" << endl;
77 break;
78 }
79 const std::string * varptr = getVar( val_r.substr( nbeg, nend-nbeg ) );
80 if ( varptr )
81 {
82 if ( cbeg < vbeg )
83 ret << val_r.substr( cbeg, vbeg-cbeg );
84 ret << *varptr;
85 cbeg = nend+1;
86 }
87 else
88 WAR << "Undefined variable %{" << val_r.substr( nbeg, nend-nbeg ) << "} in '" << val_r << "'" << endl;
89 vbeg = nend+1;
90 }
91 if ( cbeg < val_r.size() )
92 ret << val_r.substr( cbeg );
93
94 return ret;
95 }
96
97 private:
98 const std::string * getVar( const std::string & key_r ) const
99 {
100 const std::string * ret = getVar( key_r, _section );
101 if ( not ret )
102 ret = getVar( key_r, _global );
103 return ret;
104 }
105
106 const std::string * getVar( const std::string & key_r, const std::unordered_map<std::string,std::string> & map_r ) const
107 {
108 const auto & iter = map_r.find( key_r );
109 if ( iter != map_r.end() )
110 return &(iter->second);
111 return nullptr;
112 }
113
114 private:
115 std::unordered_map<std::string,std::string> _global;
116 std::unordered_map<std::string,std::string> _section;
117 };
118 } // namespace
120
122 //
123 // CLASS NAME : RepoindexFileReader::Impl
124 //
126 {
127 public:
134
138 bool consumeNode( Reader & reader_r );
139
141
142 private:
143 bool getAttrValue( const std::string & key_r, Reader & reader_r, std::string & value_r )
144 {
145 const XmlString & s( reader_r->getAttribute( key_r ) );
146 if ( s.get() )
147 {
148 value_r = _replacer.replace( s.asString() );
149 return !value_r.empty();
150 }
151 value_r.clear();
152 return false;
153 }
154
155 private:
158 VarReplacer _replacer;
159 };
160
161
164 : _callback(std::move(callback))
165 {
166 Reader reader( is );
167 MIL << "Reading " << is.path() << endl;
168 reader.foreachNode( bind( &RepoindexFileReader::Impl::consumeNode, this, _1 ) );
169 }
170
171 // --------------------------------------------------------------------------
172
173 /*
174 * xpath and multiplicity of processed nodes are included in the code
175 * for convenience:
176 *
177 * // xpath: <xpath> (?|*|+)
178 *
179 * if multiplicity is ommited, then the node has multiplicity 'one'.
180 */
181
182 // --------------------------------------------------------------------------
183
185 {
186 if ( reader_r->nodeType() == XML_READER_TYPE_ELEMENT )
187 {
188 // xpath: /repoindex
189 if ( reader_r->name() == "repoindex" )
190 {
191 while ( reader_r.nextNodeAttribute() )
192 {
193 const std::string & name( reader_r->localName().asString() );
194 const std::string & value( reader_r->value().asString() );
195 _replacer.setGlobalVar( name, value );
196 // xpath: /repoindex@ttl
197 if ( name == "ttl" )
199 }
200 return true;
201 }
202
203 // xpath: /repoindex/data (+)
204 if ( reader_r->name() == "repo" )
205 {
206 // TODO: Ideally the repo values here are interpreted the same way as
207 // corresponding ones in the RepoFileReader. Check whether we can introduce
208 // a RepoInfo ctor from a string dict. Using it here and in RepoFileReader.
209 // For now we try to parse the same way as in RepoFileReader.
210
211 RepoInfo info;
212 // Set some defaults that are not contained in the repo information
213 info.setAutorefresh( true );
214 info.setEnabled(false);
215
216 std::string attrValue;
217 _replacer.clearSectionVars();
218
219 // required alias
220 // mandatory, so we can allow it in var replacement without reset
221 if ( getAttrValue( "alias", reader_r, attrValue ) )
222 {
223 info.setAlias( attrValue );
224 _replacer.setSectionVar( "alias", attrValue );
225 }
226 else
227 throw ParseException(str::form(_("Required attribute '%s' is missing."), "alias"));
228
229 // required url
230 // SLES HACK: or path, but beware of the hardcoded '/repo' prefix!
231 {
232 std::string urlstr;
233 std::string pathstr;
234 getAttrValue( "url", reader_r, urlstr );
235 getAttrValue( "path", reader_r, pathstr );
236 if ( urlstr.empty() )
237 {
238 if ( pathstr.empty() )
239 // TODO: In fact we'd like to pass and check for url or mirrorlist at the end (check below).
240 // But there is legacy code in serviceswf.cc where an empty baseurl is replaced by
241 // the service Url. We need to check what kind of feature hides behind this code.
242 // So for now we keep requiring an url attribut.
243 throw ParseException(str::form(_("One or both of '%s' or '%s' attributes is required."), "url", "path"));
244 else
245 info.setPath( Pathname("/repo") / pathstr );
246 }
247 else
248 {
249 if ( pathstr.empty() )
250 info.setBaseUrl( Url(urlstr) );
251 else
252 {
253 Url url( urlstr );
254 url.setPathName( Pathname(url.getPathName()) / "repo" / pathstr );
255 info.setBaseUrl( url );
256 }
257 _replacer.setSectionVar( "url", urlstr );
258 }
259 }
260
261 // optional name
262 if ( getAttrValue( "name", reader_r, attrValue ) )
263 info.setName( attrValue );
264
265 // optional targetDistro
266 if ( getAttrValue( "distro_target", reader_r, attrValue ) )
267 info.setTargetDistribution( attrValue );
268
269 // optional priority
270 if ( getAttrValue( "priority", reader_r, attrValue ) )
271 info.setPriority( str::strtonum<unsigned>( attrValue ) );
272
273 // optional enabled
274 if ( getAttrValue( "enabled", reader_r, attrValue ) )
275 info.setEnabled( str::strToBool( attrValue, info.enabled() ) );
276
277 // optional autorefresh
278 if ( getAttrValue( "autorefresh", reader_r, attrValue ) )
279 info.setAutorefresh( str::strToBool( attrValue, info.autorefresh() ) );
280
281 // optional *gpgcheck
282 if ( getAttrValue( "gpgcheck", reader_r, attrValue ) )
283 info.setGpgCheck( str::strToTriBool( attrValue ) );
284 if ( getAttrValue( "repo_gpgcheck", reader_r, attrValue ) )
285 info.setRepoGpgCheck( str::strToTrue( attrValue ) );
286 if ( getAttrValue( "pkg_gpgcheck", reader_r, attrValue ) )
287 info.setPkgGpgCheck( str::strToTrue( attrValue ) );
288
289 // optional keeppackages
290 if ( getAttrValue( "keeppackages", reader_r, attrValue ) )
291 info.setKeepPackages( str::strToTrue( attrValue ) );
292
293 // optional gpgkey
294 if ( getAttrValue( "gpgkey", reader_r, attrValue ) )
295 info.setGpgKeyUrl( Url(attrValue) );
296
297 // optional mirrorlist
298 if ( getAttrValue( "mirrorlist", reader_r, attrValue ) )
299 info.setMirrorlistUrl( Url(attrValue) );
300
301 // optional metalink
302 if ( getAttrValue( "metalink", reader_r, attrValue ) )
303 info.setMetalinkUrl( Url(attrValue) );
304
305 DBG << info << endl;
306 // require at least one Url
307 // NOTE: Some legacy feature in serviceswf.cc allows a path without baseurl and
308 // combines this with the service url. That's why we require empty url and path
309 // in order to fail.
310 if ( info.baseUrlsEmpty() && info.path().empty() && not info.mirrorListUrl().isValid() ) {
311 throw ParseException(str::form(_("Neither '%s' nor '%s' nor '%s' attribute is defined for service repo '%s'."),
312 "url", "mirrorlist", "metalink", info.alias().c_str()));
313 }
314
315 // ignore the rest
316 // Specially: bsc#1177427 et.al.: type in a .repo file is legacy - ignore it
317 _callback(info);
318 return true;
319 }
320 }
321
322 return true;
323 }
324
325
327 //
328 // CLASS NAME : RepoindexFileReader
329 //
331
333 : _pimpl(new Impl( InputStream(std::move(repoindex_file)), std::move(callback) ))
334 {}
335
339
342
344
345 } // ns parser
346} // ns zypp
347
348// vim: set ts=2 sts=2 sw=2 et ai:
Interface of repoindex.xml file reader.
time_t Duration
Definition Date.h:39
Integral type with defined initial value when default constructed.
Helper to create and pass std::istream.
Definition inputstream.h:57
const Pathname & path() const
Path to the input file or empty if no file.
What is known about a repository.
Definition RepoInfo.h:72
void setPkgGpgCheck(TriBool value_r)
Set the value for pkgGpgCheck (or indeterminate to use the default).
Definition RepoInfo.cc:561
void setMetalinkUrl(const Url &url)
Set the raw metalink url.
Definition RepoInfo.cc:644
void setMirrorlistUrl(const Url &url)
Set the raw mirrorlist url.
Definition RepoInfo.cc:641
void setGpgKeyUrl(const Url &gpgkey)
(leagcy API) Set the gpgkey URL defined for this repo
Definition RepoInfo.cc:665
bool baseUrlsEmpty() const
whether repository urls are available
Definition RepoInfo.cc:807
void setKeepPackages(bool keep)
Set if packaqes downloaded from this repository will be kept in local cache.
Definition RepoInfo.cc:726
void setBaseUrl(Url url)
Clears current base URL list and adds url.
Definition RepoInfo.cc:684
void setGpgCheck(TriBool value_r)
Set the value for gpgCheck (or indeterminate to use the default).
Definition RepoInfo.cc:533
Pathname path() const
Repository path.
Definition RepoInfo.cc:783
Url mirrorListUrl() const
Url of a file which contains a list of repository urls.
Definition RepoInfo.cc:753
void setTargetDistribution(const std::string &targetDistribution)
Sets the distribution for which is this repository meant.
Definition RepoInfo.cc:732
void setPath(const Pathname &path)
set the product path.
Definition RepoInfo.cc:707
void setPriority(unsigned newval_r)
Set repository priority for solver.
Definition RepoInfo.cc:526
void setRepoGpgCheck(TriBool value_r)
Set the value for repoGpgCheck (or indeterminate to use the default).
Definition RepoInfo.cc:551
Url manipulation class.
Definition Url.h:93
bool isValid() const
Verifies the Url.
Definition Url.cc:507
bool empty() const
Test for an empty path.
Definition Pathname.h:116
DefaultIntegral< Date::Duration, 0 > _ttl
bool consumeNode(Reader &reader_r)
Callback provided to the XML parser.
Impl(const InputStream &is, ProcessResource &&callback)
CTOR.
ProcessResource _callback
Function for processing collected data.
bool getAttrValue(const std::string &key_r, Reader &reader_r, std::string &value_r)
function< bool(const RepoInfo &)> ProcessResource
Callback definition.
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
RepoindexFileReader(Pathname repoindexFile, ProcessResource callback)
CTOR.
Date::Duration ttl() const
Metadata TTL (repoindex.xml:xpath:/repoindex@ttl or 0).
void setAutorefresh(bool autorefresh)
enable or disable autorefresh
void setAlias(const std::string &alias)
set the repository alias
void setName(const std::string &name)
set the repository name
bool autorefresh() const
If true, the repostory must be refreshed before creating resolvables from it.
bool enabled() const
If enabled is false, then this repository must be ignored as if does not exists, except when checking...
void setEnabled(bool enabled)
enable or disable the repository
std::string alias() const
unique identifier for this source.
XmlString localName() const
The local name of the node.
Definition Node.h:114
NodeType nodeType() const
Get the node type of the current node.
Definition Node.h:126
XmlString value() const
Provides the text value of the node if present.
Definition Node.h:143
XmlString getAttribute(const char *name_r) const
Provides a copy of the attribute value with the specified qualified name.
Definition Node.h:71
XmlString name() const
The qualified name of the node, equal to Prefix :LocalName.
Definition Node.h:118
xmlTextReader based interface to iterate xml streams.
Definition Reader.h:96
bool nextNodeAttribute()
Definition Reader.cc:162
bool foreachNode(const ProcessNode &fnc_r)
Definition Reader.h:144
xmlChar * wrapper.
Definition XmlString.h:41
std::string asString() const
Explicit conversion to std::string.
Definition XmlString.h:77
const xmlChar * get() const
Access the xmlChar *.
Definition XmlString.h:61
Definition Arch.h:364
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition NonCopyable.h:26
Callbacks light.
Definition Callback.h:146
bool strToTrue(const C_Str &str)
Parsing boolean from string.
Definition String.cc:66
TriBool strToTriBool(const C_Str &str)
Parse str into a bool if it's a legal true or false string; else indeterminate.
Definition String.cc:96
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition String.h:500
TInt strtonum(const C_Str &str)
Parsing numbers from string.
Url details namespace.
Definition UrlBase.cc:58
Easy-to use interface to the ZYPP dependency resolver.
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define WAR
Definition Logger.h:101
Interface to gettext.