1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/parser/RepoindexFileReader.cc
10 * Implementation of repoindex.xml file reader.
13 #include <unordered_map>
15 #include "zypp/base/String.h"
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/Gettext.h"
18 #include "zypp/base/InputStream.h"
19 #include "zypp/base/DefaultIntegral.h"
21 #include "zypp/Pathname.h"
23 #include "zypp/parser/xml/Reader.h"
24 #include "zypp/parser/ParseException.h"
26 #include "zypp/RepoInfo.h"
28 #include "zypp/parser/RepoindexFileReader.h"
31 #undef ZYPP_BASE_LOGGER_LOGGROUP
32 #define ZYPP_BASE_LOGGER_LOGGROUP "parser"
43 ///////////////////////////////////////////////////////////////////
46 class VarReplacer : private base::NonCopyable
50 void setVar( const std::string & key_r, const std::string & val_r )
52 //MIL << "*** Inject " << key_r << " = " << val_r;
53 _vars[key_r] = replace( val_r );
54 //MIL << " (" << _vars[key_r] << ")" << endl;
57 std::string replace( const std::string & val_r ) const
59 std::string::size_type vbeg = val_r.find( "%{", 0 );
60 if ( vbeg == std::string::npos )
64 std::string::size_type cbeg = 0;
65 for( ; vbeg != std::string::npos; vbeg = val_r.find( "%{", vbeg ) )
67 std::string::size_type nbeg = vbeg+2;
68 std::string::size_type nend = val_r.find( "}", nbeg );
69 if ( nend == std::string::npos )
71 WAR << "Incomplete variable in '" << val_r << "'" << endl;
74 const auto & iter = _vars.find( val_r.substr( nbeg, nend-nbeg ) );
75 if ( iter != _vars.end() )
78 ret << val_r.substr( cbeg, vbeg-cbeg );
83 WAR << "Undefined variable %{" << val_r.substr( nbeg, nend-nbeg ) << "} in '" << val_r << "'" << endl;
86 if ( cbeg < val_r.size() )
87 ret << val_r.substr( cbeg );
92 std::unordered_map<std::string,std::string> _vars;
95 ///////////////////////////////////////////////////////////////////
97 ///////////////////////////////////////////////////////////////////////
99 // CLASS NAME : RepoindexFileReader::Impl
101 class RepoindexFileReader::Impl : private base::NonCopyable
107 * \see RepoindexFileReader::RepoindexFileReader(Pathname,ProcessResource)
109 Impl(const InputStream &is, const ProcessResource & callback);
112 * Callback provided to the XML parser.
114 bool consumeNode( Reader & reader_r );
116 DefaultIntegral<Date::Duration,0> _ttl;
119 bool getAttrValue( const std::string & key_r, Reader & reader_r, std::string & value_r )
121 const XmlString & s( reader_r->getAttribute( key_r ) );
124 value_r = _replacer.replace( s.asString() );
125 return !value_r.empty();
132 /** Function for processing collected data. Passed-in through constructor. */
133 ProcessResource _callback;
134 VarReplacer _replacer;
136 ///////////////////////////////////////////////////////////////////////
138 RepoindexFileReader::Impl::Impl(const InputStream &is,
139 const ProcessResource & callback)
140 : _callback(callback)
143 MIL << "Reading " << is.path() << endl;
144 reader.foreachNode( bind( &RepoindexFileReader::Impl::consumeNode, this, _1 ) );
147 // --------------------------------------------------------------------------
150 * xpath and multiplicity of processed nodes are included in the code
153 * // xpath: <xpath> (?|*|+)
155 * if multiplicity is ommited, then the node has multiplicity 'one'.
158 // --------------------------------------------------------------------------
160 bool RepoindexFileReader::Impl::consumeNode( Reader & reader_r )
162 if ( reader_r->nodeType() == XML_READER_TYPE_ELEMENT )
165 if ( reader_r->name() == "repoindex" )
167 while ( reader_r.nextNodeAttribute() )
169 const std::string & name( reader_r->localName().asString() );
170 const std::string & value( reader_r->value().asString() );
171 _replacer.setVar( name, value );
172 // xpath: /repoindex@ttl
174 _ttl = str::strtonum<Date::Duration>(value);
179 // xpath: /repoindex/data (+)
180 if ( reader_r->name() == "repo" )
183 // Set some defaults that are not contained in the repo information
184 info.setAutorefresh( true );
185 info.setEnabled(false);
187 std::string attrValue;
190 // mandatory, so we can allow it in var replacement without reset
191 if ( getAttrValue( "alias", reader_r, attrValue ) )
193 info.setAlias( attrValue );
194 _replacer.setVar( "alias", attrValue );
197 throw ParseException(str::form(_("Required attribute '%s' is missing."), "alias"));
200 // SLES HACK: or path, but beware of the hardcoded '/repo' prefix!
204 getAttrValue( "url", reader_r, urlstr );
205 getAttrValue( "path", reader_r, pathstr );
206 if ( urlstr.empty() )
208 if ( pathstr.empty() )
209 throw ParseException(str::form(_("One or both of '%s' or '%s' attributes is required."), "url", "path"));
211 info.setPath( Pathname("/repo") / pathstr );
215 if ( pathstr.empty() )
216 info.setBaseUrl( Url(urlstr) );
220 url.setPathName( Pathname(url.getPathName()) / "repo" / pathstr );
221 info.setBaseUrl( url );
227 if ( getAttrValue( "name", reader_r, attrValue ) )
228 info.setName( attrValue );
230 // optional targetDistro
231 if ( getAttrValue( "distro_target", reader_r, attrValue ) )
232 info.setTargetDistribution( attrValue );
235 if ( getAttrValue( "priority", reader_r, attrValue ) )
236 info.setPriority( str::strtonum<unsigned>( attrValue ) );
240 if ( getAttrValue( "enabled", reader_r, attrValue ) )
241 info.setEnabled( str::strToBool( attrValue, info.enabled() ) );
243 // optional autorefresh
244 if ( getAttrValue( "autorefresh", reader_r, attrValue ) )
245 info.setAutorefresh( str::strToBool( attrValue, info.autorefresh() ) );
259 ///////////////////////////////////////////////////////////////////
261 // CLASS NAME : RepoindexFileReader
263 ///////////////////////////////////////////////////////////////////
265 RepoindexFileReader::RepoindexFileReader( const Pathname & repoindex_file, const ProcessResource & callback )
266 : _pimpl(new Impl(InputStream(repoindex_file), callback))
269 RepoindexFileReader::RepoindexFileReader( const InputStream &is, const ProcessResource & callback )
270 : _pimpl(new Impl(is, callback))
273 RepoindexFileReader::~RepoindexFileReader()
276 Date::Duration RepoindexFileReader::ttl() const { return _pimpl->_ttl; }
281 // vim: set ts=2 sts=2 sw=2 et ai: