Hello community, here is the log from the commit of package libzypp for openSUSE:Factory checked in at 2018-08-02 14:50:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libzypp (Old) and /work/SRC/openSUSE:Factory/.libzypp.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libzypp" Thu Aug 2 14:50:24 2018 rev:401 rq:625747 version:17.5.2 Changes: -------- --- /work/SRC/openSUSE:Factory/libzypp/libzypp.changes 2018-06-27 10:17:16.005106943 +0200 +++ /work/SRC/openSUSE:Factory/.libzypp.new/libzypp.changes 2018-08-02 14:50:27.859509418 +0200 @@ -1,0 +2,29 @@ +Thu Jul 19 12:57:21 CEST 2018 - [email protected] + +- Prevent the system from sleeping during a commit + (fixes openSUSE/zypper#135) +- RepoManager: Explicitly request repo2solv to generate application + pseudo packages. +- version 17.5.2 (2) + +------------------------------------------------------------------- +Wed Jul 18 10:55:49 CEST 2018 - [email protected] + +- libzypp-devel should not require cmake (bsc#1101349) +- Avoid zombies from ExternalProgram +- Update ApiConfig +- fix typo +- version 17.5.1 (2) + +------------------------------------------------------------------- +Mon Jul 9 14:43:15 CEST 2018 - [email protected] + +- HardLocksFile: Prevent against empty commit without Target having + been been loaded (bsc#1096803) +- lsof: use '-K i' if lsof supports it (bsc#1099847) +- PackageProvider: Validate deta rpms before caching (bsc#1091624) +- PackageProvider: Validate downloaded rpm package signatures + before caching (bsc#1091624) +- version 17.5.0 (2) + +------------------------------------------------------------------- Old: ---- libzypp-17.4.0.tar.bz2 New: ---- libzypp-17.5.2.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libzypp.spec ++++++ --- /var/tmp/diff_new_pack.V9iFze/_old 2018-08-02 14:50:28.583510613 +0200 +++ /var/tmp/diff_new_pack.V9iFze/_new 2018-08-02 14:50:28.583510613 +0200 @@ -17,7 +17,7 @@ Name: libzypp -Version: 17.4.0 +Version: 17.5.2 Release: 0 Url: git://gitorious.org/opensuse/libzypp.git Summary: Package, Patch, Pattern, and Product Management @@ -163,7 +163,6 @@ %else Requires: hal-devel %endif -Requires: cmake %if 0%{?suse_version} %if 0%{?suse_version} >= 1100 # Code11+ ++++++ libzypp-17.4.0.tar.bz2 -> libzypp-17.5.2.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/VERSION.cmake new/libzypp-17.5.2/VERSION.cmake --- old/libzypp-17.4.0/VERSION.cmake 2018-06-25 10:57:11.000000000 +0200 +++ new/libzypp-17.5.2/VERSION.cmake 2018-07-19 13:09:00.000000000 +0200 @@ -60,9 +60,9 @@ # SET(LIBZYPP_MAJOR "17") SET(LIBZYPP_COMPATMINOR "2") -SET(LIBZYPP_MINOR "4") -SET(LIBZYPP_PATCH "0") +SET(LIBZYPP_MINOR "5") +SET(LIBZYPP_PATCH "2") # -# LAST RELEASED: 17.4.0 (2) +# LAST RELEASED: 17.5.2 (2) # (The number in parenthesis is LIBZYPP_COMPATMINOR) #======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/libzypp.spec.cmake new/libzypp-17.5.2/libzypp.spec.cmake --- old/libzypp-17.4.0/libzypp.spec.cmake 2018-03-09 11:26:43.000000000 +0100 +++ new/libzypp-17.5.2/libzypp.spec.cmake 2018-07-17 12:24:54.000000000 +0200 @@ -163,7 +163,6 @@ %else Requires: hal-devel %endif -Requires: cmake %if 0%{?suse_version} %if 0%{?suse_version} >= 1100 # Code11+ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/package/libzypp.changes new/libzypp-17.5.2/package/libzypp.changes --- old/libzypp-17.4.0/package/libzypp.changes 2018-06-25 10:57:11.000000000 +0200 +++ new/libzypp-17.5.2/package/libzypp.changes 2018-07-19 13:09:00.000000000 +0200 @@ -1,4 +1,33 @@ ------------------------------------------------------------------- +Thu Jul 19 12:57:21 CEST 2018 - [email protected] + +- Prevent the system from sleeping during a commit + (fixes openSUSE/zypper#135) +- RepoManager: Explicitly request repo2solv to generate application + pseudo packages. +- version 17.5.2 (2) + +------------------------------------------------------------------- +Wed Jul 18 10:55:49 CEST 2018 - [email protected] + +- libzypp-devel should not require cmake (bsc#1101349) +- Avoid zombies from ExternalProgram +- Update ApiConfig +- fix typo +- version 17.5.1 (2) + +------------------------------------------------------------------- +Mon Jul 9 14:43:15 CEST 2018 - [email protected] + +- HardLocksFile: Prevent against empty commit without Target having + been been loaded (bsc#1096803) +- lsof: use '-K i' if lsof supports it (bsc#1099847) +- PackageProvider: Validate deta rpms before caching (bsc#1091624) +- PackageProvider: Validate downloaded rpm package signatures + before caching (bsc#1091624) +- version 17.5.0 (2) + +------------------------------------------------------------------- Mon Jun 25 10:48:55 CEST 2018 - [email protected] - Flags: make it std=c++14 ready diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/po/de.po new/libzypp-17.5.2/po/de.po --- old/libzypp-17.4.0/po/de.po 2018-04-17 17:19:03.000000000 +0200 +++ new/libzypp-17.5.2/po/de.po 2018-07-20 11:46:11.000000000 +0200 @@ -4647,7 +4647,7 @@ #: zypp/target/RpmPostTransCollector.cc:160 #, c-format, boost-format msgid "Executing %posttrans scripts" -msgstr "%p osttrans scripts werden ausgeführt" +msgstr "%posttrans scripts werden ausgeführt" #: zypp/target/TargetImpl.cc:310 msgid " executed" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/tests/repo/yum/data/extensions/repodata/repomd.xml new/libzypp-17.5.2/tests/repo/yum/data/extensions/repodata/repomd.xml --- old/libzypp-17.4.0/tests/repo/yum/data/extensions/repodata/repomd.xml 2018-06-25 10:57:11.000000000 +0200 +++ new/libzypp-17.5.2/tests/repo/yum/data/extensions/repodata/repomd.xml 2018-07-20 11:46:11.000000000 +0200 @@ -37,8 +37,8 @@ <data type="suseinfo"> <location href="repodata/suseinfo.xml.gz"/> - <checksum type="sha">e0b9149c1b7f48c952e9b3ea996669d8d0d9e1e8</checksum> + <checksum type="sha">34599f8eed67ec256299d295617ceaf05ae7ebdd</checksum> <timestamp>1227279057.0</timestamp> - <open-checksum type="sha">b17c055bef95bca397faffdf028cfa91dd1b24bc</open-checksum> + <open-checksum type="sha">a3011438085ac55f06c68053201ea3ded17ee85c</open-checksum> </data> </repomd> Binary files old/libzypp-17.4.0/tests/repo/yum/data/extensions/repodata/suseinfo.xml.gz and new/libzypp-17.5.2/tests/repo/yum/data/extensions/repodata/suseinfo.xml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/tests/zypp/base/CMakeLists.txt new/libzypp-17.5.2/tests/zypp/base/CMakeLists.txt --- old/libzypp-17.4.0/tests/zypp/base/CMakeLists.txt 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/tests/zypp/base/CMakeLists.txt 2018-07-16 16:37:05.000000000 +0200 @@ -2,3 +2,4 @@ ADD_TESTS(Sysconfig ) ADD_TESTS(String ) ADD_TESTS( InterProcessMutex InterProcessMutex2 ) +ADD_TESTS(CleanerThread ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/tests/zypp/base/CleanerThread_test.cc new/libzypp-17.5.2/tests/zypp/base/CleanerThread_test.cc --- old/libzypp-17.4.0/tests/zypp/base/CleanerThread_test.cc 1970-01-01 01:00:00.000000000 +0100 +++ new/libzypp-17.5.2/tests/zypp/base/CleanerThread_test.cc 2018-07-16 16:37:05.000000000 +0200 @@ -0,0 +1,26 @@ +#include "TestSetup.h" +#include "zypp/ExternalProgram.h" + +#include <chrono> +#include <thread> +#include <sys/types.h> +#include <sys/wait.h> + +#define BOOST_TEST_MODULE CleanerThread + +using zypp::ExternalProgram; + +BOOST_AUTO_TEST_CASE( CleanerThread_default ) +{ + pid_t pid = -1; + { + ExternalProgram proc( "bash -c 'sleep 2'", ExternalProgram::Normal_Stderr ); + BOOST_CHECK( proc.running() ); + pid = proc.getpid(); + } + std::this_thread::sleep_for( std::chrono::seconds(4) ); + int status = 0; + int res = waitpid( pid, &status, WNOHANG ); + BOOST_CHECK_EQUAL( res, -1 ); + BOOST_CHECK_EQUAL( errno, ECHILD ); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/APIConfig.h new/libzypp-17.5.2/zypp/APIConfig.h --- old/libzypp-17.4.0/zypp/APIConfig.h 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/APIConfig.h 2018-07-16 16:37:05.000000000 +0200 @@ -31,18 +31,20 @@ * \endcode };*/ #if __GNUC__ >= 4 - #define ZYPP_HELPER_DLL_EXPORT __attribute__ ((visibility ("default"))) - #define ZYPP_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden"))) + #define ZYPP_DECL_EXPORT __attribute__ ((visibility ("default"))) + #define ZYPP_DECL_IMPORT __attribute__ ((visibility ("default"))) + #define ZYPP_DECL_HIDDEN __attribute__ ((visibility ("hidden"))) #else - #define ZYPP_HELPER_DLL_EXPORT - #define ZYPP_HELPER_DLL_LOCAL + #define ZYPP_DECL_EXPORT + #define ZYPP_DECL_IMPORT + #define ZYPP_DECL_HIDDEN #endif #ifdef ZYPP_DLL //defined if zypp is compiled as DLL - #define ZYPP_API ZYPP_HELPER_DLL_EXPORT - #define ZYPP_LOCAL ZYPP_HELPER_DLL_LOCAL + #define ZYPP_API ZYPP_DECL_EXPORT + #define ZYPP_LOCAL ZYPP_DECL_HIDDEN #else - #define ZYPP_API + #define ZYPP_API ZYPP_DECL_IMPORT #define ZYPP_LOCAL #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/CMakeLists.txt new/libzypp-17.5.2/zypp/CMakeLists.txt --- old/libzypp-17.4.0/zypp/CMakeLists.txt 2018-03-20 17:04:51.000000000 +0100 +++ new/libzypp-17.5.2/zypp/CMakeLists.txt 2018-07-19 08:52:30.000000000 +0200 @@ -72,6 +72,7 @@ ServiceInfo.cc Signature.cc SrcPackage.cc + ShutdownLock.cc SysContent.cc Target.cc TmpPath.cc @@ -202,6 +203,7 @@ SET( zypp_base_SRCS base/InterProcessMutex.cc base/Backtrace.cc + base/CleanerThread.cc base/DrunkenBishop.cc base/SerialNumber.cc base/Random.cc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/CountryCode.cc new/libzypp-17.5.2/zypp/CountryCode.cc --- old/libzypp-17.4.0/zypp/CountryCode.cc 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/CountryCode.cc 2018-07-16 16:37:05.000000000 +0200 @@ -100,7 +100,7 @@ nval.second = link->second; } } - MIL << "Remember CountryCode '" << code_r << "': '" << nval.second << "'" << endl; + MIL << "Remember CountryCode '" << code_r << "': '" << (nval.second?nval.second:"Unknown country") << "'" << endl; return (_indexMap[index_r] = _codeMap.insert( nval ).first); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/ExternalProgram.cc new/libzypp-17.5.2/zypp/ExternalProgram.cc --- old/libzypp-17.4.0/zypp/ExternalProgram.cc 2017-11-07 16:18:51.000000000 +0100 +++ new/libzypp-17.5.2/zypp/ExternalProgram.cc 2018-07-19 08:52:30.000000000 +0200 @@ -27,6 +27,7 @@ #include "zypp/base/String.h" #include "zypp/base/Gettext.h" #include "zypp/ExternalProgram.h" +#include "zypp/base/CleanerThread_p.h" using namespace std; @@ -167,16 +168,22 @@ ExternalProgram::~ExternalProgram() - {} + { + if ( running() ) { + // we got destructed while the external process is still alive + // make sure the zombie is cleaned up once it exits + CleanerThread::watchPID( pid ); + } + } - void ExternalProgram::start_program( const char *const *argv, + void ExternalProgram::start_program(const char *const *argv, const Environment & environment, Stderr_Disposition stderr_disp, int stderr_fd, bool default_locale, - const char * root ) + const char * root , bool switch_pgid) { pid = -1; _exitStatus = 0; @@ -300,6 +307,8 @@ } else { + if ( switch_pgid ) + setpgid( 0, 0); renumber_fd (to_external[0], 0); // set new stdin ::close(from_external[0]); // Belongs to father process diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/ExternalProgram.h new/libzypp-17.5.2/zypp/ExternalProgram.h --- old/libzypp-17.4.0/zypp/ExternalProgram.h 2018-03-23 18:24:02.000000000 +0100 +++ new/libzypp-17.5.2/zypp/ExternalProgram.h 2018-07-19 08:52:30.000000000 +0200 @@ -19,6 +19,7 @@ #include <string> #include <vector> +#include "zypp/APIConfig.h" #include "zypp/base/ExternalDataSource.h" #include "zypp/Pathname.h" @@ -225,10 +226,12 @@ /** Remember execution errors like failed fork/exec. */ std::string _execError; + protected: + void start_program (const char *const *argv, const Environment & environment, Stderr_Disposition stderr_disp = Normal_Stderr, int stderr_fd = -1, bool default_locale = false, - const char* root = NULL); + const char* root = NULL, bool switch_pgid = false); }; @@ -299,6 +302,22 @@ std::string _buffer; }; + /** ExternalProgram extended to change the progress group ID after forking. + * \see \ref ExternalProgram + */ + class ZYPP_LOCAL ExternalProgramWithSeperatePgid : public ExternalProgram + { + public: + ExternalProgramWithSeperatePgid (const char *const *argv, + Stderr_Disposition stderr_disp = Normal_Stderr, + int stderr_fd = -1, bool default_locale = false, + const Pathname& root = "") : ExternalProgram() + { + start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str(), true ); + } + + }; + } // namespace zypp #endif // ZYPP_EXTERNALPROGRAM_H diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/FileChecker.h new/libzypp-17.5.2/zypp/FileChecker.h --- old/libzypp-17.4.0/zypp/FileChecker.h 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/FileChecker.h 2018-07-16 16:37:05.000000000 +0200 @@ -94,7 +94,6 @@ { public: typedef SignatureCheckException ExceptionType; - typedef function<void ( const SignatureFileChecker & checker, const Pathname & file )> OnSigValidated; public: /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/LanguageCode.cc new/libzypp-17.5.2/zypp/LanguageCode.cc --- old/libzypp-17.4.0/zypp/LanguageCode.cc 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/LanguageCode.cc 2018-07-16 16:37:05.000000000 +0200 @@ -99,7 +99,7 @@ nval.second = link->second; } } - MIL << "Remember LanguageCode '" << code_r << "': '" << nval.second << "'" << endl; + MIL << "Remember LanguageCode '" << code_r << "': '" << (nval.second?nval.second:"Unknown language") << "'" << endl; return (_indexMap[index_r] = _codeMap.insert( nval ).first); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/ProvideFilePolicy.h new/libzypp-17.5.2/zypp/ProvideFilePolicy.h --- old/libzypp-17.4.0/zypp/ProvideFilePolicy.h 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/ProvideFilePolicy.h 2018-07-16 16:37:05.000000000 +0200 @@ -14,16 +14,18 @@ #include "zypp/base/Function.h" #include "zypp/base/Functional.h" +#include "zypp/FileChecker.h" /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////// -// CLASS NAME : ProvideFilePolicy - - /** Policy for \ref provideFile. - * Provides callback hook for progress reporting. - */ +{ + /////////////////////////////////////////////////////////////////// + /// \class ProvideFilePolicy + /// \brief Policy for \ref provideFile and \ref RepoMediaAccess. + /// + /// Provides callback hook for progress reporting and an optional + /// \ref FileCecker passed down to the \ref Fetcher. + /////////////////////////////////////////////////////////////////// class ProvideFilePolicy { public: @@ -38,9 +40,16 @@ bool progress( int value ) const; public: - typedef function<bool ()> FailOnChecksumErrorCB; ///< Legacy to remain bincompat + /** Add a \ref FileCecker passed down to the \ref Fetcher */ + ProvideFilePolicy & fileChecker( FileChecker fileChecker_r ) + { _fileChecker = std::move(fileChecker_r); return *this; } + + /** The \ref FileCecker. */ + const FileChecker & fileChecker() const + { return _fileChecker; } + private: - FailOnChecksumErrorCB _failOnChecksumErrorCB; ///< Legacy to remain bincompat + FileChecker _fileChecker; ProgressCB _progressCB; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/RepoManager.cc new/libzypp-17.5.2/zypp/RepoManager.cc --- old/libzypp-17.4.0/zypp/RepoManager.cc 2018-04-05 16:06:23.000000000 +0200 +++ new/libzypp-17.5.2/zypp/RepoManager.cc 2018-07-18 12:09:57.000000000 +0200 @@ -1348,6 +1348,7 @@ cmd.push_back( "-o" ); cmd.push_back( solvfile.asString() ); cmd.push_back( "-X" ); // autogenerate pattern from pattern-package + cmd.push_back( "-A" ); // autogenerate application pseudo packages if ( repokind == RepoType::RPMPLAINDIR ) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/Repository.h new/libzypp-17.5.2/zypp/Repository.h --- old/libzypp-17.4.0/zypp/Repository.h 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/Repository.h 2018-07-16 16:37:05.000000000 +0200 @@ -420,9 +420,9 @@ * MIL << "3 " << satpool << endl; * \endcode * \code - * 1 sat::pool(){0repos|2slov} - * 2 sat::pool(){1repos|2612slov} - * 3 sat::pool(){0repos|2slov} + * 1 sat::pool(){0repos|2solv} + * 2 sat::pool(){1repos|2612solv} + * 3 sat::pool(){0repos|2solv} * \endcode * Leaving the block without calling <tt>tmprepo.resetDispose();</tt> * before, will automatically remove the \ref Repo from it's \ref Pool. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/ShutdownLock.cc new/libzypp-17.5.2/zypp/ShutdownLock.cc --- old/libzypp-17.4.0/zypp/ShutdownLock.cc 1970-01-01 01:00:00.000000000 +0100 +++ new/libzypp-17.5.2/zypp/ShutdownLock.cc 2018-07-19 08:52:30.000000000 +0200 @@ -0,0 +1,32 @@ +#include "ShutdownLock_p.h" + +#include "zypp/ExternalProgram.h" +#include <iostream> + +zypp::ShutdownLock::ShutdownLock(const std::string &reason) +{ + try { + + std::string whyStr = str::form("--why=%s", reason.c_str()); + + const char* argv[] = + { + "/usr/bin/systemd-inhibit", + "--what=sleep:shutdown:idle", + "--who=zypp", + "--mode=block", + whyStr.c_str(), + "/usr/bin/cat", + NULL + }; + _prog = shared_ptr<ExternalProgramWithSeperatePgid>( new ExternalProgramWithSeperatePgid( argv, ExternalProgram::Discard_Stderr ) ); + } catch (...) { + } +} + +zypp::ShutdownLock::~ShutdownLock() +{ + if (_prog) { + _prog->kill(); + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/ShutdownLock_p.h new/libzypp-17.5.2/zypp/ShutdownLock_p.h --- old/libzypp-17.4.0/zypp/ShutdownLock_p.h 1970-01-01 01:00:00.000000000 +0100 +++ new/libzypp-17.5.2/zypp/ShutdownLock_p.h 2018-07-19 08:52:30.000000000 +0200 @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ShutdownLock_p.h + * +*/ + +#ifndef ZYPP_SHUTDOWNLOCK_P_H_INCLUDED +#define ZYPP_SHUTDOWNLOCK_P_H_INCLUDED + +#include <string> + +#include "zypp/APIConfig.h" +#include "zypp/base/PtrTypes.h" + +namespace zypp +{ + +class ExternalProgramWithSeperatePgid; + +/** + * Attempts to create a lock to prevent the system + * from going into hibernate/shutdown. The lock is automatically + * released when the object is destroyed. + */ +class ZYPP_LOCAL ShutdownLock +{ +public: + ShutdownLock( const std::string &reason ); + ~ShutdownLock(); + +private: + shared_ptr<ExternalProgramWithSeperatePgid> _prog; + +}; + +} + + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/base/CleanerThread.cc new/libzypp-17.5.2/zypp/base/CleanerThread.cc --- old/libzypp-17.4.0/zypp/base/CleanerThread.cc 1970-01-01 01:00:00.000000000 +0100 +++ new/libzypp-17.5.2/zypp/base/CleanerThread.cc 2018-07-16 16:37:05.000000000 +0200 @@ -0,0 +1,78 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/CleanerThread.cc + */ + +#include "zypp/base/CleanerThread_p.h" +#include <algorithm> +#include <thread> +#include <mutex> +#include <condition_variable> +#include <chrono> +#include <vector> +#include <sys/types.h> +#include <sys/wait.h> + +struct CleanerData +{ + static CleanerData &instance () + { + // C++11 requires that this is thread safe "magic statics" + // this is a intentional leak and will live until the application exits + static CleanerData *data( new CleanerData ); + return *data; + } + + CleanerData () + { + std::thread t ( [&](){ + this->run(); + } ); + t.detach(); //we will control the thread otherwise + } + + void run () + { + std::unique_lock<std::mutex> lk( _m ); + + while ( true ) + { + auto filter = []( pid_t pid ){ + int status = 0; + int res = waitpid( pid, &status, WNOHANG ); + // we either got an error, or the child has exited, remove it from list + bool removeMe = ( res == -1 || res == pid ); + return removeMe; + }; + _watchedPIDs.erase( std::remove_if( _watchedPIDs.begin(), _watchedPIDs.end(), filter ), _watchedPIDs.end() ); + + if ( _watchedPIDs.size() ) + _cv.wait_for( lk, std::chrono::milliseconds(100) ); + else + _cv.wait( lk ); + } + } + + std::mutex _m; // < locks all data in CleanerData, do not access it without owning the mutex + std::condition_variable _cv; + + std::vector<pid_t> _watchedPIDs; +}; + + +void zypp::CleanerThread::watchPID( pid_t pid_r ) +{ + CleanerData &data = CleanerData::instance(); + { + std::lock_guard<std::mutex> guard( data._m ); + data._watchedPIDs.push_back( pid_r ); + } + //wake the thread up + data._cv.notify_one(); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/base/CleanerThread_p.h new/libzypp-17.5.2/zypp/base/CleanerThread_p.h --- old/libzypp-17.4.0/zypp/base/CleanerThread_p.h 1970-01-01 01:00:00.000000000 +0100 +++ new/libzypp-17.5.2/zypp/base/CleanerThread_p.h 2018-07-16 16:37:05.000000000 +0200 @@ -0,0 +1,28 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/CleanerThread_p.h + * This file contains private API, it will change without notice. + * You have been warned. +*/ + +#include <unistd.h> + +#include "zypp/APIConfig.h" + +namespace zypp +{ + + class ZYPP_LOCAL CleanerThread + { + public: + CleanerThread() = delete; + static void watchPID ( pid_t pid_r ); + }; + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/base/LogControl.cc new/libzypp-17.5.2/zypp/base/LogControl.cc --- old/libzypp-17.4.0/zypp/base/LogControl.cc 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/base/LogControl.cc 2018-07-16 16:37:05.000000000 +0200 @@ -319,7 +319,13 @@ { _streamtable[group_r][level_r].reset( new Loglinestream( group_r, level_r ) ); } - return _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r ); + std::ostream & ret( _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r ) ); + if ( !ret ) + { + ret.clear(); + ret << "---<RESET LOGSTREAM FROM FAILED STATE]" << endl; + } + return ret; } /** Format and write out a logline from Loglinebuf. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/misc/CheckAccessDeleted.cc new/libzypp-17.5.2/zypp/misc/CheckAccessDeleted.cc --- old/libzypp-17.4.0/zypp/misc/CheckAccessDeleted.cc 2018-06-11 15:21:01.000000000 +0200 +++ new/libzypp-17.5.2/zypp/misc/CheckAccessDeleted.cc 2018-07-16 16:37:05.000000000 +0200 @@ -24,6 +24,7 @@ #include "zypp/base/Regex.h" #include "zypp/base/IOStream.h" #include "zypp/base/InputStream.h" +#include "zypp/target/rpm/librpmDb.h" #include "zypp/misc/CheckAccessDeleted.h" @@ -74,6 +75,29 @@ ino_t pidNS; }; + + /** bsc#1099847: Check for lsof version < 4.90 which does not support '-K i' + * Just a quick check to allow code15 libzypp runnig in a code12 environment. + */ + bool lsofNoOptKi() + { + using target::rpm::librpmDb; + // RpmDb access is blocked while the Target is not initialized. + // Launching the Target just for this query would be an overkill. + struct TmpUnblock { + TmpUnblock() + : _wasBlocked( librpmDb::isBlocked() ) + { if ( _wasBlocked ) librpmDb::unblockAccess(); } + ~TmpUnblock() + { if ( _wasBlocked ) librpmDb::blockAccess(); } + private: + bool _wasBlocked; + } tmpUnblock; + + librpmDb::db_const_iterator it; + return( it.findPackage( "lsof" ) && it->tag_edition() < Edition("4.90") ); + } + } //namespace ///////////////////////////////////////////////////////////////// @@ -312,10 +336,9 @@ CheckAccessDeleted::size_type CheckAccessDeleted::check( bool verbose_r ) { - static const char* argv[] = - { - "lsof", "-n", "-FpcuLRftkn0", NULL - }; + static const char* argv[] = { "lsof", "-n", "-FpcuLRftkn0", "-K", "i", NULL }; + if ( lsofNoOptKi() ) + argv[3] = NULL; _pimpl->_verbose = verbose_r; _pimpl->_fromLsofFileMode = false; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/repo/PackageProvider.cc new/libzypp-17.5.2/zypp/repo/PackageProvider.cc --- old/libzypp-17.4.0/zypp/repo/PackageProvider.cc 2017-10-12 18:16:06.000000000 +0200 +++ new/libzypp-17.5.2/zypp/repo/PackageProvider.cc 2018-07-16 16:37:05.000000000 +0200 @@ -41,6 +41,27 @@ namespace repo { /////////////////////////////////////////////////////////////////// + /// \class RpmSigCheckException + /// \brief Exception thrown by \ref PackageProviderImpl::rpmSigFileChecker + /////////////////////////////////////////////////////////////////// + class RpmSigCheckException : public FileCheckException + { + public: + RpmSigCheckException( repo::DownloadResolvableReport::Action action_r, std::string msg_r = "RpmSigCheckException" ) + : FileCheckException( std::move(msg_r) ) + , _action( std::move(action_r) ) + {} + + /** Users final decision how to proceed */ + const repo::DownloadResolvableReport::Action & action() const + { return _action; } + + private: + repo::DownloadResolvableReport::Action _action; + }; + + + /////////////////////////////////////////////////////////////////// // class PackageProviderPolicy /////////////////////////////////////////////////////////////////// @@ -151,6 +172,7 @@ ProvideFilePolicy policy; policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) ); + policy.fileChecker( bind( &Base::rpmSigFileChecker, this, _1 ) ); return _access.provideFile( _package->repoInfo(), loc, policy ); } @@ -163,8 +185,72 @@ bool progressPackageDownload( int value ) const { return report()->progress( value, _package ); } + + /** \name Validate a rpm packages signature. + * + * This is the \ref FileChecker passed down to the \ref Fetcher to validate + * a provided rpm package. This builtin checker includes the workflow + * communicating with the user in case of a problem with the package + * signature. + * + * \throws RpmSigCheckException if the package is not accepted, propagating + * the users decision how to proceed (\ref DownloadResolvableReport::Action). + * + * \note This check is also needed, if the the rpm is built locally by using + * delta rpms! \ref \see RpmPackageProvider + */ + //@{ + void rpmSigFileChecker( const Pathname & file_r ) const + { + const RepoInfo & info = _package->repoInfo(); + if ( info.pkgGpgCheck() ) + { + UserData userData( "pkgGpgCheck" ); + ResObject::constPtr roptr( _package ); // gcc6 needs it more explcit. Has problem deducing + userData.set( "ResObject", roptr ); // a type for '_package->asKind<ResObject>()'... + /*legacy:*/userData.set( "Package", roptr->asKind<Package>() ); + userData.set( "Localpath", file_r ); + RpmDb::CheckPackageResult res = packageSigCheck( file_r, info.pkgGpgCheckIsMandatory(), userData ); + + // publish the checkresult, even if it is OK. Apps may want to report something... + report()->pkgGpgCheck( userData ); + + if ( res != RpmDb::CHK_OK ) + { + if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action + { + resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) ); + } + else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details) + { + defaultReportSignatureError( res ); + } + else // no advice from user => usedefaults + { + switch ( res ) + { + case RpmDb::CHK_OK: // Signature is OK + break; + + case RpmDb::CHK_NOKEY: // Public key is unavailable + case RpmDb::CHK_NOTFOUND: // Signature is unknown type + case RpmDb::CHK_FAIL: // Signature does not verify + case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted + case RpmDb::CHK_ERROR: // File does not exist or can't be opened + case RpmDb::CHK_NOSIG: // File is unsigned + default: + // report problem (w. details), throw if to abort, else retry/ignore + defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) ); + break; + } + } + } + } + } + typedef target::rpm::RpmDb RpmDb; + /** Actual rpm package signature check. */ RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, bool isMandatory_r, UserData & userData ) const { if ( !_target ) @@ -189,22 +275,20 @@ return ret; } - /** React on signature verification error user action + /** React on signature verification error user action. * \note: IGNORE == accept insecure file (no SkipRequestException!) */ void resolveSignatureErrorAction( repo::DownloadResolvableReport::Action action_r ) const { switch ( action_r ) { - case repo::DownloadResolvableReport::RETRY: - _retry = true; - break; case repo::DownloadResolvableReport::IGNORE: WAR << _package->asUserString() << ": " << "User requested to accept insecure file" << endl; break; default: + case repo::DownloadResolvableReport::RETRY: case repo::DownloadResolvableReport::ABORT: - ZYPP_THROW(AbortRequestException("User requested to abort")); + ZYPP_THROW(RpmSigCheckException(action_r,"Signature verification failed")); break; } } @@ -218,6 +302,7 @@ msg << "\n" << detail_r; resolveSignatureErrorAction( report()->problem( _package, repo::DownloadResolvableReport::INVALID, msg.str() ) ); } + //@} protected: PackageProviderPolicy _policy; @@ -307,70 +392,6 @@ try { ret = doProvidePackage(); - - if ( info.pkgGpgCheck() ) - { - UserData userData( "pkgGpgCheck" ); - ResObject::constPtr roptr( _package ); // gcc6 needs it more explcit. Has problem deducing - userData.set( "ResObject", roptr ); // a type for '_package->asKind<ResObject>()'... - /*legacy:*/userData.set( "Package", roptr->asKind<Package>() ); - userData.set( "Localpath", ret.value() ); -#if ( 1 ) - bool pkgGpgCheckIsMandatory = info.pkgGpgCheckIsMandatory(); - if ( str::startsWith( VERSION, "16.15." ) ) - { - // BSC#1038984: For a short period of time, libzypp-16.15.x - // will silently accept unsigned packages IFF a repositories gpgcheck - // configuration is explicitly turned OFF like this: - // gpgcheck = 0 - // repo_gpgcheck = 0 - // pkg_gpgcheck = 1 - // This will allow some already released products to adapt to the behavioral - // changes introduced by fixing BSC#1038984, while systems with a default - // configuration (gpgcheck = 1) already benefit from the fix. - // With libzypp-16.16.x the above configuration will reject unsigned packages - // as it should. - if ( pkgGpgCheckIsMandatory && !info.gpgCheck() && !info.repoGpgCheck() ) - pkgGpgCheckIsMandatory = false; - } - RpmDb::CheckPackageResult res = packageSigCheck( ret, pkgGpgCheckIsMandatory, userData ); -#else - RpmDb::CheckPackageResult res = packageSigCheck( ret, info.pkgGpgCheckIsMandatory(), userData ); -#endif - // publish the checkresult, even if it is OK. Apps may want to report something... - report()->pkgGpgCheck( userData ); - - if ( res != RpmDb::CHK_OK ) - { - if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action - { - resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) ); - } - else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details) - { - defaultReportSignatureError( res ); - } - else // no advice from user => usedefaults - { - switch ( res ) - { - case RpmDb::CHK_OK: // Signature is OK - break; - - case RpmDb::CHK_NOKEY: // Public key is unavailable - case RpmDb::CHK_NOTFOUND: // Signature is unknown type - case RpmDb::CHK_FAIL: // Signature does not verify - case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted - case RpmDb::CHK_ERROR: // File does not exist or can't be opened - case RpmDb::CHK_NOSIG: // File is unsigned - default: - // report problem (w. details), throw if to abort, else retry/ignore - defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) ); - break; - } - } - } - } } catch ( const UserRequestException & excpt ) { @@ -378,6 +399,28 @@ if ( ! _retry ) ZYPP_RETHROW( excpt ); } + catch ( const RpmSigCheckException & excpt ) + { + ERR << "Failed to provide Package " << _package << endl; + if ( ! _retry ) + { + // Signature verification error was already reported by the + // rpmSigFileChecker. Just handle the users action decision: + switch ( excpt.action() ) + { + case repo::DownloadResolvableReport::RETRY: + _retry = true; + break; + case repo::DownloadResolvableReport::IGNORE: + ZYPP_THROW(SkipRequestException("User requested skip of corrupted file")); + break; + default: + case repo::DownloadResolvableReport::ABORT: + ZYPP_THROW(AbortRequestException("User requested to abort")); + break; + } + } + } catch ( const FileCheckException & excpt ) { ERR << "Failed to provide Package " << _package << endl; @@ -393,11 +436,10 @@ case repo::DownloadResolvableReport::IGNORE: ZYPP_THROW(SkipRequestException("User requested skip of corrupted file")); break; + default: case repo::DownloadResolvableReport::ABORT: ZYPP_THROW(AbortRequestException("User requested to abort")); break; - default: - break; } } } @@ -421,22 +463,16 @@ case repo::DownloadResolvableReport::IGNORE: ZYPP_THROW(SkipRequestException("User requested skip of file", excpt)); break; + default: case repo::DownloadResolvableReport::ABORT: ZYPP_THROW(AbortRequestException("User requested to abort", excpt)); break; - default: - ZYPP_RETHROW( excpt ); - break; } } } } while ( _retry ); } catch(...){ // bsc#1045735: Be sure no invalid files stay in the cache! - // TODO: It would be better to provide a filechecker passed to the - // fetcher that performs the pkgGpgCheck. This way a bad file would be - // discarded before it's moved to the cache. - // For now make sure the file gets deleted (even if keeppackages=1). if ( ! ret->empty() ) ret.setDispose( filesystem::unlink ); throw; @@ -487,17 +523,10 @@ ManagedFile RpmPackageProvider::doProvidePackage() const { - Url url; - RepoInfo info = _package->repoInfo(); - // FIXME we only support the first url for now. - if ( info.baseUrlsEmpty() ) - ZYPP_THROW(Exception("No url in repository.")); - else - url = * info.baseUrlsBegin(); - // check whether to process patch/delta rpms + // FIXME we only check the first url for now. if ( ZConfig::instance().download_use_deltarpm() - && ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) ) + && ( _package->repoInfo().url().schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) ) { std::list<DeltaRpm> deltaRpms; _deltas.deltaRpms( _package ).swap( deltaRpms ); @@ -550,18 +579,28 @@ return ManagedFile(); } - // build the package and put it into the cache - Pathname destination( _package->repoInfo().packagesPath() / _package->repoInfo().path() / _package->location().filename() ); + // Build the package + Pathname cachedest( _package->repoInfo().packagesPath() / _package->repoInfo().path() / _package->location().filename() ); + Pathname builddest( cachedest.extend( ".drpm" ) ); - if ( ! applydeltarpm::provide( delta, destination, + if ( ! applydeltarpm::provide( delta, builddest, bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) ) { report()->problemDeltaApply( _("applydeltarpm failed.") ); return ManagedFile(); } + ManagedFile builddestCleanup( builddest, filesystem::unlink ); report()->finishDeltaApply(); - return ManagedFile( destination, filesystem::unlink ); + // Check and move it into the cache + // Here the rpm itself is ready. If the packages sigcheck fails, it + // makes no sense to return a ManagedFile() and fallback to download the + // full rpm. It won't be different. So let the exceptions escape... + rpmSigFileChecker( builddest ); + if ( filesystem::hardlinkCopy( builddest, cachedest ) != 0 ) + ZYPP_THROW( Exception( str::Str() << "Can't hardlink/copy " << builddest << " to " << cachedest ) ); + + return ManagedFile( cachedest, filesystem::unlink ); } /////////////////////////////////////////////////////////////////// diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/repo/RepoProvideFile.cc new/libzypp-17.5.2/zypp/repo/RepoProvideFile.cc --- old/libzypp-17.4.0/zypp/repo/RepoProvideFile.cc 2017-10-12 18:16:06.000000000 +0200 +++ new/libzypp-17.5.2/zypp/repo/RepoProvideFile.cc 2018-07-16 16:37:05.000000000 +0200 @@ -307,7 +307,7 @@ MIL << "Providing file of repo '" << repo_r.alias() << "' from " << url << endl; shared_ptr<MediaSetAccess> access = _impl->mediaAccessForUrl( url, repo_r ); - fetcher.enqueue( locWithPath ); + fetcher.enqueue( locWithPath, policy_r.fileChecker() ); fetcher.start( destinationDir, *access ); // reached if no exception has been thrown, so this is the correct file @@ -322,12 +322,10 @@ } catch ( const UserRequestException & excpt ) { - ZYPP_CAUGHT( excpt ); ZYPP_RETHROW( excpt ); } catch ( const FileCheckException & excpt ) { - ZYPP_CAUGHT( excpt ); ZYPP_RETHROW( excpt ); } catch ( const Exception &e ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/sat/Pool.cc new/libzypp-17.5.2/zypp/sat/Pool.cc --- old/libzypp-17.4.0/zypp/sat/Pool.cc 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/sat/Pool.cc 2018-07-16 16:37:05.000000000 +0200 @@ -253,7 +253,7 @@ return str << "sat::pool(" << obj.serial() << ")[" << obj.capacity() << "]{" << obj.reposSize() << "repos|" - << obj.solvablesSize() << "slov}"; + << obj.solvablesSize() << "solv}"; } ///////////////////////////////////////////////////////////////// diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/target/HardLocksFile.h new/libzypp-17.5.2/zypp/target/HardLocksFile.h --- old/libzypp-17.4.0/zypp/target/HardLocksFile.h 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/target/HardLocksFile.h 2018-07-16 16:37:05.000000000 +0200 @@ -73,7 +73,11 @@ void setData( const Data & data_r ) { if ( !_dataPtr ) + { + if ( data_r.empty() ) + return; // bsc#1096803: Prevent against empty commit without Target having been been loaded (!_dataPtr ) _dataPtr.reset( new Data ); + } if ( differs( *_dataPtr, data_r ) ) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/target/TargetImpl.cc new/libzypp-17.5.2/zypp/target/TargetImpl.cc --- old/libzypp-17.4.0/zypp/target/TargetImpl.cc 2018-06-18 16:24:26.000000000 +0200 +++ new/libzypp-17.5.2/zypp/target/TargetImpl.cc 2018-07-19 08:52:30.000000000 +0200 @@ -38,6 +38,7 @@ #include "zypp/RepoStatus.h" #include "zypp/ExternalProgram.h" #include "zypp/Repository.h" +#include "zypp/ShutdownLock_p.h" #include "zypp/ResFilters.h" #include "zypp/HistoryLog.h" @@ -1095,6 +1096,7 @@ { // ----------------------------------------------------------------- // ZYppCommitPolicy policy_r( policy_rX ); + ShutdownLock lck("Zypp commit running."); // Fake outstanding YCP fix: Honour restriction to media 1 // at installation, but install all remaining packages if post-boot. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/ui/Selectable.cc new/libzypp-17.5.2/zypp/ui/Selectable.cc --- old/libzypp-17.4.0/zypp/ui/Selectable.cc 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/ui/Selectable.cc 2018-07-18 17:13:04.000000000 +0200 @@ -155,6 +155,21 @@ Selectable::picklist_iterator Selectable::picklistEnd() const { return _pimpl->picklistEnd(); } + Selectable::picklist_size_type Selectable::picklistPos( const PoolItem & pi_r ) const + { return picklistPos( pi_r.satSolvable() ); } + + Selectable::picklist_size_type Selectable::picklistPos( const sat::Solvable & solv_r ) const + { + picklist_size_type idx = picklist_size_type(0); + for ( const auto & pi : picklist() ) + { + if ( pi == solv_r ) + return idx; + ++idx; + } + return picklistNoPos; + } + //////////////////////////////////////////////////////////////////////// bool Selectable::isUnmaintained() const diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.4.0/zypp/ui/Selectable.h new/libzypp-17.5.2/zypp/ui/Selectable.h --- old/libzypp-17.4.0/zypp/ui/Selectable.h 2017-10-10 12:48:09.000000000 +0200 +++ new/libzypp-17.5.2/zypp/ui/Selectable.h 2018-07-16 16:37:05.000000000 +0200 @@ -277,6 +277,18 @@ picklist_iterator picklistEnd() const; inline Iterable<picklist_iterator> picklist() const { return makeIterable( picklistBegin(), picklistEnd() ); } + + /** Returned by \ref picklistPos if the Item does not belong to the picklist. */ + static constexpr const picklist_size_type picklistNoPos = picklist_size_type(-1); + + /** Return the position of \a pi_r in the piclist or \ref picklistNoPos. + * \note \ref picklistNoPos is returned if you pass an installed Poolitem, + * whci has an \ref identicalAvailableObj. + */ + picklist_size_type picklistPos( const PoolItem & pi_r ) const; + + /** \overload taking a sat::Solvable */ + picklist_size_type picklistPos( const sat::Solvable & solv_r ) const; //@} ////////////////////////////////////////////////////////////////////////
