1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/solver/detail/Testcase.cc
17 #define ZYPP_USE_RESOLVER_INTERNALS
19 #include "zypp/solver/detail/Testcase.h"
20 #include "zypp/base/Logger.h"
21 #include "zypp/base/LogControl.h"
22 #include "zypp/base/GzStream.h"
23 #include "zypp/base/String.h"
24 #include "zypp/base/PtrTypes.h"
25 #include "zypp/base/NonCopyable.h"
26 #include "zypp/base/ReferenceCounted.h"
28 #include "zypp/parser/xml/XmlEscape.h"
30 #include "zypp/ZConfig.h"
31 #include "zypp/PathInfo.h"
32 #include "zypp/ResPool.h"
33 #include "zypp/Repository.h"
34 #include "zypp/target/modalias/Modalias.h"
36 #include "zypp/sat/detail/PoolImpl.h"
37 #include "zypp/solver/detail/Resolver.h"
38 #include "zypp/solver/detail/SystemCheck.h"
40 /////////////////////////////////////////////////////////////////////////
42 { ///////////////////////////////////////////////////////////////////////
43 ///////////////////////////////////////////////////////////////////////
45 { /////////////////////////////////////////////////////////////////////
46 /////////////////////////////////////////////////////////////////////
48 { ///////////////////////////////////////////////////////////////////
54 using namespace zypp::str;
56 //---------------------------------------------------------------------------
58 inline std::string xml_escape( const std::string &text )
60 return zypp::xml::escape(text);
63 inline std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
66 result += "<" + tag + ">";
69 result += xml_escape(text);
73 result += "</" + tag + ">";
78 std::string helixXML( const T &obj ); //undefined
81 std::string helixXML( const Edition &edition )
84 str << xml_tag_enclose(edition.version(), "version");
85 if (!edition.release().empty())
86 str << xml_tag_enclose(edition.release(), "release");
87 if (edition.epoch() != Edition::noepoch)
88 str << xml_tag_enclose(numstring(edition.epoch()), "epoch");
93 std::string helixXML( const Arch &arch )
96 str << xml_tag_enclose(arch.asString(), "arch");
101 std::string helixXML( const Capability &cap )
104 CapDetail detail = cap.detail();
105 if (detail.isSimple()) {
106 if (detail.isVersioned()) {
107 str << "<dep name='" << xml_escape(detail.name().asString()) << "'"
108 << " op='" << xml_escape(detail.op().asString()) << "'"
109 << " version='" << xml_escape(detail.ed().version()) << "'";
110 if (!detail.ed().release().empty())
111 str << " release='" << xml_escape(detail.ed().release()) << "'";
112 if (detail.ed().epoch() != Edition::noepoch)
113 str << " epoch='" << xml_escape(numstring(detail.ed().epoch())) << "'";
114 str << " />" << endl;
116 str << "<dep name='" << xml_escape(cap.asString()) << "' />" << endl;
118 } else if (detail.isExpression()) {
119 if (detail.capRel() == CapDetail::CAP_AND
120 && detail.lhs().detail().isNamed()
121 && detail.rhs().detail().isNamed()) {
122 // packageand dependency
123 str << "<dep name='packageand("
124 << IdString(detail.lhs().id()) << ":"
125 << IdString(detail.rhs().id()) << ")' />" << endl;
126 } else if (detail.capRel() == CapDetail::CAP_NAMESPACE
127 && detail.lhs().id() == NAMESPACE_OTHERPROVIDERS) {
128 str << "<dep name='otherproviders("
129 << IdString(detail.rhs().id()) << ")' />" << endl;
132 IdString packageName;
133 if (detail.capRel() == CapDetail::CAP_AND) {
134 packageName = IdString(detail.lhs().id());
135 detail = detail.rhs().detail();
137 if (detail.capRel() == CapDetail::CAP_NAMESPACE
138 && detail.lhs().id() == NAMESPACE_MODALIAS) {
139 str << "<dep name='modalias(";
140 if (!packageName.empty())
141 str << packageName << ":";
142 str << IdString(detail.rhs().id()) << ")' />" << endl;
144 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
148 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
155 std::string helixXML( const Capabilities &caps )
158 Capabilities::const_iterator it = caps.begin();
160 for ( ; it != caps.end(); ++it)
162 str << TAB2 << helixXML((*it));
169 std::string helixXML( const CapabilitySet &caps )
172 CapabilitySet::const_iterator it = caps.begin();
174 for ( ; it != caps.end(); ++it)
176 str << TAB2 << helixXML((*it));
182 inline string helixXML( const Resolvable::constPtr &obj, Dep deptag_r )
185 Capabilities caps( obj->dep(deptag_r) );
186 if ( ! caps.empty() )
187 out << TAB << xml_tag_enclose(helixXML(caps), deptag_r.asString()) << endl;
191 std::string helixXML( const PoolItem &item )
193 const Resolvable::constPtr resolvable = item.resolvable();
195 str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
196 str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
197 str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl;
198 str << TAB << xml_tag_enclose (item->buildtime().asSeconds(), "buildtime", true) << endl;
199 if ( isKind<Package>(resolvable) ) {
200 str << TAB << "<history>" << endl << TAB << "<update>" << endl;
201 str << TAB2 << helixXML (resolvable->arch()) << endl;
202 str << TAB2 << helixXML (resolvable->edition()) << endl;
203 str << TAB << "</update>" << endl << TAB << "</history>" << endl;
205 str << TAB << helixXML (resolvable->arch()) << endl;
206 str << TAB << helixXML (resolvable->edition()) << endl;
208 str << helixXML( resolvable, Dep::PROVIDES);
209 str << helixXML( resolvable, Dep::PREREQUIRES);
210 str << helixXML( resolvable, Dep::CONFLICTS);
211 str << helixXML( resolvable, Dep::OBSOLETES);
212 str << helixXML( resolvable, Dep::REQUIRES);
213 str << helixXML( resolvable, Dep::RECOMMENDS);
214 str << helixXML( resolvable, Dep::ENHANCES);
215 str << helixXML( resolvable, Dep::SUPPLEMENTS);
216 str << helixXML( resolvable, Dep::SUGGESTS);
218 str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;
222 ///////////////////////////////////////////////////////////////////
224 // CLASS NAME : HelixResolvable
226 * Creates a file in helix format which includes all available
227 * or installed packages,patches,selections.....
229 class HelixResolvable : public base::ReferenceCounted, private base::NonCopyable{
232 std::string dumpFile; // Path of the generated testcase
236 HelixResolvable (const std::string & path);
239 void addResolvable (const PoolItem item)
240 { *file << helixXML (item); }
242 std::string filename ()
246 DEFINE_PTR_TYPE(HelixResolvable);
247 IMPL_PTR_TYPE(HelixResolvable);
249 typedef std::map<Repository, HelixResolvable_Ptr> RepositoryTable;
251 HelixResolvable::HelixResolvable(const std::string & path)
254 file = new ofgzstream(path.c_str());
256 ZYPP_THROW (Exception( "Can't open " + path ) );
259 *file << "<channel><subchannel>" << endl;
262 HelixResolvable::~HelixResolvable()
264 *file << "</subchannel></channel>" << endl;
268 ///////////////////////////////////////////////////////////////////
270 // CLASS NAME : HelixControl
272 * Creates a file in helix format which contains all controll
273 * action of a testcase ( file is known as *-test.xml)
278 std::string dumpFile; // Path of the generated testcase
282 HelixControl (const std::string & controlPath,
283 const RepositoryTable & sourceTable,
284 const Arch & systemArchitecture,
285 const target::Modalias::ModaliasList & modaliasList,
286 const std::set<std::string> & multiversionSpec,
287 const std::string & systemPath,
288 const bool forceResolve,
289 const bool onlyRequires,
290 const bool ignorealreadyrecommended);
294 void installResolvable (const ResObject::constPtr &resObject,
295 const ResStatus &status);
296 void lockResolvable (const ResObject::constPtr &resObject,
297 const ResStatus &status);
298 void keepResolvable (const ResObject::constPtr &resObject,
299 const ResStatus &status);
300 void deleteResolvable (const ResObject::constPtr &resObject,
301 const ResStatus &status);
302 void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict);
303 void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r );
306 void verifySystem ();
309 std::string filename () { return dumpFile; }
312 HelixControl::HelixControl(const std::string & controlPath,
313 const RepositoryTable & repoTable,
314 const Arch & systemArchitecture,
315 const target::Modalias::ModaliasList & modaliasList,
316 const std::set<std::string> & multiversionSpec,
317 const std::string & systemPath,
318 const bool forceResolve,
319 const bool onlyRequires,
320 const bool ignorealreadyrecommended)
321 :dumpFile (controlPath)
323 file = new ofstream(controlPath.c_str());
325 ZYPP_THROW (Exception( "Can't open " + controlPath ) );
328 *file << "<?xml version=\"1.0\"?>" << endl
329 << "<!-- testcase generated by YaST -->" << endl
331 << "<setup arch=\"" << systemArchitecture << "\">" << endl
332 << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl;
333 for ( RepositoryTable::const_iterator it = repoTable.begin();
334 it != repoTable.end(); ++it ) {
335 RepoInfo repo = it->first.info();
336 *file << TAB << "<!-- " << endl
337 << TAB << "- alias : " << repo.alias() << endl;
338 for ( RepoInfo::urls_const_iterator itUrl = repo.baseUrlsBegin();
339 itUrl != repo.baseUrlsEnd();
342 *file << TAB << "- url : " << *itUrl << endl;
344 *file << TAB << "- path : " << repo.path() << endl;
345 *file << TAB << "- type : " << repo.type() << endl;
346 *file << TAB << "- generated : " << (it->first.generatedTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
347 *file << TAB << "- outdated : " << (it->first.suggestedExpirationTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
348 *file << TAB << " -->" << endl;
350 *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id())
351 << "-package.xml.gz\" name=\"" << repo.alias() << "\""
352 << " priority=\"" << repo.priority()
353 << "\" />" << endl << endl;
356 // HACK: directly access sat::pool
357 const sat::Pool & satpool( sat::Pool::instance() );
360 const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
361 const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
362 const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
364 for ( Locale l : requestedLocales )
366 const char * fate = ( addedLocales.count(l) ? "\" fate=\"added" : "" );
367 *file << TAB << "<locale name=\"" << l << fate << "\" />" << endl;
369 for ( Locale l : removedLocales )
371 *file << TAB << "<locale name=\"" << l << "\" fate=\"removed\" />" << endl;
375 for ( IdString::IdType n : satpool.autoInstalled() )
377 *file << TAB << "<autoinst name=\"" << IdString(n) << "\" />" << endl;
382 for_( it, modaliasList.begin(), modaliasList.end() ) {
383 *file << TAB << "<modalias name=\"" << *it
387 for_( it, multiversionSpec.begin(), multiversionSpec.end() ) {
388 *file << TAB << "<multiversion name=\"" << *it
393 *file << TAB << "<forceResolve/>" << endl;
395 *file << TAB << "<onlyRequires/>" << endl;
396 if (ignorealreadyrecommended)
397 *file << TAB << "<ignorealreadyrecommended/>" << endl;
399 *file << "</setup>" << endl
400 << "<trial>" << endl;
403 HelixControl::HelixControl()
404 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
406 HelixControl (dumpFile);
409 HelixControl::~HelixControl()
411 *file << "</trial>" << endl
412 << "</test>" << endl;
416 void HelixControl::installResolvable(const ResObject::constPtr &resObject,
417 const ResStatus &status)
419 *file << "<install channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
420 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
421 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
422 << " status=\"" << status << "\""
426 void HelixControl::lockResolvable(const ResObject::constPtr &resObject,
427 const ResStatus &status)
429 *file << "<lock channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
430 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
431 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
432 << " status=\"" << status << "\""
436 void HelixControl::keepResolvable(const ResObject::constPtr &resObject,
437 const ResStatus &status)
439 *file << "<keep channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
440 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
441 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
442 << " status=\"" << status << "\""
446 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject,
447 const ResStatus &status)
449 *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
450 << " name=\"" << resObject->name() << "\""
451 << " status=\"" << status << "\""
455 void HelixControl::addDependencies (const CapabilitySet & capRequire, const CapabilitySet & capConflict)
457 for (CapabilitySet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) {
458 *file << "<addRequire " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
460 for (CapabilitySet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) {
461 *file << "<addConflict " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
465 void HelixControl::addUpgradeRepos( const std::set<Repository> & upgradeRepos_r )
467 for_( it, upgradeRepos_r.begin(), upgradeRepos_r.end() )
469 *file << "<upgradeRepo name=\"" << it->alias() << "\"/>" << endl;
473 void HelixControl::distupgrade()
475 *file << "<distupgrade/>" << endl;
478 void HelixControl::verifySystem()
480 *file << "<verify/>" << endl;
483 void HelixControl::update()
485 *file << "<update/>" << endl;
488 //---------------------------------------------------------------------------
491 :dumpPath("/var/log/YaST2/solverTestcase")
494 Testcase::Testcase(const std::string & path)
498 Testcase::~Testcase()
501 bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
503 PathInfo path (dumpPath);
505 if ( !path.isExist() ) {
506 if (zypp::filesystem::assert_dir (dumpPath)!=0) {
507 ERR << "Cannot create directory " << dumpPath << endl;
512 ERR << dumpPath << " is not a directory." << endl;
515 // remove old stuff if pool will be dump
517 zypp::filesystem::clean_dir (dumpPath);
521 zypp::base::LogControl::TmpLineWriter tempRedirect;
522 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
523 zypp::base::LogControl::TmpExcessive excessive;
525 resolver.resolvePool();
528 ResPool pool = resolver.pool();
529 RepositoryTable repoTable;
530 PoolItemList items_to_install;
531 PoolItemList items_to_remove;
532 PoolItemList items_locked;
533 PoolItemList items_keep;
534 HelixResolvable_Ptr system = NULL;
537 system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
539 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
541 Resolvable::constPtr res = it->resolvable();
543 if ( system && it->status().isInstalled() ) {
545 system->addResolvable (*it);
548 Repository repo = it->resolvable()->satSolvable().repository();
550 if (repoTable.find (repo) == repoTable.end()) {
551 repoTable[repo] = new HelixResolvable(dumpPath + "/"
552 + str::numstring((long)repo.id())
553 + "-package.xml.gz");
555 repoTable[repo]->addResolvable (*it);
559 if ( it->status().isToBeInstalled()
560 && !(it->status().isBySolver())) {
561 items_to_install.push_back (*it);
563 if ( it->status().isKept()
564 && !(it->status().isBySolver())) {
565 items_keep.push_back (*it);
567 if ( it->status().isToBeUninstalled()
568 && !(it->status().isBySolver())) {
569 items_to_remove.push_back (*it);
571 if ( it->status().isLocked()
572 && !(it->status().isBySolver())) {
573 items_locked.push_back (*it);
577 // writing control file "*-test.xml"
578 HelixControl control (dumpPath + "/solver-test.xml",
580 ZConfig::instance().systemArchitecture(),
581 target::Modalias::instance().modaliasList(),
582 ZConfig::instance().multiversionSpec(),
583 "solver-system.xml.gz",
584 resolver.forceResolve(),
585 resolver.onlyRequires(),
586 resolver.ignoreAlreadyRecommended() );
588 for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
589 control.installResolvable (iter->resolvable(), iter->status());
592 for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
593 control.lockResolvable (iter->resolvable(), iter->status());
596 for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
597 control.keepResolvable (iter->resolvable(), iter->status());
600 for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
601 control.deleteResolvable (iter->resolvable(), iter->status());
604 control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
605 control.addDependencies (SystemCheck::instance().requiredSystemCap(),
606 SystemCheck::instance().conflictSystemCap());
607 control.addUpgradeRepos( resolver.upgradeRepos() );
609 if (resolver.isUpgradeMode())
610 control.distupgrade ();
611 if (resolver.isUpdateMode())
613 if (resolver.isVerifyingMode())
614 control.verifySystem();
620 ///////////////////////////////////////////////////////////////////
621 };// namespace detail
622 /////////////////////////////////////////////////////////////////////
623 /////////////////////////////////////////////////////////////////////
624 };// namespace solver
625 ///////////////////////////////////////////////////////////////////////
626 ///////////////////////////////////////////////////////////////////////
628 /////////////////////////////////////////////////////////////////////////