yast/yast-yast2

View on GitHub
library/system/src/lib/yast2/ui_plugin_info.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/shared_lib_info"

module Yast
  # Class to get information about UI plug-ins used by a process (by default
  # the current process) from its /proc/self/maps file.
  #
  # You can also get information for a different process by specifying its
  # /proc/$pid/maps file.
  #
  # For testing, a fixed file can be used.
  #
  # The information stored in this class is only a snapshot in the life time of
  # the process. As new shared libs are loaded (e.g. plug-ins are loaded with
  # dlopen()), this information may become outdated. In that case, simply let
  # the old instance go out of scope and create a new one.
  #
  # More information: https://github.com/yast/yast-yast2/pull/1194
  #
  class UIPluginInfo < SharedLibInfo
    include Yast::Logger

    # Constructor.
    # @param maps_file [String] name of the maps file to use
    #
    def initialize(maps_file = "/proc/self/maps")
      super
      # Lazy init for those member variables
      @ui_plugins = nil
      @main_ui_plugin_complete = nil
    end

    # Find the UI plug-ins among the shared libs.
    #
    # @return [Array<String>] Complete paths of the UI plug-ins
    #
    def ui_plugins
      if @ui_plugins.nil?
        @ui_plugins = shared_libs.grep(/yui\/libyui-/)
        log.info("UI plug-ins: #{@ui_plugins}")
      end
      @ui_plugins
    end

    # Return the short name of a UI plug-in, i.e. only the lib base name with
    # any leading "libyui-" removed, i.e. something like "qt", "ncurses".
    #
    # @param ui_plugin [String] full name (with or without path) of the UI plug-in
    # @return [String] corresponding short name
    #
    def short_name(ui_plugin)
      name = SharedLibInfo.lib_basename(ui_plugin)
      name&.gsub(/^libyui-/, "")
    end

    # Return the complete name (with path and SO number) of the main UI
    # plug-in.  Several UI plug-ins might be loaded; the main plug-in is
    # generally the one with the shortest lib base name ("qt", "qt-pkg",
    # "qt-graph"; "ncurses", "ncurses-pkg").
    #
    # @return [String, nil] Complete name of the main UI plug-in
    #
    def main_ui_plugin_complete
      return nil if ui_plugins.empty?

      relevant_plugins = ui_plugins.grep_v(/rest-api/)
      @main_ui_plugin_complete ||= relevant_plugins.min do |a, b|
        SharedLibInfo.lib_basename(a).size <=> SharedLibInfo.lib_basename(b).size
      end
      @main_ui_plugin_complete
    end

    # Return the short name of the main UI plug-in, i.e. without path,
    # "libyui-" prefix and SO number Several UI plug-ins might be loaded; the
    # main plug-in is generally the one with the shortest lib base name ("qt",
    # "qt-pkg", "qt-graph"; "ncurses", "ncurses-pkg").
    #
    # @return [String, nil] Short name of the main UI plug-in
    #
    def main_ui_plugin
      name = SharedLibInfo.lib_basename(main_ui_plugin_complete)
      name&.gsub!(/^libyui-/, "")
    end

    # Find the SO number of the UI main plug-in.
    #
    # @return [String, nil] SO number (e.g. "15.0.0")
    #
    def ui_so_number
      SharedLibInfo.so_number(main_ui_plugin_complete)
    end

    # Find the SO major number of the UI main plug-in.
    #
    # @return [String, nil] SO number (e.g. "15")
    #
    def ui_so_major
      SharedLibInfo.so_major(main_ui_plugin_complete)
    end

    # Return the name of a UI extension plug-in with SO number for the current
    # UI main plug-in.
    #
    # Example:
    #   "pkg" for "libyui-qt.so.15.0.0" -> "libyui-qt-pkg.so.15.0.0"
    #   "pkg" for "libyui-ncurses.so.15.0.0" -> "libyui-ncurses-pkg.so.15.0.0"
    #
    # @param ext [String] Short name for the UI extension ("pkg", "graph")
    # @return [String] lib name without path for that extension and the current UI
    #
    def ui_extension_plugin(ext)
      (ui_name, so_number) = SharedLibInfo.split_lib_name(main_ui_plugin_complete)
      return nil if ui_name.nil?

      SharedLibInfo.build_lib_name("#{ui_name}-#{ext}", so_number)
    end

    # Return the complete name (with path) of a UI extension plug-in with SO
    # number for the current UI main plug-in.
    #
    # Example:
    #   "pkg" for "/usr/lib64/yui/libyui-qt.so.15.0.0" -> "/usr/lib64/yui/libyui-qt-pkg.so.15.0.0"
    #   "pkg" for "/usr/lib64/yui/libyui-ncurses.so.15.0.0" -> "/usr/lib64/yui/libyui-ncurses-pkg.so.15.0.0"
    #
    # @param ext [String] Short name for the UI extension ("pkg", "graph")
    # @return [String] lib name with path for that extension and the current UI
    #
    def ui_extension_plugin_complete(ext)
      return nil if main_ui_plugin_complete.nil?

      File.join(File.dirname(main_ui_plugin_complete), ui_extension_plugin(ext))
    end

    # Return the package name (with standard SUSE libyui package naming
    # conventions) for a UI extension for the current UI main plug-in.
    #
    # Example:
    #   "pkg" for "libyui-qt.so.15.0.0" -> "libyui-qt-pkg15"
    #   "pkg" for "libyui-ncurses.so.15.0.0" -> "libyui-ncurses-pkg15"
    #
    # @param ext [String] Short name for the UI extension ("pkg", "graph")
    # @return [String] package name for that extension and the current UI
    #
    def ui_extension_pkg(ext)
      ui = main_ui_plugin
      return nil if ui.nil?

      "libyui-#{ui}-#{ext}#{ui_so_major}"
    end
  end
end