libzypp  17.37.10
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 #include <boost/iterator/function_output_iterator.hpp>
17 
18 #define ZYPP_USE_RESOLVER_INTERNALS
19 
21 #include <zypp/base/Logger.h>
22 #include <zypp/base/LogControl.h>
23 #include <utility>
24 #include <zypp-core/base/GzStream>
25 #include <zypp/base/String.h>
26 #include <zypp/base/PtrTypes.h>
27 #include <zypp/base/NonCopyable.h>
29 
30 #include <zypp/AutoDispose.h>
31 #include <zypp/ZConfig.h>
32 #include <zypp/PathInfo.h>
33 #include <zypp/ResPool.h>
34 #include <zypp/Repository.h>
35 #include <zypp/VendorAttr.h>
37 
41 
42 #include <yaml-cpp/yaml.h>
43 
44 extern "C" {
45 #include <solv/testcase.h>
46 }
47 
48 using std::endl;
49 
51 namespace zypp
52 {
53  namespace solver
55  {
56  namespace detail
58  {
59 
60  //---------------------------------------------------------------------------
61 
62  Testcase::Testcase()
63  :dumpPath("/var/log/YaST2/solverTestcase")
64  {}
65 
66  Testcase::Testcase(std::string path)
67  :dumpPath(std::move(path))
68  {}
69 
70  Testcase::~Testcase()
71  {}
72 
73  bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
74  {
75  // libzypp/issues/317: make sure a satsolver instance is actually present
76  if ( not resolver.get() ) {
77  WAR << "Can't createTestcase if the satsolver is not yet initialized." << endl;
78  return false;
79  }
80 
81  MIL << "createTestcase at " << dumpPath << (dumpPool?" dumpPool":"") << (runSolver?" runSolver":"") << endl;
82  PathInfo path (dumpPath);
83 
84  if ( !path.isExist() ) {
86  ERR << "Cannot create directory " << dumpPath << endl;
87  return false;
88  }
89  } else {
90  if (!path.isDir()) {
91  ERR << dumpPath << " is not a directory." << endl;
92  return false;
93  }
94  // remove old stuff if pool will be dump
95  if (dumpPool)
97  }
98 
99  if (runSolver) {
103 
104  resolver.resolvePool();
105  }
106 
107  ResPool pool = resolver.pool();
108  PoolItemList items_to_install;
109  PoolItemList items_to_remove;
110  PoolItemList items_locked;
111  PoolItemList items_keep;
112 
113 
114  const std::string slvTestcaseName = "testcase.t";
115  const std::string slvResult = "solver.result";
116 
117  zypp::AutoDispose<const char **> repoFileNames( testcase_mangle_repo_names( resolver.get()->pool ),
118  [ nrepos = resolver.get()->pool->nrepos ]( auto **x ){
119  if (!x) return;
120  for ( int i = 1; i < nrepos; i++ )
121  solv_free((void *)x[i]);
122  solv_free((void *)x);
123  });
124 
125  if ( ::testcase_write( resolver.get(), dumpPath.c_str(), TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS, slvTestcaseName.c_str(), slvResult.c_str() ) == 0 ) {
126  ERR << "Failed to write solv data, aborting." << endl;
127  return false;
128  }
129 
130  // HACK: directly access sat::pool
131  const sat::Pool & satpool( sat::Pool::instance() );
132 
133  YAML::Emitter yOut;
134 
135  const auto addTag = [&]( const std::string & tag_r, bool yesno_r = true ){
136  yOut << YAML::Key << tag_r << YAML::Value << yesno_r;
137  };
138 
139  yOut << YAML::BeginMap << YAML::Key << "version" << YAML::Value << "1.0";
140 
141  yOut << YAML::Key << "setup" << YAML::Value << YAML::BeginMap;
142 
143  yOut << YAML::Key << "channels";
144  yOut << YAML::Value << YAML::BeginSeq;
145 
146  std::set<Repository::IdType> repos;
147  for ( const PoolItem & pi : pool ) {
148  if ( pi.status().isToBeInstalled()
149  && !(pi.status().isBySolver())) {
150  items_to_install.push_back( pi );
151  }
152  if ( pi.status().isKept()
153  && !(pi.status().isBySolver())) {
154  items_keep.push_back( pi );
155  }
156  if ( pi.status().isToBeUninstalled()
157  && !(pi.status().isBySolver())) {
158  items_to_remove.push_back( pi );
159  }
160  if ( pi.status().isLocked()
161  && !(pi.status().isBySolver())) {
162  items_locked.push_back( pi );
163  }
164 
165  const auto &myRepo = pi.repository();
166  const auto &myRepoInfo = myRepo.info();
167  if ( repos.find( myRepo.id()) == repos.end() ) {
168  repos.insert( myRepo.id() );
169  yOut << YAML::Value << YAML::BeginMap;
170  yOut << YAML::Key << "alias" << YAML::Value << myRepo.alias();
171  yOut << YAML::Key << "url" << YAML::BeginSeq;
172  for ( const auto &origin : myRepoInfo.repoOrigins () ) {
173  for ( const auto &originEndpoint : origin ) {
174  yOut << YAML::Value << originEndpoint.url().asString();
175  }
176  }
177  yOut << YAML::EndSeq;
178  yOut << YAML::Key << "path" << YAML::Value << myRepoInfo.path().asString();
179  yOut << YAML::Key << "type" << YAML::Value << myRepoInfo.type().asString();
180  yOut << YAML::Key << "generated" << YAML::Value << myRepo.generatedTimestamp().form( "%Y-%m-%d %H:%M:%S" );
181  yOut << YAML::Key << "outdated" << YAML::Value << myRepo.suggestedExpirationTimestamp().form( "%Y-%m-%d %H:%M:%S" );
182  yOut << YAML::Key << "priority" << YAML::Value << myRepoInfo.priority();
183  yOut << YAML::Key << "file" << YAML::Value << str::Format("%1%.repo.gz") % repoFileNames[myRepo.id()->repoid];
184 
185  yOut << YAML::EndMap;
186  }
187 
188  }
189 
190  yOut << YAML::EndSeq;
191 
192  yOut << YAML::Key << "arch" << YAML::Value << ZConfig::instance().systemArchitecture().asString() ;
193  yOut << YAML::Key << "solverTestcase" << YAML::Value << slvTestcaseName ;
194  yOut << YAML::Key << "solverResult" << YAML::Value << slvResult ;
195 
196  // RequestedLocales
197  const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
198  const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
199  const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
200 
201  yOut << YAML::Key << "locales" << YAML::Value << YAML::BeginSeq ;
202  for ( const Locale& l : requestedLocales ) {
203  yOut << YAML::Value << YAML::BeginMap;
204  yOut << YAML::Key << "fate" << YAML::Value << ( addedLocales.count(l) ? "added" : "" ) ;
205  yOut << YAML::Key << "name" << YAML::Value << l.asString() ;
206  yOut << YAML::EndMap;
207  }
208 
209  for ( const Locale& l : removedLocales ) {
210  yOut << YAML::Value << YAML::BeginMap;
211  yOut << YAML::Key << "fate" << YAML::Value << "removed" ;
212  yOut << YAML::Key << "name" << YAML::Value << l.asString() ;
213  yOut << YAML::EndMap;
214  }
215  yOut << YAML::EndSeq; // locales
216 
217  // Vendor settings
218  yOut << YAML::Key << "vendors" << YAML::Value << YAML::BeginSeq ;
219  VendorAttr::instance().foreachVendorList( [&]( const VendorAttr::VendorList& vlist )->bool {
220  if ( ! vlist.empty() ) {
221  yOut << YAML::Value << YAML::BeginSeq;
222  for( const auto & v : vlist )
223  yOut << YAML::Value << v ;
224  yOut << YAML::EndSeq;
225  }
226  return true;
227  } );
228  yOut << YAML::EndSeq; // vendors
229 
230  // helper lambda to write a list of elements into a external file instead of the main file
231  const auto &writeListOrFile = [&]( const std::string &name, const auto &list, const auto &callback ) {
232  if ( list.size() > 10 ) {
233  const std::string fName = str::Format("zypp-%1%.yaml") % name;
234  yOut << YAML::Key << name << YAML::Value << fName;
235 
236  YAML::Emitter yOutFile;
237  callback( yOutFile, list );
238 
239  std::ofstream fout( dumpPath+"/"+fName );
240  fout << yOutFile.c_str();
241  } else {
242  yOut << YAML::Key << name << YAML::Value ;
243  callback( yOut, list );
244  }
245  };
246 
247  // AutoInstalled
248  const auto &writeAutoInst = [] ( YAML::Emitter &out, const auto &autoInstalledList ) {
249  out << YAML::BeginSeq;
250  for ( IdString::IdType n : autoInstalledList ) {
251  out << YAML::Value << IdString(n).asString() ;
252  }
253  out << YAML::EndSeq;
254  };
255  writeListOrFile( "autoinst", satpool.autoInstalled(), writeAutoInst );
256 
257  // ModAlias
258  const auto &writeModalias = []( YAML::Emitter &out, const auto &modAliasList ){
259  out << YAML::BeginSeq;
260  for ( const auto &modAlias : modAliasList ) {
261  out << YAML::Value << modAlias ;
262  }
263  out << YAML::EndSeq;
264  };
265  writeListOrFile( "modalias", target::Modalias::instance().modaliasList(), writeModalias );
266 
267  // Multiversion
268  const auto &writeMultiVersion = [] ( YAML::Emitter &out, const auto &multiversionList ) {
269  out << YAML::BeginSeq;
270  for ( const auto &multiver : multiversionList ) {
271  out << YAML::Value << multiver ;
272  }
273  out << YAML::EndSeq;
274  };
275  writeListOrFile( "multiversion", ZConfig::instance().multiversionSpec(), writeMultiVersion );
276 
277 
278  yOut << YAML::Key << "resolverFlags" << YAML::Value << YAML::BeginMap;
279  yOut << YAML::Key << "focus" << YAML::Value << asString( resolver.focus() );
280 
281  addTag( "ignorealreadyrecommended", resolver.ignoreAlreadyRecommended() );
282  addTag( "onlyRequires", resolver.onlyRequires() );
283  addTag( "forceResolve", resolver.forceResolve() );
284 
285  addTag( "cleandepsOnRemove", resolver.cleandepsOnRemove() );
286 
287  addTag( "allowDowngrade", resolver.allowDowngrade() );
288  addTag( "allowNameChange", resolver.allowNameChange() );
289  addTag( "allowArchChange", resolver.allowArchChange() );
290  addTag( "allowVendorChange", resolver.allowVendorChange() );
291 
292  addTag( "dupAllowDowngrade", resolver.dupAllowDowngrade() );
293  addTag( "dupAllowNameChange", resolver.dupAllowNameChange() );
294  addTag( "dupAllowArchChange", resolver.dupAllowArchChange() );
295  addTag( "dupAllowVendorChange", resolver.dupAllowVendorChange() );
296 
297 
298  yOut << YAML::EndMap; // resolverFlags
299  yOut << YAML::EndMap; // setup
300 
301  yOut << YAML::Key << "trials" << YAML::Value << YAML::BeginSeq;
302 
303  yOut << YAML::Value << YAML::BeginMap << YAML::Key << "trial" << YAML::Value;
304 
305  yOut << YAML::BeginSeq;
306 
307  const auto &writeJobsToFile = [&]( const std::string &fName, const auto &data, const auto &cb ){
308  yOut << YAML::Value << YAML::BeginMap;
309  yOut << YAML::Key << "include" << YAML::Value << fName;
310  yOut << YAML::EndMap;
311 
312  YAML::Emitter yOutFile;
313  yOutFile << YAML::BeginSeq;
314  cb( yOutFile, data );
315  yOutFile << YAML::EndSeq;
316 
317  std::ofstream fout( dumpPath+"/"+fName );
318  fout << yOutFile.c_str();
319  };
320 
321  // Multiversion
322  const auto &writePoolItemJobs = []( const std::string &jobName ){
323  return [ &jobName ] ( YAML::Emitter &yOut, const PoolItemList &poolItems, bool shortInfo = false ) {
324  for ( const PoolItem & pi : poolItems ) {
325  yOut << YAML::Value << YAML::BeginMap;
326 
327  std::stringstream status;
328  status << pi.status();
329 
330  yOut << YAML::Key << "job" << YAML::Value << jobName
331  << YAML::Key << "kind" << YAML::Value << pi.kind().asString()
332  << YAML::Key << "name" << YAML::Value << pi.name()
333  << YAML::Key << "status" << YAML::Value << status.str();
334  if ( !shortInfo ) {
335  yOut << YAML::Key << "channel" << YAML::Value << pi.repoInfo().alias()
336  << YAML::Key << "arch" << YAML::Value << pi.arch().asString()
337  << YAML::Key << "version" << YAML::Value << pi.edition().version()
338  << YAML::Key << "release" << YAML::Value << pi.edition().release();
339  }
340  yOut << YAML::EndMap;
341  }
342  };
343  };
344 
345  const auto &writeMapJob = []( YAML::Emitter &yOut, const std::string &name, const std::map<std::string, std::string> &values = std::map<std::string, std::string>() ){
346  yOut << YAML::Value << YAML::BeginMap;
347  yOut << YAML::Key << "job" << YAML::Value << name;
348  for ( const auto &v : values )
349  yOut << YAML::Key << v.first << YAML::Value << v.second;
350  yOut << YAML::EndMap;
351  };
352 
353  writePoolItemJobs("install")( yOut, items_to_install );
354  writePoolItemJobs("keep")( yOut, items_keep );
355  writePoolItemJobs("uninstall")( yOut, items_to_remove, true );
356 
357  if ( items_locked.size() )
358  writeJobsToFile("zypp-locks.yaml", items_locked, writePoolItemJobs("lock") );
359 
360  for ( const auto &v : resolver.extraRequires() )
361  writeMapJob( yOut, "addRequire", { { "name", v.asString() } } );
362  for ( const auto &v : SystemCheck::instance().requiredSystemCap() )
363  writeMapJob( yOut, "addRequire", { { "name", v.asString() } } );
364 
365  for ( const auto &v : resolver.extraConflicts() )
366  writeMapJob( yOut, "addConflict", { { "name", v.asString() } } );
367  for ( const auto &v : SystemCheck::instance().conflictSystemCap() )
368  writeMapJob( yOut, "addConflict", { { "name", v.asString() } } );
369 
370  for ( const auto &v : resolver.upgradeRepos() )
371  writeMapJob( yOut, "upgradeRepo", { { "name", v.alias() } } );
372 
373  if ( resolver.isUpgradeMode() )
374  writeMapJob( yOut, "distupgrade" );
375 
376  if ( resolver.isUpdateMode() )
377  writeMapJob( yOut, "update" );
378 
379  if ( resolver.isVerifyingMode() )
380  writeMapJob( yOut, "verify" );
381 
382  yOut << YAML::EndSeq;
383  yOut << YAML::EndMap; // trial
384  yOut << YAML::EndSeq; // trials list
385  yOut << YAML::EndMap; // trials
386  yOut << YAML::EndMap; // root
387 
388  std::ofstream fout( dumpPath+"/zypp-control.yaml" );
389  fout << yOut.c_str();
390 
391  MIL << "createTestcase done at " << dumpPath << endl;
392  return true;
393  }
395  };// namespace detail
398  };// namespace solver
401 };// namespace zypp
#define MIL
Definition: Logger.h:100
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:324
int clean_dir(const Pathname &path)
Like &#39;rm -r DIR/ *&#39;.
Definition: PathInfo.cc:447
std::unordered_set< Locale > LocaleSet
Definition: Locale.h:29
Definition: Arch.h:363
int IdType
Generic Id type.
Definition: PoolMember.h:104
Exchange LineWriter for the lifetime of this object.
Definition: LogControl.h:190
#define ERR
Definition: Logger.h:102
void logfile(const Pathname &logfile_r)
Set path for the logfile.
Definition: LogControl.cc:862
static LogControl instance()
Singleton access.
Definition: LogControl.h:102
_dumpPath dumpPath(const Pathname &root_r, const Pathname &sub_r)
dumpPath iomaip to dump &#39;(root_r)sub_r&#39; output,
Definition: librpmDb.h:42
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
Definition: Bit.h:57
#define WAR
Definition: Logger.h:101
Turn on excessive logging for the lifetime of this object.
Definition: LogControl.h:181
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:94
std::string asString() const
Conversion to std::string
Definition: IdString.h:99
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
zypp::IdString IdString
Definition: idstring.h:16