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