Imported Upstream version 17.3.0 upstream/17.3.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 2 Sep 2019 07:15:26 +0000 (16:15 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 2 Sep 2019 07:15:26 +0000 (16:15 +0900)
34 files changed:
VERSION.cmake
package/libzypp.changes
tests/zypp/CMakeLists.txt
tests/zypp/DrunkenBishop_test.cc [new file with mode: 0644]
tests/zypp/MediaSetAccess_test.cc
tests/zypp/Pathname_test.cc
tests/zypp/RepoManager_test.cc
tools/zypp-pubkey.cc
zypp/CMakeLists.txt
zypp/ExternalProgram.h
zypp/KeyRing.cc
zypp/KeyRing.h
zypp/MediaSetAccess.cc
zypp/MediaSetAccess.h
zypp/Pathname.cc
zypp/Pathname.h
zypp/Product.cc
zypp/PublicKey.cc
zypp/PublicKey.h
zypp/RepoManager.cc
zypp/TmpPath.cc
zypp/TmpPath.h
zypp/ZConfig.cc
zypp/ZConfig.h
zypp/base/DrunkenBishop.cc [new file with mode: 0644]
zypp/base/DrunkenBishop.h [new file with mode: 0644]
zypp/media/MediaCIFS.cc
zypp/media/MediaCurl.cc
zypp/repo/RepoVariables.cc
zypp/repo/ServiceRepos.cc
zypp/repo/ServiceRepos.h
zypp/target/RpmPostTransCollector.cc
zypp/target/RpmPostTransCollector.h
zypp/target/TargetImpl.cc

index 00e3b4e..436eba4 100644 (file)
@@ -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)
 #=======
index 1ddb5f1..48af1b4 100644 (file)
@@ -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)
index 6992f8d..25a47bb 100644 (file)
@@ -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 (file)
index 0000000..c094783
--- /dev/null
@@ -0,0 +1,91 @@
+#include <boost/test/auto_unit_test.hpp>
+#include <iostream>
+#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]-----+" );
+  }
+}
index 33dea03..9160f11 100644 (file)
@@ -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();
 }
 
index c749b4e..3de6d0b 100644 (file)
@@ -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" );
+}
index 329aa46..b9a2336 100644 (file)
@@ -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());
index 4d7ef6f..1776a17 100644 (file)
@@ -8,6 +8,7 @@ using std::flush;
 namespace opt = boost::program_options;
 
 #include <zypp/target/rpm/RpmDb.h>
+#include <zypp/base/String.h>
 
 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<std::string> art( key_r.asciiArt().asLines( " ", PublicKey::AsciiArt::USE_COLOR ) );
+
+  std::vector<std::string> 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<PublicKey> 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() );
index a30696e..379ecca 100644 (file)
@@ -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
index f3fc850..76ec38e 100644 (file)
@@ -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.
index f999239..d9e0c9a 100644 (file)
@@ -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<PublicKeyData> 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 ); }
 
index fdf18f8..b3212fb 100644 (file)
@@ -240,6 +240,11 @@ namespace zypp
     std::list<PublicKeyData> 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.
      *
index 8ec5c65..940c26a 100644 (file)
@@ -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
index 71223e4..6116d1d 100644 (file)
@@ -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
index 0dbb04e..3237fbe 100644 (file)
@@ -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
index 0a37556..09d37d0 100644 (file)
@@ -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"
index 80ae25e..7e98447 100644 (file)
@@ -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();
index 41d093d..83db0d5 100644 (file)
@@ -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;
index 4c93d8b..6ad5c67 100644 (file)
@@ -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<Impl> _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;
 
index 0d48a86..fa022e0 100644 (file)
@@ -456,13 +456,7 @@ namespace zypp
 
   std::list<RepoInfo> 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<DefaultIntegral<bool,false>, 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 )
     {
index a8334cd..bbf4dc5 100644 (file)
@@ -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
index 8d84bfd..cef9e5e 100644 (file)
@@ -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.)
index a439bf8..59aad94 100644 (file)
@@ -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
index 6114e7b..5d5158f 100644 (file)
@@ -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 (file)
index 0000000..85f9dee
--- /dev/null
@@ -0,0 +1,408 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/base/DrunkenBishop.cc
+ */
+#include <iostream>
+//#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<std::uint8_t>( _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<const char *> 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<std::uint8_t> _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<Impl> nullimpl()
+      {
+       static shared_ptr<Impl> _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<std::string> DrunkenBishop::asLines( const std::string & prefix_r, Options options_r ) const
+    {
+      std::vector<std::string> 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 (file)
index 0000000..5a31993
--- /dev/null
@@ -0,0 +1,130 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/base/DrunkenBishop.h
+ */
+#ifndef ZYPP_BASE_DRUNKENBISHOP_H
+#define ZYPP_BASE_DRUNKENBISHOP_H
+
+#include <iosfwd>
+#include <vector>
+#include <string>
+
+#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 <build@suse.de>]
+    ///      +------[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<std::string> asLines( Options options_r = Options() ) const
+      { return asLines( std::string(), options_r ); }
+      /** \overload taking an indent string prefixing each line. */
+      std::vector<std::string> asLines( const std::string & prefix_r, Options options_r = Options() ) const;
+
+    public:
+      class Impl;              ///< Implementation class.
+    private:
+      RW_pointer<Impl> _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
index b47ed44..a6396e0 100644 (file)
@@ -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);
index a44f019..0457ac8 100644 (file)
@@ -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
index 552cc31..8370cbb 100644 (file)
@@ -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.
index e27c260..7869174 100644 (file)
@@ -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<ServiceRepos::Impl*>( new PluginServiceRepos( service, callback, progress ) )
-           : static_cast<ServiceRepos::Impl*>( new RIMServiceRepos (service, callback, progress ) ) )
+    ? static_cast<ServiceRepos::Impl*>( new PluginServiceRepos( root_r, service, callback, progress ) )
+    : static_cast<ServiceRepos::Impl*>( new RIMServiceRepos( root_r, service, callback, progress ) ) )
     {}
 
     ServiceRepos::~ServiceRepos()
index 25e9240..ea209ab 100644 (file)
@@ -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();
index a5bec21..d00a139 100644 (file)
@@ -12,6 +12,7 @@
 #include <fstream>
 #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<ProgressData::value_type>(_scripts.size()) );
+         callback::SendReport<ProgressReport> 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()
index de0de60..b6c773b 100644 (file)
@@ -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();
index b894100..794b582 100644 (file)
@@ -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,