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)
 
   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;
 
  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;
 
  248          for ( IdString::IdType n : autoInstalledList ) {
 
  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;
 
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
std::string asString() const
Conversion to std::string
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 clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
_dumpPath dumpPath(const Pathname &root_r, const Pathname &sub_r)
dumpPath iomaip to dump '(root_r)sub_r' output,
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.