libzypp 17.25.7
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
16#include "LoadTestcase.h"
17#include "TestcaseSetupImpl.h"
18
19#include <yaml-cpp/yaml.h>
20
21#include <type_traits>
22
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 {
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{
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 successful" << 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
#define MIL
Definition: Logger.h:79
#define ERR
Definition: Logger.h:81
Url url
Definition: MediaCurl.cc:66
#define if_SolverFlag(N)
Architecture.
Definition: Arch.h:37
Access to the sat-pools string space.
Definition: IdString.h:43
IdType id() const
Expert backdoor.
Definition: IdString.h:122
'Language[_Country]' codes.
Definition: Locale.h:50
bool parseSetup(const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err)
bool parseTrial(const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, std::string *err)
bool parseJobs(const YAML::Node &trial, std::vector< T > &target, std::string *err)
bool parseSingleJob(const YAML::Node &jobNode, std::vector< T > &target, std::string *err)
std::ostream & node(std::ostream &out_r, const std::string &name_r, Node::Attr attr_r)
Definition: Xml.h:203
const std::vector< std::shared_ptr< Node > > & children() const
Definition: LoadTestcase.cc:91
const std::string & name() const
Definition: LoadTestcase.cc:66
const std::map< std::string, std::string > & properties() const
Definition: LoadTestcase.cc:85
const std::string & value() const
Definition: LoadTestcase.cc:72
const std::vector< Node > & nodes() const
Definition: LoadTestcase.cc:54
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:209