Imported Upstream version 17.25.3 upstream/17.25.3
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 30 Nov 2020 23:35:23 +0000 (08:35 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 30 Nov 2020 23:35:23 +0000 (08:35 +0900)
52 files changed:
VERSION.cmake
devel/devel.ma/Test.cc
package/libzypp.changes
po/es.po
po/fi.po
tests/lib/TestSetup.h
tests/sat/LookupAttr_test.cc
tests/zypp/RepoStatus_test.cc
tests/zypp/Url_test.cc
zypp/CMakeLists.txt
zypp/ExternalProgram.cc
zypp/Locks.cc
zypp/PathInfo.cc
zypp/RepoInfo.cc
zypp/RepoManager.cc
zypp/RepoStatus.cc
zypp/RepoStatus.h
zypp/ServiceInfo.cc
zypp/Url.cc
zypp/Url.h
zypp/VendorAttr.cc
zypp/VendorAttr.h
zypp/ZConfig.cc
zypp/ZYppFactory.cc
zypp/base/Function.h
zypp/base/IOTools.cc
zypp/base/Iterator.h
zypp/base/Measure.cc
zypp/base/Measure.h
zypp/base/ProvideNumericId.h
zypp/base/StringV.cc
zypp/misc/HelixHelpers.h
zypp/misc/LoadTestcase.cc
zypp/misc/LoadTestcase.h
zypp/misc/TestcaseSetup.cc [new file with mode: 0644]
zypp/misc/TestcaseSetup.h [new file with mode: 0644]
zypp/misc/TestcaseSetupImpl.h [new file with mode: 0644]
zypp/misc/YamlTestcaseHelpers.h
zypp/parser/RepoFileReader.cc
zypp/repo/RepoVariables.cc
zypp/sat/AttrMatcher.h [deleted file]
zypp/sat/SolvAttr.cc
zypp/solver/detail/Testcase.cc
zypp/target/TargetImpl.cc
zypp/target/rpm/RpmDb.cc
zypp/target/rpm/RpmDb.h
zypp/target/rpm/RpmHeader.cc
zypp/target/rpm/librpmDb.cc
zypp/target/rpm/librpmDb.h
zypp/ui/UserWantedPackages.cc
zypp/url/UrlBase.cc
zypp/url/UrlBase.h

index f700ca6..70e2889 100644 (file)
@@ -61,8 +61,8 @@
 SET(LIBZYPP_MAJOR "17")
 SET(LIBZYPP_COMPATMINOR "22")
 SET(LIBZYPP_MINOR "25")
-SET(LIBZYPP_PATCH "2")
+SET(LIBZYPP_PATCH "3")
 #
-# LAST RELEASED: 17.25.2 (22)
+# LAST RELEASED: 17.25.3 (22)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
index f39a634..8abb6c9 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <zypp/sat/LookupAttr.h>
 #include <zypp/PoolQuery.h>
-#include <zypp/sat/AttrMatcher.h>
 
 static const Pathname sysRoot( "/tmp/ToolScanRepos" );
 
index 01e6a7a..a43dbce 100644 (file)
@@ -1,4 +1,20 @@
 -------------------------------------------------------------------
+Fri Nov 27 10:17:50 CET 2020 - ma@suse.de
+
+- RepoManager: Carefully tidy up the caches. Remove non-directory
+  entries. (bsc#1178966)
+- RpmDb: If no database exists use the _dbpath configured in rpm.
+  Still makes sure a compat symlink at /var/lib/rpm exists in case
+  the configures _dbpath is elsewhere. (bsc#1178910)
+- Url: Hide known password entires when writing the query part
+  (bsc#1050625 bsc#1177583)
+- adapt testcase to change introduced by libsolv#402.
+- RepoManager: Force refresh if repo url has changed (bsc#1174016)
+- RepoInfo: ignore legacy type= in a .repo file and let RepoManager
+  probe (bsc#1177427, Fixes openSUSE/zypper#357).
+- version 17.25.3 (22)
+
+-------------------------------------------------------------------
 Wed Oct  7 12:05:33 CEST 2020 - ma@suse.de
 
 - Bump version to force rebuild against a fixed libsolv.
index 9ebfde7..1fa3041 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -17,8 +17,8 @@ msgstr ""
 "Project-Id-Version: zypp\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2020-09-18 16:45+0200\n"
-"PO-Revision-Date: 2020-02-19 23:54+0000\n"
-"Last-Translator: Juan Sarria <juansarriam@gmail.com>\n"
+"PO-Revision-Date: 2020-10-08 19:48+0000\n"
+"Last-Translator: Andrés Barrantes Silman <andresbs2000@protonmail.com>\n"
 "Language-Team: Spanish <https://l10n.opensuse.org/projects/libzypp/master/es/"
 ">\n"
 "Language: es\n"
@@ -4940,6 +4940,8 @@ msgid ""
 "Download (curl) error for '%s':\n"
 "Error code: %s\n"
 msgstr ""
+"(curl) Error de descarga para '%s':\n"
+"Código de error: %s\n"
 
 #: zypp/zyppng/media/network/networkrequesterror.cc:138
 #, c-format, boost-format
@@ -4947,6 +4949,8 @@ msgid ""
 "Download (curl) error for '%s':\n"
 "Unable to retrieve HTTP response\n"
 msgstr ""
+"(curl) Error de descarga para '%s':\n"
+"No se recibió una respuesta HTTP\n"
 
 #~ msgid "Can't open lock file: %s"
 #~ msgstr "No es posible abrir el archivo de bloqueo: %s"
index e82823d..bb2a1b8 100644 (file)
--- a/po/fi.po
+++ b/po/fi.po
@@ -20,8 +20,8 @@ msgstr ""
 "Project-Id-Version: zypp.fi\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2020-09-18 16:45+0200\n"
-"PO-Revision-Date: 2020-06-28 06:55+0000\n"
-"Last-Translator: Kimmo Kujansuu <mrkujansuu@gmail.com>\n"
+"PO-Revision-Date: 2020-10-28 22:49+0000\n"
+"Last-Translator: Tommi Nieminen <software@legisign.org>\n"
 "Language-Team: Finnish <https://l10n.opensuse.org/projects/libzypp/master/fi/"
 ">\n"
 "Language: fi\n"
@@ -5105,6 +5105,8 @@ msgid ""
 "Download (curl) error for '%s':\n"
 "Error code: %s\n"
 msgstr ""
+"Latausvirhe (curl) kohteelle ”%s”:\n"
+"Virhekoodi: %s\n"
 
 #: zypp/zyppng/media/network/networkrequesterror.cc:138
 #, c-format, boost-format
@@ -5112,6 +5114,8 @@ msgid ""
 "Download (curl) error for '%s':\n"
 "Unable to retrieve HTTP response\n"
 msgstr ""
+"Latausvirhe (curl) kohteelle ”%s”:\n"
+"HTTP-vastausta ei saatu\n"
 
 #~ msgid "Can't open lock file: %s"
 #~ msgstr "Lukitustiedoston avaaminen ei onnistu: %s"
index b10bbcc..bd3c6d3 100644 (file)
@@ -212,7 +212,7 @@ public:
     }
 
     {
-      base::SetTracker<LocaleSet> localesTracker = setup.localesTracker;
+      base::SetTracker<LocaleSet> localesTracker = setup.localesTracker();
       localesTracker.removed().insert( localesTracker.current().begin(), localesTracker.current().end() );
       satpool().initRequestedLocales( localesTracker.removed() );
 
index 35ad17b..e534946 100644 (file)
@@ -67,8 +67,6 @@ BOOST_AUTO_TEST_CASE(LookupAttr_existingattr_matcher)
   BOOST_CHECK( q.strMatcher() );
 
   BOOST_CHECK_EQUAL( q.size(), 9 );
-  for_(it,q.begin(),q.end())
-  { cout << it << endl;}
 }
 
 BOOST_AUTO_TEST_CASE(LookupAttr_iterate_solvables)
@@ -205,8 +203,14 @@ BOOST_AUTO_TEST_CASE(LookupAttr_solvable_attribute_substructure)
   BOOST_CHECK_EQUAL( q.size(), 1212 );
 
   // search any id in any parent-structure:
+  // - https://github.com/openSUSE/libsolv/pull/402 added an additional
+  // <update:collection> flexarray to each of the 2287 entries. This is
+  // why the total size varies depending on the libsolv version used.
   q = sat::LookupAttr( sat::SolvAttr::allAttr, sat::SolvAttr::allAttr );
-  BOOST_CHECK_EQUAL( q.size(), 10473 );
+  auto qs = q.size();
+  BOOST_CHECK( qs == 10473 || qs == 12760 );
+  // for_(it,q.begin(),q.end())
+  // { cout << it << endl;}
 }
 
 BOOST_AUTO_TEST_CASE(LookupAttr_repoattr)
index 0f1dd24..bf98ec3 100644 (file)
@@ -15,18 +15,42 @@ using namespace zypp::filesystem;
 
 BOOST_AUTO_TEST_CASE(repostatus_test)
 {
-  TmpFile tmpPath;
-  TmpFile tmpPath2;
-  RepoStatus status;
-  RepoStatus fstatus( tmpPath );
-  RepoStatus fstatus2( tmpPath2 );
-  BOOST_CHECK_EQUAL( status.empty(), true );
-  BOOST_CHECK_EQUAL( (status&&status).empty(), true );
-
-  BOOST_CHECK_EQUAL( fstatus.empty(), false );
-  BOOST_CHECK_EQUAL( (fstatus&&status).empty(), false );
-
-  BOOST_CHECK_EQUAL( (fstatus&&status), (status&&fstatus) );
-  BOOST_CHECK_EQUAL( (fstatus&&fstatus2), (fstatus2&&fstatus) );
-
+  RepoStatus e;
+  RepoStatus E { "", 42 };     // empty refers to the checksum only, not to the timestamp!
+  RepoStatus a { "aa", 0 };
+  RepoStatus b { "bb", 1 };
+  RepoStatus c { "cc", 2 };
+
+  BOOST_CHECK_EQUAL( e.empty(), true );
+  BOOST_CHECK_EQUAL( e.timestamp(), 0 );
+  BOOST_CHECK_EQUAL( (e && e).empty(), true );
+
+  BOOST_CHECK_EQUAL( E.empty(), true );
+  BOOST_CHECK_EQUAL( E.timestamp(), 42 );
+  RepoStatus r { E && e };
+  BOOST_CHECK_EQUAL( r.empty(), true );
+  BOOST_CHECK_EQUAL( r.timestamp(), 42 );
+  r = e && E;
+  BOOST_CHECK_EQUAL( r.empty(), true );
+  BOOST_CHECK_EQUAL( r.timestamp(), 42 );
+  r = E && E;
+  BOOST_CHECK_EQUAL( r.empty(), true );
+  BOOST_CHECK_EQUAL( r.timestamp(), 42 );
+
+
+  BOOST_CHECK_EQUAL( a.empty(), false );
+  BOOST_CHECK_EQUAL( a.timestamp(), 0 );
+
+  r = e && a;
+  BOOST_CHECK_EQUAL( r.empty(), false );
+  BOOST_CHECK_EQUAL( r.timestamp(), a.timestamp() );   // max timestamp
+
+  r = a && b;
+  BOOST_CHECK_EQUAL( r, (b && a) );
+  BOOST_CHECK_EQUAL( r.timestamp(), b.timestamp() );   // max timestamp
+
+  r = a && b && c;
+  BOOST_CHECK_EQUAL( r, (a && b) && c );
+  BOOST_CHECK_EQUAL( r, a && (b && c) );
+  BOOST_CHECK_EQUAL( r.timestamp(), c.timestamp() );   // max timestamp
 }
index bea8d7a..7f44363 100644 (file)
@@ -90,13 +90,15 @@ BOOST_AUTO_TEST_CASE(test_url1)
 
     // asString shouldn't print the password, asCompleteString should.
     // further, the "//" at the begin of the path should be keept.
-    str = "http://user:pass@localhost//srv/ftp";
-    one = "http://user@localhost//srv/ftp";
+    str = "http://user:pass@localhost//srv/ftp?proxypass=@PROXYPASS@&proxy=proxy.my&proxyuser=@PROXYUSER@&Xproxypass=NOTTHIS&proxypass=@PROXYPASS@&proxypass=@PROXYPASS@";
+    one = "http://user@localhost//srv/ftp?proxy=proxy.my&proxyuser=@PROXYUSER@&Xproxypass=NOTTHIS";
     two = str;
     url = str;
 
     BOOST_CHECK_EQUAL( one, url.asString() );
     BOOST_CHECK_EQUAL( two, url.asCompleteString() );
+    // hidden proxypass in the query is available when explicitely asked for
+    BOOST_CHECK_EQUAL( url.getQueryParam( "proxypass" ), "@PROXYPASS@" );
 
     // absolute path defaults to 'file://'
     str = "/some/local/path";
index fdc2572..d74f2bc 100644 (file)
@@ -794,12 +794,14 @@ SET( zypp_misc_HEADERS
   Misc.h
   misc/DefaultLoadSystem.h
   misc/CheckAccessDeleted.h
+  misc/TestcaseSetup.h
   misc/LoadTestcase.h
 )
 
 SET( zypp_misc_SRCS
   misc/DefaultLoadSystem.cc
   misc/CheckAccessDeleted.cc
+  misc/TestcaseSetup.cc
   misc/LoadTestcase.cc
 )
 
index 9b7f3cb..ab853d2 100644 (file)
@@ -483,9 +483,10 @@ namespace zypp {
 
            if ( retval == -1 )
            {
-             ERR << "select error: " << strerror(errno) << endl;
-             if ( errno != EINTR )
+              if ( errno != EINTR ) {
+                ERR << "select error: " << strerror(errno) << endl;
                break;
+              }
            }
            else if ( retval )
            {
index d8c65f0..638bd75 100644 (file)
@@ -10,7 +10,7 @@
 #include <set>
 #include <fstream>
 #include <boost/function.hpp>
-#include <boost/function_output_iterator.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
 #include <algorithm>
 
 #include <zypp/base/Regex.h>
index baf9e43..63a71d9 100644 (file)
@@ -423,6 +423,15 @@ namespace zypp
         return logResult( ENOTDIR );
       }
 
+      p.lstat();       // get dir symlinks
+      if ( !p.isDir() ) {
+       MIL << "unlink symlink ";
+       if ( ::unlink( path.asString().c_str() ) == -1 ) {
+         return logResult( errno );
+       }
+       return logResult( 0 );
+      }
+
       return logResult( recursive_rmdir_1( path ) );
     }
 
index 26b4066..27a1c67 100644 (file)
@@ -62,7 +62,7 @@ namespace zypp
        else if ( PathInfo(path_r/"/cookie").isFile() )
        { ret = repo::RepoType::RPMPLAINDIR; }
       }
-      MIL << "Probed cached type " << ret << " at " << path_r << endl;
+      DBG << "Probed cached type " << ret << " at " << path_r << endl;
       return ret;
     }
   } // namespace
@@ -934,7 +934,7 @@ namespace zypp
       std::string indent;
       for ( const auto & url : _pimpl->baseUrls().raw() )
       {
-        str << indent << url << endl;
+        str << indent << hotfix1050625::asString( url ) << endl;
        if ( indent.empty() ) indent = "        ";      // "baseurl="
       }
     }
@@ -943,7 +943,7 @@ namespace zypp
       str << "path="<< path() << endl;
 
     if ( ! (rawMirrorListUrl().asString().empty()) )
-      str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << rawMirrorListUrl() << endl;
+      str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << hotfix1050625::asString( rawMirrorListUrl() ) << endl;
 
     if ( type() != repo::RepoType::NONE )
       str << "type=" << type().asString() << endl;
index e932ec8..9eb19a5 100644 (file)
@@ -814,11 +814,20 @@ namespace zypp
        std::set<std::string> oldfiles;
        set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
                        std::inserter( oldfiles, oldfiles.end() ) );
+
+       // bsc#1178966: Files or symlinks here have been created by the user
+       // for whatever purpose. It's our cache, so we purge them now before
+       // they may later conflict with directories we need.
+       PathInfo pi;
        for ( const std::string & old : oldfiles )
        {
          if ( old == Repository::systemRepoAlias() )   // don't remove the @System solv file
            continue;
-         filesystem::recursive_rmdir( cachePath_r / old );
+         pi( cachePath_r/old );
+         if ( pi.isDir() )
+           filesystem::recursive_rmdir( pi.path() );
+         else
+           filesystem::unlink( pi.path() );
        }
       }
     }
@@ -901,6 +910,10 @@ namespace zypp
     if ( repokind == RepoType::NONE )
       repokind = probeCache( productdatapath );
 
+    // NOTE: The calling code expects an empty RepoStatus being returned
+    // if the metadata cache is empty. So additioanl components like the
+    // RepoInfos status are joined after the switch IFF the status is not
+    // empty.
     RepoStatus status;
     switch ( repokind.toEnum() )
     {
@@ -913,7 +926,7 @@ namespace zypp
        break;
 
       case RepoType::RPMPLAINDIR_e :
-       status = RepoStatus::fromCookieFile( productdatapath/"cookie" );
+       status = RepoStatus::fromCookieFile( productdatapath/"cookie" );        // dir status at last refresh
        break;
 
       case RepoType::NONE_e :
@@ -922,6 +935,10 @@ namespace zypp
         // ZYPP_THROW(RepoUnknownTypeException());
        break;
     }
+
+    if ( ! status.empty() )
+      status = status && RepoStatus( info );
+
     return status;
   }
 
@@ -968,12 +985,13 @@ namespace zypp
     assert_alias(info);
     try
     {
-      MIL << "Going to try to check whether refresh is needed for " << url << " (" << info.type() << ")" << endl;
+      MIL << "Check if to refresh repo " << info.alias() << " at " << url << " (" << info.type() << ")" << endl;
 
       // first check old (cached) metadata
       Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
       filesystem::assert_dir( mediarootpath );
       RepoStatus oldstatus = metadataStatus( info );
+
       if ( oldstatus.empty() )
       {
         MIL << "No cached metadata, going to refresh" << endl;
@@ -997,33 +1015,37 @@ namespace zypp
        policy = RefreshIfNeededIgnoreDelay;
       }
 
-      // now we've got the old (cached) status, we can decide repo.refresh.delay
+      // Check whether repo.refresh.delay applies...
       if ( policy != RefreshIfNeededIgnoreDelay )
       {
-        // difference in seconds
-        double diff = difftime(
-          (Date::ValueType)Date::now(),
-          (Date::ValueType)oldstatus.timestamp()) / 60;
+       // bsc#1174016: Prerequisite to skipping the refresh is that metadata
+       // and solv cache status match. They will not, if the repos URL was
+       // changed e.g. due to changed repovars.
+       RepoStatus cachestatus = cacheStatus( info );
 
-        DBG << "oldstatus: " << (Date::ValueType)oldstatus.timestamp() << endl;
-        DBG << "current time: " << (Date::ValueType)Date::now() << endl;
-        DBG << "last refresh = " << diff << " minutes ago" << endl;
-
-        if ( diff < ZConfig::instance().repo_refresh_delay() )
-        {
-         if ( diff < 0 )
-         {
-           WAR << "Repository '" << info.alias() << "' was refreshed in the future!" << endl;
-         }
-         else
+       if ( oldstatus == cachestatus )
+       {
+         // difference in seconds
+         double diff = ::difftime( (Date::ValueType)Date::now(), (Date::ValueType)oldstatus.timestamp() ) / 60;
+         if ( diff < ZConfig::instance().repo_refresh_delay() )
          {
-           MIL << "Repository '" << info.alias()
-               << "' has been refreshed less than repo.refresh.delay ("
-               << ZConfig::instance().repo_refresh_delay()
-               << ") minutes ago. Advising to skip refresh" << endl;
-           return REPO_CHECK_DELAYED;
+           if ( diff < 0 )
+           {
+             WAR << "Repository '" << info.alias() << "' was refreshed in the future!" << endl;
+           }
+           else
+           {
+             MIL << "Repository '" << info.alias()
+             << "' has been refreshed less than repo.refresh.delay ("
+             << ZConfig::instance().repo_refresh_delay()
+             << ") minutes ago. Advising to skip refresh" << endl;
+             return REPO_CHECK_DELAYED;
+           }
          }
-        }
+       }
+       else {
+         MIL << "Metadata and solv cache don't match. Check data on server..." << endl;
+       }
       }
 
       repo::RepoType repokind = info.type();
@@ -1038,19 +1060,19 @@ namespace zypp
        case RepoType::RPMMD_e:
        {
          MediaSetAccess media( url );
-         newstatus = yum::Downloader( info, mediarootpath ).status( media );
+         newstatus = RepoStatus( info ) && yum::Downloader( info, mediarootpath ).status( media );
        }
        break;
 
        case RepoType::YAST2_e:
        {
          MediaSetAccess media( url );
-         newstatus = susetags::Downloader( info, mediarootpath ).status( media );
+         newstatus = RepoStatus( info ) && susetags::Downloader( info, mediarootpath ).status( media );
        }
        break;
 
        case RepoType::RPMPLAINDIR_e:
-         newstatus = RepoStatus( MediaMounter(url).getPathName(info.path()) ); // dir status
+         newstatus = RepoStatus( info ) && RepoStatus( MediaMounter(url).getPathName(info.path()) );   // dir status
          break;
 
        default:
@@ -1183,6 +1205,7 @@ namespace zypp
         }
         else if ( repokind.toEnum() == RepoType::RPMPLAINDIR_e )
         {
+         // as substitute for real metadata remember the checksum of the directory we refreshed
           MediaMounter media( url );
           RepoStatus newstatus = RepoStatus( media.getPathName( info.path() ) );       // dir status
 
index 059474f..ba10fc7 100644 (file)
 #include <iostream>
 #include <sstream>
 #include <fstream>
+#include <set>
 #include <zypp/base/Logger.h>
 #include <zypp/base/String.h>
 #include <zypp/RepoStatus.h>
+#include <zypp/RepoInfo.h>
 #include <zypp/PathInfo.h>
 
 using std::endl;
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
+  ///////////////////////////////////////////////////////////////////
+  namespace
+  {
+    /** Recursive computation of max dir timestamp. */
+    void recursiveTimestamp( const Pathname & dir_r, time_t & max_r )
+    {
+      std::list<std::string> dircontent;
+      if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 )
+       return; // readdir logged the error
+
+      for_( it, dircontent.begin(), dircontent.end() )
+      {
+       PathInfo pi( dir_r + *it, PathInfo::LSTAT );
+       if ( pi.isDir() )
+       {
+         if ( pi.mtime() > max_r )
+           max_r = pi.mtime();
+         recursiveTimestamp( pi.path(), max_r );
+       }
+      }
+    }
+  } // namespace
+  ///////////////////////////////////////////////////////////////////
 
   ///////////////////////////////////////////////////////////////////
   //
@@ -30,44 +55,89 @@ namespace zypp
   /** RepoStatus implementation. */
   struct RepoStatus::Impl
   {
-  public:
-    std::string _checksum;
-    Date _timestamp;
+    using Checksums = std::set<std::string>;
 
-    // NOTE: Changing magic will at once invalidate all solv file caches.
-    // Helpfull if solv file content must be refreshed (e.g. due to different
-    // repo2* arguments) even if raw metadata are unchanged.
-    // Only values set from a RepoStatus ctor need magic to be added.
+  public:
+    /** Assign data called from RepoStatus ctor (adds magic).
+     *
+     * \Note Changing magic will at once invalidate all solv file caches.
+     * Helpfull if solv file content must be refreshed (e.g. due to different
+     * repo2solv arguments) even if raw metadata are unchanged. Only values
+     * set from a RepoStatus ctor need magic to be added!
+     */
     void assignFromCtor( std::string && checksum_r, Date && timestamp_r )
     {
-      _checksum = std::move(checksum_r);
-      _timestamp = std::move(timestamp_r);
-      if ( !_checksum.empty() )
-      {
+      if ( !checksum_r.empty() ) {
        static const std::string magic( "43" );
-       _checksum += magic;
+       checksum_r += magic;
+       _checksums.insert( std::move(checksum_r) );
       }
+      _timestamp = std::move(timestamp_r);
     }
 
-    /** Recursive computation of max dir timestamp. */
-    static void recursive_timestamp( const Pathname & dir_r, time_t & max_r )
+    /** Inject raw data (no magic added). */
+    void inject( std::string && checksum_r, Date && timestamp_r )
     {
-      std::list<std::string> dircontent;
-      if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 )
-       return; // readdir logged the error
+      if ( !checksum_r.empty() ) {
+       _checksums.insert( std::move(checksum_r) );
+       _cachedchecksum.reset();
+      }
 
-      for_( it, dircontent.begin(), dircontent.end() )
-      {
-       PathInfo pi( dir_r + *it, PathInfo::LSTAT );
-       if ( pi.isDir() )
-       {
-         if ( pi.mtime() > max_r )
-           max_r = pi.mtime();
-         recursive_timestamp( pi.path(), max_r );
+      if ( timestamp_r > _timestamp )
+       _timestamp = timestamp_r;
+    }
+
+    /** Inject the raw data from rhs */
+    void injectFrom( const Impl & rhs )
+    {
+      if ( &rhs == this )      // no self insert
+       return;
+
+      if ( !rhs._checksums.empty() ) {
+       _checksums.insert( rhs._checksums.begin(), rhs._checksums.end() );
+       _cachedchecksum.reset();
+      }
+
+      if ( rhs._timestamp > _timestamp )
+       _timestamp = rhs._timestamp;
+    }
+
+    bool empty() const
+    { return _checksums.empty(); }
+
+    std::string checksum() const
+    {
+      std::string ret;
+      if ( _checksums.empty() )
+       return ret;
+
+      if ( _checksums.size() == 1 )
+       ret = *_checksums.begin();
+      else {
+       if ( !_cachedchecksum ) {
+         std::stringstream ss;
+         for ( std::string_view c : _checksums )
+           ss << c;
+         _cachedchecksum = CheckSum::sha1(ss).checksum();
        }
+       ret = *_cachedchecksum;
       }
+      return ret;
     }
 
+    Date timestamp() const
+    { return _timestamp; }
+
+    /** Dump to log file (not to/from CookieFile). */
+    std::ostream & dumpOn( std::ostream & str ) const
+    { return str << ( empty() ? "NO_REPOSTATUS" : checksum() ) << " " << time_t(_timestamp); }
+
+  private:
+    Checksums _checksums;
+    Date _timestamp;
+
+    mutable std::optional<std::string> _cachedchecksum;
+
   private:
     friend Impl * rwcowClone<Impl>( const Impl * rhs );
     /** clone for RWCOW_pointer */
@@ -76,10 +146,6 @@ namespace zypp
   };
   ///////////////////////////////////////////////////////////////////
 
-  /** \relates RepoStatus::Impl Stream output */
-  inline std::ostream & operator<<( std::ostream & str, const RepoStatus::Impl & obj )
-  { return str << obj._checksum << " " << (time_t)obj._timestamp; }
-
   ///////////////////////////////////////////////////////////////////
   //
   //   CLASS NAME : RepoStatus
@@ -103,12 +169,18 @@ namespace zypp
       else if ( info.isDir() )
       {
        time_t t = info.mtime();
-       Impl::recursive_timestamp( path_r, t );
+       recursiveTimestamp( path_r, t );
        _pimpl->assignFromCtor( CheckSum::sha1FromString( str::numstring( t ) ).checksum(), Date( t ) );
       }
     }
   }
 
+  RepoStatus::RepoStatus( const RepoInfo & info_r )
+  : _pimpl( new Impl() )
+  {
+    _pimpl->assignFromCtor( CheckSum::sha1FromString( info_r.url().asString() ).checksum(), Date() );
+  }
+
   RepoStatus::RepoStatus( std::string checksum_r, Date timestamp_r )
   : _pimpl( new Impl() )
   {
@@ -128,10 +200,10 @@ namespace zypp
     }
     else
     {
-      // line := "[checksum] time_t"
-      std::string line( str::getline( file ) );
-      ret._pimpl->_timestamp = Date( str::strtonum<time_t>( str::stripLastWord( line ) ) );
-      ret._pimpl->_checksum = line;
+      // line := "[checksum] time_t"  !!! strip time from line
+      std::string line { str::getline( file ) };
+      Date        stmp { str::strtonum<time_t>( str::stripLastWord( line ) ) };
+      ret._pimpl->inject( std::move(line), std::move(stmp) );  // raw inject to avoid magic being added
     }
     return ret;
   }
@@ -142,42 +214,28 @@ namespace zypp
     if (!file) {
       ZYPP_THROW (Exception( "Can't open " + path_r.asString() ) );
     }
-    file << _pimpl->_checksum << " " << (time_t)_pimpl->_timestamp << endl;
+    file << _pimpl->checksum() << " " << time_t(_pimpl->timestamp()) << endl;
     file.close();
   }
 
   bool RepoStatus::empty() const
-  { return _pimpl->_checksum.empty(); }
+  { return _pimpl->empty(); }
 
   Date RepoStatus::timestamp() const
-  { return _pimpl->_timestamp; }
+  { return _pimpl->timestamp(); }
 
   std::ostream & operator<<( std::ostream & str, const RepoStatus & obj )
-  { return str << *obj._pimpl; }
+  { return obj._pimpl->dumpOn( str ); }
 
   RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs )
   {
-    RepoStatus result;
-
-    if ( lhs.empty() )
-      result = rhs;
-    else if ( rhs.empty() )
-      result = lhs;
-    else
-    {
-      // order strings to assert && is kommutativ
-      std::string lchk( lhs._pimpl->_checksum );
-      std::string rchk( rhs._pimpl->_checksum );
-      std::stringstream ss( lchk < rchk ? lchk+rchk : rchk+lchk );
-
-      result._pimpl->_checksum = CheckSum::sha1(ss).checksum();
-      result._pimpl->_timestamp = std::max( lhs._pimpl->_timestamp, rhs._pimpl->_timestamp );
-    }
+    RepoStatus result { lhs };
+    result._pimpl->injectFrom( *rhs._pimpl );
     return result;
   }
 
   bool operator==( const RepoStatus & lhs, const RepoStatus & rhs )
-  { return lhs._pimpl->_checksum == rhs._pimpl->_checksum; }
+  { return lhs._pimpl->checksum() == rhs._pimpl->checksum(); }
 
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
index 41e0152..7ab4972 100644 (file)
@@ -21,6 +21,8 @@
 namespace zypp
 { /////////////////////////////////////////////////////////////////
 
+  class RepoInfo;
+
   ///////////////////////////////////////////////////////////////////
   /// \class RepoStatus
   /// \brief Track changing files or directories.
@@ -52,6 +54,9 @@ namespace zypp
      */
     explicit RepoStatus( const Pathname & path_r );
 
+    /** Compute status of a \a RepoInfo to track changes requiring a refresh. */
+    explicit RepoStatus( const RepoInfo & info_r );
+
     /** Explicitly specify checksum string and timestamp to use. */
     RepoStatus( std::string checksum_r, Date timestamp_r );
 
@@ -73,14 +78,14 @@ namespace zypp
     void saveToCookieFile( const Pathname & path_r ) const;
 
   public:
-    /** Whether the status is empty (default constucted) */
+    /** Whether the status is empty (empty checksum) */
     bool empty() const;
 
     /** The time the data were changed the last time */
     Date timestamp() const;
 
   public:
-    struct Impl;                       ///< Implementation
+    struct Impl;               ///< Implementation
   private:
     RWCOW_pointer<Impl> _pimpl;        ///< Pointer to implementation
   };
index 04bfcb2..dc7684a 100644 (file)
@@ -173,7 +173,7 @@ namespace zypp
   std::ostream & ServiceInfo::dumpAsIniOn( std::ostream & str ) const
   {
     RepoInfoBase::dumpAsIniOn(str)
-      << "url = " << rawUrl() << endl
+      << "url = " << hotfix1050625::asString( rawUrl() ) << endl
       << "type = " << type() << endl;
 
     if ( ttl() )
index 2e9a554..4572e75 100644 (file)
@@ -877,6 +877,11 @@ namespace zypp
     return (lhs.asCompleteString() != rhs.asCompleteString());
   }
 
+  namespace hotfix1050625 {
+    std::string asString( const Url & url_r )
+    { return url_r.m_impl->asString1050625(); }
+  }
+
   ////////////////////////////////////////////////////////////////////
 } // namespace zypp
 //////////////////////////////////////////////////////////////////////
index ff2cbb4..9323fcf 100644 (file)
 namespace zypp
 { ////////////////////////////////////////////////////////////////////
 
+  class Url;
+  namespace hotfix1050625 {
+    std::string asString( const Url & url_r );
+  }
   namespace filesystem {
     class Pathname;
   }
@@ -821,6 +825,7 @@ namespace zypp
     setViewOptions(const ViewOptions &vopts);
 
   private:
+    friend std::string hotfix1050625::asString( const Url & url_r );
     url::UrlRef m_impl;
   };
 
index 580c1d8..47680d1 100644 (file)
@@ -58,6 +58,24 @@ namespace zypp
     bool equivalent( IdString lVendor, IdString rVendor ) const
     { return lVendor == rVendor || vendorMatchId( lVendor ) == vendorMatchId( rVendor ); }
 
+    unsigned foreachVendorList( std::function<bool(VendorList)> fnc_r ) const
+    {
+      std::map<unsigned,VendorList> lists;
+      for( const auto & el : _vendorGroupMap )
+       lists[el.second].push_back( el.first );
+
+      unsigned ret = 0;
+      for ( auto el : lists ) {
+       VendorList & vlist { el.second };
+       if ( vlist.empty() )
+         continue;
+       ++ret;
+       if ( fnc_r && !fnc_r( std::move(vlist) ) )
+         break;
+      }
+      return ret;
+    }
+
   private:
     using VendorGroupMap = std::map<std::string,unsigned>;
     VendorGroupMap _vendorGroupMap;    ///< Vendor group definition. Equivalent groups share the same ID.
@@ -265,6 +283,9 @@ namespace zypp
   void VendorAttr::_addVendorList( VendorList && vendorList_r )
   { _pimpl->addVendorList( std::move(vendorList_r) ); }
 
+  unsigned VendorAttr::foreachVendorList( std::function<bool(VendorList)> fnc_r ) const
+  { return _pimpl->foreachVendorList( std::move(fnc_r) ); }
+
 #if LEGACY(1722)
   bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const
   { return const_cast<VendorAttr*>(this)->addVendorDirectory( dirname ); }
index 0c13d9f..65e8a73 100644 (file)
@@ -143,6 +143,12 @@ class VendorAttr
     bool equivalent( const PoolItem & lVendor, const PoolItem & rVendor ) const;
 
   public:
+    /** Call \a fnc_r for each equivalent vendor list (return \c false to break).
+     * \return The number of calls to \a fnc_r.
+     */
+    unsigned foreachVendorList( std::function<bool(VendorList)> fnc_r ) const;
+
+  public:
     class Impl;                 ///< Implementation class.
     RWCOW_pointer<Impl> _pimpl; ///< Pointer to implementation.
 
index 3bf1185..4a217dc 100644 (file)
@@ -879,7 +879,7 @@ namespace zypp
     {
       WAR << "Overriding text locale (" << _pimpl->cfg_textLocale << "): " << locale_r << endl;
       _pimpl->cfg_textLocale = locale_r;
-#warning prefer signal
+      // Propagate changes
       sat::Pool::instance().setTextLocale( locale_r );
     }
   }
index c1f0bca..f9663df 100644 (file)
@@ -26,7 +26,6 @@ extern "C"
 
 #include <zypp/ZYppFactory.h>
 #include <zypp/zypp_detail/ZYppImpl.h>
-#include <zypp/zypp_detail/ZYppReadOnlyHack.h>
 
 #include <boost/interprocess/sync/file_lock.hpp>
 #include <boost/interprocess/sync/scoped_lock.hpp>
@@ -70,7 +69,7 @@ namespace zypp
 
     static bool active = getenv("ZYPP_READONLY_HACK");
 
-    void IWantIt()
+    void IWantIt()     // see zypp/zypp_detail/ZYppReadOnlyHack.h
     {
       active = true;
       MIL << "ZYPP_READONLY promised." <<  endl;
index 95b1fe7..3750cf1 100644 (file)
@@ -13,6 +13,7 @@
 #define ZYPP_BASE_FUNCTION_H
 
 #include <boost/function.hpp>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
 #include <boost/bind.hpp>
 #include <boost/ref.hpp>
 
index 52817be..9abce85 100644 (file)
@@ -94,9 +94,10 @@ namespace zypp::io {
       int retval = g_poll( &fd, 1, timeout );
       if ( retval == -1 )
       {
-        ERR << "select error: " << strerror(errno) << std::endl;
-        if ( errno != EINTR )
+        if ( errno != EINTR ) {
+          ERR << "select error: " << strerror(errno) << std::endl;
           return std::make_pair( ReceiveUpToResult::Error, std::string() );
+        }
       }
       else if ( retval )
       {
index 165996d..b3a0c27 100644 (file)
@@ -18,7 +18,7 @@
 #include <boost/functional.hpp>
 #include <boost/iterator/filter_iterator.hpp>
 #include <boost/iterator/transform_iterator.hpp>
-#include <boost/function_output_iterator.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
 
 #include <zypp/base/Iterable.h>
 
index 391b446..05eaccd 100644 (file)
@@ -138,10 +138,11 @@ namespace zypp
     class Measure::Impl
     {
     public:
-      Impl( const std::string & ident_r )
+      Impl( const std::string & ident_r, std::ostream * log_r = nullptr )
       : _ident  ( ident_r )
       , _level  ( _glevel )
       , _seq    ( 0 )
+      , _log    ( log_r )
       {
        _glevel += "..";
         log() << _level << "START MEASURE(" << _ident << ")" << endl;
@@ -172,11 +173,13 @@ namespace zypp
         _elapsed = _stop;
       }
 
-    private:
       /** Return the log stream. */
       std::ostream & log() const
-      { return INT; }
+      { return _log ? *_log : INT; }
+      std::ostream * logp() const
+      { return _log; }
 
+    private:
       std::ostream & dumpMeasure( std::ostream & str_r, const std::string & tag_r = std::string() ) const
       {
         str_r << ( _stop - _start );
@@ -198,6 +201,8 @@ namespace zypp
       mutable unsigned _seq;
       mutable Tm       _elapsed;
       mutable Tm       _stop;
+
+      std::ostream *   _log = nullptr;
     };
 
     std::string Measure::Impl::_glevel;
@@ -217,11 +222,15 @@ namespace zypp
     : _pimpl( new Impl( ident_r ) )
     {}
 
+    Measure::Measure( const std::string & ident_r, std::ostream & out_r )
+    : _pimpl( new Impl( ident_r, &out_r ) )
+    {}
+
     Measure::~Measure()
     {}
 
     void Measure::start( const std::string & ident_r )
-    { stop(); _pimpl.reset( new Impl( ident_r ) ); }
+    { stop(); _pimpl.reset( _pimpl ? new Impl( ident_r, _pimpl->logp() ) : new Impl( ident_r ) ); }
 
     void Measure::restart()
     { _pimpl->restart(); }
index b1f9d30..4a82d40 100644 (file)
@@ -74,6 +74,8 @@ namespace zypp
       /** Ctor taking \a ident_r string and auto starts timer. */
       explicit
       Measure( const std::string & ident_r );
+      /** \overload log to custom ostream */
+      Measure( const std::string & ident_r, std::ostream & out_r );
 
       /** Dtor. */
       ~Measure();
index b6142fb..482e5e8 100644 (file)
@@ -61,6 +61,13 @@ namespace zypp
         /** Assign */
         ProvideNumericId & operator=( const ProvideNumericId & /*rhs*/ )
         { return *this; }
+        /** Move ctor */
+        ProvideNumericId( ProvideNumericId && rhs )
+        : _numericId( rhs._numericId )
+        { /*rhs._numericId = 0;*/ }
+        /** Move Assign */
+        ProvideNumericId & operator=( ProvideNumericId && rhs )
+        { if ( &rhs != this ) { _numericId = rhs._numericId; /*rhs._numericId = 0;*/ } return *this; }
         /** Dtor */
         ~ProvideNumericId()
         {}
index 0d3cfd5..67d0242 100644 (file)
@@ -22,7 +22,8 @@ namespace zypp
     {
 #warning REIMPLEMENT
       std::vector<std::string> words;
-      str::split( std::string(line_r), std::back_inserter(words), ",", str::TRIM );
+      str::split( std::string(line_r), std::back_inserter(words), std::string(sep_r), str::TRIM );
+
       if ( fnc_r ) {
        for ( const auto & w : words )
          fnc_r( std::string_view(w) );
index b11a70f..2fa8ddd 100644 (file)
@@ -15,6 +15,7 @@
 #include <zypp/AutoDispose.h>
 #include <zypp/base/LogControl.h>
 #include <zypp/misc/LoadTestcase.h>
+#include <zypp/misc/TestcaseSetupImpl.h>
 
 #include <libxml/parser.h>
 #include <libxml/xmlmemory.h>
@@ -134,8 +135,9 @@ namespace helix::detail {
     return res;
   }
 
-  bool parseSetup ( const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &target, std::string *err )
+  bool parseSetup ( const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err )
   {
+    auto &target = t.data();
     auto architecture = setup.getProp( "arch" );
     if ( !architecture.empty() )
     {
@@ -178,7 +180,7 @@ namespace helix::detail {
         target.resolverFocus = zypp::resolverFocusFromString( node->getProp("value") );
       }
       else if ( node->equals("system") ) {
-        target.systemRepo = zypp::misc::testcase::RepoData {
+        target.systemRepo = zypp::misc::testcase::RepoDataImpl {
           zypp::misc::testcase::TestcaseRepoType::Helix,
           "@System",
           99,
@@ -205,7 +207,7 @@ namespace helix::detail {
           prio = zypp::str::strtonum<unsigned>( priority );
         }
 
-        target.repos.push_back( zypp::misc::testcase::RepoData{
+        target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
           zypp::misc::testcase::TestcaseRepoType::Helix,
           name,
           prio,
@@ -216,7 +218,7 @@ namespace helix::detail {
       {
         std::string url = node->getProp("url");
         std::string alias = node->getProp("name");
-        target.repos.push_back( zypp::misc::testcase::RepoData{
+        target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
           zypp::misc::testcase::TestcaseRepoType::Url,
           alias,
           99,
@@ -225,7 +227,7 @@ namespace helix::detail {
       }
       else if ( node->equals("force-install") )
       {
-        target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstall{
+        target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstallImpl{
           node->getProp("channel"),
           node->getProp("package"),
           node->getProp("kind")
@@ -282,18 +284,18 @@ namespace helix::detail {
 
   bool parseTrialNode ( const XmlNode &node, zypp::misc::testcase::TestcaseTrial::Node &testcaseNode )
   {
-    testcaseNode.name = node.name();
+    testcaseNode.name() = node.name();
     const auto & content = node.getContent();
     if ( !content.empty() ) {
-      testcaseNode.value = content;
+      testcaseNode.value() = content;
     }
-    testcaseNode.properties = node.getAllProps();
+    testcaseNode.properties() = node.getAllProps();
 
     for ( auto childNode = node.children(); childNode; childNode = childNode->next() ) {
       auto testNode = std::make_shared<zypp::misc::testcase::TestcaseTrial::Node>();
       if ( !parseTrialNode( *childNode, *testNode ) )
         return false;
-      testcaseNode.children.push_back( testNode );
+      testcaseNode.children().push_back( testNode );
     }
     return true;
   }
@@ -309,7 +311,7 @@ namespace helix::detail {
 
       zypp::misc::testcase::TestcaseTrial::Node testcaseNode;
       parseTrialNode( *node, testcaseNode );
-      target.nodes.push_back( testcaseNode );
+      target.nodes().push_back( testcaseNode );
       node = node->next();
     }
     return true;
index e0be450..dbe4068 100644 (file)
 #include "YamlTestcaseHelpers.h"
 #include <zypp/PathInfo.h>
 #include <zypp/base/LogControl.h>
-#include <zypp/Repository.h>
-#include <zypp/RepoManager.h>
-#include <zypp/sat/Pool.h>
-
-#define ZYPP_USE_RESOLVER_INTERNALS
-#include <zypp/solver/detail/SystemCheck.h>
 
 namespace zypp::misc::testcase {
 
@@ -36,6 +30,70 @@ namespace zypp::misc::testcase {
   };
 
 
+  struct TestcaseTrial::Impl
+  {
+    std::vector<Node> nodes;
+    Impl *clone() const { return new Impl(*this); }
+  };
+
+  struct TestcaseTrial::Node::Impl
+  {
+    std::string name;
+    std::string value;
+    std::map<std::string, std::string> properties;
+    std::vector<std::shared_ptr<Node>> children;
+    Impl *clone() const { return new Impl(*this); }
+  };
+
+  TestcaseTrial::TestcaseTrial() : _pimpl ( new Impl() )
+  { }
+
+  TestcaseTrial::~TestcaseTrial()
+  { }
+
+  const std::vector<TestcaseTrial::Node> &TestcaseTrial::nodes() const
+  { return _pimpl->nodes; }
+
+  std::vector<TestcaseTrial::Node> &TestcaseTrial::nodes()
+  { return _pimpl->nodes; }
+
+  TestcaseTrial::Node::Node() : _pimpl ( new Impl() )
+  { }
+
+  TestcaseTrial::Node::~Node()
+  { }
+
+  const std::string &TestcaseTrial::Node::name() const
+  { return _pimpl->name; }
+
+  std::string &TestcaseTrial::Node::name()
+  { return _pimpl->name; }
+
+  const std::string &TestcaseTrial::Node::value() const
+  { return _pimpl->value; }
+
+  std::string &TestcaseTrial::Node::value()
+  { return _pimpl->value; }
+
+  const std::string &TestcaseTrial::Node::getProp( const std::string &name, const std::string &def ) const
+  {
+    if ( _pimpl->properties.find( name) == _pimpl->properties.end() )
+      return def;
+    return _pimpl->properties.at( name );
+  }
+
+  const std::map<std::string, std::string> &TestcaseTrial::Node::properties() const
+  { return _pimpl->properties; }
+
+  std::map<std::string, std::string> &TestcaseTrial::Node::properties()
+  { return _pimpl->properties; }
+
+  const std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children() const
+  { return _pimpl->children; }
+
+  std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children()
+  { return _pimpl->children; }
+
   bool LoadTestcase::Impl::loadHelix(const zypp::filesystem::Pathname &filename, std::string *err)
   {
     xmlDocPtr xml_doc = xmlParseFile ( filename.c_str() );
@@ -150,7 +208,7 @@ namespace zypp::misc::testcase {
 
     // reset everything
     _pimpl.reset( new Impl() );
-    _pimpl->_setup.globalPath = path;
+    _pimpl->_setup.data().globalPath = path;
 
     switch (t) {
       case LoadTestcase::Helix:
@@ -182,119 +240,4 @@ namespace zypp::misc::testcase {
     return _pimpl->_trials;
   }
 
-  const std::string &TestcaseTrial::Node::getProp( const std::string &name, const std::string &def ) const
-  {
-    if ( properties.find( name) == properties.end() )
-      return def;
-    return properties.at( name );
-  }
-
-  bool TestcaseSetup::applySetup( RepoManager &manager) const
-  {
-    const auto &setup = *this;
-    if ( !setup.architecture.empty() )
-    {
-      MIL << "Setting architecture to '" << setup.architecture << "'" << std::endl;
-      ZConfig::instance().setSystemArchitecture( setup.architecture );
-      setenv ("ZYPP_TESTSUITE_FAKE_ARCH", setup.architecture.c_str(), 1);
-    }
-
-    if ( setup.systemRepo ) {
-      if (!loadRepo( manager, setup, *setup.systemRepo ) )
-      {
-        ERR << "Can't setup 'system'" << std::endl;
-        return false;
-      }
-    }
-
-    if ( !setup.hardwareInfoFile.empty() ) {
-      setenv( "ZYPP_MODALIAS_SYSFS", setup.hardwareInfoFile.asString().c_str(), 1 );
-      MIL << "setting HardwareInfo to: " << setup.hardwareInfoFile.asString() << std::endl;
-    }
-
-    for ( const auto &channel : setup.repos ) {
-      if ( !loadRepo( manager, setup, channel )  )
-      {
-        ERR << "Can't setup 'channel'" << std::endl;
-        return false;
-      }
-    }
-
-    if ( !setup.systemCheck.empty() ) {
-      MIL << "setting systemCheck to: " << setup.systemCheck.asString() << std::endl;
-      SystemCheck::instance().setFile( setup.systemCheck );
-    }
-
-    return true;
-  }
-
-  bool TestcaseSetup::loadRepo( zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data )
-  {
-    Pathname pathname = setup.globalPath + data.path;
-    MIL << "'" << pathname << "'" << std::endl;
-
-    Repository repo;
-
-    using TrType = zypp::misc::testcase::TestcaseRepoType;
-
-    if ( data.type == TrType::Url ) {
-      try {
-        MIL << "Load from Url '" << data.path << "'" << std::endl;
-
-        RepoInfo nrepo;
-        nrepo.setAlias      ( data.alias );
-        nrepo.setName       ( data.alias );
-        nrepo.setEnabled    ( true );
-        nrepo.setAutorefresh( false );
-        nrepo.setPriority   ( data.priority );
-        nrepo.addBaseUrl   ( Url(data.path) );
-
-        manager.refreshMetadata( nrepo );
-        manager.buildCache( nrepo );
-        manager.loadFromCache( nrepo );
-      }
-      catch ( Exception & excpt_r ) {
-        ZYPP_CAUGHT (excpt_r);
-        ERR << "Couldn't load packages from Url '" << data.path << "'" << std::endl;
-        return false;
-      }
-    }
-    else {
-      try {
-        MIL << "Load from File '" << pathname << "'" << std::endl;
-        zypp::Repository satRepo;
-
-        if ( data.alias == "@System" ) {
-          satRepo = zypp::sat::Pool::instance().systemRepo();
-        } else {
-          satRepo = zypp::sat::Pool::instance().reposInsert( data.alias );
-        }
-
-        RepoInfo nrepo;
-
-        nrepo.setAlias      ( data.alias );
-        nrepo.setName       ( data.alias );
-        nrepo.setEnabled    ( true );
-        nrepo.setAutorefresh( false );
-        nrepo.setPriority   ( data.priority );
-        nrepo.addBaseUrl   ( pathname.asUrl() );
-
-        satRepo.setInfo (nrepo);
-        if ( data.type == TrType::Helix )
-          satRepo.addHelix( pathname );
-        else
-          satRepo.addTesttags( pathname );
-        MIL << "Loaded " << satRepo.solvablesSize() << " resolvables from " << ( data.path.empty()?pathname.asString():data.path) << "." << std::endl;
-      }
-      catch ( Exception & excpt_r ) {
-        ZYPP_CAUGHT (excpt_r);
-        ERR << "Couldn't load packages from XML file '" << data.path << "'" << std::endl;
-        return false;
-      }
-    }
-    return true;
-  }
-
-
-
 }
index 20d181b..f1ed5e5 100644 (file)
 #ifndef ZYPP_MISC_LOADTESTCASE_H
 #define ZYPP_MISC_LOADTESTCASE_H
 
-#include <zypp/Arch.h>
-#include <zypp/Locale.h>
 #include <zypp/Pathname.h>
-#include <zypp/ResolverFocus.h>
 #include <zypp/Url.h>
 #include <zypp/base/PtrTypes.h>
-#include <zypp/base/SetTracker.h>
 #include <zypp/base/NonCopyable.h>
-#include <zypp/sat/Queue.h>
-#include <zypp/target/modalias/Modalias.h>
+#include <zypp/misc/TestcaseSetup.h>
 
 #include <optional>
 #include <memory>
 
-namespace zypp {
-  class RepoManager;
-}
-
 namespace zypp::misc::testcase {
 
-  enum class TestcaseRepoType {
-    Helix,
-    Testtags,
-    Url
-  };
-
-  struct RepoData {
-    TestcaseRepoType type;
-    std::string alias;
-    uint priority = 99;
-    std::string path;
-  };
-
-  struct ForceInstall {
-    std::string channel;
-    std::string package;
-    std::string kind;
-  };
-
-  struct TestcaseSetup
-  {
-    Arch architecture = Arch_noarch;
-
-    std::optional<RepoData> systemRepo;
-    std::vector<RepoData> repos;
-
-    // solver flags: default to false - set true if mentioned in <setup>
-    ResolverFocus resolverFocus  = ResolverFocus::Default;
-
-    Pathname globalPath;
-    Pathname hardwareInfoFile;
-    Pathname systemCheck;
-
-    target::Modalias::ModaliasList modaliasList;
-    base::SetTracker<LocaleSet> localesTracker;
-    sat::StringQueue autoinstalled;
-    std::set<std::string> multiversionSpec;
-    std::vector<ForceInstall> forceInstallTasks;
-
-    bool set_licence = false;
-    bool show_mediaid = false;
-
-    bool ignorealreadyrecommended   = false;
-    bool onlyRequires               = false;
-    bool forceResolve               = false;
-    bool cleandepsOnRemove          = false;
-
-    bool allowDowngrade     = false;
-    bool allowNameChange    = false;
-    bool allowArchChange    = false;
-    bool allowVendorChange  = false;
-
-    bool dupAllowDowngrade     = false;
-    bool dupAllowNameChange    = false;
-    bool dupAllowArchChange    = false;
-    bool dupAllowVendorChange  = false;
-
-    bool applySetup ( zypp::RepoManager &manager ) const;
-
-    static bool loadRepo (zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data );
-  };
-
   struct TestcaseTrial
   {
     struct Node {
-      std::string name;
-      std::string value;
+      struct Impl;
+
+      Node();
+      ~Node();
+      const std::string &name  () const;
+      std::string &name  ();
+      const std::string &value () const;
+      std::string &value ();
 
       const std::string &getProp( const std::string &name, const std::string &def = std::string() ) const;
+      const std::map<std::string, std::string> &properties() const;
+      std::map<std::string, std::string> &properties();
+      const std::vector<std::shared_ptr<Node>> &children() const;
+      std::vector<std::shared_ptr<Node>> &children();
+
+    private:
+      RWCOW_pointer<Impl> _pimpl;
 
-      std::map<std::string, std::string> properties;
-      std::vector<std::shared_ptr<Node>> children;
     };
-    std::vector<Node> nodes;
+
+    TestcaseTrial();
+    ~TestcaseTrial();
+    const std::vector<Node> &nodes () const;
+    std::vector<Node> &nodes ();
+  private:
+    struct Impl;
+    RWCOW_pointer<Impl> _pimpl;
   };
 
   class LoadTestcase : private zypp::base::NonCopyable
diff --git a/zypp/misc/TestcaseSetup.cc b/zypp/misc/TestcaseSetup.cc
new file mode 100644 (file)
index 0000000..0766b9f
--- /dev/null
@@ -0,0 +1,260 @@
+#include "TestcaseSetupImpl.h"
+
+namespace zypp::misc::testcase
+{
+  RepoData::RepoData() : _pimpl( new RepoDataImpl )
+  {}
+
+  RepoData::~RepoData()
+  { }
+
+  RepoData::RepoData(RepoDataImpl &&data) : _pimpl( new RepoDataImpl( std::move(data)) )
+  { }
+
+  TestcaseRepoType RepoData::type() const
+  { return _pimpl->type; }
+
+  const std::string &RepoData::alias() const
+  { return _pimpl->alias; }
+
+  uint RepoData::priority() const
+  { return _pimpl->priority; }
+
+  const std::string &RepoData::path() const
+  { return _pimpl->path; }
+
+  const RepoDataImpl &RepoData::data() const
+  { return *_pimpl; }
+
+  RepoDataImpl &RepoData::data()
+  { return *_pimpl; }
+
+  ForceInstall::ForceInstall() : _pimpl( new ForceInstallImpl )
+  { }
+
+  ForceInstall::~ForceInstall()
+  { }
+
+  ForceInstall::ForceInstall(ForceInstallImpl &&data) : _pimpl( new ForceInstallImpl( std::move(data) ))
+  { }
+
+  const ForceInstallImpl &ForceInstall::data() const
+  { return *_pimpl; }
+
+  ForceInstallImpl &ForceInstall::data()
+  { return *_pimpl; }
+
+  const std::string &ForceInstall::channel() const
+  { return _pimpl->channel; }
+
+  const std::string &ForceInstall::package() const
+  { return _pimpl->package; }
+
+  const std::string &ForceInstall::kind() const
+  { return _pimpl->kind; }
+
+  TestcaseSetup::TestcaseSetup() : _pimpl( new TestcaseSetupImpl )
+  { }
+
+  TestcaseSetup::~TestcaseSetup()
+  { }
+
+  Arch TestcaseSetup::architecture() const
+  { return _pimpl->architecture; }
+
+  const std::optional<RepoData> &TestcaseSetup::systemRepo() const
+  { return _pimpl->systemRepo; }
+
+  const std::vector<RepoData> &TestcaseSetup::repos() const
+  { return _pimpl->repos; }
+
+  ResolverFocus TestcaseSetup::resolverFocus() const
+  { return _pimpl->resolverFocus; }
+
+  const zypp::filesystem::Pathname &TestcaseSetup::globalPath() const
+  { return _pimpl->globalPath; }
+
+  const zypp::filesystem::Pathname &TestcaseSetup::hardwareInfoFile() const
+  { return _pimpl->hardwareInfoFile; }
+
+  const zypp::filesystem::Pathname &TestcaseSetup::systemCheck() const
+  { return _pimpl->systemCheck; }
+
+  const target::Modalias::ModaliasList &TestcaseSetup::modaliasList() const
+  { return _pimpl->modaliasList; }
+
+  const base::SetTracker<LocaleSet> &TestcaseSetup::localesTracker() const
+  { return _pimpl->localesTracker; }
+
+  const std::vector<std::vector<std::string> > &TestcaseSetup::vendorLists() const
+  { return _pimpl->vendorLists; }
+
+  const sat::StringQueue &TestcaseSetup::autoinstalled() const
+  { return _pimpl->autoinstalled; }
+
+  const std::set<std::string> &TestcaseSetup::multiversionSpec() const
+  { return _pimpl->multiversionSpec; }
+
+  const std::vector<ForceInstall> &TestcaseSetup::forceInstallTasks() const
+  { return _pimpl->forceInstallTasks; }
+
+  bool TestcaseSetup::set_licence() const
+  { return _pimpl->set_licence; }
+
+  bool TestcaseSetup::show_mediaid() const
+  { return _pimpl->show_mediaid; }
+
+  bool TestcaseSetup::ignorealreadyrecommended() const
+  { return _pimpl->ignorealreadyrecommended; }
+
+  bool TestcaseSetup::onlyRequires() const
+  { return _pimpl->onlyRequires; }
+
+  bool TestcaseSetup::forceResolve() const
+  { return _pimpl->forceResolve; }
+
+  bool TestcaseSetup::cleandepsOnRemove() const
+  { return _pimpl->cleandepsOnRemove; }
+
+  bool TestcaseSetup::allowDowngrade() const
+  { return _pimpl->allowDowngrade; }
+
+  bool TestcaseSetup::allowNameChange() const
+  { return _pimpl->allowNameChange; }
+
+  bool TestcaseSetup::allowArchChange() const
+  { return _pimpl->allowArchChange; }
+
+  bool TestcaseSetup::allowVendorChange() const
+  { return _pimpl->allowVendorChange; }
+
+  bool TestcaseSetup::dupAllowDowngrade() const
+  { return _pimpl->dupAllowDowngrade; }
+
+  bool TestcaseSetup::dupAllowNameChange() const
+  { return _pimpl->dupAllowNameChange; }
+
+  bool TestcaseSetup::dupAllowArchChange() const
+  { return _pimpl->dupAllowArchChange; }
+
+  bool TestcaseSetup::dupAllowVendorChange() const
+  { return _pimpl->dupAllowVendorChange; }
+
+  bool TestcaseSetup::applySetup( zypp::RepoManager &manager ) const
+  {
+    const auto &setup = data();
+    if ( !setup.architecture.empty() )
+    {
+      MIL << "Setting architecture to '" << setup.architecture << "'" << std::endl;
+      ZConfig::instance().setSystemArchitecture( setup.architecture );
+      setenv ("ZYPP_TESTSUITE_FAKE_ARCH", setup.architecture.c_str(), 1);
+    }
+
+    if ( setup.systemRepo ) {
+      if (!loadRepo( manager, *this, *setup.systemRepo ) )
+      {
+        ERR << "Can't setup 'system'" << std::endl;
+        return false;
+      }
+    }
+
+    if ( !setup.hardwareInfoFile.empty() ) {
+      setenv( "ZYPP_MODALIAS_SYSFS", setup.hardwareInfoFile.asString().c_str(), 1 );
+      MIL << "setting HardwareInfo to: " << setup.hardwareInfoFile.asString() << std::endl;
+    }
+
+    for ( const auto &channel : setup.repos ) {
+      if ( !loadRepo( manager, *this, channel )  )
+      {
+        ERR << "Can't setup 'channel'" << std::endl;
+        return false;
+      }
+    }
+
+    if ( !setup.systemCheck.empty() ) {
+      MIL << "setting systemCheck to: " << setup.systemCheck.asString() << std::endl;
+      SystemCheck::instance().setFile( setup.systemCheck );
+    }
+
+    return true;
+  }
+
+  bool TestcaseSetup::loadRepo( zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data )
+  {
+    const auto &repoData = data.data();
+    Pathname pathname = setup._pimpl->globalPath + repoData.path;
+    MIL << "'" << pathname << "'" << std::endl;
+
+    Repository repo;
+
+    using TrType = zypp::misc::testcase::TestcaseRepoType;
+
+    if ( repoData.type == TrType::Url ) {
+      try {
+        MIL << "Load from Url '" << repoData.path << "'" << std::endl;
+
+        RepoInfo nrepo;
+        nrepo.setAlias      ( repoData.alias );
+        nrepo.setName       ( repoData.alias );
+        nrepo.setEnabled    ( true );
+        nrepo.setAutorefresh( false );
+        nrepo.setPriority   ( repoData.priority );
+        nrepo.addBaseUrl   ( Url(repoData.path) );
+
+        manager.refreshMetadata( nrepo );
+        manager.buildCache( nrepo );
+        manager.loadFromCache( nrepo );
+      }
+      catch ( Exception & excpt_r ) {
+        ZYPP_CAUGHT (excpt_r);
+        ERR << "Couldn't load packages from Url '" << repoData.path << "'" << std::endl;
+        return false;
+      }
+    }
+    else {
+      try {
+        MIL << "Load from File '" << pathname << "'" << std::endl;
+        zypp::Repository satRepo;
+
+        if ( repoData.alias == "@System" ) {
+          satRepo = zypp::sat::Pool::instance().systemRepo();
+        } else {
+          satRepo = zypp::sat::Pool::instance().reposInsert( repoData.alias );
+        }
+
+        RepoInfo nrepo;
+
+        nrepo.setAlias      ( repoData.alias );
+        nrepo.setName       ( repoData.alias );
+        nrepo.setEnabled    ( true );
+        nrepo.setAutorefresh( false );
+        nrepo.setPriority   ( repoData.priority );
+        nrepo.addBaseUrl   ( pathname.asUrl() );
+
+        satRepo.setInfo (nrepo);
+        if ( repoData.type == TrType::Helix )
+          satRepo.addHelix( pathname );
+        else
+          satRepo.addTesttags( pathname );
+        MIL << "Loaded " << satRepo.solvablesSize() << " resolvables from " << ( repoData.path.empty()?pathname.asString():repoData.path) << "." << std::endl;
+      }
+      catch ( Exception & excpt_r ) {
+        ZYPP_CAUGHT (excpt_r);
+        ERR << "Couldn't load packages from XML file '" << repoData.path << "'" << std::endl;
+        return false;
+      }
+    }
+    return true;
+  }
+
+  TestcaseSetupImpl &TestcaseSetup::data()
+  {
+    return *_pimpl;
+  }
+
+  const TestcaseSetupImpl &TestcaseSetup::data() const
+  {
+    return *_pimpl;
+  }
+
+}
diff --git a/zypp/misc/TestcaseSetup.h b/zypp/misc/TestcaseSetup.h
new file mode 100644 (file)
index 0000000..edf2552
--- /dev/null
@@ -0,0 +1,135 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/misc/TestcaseSetup.h
+ *
+*/
+
+#ifndef ZYPP_MISC_TESTCASESETUP_H
+#define ZYPP_MISC_TESTCASESETUP_H
+
+#include <zypp/Arch.h>
+#include <zypp/Locale.h>
+#include <zypp/Pathname.h>
+#include <zypp/ResolverFocus.h>
+#include <zypp/Url.h>
+#include <zypp/base/PtrTypes.h>
+#include <zypp/base/SetTracker.h>
+#include <zypp/sat/Queue.h>
+#include <zypp/target/modalias/Modalias.h>
+
+#include <optional>
+#include <vector>
+
+namespace zypp {
+  class RepoManager;
+}
+
+namespace zypp::misc::testcase
+{
+
+  enum class TestcaseRepoType {
+    Helix,
+    Testtags,
+    Url
+  };
+
+  struct RepoDataImpl;
+  struct ForceInstallImpl;
+  struct TestcaseSetupImpl;
+
+  class RepoData {
+  public:
+    RepoData ();
+    ~RepoData ();
+    RepoData ( RepoDataImpl &&data );
+    TestcaseRepoType type() const;
+    const std::string &alias() const;
+    uint priority() const;
+    const std::string &path() const;
+
+    const RepoDataImpl &data() const;
+    RepoDataImpl &data();
+  private:
+    RWCOW_pointer<RepoDataImpl> _pimpl;
+  };
+
+  class ForceInstall {
+  public:
+    ForceInstall ();
+    ~ForceInstall ();
+    ForceInstall ( ForceInstallImpl &&data );
+    const std::string &channel () const;
+    const std::string &package () const;
+    const std::string &kind () const;
+
+    const ForceInstallImpl &data() const;
+    ForceInstallImpl &data();
+  private:
+    RWCOW_pointer<ForceInstallImpl> _pimpl;
+  };
+
+  class TestcaseSetup
+  {
+  public:
+
+    TestcaseSetup();
+    ~TestcaseSetup();
+
+    Arch architecture () const;
+
+    const std::optional<RepoData> &systemRepo() const;
+    const std::vector<RepoData> &repos() const;
+
+    // solver flags: default to false - set true if mentioned in <setup>
+    ResolverFocus resolverFocus() const;
+
+    const Pathname &globalPath() const;
+    const Pathname &hardwareInfoFile() const;
+    const Pathname &systemCheck() const;
+
+    const target::Modalias::ModaliasList &modaliasList() const;
+    const base::SetTracker<LocaleSet> &localesTracker() const;
+    const std::vector<std::vector<std::string>> &vendorLists() const;
+    const sat::StringQueue &autoinstalled() const;
+    const std::set<std::string> &multiversionSpec() const;
+    const std::vector<ForceInstall> &forceInstallTasks() const;
+
+    bool set_licence() const;
+    bool show_mediaid() const;
+
+    bool ignorealreadyrecommended() const;
+    bool onlyRequires() const;
+    bool forceResolve() const;
+    bool cleandepsOnRemove() const;
+
+    bool allowDowngrade() const;
+    bool allowNameChange() const;
+    bool allowArchChange() const;
+    bool allowVendorChange() const;
+
+    bool dupAllowDowngrade() const;
+    bool dupAllowNameChange() const;
+    bool dupAllowArchChange() const;
+    bool dupAllowVendorChange() const;
+
+    bool applySetup ( zypp::RepoManager &manager ) const;
+
+    static bool loadRepo (zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data );
+
+    TestcaseSetupImpl &data();
+    const TestcaseSetupImpl &data() const;
+
+  private:
+    RWCOW_pointer<TestcaseSetupImpl> _pimpl;
+  };
+
+}
+
+
+#endif // ZYPP_MISC_TESTCASESETUPIMPL_H
diff --git a/zypp/misc/TestcaseSetupImpl.h b/zypp/misc/TestcaseSetupImpl.h
new file mode 100644 (file)
index 0000000..6598a46
--- /dev/null
@@ -0,0 +1,85 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#ifndef ZYPP_MISC_TESTCASESETUPIMPL_H
+#define ZYPP_MISC_TESTCASESETUPIMPL_H
+
+#include <zypp/misc/TestcaseSetup.h>
+#include <zypp/ZConfig.h>
+#include <zypp/base/LogControl.h>
+#include <zypp/Repository.h>
+#include <zypp/RepoManager.h>
+#include <zypp/sat/Pool.h>
+
+#define ZYPP_USE_RESOLVER_INTERNALS
+#include <zypp/solver/detail/SystemCheck.h>
+
+namespace zypp::misc::testcase
+{
+  struct RepoDataImpl {
+    TestcaseRepoType type;
+    std::string alias;
+    uint priority = 99;
+    std::string path;
+
+    RepoDataImpl *clone () const { return new RepoDataImpl(*this); }
+  };
+
+  struct ForceInstallImpl {
+    std::string channel;
+    std::string package;
+    std::string kind;
+
+    ForceInstallImpl *clone () const { return new ForceInstallImpl(*this); }
+  };
+
+  struct TestcaseSetupImpl
+  {
+    Arch architecture = Arch_noarch;
+
+    std::optional<RepoData> systemRepo;
+    std::vector<RepoData> repos;
+
+    // solver flags: default to false - set true if mentioned in <setup>
+    ResolverFocus resolverFocus  = ResolverFocus::Default;
+
+    Pathname globalPath;
+    Pathname hardwareInfoFile;
+    Pathname systemCheck;
+
+    target::Modalias::ModaliasList modaliasList;
+    base::SetTracker<LocaleSet> localesTracker;
+    std::vector<std::vector<std::string>> vendorLists;
+    sat::StringQueue autoinstalled;
+    std::set<std::string> multiversionSpec;
+    std::vector<ForceInstall> forceInstallTasks;
+
+    bool set_licence = false;
+    bool show_mediaid = false;
+
+    bool ignorealreadyrecommended   = false;
+    bool onlyRequires               = false;
+    bool forceResolve               = false;
+    bool cleandepsOnRemove          = false;
+
+    bool allowDowngrade     = false;
+    bool allowNameChange    = false;
+    bool allowArchChange    = false;
+    bool allowVendorChange  = false;
+
+    bool dupAllowDowngrade     = false;
+    bool dupAllowNameChange    = false;
+    bool dupAllowArchChange    = false;
+    bool dupAllowVendorChange  = false;
+
+    TestcaseSetupImpl *clone () const { return new TestcaseSetupImpl(*this); }
+  };
+}
+
+#endif
index 71a483c..349d489 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <zypp/base/LogControl.h>
 #include "LoadTestcase.h"
+#include "TestcaseSetupImpl.h"
 
 #include <yaml-cpp/yaml.h>
 
@@ -21,8 +22,9 @@
 
 namespace yamltest::detail {
 
-  bool parseSetup ( const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &target, std::string *err ) {
+  bool parseSetup ( const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err ) {
 
+    auto &target = t.data();
     MIL << "Parsing setup node " << std::endl;
     for ( YAML::const_iterator it = setup.begin(); it != setup.end(); it++ ) {
 
@@ -89,7 +91,7 @@ namespace yamltest::detail {
           target.resolverFocus = zypp::resolverFocusFromString( data["focus"].as<std::string>() );
         }
       } else if ( key == ("system") ) {
-        target.systemRepo = zypp::misc::testcase::RepoData {
+        target.systemRepo = zypp::misc::testcase::RepoDataImpl {
           zypp::misc::testcase::TestcaseRepoType::Testtags,
           "@System",
           99,
@@ -123,7 +125,7 @@ namespace yamltest::detail {
           if ( dataNode["priority"] )
             prio = dataNode["priority"].as<unsigned>();
 
-          target.repos.push_back( zypp::misc::testcase::RepoData{
+          target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
             zypp::misc::testcase::TestcaseRepoType::Testtags,
             name,
             prio,
@@ -138,7 +140,7 @@ namespace yamltest::detail {
         bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
           std::string url   = dataNode["url"].as<std::string>();
           std::string alias = dataNode["name"].as<std::string>();
-          target.repos.push_back( zypp::misc::testcase::RepoData{
+          target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
             zypp::misc::testcase::TestcaseRepoType::Url,
             alias,
             99,
@@ -151,7 +153,7 @@ namespace yamltest::detail {
       else if ( key == ("force-install") )
       {
         bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
-          target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstall{
+          target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstallImpl{
             dataNode["channel"].as<std::string>(),
             dataNode["package"].as<std::string>(),
             dataNode["kind"].as<std::string>()
@@ -197,6 +199,18 @@ namespace yamltest::detail {
         }, err );
         if ( !success ) return false;
       }
+      else if ( key == ("vendors") )
+      {
+        bool success = readListInlineOrFromFile( [&target]( const YAML::Node & dataNode, std::string * err ) {
+         std::vector<std::string> vlist;
+         for ( const auto & node : dataNode )
+           vlist.push_back( node.as<std::string>() );
+         if ( ! vlist.empty() )
+           target.vendorLists.push_back( std::move(vlist) );
+          return true;
+        }, err );
+        if ( !success ) return false;
+      }
       else if ( key == ("autoinst") ) {
         bool success = readListInlineOrFromFile( [&]( const YAML::Node &dataNode, auto ){
           target.autoinstalled.push( zypp::IdString( dataNode.as<std::string>() ).id() );
@@ -261,23 +275,23 @@ namespace yamltest::detail {
       const std::string &key = elem.first.as<std::string>();
       const auto &data = elem.second;
       if ( key == "job" ) {
-        n.name = data.as<std::string>();
+        n.name() = data.as<std::string>();
       } else if ( key == "__content") {
-        n.value = data.as<std::string>();
+        n.value() = data.as<std::string>();
       } else {
         if( data.IsScalar() ) {
-          n.properties.insert( { key, data.as<std::string>() } );
+          n.properties().insert( { key, data.as<std::string>() } );
         } if ( data.IsSequence() ) {
           // if the type of a data field is a sequence, we treat all the elements in there
           // as sub elements. Just like in XML you can have sub nodes its the same here
           // the key name is ignored in those cases and can be chosen freely
-          if ( !parseJobs( data, n.children, err ) )
+          if ( !parseJobs( data, n.children(), err ) )
             return false;
         } else if ( data.IsMap() ) {
           // if the type of a data field is a map, we build a child node from it.
           // Just like with sequence but a single field.
           // The key name is ignored in those cases and can be chosen freely
-          if ( !parseSingleJob( data, n.children, err) )
+          if ( !parseSingleJob( data, n.children(), err) )
             return false;
         } else {
           ERR << "Ignoring field " << key << " with unsupported type." << std::endl;
@@ -303,7 +317,7 @@ namespace yamltest::detail {
 
   bool parseTrial ( const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, std::string *err ) {
     MIL << "Parsing trials." << std::endl;
-    return parseJobs( trial, target.nodes, err );
+    return parseJobs( trial, target.nodes(), err );
   }
 }
 
index 0f7040d..a878c64 100644 (file)
@@ -137,7 +137,7 @@ namespace zypp
           else if ( it->first == "path" )
             info.setPath( Pathname(it->second) );
           else if ( it->first == "type" )
-            info.setType(repo::RepoType(it->second));
+            ; // bsc#1177427 et.al.: type in a .repo file is legacy - ignore it and let RepoManager probe
           else if ( it->first == "autorefresh" )
             info.setAutorefresh( str::strToTrue( it->second ) );
           else if ( it->first == "mirrorlist" && !it->second.empty())
index 6009859..2eacab8 100644 (file)
@@ -554,7 +554,13 @@ namespace zypp
     Url RepoVariablesUrlReplacer::operator()( const Url & value ) const
     {
       Url::ViewOptions toReplace = value.getViewOptions() - url::ViewOption::WITH_USERNAME - url::ViewOption::WITH_PASSWORD;
-      const std::string & replaced( RepoVarExpand()( value.asString( toReplace ), RepoVarsMap::lookup ) );
+      // Legacy: Not 100% correct because it substitutes inside the 'proxypass=' value,
+      // but this was done before as well. The final fix will have to keep the proxypasswd
+      // out side the url in a cedential file.
+      Url tmpurl { value };
+      tmpurl.setViewOptions( toReplace );
+      const std::string & replaced( RepoVarExpand()( hotfix1050625::asString( tmpurl ), RepoVarsMap::lookup ) );
+
       Url newurl;
       if ( !replaced.empty() )
       {
diff --git a/zypp/sat/AttrMatcher.h b/zypp/sat/AttrMatcher.h
deleted file mode 100644 (file)
index c804bbf..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*---------------------------------------------------------------------\
-|                          ____ _   __ __ ___                          |
-|                         |__  / \ / / . \ . \                         |
-|                           / / \ V /|  _/  _/                         |
-|                          / /__ | | | | | |                           |
-|                         /_____||_| |_| |_|                           |
-|                                                                      |
-\---------------------------------------------------------------------*/
-/** \file      zypp/sat/AttrMatcher.h
- *
-*/
-#ifndef ZYPP_SAT_ATTRMATCHER_H
-#define ZYPP_SAT_ATTRMATCHER_H
-#warning sat::AttrMatcher was renamed to StrMatcher. Deprecated include of zypp/sat/AttrMatcher.h use zypp/base/StrMatcher.h
-
-#include <zypp/base/StrMatcher.h>
-
-///////////////////////////////////////////////////////////////////
-namespace zypp
-{
-  ///////////////////////////////////////////////////////////////////
-  namespace sat
-  {
-    typedef StrMatcher AttrMatcher;
-
-  } // namespace sat
-  ///////////////////////////////////////////////////////////////////
-} // namespace zypp
-///////////////////////////////////////////////////////////////////
-#endif // ZYPP_SAT_ATTRMATCHER_H
index e63953c..2460eb8 100644 (file)
@@ -30,7 +30,7 @@ namespace sat
   const SolvAttr SolvAttr::allAttr( detail::noId );
   const SolvAttr SolvAttr::noAttr;
 
-#warning STILL ATTRIBUTES HERE WHICH ARE NOT PROVIDED BY SOLV FILES
+// There are some attributes here which are not provided by solv files.
 // At least the ones that do nat have a solv/knownid.
 
   const SolvAttr SolvAttr::name         ( SOLVABLE_NAME );
index 504d8d8..7cc00c0 100644 (file)
@@ -13,7 +13,7 @@
 #include <fstream>
 #include <sstream>
 #include <streambuf>
-#include <boost/function_output_iterator.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
 
 #define ZYPP_USE_RESOLVER_INTERNALS
 
@@ -31,6 +31,7 @@
 #include <zypp/PathInfo.h>
 #include <zypp/ResPool.h>
 #include <zypp/Repository.h>
+#include <zypp/VendorAttr.h>
 #include <zypp/target/modalias/Modalias.h>
 
 #include <zypp/sat/detail/PoolImpl.h>
@@ -70,6 +71,7 @@ namespace zypp
 
       bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
       {
+       MIL << "createTestcase at " << dumpPath << (dumpPool?" dumpPool":"") << (runSolver?" runSolver":"") << endl;
         PathInfo path (dumpPath);
 
         if ( !path.isExist() ) {
@@ -203,6 +205,19 @@ namespace zypp
         }
         yOut << YAML::EndSeq; // locales
 
+        // Vendor settings
+        yOut << YAML::Key << "vendors" << YAML::Value << YAML::BeginSeq ;
+       VendorAttr::instance().foreachVendorList( [&]( VendorAttr::VendorList vlist )->bool {
+         if ( ! vlist.empty() ) {
+           yOut << YAML::Value << YAML::BeginSeq;
+           for( const auto & v : vlist )
+             yOut << YAML::Value << v ;
+           yOut << YAML::EndSeq;
+         }
+         return true;
+       } );
+       yOut << YAML::EndSeq; // vendors
+
         // helper lambda to write a list of elements into a external file instead of the main file
         const auto &writeListOrFile = [&]( const std::string &name, const auto &list, const auto &callback ) {
           if ( list.size() > 10 ) {
@@ -364,6 +379,7 @@ namespace zypp
         std::ofstream fout( dumpPath+"/zypp-control.yaml" );
         fout << yOut.c_str();
 
+       MIL << "createTestcase done at " << dumpPath << endl;
         return true;
       }
       ///////////////////////////////////////////////////////////////////
index 3722259..5bd5d1a 100644 (file)
@@ -1528,7 +1528,6 @@ namespace zypp
               continue;
             }
 
-#warning Exception handling
             // create a installation progress report proxy
             RpmInstallPackageReceiver progress( citem.resolvable() );
             progress.connect(); // disconnected on destruction.
index 807b579..c7bb912 100644 (file)
@@ -271,44 +271,39 @@ void RpmDb::initDatabase( Pathname root_r, bool doRebuild_r )
   if ( root_r.empty() )
     root_r = "/";
 
-  // NOTE: Former argument, but now locked to "/var/lib/rpm".
-  // A custom dbPath is not actually needed and would only work
-  // reliably if libsolv also supports it. By now no further
-  // cleanup in the code.
-  const Pathname & dbPath_r { librpmDb::defaultDbPath() };
+  const Pathname & dbPath_r { librpmDb::suggestedDbPath( root_r ) };   // also asserts root_r is absolute
 
-  if ( ! root_r.absolute() )
+  // The rpmdb compat symlink.
+  // Required at least until rpmdb2solv takes a dppath argument.
+  // Otherwise it creates a db at "/var/lib/rpm".
+  if ( dbPath_r != "/var/lib/rpm" && ! PathInfo( root_r/"/var/lib/rpm" ).isExist() )
   {
-    ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
-    ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
+    WAR << "Inject missing /var/lib/rpm compat symlink to " << dbPath_r << endl;
+    filesystem::assert_dir( root_r/"/var/lib" );
+    filesystem::symlink( "../../"/dbPath_r, root_r/"/var/lib/rpm" );
   }
 
-  if ( ! PathInfo( root_r/"/var/lib/rpm" ).isExist()
-    && PathInfo( root_r/"/usr/lib/sysimage/rpm" ).isDir() )
-  {
-    WAR << "Rpm package was deleted? Injecting missing rpmdb compat symlink." << endl;
-    filesystem::symlink( "../../usr/lib/sysimage/rpm", root_r/"/var/lib/rpm" );
-  }
-
-  MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
-      << ( doRebuild_r ? " (rebuilddb)" : "" )
-      << ( quickinit ? " (quickinit)" : "" ) << endl;
-
   ///////////////////////////////////////////////////////////////////
   // Check whether already initialized
   ///////////////////////////////////////////////////////////////////
   if ( initialized() )
   {
-    if ( root_r == _root && dbPath_r == _dbPath )
-    {
+    // Just check for a changing root because the librpmDb::suggestedDbPath
+    // may indeed change: rpm %post moving the db from /var/lib/rpm
+    // to /usr/lib/sysimage/rpm. We continue to use the old dbpath
+    // (via the compat symlink) until a re-init.
+    if ( root_r == _root ) {
+      MIL << "Calling initDatabase: already initialized at " << stringPath( _root, _dbPath ) << endl;
       return;
     }
     else
-    {
       ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
-    }
   }
 
+  MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
+      << ( doRebuild_r ? " (rebuilddb)" : "" )
+      << ( quickinit ? " (quickinit)" : "" ) << endl;
+
   ///////////////////////////////////////////////////////////////////
   // init database
   ///////////////////////////////////////////////////////////////////
index 74fc15a..38cdff5 100644 (file)
@@ -108,7 +108,7 @@ public:
   }
 
   /**
-   * Prepare access to the rpm database at \c/var/lib/rpm.
+   * Prepare access to the rpm database below \a root_r.
    *
    * An optional argument denotes the root directory for all operations. If
    * an empty Pathname is given the default (\c/) is used.
index b120aad..e5b5c73 100644 (file)
@@ -392,7 +392,7 @@ Date RpmHeader::tag_buildtime() const
 {
   return int_val( RPMTAG_BUILDTIME );
 }
-#warning CHECK IF FILE REQUIRES HANDLING IS OBSOLETE
+
 ///////////////////////////////////////////////////////////////////
 //
 //
index 35f0229..d40bb11 100644 (file)
@@ -96,15 +96,11 @@ public:
 //
 ///////////////////////////////////////////////////////////////////
 
-Pathname         librpmDb::_defaultRoot  ( "/" );
-// NOTE: Former variable, but now locked to "/var/lib/rpm".
-// A custom dbPath is not actually needed and would only work
-// reliably if libsolv also supports it.
-// The protected librpmDb ctor would allow to build a db_const_iterator
-// to access (ro) a database at a custom location.
-const Pathname   librpmDb::_defaultDbPath( "/var/lib/rpm" );
+Pathname librpmDb::_defaultRoot { "/" };
+Pathname librpmDb::_defaultDbPath;     // set in dbAccess depending on suggestedDbPath below /root
+Pathname librpmDb::_rpmDefaultDbPath;  // set by globalInit
 librpmDb::constPtr librpmDb::_defaultDb;
-bool             librpmDb::_dbBlocked    ( true );
+bool librpmDb::_dbBlocked = true;
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -127,13 +123,9 @@ bool librpmDb::globalInit()
   }
 
   initialized = true; // Necessary to be able to use exand().
+  _rpmDefaultDbPath = expand( "%{_dbpath}" );
 
-#define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
-  MIL << "librpm init done:"
-  OUTVAL(_target)
-  OUTVAL(_dbpath)
-  << endl;
-#undef OUTVAL
+  MIL << "librpm init done: (_target:" << expand( "%{_target}" ) << ") (_dbpath:" << _rpmDefaultDbPath << ")" << endl;
   return initialized;
 }
 
@@ -187,6 +179,30 @@ librpmDb * librpmDb::newLibrpmDb()
   return ret;
 }
 
+
+Pathname librpmDb::suggestedDbPath( const Pathname & root_r )
+{
+  if ( ! root_r.absolute() )
+    ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
+
+  // initialize librpm (for _rpmDefaultDbPath)
+  if ( ! globalInit() )
+    ZYPP_THROW(GlobalRpmInitException());
+
+  if ( PathInfo( root_r ).isDir() ) {
+    // If a known dbpath exsists, we continue to use it
+    for ( auto p : { "/var/lib/rpm", "/usr/lib/sysimage/rpm" } ) {
+      if ( PathInfo( root_r/p, PathInfo::LSTAT/*!no symlink*/ ).isDir() ) {
+       MIL << "Suggest existing database at " << stringPath( root_r, p ) << endl;
+       return p;
+      }
+    }
+  }
+
+  MIL << "Suggest rpm _dbpath " << stringPath( root_r, _rpmDefaultDbPath ) << endl;
+  return _rpmDefaultDbPath;
+}
+
 ///////////////////////////////////////////////////////////////////
 //
 //
@@ -205,20 +221,10 @@ void librpmDb::dbAccess( const Pathname & root_r )
   }
 
   // got no database: we could switch to a new one (even if blocked!)
-
-  if ( root_r.empty() || ! root_r.absolute() )
-    ZYPP_THROW(RpmInvalidRootException(root_r, _defaultDbPath));
-
-  PathInfo pi { root_r / _defaultDbPath };
-  if ( pi.isExist() && ! pi.isDir() ) {
-    RpmInvalidRootException excpt { root_r, _defaultDbPath };
-    excpt.addHistory( str::Str() << pi );
-    ZYPP_THROW(excpt);
-  }
-
+  _defaultDbPath = suggestedDbPath( root_r );  // also asserts root_r is absolute
   _defaultRoot = root_r;
-  MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
 
+  MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
   return dbAccess();
 }
 
@@ -584,7 +590,6 @@ public:
   {
     if ( ! create( RPMDBI_PACKAGES ) )
       return false;
-#warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
 #ifdef RPMFILEITERMAX  // since rpm.4.12
     ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
 #else
@@ -603,7 +608,6 @@ public:
     if ( !_mi )
       return 0;
     int ret = ::rpmdbGetIteratorCount( _mi );
-#warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
     return( ret ? ret : -1 ); // -1: sequential access
   }
 };
index 193d436..b08ce97 100644 (file)
@@ -63,15 +63,19 @@ private:
 
   /**
    * Current root directory for all operations.
-   * (initialy /)
+   * (initially /)
    **/
   static Pathname _defaultRoot;
 
   /**
    * Current directory (below root) that contains the rpmdb.
-   * (initialy /var/lib/rpm)
    **/
-  static const Pathname _defaultDbPath;
+  static Pathname _defaultDbPath;
+
+  /**
+   * %_dbpath configured in rpm config.
+   **/
+  static Pathname _rpmDefaultDbPath;
 
   /**
    * Current rpmdb handle.
@@ -148,6 +152,16 @@ public:
   }
 
   /**
+   * \return The preferred location of the rpmdb below \a root_r.
+   * It's the location of an already exising db, otherwise the
+   * default location sugested by rpms config.
+   *
+   * \throws RpmInvalidRootException if root is not an absolute path or
+   * no directory for the rpmdb can determined.
+   **/
+  static Pathname suggestedDbPath( const Pathname & root_r );
+
+  /**
    * Adjust access to the given database location, making it the new
    * default location on success. No relative Pathnames are allowed.
    *
index b8a790b..8536725 100644 (file)
@@ -44,9 +44,6 @@ namespace zypp
        static inline PoolProxyIterator pkgBegin()              { return poolProxyBegin<Package>();     }
        static inline PoolProxyIterator pkgEnd()                { return poolProxyEnd<Package>();       }
 
-//     static inline PoolProxyIterator langBegin()             { return poolProxyBegin<Language>();    }
-//     static inline PoolProxyIterator langEnd()               { return poolProxyEnd<Language>();      }
-
        static inline PoolProxyIterator patchesBegin()          { return poolProxyBegin<Patch>();       }
        static inline PoolProxyIterator patchesEnd()            { return poolProxyEnd<Patch>();         }
 
@@ -60,7 +57,6 @@ namespace zypp
        static void addDirectlySelectedPackages ( set<string> & pkgNames );
         template<class PkgSet_T> void addPkgSetPackages( set<string> & pkgNames );
 
-       static void addPatternPackages          ( set<string> & pkgNames );
        static void addPatchPackages            ( set<string> & pkgNames );
 
 
@@ -72,7 +68,6 @@ namespace zypp
            DBG << "Collecting packages the user explicitly asked for" << endl;
 
            addDirectlySelectedPackages ( pkgNames );
-           addPatternPackages          ( pkgNames );
            addPatchPackages            ( pkgNames );
 
            return pkgNames;
@@ -99,42 +94,6 @@ namespace zypp
        }
 
 
-
-       static void addPatternPackages( set<string> & pkgNames )
-       {
-           addPkgSetPackages<Pattern>( pkgNames );
-       }
-
-
-       /**
-        * Template to handle Patterns
-        **/
-        template<class PkgSet_T> void addPkgSetPackages( set<string> & pkgNames )
-       {
-           for ( PoolProxyIterator it = poolProxyBegin<PkgSet_T>();
-                 it != poolProxyEnd<PkgSet_T>();
-                 ++it )
-           {
-               // Take all pkg sets (patterns) into account that
-               // will be transacted, no matter if the user explicitly asked
-               // for that pkg set or if the patterns is required by another
-               // pkg set of the same class
-
-          typename PkgSet_T::constPtr pkgSet = dynamic_pointer_cast<const PkgSet_T>( (*it)->theObj() ? (*it)->theObj().resolvable() : 0L );
-
-               if ( pkgSet && (*it)->toModify() )
-               {
-                   DBG << (*it)->theObj()->kind().asString()
-                       << " will be transacted: \"" << pkgSet->name() << "\"" << endl;
-
-#warning NEEDS FIX
-                   set<string> setPkgs;// = pkgSet->install_packages();
-                   pkgNames.insert( setPkgs.begin(), setPkgs.end() );
-               }
-           }
-       }
-
-
         static void addPatchPackages( set<string> & pkgNames )
         {
             for ( PoolProxyIterator patch_it = patchesBegin();
index 0cd024a..5f94793 100644 (file)
@@ -13,6 +13,7 @@
 #include <zypp/base/String.h>
 #include <zypp/base/Gettext.h>
 #include <zypp/base/Regex.h>
+#include <zypp/base/StringV.h>
 
 #include <stdexcept>
 #include <climits>
@@ -74,6 +75,8 @@ namespace zypp
     const ViewOption  ViewOption::EMPTY_QUERY_STR   = 0x1000;
     const ViewOption  ViewOption::EMPTY_FRAGMENT    = 0x2000;
     const ViewOption  ViewOption::DEFAULTS          = 0x07bb;
+
+    const ViewOption  ViewOption::hotfix1050625     = 0x8000;
     /*
     const ViewOption  ViewOption::DEFAULTS          =
                       ViewOption::WITH_SCHEME       +
@@ -106,6 +109,68 @@ namespace zypp
 
 
     // ---------------------------------------------------------------
+
+    /// \brief Hide passwords embedded in a querystr,
+    ///
+    /// Stores the full querystring and maintains a safe version with
+    /// password field stripped. Url::asString will print the passwords
+    /// on demand only.
+    ///
+    /// \see bsc#1050625: VUL-1: CVE-2017-9271: zypper: proxy credentials written to log files
+    class SafeQuerystr
+    {
+    public:
+      SafeQuerystr()
+      {}
+
+      SafeQuerystr( std::string rhs )
+      { _assign( std::move(rhs) ); }
+
+      SafeQuerystr & operator=( std::string rhs )
+      { _assign( std::move(rhs) ); return *this; }
+
+
+      operator const std::string &() const
+      { return str(); }
+
+      const std::string & str() const
+      { return fullStr(); }
+
+      const std::string & str( const ViewOptions & viewopts_r ) const
+      { return (viewopts_r.has( ViewOptions::WITH_PASSWORD ) || viewopts_r.has( ViewOptions::hotfix1050625 )) ? fullStr() : safeStr(); }
+
+      const std::string & fullStr() const
+      { return _fullQuerytsr; }
+
+      const std::string & safeStr() const
+      { return _safeQuerytsr ? _safeQuerytsr.value() : _fullQuerytsr; }
+
+    private:
+      void _assign( std::string && rhs )
+      {
+       _fullQuerytsr = std::move(rhs);
+
+       static constexpr std::string_view tag { "proxypass=" };
+       if ( _fullQuerytsr.find( tag ) != std::string::npos )
+       {
+         std::string safe;
+         strv::split( _fullQuerytsr, "&", [&safe]( std::string_view val ) {
+           if ( val.substr( 0, tag.size()  ) != tag ) {
+             if ( ! safe.empty() )
+               safe += "&";
+             safe += val;
+           }
+         });
+         _safeQuerytsr = std::move(safe);
+       }
+       else
+         _safeQuerytsr = std::nullopt;
+      }
+    private:
+      std::string                _fullQuerytsr;        ///<
+      std::optional<std::string> _safeQuerytsr;        ///<.
+    };
+
     /**
      * \brief Internal data used by UrlBase.
      */
@@ -129,7 +194,7 @@ namespace zypp
       std::string     port;
       std::string     pathname;
       std::string     pathparams;
-      std::string     querystr;
+      SafeQuerystr    querystr;
       std::string     fragment;
     };
 
@@ -440,6 +505,12 @@ namespace zypp
       return asString(getViewOptions());
     }
 
+    std::string UrlBase::asString1050625() const
+    {
+      // Temp. fix to keep the proxypass in the query when writing the .repo files,
+      // but otherwise hiding it, when WITH_PASSWORD is not set.
+      return asString(getViewOptions()+ViewOptions::hotfix1050625);
+    }
 
     // ---------------------------------------------------------------
     std::string
@@ -547,10 +618,10 @@ namespace zypp
 
       if( opts.has(ViewOptions::WITH_QUERY_STR))
       {
-        tmp.querystr = getQueryString();
-        if( !tmp.querystr.empty())
+       const std::string & querystr { getQueryString( opts ) };        // full or safe depending on opts
+        if( !querystr.empty() )
         {
-          url += "?" + tmp.querystr;
+          url += "?" + querystr;
         }
         else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
         {
@@ -627,6 +698,11 @@ namespace zypp
       return m_data->querystr;
     }
 
+    std::string
+    UrlBase::getQueryString( const ViewOptions & viewopts_r ) const
+    {
+      return m_data->querystr.str( viewopts_r );
+    }
 
     // ---------------------------------------------------------------
     std::string
index 005bce9..9c96678 100644 (file)
@@ -230,6 +230,7 @@ namespace zypp
         return o.opt & opt;
       }
 
+      static const ViewOption hotfix1050625;
     private:
       ViewOption(int option);
       int opt;
@@ -594,6 +595,10 @@ namespace zypp
       virtual std::string
       getQueryString() const;
 
+      /** \overload Returns the safe query string (passwds stripped) unless WITH_PASSWORD is set. */
+      virtual std::string
+      getQueryString( const ViewOptions & viewopts_r ) const;
+
       /**
        * Returns a vector with query string parameter substrings.
        *
@@ -995,7 +1000,7 @@ namespace zypp
       void
       setViewOptions(const ViewOptions &vopts);
 
-
+      std::string asString1050625() const;
     protected:
       /**
        * Utility method to cleanup an encoded path name.