libzypp 17.38.15
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
18#include <utility>
19#include <zypp-core/base/InputStream>
20#include <zypp-core/base/DefaultIntegral>
21
22#include <zypp-core/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
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
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:
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:129
#define MIL
Definition Logger.h:130
#define WAR
Definition Logger.h:131
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
Url manipulation class.
Definition Url.h:93
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).
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
nullptr CURL handle void p CURLversion nullptr struct curl_slist list CURLM CURLM_INTERNAL_ERROR CURLM CURL CURLM_INTERNAL_ERROR CURLM curl_socket_t s
Definition curl_dl.cc:111
nullptr CURL handle void p CURLversion nullptr struct curl_slist list CURLM CURLM_INTERNAL_ERROR CURLM CURL CURLM_INTERNAL_ERROR CURLM curl_socket_t int int CURLM_INTERNAL_ERROR CURLINFO info
Definition curl_dl.cc:117
Definition ansi.h:855
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.