libzypp 8.13.6

Testcase.cc

Go to the documentation of this file.
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