libzypp  12.16.5
Testcase.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <streambuf>
16 
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/LogControl.h"
20 #include "zypp/base/GzStream.h"
21 #include "zypp/base/String.h"
22 #include "zypp/base/PtrTypes.h"
23 #include "zypp/base/NonCopyable.h"
25 
27 
28 #include "zypp/ZConfig.h"
29 #include "zypp/PathInfo.h"
30 #include "zypp/ResPool.h"
31 #include "zypp/Repository.h"
33 
36 
38 namespace zypp
39 {
40 
41  namespace solver
42  {
43 
44  namespace detail
45  {
46 
47 #define TAB "\t"
48 #define TAB2 "\t\t"
49 
50 using namespace std;
51 using namespace zypp::str;
52 
53 //---------------------------------------------------------------------------
54 
55 inline std::string xml_escape( const std::string &text )
56 {
57  return zypp::xml::escape(text);
58 }
59 
60 inline std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
61 {
62  string result;
63  result += "<" + tag + ">";
64 
65  if ( escape)
66  result += xml_escape(text);
67  else
68  result += text;
69 
70  result += "</" + tag + ">";
71  return result;
72 }
73 
74 template<class T>
75 std::string helixXML( const T &obj ); //undefined
76 
77 template<>
78 std::string helixXML( const Edition &edition )
79 {
80  stringstream str;
81  str << xml_tag_enclose(edition.version(), "version");
82  if (!edition.release().empty())
83  str << xml_tag_enclose(edition.release(), "release");
84  if (edition.epoch() != Edition::noepoch)
85  str << xml_tag_enclose(numstring(edition.epoch()), "epoch");
86  return str.str();
87 }
88 
89 template<>
90 std::string helixXML( const Arch &arch )
91 {
92  stringstream str;
93  str << xml_tag_enclose(arch.asString(), "arch");
94  return str.str();
95 }
96 
97 template<>
98 std::string helixXML( const Capability &cap )
99 {
100  stringstream str;
101  CapDetail detail = cap.detail();
102  if (detail.isSimple()) {
103  if (detail.isVersioned()) {
104  str << "<dep name='" << xml_escape(detail.name().asString()) << "'"
105  << " op='" << xml_escape(detail.op().asString()) << "'"
106  << " version='" << xml_escape(detail.ed().version()) << "'";
107  if (!detail.ed().release().empty())
108  str << " release='" << xml_escape(detail.ed().release()) << "'";
109  if (detail.ed().epoch() != Edition::noepoch)
110  str << " epoch='" << xml_escape(numstring(detail.ed().epoch())) << "'";
111  str << " />" << endl;
112  } else {
113  str << "<dep name='" << xml_escape(cap.asString()) << "' />" << endl;
114  }
115  } else if (detail.isExpression()) {
116  if (detail.capRel() == CapDetail::CAP_AND
117  && detail.lhs().detail().isNamed()
118  && detail.rhs().detail().isNamed()) {
119  // packageand dependency
120  str << "<dep name='packageand("
121  << IdString(detail.lhs().id()) << ":"
122  << IdString(detail.rhs().id()) << ")' />" << endl;
123  } else {
124  // modalias ?
125  IdString packageName;
126  if (detail.capRel() == CapDetail::CAP_AND) {
127  packageName = IdString(detail.lhs().id());
128  detail = detail.rhs().detail();
129  }
130  if (detail.capRel() == CapDetail::CAP_NAMESPACE
131  && detail.lhs().id() == NAMESPACE_MODALIAS) {
132  str << "<dep name='modalias(";
133  if (!packageName.empty())
134  str << packageName << ":";
135  str << IdString(detail.rhs().id()) << ")' />" << endl;
136  } else {
137  str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
138  }
139  }
140  } else {
141  str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
142  }
143 
144  return str.str();
145 }
146 
147 template<>
148 std::string helixXML( const Capabilities &caps )
149 {
150  stringstream str;
152  str << endl;
153  for ( ; it != caps.end(); ++it)
154  {
155  str << TAB2 << helixXML((*it));
156  }
157  str << TAB;
158  return str.str();
159 }
160 
161 template<>
162 std::string helixXML( const CapabilitySet &caps )
163 {
164  stringstream str;
165  CapabilitySet::const_iterator it = caps.begin();
166  str << endl;
167  for ( ; it != caps.end(); ++it)
168  {
169  str << TAB2 << helixXML((*it));
170  }
171  str << TAB;
172  return str.str();
173 }
174 
175 inline string helixXML( const Resolvable::constPtr &obj, Dep deptag_r )
176 {
177  stringstream out;
178  Capabilities caps( obj->dep(deptag_r) );
179  if ( ! caps.empty() )
180  out << TAB << xml_tag_enclose(helixXML(caps), deptag_r.asString()) << endl;
181  return out.str();
182 }
183 
184 std::string helixXML( const PoolItem &item )
185 {
186  const Resolvable::constPtr resolvable = item.resolvable();
187  stringstream str;
188  str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
189  str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
190  str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl;
191  str << TAB << xml_tag_enclose (item->buildtime().asSeconds(), "buildtime", true) << endl;
192  if ( isKind<Package>(resolvable) ) {
193  str << TAB << "<history>" << endl << TAB << "<update>" << endl;
194  str << TAB2 << helixXML (resolvable->arch()) << endl;
195  str << TAB2 << helixXML (resolvable->edition()) << endl;
196  str << TAB << "</update>" << endl << TAB << "</history>" << endl;
197  } else {
198  str << TAB << helixXML (resolvable->arch()) << endl;
199  str << TAB << helixXML (resolvable->edition()) << endl;
200  }
201  str << helixXML( resolvable, Dep::PROVIDES);
202  str << helixXML( resolvable, Dep::PREREQUIRES);
203  str << helixXML( resolvable, Dep::CONFLICTS);
204  str << helixXML( resolvable, Dep::OBSOLETES);
205  str << helixXML( resolvable, Dep::REQUIRES);
206  str << helixXML( resolvable, Dep::RECOMMENDS);
207  str << helixXML( resolvable, Dep::ENHANCES);
208  str << helixXML( resolvable, Dep::SUPPLEMENTS);
209  str << helixXML( resolvable, Dep::SUGGESTS);
210 
211  str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;
212  return str.str();
213 }
214 
216 //
217 // CLASS NAME : HelixResolvable
223 
224  private:
225  std::string dumpFile; // Path of the generated testcase
227 
228  public:
229  HelixResolvable (const std::string & path);
230  ~HelixResolvable ();
231 
232  void addResolvable (const PoolItem item)
233  { *file << helixXML (item); }
234 
235  std::string filename ()
236  { return dumpFile; }
237 };
238 
239 DEFINE_PTR_TYPE(HelixResolvable);
240 IMPL_PTR_TYPE(HelixResolvable);
241 
242 typedef std::map<Repository, HelixResolvable_Ptr> RepositoryTable;
243 
244 HelixResolvable::HelixResolvable(const std::string & path)
245  :dumpFile (path)
246 {
247  file = new ofgzstream(path.c_str());
248  if (!file) {
249  ZYPP_THROW (Exception( "Can't open " + path ) );
250  }
251 
252  *file << "<channel><subchannel>" << endl;
253 }
254 
256 {
257  *file << "</subchannel></channel>" << endl;
258  delete(file);
259 }
260 
262 //
263 // CLASS NAME : HelixControl
269 
270  private:
271  std::string dumpFile; // Path of the generated testcase
272  std::ofstream *file;
273 
274  public:
275  HelixControl (const std::string & controlPath,
276  const RepositoryTable & sourceTable,
277  const Arch & systemArchitecture,
278  const LocaleSet &languages,
279  const target::Modalias::ModaliasList & modaliasList,
280  const std::set<std::string> & multiversionSpec,
281  const std::string & systemPath = "solver-system.xml.gz",
282  const bool forceResolve = false,
283  const bool onlyRequires = false,
284  const bool ignorealreadyrecommended = false);
285  HelixControl ();
286  ~HelixControl ();
287 
288  void installResolvable (const ResObject::constPtr &resObject,
289  const ResStatus &status);
290  void lockResolvable (const ResObject::constPtr &resObject,
291  const ResStatus &status);
292  void keepResolvable (const ResObject::constPtr &resObject,
293  const ResStatus &status);
294  void deleteResolvable (const ResObject::constPtr &resObject,
295  const ResStatus &status);
296  void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict);
297  void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r );
298 
299  void distupgrade ();
300  void verifySystem ();
301  void update ();
302 
303  std::string filename () { return dumpFile; }
304 };
305 
306 HelixControl::HelixControl(const std::string & controlPath,
307  const RepositoryTable & repoTable,
308  const Arch & systemArchitecture,
309  const LocaleSet &languages,
310  const target::Modalias::ModaliasList & modaliasList,
311  const std::set<std::string> & multiversionSpec,
312  const std::string & systemPath,
313  const bool forceResolve,
314  const bool onlyRequires,
315  const bool ignorealreadyrecommended)
316  :dumpFile (controlPath)
317 {
318  file = new ofstream(controlPath.c_str());
319  if (!file) {
320  ZYPP_THROW (Exception( "Can't open " + controlPath ) );
321  }
322 
323  *file << "<?xml version=\"1.0\"?>" << endl
324  << "<!-- testcase generated by YaST -->" << endl
325  << "<test>" << endl
326  << "<setup arch=\"" << systemArchitecture << "\">" << endl
327  << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl;
328  for ( RepositoryTable::const_iterator it = repoTable.begin();
329  it != repoTable.end(); ++it ) {
330  RepoInfo repo = it->first.info();
331  *file << TAB << "<!-- " << endl
332  << TAB << "- alias : " << repo.alias() << endl;
333  for ( RepoInfo::urls_const_iterator itUrl = repo.baseUrlsBegin();
334  itUrl != repo.baseUrlsEnd();
335  ++itUrl )
336  {
337  *file << TAB << "- url : " << *itUrl << endl;
338  }
339  *file << TAB << "- path : " << repo.path() << endl;
340  *file << TAB << "- type : " << repo.type() << endl;
341  *file << TAB << "- generated : " << (it->first.generatedTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
342  *file << TAB << "- outdated : " << (it->first.suggestedExpirationTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
343  *file << TAB << " -->" << endl;
344 
345  *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id())
346  << "-package.xml.gz\" name=\"" << repo.alias() << "\""
347  << " priority=\"" << repo.priority()
348  << "\" />" << endl << endl;
349  }
350 
351  for (LocaleSet::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
352  *file << TAB << "<locale name=\"" << iter->code()
353  << "\" />" << endl;
354  }
355 
356  for_( it, modaliasList.begin(), modaliasList.end() ) {
357  *file << TAB << "<modalias name=\"" << *it
358  << "\" />" << endl;
359  }
360 
361  for_( it, multiversionSpec.begin(), multiversionSpec.end() ) {
362  *file << TAB << "<multiversion name=\"" << *it
363  << "\" />" << endl;
364  }
365 
366  if (forceResolve)
367  *file << TAB << "<forceResolve/>" << endl;
368  if (onlyRequires)
369  *file << TAB << "<onlyRequires/>" << endl;
370  if (ignorealreadyrecommended)
371  *file << TAB << "<ignorealreadyrecommended/>" << endl;
372 
373  *file << "</setup>" << endl
374  << "<trial>" << endl;
375 }
376 
378  :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
379 {
381 }
382 
384 {
385  *file << "</trial>" << endl
386  << "</test>" << endl;
387  delete(file);
388 }
389 
391  const ResStatus &status)
392 {
393  *file << "<install channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
394  << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
395  << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
396  << " status=\"" << status << "\""
397  << "/>" << endl;
398 }
399 
401  const ResStatus &status)
402 {
403  *file << "<lock channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
404  << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
405  << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
406  << " status=\"" << status << "\""
407  << "/>" << endl;
408 }
409 
411  const ResStatus &status)
412 {
413  *file << "<keep channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
414  << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
415  << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
416  << " status=\"" << status << "\""
417  << "/>" << endl;
418 }
419 
421  const ResStatus &status)
422 {
423  *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
424  << " name=\"" << resObject->name() << "\""
425  << " status=\"" << status << "\""
426  << "/>" << endl;
427 }
428 
429 void HelixControl::addDependencies (const CapabilitySet & capRequire, const CapabilitySet & capConflict)
430 {
431  for (CapabilitySet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) {
432  *file << "<addRequire " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
433  }
434  for (CapabilitySet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) {
435  *file << "<addConflict " << " name=\"" << iter->asString() << "\"" << "/>" << endl;
436  }
437 }
438 
439 void HelixControl::addUpgradeRepos( const std::set<Repository> & upgradeRepos_r )
440 {
441  for_( it, upgradeRepos_r.begin(), upgradeRepos_r.end() )
442  {
443  *file << "<upgradeRepo name=\"" << it->alias() << "\"/>" << endl;
444  }
445 }
446 
448 {
449  *file << "<distupgrade/>" << endl;
450 }
451 
453 {
454  *file << "<verify/>" << endl;
455 }
456 
458 {
459  *file << "<update/>" << endl;
460 }
461 
462 //---------------------------------------------------------------------------
463 
465  :dumpPath("/var/log/YaST2/solverTestcase")
466 {}
467 
468 Testcase::Testcase(const std::string & path)
469  :dumpPath(path)
470 {}
471 
473 {}
474 
475 bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
476 {
477  PathInfo path (dumpPath);
478 
479  if ( !path.isExist() ) {
481  ERR << "Cannot create directory " << dumpPath << endl;
482  return false;
483  }
484  } else {
485  if (!path.isDir()) {
486  ERR << dumpPath << " is not a directory." << endl;
487  return false;
488  }
489  // remove old stuff if pool will be dump
490  if (dumpPool)
492  }
493 
494  if (runSolver) {
498 
499  resolver.resolvePool();
500  }
501 
502  ResPool pool = resolver.pool();
503  RepositoryTable repoTable;
504  PoolItemList items_to_install;
505  PoolItemList items_to_remove;
506  PoolItemList items_locked;
507  PoolItemList items_keep;
508  HelixResolvable_Ptr system = NULL;
509 
510  if (dumpPool)
511  system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
512 
513  for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
514  {
515  Resolvable::constPtr res = it->resolvable();
516 
517  if ( system && it->status().isInstalled() ) {
518  // system channel
519  system->addResolvable (*it);
520  } else {
521  // repo channels
522  Repository repo = it->resolvable()->satSolvable().repository();
523  if (dumpPool) {
524  if (repoTable.find (repo) == repoTable.end()) {
525  repoTable[repo] = new HelixResolvable(dumpPath + "/"
526  + str::numstring((long)repo.id())
527  + "-package.xml.gz");
528  }
529  repoTable[repo]->addResolvable (*it);
530  }
531  }
532 
533  if ( it->status().isToBeInstalled()
534  && !(it->status().isBySolver())) {
535  items_to_install.push_back (*it);
536  }
537  if ( it->status().isKept()
538  && !(it->status().isBySolver())) {
539  items_keep.push_back (*it);
540  }
541  if ( it->status().isToBeUninstalled()
542  && !(it->status().isBySolver())) {
543  items_to_remove.push_back (*it);
544  }
545  if ( it->status().isLocked()
546  && !(it->status().isBySolver())) {
547  items_locked.push_back (*it);
548  }
549  }
550 
551  // writing control file "*-test.xml"
552  HelixControl control (dumpPath + "/solver-test.xml",
553  repoTable,
554  ZConfig::instance().systemArchitecture(),
555  pool.getRequestedLocales(),
558  "solver-system.xml.gz",
559  resolver.forceResolve(),
560  resolver.onlyRequires(),
561  resolver.ignoreAlreadyRecommended() );
562 
563  for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
564  control.installResolvable (iter->resolvable(), iter->status());
565  }
566 
567  for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
568  control.lockResolvable (iter->resolvable(), iter->status());
569  }
570 
571  for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
572  control.keepResolvable (iter->resolvable(), iter->status());
573  }
574 
575  for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
576  control.deleteResolvable (iter->resolvable(), iter->status());
577  }
578 
579  control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
580  control.addDependencies (SystemCheck::instance().requiredSystemCap(),
581  SystemCheck::instance().conflictSystemCap());
582  control.addUpgradeRepos( resolver.upgradeRepos() );
583 
584  if (resolver.isUpgradeMode())
585  control.distupgrade ();
586  if (resolver.isUpdateMode())
587  control.update();
588  if (resolver.isVerifyingMode())
589  control.verifySystem();
590 
591  return true;
592 }
593 
594 
596  };// namespace detail
599  };// namespace solver
602 };// namespace zypp