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 ( 
const auto &origin : myRepoInfo.repoOrigins () ) {
 
  173              for ( 
const auto &originEndpoint : origin ) {
 
  174                yOut << YAML::Value << originEndpoint.url().asString();
 
  177            yOut << YAML::EndSeq;
 
  178            yOut << YAML::Key << 
"path" << YAML::Value << myRepoInfo.path().asString();
 
  179            yOut << YAML::Key << 
"type" << YAML::Value << myRepoInfo.type().asString();
 
  180            yOut << YAML::Key << 
"generated" << YAML::Value << myRepo.generatedTimestamp().form( 
"%Y-%m-%d %H:%M:%S" );
 
  181            yOut << YAML::Key << 
"outdated" << YAML::Value << myRepo.suggestedExpirationTimestamp().form( 
"%Y-%m-%d %H:%M:%S" );
 
  182            yOut << YAML::Key << 
"priority" << YAML::Value << myRepoInfo.priority();
 
  183            yOut << YAML::Key << 
"file" << YAML::Value << str::Format(
"%1%.repo.gz") % repoFileNames[myRepo.id()->repoid];
 
  185            yOut << YAML::EndMap;
 
  190        yOut << YAML::EndSeq;
 
  192        yOut << YAML::Key << 
"arch" << YAML::Value << ZConfig::instance().systemArchitecture().asString() ;
 
  193        yOut << YAML::Key << 
"solverTestcase" << YAML::Value << slvTestcaseName ;
 
  194        yOut << YAML::Key << 
"solverResult" << YAML::Value << slvResult ;
 
  197        const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
 
  198        const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
 
  199        const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
 
  201        yOut << YAML::Key << 
"locales" << YAML::Value << YAML::BeginSeq ;
 
  202        for ( 
const Locale& l : requestedLocales ) {
 
  203          yOut << YAML::Value << YAML::BeginMap;
 
  204          yOut << YAML::Key << 
"fate" << YAML::Value << ( addedLocales.count(l) ? 
"added" : 
"" ) ;
 
  205          yOut << YAML::Key << 
"name" << YAML::Value << l.asString() ;
 
  206          yOut << YAML::EndMap;
 
  209        for ( 
const Locale& l : removedLocales ) {
 
  210          yOut << YAML::Value << YAML::BeginMap;
 
  211          yOut << YAML::Key << 
"fate" << YAML::Value << 
"removed" ;
 
  212          yOut << YAML::Key << 
"name" << YAML::Value << l.asString() ;
 
  213          yOut << YAML::EndMap;
 
  215        yOut << YAML::EndSeq; 
 
  218        yOut << YAML::Key << 
"vendors" << YAML::Value << YAML::BeginSeq ;
 
  219        VendorAttr::instance().foreachVendorList( [&]( 
const VendorAttr::VendorList& vlist )->
bool {
 
  220          if ( ! vlist.empty() ) {
 
  221            yOut << YAML::Value << YAML::BeginSeq;
 
  222            for( 
const auto & v : vlist )
 
  223              yOut << YAML::Value << v ;
 
  224            yOut << YAML::EndSeq;
 
  228        yOut << YAML::EndSeq; 
 
  231        const auto &writeListOrFile = [&]( 
const std::string &name, 
const auto &list, 
const auto &callback ) {
 
  232          if ( list.size() > 10 ) {
 
  233            const std::string fName = str::Format(
"zypp-%1%.yaml") % name;
 
  234            yOut << YAML::Key << name << YAML::Value << fName;
 
  236            YAML::Emitter yOutFile;
 
  237            callback( yOutFile, list );
 
  239            std::ofstream fout( dumpPath+
"/"+fName );
 
  240            fout << yOutFile.c_str();
 
  242            yOut << YAML::Key << name << YAML::Value ;
 
  243            callback( yOut, list );
 
  248        const auto &writeAutoInst = [] ( YAML::Emitter &out, 
const auto &autoInstalledList ) {
 
  249          out << YAML::BeginSeq;
 
  250          for ( IdString::IdType n : autoInstalledList ) {
 
  255        writeListOrFile( 
"autoinst", satpool.autoInstalled(), writeAutoInst );
 
  258        const auto &writeModalias = []( YAML::Emitter &out, 
const auto &modAliasList ){
 
  259          out << YAML::BeginSeq;
 
  260          for ( 
const auto &modAlias : modAliasList ) {
 
  261            out << YAML::Value << modAlias ;
 
  265        writeListOrFile( 
"modalias", target::Modalias::instance().modaliasList(), writeModalias );
 
  268        const auto &writeMultiVersion = [] ( YAML::Emitter &out, 
const auto &multiversionList ) {
 
  269          out << YAML::BeginSeq;
 
  270          for ( 
const auto &multiver : multiversionList ) {
 
  271            out << YAML::Value << multiver ;
 
  275        writeListOrFile( 
"multiversion", ZConfig::instance().multiversionSpec(), writeMultiVersion );
 
  278        yOut << YAML::Key << 
"resolverFlags" << YAML::Value << YAML::BeginMap;
 
  279        yOut << YAML::Key << 
"focus" << YAML::Value << 
asString( resolver.focus() );
 
  281        addTag( 
"ignorealreadyrecommended", resolver.ignoreAlreadyRecommended() );
 
  282        addTag( 
"onlyRequires",             resolver.onlyRequires() );
 
  283        addTag( 
"forceResolve",             resolver.forceResolve() );
 
  285        addTag( 
"cleandepsOnRemove",        resolver.cleandepsOnRemove() );
 
  287        addTag( 
"allowDowngrade",           resolver.allowDowngrade() );
 
  288        addTag( 
"allowNameChange",          resolver.allowNameChange() );
 
  289        addTag( 
"allowArchChange",          resolver.allowArchChange() );
 
  290        addTag( 
"allowVendorChange",        resolver.allowVendorChange() );
 
  292        addTag( 
"dupAllowDowngrade",        resolver.dupAllowDowngrade() );
 
  293        addTag( 
"dupAllowNameChange",       resolver.dupAllowNameChange() );
 
  294        addTag( 
"dupAllowArchChange",       resolver.dupAllowArchChange() );
 
  295        addTag( 
"dupAllowVendorChange",     resolver.dupAllowVendorChange() );
 
  298        yOut << YAML::EndMap; 
 
  299        yOut << YAML::EndMap; 
 
  301        yOut << YAML::Key << 
"trials" << YAML::Value << YAML::BeginSeq;
 
  303        yOut << YAML::Value << YAML::BeginMap << YAML::Key << 
"trial" << YAML::Value;
 
  305        yOut << YAML::BeginSeq;
 
  307        const auto &writeJobsToFile = [&]( 
const std::string &fName, 
const auto &data, 
const auto &cb ){
 
  308          yOut << YAML::Value << YAML::BeginMap;
 
  309          yOut << YAML::Key << 
"include" << YAML::Value << fName;
 
  310          yOut << YAML::EndMap;
 
  312          YAML::Emitter yOutFile;
 
  313          yOutFile << YAML::BeginSeq;
 
  314          cb( yOutFile, data );
 
  315          yOutFile << YAML::EndSeq;
 
  317          std::ofstream fout( dumpPath+
"/"+fName );
 
  318          fout << yOutFile.c_str();
 
  322        const auto &writePoolItemJobs = []( 
const std::string &jobName ){
 
  323          return [ &jobName ] ( YAML::Emitter &yOut, 
const PoolItemList &poolItems, 
bool shortInfo = false ) {
 
  324            for ( 
const PoolItem & pi : poolItems ) {
 
  325              yOut << YAML::Value << YAML::BeginMap;
 
  327              std::stringstream status;
 
  328              status << pi.status();
 
  330              yOut << YAML::Key << 
"job"     << YAML::Value << jobName
 
  331                   << YAML::Key << 
"kind"    << YAML::Value << pi.kind().asString()
 
  332                   << YAML::Key << 
"name"    << YAML::Value << pi.name()
 
  333                   << YAML::Key << 
"status"  << YAML::Value << status.str();
 
  335                yOut << YAML::Key << 
"channel" << YAML::Value << pi.repoInfo().alias()
 
  336                     << YAML::Key << 
"arch"    << YAML::Value << pi.arch().asString()
 
  337                     << YAML::Key << 
"version" << YAML::Value << pi.edition().version()
 
  338                     << YAML::Key << 
"release" << YAML::Value << pi.edition().release();
 
  340              yOut << YAML::EndMap;
 
  345        const auto &writeMapJob = []( YAML::Emitter &yOut, 
const std::string &name, 
const std::map<std::string, std::string> &values = std::map<std::string, std::string>() ){
 
  346          yOut << YAML::Value << YAML::BeginMap;
 
  347          yOut << YAML::Key << 
"job"     << YAML::Value << name;
 
  348          for ( 
const auto &v : values )
 
  349            yOut << YAML::Key << v.first << YAML::Value << v.second;
 
  350          yOut << YAML::EndMap;
 
  353        writePoolItemJobs(
"install")( yOut, items_to_install );
 
  354        writePoolItemJobs(
"keep")( yOut, items_keep );
 
  355        writePoolItemJobs(
"uninstall")( yOut, items_to_remove, true );
 
  357        if ( items_locked.size() )
 
  358          writeJobsToFile(
"zypp-locks.yaml", items_locked, writePoolItemJobs(
"lock") );
 
  360        for ( 
const auto &v : resolver.extraRequires() )
 
  361          writeMapJob( yOut, 
"addRequire", { { 
"name", v.asString() } } );
 
  362        for ( 
const auto &v : SystemCheck::instance().requiredSystemCap() )
 
  363          writeMapJob( yOut, 
"addRequire", { { 
"name", v.asString() } } );
 
  365        for ( 
const auto &v : resolver.extraConflicts() )
 
  366          writeMapJob( yOut, 
"addConflict", { { 
"name", v.asString() } } );
 
  367        for ( 
const auto &v : SystemCheck::instance().conflictSystemCap() )
 
  368          writeMapJob( yOut, 
"addConflict", { { 
"name", v.asString() } } );
 
  370        for ( 
const auto &v : resolver.upgradeRepos() )
 
  371          writeMapJob( yOut, 
"upgradeRepo", { { 
"name", v.alias() } } );
 
  373        if ( resolver.isUpgradeMode() )
 
  374          writeMapJob( yOut, 
"distupgrade" );
 
  376        if ( resolver.isUpdateMode() )
 
  377          writeMapJob( yOut, 
"update" );
 
  379        if ( resolver.isVerifyingMode() )
 
  380          writeMapJob( yOut, 
"verify" );
 
  382        yOut << YAML::EndSeq;
 
  383        yOut << YAML::EndMap; 
 
  384        yOut << YAML::EndSeq; 
 
  385        yOut << YAML::EndMap; 
 
  386        yOut << YAML::EndMap; 
 
  388        std::ofstream fout( dumpPath+
"/zypp-control.yaml" );
 
  389        fout << yOut.c_str();
 
  391        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.