yast/yast-yast2

View on GitHub
library/general/src/lib/ui/ui_extension_checker.rb

Summary

Maintainability
A
0 mins
Test Coverage
# ------------------------------------------------------------------------------
# Copyright (c) 2021 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# ------------------------------------------------------------------------------

require "yast"
require "yast2/ui_plugin_info"

Yast.import "Package"
Yast.import "Report"
Yast.import "Popup"

module Yast
  # Class to check if a UI extension plug-in ("pkg", "graph") is installed.
  # If it's not installed, ask the user if the package containing it should be
  # installed and (if the user answers "yes") install it.
  #
  class UIExtensionChecker
    include Yast::Logger
    include Yast::I18n

    # Constructor: Create a UI extension checker for the specified extension.
    #
    # @param ext_name [String] Short name of the UI extension ("pkg", "graph")
    # @param force_ui [Boolean] Enforce creating a UI?
    #
    def initialize(ext_name, force_ui = true)
      textdomain "base"
      @ext_name = ext_name
      @ok = false
      ensure_ui_created if force_ui
      @ui_plugin_info = UIPluginInfo.new
      ensure_ext_installed
    end

    # Check if the UI extension was either installed to begin with or if the
    # user (after being asked) confirmed to install it, and it was installed
    # successfully.
    #
    # @return [Boolean] UI extension is available now
    #
    def ok?
      @ok
    end

  private

    # Ensure that the UI extension is installed: If it isn't installed yet
    # anyway, ask the user if it should be installed and if yes, install it.
    #
    # @return [Boolean] UI extension is available now (same as ok?)
    #
    def ensure_ext_installed
      return if installed?

      if available_for_ui?
        ask && install
      else
        not_available_error
      end
      @ok
    end

    # Ensure that the UI is actually created: In CLI mode, that might be
    # delayed because normally they should't create a UI at all.
    #
    def ensure_ui_created
      # Just a UI call that doesn't do anything; this is already sufficient to
      # load the UI main plug-in completely if it wasn't loaded yet.
      # See also bsc#1192650
      UI.WidgetExists(:foo)
    end

    # Check if the UI extension plug-in is installed.
    # This also sets @ok.
    #
    # @return [Boolean] true if the UI extension is already installed, false if not
    #
    def installed?
      # Notice that this intentionally checks if the extension plug-in binary
      # is available, and that it is available in the same path as the main UI
      # plug-in: That way it also works for libyui developers that had to bump
      # the UI SO version, or for third-party developers who like to install
      # their binaries to a different path to avoid interfering with existing
      # distro packages.
      #
      # If this would check for the package instead (which includes the SO
      # number, e.g. libyui-qt-pkg42 for libyui-qt42), none of that would work:
      # After a libyui SO version bump, there is no corresponding package yet
      # in OBS with that name that could be installed, so this would always
      # throw an error - an error that is hard to recover from in a development
      # environment.
      #
      # 2021-09-15 shundhammer
      #
      ext_plugin = @ui_plugin_info.ui_extension_plugin_complete(@ext_name)
      @ok = File.exist?(ext_plugin)
      log.info("Not found: #{ext_plugin}") unless @ok
      @ok
    end

    # Open a dialog to ask the user if the UI extension should be installed.
    #
    # @return [Boolean] true if the user wants to install the extension, false if not
    #
    def ask
      # Translators: %s is a software packge name like libyui-qt-pkg15
      msg = _("This needs package %s to be installed.") % ext_pkg
      msg += "\n\n"
      msg += _("Press \"Continue\" to install this package now or \"Cancel\" to exit.")
      @ok = Popup.ContinueCancel(msg)
    end

    # Install the package for the UI extension.
    # This also sets @ok.
    #
    def install
      @ok = Package.DoInstall([ext_pkg])
      if !@ok
        log.error("UI extension package could not be installed: #{ext_pkg}")
        # Translators: %s is a software packge name like libyui-qt-pkg15
        Report.Error(_("Package %s could not be installed.") % ext_pkg)
      end
      @ok
    end

    # Return the package name for the UI extension.
    #
    # @return [String] package name
    #
    def ext_pkg
      @ui_plugin_info.ui_extension_pkg(@ext_name)
    end

    # Check if the UI extension is available for this UI.
    #
    # @return [Boolean] true if the extension is available, false if not
    #
    def available_for_ui?
      ui = @ui_plugin_info.main_ui_plugin
      case @ext_name
      when "pkg"
        ["qt", "ncurses"].include?(ui)
      when "graph"
        ui == "qt"
      else
        log.error("Unknown UI extension #{@ext_name}")
        false
      end
    end

    # Post an error that the UI extension is not available for this UI.
    #
    def not_available_error
      @ok = false
      # Translators: %s is a UI extension name like pkg or graph
      Report.Error(_("UI extension \"%s\" is not available for this UI.") % @ext_name)
    end
  end
end