libzypp: zypp/solver/detail/Testcase.cc Source File

libzypp 17.36.6

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
20#include <zypp/solver/detail/Testcase.h>
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>
28#include <zypp/base/ReferenceCounted.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>
36#include <zypp/target/modalias/Modalias.h>
37
38#include <zypp/sat/detail/PoolImpl.h>
39#include <zypp/solver/detail/Resolver.h>
40#include <zypp/solver/detail/SystemCheck.h>
41
42#include <yaml-cpp/yaml.h>
43
44extern "C" {
45#include <solv/testcase.h>
46}
47
48using std::endl;
49
51namespace zypp
52{
54 namespace solver
55 {
57 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() ) {
85 if (zypp::filesystem::assert_dir (dumpPath)!=0) {
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)
96 zypp::filesystem::clean_dir (dumpPath);
97 }
98
99 if (runSolver) {
100 zypp::base::LogControl::TmpLineWriter tempRedirect;
101 zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
102 zypp::base::LogControl::TmpExcessive excessive;
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 ( auto itUrl = myRepoInfo.baseUrlsBegin(); itUrl != myRepoInfo.baseUrlsEnd(); ++itUrl ) {
173 yOut << YAML::Value << itUrl->asString();
174 }
175 yOut << YAML::EndSeq;
176 yOut << YAML::Key << "path" << YAML::Value << myRepoInfo.path().asString();
177 yOut << YAML::Key << "type" << YAML::Value << myRepoInfo.type().asString();
178 yOut << YAML::Key << "generated" << YAML::Value << myRepo.generatedTimestamp().form( "%Y-%m-%d %H:%M:%S" );
179 yOut << YAML::Key << "outdated" << YAML::Value << myRepo.suggestedExpirationTimestamp().form( "%Y-%m-%d %H:%M:%S" );
180 yOut << YAML::Key << "priority" << YAML::Value << myRepoInfo.priority();
181 yOut << YAML::Key << "file" << YAML::Value << str::Format("%1%.repo.gz") % repoFileNames[myRepo.id()->repoid];
182
183 yOut << YAML::EndMap;
184 }
185
186 }
187
188 yOut << YAML::EndSeq;
189
190 yOut << YAML::Key << "arch" << YAML::Value << ZConfig::instance().systemArchitecture().asString() ;
191 yOut << YAML::Key << "solverTestcase" << YAML::Value << slvTestcaseName ;
192 yOut << YAML::Key << "solverResult" << YAML::Value << slvResult ;
193
194 // RequestedLocales
195 const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
196 const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
197 const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
198
199 yOut << YAML::Key << "locales" << YAML::Value << YAML::BeginSeq ;
200 for ( const Locale& l : requestedLocales ) {
201 yOut << YAML::Value << YAML::BeginMap;
202 yOut << YAML::Key << "fate" << YAML::Value << ( addedLocales.count(l) ? "added" : "" ) ;
203 yOut << YAML::Key << "name" << YAML::Value << l.asString() ;
204 yOut << YAML::EndMap;
205 }
206
207 for ( const Locale& l : removedLocales ) {
208 yOut << YAML::Value << YAML::BeginMap;
209 yOut << YAML::Key << "fate" << YAML::Value << "removed" ;
210 yOut << YAML::Key << "name" << YAML::Value << l.asString() ;
211 yOut << YAML::EndMap;
212 }
213 yOut << YAML::EndSeq; // locales
214
215 // Vendor settings
216 yOut << YAML::Key << "vendors" << YAML::Value << YAML::BeginSeq ;
217 VendorAttr::instance().foreachVendorList( [&]( const VendorAttr::VendorList& vlist )->bool {
218 if ( ! vlist.empty() ) {
219 yOut << YAML::Value << YAML::BeginSeq;
220 for( const auto & v : vlist )
221 yOut << YAML::Value << v ;
222 yOut << YAML::EndSeq;
223 }
224 return true;
225 } );
226 yOut << YAML::EndSeq; // vendors
227
228 // helper lambda to write a list of elements into a external file instead of the main file
229 const auto &writeListOrFile = [&]( const std::string &name, const auto &list, const auto &callback ) {
230 if ( list.size() > 10 ) {
231 const std::string fName = str::Format("zypp-%1%.yaml") % name;
232 yOut << YAML::Key << name << YAML::Value << fName;
233
234 YAML::Emitter yOutFile;
235 callback( yOutFile, list );
236
237 std::ofstream fout( dumpPath+"/"+fName );
238 fout << yOutFile.c_str();
239 } else {
240 yOut << YAML::Key << name << YAML::Value ;
241 callback( yOut, list );
242 }
243 };
244
245 // AutoInstalled
246 const auto &writeAutoInst = [] ( YAML::Emitter &out, const auto &autoInstalledList ) {
247 out << YAML::BeginSeq;
248 for ( IdString::IdType n : autoInstalledList ) {
249 out << YAML::Value << IdString(n).asString() ;
250 }
251 out << YAML::EndSeq;
252 };
253 writeListOrFile( "autoinst", satpool.autoInstalled(), writeAutoInst );
254
255 // ModAlias
256 const auto &writeModalias = []( YAML::Emitter &out, const auto &modAliasList ){
257 out << YAML::BeginSeq;
258 for ( const auto &modAlias : modAliasList ) {
259 out << YAML::Value << modAlias ;
260 }
261 out << YAML::EndSeq;
262 };
263 writeListOrFile( "modalias", target::Modalias::instance().modaliasList(), writeModalias );
264
265 // Multiversion
266 const auto &writeMultiVersion = [] ( YAML::Emitter &out, const auto &multiversionList ) {
267 out << YAML::BeginSeq;
268 for ( const auto &multiver : multiversionList ) {
269 out << YAML::Value << multiver ;
270 }
271 out << YAML::EndSeq;
272 };
273 writeListOrFile( "multiversion", ZConfig::instance().multiversionSpec(), writeMultiVersion );
274
275
276 yOut << YAML::Key << "resolverFlags" << YAML::Value << YAML::BeginMap;
277 yOut << YAML::Key << "focus" << YAML::Value << asString( resolver.focus() );
278
279 addTag( "ignorealreadyrecommended", resolver.ignoreAlreadyRecommended() );
280 addTag( "onlyRequires", resolver.onlyRequires() );
281 addTag( "forceResolve", resolver.forceResolve() );
282
283 addTag( "cleandepsOnRemove", resolver.cleandepsOnRemove() );
284
285 addTag( "allowDowngrade", resolver.allowDowngrade() );
286 addTag( "allowNameChange", resolver.allowNameChange() );
287 addTag( "allowArchChange", resolver.allowArchChange() );
288 addTag( "allowVendorChange", resolver.allowVendorChange() );
289
290 addTag( "dupAllowDowngrade", resolver.dupAllowDowngrade() );
291 addTag( "dupAllowNameChange", resolver.dupAllowNameChange() );
292 addTag( "dupAllowArchChange", resolver.dupAllowArchChange() );
293 addTag( "dupAllowVendorChange", resolver.dupAllowVendorChange() );
294
295
296 yOut << YAML::EndMap; // resolverFlags
297 yOut << YAML::EndMap; // setup
298
299 yOut << YAML::Key << "trials" << YAML::Value << YAML::BeginSeq;
300
301 yOut << YAML::Value << YAML::BeginMap << YAML::Key << "trial" << YAML::Value;
302
303 yOut << YAML::BeginSeq;
304
305 const auto &writeJobsToFile = [&]( const std::string &fName, const auto &data, const auto &cb ){
306 yOut << YAML::Value << YAML::BeginMap;
307 yOut << YAML::Key << "include" << YAML::Value << fName;
308 yOut << YAML::EndMap;
309
310 YAML::Emitter yOutFile;
311 yOutFile << YAML::BeginSeq;
312 cb( yOutFile, data );
313 yOutFile << YAML::EndSeq;
314
315 std::ofstream fout( dumpPath+"/"+fName );
316 fout << yOutFile.c_str();
317 };
318
319 // Multiversion
320 const auto &writePoolItemJobs = []( const std::string &jobName ){
321 return [ &jobName ] ( YAML::Emitter &yOut, const PoolItemList &poolItems, bool shortInfo = false ) {
322 for ( const PoolItem & pi : poolItems ) {
323 yOut << YAML::Value << YAML::BeginMap;
324
325 std::stringstream status;
326 status << pi.status();
327
328 yOut << YAML::Key << "job" << YAML::Value << jobName
329 << YAML::Key << "kind" << YAML::Value << pi.kind().asString()
330 << YAML::Key << "name" << YAML::Value << pi.name()
331 << YAML::Key << "status" << YAML::Value << status.str();
332 if ( !shortInfo ) {
333 yOut << YAML::Key << "channel" << YAML::Value << pi.repoInfo().alias()
334 << YAML::Key << "arch" << YAML::Value << pi.arch().asString()
335 << YAML::Key << "version" << YAML::Value << pi.edition().version()
336 << YAML::Key << "release" << YAML::Value << pi.edition().release();
337 }
338 yOut << YAML::EndMap;
339 }
340 };
341 };
342
343 const auto &writeMapJob = []( YAML::Emitter &yOut, const std::string &name, const std::map<std::string, std::string> &values = std::map<std::string, std::string>() ){
344 yOut << YAML::Value << YAML::BeginMap;
345 yOut << YAML::Key << "job" << YAML::Value << name;
346 for ( const auto &v : values )
347 yOut << YAML::Key << v.first << YAML::Value << v.second;
348 yOut << YAML::EndMap;
349 };
350
351 writePoolItemJobs("install")( yOut, items_to_install );
352 writePoolItemJobs("keep")( yOut, items_keep );
353 writePoolItemJobs("uninstall")( yOut, items_to_remove, true );
354
355 if ( items_locked.size() )
356 writeJobsToFile("zypp-locks.yaml", items_locked, writePoolItemJobs("lock") );
357
358 for ( const auto &v : resolver.extraRequires() )
359 writeMapJob( yOut, "addRequire", { { "name", v.asString() } } );
360 for ( const auto &v : SystemCheck::instance().requiredSystemCap() )
361 writeMapJob( yOut, "addRequire", { { "name", v.asString() } } );
362
363 for ( const auto &v : resolver.extraConflicts() )
364 writeMapJob( yOut, "addConflict", { { "name", v.asString() } } );
365 for ( const auto &v : SystemCheck::instance().conflictSystemCap() )
366 writeMapJob( yOut, "addConflict", { { "name", v.asString() } } );
367
368 for ( const auto &v : resolver.upgradeRepos() )
369 writeMapJob( yOut, "upgradeRepo", { { "name", v.alias() } } );
370
371 if ( resolver.isUpgradeMode() )
372 writeMapJob( yOut, "distupgrade" );
373
374 if ( resolver.isUpdateMode() )
375 writeMapJob( yOut, "update" );
376
377 if ( resolver.isVerifyingMode() )
378 writeMapJob( yOut, "verify" );
379
380 yOut << YAML::EndSeq;
381 yOut << YAML::EndMap; // trial
382 yOut << YAML::EndSeq; // trials list
383 yOut << YAML::EndMap; // trials
384 yOut << YAML::EndMap; // root
385
386 std::ofstream fout( dumpPath+"/zypp-control.yaml" );
387 fout << yOut.c_str();
388
389 MIL << "createTestcase done at " << dumpPath << endl;
390 return true;
391 }
393 };// namespace detail
396 };// namespace solver
399};// namespace zypp
Modalias.h
Repository.h
ResPool.h
SystemCheck.h
Testcase.h
VendorAttr.h
ZConfig.h
LocaleSet
zypp::AutoDispose
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
zypp::IdString::asString
std::string asString() const
Conversion to std::string
Definition IdString.h:99
zypp::base::LogControl::instance
static LogControl instance()
Singleton access.
Definition LogControl.h:102
zypp::base::LogControl::logfile
void logfile(const Pathname &logfile_r)
Set path for the logfile.
Definition LogControl.cc:862
std
Definition Arch.h:364
zypp::bit::asString
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
Definition Bit.h:57
zypp::filesystem::clean_dir
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
Definition PathInfo.cc:447
zypp::filesystem::assert_dir
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:324
zypp::solver::detail
Definition PoolImpl.h:110
zypp::solver
Definition PoolImpl.h:109
zypp::target::rpm::dumpPath
_dumpPath dumpPath(const Pathname &root_r, const Pathname &sub_r)
dumpPath iomaip to dump '(root_r)sub_r' output,
Definition librpmDb.h:42
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition Application.cc:20
zyppng::IdString
zypp::IdString IdString
Definition idstring.h:16
PoolImpl.h
Resolver.h
zypp::base::LogControl::TmpExcessive
Turn on excessive logging for the lifetime of this object.
Definition LogControl.h:182
zypp::base::LogControl::TmpLineWriter
Exchange LineWriter for the lifetime of this object.
Definition LogControl.h:191
MIL
#define MIL
Definition Logger.h:100
ERR
#define ERR
Definition Logger.h:102
WAR
#define WAR
Definition Logger.h:101
AutoDispose.h
PathInfo.h
LogControl.h
Logger.h
NonCopyable.h
PtrTypes.h
ReferenceCounted.h
String.h