libzypp  17.25.6
YamlTestcaseHelpers.h
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #ifndef ZYPP_MISC_YAMLTESTCASEHELPERS_H
13 #define ZYPP_MISC_YAMLTESTCASEHELPERS_H
14 
15 #include <zypp/base/LogControl.h>
16 #include "LoadTestcase.h"
17 #include "TestcaseSetupImpl.h"
18 
19 #include <yaml-cpp/yaml.h>
20 
21 #include <type_traits>
22 
23 namespace yamltest::detail {
24 
25  bool parseSetup ( const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err ) {
26 
27  auto &target = t.data();
28  MIL << "Parsing setup node " << std::endl;
29  for ( YAML::const_iterator it = setup.begin(); it != setup.end(); it++ ) {
30 
31  const std::string &key = it->first.as<std::string>();
32  const auto &data = it->second;
33 
34  MIL << "Found key " << key << std::endl;
35 
36  // reads a sequence either from a file or inline, depending on the type of "data"
37  auto readListInlineOrFromFile = [&]( const auto &cb , std::string *err ) -> bool {
38  if ( data.Type() == YAML::NodeType::Sequence ) {
39  int cnt = 0;
40  for ( const auto &node: data ) {
41  if ( !cb( node, err ) ) return false;
42  cnt ++;
43  }
44  MIL << "Loaded " << cnt << " Elements inline" << std::endl;
45  } else {
46  const std::string &fName = data.as<std::string>();
47  MIL << "Trying to load list from file " << fName << std::endl;
48  try {
49  auto doc = YAML::LoadFile( fName );
50  if ( doc.Type() != YAML::NodeType::Sequence ) {
51  if ( err ) *err = "Expected the top node to be a sequence in external file for key: ";
52  return false;
53  }
54 
55  int cnt = 0;
56  for ( const auto &node : doc ) {
57  if ( !cb( node, err ) ) return false;
58  cnt ++;
59  }
60  MIL << "Loaded " << cnt << " Elements from file" << std::endl;
61  } catch ( YAML::Exception &e ) {
62  if ( err ) *err = e.what();
63  return false;
64  } catch ( ... ) {
65  if ( err ) *err = zypp::str::Str() << "Unknown error when parsing the file for " << key;
66  return false;
67  }
68  }
69  return true;
70  };
71 
72  if ( key == "resolverFlags" ) {
73 #define if_SolverFlag( N ) if ( data[#N] ) { target.N = data[#N].as<bool>(); }
74  if_SolverFlag( ignorealreadyrecommended ) if ( data["ignorealready"] ) { target.ignorealreadyrecommended = data["ignorealready"].as<bool>(); }
75  if_SolverFlag( onlyRequires ) if ( data["ignorerecommended"] ) { target.onlyRequires = data["ignorerecommended"].as<bool>(); }
76  if_SolverFlag( forceResolve )
77 
78  if_SolverFlag( cleandepsOnRemove )
79 
80  if_SolverFlag( allowDowngrade )
81  if_SolverFlag( allowNameChange )
82  if_SolverFlag( allowArchChange )
84 
89 #undef if_SolverFlag
90  if ( data["focus"] ) {
91  target.resolverFocus = zypp::resolverFocusFromString( data["focus"].as<std::string>() );
92  }
93  } else if ( key == ("system") ) {
94  target.systemRepo = zypp::misc::testcase::RepoDataImpl {
95  zypp::misc::testcase::TestcaseRepoType::Testtags,
96  "@System",
97  99,
98  data["file"].as<std::string>()
99  };
100  }
101  else if ( key == ("hardwareInfo") ) {
102  target.hardwareInfoFile = data.as<std::string>();
103  }
104  else if ( key == ("modalias") ) {
105  bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
106  target.modaliasList.push_back( dataNode.as<std::string>() );
107  return true;
108  }, err );
109  if ( !success ) return false;
110  }
111  else if ( key == ("multiversion") ) {
112  bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
113  target.multiversionSpec.insert( dataNode.as<std::string>() );
114  return true;
115  }, err );
116  if ( !success ) return false;
117  }
118  else if (key == ("channels")) {
119  bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
120  std::string name = dataNode["alias"].as<std::string>();
121  std::string file = dataNode["file"].as<std::string>();
122 
123  unsigned prio = 99;
124  if ( dataNode["priority"] )
125  prio = dataNode["priority"].as<unsigned>();
126 
127  target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
128  zypp::misc::testcase::TestcaseRepoType::Testtags,
129  name,
130  prio,
131  file
132  });
133  return true;
134  }, err );
135  if ( !success ) return false;
136  }
137  else if ( key == ("sources") )
138  {
139  bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
140  std::string url = dataNode["url"].as<std::string>();
141  std::string alias = dataNode["name"].as<std::string>();
142  target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
144  alias,
145  99,
146  url
147  });
148  return true;
149  }, err );
150  if ( !success ) return false;
151  }
152  else if ( key == ("force-install") )
153  {
154  bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
155  target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstallImpl{
156  dataNode["channel"].as<std::string>(),
157  dataNode["package"].as<std::string>(),
158  dataNode["kind"].as<std::string>()
159  });
160  return true;
161  }, err );
162  if ( !success ) return false;
163  }
164  else if ( key == ("mediaid") )
165  {
166  target.show_mediaid = data.as<bool>();
167  }
168  else if ( key == ("arch") ) {
169  std::string architecture = data.as<std::string>();
170  if ( architecture.empty() ) {
171  if (err) *err = zypp::str::Str() << "Property 'arch' in setup can not be empty." << std::endl;
172  return false;
173  }
174  else {
175  MIL << "Setting architecture to '" << architecture << "'" << std::endl;
176  target.architecture = zypp::Arch( architecture );
177  }
178  }
179  else if ( key == ("locales") )
180  {
181  bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, std::string *err ){
182  zypp::Locale loc( dataNode["name"].as<std::string>() );
183  std::string fate = dataNode["fate"].as<std::string>();
184  if ( !loc ) {
185  if (err) *err = zypp::str::Str() << "Bad or missing name in locale..." << std::endl;
186  return false;
187  }
188  else if ( fate == "added" ) {
189  target.localesTracker.added().insert( loc );
190  }
191  else if ( fate == "removed" ) {
192  target.localesTracker.removed().insert( loc );
193  }
194  else {
195  target.localesTracker.current().insert( loc );
196  }
197  return true;
198  }, err );
199  if ( !success ) return false;
200  }
201  else if ( key == ("vendors") )
202  {
203  bool success = readListInlineOrFromFile( [&target]( const YAML::Node & dataNode, std::string * err ) {
204  std::vector<std::string> vlist;
205  for ( const auto & node : dataNode )
206  vlist.push_back( node.as<std::string>() );
207  if ( ! vlist.empty() )
208  target.vendorLists.push_back( std::move(vlist) );
209  return true;
210  }, err );
211  if ( !success ) return false;
212  }
213  else if ( key == ("autoinst") ) {
214  bool success = readListInlineOrFromFile( [&]( const YAML::Node &dataNode, auto ){
215  target.autoinstalled.push( zypp::IdString( dataNode.as<std::string>() ).id() );
216  return true;
217  }, err );
218  if ( !success ) return false;
219  }
220  else if ( key == ("systemCheck") ) {
221  target.systemCheck = data.as<std::string>();
222  }
223  else if ( key == ("setlicencebit") ) {
224  target.set_licence = data.as<bool>();
225  }
226  else {
227  ERR << "Ignoring unrecognized tag '" << key << "' in setup" << std::endl;
228  }
229  }
230  return true;
231  }
232 
233  template <typename T>
234  bool parseJobs ( const YAML::Node &trial, std::vector<T> &target, std::string *err );
235 
236  template <typename T>
237  bool parseSingleJob ( const YAML::Node &jobNode, std::vector<T> &target, std::string *err ) {
238 
239  constexpr bool isSubNode = std::is_same_v<T, std::shared_ptr<zypp::misc::testcase::TestcaseTrial::Node>>;
240  if ( jobNode["include"] ) {
241  //handle include
242  const auto &fName = jobNode["include"].as<std::string>();
243  MIL << "Including file " << fName << std::endl;
244  try {
245  auto doc = YAML::LoadFile( fName );
246  if ( !parseJobs( doc, target, err ) )
247  return false;
248  MIL << "Including file " << fName << "was successfull" << std::endl;
249  } catch ( YAML::Exception &e ) {
250  if ( err ) *err = e.what();
251  return false;
252  } catch ( ... ) {
253  if ( err ) *err = zypp::str::Str() << "Unknown error when parsing the file: " << fName;
254  return false;
255  }
256  return true;
257  }
258 
260  if ( !jobNode["job"] ) {
261  if ( err ) {
262  auto errStr = zypp::str::Str();
263  const auto &mark = jobNode.Mark();
264  errStr << "'job' key missing from trial node.";
265  if ( !mark.is_null() ) {
266  errStr << " Line: " << mark.line << " Col: " << mark.column << " pos: " << mark.pos;
267  }
268  *err = errStr;
269  }
270  return false;
271  }
272 
273  for ( const auto &elem : jobNode ) {
274  const std::string &key = elem.first.as<std::string>();
275  const auto &data = elem.second;
276  if ( key == "job" ) {
277  n.name() = data.as<std::string>();
278  } else if ( key == "__content") {
279  n.value() = data.as<std::string>();
280  } else {
281  if( data.IsScalar() ) {
282  n.properties().insert( { key, data.as<std::string>() } );
283  } else if ( data.IsSequence() ) {
284  // if the type of a data field is a sequence, we treat all the elements in there
285  // as sub elements. Just like in XML you can have sub nodes its the same here
286  // the key name is ignored in those cases and can be chosen freely
287  if ( !parseJobs( data, n.children(), err ) )
288  return false;
289  } else if ( data.IsMap() ) {
290  // if the type of a data field is a map, we build a child node from it.
291  // Just like with sequence but a single field.
292  // The key name is ignored in those cases and can be chosen freely
293  if ( !parseSingleJob( data, n.children(), err) )
294  return false;
295  } else {
296  ERR << "Ignoring field " << key << " with unsupported type." << std::endl;
297  }
298  }
299  }
300  if constexpr ( isSubNode ) {
301  target.push_back( std::make_shared<zypp::misc::testcase::TestcaseTrial::Node>( std::move(n) ) );
302  } else {
303  target.push_back( std::move(n) );
304  }
305  return true;
306  }
307 
308  template <typename T>
309  bool parseJobs ( const YAML::Node &trial, std::vector<T> &target, std::string *err ) {
310  for ( const auto &jobNode : trial ) {
311  if ( !parseSingleJob( jobNode, target, err ) )
312  return false;
313  }
314  return true;
315  }
316 
317  bool parseTrial ( const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, std::string *err ) {
318  MIL << "Parsing trials." << std::endl;
319  return parseJobs( trial, target.nodes(), err );
320  }
321 }
322 
323 #endif // ZYPP_MISC_YAMLTESTCASEHELPERS_H
yamltest::detail::parseSetup
bool parseSetup(const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err)
Definition: YamlTestcaseHelpers.h:25
zypp::solver::detail::dupAllowDowngrade
dupAllowDowngrade
Definition: Resolver.cc:123
zypp::misc::testcase::TestcaseTrial::Node::properties
const std::map< std::string, std::string > & properties() const
Definition: LoadTestcase.cc:85
LogControl.h
zypp::misc::testcase::TestcaseTrial
Definition: LoadTestcase.h:27
zypp::misc::testcase::ForceInstallImpl
Definition: TestcaseSetupImpl.h:34
zypp::misc::testcase::TestcaseTrial::Node::children
const std::vector< std::shared_ptr< Node > > & children() const
Definition: LoadTestcase.cc:91
zypp::xmlout::node
std::ostream & node(std::ostream &out_r, const std::string &name_r, Node::Attr attr_r)
Definition: Xml.h:203
zypp::misc::testcase::TestcaseTrial::Node
Definition: LoadTestcase.h:28
zypp::misc::testcase::TestcaseSetup::data
TestcaseSetupImpl & data()
Definition: TestcaseSetup.cc:250
zypp::misc::testcase::TestcaseTrial::Node::name
const std::string & name() const
Definition: LoadTestcase.cc:66
MIL
#define MIL
Definition: Logger.h:79
yamltest::detail
Definition: YamlTestcaseHelpers.h:23
zypp::solver::detail::allowVendorChange
allowVendorChange
Definition: Resolver.cc:121
LoadTestcase.h
zypp::Arch
Architecture.
Definition: Arch.h:37
TestcaseSetupImpl.h
zypp::IdString
Access to the sat-pools string space.
Definition: IdString.h:43
zypp::misc::testcase::TestcaseTrial::Node::value
const std::string & value() const
Definition: LoadTestcase.cc:72
yamltest::detail::parseJobs
bool parseJobs(const YAML::Node &trial, std::vector< T > &target, std::string *err)
Definition: YamlTestcaseHelpers.h:309
zypp::misc::testcase::TestcaseRepoType::Url
@ Url
zypp::misc::testcase::RepoDataImpl
Definition: TestcaseSetupImpl.h:25
zypp::solver::detail::dupAllowArchChange
dupAllowArchChange
Definition: Resolver.cc:125
zypp::str::Str
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:209
zypp::IdString::id
IdType id() const
Expert backdoor.
Definition: IdString.h:122
yamltest::detail::parseSingleJob
bool parseSingleJob(const YAML::Node &jobNode, std::vector< T > &target, std::string *err)
Definition: YamlTestcaseHelpers.h:237
if_SolverFlag
#define if_SolverFlag(N)
ERR
#define ERR
Definition: Logger.h:81
zypp::misc::testcase::TestcaseTrial::nodes
const std::vector< Node > & nodes() const
Definition: LoadTestcase.cc:54
zypp::misc::testcase::TestcaseSetup
Definition: TestcaseSetup.h:78
zypp::solver::detail::dupAllowNameChange
dupAllowNameChange
Definition: Resolver.cc:124
yamltest::detail::parseTrial
bool parseTrial(const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, std::string *err)
Definition: YamlTestcaseHelpers.h:317
url
Url url
Definition: MediaCurl.cc:66
zypp::solver::detail::dupAllowVendorChange
dupAllowVendorChange
Definition: Resolver.cc:126
zypp::Locale
'Language[_Country]' codes.
Definition: Locale.h:50