00001
00002
00003
00004
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/PathInfo.h"
00021 #include "zypp/Product.h"
00022 #include "zypp/Package.h"
00023 #include "zypp/Edition.h"
00024 #include "zypp/target/store/xml_escape_parser.hpp"
00025 #include "zypp/capability/VersionedCap.h"
00026 #include "zypp/base/String.h"
00027 #include "zypp/base/PtrTypes.h"
00028
00029
00031 namespace zypp
00032 {
00033
00034 namespace solver
00035 {
00036
00037 namespace detail
00038 {
00039
00040 #define TAB "\t"
00041 #define TAB2 "\t\t"
00042
00043 using namespace std;
00044 using namespace zypp::capability;
00045 using namespace zypp::str;
00046
00047 IMPL_PTR_TYPE(HelixResolvable);
00048
00049 static std::string xml_escape( const std::string &text )
00050 {
00051 iobind::parser::xml_escape_parser parser;
00052 return parser.escape(text);
00053 }
00054
00055 static std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
00056 {
00057 string result;
00058 result += "<" + tag + ">";
00059
00060 if ( escape)
00061 result += xml_escape(text);
00062 else
00063 result += text;
00064
00065 result += "</" + tag + ">";
00066 return result;
00067 }
00068
00069
00070 template<class T>
00071 std::string helixXML( const T &obj );
00072
00073 template<>
00074 std::string helixXML( const Edition &edition )
00075 {
00076 stringstream str;
00077 str << xml_tag_enclose(edition.version(), "version");
00078 if (!edition.release().empty())
00079 str << xml_tag_enclose(edition.release(), "release");
00080 if (edition.epoch() != Edition::noepoch)
00081 str << xml_tag_enclose(numstring(edition.epoch()), "epoch");
00082 return str.str();
00083 }
00084
00085 template<>
00086 std::string helixXML( const Arch &arch )
00087 {
00088 stringstream str;
00089 str << xml_tag_enclose(arch.asString(), "arch");
00090 return str.str();
00091 }
00092
00093 template<>
00094 std::string helixXML( const Capability &cap )
00095 {
00096 stringstream str;
00097 VersionedCap::constPtr vercap = asKind<VersionedCap>(cap);
00098 if (vercap
00099 && vercap->op() != Rel::NONE
00100 && vercap->op() != Rel::ANY
00101 && !vercap->edition().version().empty() )
00102 {
00103
00104 str << "<dep name='" << xml_escape(vercap->index()) << "' op='" << xml_escape(vercap->op().asString()) <<
00105 "' version='" << vercap->edition().version() << "'";
00106 if (!vercap->edition().release().empty())
00107 str << " release='" << vercap->edition().release() << "'";
00108 if (vercap->edition().epoch() != Edition::noepoch)
00109 str << " epoch='" << numstring(vercap->edition().epoch()) << "'";
00110 }
00111 else
00112 {
00113 str << "<dep name='" << xml_escape(cap.asString()) << "'";
00114 }
00115
00116 str << " kind=\"" << toLower (cap.refers().asString()) << "\""
00117 << " />" << endl;
00118
00119 return str.str();
00120 }
00121
00122 template<>
00123 std::string helixXML( const CapSet &caps )
00124 {
00125 stringstream str;
00126 CapSet::iterator it = caps.begin();
00127 str << endl;
00128 for ( ; it != caps.end(); ++it)
00129 {
00130 str << TAB2 << helixXML((*it));
00131 }
00132 str << TAB;
00133 return str.str();
00134 }
00135
00136 template<>
00137 std::string helixXML( const Dependencies &dep )
00138 {
00139 stringstream str;
00140 if ( dep[Dep::PROVIDES].size() > 0 )
00141 str << TAB << xml_tag_enclose(helixXML(dep[Dep::PROVIDES]), "provides") << endl;
00142 if ( dep[Dep::CONFLICTS].size() > 0 )
00143 str << TAB << xml_tag_enclose(helixXML(dep[Dep::CONFLICTS]), "conflicts") << endl;
00144 if ( dep[Dep::OBSOLETES].size() > 0 )
00145 str << TAB << xml_tag_enclose(helixXML(dep[Dep::OBSOLETES]), "obsoletes") << endl;
00146 if ( dep[Dep::FRESHENS].size() > 0 )
00147 str << TAB << xml_tag_enclose(helixXML(dep[Dep::FRESHENS]), "freshens") << endl;
00148 if ( dep[Dep::REQUIRES].size() > 0 )
00149 str << TAB << xml_tag_enclose(helixXML(dep[Dep::REQUIRES]), "requires") << endl;
00150 if ( dep[Dep::RECOMMENDS].size() > 0 )
00151 str << TAB << xml_tag_enclose(helixXML(dep[Dep::RECOMMENDS]), "recommends") << endl;
00152 if ( dep[Dep::ENHANCES].size() > 0 )
00153 str << TAB << xml_tag_enclose(helixXML(dep[Dep::ENHANCES]), "enhances") << endl;
00154 if ( dep[Dep::SUPPLEMENTS].size() > 0 )
00155 str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUPPLEMENTS]), "supplements") << endl;
00156 if ( dep[Dep::SUGGESTS].size() > 0 )
00157 str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUGGESTS]), "suggests") << endl;
00158 return str.str();
00159 }
00160
00161 std::string helixXML( const Resolvable::constPtr &resolvable )
00162 {
00163 stringstream str;
00164 if ( isKind<SystemResObject>(resolvable)
00165 || isKind<Language>(resolvable) ) {
00166
00167
00168 return str.str();
00169 }
00170
00171 str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
00172 str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
00173 if ( isKind<Package>(resolvable) ) {
00174 str << TAB << "<history>" << endl << TAB << "<update>" << endl;
00175 str << TAB2 << helixXML (resolvable->arch()) << endl;
00176 str << TAB2 << helixXML (resolvable->edition()) << endl;
00177 str << TAB << "</update>" << endl << TAB << "</history>" << endl;
00178 } else {
00179 str << TAB << helixXML (resolvable->arch()) << endl;
00180 str << TAB << helixXML (resolvable->edition()) << endl;
00181 }
00182 str << helixXML (resolvable->deps());
00183
00184 str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;
00185 return str.str();
00186 }
00187
00188
00189
00190 Testcase::Testcase()
00191 :dumpPath("/var/log/YaST2/solverTestcase")
00192 {
00193 }
00194
00195 Testcase::Testcase(const std::string & path)
00196 :dumpPath(path)
00197 {
00198 }
00199
00200
00201 Testcase::~Testcase()
00202 {
00203 }
00204
00205 bool Testcase::createTestcase(Resolver & resolver)
00206 {
00207 PathInfo path (dumpPath);
00208
00209 if ( !path.isExist() ) {
00210 if (zypp::filesystem::mkdir (dumpPath)!=0) {
00211 ERR << "Cannot create directory " << dumpPath << endl;
00212 return false;
00213 }
00214 } else {
00215 if (!path.isDir()) {
00216 ERR << dumpPath << " is not a directory." << endl;
00217 return false;
00218 }
00219
00220 zypp::filesystem::clean_dir (dumpPath);
00221 }
00222
00223 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
00224 zypp::base::LogControl::TmpExcessive excessive;
00225
00226 resolver.reset(true);
00227 resolver.resolvePool();
00228
00229 zypp::base::LogControl::instance().logfile( "/var/log/YaST2/y2log" );
00230
00231 ResPool pool = resolver.pool();
00232 RepositoryTable repoTable;
00233 PoolItemList items_to_install;
00234 PoolItemList items_to_remove;
00235 PoolItemList items_locked;
00236 PoolItemList language;
00237 HelixResolvable system (dumpPath + "/solver-system.xml");
00238
00239 for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
00240 {
00241 Resolvable::constPtr res = it->resolvable();
00242
00243 if (isKind<Language>(res)) {
00244 if ( it->status().isInstalled()
00245 || it->status().isToBeInstalled()) {
00246 language.push_back (*it);
00247 }
00248 } else {
00249 if ( it->status().isInstalled() ) {
00250
00251 system.addResolvable (res);
00252 } else {
00253
00254 ResObject::constPtr repoItem = it->resolvable();
00255 Repository repo = repoItem->repository();
00256 if (repoTable.find (repo) == repoTable.end()) {
00257 repoTable[repo] = new HelixResolvable(dumpPath + "/"
00258 + numstring(repo.numericId())
00259 + "-package.xml");
00260 }
00261 repoTable[repo]->addResolvable (res);
00262 }
00263
00264 if ( it->status().isToBeInstalled()
00265 && !(it->status().isBySolver())) {
00266 items_to_install.push_back (*it);
00267 }
00268 if ( it->status().isToBeUninstalled()
00269 && !(it->status().isBySolver())) {
00270 items_to_remove.push_back (*it);
00271 }
00272 if ( it->status().isLocked()
00273 && !(it->status().isBySolver())
00274 && !isKind<SystemResObject>(res)) {
00275 items_locked.push_back (*it);
00276 }
00277
00278 }
00279 }
00280
00281
00282
00283 HelixControl control (dumpPath + "/solver-test.xml",
00284 repoTable,
00285 resolver.architecture(),
00286 language);
00287
00288 for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
00289 control.installResolvable (iter->resolvable());
00290 }
00291
00292 for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
00293 control.lockResolvable (iter->resolvable());
00294 }
00295
00296
00297 for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
00298 control.deleteResolvable (iter->resolvable());
00299 }
00300
00301 control.addDependencies (resolver.extraCapability(), resolver.extraConflicts());
00302
00303 return true;
00304 }
00305
00306
00307
00308 HelixResolvable::HelixResolvable(const std::string & path)
00309 :dumpFile (path)
00310 {
00311 file = new ofstream(path.c_str());
00312 if (!file) {
00313 ZYPP_THROW (Exception( "Can't open " + path ) );
00314 }
00315
00316 *file << "<channel><subchannel>" << endl;
00317 }
00318
00319 HelixResolvable::~HelixResolvable()
00320 {
00321 *file << "</subchannel></channel>" << endl;
00322 }
00323
00324
00325 void HelixResolvable::addResolvable(const Resolvable::constPtr &resolvable)
00326 {
00327 *file << helixXML (resolvable);
00328 }
00329
00330
00331
00332 HelixControl::HelixControl(const std::string & controlPath,
00333 const RepositoryTable & repoTable,
00334 const Arch & systemArchitecture,
00335 const PoolItemList &languages,
00336 const std::string & systemPath)
00337 :dumpFile (controlPath)
00338 {
00339 file = new ofstream(controlPath.c_str());
00340 if (!file) {
00341 ZYPP_THROW (Exception( "Can't open " + controlPath ) );
00342 }
00343
00344 *file << "<?xml version=\"1.0\"?>" << endl
00345 << "<!-- testcase generated by YaST -->" << endl
00346 << "<test>" << endl
00347 << "<setup arch=\"" << systemArchitecture << "\">" << endl
00348 << TAB << "<system file=\"" << systemPath << "\"/>" << endl;
00349 for ( RepositoryTable::const_iterator it = repoTable.begin();
00350 it != repoTable.end(); ++it ) {
00351 Repository repo = it->first;
00352 *file << TAB << "<channel file=\"" << numstring(repo.numericId())
00353 << "-package.xml\" name=\"" << numstring(repo.numericId())
00354 << "\" />" << endl;
00355 }
00356 for (PoolItemList::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
00357 *file << TAB << "<locale name=\"" << iter->resolvable()->name()
00358 << "\" />" << endl;
00359 }
00360 *file << "</setup>" << endl
00361 << "<trial>" << endl
00362 << "<showpool all=\"yes\"/>" << endl
00363 << "<establish/>" << endl
00364 << "<showpool all=\"true\" prefix=\">!> ESTABLISHED:\"/>" << endl;
00365 }
00366
00367 HelixControl::HelixControl()
00368 :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
00369 {
00370 HelixControl (dumpFile);
00371 }
00372
00373 HelixControl::~HelixControl()
00374 {
00375 *file << "</trial>" << endl
00376 << "</test>" << endl;
00377 }
00378
00379 void HelixControl::installResolvable(const ResObject::constPtr &resObject)
00380 {
00381 Repository repo = resObject->repository();
00382 *file << "<install channel=\"" << numstring(repo.numericId()) << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
00383 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
00384 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
00385 << "/>" << endl;
00386 }
00387
00388 void HelixControl::lockResolvable(const ResObject::constPtr &resObject)
00389 {
00390 Repository repo = resObject->repository();
00391 *file << "<lock channel=\"" << numstring(repo.numericId()) << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
00392 << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
00393 << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
00394 << "/>" << endl;
00395 }
00396
00397 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject)
00398 {
00399 Repository repo = resObject->repository();
00400 *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
00401 << " name=\"" << resObject->name() << "\"" << "/>" << endl;
00402 }
00403
00404 void HelixControl::addDependencies (const CapSet & capRequire, const CapSet & capConflict)
00405 {
00406 for (CapSet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) {
00407 *file << "<addRequire " << " kind=\"" << toLower (iter->kind().asString()) << "\""
00408 << " name=\"" << iter->asString() << "\"" << "/>" << endl;
00409 }
00410 for (CapSet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) {
00411 *file << "<addConflict " << " kind=\"" << toLower (iter->kind().asString()) << "\""
00412 << " name=\"" << iter->asString() << "\"" << "/>" << endl;
00413 }
00414 }
00415
00416
00418 };
00421 };
00424 };