libzypp 9.41.1
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00012 #include <iostream> 00013 #include <fstream> 00014 #include <sstream> 00015 #include <streambuf> 00016 00017 #include "zypp/solver/detail/Testcase.h" 00018 #include "zypp/base/Logger.h" 00019 #include "zypp/base/LogControl.h" 00020 #include "zypp/base/GzStream.h" 00021 #include "zypp/base/String.h" 00022 #include "zypp/base/PtrTypes.h" 00023 #include "zypp/base/NonCopyable.h" 00024 #include "zypp/base/ReferenceCounted.h" 00025 00026 #include "zypp/parser/xml/XmlEscape.h" 00027 00028 #include "zypp/ZConfig.h" 00029 #include "zypp/PathInfo.h" 00030 #include "zypp/ResPool.h" 00031 #include "zypp/Repository.h" 00032 #include "zypp/target/modalias/Modalias.h" 00033 00034 #include "zypp/sat/detail/PoolImpl.h" 00035 #include "zypp/solver/detail/SystemCheck.h" 00036 00038 namespace zypp 00039 { 00040 00041 namespace solver 00042 { 00043 00044 namespace detail 00045 { 00046 00047 #define TAB "\t" 00048 #define TAB2 "\t\t" 00049 00050 using namespace std; 00051 using namespace zypp::str; 00052 00053 //--------------------------------------------------------------------------- 00054 00055 inline std::string xml_escape( const std::string &text ) 00056 { 00057 return zypp::xml::escape(text); 00058 } 00059 00060 inline std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false ) 00061 { 00062 string result; 00063 result += "<" + tag + ">"; 00064 00065 if ( escape) 00066 result += xml_escape(text); 00067 else 00068 result += text; 00069 00070 result += "</" + tag + ">"; 00071 return result; 00072 } 00073 00074 template<class T> 00075 std::string helixXML( const T &obj ); //undefined 00076 00077 template<> 00078 std::string helixXML( const Edition &edition ) 00079 { 00080 stringstream str; 00081 str << xml_tag_enclose(edition.version(), "version"); 00082 if (!edition.release().empty()) 00083 str << xml_tag_enclose(edition.release(), "release"); 00084 if (edition.epoch() != Edition::noepoch) 00085 str << xml_tag_enclose(numstring(edition.epoch()), "epoch"); 00086 return str.str(); 00087 } 00088 00089 template<> 00090 std::string helixXML( const Arch &arch ) 00091 { 00092 stringstream str; 00093 str << xml_tag_enclose(arch.asString(), "arch"); 00094 return str.str(); 00095 } 00096 00097 template<> 00098 std::string helixXML( const Capability &cap ) 00099 { 00100 stringstream str; 00101 CapDetail detail = cap.detail(); 00102 if (detail.isSimple()) { 00103 if (detail.isVersioned()) { 00104 str << "<dep name='" << xml_escape(detail.name().asString()) << "'" 00105 << " op='" << xml_escape(detail.op().asString()) << "'" 00106 << " version='" << xml_escape(detail.ed().version()) << "'"; 00107 if (!detail.ed().release().empty()) 00108 str << " release='" << xml_escape(detail.ed().release()) << "'"; 00109 if (detail.ed().epoch() != Edition::noepoch) 00110 str << " epoch='" << xml_escape(numstring(detail.ed().epoch())) << "'"; 00111 str << " />" << endl; 00112 } else { 00113 str << "<dep name='" << xml_escape(cap.asString()) << "' />" << endl; 00114 } 00115 } else if (detail.isExpression()) { 00116 if (detail.capRel() == CapDetail::CAP_AND 00117 && detail.lhs().detail().isNamed() 00118 && detail.rhs().detail().isNamed()) { 00119 // packageand dependency 00120 str << "<dep name='packageand(" 00121 << IdString(detail.lhs().id()) << ":" 00122 << IdString(detail.rhs().id()) << ")' />" << endl; 00123 } else { 00124 // modalias ? 00125 IdString packageName; 00126 if (detail.capRel() == CapDetail::CAP_AND) { 00127 packageName = IdString(detail.lhs().id()); 00128 detail = detail.rhs().detail(); 00129 } 00130 if (detail.capRel() == CapDetail::CAP_NAMESPACE 00131 && detail.lhs().id() == NAMESPACE_MODALIAS) { 00132 str << "<dep name='modalias("; 00133 if (!packageName.empty()) 00134 str << packageName << ":"; 00135 str << IdString(detail.rhs().id()) << ")' />" << endl; 00136 } else { 00137 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl; 00138 } 00139 } 00140 } else { 00141 str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl; 00142 } 00143 00144 return str.str(); 00145 } 00146 00147 template<> 00148 std::string helixXML( const Capabilities &caps ) 00149 { 00150 stringstream str; 00151 Capabilities::const_iterator it = caps.begin(); 00152 str << endl; 00153 for ( ; it != caps.end(); ++it) 00154 { 00155 str << TAB2 << helixXML((*it)); 00156 } 00157 str << TAB; 00158 return str.str(); 00159 } 00160 00161 template<> 00162 std::string helixXML( const CapabilitySet &caps ) 00163 { 00164 stringstream str; 00165 CapabilitySet::const_iterator it = caps.begin(); 00166 str << endl; 00167 for ( ; it != caps.end(); ++it) 00168 { 00169 str << TAB2 << helixXML((*it)); 00170 } 00171 str << TAB; 00172 return str.str(); 00173 } 00174 00175 inline string helixXML( const Resolvable::constPtr &obj, Dep deptag_r ) 00176 { 00177 stringstream out; 00178 Capabilities caps( obj->dep(deptag_r) ); 00179 if ( ! caps.empty() ) 00180 out << TAB << xml_tag_enclose(helixXML(caps), deptag_r.asString()) << endl; 00181 return out.str(); 00182 } 00183 00184 std::string helixXML( const PoolItem &item ) 00185 { 00186 const Resolvable::constPtr resolvable = item.resolvable(); 00187 stringstream str; 00188 str << "<" << toLower (resolvable->kind().asString()) << ">" << endl; 00189 str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl; 00190 str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl; 00191 str << TAB << xml_tag_enclose (item->buildtime().asSeconds(), "buildtime", true) << endl; 00192 if ( isKind<Package>(resolvable) ) { 00193 str << TAB << "<history>" << endl << TAB << "<update>" << endl; 00194 str << TAB2 << helixXML (resolvable->arch()) << endl; 00195 str << TAB2 << helixXML (resolvable->edition()) << endl; 00196 str << TAB << "</update>" << endl << TAB << "</history>" << endl; 00197 } else { 00198 str << TAB << helixXML (resolvable->arch()) << endl; 00199 str << TAB << helixXML (resolvable->edition()) << endl; 00200 } 00201 str << helixXML( resolvable, Dep::PROVIDES); 00202 str << helixXML( resolvable, Dep::PREREQUIRES); 00203 str << helixXML( resolvable, Dep::CONFLICTS); 00204 str << helixXML( resolvable, Dep::OBSOLETES); 00205 str << helixXML( resolvable, Dep::REQUIRES); 00206 str << helixXML( resolvable, Dep::RECOMMENDS); 00207 str << helixXML( resolvable, Dep::ENHANCES); 00208 str << helixXML( resolvable, Dep::SUPPLEMENTS); 00209 str << helixXML( resolvable, Dep::SUGGESTS); 00210 00211 str << "</" << toLower (resolvable->kind().asString()) << ">" << endl; 00212 return str.str(); 00213 } 00214 00216 // 00217 // CLASS NAME : HelixResolvable 00222 class HelixResolvable : public base::ReferenceCounted, private base::NonCopyable{ 00223 00224 private: 00225 std::string dumpFile; // Path of the generated testcase 00226 ofgzstream *file; 00227 00228 public: 00229 HelixResolvable (const std::string & path); 00230 ~HelixResolvable (); 00231 00232 void addResolvable (const PoolItem item) 00233 { *file << helixXML (item); } 00234 00235 std::string filename () 00236 { return dumpFile; } 00237 }; 00238 00239 DEFINE_PTR_TYPE(HelixResolvable); 00240 IMPL_PTR_TYPE(HelixResolvable); 00241 00242 typedef std::map<Repository, HelixResolvable_Ptr> RepositoryTable; 00243 00244 HelixResolvable::HelixResolvable(const std::string & path) 00245 :dumpFile (path) 00246 { 00247 file = new ofgzstream(path.c_str()); 00248 if (!file) { 00249 ZYPP_THROW (Exception( "Can't open " + path ) ); 00250 } 00251 00252 *file << "<channel><subchannel>" << endl; 00253 } 00254 00255 HelixResolvable::~HelixResolvable() 00256 { 00257 *file << "</subchannel></channel>" << endl; 00258 delete(file); 00259 } 00260 00262 // 00263 // CLASS NAME : HelixControl 00268 class HelixControl { 00269 00270 private: 00271 std::string dumpFile; // Path of the generated testcase 00272 std::ofstream *file; 00273 00274 public: 00275 HelixControl (const std::string & controlPath, 00276 const RepositoryTable & sourceTable, 00277 const Arch & systemArchitecture, 00278 const LocaleSet &languages, 00279 const target::Modalias::ModaliasList & modaliasList, 00280 const std::set<std::string> & multiversionSpec, 00281 const std::string & systemPath = "solver-system.xml.gz", 00282 const bool forceResolve = false, 00283 const bool onlyRequires = false, 00284 const bool ignorealreadyrecommended = false); 00285 HelixControl (); 00286 ~HelixControl (); 00287 00288 void installResolvable (const ResObject::constPtr &resObject, 00289 const ResStatus &status); 00290 void lockResolvable (const ResObject::constPtr &resObject, 00291 const ResStatus &status); 00292 void keepResolvable (const ResObject::constPtr &resObject, 00293 const ResStatus &status); 00294 void deleteResolvable (const ResObject::constPtr &resObject, 00295 const ResStatus &status); 00296 void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict); 00297 void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r ); 00298 00299 void distupgrade (); 00300 void verifySystem (); 00301 void update (); 00302 00303 std::string filename () { return dumpFile; } 00304 }; 00305 00306 HelixControl::HelixControl(const std::string & controlPath, 00307 const RepositoryTable & repoTable, 00308 const Arch & systemArchitecture, 00309 const LocaleSet &languages, 00310 const target::Modalias::ModaliasList & modaliasList, 00311 const std::set<std::string> & multiversionSpec, 00312 const std::string & systemPath, 00313 const bool forceResolve, 00314 const bool onlyRequires, 00315 const bool ignorealreadyrecommended) 00316 :dumpFile (controlPath) 00317 { 00318 file = new ofstream(controlPath.c_str()); 00319 if (!file) { 00320 ZYPP_THROW (Exception( "Can't open " + controlPath ) ); 00321 } 00322 00323 *file << "<?xml version=\"1.0\"?>" << endl 00324 << "<!-- testcase generated by YaST -->" << endl 00325 << "<test>" << endl 00326 << "<setup arch=\"" << systemArchitecture << "\">" << endl 00327 << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl; 00328 for ( RepositoryTable::const_iterator it = repoTable.begin(); 00329 it != repoTable.end(); ++it ) { 00330 RepoInfo repo = it->first.info(); 00331 *file << TAB << "<!-- " << endl 00332 << TAB << "- alias : " << repo.alias() << endl; 00333 for ( RepoInfo::urls_const_iterator itUrl = repo.baseUrlsBegin(); 00334 itUrl != repo.baseUrlsEnd(); 00335 ++itUrl ) 00336 { 00337 *file << TAB << "- url : " << *itUrl << endl; 00338 } 00339 *file << TAB << "- path : " << repo.path() << endl; 00340 *file << TAB << "- type : " << repo.type() << endl; 00341 *file << TAB << "- generated : " << (it->first.generatedTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl; 00342 *file << TAB << "- outdated : " << (it->first.suggestedExpirationTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl; 00343 *file << TAB << " -->" << endl; 00344 00345 *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id()) 00346 << "-package.xml.gz\" name=\"" << repo.alias() << "\"" 00347 << " priority=\"" << repo.priority() 00348 << "\" />" << endl << endl; 00349 } 00350 00351 for (LocaleSet::const_iterator iter = languages.begin(); iter != languages.end(); iter++) { 00352 *file << TAB << "<locale name=\"" << iter->code() 00353 << "\" />" << endl; 00354 } 00355 00356 for_( it, modaliasList.begin(), modaliasList.end() ) { 00357 *file << TAB << "<modalias name=\"" << *it 00358 << "\" />" << endl; 00359 } 00360 00361 for_( it, multiversionSpec.begin(), multiversionSpec.end() ) { 00362 *file << TAB << "<multiversion name=\"" << *it 00363 << "\" />" << endl; 00364 } 00365 00366 if (forceResolve) 00367 *file << TAB << "<forceResolve/>" << endl; 00368 if (onlyRequires) 00369 *file << TAB << "<onlyRequires/>" << endl; 00370 if (ignorealreadyrecommended) 00371 *file << TAB << "<ignorealreadyrecommended/>" << endl; 00372 00373 *file << "</setup>" << endl 00374 << "<trial>" << endl; 00375 } 00376 00377 HelixControl::HelixControl() 00378 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml") 00379 { 00380 HelixControl (dumpFile); 00381 } 00382 00383 HelixControl::~HelixControl() 00384 { 00385 *file << "</trial>" << endl 00386 << "</test>" << endl; 00387 delete(file); 00388 } 00389 00390 void HelixControl::installResolvable(const ResObject::constPtr &resObject, 00391 const ResStatus &status) 00392 { 00393 *file << "<install channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\"" 00394 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\"" 00395 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\"" 00396 << " status=\"" << status << "\"" 00397 << "/>" << endl; 00398 } 00399 00400 void HelixControl::lockResolvable(const ResObject::constPtr &resObject, 00401 const ResStatus &status) 00402 { 00403 *file << "<lock channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\"" 00404 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\"" 00405 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\"" 00406 << " status=\"" << status << "\"" 00407 << "/>" << endl; 00408 } 00409 00410 void HelixControl::keepResolvable(const ResObject::constPtr &resObject, 00411 const ResStatus &status) 00412 { 00413 *file << "<keep channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\"" 00414 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\"" 00415 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\"" 00416 << " status=\"" << status << "\"" 00417 << "/>" << endl; 00418 } 00419 00420 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject, 00421 const ResStatus &status) 00422 { 00423 *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\"" 00424 << " name=\"" << resObject->name() << "\"" 00425 << " status=\"" << status << "\"" 00426 << "/>" << endl; 00427 } 00428 00429 void HelixControl::addDependencies (const CapabilitySet & capRequire, const CapabilitySet & capConflict) 00430 { 00431 for (CapabilitySet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) { 00432 *file << "<addRequire " << " name=\"" << iter->asString() << "\"" << "/>" << endl; 00433 } 00434 for (CapabilitySet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) { 00435 *file << "<addConflict " << " name=\"" << iter->asString() << "\"" << "/>" << endl; 00436 } 00437 } 00438 00439 void HelixControl::addUpgradeRepos( const std::set<Repository> & upgradeRepos_r ) 00440 { 00441 for_( it, upgradeRepos_r.begin(), upgradeRepos_r.end() ) 00442 { 00443 *file << "<upgradeRepo name=\"" << it->alias() << "\"/>" << endl; 00444 } 00445 } 00446 00447 void HelixControl::distupgrade() 00448 { 00449 *file << "<distupgrade/>" << endl; 00450 } 00451 00452 void HelixControl::verifySystem() 00453 { 00454 *file << "<verify/>" << endl; 00455 } 00456 00457 void HelixControl::update() 00458 { 00459 *file << "<update/>" << endl; 00460 } 00461 00462 //--------------------------------------------------------------------------- 00463 00464 Testcase::Testcase() 00465 :dumpPath("/var/log/YaST2/solverTestcase") 00466 {} 00467 00468 Testcase::Testcase(const std::string & path) 00469 :dumpPath(path) 00470 {} 00471 00472 Testcase::~Testcase() 00473 {} 00474 00475 bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver) 00476 { 00477 PathInfo path (dumpPath); 00478 00479 if ( !path.isExist() ) { 00480 if (zypp::filesystem::assert_dir (dumpPath)!=0) { 00481 ERR << "Cannot create directory " << dumpPath << endl; 00482 return false; 00483 } 00484 } else { 00485 if (!path.isDir()) { 00486 ERR << dumpPath << " is not a directory." << endl; 00487 return false; 00488 } 00489 // remove old stuff if pool will be dump 00490 if (dumpPool) 00491 zypp::filesystem::clean_dir (dumpPath); 00492 } 00493 00494 if (runSolver) { 00495 zypp::base::LogControl::TmpLineWriter tempRedirect; 00496 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" ); 00497 zypp::base::LogControl::TmpExcessive excessive; 00498 00499 resolver.resolvePool(); 00500 } 00501 00502 ResPool pool = resolver.pool(); 00503 RepositoryTable repoTable; 00504 PoolItemList items_to_install; 00505 PoolItemList items_to_remove; 00506 PoolItemList items_locked; 00507 PoolItemList items_keep; 00508 HelixResolvable_Ptr system = NULL; 00509 00510 if (dumpPool) 00511 system = new HelixResolvable(dumpPath + "/solver-system.xml.gz"); 00512 00513 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it ) 00514 { 00515 Resolvable::constPtr res = it->resolvable(); 00516 00517 if ( system && it->status().isInstalled() ) { 00518 // system channel 00519 system->addResolvable (*it); 00520 } else { 00521 // repo channels 00522 Repository repo = it->resolvable()->satSolvable().repository(); 00523 if (dumpPool) { 00524 if (repoTable.find (repo) == repoTable.end()) { 00525 repoTable[repo] = new HelixResolvable(dumpPath + "/" 00526 + str::numstring((long)repo.id()) 00527 + "-package.xml.gz"); 00528 } 00529 repoTable[repo]->addResolvable (*it); 00530 } 00531 } 00532 00533 if ( it->status().isToBeInstalled() 00534 && !(it->status().isBySolver())) { 00535 items_to_install.push_back (*it); 00536 } 00537 if ( it->status().isKept() 00538 && !(it->status().isBySolver())) { 00539 items_keep.push_back (*it); 00540 } 00541 if ( it->status().isToBeUninstalled() 00542 && !(it->status().isBySolver())) { 00543 items_to_remove.push_back (*it); 00544 } 00545 if ( it->status().isLocked() 00546 && !(it->status().isBySolver())) { 00547 items_locked.push_back (*it); 00548 } 00549 } 00550 00551 // writing control file "*-test.xml" 00552 HelixControl control (dumpPath + "/solver-test.xml", 00553 repoTable, 00554 ZConfig::instance().systemArchitecture(), 00555 pool.getRequestedLocales(), 00556 target::Modalias::instance().modaliasList(), 00557 ZConfig::instance().multiversionSpec(), 00558 "solver-system.xml.gz", 00559 resolver.forceResolve(), 00560 resolver.onlyRequires(), 00561 resolver.ignoreAlreadyRecommended() ); 00562 00563 for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) { 00564 control.installResolvable (iter->resolvable(), iter->status()); 00565 } 00566 00567 for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) { 00568 control.lockResolvable (iter->resolvable(), iter->status()); 00569 } 00570 00571 for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) { 00572 control.keepResolvable (iter->resolvable(), iter->status()); 00573 } 00574 00575 for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) { 00576 control.deleteResolvable (iter->resolvable(), iter->status()); 00577 } 00578 00579 control.addDependencies (resolver.extraRequires(), resolver.extraConflicts()); 00580 control.addDependencies (SystemCheck::instance().requiredSystemCap(), 00581 SystemCheck::instance().conflictSystemCap()); 00582 control.addUpgradeRepos( resolver.upgradeRepos() ); 00583 00584 if (resolver.isUpgradeMode()) 00585 control.distupgrade (); 00586 if (resolver.isUpdateMode()) 00587 control.update(); 00588 if (resolver.isVerifyingMode()) 00589 control.verifySystem(); 00590 00591 return true; 00592 } 00593 00594 00596 };// namespace detail 00599 };// namespace solver 00602 };// namespace zypp