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