From 681d59ef2028f39b15b9a85809389f1c8ba1673e Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Fri, 27 Nov 2020 15:44:43 +0900 Subject: [PATCH] Imported Upstream version 17.17.0 --- VERSION.cmake | 4 +- libzypp.spec.cmake | 2 +- package/libzypp.changes | 15 + tests/lib/TestSetup.h | 529 ++++++------ tests/parser/ProductFileReader_test.cc | 9 +- tests/repo/RepoLicense_test.cc | 10 +- tests/repo/RepoSigcheck_test.cc | 9 +- tests/sat/LookupAttr_test.cc | 9 +- tests/sat/Pool_test.cc | 9 +- tests/sat/Solvable_test.cc | 15 +- tests/zypp/CMakeLists.txt | 1 + tests/zypp/Capabilities_test.cc | 9 +- tests/zypp/Dup_test.cc | 28 +- tests/zypp/ExtendedPool_test.cc | 26 +- tests/zypp/InstanceId_test.cc | 23 +- tests/zypp/Locks_test.cc | 19 +- tests/zypp/PoolQueryCC_test.cc | 21 +- tests/zypp/PoolQuery_test.cc | 26 +- tests/zypp/PurgeKernels_test.cc | 234 +++++ tests/zypp/Resolver_test.cc | 29 +- tests/zypp/RpmPkgSigCheck_test.cc | 10 +- tests/zypp/Selectable_test.cc | 24 +- .../zypp/data/PurgeKernels/arch/solver-system.xml | 949 +++++++++++++++++++++ tests/zypp/data/PurgeKernels/arch/solver-test.xml | 8 + .../data/PurgeKernels/simple/solver-system.xml | 583 +++++++++++++ .../zypp/data/PurgeKernels/simple/solver-test.xml | 8 + .../data/PurgeKernels/withdeps/solver-system.xml | 411 +++++++++ .../data/PurgeKernels/withdeps/solver-test.xml | 8 + tools/zypp-NameReqPrv.cc | 93 +- zypp/CMakeLists.txt | 2 + zypp/Date.cc | 2 +- zypp/PurgeKernels.cc | 422 +++++++++ zypp/PurgeKernels.h | 72 ++ zypp/ZConfig.cc | 10 + zypp/ZConfig.h | 5 + zypp/base/Iterator.h | 12 + zypp/base/String.h | 63 +- zypp/sat/detail/PoolImpl.cc | 8 +- zypp/solver/detail/SATResolver.cc | 10 + zypp/target/RpmPostTransCollector.cc | 23 +- 40 files changed, 3330 insertions(+), 420 deletions(-) create mode 100644 tests/zypp/PurgeKernels_test.cc create mode 100644 tests/zypp/data/PurgeKernels/arch/solver-system.xml create mode 100644 tests/zypp/data/PurgeKernels/arch/solver-test.xml create mode 100644 tests/zypp/data/PurgeKernels/simple/solver-system.xml create mode 100644 tests/zypp/data/PurgeKernels/simple/solver-test.xml create mode 100644 tests/zypp/data/PurgeKernels/withdeps/solver-system.xml create mode 100644 tests/zypp/data/PurgeKernels/withdeps/solver-test.xml create mode 100644 zypp/PurgeKernels.cc create mode 100644 zypp/PurgeKernels.h diff --git a/VERSION.cmake b/VERSION.cmake index 877256e..e5e73d8 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -60,9 +60,9 @@ # SET(LIBZYPP_MAJOR "17") SET(LIBZYPP_COMPATMINOR "12") -SET(LIBZYPP_MINOR "16") +SET(LIBZYPP_MINOR "17") SET(LIBZYPP_PATCH "0") # -# LAST RELEASED: 17.16.0 (12) +# LAST RELEASED: 17.17.0 (12) # (The number in parenthesis is LIBZYPP_COMPATMINOR) #======= diff --git a/libzypp.spec.cmake b/libzypp.spec.cmake index 8aae395..376b6a1 100644 --- a/libzypp.spec.cmake +++ b/libzypp.spec.cmake @@ -71,7 +71,7 @@ BuildRequires: pkgconfig BuildRequires: pkg-config %endif -BuildRequires: libsolv-devel >= 0.7.7 +BuildRequires: libsolv-devel >= 0.7.8 %if 0%{?suse_version} >= 1100 BuildRequires: libsolv-tools %requires_eq libsolv-tools diff --git a/package/libzypp.changes b/package/libzypp.changes index 6daaaac..6aecacd 100644 --- a/package/libzypp.changes +++ b/package/libzypp.changes @@ -1,4 +1,19 @@ ------------------------------------------------------------------- +Thu Nov 28 18:20:04 CET 2019 - ma@suse.de + +- Introduce PurgeKernels class (bsc#1155198) + Adds libzypp API to mark all obsolete kernels according to the + existing purge-kernel script rules. +- Add solver jobs for retracted packages and ptfs. + Support for ptf packages and retract ed patches. +- Do not enforce 'en' being in RequestedLocales (bsc#1155678) + If the user decides to have a system without explicit language + support he may do so. +- Pass correct posttrans script argument (fixes #190) +- BuildRequires: libsolv-devel >= 0.7.8. +- version 17.17.0 (12) + +------------------------------------------------------------------- Tue Oct 29 14:54:51 CET 2019 - ma@suse.de - Expose new libsolv API via C++ counterparts diff --git a/tests/lib/TestSetup.h b/tests/lib/TestSetup.h index 1a24bc0..eab7786 100644 --- a/tests/lib/TestSetup.h +++ b/tests/lib/TestSetup.h @@ -78,322 +78,330 @@ ZYPP_DECLARE_FLAGS_AND_OPERATORS( TestSetupOptions, TestSetupOptionBits ); */ class TestSetup { - public: - typedef TestSetupOptions Options; +public: + typedef TestSetupOptions Options; - public: - TestSetup( const Arch & sysarch_r = Arch_empty, const Options & options_r = Options() ) - { _ctor( Pathname(), sysarch_r, options_r ); } +public: + struct InitLaterType {}; + static constexpr InitLaterType initLater = InitLaterType(); - TestSetup( const Pathname & rootdir_r, const Arch & sysarch_r = Arch_empty, const Options & options_r = Options() ) - { _ctor( rootdir_r, sysarch_r, options_r ); } + TestSetup( InitLaterType ) + {} - TestSetup( const Pathname & rootdir_r, const Options & options_r ) - { _ctor( rootdir_r, Arch_empty, options_r ); } + TestSetup( const Arch & sysarch_r = Arch_empty, const Options & options_r = Options() ) + : _pimpl { new Impl( Pathname(), sysarch_r, options_r ) } + {} - ~TestSetup() - { - USR << (_tmprootdir.path() == _rootdir ? "DELETE" : "KEEP") << " TESTSETUP below " << _rootdir << endl; - ZConfig::instance().setRepoManagerRoot( Pathname() ); - } + TestSetup( const Pathname & rootdir_r, const Arch & sysarch_r = Arch_empty, const Options & options_r = Options() ) + : _pimpl { new Impl( rootdir_r, sysarch_r, options_r ) } + {} - public: - /** Whether directory \a path_r contains a solver testcase. */ - static bool isTestcase( const Pathname & path_r ) - { - return filesystem::PathInfo( path_r / "solver-test.xml" ).isFile(); - } + TestSetup( const Pathname & rootdir_r, const Options & options_r ) + : _pimpl { new Impl( rootdir_r, Arch_empty, options_r ) } + {} - /** Whether directory \a path_r contains a testsetup. */ - static bool isTestSetup( const Pathname & path_r ) - { - return filesystem::PathInfo( path_r / "repos.d" ).isDir() && filesystem::PathInfo( path_r / "raw" ).isDir(); - } + void reset() + { _pimpl.reset(); } - public: - const Pathname & root() const { return _rootdir; } - - Target & target() { if ( ! getZYpp()->getTarget() ) getZYpp()->initializeTarget( _rootdir ); return *getZYpp()->getTarget(); } - RepoManager repomanager() { return RepoManager( RepoManagerOptions::makeTestSetup( _rootdir ) ); } - ResPool pool() { return ResPool::instance(); } - ResPoolProxy poolProxy() { return pool().proxy(); } - sat::Pool satpool() { return sat::Pool::instance(); } - Resolver & resolver() { return *getZYpp()->resolver(); } - - public: - /** Load target repo. */ - void loadTarget() - { target().load(); } - /** Fake @System repo from url. */ - void loadTargetRepo( const Url & url_r ) - { loadRepo( url_r, sat::Pool::systemRepoAlias() ); } - /** Fake @System repo from Path. */ - void loadTargetRepo( const Pathname & path_r ) - { loadRepo( path_r, sat::Pool::systemRepoAlias() ); } - /** Fake @System repo from helix repo. */ - void loadTargetHelix( const Pathname & path_r ) - { loadHelix( path_r, sat::Pool::systemRepoAlias() ); } - - public: - /** Directly load repoinfo to pool. */ - void loadRepo( RepoInfo nrepo ) - { - RepoManager rmanager( repomanager() ); - if ( rmanager.hasRepo( nrepo ) ) - nrepo.setAlias( RepoManager::makeStupidAlias( nrepo.url() ) ); - rmanager.addRepository( nrepo ); - rmanager.buildCache( nrepo ); - rmanager.loadFromCache( nrepo ); - } - /** Directly load repo from url to pool. */ - void loadRepo( const Url & url_r, const std::string & alias_r = std::string() ) - { - RepoInfo nrepo; - nrepo.setAlias( alias_r.empty() ? url_r.getHost()+":"+Pathname::basename(url_r.getPathName()) : alias_r ); - nrepo.addBaseUrl( url_r ); - if ( ! _options.testFlag( TSO_REPO_DEFAULT_GPG ) ) - nrepo.setGpgCheck( false ); - loadRepo( nrepo ); - } - /** Directly load repo from metadata(dir) or solvfile(file) to pool. +public: + /** Whether directory \a path_r contains a solver testcase. */ + static bool isTestcase( const Pathname & path_r ) + { + return filesystem::PathInfo( path_r / "solver-test.xml" ).isFile(); + } + + /** Whether directory \a path_r contains a testsetup. */ + static bool isTestSetup( const Pathname & path_r ) + { + return filesystem::PathInfo( path_r / "repos.d" ).isDir() && filesystem::PathInfo( path_r / "raw" ).isDir(); + } + +public: + const Pathname & root() const { return _pimpl->_rootdir; } + + Target & target() { if ( ! getZYpp()->getTarget() ) getZYpp()->initializeTarget( _pimpl->_rootdir ); return *getZYpp()->getTarget(); } + RepoManager repomanager() { return RepoManager( RepoManagerOptions::makeTestSetup( _pimpl->_rootdir ) ); } + ResPool pool() { return ResPool::instance(); } + ResPoolProxy poolProxy() { return pool().proxy(); } + sat::Pool satpool() { return sat::Pool::instance(); } + Resolver & resolver() { return *getZYpp()->resolver(); } + +public: + /** Load target repo. */ + void loadTarget() + { target().load(); } + /** Fake @System repo from url. */ + void loadTargetRepo( const Url & url_r ) + { loadRepo( url_r, sat::Pool::systemRepoAlias() ); } + /** Fake @System repo from Path. */ + void loadTargetRepo( const Pathname & path_r ) + { loadRepo( path_r, sat::Pool::systemRepoAlias() ); } + /** Fake @System repo from helix repo. */ + void loadTargetHelix( const Pathname & path_r ) + { loadHelix( path_r, sat::Pool::systemRepoAlias() ); } + +public: + /** Directly load repoinfo to pool. */ + void loadRepo( RepoInfo nrepo ) + { + RepoManager rmanager( repomanager() ); + if ( rmanager.hasRepo( nrepo ) ) + nrepo.setAlias( RepoManager::makeStupidAlias( nrepo.url() ) ); + rmanager.addRepository( nrepo ); + rmanager.buildCache( nrepo ); + rmanager.loadFromCache( nrepo ); + } + /** Directly load repo from url to pool. */ + void loadRepo( const Url & url_r, const std::string & alias_r = std::string() ) + { + RepoInfo nrepo; + nrepo.setAlias( alias_r.empty() ? url_r.getHost()+":"+Pathname::basename(url_r.getPathName()) : alias_r ); + nrepo.addBaseUrl( url_r ); + if ( ! _pimpl->_options.testFlag( TSO_REPO_DEFAULT_GPG ) ) + nrepo.setGpgCheck( false ); + loadRepo( nrepo ); + } + /** Directly load repo from metadata(dir) or solvfile(file) to pool. * An empty alias is guessed. */ - void loadRepo( const Pathname & path_r, const std::string & alias_r = std::string() ) + void loadRepo( const Pathname & path_r, const std::string & alias_r = std::string() ) + { + if ( filesystem::PathInfo( path_r ).isDir() ) { - if ( filesystem::PathInfo( path_r ).isDir() ) - { - loadRepo( path_r.asUrl(), alias_r ); - return; - } - // .solv file is loaded directly using a faked RepoInfo - RepoInfo nrepo; - nrepo.setAlias( alias_r.empty() ? path_r.basename() : alias_r ); - satpool().addRepoSolv( path_r, nrepo ); + loadRepo( path_r.asUrl(), alias_r ); + return; } - /** Directly load repo from some location (url or absolute(!)path). + // .solv file is loaded directly using a faked RepoInfo + RepoInfo nrepo; + nrepo.setAlias( alias_r.empty() ? path_r.basename() : alias_r ); + satpool().addRepoSolv( path_r, nrepo ); + } + /** Directly load repo from some location (url or absolute(!)path). * An empty alias is guessed. */ - void loadRepo( const std::string & loc_r, const std::string & alias_r = std::string() ) + void loadRepo( const std::string & loc_r, const std::string & alias_r = std::string() ) + { + if ( *loc_r.c_str() == '/' ) { - if ( *loc_r.c_str() == '/' ) - { - loadRepo( Pathname( loc_r ), alias_r ); - } - else - { - loadRepo( Url( loc_r ), alias_r ); - } + loadRepo( Pathname( loc_r ), alias_r ); + } + else + { + loadRepo( Url( loc_r ), alias_r ); } - /** Directly load repo from some location (url or absolute(!)path). + } + /** Directly load repo from some location (url or absolute(!)path). * An empty alias is guessed. */ - void loadRepo( const char * loc_r, const std::string & alias_r = std::string() ) - { loadRepo( std::string( loc_r ? loc_r : "" ), alias_r ); } - - private: - // repo data from solver-test.xml - struct RepoD { - DefaultIntegral priority; - std::string alias; - Url url; - }; - - public: - /** Directly load a helix repo from some testcase. + void loadRepo( const char * loc_r, const std::string & alias_r = std::string() ) + { loadRepo( std::string( loc_r ? loc_r : "" ), alias_r ); } + +private: + // repo data from solver-test.xml + struct RepoD { + DefaultIntegral priority; + std::string alias; + Url url; + }; + +public: + /** Directly load a helix repo from some testcase. * An empty alias is guessed. */ - void loadHelix( const Pathname & path_r, const std::string & alias_r = std::string() ) + void loadHelix( const Pathname & path_r, const std::string & alias_r = std::string() ) + { + // .solv file is loaded directly using a faked RepoInfo + RepoInfo nrepo; + nrepo.setAlias( alias_r.empty() ? path_r.basename() : alias_r ); + satpool().addRepoHelix( path_r, nrepo ); + } + + // Load repos included in a solver testcase. + void loadTestcaseRepos( const Pathname & path_r ) + { + filesystem::PathInfo pi( path_r / "solver-test.xml" ); + if ( ! pi.isFile() ) { - // .solv file is loaded directly using a faked RepoInfo - RepoInfo nrepo; - nrepo.setAlias( alias_r.empty() ? path_r.basename() : alias_r ); - satpool().addRepoHelix( path_r, nrepo ); + ERR << "No testcase in " << filesystem::PathInfo( path_r ) << endl; + return; } - - // Load repos included in a solver testcase. - void loadTestcaseRepos( const Pathname & path_r ) + // dumb parse + InputStream infile( pi.path() ); + Arch sysarch( Arch_empty ); + Url guessedUrl; + typedef std::map RepoI; + RepoI repoi; + for( iostr::EachLine in( infile ); in; in.next() ) { - filesystem::PathInfo pi( path_r / "solver-test.xml" ); - if ( ! pi.isFile() ) + if ( str::hasPrefix( *in, "\t( getXmlNodeVal( *in, "priority" ) ); + repod.url = guessedUrl; + guessedUrl = Url(); } - // dumb parse - InputStream infile( pi.path() ); - Arch sysarch( Arch_empty ); - Url guessedUrl; - typedef std::map RepoI; - RepoI repoi; - for( iostr::EachLine in( infile ); in; in.next() ) + else if ( str::hasPrefix( *in, "\t- url " ) ) { - if ( str::hasPrefix( *in, "\t( getXmlNodeVal( *in, "priority" ) ); - repod.url = guessedUrl; - guessedUrl = Url(); - } - else if ( str::hasPrefix( *in, "\t- url " ) ) - { - std::string::size_type pos = in->find( ": " ); - if ( pos != std::string::npos ) - { - guessedUrl = Url( in->substr( pos+2 ) ); - } - } - else if ( str::hasPrefix( *in, "\tfind( ": " ); + if ( pos != std::string::npos ) { - sysarch = Arch( getXmlNodeVal( *in, "arch" ) ); - if ( ! sysarch.empty() ) - ZConfig::instance().setSystemArchitecture( sysarch ); + guessedUrl = Url( in->substr( pos+2 ) ); } } + else if ( str::hasPrefix( *in, "\tinitializeTarget( sysRoot ); + getZYpp()->target()->load(); + USR << satpool.systemRepo() << endl; } - else + + if ( 1 ) { - sat::Pool satpool( sat::Pool::instance() ); - // a system - USR << str::form( "*** Load system at '%s'", sysRoot.c_str() ) << endl; - if ( 1 ) + RepoManager repoManager( sysRoot ); + RepoInfoList repos = repoManager.knownRepositories(); + for_( it, repos.begin(), repos.end() ) { - USR << "*** load target '" << Repository::systemRepoAlias() << "'\t" << endl; - getZYpp()->initializeTarget( sysRoot ); - getZYpp()->target()->load(); - USR << satpool.systemRepo() << endl; - } + RepoInfo & nrepo( *it ); - if ( 1 ) - { - RepoManager repoManager( sysRoot ); - RepoInfoList repos = repoManager.knownRepositories(); - for_( it, repos.begin(), repos.end() ) + if ( ! nrepo.enabled() ) + continue; + + if ( ! repoManager.isCached( nrepo ) ) + { + USR << str::form( "*** omit uncached repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl; + continue; + } + + USR << str::form( "*** load repo '%s'\t", nrepo.name().c_str() ) << flush; + try + { + repoManager.loadFromCache( nrepo ); + USR << satpool.reposFind( nrepo.alias() ) << endl; + } + catch ( const Exception & exp ) { - RepoInfo & nrepo( *it ); - - if ( ! nrepo.enabled() ) - continue; - - if ( ! repoManager.isCached( nrepo ) ) - { - USR << str::form( "*** omit uncached repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl; - continue; - } - - USR << str::form( "*** load repo '%s'\t", nrepo.name().c_str() ) << flush; - try - { - repoManager.loadFromCache( nrepo ); - USR << satpool.reposFind( nrepo.alias() ) << endl; - } - catch ( const Exception & exp ) - { - USR << exp.asString() + "\n" + exp.historyAsString() << endl; - USR << str::form( "*** omit broken repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl; - continue; - } + USR << exp.asString() + "\n" + exp.historyAsString() << endl; + USR << str::form( "*** omit broken repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl; + continue; } } } } + } - private: - void _ctor( const Pathname & rootdir_r, const Arch & sysarch_r, const Options & options_r ) +private: + struct Impl + { + Impl( const Pathname & rootdir_r, const Arch & sysarch_r, const Options & options_r ) { _options = options_r; @@ -412,10 +420,21 @@ class TestSetup ZConfig::instance().setSystemArchitecture( sysarch_r ); USR << "CREATED TESTSETUP below " << _rootdir << endl; } - private: + + ~Impl() + { + USR << (_tmprootdir.path() == _rootdir ? "DELETE" : "KEEP") << " TESTSETUP below " << _rootdir << endl; + ZConfig::instance().setRepoManagerRoot( Pathname() ); + getZYpp()->finishTarget(); + sat::Pool::instance().reposEraseAll(); + } + filesystem::TmpDir _tmprootdir; Pathname _rootdir; Options _options; + }; + + std::unique_ptr _pimpl; // maybe worth creating RW_pointer traits for it }; diff --git a/tests/parser/ProductFileReader_test.cc b/tests/parser/ProductFileReader_test.cc index e2b7246..568b1d2 100644 --- a/tests/parser/ProductFileReader_test.cc +++ b/tests/parser/ProductFileReader_test.cc @@ -1,7 +1,14 @@ #include "TestSetup.h" #include -//static TestSetup test( Arch_x86_64 ); +//TestSetup test( TestSetup::initLater ); +//struct TestInit { +// TestInit() { +// test = TestSetup( Arch_x86_64 ); +// } +// ~TestInit() { test.reset(); } +//}; +//BOOST_GLOBAL_FIXTURE( TestInit ); // Must be the first test! BOOST_AUTO_TEST_CASE(basic) diff --git a/tests/repo/RepoLicense_test.cc b/tests/repo/RepoLicense_test.cc index 20c724e..72fd91c 100644 --- a/tests/repo/RepoLicense_test.cc +++ b/tests/repo/RepoLicense_test.cc @@ -11,7 +11,15 @@ using namespace zypp; using std::cout; using std::endl; -TestSetup test( Arch_x86_64 ); +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); + const Pathname DATADIR( TESTS_SRC_DIR "/repo/RepoLicense" ); /////////////////////////////////////////////////////////////////// diff --git a/tests/repo/RepoSigcheck_test.cc b/tests/repo/RepoSigcheck_test.cc index 8231ede..62a479d 100644 --- a/tests/repo/RepoSigcheck_test.cc +++ b/tests/repo/RepoSigcheck_test.cc @@ -16,7 +16,14 @@ using std::endl; #define COUT if ( TC_VERBOSE ) std::cout #define TAG COUT << "*** " << __PRETTY_FUNCTION__ << endl -TestSetup test( Arch_x86_64, TSO_REPO_DEFAULT_GPG ); +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64, TSO_REPO_DEFAULT_GPG ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); const Pathname DATADIR( TESTS_SRC_DIR "/repo/RepoSigcheck" ); /////////////////////////////////////////////////////////////////// diff --git a/tests/sat/LookupAttr_test.cc b/tests/sat/LookupAttr_test.cc index 936307a..35ad17b 100644 --- a/tests/sat/LookupAttr_test.cc +++ b/tests/sat/LookupAttr_test.cc @@ -3,7 +3,14 @@ #include #include -static TestSetup test( Arch_x86_64 ); +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); // Must be the first test! BOOST_AUTO_TEST_CASE(bnc_435838) diff --git a/tests/sat/Pool_test.cc b/tests/sat/Pool_test.cc index 119c849..018a236 100644 --- a/tests/sat/Pool_test.cc +++ b/tests/sat/Pool_test.cc @@ -2,7 +2,14 @@ #include #include -static TestSetup test( Arch_x86_64 ); +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); namespace zypp { namespace detail { /** \relates RepositoryIterator Stream output */ diff --git a/tests/sat/Solvable_test.cc b/tests/sat/Solvable_test.cc index f4685ed..ad3e41d 100644 --- a/tests/sat/Solvable_test.cc +++ b/tests/sat/Solvable_test.cc @@ -18,13 +18,16 @@ using namespace zypp; using namespace boost::unit_test; -BOOST_AUTO_TEST_CASE(test_init) -{ - TestSetup test( Arch_x86_64 ); - test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); - test.loadRepo( TESTS_SRC_DIR "/data/11.0-update", "update" ); -} +struct TestInit { + TestInit() + : _test( Arch_x86_64 ){ + _test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); + _test.loadRepo( TESTS_SRC_DIR "/data/11.0-update", "update" ); + } + TestSetup _test; +}; +BOOST_GLOBAL_FIXTURE( TestInit ); BOOST_AUTO_TEST_CASE(attributes) { diff --git a/tests/zypp/CMakeLists.txt b/tests/zypp/CMakeLists.txt index 093f8f3..a0201d4 100644 --- a/tests/zypp/CMakeLists.txt +++ b/tests/zypp/CMakeLists.txt @@ -34,6 +34,7 @@ ADD_TESTS( ProgressData PtrTypes PublicKey + PurgeKernels RWPtr RepoInfo RepoManager diff --git a/tests/zypp/Capabilities_test.cc b/tests/zypp/Capabilities_test.cc index 0f64f4d..3a72142 100644 --- a/tests/zypp/Capabilities_test.cc +++ b/tests/zypp/Capabilities_test.cc @@ -19,7 +19,14 @@ using boost::unit_test::test_case; using namespace std; using namespace zypp; -static TestSetup test( Arch_x86_64 ); +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); BOOST_AUTO_TEST_CASE(capabilities_test) { diff --git a/tests/zypp/Dup_test.cc b/tests/zypp/Dup_test.cc index d063bcd..079e6f4 100644 --- a/tests/zypp/Dup_test.cc +++ b/tests/zypp/Dup_test.cc @@ -8,7 +8,16 @@ ///////////////////////////////////////////////////////////////////////////// -static TestSetup test; +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + test.loadTestcaseRepos( TESTS_SRC_DIR"/data/TCdup" ); + dumpRange( USR, test.pool().knownRepositoriesBegin(), + test.pool().knownRepositoriesEnd() ) << endl; + } + ~TestInit() { test.reset(); } +}; template std::ostream & vdumpPoolStats( std::ostream & str, TIterator begin_r, TIterator end_r ) @@ -22,7 +31,7 @@ std::ostream & vdumpPoolStats( std::ostream & str, TIterator begin_r, TIterator return str << stats; } -bool upgrade() +bool upgrade( ) { bool rres = false; { @@ -42,22 +51,17 @@ bool upgrade() } -BOOST_AUTO_TEST_CASE(testcase_init) +BOOST_GLOBAL_FIXTURE( TestInit ); + +BOOST_AUTO_TEST_CASE( orphaned ) { - //zypp::base::LogControl::instance().logToStdErr(); - test.loadTestcaseRepos( TESTS_SRC_DIR"/data/TCdup" ); - dumpRange( USR, test.pool().knownRepositoriesBegin(), - test.pool().knownRepositoriesEnd() ) << endl; USR << "pool: " << test.pool() << endl; - BOOST_REQUIRE( upgrade() ); -} -///////////////////////////////////////////////////////////////////////////// + BOOST_REQUIRE( upgrade( ) ); -BOOST_AUTO_TEST_CASE(orphaned) -{ ResPoolProxy proxy( test.poolProxy() ); BOOST_CHECK_EQUAL( proxy.lookup( ResKind::package, "glibc" )->status(), ui::S_KeepInstalled ); BOOST_CHECK_EQUAL( proxy.lookup( ResKind::package, "release-package" )->status(), ui::S_AutoUpdate ); BOOST_CHECK_EQUAL( proxy.lookup( ResKind::package, "dropped_required" )->status(), ui::S_KeepInstalled ); BOOST_CHECK_EQUAL( proxy.lookup( ResKind::package, "dropped" )->status(), ui::S_AutoDel ); } + diff --git a/tests/zypp/ExtendedPool_test.cc b/tests/zypp/ExtendedPool_test.cc index 3324cb5..c0d8317 100644 --- a/tests/zypp/ExtendedPool_test.cc +++ b/tests/zypp/ExtendedPool_test.cc @@ -15,7 +15,14 @@ using std::cerr; using std::endl; using namespace zypp; -static TestSetup test; +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); void testcase_init() { @@ -79,7 +86,16 @@ void repocheck() // Resolvable is still the original one created for a package... /////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE(t_1) { testcase_init(); } -BOOST_AUTO_TEST_CASE(t_2) { repocheck(); } -BOOST_AUTO_TEST_CASE(t_4) { testcase_init2(); } -BOOST_AUTO_TEST_CASE(t_5) { repocheck(); } +BOOST_AUTO_TEST_CASE(t_1) { + + //will print additional context information on error + BOOST_TEST_CONTEXT("First phase") { + testcase_init(); + repocheck(); + } + + BOOST_TEST_CONTEXT("Second phase") { + testcase_init2(); + repocheck(); + } +} diff --git a/tests/zypp/InstanceId_test.cc b/tests/zypp/InstanceId_test.cc index 248056b..90896a6 100644 --- a/tests/zypp/InstanceId_test.cc +++ b/tests/zypp/InstanceId_test.cc @@ -4,16 +4,19 @@ #define BOOST_TEST_MODULE InstanceId ///////////////////////////////////////////////////////////////////////////// -static TestSetup test( Arch_x86_64 ); - -BOOST_AUTO_TEST_CASE(pool_query_init) -{ - // Abuse;) vbox as System repo: - test.loadTargetRepo( TESTS_SRC_DIR "/data/obs_virtualbox_11_1" ); - test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); - test.loadRepo( TESTS_SRC_DIR "/data/OBS_zypp_svn-11.1", "zyppsvn" ); -} - +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + + // Abuse;) vbox as System repo: + test.loadTargetRepo( TESTS_SRC_DIR "/data/obs_virtualbox_11_1" ); + test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); + test.loadRepo( TESTS_SRC_DIR "/data/OBS_zypp_svn-11.1", "zyppsvn" ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); ///////////////////////////////////////////////////////////////////////////// BOOST_AUTO_TEST_CASE(default_constructed) diff --git a/tests/zypp/Locks_test.cc b/tests/zypp/Locks_test.cc index aac487b..dc2b013 100644 --- a/tests/zypp/Locks_test.cc +++ b/tests/zypp/Locks_test.cc @@ -26,14 +26,17 @@ bool isLocked( const sat::Solvable & solvable ) return false; } -BOOST_AUTO_TEST_CASE(pool_query_init) -{ - TestSetup test( Arch_x86_64 ); - //test.loadTarget(); // initialize and load target - test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); - test.loadRepo( TESTS_SRC_DIR "/data/OBS_zypp_svn-11.1", "@System" ); -} - +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + //test.loadTarget(); // initialize and load target + test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); + test.loadRepo( TESTS_SRC_DIR "/data/OBS_zypp_svn-11.1", "@System" ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); ///////////////////////////////////////////////////////////////////////////// // 0xx basic queries diff --git a/tests/zypp/PoolQueryCC_test.cc b/tests/zypp/PoolQueryCC_test.cc index 6c50db4..afccf25 100644 --- a/tests/zypp/PoolQueryCC_test.cc +++ b/tests/zypp/PoolQueryCC_test.cc @@ -14,9 +14,6 @@ using std::cerr; using std::endl; using namespace zypp; -static TestSetup test; - -///////////////////////////////////////////////////////////////////////////// template std::ostream & nlist( std::ostream & str, const TCont & set_r ) { @@ -26,11 +23,19 @@ std::ostream & nlist( std::ostream & str, const TCont & set_r ) return str << endl; } -BOOST_AUTO_TEST_CASE(init) -{ - test.loadTargetHelix( TESTS_SRC_DIR "/zypp/data/PoolQueryCC/rxnames.xml" ); - nlist( cout << "repo ", ResPool::instance() ); -} +///////////////////////////////////////////////////////////////////////////// + +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); + + test.loadTargetHelix( TESTS_SRC_DIR "/zypp/data/PoolQueryCC/rxnames.xml" ); + nlist( cout << "repo ", ResPool::instance() ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); ///////////////////////////////////////////////////////////////////////////// // Basic issue: Multiple match strings are compiled into a singe regex. The diff --git a/tests/zypp/PoolQuery_test.cc b/tests/zypp/PoolQuery_test.cc index b814e8d..7344e12 100644 --- a/tests/zypp/PoolQuery_test.cc +++ b/tests/zypp/PoolQuery_test.cc @@ -5,19 +5,23 @@ #define BOOST_TEST_MODULE PoolQuery ///////////////////////////////////////////////////////////////////////////// -static TestSetup test( Arch_x86_64 ); +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( Arch_x86_64 ); -BOOST_AUTO_TEST_CASE(pool_query_init) -{ - // Abuse;) vbox as System repo: - test.loadTargetRepo( TESTS_SRC_DIR "/data/obs_virtualbox_11_1" ); - test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); - test.loadRepo( TESTS_SRC_DIR "/data/OBS_zypp_svn-11.1", "zyppsvn" ); + // Abuse;) vbox as System repo: + test.loadTargetRepo( TESTS_SRC_DIR "/data/obs_virtualbox_11_1" ); + test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" ); + test.loadRepo( TESTS_SRC_DIR "/data/OBS_zypp_svn-11.1", "zyppsvn" ); - dumpRange( USR, test.pool().knownRepositoriesBegin(), - test.pool().knownRepositoriesEnd() ); - USR << "pool: " << test.pool() << endl; -} + dumpRange( USR, test.pool().knownRepositoriesBegin(), + test.pool().knownRepositoriesEnd() ); + USR << "pool: " << test.pool() << endl; + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); ///////////////////////////////////////////////////////////////////////////// static std::ofstream devNull; diff --git a/tests/zypp/PurgeKernels_test.cc b/tests/zypp/PurgeKernels_test.cc new file mode 100644 index 0000000..f13f1ae --- /dev/null +++ b/tests/zypp/PurgeKernels_test.cc @@ -0,0 +1,234 @@ +#include "TestSetup.h" +#include "zypp/PurgeKernels.h" + +#include + +using namespace zypp; +using namespace boost::unit_test; + +namespace boost { namespace test_tools { namespace tt_detail { +template<> +struct print_log_value< std::map > { +void operator()( std::ostream& ostr, + std::map const& set) +{ + ostr << "{" << std::endl; + for( const auto &elem : set ) ostr << "'" << elem.first << "'," << std::endl; + ostr << "}" << std::endl; +} +}; +}}} + +namespace { + std::string makeNVRA( const PoolItem &pck ) { + return pck.name() + "-" + pck.edition().asString() + "." + pck.arch().asString(); + } + + using TestSample = std::tuple >; + + std::vector maketestdata() { + return { + TestSample { + TESTS_SRC_DIR"/zypp/data/PurgeKernels/simple", + "1-3-default", + Arch("x86_64"), + "oldest,running,latest", + { + { "kernel-default-1-2.x86_64", false }, + { "kernel-default-devel-1-2.x86_64", false }, + { "kernel-default-devel-debuginfo-1-2.x86_64", false }, + { "kernel-devel-1-2.noarch", false }, + { "kernel-livepatch-default-1-2.x86_64", false }, + { "kernel-syms-1-2.x86_64", false }, + { "kernel-default-1-4.x86_64", false }, + { "kernel-default-devel-1-4.x86_64", false }, + { "kernel-default-devel-debuginfo-1-4.x86_64", false }, + { "kernel-devel-1-4.noarch", false }, + { "kernel-syms-1-4.x86_64", false }, + } + }, + //test that keeps only the running kernel + TestSample { + TESTS_SRC_DIR"/zypp/data/PurgeKernels/simple", + "1-3-default", + Arch("x86_64"), + "running", + { + { "kernel-default-1-1.x86_64", false }, + { "kernel-default-devel-1-1.x86_64", false }, + { "kernel-default-devel-debuginfo-1-1.x86_64", false }, + { "kernel-livepatch-default-1-1.x86_64", false }, + { "kernel-devel-1-1.noarch", false }, + { "kernel-syms-1-1.x86_64", false }, + { "kernel-source-1-1.noarch", false }, + { "kernel-default-1-2.x86_64", false }, + { "kernel-default-devel-1-2.x86_64", false }, + { "kernel-default-devel-debuginfo-1-2.x86_64", false }, + { "kernel-devel-1-2.noarch", false }, + { "kernel-livepatch-default-1-2.x86_64", false }, + { "kernel-syms-1-2.x86_64", false }, + { "kernel-default-1-4.x86_64", false }, + { "kernel-default-devel-1-4.x86_64", false }, + { "kernel-default-devel-debuginfo-1-4.x86_64", false }, + { "kernel-devel-1-4.noarch", false }, + { "kernel-syms-1-4.x86_64", false }, + { "kernel-default-1-5.x86_64", false }, + { "kernel-default-devel-1-5.x86_64", false }, + { "kernel-default-devel-debuginfo-1-5.x86_64", false }, + { "kernel-devel-1-5.noarch", false }, + { "kernel-syms-1-5.x86_64", false }, + { "dummy-kmp-default-1-0.x86_64", false }, + } + }, + TestSample { + TESTS_SRC_DIR"/zypp/data/PurgeKernels/simple", + "1-3-default", + Arch("x86_64"), + "oldest+1,running,latest-1", + { + { "kernel-default-1-1.x86_64", false }, + { "kernel-livepatch-default-1-1.x86_64", false }, + { "kernel-default-devel-1-1.x86_64", false }, + { "kernel-default-devel-debuginfo-1-1.x86_64", false }, + { "kernel-devel-1-1.noarch", false }, + { "kernel-syms-1-1.x86_64", false }, + { "kernel-source-1-1.noarch", false }, + { "kernel-default-1-5.x86_64", false }, + { "kernel-default-devel-1-5.x86_64", false }, + { "kernel-default-devel-debuginfo-1-5.x86_64", false }, + { "kernel-devel-1-5.noarch", false }, + { "kernel-syms-1-5.x86_64", false }, + { "dummy-kmp-default-1-0.x86_64", false }, + } + }, + TestSample { + //kernel-1-1 has a non kernel package depending on it, it should not be removed + TESTS_SRC_DIR"/zypp/data/PurgeKernels/withdeps", + "1-5-default", + Arch("x86_64"), + "running", + { + { "kernel-default-1-2.x86_64", false }, + { "kernel-default-devel-1-2.x86_64", false }, + { "kernel-default-devel-debuginfo-1-2.x86_64", false }, + { "kernel-devel-1-2.noarch", false }, + { "kernel-livepatch-default-1-2.x86_64", false }, + { "kernel-syms-1-2.x86_64", false }, + } + }, + TestSample { + //kernel-1-5 provides a symbol for a kmp that has a non kernel package depending on it, it should not be removed + TESTS_SRC_DIR"/zypp/data/PurgeKernels/withdeps", + "1-1-default", + Arch("x86_64"), + "running", + { + { "kernel-default-1-2.x86_64", false }, + { "kernel-default-devel-1-2.x86_64", false }, + { "kernel-default-devel-debuginfo-1-2.x86_64", false }, + { "kernel-devel-1-2.noarch", false }, + { "kernel-livepatch-default-1-2.x86_64", false }, + { "kernel-syms-1-2.x86_64", false }, + } + }, + TestSample { + //kernel-1-2 is explicitely in the keep spec, it should not be removed + //kernel-1-5 provides a symbol for a kmp that has a non kernel package depending on it, it should not be removed + TESTS_SRC_DIR"/zypp/data/PurgeKernels/withdeps", + "1-1-default", + Arch("x86_64"), + "running,1-2", + { + } + }, + TestSample { + //kernel-default-1-1.x86_64 is the running kernel it should not be removed, + //in all sets with different arch only the latest should be kept + TESTS_SRC_DIR"/zypp/data/PurgeKernels/arch", + "1-1-default", + Arch("x86_64"), + "latest,running", + { + { "kernel-default-1-1.aarch64", false }, + { "kernel-default-1-1.i686", false }, + + /* + { "kernel-default-devel-1-1.x86_64", false }, + { "kernel-default-devel-debuginfo-1-1.x86_64", false }, + { "kernel-syms-1-1.x86_64", false }, + */ + + { "kernel-default-1-2.aarch64", false }, + { "kernel-default-1-2.i686", false }, + { "kernel-default-1-2.x86_64", false }, + + { "kernel-default-devel-1-1.aarch64", false }, + { "kernel-default-devel-1-1.i686", false }, + { "kernel-default-devel-1-2.aarch64", false }, + { "kernel-default-devel-1-2.i686", false }, + { "kernel-default-devel-1-2.x86_64", false }, + + { "kernel-default-devel-debuginfo-1-1.aarch64", false }, + { "kernel-default-devel-debuginfo-1-1.i686", false }, + { "kernel-default-devel-debuginfo-1-2.aarch64", false }, + { "kernel-default-devel-debuginfo-1-2.i686", false }, + { "kernel-default-devel-debuginfo-1-2.x86_64", false }, + + { "kernel-devel-1-2.noarch", false }, + + { "kernel-livepatch-default-1-2.aarch64", false }, + { "kernel-livepatch-default-1-2.i686", false }, + { "kernel-livepatch-default-1-2.x86_64", false }, + + /* + Since kernel-syms package requires do not care about architecture, every kernel-syms + package for flavour-version will be kept as long as a kernel-flavour-devel package of any arch is installed + { "kernel-syms-1-1.aarch64", false }, + { "kernel-syms-1-1.i686", false }, + */ + { "kernel-syms-1-2.aarch64", false }, + { "kernel-syms-1-2.i686", false }, + { "kernel-syms-1-2.x86_64", false }, + } + }, + }; + } +} + +namespace bdata = boost::unit_test::data; + +BOOST_DATA_TEST_CASE(purge_kernels, bdata::make( maketestdata() ), repoPath, uname_r, arch, keepSpec, expectedRems ) +{ + TestSetup test( Arch_x86_64 ); + test.loadTestcaseRepos( repoPath ); + + auto expectedRemovals = expectedRems; + + PurgeKernels krnls; + krnls.setUnameR( uname_r ); + krnls.setKernelArch( arch ); + krnls.setKeepSpec( keepSpec ); + krnls.markObsoleteKernels(); + + auto pool = ResPool::instance(); + BOOST_REQUIRE( pool.resolver().resolvePool() ); + + unsigned removeCount = 0; + const filter::ByStatus toBeUninstalledFilter( &ResStatus::isToBeUninstalled ); + for ( auto it = pool.byStatusBegin( toBeUninstalledFilter ); it != pool.byStatusEnd( toBeUninstalledFilter ); it++ ) { + removeCount++; + + auto pck = expectedRemovals.find( makeNVRA(*it) ); + BOOST_REQUIRE_MESSAGE( pck != expectedRemovals.end(), std::string("Unexpected package removed: ") + makeNVRA(*it) ); + + pck->second = true; + } + + for ( const auto &rem : expectedRemovals ) { + if (!rem.second) + std::cout << std::string( "Expected package removal did not happen for: ") + rem.first << std::endl; + //BOOST_REQUIRE_MESSAGE( rem.second, std::string( "Expected package removal did not happen for: ") + rem.first ); + } + + BOOST_REQUIRE_EQUAL( expectedRemovals.size(), removeCount ); +} diff --git a/tests/zypp/Resolver_test.cc b/tests/zypp/Resolver_test.cc index eca9c39..a776ea1 100644 --- a/tests/zypp/Resolver_test.cc +++ b/tests/zypp/Resolver_test.cc @@ -8,7 +8,7 @@ using namespace boost::unit_test; #include "zypp/pool/PoolStats.h" #include "zypp/ui/Selectable.h" -static TestSetup test; +static TestSetup test( TestSetup::initLater ); struct BAD_TESTCASE {}; @@ -48,17 +48,22 @@ PoolItem Apde; // A: aspell-de (wanted locale) PoolItem Apfr; // A: aspell-fr (unwanted locale) PoolItem Aprec; // A: recommended-pkg (by aspell) -BOOST_AUTO_TEST_CASE(testcase_init) -{ - test.loadTestcaseRepos( TESTS_SRC_DIR"/data/TCNamespaceRecommends" ); - Ip = getIPi( "aspell" ); - Ap = getAPi( "aspell" ); - Ipen = getIPi( "aspell-en" ); - Apen = getAPi( "aspell-en" ); - Apde = getAPi( "aspell-de" ); - Apfr = getAPi( "aspell-fr" ); - Aprec = getAPi( "recommended-pkg" ); -} +struct TestInit { + TestInit() { + test = TestSetup( ); + + test.loadTestcaseRepos( TESTS_SRC_DIR"/data/TCNamespaceRecommends" ); + Ip = getIPi( "aspell" ); + Ap = getAPi( "aspell" ); + Ipen = getIPi( "aspell-en" ); + Apen = getAPi( "aspell-en" ); + Apde = getAPi( "aspell-de" ); + Apfr = getAPi( "aspell-fr" ); + Aprec = getAPi( "recommended-pkg" ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); ///////////////////////////////////////////////////////////////////////////// diff --git a/tests/zypp/RpmPkgSigCheck_test.cc b/tests/zypp/RpmPkgSigCheck_test.cc index 74f1178..e18d5b0 100644 --- a/tests/zypp/RpmPkgSigCheck_test.cc +++ b/tests/zypp/RpmPkgSigCheck_test.cc @@ -1,5 +1,4 @@ #include "TestSetup.h" -static TestSetup test; #include "zypp/target/rpm/RpmDb.h" using target::rpm::RpmDb; @@ -10,6 +9,15 @@ using target::rpm::RpmDb; #define HAVE_RPMTSSETVFYFLAGS #endif +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( ); + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); + /////////////////////////////////////////////////////////////////// // // - RpmDb::checkPackage (legacy) and RpmDb::checkPackageSignature are diff --git a/tests/zypp/Selectable_test.cc b/tests/zypp/Selectable_test.cc index 02fc67e..82afc21 100644 --- a/tests/zypp/Selectable_test.cc +++ b/tests/zypp/Selectable_test.cc @@ -6,17 +6,23 @@ ///////////////////////////////////////////////////////////////////////////// -static TestSetup test; +static TestSetup test( TestSetup::initLater ); +struct TestInit { + TestInit() { + test = TestSetup( ); -BOOST_AUTO_TEST_CASE(testcase_init) -{ -// zypp::base::LogControl::instance().logToStdErr(); - test.loadTestcaseRepos( TESTS_SRC_DIR"/data/TCSelectable" ); + // zypp::base::LogControl::instance().logToStdErr(); + test.loadTestcaseRepos( TESTS_SRC_DIR"/data/TCSelectable" ); + + // dumpRange( USR, test.pool().knownRepositoriesBegin(), + // test.pool().knownRepositoriesEnd() ) << endl; + // USR << "pool: " << test.pool() << endl; + + } + ~TestInit() { test.reset(); } +}; +BOOST_GLOBAL_FIXTURE( TestInit ); -// dumpRange( USR, test.pool().knownRepositoriesBegin(), -// test.pool().knownRepositoriesEnd() ) << endl; -// USR << "pool: " << test.pool() << endl; -} ///////////////////////////////////////////////////////////////////////////// BOOST_AUTO_TEST_CASE(candiadate) diff --git a/tests/zypp/data/PurgeKernels/arch/solver-system.xml b/tests/zypp/data/PurgeKernels/arch/solver-system.xml new file mode 100644 index 0000000..1268681 --- /dev/null +++ b/tests/zypp/data/PurgeKernels/arch/solver-system.xml @@ -0,0 +1,949 @@ + + + glibc + openSUSE + + + x86_64 + 11 + + + + + + + + + kernel-firmware + + + + + + + kernel-macros + openSUSE + + + noarch + 10 + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 11 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 11 + + + + + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + x86_64 + 11 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 12 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 12 + + + + + + + + + + + + + kernel-syms + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 15 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 15 + + + + + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + x86_64 + 15 + + + + + + + + + + + + + + dummy-kmp-default + + + x86_64 + 10 + + + + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + i686 + 11 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + i686 + 11 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + i686 + 11 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + i686 + 11 + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + i686 + 11 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + i686 + 12 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + i686 + 12 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + i686 + 12 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + i686 + 12 + + + + + + + + + kernel-syms + openSUSE + + + i686 + 12 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + i686 + 15 + + + + + + + + + + + + + + + + kernel-default-devel + openSUSE + + + i686 + 15 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + i686 + 15 + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + i686 + 15 + + + + + + + + + + + + + + dummy-kmp-default + + + i686 + 10 + + + + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + aarch64 + 11 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + aarch64 + 11 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + aarch64 + 11 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + aarch64 + 11 + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + aarch64 + 11 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + aarch64 + 12 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + aarch64 + 12 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + aarch64 + 12 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + aarch64 + 12 + + + + + + + + + kernel-syms + openSUSE + + + aarch64 + 12 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + aarch64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel + openSUSE + + + aarch64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + aarch64 + 15 + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + aarch64 + 15 + + + + + + + + + + + + + + dummy-kmp-default + + + aarch64 + 10 + + + + + + + + + + + + + + + + diff --git a/tests/zypp/data/PurgeKernels/arch/solver-test.xml b/tests/zypp/data/PurgeKernels/arch/solver-test.xml new file mode 100644 index 0000000..993d537 --- /dev/null +++ b/tests/zypp/data/PurgeKernels/arch/solver-test.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/zypp/data/PurgeKernels/simple/solver-system.xml b/tests/zypp/data/PurgeKernels/simple/solver-system.xml new file mode 100644 index 0000000..2a14967 --- /dev/null +++ b/tests/zypp/data/PurgeKernels/simple/solver-system.xml @@ -0,0 +1,583 @@ + + + glibc + openSUSE + + + x86_64 + 11 + + + + + + + + + kernel-firmware + + + + + + + kernel-macros + openSUSE + + + noarch + 10 + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 11 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 11 + + + + + + + + + + + + + kernel-source + openSUSE + + + noarch + 11 + + + + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + x86_64 + 11 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 12 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 12 + + + + + + + + + + + + + kernel-syms + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 13 + + + + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 13 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 13 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 13 + + + + + + + + + + + + + kernel-syms + openSUSE + + + x86_64 + 13 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 14 + + + + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 14 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 14 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 14 + + + + + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + x86_64 + 14 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 15 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 15 + + + + + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + x86_64 + 15 + + + + + + + + + + + + + + dummy-kmp-default + + + x86_64 + 10 + + + + + + + + + + + + + + + + diff --git a/tests/zypp/data/PurgeKernels/simple/solver-test.xml b/tests/zypp/data/PurgeKernels/simple/solver-test.xml new file mode 100644 index 0000000..993d537 --- /dev/null +++ b/tests/zypp/data/PurgeKernels/simple/solver-test.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/zypp/data/PurgeKernels/withdeps/solver-system.xml b/tests/zypp/data/PurgeKernels/withdeps/solver-system.xml new file mode 100644 index 0000000..6e30db8 --- /dev/null +++ b/tests/zypp/data/PurgeKernels/withdeps/solver-system.xml @@ -0,0 +1,411 @@ + + + glibc + openSUSE + + + x86_64 + 11 + + + + + + + + + kernel-firmware + + + + + + + kernel-macros + openSUSE + + + noarch + 10 + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + + foo + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 11 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 11 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 11 + + + + + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + x86_64 + 11 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + kernel-livepatch-default + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 12 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 12 + + + + + + + + + + + + + kernel-syms + openSUSE + + + x86_64 + 12 + + + + + + + + + + + + + + + + kernel-default + openSUSE + + + x86_64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel + openSUSE + + + x86_64 + 15 + + + + + + + + + + + + + + + + kernel-default-devel-debuginfo + openSUSE + + + x86_64 + 15 + + + + + + + + + kernel-devel + openSUSE + + + noarch + 15 + + + + + + + + + + + + + kernel-syms + openSUSE + 1570603549 + + + x86_64 + 15 + + + + + + + + + + + + + + dummy-kmp-default + + + x86_64 + 10 + + + + + + + + + + + + + + package-needing-krnlmodule + + + x86_64 + 10 + + + + + + + + + + + + + + diff --git a/tests/zypp/data/PurgeKernels/withdeps/solver-test.xml b/tests/zypp/data/PurgeKernels/withdeps/solver-test.xml new file mode 100644 index 0000000..993d537 --- /dev/null +++ b/tests/zypp/data/PurgeKernels/withdeps/solver-test.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tools/zypp-NameReqPrv.cc b/tools/zypp-NameReqPrv.cc index a5204f6..f21adc3 100644 --- a/tools/zypp-NameReqPrv.cc +++ b/tools/zypp-NameReqPrv.cc @@ -50,6 +50,32 @@ int usage( const std::string & msg_r = std::string(), int exit_r = 100 ) return exit_r; } +#define COL_R "\033[0;31m" +#define COL_G "\033[0;32m" +#define COL_B "\033[0;34m" +#define COL_C "\033[0;36m" +#define COL_M "\033[0;35m" +#define COL_Y "\033[0;33m" +#define COL_BL "\033[0;30m" +#define COL_WH "\033[1;37m" +#define COL_OFF "\033[0m" + +std::string colorId( sat::Solvable solv_r ) +{ + // return solv_r.asString(); + std::string ret; + if ( solv_r ) + { + static str::Format fmt { COL_B "%s" COL_OFF "-" COL_G "%s" COL_OFF ".%s" }; + ret = fmt % solv_r.name() % solv_r.edition() % solv_r.arch(); + } + else + { + ret = ( solv_r.id() == sat::detail::systemSolvableId ? "systemSolvable" : "noSolvable" ); + } + return ret; +} + void tableOut( const std::string & s1 = std::string(), const std::string & s2 = std::string(), const std::string & s3 = std::string(), @@ -241,38 +267,41 @@ int main( int argc, char * argv[] ) { if ( (*argv)[0] == '-' ) { - switch ( (*argv)[1] ) + for ( const char * arg = (*argv)+1; *arg != '\0'; ++arg ) // -pr for -p -r { - case 'a': names = true, requires = provides = true; break; - case 'A': names = true, requires = provides = false; break; - case 'D': - if ( argc > 1 ) - { - --argc,++argv; - dDump( *argv ); - } - else - return errexit("-D requires an argument."); - break; - case 'i': ignorecase = true; break; - case 'I': ignorecase = false; break; - case 'x': matechexact = true; break; - case 'n': names = true; break; - case 'N': names = false; break; - case 'r': requires = true; break; - case 'R': requires = false; break; - case 'p': provides = true; break; - case 'P': provides = false; break; - case 'c': conflicts = true; break; - case 'C': conflicts = false; break; - case 'o': obsoletes = true; break; - case 'O': obsoletes = false; break; - case 'm': recommends = true; break; - case 'M': recommends = false; break; - case 's': supplements = true; break; - case 'S': supplements = false; break; - case 'e': enhacements = true; break; - case 'E': enhacements = false; break; + switch ( *arg ) + { + case 'a': names = true, requires = provides = true; break; + case 'A': names = true, requires = provides = false; break; + case 'D': + if ( argc > 1 ) + { + --argc,++argv; + dDump( *argv ); + } + else + return errexit("-D requires an argument."); + break; + case 'i': ignorecase = true; break; + case 'I': ignorecase = false; break; + case 'x': matechexact = true; break; + case 'n': names = true; break; + case 'N': names = false; break; + case 'r': requires = true; break; + case 'R': requires = false; break; + case 'p': provides = true; break; + case 'P': provides = false; break; + case 'c': conflicts = true; break; + case 'C': conflicts = false; break; + case 'o': obsoletes = true; break; + case 'O': obsoletes = false; break; + case 'm': recommends = true; break; + case 'M': recommends = false; break; + case 's': supplements = true; break; + case 'S': supplements = false; break; + case 'e': enhacements = true; break; + case 'E': enhacements = false; break; + } } continue; } @@ -365,7 +394,7 @@ int main( int argc, char * argv[] ) if ( it->isKind( ResKind::srcpackage ) && !withSrcPackages ) continue; - tableOut( str::numstring( it->id() ), it->asString(), + tableOut( str::numstring( it->id() ), colorId(*it), str::form( "(%d)%s", it->repository().info().priority(), it->repository().name().c_str() ), str::numstring( PoolItem(*it)->buildtime() ) ); tableOut( "", "", diff --git a/zypp/CMakeLists.txt b/zypp/CMakeLists.txt index 6cedd9c..2523d5a 100644 --- a/zypp/CMakeLists.txt +++ b/zypp/CMakeLists.txt @@ -55,6 +55,7 @@ SET( zypp_SRCS ProgressData.cc ProvideFilePolicy.cc PublicKey.cc + PurgeKernels.cc Range.cc Rel.cc RepoInfo.cc @@ -159,6 +160,7 @@ SET( zypp_HEADERS ProgressData.h ProvideFilePolicy.h PublicKey.h + PurgeKernels.h Range.h RelCompare.h Rel.h diff --git a/zypp/Date.cc b/zypp/Date.cc index 4651e72..43059dd 100644 --- a/zypp/Date.cc +++ b/zypp/Date.cc @@ -234,7 +234,7 @@ namespace zypp { return xmlout::node( str, name_r, { { "time_t", Date::ValueType(obj) }, - { "text", obj.printISO() }, + { "text", obj.printISO( Date::TB_UTC ) }, } ); } diff --git a/zypp/PurgeKernels.cc b/zypp/PurgeKernels.cc new file mode 100644 index 0000000..cfe7c7e --- /dev/null +++ b/zypp/PurgeKernels.cc @@ -0,0 +1,422 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/PurgeKernels.cc + * +*/ + +#include "zypp/base/String.h" +#include "zypp/base/Logger.h" +#include "zypp/base/Regex.h" +#include "zypp/ui/Selectable.h" +#include "zypp/PurgeKernels.h" +#include "zypp/PoolQuery.h" +#include "zypp/ResPool.h" +#include "zypp/Resolver.h" +#include "zypp/Filter.h" +#include "zypp/ZConfig.h" + +#include +#include +#include +#include +#include + +#undef ZYPP_BASE_LOGGER_LOGGROUP +#define ZYPP_BASE_LOGGER_LOGGROUP "PurgeKernels" + +namespace zypp { + + struct PurgeKernels::Impl { + + Impl() { + struct utsname unameData; + if ( uname( &unameData) == 0 ) { + _kernelArch = Arch( unameData.machine ); + _uname_r = std::string( unameData.release ); + } + } + + bool removePackageAndCheck( PoolItem &item, const str::regex &validRemovals ) const; + void parseKeepSpec(); + void fillKeepList( const std::unordered_map< std::string, std::map< Arch, std::map > > &installedKernels, std::set &list ) const; + void cleanDevelAndSrcPackages ( const str::regex &validRemovals, std::set &validEditions, const std::string &flavour = std::string() ); + + static std::string detectRunningKernel() { + + std::string kernelVersion; + std::ifstream procKernel( "/proc/sys/kernel/osrelease" ); + if ( procKernel ) { + std::getline( procKernel, kernelVersion ); + } + return kernelVersion; + + } + + + std::set _keepLatestOffsets = { 0 }; + std::set _keepOldestOffsets; + std::set _keepSpecificEditions; + std::string _uname_r; + Arch _kernelArch; + std::string _keepSpec = ZConfig::instance().multiversionKernels(); + bool _keepRunning = true; + }; + + /*! + * tries to remove a the \ref PoolItem \a pi from the pool, solves and checks if no unexpected packages are removed due to the \a validRemovals regex. + * If the constraint fails the changes are reverted and \a false is returned. + */ + bool PurgeKernels::Impl::removePackageAndCheck( PoolItem &pi, const str::regex &validRemovals ) const + { + const filter::ByStatus toBeUninstalledFilter( &ResStatus::isToBeUninstalled ); + auto pool = ResPool::instance(); + + //remember which packages are already marked for removal, we do not need to check them again + std::set< sat::Solvable::IdType> currentSetOfRemovals; + for ( auto it = pool.byStatusBegin( toBeUninstalledFilter ); it != pool.byStatusEnd( toBeUninstalledFilter ); it++ ) + currentSetOfRemovals.insert( it->id() ); + + pi.status().setToBeUninstalled( ResStatus::USER ); + + if ( !pool.resolver().resolvePool() ) { + MIL << "Failed to resolve pool, skipping " << pi << std::endl; + pool.resolver().problems(); + pi.statusReset(); + + return false; + } + + for ( auto it = pool.byStatusBegin( toBeUninstalledFilter ); it != pool.byStatusEnd( toBeUninstalledFilter ); it++ ) { + + //this was set by us or marked by a previous removal, ignore them + if ( it->status().isByUser() || (currentSetOfRemovals.find( it->id() ) != currentSetOfRemovals.end()) ) + continue; + + str::smatch what; + if ( !str::regex_match( it->name(), what, validRemovals) ) { + MIL << "Package " << PoolItem(*it) << " should not be removed, skipping " << pi << std::endl; + pi.statusReset(); + return false; + } + } + + MIL << "Removing package: " << pi << std::endl; + return true; + } + + /*! + * Parse the config line keep spec that tells us which kernels should be kept + */ + void PurgeKernels::Impl::parseKeepSpec( ) + { + //keep spec parse regex, make sure to edit the group offsets if changing this regex + const str::regex specRegex( "^(latest|oldest)([+-][0-9]+)?$", str::regex::match_extended ); + + const unsigned tokenGrp = 1; //index of the group matching the token + const unsigned modifierGrp = 2; //index of the group matching the offset modifier + + + MIL << "Parsing keep spec: " << _keepSpec << std::endl; + + std::vector words; + str::split( _keepSpec, std::back_inserter(words), ",", str::TRIM ); + if ( words.empty() ) { + WAR << "Invalid keep spec: " << _keepSpec << " using default latest,running." << std::endl; + return; + } + + _keepRunning = false; + _keepLatestOffsets.clear(); + _keepOldestOffsets.clear(); + + for ( const std::string &word : words ) { + if ( word == "running" ) { + _keepRunning = true; + } else { + str::smatch what; + if ( !str::regex_match( word, what, specRegex ) ) { + _keepSpecificEditions.insert( Edition(word) ); + continue; + } + + auto addKeepOff = []( const auto &off, auto &set, const auto &constraint ){ + const off_t num = off.empty() ? 0 : str::strtonum( off ); + if ( !constraint(num) ) return false; + set.insert( static_cast(std::abs(num)) ); + return true; + }; + + if ( what[tokenGrp] == "oldest" ) { + addKeepOff( what[modifierGrp], _keepOldestOffsets, [ &word ]( off_t num ) { + if ( num < 0 ) { + WAR << "Ignoring invalid modifier in keep spec: " << word << ", oldest supports only positive modifiers." << std::endl; + return false; + } + return true; + }); + } else { + addKeepOff( what[modifierGrp], _keepLatestOffsets, [ &word ]( off_t num ) { + if ( num > 0 ) { + WAR << "Ignoring invalid modifier in keep spec: " << word << ", latest supports only negative modifiers." << std::endl; + return false; + } + return true; + }); + } + } + } + } + + /*! + * Go over the list of installed kernels and mark those as "do not remove" that match + * a entry in the keep spec + */ + void PurgeKernels::Impl::fillKeepList( const std::unordered_map > > &installedKernels, std::set &list ) const + { + for ( const auto &flavourMap : installedKernels ) { + for ( const auto &archMap : flavourMap.second ) { + size_t currOff = 0; //the current "oldest" offset ( runs from map start to end ) + size_t currROff = archMap.second.size() - 1; // the current "latest" offset ( runs from map end to start ) + for ( const auto &kernelMap : archMap.second ) { + + //if we find one of the running offsets in the keepspec, we add the kernel id the the list of packages to keep + if ( _keepOldestOffsets.find( currOff ) != _keepOldestOffsets.end() + || _keepLatestOffsets.find( currROff ) != _keepLatestOffsets.end() + // a kernel might be explicitely locked by version + || _keepSpecificEditions.find( kernelMap.second.edition() ) != _keepSpecificEditions.end() ) { + MIL << "Marking kernel " << kernelMap.second << " as to keep." << std::endl; + list.insert( kernelMap.second.id() ) ; + } + + currOff++; + currROff--; + } + } + } + } + + /*! + * This cleans up the source and devel packages tree for a specific flavour. + */ + void PurgeKernels::Impl::cleanDevelAndSrcPackages(const str::regex &validRemovals, std::set &validEditions, const std::string &flavour ) + { + bool isWithFlavour = flavour.size(); + + if ( isWithFlavour ) + MIL << "Trying to remove source/devel packages for flavour " << flavour << std::endl; + else + MIL << "Trying to remove global/default source/devel packages "<< std::endl; + + auto withFlavour = [&isWithFlavour, &flavour]( const std::string &name ) { + return isWithFlavour ? name+"-"+flavour : name; + }; + + //try to remove the kernel-devel-flavour and kernel-source-flavour packages + PoolQuery q; + q.addKind( zypp::ResKind::package ); + + q.addAttribute( sat::SolvAttr::name, withFlavour("kernel-devel") ); + q.addAttribute( sat::SolvAttr::name, withFlavour("kernel-source") ); + q.setInstalledOnly(); + q.setMatchExact(); + + for ( auto installedSrcPck : q ) { + + if ( validEditions.find( installedSrcPck.edition() ) == validEditions.end() ) { + MIL << "Skipping source package " << installedSrcPck << " no corresponding kernel with the same version was installed." << std::endl; + continue; + } + + //if no package providing kernel-flavour = VERSION is installed , we are free to remove the package + PoolQuery instKrnl; + instKrnl.addKind( zypp::ResKind::package ); + instKrnl.setInstalledOnly(); + instKrnl.setMatchExact(); + instKrnl.addDependency( sat::SolvAttr::provides, withFlavour("kernel"), Rel::EQ, installedSrcPck.edition() ); + + bool found = std::any_of ( instKrnl.begin(), instKrnl.end(), []( auto it ) { return !PoolItem(it).status().isToBeUninstalled(); } ); + if ( found ) { + MIL << "Skipping source package " << installedSrcPck << " binary packages with the same edition are still installed" << std::endl; + continue; + } + + PoolItem pi( installedSrcPck ); + removePackageAndCheck( pi, validRemovals ); + } + } + + PurgeKernels::PurgeKernels() + : _pimpl( new Impl() ) + { + + } + + void PurgeKernels::markObsoleteKernels() + { + if ( _pimpl->_keepSpec.empty() ) + return; + + _pimpl->parseKeepSpec(); + + auto pool = ResPool::instance(); + pool.resolver().setForceResolve( true ); // set allow uninstall flag + + const filter::ByStatus toBeUninstalledFilter( &ResStatus::isToBeUninstalled ); + + //list of packages that are allowed to be removed automatically. + const str::regex validRemovals("(kernel-syms(-.*)?|kgraft-patch(-.*)?|kernel-livepatch(-.*)?|.*-kmp(-.*)?)"); + + //list of packages that are allowed to be removed automatically when uninstalling kernel-devel packages + const str::regex validDevelRemovals("(kernel-source(-.*)?|(kernel-syms(-.*)?)|(kernel-devel(-.*)?)|(kernel(-.*)?-devel))"); + + // kernel flavour regex + const str::regex kernelFlavourRegex("^kernel-(.*)$"); + + // the map of all installed kernels, grouped by Flavour -> Arch -> Version + std::unordered_map< std::string, std::map< Arch, std::map > > installedKernels; + + // the set of kernel package IDs that have to be kept always + std::set packagesToKeep; + + //collect the list of installed kernel packages + PoolQuery q; + q.addKind( zypp::ResKind::package ); + q.addAttribute( sat::SolvAttr::provides, "kernel" ); + q.setInstalledOnly(); + q.setMatchExact(); + + MIL << "Searching for obsolete kernels." << std::endl; + + for ( auto installedKernel : q ) { + + MIL << "Found installed kernel " << installedKernel << std::endl; + + //we can not simply skip the running kernel to make sure the keep-spec works correctly + if ( _pimpl->_keepRunning + && installedKernel.provides().matches( Capability( "kernel-uname-r", Rel::EQ, Edition( _pimpl->_uname_r ) ) ) + && installedKernel.arch() == _pimpl->_kernelArch ) { + MIL << "Marking kernel " << installedKernel << " as to keep." << std::endl; + packagesToKeep.insert( installedKernel.id() ); + } + + str::smatch what; + str::regex_match( installedKernel.name(), what, kernelFlavourRegex ); + if ( what[1].empty() ) { + WAR << "Could not detect kernel flavour for: " << installedKernel << " ...skipping" << std::endl; + continue; + } + + const std::string flavour = what[1]; + if ( !installedKernels.count( flavour ) ) + installedKernels.insert( std::make_pair( flavour, std::map< Arch, std::map > {} ) ); + + auto &flavourMap = installedKernels[ flavour ]; + if ( !flavourMap.count( installedKernel.arch() ) ) + flavourMap.insert( std::make_pair( installedKernel.arch(), std::map{} ) ); + + flavourMap[ installedKernel.arch() ].insert( std::make_pair( installedKernel.edition(), installedKernel ) ); + } + + _pimpl->fillKeepList( installedKernels, packagesToKeep ); + + + MIL << "Starting to remove obsolete kernels." << std::endl; + + + std::set removedVersions; + + /* + * If there is a KMP or livepatch depending on the package remove it as well. If + * there is another package depending on the kernel keep the kernel. If there is + * a package that depends on a KMP keep the KMP and a kernel required to use the + * KMP. + */ + for ( const auto &flavourMap : installedKernels ) { + + // collect all removed versions of this edition + std::set removedFlavourVersions; + + for ( const auto &archMap : flavourMap.second ) { + for ( const auto &kernelMap : archMap.second ) { + auto &installedKernel = kernelMap.second; + + // if the kernel is locked by the user, its not removed automatically + if ( ui::asSelectable()( installedKernel )->hasLocks() ) + continue; + + // this package is in the keep spec, do not touch + if ( packagesToKeep.count( installedKernel.id() ) ) + continue; + + // try to remove the kernel package, check afterwards if only expected packages have been removed + PoolItem pi( installedKernel ); + if ( !_pimpl->removePackageAndCheck( pi, validRemovals ) ) { + continue; + } + + removedFlavourVersions.insert( installedKernel.edition() ); + + //lets remove the kernel-flavour-devel package too + PoolQuery develPckQ; + develPckQ.addKind( zypp::ResKind::package ); + develPckQ.addDependency( sat::SolvAttr::name, installedKernel.name()+"-devel", Rel::EQ, installedKernel.edition() ); + develPckQ.addDependency( sat::SolvAttr::name, installedKernel.name()+"-devel-debuginfo", Rel::EQ, installedKernel.edition() ); + develPckQ.setInstalledOnly(); + develPckQ.setMatchExact(); + + for ( auto krnlDevPck : develPckQ ) { + + if ( krnlDevPck.arch() != installedKernel.arch() ) + continue; + + PoolItem devPi(krnlDevPck); + _pimpl->removePackageAndCheck( devPi, validDevelRemovals ); + } + } + } + //try to remove the kernel-devel-flavour and kernel-source-flavour packages + _pimpl->cleanDevelAndSrcPackages( validDevelRemovals, removedFlavourVersions, flavourMap.first ); + removedVersions.insert( removedFlavourVersions.begin(), removedFlavourVersions.end() ); + } + + // clean the global -devel and -source packages + _pimpl->cleanDevelAndSrcPackages( validDevelRemovals, removedVersions ); + } + + void PurgeKernels::setUnameR( const std::string &val ) + { + _pimpl->_uname_r = val; + } + + std::string PurgeKernels::unameR() const + { + return _pimpl->_uname_r; + } + + void PurgeKernels::setKernelArch(const Arch &arch) + { + _pimpl->_kernelArch = arch; + } + + Arch PurgeKernels::kernelArch() const + { + return _pimpl->_kernelArch; + } + + void PurgeKernels::setKeepSpec( const std::string &val ) + { + _pimpl->_keepSpec = val; + } + + std::string PurgeKernels::keepSpec() const + { + return _pimpl->_keepSpec; + } + +} diff --git a/zypp/PurgeKernels.h b/zypp/PurgeKernels.h new file mode 100644 index 0000000..c0034d5 --- /dev/null +++ b/zypp/PurgeKernels.h @@ -0,0 +1,72 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/PurgeKernels.h + * +*/ + +#include +#include + +namespace zypp { + + namespace str { + class regex; + } + + /*! + * Implements the logic of the "purge-kernels" command. + * + */ + class PurgeKernels + { + public: + PurgeKernels(); + + + /*! + * Marks all currently obsolete Kernels according to the keep spec. + * \note This will not commit the changes + */ + void markObsoleteKernels(); + + /*! + * Force a specific uname to be set, only used for testing, + * in production the running kernel is detected. + */ + void setUnameR( const std::string &val ); + std::string unameR() const; + + + /*! + * Force a specific kernel arch to be set, only used for testing, + * in production the running kernel arch is detected. + */ + void setKernelArch( const zypp::Arch &arch ); + Arch kernelArch() const; + + /*! + * Overrides the keep spec, the default value is read from ZConfig. + * The keep spec is a string of tokens seperated by ",". + * It only supports 3 different tokens: + * - "running" matches only the currently running kernel of the system + * - "oldest" matches the kernel version for each flavour/arch combination with the lowest edition + * can be modified with a positive number: oldest+n + * - "latest" matches the kernel version for each flavour/arch combination with the highest edition + * can be modified with a negative number: latest-n + */ + void setKeepSpec( const std::string &val ); + std::string keepSpec () const; + + struct Impl; + private: + RW_pointer _pimpl; + }; + +} + diff --git a/zypp/ZConfig.cc b/zypp/ZConfig.cc index 607c90e..ed80fa2 100644 --- a/zypp/ZConfig.cc +++ b/zypp/ZConfig.cc @@ -495,6 +495,10 @@ namespace zypp { cfg_multiversion_path = Pathname(value); } + else if ( entry == "multiversion.kernels" ) + { + cfg_kernel_keep_spec = value; + } else if ( entry == "solver.focus" ) { fromString( value, solver_focus ); @@ -637,6 +641,7 @@ namespace zypp Pathname cfg_vendor_path; Pathname cfg_multiversion_path; + std::string cfg_kernel_keep_spec; Pathname locks_file; Pathname update_data_path; @@ -1182,6 +1187,11 @@ namespace zypp Pathname ZConfig::pluginsPath() const { return _pimpl->pluginsPath.get(); } + string ZConfig::multiversionKernels() const + { + return _pimpl->cfg_kernel_keep_spec; + } + /////////////////////////////////////////////////////////////////// std::ostream & ZConfig::about( std::ostream & str ) const diff --git a/zypp/ZConfig.h b/zypp/ZConfig.h index 73a1a68..884047c 100644 --- a/zypp/ZConfig.h +++ b/zypp/ZConfig.h @@ -534,6 +534,11 @@ namespace zypp */ Pathname pluginsPath() const; + /*! + * Defaults to a empty string, if no keep spec is defined no kernels are removed + */ + std::string multiversionKernels() const; + //@} public: class Impl; diff --git a/zypp/base/Iterator.h b/zypp/base/Iterator.h index f4deb90..8486b8f 100644 --- a/zypp/base/Iterator.h +++ b/zypp/base/Iterator.h @@ -263,6 +263,18 @@ namespace zypp inline typename MapKVIteratorTraits::Value_const_iterator make_map_value_upper_bound( const TMap & map_r, const typename TMap::key_type & key_r ) { return make_transform_iterator( map_r.upper_bound( key_r ), GetPairSecond() ); } + + /** Convenience to create an \ref Iterable over the container keys */ + template + inline Iterable::Key_const_iterator> make_map_key_Iterable( const TMap & map_r ) + { return makeIterable( make_map_key_begin( map_r ), make_map_key_end( map_r ) ); } + + /** Convenience to create an \ref Iterable over the container values */ + template + inline Iterable::Value_const_iterator> make_map_value_Iterable( const TMap & map_r ) + { return makeIterable( make_map_value_begin( map_r ), make_map_value_end( map_r ) ); } + + /** \class function_output_iterator * An output iterator wrapping a unary function object; each time an * element is written into the dereferenced iterator, it is passed as diff --git a/zypp/base/String.h b/zypp/base/String.h index 27c4536..776c2fa 100644 --- a/zypp/base/String.h +++ b/zypp/base/String.h @@ -487,6 +487,33 @@ namespace zypp } /////////////////////////////////////////////////////////////////// + /** \name Trimming whitepace. + * \todo optimize l/r trim. + */ + //@{ + /** To define how to trim. */ + enum Trim { + NO_TRIM = 0x00, + L_TRIM = 0x01, + R_TRIM = 0x02, + TRIM = (L_TRIM|R_TRIM) + }; + + std::string trim( const std::string & s, const Trim trim_r = TRIM ); + std::string trim( std::string && s, const Trim trim_r = TRIM ); + + inline std::string ltrim( const std::string & s ) + { return trim( s, L_TRIM ); } + inline std::string ltrim( std::string && s ) + { return trim( std::move(s), L_TRIM ); } + + inline std::string rtrim( const std::string & s ) + { return trim( s, R_TRIM ); } + inline std::string rtrim( std::string && s ) + { return trim( std::move(s), R_TRIM ); } + //@} + + /////////////////////////////////////////////////////////////////// /** \name Split. */ //@{ /** Split \a line_r into words. @@ -499,7 +526,7 @@ namespace zypp * */ template - unsigned split( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t" ) + unsigned split( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t", const Trim trim_r = NO_TRIM ) { const char * beg = line_r; const char * cur = beg; @@ -513,7 +540,7 @@ namespace zypp while( *cur && !::strchr( sepchars_r, *cur ) ) ++cur; // build string - *result_r = std::string( beg, cur-beg ); + *result_r = trim( std::string( beg, cur-beg ), trim_r ); // skip sepchars while ( *cur && ::strchr( sepchars_r, *cur ) ) ++cur; @@ -521,6 +548,11 @@ namespace zypp return ret; } + template + unsigned split( const C_Str & line_r, TOutputIterator result_r, const Trim trim_r ) + { return split( line_r, result_r, " \t", trim_r ); } + + /** Split \a line_r into words with respect to escape delimeters. * Any sequence of characters in \a sepchars_r is treated as * delimiter if not inside \c "" or \c '' or escaped by \c \. @@ -961,33 +993,6 @@ namespace zypp { return ::strcasestr( str_r, val_r ); } //@} - /////////////////////////////////////////////////////////////////// - /** \name Trimming whitepace. - * \todo optimize l/r trim. - */ - //@{ - /** To define how to trim. */ - enum Trim { - NO_TRIM = 0x00, - L_TRIM = 0x01, - R_TRIM = 0x02, - TRIM = (L_TRIM|R_TRIM) - }; - - std::string trim( const std::string & s, const Trim trim_r = TRIM ); - std::string trim( std::string && s, const Trim trim_r = TRIM ); - - inline std::string ltrim( const std::string & s ) - { return trim( s, L_TRIM ); } - inline std::string ltrim( std::string && s ) - { return trim( std::move(s), L_TRIM ); } - - inline std::string rtrim( const std::string & s ) - { return trim( s, R_TRIM ); } - inline std::string rtrim( std::string && s ) - { return trim( std::move(s), R_TRIM ); } - //@} - std::string stripFirstWord( std::string & line, const bool ltrim_first = true ); std::string stripLastWord( std::string & line, const bool rtrim_first = true ); diff --git a/zypp/sat/detail/PoolImpl.cc b/zypp/sat/detail/PoolImpl.cc index b9f42b3..f01de1b 100644 --- a/zypp/sat/detail/PoolImpl.cc +++ b/zypp/sat/detail/PoolImpl.cc @@ -522,10 +522,10 @@ namespace zypp { localeIds.removed().insert( IdString(lang) ); } } - // Assert that TrackedLocaleIds::current is not empty. - // If, so fill in LanguageCode::enCode as last resort. - if ( localeIds.current().empty() ) - { localeIds.current().insert( IdString(Locale::enCode) ); } + // bsc#1155678: We try to differ between an empty RequestedLocales + // and one containing 'en' (explicit or as fallback). An empty RequestedLocales + // should not even drag in recommended 'en' packages. So we no longer enforce + // 'en' being in the set. } return *_trackedLocaleIdsPtr; } diff --git a/zypp/solver/detail/SATResolver.cc b/zypp/solver/detail/SATResolver.cc index 0d98e19..0fd2b4c 100644 --- a/zypp/solver/detail/SATResolver.cc +++ b/zypp/solver/detail/SATResolver.cc @@ -645,6 +645,16 @@ SATResolver::solverInit(const PoolItemList & weakItems) queue_push( &(_jobQueue), id ); } + // Ad rules for retracted pathces and packages + { + static const IdString retractedToken { "retracted-patch-package()" }; + static const IdString ptfToken { "ptf()" }; + queue_push( &(_jobQueue), SOLVER_BLACKLIST|SOLVER_SOLVABLE_PROVIDES ); + queue_push( &(_jobQueue), retractedToken.id() ); + queue_push( &(_jobQueue), SOLVER_BLACKLIST|SOLVER_SOLVABLE_PROVIDES ); + queue_push( &(_jobQueue), ptfToken.id() ); + } + // Ad rules for changed requestedLocales { const auto & trackedLocaleIds( myPool().trackedLocaleIds() ); diff --git a/zypp/target/RpmPostTransCollector.cc b/zypp/target/RpmPostTransCollector.cc index d449677..fcc6bb5 100644 --- a/zypp/target/RpmPostTransCollector.cc +++ b/zypp/target/RpmPostTransCollector.cc @@ -21,6 +21,7 @@ #include "zypp/ZYppCallbacks.h" #include "zypp/ExternalProgram.h" #include "zypp/target/rpm/RpmHeader.h" +#include "zypp/target/rpm/librpmDb.h" #include "zypp/ZConfig.h" #include "zypp/ZYppCallbacks.h" @@ -73,8 +74,8 @@ namespace zypp out << "#! " << pkg->tag_posttransprog() << endl << pkg->tag_posttrans() << endl; } - _scripts.push_back( script.path().basename() ); - MIL << "COLLECT posttrans: " << PathInfo( script.path() ) << endl; + _scripts.push_back( std::make_pair( script.path().basename(), pkg->tag_name() ) ); + MIL << "COLLECT posttrans: '" << PathInfo( script.path() ) << "' for package: '" << pkg->tag_name() << "'" << endl; //DBG << "PROG: " << pkg->tag_posttransprog() << endl; //DBG << "SCRPT: " << pkg->tag_posttrans() << endl; return true; @@ -97,7 +98,8 @@ namespace zypp bool firstScript = true; while ( ! _scripts.empty() ) { - const std::string & script = _scripts.front(); + const auto &scriptPair = _scripts.front(); + const std::string & script = scriptPair.first; const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix scriptProgress.name( str::Format(_("Executing %%posttrans script '%1%'")) % pkgident ); @@ -119,8 +121,13 @@ namespace zypp return false; } - MIL << "EXECUTE posttrans: " << script << endl; - ExternalProgram prog( (noRootScriptDir/script).asString() + " 0", ExternalProgram::Stderr_To_Stdout, false, -1, true, _root ); + int npkgs = 0; + rpm::librpmDb::db_const_iterator it; + for ( it.findByName( scriptPair.second ); *it; ++it ) + npkgs++; + + MIL << "EXECUTE posttrans: " << script << " with argument: " << npkgs << endl; + ExternalProgram prog( (noRootScriptDir/script).asString() + " " +str::numstring( npkgs ), ExternalProgram::Stderr_To_Stdout, false, -1, true, _root ); str::Str collect; for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() ) @@ -176,8 +183,8 @@ namespace zypp msg << "%posttrans scripts skipped while aborting:\n"; for ( const auto & script : _scripts ) { - const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix - WAR << "UNEXECUTED posttrans: " << script << endl; + const std::string & pkgident( script.first.substr( 0, script.first.size()-6 ) ); // strip tmp file suffix + WAR << "UNEXECUTED posttrans: " << script.first << endl; msg << " " << pkgident << "\n"; } @@ -199,7 +206,7 @@ namespace zypp private: Pathname _root; - std::list _scripts; + std::list< std::pair< std::string, std::string > > _scripts; boost::scoped_ptr _ptrTmpdir; }; -- 2.7.4