Hello community,

here is the log from the commit of package yast2-services-manager for 
openSUSE:Factory checked in at 2017-10-19 19:30:56
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yast2-services-manager (Old)
 and      /work/SRC/openSUSE:Factory/.yast2-services-manager.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "yast2-services-manager"

Thu Oct 19 19:30:56 2017 rev:37 rq:534341 version:4.0.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/yast2-services-manager/yast2-services-manager.changes
    2017-08-04 11:57:37.534486046 +0200
+++ 
/work/SRC/openSUSE:Factory/.yast2-services-manager.new/yast2-services-manager.changes
       2017-10-19 19:30:57.704175168 +0200
@@ -1,0 +2,12 @@
+Mon Oct 16 12:22:31 UTC 2017 - [email protected]
+
+- respect target level specified in control file (bsc#1063216)
+- 4.0.1
+
+-------------------------------------------------------------------
+Wed Aug 30 14:12:29 UTC 2017 - [email protected]
+
+- Use fewer calls of systemctl to speed up startup (bsc#1045658)
+- 4.0.0
+
+-------------------------------------------------------------------
@@ -13,0 +26,6 @@
+
+-------------------------------------------------------------------
+Tue Feb 14 14:25:04 CET 2017 - [email protected]
+
+- Added lib/services-manager/clients/*.rb to spec file
+  (FATE#321738).

Old:
----
  yast2-services-manager-3.3.1.tar.bz2

New:
----
  yast2-services-manager-4.0.1.tar.bz2

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

Other differences:
------------------
++++++ yast2-services-manager.spec ++++++
--- /var/tmp/diff_new_pack.9V2gYj/_old  2017-10-19 19:30:58.252149528 +0200
+++ /var/tmp/diff_new_pack.9V2gYj/_new  2017-10-19 19:30:58.256149340 +0200
@@ -24,7 +24,7 @@
 ######################################################################
 
 Name:           yast2-services-manager
-Version:        3.3.1
+Version:        4.0.1
 Release:        0
 BuildArch:      noarch
 
@@ -33,7 +33,7 @@
 
 Requires:       ruby
 # ServicesManager library
-Requires:       yast2 >= 3.1.86
+Requires:       yast2 >= 4.0.5
 Requires:       yast2-ruby-bindings >= 1.2.0
 # need new enough installation for its inst clients
 Conflicts:      yast2-installation < 3.1.32
@@ -45,7 +45,7 @@
 BuildRequires:  update-desktop-files
 BuildRequires:  yast2-ruby-bindings >= 1.2.0
 # ServicesManager library
-BuildRequires:  yast2 >= 3.1.86
+BuildRequires:  yast2 >= 4.0.5
 # Support for 'data' directory in rake install task
 BuildRequires:  rubygem(rspec)
 BuildRequires:  rubygem(yast-rake) >= 0.1.7

++++++ yast2-services-manager-3.3.1.tar.bz2 -> 
yast2-services-manager-4.0.1.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-services-manager-3.3.1/.travis.yml 
new/yast2-services-manager-4.0.1/.travis.yml
--- old/yast2-services-manager-3.3.1/.travis.yml        2017-08-02 
16:54:45.593985485 +0200
+++ new/yast2-services-manager-4.0.1/.travis.yml        2017-10-17 
09:15:42.757629420 +0200
@@ -5,6 +5,9 @@
 
 before_install:
   - docker build -t yast-services-manager-image .
+  # list the installed packages (just for easier debugging)
+  - docker run --rm -it yast-services-manager-image rpm -qa | sort
+
 script:
   # the "yast-travis-ruby" script is included in the base yastdevel/ruby image
   # see https://github.com/yast/docker-yast-ruby/blob/master/yast-travis-ruby
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-services-manager-3.3.1/README.md 
new/yast2-services-manager-4.0.1/README.md
--- old/yast2-services-manager-3.3.1/README.md  2017-08-02 16:54:45.593985485 
+0200
+++ new/yast2-services-manager-4.0.1/README.md  2017-10-17 09:15:42.757629420 
+0200
@@ -2,6 +2,7 @@
 
 [![Travis 
Build](https://travis-ci.org/yast/yast-services-manager.svg?branch=master)](https://travis-ci.org/yast/yast-services-manager)
 [![Jenkins 
Build](http://img.shields.io/jenkins/s/https/ci.opensuse.org/yast-services-manager-master.svg)](https://ci.opensuse.org/view/Yast/job/yast-services-manager-master/)
+[![Coverage 
Status](https://coveralls.io/repos/github/yast/yast-services-manager/badge.svg?branch=master)](https://coveralls.io/github/yast/yast-services-manager?branch=master)
 
 
 Systemd target and services configuration library for Yast
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/package/yast2-services-manager.changes 
new/yast2-services-manager-4.0.1/package/yast2-services-manager.changes
--- old/yast2-services-manager-3.3.1/package/yast2-services-manager.changes     
2017-08-02 16:54:45.593985485 +0200
+++ new/yast2-services-manager-4.0.1/package/yast2-services-manager.changes     
2017-10-17 09:15:42.757629420 +0200
@@ -1,4 +1,16 @@
 -------------------------------------------------------------------
+Mon Oct 16 12:22:31 UTC 2017 - [email protected]
+
+- respect target level specified in control file (bsc#1063216)
+- 4.0.1
+
+-------------------------------------------------------------------
+Wed Aug 30 14:12:29 UTC 2017 - [email protected]
+
+- Use fewer calls of systemctl to speed up startup (bsc#1045658)
+- 4.0.0
+
+-------------------------------------------------------------------
 Wed Aug  2 14:22:08 UTC 2017 - [email protected]
 
 - Optimize services manager output for ncurses on 80x24
@@ -13,6 +25,12 @@
 - 3.3.0
 
 -------------------------------------------------------------------
+Tue Feb 14 14:25:04 CET 2017 - [email protected]
+
+- Added lib/services-manager/clients/*.rb to spec file
+  (FATE#321738).
+
+-------------------------------------------------------------------
 Mon Feb 13 14:34:34 CET 2017 - [email protected]
 
 - AutoYaST: "Write" can be called in first and second installation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/package/yast2-services-manager.spec 
new/yast2-services-manager-4.0.1/package/yast2-services-manager.spec
--- old/yast2-services-manager-3.3.1/package/yast2-services-manager.spec        
2017-08-02 16:54:45.593985485 +0200
+++ new/yast2-services-manager-4.0.1/package/yast2-services-manager.spec        
2017-10-17 09:15:42.761629420 +0200
@@ -24,7 +24,7 @@
 ######################################################################
 
 Name:           yast2-services-manager
-Version:        3.3.1
+Version:        4.0.1
 Release:        0
 BuildArch:      noarch
 
@@ -33,7 +33,7 @@
 
 Requires:       ruby
 # ServicesManager library
-Requires:       yast2 >= 3.1.86
+Requires:       yast2 >= 4.0.5
 Requires:       yast2-ruby-bindings >= 1.2.0
 # need new enough installation for its inst clients
 Conflicts:      yast2-installation < 3.1.32
@@ -45,7 +45,7 @@
 BuildRequires:  update-desktop-files
 BuildRequires:  yast2-ruby-bindings >= 1.2.0
 # ServicesManager library
-BuildRequires:  yast2 >= 3.1.86
+BuildRequires:  yast2 >= 4.0.5
 # Support for 'data' directory in rake install task
 BuildRequires:  rubygem(yast-rake) >= 0.1.7
 BuildRequires:  rubygem(rspec)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/src/clients/default_target_proposal.rb 
new/yast2-services-manager-4.0.1/src/clients/default_target_proposal.rb
--- old/yast2-services-manager-3.3.1/src/clients/default_target_proposal.rb     
2017-08-02 16:54:45.597985485 +0200
+++ new/yast2-services-manager-4.0.1/src/clients/default_target_proposal.rb     
2017-10-17 09:15:42.761629420 +0200
@@ -1,276 +1,4 @@
-require 'services-manager/ui_elements'
+require "yast"
+require "services-manager/clients/default_target_proposal"
 
-module Yast
-  import 'Arch'
-  import 'Linuxrc'
-  import 'Mode'
-  import 'Pkg'
-  import 'Popup'
-  import 'ProductFeatures'
-  import 'ServicesManagerTarget'
-  import 'Wizard'
-
-  class TargetProposal < Client
-
-    module Target
-      include ServicesManagerTargetClass::BaseTargets
-
-      SUPPORTED = [ GRAPHICAL, MULTIUSER ]
-    end
-
-    module Warnings
-      attr_reader :warnings
-
-      def detect_warnings selected_target
-        if Linuxrc.vnc && selected_target != Target::GRAPHICAL
-          warnings << _('VNC needs graphical system to be available')
-        end
-      end
-    end
-
-    def initialize
-      textdomain 'services-manager'
-    end
-
-    def call args
-      function = args.shift.to_s
-      #TODO implement behaviour if force_reset parameter provided
-      force_reset = !!args.shift
-      case function
-        when 'MakeProposal' then Proposal.new.create
-        when 'AskUser'      then Dialog.new.show
-        when 'Description'  then description
-        when 'Write'        then write
-        else  Builtins.y2error("Unknown function: %1", function)
-      end
-    end
-
-    def description
-      {
-        'id'              => 'services-manager',
-        'menu_title'      => _("&Default systemd target"),
-        'rich_text_title' => _("Default systemd target")
-      }
-    end
-
-    def write
-      Builtins.y2milestone("Not writing yet, will be done in inst_finish")
-    end
-
-    class Dialog < Client
-      include Warnings
-      include UIElements
-
-      attr_accessor :dialog
-      attr_reader   :available_targets
-
-      def initialize
-        textdomain 'services-manager'
-        @warnings = []
-        @available_targets = Target::SUPPORTED
-      end
-
-      def show
-        # create the proposal dialog and get the sequence symbol from block
-        sequence = create_dialog { handle_dialog }
-        {'workflow_sequence' => sequence}
-      end
-
-      private
-
-      def handle_dialog
-        case UI.UserInput
-        when :next, :ok
-          selected_target = UI.QueryWidget(Id(:selected_target), 
:CurrentButton)
-          detect_warnings(selected_target)
-          if !warnings.empty?
-            return handle_dialog unless Popup.ContinueCancel(warnings.join 
"\n")
-          end
-          Builtins.y2milestone "User selected target '#{selected_target}'"
-          ServicesManagerTarget.default_target = selected_target
-          ServicesManagerTarget.force = true
-          :next
-        when :cancel
-          :cancel
-        end
-      end
-
-      def generate_target_buttons
-        Builtins.y2milestone "Available targets: #{available_targets}"
-
-        radio_buttons = available_targets.map do |target_name|
-          selected = target_name == ServicesManagerTarget.default_target
-          Left(
-            RadioButton(
-              Id(target_name),
-              ServicesManagerTargetClass::BaseTargets.localize(target_name),
-              selected
-            )
-          )
-        end
-
-        VBox(*radio_buttons)
-      end
-
-      def create_dialog
-        caption = _("Set Default Systemd Target")
-        Wizard.CreateDialog
-        Wizard.SetTitleIcon "yast-runlevel"
-        Wizard.SetContentsButtons(
-          caption,
-          generate_content,
-          help,
-          Label.BackButton,
-          Label.OKButton
-        )
-        Wizard.SetAbortButton(:cancel, Label.CancelButton)
-        Wizard.HideBackButton
-        yield
-      ensure
-        Wizard.CloseDialog
-      end
-
-      def help
-        header = para _("Selecting the Default Systemd Target")
-
-        intro = para _("Systemd is a system and service manager for Linux. " +
-         "It consists of units whose job is to activate services and other 
units.")
-
-        default = para _("Default target unit is activated on boot " +
-          "by default. Usually it is a symlink located in path" +
-          "/etc/systemd/system/default.target . See more on systemd man page.")
-
-        multiuser = para _("Multi-User target is for setting up a 
non-graphical " +
-          "multi-user system with network suitable for server (similar to 
runlevel 3).")
-
-        graphical = para _("Graphical target for setting up a graphical login 
screen " +
-          "with network which is typical for workstations (similar to runlevel 
5).")
-
-        recommendation = para _("When you are not sure what would be the best 
option " +
-           "for you then go with graphical target.")
-
-        header + intro + multiuser + graphical + recommendation
-      end
-
-      def generate_content
-        VBox(
-          RadioButtonGroup(
-            Id(:selected_target),
-            Frame(
-              _('Available Targets'),
-              HSquash(MarginBox(0.5, 0.5, generate_target_buttons))
-            )
-          )
-        )
-      end
-
-    end
-
-    class Proposal < Client
-      include Warnings
-      include UIElements
-
-      attr_accessor :default_target
-
-      def initialize
-        textdomain 'services-manager'
-        @warnings = []
-        if ServicesManagerTarget.force
-          Builtins.y2milestone(
-            "Default target has been changed before by user manually to 
'#{ServicesManagerTarget.default_target}'"
-          )
-        end
-
-        # While autoyast installation default target will be set by autoyast 
(file inst_autosetup.rb).
-        # (bnc#889055)
-        if Mode.autoinst || Mode.autoupgrade
-          self.default_target = ServicesManagerTarget.default_target
-        else
-          change_default_target
-        end
-
-        detect_warnings(default_target)
-        Builtins.y2milestone("Systemd default target is set to 
'#{ServicesManagerTarget.default_target}'")
-      end
-
-      def create
-        proposal = {
-          'preformatted_proposal' => list(
-            ServicesManagerTargetClass::BaseTargets.localize(default_target)
-          )
-        }
-
-        return proposal if warnings.empty?
-
-        proposal.update 'warning_level' => :warning
-        proposal.update 'warning'       => list(*warnings)
-        proposal
-      end
-
-      private
-
-      def change_default_target
-        self.default_target = ProductFeatures.GetFeature('globals', 
'default_target')
-        detect_target
-        # Check if the user forced a particular target before; if he did and 
the
-        # autodetection recommends a different one now, warn the user about 
this
-        # and keep the default target unchanged.
-        if ServicesManagerTarget.force && default_target != 
ServicesManagerTarget.default_target
-          localized_target = 
ServicesManagerTargetClass::BaseTargets.localize(default_target)
-          warnings << _("The installer is recommending you the default target 
'%s' ") % localized_target
-          warnings << ServicesManagerTarget.proposal_reason
-          self.default_target = ServicesManagerTarget.default_target
-          return
-        end
-        Builtins.y2milestone("Setting systemd default target to 
#{default_target}")
-        ServicesManagerTarget.default_target = default_target
-      end
-
-      def detect_target
-        self.default_target =
-          if Arch.x11_setup_needed && Pkg.IsSelected("xorg-x11-server")
-            give_reason _("X11 packages have been selected for installation")
-            Target::GRAPHICAL
-          elsif Mode.live_installation
-            give_reason _("Live Installation is typically used for full GUI in 
target system")
-            Target::GRAPHICAL
-          elsif Linuxrc.serial_console
-            give_reason _("Serial connection does typically not support GUI")
-            Target::MULTIUSER
-          elsif Linuxrc.vnc && Linuxrc.usessh
-            if UI.GetDisplayInfo == 'TextMode'
-              give_reason _("Text mode installation assumes no GUI on the 
target system")
-              Target::MULTIUSER
-            else
-              give_reason _("Using VNC assumes a GUI on the target system")
-              Target::GRAPHICAL
-            end
-          elsif Linuxrc.vnc
-            give_reason _("Using VNC assumes a GUI on the target system")
-            Target::GRAPHICAL
-          elsif Linuxrc.usessh
-            give_reason _("SSH installation mode assumes no GUI on the target 
system")
-            Target::MULTIUSER
-          elsif !(Arch.x11_setup_needed && Pkg.IsSelected("xorg-x11-server"))
-            give_reason _("X11 packages have not been selected for 
installation")
-            Target::MULTIUSER
-          else
-            give_reason _("This recommendation is based on the analysis of 
other installation settings")
-            Target::MULTIUSER
-          end
-
-        Builtins.y2milestone("Detected target proposal '#{default_target}'")
-      end
-
-      def give_reason message
-        ServicesManagerTarget.proposal_reason = message
-        Builtins.y2milestone("Systemd target detection says: #{message}")
-      end
-
-    end
-  # clients are always re-evaluated, so avoid redefine of class otherwise
-  # constant redefine warning happen
-  end unless defined? TargetProposal
-
-  TargetProposal.new.call(WFM.Args)
-end
+Yast::TargetProposal.new.call(Yast::WFM.Args)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/src/clients/services_proposal.rb 
new/yast2-services-manager-4.0.1/src/clients/services_proposal.rb
--- old/yast2-services-manager-3.3.1/src/clients/services_proposal.rb   
2017-08-02 16:54:45.597985485 +0200
+++ new/yast2-services-manager-4.0.1/src/clients/services_proposal.rb   
2017-10-17 09:15:42.761629420 +0200
@@ -24,7 +24,6 @@
       function = args.shift.to_s
       service_id = args.find {|i| i == 'chosen_id'}.to_s
       #TODO implement behaviour if force_reset parameter provided
-      force_reset = !!(args.find {|i| i == 'force_reset'})
 
       case function
         when 'MakeProposal' then proposal.read
@@ -37,7 +36,7 @@
 
     def ask_user service_id
       Builtins.y2milestone "Services proposal wanted to change with id %1", 
service_id
-      if service_id.match /\Atoggle_service_\d+\z/
+      if service_id.match(/\Atoggle_service_\d+\z/)
         Builtins.y2milestone "User requested #{service_id}"
         toggle_service(service_id)
       else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/src/lib/services-manager/clients/default_target_proposal.rb
 
new/yast2-services-manager-4.0.1/src/lib/services-manager/clients/default_target_proposal.rb
--- 
old/yast2-services-manager-3.3.1/src/lib/services-manager/clients/default_target_proposal.rb
        1970-01-01 01:00:00.000000000 +0100
+++ 
new/yast2-services-manager-4.0.1/src/lib/services-manager/clients/default_target_proposal.rb
        2017-10-17 09:15:42.761629420 +0200
@@ -0,0 +1,278 @@
+require 'services-manager/ui_elements'
+
+module Yast
+  import 'Arch'
+  import 'Linuxrc'
+  import 'Mode'
+  import 'Pkg'
+  import 'Popup'
+  import 'ProductFeatures'
+  import 'ServicesManagerTarget'
+  import 'Wizard'
+
+  class TargetProposal < Client
+
+    module Target
+      include ServicesManagerTargetClass::BaseTargets
+
+      SUPPORTED = [ GRAPHICAL, MULTIUSER ]
+    end
+
+    module Warnings
+      attr_reader :warnings
+
+      def detect_warnings selected_target
+        if Linuxrc.vnc && selected_target != Target::GRAPHICAL
+          warnings << _('VNC needs graphical system to be available')
+        end
+      end
+    end
+
+    def initialize
+      textdomain 'services-manager'
+    end
+
+    def call args
+      function = args.shift.to_s
+      #TODO implement behaviour if force_reset parameter provided
+      case function
+        when 'MakeProposal' then Proposal.new.create
+        when 'AskUser'      then Dialog.new.show
+        when 'Description'  then description
+        when 'Write'        then write
+        else  Builtins.y2error("Unknown function: %1", function)
+      end
+    end
+
+    def description
+      {
+        'id'              => 'services-manager',
+        'menu_title'      => _("&Default systemd target"),
+        'rich_text_title' => _("Default systemd target")
+      }
+    end
+
+    def write
+      Builtins.y2milestone("Not writing yet, will be done in inst_finish")
+    end
+
+    class Dialog < Client
+      include Warnings
+      include UIElements
+
+      attr_accessor :dialog
+      attr_reader   :available_targets
+
+      def initialize
+        textdomain 'services-manager'
+        @warnings = []
+        @available_targets = Target::SUPPORTED
+      end
+
+      def show
+        # create the proposal dialog and get the sequence symbol from block
+        sequence = create_dialog { handle_dialog }
+        {'workflow_sequence' => sequence}
+      end
+
+      private
+
+      def handle_dialog
+        case UI.UserInput
+        when :next, :ok
+          selected_target = UI.QueryWidget(Id(:selected_target), 
:CurrentButton)
+          detect_warnings(selected_target)
+          if !warnings.empty?
+            return handle_dialog unless Popup.ContinueCancel(warnings.join 
"\n")
+          end
+          Builtins.y2milestone "User selected target '#{selected_target}'"
+          ServicesManagerTarget.default_target = selected_target
+          ServicesManagerTarget.force = true
+          :next
+        when :cancel
+          :cancel
+        end
+      end
+
+      def generate_target_buttons
+        Builtins.y2milestone "Available targets: #{available_targets}"
+
+        radio_buttons = available_targets.map do |target_name|
+          selected = target_name == ServicesManagerTarget.default_target
+          Left(
+            RadioButton(
+              Id(target_name),
+              ServicesManagerTargetClass::BaseTargets.localize(target_name),
+              selected
+            )
+          )
+        end
+
+        VBox(*radio_buttons)
+      end
+
+      def create_dialog
+        caption = _("Set Default Systemd Target")
+        Wizard.CreateDialog
+        Wizard.SetTitleIcon "yast-runlevel"
+        Wizard.SetContentsButtons(
+          caption,
+          generate_content,
+          help,
+          Label.BackButton,
+          Label.OKButton
+        )
+        Wizard.SetAbortButton(:cancel, Label.CancelButton)
+        Wizard.HideBackButton
+        yield
+      ensure
+        Wizard.CloseDialog
+      end
+
+      def help
+        header = para _("Selecting the Default Systemd Target")
+
+        intro = para _("Systemd is a system and service manager for Linux. " +
+         "It consists of units whose job is to activate services and other 
units.")
+
+        default = para _("Default target unit is activated on boot " +
+          "by default. Usually it is a symlink located in path" +
+          "/etc/systemd/system/default.target . See more on systemd man page.")
+
+        multiuser = para _("Multi-User target is for setting up a 
non-graphical " +
+          "multi-user system with network suitable for server (similar to 
runlevel 3).")
+
+        graphical = para _("Graphical target for setting up a graphical login 
screen " +
+          "with network which is typical for workstations (similar to runlevel 
5).")
+
+        recommendation = para _("When you are not sure what would be the best 
option " +
+           "for you then go with graphical target.")
+
+        header + intro + default + multiuser + graphical + recommendation
+      end
+
+      def generate_content
+        VBox(
+          RadioButtonGroup(
+            Id(:selected_target),
+            Frame(
+              _('Available Targets'),
+              HSquash(MarginBox(0.5, 0.5, generate_target_buttons))
+            )
+          )
+        )
+      end
+
+    end
+
+    class Proposal < Client
+      include Warnings
+      include UIElements
+      include Yast::Logger
+
+      attr_accessor :default_target
+
+      def initialize
+        textdomain 'services-manager'
+        @warnings = []
+        if ServicesManagerTarget.force
+          Builtins.y2milestone(
+            "Default target has been changed before by user manually to 
'#{ServicesManagerTarget.default_target}'"
+          )
+        end
+
+        # While autoyast installation default target will be set by autoyast 
(file inst_autosetup.rb).
+        # (bnc#889055)
+        if Mode.autoinst || Mode.autoupgrade
+          self.default_target = ServicesManagerTarget.default_target
+        else
+          change_default_target
+        end
+
+        detect_warnings(default_target)
+        Builtins.y2milestone("Systemd default target is set to 
'#{ServicesManagerTarget.default_target}'")
+      end
+
+      def create
+        proposal = {
+          'preformatted_proposal' => list(
+            ServicesManagerTargetClass::BaseTargets.localize(default_target)
+          )
+        }
+
+        return proposal if warnings.empty?
+
+        proposal.update 'warning_level' => :warning
+        proposal.update 'warning'       => list(*warnings)
+        proposal
+      end
+
+      private
+
+      def change_default_target
+        self.default_target = ProductFeatures.GetFeature('globals', 
'default_target')
+        if default_target.nil? || default_target.empty?
+          detect_target
+        elsif Target::SUPPORTED.include?(default_target)
+          log.info "Using target '#{default_target}' from control file."
+        else
+          raise "Invalid value in control file for default_target: 
'#{default_target}'"
+        end
+        # Check if the user forced a particular target before; if he did and 
the
+        # autodetection recommends a different one now, warn the user about 
this
+        # and keep the default target unchanged.
+        if ServicesManagerTarget.force && default_target != 
ServicesManagerTarget.default_target
+          localized_target = 
ServicesManagerTargetClass::BaseTargets.localize(default_target)
+          warnings << _("The installer is recommending you the default target 
'%s' ") % localized_target
+          warnings << ServicesManagerTarget.proposal_reason
+          self.default_target = ServicesManagerTarget.default_target
+          return
+        end
+        Builtins.y2milestone("Setting systemd default target to 
#{default_target}")
+        ServicesManagerTarget.default_target = default_target
+      end
+
+      def detect_target
+        self.default_target =
+          if Arch.x11_setup_needed && Pkg.IsSelected("xorg-x11-server")
+            give_reason _("X11 packages have been selected for installation")
+            Target::GRAPHICAL
+          elsif Mode.live_installation
+            give_reason _("Live Installation is typically used for full GUI in 
target system")
+            Target::GRAPHICAL
+          elsif Linuxrc.serial_console
+            give_reason _("Serial connection does typically not support GUI")
+            Target::MULTIUSER
+          elsif Linuxrc.vnc && Linuxrc.usessh
+            if UI.GetDisplayInfo == 'TextMode'
+              give_reason _("Text mode installation assumes no GUI on the 
target system")
+              Target::MULTIUSER
+            else
+              give_reason _("Using VNC assumes a GUI on the target system")
+              Target::GRAPHICAL
+            end
+          elsif Linuxrc.vnc
+            give_reason _("Using VNC assumes a GUI on the target system")
+            Target::GRAPHICAL
+          elsif Linuxrc.usessh
+            give_reason _("SSH installation mode assumes no GUI on the target 
system")
+            Target::MULTIUSER
+          elsif !(Arch.x11_setup_needed && Pkg.IsSelected("xorg-x11-server"))
+            give_reason _("X11 packages have not been selected for 
installation")
+            Target::MULTIUSER
+          else
+            give_reason _("This recommendation is based on the analysis of 
other installation settings")
+            Target::MULTIUSER
+          end
+
+        Builtins.y2milestone("Detected target proposal '#{default_target}'")
+      end
+
+      def give_reason message
+        ServicesManagerTarget.proposal_reason = message
+        Builtins.y2milestone("Systemd target detection says: #{message}")
+      end
+    end
+  end
+end
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/src/modules/services_manager_service.rb 
new/yast2-services-manager-4.0.1/src/modules/services_manager_service.rb
--- old/yast2-services-manager-3.3.1/src/modules/services_manager_service.rb    
2017-08-02 16:54:45.597985485 +0200
+++ new/yast2-services-manager-4.0.1/src/modules/services_manager_service.rb    
2017-10-17 09:15:42.761629420 +0200
@@ -12,31 +12,81 @@
     LIST_UNIT_FILES_COMMAND = 'systemctl list-unit-files --type service'
     LIST_UNITS_COMMAND      = 'systemctl list-units --all --type service'
     STATUS_COMMAND          = 'systemctl status'
-    IS_ACTIVE_COMMAND       = 'systemctl is-active'
+    # FIXME: duplicated in Yast::Systemctl
     COMMAND_OPTIONS         = ' --no-legend --no-pager --no-ask-password '
     TERM_OPTIONS            = ' LANG=C TERM=dumb COLUMNS=1024 '
     SERVICE_SUFFIX          = '.service'
 
+    # Used by ServicesManagerServiceClass to keep data about an individual 
service.
+    # (Not a real class; documents the structure of a Hash)
+    #
+    # Why does this hash exist if we have Yast::SystemdServiceClass::Service?
+    class Settings < Hash
+      # @!method [](k)
+      #   @option k :enabled  [Boolean] service has been enabled
+      #   @option k :can_be_enabled [Boolean] service can be enabled/disabled 
by the user
+      #   @option k :modified [Boolean] service has been changed (got 
enabled/disabled)
+      #   @option k :active   [Boolean] The high-level unit activation state, 
i.e. generalization of SUB
+      #   @option k :loaded   [Boolean] Reflects whether the unit definition 
was properly loaded
+      #   @option k :description [String] English description of the service
+    end
+
+    # @return [Settings]
     DEFAULT_SERVICE_SETTINGS = {
-      :enabled        => false, # Whether the service has been enabled
-      :can_be_enabled => true,  # Whether the service can be enabled/disabled 
by the user
-      :modified       => false, # Whether the service has been changed (got 
enabled/disabled)
-      :active         => false, # The high-level unit activation state, i.e. 
generalization of SUB
-      :loaded         => false, # Reflects whether the unit definition was 
properly loaded
-      :description    => nil    # English description of the service
+      :enabled        => false,
+      :can_be_enabled => true,
+      :modified       => false,
+      :active         => nil,
+      :loaded         => false,
+      :description    => nil
     }
 
+    # FIXME: this is a mixture of
+    # LoadState (the LOAD column of systemctl list-units) and
+    # UnitFileState (STATE of systemctl list-unit-files)
     module Status
+      # LoadState
       LOADED     = 'loaded'
+      # LoadState
       NOTFOUND   = 'not-found'
-      MASKED     = 'masked' # The service has been marked as completely 
unstartable, automatically or manually.
-      STATIC     = 'static' # The service is missing the [Install] section in 
its init script, so you cannot enable or disable it.
+      # masked is both a LoadState and a UnitFileState :-/
+      # The service has been marked as completely unstartable, automatically 
or manually.
+      MASKED     = 'masked'
+      # UnitFileState
+      # The service is missing the [Install] section in its init script, so 
you cannot enable or disable it.
+      STATIC     = 'static'
     end
 
+    # @api private
     class ServiceLoader
-      attr_reader :unit_files, :units, :services
-      attr_reader :supported_unit_files, :supported_units
+      include Yast::Logger
 
+      # @return [Hash{String => String}] service name -> status, like "foo" => 
"enabled" (UnitFileState)
+      # @see Status
+      attr_reader :unit_files
+
+      # @return [Hash{String => Hash}]
+      #   like "foo" => { status: "loaded", description: "Features OO" }
+      # @see Status
+      attr_reader :units
+
+      # @return [Hash{String => Settings}]
+      #   like "foo" => { enabled: false, loaded: true, ..., description: 
"Features OO" }
+      attr_reader :services
+
+      # Like {#unit_files} except those that are "masked"
+      # @return [Hash{String => String}] service name -> status, like "foo" => 
"enabled" (UnitFileState)
+      # @see Status
+      attr_reader :supported_unit_files
+
+      # Like {#units} except those with status: "not-found"
+      # @return [Hash{String => Hash}]
+      #   like "foo" => { status: "loaded", description: "Features OO" }
+      # @see Status
+      attr_reader :supported_units
+
+      # @return [Hash{String => Settings}]
+      #   like "foo" => { enabled: false, loaded: true, ..., description: 
"Features OO" }
       def read
         @services   = {}
         @unit_files = {}
@@ -59,39 +109,36 @@
 
       private
 
+      # FIXME: use Yast::Systemctl for this, remember to chomp SERVICE_SUFFIX
+
+      # @return [Array<String>] "apache2.service   enabled\n"
       def list_unit_files
         command = TERM_OPTIONS + LIST_UNIT_FILES_COMMAND + COMMAND_OPTIONS
-        SCR.Execute(Path.new('.target.bash_output'), command)
+        out = SCR.Execute(Path.new('.target.bash_output'), command)['stdout']
+        out.lines
       end
 
+      # @return [Array<String>] "dbus.service   loaded active running D-Bus 
System Message Bus\n"
       def list_units
         command = TERM_OPTIONS + LIST_UNITS_COMMAND + COMMAND_OPTIONS
-        SCR.Execute(Path.new('.target.bash_output'), command)
-      end
-
-      # Checking if a service is active or not.
-      #
-      # @param service [String] Service name
-      # @return [Boolean] is it active or not
-      def is_active?(service)
-        # There is a active? method in SystemdUnit class but it checks the 
status
-        # active and activating only. Not sure if this correct. So we are 
taking the
-        # official call of systemctl command.
-        command = "#{TERM_OPTIONS}#{IS_ACTIVE_COMMAND} 
#{service}#{SERVICE_SUFFIX} 2>&1"
-        SCR.Execute(Path.new('.target.bash_output'), command)["exit"] == 0
+        out = SCR.Execute(Path.new('.target.bash_output'), command)['stdout']
+        out.lines
       end
 
       def load_unit_files
-        list_unit_files['stdout'].each_line do |line|
+        list_unit_files.each do |line|
           service, status = line.split(/[\s]+/)
           service.chomp! SERVICE_SUFFIX
+          # Unit template, errors out when inquired with `systemctl show`
+          # See systemd.unit(5)
+          next if service.end_with?("@")
           unit_files[service] = status
         end
       end
 
       def load_units
-        list_units['stdout'].each_line do |line|
-          service, status, active, _, *description = line.split(/[\s]+/)
+        list_units.each do |line|
+          service, status, _active, _sub_state, *description = 
line.split(/[\s]+/)
           service.chomp! SERVICE_SUFFIX
           units[service] = {
             :status => status,
@@ -127,28 +174,35 @@
         # Add old LSB services (Services which are loaded but not available as 
a unit file)
         extract_services_from_units
 
+        service_names = services.keys.sort
+        ss = SystemdService.find_many(service_names)
         # Rest of settings
-        services.each_key do |name|
-          services[name][:enabled] = Yast::Service.Enabled(name)
-          services[name][:active] = is_active?(name)
-          if !services[name][:description] || 
services[name][:description].empty?
-            # Trying to evaluate description via the show command of systemctl
-            s = SystemdService.find(name)
-            services[name][:description] = 
SystemdService.find(name).description if s
+        service_names.zip(ss).each do |name, s|
+          sh = services[name] # service hash
+          sh[:enabled] = s && s.enabled?
+          sh[:active] = s && s.active?
+          if !sh[:description] || sh[:description].empty?
+            sh[:description] = s ? s.description : ""
           end
         end
       end
     end
 
     attr_reader   :modified
-    attr_accessor :errors, :services
+
+    # @return [Array<String>]
+    attr_accessor :errors
 
     alias_method :modified?, :modified
 
+    # @return [Hash{String => Settings}]
+    #   like "foo" => { enabled: false, loaded: true, ..., description: 
"Features OO" }
     def services
       @services ||= read
     end
 
+    attr_writer :services
+
     alias_method :all, :services
 
     def initialize
@@ -159,8 +213,8 @@
 
     # Sets whether service should be running after writing the configuration
     #
-    # @param String service name
-    # @param Boolean running
+    # @param [String] service name
+    # @return [Boolean] whether the service exists
     def activate(service)
       exists?(service) do
         services[service][:active]  = true
@@ -172,8 +226,8 @@
 
     # Sets whether service should be running after writing the configuration
     #
-    # @param String service name
-    # @param Boolean running
+    # @param [String] service name
+    # @return [Boolean] whether the service exists
     def deactivate(service)
       exists?(service) do
         services[service][:active]   = false
@@ -182,10 +236,8 @@
       end
     end
 
-    # Returns the current setting whether service should be running
-    #
-    # @param String service name
-    # @return Boolean running
+    # @param [String] service name
+    # @return [Boolean] the current setting whether service should be running
     def active(service)
       exists?(service) { services[service][:active] }
     end
@@ -255,7 +307,8 @@
 
     # Reads all services' data
     #
-    # @return [Hash] map of services
+    # @return [Hash{String => Settings}]
+    #   like "foo" => { enabled: false, loaded: true, ..., description: 
"Features OO" }
     def read
       ServiceLoader.new.read
     end
@@ -400,8 +453,8 @@
     # @param String service name
     # @return String full unformatted information
     def status(service)
-      command = "#{TERM_OPTIONS}#{STATUS_COMMAND} #{service}#{SERVICE_SUFFIX} 
2>&1"
-      SCR.Execute(path('.target.bash_output'), command)['stdout']
+      out = Systemctl.execute("status #{service}#{SERVICE_SUFFIX} 2>&1")
+      out['stdout']
     end
 
     private
@@ -410,8 +463,10 @@
     # When passed a block, this will be executed only if the service exists
     # Whitout block it returns the boolean value
     #
-    # @params [String] service name
-    # @return [Boolean]
+    # @param [String] service name
+    # @yieldreturn [Boolean]
+    # @return [Boolean] false if the service does not exist,
+    #   otherwise what the block returned
     def exists?(service)
       if Stage.initial && !services[service]
         # We are in inst-sys. So we cannot check for installed services but 
generate entries
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/test/default_target_proposal_test.rb 
new/yast2-services-manager-4.0.1/test/default_target_proposal_test.rb
--- old/yast2-services-manager-3.3.1/test/default_target_proposal_test.rb       
1970-01-01 01:00:00.000000000 +0100
+++ new/yast2-services-manager-4.0.1/test/default_target_proposal_test.rb       
2017-10-17 09:15:42.761629420 +0200
@@ -0,0 +1,66 @@
+#! /usr/bin/env rspec
+
+require_relative "./test_helper"
+
+require "services-manager/clients/default_target_proposal"
+
+describe Yast::TargetProposal do
+  subject { described_class }
+  describe "#call with Description command" do
+    it "returns hash" do
+      expect(subject.new.call(["Description"])).to be_a(::Hash)
+    end
+  end
+
+  describe "#call with MakeProposal command" do
+    before do
+      allow(Yast::ServicesManagerTarget).to receive(:read) # avoid real read
+      allow(Yast::Stage).to receive(:initial).and_return(true) # skip state 
validation
+    end
+
+    context "auto mode" do
+      before do
+        allow(Yast::Mode).to receive(:autoinst).and_return(true)
+      end
+
+      it "keep default target as it was before" do
+        Yast::ServicesManagerTarget.default_target = "multi-user"
+
+        expect(Yast::ServicesManagerTarget).to_not receive(:default_target=)
+        subject.new.call(["MakeProposal"])
+      end
+    end
+
+    context "non-auto mode" do
+      before do
+        allow(Yast::Mode).to receive(:autoinst).and_return(false)
+        allow(Yast::Mode).to receive(:autoupgrade).and_return(false)
+      end
+
+      it "sets target level according to control file" do
+        allow(Yast::ProductFeatures).to receive(:GetFeature).with("globals", 
"default_target")
+          .and_return("multi-user")
+
+        subject.new.call(["MakeProposal"])
+
+        expect(Yast::ServicesManagerTarget.default_target).to eq "multi-user"
+      end
+
+      it "proposes target when it is not specified in control file" do
+        allow(Yast::ProductFeatures).to receive(:GetFeature).with("globals", 
"default_target")
+          .and_return(nil)
+
+        subject.new.call(["MakeProposal"])
+
+        expect(Yast::ServicesManagerTarget.default_target).to_not be_empty
+      end
+
+      it "raises exception if control file contain invalid value" do
+        allow(Yast::ProductFeatures).to receive(:GetFeature).with("globals", 
"default_target")
+          .and_return("COBE invalid value")
+
+        expect{subject.new.call(["MakeProposal"])}.to raise_error(RuntimeError)
+      end
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-services-manager-3.3.1/test/services_manager_service_test.rb 
new/yast2-services-manager-4.0.1/test/services_manager_service_test.rb
--- old/yast2-services-manager-3.3.1/test/services_manager_service_test.rb      
2017-08-02 16:54:45.597985485 +0200
+++ new/yast2-services-manager-4.0.1/test/services_manager_service_test.rb      
2017-10-17 09:15:42.761629420 +0200
@@ -14,46 +14,57 @@
       allow(Service).to receive(:Disable).and_return true
       allow(Service).to receive(:Start).and_return true
       allow(Service).to receive(:Stop).and_return true
-      allow(Service).to receive(:Enabled).with("sshd").and_return true
-      allow(Service).to receive(:Enabled).with("postfix").and_return false
-      allow(Service).to receive(:Enabled).with("swap").and_return false
-      allow(Service).to receive(:Enabled).with("dbus").and_return false
-      allow(Service).to receive(:Enabled).with("notloaded").and_return false
-      allow(Service).to receive(:Enabled).with("xbus").and_return true
-      allow(Service).to receive(:Enabled).with("ybus").and_return true
-      allow(Service).to receive(:Enabled).with("zbus").and_return true
-      allow(Service).to receive(:Enabled).with("lsb").and_return false
-      allow(Service).to receive(:Enabled).with("").and_return true
+
+      all_services = {}
+      declare_service = lambda do |name, enabled|
+        d = double(description: "Stub #{name}", enabled?: enabled, active?: 
true)
+        all_services[name] = d
+      end
+
+      declare_service.call("sshd", true)
+      declare_service.call("postfix", false)
+      declare_service.call("dbus", false)
+      declare_service.call("notloaded", false)
+      declare_service.call("xbus", true)
+      declare_service.call("ybus", true)
+      declare_service.call("zbus", true)
+      declare_service.call("lsb", false)
+
+      keys = all_services.sort.map(&:first)
+      values = all_services.sort.map(&:last)
+      allow(SystemdService)
+        .to receive(:find_many).with(keys)
+              .and_return(values)
     end
 
     before do
+      stub_services
+
       allow_any_instance_of(ServicesManagerServiceClass::ServiceLoader).to 
receive(:list_unit_files)
-        .and_return({
-          'stdout'=> "sshd.service      enabled \n"  +
-                     "postfix.service   disabled\n " +
-                     "swap.service      masked  \n"  +
-                     "dbus.service      static  \n"  +
-                     "notloaded.service static  \n"  +
-                     "xbus.service      enabled \n"  +
-                     "ybus.service      enabled \n"  +
-                     "zbus.service      enabled \n",
-          'stderr' => '',
-          'exit'   => 0
-        })
+        .and_return(
+          [
+                     "sshd.service      enabled \n",
+                     "postfix.service   disabled\n",
+                     "swap.service      masked  \n",
+                     "dbus.service      static  \n",
+                     "notloaded.service static  \n",
+                     "xbus.service      enabled \n",
+                     "ybus.service      enabled \n",
+                     "zbus.service      enabled \n"
+          ]
+        )
       allow_any_instance_of(ServicesManagerServiceClass::ServiceLoader).to 
receive(:list_units)
-        .and_return({
-          'stdout'=>"sshd.service  loaded active   running OpenSSH Daemon\n" +
-                    "postfix.service loaded inactive dead    Postfix Mail 
Agent\n" +
-                    "dbus.service  loaded active   running D-Bus System 
Message Bus\n" +
-                    "lsb.service  loaded active   running LSB service\n" +
-                    "xbus.service loaded activating start start YaST2 Second 
Stage (1)\n" +
-                    "ybus.service loaded deactivating stop start YaST2 Second 
Stage (2)\n" +
-                    "zbus.service loaded reloading stop start YaST2 Second 
Stage (3)\n",
-          'stderr' => '',
-          'exit'   => 0
-        })
-
-      allow_any_instance_of(ServicesManagerServiceClass::ServiceLoader).to 
receive(:is_active?).and_return true
+        .and_return(
+          [
+            "sshd.service  loaded active   running OpenSSH Daemon\n",
+            "postfix.service loaded inactive dead    Postfix Mail Agent\n",
+            "dbus.service  loaded active   running D-Bus System Message Bus\n",
+            "lsb.service  loaded active   running LSB service\n",
+            "xbus.service loaded activating start start YaST2 Second Stage 
(1)\n",
+            "ybus.service loaded deactivating stop start YaST2 Second Stage 
(2)\n",
+            "zbus.service loaded reloading stop start YaST2 Second Stage (3)\n"
+          ]
+        )
 
       @service = Yast::ServicesManagerServiceClass.new
     end
@@ -70,7 +81,6 @@
     end
 
     it "can enable a service which is disabled" do
-      stub_services
       postfix = service.all['postfix']
       expect(postfix[:enabled]).to eq(false)
       expect(postfix[:modified]).to eq(false)
@@ -83,7 +93,6 @@
     end
 
     it "can disable a service which is enabled" do
-      stub_services
       sshd = service.all['sshd']
       expect(sshd[:enabled]).to eq(true)
       expect(sshd[:modified]).to eq(false)
@@ -96,7 +105,6 @@
     end
 
     it "can start an inactive service" do
-      stub_services
       postfix = service.all['postfix']
       expect(postfix[:modified]).to be(false)
       service.activate 'postfix'
@@ -108,7 +116,6 @@
     end
 
     it "can stop an active service" do
-      stub_services
       sshd = service.all['sshd']
       expect(sshd[:active]).to be(true)
       expect(sshd[:modified]).to be(false)
@@ -121,7 +128,6 @@
     end
 
     it "can toggle a service" do
-      stub_services
       sshd = service.all['sshd']
       status = sshd[:enabled]
       service.toggle 'sshd'
@@ -131,7 +137,6 @@
     end
 
     it "can switch a service" do
-      stub_services
       postfix = service.all['postfix']
       status  = postfix[:active]
       service.switch 'postfix'
@@ -166,7 +171,6 @@
 
     context "when enabling is failing" do
       before do
-        stub_services
         allow(Service).to receive(:Enable).and_return false
         allow(Service).to receive(:Disable).and_return false
         service.toggle 'postfix'
@@ -190,7 +194,6 @@
 
     context "when service is in state 'reloading'" do
       it "is considered to be active" do
-        stub_services
         zbus_service = service.all['zbus']
         expect(zbus_service[:active]).to eq(true)
       end
@@ -198,7 +201,6 @@
 
     context "when running in installation-system" do
       it "do not switch a service at all" do
-        stub_services
         postfix = service.all['postfix']
         status  = postfix[:active]
         service.switch 'postfix' # locally only
@@ -207,7 +209,6 @@
         service.save
       end
       it "generates missing services entries" do
-        stub_services
         allow(Stage).to receive(:initial).and_return true
         service.enable("new_service")
         expect(service.services["new_service"]).not_to be_nil
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-services-manager-3.3.1/test/test_helper.rb 
new/yast2-services-manager-4.0.1/test/test_helper.rb
--- old/yast2-services-manager-3.3.1/test/test_helper.rb        2017-08-02 
16:54:45.597985485 +0200
+++ new/yast2-services-manager-4.0.1/test/test_helper.rb        2017-10-17 
09:15:42.761629420 +0200
@@ -1,7 +1,28 @@
-require 'rspec'
+srcdir = File.expand_path("../../src", __FILE__)
+y2dirs = ENV.fetch("Y2DIR", "").split(":")
+ENV["Y2DIR"] = y2dirs.unshift(srcdir).join(":")
 
-ENV["Y2DIR"] = File.expand_path("../../src", __FILE__)
+if ENV["COVERAGE"]
+  require "simplecov"
+  SimpleCov.start do
+    add_filter "/test/"
+  end
 
+  src_location = File.expand_path("../../src", __FILE__)
+  # track all ruby files under src
+  SimpleCov.track_files("#{src_location}/**/*.rb")
+
+  # use coveralls for on-line code coverage reporting at Travis CI
+  if ENV["TRAVIS"]
+    require "coveralls"
+    SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
+      SimpleCov::Formatter::HTMLFormatter,
+      Coveralls::SimpleCov::Formatter
+    ]
+  end
+end
+
+require "rspec"
 require "yast"
 
 Yast.import 'ServicesManager'


Reply via email to