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/base/GzStream.h"
21 #include "zypp/base/String.h"
22 #include "zypp/base/PtrTypes.h"
23 #include "zypp/base/NonCopyable.h"
24 #include "zypp/base/ReferenceCounted.h"
26 #include "zypp/parser/xml/XmlEscape.h"
28 #include "zypp/ZConfig.h"
29 #include "zypp/PathInfo.h"
30 #include "zypp/ResPool.h"
31 #include "zypp/Repository.h"
32 #include "zypp/target/modalias/Modalias.h"
34 #include "zypp/sat/detail/PoolImpl.h"
35 #include "zypp/solver/detail/SystemCheck.h"
37 /////////////////////////////////////////////////////////////////////////
39 { ///////////////////////////////////////////////////////////////////////
40 ///////////////////////////////////////////////////////////////////////
42 { /////////////////////////////////////////////////////////////////////
43 /////////////////////////////////////////////////////////////////////
45 { ///////////////////////////////////////////////////////////////////
51 using namespace zypp::str;
53 //---------------------------------------------------------------------------
55 inline std::string xml_escape( const std::string &text )
57 return zypp::xml::escape(text);
60 inline std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
63 result += "<" + tag + ">";
66 result += xml_escape(text);
70 result += "</" + tag + ">";
75 std::string helixXML( const T &obj ); //undefined
78 std::string helixXML( const Edition &edition )
81 str << xml_tag_enclose(edition.version(), "version");
82 if (!edition.release().empty())
83 str << xml_tag_enclose(edition.release(), "release");
84 if (edition.epoch() != Edition::noepoch)
85 str << xml_tag_enclose(numstring(edition.epoch()), "epoch");
90 std::string helixXML( const Arch &arch )
93 str << xml_tag_enclose(arch.asString(), "arch");
98 std::string helixXML( const Capability &cap )
101 CapDetail detail = cap.detail();
102 if (detail.isSimple()) {
103 if (detail.isVersioned()) {
104 str << "<dep name='" << xml_escape(detail.name().asString()) << "'"
105 << " op='" << xml_escape(detail.op().asString()) << "'"
106 << " version='" << xml_escape(detail.ed().version()) << "'";
107 if (!detail.ed().release().empty())
108 str << " release='" << xml_escape(detail.ed().release()) << "'";
109 if (detail.ed().epoch() != Edition::noepoch)
110 str << " epoch='" << xml_escape(numstring(detail.ed().epoch())) << "'";
111 str << " />" << endl;
113 str << "<dep name='" << xml_escape(cap.asString()) << "' />" << endl;
115 } else if (detail.isExpression()) {
116 if (detail.capRel() == CapDetail::CAP_AND
117 && detail.lhs().detail().isNamed()
118 && detail.rhs().detail().isNamed()) {
119 // packageand dependency
120 str << "<dep name='packageand("
121 << IdString(detail.lhs().id()) << ":"
122 << IdString(detail.rhs().id()) << ")' />" << endl;
123 } else if (detail.capRel() == CapDetail::CAP_NAMESPACE
124 && detail.lhs().id() == NAMESPACE_OTHERPROVIDERS) {
125 str << "<dep name='otherproviders("
126 << IdString(detail.rhs().id()) << ")' />" << endl;
129 IdString packageName;
130 if (detail.capRel() == CapDetail::CAP_AND) {
131 packageName = IdString(detail.lhs().id());
132 detail = detail.rhs().detail();
134 if (detail.capRel() == CapDetail::CAP_NAMESPACE
135 && detail.lhs().id() == NAMESPACE_MODALIAS) {
136 str << "<dep name='modalias(";
137 if (!packageName.empty())
138 str << packageName << ":";
139 str << IdString(detail.rhs().id()) << ")' />" << endl;
141 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
145 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
152 std::string helixXML( const Capabilities &caps )
155 Capabilities::const_iterator it = caps.begin();
157 for ( ; it != caps.end(); ++it)
159 str << TAB2 << helixXML((*it));
166 std::string helixXML( const CapabilitySet &caps )
169 CapabilitySet::const_iterator it = caps.begin();
171 for ( ; it != caps.end(); ++it)
173 str << TAB2 << helixXML((*it));
179 inline string helixXML( const Resolvable::constPtr &obj, Dep deptag_r )
182 Capabilities caps( obj->dep(deptag_r) );
183 if ( ! caps.empty() )
184 out << TAB << xml_tag_enclose(helixXML(caps), deptag_r.asString()) << endl;
188 std::string helixXML( const PoolItem &item )
190 const Resolvable::constPtr resolvable = item.resolvable();
192 str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
193 str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
194 str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl;
195 str << TAB << xml_tag_enclose (item->buildtime().asSeconds(), "buildtime", true) << endl;
196 if ( isKind<Package>(resolvable) ) {
197 str << TAB << "<history>" << endl << TAB << "<update>" << endl;
198 str << TAB2 << helixXML (resolvable->arch()) << endl;
199 str << TAB2 << helixXML (resolvable->edition()) << endl;
200 str << TAB << "</update>" << endl << TAB << "</history>" << endl;
202 str << TAB << helixXML (resolvable->arch()) << endl;
203 str << TAB << helixXML (resolvable->edition()) << endl;
205 str << helixXML( resolvable, Dep::PROVIDES);
206 str << helixXML( resolvable, Dep::PREREQUIRES);
207 str << helixXML( resolvable, Dep::CONFLICTS);
208 str << helixXML( resolvable, Dep::OBSOLETES);
209 str << helixXML( resolvable, Dep::REQUIRES);
210 str << helixXML( resolvable, Dep::RECOMMENDS);
211 str << helixXML( resolvable, Dep::ENHANCES);
212 str << helixXML( resolvable, Dep::SUPPLEMENTS);
213 str << helixXML( resolvable, Dep::SUGGESTS);
215 str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;
219 ///////////////////////////////////////////////////////////////////
221 // CLASS NAME : HelixResolvable
223 * Creates a file in helix format which includes all available
224 * or installed packages,patches,selections.....
226 class HelixResolvable : public base::ReferenceCounted, private base::NonCopyable{
229 std::string dumpFile; // Path of the generated testcase
233 HelixResolvable (const std::string & path);
236 void addResolvable (const PoolItem item)
237 { *file << helixXML (item); }
239 std::string filename ()
243 DEFINE_PTR_TYPE(HelixResolvable);
244 IMPL_PTR_TYPE(HelixResolvable);
246 typedef std::map<Repository, HelixResolvable_Ptr> RepositoryTable;
248 HelixResolvable::HelixResolvable(const std::string & path)
251 file = new ofgzstream(path.c_str());
253 ZYPP_THROW (Exception( "Can't open " + path ) );
256 *file << "<channel><subchannel>" << endl;
259 HelixResolvable::~HelixResolvable()
261 *file << "</subchannel></channel>" << endl;
265 ///////////////////////////////////////////////////////////////////
267 // CLASS NAME : HelixControl
269 * Creates a file in helix format which contains all controll
270 * action of a testcase ( file is known as *-test.xml)
275 std::string dumpFile; // Path of the generated testcase
280 HelixControl (const std::string & controlPath,
281 const RepositoryTable & sourceTable,
282 const Arch & systemArchitecture,
283 const LocaleSet &languages,
284 const target::Modalias::ModaliasList & modaliasList,
285 const std::set<std::string> & multiversionSpec,
286 const std::string & systemPath);
294 *file << "</setup>" << endl << "<trial>" << endl;
299 void addTagIf( const std::string & tag_r, bool yesno_r = true )
302 *file << (_inSetup ? TAB : "") << "<" << tag_r << "/>" << endl;
305 void installResolvable (const ResObject::constPtr &resObject,
306 const ResStatus &status);
307 void lockResolvable (const ResObject::constPtr &resObject,
308 const ResStatus &status);
309 void keepResolvable (const ResObject::constPtr &resObject,
310 const ResStatus &status);
311 void deleteResolvable (const ResObject::constPtr &resObject,
312 const ResStatus &status);
313 void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict);
314 void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r );
316 std::string filename () { return dumpFile; }
319 HelixControl::HelixControl(const std::string & controlPath,
320 const RepositoryTable & repoTable,
321 const Arch & systemArchitecture,
322 const LocaleSet &languages,
323 const target::Modalias::ModaliasList & modaliasList,
324 const std::set<std::string> & multiversionSpec,
325 const std::string & systemPath)
326 :dumpFile (controlPath)
329 file = new ofstream(controlPath.c_str());
331 ZYPP_THROW (Exception( "Can't open " + controlPath ) );
334 *file << "<?xml version=\"1.0\"?>" << endl
335 << "<!-- testcase generated by YaST -->" << endl
337 << "<setup arch=\"" << systemArchitecture << "\">" << endl
338 << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl;
339 for ( RepositoryTable::const_iterator it = repoTable.begin();
340 it != repoTable.end(); ++it ) {
341 RepoInfo repo = it->first.info();
342 *file << TAB << "<!-- " << endl
343 << TAB << "- alias : " << repo.alias() << endl;
344 for ( RepoInfo::urls_const_iterator itUrl = repo.baseUrlsBegin();
345 itUrl != repo.baseUrlsEnd();
348 *file << TAB << "- url : " << *itUrl << endl;
350 *file << TAB << "- path : " << repo.path() << endl;
351 *file << TAB << "- type : " << repo.type() << endl;
352 *file << TAB << "- generated : " << (it->first.generatedTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
353 *file << TAB << "- outdated : " << (it->first.suggestedExpirationTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
354 *file << TAB << " -->" << endl;
356 *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id())
357 << "-package.xml.gz\" name=\"" << repo.alias() << "\""
358 << " priority=\"" << repo.priority()
359 << "\" />" << endl << endl;
362 for (LocaleSet::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
363 *file << TAB << "<locale name=\"" << iter->code()
367 for_( it, modaliasList.begin(), modaliasList.end() ) {
368 *file << TAB << "<modalias name=\"" << xml_escape(*it)
372 for_( it, multiversionSpec.begin(), multiversionSpec.end() ) {
373 *file << TAB << "<multiversion name=\"" << *it
377 // setup continued outside....
380 HelixControl::HelixControl()
381 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
383 HelixControl (dumpFile);
386 HelixControl::~HelixControl()
388 closeSetup(); // in case it is still open
389 *file << "</trial>" << endl
390 << "</test>" << endl;
394 void HelixControl::installResolvable(const ResObject::constPtr &resObject,
395 const ResStatus &status)
397 *file << "<install channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
398 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
399 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
400 << " status=\"" << status << "\""
404 void HelixControl::lockResolvable(const ResObject::constPtr &resObject,
405 const ResStatus &status)
407 *file << "<lock channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
408 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
409 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
410 << " status=\"" << status << "\""
414 void HelixControl::keepResolvable(const ResObject::constPtr &resObject,
415 const ResStatus &status)
417 *file << "<keep channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
418 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
419 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
420 << " status=\"" << status << "\""
424 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject,
425 const ResStatus &status)
427 *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
428 << " name=\"" << resObject->name() << "\""
429 << " status=\"" << status << "\""
433 void HelixControl::addDependencies (const CapabilitySet & capRequire, const CapabilitySet & capConflict)
435 for (CapabilitySet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) {
436 *file << "<addRequire " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
438 for (CapabilitySet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) {
439 *file << "<addConflict " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
443 void HelixControl::addUpgradeRepos( const std::set<Repository> & upgradeRepos_r )
445 for_( it, upgradeRepos_r.begin(), upgradeRepos_r.end() )
447 *file << "<upgradeRepo name=\"" << it->alias() << "\"/>" << endl;
451 //---------------------------------------------------------------------------
454 :dumpPath("/var/log/YaST2/solverTestcase")
457 Testcase::Testcase(const std::string & path)
461 Testcase::~Testcase()
464 bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
466 PathInfo path (dumpPath);
468 if ( !path.isExist() ) {
469 if (zypp::filesystem::assert_dir (dumpPath)!=0) {
470 ERR << "Cannot create directory " << dumpPath << endl;
475 ERR << dumpPath << " is not a directory." << endl;
478 // remove old stuff if pool will be dump
480 zypp::filesystem::clean_dir (dumpPath);
484 zypp::base::LogControl::TmpLineWriter tempRedirect;
485 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
486 zypp::base::LogControl::TmpExcessive excessive;
488 resolver.resolvePool();
491 ResPool pool = resolver.pool();
492 RepositoryTable repoTable;
493 PoolItemList items_to_install;
494 PoolItemList items_to_remove;
495 PoolItemList items_locked;
496 PoolItemList items_keep;
497 HelixResolvable_Ptr system = NULL;
500 system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
502 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
504 Resolvable::constPtr res = it->resolvable();
506 if ( system && it->status().isInstalled() ) {
508 system->addResolvable (*it);
511 Repository repo = it->resolvable()->satSolvable().repository();
513 if (repoTable.find (repo) == repoTable.end()) {
514 repoTable[repo] = new HelixResolvable(dumpPath + "/"
515 + str::numstring((long)repo.id())
516 + "-package.xml.gz");
518 repoTable[repo]->addResolvable (*it);
522 if ( it->status().isToBeInstalled()
523 && !(it->status().isBySolver())) {
524 items_to_install.push_back (*it);
526 if ( it->status().isKept()
527 && !(it->status().isBySolver())) {
528 items_keep.push_back (*it);
530 if ( it->status().isToBeUninstalled()
531 && !(it->status().isBySolver())) {
532 items_to_remove.push_back (*it);
534 if ( it->status().isLocked()
535 && !(it->status().isBySolver())) {
536 items_locked.push_back (*it);
540 // writing control file "*-test.xml"
541 HelixControl control (dumpPath + "/solver-test.xml",
543 ZConfig::instance().systemArchitecture(),
544 pool.getRequestedLocales(),
545 target::Modalias::instance().modaliasList(),
546 ZConfig::instance().multiversionSpec(),
547 "solver-system.xml.gz");
549 // In <setup>: resolver flags,...
550 control.addTagIf( "ignorealreadyrecommended", resolver.ignoreAlreadyRecommended() );
551 control.addTagIf( "onlyRequires", resolver.onlyRequires() );
552 control.addTagIf( "forceResolve", resolver.forceResolve() );
554 control.addTagIf( "cleandepsOnRemove", resolver.cleandepsOnRemove() );
556 control.addTagIf( "allowVendorChange", resolver.allowVendorChange() );
558 control.addTagIf( "dupAllowDowngrade", resolver.dupAllowDowngrade() );
559 control.addTagIf( "dupAllowNameChange", resolver.dupAllowNameChange() );
560 control.addTagIf( "dupAllowArchChange", resolver.dupAllowArchChange() );
561 control.addTagIf( "dupAllowVendorChange", resolver.dupAllowVendorChange() );
563 control.closeSetup();
564 // Entering <trial>...
566 for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
567 control.installResolvable (iter->resolvable(), iter->status());
570 for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
571 control.lockResolvable (iter->resolvable(), iter->status());
574 for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
575 control.keepResolvable (iter->resolvable(), iter->status());
578 for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
579 control.deleteResolvable (iter->resolvable(), iter->status());
582 control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
583 control.addDependencies (SystemCheck::instance().requiredSystemCap(),
584 SystemCheck::instance().conflictSystemCap());
585 control.addUpgradeRepos( resolver.upgradeRepos() );
587 control.addTagIf( "distupgrade", resolver.isUpgradeMode() );
588 control.addTagIf( "update", resolver.isUpdateMode() );
589 control.addTagIf( "verify", resolver.isVerifyingMode() );
595 ///////////////////////////////////////////////////////////////////
596 };// namespace detail
597 /////////////////////////////////////////////////////////////////////
598 /////////////////////////////////////////////////////////////////////
599 };// namespace solver
600 ///////////////////////////////////////////////////////////////////////
601 ///////////////////////////////////////////////////////////////////////
603 /////////////////////////////////////////////////////////////////////////