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 PoolItem & obj, Dep deptag_r )
185 Capabilities caps( obj[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 )
194 str << "<" << item.kind() << ">" << endl;
195 str << TAB << xml_tag_enclose( item.name(), "name", true ) << endl;
196 str << TAB << xml_tag_enclose( item.vendor().asString(), "vendor", true ) << endl;
197 str << TAB << xml_tag_enclose( item.buildtime().asSeconds(), "buildtime", true ) << endl;
198 if ( isKind<Package>( item ) ) {
199 str << TAB << "<history>" << endl << TAB << "<update>" << endl;
200 str << TAB2 << helixXML( item.arch() ) << endl;
201 str << TAB2 << helixXML( item.edition() ) << endl;
202 str << TAB << "</update>" << endl << TAB << "</history>" << endl;
204 str << TAB << helixXML( item.arch() ) << endl;
205 str << TAB << helixXML( item.edition() ) << endl;
207 str << helixXML( item, Dep::PROVIDES );
208 str << helixXML( item, Dep::PREREQUIRES );
209 str << helixXML( item, Dep::CONFLICTS );
210 str << helixXML( item, Dep::OBSOLETES );
211 str << helixXML( item, Dep::REQUIRES );
212 str << helixXML( item, Dep::RECOMMENDS );
213 str << helixXML( item, Dep::ENHANCES );
214 str << helixXML( item, Dep::SUPPLEMENTS );
215 str << helixXML( item, Dep::SUGGESTS );
217 str << "</" << item.kind() << ">" << endl;
221 ///////////////////////////////////////////////////////////////////
223 // CLASS NAME : HelixResolvable
225 * Creates a file in helix format which includes all available
226 * or installed packages,patches,selections.....
228 class HelixResolvable : public base::ReferenceCounted, private base::NonCopyable{
231 std::string dumpFile; // Path of the generated testcase
235 HelixResolvable (const std::string & path);
238 void addResolvable (const PoolItem item)
239 { *file << helixXML (item); }
241 std::string filename ()
245 DEFINE_PTR_TYPE(HelixResolvable);
246 IMPL_PTR_TYPE(HelixResolvable);
248 typedef std::map<Repository, HelixResolvable_Ptr> RepositoryTable;
250 HelixResolvable::HelixResolvable(const std::string & path)
253 file = new ofgzstream(path.c_str());
255 ZYPP_THROW (Exception( "Can't open " + path ) );
258 *file << "<channel><subchannel>" << endl;
261 HelixResolvable::~HelixResolvable()
263 *file << "</subchannel></channel>" << endl;
267 ///////////////////////////////////////////////////////////////////
269 // CLASS NAME : HelixControl
271 * Creates a file in helix format which contains all controll
272 * action of a testcase ( file is known as *-test.xml)
277 std::string dumpFile; // Path of the generated testcase
281 HelixControl (const std::string & controlPath,
282 const RepositoryTable & sourceTable,
283 const Arch & systemArchitecture,
284 const target::Modalias::ModaliasList & modaliasList,
285 const std::set<std::string> & multiversionSpec,
286 const std::string & systemPath,
287 const bool forceResolve,
288 const bool onlyRequires,
289 const bool ignorealreadyrecommended);
293 void installResolvable( const PoolItem & pi_r );
294 void lockResolvable( const PoolItem & pi_r );
295 void keepResolvable( const PoolItem & pi_r );
296 void deleteResolvable( const PoolItem & pi_r );
297 void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict);
298 void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r );
301 void verifySystem ();
304 std::string filename () { return dumpFile; }
307 HelixControl::HelixControl(const std::string & controlPath,
308 const RepositoryTable & repoTable,
309 const Arch & systemArchitecture,
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 // HACK: directly access sat::pool
352 const sat::Pool & satpool( sat::Pool::instance() );
355 const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
356 const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
357 const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
359 for ( Locale l : requestedLocales )
361 const char * fate = ( addedLocales.count(l) ? "\" fate=\"added" : "" );
362 *file << TAB << "<locale name=\"" << l << fate << "\" />" << endl;
364 for ( Locale l : removedLocales )
366 *file << TAB << "<locale name=\"" << l << "\" fate=\"removed\" />" << endl;
370 for ( IdString::IdType n : satpool.autoInstalled() )
372 *file << TAB << "<autoinst name=\"" << IdString(n) << "\" />" << endl;
377 for_( it, modaliasList.begin(), modaliasList.end() ) {
378 *file << TAB << "<modalias name=\"" << *it
382 for_( it, multiversionSpec.begin(), multiversionSpec.end() ) {
383 *file << TAB << "<multiversion name=\"" << *it
388 *file << TAB << "<forceResolve/>" << endl;
390 *file << TAB << "<onlyRequires/>" << endl;
391 if (ignorealreadyrecommended)
392 *file << TAB << "<ignorealreadyrecommended/>" << endl;
394 *file << "</setup>" << endl
395 << "<trial>" << endl;
398 HelixControl::HelixControl()
399 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
401 HelixControl (dumpFile);
404 HelixControl::~HelixControl()
406 *file << "</trial>" << endl
407 << "</test>" << endl;
411 void HelixControl::installResolvable( const PoolItem & pi_r )
413 *file << "<install channel=\"" << pi_r.repoInfo().alias() << "\""
414 << " kind=\"" << pi_r.kind() << "\""
415 << " name=\"" << pi_r.name() << "\""
416 << " arch=\"" << pi_r.arch() << "\""
417 << " version=\"" << pi_r.edition().version() << "\""
418 << " release=\"" << pi_r.edition().release() << "\""
419 << " status=\"" << pi_r.status() << "\""
423 void HelixControl::lockResolvable( const PoolItem & pi_r )
425 *file << "<lock channel=\"" << pi_r.repoInfo().alias() << "\""
426 << " kind=\"" << pi_r.kind() << "\""
427 << " name=\"" << pi_r.name() << "\""
428 << " arch=\"" << pi_r.arch() << "\""
429 << " version=\"" << pi_r.edition().version() << "\""
430 << " release=\"" << pi_r.edition().release() << "\""
431 << " status=\"" << pi_r.status() << "\""
435 void HelixControl::keepResolvable( const PoolItem & pi_r )
437 *file << "<keep channel=\"" << pi_r.repoInfo().alias() << "\""
438 << " kind=\"" << pi_r.kind() << "\""
439 << " name=\"" << pi_r.name() << "\""
440 << " arch=\"" << pi_r.arch() << "\""
441 << " version=\"" << pi_r.edition().version() << "\""
442 << " release=\"" << pi_r.edition().release() << "\""
443 << " status=\"" << pi_r.status() << "\""
447 void HelixControl::deleteResolvable( const PoolItem & pi_r )
449 *file << "<uninstall kind=\"" << pi_r.kind() << "\""
450 << " name=\"" << pi_r.name() << "\""
451 << " status=\"" << pi_r.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 ( const PoolItem & pi : pool )
541 if ( system && pi.status().isInstalled() ) {
543 system->addResolvable( pi );
546 Repository repo = pi.repository();
548 if (repoTable.find (repo) == repoTable.end()) {
549 repoTable[repo] = new HelixResolvable(dumpPath + "/"
550 + str::numstring((long)repo.id())
551 + "-package.xml.gz");
553 repoTable[repo]->addResolvable( pi );
557 if ( pi.status().isToBeInstalled()
558 && !(pi.status().isBySolver())) {
559 items_to_install.push_back( pi );
561 if ( pi.status().isKept()
562 && !(pi.status().isBySolver())) {
563 items_keep.push_back( pi );
565 if ( pi.status().isToBeUninstalled()
566 && !(pi.status().isBySolver())) {
567 items_to_remove.push_back( pi );
569 if ( pi.status().isLocked()
570 && !(pi.status().isBySolver())) {
571 items_locked.push_back( pi );
575 // writing control file "*-test.xml"
576 HelixControl control (dumpPath + "/solver-test.xml",
578 ZConfig::instance().systemArchitecture(),
579 target::Modalias::instance().modaliasList(),
580 ZConfig::instance().multiversionSpec(),
581 "solver-system.xml.gz",
582 resolver.forceResolve(),
583 resolver.onlyRequires(),
584 resolver.ignoreAlreadyRecommended() );
586 for ( const PoolItem & pi : items_to_install )
587 { control.installResolvable( pi ); }
589 for ( const PoolItem & pi : items_locked )
590 { control.lockResolvable( pi ); }
592 for ( const PoolItem & pi : items_keep )
593 { control.keepResolvable( pi ); }
595 for ( const PoolItem & pi : items_to_remove )
596 { control.deleteResolvable( pi ); }
598 control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
599 control.addDependencies (SystemCheck::instance().requiredSystemCap(),
600 SystemCheck::instance().conflictSystemCap());
601 control.addUpgradeRepos( resolver.upgradeRepos() );
603 if (resolver.isUpgradeMode())
604 control.distupgrade ();
605 if (resolver.isUpdateMode())
607 if (resolver.isVerifyingMode())
608 control.verifySystem();
614 ///////////////////////////////////////////////////////////////////
615 };// namespace detail
616 /////////////////////////////////////////////////////////////////////
617 /////////////////////////////////////////////////////////////////////
618 };// namespace solver
619 ///////////////////////////////////////////////////////////////////////
620 ///////////////////////////////////////////////////////////////////////
622 /////////////////////////////////////////////////////////////////////////