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>
19 #include <libxml/parser.h>
20 #include <libxml/xmlmemory.h>
24 #include <string_view>
28 namespace helix::detail {
30 template <typename Tp>
31 struct AutoXmlFree : public zypp::AutoDispose<Tp*>
33 AutoXmlFree( Tp* ptr_r = nullptr ) : zypp::AutoDispose<Tp*>( ptr_r, [] ( Tp* ptr_r ) { if ( ptr_r ) ::xmlFree( ptr_r ); } ) {}
43 XmlNode (const xmlNodePtr node) : _node(node){};
44 virtual ~XmlNode (){};
46 // ---------------------------------- accessors
48 std::string_view name() const { return (std::string_view((const char *)_node->name)); }
49 xmlElementType type() const { return (_node->type); }
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)); }
55 // ---------------------------------- methods
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); }
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 )
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() ) ) );
71 std::string getContent (void) const {
72 AutoXmlFree<xmlChar> buf;
75 *buf = xmlNodeGetContent (_node);
77 ret = std::string ((const char *)buf.value());
82 std::string getProp (const std::string & name, const std::string & deflt = "") const {
83 AutoXmlFree<xmlChar> ret;
86 *ret = xmlGetProp (_node, (const xmlChar *)name.c_str());
89 gs = std::string ((const char *)ret.value());
97 T getValue ( const std::string & name, const T& deflt ) const;
100 bool getValue ( const std::string & name, T& target ) const;
104 bool XmlNode::getValue ( const std::string & name, std::string& target ) const {
105 AutoXmlFree<xmlChar> xml_s;
108 *xml_s = xmlGetProp(_node, (const xmlChar *)name.c_str());
110 target = std::string ((const char *)xml_s.value());
114 child = _node->xmlChildrenNode;
117 if (strcasecmp((const char *)(child->name), name.c_str()) == 0) {
118 xml_s = xmlNodeGetContent(child);
120 target = std::string ((const char *)xml_s.value());
130 std::string XmlNode::getValue ( const std::string & name, const std::string& deflt ) const {
132 if ( !getValue( name, res ) )
137 bool parseSetup ( const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &target, std::string *err )
139 auto architecture = setup.getProp( "arch" );
140 if ( !architecture.empty() )
143 target.architecture = ( zypp::Arch(architecture) );
145 catch( const zypp::Exception & excpt_r ) {
146 ZYPP_CAUGHT( excpt_r );
147 if ( err ) *err = zypp::str::Str() << "Bad architecture '" << architecture << "' in <setup...>";
152 auto node = setup.children();
155 if ( !node->isElement() ) {
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 )
165 else if_SolverFlag( cleandepsOnRemove )
167 else if_SolverFlag( allowDowngrade )
168 else if_SolverFlag( allowNameChange )
169 else if_SolverFlag( allowArchChange )
170 else if_SolverFlag( allowVendorChange )
172 else if_SolverFlag( dupAllowDowngrade )
173 else if_SolverFlag( dupAllowNameChange )
174 else if_SolverFlag( dupAllowArchChange )
175 else if_SolverFlag( dupAllowVendorChange )
177 else if ( node->equals("focus") ) {
178 target.resolverFocus = zypp::resolverFocusFromString( node->getProp("value") );
180 else if ( node->equals("system") ) {
181 target.systemRepo = zypp::misc::testcase::RepoData {
182 zypp::misc::testcase::TestcaseRepoType::Helix,
185 node->getProp("file")
188 else if ( node->equals("hardwareInfo") ) {
189 target.hardwareInfoFile = target.globalPath / node->getProp("path");
191 else if ( node->equals("modalias") ) {
192 target.modaliasList.push_back( node->getProp("name") );
194 else if ( node->equals("multiversion") ) {
195 target.multiversionSpec.insert( node->getProp("name") );
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");
203 std::string priority = node->getProp("priority");
204 if ( !priority.empty() ) {
205 prio = zypp::str::strtonum<unsigned>( priority );
208 target.repos.push_back( zypp::misc::testcase::RepoData{
209 zypp::misc::testcase::TestcaseRepoType::Helix,
215 else if ( node->equals("source") )
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,
226 else if ( node->equals("force-install") )
228 target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstall{
229 node->getProp("channel"),
230 node->getProp("package"),
231 node->getProp("kind")
234 else if ( node->equals("mediaid") )
236 target.show_mediaid = true;
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;
245 MIL << "Setting architecture to '" << architecture << "'" << std::endl;
246 target.architecture = zypp::Arch( architecture );
249 else if ( node->equals("locale") )
251 zypp::Locale loc( node->getProp("name") );
252 std::string fate = node->getProp("fate");
254 ERR << "Bad or missing name in <locale...>" << std::endl;
256 else if ( fate == "added" ) {
257 target.localesTracker.added().insert( loc );
259 else if ( fate == "removed" ) {
260 target.localesTracker.removed().insert( loc );
263 target.localesTracker.current().insert( loc );
266 else if ( node->equals("autoinst") ) {
267 target.autoinstalled.push( zypp::IdString( node->getProp("name") ).id() );
269 else if ( node->equals("systemCheck") ) {
270 target.systemCheck = target.globalPath / node->getProp("path");
272 else if ( node->equals("setlicencebit") ) {
273 target.set_licence = true;
276 ERR << "Unrecognized tag '" << node->name() << "' in setup" << std::endl;
283 bool parseTrialNode ( const XmlNode &node, zypp::misc::testcase::TestcaseTrial::Node &testcaseNode )
285 testcaseNode.name = node.name();
286 const auto & content = node.getContent();
287 if ( !content.empty() ) {
288 testcaseNode.value = content;
290 testcaseNode.properties = node.getAllProps();
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 ) )
296 testcaseNode.children.push_back( testNode );
301 bool parseTrial ( const XmlNode &trial, zypp::misc::testcase::TestcaseTrial &target, std::string * )
303 auto node = trial.children();
305 if (!node->isElement()) {
310 zypp::misc::testcase::TestcaseTrial::Node testcaseNode;
311 parseTrialNode( *node, testcaseNode );
312 target.nodes.push_back( testcaseNode );