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