Hello community,

here is the log from the commit of package libzypp for openSUSE:Factory checked 
in at 2016-04-30 23:28:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libzypp (Old)
 and      /work/SRC/openSUSE:Factory/.libzypp.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libzypp"

Changes:
--------
--- /work/SRC/openSUSE:Factory/libzypp/libzypp.changes  2016-03-26 
15:11:12.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.libzypp.new/libzypp.changes     2016-04-30 
23:28:48.000000000 +0200
@@ -1,0 +2,23 @@
+Mon Apr 25 14:59:41 CEST 2016 - [email protected]
+
+- Fix credential file parser losing entries with known URL but
+  different user name (bsc#933760)
+- RepoManager: allow extraction of multiple baseurls for service
+  repos (bsc#964932)
+- addRepository: fix to use the correct history file for logging
+- specfile: add /etc/zypp/credentials.d to the file list
+- version 15.22.0 (19)
+
+-------------------------------------------------------------------
+Mon Apr 18 15:03:13 CEST 2016 - [email protected]
+
+- RepoindexFileReader: fix service metadata TTL default value (bsc#967828)
+- version 15.21.7 (19)
+
+-------------------------------------------------------------------
+Fri Apr 15 11:31:08 CEST 2016 - [email protected]
+
+- DiskUsageCounter: Limit estimated waste per file (bsc#974275)
+- version 15.21.6 (19)
+
+-------------------------------------------------------------------

Old:
----
  libzypp-15.21.5.tar.bz2

New:
----
  libzypp-15.22.0.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libzypp.spec ++++++
--- /var/tmp/diff_new_pack.WY7OPz/_old  2016-04-30 23:28:49.000000000 +0200
+++ /var/tmp/diff_new_pack.WY7OPz/_new  2016-04-30 23:28:49.000000000 +0200
@@ -19,7 +19,7 @@
 %define force_gcc_46 0
 
 Name:           libzypp
-Version:        15.21.5
+Version:        15.22.0
 Release:        0
 Url:            git://gitorious.org/opensuse/libzypp.git
 Summary:        Package, Patch, Pattern, and Product Management
@@ -35,7 +35,7 @@
 Provides:       libzypp(plugin) = 0
 Provides:       libzypp(plugin:appdata) = 0
 Provides:       libzypp(plugin:commit) = 1
-Provides:       libzypp(plugin:services) = 0
+Provides:       libzypp(plugin:services) = 1
 Provides:       libzypp(plugin:system) = 1
 Provides:       libzypp(plugin:urlresolver) = 0
 Provides:       libzypp(repovarexpand) = 0
@@ -242,6 +242,7 @@
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/systemCheck.d
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/vendors.d
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/multiversion.d
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/credentials.d
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/appdata
@@ -339,6 +340,7 @@
 %dir               %{_sysconfdir}/zypp/systemCheck.d
 %dir               %{_sysconfdir}/zypp/vendors.d
 %dir               %{_sysconfdir}/zypp/multiversion.d
+%dir               %{_sysconfdir}/zypp/credentials.d
 %config(noreplace) %{_sysconfdir}/zypp/zypp.conf
 %config(noreplace) %{_sysconfdir}/zypp/systemCheck
 %config(noreplace) %{_sysconfdir}/logrotate.d/zypp-history.lr

++++++ libzypp-15.21.5.tar.bz2 -> libzypp-15.22.0.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/VERSION.cmake 
new/libzypp-15.22.0/VERSION.cmake
--- old/libzypp-15.21.5/VERSION.cmake   2016-03-18 13:40:46.000000000 +0100
+++ new/libzypp-15.22.0/VERSION.cmake   2016-04-25 15:05:27.000000000 +0200
@@ -60,9 +60,9 @@
 #
 SET(LIBZYPP_MAJOR "15")
 SET(LIBZYPP_COMPATMINOR "19")
-SET(LIBZYPP_MINOR "21")
-SET(LIBZYPP_PATCH "5")
+SET(LIBZYPP_MINOR "22")
+SET(LIBZYPP_PATCH "0")
 #
-# LAST RELEASED: 15.21.5 (19)
+# LAST RELEASED: 15.22.0 (19)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/doc/autoinclude/FeatureTest.doc 
new/libzypp-15.22.0/doc/autoinclude/FeatureTest.doc
--- old/libzypp-15.21.5/doc/autoinclude/FeatureTest.doc 2016-03-18 
13:28:44.000000000 +0100
+++ new/libzypp-15.22.0/doc/autoinclude/FeatureTest.doc 2016-04-25 
15:49:26.000000000 +0200
@@ -41,6 +41,8 @@
     <DT>\ref plugin-services </DT>
     <DT>version 0</DT>
     <DD>Provide a client a list of repositories.</DD>
+    <DT>version 1</DT>
+    <DD>Support multiple repo baseurls in plugin services.</DD>
   </DL></DD>
 
   <DT>plugin:system</DT>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/libzypp.spec.cmake 
new/libzypp-15.22.0/libzypp.spec.cmake
--- old/libzypp-15.21.5/libzypp.spec.cmake      2016-03-18 13:28:44.000000000 
+0100
+++ new/libzypp-15.22.0/libzypp.spec.cmake      2016-04-25 15:49:26.000000000 
+0200
@@ -35,7 +35,7 @@
 Provides:       libzypp(plugin) = 0
 Provides:       libzypp(plugin:appdata) = 0
 Provides:       libzypp(plugin:commit) = 1
-Provides:       libzypp(plugin:services) = 0
+Provides:       libzypp(plugin:services) = 1
 Provides:       libzypp(plugin:system) = 1
 Provides:       libzypp(plugin:urlresolver) = 0
 Provides:       libzypp(repovarexpand) = 0
@@ -242,6 +242,7 @@
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/systemCheck.d
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/vendors.d
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/multiversion.d
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/credentials.d
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/appdata
@@ -339,6 +340,7 @@
 %dir               %{_sysconfdir}/zypp/systemCheck.d
 %dir               %{_sysconfdir}/zypp/vendors.d
 %dir               %{_sysconfdir}/zypp/multiversion.d
+%dir               %{_sysconfdir}/zypp/credentials.d
 %config(noreplace) %{_sysconfdir}/zypp/zypp.conf
 %config(noreplace) %{_sysconfdir}/zypp/systemCheck
 %config(noreplace) %{_sysconfdir}/logrotate.d/zypp-history.lr
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/package/libzypp.changes 
new/libzypp-15.22.0/package/libzypp.changes
--- old/libzypp-15.21.5/package/libzypp.changes 2016-03-18 13:40:46.000000000 
+0100
+++ new/libzypp-15.22.0/package/libzypp.changes 2016-04-25 15:05:27.000000000 
+0200
@@ -1,4 +1,27 @@
 -------------------------------------------------------------------
+Mon Apr 25 14:59:41 CEST 2016 - [email protected]
+
+- Fix credential file parser losing entries with known URL but
+  different user name (bsc#933760)
+- RepoManager: allow extraction of multiple baseurls for service
+  repos (bsc#964932)
+- addRepository: fix to use the correct history file for logging
+- specfile: add /etc/zypp/credentials.d to the file list
+- version 15.22.0 (19)
+
+-------------------------------------------------------------------
+Mon Apr 18 15:03:13 CEST 2016 - [email protected]
+
+- RepoindexFileReader: fix service metadata TTL default value (bsc#967828)
+- version 15.21.7 (19)
+
+-------------------------------------------------------------------
+Fri Apr 15 11:31:08 CEST 2016 - [email protected]
+
+- DiskUsageCounter: Limit estimated waste per file (bsc#974275)
+- version 15.21.6 (19)
+
+-------------------------------------------------------------------
 Fri Mar 18 13:37:22 CET 2016 - [email protected]
 
 - Use PluginExecutor for commit- and system-hooks (bnc#971637)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libzypp-15.21.5/tests/media/CredentialFileReader_test.cc 
new/libzypp-15.22.0/tests/media/CredentialFileReader_test.cc
--- old/libzypp-15.21.5/tests/media/CredentialFileReader_test.cc        
2016-02-11 17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/tests/media/CredentialFileReader_test.cc        
2016-04-26 18:01:29.000000000 +0200
@@ -34,5 +34,5 @@
   CredentialFileReader reader(credfile,
       bind( &CredCollector::collect, &collector, _1 ));
 
-  BOOST_CHECK(collector.creds.size() == 2);
+  BOOST_CHECK_EQUAL(collector.creds.size(), 3);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libzypp-15.21.5/tests/media/CredentialManager_test.cc 
new/libzypp-15.22.0/tests/media/CredentialManager_test.cc
--- old/libzypp-15.21.5/tests/media/CredentialManager_test.cc   2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/tests/media/CredentialManager_test.cc   2016-04-26 
18:01:29.000000000 +0200
@@ -13,38 +13,47 @@
 using namespace zypp;
 using namespace zypp::media;
 
+inline void testGetCreds( CredentialManager & cm_r, const std::string & url_r,
+                     const std::string & user_r = "",
+                     const std::string & pass_r = "" )
+{
+  Url url( url_r );
+  AuthData_Ptr cred = cm_r.getCred( url );
+  //cout << "FOR: " << url << endl;
+  //cout << "GOT: " << cred << endl;
+  if ( user_r.empty() && pass_r.empty() )
+  {
+    BOOST_CHECK_EQUAL( cred, AuthData_Ptr() );
+  }
+  else
+  {
+    BOOST_CHECK_EQUAL( cred->username(), user_r );
+    BOOST_CHECK_EQUAL( cred->password(), pass_r );
+  }
+}
 
 BOOST_AUTO_TEST_CASE(read_cred_for_url)
 {
   CredManagerOptions opts;
   opts.globalCredFilePath = TESTS_SRC_DIR "/media/data/credentials.cat";
   opts.userCredFilePath = Pathname();
+  CredentialManager cm( opts );
 
-  CredentialManager cm(opts);
-  BOOST_CHECK(cm.credsGlobalSize() == 2);
+  BOOST_CHECK_EQUAL( cm.credsGlobalSize(), 3 );
 
-  Url url("https://drink.it/repo/roots";);
-  AuthData_Ptr credentials = cm.getCred(url);
-  BOOST_CHECK(credentials.get() != NULL);
-  if (!credentials)
-    return;
-  BOOST_CHECK(credentials->username() == "ginger");
-  BOOST_CHECK(credentials->password() == "ale");
-
-  Url url2("ftp://[email protected]/download/opensuse/110";);
-  credentials = cm.getCred(url2);
-  BOOST_CHECK(credentials.get() != NULL);
-  if (!credentials)
-    return;
-  BOOST_CHECK(credentials->username() == "magda");
-  BOOST_CHECK(credentials->password() == "richard");
+  testGetCreds( cm, "https://drink.it/repo/roots";,                             
"ginger", "ale" );
+  testGetCreds( cm, "ftp://weprovidesoft.fr/download/opensuse/110";,            
"agda", "ichard" );
+  testGetCreds( cm, "ftp://[email protected]/download/opensuse/110";,      
"magda", "richard" );
+  testGetCreds( cm, "ftp://[email protected]/download/opensuse/110";,       
"agda", "ichard" );
+  testGetCreds( cm, "ftp://[email protected]/download/opensuse/110"; );  
// NULL
+  testGetCreds( cm, "http://url.ok/but/not/creds"; );                           
// NULL
 }
 
 struct CredCollector
 {
   bool collect(AuthData_Ptr & cred)
   {
-    cout << "got: " << endl << *cred << endl;
+    //cout << "got: " << endl << *cred << endl;
     creds.insert(cred);
     return true;
   }
@@ -56,13 +65,13 @@
 BOOST_AUTO_TEST_CASE(save_creds)
 {
   filesystem::TmpDir tmp;
-
   CredManagerOptions opts;
   opts.globalCredFilePath = tmp / "fooha";
-
   CredentialManager cm1(opts);
+
   AuthData cr1("benson","absolute");
   cr1.setUrl(Url("http://joooha.com";));
+
   AuthData cr2("pat","vymetheny");
   cr2.setUrl(Url("ftp://filesuck.org";));
 
@@ -70,27 +79,19 @@
   cm1.saveInGlobal(cr1);
 
   CredCollector collector;
-  CredentialFileReader reader(opts.globalCredFilePath,
-      bind( &CredCollector::collect, &collector, _1 ));
-  BOOST_CHECK(collector.creds.size() == 1);
+  CredentialFileReader( opts.globalCredFilePath, bind( 
&CredCollector::collect, &collector, _1 ) );
+  BOOST_CHECK_EQUAL( collector.creds.size(), 1 );
 
-  cout << "----" << endl;
   collector.creds.clear();
-
   cm1.saveInGlobal(cr2);
+  CredentialFileReader( opts.globalCredFilePath, bind( 
&CredCollector::collect, &collector, _1 ) );
+  BOOST_CHECK_EQUAL(collector.creds.size(), 2 );
   
-  CredentialFileReader reader1(opts.globalCredFilePath,
-      bind( &CredCollector::collect, &collector, _1 ));
-  BOOST_CHECK(collector.creds.size() == 2);
-  
-  cout << "----" << endl;
   collector.creds.clear();
-
   // save the same creds again
   cm1.saveInGlobal(cr2);
-  CredentialFileReader reader2(opts.globalCredFilePath,
-      bind( &CredCollector::collect, &collector, _1 ));
-  BOOST_CHECK(collector.creds.size() == 2);
+  CredentialFileReader( opts.globalCredFilePath, bind( 
&CredCollector::collect, &collector, _1 ) );
+  BOOST_CHECK_EQUAL(collector.creds.size(), 2 );
 
   // todo check created file permissions
 }
@@ -98,30 +99,15 @@
 BOOST_AUTO_TEST_CASE(service_base_url)
 {
   filesystem::TmpDir tmp;
-
   CredManagerOptions opts;
   opts.globalCredFilePath = tmp / "fooha";
+  CredentialManager cm( opts );
 
-  CredentialManager cm1(opts);
-  AuthData cr1("benson","absolute");
-  cr1.setUrl(Url("http://joooha.com/service/path";));
-  cm1.addGlobalCred(cr1);
-
-  AuthData_Ptr creds;
-  creds = cm1.getCred(Url("http://joooha.com/service/path/repo/repofoo";));
-
-  BOOST_CHECK(creds.get() != NULL);
-  if (!creds)
-    return;
-  BOOST_CHECK(creds->username() == "benson");
-
-  creds = 
cm1.getCred(Url("http://[email protected]/service/path/repo/repofoo";));
-
-  BOOST_CHECK(creds.get() != NULL);
-  if (!creds)
-    return;
-  BOOST_CHECK(creds->username() == "benson");
-
-  creds = 
cm1.getCred(Url("http://[email protected]/service/path/repo/repofoo";));
-  BOOST_CHECK(creds.get() == NULL);
+  AuthData cred( "benson","absolute" );
+  cred.setUrl( Url( "http://joooha.com/service/path"; ) );
+  cm.addGlobalCred( cred );
+
+  testGetCreds( cm, "http://joooha.com/service/path/repo/repofoo";,             
"benson", "absolute" );
+  testGetCreds( cm, "http://[email protected]/service/path/repo/repofoo";,      
"benson", "absolute" );
+  testGetCreds( cm, "http://[email protected]/service/path/repo/repofoo"; );    
// NULL
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/tests/media/data/credentials.cat 
new/libzypp-15.22.0/tests/media/data/credentials.cat
--- old/libzypp-15.21.5/tests/media/data/credentials.cat        2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/tests/media/data/credentials.cat        2016-04-26 
18:01:29.000000000 +0200
@@ -1,15 +1,24 @@
+# no 1
 [https://drink.it/repo/roots]
 username=ginger
 password=ale
 
+#no 2
 [ftp://weprovidesoft.fr/download/opensuse/110]
 username=magda
 password=richard
 
+# no 3 - same urla s 2 but different user (lex less than magda)
+[ftp://weprovidesoft.fr/download/opensuse/110]
+username=agda
+password=ichard
+
+# fail
 [http://url.ok/but/not/creds]
 username=
 password=any
 
+# fail
 [badurl]
 username=foo
 password=bar
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/DiskUsageCounter.cc 
new/libzypp-15.22.0/zypp/DiskUsageCounter.cc
--- old/libzypp-15.21.5/zypp/DiskUsageCounter.cc        2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/DiskUsageCounter.cc        2016-04-15 
11:32:37.000000000 +0200
@@ -71,10 +71,13 @@
         unsigned idx = 0;
         for_( it, result.begin(), result.end() )
         {
-          static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * 
blocksize) / (2 * 1K)
+         // Limit estimated waste (half block per file) as it does not apply to
+         // btrfs, which reports up to 64K blocksize (bsc#974275,bsc#965322)
+         static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * 
blocksize) / 2 / 1K; result value in K!
+
           it->pkg_size = it->used_size          // current usage
                        + duchanges[idx].kbytes  // package data size
-                       + ( duchanges[idx].files * it->block_size / blockAdjust 
); // half block per file
+                       + ( duchanges[idx].files * ( it->fstype == "btrfs" ? 
4096 : it->block_size ) / blockAdjust ); // half block per file
           ++idx;
         }
       }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/RepoInfo.cc 
new/libzypp-15.22.0/zypp/RepoInfo.cc
--- old/libzypp-15.21.5/zypp/RepoInfo.cc        2016-02-11 17:22:14.000000000 
+0100
+++ new/libzypp-15.22.0/zypp/RepoInfo.cc        2016-04-25 15:05:27.000000000 
+0200
@@ -347,6 +347,9 @@
     _pimpl->baseUrls().raw().push_back( url_r );
   }
 
+  void RepoInfo::setBaseUrls( url_set urls )
+  { _pimpl->baseUrls().raw().swap( urls ); }
+
   void RepoInfo::setPath( const Pathname &path )
   { _pimpl->path = path; }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/RepoInfo.h 
new/libzypp-15.22.0/zypp/RepoInfo.h
--- old/libzypp-15.21.5/zypp/RepoInfo.h 2016-02-11 17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/RepoInfo.h 2016-04-25 15:05:27.000000000 +0200
@@ -159,6 +159,10 @@
        * Clears current base URL list and adds \a url.
        */
       void setBaseUrl( const Url &url );
+      /**
+       * Clears current base URL list and adds an \ref url_set.
+       */
+      void setBaseUrls( url_set urls );
 
       /**
        * \short Repository path
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/RepoManager.cc 
new/libzypp-15.22.0/zypp/RepoManager.cc
--- old/libzypp-15.21.5/zypp/RepoManager.cc     2016-02-11 17:22:14.000000000 
+0100
+++ new/libzypp-15.22.0/zypp/RepoManager.cc     2016-04-25 15:05:27.000000000 
+0200
@@ -64,6 +64,76 @@
   ///////////////////////////////////////////////////////////////////
   namespace
   {
+    ///////////////////////////////////////////////////////////////////
+    /// \class UrlCredentialExtractor
+    /// \brief Extract credentials in \ref Url authority and store them via 
\ref CredentialManager.
+    ///
+    /// Lazy init CredentialManager and save collected credentials when
+    /// going out of scope.
+    ///
+    /// Methods return whether a password has been collected/extracted.
+    ///
+    /// \code
+    /// UrlCredentialExtractor( "/rootdir" ).collect( oneUrlOrUrlContainer );
+    /// \endcode
+    /// \code
+    /// {
+    ///   UrlCredentialExtractor extractCredentials;
+    ///   extractCredentials.collect( oneUrlOrUrlContainer );
+    ///   extractCredentials.extract( oneMoreUrlOrUrlContainer );
+    ///   ....
+    /// }
+    /// \endcode
+    ///
+    class UrlCredentialExtractor
+    {
+    public:
+      UrlCredentialExtractor( Pathname & root_r )
+      : _root( root_r )
+      {}
+
+      ~UrlCredentialExtractor()
+      { if ( _cmPtr ) _cmPtr->save(); }
+
+      /** Remember credentials stored in URL authority leaving the password in 
\a url_r. */
+      bool collect( const Url & url_r )
+      {
+       bool ret = url_r.hasCredentialsInAuthority();
+       if ( ret )
+       {
+         if ( !_cmPtr ) _cmPtr.reset( new media::CredentialManager( _root ) );
+         _cmPtr->addUserCred( url_r );
+       }
+       return ret;
+      }
+      /** \overload operating on Url container */
+      template<class TContainer>
+      bool collect( const TContainer & urls_r )
+      {        bool ret = false; for ( const Url & url : urls_r ) { if ( 
collect( url ) && !ret ) ret = true; } return ret; }
+
+      /** Remember credentials stored in URL authority stripping the passowrd 
from \a url_r. */
+      bool extract( Url & url_r )
+      {
+       bool ret = collect( url_r );
+       if ( ret )
+         url_r.setPassword( std::string() );
+       return ret;
+      }
+      /** \overload operating on Url container */
+      template<class TContainer>
+      bool extract( TContainer & urls_r )
+      {        bool ret = false; for ( Url & url : urls_r ) { if ( extract( 
url ) && !ret ) ret = true; } return ret; }
+
+    private:
+      const Pathname & _root;
+      scoped_ptr<media::CredentialManager> _cmPtr;
+    };
+  } // namespace
+  ///////////////////////////////////////////////////////////////////
+
+  ///////////////////////////////////////////////////////////////////
+  namespace
+  {
     /** Simple media mounter to access non-downloading URLs e.g. for non-local 
plaindir repos.
      * \ingroup g_RAII
      */
@@ -1596,26 +1666,9 @@
     progress.set(90);
 
     // check for credentials in Urls
-    bool havePasswords = false;
-    for_( urlit, tosave.baseUrlsBegin(), tosave.baseUrlsEnd() )
-      if ( urlit->hasCredentialsInAuthority() )
-      {
-        havePasswords = true;
-        break;
-      }
-    // save the credentials
-    if ( havePasswords )
-    {
-      media::CredentialManager cm(
-          media::CredManagerOptions(_options.rootDir) );
-
-      for_(urlit, tosave.baseUrlsBegin(), tosave.baseUrlsEnd())
-        if (urlit->hasCredentialsInAuthority())
-          //! \todo use a method calling UI callbacks to ask where to save 
creds?
-          cm.saveInUser(media::AuthData(*urlit));
-    }
+    UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
 
-    HistoryLog().addRepository(tosave);
+    HistoryLog(_options.rootDir).addRepository(tosave);
 
     progress.toMax();
     MIL << "done" << endl;
@@ -1823,6 +1876,8 @@
       newinfo.setFilepath(toedit.filepath());
       reposManip().erase(toedit);
       reposManip().insert(newinfo);
+      // check for credentials in Urls
+      UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() );
       HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
       MIL << "repo " << alias << " modified" << endl;
     }
@@ -1876,15 +1931,8 @@
     saveService( toSave );
     _services.insert( toSave );
 
-    // check for credentials in Url (username:password, not ?credentials param)
-    if ( toSave.url().hasCredentialsInAuthority() )
-    {
-      media::CredentialManager cm(
-          media::CredManagerOptions(_options.rootDir) );
-
-      //! \todo use a method calling UI callbacks to ask where to save creds?
-      cm.saveInUser(media::AuthData(toSave.url()));
-    }
+    // check for credentials in Url
+    UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
 
     MIL << "added service " << toSave.alias() << endl;
   }
@@ -1972,7 +2020,7 @@
     assert_url( service );
     MIL << "Going to refresh service '" << service.alias() <<  "', url: " << 
service.url() << ", opts: " << options_r << endl;
 
-    if ( service.ttl() && !options_r.testFlag( RefreshService_forceRefresh ) )
+    if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) 
|| options_r.testFlag( RefreshService_restoreStatus ) ) )
     {
       // Service defines a TTL; maybe we can re-use existing data without 
refresh.
       Date lrf = service.lrf();
@@ -2051,34 +2099,41 @@
     {
       // First of all: Prepend service alias:
       it->setAlias( str::form( "%s:%s", service.alias().c_str(), 
it->alias().c_str() ) );
-      // set refrence to the parent service
+      // set reference to the parent service
       it->setService( service.alias() );
 
       // remember the new parsed repo state
       newRepoStates[it->alias()] = *it;
 
-      // if the repo url was not set by the repoindex parser, set service's url
-      Url url;
-      if ( it->baseUrlsEmpty() )
-        url = service.rawUrl();
-      else
+      // - If the repo url was not set by the repoindex parser, set service's 
url.
+      // - Libzypp currently has problem with separate url + path handling so 
just
+      //   append a path, if set, to the baseurls
+      // - Credentials in the url authority will be extracted later, either if 
the
+      //   repository is added or if we check for changed urls.
+      Pathname path;
+      if ( !it->path().empty() )
       {
-        // service repo can contain only one URL now, so no need to iterate.
-        url = it->rawUrl();    // raw!
+       if ( it->path() != "/" )
+         path = it->path();
+       it->setPath("");
       }
 
-      // libzypp currently has problem with separate url + path handling
-      // so just append the path to the baseurl
-      if ( !it->path().empty() )
+      if ( it->baseUrlsEmpty() )
       {
-        Pathname path(url.getPathName());
-        path /= it->path();
-        url.setPathName( path.asString() );
-        it->setPath("");
+       Url url( service.rawUrl() );
+       if ( !path.empty() )
+         url.setPathName( url.getPathName() / path );
+       it->setBaseUrl( std::move(url) );
+      }
+      else if ( !path.empty() )
+      {
+       RepoInfo::url_set urls( it->rawBaseUrls() );
+       for ( Url & url : urls )
+       {
+         url.setPathName( url.getPathName() / path );
+       }
+       it->setBaseUrls( std::move(urls) );
       }
-
-      // save the url
-      it->setBaseUrl( url );
     }
 
     
////////////////////////////////////////////////////////////////////////////
@@ -2114,7 +2169,8 @@
     }
 
     
////////////////////////////////////////////////////////////////////////////
-    // create missing repositories and modify exising ones if needed...
+    // create missing repositories and modify existing ones if needed...
+    UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To 
collect any credentials stored in repo URLs
     for_( it, collector.repos.begin(), collector.repos.end() )
     {
       // User explicitly requested the repo being enabled?
@@ -2239,13 +2295,16 @@
        }
 
         // changed url?
-        // service repo can contain only one URL now, so no need to iterate.
-        if ( oldRepo->rawUrl() != it->rawUrl() )
         {
-          DBG << "Service repo " << it->alias() << " gets new URL " << 
it->rawUrl() << endl;
-          oldRepo->setBaseUrl( it->rawUrl() );
-          oldRepoModified = true;
-        }
+         RepoInfo::url_set newUrls( it->rawBaseUrls() );
+         urlCredentialExtractor.extract( newUrls );    // Extract! to prevent 
passwds from disturbing the comparison below
+         if ( oldRepo->rawBaseUrls() != newUrls )
+         {
+           DBG << "Service repo " << it->alias() << " gets new URLs " << 
newUrls << endl;
+           oldRepo->setBaseUrls( std::move(newUrls) );
+           oldRepoModified = true;
+         }
+       }
 
         // changed gpg check settings?
        // ATM only plugin services can set GPG values.
@@ -2353,6 +2412,9 @@
 
     _services.erase(oldAlias);
     _services.insert(service);
+    // check for credentials in Urls
+    UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
+
 
     // changed properties affecting also repositories
     if ( oldAlias != service.alias()                   // changed alias
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/media/CredentialFileReader.cc 
new/libzypp-15.22.0/zypp/media/CredentialFileReader.cc
--- old/libzypp-15.21.5/zypp/media/CredentialFileReader.cc      2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/media/CredentialFileReader.cc      2016-04-25 
15:05:27.000000000 +0200
@@ -22,79 +22,123 @@
 #undef ZYPP_BASE_LOGGER_LOGGROUP
 #define ZYPP_BASE_LOGGER_LOGGROUP "parser"
 
-
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
   ///////////////////////////////////////////////////////////////////
   namespace media
-  { /////////////////////////////////////////////////////////////////
-
-
-  //////////////////////////////////////////////////////////////////////
-  //
-  // CLASS NAME : CredentialFileReader
-  //
-  //////////////////////////////////////////////////////////////////////
-
-  CredentialFileReader::CredentialFileReader(
-      const Pathname & crfile,
-      const ProcessCredentials & callback)
   {
-    InputStream is(crfile);
-    parser::IniDict dict(is);
-    for (parser::IniDict::section_const_iterator its = dict.sectionsBegin();
-         its != dict.sectionsEnd();
-         ++its)
+    ///////////////////////////////////////////////////////////////////
+    namespace
     {
-      Url storedUrl;
-      if (!its->empty())
+      // Looks like INI but allows multiple sections for the same URL
+      // but different user (in .cat files). So don't use an Ini
+      // Also support a global section without '[URL]' which is used
+      // in credential files.
+      // -------------------------------------
+      // username = emptyUSER
+      // password = emptyPASS
+      // -------------------------------------
+      // [http://server/tmp/sumafake222]
+      // username = USER
+      // password = PASS
+      //
+      // [http://server/tmp/sumafake222]
+      // username = USER2
+      // password = PASS
+      // -------------------------------------
+      struct CredentialFileReaderImpl : public parser::IniParser
       {
-        try { storedUrl = Url(*its); }
-        catch (const url::UrlException &)
-        {
-          ERR << "invalid URL '" << *its << "' in credentials in file: "
-              << crfile << endl;
-          continue;
-        }
-      }
-
-      AuthData_Ptr credentials;
-      credentials.reset(new AuthData());
-
-      // set url
-      if (storedUrl.isValid())
-        credentials->setUrl(storedUrl);
-
-      for (parser::IniDict::entry_const_iterator it = dict.entriesBegin(*its);
-           it != dict.entriesEnd(*its);
-           ++it)
-      {
-        if (it->first == "username")
-          credentials->setUsername(it->second);
-        else if (it->first == "password")
-          credentials->setPassword(it->second);
-        else
-          ERR << "Unknown attribute in [" << crfile << "]: "
-              << it->second << " ignored" << endl;
-      }
-
-      if (credentials->valid())
-        callback(credentials);
-      else
-        ERR << "invalid credentials in file: " << crfile << endl;
-    } // sections
-  }
+       typedef CredentialFileReader::ProcessCredentials ProcessCredentials;
+
+       struct StopParsing {};
 
+       CredentialFileReaderImpl( const Pathname & input_r, const 
ProcessCredentials & callback_r )
+       : _input( input_r )
+       , _callback( callback_r )
+       {
+         try
+         {
+           parse( input_r );
+         }
+         catch ( StopParsing )
+         { /* NO error but consumer aborted parsing */ }
+       }
+
+       // NO-OP; new sections are opened in consume()
+       virtual void beginParse()
+       { /*EMPTY*/ }
+
+       // start a new section [url]
+       virtual void consume( const std::string & section_r )
+       {
+         endParse();   // close any open section
+         _secret.reset( new AuthData );
+         try
+         {
+           _secret->setUrl( Url(section_r) );
+         }
+         catch ( const url::UrlException & )
+         {
+           ERR << "Ignore invalid URL '" << section_r << "' in file " << 
_input << endl;
+           _secret.reset();    // ignore this section
+         }
+       }
+
+       virtual void consume( const std::string & section_r, const std::string 
& key_r, const std::string & value_r )
+       {
+         if ( !_secret && section_r.empty() )
+           _secret.reset( new AuthData );      // a initial global section 
without [URL]
+
+         if ( _secret )
+         {
+           if ( key_r == "username" )
+             _secret->setUsername( value_r );
+           else if ( key_r == "password" )
+             _secret->setPassword( value_r );
+           else
+             WAR << "Ignore unknown attribute '" << key_r << "=" << value_r << 
"' in file " << _input << endl;
+         }
+         // else: ignored section due to wrong URL
+       }
+
+       // send any valid pending section
+       virtual void endParse()
+       {
+         if ( _secret )
+         {
+           if ( _secret->valid() )
+           {
+             if ( !_callback( _secret ) )
+               throw( StopParsing() );
+           }
+           else
+             ERR << "Ignore invalid credentials for URL '" << _secret->url() 
<< "' in file " << _input << endl;
+         }
+       }
+
+      private:
+       const Pathname &                _input;
+       const ProcessCredentials &      _callback;
+       AuthData_Ptr                    _secret;
+      };
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
+
+    //////////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CredentialFileReader
+    //
+    //////////////////////////////////////////////////////////////////////
 
-  CredentialFileReader::~CredentialFileReader()
-  {}
+    CredentialFileReader::CredentialFileReader( const Pathname & crfile_r, 
const ProcessCredentials & callback_r )
+    { CredentialFileReaderImpl( crfile_r, callback_r ); }
 
+    CredentialFileReader::~CredentialFileReader()
+    {}
 
-    /////////////////////////////////////////////////////////////////
-  } // media
+  } // namespace media
   ///////////////////////////////////////////////////////////////////
-  /////////////////////////////////////////////////////////////////
-} // zypp
+} // namespace zypp
 ///////////////////////////////////////////////////////////////////
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/media/CredentialFileReader.h 
new/libzypp-15.22.0/zypp/media/CredentialFileReader.h
--- old/libzypp-15.21.5/zypp/media/CredentialFileReader.h       2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/media/CredentialFileReader.h       2016-04-25 
15:05:27.000000000 +0200
@@ -20,43 +20,31 @@
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
   ///////////////////////////////////////////////////////////////////
   namespace media
-  { /////////////////////////////////////////////////////////////////
-
-
-  //////////////////////////////////////////////////////////////////////
-  //
-  // CLASS NAME : CredentialFileReader 
-  //
-  class CredentialFileReader
   {
-  public:
-    /**
-      * Callback definition.
-      * First parameter is the \ref Url with which the credentials are
-      * associated, the second are the credentials.
-      *
-      * Return false from the callback to get a \ref AbortRequestException
-      * to be thrown and the processing to be cancelled.
-      */
-    typedef function<bool(AuthData_Ptr &)> ProcessCredentials;
-
-    CredentialFileReader(const Pathname & crfile,
-                         const ProcessCredentials & callback);
-    ~CredentialFileReader();
-  private:
-    ProcessCredentials _callback;
-  };
-  //////////////////////////////////////////////////////////////////////
-
+    //////////////////////////////////////////////////////////////////////
+    /// \class CredentialFileReader
+    /// \brief Parse credentials files and catalogs
+    class CredentialFileReader
+    {
+    public:
+      /** Callback invoked for each entry found in the file.
+       * Return \c false to abort parsing.
+       */
+      typedef function<bool(AuthData_Ptr &)> ProcessCredentials;
+
+      CredentialFileReader( const Pathname & crfile_r, const 
ProcessCredentials & callback_r );
+      ~CredentialFileReader();
+    private:
+      ProcessCredentials _callback;
+    };
+    //////////////////////////////////////////////////////////////////////
 
-    /////////////////////////////////////////////////////////////////
-  } // media
+  } // namespace media
   ///////////////////////////////////////////////////////////////////
-  /////////////////////////////////////////////////////////////////
-} // zypp
+} // namespace zypp
 ///////////////////////////////////////////////////////////////////
 
 #endif /* ZYPP_MEDIA_CREDENTIALFILEREADER_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/media/CredentialManager.cc 
new/libzypp-15.22.0/zypp/media/CredentialManager.cc
--- old/libzypp-15.21.5/zypp/media/CredentialManager.cc 2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/media/CredentialManager.cc 2016-04-25 
15:05:27.000000000 +0200
@@ -39,23 +39,17 @@
   //
   //////////////////////////////////////////////////////////////////////
 
-  bool
-  AuthDataComparator::operator()(
-      const AuthData_Ptr & lhs, const AuthData_Ptr & rhs)
+  bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const 
AuthData_Ptr & rhs )
   {
-    static const url::ViewOption vopt =
-        url::ViewOption::DEFAULTS
-        - url::ViewOption::WITH_USERNAME
-        - url::ViewOption::WITH_PASSWORD
-        - url::ViewOption::WITH_QUERY_STR;
-
-    if (lhs->username() != rhs->username())
-      return true;
-
-    if (lhs->url().asString(vopt) != rhs->url().asString(vopt))
-      return true;
-
-    return false;
+    static const url::ViewOption vopt = url::ViewOption::DEFAULTS
+                                     - url::ViewOption::WITH_USERNAME
+                                     - url::ViewOption::WITH_PASSWORD
+                                     - url::ViewOption::WITH_QUERY_STR;
+    // std::less semantic!
+    int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) );
+    if ( ! cmp )
+      cmp = lhs->username().compare( rhs->username() );
+    return( cmp < 0 );
   }
 
   //////////////////////////////////////////////////////////////////////
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/media/MediaUserAuth.cc 
new/libzypp-15.22.0/zypp/media/MediaUserAuth.cc
--- old/libzypp-15.21.5/zypp/media/MediaUserAuth.cc     2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/media/MediaUserAuth.cc     2016-04-25 
15:05:27.000000000 +0200
@@ -41,9 +41,12 @@
 
 std::ostream & AuthData::dumpOn( std::ostream & str ) const
 {
+  if (_url.isValid())
+    str << "[" << _url.asString( url::ViewOptions() - 
url::ViewOptions::WITH_USERNAME - url::ViewOptions::WITH_PASSWORD ) << "]" << 
endl;
+  else
+    str << "[<no-url>]" << endl;
   str << "username: '" << _username << "'" << std::endl
-      << "password: " << (_password.empty() ? "<empty>" : "<non-empty>")
-      << std::endl;
+      << "password: " << (_password.empty() ? "<empty>" : "<non-empty>");
   return str;
 }
 
@@ -83,8 +86,8 @@
 
 std::ostream & CurlAuthData::dumpOn( std::ostream & str ) const
 {
-  AuthData::dumpOn(str) << " auth_type: " << _auth_type_str
-    << " (" << _auth_type << ")" << std::endl;
+  AuthData::dumpOn(str) << endl
+  << " auth_type: " << _auth_type_str << " (" << _auth_type << ")";
   return str;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/parser/RepoindexFileReader.cc 
new/libzypp-15.22.0/zypp/parser/RepoindexFileReader.cc
--- old/libzypp-15.21.5/zypp/parser/RepoindexFileReader.cc      2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/parser/RepoindexFileReader.cc      2016-04-18 
15:04:47.000000000 +0200
@@ -113,7 +113,7 @@
      */
     bool consumeNode( Reader & reader_r );
 
-    DefaultIntegral<Date::Duration,2> _ttl;
+    DefaultIntegral<Date::Duration,0> _ttl;
 
   private:
     bool getAttrValue( const std::string & key_r, Reader & reader_r, 
std::string & value_r )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.5/zypp/target/rpm/RpmDb.cc 
new/libzypp-15.22.0/zypp/target/rpm/RpmDb.cc
--- old/libzypp-15.21.5/zypp/target/rpm/RpmDb.cc        2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.22.0/zypp/target/rpm/RpmDb.cc        2016-04-13 
10:24:44.000000000 +0200
@@ -1525,7 +1525,8 @@
 
   if ( res == 0 )
   {
-    detail_r.push_back( CheckPackageDetail::value_type( CHK_OK, 
std::move(vresult) ) );
+    // remove trailing NL!
+    detail_r.push_back( CheckPackageDetail::value_type( CHK_OK, str::rtrim( 
std::move(vresult) ) ) );
     return CHK_OK;
   }
 


Reply via email to