Skip to content

Commit

Permalink
Put implicit knowledge about UI plug-ins and packages into one common…
Browse files Browse the repository at this point in the history
… library class
  • Loading branch information
shundhammer committed Sep 15, 2021
1 parent 3567962 commit 9a289c8
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 30 deletions.
27 changes: 17 additions & 10 deletions library/system/src/lib/yast2/shared_lib_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ def initialize(maps_file = "/proc/self/maps")
read(maps_file)
end

# Return the directory name of a shared lib with a full path.
# This is really only an alias for File.dirname().
#
# @param lib [String] full name (with path) of a shared lib
# @return [String] the directory part of that full name
#
def self.dirname(lib)
File.dirname(lib)
end

# Return the library basename of a shared lib. Unlike File.basename(), this
# also cuts off the SO number.
#
Expand Down Expand Up @@ -107,6 +97,23 @@ def self.split_lib_name(lib)
full_name.split(/\.so\.?/) # ["libscr", "3.0.0"]
end

# Counterpart to split_lib_name: Build a library name from its base name
# and its SO number.
#
# Example:
# "libscr", "3.0.0" -> "libscr.so.3.0.0"
# "libc-2.33", nil -> "libc-2.33.so"
#
# @param basename [String] lib base name without path and SO number
# @param so_number [String] lib SO number or nil or empty
# @return [String]
#
def self.build_lib_name(basename, so_number)
lib_name = basename + ".so"
lib_name += "." + so_number unless so_number.nil? || so_number.empty?
lib_name
end

protected

# Clear all previous content.
Expand Down
98 changes: 78 additions & 20 deletions library/system/src/lib/yast2/ui_plugin_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ class UiPluginInfo < SharedLibInfo
# @param maps_file [String] name of the maps file to use
#
def initialize(maps_file = "/proc/self/maps")
@ui_plugins = nil # Lazy init
super(maps_file)
log.info("Creating SharedLibInfo from #{maps_file}")
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.
Expand All @@ -52,44 +53,101 @@ def ui_plugins
#
def short_name(ui_plugin)
name = SharedLibInfo.lib_basename(ui_plugin)
return nil if name.nil?
name&.gsub(/^libyui-/, "")
end

name.gsub(/^libyui-/, "")
# 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?

@main_ui_plugin_complete ||= ui_plugins.min do |a, b|
SharedLibInfo.lib_basename(a).size <=> SharedLibInfo.lib_basename(b).size
end
@main_ui_plugin_complete
end

# Find the main UI plug-in (if there are several).
# This is generally the one with the shortest name.
# 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
return nil if ui_plugins.empty?

plugins = ui_plugins.map { |p| SharedLibInfo.lib_basename(p) }
main_plugin = plugins.min { |a, b| a.size <=> b.size }
short_name(main_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
ui_short_name = main_ui_plugin
return nil if ui_short_name.nil?

plugin = ui_plugins.find { |p| p =~ /#{ui_short_name}\.so/ }
SharedLibInfo.so_number(plugin)
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
so = ui_so_number
return nil if so.nil?
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?

so.split(".").first
"libyui-#{ui}-#{ext}#{ui_so_major}"
end
end
end
134 changes: 134 additions & 0 deletions library/system/test/ui_plugin_info_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ def stored_proc_maps(scenario)
end
end

describe "#main_ui_plugin_complete" do
let(:subject) { described_class.new(maps_file) }

# Just one context for this since the other cases are implicitly already
# tested with main_ui_plugin
context "with the Qt UI + Qt-Pkg extension" do
let(:maps_file) { stored_proc_maps("qt-pkg") }

it "identifies the UI as \"/usr/lib64/yui/libyui-qt.so.15.0.0\"" do
expect(subject.main_ui_plugin_complete).to eq "/usr/lib64/yui/libyui-qt.so.15.0.0"
end
end
end

describe "#ui_so_number" do
let(:subject) { described_class.new(maps_file) }

Expand Down Expand Up @@ -169,4 +183,124 @@ def stored_proc_maps(scenario)
end
end
end

describe "#ui_extension_plugin" do
let(:subject) { described_class.new(maps_file) }

context "empty" do
let(:maps_file) { nil }

it "does not crash and burn" do
expect(subject.ui_extension_plugin("pkg")).to eq nil
end
end

context "with the Qt UI" do
let(:maps_file) { stored_proc_maps("qt") }

it "returns the -pkg counterpart" do
expect(subject.ui_extension_plugin("pkg")).to eq "libyui-qt-pkg.so.15.0.0"
end
end

context "with the Qt UI + Qt-Graph extension" do
let(:maps_file) { stored_proc_maps("qt-graph") }

it "returns the -pkg counterpart" do
expect(subject.ui_extension_plugin("pkg")).to eq "libyui-qt-pkg.so.15.0.0"
end
end

context "with the NCurses UI" do
let(:maps_file) { stored_proc_maps("ncurses") }

it "returns the -pkg counterpart" do
expect(subject.ui_extension_plugin("pkg")).to eq "libyui-ncurses-pkg.so.15.0.0"
end
end

context "without any UI" do
let(:maps_file) { stored_proc_maps("no-ui") }

it "returns nil" do
expect(subject.ui_extension_plugin("pkg")).to eq nil
end
end
end

describe "#ui_extension_plugin_complete" do
let(:subject) { described_class.new(maps_file) }

context "empty" do
let(:maps_file) { nil }

it "does not crash and burn" do
expect(subject.ui_extension_plugin_complete("pkg")).to eq nil
end
end

context "with the Qt UI" do
let(:maps_file) { stored_proc_maps("qt") }

it "returns the -pkg counterpart" do
expect(subject.ui_extension_plugin_complete("pkg")).to eq "/usr/lib64/yui/libyui-qt-pkg.so.15.0.0"
end
end

context "with the NCurses UI" do
let(:maps_file) { stored_proc_maps("ncurses") }

it "returns the -pkg counterpart" do
expect(subject.ui_extension_plugin_complete("pkg")).to eq "/usr/lib64/yui/libyui-ncurses-pkg.so.15.0.0"
end
end

context "without any UI" do
let(:maps_file) { stored_proc_maps("no-ui") }

it "returns nil" do
expect(subject.ui_extension_plugin_complete("pkg")).to eq nil
end
end
end

describe "#ui_extension_pkg" do
let(:subject) { described_class.new(maps_file) }

context "empty" do
let(:maps_file) { nil }

it "does not crash and burn" do
expect(subject.ui_extension_pkg("pkg")).to eq nil
end
end

context "with the Qt UI" do
let(:maps_file) { stored_proc_maps("qt") }

it "returns the correct package name for the -pkg UI extension" do
expect(subject.ui_extension_pkg("pkg")).to eq "libyui-qt-pkg15"
end

it "returns the correct package name for the -graph UI extension" do
expect(subject.ui_extension_pkg("graph")).to eq "libyui-qt-graph15"
end
end

context "with the NCurses UI" do
let(:maps_file) { stored_proc_maps("ncurses") }

it "returns the correct package name for the -pkg UI extension" do
expect(subject.ui_extension_pkg("pkg")).to eq "libyui-ncurses-pkg15"
end
end

context "without any UI" do
let(:maps_file) { stored_proc_maps("no-ui") }

it "returns nil" do
expect(subject.ui_extension_pkg("pkg")).to eq nil
end
end
end
end

0 comments on commit 9a289c8

Please sign in to comment.