16#include <boost/iterator/function_output_iterator.hpp>
18#define ZYPP_USE_RESOLVER_INTERNALS
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>
29#include <zypp/AutoDispose.h>
31#include <zypp/PathInfo.h>
37#include <zypp/sat/detail/PoolImpl.h>
38#include <zypp/solver/detail/Resolver.h>
41#include <yaml-cpp/yaml.h>
44#include <solv/testcase.h>
62 :dumpPath(
"/var/log/YaST2/solverTestcase")
65 Testcase::Testcase(
const std::string & path)
72 bool Testcase::createTestcase(Resolver & resolver,
bool dumpPool,
bool runSolver)
75 if ( not resolver.get() ) {
76 WAR <<
"Can't createTestcase if the satsolver is not yet initialized." << endl;
80 MIL <<
"createTestcase at " << dumpPath << (dumpPool?
" dumpPool":
"") << (runSolver?
" runSolver":
"") << endl;
81 PathInfo path (dumpPath);
83 if ( !path.isExist() ) {
85 ERR <<
"Cannot create directory " << dumpPath << endl;
90 ERR << dumpPath <<
" is not a directory." << endl;
103 resolver.resolvePool();
106 ResPool pool = resolver.pool();
107 PoolItemList items_to_install;
108 PoolItemList items_to_remove;
109 PoolItemList items_locked;
110 PoolItemList items_keep;
113 const std::string slvTestcaseName =
"testcase.t";
114 const std::string slvResult =
"solver.result";
117 [ nrepos = resolver.get()->pool->nrepos ](
auto **x ){
119 for ( int i = 1; i < nrepos; i++ )
120 solv_free((void *)x[i]);
121 solv_free((void *)x);
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;
130 const sat::Pool & satpool( sat::Pool::instance() );
134 const auto addTag = [&](
const std::string & tag_r,
bool yesno_r = true ){
135 yOut << YAML::Key << tag_r << YAML::Value << yesno_r;
138 yOut << YAML::BeginMap << YAML::Key <<
"version" << YAML::Value <<
"1.0";
140 yOut << YAML::Key <<
"setup" << YAML::Value << YAML::BeginMap;
142 yOut << YAML::Key <<
"channels";
143 yOut << YAML::Value << YAML::BeginSeq;
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 );
151 if ( pi.status().isKept()
152 && !(pi.status().isBySolver())) {
153 items_keep.push_back( pi );
155 if ( pi.status().isToBeUninstalled()
156 && !(pi.status().isBySolver())) {
157 items_to_remove.push_back( pi );
159 if ( pi.status().isLocked()
160 && !(pi.status().isBySolver())) {
161 items_locked.push_back( pi );
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();
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];
182 yOut << YAML::EndMap;
187 yOut << YAML::EndSeq;
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 ;
194 const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
195 const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
196 const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
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;
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;
212 yOut << YAML::EndSeq;
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;
225 yOut << YAML::EndSeq;
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;
233 YAML::Emitter yOutFile;
234 callback( yOutFile, list );
236 std::ofstream fout( dumpPath+
"/"+fName );
237 fout << yOutFile.c_str();
239 yOut << YAML::Key << name << YAML::Value ;
240 callback( yOut, list );
245 const auto &writeAutoInst = [] ( YAML::Emitter &out,
const auto &autoInstalledList ) {
246 out << YAML::BeginSeq;
248 out << YAML::Value << IdString(n).asString() ;
252 writeListOrFile(
"autoinst", satpool.autoInstalled(), writeAutoInst );
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 ;
262 writeListOrFile(
"modalias", target::Modalias::instance().modaliasList(), writeModalias );
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 ;
272 writeListOrFile(
"multiversion", ZConfig::instance().multiversionSpec(), writeMultiVersion );
275 yOut << YAML::Key <<
"resolverFlags" << YAML::Value << YAML::BeginMap;
276 yOut << YAML::Key <<
"focus" << YAML::Value <<
asString( resolver.focus() );
278 addTag(
"ignorealreadyrecommended", resolver.ignoreAlreadyRecommended() );
279 addTag(
"onlyRequires", resolver.onlyRequires() );
280 addTag(
"forceResolve", resolver.forceResolve() );
282 addTag(
"cleandepsOnRemove", resolver.cleandepsOnRemove() );
284 addTag(
"allowDowngrade", resolver.allowDowngrade() );
285 addTag(
"allowNameChange", resolver.allowNameChange() );
286 addTag(
"allowArchChange", resolver.allowArchChange() );
287 addTag(
"allowVendorChange", resolver.allowVendorChange() );
289 addTag(
"dupAllowDowngrade", resolver.dupAllowDowngrade() );
290 addTag(
"dupAllowNameChange", resolver.dupAllowNameChange() );
291 addTag(
"dupAllowArchChange", resolver.dupAllowArchChange() );
292 addTag(
"dupAllowVendorChange", resolver.dupAllowVendorChange() );
295 yOut << YAML::EndMap;
296 yOut << YAML::EndMap;
298 yOut << YAML::Key <<
"trials" << YAML::Value << YAML::BeginSeq;
300 yOut << YAML::Value << YAML::BeginMap << YAML::Key <<
"trial" << YAML::Value;
302 yOut << YAML::BeginSeq;
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;
309 YAML::Emitter yOutFile;
310 yOutFile << YAML::BeginSeq;
311 cb( yOutFile, data );
312 yOutFile << YAML::EndSeq;
314 std::ofstream fout( dumpPath+
"/"+fName );
315 fout << yOutFile.c_str();
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;
324 std::stringstream status;
325 status << pi.status();
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();
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();
337 yOut << YAML::EndMap;
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;
350 writePoolItemJobs(
"install")( yOut, items_to_install );
351 writePoolItemJobs(
"keep")( yOut, items_keep );
352 writePoolItemJobs(
"uninstall")( yOut, items_to_remove, true );
354 if ( items_locked.size() )
355 writeJobsToFile(
"zypp-locks.yaml", items_locked, writePoolItemJobs(
"lock") );
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() } } );
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() } } );
367 for (
const auto &v : resolver.upgradeRepos() )
368 writeMapJob( yOut,
"upgradeRepo", { {
"name", v.alias() } } );
370 if ( resolver.isUpgradeMode() )
371 writeMapJob( yOut,
"distupgrade" );
373 if ( resolver.isUpdateMode() )
374 writeMapJob( yOut,
"update" );
376 if ( resolver.isVerifyingMode() )
377 writeMapJob( yOut,
"verify" );
379 yOut << YAML::EndSeq;
380 yOut << YAML::EndMap;
381 yOut << YAML::EndSeq;
382 yOut << YAML::EndMap;
383 yOut << YAML::EndMap;
385 std::ofstream fout( dumpPath+
"/zypp-control.yaml" );
386 fout << yOut.c_str();
388 MIL <<
"createTestcase done at " << dumpPath << endl;
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
static LogControl instance()
Singleton access.
void logfile(const Pathname &logfile_r)
Set path for the logfile.
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
int IdType
Generic Id type.
Easy-to use interface to the ZYPP dependency resolver.
Turn on excessive logging for the lifetime of this object.
Exchange LineWriter for the lifetime of this object.