From: DongHun Kwak Date: Mon, 2 Sep 2019 07:15:26 +0000 (+0900) Subject: Imported Upstream version 17.3.0 X-Git-Tag: upstream/17.3.0^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ad1e68d450b9f0040c4efdcc52466e2d3be34a54;p=platform%2Fupstream%2Flibzypp.git Imported Upstream version 17.3.0 --- diff --git a/VERSION.cmake b/VERSION.cmake index 00e3b4e..436eba4 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -60,9 +60,9 @@ # SET(LIBZYPP_MAJOR "17") SET(LIBZYPP_COMPATMINOR "2") -SET(LIBZYPP_MINOR "2") -SET(LIBZYPP_PATCH "2") +SET(LIBZYPP_MINOR "3") +SET(LIBZYPP_PATCH "0") # -# LAST RELEASED: 17.2.2 (2) +# LAST RELEASED: 17.3.0 (2) # (The number in parenthesis is LIBZYPP_COMPATMINOR) #======= diff --git a/package/libzypp.changes b/package/libzypp.changes index 1ddb5f1..48af1b4 100644 --- a/package/libzypp.changes +++ b/package/libzypp.changes @@ -1,4 +1,17 @@ ------------------------------------------------------------------- +Mon Apr 9 13:11:50 CEST 2018 - ma@suse.de + +- Show progressbar when running posttrans scripts +- Execute service plugin script chrooted to the RepoManagers root + (bsc#1080693) +- Make sure the product file comes from /etc/products.d for the + fallback product search (bsc#1086602) +- Introduce ZConfig::repoManagerRoot to support having diverging + target and repomanager root paths +- Rename `stderr` as it can be a macro (fixes #102) +- version 17.3.0 (2) + +------------------------------------------------------------------- Tue Mar 13 18:03:42 CET 2018 - ma@suse.de - Protect code against broken translations (bsc#1082711) diff --git a/tests/zypp/CMakeLists.txt b/tests/zypp/CMakeLists.txt index 6992f8d..25a47bb 100644 --- a/tests/zypp/CMakeLists.txt +++ b/tests/zypp/CMakeLists.txt @@ -12,6 +12,7 @@ ADD_TESTS( ContentType CpeId Date + DrunkenBishop Dup Digest Deltarpm diff --git a/tests/zypp/DrunkenBishop_test.cc b/tests/zypp/DrunkenBishop_test.cc new file mode 100644 index 0000000..c094783 --- /dev/null +++ b/tests/zypp/DrunkenBishop_test.cc @@ -0,0 +1,91 @@ +#include +#include +#include "zypp/base/DrunkenBishop.h" + +using boost::unit_test::test_case; + +using namespace std; +using namespace zypp; +using base::DrunkenBishop; + +BOOST_AUTO_TEST_CASE(drunkenbishop) +{ + { + DrunkenBishop b; + BOOST_CHECK_EQUAL( b.asString(), + "++\n" + "++" ); + } + { + DrunkenBishop b( "94", 0, 0 ); + BOOST_CHECK_EQUAL( b.asString(), + "+-+\n" + "|E|\n" + "+-+" ); + } + { + BOOST_CHECK_THROW( DrunkenBishop( "9g" ), std::invalid_argument ); + } + { + DrunkenBishop b( "" ); + BOOST_CHECK_EQUAL( b.asString(), + "+-----------------+\n" + "| |\n" + "| |\n" + "| |\n" + "| |\n" + "| E |\n" + "| |\n" + "| |\n" + "| |\n" + "| |\n" + "+-----------------+" ); + } + { + DrunkenBishop b( "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", "Title" ); + BOOST_CHECK_EQUAL( b.asString(), + "+-----[Title]-----+\n" + "| |\n" + "| |\n" + "| |\n" + "| ^ |\n" + "| E |\n" + "| |\n" + "| |\n" + "| |\n" + "| |\n" + "+---[CCCCCCCC]----+" ); + } + { + DrunkenBishop b( "9c6fb17fa201ad829d808739379a2a51", "very very long Title" ); + BOOST_CHECK_EQUAL( b.asString(), + "+[very very long ]+\n" + "| |\n" + "| |\n" + "| |\n" + "| E+ . o |\n" + "| .= = S o |\n" + "|. * = . + o |\n" + "| .o . + . = |\n" + "|.. . . o. . |\n" + "|o ...o |\n" + "+---[379A2A51]----+" ); + } + { + DrunkenBishop b( "4E98E67519D98DC7362A5990E3A5C360307E3D54" ); + BOOST_CHECK_EQUAL( b.asString(), + "+-------------------+\n" + "| ^. .^E |\n" + "| . .^^: . |\n" + "| ...:^? : |\n" + "| . ?.: i |\n" + "| ^ i : . |\n" + "| : S l . |\n" + "| ^ : . . |\n" + "| . . |\n" + "| |\n" + "| |\n" + "| |\n" + "+----[307E3D54]-----+" ); + } +} diff --git a/tests/zypp/MediaSetAccess_test.cc b/tests/zypp/MediaSetAccess_test.cc index 33dea03..9160f11 100644 --- a/tests/zypp/MediaSetAccess_test.cc +++ b/tests/zypp/MediaSetAccess_test.cc @@ -260,6 +260,25 @@ BOOST_AUTO_TEST_CASE(msa_remote_tests) // providing a file which does not exist should throw BOOST_CHECK_THROW(setaccess.provideFile("/testBADNAME.txt"), media::MediaFileNotFoundException); + + Pathname fPath; + { + Url url = web.url(); + url.setPathName("/testBADNAME.txt"); + + // providing a file which does not exist should throw + BOOST_CHECK_THROW(MediaSetAccess::provideFileFromUrl(url), media::MediaFileNotFoundException); + + url.setPathName("/test.txt"); + + //providing a file by static method, file should exist after method call + ManagedFile file = MediaSetAccess::provideFileFromUrl( url ); + fPath = file; + BOOST_CHECK(check_file_exists(fPath) == true); + } + //file should be removed once the ManagedFile goes out of scope + BOOST_CHECK(check_file_exists(fPath) == false); + web.stop(); } diff --git a/tests/zypp/Pathname_test.cc b/tests/zypp/Pathname_test.cc index c749b4e..3de6d0b 100644 --- a/tests/zypp/Pathname_test.cc +++ b/tests/zypp/Pathname_test.cc @@ -149,3 +149,19 @@ BOOST_AUTO_TEST_CASE(pathname_strval) BOOST_CHECK_EQUAL(Pathname("cc:a/b").asString(), "./cc:a/b" ); } +BOOST_AUTO_TEST_CASE(pathname_stripprefix) +{ + BOOST_CHECK_EQUAL( Pathname::stripprefix( "", "" ), "" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "", "/" ), "/" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "", "/foo" ), "/foo" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/", "" ), "" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/", "/" ), "/" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/", "/foo" ), "/foo" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/f", "" ), "" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/f", "/" ), "/" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/f", "/foo" ), "/foo" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/foo", "" ), "" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/foo", "/" ), "/" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/foo", "/foo" ), "/" ); + BOOST_CHECK_EQUAL( Pathname::stripprefix( "/foo", "/foo/baa" ), "/baa" ); +} diff --git a/tests/zypp/RepoManager_test.cc b/tests/zypp/RepoManager_test.cc index 329aa46..b9a2336 100644 --- a/tests/zypp/RepoManager_test.cc +++ b/tests/zypp/RepoManager_test.cc @@ -66,8 +66,9 @@ BOOST_AUTO_TEST_CASE(pluginservices_test) TmpDir tmpCachePath; RepoManagerOptions opts( RepoManagerOptions::makeTestSetup( tmpCachePath ) ) ; - filesystem::assert_dir( opts.knownReposPath ); - filesystem::assert_dir( opts.pluginsPath / "services"); + opts.rootDir = ""; // NOTE: After all paths have been setup correctly, + // we must reset the RepoManager rootDir to prevent the plugin script + // from being executed chrooted (would require UID 0). opts.pluginsPath = DATADIR + "/plugin-service-lib-1"; BOOST_CHECK(PathInfo(opts.pluginsPath / "services/service").isExist()); diff --git a/tools/zypp-pubkey.cc b/tools/zypp-pubkey.cc index 4d7ef6f..1776a17 100644 --- a/tools/zypp-pubkey.cc +++ b/tools/zypp-pubkey.cc @@ -8,6 +8,7 @@ using std::flush; namespace opt = boost::program_options; #include +#include static std::string appname( "unknown" ); @@ -27,6 +28,22 @@ bool byTTL( const PublicKey & lhs, const PublicKey & rhs ) return lhs.gpgPubkeyRelease() > rhs.gpgPubkeyRelease(); // intentionally reverse cdate } +std::ostream & dumpPubkeyOn( std::ostream & str, const PublicKey & key_r ) +{ + std::vector art( key_r.asciiArt().asLines( " ", PublicKey::AsciiArt::USE_COLOR ) ); + + std::vector info; + str::split( (str::Str() << dump(key_r)).str(), std::back_inserter( info ), "\n" ); + + for ( unsigned i = 1; i < info.size(); ++i ) + art[i] += info[i]; + + str << info[0] << endl; + for ( const auto & line : art ) + str << line << endl; + return str << endl; +} + /****************************************************************** ** ** FUNCTION NAME : main @@ -71,6 +88,8 @@ int main( int argc, char * argv[] ) std::list rpmpubkeys( rpmdb.pubkeys() ); rpmpubkeys.sort( byTTL ); + + if ( ! vm.count( "key-file" ) ) { std::string last; @@ -80,7 +99,7 @@ int main( int argc, char * argv[] ) cout << *it << endl; else { - cout << dump( *it ) << endl; + dumpPubkeyOn( cout, *it ); last = it->gpgPubkeyVersion(); } } @@ -93,7 +112,7 @@ int main( int argc, char * argv[] ) { cout << "=== " << PathInfo(*it) << endl; PublicKey pubkey( *it ); - cout << dump( pubkey ) << endl; + dumpPubkeyOn( cout, pubkey ); std::string pubkeyV( pubkey.gpgPubkeyVersion() ); std::string pubkeyR( pubkey.gpgPubkeyRelease() ); diff --git a/zypp/CMakeLists.txt b/zypp/CMakeLists.txt index a30696e..379ecca 100644 --- a/zypp/CMakeLists.txt +++ b/zypp/CMakeLists.txt @@ -202,6 +202,7 @@ INSTALL( FILES ${zypp_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/zypp" ) SET( zypp_base_SRCS base/InterProcessMutex.cc base/Backtrace.cc + base/DrunkenBishop.cc base/SerialNumber.cc base/Random.cc base/Measure.cc @@ -229,6 +230,7 @@ SET( zypp_base_HEADERS base/InterProcessMutex.h base/Backtrace.h base/Collector.h + base/DrunkenBishop.h base/SerialNumber.h base/Easy.h base/Errno.h diff --git a/zypp/ExternalProgram.h b/zypp/ExternalProgram.h index f3fc850..76ec38e 100644 --- a/zypp/ExternalProgram.h +++ b/zypp/ExternalProgram.h @@ -246,7 +246,7 @@ namespace zypp { EarlyPipe(); ~EarlyPipe(); void closeW() { if ( _fds[W] != -1 ) { ::close( _fds[W] ); _fds[W] = -1; } } - FILE * stderr() { return _stderr; } + FILE * fStdErr() { return _stderr; } protected: FILE * _stderr; int _fds[2]; @@ -259,17 +259,24 @@ namespace zypp { class ExternalProgramWithStderr : private externalprogram::EarlyPipe, public ExternalProgram { public: - ExternalProgramWithStderr( const Arguments & argv_r ) - : ExternalProgram( argv_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W] ) + ExternalProgramWithStderr( const Arguments & argv_r, bool defaultLocale_r = false, const Pathname & root_r = "" ) + : ExternalProgram( argv_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W], defaultLocale_r, root_r ) { _initStdErr(); } + /** \overlocad Convenience taking just the \a root_r. */ + ExternalProgramWithStderr( const Arguments & argv_r, const Pathname & root_r ) + : ExternalProgramWithStderr( argv_r, false, root_r ) + {} - ExternalProgramWithStderr( const Arguments & argv_r, const Environment & environment_r ) - : ExternalProgram( argv_r, environment_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W] ) + ExternalProgramWithStderr( const Arguments & argv_r, const Environment & environment_r, bool defaultLocale_r = false, const Pathname & root_r = "" ) + : ExternalProgram( argv_r, environment_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W], defaultLocale_r, root_r ) { _initStdErr(); } - - public: + /** \overlocad Convenience taking just the \a root_r. */ + ExternalProgramWithStderr( const Arguments & argv_r, const Environment & environment_r, const Pathname & root_r ) + : ExternalProgramWithStderr( argv_r, environment_r, false, root_r ) + {} + public: /** Return \c FILE* to read programms stderr (O_NONBLOCK set). */ - using externalprogram::EarlyPipe::stderr; + using externalprogram::EarlyPipe::fStdErr; /** Read data up to \c delim_r from stderr (nonblocking). * \note If \c delim_r is '\0', we read as much data as possible. diff --git a/zypp/KeyRing.cc b/zypp/KeyRing.cc index f999239..d9e0c9a 100644 --- a/zypp/KeyRing.cc +++ b/zypp/KeyRing.cc @@ -211,6 +211,9 @@ namespace zypp bool verifyFileTrustedSignature( const Pathname & file, const Pathname & signature ) { return verifyFile( file, signature, trustedKeyRing() ); } + PublicKeyData trustedPublicKeyExists( const std::string & id ) + { return publicKeyExists(id, trustedKeyRing());} + private: bool verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring ); void importKey( const Pathname & keyfile, const Pathname & keyring ); @@ -619,6 +622,9 @@ namespace zypp std::list KeyRing::trustedPublicKeyData() { return _pimpl->trustedPublicKeyData(); } + PublicKeyData KeyRing::trustedPublicKeyData(const std::string &id_r) + { return _pimpl->trustedPublicKeyExists( id_r ); } + bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext ) { return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, sigValid_r, keycontext ); } diff --git a/zypp/KeyRing.h b/zypp/KeyRing.h index fdf18f8..b3212fb 100644 --- a/zypp/KeyRing.h +++ b/zypp/KeyRing.h @@ -240,6 +240,11 @@ namespace zypp std::list trustedPublicKeyData(); /** + * Get a trusted public key's data in the keyring (key data only) + */ + PublicKeyData trustedPublicKeyData( const std::string &id ); + + /** * Follows a signature verification interacting with the user. * The bool returned depends on user decision to trust or not. * diff --git a/zypp/MediaSetAccess.cc b/zypp/MediaSetAccess.cc index 8ec5c65..940c26a 100644 --- a/zypp/MediaSetAccess.cc +++ b/zypp/MediaSetAccess.cc @@ -16,6 +16,7 @@ #include "zypp/ZYppCallbacks.h" #include "zypp/MediaSetAccess.h" #include "zypp/PathInfo.h" +#include "zypp/TmpPath.h" //#include "zypp/source/MediaSetAccessReportReceivers.h" using namespace std; @@ -170,6 +171,24 @@ IMPL_PTR_TYPE(MediaSetAccess); return op.result; } + ManagedFile MediaSetAccess::provideFileFromUrl(const Url &file_url, ProvideFileOptions options) + { + Url url(file_url); + Pathname path(url.getPathName()); + url.setPathName ("/"); + MediaSetAccess access(url); + + ManagedFile tmpFile = filesystem::TmpFile::asManagedFile(); + + Pathname file = access.provideFile(path, 1, options); + + //prevent the file from being deleted when MediaSetAccess gets out of scope + if ( filesystem::hardlinkCopy(file, tmpFile) != 0 ) + ZYPP_THROW(Exception("Can't copy file from " + file.asString() + " to " + tmpFile->asString() )); + + return tmpFile; + } + Pathname MediaSetAccess::provideOptionalFile( const Pathname & file, unsigned media_nr ) { try diff --git a/zypp/MediaSetAccess.h b/zypp/MediaSetAccess.h index 71223e4..6116d1d 100644 --- a/zypp/MediaSetAccess.h +++ b/zypp/MediaSetAccess.h @@ -23,6 +23,7 @@ #include "zypp/Pathname.h" #include "zypp/CheckSum.h" #include "zypp/OnMediaLocation.h" +#include "zypp/ManagedFile.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -172,6 +173,25 @@ namespace zypp Pathname provideFile(const Pathname & file, unsigned media_nr = 1, ProvideFileOptions options = PROVIDE_DEFAULT ); /** + * Provides \a file from \a url. + * + * \param absolute url to the file + * \return local pathname of the requested file + * + * \note interaction with the user does not ocurr if + * \ref ProvideFileOptions::NON_INTERACTIVE is set. + * + * \throws MediaException if a problem occured and user has chosen to + * abort the operation. The calling code should take care + * to quit the current operation. + * \throws SkipRequestException if a problem occured and user has chosen + * to skip the current operation. The calling code should continue + * with the next one, if possible. + * \see zypp::media::MediaManager::provideFile() + */ + static ManagedFile provideFileFromUrl( const Url & file_url, ProvideFileOptions options = PROVIDE_DEFAULT ); + + /** * Provides an optional \a file from media \a media_nr. * * Like \ref provideFile (NON_INTERACTIVE), but return an empty \ref Pathname diff --git a/zypp/Pathname.cc b/zypp/Pathname.cc index 0dbb04e..3237fbe 100644 --- a/zypp/Pathname.cc +++ b/zypp/Pathname.cc @@ -241,6 +241,18 @@ namespace zypp return root_r / path_r; } + Pathname Pathname::stripprefix( const Pathname & root_r, const Pathname & path_r ) + { + if ( root_r.emptyOrRoot() ) + return path_r; + if ( root_r == path_r ) + return "/"; + std::string rest( str::stripPrefix( path_r.asString(), root_r.asString() ) ); + if ( rest[0] == '/' ) // needs to be a dir prefix! + return std::move(rest); + return path_r; + } + /////////////////////////////////////////////////////////////////// // // METHOD NAME : Pathname::cat diff --git a/zypp/Pathname.h b/zypp/Pathname.h index 0a37556..09d37d0 100644 --- a/zypp/Pathname.h +++ b/zypp/Pathname.h @@ -147,6 +147,9 @@ namespace zypp /** Return \c path_r prefixed with \c root_r, unless it is already prefixed. */ static Pathname assertprefix( const Pathname & root_r, const Pathname & path_r ); + /** Return \c path_r with any \c root_r dir prefix striped. */ + static Pathname stripprefix( const Pathname & root_r, const Pathname & path_r ); + /** Concatenation of pathnames. * \code * "foo" / "baa" ==> "foo/baa" diff --git a/zypp/Product.cc b/zypp/Product.cc index 80ae25e..7e98447 100644 --- a/zypp/Product.cc +++ b/zypp/Product.cc @@ -110,10 +110,10 @@ namespace zypp // bnc#784900: for installed products check whether the file is owned by // some package. If so, ust this as buddy. sat::LookupAttr q( sat::SolvAttr::filelist, repository() ); - std::string refFile( referenceFilename() ); + std::string refFile( referenceFilename() ); // the basename only! if ( ! refFile.empty() ) { - StrMatcher matcher( referenceFilename() ); + StrMatcher matcher( "/etc/products.d/"+refFile, Match::STRING | Match::FILES ); q.setStrMatcher( matcher ); if ( ! q.empty() ) found = q.begin().inSolvable(); diff --git a/zypp/PublicKey.cc b/zypp/PublicKey.cc index 41d093d..83db0d5 100644 --- a/zypp/PublicKey.cc +++ b/zypp/PublicKey.cc @@ -337,6 +337,9 @@ namespace zypp bool PublicKeyData::providesKey( const std::string & id_r ) const { return( id_r == _pimpl->_id || _pimpl->hasSubkeyId( id_r ) ); } + PublicKeyData::AsciiArt PublicKeyData::asciiArt() const + { return AsciiArt( fingerprint() /* TODO: key algorithm could be added as top tile. */ ); } + std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj ) { str << "[" << obj.name() << "]" << endl; diff --git a/zypp/PublicKey.h b/zypp/PublicKey.h index 4c93d8b..6ad5c67 100644 --- a/zypp/PublicKey.h +++ b/zypp/PublicKey.h @@ -21,6 +21,7 @@ #include "zypp/base/Iterable.h" #include "zypp/base/PtrTypes.h" #include "zypp/base/Exception.h" +#include "zypp/base/DrunkenBishop.h" #include "zypp/Pathname.h" #include "zypp/Edition.h" #include "zypp/Date.h" @@ -216,6 +217,18 @@ namespace zypp /** Whether \a id_r is the \ref id of the primary key or of a subkey. */ bool providesKey( const std::string & id_r ) const; + public: + /** Random art fingerprint visualization type (\ref base::DrunkenBishop). */ + typedef base::DrunkenBishop AsciiArt; + + /** Random art fingerprint visualization (\ref base::DrunkenBishop). + * \code + * PublicKeyData key; + * cout << key.asciiArt( PublicKey::AsciiArt::USE_COLOR ) << endl; + * \endcode + */ + AsciiArt asciiArt() const; + private: class Impl; RWCOW_pointer _pimpl; @@ -317,6 +330,12 @@ namespace zypp { return keyData().providesKey( id_r ); } public: + typedef PublicKeyData::AsciiArt AsciiArt; ///!< \see \ref PublicKeyData + + AsciiArt asciiArt() const ///!< \see \ref PublicKeyData + { return keyData().asciiArt(); } + + public: /** File containig the ASCII armored key. */ Pathname path() const; diff --git a/zypp/RepoManager.cc b/zypp/RepoManager.cc index 0d48a86..fa022e0 100644 --- a/zypp/RepoManager.cc +++ b/zypp/RepoManager.cc @@ -456,13 +456,7 @@ namespace zypp std::list readRepoFile( const Url & repo_file ) { - // no interface to download a specific file, using workaround: - //! \todo add MediaManager::provideFile(Url file_url) to easily access any file URLs? (no need for media access id or media_nr) - Url url(repo_file); - Pathname path(url.getPathName()); - url.setPathName ("/"); - MediaSetAccess access(url); - Pathname local = access.provideFile(path); + ManagedFile local = MediaSetAccess::provideFileFromUrl(repo_file); DBG << "reading repo file " << repo_file << ", local path: " << local << endl; @@ -796,7 +790,7 @@ namespace zypp } } - repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services)); + repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services)); } /////////////////////////////////////////////////////////////////// @@ -2099,7 +2093,13 @@ namespace zypp // and in zypper. std::pair, repo::ServicePluginInformalException> uglyHack; try { - ServiceRepos( service, bind( &RepoCollector::collect, &collector, _1 ) ); + // FIXME bsc#1080693: Shortcoming of (plugin)services (and repos as well) is that they + // are not aware of the RepoManagers rootDir. The service url, as created in known_services, + // contains the full path to the script. The script however has to be executed chrooted. + // Repos would need to know the RepoMangers rootDir to use the correct vars.d to replace + // repos variables. Until RepoInfoBase is aware if the rootDir, we need to explicitly pass it + // to ServiceRepos. + ServiceRepos( _options.rootDir, service, bind( &RepoCollector::collect, &collector, _1 ) ); } catch ( const repo::ServicePluginInformalException & e ) { diff --git a/zypp/TmpPath.cc b/zypp/TmpPath.cc index a8334cd..bbf4dc5 100644 --- a/zypp/TmpPath.cc +++ b/zypp/TmpPath.cc @@ -227,6 +227,14 @@ namespace zypp { return ret; } + ManagedFile TmpFile::asManagedFile() + { + filesystem::TmpFile tmpFile; + ManagedFile mFile ( tmpFile.path(), filesystem::unlink ); + tmpFile.autoCleanup(false); //cleaned up by ManagedFile + return mFile; + } + /////////////////////////////////////////////////////////////////// // // METHOD NAME : TmpFile::defaultPrefix diff --git a/zypp/TmpPath.h b/zypp/TmpPath.h index 8d84bfd..cef9e5e 100644 --- a/zypp/TmpPath.h +++ b/zypp/TmpPath.h @@ -16,6 +16,7 @@ #include "zypp/Pathname.h" #include "zypp/base/PtrTypes.h" +#include "zypp/ManagedFile.h" namespace zypp { namespace filesystem { @@ -142,6 +143,12 @@ namespace zypp { */ static TmpFile makeSibling( const Pathname & sibling_r ); + /** + * Create a temporary file and convert it to a automatically + * cleaned up ManagedFile + */ + static ManagedFile asManagedFile (); + public: /** * @return The default prefix for temporary files (TmpFile.) diff --git a/zypp/ZConfig.cc b/zypp/ZConfig.cc index a439bf8..59aad94 100644 --- a/zypp/ZConfig.cc +++ b/zypp/ZConfig.cc @@ -628,6 +628,7 @@ namespace zypp Pathname cfg_known_repos_path; Pathname cfg_known_services_path; Pathname cfg_vars_path; + Pathname cfg_repo_mgr_root_path; Pathname cfg_vendor_path; Pathname cfg_multiversion_path; @@ -818,6 +819,16 @@ namespace zypp Pathname ZConfig::systemRoot() const { return _autodetectSystemRoot(); } + + Pathname ZConfig::repoManagerRoot() const + { + return ( _pimpl->cfg_repo_mgr_root_path.empty() + ? systemRoot() : _pimpl->cfg_repo_mgr_root_path ); + } + + void ZConfig::setRepoManagerRoot(const zypp::filesystem::Pathname &root) + { _pimpl->cfg_repo_mgr_root_path = root; } + /////////////////////////////////////////////////////////////////// // // system architecture diff --git a/zypp/ZConfig.h b/zypp/ZConfig.h index 6114e7b..5d5158f 100644 --- a/zypp/ZConfig.h +++ b/zypp/ZConfig.h @@ -73,6 +73,16 @@ namespace zypp */ Pathname systemRoot() const; + /** The RepoManager root directory. + * Returns the same as \sa systemRoot() if not explicitely set. + */ + Pathname repoManagerRoot() const; + + /** Sets the RepoManager root directory. + * \sa repoManagerRoot() + */ + void setRepoManagerRoot ( const Pathname &root ); + public: /** The autodetected system architecture. */ diff --git a/zypp/base/DrunkenBishop.cc b/zypp/base/DrunkenBishop.cc new file mode 100644 index 0000000..85f9dee --- /dev/null +++ b/zypp/base/DrunkenBishop.cc @@ -0,0 +1,408 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/DrunkenBishop.cc + */ +#include +//#include "zypp/base/LogTools.h" +#include "zypp/base/Flags.h" +#include "zypp/base/String.h" +#include "zypp/base/NonCopyable.h" +#include "zypp/base/DrunkenBishop.h" + +using std::endl; + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace base + { + /////////////////////////////////////////////////////////////////// + namespace + { + /** Direction the drunken Bishop wants to move. */ + enum class Direction : std::uint8_t // actually 2 bits + { + NW = 0x0, + NE = 0x1, + SW = 0x2, + SE = 0x3, + }; + + /** Convert a hex digit (case insensitive) into it's (4bit) integral value. + * \throws std::invalid_argument if char + */ + inline std::uint8_t hexDigit( char ch_r ) + { + switch ( ch_r ) + { + case 'F': case 'f': return 15; + case 'E': case 'e': return 14; + case 'D': case 'd': return 13; + case 'C': case 'c': return 12; + case 'B': case 'b': return 11; + case 'A': case 'a': return 10; + case '9': return 9; + case '8': return 8; + case '7': return 7; + case '6': return 6; + case '5': return 5; + case '4': return 4; + case '3': return 3; + case '2': return 2; + case '1': return 1; + case '0': return 0; + } + throw std::invalid_argument( str::Str() << "Not a hex digit '" << ch_r << "'" ); + } + } // namespace + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + /// \class DrunkenBishop::Impl + /// \brief DrunkenBishop implementation. + /////////////////////////////////////////////////////////////////// + class DrunkenBishop::Impl : private base::NonCopyable + { + public: + /** Default is an empty board. */ + Impl() + : _h( 0U ) + , _w( 0u ) + , _s( 0U ) + , _e( 0U ) + , _renderSSH( true ) + {} + + /** Build up a new board. + * \throws std::invalid_argument + */ + void compute( const std::string & data_r, const std::string & title_r, unsigned height_r = Auto, unsigned width_r = Auto ) + { + // store rendering details + _renderSSH = ( data_r.size() <= 32 ); // up to the ssh fingerprint size + _fp = str::toUpper( data_r.size() <= 8 ? data_r : data_r.substr( data_r.size()-8 ) ); + _tt = title_r; + + // init the board + _h = odd(height_r); + _w = odd(width_r); + + if ( _h == Auto ) + { + if ( _renderSSH ) + { _w = 17; _h = 9; } + else + { _w = 19; _h = 11; } + } + else if ( _w == Auto ) + { + _w = (2*_h)-1; + } + + _board = std::vector( _w*_h, 0 ); + _s = _w*_h/2; // start + _e = _s; // current/end + ++_board[_e]; + + // go + for ( const char * ch = data_r.c_str(); *ch; /*NOOP*/ ) + { + std::uint8_t next4 = bite( ch ); + // next4: 0x94 + // bits: 10 01 01 00 + // step: 4 3 2 1 + static const std::uint8_t stepMask(0x3); + move( Direction( next4 & stepMask ) ); + move( Direction( (next4>>2) & stepMask ) ); + move( Direction( (next4>>4) & stepMask ) ); + move( Direction( (next4>>6) ) ); + } + } + + /** Render board to a stream. */ + std::ostream & dumpOn( std::ostream & str, const std::string & prefix_r, Options options_r ) const + { + if ( _board.empty() ) + { + // "++\n" + // "++" + return str << prefix_r << "++" << endl << prefix_r << "++"; + } + + static const char * colorReset = "\033[0m"; + static const char * colorBg = "\033[48;5;242m"; + bool useColor = options_r.testFlag( USE_COLOR ); + + renderTitleOn( str << prefix_r , _tt ); + + for ( unsigned p = 0; p < _board.size(); ++p ) + { + if ( ( p % _w ) == 0 ) + { + if ( p ) + str << ( useColor ? colorReset: "" ) << '|'; + str << endl << prefix_r << '|' << ( useColor ? colorBg : "" ); + } + renderOn( str, useColor, p ); + } + str << ( useColor ? colorReset: "" ) << '|'; + + renderTitleOn( str << endl << prefix_r, _fp ); + return str; + } + + private: + /** Increment even width/height values. */ + static unsigned odd( unsigned val_r ) + { return( val_r == Auto ? val_r : val_r|1U ); } + + /** Get next 4 moves (8 bit) from next 2 hex digits (1st digit != '\0' asserted, 0-pad if necessary). + * \throws std::invalid_argument if char is not a hex digit or 1st char is \c \0 + */ + static std::uint8_t bite( const char *& ch_r ) + { + std::uint8_t ret = hexDigit( *ch_r ) << 4; + if ( *(++ch_r) ) + ret |= hexDigit( *(ch_r++) ); + return ret; + } + + private: + /** Move Bishop from \ref _e into \a direction_r and update the \ref _board. */ + void move( Direction direction_r ) + { + switch ( direction_r ) + { + case Direction::NW: + if ( atTL() ) + /*no move*/; + else if ( atT() ) + _e -= 1; + else if ( atL() ) + _e -= _w; + else + _e -= _w+1; + break; + + case Direction::NE: + if ( atTR() ) + /*no move*/; + else if ( atT() ) + _e += 1; + else if ( atR() ) + _e -= _w; + else + _e -= _w-1; + break; + + case Direction::SW: + if ( atBL() ) + /*no move*/; + else if ( atB() ) + _e -= 1; + else if ( atL() ) + _e += _w; + else + _e += _w-1; + break; + + case Direction::SE: + if ( atBR() ) + /*no move*/; + else if ( atB() ) + _e += 1; + else if ( atR() ) + _e += _w; + else + _e += _w+1; + break; + + default: + throw std::invalid_argument( str::Str() << "Bad Direction " << unsigned(direction_r) ); + } + // update the board + ++_board[_e]; + } + + /** Whether \ref _e is in the top left corner. */ + bool atTL() const + { return( _e == 0 ); } + + /** Whether \ref _e is in the top right corner. */ + bool atTR() const + { return( _e == _w-1 ); } + + /** Whether \ref _e is in the bottom left corner. */ + bool atBL() const + { return( _e == _board.size()-_w ); } + + /** Whether \ref _e is in the bottom right corner. */ + bool atBR() const + { return( _e == _board.size()-1 ); } + + /** Whether \ref _e is in the top row. */ + bool atT() const + { return( _e < _w ); } + + /** Whether \ref _e is in the bottom row. */ + bool atB() const + { return( _e >= _board.size()-_w ); } + + /** Whether \ref _e is in the left column. */ + bool atL() const + { return( ( _e % _w ) == 0 ); } + + /** Whether \ref _e is in the right column. */ + bool atR() const + { return( ( _e % _w ) == (_w-1) ); } + + private: + /** ANSI color heatmap. */ + const char * color( std::uint8_t idx_r ) const + { + static const std::vector colors = { + "", // no coin + "\033[38;5;21m", // blue (cold) + "\033[38;5;39m", + "\033[38;5;50m", + "\033[38;5;48m", + "\033[38;5;46m", // green + "\033[38;5;118m", + "\033[38;5;190m", + "\033[38;5;226m", // yellow + "\033[38;5;220m", + "\033[38;5;214m", // orange + "\033[38;5;208m", + "\033[38;5;202m", + "\033[38;5;196m", // red + "\033[38;5;203m", + "\033[38;5;210m", + "\033[38;5;217m", // pink + "\033[38;5;224m", + "\033[38;5;231m", // white (hot) + }; +#if 0 + // cycle through heat map to test all colors + if ( ! idx_r ) + return ""; + static unsigned i = 0; + if ( ++i == colors.size() ) + i = 1; + return colors[i]; +#endif + return ( idx_r < colors.size() ? colors[idx_r] : *colors.rbegin() ); + } + + /** Render non empty title strings */ + std::ostream & renderTitleOn( std::ostream & str, const std::string & title_r ) const + { + std::string buffer( _w+2, '-' ); + *buffer.begin() = *buffer.rbegin() = '+'; + + if ( !title_r.empty() && _w >= 2 ) // extra 2 for "[]" + { + std::string::size_type tlen = std::min( title_r.size(), std::string::size_type(_w-2) ); + std::string::size_type tpos = (_w-tlen)/2; // not (_w-2-tlen) because buffer is size _w+2 + buffer[tpos++] = '['; + for ( std::string::size_type p = 0; p < tlen; ++p, ++tpos ) + buffer[tpos] = title_r[p]; + buffer[tpos] = ']'; + } + return str << buffer; + } + + /** Render board numbers to printable chars. */ + std::ostream & renderOn( std::ostream & str, bool useColor_r, unsigned pos_r ) const + { + static const std::string sshSet( " .o+=*BOX@%&#/^" ); + static const std::string gpgSet( " .^:li?(fxXZ#MW&8%@" ); + const std::string & charSet( _renderSSH ? sshSet : gpgSet ); + + if ( useColor_r ) + str << color( _board[pos_r] ); + + if ( pos_r == _e ) + return str << 'E'; + + if ( pos_r == _s ) + return str << 'S'; + + return str << ( _board[pos_r] < charSet.size() ? charSet[_board[pos_r]] : *charSet.rbegin() ); + } + + private: + /** Request default width/height values. */ + static constexpr const unsigned Auto = unsigned(-1); + + private: + std::vector _board; ///< the board + unsigned _h; ///< board height + unsigned _w; ///< board with + unsigned _s; ///< start position + unsigned _e; ///< end position + + private: + bool _renderSSH; ///< whether to render the ssh (or gpg) char set + std::string _fp; ///< fingerprint to render as bottom title + std::string _tt; ///< text to render as top title + + public: + /** Offer default Impl. */ + static shared_ptr nullimpl() + { + static shared_ptr _nullimpl( new Impl ); + return _nullimpl; + } + }; + + /////////////////////////////////////////////////////////////////// + // CLASS NAME : DrunkenBishop + /////////////////////////////////////////////////////////////////// + + DrunkenBishop::DrunkenBishop() + : _pimpl( Impl::nullimpl() ) + { /*nothing to compute*/ } + + DrunkenBishop::DrunkenBishop( const std::string & data_r, const std::string & title_r ) + : _pimpl( new Impl ) + { _pimpl->compute( data_r, title_r ); } + + DrunkenBishop::DrunkenBishop( const std::string & data_r, const std::string & title_r, unsigned height_r ) + : _pimpl( new Impl ) + { _pimpl->compute( data_r, title_r, height_r ); } + + DrunkenBishop::DrunkenBishop( const std::string & data_r, const std::string & title_r, unsigned height_r, unsigned width_r ) + : _pimpl( new Impl ) + { _pimpl->compute( data_r, title_r, height_r, width_r ); } + + DrunkenBishop::~DrunkenBishop() + {} + + std::ostream & DrunkenBishop::dumpOn( std::ostream & str, const std::string & prefix_r, Options options_r ) const + { return _pimpl->dumpOn( str, prefix_r, options_r ); } + + std::string DrunkenBishop::asString( const std::string & prefix_r, Options options_r ) const + { + std::ostringstream str; + dumpOn( str, prefix_r, options_r ); + return str.str(); + } + + std::vector DrunkenBishop::asLines( const std::string & prefix_r, Options options_r ) const + { + std::vector ret; + str::split( asString( prefix_r, options_r ), std::back_inserter(ret), "\n" ); + return ret; + } + + } // namespace base + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/zypp/base/DrunkenBishop.h b/zypp/base/DrunkenBishop.h new file mode 100644 index 0000000..5a31993 --- /dev/null +++ b/zypp/base/DrunkenBishop.h @@ -0,0 +1,130 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/DrunkenBishop.h + */ +#ifndef ZYPP_BASE_DRUNKENBISHOP_H +#define ZYPP_BASE_DRUNKENBISHOP_H + +#include +#include +#include + +#include "zypp/base/PtrTypes.h" +#include "zypp/base/Flags.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace base + { + /////////////////////////////////////////////////////////////////// + /// \class DrunkenBishop + /// \brief Random art fingerprint visualization + /// Visualize fingerprint data on a [17x9] (SSH) or [19x11] (GPG) or + /// custom sized board. The default board size and layout depends on + /// the data string length (above 32 the GPG board and layout is used). + /// + /// The data string should be an even sized HEX string, otherwise + /// it will be 0-padded. + /// + /// All ctor calls may throw \ref std::invalid_argument. + /// + /// \code + /// [SuSE Package Signing Key ] + /// +------[Title]------+ + /// | . . ^ | fpr FEAB502539D846DB2C0961CA70AF9E8139DB7C82 + /// | : : . | id 70AF9E8139DB7C82 + /// | ^ ^ . | cre 1481108255 Wed Dec 7 11:57:35 2016 + /// | ^ . l i | exp 1607252255 Sun Dec 6 11:57:35 2020 + /// | : ^ . f : | ttl 992 + /// | ? ^ .Sl | rpm 39db7c82-5847eb1f + /// | E i ... | + /// | ^ .. | + /// | . . | + /// | . . | + /// | .... | + /// +----[39DB7C82]-----+ + /// \endcode + //// + /// Based on https://github.com/atoponce/keyart, the development location + /// for the Debian signing-party package. We try to use the same charset + /// and heatmap. + /// See also http://dirk-loss.de/sshvis/drunken_bishop.pdf. + /////////////////////////////////////////////////////////////////// + class DrunkenBishop + { + friend std::ostream & operator<<( std::ostream & str, const DrunkenBishop & obj ); + + public: + /** Default ctor: empty board (1x1) */ + DrunkenBishop(); + + /** Ctor taking a data string (and optional title) and using a default (SSH/GPG) board. */ + DrunkenBishop( const std::string & data_r, const std::string & title_r = std::string() ); + + /** Ctor also taking a desired board height (even value is incremented, width is 2*height-1). */ + DrunkenBishop( const std::string & data_r, const std::string & title_r, unsigned height_r ); + /** Ctor \overload without optional title */ + DrunkenBishop( const std::string & data_r, unsigned height_r ) + : DrunkenBishop( data_r, std::string(), height_r ) + {} + + /** Ctor also taking a desired board height and width (even values are incremented). */ + DrunkenBishop( const std::string & data_r, const std::string & title_r, unsigned height_r, unsigned width_r ); + /** Ctor \overload without optional title */ + DrunkenBishop( const std::string & data_r, unsigned height_r, unsigned width_r ) + : DrunkenBishop( data_r, std::string(), height_r, width_r ) + {} + + /** Dtor */ + ~DrunkenBishop(); + + public: + /* Rendering options */ + enum OptionBits { + USE_COLOR = (1<<0), ///< use colors + }; + ZYPP_DECLARE_FLAGS(Options,OptionBits); + + /** Render board to steam.*/ + std::ostream & dumpOn( std::ostream & str, Options options_r = Options() ) const + { return dumpOn( str, std::string(), options_r ); } + /** \overload taking an indent string prefixing each line. */ + std::ostream & dumpOn( std::ostream & str, const std::string & prefix_r, Options options_r = Options() ) const; + + /** Render board as string.*/ + std::string asString( Options options_r = Options() ) const + { return asString( std::string(), options_r ); } + /** \overload taking an indent string prefixing each line. */ + std::string asString( const std::string & prefix_r, Options options_r = Options() ) const; + + /** Render to an array of lines. */ + std::vector asLines( Options options_r = Options() ) const + { return asLines( std::string(), options_r ); } + /** \overload taking an indent string prefixing each line. */ + std::vector asLines( const std::string & prefix_r, Options options_r = Options() ) const; + + public: + class Impl; ///< Implementation class. + private: + RW_pointer _pimpl; ///< Pointer to implementation. + }; + + ZYPP_DECLARE_OPERATORS_FOR_FLAGS(DrunkenBishop::Options); + + /** \relates DrunkenBishop Stream output */ + inline std::ostream & operator<<( std::ostream & str, const DrunkenBishop & obj ) + { return obj.dumpOn( str ); } + + } // namespace base + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_BASE_DRUNKENBISHOP_H diff --git a/zypp/media/MediaCIFS.cc b/zypp/media/MediaCIFS.cc index b47ed44..a6396e0 100644 --- a/zypp/media/MediaCIFS.cc +++ b/zypp/media/MediaCIFS.cc @@ -162,7 +162,7 @@ namespace zypp { std::string mountpoint( attachPoint().asString() ); Mount mount; - CredentialManager cm; + CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); Mount::Options options( _url.getQueryParam("mountoptions") ); string username = _url.getUsername(); @@ -403,7 +403,7 @@ namespace zypp { bool MediaCIFS::authenticate(AuthData & authdata, bool firstTry) const { //! \todo need a way to pass different CredManagerOptions here - CredentialManager cm(CredManagerOptions(ZConfig::instance().systemRoot())); + CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); // get stored credentials AuthData_Ptr cmcred = cm.getCred(_url); diff --git a/zypp/media/MediaCurl.cc b/zypp/media/MediaCurl.cc index a44f019..0457ac8 100644 --- a/zypp/media/MediaCurl.cc +++ b/zypp/media/MediaCurl.cc @@ -1693,8 +1693,7 @@ string MediaCurl::getAuthHint() const bool MediaCurl::authenticate(const string & availAuthTypes, bool firstTry) const { //! \todo need a way to pass different CredManagerOptions here - Target_Ptr target = zypp::getZYpp()->getTarget(); - CredentialManager cm(CredManagerOptions(target ? target->root() : "")); + CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); CurlAuthData_Ptr credentials; // get stored credentials diff --git a/zypp/repo/RepoVariables.cc b/zypp/repo/RepoVariables.cc index 552cc31..8370cbb 100644 --- a/zypp/repo/RepoVariables.cc +++ b/zypp/repo/RepoVariables.cc @@ -403,7 +403,7 @@ namespace zypp if ( empty() ) // at init / after reset { // load user definitions from vars.d - filesystem::dirForEach( ZConfig::instance().systemRoot() / ZConfig::instance().varsPath(), + filesystem::dirForEach( ZConfig::instance().repoManagerRoot() / ZConfig::instance().varsPath(), filesystem::matchNoDots(), bind( &RepoVarsMap::parse, this, _1, _2 ) ); // releasever_major/_minor are per default derived from releasever. // If releasever is userdefined, inject missing _major/_minor too. diff --git a/zypp/repo/ServiceRepos.cc b/zypp/repo/ServiceRepos.cc index e27c260..7869174 100644 --- a/zypp/repo/ServiceRepos.cc +++ b/zypp/repo/ServiceRepos.cc @@ -25,7 +25,8 @@ namespace zypp struct RIMServiceRepos : public ServiceRepos::Impl { - RIMServiceRepos( const ServiceInfo & service, + RIMServiceRepos( const Pathname & /*root_r*/, + const ServiceInfo & service, const ServiceRepos::ProcessRepo & callback, const ProgressData::ReceiverFnc & progress = ProgressData::ReceiverFnc() ) { @@ -50,19 +51,22 @@ namespace zypp struct PluginServiceRepos : public ServiceRepos::Impl { - PluginServiceRepos( const ServiceInfo & service, + PluginServiceRepos( const Pathname & root_r, + const ServiceInfo & service, const ServiceRepos::ProcessRepo & callback, const ProgressData::ReceiverFnc & progress = ProgressData::ReceiverFnc() ) { - Url serviceUrl( service.url() ); + // bsc#1080693: Service script needs to be executed chrooted to the RepoManagers rootDir. + // The service is not aware of the rootDir, so it's explicitly passed and needs to be + // stripped from the URLs path. stringstream buffer; ExternalProgram::Arguments args; args.reserve( 3 ); args.push_back( "/bin/sh" ); args.push_back( "-c" ); - args.push_back( serviceUrl.getPathName() ); - ExternalProgramWithStderr prog( args ); + args.push_back( Pathname::stripprefix( root_r, service.url().getPathName() ).asString() ); + ExternalProgramWithStderr prog( args, root_r ); prog >> buffer; if ( prog.close() != 0 ) @@ -80,12 +84,13 @@ namespace zypp /////////////////////////////////////////////////////////////////// - ServiceRepos::ServiceRepos( const ServiceInfo & service, + ServiceRepos::ServiceRepos( const Pathname & root_r, + const ServiceInfo & service, const ServiceRepos::ProcessRepo & callback, const ProgressData::ReceiverFnc &progress ) : _impl( ( service.type() == ServiceType::PLUGIN ) - ? static_cast( new PluginServiceRepos( service, callback, progress ) ) - : static_cast( new RIMServiceRepos (service, callback, progress ) ) ) + ? static_cast( new PluginServiceRepos( root_r, service, callback, progress ) ) + : static_cast( new RIMServiceRepos( root_r, service, callback, progress ) ) ) {} ServiceRepos::~ServiceRepos() diff --git a/zypp/repo/ServiceRepos.h b/zypp/repo/ServiceRepos.h index 25e9240..ea209ab 100644 --- a/zypp/repo/ServiceRepos.h +++ b/zypp/repo/ServiceRepos.h @@ -27,11 +27,16 @@ namespace zypp public: /** * Return false from the callback to get a \ref AbortRequestException - * to be thrown and the processing to be cancelled. + * to be thrown and the processing to be canceled. */ typedef function< bool( const RepoInfo & )> ProcessRepo; - ServiceRepos( const ServiceInfo & service, + /** + * bsc#1080693: Explicitly pass the RemoManagers rootDir until it can be queried from the ServiceInfo. + * Required to execute plugin services chrooted. + */ + ServiceRepos( const Pathname & root_r, + const ServiceInfo & service, const ProcessRepo & callback, const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc() ); ~ServiceRepos(); diff --git a/zypp/target/RpmPostTransCollector.cc b/zypp/target/RpmPostTransCollector.cc index a5bec21..d00a139 100644 --- a/zypp/target/RpmPostTransCollector.cc +++ b/zypp/target/RpmPostTransCollector.cc @@ -12,6 +12,7 @@ #include #include "zypp/base/LogTools.h" #include "zypp/base/NonCopyable.h" +#include "zypp/base/Gettext.h" #include "zypp/target/RpmPostTransCollector.h" #include "zypp/TmpPath.h" @@ -21,6 +22,7 @@ #include "zypp/ExternalProgram.h" #include "zypp/target/rpm/RpmHeader.h" #include "zypp/ZConfig.h" +#include "zypp/ZYppCallbacks.h" using std::endl; #undef ZYPP_BASE_LOGGER_LOGGROUP @@ -78,20 +80,47 @@ namespace zypp return true; } - /** Execute te remembered scripts. */ - void executeScripts() + /** Execute the remembered scripts. */ + bool executeScripts() { if ( _scripts.empty() ) - return; + return true; HistoryLog historylog; Pathname noRootScriptDir( ZConfig::instance().update_scriptsPath() / tmpDir().basename() ); - for ( const auto & script : _scripts ) + ProgressData scriptProgress( static_cast(_scripts.size()) ); + callback::SendReport report; + scriptProgress.sendTo( ProgressReportAdaptor( ProgressData::ReceiverFnc(), report ) ); + + bool firstScript = true; + while ( ! _scripts.empty() ) { + const std::string & script = _scripts.front(); + const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix + + scriptProgress.name( str::Format(_("Executing %%posttrans script '%1%'")) % pkgident ); + + bool canContinue = true; + if (firstScript) { + firstScript = false; + canContinue = scriptProgress.toMin(); + } else { + canContinue = scriptProgress.incr(); + } + + if (!canContinue) { + str::Str msg; + msg << "Execution of %posttrans scripts cancelled"; + WAR << msg << endl; + historylog.comment( msg, true /*timestamp*/); + JobReport::warning( msg ); + return false; + } + MIL << "EXECUTE posttrans: " << script << endl; - ExternalProgram prog( (noRootScriptDir/script).asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, _root ); + ExternalProgram prog( (noRootScriptDir/script).asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, _root ); str::Str collect; for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() ) @@ -99,13 +128,15 @@ namespace zypp DBG << line; collect << " " << line; } + + //script was executed, remove it from the list + _scripts.pop_front(); + int ret = prog.close(); const std::string & scriptmsg( collect ); if ( ret != 0 || ! scriptmsg.empty() ) { - const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix - if ( ! scriptmsg.empty() ) { str::Str msg; @@ -124,7 +155,12 @@ namespace zypp } } } + + //show a final message + scriptProgress.name( _("Executing %posttrans scripts") ); + scriptProgress.toMax(); _scripts.clear(); + return true; } /** Discard all remembered scrips. */ @@ -150,6 +186,7 @@ namespace zypp _scripts.clear(); } + private: /** Lazy create tmpdir on demand. */ Pathname tmpDir() @@ -189,7 +226,7 @@ namespace zypp bool RpmPostTransCollector::collectScriptFromPackage( ManagedFile rpmPackage_r ) { return _pimpl->collectScriptFromPackage( rpmPackage_r ); } - void RpmPostTransCollector::executeScripts() + bool RpmPostTransCollector::executeScripts() { return _pimpl->executeScripts(); } void RpmPostTransCollector::discardScripts() diff --git a/zypp/target/RpmPostTransCollector.h b/zypp/target/RpmPostTransCollector.h index de0de60..b6c773b 100644 --- a/zypp/target/RpmPostTransCollector.h +++ b/zypp/target/RpmPostTransCollector.h @@ -47,7 +47,7 @@ namespace zypp bool collectScriptFromPackage( ManagedFile rpmPackage_r ); /** Execute te remembered scripts. */ - void executeScripts(); + bool executeScripts(); /** Discard all remembered scrips. */ void discardScripts(); diff --git a/zypp/target/TargetImpl.cc b/zypp/target/TargetImpl.cc index b894100..794b582 100644 --- a/zypp/target/TargetImpl.cc +++ b/zypp/target/TargetImpl.cc @@ -1601,8 +1601,9 @@ namespace zypp // process all remembered posttrans scripts. if ( !abort ) - postTransCollector.executeScripts(); - else + abort = postTransCollector.executeScripts(); + + if ( abort ) postTransCollector.discardScripts(); // Check presence of update scripts/messages. If aborting,