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

doxygen