libzypp 17.25.7
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>
23#include <zypp/base/GzStream.h>
24#include <zypp/base/String.h>
25#include <zypp/base/PtrTypes.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
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 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)
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
#define MIL
Definition: Logger.h:79
#define ERR
Definition: Logger.h:81
RepoInfoList repos
Definition: RepoManager.cc:277
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
static LogControl instance()
Singleton access.
Definition: LogControl.h:102
void logfile(const Pathname &logfile_r)
Set path for the logfile.
Definition: LogControl.cc:464
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:320
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
Definition: PathInfo.cc:443
int IdType
Generic Id type.
Definition: PoolMember.h:104
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
std::string asString(const DefaultIntegral< Tp, TInitial > &obj)
Turn on excessive logging for the lifetime of this object.
Definition: LogControl.h:162
Exchange LineWriter for the lifetime of this object.
Definition: LogControl.h:171