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