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;
125 IdString packageName;
126 if (detail.capRel() == CapDetail::CAP_AND) {
127 packageName = IdString(detail.lhs().id());
128 detail = detail.rhs().detail();
130 if (detail.capRel() == CapDetail::CAP_NAMESPACE
131 && detail.lhs().id() == NAMESPACE_MODALIAS) {
132 str << "<dep name='modalias(";
133 if (!packageName.empty())
134 str << packageName << ":";
135 str << IdString(detail.rhs().id()) << ")' />" << endl;
137 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
141 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << 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));
175 inline string helixXML( const Resolvable::constPtr &obj, Dep deptag_r )
178 Capabilities caps( obj->dep(deptag_r) );
179 if ( ! caps.empty() )
180 out << TAB << xml_tag_enclose(helixXML(caps), deptag_r.asString()) << endl;
184 std::string helixXML( const PoolItem &item )
186 const Resolvable::constPtr resolvable = item.resolvable();
188 str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
189 str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
190 str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl;
191 str << TAB << xml_tag_enclose (item->buildtime().asSeconds(), "buildtime", true) << endl;
192 if ( isKind<Package>(resolvable) ) {
193 str << TAB << "<history>" << endl << TAB << "<update>" << endl;
194 str << TAB2 << helixXML (resolvable->arch()) << endl;
195 str << TAB2 << helixXML (resolvable->edition()) << endl;
196 str << TAB << "</update>" << endl << TAB << "</history>" << endl;
198 str << TAB << helixXML (resolvable->arch()) << endl;
199 str << TAB << helixXML (resolvable->edition()) << endl;
201 str << helixXML( resolvable, Dep::PROVIDES);
202 str << helixXML( resolvable, Dep::PREREQUIRES);
203 str << helixXML( resolvable, Dep::CONFLICTS);
204 str << helixXML( resolvable, Dep::OBSOLETES);
205 str << helixXML( resolvable, Dep::REQUIRES);
206 str << helixXML( resolvable, Dep::RECOMMENDS);
207 str << helixXML( resolvable, Dep::ENHANCES);
208 str << helixXML( resolvable, Dep::SUPPLEMENTS);
209 str << helixXML( resolvable, Dep::SUGGESTS);
211 str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;
215 ///////////////////////////////////////////////////////////////////
217 // CLASS NAME : HelixResolvable
219 * Creates a file in helix format which includes all available
220 * or installed packages,patches,selections.....
222 class HelixResolvable : public base::ReferenceCounted, private base::NonCopyable{
225 std::string dumpFile; // Path of the generated testcase
229 HelixResolvable (const std::string & path);
232 void addResolvable (const PoolItem item)
233 { *file << helixXML (item); }
235 std::string filename ()
239 DEFINE_PTR_TYPE(HelixResolvable);
240 IMPL_PTR_TYPE(HelixResolvable);
242 typedef std::map<Repository, HelixResolvable_Ptr> RepositoryTable;
244 HelixResolvable::HelixResolvable(const std::string & path)
247 file = new ofgzstream(path.c_str());
249 ZYPP_THROW (Exception( "Can't open " + path ) );
252 *file << "<channel><subchannel>" << endl;
255 HelixResolvable::~HelixResolvable()
257 *file << "</subchannel></channel>" << endl;
261 ///////////////////////////////////////////////////////////////////
263 // CLASS NAME : HelixControl
265 * Creates a file in helix format which contains all controll
266 * action of a testcase ( file is known as *-test.xml)
271 std::string dumpFile; // Path of the generated testcase
275 HelixControl (const std::string & controlPath,
276 const RepositoryTable & sourceTable,
277 const Arch & systemArchitecture,
278 const LocaleSet &languages,
279 const target::Modalias::ModaliasList & modaliasList,
280 const std::set<std::string> & multiversionSpec,
281 const std::string & systemPath,
282 const bool forceResolve,
283 const bool onlyRequires,
284 const bool ignorealreadyrecommended);
288 void installResolvable (const ResObject::constPtr &resObject,
289 const ResStatus &status);
290 void lockResolvable (const ResObject::constPtr &resObject,
291 const ResStatus &status);
292 void keepResolvable (const ResObject::constPtr &resObject,
293 const ResStatus &status);
294 void deleteResolvable (const ResObject::constPtr &resObject,
295 const ResStatus &status);
296 void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict);
297 void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r );
300 void verifySystem ();
303 std::string filename () { return dumpFile; }
306 HelixControl::HelixControl(const std::string & controlPath,
307 const RepositoryTable & repoTable,
308 const Arch & systemArchitecture,
309 const LocaleSet &languages,
310 const target::Modalias::ModaliasList & modaliasList,
311 const std::set<std::string> & multiversionSpec,
312 const std::string & systemPath,
313 const bool forceResolve,
314 const bool onlyRequires,
315 const bool ignorealreadyrecommended)
316 :dumpFile (controlPath)
318 file = new ofstream(controlPath.c_str());
320 ZYPP_THROW (Exception( "Can't open " + controlPath ) );
323 *file << "<?xml version=\"1.0\"?>" << endl
324 << "<!-- testcase generated by YaST -->" << endl
326 << "<setup arch=\"" << systemArchitecture << "\">" << endl
327 << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl;
328 for ( RepositoryTable::const_iterator it = repoTable.begin();
329 it != repoTable.end(); ++it ) {
330 RepoInfo repo = it->first.info();
331 *file << TAB << "<!-- " << endl
332 << TAB << "- alias : " << repo.alias() << endl;
333 for ( RepoInfo::urls_const_iterator itUrl = repo.baseUrlsBegin();
334 itUrl != repo.baseUrlsEnd();
337 *file << TAB << "- url : " << *itUrl << endl;
339 *file << TAB << "- path : " << repo.path() << endl;
340 *file << TAB << "- type : " << repo.type() << endl;
341 *file << TAB << "- generated : " << (it->first.generatedTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
342 *file << TAB << "- outdated : " << (it->first.suggestedExpirationTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
343 *file << TAB << " -->" << endl;
345 *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id())
346 << "-package.xml.gz\" name=\"" << repo.alias() << "\""
347 << " priority=\"" << repo.priority()
348 << "\" />" << endl << endl;
351 for (LocaleSet::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
352 *file << TAB << "<locale name=\"" << iter->code()
356 for_( it, modaliasList.begin(), modaliasList.end() ) {
357 *file << TAB << "<modalias name=\"" << *it
361 for_( it, multiversionSpec.begin(), multiversionSpec.end() ) {
362 *file << TAB << "<multiversion name=\"" << *it
367 *file << TAB << "<forceResolve/>" << endl;
369 *file << TAB << "<onlyRequires/>" << endl;
370 if (ignorealreadyrecommended)
371 *file << TAB << "<ignorealreadyrecommended/>" << endl;
373 *file << "</setup>" << endl
374 << "<trial>" << endl;
377 HelixControl::HelixControl()
378 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
380 HelixControl (dumpFile);
383 HelixControl::~HelixControl()
385 *file << "</trial>" << endl
386 << "</test>" << endl;
390 void HelixControl::installResolvable(const ResObject::constPtr &resObject,
391 const ResStatus &status)
393 *file << "<install channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
394 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
395 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
396 << " status=\"" << status << "\""
400 void HelixControl::lockResolvable(const ResObject::constPtr &resObject,
401 const ResStatus &status)
403 *file << "<lock channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
404 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
405 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
406 << " status=\"" << status << "\""
410 void HelixControl::keepResolvable(const ResObject::constPtr &resObject,
411 const ResStatus &status)
413 *file << "<keep channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
414 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
415 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
416 << " status=\"" << status << "\""
420 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject,
421 const ResStatus &status)
423 *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
424 << " name=\"" << resObject->name() << "\""
425 << " status=\"" << status << "\""
429 void HelixControl::addDependencies (const CapabilitySet & capRequire, const CapabilitySet & capConflict)
431 for (CapabilitySet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) {
432 *file << "<addRequire " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
434 for (CapabilitySet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) {
435 *file << "<addConflict " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
439 void HelixControl::addUpgradeRepos( const std::set<Repository> & upgradeRepos_r )
441 for_( it, upgradeRepos_r.begin(), upgradeRepos_r.end() )
443 *file << "<upgradeRepo name=\"" << it->alias() << "\"/>" << endl;
447 void HelixControl::distupgrade()
449 *file << "<distupgrade/>" << endl;
452 void HelixControl::verifySystem()
454 *file << "<verify/>" << endl;
457 void HelixControl::update()
459 *file << "<update/>" << endl;
462 //---------------------------------------------------------------------------
465 :dumpPath("/var/log/YaST2/solverTestcase")
468 Testcase::Testcase(const std::string & path)
472 Testcase::~Testcase()
475 bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
477 PathInfo path (dumpPath);
479 if ( !path.isExist() ) {
480 if (zypp::filesystem::assert_dir (dumpPath)!=0) {
481 ERR << "Cannot create directory " << dumpPath << endl;
486 ERR << dumpPath << " is not a directory." << endl;
489 // remove old stuff if pool will be dump
491 zypp::filesystem::clean_dir (dumpPath);
495 zypp::base::LogControl::TmpLineWriter tempRedirect;
496 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
497 zypp::base::LogControl::TmpExcessive excessive;
499 resolver.resolvePool();
502 ResPool pool = resolver.pool();
503 RepositoryTable repoTable;
504 PoolItemList items_to_install;
505 PoolItemList items_to_remove;
506 PoolItemList items_locked;
507 PoolItemList items_keep;
508 HelixResolvable_Ptr system = NULL;
511 system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
513 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
515 Resolvable::constPtr res = it->resolvable();
517 if ( system && it->status().isInstalled() ) {
519 system->addResolvable (*it);
522 Repository repo = it->resolvable()->satSolvable().repository();
524 if (repoTable.find (repo) == repoTable.end()) {
525 repoTable[repo] = new HelixResolvable(dumpPath + "/"
526 + str::numstring((long)repo.id())
527 + "-package.xml.gz");
529 repoTable[repo]->addResolvable (*it);
533 if ( it->status().isToBeInstalled()
534 && !(it->status().isBySolver())) {
535 items_to_install.push_back (*it);
537 if ( it->status().isKept()
538 && !(it->status().isBySolver())) {
539 items_keep.push_back (*it);
541 if ( it->status().isToBeUninstalled()
542 && !(it->status().isBySolver())) {
543 items_to_remove.push_back (*it);
545 if ( it->status().isLocked()
546 && !(it->status().isBySolver())) {
547 items_locked.push_back (*it);
551 // writing control file "*-test.xml"
552 HelixControl control (dumpPath + "/solver-test.xml",
554 ZConfig::instance().systemArchitecture(),
555 pool.getRequestedLocales(),
556 target::Modalias::instance().modaliasList(),
557 ZConfig::instance().multiversionSpec(),
558 "solver-system.xml.gz",
559 resolver.forceResolve(),
560 resolver.onlyRequires(),
561 resolver.ignoreAlreadyRecommended() );
563 for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
564 control.installResolvable (iter->resolvable(), iter->status());
567 for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
568 control.lockResolvable (iter->resolvable(), iter->status());
571 for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
572 control.keepResolvable (iter->resolvable(), iter->status());
575 for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
576 control.deleteResolvable (iter->resolvable(), iter->status());
579 control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
580 control.addDependencies (SystemCheck::instance().requiredSystemCap(),
581 SystemCheck::instance().conflictSystemCap());
582 control.addUpgradeRepos( resolver.upgradeRepos() );
584 if (resolver.isUpgradeMode())
585 control.distupgrade ();
586 if (resolver.isUpdateMode())
588 if (resolver.isVerifyingMode())
589 control.verifySystem();
595 ///////////////////////////////////////////////////////////////////
596 };// namespace detail
597 /////////////////////////////////////////////////////////////////////
598 /////////////////////////////////////////////////////////////////////
599 };// namespace solver
600 ///////////////////////////////////////////////////////////////////////
601 ///////////////////////////////////////////////////////////////////////
603 /////////////////////////////////////////////////////////////////////////