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 #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

Generated on Tue May 5 14:43:19 2015 for libzypp by  doxygen 1.5.6