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"
20 #include "zypp/Pathname.h"
22 #include "zypp/parser/xml/Reader.h"
23 #include "zypp/parser/ParseException.h"
25 #include "zypp/RepoInfo.h"
27 #include "zypp/parser/RepoindexFileReader.h"
30 #undef ZYPP_BASE_LOGGER_LOGGROUP
31 #define ZYPP_BASE_LOGGER_LOGGROUP "parser"
42 ///////////////////////////////////////////////////////////////////
45 class VarReplacer : private base::NonCopyable
49 void setVar( const std::string & key_r, const std::string & val_r )
51 MIL << "*** Inject " << key_r << " = " << val_r;
52 _vars[key_r] = replace( val_r );
53 MIL << " (" << _vars[key_r] << ")" << endl;
56 std::string replace( const std::string & val_r ) const
58 std::string::size_type vbeg = val_r.find( "%{", 0 );
59 if ( vbeg == std::string::npos )
63 std::string::size_type cbeg = 0;
64 for( ; vbeg != std::string::npos; vbeg = val_r.find( "%{", vbeg ) )
66 std::string::size_type nbeg = vbeg+2;
67 std::string::size_type nend = val_r.find( "}", nbeg );
68 if ( nend == std::string::npos )
70 WAR << "Incomplete variable in '" << val_r << "'" << endl;
73 const auto & iter = _vars.find( val_r.substr( nbeg, nend-nbeg ) );
74 if ( iter != _vars.end() )
77 ret << val_r.substr( cbeg, vbeg-cbeg );
82 WAR << "Undefined variable %{" << val_r.substr( nbeg, nend-nbeg ) << "} in '" << val_r << "'" << endl;
85 if ( cbeg < val_r.size() )
86 ret << val_r.substr( cbeg );
91 std::unordered_map<std::string,std::string> _vars;
94 ///////////////////////////////////////////////////////////////////
96 ///////////////////////////////////////////////////////////////////////
98 // CLASS NAME : RepoindexFileReader::Impl
100 class RepoindexFileReader::Impl : private base::NonCopyable
106 * \see RepoindexFileReader::RepoindexFileReader(Pathname,ProcessResource)
108 Impl(const InputStream &is, const ProcessResource & callback);
111 * Callback provided to the XML parser.
113 bool consumeNode( Reader & reader_r );
116 bool getAttrValue( const std::string & key_r, Reader & reader_r, std::string & value_r )
118 const XmlString & s( reader_r->getAttribute( key_r ) );
121 value_r = _replacer.replace( s.asString() );
122 return !value_r.empty();
129 /** Function for processing collected data. Passed-in through constructor. */
130 ProcessResource _callback;
131 VarReplacer _replacer;
133 ///////////////////////////////////////////////////////////////////////
135 RepoindexFileReader::Impl::Impl(const InputStream &is,
136 const ProcessResource & callback)
137 : _callback(callback)
140 MIL << "Reading " << is.path() << endl;
141 reader.foreachNode( bind( &RepoindexFileReader::Impl::consumeNode, this, _1 ) );
144 // --------------------------------------------------------------------------
147 * xpath and multiplicity of processed nodes are included in the code
150 * // xpath: <xpath> (?|*|+)
152 * if multiplicity is ommited, then the node has multiplicity 'one'.
155 // --------------------------------------------------------------------------
157 bool RepoindexFileReader::Impl::consumeNode( Reader & reader_r )
159 if ( reader_r->nodeType() == XML_READER_TYPE_ELEMENT )
162 if ( reader_r->name() == "repoindex" )
164 while ( reader_r.nextNodeAttribute() )
165 _replacer.setVar( reader_r->localName().asString(), reader_r->value().asString() );
169 // xpath: /repoindex/data (+)
170 if ( reader_r->name() == "repo" )
173 // Set some defaults that are not contained in the repo information
174 info.setAutorefresh( true );
175 info.setEnabled(false);
177 std::string attrValue;
180 // mandatory, so we can allow it in var replacement without reset
181 if ( getAttrValue( "alias", reader_r, attrValue ) )
183 info.setAlias( attrValue );
184 _replacer.setVar( "alias", attrValue );
187 throw ParseException(str::form(_("Required attribute '%s' is missing."), "alias"));
190 // SLES HACK: or path, but beware of the hardcoded '/repo' prefix!
194 getAttrValue( "url", reader_r, urlstr );
195 getAttrValue( "path", reader_r, pathstr );
196 if ( urlstr.empty() )
198 if ( pathstr.empty() )
199 throw ParseException(str::form(_("One or both of '%s' or '%s' attributes is required."), "url", "path"));
201 info.setPath( Pathname("/repo") / pathstr );
205 if ( pathstr.empty() )
206 info.setBaseUrl( Url(urlstr) );
210 url.setPathName( Pathname(url.getPathName()) / "repo" / pathstr );
211 info.setBaseUrl( url );
217 if ( getAttrValue( "name", reader_r, attrValue ) )
218 info.setName( attrValue );
220 // optional targetDistro
221 if ( getAttrValue( "distro_target", reader_r, attrValue ) )
222 info.setTargetDistribution( attrValue );
225 if ( getAttrValue( "priority", reader_r, attrValue ) )
226 info.setPriority( str::strtonum<unsigned>( attrValue ) );
230 if ( getAttrValue( "enabled", reader_r, attrValue ) )
231 info.setEnabled( str::strToBool( attrValue, info.enabled() ) );
233 // optional autorefresh
234 if ( getAttrValue( "autorefresh", reader_r, attrValue ) )
235 info.setAutorefresh( str::strToBool( attrValue, info.autorefresh() ) );
249 ///////////////////////////////////////////////////////////////////
251 // CLASS NAME : RepoindexFileReader
253 ///////////////////////////////////////////////////////////////////
255 RepoindexFileReader::RepoindexFileReader(
256 const Pathname & repoindex_file, const ProcessResource & callback)
258 _pimpl(new Impl(InputStream(repoindex_file), callback))
261 RepoindexFileReader::RepoindexFileReader(
262 const InputStream &is, const ProcessResource & callback )
263 : _pimpl(new Impl(is, callback))
266 RepoindexFileReader::~RepoindexFileReader()
273 // vim: set ts=2 sts=2 sw=2 et ai: