b11a70ff89a25ed98977b413ca224f7003f7c638
[platform/upstream/libzypp.git] / zypp / misc / HelixHelpers.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file  zypp/misc/HelixHelpers.h
10  *
11 */
12 #ifndef ZYPP_MISC_HELIXHELPERS_H
13 #define ZYPP_MISC_HELIXHELPERS_H
14
15 #include <zypp/AutoDispose.h>
16 #include <zypp/base/LogControl.h>
17 #include <zypp/misc/LoadTestcase.h>
18
19 #include <libxml/parser.h>
20 #include <libxml/xmlmemory.h>
21
22 #include <string>
23 #include <map>
24 #include <string_view>
25 #include <optional>
26
27
28 namespace helix::detail {
29
30   template <typename Tp>
31   struct AutoXmlFree : public zypp::AutoDispose<Tp*>
32   {
33     AutoXmlFree( Tp* ptr_r = nullptr ) : zypp::AutoDispose<Tp*>( ptr_r, [] ( Tp* ptr_r ) { if ( ptr_r ) ::xmlFree( ptr_r ); } ) {}
34   };
35
36   class XmlNode
37   {
38
39   private:
40     xmlNodePtr _node;
41
42   public:
43     XmlNode (const xmlNodePtr node) : _node(node){};
44     virtual ~XmlNode (){};
45
46     // ---------------------------------- accessors
47
48     std::string_view name() const { return (std::string_view((const char *)_node->name)); }
49     xmlElementType type() const { return (_node->type); }
50
51     xmlNodePtr node() const { return (_node); }
52     std::optional<XmlNode> next() const { return (_node->next == NULL ? std::optional<XmlNode>() : XmlNode (_node->next)); }
53     std::optional<XmlNode> children() const { return (_node->xmlChildrenNode == NULL ? std::optional<XmlNode>() : XmlNode (_node->xmlChildrenNode)); }
54
55     // ---------------------------------- methods
56
57     bool equals (const std::string_view & n) const { return (strncasecmp ( name().data(), n.data(), n.length() ) == 0); }
58     bool isElement (void) const { return (type() == XML_ELEMENT_NODE); }
59
60     std::map<std::string, std::string> getAllProps () const {
61       std::map<std::string, std::string> res;
62       for( xmlAttrPtr attr = _node->properties; NULL != attr; attr = attr->next ) {
63         if ( !attr->children )
64           continue;
65         AutoXmlFree<xmlChar> value( xmlNodeListGetString( _node->doc, attr->children, 1 ) );
66         res.insert( std::make_pair( std::string((char *)attr->name), std::string( (char *)value.value() ) ) );
67       }
68       return res;
69     }
70
71     std::string getContent (void) const {
72       AutoXmlFree<xmlChar> buf;
73       std::string ret;
74
75       *buf = xmlNodeGetContent (_node);
76
77       ret = std::string ((const char *)buf.value());
78
79       return (ret);
80     }
81
82     std::string getProp (const std::string & name, const std::string & deflt = "") const {
83       AutoXmlFree<xmlChar> ret;
84       std::string gs;
85
86       *ret = xmlGetProp (_node, (const xmlChar *)name.c_str());
87
88       if (ret) {
89         gs = std::string ((const char  *)ret.value());
90         return gs;
91       }
92       return deflt;
93     }
94
95
96     template<typename T>
97     T getValue ( const std::string & name, const T& deflt ) const;
98
99     template<typename T>
100     bool getValue ( const std::string & name, T& target ) const;
101   };
102
103   template<>
104   bool XmlNode::getValue ( const std::string & name, std::string& target ) const {
105     AutoXmlFree<xmlChar> xml_s;
106     xmlNode *child;
107
108     *xml_s = xmlGetProp(_node, (const xmlChar *)name.c_str());
109     if (xml_s) {
110       target = std::string ((const char *)xml_s.value());
111       return true;
112     }
113
114     child = _node->xmlChildrenNode;
115
116     while (child) {
117       if (strcasecmp((const char *)(child->name), name.c_str()) == 0) {
118         xml_s = xmlNodeGetContent(child);
119         if (xml_s) {
120           target = std::string ((const char *)xml_s.value());
121           return true;
122         }
123       }
124       child = child->next;
125     }
126     return false;
127   }
128
129   template<>
130   std::string XmlNode::getValue ( const std::string & name, const std::string& deflt ) const {
131     std::string res;
132     if ( !getValue( name, res ) )
133       return deflt;
134     return res;
135   }
136
137   bool parseSetup ( const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &target, std::string *err )
138   {
139     auto architecture = setup.getProp( "arch" );
140     if ( !architecture.empty() )
141     {
142       try {
143         target.architecture = ( zypp::Arch(architecture) );
144       }
145       catch( const zypp::Exception & excpt_r ) {
146         ZYPP_CAUGHT( excpt_r );
147         if ( err ) *err = zypp::str::Str() << "Bad architecture '" << architecture << "' in <setup...>";
148         return false;
149       }
150     }
151
152     auto node = setup.children();
153     while ( node )
154     {
155       if ( !node->isElement() ) {
156         node = node->next();
157         continue;
158       }
159
160 #define if_SolverFlag( N ) if ( node->equals( #N ) ) { target.N = true; }
161       if_SolverFlag( ignorealreadyrecommended ) else if ( node->equals( "ignorealready" ) )     { target.ignorealreadyrecommended = true; }
162       else if_SolverFlag( onlyRequires )        else if ( node->equals( "ignorerecommended" ) ) { target.onlyRequires = true; }
163       else if_SolverFlag( forceResolve )
164
165       else if_SolverFlag( cleandepsOnRemove )
166
167       else if_SolverFlag( allowDowngrade )
168       else if_SolverFlag( allowNameChange )
169       else if_SolverFlag( allowArchChange )
170       else if_SolverFlag( allowVendorChange )
171
172       else if_SolverFlag( dupAllowDowngrade )
173       else if_SolverFlag( dupAllowNameChange )
174       else if_SolverFlag( dupAllowArchChange )
175       else if_SolverFlag( dupAllowVendorChange )
176 #undef if_SolverFlag
177       else if ( node->equals("focus") ) {
178         target.resolverFocus = zypp::resolverFocusFromString( node->getProp("value") );
179       }
180       else if ( node->equals("system") ) {
181         target.systemRepo = zypp::misc::testcase::RepoData {
182           zypp::misc::testcase::TestcaseRepoType::Helix,
183           "@System",
184           99,
185           node->getProp("file")
186         };
187       }
188       else if ( node->equals("hardwareInfo") ) {
189         target.hardwareInfoFile = target.globalPath / node->getProp("path");
190       }
191       else if ( node->equals("modalias") ) {
192         target.modaliasList.push_back( node->getProp("name") );
193       }
194       else if ( node->equals("multiversion") ) {
195         target.multiversionSpec.insert( node->getProp("name") );
196       }
197       else if (node->equals ("channel")) {
198         std::string name = node->getProp("name");
199         std::string file = node->getProp("file");
200         std::string type = node->getProp("type");
201
202         unsigned prio = 99;
203         std::string priority = node->getProp("priority");
204         if ( !priority.empty() ) {
205           prio = zypp::str::strtonum<unsigned>( priority );
206         }
207
208         target.repos.push_back( zypp::misc::testcase::RepoData{
209           zypp::misc::testcase::TestcaseRepoType::Helix,
210           name,
211           prio,
212           file
213         });
214       }
215       else if ( node->equals("source") )
216       {
217         std::string url = node->getProp("url");
218         std::string alias = node->getProp("name");
219         target.repos.push_back( zypp::misc::testcase::RepoData{
220           zypp::misc::testcase::TestcaseRepoType::Url,
221           alias,
222           99,
223           url
224         });
225       }
226       else if ( node->equals("force-install") )
227       {
228         target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstall{
229           node->getProp("channel"),
230           node->getProp("package"),
231           node->getProp("kind")
232         });
233       }
234       else if ( node->equals("mediaid") )
235       {
236         target.show_mediaid = true;
237       }
238       else if ( node->equals("arch") ) {
239         MIL << "<arch...> deprecated, use <setup arch=\"...\"> instead" << std::endl;
240         std::string architecture = node->getProp("name");
241         if ( architecture.empty() ) {
242           ERR << "Property 'name=' in <arch.../> missing or empty" << std::endl;
243         }
244         else {
245           MIL << "Setting architecture to '" << architecture << "'" << std::endl;
246           target.architecture = zypp::Arch( architecture );
247         }
248       }
249       else if ( node->equals("locale") )
250       {
251         zypp::Locale loc( node->getProp("name") );
252         std::string fate = node->getProp("fate");
253         if ( !loc ) {
254           ERR << "Bad or missing name in <locale...>" << std::endl;
255         }
256         else if ( fate == "added" ) {
257           target.localesTracker.added().insert( loc );
258         }
259         else if ( fate == "removed" ) {
260           target.localesTracker.removed().insert( loc );
261         }
262         else {
263           target.localesTracker.current().insert( loc );
264         }
265       }
266       else if ( node->equals("autoinst") ) {
267         target.autoinstalled.push( zypp::IdString( node->getProp("name") ).id() );
268       }
269       else if ( node->equals("systemCheck") ) {
270         target.systemCheck = target.globalPath / node->getProp("path");
271       }
272       else if ( node->equals("setlicencebit") ) {
273         target.set_licence = true;
274       }
275       else {
276         ERR << "Unrecognized tag '" << node->name() << "' in setup" << std::endl;
277       }
278       node = node->next();
279     }
280     return true;
281   }
282
283   bool parseTrialNode ( const XmlNode &node, zypp::misc::testcase::TestcaseTrial::Node &testcaseNode )
284   {
285     testcaseNode.name = node.name();
286     const auto & content = node.getContent();
287     if ( !content.empty() ) {
288       testcaseNode.value = content;
289     }
290     testcaseNode.properties = node.getAllProps();
291
292     for ( auto childNode = node.children(); childNode; childNode = childNode->next() ) {
293       auto testNode = std::make_shared<zypp::misc::testcase::TestcaseTrial::Node>();
294       if ( !parseTrialNode( *childNode, *testNode ) )
295         return false;
296       testcaseNode.children.push_back( testNode );
297     }
298     return true;
299   }
300
301   bool parseTrial ( const XmlNode &trial, zypp::misc::testcase::TestcaseTrial &target, std::string * )
302   {
303     auto node = trial.children();
304     while (node) {
305       if (!node->isElement()) {
306         node = node->next();
307         continue;
308       }
309
310       zypp::misc::testcase::TestcaseTrial::Node testcaseNode;
311       parseTrialNode( *node, testcaseNode );
312       target.nodes.push_back( testcaseNode );
313       node = node->next();
314     }
315     return true;
316   }
317 }
318
319 #endif