1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/solver/detail/Testcase.cc
17 #include "zypp/solver/detail/Testcase.h"
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/LogControl.h"
20 #include "zypp/ZConfig.h"
21 #include "zypp/PathInfo.h"
22 #include "zypp/Product.h"
23 #include "zypp/Package.h"
24 #include "zypp/Edition.h"
25 #include "zypp/parser/xml_escape_parser.hpp"
26 #include "zypp/base/String.h"
27 #include "zypp/base/PtrTypes.h"
28 #include "zypp/Capabilities.h"
29 #include "zypp/sat/Solvable.h"
30 #include "zypp/sat/detail/PoolImpl.h"
33 /////////////////////////////////////////////////////////////////////////
35 { ///////////////////////////////////////////////////////////////////////
36 ///////////////////////////////////////////////////////////////////////
38 { /////////////////////////////////////////////////////////////////////
39 /////////////////////////////////////////////////////////////////////
41 { ///////////////////////////////////////////////////////////////////
47 using namespace zypp::str;
49 IMPL_PTR_TYPE(HelixResolvable);
51 static std::string xml_escape( const std::string &text )
53 iobind::parser::xml_escape_parser parser;
54 return parser.escape(text);
57 static std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
60 result += "<" + tag + ">";
63 result += xml_escape(text);
67 result += "</" + tag + ">";
73 std::string helixXML( const T &obj ); //undefined
76 std::string helixXML( const Edition &edition )
79 str << xml_tag_enclose(edition.version(), "version");
80 if (!edition.release().empty())
81 str << xml_tag_enclose(edition.release(), "release");
82 if (edition.epoch() != Edition::noepoch)
83 str << xml_tag_enclose(numstring(edition.epoch()), "epoch");
88 std::string helixXML( const Arch &arch )
91 str << xml_tag_enclose(arch.asString(), "arch");
96 std::string helixXML( const Capability &cap )
99 CapDetail detail = cap.detail();
100 if (detail.isSimple()) {
101 if (detail.isVersioned()) {
102 str << "<dep name='" << xml_escape(detail.name().asString()) << "'"
103 << " op='" << xml_escape(detail.op().asString()) << "'"
104 << " version='" << xml_escape(detail.ed().version()) << "'";
105 if (!detail.ed().release().empty())
106 str << " release='" << xml_escape(detail.ed().release()) << "'";
107 if (detail.ed().epoch() != Edition::noepoch)
108 str << " epoch='" << xml_escape(numstring(detail.ed().epoch())) << "'";
109 str << " />" << endl;
111 str << "<dep name='" << xml_escape(cap.asString()) << "' />" << endl;
113 } else if (detail.isExpression()) {
114 if (detail.capRel() == CapDetail::CAP_AND
115 && detail.lhs().detail().isNamed()
116 && detail.rhs().detail().isNamed()) {
117 // packageand dependency
118 str << "<dep name='packageand("
119 << IdString(detail.lhs().id()) << ","
120 << IdString(detail.rhs().id()) << ")' />" << endl;
123 IdString packageName;
124 if (detail.capRel() == CapDetail::CAP_AND) {
125 packageName = IdString(detail.lhs().id());
126 detail = detail.rhs().detail();
128 if (detail.capRel() == CapDetail::CAP_NAMESPACE
129 && detail.lhs().id() == NAMESPACE_MODALIAS) {
130 str << "<dep name='modalias(";
131 if (!packageName.empty())
132 str << packageName << ":";
133 str << IdString(detail.rhs().id()) << ")' />" << endl;
135 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
136 MIL << "ignoring " << cap << " cause this format will be supported" << endl;
140 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
141 MIL << "ignoring " << cap << " cause this format will be supported" << endl;
148 std::string helixXML( const Capabilities &caps )
151 Capabilities::const_iterator it = caps.begin();
153 for ( ; it != caps.end(); ++it)
155 str << TAB2 << helixXML((*it));
162 std::string helixXML( const CapabilitySet &caps )
165 CapabilitySet::const_iterator it = caps.begin();
167 for ( ; it != caps.end(); ++it)
169 str << TAB2 << helixXML((*it));
177 std::string helixXML( const Dependencies &dep )
180 if ( dep[Dep::PROVIDES].size() > 0 )
181 str << TAB << xml_tag_enclose(helixXML(dep[Dep::PROVIDES]), "provides") << endl;
182 if ( dep[Dep::CONFLICTS].size() > 0 )
183 str << TAB << xml_tag_enclose(helixXML(dep[Dep::CONFLICTS]), "conflicts") << endl;
184 if ( dep[Dep::OBSOLETES].size() > 0 )
185 str << TAB << xml_tag_enclose(helixXML(dep[Dep::OBSOLETES]), "obsoletes") << endl;
186 if ( dep[Dep::FRESHENS].size() > 0 )
187 str << TAB << xml_tag_enclose(helixXML(dep[Dep::FRESHENS]), "freshens") << endl;
188 if ( dep[Dep::REQUIRES].size() > 0 )
189 str << TAB << xml_tag_enclose(helixXML(dep[Dep::REQUIRES]), "requires") << endl;
190 if ( dep[Dep::RECOMMENDS].size() > 0 )
191 str << TAB << xml_tag_enclose(helixXML(dep[Dep::RECOMMENDS]), "recommends") << endl;
192 if ( dep[Dep::ENHANCES].size() > 0 )
193 str << TAB << xml_tag_enclose(helixXML(dep[Dep::ENHANCES]), "enhances") << endl;
194 if ( dep[Dep::SUPPLEMENTS].size() > 0 )
195 str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUPPLEMENTS]), "supplements") << endl;
196 if ( dep[Dep::SUGGESTS].size() > 0 )
197 str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUGGESTS]), "suggests") << endl;
201 inline string helixXML( const Resolvable::constPtr &obj, Dep deptag_r )
204 Capabilities caps( obj->dep(deptag_r) );
205 if ( ! caps.empty() )
206 out << TAB << xml_tag_enclose(helixXML(caps), deptag_r.asString()) << endl;
210 std::string helixXML( const PoolItem &item )
212 const Resolvable::constPtr resolvable = item.resolvable();
214 str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
215 str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
216 str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl;
217 if ( isKind<Package>(resolvable) ) {
218 str << TAB << "<history>" << endl << TAB << "<update>" << endl;
219 str << TAB2 << helixXML (resolvable->arch()) << endl;
220 str << TAB2 << helixXML (resolvable->edition()) << endl;
221 str << TAB << "</update>" << endl << TAB << "</history>" << endl;
223 str << TAB << helixXML (resolvable->arch()) << endl;
224 str << TAB << helixXML (resolvable->edition()) << endl;
226 str << helixXML( resolvable, Dep::PROVIDES);
227 str << helixXML( resolvable, Dep::PREREQUIRES);
228 str << helixXML( resolvable, Dep::CONFLICTS);
229 str << helixXML( resolvable, Dep::OBSOLETES);
230 str << helixXML( resolvable, Dep::FRESHENS);
231 str << helixXML( resolvable, Dep::REQUIRES);
232 str << helixXML( resolvable, Dep::RECOMMENDS);
233 str << helixXML( resolvable, Dep::ENHANCES);
234 str << helixXML( resolvable, Dep::SUPPLEMENTS);
235 str << helixXML( resolvable, Dep::SUGGESTS);
237 str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;
241 //---------------------------------------------------------------------------
244 :dumpPath("/var/log/YaST2/solverTestcase")
248 Testcase::Testcase(const std::string & path)
254 Testcase::~Testcase()
259 bool Testcase::createTestcasePool(const ResPool &pool)
261 PathInfo path (dumpPath);
263 if ( !path.isExist() ) {
264 if (zypp::filesystem::mkdir (dumpPath)!=0) {
265 ERR << "Cannot create directory " << dumpPath << endl;
270 ERR << dumpPath << " is not a directory." << endl;
274 zypp::filesystem::clean_dir (dumpPath);
277 RepositoryTable repoTable;
278 HelixResolvable system (dumpPath + "/solver-system.xml.gz");
280 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
282 if ( it->status().isInstalled() ) {
284 system.addResolvable (*it);
287 sat::Repo repo = it->resolvable()->satSolvable().repo();
288 if (repoTable.find (repo) == repoTable.end()) {
289 repoTable[repo] = new HelixResolvable(dumpPath + "/"
290 + str::numstring((long)repo.id())
291 + "-package.xml.gz");
293 repoTable[repo]->addResolvable (*it);
299 bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
301 PathInfo path (dumpPath);
303 if ( !path.isExist() ) {
304 if (zypp::filesystem::mkdir (dumpPath)!=0) {
305 ERR << "Cannot create directory " << dumpPath << endl;
310 ERR << dumpPath << " is not a directory." << endl;
313 // remove old stuff if pool will be dump
315 zypp::filesystem::clean_dir (dumpPath);
319 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
320 zypp::base::LogControl::TmpExcessive excessive;
322 resolver.reset(true); // true = resetting all valid solverresults
323 resolver.resolvePool();
325 zypp::base::LogControl::instance().logfile( "/var/log/YaST2/y2log" );
328 ResPool pool = resolver.pool();
329 RepositoryTable repoTable;
330 PoolItemList items_to_install;
331 PoolItemList items_to_remove;
332 PoolItemList items_locked;
333 PoolItemList items_keep;
334 PoolItemList language;
335 HelixResolvable_Ptr system = NULL;
338 system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
340 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
342 Resolvable::constPtr res = it->resolvable();
344 #warning NO MORE LANGUAGE RESOLVABLE
345 // - use pools list of requested locales and pass it as 'LocaleList language'
346 // - restore the list via Pool::setRequestedLocales.
348 if (isKind<Language>(res)) {
349 if ( it->status().isInstalled()
350 || it->status().isToBeInstalled()) {
351 language.push_back (*it);
355 if ( system && it->status().isInstalled() ) {
357 system->addResolvable (*it);
360 sat::Repo repo = it->resolvable()->satSolvable().repo();
362 if (repoTable.find (repo) == repoTable.end()) {
363 repoTable[repo] = new HelixResolvable(dumpPath + "/"
364 + str::numstring((long)repo.id())
365 + "-package.xml.gz");
367 repoTable[repo]->addResolvable (*it);
371 if ( it->status().isToBeInstalled()
372 && !(it->status().isBySolver())) {
373 items_to_install.push_back (*it);
375 if ( it->status().isKept()
376 && !(it->status().isBySolver())) {
377 items_keep.push_back (*it);
379 if ( it->status().isToBeUninstalled()
380 && !(it->status().isBySolver())) {
381 items_to_remove.push_back (*it);
383 if ( it->status().isLocked()
384 && !(it->status().isBySolver())) {
385 items_locked.push_back (*it);
389 // writing control file "*-test.xml"
391 HelixControl control (dumpPath + "/solver-test.xml",
393 ZConfig::instance().systemArchitecture(),
396 for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
397 control.installResolvable (iter->resolvable(), iter->status());
400 for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
401 control.lockResolvable (iter->resolvable(), iter->status());
404 for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
405 control.keepResolvable (iter->resolvable(), iter->status());
408 for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
409 control.deleteResolvable (iter->resolvable(), iter->status());
412 control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
417 //---------------------------------------------------------------------------
419 HelixResolvable::HelixResolvable(const std::string & path)
422 file = new ofgzstream(path.c_str());
424 ZYPP_THROW (Exception( "Can't open " + path ) );
427 *file << "<channel><subchannel>" << endl;
430 HelixResolvable::~HelixResolvable()
432 *file << "</subchannel></channel>" << endl;
437 void HelixResolvable::addResolvable(const PoolItem item)
439 *file << helixXML (item);
442 //---------------------------------------------------------------------------
444 HelixControl::HelixControl(const std::string & controlPath,
445 const RepositoryTable & repoTable,
446 const Arch & systemArchitecture,
447 const PoolItemList &languages,
448 const std::string & systemPath)
449 :dumpFile (controlPath)
451 file = new ofstream(controlPath.c_str());
453 ZYPP_THROW (Exception( "Can't open " + controlPath ) );
456 *file << "<?xml version=\"1.0\"?>" << endl
457 << "<!-- testcase generated by YaST -->" << endl
459 << "<setup arch=\"" << systemArchitecture << "\">" << endl
460 << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl;
461 for ( RepositoryTable::const_iterator it = repoTable.begin();
462 it != repoTable.end(); ++it ) {
463 RepoInfo repo = it->first.info();
464 *file << TAB << "<!-- " << endl
465 << TAB << "- alias : " << repo.alias() << endl;
466 for ( RepoInfo::urls_const_iterator itUrl = repo.baseUrlsBegin();
467 itUrl != repo.baseUrlsEnd();
470 *file << TAB << "- url : " << *itUrl << endl;
472 *file << TAB << "- path : " << repo.path() << endl;
473 *file << TAB << "- type : " << repo.type() << endl;
474 *file << TAB << " -->" << endl;
476 *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id())
477 << "-package.xml.gz\" name=\"" << repo.alias()
478 << "\" />" << endl << endl;
480 for (PoolItemList::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
481 *file << TAB << "<locale name=\"" << iter->resolvable()->name()
484 *file << "</setup>" << endl
486 << "<showpool all=\"yes\"/>" << endl;
489 HelixControl::HelixControl()
490 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
492 HelixControl (dumpFile);
495 HelixControl::~HelixControl()
497 *file << "</trial>" << endl
498 << "</test>" << endl;
502 void HelixControl::installResolvable(const ResObject::constPtr &resObject,
503 const ResStatus &status)
505 *file << "<install channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
506 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
507 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
508 << " status=\"" << status << "\""
512 void HelixControl::lockResolvable(const ResObject::constPtr &resObject,
513 const ResStatus &status)
515 *file << "<lock channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
516 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
517 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
518 << " status=\"" << status << "\""
522 void HelixControl::keepResolvable(const ResObject::constPtr &resObject,
523 const ResStatus &status)
525 *file << "<keep channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
526 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
527 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
528 << " status=\"" << status << "\""
532 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject,
533 const ResStatus &status)
535 *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
536 << " name=\"" << resObject->name() << "\""
537 << " status=\"" << status << "\""
541 void HelixControl::addDependencies (const CapabilitySet & capRequire, const CapabilitySet & capConflict)
543 for (CapabilitySet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) {
544 *file << "<addRequire " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
546 for (CapabilitySet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) {
547 *file << "<addConflict " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
552 ///////////////////////////////////////////////////////////////////
553 };// namespace detail
554 /////////////////////////////////////////////////////////////////////
555 /////////////////////////////////////////////////////////////////////
556 };// namespace solver
557 ///////////////////////////////////////////////////////////////////////
558 ///////////////////////////////////////////////////////////////////////
560 /////////////////////////////////////////////////////////////////////////