1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/misc/HelixHelpers.h
12 #ifndef ZYPP_MISC_HELIXHELPERS_H
13 #define ZYPP_MISC_HELIXHELPERS_H
15 #include <zypp/AutoDispose.h>
16 #include <zypp/base/LogControl.h>
17 #include <zypp/misc/LoadTestcase.h>
18 #include <zypp/misc/TestcaseSetupImpl.h>
20 #include <libxml/parser.h>
21 #include <libxml/xmlmemory.h>
25 #include <string_view>
29 namespace helix::detail {
31 template <typename Tp>
32 struct AutoXmlFree : public zypp::AutoDispose<Tp*>
34 AutoXmlFree( Tp* ptr_r = nullptr ) : zypp::AutoDispose<Tp*>( ptr_r, [] ( Tp* ptr_r ) { if ( ptr_r ) ::xmlFree( ptr_r ); } ) {}
44 XmlNode (const xmlNodePtr node) : _node(node){};
45 virtual ~XmlNode (){};
47 // ---------------------------------- accessors
49 std::string_view name() const { return (std::string_view((const char *)_node->name)); }
50 xmlElementType type() const { return (_node->type); }
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)); }
56 // ---------------------------------- methods
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); }
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 )
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() ) ) );
72 std::string getContent (void) const {
73 AutoXmlFree<xmlChar> buf;
76 *buf = xmlNodeGetContent (_node);
78 ret = std::string ((const char *)buf.value());
83 std::string getProp (const std::string & name, const std::string & deflt = "") const {
84 AutoXmlFree<xmlChar> ret;
87 *ret = xmlGetProp (_node, (const xmlChar *)name.c_str());
90 gs = std::string ((const char *)ret.value());
98 T getValue ( const std::string & name, const T& deflt ) const;
101 bool getValue ( const std::string & name, T& target ) const;
105 bool XmlNode::getValue ( const std::string & name, std::string& target ) const {
106 AutoXmlFree<xmlChar> xml_s;
109 *xml_s = xmlGetProp(_node, (const xmlChar *)name.c_str());
111 target = std::string ((const char *)xml_s.value());
115 child = _node->xmlChildrenNode;
118 if (strcasecmp((const char *)(child->name), name.c_str()) == 0) {
119 xml_s = xmlNodeGetContent(child);
121 target = std::string ((const char *)xml_s.value());
131 std::string XmlNode::getValue ( const std::string & name, const std::string& deflt ) const {
133 if ( !getValue( name, res ) )
138 bool parseSetup ( const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err )
140 auto &target = t.data();
141 auto architecture = setup.getProp( "arch" );
142 if ( !architecture.empty() )
145 target.architecture = ( zypp::Arch(architecture) );
147 catch( const zypp::Exception & excpt_r ) {
148 ZYPP_CAUGHT( excpt_r );
149 if ( err ) *err = zypp::str::Str() << "Bad architecture '" << architecture << "' in <setup...>";
154 auto node = setup.children();
157 if ( !node->isElement() ) {
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 )
167 else if_SolverFlag( cleandepsOnRemove )
169 else if_SolverFlag( allowDowngrade )
170 else if_SolverFlag( allowNameChange )
171 else if_SolverFlag( allowArchChange )
172 else if_SolverFlag( allowVendorChange )
174 else if_SolverFlag( dupAllowDowngrade )
175 else if_SolverFlag( dupAllowNameChange )
176 else if_SolverFlag( dupAllowArchChange )
177 else if_SolverFlag( dupAllowVendorChange )
179 else if ( node->equals("focus") ) {
180 target.resolverFocus = zypp::resolverFocusFromString( node->getProp("value") );
182 else if ( node->equals("system") ) {
183 target.systemRepo = zypp::misc::testcase::RepoDataImpl {
184 zypp::misc::testcase::TestcaseRepoType::Helix,
187 node->getProp("file")
190 else if ( node->equals("hardwareInfo") ) {
191 target.hardwareInfoFile = target.globalPath / node->getProp("path");
193 else if ( node->equals("modalias") ) {
194 target.modaliasList.push_back( node->getProp("name") );
196 else if ( node->equals("multiversion") ) {
197 target.multiversionSpec.insert( node->getProp("name") );
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");
205 std::string priority = node->getProp("priority");
206 if ( !priority.empty() ) {
207 prio = zypp::str::strtonum<unsigned>( priority );
210 target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
211 zypp::misc::testcase::TestcaseRepoType::Helix,
217 else if ( node->equals("source") )
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,
228 else if ( node->equals("force-install") )
230 target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstallImpl{
231 node->getProp("channel"),
232 node->getProp("package"),
233 node->getProp("kind")
236 else if ( node->equals("mediaid") )
238 target.show_mediaid = true;
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;
247 MIL << "Setting architecture to '" << architecture << "'" << std::endl;
248 target.architecture = zypp::Arch( architecture );
251 else if ( node->equals("locale") )
253 zypp::Locale loc( node->getProp("name") );
254 std::string fate = node->getProp("fate");
256 ERR << "Bad or missing name in <locale...>" << std::endl;
258 else if ( fate == "added" ) {
259 target.localesTracker.added().insert( loc );
261 else if ( fate == "removed" ) {
262 target.localesTracker.removed().insert( loc );
265 target.localesTracker.current().insert( loc );
268 else if ( node->equals("autoinst") ) {
269 target.autoinstalled.push( zypp::IdString( node->getProp("name") ).id() );
271 else if ( node->equals("systemCheck") ) {
272 target.systemCheck = target.globalPath / node->getProp("path");
274 else if ( node->equals("setlicencebit") ) {
275 target.set_licence = true;
278 ERR << "Unrecognized tag '" << node->name() << "' in setup" << std::endl;
285 bool parseTrialNode ( const XmlNode &node, zypp::misc::testcase::TestcaseTrial::Node &testcaseNode )
287 testcaseNode.name() = node.name();
288 const auto & content = node.getContent();
289 if ( !content.empty() ) {
290 testcaseNode.value() = content;
292 testcaseNode.properties() = node.getAllProps();
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 ) )
298 testcaseNode.children().push_back( testNode );
303 bool parseTrial ( const XmlNode &trial, zypp::misc::testcase::TestcaseTrial &target, std::string * )
305 auto node = trial.children();
307 if (!node->isElement()) {
312 zypp::misc::testcase::TestcaseTrial::Node testcaseNode;
313 parseTrialNode( *node, testcaseNode );
314 target.nodes().push_back( testcaseNode );