libzypp  17.37.5
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 
24 #include <zypp/parser/xml/Reader.h>
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 
35 using std::endl;
36 
37 namespace 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:
133  Impl(const InputStream &is, ProcessResource &&callback);
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  };
161 
163  ProcessResource &&callback)
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" )
198  _ttl = str::strtonum<Date::Duration>(value);
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 
337  : _pimpl(new Impl( is, std::move(callback) ))
338  {}
339 
341  {}
342 
344 
345  } // ns parser
346 } // ns zypp
347 
348 // vim: set ts=2 sts=2 sw=2 et ai:
void setBaseUrl(Url url)
Clears current base URL list and adds url.
Definition: RepoInfo.cc:693
Pathname path() const
Repository path.
Definition: RepoInfo.cc:792
Interface to gettext.
#define MIL
Definition: Logger.h:100
void setGpgKeyUrl(const Url &gpgkey)
(leagcy API) Set the gpgkey URL defined for this repo
Definition: RepoInfo.cc:674
#define _(MSG)
Definition: Gettext.h:39
ProcessResource _callback
Function for processing collected data.
void setAutorefresh(bool autorefresh)
enable or disable autorefresh
Definition: RepoInfoBase.cc:86
void setPriority(unsigned newval_r)
Set repository priority for solver.
Definition: RepoInfo.cc:535
function< bool(const RepoInfo &)> ProcessResource
Callback definition.
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
void setEnabled(bool enabled)
enable or disable the repository
Definition: RepoInfoBase.cc:83
RepoindexFileReader(Pathname repoindexFile, ProcessResource callback)
CTOR.
void setAlias(const std::string &alias)
set the repository alias
Definition: RepoInfoBase.cc:89
xmlChar * wrapper.
Definition: XmlString.h:40
Definition: Arch.h:363
What is known about a repository.
Definition: RepoInfo.h:71
void setGpgCheck(TriBool value_r)
Set the value for gpgCheck (or indeterminate to use the default).
Definition: RepoInfo.cc:542
Helper to create and pass std::istream.
Definition: inputstream.h:56
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:39
bool enabled() const
If enabled is false, then this repository must be ignored as if does not exists, except when checking...
Definition: RepoInfoBase.cc:98
std::unordered_map< std::string, std::string > _global
Interface of repoindex.xml file reader.
bool baseUrlsEmpty() const
whether repository urls are available
Definition: RepoInfo.cc:819
TriBool strToTriBool(const C_Str &str)
Parse str into a bool if it&#39;s a legal true or false string; else indeterminate.
Definition: String.cc:96
void setMirrorlistUrl(const Url &url)
Set the raw mirrorlist url.
Definition: RepoInfo.cc:650
Url mirrorListUrl() const
Url of a file which contains a list of repository urls.
Definition: RepoInfo.cc:762
bool empty() const
Test for an empty path.
Definition: Pathname.h:116
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:782
XmlString getAttribute(const char *name_r) const
Provides a copy of the attribute value with the specified qualified name.
Definition: Node.h:71
void setRepoGpgCheck(TriBool value_r)
Set the value for repoGpgCheck (or indeterminate to use the default).
Definition: RepoInfo.cc:560
std::string alias() const
unique identifier for this source.
void setPath(const Pathname &path)
set the product path.
Definition: RepoInfo.cc:716
#define WAR
Definition: Logger.h:101
std::unordered_map< std::string, std::string > _section
void setKeepPackages(bool keep)
Set if packaqes downloaded from this repository will be kept in local cache.
Definition: RepoInfo.cc:735
time_t Duration
Definition: Date.h:39
const Pathname & path() const
Path to the input file or empty if no file.
Definition: inputstream.h:111
bool isValid() const
Verifies the Url.
Definition: Url.cc:507
DefaultIntegral< Date::Duration, 0 > _ttl
const ProcessCredentials & _callback
void setMetalinkUrl(const Url &url)
Set the raw metalink url.
Definition: RepoInfo.cc:653
Impl(const InputStream &is, ProcessResource &&callback)
CTOR.
bool nextNodeAttribute()
Definition: Reader.cc:162
bool foreachNode(const ProcessNode &fnc_r)
Definition: Reader.h:144
void setTargetDistribution(const std::string &targetDistribution)
Sets the distribution for which is this repository meant.
Definition: RepoInfo.cc:741
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:622
std::string asString() const
Explicit conversion to std::string.
Definition: XmlString.h:77
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition: String.h:500
XmlString name() const
The qualified name of the node, equal to Prefix :LocalName.
Definition: Node.h:118
Date::Duration ttl() const
Metadata TTL (repoindex.xml:xpath:/repoindex or 0).
bool autorefresh() const
If true, the repostory must be refreshed before creating resolvables from it.
void setName(const std::string &name)
set the repository name
Definition: RepoInfoBase.cc:92
bool getAttrValue(const std::string &key_r, Reader &reader_r, std::string &value_r)
bool consumeNode(Reader &reader_r)
Callback provided to the XML parser.
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
SolvableIdType size_type
Definition: PoolMember.h:126
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
void setPkgGpgCheck(TriBool value_r)
Set the value for pkgGpgCheck (or indeterminate to use the default).
Definition: RepoInfo.cc:570
Url manipulation class.
Definition: Url.h:92
#define DBG
Definition: Logger.h:99
XmlString localName() const
The local name of the node.
Definition: Node.h:114
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
bool strToTrue(const C_Str &str)
Parsing boolean from string.
Definition: String.cc:66
xmlTextReader based interface to iterate xml streams.
Definition: Reader.h:95