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