16 #include <boost/iterator/function_output_iterator.hpp> 18 #define ZYPP_USE_RESOLVER_INTERNALS 24 #include <zypp-core/base/GzStream> 42 #include <yaml-cpp/yaml.h> 45 #include <solv/testcase.h> 63 :dumpPath(
"/var/log/YaST2/solverTestcase")
66 Testcase::Testcase(std::string path)
67 :dumpPath(
std::move(path))
73 bool Testcase::createTestcase(Resolver & resolver,
bool dumpPool,
bool runSolver)
76 if ( not resolver.get() ) {
77 WAR <<
"Can't createTestcase if the satsolver is not yet initialized." << endl;
81 MIL <<
"createTestcase at " << dumpPath << (dumpPool?
" dumpPool":
"") << (runSolver?
" runSolver":
"") << endl;
82 PathInfo path (dumpPath);
84 if ( !path.isExist() ) {
86 ERR <<
"Cannot create directory " << dumpPath << endl;
91 ERR << dumpPath <<
" is not a directory." << endl;
104 resolver.resolvePool();
107 ResPool pool = resolver.pool();
108 PoolItemList items_to_install;
109 PoolItemList items_to_remove;
110 PoolItemList items_locked;
111 PoolItemList items_keep;
114 const std::string slvTestcaseName =
"testcase.t";
115 const std::string slvResult =
"solver.result";
118 [ nrepos = resolver.get()->pool->nrepos ](
auto **x ){
120 for (
int i = 1; i < nrepos; i++ )
121 solv_free((
void *)x[i]);
122 solv_free((
void *)x);
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;
131 const sat::Pool & satpool( sat::Pool::instance() );
135 const auto addTag = [&](
const std::string & tag_r,
bool yesno_r = true ){
136 yOut << YAML::Key << tag_r << YAML::Value << yesno_r;
139 yOut << YAML::BeginMap << YAML::Key <<
"version" << YAML::Value <<
"1.0";
141 yOut << YAML::Key <<
"setup" << YAML::Value << YAML::BeginMap;
143 yOut << YAML::Key <<
"channels";
144 yOut << YAML::Value << YAML::BeginSeq;
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 );
152 if ( pi.status().isKept()
153 && !(pi.status().isBySolver())) {
154 items_keep.push_back( pi );
156 if ( pi.status().isToBeUninstalled()
157 && !(pi.status().isBySolver())) {
158 items_to_remove.push_back( pi );
160 if ( pi.status().isLocked()
161 && !(pi.status().isBySolver())) {
162 items_locked.push_back( pi );
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();
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];
183 yOut << YAML::EndMap;
188 yOut << YAML::EndSeq;
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 ;
195 const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
196 const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
197 const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
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;
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;
213 yOut << YAML::EndSeq;
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;
226 yOut << YAML::EndSeq;
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;
234 YAML::Emitter yOutFile;
235 callback( yOutFile, list );
237 std::ofstream fout( dumpPath+
"/"+fName );
238 fout << yOutFile.c_str();
240 yOut << YAML::Key << name << YAML::Value ;
241 callback( yOut, list );
246 const auto &writeAutoInst = [] ( YAML::Emitter &out,
const auto &autoInstalledList ) {
247 out << YAML::BeginSeq;
249 out << YAML::Value << IdString(n).asString() ;
253 writeListOrFile(
"autoinst", satpool.autoInstalled(), writeAutoInst );
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 ;
263 writeListOrFile(
"modalias", target::Modalias::instance().modaliasList(), writeModalias );
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 ;
273 writeListOrFile(
"multiversion", ZConfig::instance().multiversionSpec(), writeMultiVersion );
276 yOut << YAML::Key <<
"resolverFlags" << YAML::Value << YAML::BeginMap;
277 yOut << YAML::Key <<
"focus" << YAML::Value <<
asString( resolver.focus() );
279 addTag(
"ignorealreadyrecommended", resolver.ignoreAlreadyRecommended() );
280 addTag(
"onlyRequires", resolver.onlyRequires() );
281 addTag(
"forceResolve", resolver.forceResolve() );
283 addTag(
"cleandepsOnRemove", resolver.cleandepsOnRemove() );
285 addTag(
"allowDowngrade", resolver.allowDowngrade() );
286 addTag(
"allowNameChange", resolver.allowNameChange() );
287 addTag(
"allowArchChange", resolver.allowArchChange() );
288 addTag(
"allowVendorChange", resolver.allowVendorChange() );
290 addTag(
"dupAllowDowngrade", resolver.dupAllowDowngrade() );
291 addTag(
"dupAllowNameChange", resolver.dupAllowNameChange() );
292 addTag(
"dupAllowArchChange", resolver.dupAllowArchChange() );
293 addTag(
"dupAllowVendorChange", resolver.dupAllowVendorChange() );
296 yOut << YAML::EndMap;
297 yOut << YAML::EndMap;
299 yOut << YAML::Key <<
"trials" << YAML::Value << YAML::BeginSeq;
301 yOut << YAML::Value << YAML::BeginMap << YAML::Key <<
"trial" << YAML::Value;
303 yOut << YAML::BeginSeq;
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;
310 YAML::Emitter yOutFile;
311 yOutFile << YAML::BeginSeq;
312 cb( yOutFile, data );
313 yOutFile << YAML::EndSeq;
315 std::ofstream fout( dumpPath+
"/"+fName );
316 fout << yOutFile.c_str();
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;
325 std::stringstream status;
326 status << pi.status();
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();
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();
338 yOut << YAML::EndMap;
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;
351 writePoolItemJobs(
"install")( yOut, items_to_install );
352 writePoolItemJobs(
"keep")( yOut, items_keep );
353 writePoolItemJobs(
"uninstall")( yOut, items_to_remove, true );
355 if ( items_locked.size() )
356 writeJobsToFile(
"zypp-locks.yaml", items_locked, writePoolItemJobs(
"lock") );
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() } } );
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() } } );
368 for (
const auto &v : resolver.upgradeRepos() )
369 writeMapJob( yOut,
"upgradeRepo", { {
"name", v.alias() } } );
371 if ( resolver.isUpgradeMode() )
372 writeMapJob( yOut,
"distupgrade" );
374 if ( resolver.isUpdateMode() )
375 writeMapJob( yOut,
"update" );
377 if ( resolver.isVerifyingMode() )
378 writeMapJob( yOut,
"verify" );
380 yOut << YAML::EndSeq;
381 yOut << YAML::EndMap;
382 yOut << YAML::EndSeq;
383 yOut << YAML::EndMap;
384 yOut << YAML::EndMap;
386 std::ofstream fout( dumpPath+
"/zypp-control.yaml" );
387 fout << yOut.c_str();
389 MIL <<
"createTestcase done at " << dumpPath << endl;
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
std::unordered_set< Locale > LocaleSet
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
int IdType
Generic Id type.
Exchange LineWriter for the lifetime of this object.
void logfile(const Pathname &logfile_r)
Set path for the logfile.
static LogControl instance()
Singleton access.
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
Turn on excessive logging for the lifetime of this object.
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Easy-to use interface to the ZYPP dependency resolver.