yast / yast-yast2

YaST module yast2
http://en.opensuse.org/Portal:YaST
GNU General Public License v2.0
54 stars 44 forks source link

Get Information about Shared Libs and Plug-ins and Missing UI Extension Handling #1194

Closed shundhammer closed 2 years ago

shundhammer commented 2 years ago

Trello

https://trello.com/c/gT8nMq7O/2635-3-featureshouldhave-handle-more-gracefully-when-libyui-libraries-are-missing

Jira

Problem

When a user installed the system with "no recommends", i.e. recommended packages were not installed, the resulting system will also not have the Qt-Pkg (YQPackageSelector) plug-in because the libyui-qt-pkg package is not required unconditionally.

So when the user starts the YaST control center in the graphical (Qt) version and wants to start the YaST package management module from there, this will fail with a very obscure error message telling the user that "UI plug-in qt-pkg could not be loaded".

Desired Outcome

Give the user a much better message so there is a realistic chance to fix the problem.

Minimum: Give a hint that the package needed for that action was not installed, of course including what package that was.

Better: Open a pop-up dialog explaining the situation and offering to try to install that package directly from there, and give a hint to the alternative: Start the package management module in the NCurses version.

Infrastructure for the Solution

This PR adds a class SharedLibInfo to query the system what shared libs were loaded in the running process, and a more specialized subclass UIPluginInfo that gives more specific information about UI plug-ins among those loaded shared libs.

The SharedLibInfo base class uses the (very handy) /proc/self/maps file to collect that information. That file contains information about all memory-mapped objects which includes all shared libs and all dlopen()'ed files (which includes our UI plug-ins).

Sample /proc/self/maps:

https://github.com/yast/yast-yast2/blob/huha-plugins/library/system/test/data/proc-maps/proc-maps-qt

UI Plug-Ins

UIPluginInfo uses that to find shared libs that follow the directory and naming convention for libyui plug-ins, i.e. all shared libs in a subdirectory yui/ somewhere that start with the libyui- prefix. The one with the shortest base name among them is considered the UI main plug-in, regardless of what UI is currently being used; this does not limit the strategy to the well-known Qt and NCurses UIs, but leaves room for further development.

In practice, a YaST process running the Qt UI might have those loaded:

with the NCurses UI, it might be those instead:

In practice, when this class is used to check if a UI extension like "-pkg" or "-graph" is available, there will only be one of them, libyui-qt or libyui-ncurses.

The UiPluginsInfo class also provides some methods to build a full path for a UI extension that may or may not be available, based on the currently used UI main plugin's path and SO number; and also for the name of the package that should (per our conventions) include that extension.

UI Developer Support

This can (and should) be used to check if the plug-in is actually there, and if it's there in the right directory and with the right libyui SO number: In the directory from where the UI will attempt to load the extension.

That means that it even covers cases where a developer needs to bump the libyui SO version, yet (since that part is still under development) there is no package available yet: If everything is done correctly, it will check for a plug-in libyui-qt-pkg.so.42.0.0 from a development plug-in directory /work/devel/lib/yui if the UI was loaded from /work/devel/lib/yui/libyui-qt.so.42.0.0, and if that actually exists, it will not insist to install a nonexistent package libyui-qt-pkg42 which would very much block that developer's work.

Caveat

Those classes are not meant for UI layout micro-tweaking. Do not use them to check if the UI is running in graphical or in text mode and then use a different layout or different margins; that would pretty much defeat the purpose of having a back-end-transparent UI engine. Use UI capabilities instead (see the UI reference documentation) if needed.

If you find they are not granular enough, please let's discuss that and add new capabilities instead; or, better yet, let's find a way to avoid the need to get down to that level of UI implementation detail.

Using the Infrastructure: Handling Missing UI Extension Plug-Ins

Since we need this in several YaST modules, making use of this infrastructure went to this same package, so all that we need in the YaST application parts are now 3 lines of code:

  require "ui/ui_extension_checker"
  ...
  ...
  ui_extension_checker = UIExtensionChecker.new("pkg")
  return unless ui_extension_checker.ok?

  # Run the package selection

This will take care of the rest:

Notice that it doesn't matter at all if the package was previously installed or not; this works even if you messed up your system manually.

Screenshots

need-pkg-installed-qt

need-pkg-installed-ncurses

Related PRs

coveralls commented 2 years ago

Coverage Status

Coverage increased (+0.3%) to 41.218% when pulling 9f2248719ae15b3c15bf69609c6f7f230a056d8f on huha-plugins into 8f7e70920370d9e03e34145b9b1036ce81bf07ca on master.

yast-bot commented 2 years ago

:heavy_check_mark: Public Jenkins job #325 successfully finished :heavy_check_mark: Created OBS submit request #919267

yast-bot commented 2 years ago

:heavy_check_mark: Internal Jenkins job #163 successfully finished :heavy_check_mark: Created IBS submit request #252142