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