libzypp 17.38.14
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( (target.globalPath / fName).asString() );
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 ) {
63 auto errStr = zypp::str::Str();
64 errStr << e.what();
65 if ( !e.mark.is_null() ) {
66 errStr << " Line: " << e.mark.line << " Col: " << e.mark.column << " pos: " << e.mark.pos;
67 }
68 *err = errStr;
69 }
70 return false;
71 } catch ( ... ) {
72 if ( err ) *err = zypp::str::Str() << "Unknown error when parsing the file for " << key;
73 return false;
74 }
75 }
76 return true;
77 };
78
79 if ( key == "resolverFlags" ) {
80#define if_SolverFlag( N ) if ( data[#N] ) { target.N = data[#N].as<bool>(); }
81 if_SolverFlag( ignorealreadyrecommended ) if ( data["ignorealready"] ) { target.ignorealreadyrecommended = data["ignorealready"].as<bool>(); }
82 if_SolverFlag( onlyRequires ) if ( data["ignorerecommended"] ) { target.onlyRequires = data["ignorerecommended"].as<bool>(); }
83 if_SolverFlag( forceResolve )
84
85 if_SolverFlag( cleandepsOnRemove )
86 if_SolverFlag( noUpdateProvide )
87
88 if_SolverFlag( allowDowngrade )
89 if_SolverFlag( allowNameChange )
90 if_SolverFlag( allowArchChange )
91 if_SolverFlag( allowVendorChange )
92
93 if_SolverFlag( dupAllowDowngrade )
94 if_SolverFlag( dupAllowNameChange )
95 if_SolverFlag( dupAllowArchChange )
96 if_SolverFlag( dupAllowVendorChange )
97#undef if_SolverFlag
98 if ( data["focus"] ) {
99 target.resolverFocus = zypp::resolverFocusFromString( data["focus"].as<std::string>() );
100 }
101 } else if ( key == ("system") ) {
102 target.systemRepo = zypp::misc::testcase::RepoDataImpl {
104 "@System",
105 99,
106 data["file"].as<std::string>()
107 };
108 }
109 else if ( key == ("hardwareInfo") ) {
110 target.hardwareInfoFile = data.as<std::string>();
111 }
112 else if ( key == ("modalias") ) {
113 bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
114 target.modaliasList.push_back( dataNode.as<std::string>() );
115 return true;
116 }, err );
117 if ( !success ) return false;
118 }
119 else if ( key == ("multiversion") ) {
120 bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
121 target.multiversionSpec.insert( dataNode.as<std::string>() );
122 return true;
123 }, err );
124 if ( !success ) return false;
125 }
126 else if (key == ("channels")) {
127 bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
128 std::string name = dataNode["alias"].as<std::string>();
129 std::string file = dataNode["file"].as<std::string>();
130
131 unsigned prio = 99;
132 if ( dataNode["priority"] )
133 prio = dataNode["priority"].as<unsigned>();
134
135 target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
137 name,
138 prio,
139 file
140 });
141 return true;
142 }, err );
143 if ( !success ) return false;
144 }
145 else if ( key == ("sources") )
146 {
147 bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
148 std::string url = dataNode["url"].as<std::string>();
149 std::string alias = dataNode["name"].as<std::string>();
150 target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
152 alias,
153 99,
154 url
155 });
156 return true;
157 }, err );
158 if ( !success ) return false;
159 }
160 else if ( key == ("force-install") )
161 {
162 bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
163 target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstallImpl{
164 dataNode["channel"].as<std::string>(),
165 dataNode["package"].as<std::string>(),
166 dataNode["kind"].as<std::string>()
167 });
168 return true;
169 }, err );
170 if ( !success ) return false;
171 }
172 else if ( key == ("mediaid") )
173 {
174 target.show_mediaid = data.as<bool>();
175 }
176 else if ( key == ("arch") ) {
177 std::string architecture = data.as<std::string>();
178 if ( architecture.empty() ) {
179 if (err) *err = zypp::str::Str() << "Property 'arch' in setup can not be empty." << std::endl;
180 return false;
181 }
182 else {
183 MIL << "Setting architecture to '" << architecture << "'" << std::endl;
184 target.architecture = zypp::Arch( architecture );
185 }
186 }
187 else if ( key == ("locales") )
188 {
189 bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, std::string *err ){
190 zypp::Locale loc( dataNode["name"].as<std::string>() );
191 std::string fate = dataNode["fate"].as<std::string>();
192 if ( !loc ) {
193 if (err) *err = zypp::str::Str() << "Bad or missing name in locale..." << std::endl;
194 return false;
195 }
196 else if ( fate == "added" ) {
197 target.localesTracker.added().insert( loc );
198 }
199 else if ( fate == "removed" ) {
200 target.localesTracker.removed().insert( loc );
201 }
202 else {
203 target.localesTracker.current().insert( loc );
204 }
205 return true;
206 }, err );
207 if ( !success ) return false;
208 }
209 else if ( key == ("vendors") )
210 {
211 bool success = readListInlineOrFromFile( [&target]( const YAML::Node & dataNode, std::string * err ) {
212 std::vector<std::string> vlist;
213 for ( const auto & node : dataNode )
214 vlist.push_back( node.as<std::string>() );
215 if ( ! vlist.empty() )
216 target.vendorLists.push_back( std::move(vlist) );
217 return true;
218 }, err );
219 if ( !success ) return false;
220 }
221 else if ( key == ("autoinst") ) {
222 bool success = readListInlineOrFromFile( [&]( const YAML::Node &dataNode, std::string * err ){
223 target.autoinstalled.push( zypp::IdString( dataNode.as<std::string>() ).id() );
224 return true;
225 }, err );
226 if ( !success ) return false;
227 }
228 else if ( key == ("systemCheck") ) {
229 // Prefix with globalPath like the helix loader does, so relative
230 // paths in the YAML resolve correctly against the testcase directory.
231 target.systemCheck = target.globalPath / data.as<std::string>();
232 }
233 else if ( key == ("setlicencebit") ) {
234 target.set_licence = data.as<bool>();
235 }
236 else {
237 ERR << "Ignoring unrecognized tag '" << key << "' in setup" << std::endl;
238 }
239 }
240 return true;
241 }
242
243 template <typename T>
244 bool parseJobs ( const YAML::Node &trial, std::vector<T> &target, const zypp::Pathname &testcaseDir, std::string *err );
245
246 template <typename T>
247 bool parseSingleJob ( const YAML::Node &jobNode, std::vector<T> &target, const zypp::Pathname &testcaseDir, std::string *err ) {
248
249 constexpr bool isSubNode = std::is_same_v<T, std::shared_ptr<zypp::misc::testcase::TestcaseTrial::Node>>;
250 if ( jobNode["include"] ) {
251 //handle include
252 const auto &fName = jobNode["include"].as<std::string>();
253 MIL << "Including file " << fName << std::endl;
254 try {
255 auto doc = YAML::LoadFile( (testcaseDir / fName).asString() );
256 if ( !parseJobs( doc, target, testcaseDir, err ) )
257 return false;
258 MIL << "Including file " << fName << "was successful" << std::endl;
259 } catch ( YAML::Exception &e ) {
260 if ( err ) *err = e.what();
261 return false;
262 } catch ( ... ) {
263 if ( err ) *err = zypp::str::Str() << "Unknown error when parsing the file: " << fName;
264 return false;
265 }
266 return true;
267 }
268
270 if ( !jobNode["job"] ) {
271 if ( err ) {
272 auto errStr = zypp::str::Str();
273 const auto &mark = jobNode.Mark();
274 errStr << "'job' key missing from trial node.";
275 if ( !mark.is_null() ) {
276 errStr << " Line: " << mark.line << " Col: " << mark.column << " pos: " << mark.pos;
277 }
278 *err = errStr;
279 }
280 return false;
281 }
282
283 for ( const auto &elem : jobNode ) {
284 const std::string &key = elem.first.as<std::string>();
285 const auto &data = elem.second;
286 if ( key == "job" ) {
287 n.name() = data.as<std::string>();
288 } else if ( key == "__content") {
289 n.value() = data.as<std::string>();
290 } else {
291 if( data.IsScalar() ) {
292 n.properties().insert( { key, data.as<std::string>() } );
293 } else if ( data.IsSequence() ) {
294 // if the type of a data field is a sequence, we treat all the elements in there
295 // as sub elements. Just like in XML you can have sub nodes its the same here
296 // the key name is ignored in those cases and can be chosen freely
297 if ( !parseJobs( data, n.children(), testcaseDir, err ) )
298 return false;
299 } else if ( data.IsMap() ) {
300 // if the type of a data field is a map, we build a child node from it.
301 // Just like with sequence but a single field.
302 // The key name is ignored in those cases and can be chosen freely
303 if ( !parseSingleJob( data, n.children(), testcaseDir, err) )
304 return false;
305 } else {
306 ERR << "Ignoring field " << key << " with unsupported type:" << data.Type() << std::endl;
307 }
308 }
309 }
310 if constexpr ( isSubNode ) {
311 target.push_back( std::make_shared<zypp::misc::testcase::TestcaseTrial::Node>( std::move(n) ) );
312 } else {
313 target.push_back( std::move(n) );
314 }
315 return true;
316 }
317
318 template <typename T>
319 bool parseJobs ( const YAML::Node &trial, std::vector<T> &target, const zypp::Pathname &testcaseDir, std::string *err ) {
320 for ( const auto &jobNode : trial ) {
321 if ( !parseSingleJob( jobNode, target, testcaseDir, err ) )
322 return false;
323 }
324 return true;
325 }
326
327 bool parseTrial ( const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, const zypp::Pathname &testcaseDir, std::string *err ) {
328 MIL << "Parsing trials." << std::endl;
329 return parseJobs( trial, target.nodes(), testcaseDir, err );
330 }
331}
332
333#endif // ZYPP_MISC_YAMLTESTCASEHELPERS_H
#define if_SolverFlag(N)
#define MIL
Definition Logger.h:130
#define ERR
Definition Logger.h:132
Architecture.
Definition Arch.h:37
Access to the sat-pools string space.
Definition IdString.h:55
IdType id() const
Expert backdoor.
Definition IdString.h:144
'Language[_Country]' codes.
Definition Locale.h:51
bool parseSetup(const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err)
bool parseSingleJob(const YAML::Node &jobNode, std::vector< T > &target, const zypp::Pathname &testcaseDir, std::string *err)
bool parseTrial(const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, const zypp::Pathname &testcaseDir, std::string *err)
bool parseJobs(const YAML::Node &trial, std::vector< T > &target, const zypp::Pathname &testcaseDir, std::string *err)
ResolverFocus resolverFocusFromString(const std::string &val_r)
relates: ResolverFocus Conversion from string (convenience)
const std::vector< std::shared_ptr< Node > > & children() const
const std::map< std::string, std::string > & properties() const
const std::string & value() const
const std::vector< Node > & nodes() const
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:213