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
279 HelixControl (const std::string & controlPath,
280 const RepositoryTable & sourceTable,
281 const Arch & systemArchitecture,
282 const LocaleSet &languages,
283 const target::Modalias::ModaliasList & modaliasList,
284 const std::set<std::string> & multiversionSpec,
285 const std::string & systemPath,
286 const bool forceResolve,
287 const bool onlyRequires,
288 const bool ignorealreadyrecommended);
292 void installResolvable (const ResObject::constPtr &resObject,
293 const ResStatus &status);
294 void lockResolvable (const ResObject::constPtr &resObject,
295 const ResStatus &status);
296 void keepResolvable (const ResObject::constPtr &resObject,
297 const ResStatus &status);
298 void deleteResolvable (const ResObject::constPtr &resObject,
299 const ResStatus &status);
300 void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict);
301 void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r );
304 void verifySystem ();
307 std::string filename () { return dumpFile; }
310 HelixControl::HelixControl(const std::string & controlPath,
311 const RepositoryTable & repoTable,
312 const Arch & systemArchitecture,
313 const LocaleSet &languages,
314 const target::Modalias::ModaliasList & modaliasList,
315 const std::set<std::string> & multiversionSpec,
316 const std::string & systemPath,
317 const bool forceResolve,
318 const bool onlyRequires,
319 const bool ignorealreadyrecommended)
320 :dumpFile (controlPath)
322 file = new ofstream(controlPath.c_str());
324 ZYPP_THROW (Exception( "Can't open " + controlPath ) );
327 *file << "<?xml version=\"1.0\"?>" << endl
328 << "<!-- testcase generated by YaST -->" << endl
330 << "<setup arch=\"" << systemArchitecture << "\">" << endl
331 << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl;
332 for ( RepositoryTable::const_iterator it = repoTable.begin();
333 it != repoTable.end(); ++it ) {
334 RepoInfo repo = it->first.info();
335 *file << TAB << "<!-- " << endl
336 << TAB << "- alias : " << repo.alias() << endl;
337 for ( RepoInfo::urls_const_iterator itUrl = repo.baseUrlsBegin();
338 itUrl != repo.baseUrlsEnd();
341 *file << TAB << "- url : " << *itUrl << endl;
343 *file << TAB << "- path : " << repo.path() << endl;
344 *file << TAB << "- type : " << repo.type() << endl;
345 *file << TAB << "- generated : " << (it->first.generatedTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
346 *file << TAB << "- outdated : " << (it->first.suggestedExpirationTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
347 *file << TAB << " -->" << endl;
349 *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id())
350 << "-package.xml.gz\" name=\"" << repo.alias() << "\""
351 << " priority=\"" << repo.priority()
352 << "\" />" << endl << endl;
355 for (LocaleSet::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
356 *file << TAB << "<locale name=\"" << iter->code()
360 for_( it, modaliasList.begin(), modaliasList.end() ) {
361 *file << TAB << "<modalias name=\"" << *it
365 for_( it, multiversionSpec.begin(), multiversionSpec.end() ) {
366 *file << TAB << "<multiversion name=\"" << *it
371 *file << TAB << "<forceResolve/>" << endl;
373 *file << TAB << "<onlyRequires/>" << endl;
374 if (ignorealreadyrecommended)
375 *file << TAB << "<ignorealreadyrecommended/>" << endl;
377 *file << "</setup>" << endl
378 << "<trial>" << endl;
381 HelixControl::HelixControl()
382 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
384 HelixControl (dumpFile);
387 HelixControl::~HelixControl()
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 void HelixControl::distupgrade()
453 *file << "<distupgrade/>" << endl;
456 void HelixControl::verifySystem()
458 *file << "<verify/>" << endl;
461 void HelixControl::update()
463 *file << "<update/>" << endl;
466 //---------------------------------------------------------------------------
469 :dumpPath("/var/log/YaST2/solverTestcase")
472 Testcase::Testcase(const std::string & path)
476 Testcase::~Testcase()
479 bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
481 PathInfo path (dumpPath);
483 if ( !path.isExist() ) {
484 if (zypp::filesystem::assert_dir (dumpPath)!=0) {
485 ERR << "Cannot create directory " << dumpPath << endl;
490 ERR << dumpPath << " is not a directory." << endl;
493 // remove old stuff if pool will be dump
495 zypp::filesystem::clean_dir (dumpPath);
499 zypp::base::LogControl::TmpLineWriter tempRedirect;
500 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
501 zypp::base::LogControl::TmpExcessive excessive;
503 resolver.resolvePool();
506 ResPool pool = resolver.pool();
507 RepositoryTable repoTable;
508 PoolItemList items_to_install;
509 PoolItemList items_to_remove;
510 PoolItemList items_locked;
511 PoolItemList items_keep;
512 HelixResolvable_Ptr system = NULL;
515 system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
517 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
519 Resolvable::constPtr res = it->resolvable();
521 if ( system && it->status().isInstalled() ) {
523 system->addResolvable (*it);
526 Repository repo = it->resolvable()->satSolvable().repository();
528 if (repoTable.find (repo) == repoTable.end()) {
529 repoTable[repo] = new HelixResolvable(dumpPath + "/"
530 + str::numstring((long)repo.id())
531 + "-package.xml.gz");
533 repoTable[repo]->addResolvable (*it);
537 if ( it->status().isToBeInstalled()
538 && !(it->status().isBySolver())) {
539 items_to_install.push_back (*it);
541 if ( it->status().isKept()
542 && !(it->status().isBySolver())) {
543 items_keep.push_back (*it);
545 if ( it->status().isToBeUninstalled()
546 && !(it->status().isBySolver())) {
547 items_to_remove.push_back (*it);
549 if ( it->status().isLocked()
550 && !(it->status().isBySolver())) {
551 items_locked.push_back (*it);
555 // writing control file "*-test.xml"
556 HelixControl control (dumpPath + "/solver-test.xml",
558 ZConfig::instance().systemArchitecture(),
559 pool.getRequestedLocales(),
560 target::Modalias::instance().modaliasList(),
561 ZConfig::instance().multiversionSpec(),
562 "solver-system.xml.gz",
563 resolver.forceResolve(),
564 resolver.onlyRequires(),
565 resolver.ignoreAlreadyRecommended() );
567 for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
568 control.installResolvable (iter->resolvable(), iter->status());
571 for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
572 control.lockResolvable (iter->resolvable(), iter->status());
575 for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
576 control.keepResolvable (iter->resolvable(), iter->status());
579 for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
580 control.deleteResolvable (iter->resolvable(), iter->status());
583 control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
584 control.addDependencies (SystemCheck::instance().requiredSystemCap(),
585 SystemCheck::instance().conflictSystemCap());
586 control.addUpgradeRepos( resolver.upgradeRepos() );
588 if (resolver.isUpgradeMode())
589 control.distupgrade ();
590 if (resolver.isUpdateMode())
592 if (resolver.isVerifyingMode())
593 control.verifySystem();
599 ///////////////////////////////////////////////////////////////////
600 };// namespace detail
601 /////////////////////////////////////////////////////////////////////
602 /////////////////////////////////////////////////////////////////////
603 };// namespace solver
604 ///////////////////////////////////////////////////////////////////////
605 ///////////////////////////////////////////////////////////////////////
607 /////////////////////////////////////////////////////////////////////////