Imported Upstream version 17.10.0 upstream/17.10.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 2 Sep 2019 07:18:39 +0000 (16:18 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 2 Sep 2019 07:18:39 +0000 (16:18 +0900)
23 files changed:
VERSION.cmake
libzypp.spec.cmake
package/libzypp.changes
tests/data/TCSelectable/RepoSRC.xml [new file with mode: 0644]
tests/data/TCSelectable/solver-test.xml
tests/sat/CMakeLists.txt
tests/sat/SolvableSpec_test.cc [new file with mode: 0644]
tools/DiskUsageCounter.cc [new file with mode: 0644]
tools/argparse.h [new file with mode: 0644]
zypp/CMakeLists.txt
zypp/base/String.cc
zypp/base/String.h
zypp/sat/Pool.cc
zypp/sat/Pool.h
zypp/sat/Solvable.cc
zypp/sat/Solvable.h
zypp/sat/SolvableSpec.cc [new file with mode: 0644]
zypp/sat/SolvableSpec.h [new file with mode: 0644]
zypp/sat/SolvableType.h
zypp/sat/detail/PoolImpl.cc
zypp/sat/detail/PoolImpl.h
zypp/sat/detail/PoolMember.h
zypp/target/TargetImpl.cc

index 22966dc..557adb4 100644 (file)
@@ -60,9 +60,9 @@
 #
 SET(LIBZYPP_MAJOR "17")
 SET(LIBZYPP_COMPATMINOR "9")
-SET(LIBZYPP_MINOR "9")
+SET(LIBZYPP_MINOR "10")
 SET(LIBZYPP_PATCH "0")
 #
-# LAST RELEASED: 17.9.0 (9)
+# LAST RELEASED: 17.10.0 (9)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
index 5b0f81a..6b5d903 100644 (file)
@@ -21,7 +21,7 @@ Version:        @VERSION@
 Release:        0
 License:        GPL-2.0+
 Url:            https://github.com/openSUSE/libzypp
-Summary:        Package, Patch, Pattern, and Product Management
+Summary:        Library for package, patch, pattern and product management
 Group:          System/Packages
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 Source:         %{name}-%{version}.tar.bz2
@@ -75,7 +75,7 @@ BuildRequires:  pkgconfig
 BuildRequires:  pkg-config
 %endif
 
-BuildRequires:  libsolv-devel >= 0.6.35
+BuildRequires:  libsolv-devel >= 0.7.1
 %if 0%{?suse_version} >= 1100
 BuildRequires:  libsolv-tools
 %requires_eq    libsolv-tools
@@ -134,10 +134,24 @@ BuildRequires:  libxslt-tools
 %endif
 
 %description
-Package, Patch, Pattern, and Product Management
+libzypp is the package management library that powers applications
+like YaST, zypper and the openSUSE/SLE implementation of PackageKit.
+
+libzypp provides functionality for a package manager:
+
+  * An API for package repository management, supporting most common
+    repository metadata formats and signed repositories.
+  * An API for solving packages, products, patterns and patches
+    (installation, removal, update and distribution upgrade
+    operations) dependencies, with additional features like locking.
+  * An API for commiting the transaction to the system over a rpm
+    target. Supporting deltarpm calculation, media changing and
+    installation order calculation.
+  * An API for browsing available and installed software, with some
+    facilities for programs with an user interface.
 
 %package devel
-Summary:        Package, Patch, Pattern, and Product Management - developers files
+Summary:        Header files for libzypp, a library for package management
 Group:          Development/Libraries/C and C++
 Provides:       yast2-packagemanager-devel
 Obsoletes:      yast2-packagemanager-devel
@@ -182,14 +196,15 @@ Requires:       libsolv-devel
 %endif
 
 %description devel
-Package, Patch, Pattern, and Product Management - developers files
+Development files for libzypp, a library for package, patch, pattern
+and product management.
 
 %package devel-doc
-Summary:        Package, Patch, Pattern, and Product Management - developers files
+Summary:        Developer documentation for libzypp
 Group:          Documentation/HTML
 
 %description devel-doc
-Package, Patch, Pattern, and Product Management - developers files
+Developer documentation for libzypp.
 
 %prep
 %setup -q
@@ -197,8 +212,8 @@ Package, Patch, Pattern, and Product Management - developers files
 %build
 mkdir build
 cd build
-export CFLAGS="$RPM_OPT_FLAGS"
-export CXXFLAGS="$RPM_OPT_FLAGS"
+export CFLAGS="%{optflags}"
+export CXXFLAGS="%{optflags}"
 unset EXTRA_CMAKE_OPTIONS
 # No libproxy on SLE11
 %if 0%{?suse_version} == 1110
@@ -218,46 +233,45 @@ make -C po %{?_smp_mflags} translations
 make -C tests %{?_smp_mflags}
 
 %install
-rm -rf "$RPM_BUILD_ROOT"
 cd build
-make install DESTDIR=$RPM_BUILD_ROOT
-make -C doc/autodoc install DESTDIR=$RPM_BUILD_ROOT
+%make_install
+%make_install -C doc/autodoc
 %if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600
-ln -s %{_sysconfdir}/yum.repos.d $RPM_BUILD_ROOT%{_sysconfdir}/zypp/repos.d
+ln -s %{_sysconfdir}/yum.repos.d %{buildroot}/%{_sysconfdir}/zypp/repos.d
 %else
-mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/repos.d
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/repos.d
 %endif
-mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/services.d
-mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/systemCheck.d
-mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/vars.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/needreboot.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
-mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/commit
-mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/services
-mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/system
-mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/urlresolver
-mkdir -p $RPM_BUILD_ROOT%{_var}/lib/zypp
-mkdir -p $RPM_BUILD_ROOT%{_var}/log/zypp
-mkdir -p $RPM_BUILD_ROOT%{_var}/cache/zypp
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/services.d
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/systemCheck.d
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/vars.d
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/vendors.d
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/multiversion.d
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/needreboot.d
+mkdir -p %{buildroot}/%{_sysconfdir}/zypp/credentials.d
+mkdir -p %{buildroot}/%{_prefix}/lib/zypp
+mkdir -p %{buildroot}/%{_prefix}/lib/zypp/plugins
+mkdir -p %{buildroot}/%{_prefix}/lib/zypp/plugins/appdata
+mkdir -p %{buildroot}/%{_prefix}/lib/zypp/plugins/commit
+mkdir -p %{buildroot}/%{_prefix}/lib/zypp/plugins/services
+mkdir -p %{buildroot}/%{_prefix}/lib/zypp/plugins/system
+mkdir -p %{buildroot}/%{_prefix}/lib/zypp/plugins/urlresolver
+mkdir -p %{buildroot}/%{_var}/lib/zypp
+mkdir -p %{buildroot}/%{_var}/log/zypp
+mkdir -p %{buildroot}/%{_var}/cache/zypp
 
 # Default to 'solver.dupAllowVendorChange = false' on TW and post SLE12
 %if 0%{?suse_version} >= 1330 || "%{distribution}" == "openSUSE Tumbleweed"
 sed -i "s|# solver.dupAllowVendorChange = true|solver.dupAllowVendorChange = false|g" %{buildroot}%{_sysconfdir}/zypp/zypp.conf
 %endif
 
-make -C po install DESTDIR=$RPM_BUILD_ROOT
+%make_install -C po
 # Create filelist with translations
 cd ..
 %{find_lang} zypp
 
 %check
 pushd build/tests
-LD_LIBRARY_PATH=$RPM_BUILD_ROOT%{_libdir}:${LD_LIBRARY_PATH} ctest .
+LD_LIBRARY_PATH="%{buildroot}/%{_libdir}:$LD_LIBRARY_PATH" ctest .
 popd
 
 %post
@@ -326,9 +340,6 @@ fi
 
 %postun -p /sbin/ldconfig
 
-%clean
-rm -rf "$RPM_BUILD_ROOT"
-
 %files -f zypp.lang
 %defattr(-,root,root)
 %if 0%{?suse_version} >= 1500
index 0f4ed27..386e136 100644 (file)
@@ -1,4 +1,12 @@
 -------------------------------------------------------------------
+Mon Nov 26 12:14:49 CET 2018 - ma@suse.de
+
+- str: recognize 'always' and 'never' as valid boolean strings
+- Fix needreboot code to use SolvableSpec parser (fate#326451)
+- SolvableSpec: Define a set of Solvables by ident and provides
+- version 17.10.0 (9)
+
+-------------------------------------------------------------------
 Wed Nov 14 11:48:35 CET 2018 - ma@suse.de
 
 - Provide needreboot config files in /etc/zypp (fate#326451, fixes #140)
diff --git a/tests/data/TCSelectable/RepoSRC.xml b/tests/data/TCSelectable/RepoSRC.xml
new file mode 100644 (file)
index 0000000..dc12a6d
--- /dev/null
@@ -0,0 +1,57 @@
+<channel><subchannel>
+<srcpackage>
+       <name>candidate</name>
+       <vendor>openSUSE</vendor>
+       <history><update>
+               <arch>noarch</arch>
+               <version>0</version>
+               <release>1</release>
+       </update></history>
+</srcpackage>
+<srcpackage>
+       <name>candidate</name>
+       <vendor>openSUSE</vendor>
+       <history><update>
+               <arch>noarch</arch>
+               <version>0</version>
+               <release>1</release>
+       </update></history>
+</srcpackage>
+
+<srcpackage>
+       <name>candidatenoarch</name>
+       <vendor>openSUSE</vendor>
+       <history><update>
+               <arch>noarch</arch>
+               <version>0</version>
+               <release>2</release>
+       </update></history>
+</srcpackage>
+<srcpackage>
+       <name>candidatenoarch</name>
+       <vendor>openSUSE</vendor>
+       <history><update>
+               <arch>noarch</arch>
+               <version>0</version>
+               <release>1</release>
+       </update></history>
+</srcpackage>
+<srcpackage>
+       <name>candidatenoarch</name>
+       <vendor>openSUSE</vendor>
+       <history><update>
+               <arch>noarch</arch>
+               <version>0</version>
+               <release>1</release>
+       </update></history>
+</srcpackage>
+<srcpackage>
+       <name>candidatenoarch</name>
+       <vendor>openSUSE</vendor>
+       <history><update>
+               <arch>noarch</arch>
+               <version>0</version>
+               <release>1</release>
+       </update></history>
+</srcpackage>
+</subchannel></channel>
index 64a28d4..657a7d5 100644 (file)
        - url         : http://foo.org/distribution/LOW
        -->
        <channel file="RepoLOW.xml" name="RepoLOW" priority="99" />
+       <!--
+       - alias       : RepoLOW
+       - url         : http://foo.org/distribution/LOW
+       -->
+       <channel file="RepoSRC.xml" name="RepoSRC" priority="99" />
        <locale name="en_US" />
        <locale name="de" />
 </setup>
index 0ec7547..d7323a3 100644 (file)
@@ -9,6 +9,7 @@ ADD_TESTS(
   Queue
   Map
   Solvable
+  SolvableSpec
   SolvParsing
   WhatObsoletes
   WhatProvides
diff --git a/tests/sat/SolvableSpec_test.cc b/tests/sat/SolvableSpec_test.cc
new file mode 100644 (file)
index 0000000..2e54874
--- /dev/null
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <iostream>
+#include <boost/test/auto_unit_test.hpp>
+
+#include "zypp/sat/SolvableSpec.h"
+#include "zypp/base/Logger.h"
+#include "TestSetup.h"
+
+#define BOOST_CHECK_MODULE SolvableSpec
+
+using std::cout;
+using std::endl;
+using std::string;
+using namespace zypp;
+using namespace boost::unit_test;
+
+
+BOOST_AUTO_TEST_CASE(parsing)
+{
+  {
+    sat::SolvableSpec specs;
+    // adds no empty values
+    specs.addIdent   ( IdString() );
+    specs.addIdent   ( IdString( "" ) );
+    specs.addProvides( Capability() );
+    specs.addProvides( Capability( "" ) );
+    BOOST_CHECK( ! specs.containsIdent( IdString() ) );
+    BOOST_CHECK( ! specs.containsProvides( Capability() ) );
+    BOOST_CHECK( ! specs.containsIdent( IdString( "" ) ) );
+    BOOST_CHECK( ! specs.containsProvides( Capability( "" ) ) );
+  }
+  {
+    sat::SolvableSpec specs;
+    specs.addIdent   ( IdString( "idstr" ) );
+    specs.addProvides( Capability( "idcap" ) );
+    specs.addProvides( Capability( "idvcap=13" ) );
+    specs.addProvides( Capability( "idvwcap = 14" ) );
+    BOOST_CHECK( specs.containsIdent   ( IdString( "idstr" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idcap", "", "" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvcap", "=", "13" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvwcap", "=", "14" ) ) );
+  }
+  {
+    sat::SolvableSpec specs;
+    specs.parse( "idstr" );
+    specs.parse( "provides:idcap" );
+    specs.parse( "provides:idvcap=13" );
+    specs.parse( "provides:idvwcap = 14" );
+    BOOST_CHECK( specs.containsIdent   ( IdString( "idstr" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idcap", "", "" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvcap", "=", "13" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvwcap", "=", "14" ) ) );
+  }
+  {
+    sat::SolvableSpec specs;
+    std::stringstream str;
+    str << "# some comment" << endl;
+    str << "  # maybe indented" << endl;
+    str << "  \t   " << endl;  // white line
+    str << " idstr " << endl;
+      str << " provides:idcap  " << endl;
+    str << " provides:idvcap=13 " << endl;
+    str << " provides:idvwcap = 14 " << endl;
+    str << "" << endl;
+    specs.parseFrom( str );
+    BOOST_CHECK( specs.containsIdent   ( IdString( "idstr" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idcap", "", "" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvcap", "=", "13" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvwcap", "=", "14" ) ) );
+  }
+  {
+    sat::SolvableSpec specs;
+    specs.splitParseFrom( "idstr  provides:idcap  provides:idvcap=13  provides:idvwcap\\ =\\ 14  id\\ ws\\ str  provides:id\\ ws\\ cap\\ =\\ 99" );
+    BOOST_CHECK( specs.containsIdent   ( IdString( "idstr" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idcap", "", "" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvcap", "=", "13" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "idvwcap", "=", "14" ) ) );
+    BOOST_CHECK( specs.containsIdent   ( IdString( "id ws str" ) ) );
+    BOOST_CHECK( specs.containsProvides( Capability( "", "id ws cap", "=", "99" ) ) );
+  }
+}
+
+BOOST_AUTO_TEST_CASE(eval)
+{
+  sat::SolvableSpec specs;
+  specs.parse( "candidate" );
+  BOOST_CHECK( !specs.dirty() );       // ident don't
+  specs.parse( "provides:available_only > 1-1" );
+  BOOST_CHECK( specs.dirty() );                // deps do
+
+  TestSetup test( Arch_x86_64 );
+  test.loadTestcaseRepos( TESTS_SRC_DIR "/data/TCSelectable" );
+  std::set<sat::Solvable::IdType> matches {2,3,8,9,14,15,16,17,28};    // matching Solvable IDs in TestcaseRepo (does not match srcpackage:!)
+  for ( const auto & solv : ResPool::instance() )
+  {
+    //cout << ( specs.contains( solv ) ? "* " : "  " ) << solv << endl;
+    BOOST_CHECK_MESSAGE( specs.contains( solv ) == matches.count( solv.id() ), str::Str() << "Wrong: " << ( specs.contains( solv ) ? "* " : "  " ) << solv );
+  }
+
+  BOOST_CHECK( !specs.dirty() );       // loop built the cache
+  specs.parse( "provides:available_only > 1-1" );
+  BOOST_CHECK( !specs.dirty() );       // already have this spec, no need to set dirty
+
+  specs.parse( "provides:available_only = 1-1" );
+  BOOST_CHECK( specs.dirty() );                // This is a new one, so got dirty
+  matches.insert( 13 );
+
+  for ( const auto & solv : ResPool::instance() )
+  {
+    BOOST_CHECK_MESSAGE( specs.contains( solv ) == matches.count( solv.id() ), str::Str() << "Wrong: " << ( specs.contains( solv ) ? "* " : "  " ) << solv );
+  }
+}
diff --git a/tools/DiskUsageCounter.cc b/tools/DiskUsageCounter.cc
new file mode 100644 (file)
index 0000000..871b367
--- /dev/null
@@ -0,0 +1,54 @@
+#define INCLUDE_TESTSETUP_WITHOUT_BOOST
+#include "zypp/../tests/lib/TestSetup.h"
+#undef  INCLUDE_TESTSETUP_WITHOUT_BOOST
+#include "argparse.h"
+
+#include <iostream>
+#include <zypp/DiskUsageCounter.h>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+static std::string appname { "NO_NAME" };
+
+int errexit( const std::string & msg_r = std::string(), int exit_r = 100 )
+{
+  if ( ! msg_r.empty() )
+    cerr << endl << appname << ": ERR: " << msg_r << endl << endl;
+  return exit_r;
+}
+
+int usage( const argparse::Options & options_r, int return_r = 0 )
+{
+  cerr << "USAGE: " << appname << " [OPTION]... [ARGS]..." << endl;
+  cerr << "    Print default mountpoint set for disk usage computation." << endl;
+  cerr << options_r << endl;
+  return return_r;
+}
+
+int main( int argc, char * argv[] )
+{
+  appname = Pathname::basename( argv[0] );
+
+  std::string sysRoot { "/" };
+
+  argparse::Options options;
+  options.add()
+    ( "help,h",        "Print help and exit." )
+    ( "root",  "Use the system located below ROOTDIR.", argparse::Option::Arg::required )
+    ;
+  auto result = options.parse( argc, argv );
+
+  if ( result.count( "help" ) )
+    return usage( options );
+
+  if ( result.count( "root" ) )
+    sysRoot = result["root"].arg();
+
+  // go...
+  cout << "DiskUsageCounter: relevant mount points detected below '" << sysRoot << "':" << endl;
+  cout << DiskUsageCounter::detectMountPoints( sysRoot ) << endl;
+
+  return 0;
+}
diff --git a/tools/argparse.h b/tools/argparse.h
new file mode 100644 (file)
index 0000000..8b22073
--- /dev/null
@@ -0,0 +1,340 @@
+#ifndef ZYPP_TOOLS_ARGPARSE_H
+#define ZYPP_TOOLS_ARGPARSE_H
+
+#include <iosfwd>
+#include <string>
+#include <exception>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+//#include <regex> seems to be bad with gcc < 4.9
+#include <zypp/base/Regex.h>
+
+///////////////////////////////////////////////////////////////////
+/// Simple arg parser for tools
+/// \code
+///  argparse::Options options;
+///  options.add()
+///    ( "help,h",     "Print help and exit." )
+///    ( "root",       "Use the system located below ROOTDIR.", argparse::Option::Arg::required )
+///    ;
+///  auto result = options.parse( argc, argv );
+///
+///  if ( result.count( "root" ) )
+///    sysRoot = result["root"].arg();
+/// \endcode
+namespace argparse
+{
+  using zypp::str::regex;
+  using zypp::str::smatch;
+  using zypp::str::regex_match;
+
+  ///////////////////////////////////////////////////////////////////
+  /// Exception thrown when defining Options or parsing.
+  class OptionException : public std::exception
+  {
+  public:
+    OptionException( std::string msg_r )
+    : _msg { std::move(msg_r) }
+    {}
+
+    OptionException( std::string msg_r, const std::string & msg2_r )
+    : _msg { std::move(msg_r) }
+    { if ( ! msg2_r.empty() ) _msg += msg2_r; }
+
+    const char* what() const noexcept override
+    { return _msg.c_str(); }
+
+  private:
+    std::string _msg;
+  };
+
+  ///////////////////////////////////////////////////////////////////
+  /// Option description (TBD define arg consumer)
+  class Option
+  {
+  public:
+    enum class Arg { none, required, optional };
+
+  public:
+    Option( std::string descr_r, Arg hasarg_r  )
+    : _descr { std::move(descr_r) }
+    , _hasarg { hasarg_r }
+    {
+      if ( hasarg_r == Arg::optional )
+       throw OptionException( "Not yet implemented: Option::Arg::optional" );
+    }
+
+    const std::string & descr() const
+    { return _descr; }
+
+    Arg hasarg() const
+    { return _hasarg; }
+
+  private:
+    std::string _descr;
+    Arg         _hasarg;
+  };
+
+
+  class ParsedOptions;
+
+  ///////////////////////////////////////////////////////////////////
+  /// Map of option names -> option descriptions.
+  class Options
+  {
+    typedef std::unordered_map<std::string, std::shared_ptr<const Option>> OptionMap;
+  public:
+    Options()
+    {}
+
+  public:
+    class Injector
+    {
+    public:
+      Injector( OptionMap & optmap_r )
+      : _optmap { optmap_r }
+      {}
+
+      Injector & operator()( const std::string & names_r, std::string descr_r, Option::Arg hasarg_r = Option::Arg::none )
+      {
+       smatch result;
+       if ( regex_match( names_r, result, regex("([[:alnum:]][-_[:alnum:]]+)(,([[:alnum:]]))?") ) )
+       {
+         auto opt = std::make_shared<const Option>( std::move(descr_r), hasarg_r );
+         add( result[1], opt );
+         if ( ! result[3].empty() )
+           add( result[3], opt );
+       }
+       else
+         throw OptionException( "Illegal option names: ", names_r );
+
+       return *this;
+      }
+
+    private:
+      void add( std::string name_r, std::shared_ptr<const Option> opt_r )
+      {
+       if ( _optmap.count( name_r ) )
+         throw OptionException( "Duplicate option name: ", name_r );
+       _optmap[name_r] = opt_r;
+      }
+
+    private:
+      OptionMap & _optmap;
+    };
+
+    Injector add()
+    { return Injector( _optmap ); }
+
+  public:
+    ParsedOptions parse( int argc, char * argv[] ) const;
+
+  public:
+    std::ostream & dumpOn( std::ostream & str_r ) const
+    {
+      str_r << "OPTIONS:";
+      if ( ! _optmap.empty() )
+      {
+       std::unordered_map<std::shared_ptr<const Option>, std::string> unify;
+       for ( const auto & p : _optmap )
+       {
+         std::string & t { unify[p.second] };
+         if ( t.empty() )
+           t = (p.first.length()>1?"--":"-")+p.first;
+         else if ( p.first.length() > 1 )
+           t = "--"+p.first+", "+t;
+         else
+           t = t+", -"+p.first;
+       }
+
+       boost::format fmt( "\n    %1% %|30t|%2%" );
+       for ( const auto & p : unify )
+       {
+         fmt % p.second % p.first->descr();
+         str_r << fmt.str();
+       }
+      }
+      else
+      {
+       str_r << "    This command accepts no options.";
+      }
+      return str_r;
+    }
+
+  private:
+    OptionMap _optmap;
+  };
+
+  inline std::ostream & operator<<( std::ostream & str_r, const Options & obj_r )
+  { return obj_r.dumpOn( str_r ); }
+
+  ///////////////////////////////////////////////////////////////////
+  /// Parsed option incl. option args value (by now just stores the string)
+  class OptionValue
+  {
+  public:
+    OptionValue( std::shared_ptr<const Option> opt_r )
+    : _opt { opt_r }
+    {}
+
+    OptionValue( std::shared_ptr<const Option> opt_r, std::string arg_r )
+    : _opt { opt_r }
+    , _arg { std::make_shared<std::string>( std::move(arg_r) ) }
+    {}
+
+    const std::string & arg() const
+    {
+      if ( ! _arg )
+       throw std::domain_error( "No arg value" );
+
+      return *_arg;
+    }
+
+  private:
+    std::shared_ptr<const Option> _opt;
+    std::shared_ptr<std::string> _arg;
+  };
+
+  ///////////////////////////////////////////////////////////////////
+  /// Parsed options and positional args
+  class ParsedOptions
+  {
+    typedef std::unordered_map<std::string, std::shared_ptr<const Option>> OptionMap;
+    typedef std::unordered_map<std::shared_ptr<const Option>, OptionValue> ResultMap;
+  public:
+    ParsedOptions( const OptionMap & optmap_r, int argc, char * argv[] )
+    : _optmap { optmap_r }
+    { parse( argc, argv ); }
+
+  public:
+    size_t count( const std::string & optname_r ) const
+    {
+      auto iter = _optmap.find( optname_r );
+      if ( iter == _optmap.end() )
+       return 0;
+
+      auto resiter = _options.find( iter->second );
+      return( resiter == _options.end() ? 0 : 1 );
+    }
+
+    const OptionValue & operator[]( const std::string & optname_r ) const
+    {
+      return requireOptValByName( optname_r );
+    }
+
+    const std::vector<std::string> & positionals() const
+    { return _positionals; }
+
+  private:
+    void parse( int argc, char * argv[] )
+    {
+      bool collectpositional = false;
+      for ( --argc,++argv; argc; --argc,++argv )
+      {
+       if ( (*argv)[0] == '-' && !collectpositional )
+       {
+         if ( (*argv)[1] == '-' )
+         {
+           if ( (*argv)[2] == '\0' )
+           {
+             // -- rest are positional...
+             collectpositional = true;
+           }
+           else
+           {
+             // --longopt
+             parseoptl( (*argv)+2, argc, argv );
+           }
+         }
+         else
+         {
+           // -s(hortopt)
+           parseopts( (*argv)+1, argc, argv );
+         }
+       }
+       else
+       {
+         // positional
+         _positionals.push_back( *argv );
+       }
+      }
+    }
+
+  private:
+    std::string dashed( std::string name_r ) const
+    { return name_r.insert( 0, name_r.size()>1?"--":"-" ); }
+
+    void parseoptl( const std::string & name_r, int & argc, char **& argv )
+    {
+      if ( name_r.length() < 2 )
+       throw OptionException( "Illegal long opt: --", name_r );
+
+      parseopt( name_r, argc, argv );
+    }
+
+    void parseopts( const std::string & name_r, int & argc, char **& argv )
+    {
+     if ( name_r.length() != 1 )
+       throw OptionException( "Illegal short opt: -", name_r );
+
+     parseopt( name_r, argc, argv );
+    }
+
+    void parseopt( const std::string & name_r, int & argc, char **& argv )
+    {
+      auto opt = requireOptByName( name_r );
+
+      auto iter = _options.find( opt );
+      if ( iter != _options.end() )
+       throw OptionException( "Multiple occurrences of option: ", dashed( name_r ) );
+
+      if ( opt->hasarg() != Option::Arg::none )
+      {
+       if ( opt->hasarg() == Option::Arg::optional )
+         throw OptionException( "Not yet implemented: Option::Arg::optional" ); // i.e. '--opt=arg'
+
+       if ( argc < 2 )
+         throw OptionException( "Missing argument for option: ", dashed( name_r ) );
+
+       --argc,++argv;
+       moveToResult( opt, OptionValue( opt, *argv ) );
+      }
+      else
+       moveToResult( opt, OptionValue( opt ) );
+    }
+
+    void moveToResult( std::shared_ptr<const Option> opt_r, OptionValue && value_r )
+    { _options.insert( std::make_pair( opt_r, std::move(value_r) ) ); }
+
+    std::shared_ptr<const Option> requireOptByName( const std::string & name_r ) const
+    {
+      auto iter = _optmap.find( name_r );
+      if ( iter == _optmap.end() )
+       throw OptionException( "Unknown option: ", dashed( name_r ) );
+      return iter->second;
+    }
+
+    const OptionValue & requireOptValByName( const std::string & name_r ) const
+    {
+      auto iter = _options.find( requireOptByName( name_r ) );
+      if ( iter == _options.end() )
+       throw OptionException( "Option not present: ", dashed( name_r ) );
+      return iter->second;
+    }
+
+  private:
+    const OptionMap &          _optmap;
+    ResultMap                  _options;
+    std::vector<std::string>   _positionals;
+  };
+
+  inline ParsedOptions Options::parse( int argc, char * argv[] ) const
+  { return ParsedOptions( _optmap, argc, argv ); }
+
+
+
+} // namespace argparse
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_TOOLS_ARGPARSE_H
index dd81eaf..414af29 100644 (file)
@@ -534,6 +534,7 @@ SET( zypp_sat_SRCS
   sat/Pool.cc
   sat/Solvable.cc
   sat/SolvableSet.cc
+  sat/SolvableSpec.cc
   sat/SolvIterMixin.cc
   sat/Map.cc
   sat/Queue.cc
@@ -551,6 +552,7 @@ SET( zypp_sat_HEADERS
   sat/Solvable.h
   sat/SolvableSet.h
   sat/SolvableType.h
+  sat/SolvableSpec.h
   sat/SolvIterMixin.h
   sat/Map.h
   sat/Queue.h
index c5fa4b8..1d9b6da 100644 (file)
@@ -66,6 +66,7 @@ namespace zypp
       return(    t == "1"
               || t == "yes"
               || t == "true"
+              || t == "always"
               || t == "on"
               || t == "+"
               || strtonum<long long>( str )
@@ -83,6 +84,7 @@ namespace zypp
       return ! (    t == "0"
                  || t == "no"
                  || t == "false"
+                 || t == "never"
                  || t == "off"
                  || t == "-"
                );
index 40b6413..27c4536 100644 (file)
@@ -415,10 +415,10 @@ namespace zypp
     /** Parsing boolean from string.
     */
     //@{
-    /** Return \c true if str is <tt>1, true, yes, on</tt> (or a nonzero number). */
+    /** Return \c true if str is <tt>1, true, yes, on, always</tt> (or a nonzero number). */
     bool strToTrue( const C_Str & str );
 
-    /** Return \c false if str is <tt>0, false, no, off</tt>. */
+    /** Return \c false if str is <tt>0, false, no, off, never</tt>. */
     bool strToFalse( const C_Str & str );
 
     /** Parse \c str into a bool depending on the default value.
index a073577..a94c90a 100644 (file)
@@ -243,8 +243,7 @@ namespace zypp
     Queue Pool::autoInstalled() const                          { return myPool().autoInstalled(); }
     void Pool::setAutoInstalled( const Queue & autoInstalled_r ){ myPool().setAutoInstalled( autoInstalled_r ); }
 
-    Queue Pool::rebootNeededIdents() const                             { return myPool().rebootNeededIdents(); }
-    void Pool::setRebootNeededIdents( const Queue & rebootNeeded_r ){ myPool().setRebootNeededIdents( rebootNeeded_r ); }
+    void Pool::setNeedrebootSpec( sat::SolvableSpec needrebootSpec_r ) { myPool().setNeedrebootSpec( std::move(needrebootSpec_r) ); }
 
    /******************************************************************
     **
index e143348..6701493 100644 (file)
@@ -33,6 +33,8 @@ namespace zypp
   namespace sat
   { /////////////////////////////////////////////////////////////////
 
+    class SolvableSpec;
+
     ///////////////////////////////////////////////////////////////////
     //
     // CLASS NAME : Pool
@@ -265,11 +267,12 @@ namespace zypp
        void setAutoInstalled( const Queue & autoInstalled_r );
         //@}
 
-        /** Get ident list of all solvables that trigger the "reboot needed" flag. */
-        Queue rebootNeededIdents() const;
-
-       /** Set ident list of all solvables that trigger the "reboot needed" flag. */
-       void setRebootNeededIdents( const Queue & rebootNeeded_r );
+      public:
+        /** \name Needreboot */
+        //@{
+        /** Solvables which should trigger the reboot-needed hint if installed/updated. */
+        void setNeedrebootSpec( sat::SolvableSpec needrebootSpec_r );
+        //@}
 
       public:
         /** Expert backdoor. */
index 924a065..42b274a 100644 (file)
@@ -387,9 +387,10 @@ namespace zypp
       return myPool().isOnSystemByAuto( ident_r );
     }
 
-    bool Solvable::identTriggersRebootNeededHint ( const IdString &ident_r )
+    bool Solvable::isNeedreboot() const
     {
-      return myPool().triggersRebootNeededHint( ident_r );
+      NO_SOLVABLE_RETURN( false );
+      return myPool().isNeedreboot( *this );
     }
 
     bool Solvable::multiversionInstall() const
index 38db264..5b6ec7f 100644 (file)
@@ -136,10 +136,8 @@ namespace zypp
       /** \overload static version */
       static bool identIsAutoInstalled( const IdString & ident_r );
 
-      /** Whether installing or upgrading a solvable with the same \ref ident will trigger the reboot needed hint. */
-      bool identTriggersRebootNeededHint() const
-      { return identTriggersRebootNeededHint( ident() ); }
-      static bool identTriggersRebootNeededHint ( const IdString &ident_r );
+      /** Whether this solvable triggers the reboot-needed hint if installed/updated. */
+      bool isNeedreboot() const;
 
       /** Whether different versions of this package can be installed at the same time.
        * Per default \c false. \see also \ref ZConfig::multiversion.
diff --git a/zypp/sat/SolvableSpec.cc b/zypp/sat/SolvableSpec.cc
new file mode 100644 (file)
index 0000000..6f423d6
--- /dev/null
@@ -0,0 +1,167 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/sat/SolvableSpec.cc
+ */
+#include <iostream>
+
+#include "zypp/base/LogTools.h"
+#include "zypp/base/IOStream.h"
+
+#include "zypp/sat/SolvableSpec.h"
+#include "zypp/sat/WhatProvides.h"
+
+using std::endl;
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  namespace sat
+  {
+    ///////////////////////////////////////////////////////////////////
+    /// \class SolvableSpec::Impl
+    /// \brief SolvableSpec implementation.
+    ///////////////////////////////////////////////////////////////////
+    class SolvableSpec::Impl
+    {
+    public:
+      void addIdent( IdString ident_r )
+      {
+       if ( ! ident_r.empty() )
+         _idents.insert( ident_r );
+      }
+
+      void addProvides( Capability provides_r )
+      {
+       if ( ! provides_r.empty() && _provides.insert( provides_r ).second )
+         setDirty();
+      }
+
+
+      void parse( const C_Str & spec_r )
+      {
+       if ( str::hasPrefix( spec_r, "provides:" ) )
+         addProvides( Capability(spec_r.c_str()+9) );
+       else
+         addIdent( IdString(spec_r) );
+      }
+
+
+      bool needed() const
+      { return !_provides.empty(); }
+
+      bool dirty() const
+      { return needed() && !_cache; }
+
+      void setDirty() const
+      { _cache.reset(); }
+
+      const WhatProvides & cache() const
+      {
+       if ( !_cache )
+       {
+         _cache.reset( new WhatProvides( _provides ) );
+       }
+       return *_cache;
+      }
+
+      bool contains( const sat::Solvable & solv_r ) const
+      { return( _idents.count( solv_r.ident() ) || ( needed() && cache().contains( solv_r ) ) ); }
+
+
+      const IdStringSet & idents() const
+      { return _idents; }
+
+      const CapabilitySet & provides() const
+      { return _provides; }
+
+    private:
+      IdStringSet  _idents;
+      CapabilitySet _provides;
+
+      mutable shared_ptr<WhatProvides> _cache;
+
+    private:
+      friend Impl * rwcowClone<Impl>( const Impl * rhs );
+      /** clone for RWCOW_pointer */
+      Impl * clone() const
+      { return new Impl( *this ); }
+    };
+
+    /** \relates SolvableSpec::Impl Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const SolvableSpec::Impl & obj )
+    {
+      str << "SolvableSpec {" << endl
+          << " Idents " << obj.idents() << endl
+          << " Provides " << obj.provides() << endl
+          << "}";
+      return str;
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : SolvableSpec
+    //
+    ///////////////////////////////////////////////////////////////////
+
+    SolvableSpec::SolvableSpec()
+      : _pimpl( new Impl )
+    {}
+
+    SolvableSpec::~SolvableSpec()
+    {}
+
+    void SolvableSpec::addIdent( IdString ident_r )
+    { _pimpl->addIdent( ident_r ); }
+
+    void SolvableSpec::addProvides( Capability provides_r )
+    { _pimpl->addProvides( provides_r ); }
+
+    void SolvableSpec::parse( const C_Str & spec_r )
+    { _pimpl->parse( spec_r ); }
+
+    void SolvableSpec::parseFrom( const InputStream & istr_r )
+    {
+      iostr::simpleParseFile( istr_r,
+                             [this]( int num_r, const std::string & line_r )->bool
+                             {
+                               this->parse( line_r );
+                               return true;
+                             });
+    }
+
+    void SolvableSpec::splitParseFrom( const C_Str & multispec_r )
+    {
+      std::vector<std::string> v;
+      str::splitEscaped( multispec_r, std::back_inserter( v ), ", \t" );
+      parseFrom( v.begin(), v.end() );
+    }
+
+    bool SolvableSpec::contains( const sat::Solvable & solv_r ) const
+    { return _pimpl->contains( solv_r ) && !solv_r.isKind( ResKind::srcpackage ); }
+
+    bool SolvableSpec::dirty() const
+    { return _pimpl->dirty(); }
+
+    void SolvableSpec::setDirty() const
+    { _pimpl->setDirty(); }
+
+    bool SolvableSpec::containsIdent( const IdString & ident_r ) const
+    { return _pimpl->idents().count( ident_r ); }
+
+    bool SolvableSpec::containsProvides( const Capability & provides_r ) const
+    { return _pimpl->provides().count( provides_r ); }
+
+    std::ostream & operator<<( std::ostream & str, const SolvableSpec & obj )
+    { return str << *obj._pimpl; }
+
+  } // namespace sat
+  ///////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
diff --git a/zypp/sat/SolvableSpec.h b/zypp/sat/SolvableSpec.h
new file mode 100644 (file)
index 0000000..9cf6c3b
--- /dev/null
@@ -0,0 +1,118 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/sat/SolvableSpec.h
+ */
+#ifndef ZYPP_SAT_SOLVABLESPEC_H
+#define ZYPP_SAT_SOLVABLESPEC_H
+
+#include <iosfwd>
+
+#include "zypp/APIConfig.h"
+#include "zypp/base/PtrTypes.h"
+#include "zypp/base/InputStream.h"
+#include "zypp/base/String.h"
+
+#include "zypp/sat/SolvableType.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  namespace sat
+  {
+    ///////////////////////////////////////////////////////////////////
+    /// \class SolvableSpec
+    /// \brief Define a set of \ref Solvables by ident and provides.
+    ///
+    /// Able to keep the definition of solvable sets like in 'needreboot'
+    /// or 'multiversion'. The associated file parser allows reading
+    /// stored definitions (one `IDENT` or provides:CAPABILITY` per line;
+    /// empty lines and lines starting with '#' are ignored).
+    ///
+    /// The use of provides requires re-computation of the solvable set,
+    /// whenever the solvable pool changes. This computation via \ref WhatProvides
+    /// is expensive, that's why a built in cache is also offered.
+    ///
+    /// \note \ref contains does not match srcpackage: per default.
+    ///////////////////////////////////////////////////////////////////
+    class SolvableSpec
+    {
+    public:
+      /** Default ctor */
+      SolvableSpec();
+
+      /** Dtor */
+      ~SolvableSpec();
+
+    public:
+      /** Add all \ref sat::Solvable with this \a ident_r */
+      void addIdent( IdString ident_r );
+
+      /** A all \ref sat::Solvable matching this \a provides_r. */
+      void addProvides( Capability provides_r );
+
+    public:
+      /** Parse and add spec from a string (`IDENT` or provides:CAPABILITY`). */
+      void parse( const C_Str & spec_r );
+
+      /** Parse file \a istr_r and add it's specs (one per line, #-comments). */
+      void parseFrom( const InputStream & istr_r );
+
+      /** Parse and add specs from iterator range. */
+      template <class TIterator>
+      void parseFrom( TIterator begin, TIterator end )
+      { for_( it, begin, end ) parse( *it ); }
+
+      /** Convenience using \ref str::splitEscaped(", \t") to parse multiple specs from one line. */
+      void splitParseFrom( const C_Str & multispec_r );
+
+    public:
+      /** Test whether \a solv_r matches the spec.
+       * (Re-)builds the \ref WhatProvides cache on demand.
+       *
+       * \note Does not match srcpackage: per default.
+       */
+      bool contains( const sat::Solvable & solv_r ) const;
+      /** \overload */
+      template <class Derived>
+      bool contains( const SolvableType<Derived> & solv_r ) const
+      { return contains( solv_r.satSolvable() ); }
+
+      /** Whether the cache is needed and dirty. */
+      bool dirty() const;
+
+      /** Explicitly flag the cache as dirty, so it will be rebuilt on the next request.
+       * To be called if the \ref ResPool content has changed. Intentionally `const` as
+       * this does not change the set of spects (though the set of matches might change).
+       * \note This has no effect if no cache is needed (i.e. no provides: are used).
+       */
+      void setDirty() const;
+
+    public:
+      /** Whether \a ident_r has been added to the specs (mainly for parser tests). */
+      bool containsIdent( const IdString & ident_r ) const;
+
+      /** Whether \a provides_r has been added to the sepcs (mainly for parser tests).*/
+      bool containsProvides( const Capability & provides_r ) const;
+
+    public:
+      class Impl;                 ///< Implementation class.
+    private:
+      RWCOW_pointer<Impl> _pimpl; ///< Pointer to implementation.
+      friend std::ostream & operator<<( std::ostream & str, const SolvableSpec & obj );
+    };
+
+    /** \relates SolvableSpec Stream output */
+    std::ostream & operator<<( std::ostream & str, const SolvableSpec & obj );
+
+  } // namespace sat
+  ///////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_SAT_SOLVABLESPEC_H
index 65f4d36..55db076 100644 (file)
@@ -80,7 +80,7 @@ namespace zypp
       bool             onSystemByAuto() const                  { return satSolvable().onSystemByAuto(); }
       bool             identIsAutoInstalled() const            { return satSolvable().identIsAutoInstalled(); }
       bool             multiversionInstall() const             { return satSolvable().multiversionInstall(); }
-      bool              identTriggersRebootNeededHint() const   { return satSolvable().identTriggersRebootNeededHint(); }
+      bool              isNeedreboot() const                   { return satSolvable().isNeedreboot(); }
 
       Date             buildtime() const                       { return satSolvable().buildtime(); }
       Date             installtime() const                     { return satSolvable().installtime(); }
index a5d042d..38ec751 100644 (file)
@@ -236,6 +236,7 @@ namespace zypp
         _serial.setDirty();           // pool content change
         _availableLocalesPtr.reset(); // available locales may change
         _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec.
+       _needrebootSpec.setDirty();   // re-evaluate needrebootSpec
 
         depSetDirty(); // invaldate dependency/namespace related indices
       }
index 3350147..89724ad 100644 (file)
@@ -26,6 +26,7 @@ extern "C"
 #include "zypp/base/SerialNumber.h"
 #include "zypp/base/SetTracker.h"
 #include "zypp/sat/detail/PoolMember.h"
+#include "zypp/sat/SolvableSpec.h"
 #include "zypp/sat/Queue.h"
 #include "zypp/RepoInfo.h"
 #include "zypp/Locale.h"
@@ -306,18 +307,21 @@ namespace zypp
 
           bool isOnSystemByAuto( IdString ident_r ) const
           { return _autoinstalled.contains( ident_r.id() ); }
+          //@}
 
-          /** Get ident list of all solvables that trigger the "reboot needed" flag. */
-         StringQueue rebootNeededIdents() const
-         { return _rebootNeeded; }
-
-         /** Set ident list of all solvables that trigger the "reboot needed" flag. */
-         void setRebootNeededIdents( const StringQueue & rebootNeeded_r )
-         { _rebootNeeded = rebootNeeded_r; }
-
-         bool triggersRebootNeededHint( IdString ident_r ) const
-          { return _rebootNeeded.contains( ident_r.id() ); }
+       public:
+         /** \name Solvables which should trigger the reboot-needed hint if installed/updated. */
+          //@{
+          /** Set new Solvable specs.*/
+          void setNeedrebootSpec( sat::SolvableSpec needrebootSpec_r )
+         {
+           _needrebootSpec = std::move(needrebootSpec_r);
+           _needrebootSpec.setDirty();
+         }
 
+         /** Whether \a solv_r matches the spec.*/
+         bool isNeedreboot( const Solvable & solv_r ) const
+         { return _needrebootSpec.contains( solv_r ); }
           //@}
 
        public:
@@ -349,8 +353,8 @@ namespace zypp
           /**  */
          sat::StringQueue _autoinstalled;
 
-         /** database of all identifiers that will trigger the "reboot needed" flag */
-         sat::StringQueue _rebootNeeded;
+         /** Solvables which should trigger the reboot-needed hint if installed/updated. */
+         sat::SolvableSpec _needrebootSpec;
 
          /** filesystems mentioned in /etc/sysconfig/storage */
          mutable scoped_ptr<std::set<std::string> > _requiredFilesystemsPtr;
index ecb28a9..52ab226 100644 (file)
@@ -12,8 +12,6 @@
 #ifndef ZYPP_SAT_DETAIL_POOLMEMBER_H
 #define ZYPP_SAT_DETAIL_POOLMEMBER_H
 
-#include <solv/solvversion.h>
-
 #include "zypp/base/Hash.h"
 #include "zypp/base/Iterator.h"
 #include "zypp/base/String.h"
@@ -21,8 +19,7 @@
 
 extern "C"
 {
-  // Those _Type names are exposed as sat::detail::CType below!
-#if ( LIBSOLV_VERSION >= 700 )
+  // Those s_Type names are exposed as sat::detail::CType below!
   struct s_Dataiterator;
   struct s_Datamatcher;
   struct s_Map;
@@ -32,17 +29,6 @@ extern "C"
   struct s_Solvable;
   struct s_Solver;
   struct s_Transaction;
-#else
-  struct _Dataiterator;
-  struct _Datamatcher;
-  struct _Map;
-  struct _Pool;
-  struct _Queue;
-  struct _Repo;
-  struct _Solvable;
-  struct _Solver;
-  struct _Transaction;
-#endif
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -69,7 +55,6 @@ namespace zypp
     ///////////////////////////////////////////////////////////////////
     namespace detail
     {
-#if ( LIBSOLV_VERSION >= 700 )
       typedef ::s_Dataiterator CDataiterator;  ///< Wrapped libsolv C data type exposed as backdoor
       typedef ::s_Datamatcher  CDatamatcher;   ///< Wrapped libsolv C data type exposed as backdoor
       typedef ::s_Map          CMap;           ///< Wrapped libsolv C data type exposed as backdoor
@@ -79,17 +64,6 @@ namespace zypp
       typedef ::s_Solvable     CSolvable;      ///< Wrapped libsolv C data type exposed as backdoor
       typedef ::s_Solver       CSolver;        ///< Wrapped libsolv C data type exposed as backdoor
       typedef ::s_Transaction  CTransaction;   ///< Wrapped libsolv C data type exposed as backdoor
-#else
-      typedef ::_Dataiterator  CDataiterator;  ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Datamatcher   CDatamatcher;   ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Map           CMap;           ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Pool          CPool;          ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Queue         CQueue;         ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Repo          CRepo;          ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Solvable      CSolvable;      ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Solver                CSolver;        ///< Wrapped libsolv C data type exposed as backdoor
-      typedef ::_Transaction   CTransaction;   ///< Wrapped libsolv C data type exposed as backdoor
-#endif
     } // namespace detail
     ///////////////////////////////////////////////////////////////////
 
index ec5cd7b..605c9cb 100644 (file)
@@ -54,6 +54,7 @@
 
 #include "zypp/sat/Pool.h"
 #include "zypp/sat/detail/PoolImpl.h"
+#include "zypp/sat/SolvableSpec.h"
 #include "zypp/sat/Transaction.h"
 
 #include "zypp/PluginExecutor.h"
@@ -1074,53 +1075,34 @@ namespace zypp
        satpool.setAutoInstalled( q );
       }
 
-      //load the packages that will trigger the update flag being set
+      // Load the needreboot package specs
       {
-        sat::StringQueue q;
-        filesystem::Pathname needRebootFile { Pathname::assertprefix( root(), ZConfig::instance().needrebootFile() ) };
-        if ( filesystem::PathInfo ( needRebootFile ).isExist() ) {
-          SolvIdentFile file ( needRebootFile );
-          for ( const auto & idstr : file.data() ) {
-            q.push( idstr.id() );
-          }
-#if 1
-#warning Hotfix: temp workaround missing SolvableSpec Parser
-         // Also consider excluding .rpmnew/.rpmsave/.rpmorig files in needreboot.d
-          q.push( IdString("kernel-azure").id() );
-         q.push( IdString("kernel-azure-base").id() );
-         q.push( IdString("kernel-debug").id() );
-         q.push( IdString("kernel-debug-base").id() );
-         q.push( IdString("kernel-default").id() );
-         q.push( IdString("kernel-default-base").id() );
-         q.push( IdString("kernel-kvmsmall").id() );
-         q.push( IdString("kernel-kvmsmall-base").id() );
-         q.push( IdString("kernel-rt").id() );
-         q.push( IdString("kernel-rt-base").id() );
-         q.push( IdString("kernel-rt_debug").id() );
-         q.push( IdString("kernel-rt_debug-base").id() );
-         q.push( IdString("kernel-vanilla").id() );
-         q.push( IdString("kernel-vanilla-base").id() );
-#endif
-       }
-
-        filesystem::Pathname needRebootDir { Pathname::assertprefix( root(), ZConfig::instance().needrebootPath() ) };
-        if ( filesystem::PathInfo ( needRebootDir ).isExist() ) {
-          filesystem::DirContent ls;
-          filesystem::readdir( ls, needRebootDir, false );
+       sat::SolvableSpec needrebootSpec;
 
-          for ( const filesystem::DirEntry &entry : ls ) {
-
-            if ( entry.type != filesystem::FT_FILE )
-              continue;
+       Pathname needrebootFile { Pathname::assertprefix( root(), ZConfig::instance().needrebootFile() ) };
+       if ( PathInfo( needrebootFile ).isFile() )
+         needrebootSpec.parseFrom( needrebootFile );
 
-            SolvIdentFile file ( needRebootDir / entry.name );
-            for ( const auto & idstr : file.data() ) {
-              q.push( idstr.id() );
-            }
-          }
-        }
+       Pathname needrebootDir { Pathname::assertprefix( root(), ZConfig::instance().needrebootPath() ) };
+        if ( PathInfo( needrebootDir ).isDir() )
+       {
+         static const StrMatcher isRpmConfigBackup( "\\.rpm(new|save|orig)$", Match::REGEX );
+
+         filesystem::dirForEach( needrebootDir, filesystem::matchNoDots(),
+                                 [&]( const Pathname & dir_r, const char *const str_r )->bool
+                                 {
+                                   if ( ! isRpmConfigBackup( str_r ) )
+                                   {
+                                     Pathname needrebootFile { needrebootDir / str_r };
+                                     if ( PathInfo( needrebootFile ).isFile() )
+                                       needrebootSpec.parseFrom( needrebootFile );
+                                   }
+                                   return true;
+                                 });
+       }
 
-        satpool.setRebootNeededIdents( q );
+        INT << "Needreboot " << needrebootSpec << endl;
+        satpool.setNeedrebootSpec( std::move(needrebootSpec) );
       }
 
       if ( ZConfig::instance().apply_locks_file() )
@@ -1519,7 +1501,7 @@ namespace zypp
               }
               else
               {
-                if ( citem.identTriggersRebootNeededHint() ) {
+                if ( citem.isNeedreboot() ) {
                   auto rebootNeededFile = root() / "/var/run/reboot-needed";
                   if ( filesystem::assert_file( rebootNeededFile ) == EEXIST)
                     filesystem::touch( rebootNeededFile );