Nothing Special   »   [go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System vs user configuration #1406

Closed
spl237 opened this issue Jan 4, 2024 · 25 comments
Closed

System vs user configuration #1406

spl237 opened this issue Jan 4, 2024 · 25 comments

Comments

@spl237
Copy link
Contributor
spl237 commented Jan 4, 2024

Has any consideration been given to system-wide vs user-specific configuration of labwc?

On Raspberry Pi Desktop, I set up most components of the desktop with default configuration options which are installed as part of the packages, or as part of a global configuration package. The user can then apply further customisation, but it means that every user account which is created starts out with the same initial setup.

(It is not possible to install files into the user's directory as part of the installation of a Debian package, so anything which can only be configured with files in the user's directory cannot easily be preconfigured on install.)

For applications which conform to the XDG spec, this is usually achieved by a default system-wide configuration file or files stored in a subdirectory of /etc/xdg, which loads by default, and can then be overridden by files in a subdirectory of ~/.config.

The rather more hack-y alternative is when an application runs, it checks to see if it can find any configuration files in ~/.config, and if not, it copies a default set from somewhere in /etc into ~/.config and then uses them.

I can't find any reference to system vs user configuration of this kind in the documentation, so I assume it isn't currently implemented. (Or is it?) I'm going to need something like this, so am happy to have a look at writing it - would that be something which would be accepted upstream, or is it something I would need to keep for a local version?

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

This sounds like an x-y problem. Why would you expect all users in a multi-user Raspberry Pi to want the same configuration?

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

As one example, I would want them all to have the same set of keyboard bindings.

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

You can always add the config to /etc/skel and let useradd populate the home directory when the user account is created.

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

Yes, but that would only work on initial user creation, though - if I subsequently wanted to, say, add a new keybinding for all users, it wouldn't be possible to update systems which had already had user accounts created. This is why the XDG approach - of a global file which can then be overridden by specific entries in a user-specific file - seems like the best way to do this.

@Consolatis
Copy link
Member
Consolatis commented Jan 4, 2024

We are doing something similar with the theme + ~/.config/labwc/themerc-override already.

Personally, I have no preference either way regarding accepting the same for the config itself (and environment as well I assume?). CC @johanmalm

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

Merging configurations like this is a bad idea. It makes configurations non-obvious and difficult to model mentally. What's worse, it dramatically increases the likelihood that administrative actions (modifying a system configuration) can break established user workflows. This would be extremely frustrating to encounter and even more frustrating to debug, because users will never suspect changes in a config file that is magically included and not under their control.

There may be good arguments for a locally provided default configuration. There may also be good arguments for supporting an <include> directive to allow users to opt into relying on the local default while overriding or adding to it. Nevertheless, unless explicitly requested, user configurations should always supersede, not augment, local defaults.

Edit: note that the theme override mentioned above is entirely analogous to an include directive.

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

Merging configurations like this is a bad idea. It makes configurations non-obvious and difficult to model mentally. What's worse, it dramatically increases the likelihood that administrative actions (modifying a system configuration) can break established user workflows. This would be extremely frustrating to encounter and even more frustrating to debug, because users will never suspect changes in a config file that is magically included and not under their control.

I don't think that is the case. The rule is that a setting made in a user config file always takes precedence over one in a system config file. So pushing changes out can never change settings a user has deliberately made. And it's fundamentally a lot less likely to break a user workflow than a code change which can equally be silently pushed out in an update.

There may be good arguments for a locally provided default configuration. There may also be good arguments for supporting an <include> directive to allow users to opt into relying on the local default while overriding or adding to it. Nevertheless, unless explicitly requested, user configurations should always supersede, not augment, local defaults.

Numerous XDG applications have worked otherwise for decades without problem: I ship 5 or 6 of them as standard parts of the Pi Desktop, and indeed have modified others so that they behave in the same way. (What caused untold problems in the past was trying to work out a way to update configurations for applications which did not support this mechanism - now that did cause many complaints and user confusion, and I really don't want to get back into that situation again!)

As long as you stick to the rule that a user setting always takes priority over a system setting, but that a system setting which is not overridden can be changed, added or removed, in my experience (which is not inconsiderable... ;) ), a global default file which is overridden on a per-parameter basis by a user file is by far the best way to do this.

@Consolatis
Copy link
Member

Just for further input from lxqt regarding this topic: CC @stefonarch

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

User behavior is influenced by the absence of configuration as much as its presence, so any change you make to a user configuration can break workflows where the user is relying on no action. (For example, suppose a user application accepts a particular key combination, which you inadvertently shadow by adding a keybind later.)

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

User behavior is influenced by the absence of configuration as much as its presence, so any change you make to a user configuration can break workflows where the user is relying on no action. (For example, suppose a user application accepts a particular key combination, which you inadvertently shadow by adding a keybind later.)

Yes, but as I said, that is just as possible with code changes as with configuration changes. (And is in fact probably more likely with code changes.) I don't see a fundamental difference between a global configuration change and a code change, not least because any global configuration change can also, by definition, be made by changing the code anyway.

Your argument seems to be that once an application is configured, that configuration should never be changed in case the change causes problems for users. But if you accept that, then you also block any potential for improvements or fixes as well. Applications aren't static, and things move on. The idea is to take care not to break things in the process, but simply saying that you mustn't change anything in case you do break things as a result would put most of us out of a job...

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024
  1. There's a difference between upstream adding new features and deciding how to set new preferences created by these features, and a Linux distribution altering application defaults (and, later, altering their alterations).
  2. Even the upstream, if responsible, should provide a long transition period and plenty of warning when changing or removing existing default behavior, to give users time to realize the change is coming and respond to it.
  3. Distribution-provided configurations like you propose (or emply) necessarily deviate from documented, application-default behavior (otherwise, there would be no need for you to ship them), making these changes even less discoverable than those originating upstream.
  4. Automatic includes that affirmatively set values can be particularly problematic to override when those values are desired unset. Should I really have to write a configuration that defines 50 no-op keybinds just because you decide to ship your 50 preferred keybinds?

All of these points militate against magically merging system configurations. Merging should be opt-in, always. ~/.config/labwc/rc.xml ought to shadow any configuration, but things like <include ...> or support for add-in directory structures like ~/.config/labwc/rc.xml.d which modify a configuration rather than replace it are reasonable ways to allow users to benefit from upstream or distribution-provided configuration changes.

These views have been forged by numerous painful transitions (e.g. moving pipewire from pipewire-media-session to wireplumber) in Void Linux that were hindered by our prior decisions to ship "reasonable" configurations. Distribution-provided configurations can bite not only users, but distribution maintainers as well!

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

You seem to be making a distinction between changing a configuration, and changing code. My contention is that there is fundamentally no difference between the two, at least in terms of potentially disrupting the user experience.

Also, I think you are exaggerating the case somewhat. I cannot think of any situation in which I am going to want to push out 50 new keybindings, for example. But if I add a new feature which requires a single keybinding to enable it, by your argument, that new feature will never become available to any user unless they explicitly find out about it and choose for themselves to enable it. In other words, just to avoid the slight possibility that said new feature will upset the workflow of a small number of users, every other user has to be denied it - that makes no sense to me. I think a degree of pragmatism is required, and that involves a degree of flexibility.

It's not just keybindings, either. Say there is, for example, a configuration parameter which enables or disables some form of hardware acceleration; when the product is launched, that parameter is enabled because hardware acceleration is regarded as a good thing, and then it is discovered that on some platforms it causes instability. By your argument, the only way that parameter can be changed to remove the instability is for users to all individually go in and change it themselves - which again, most won't know that they need to do anyway. Upstream changes happen, and on occasion, it is necessary to make these changes without users necessarily being aware of them, particularly when many users are non-technical and would not know either how to make said changes, or even that they do need to make said changes.

Put it this way - if we decide to use labwc on Pi, I can easily change the default set of keybindings in the code just by modifying the table in rcxml.c. And I can continue to change that in subsequent releases to my heart's content. Not allowing an overridable global configuration file does not prevent exactly the problem you wish to avoid, because I can cause that problem in numerous other ways! But what it does do is to hide that those changes have happened from the user - one advantage of a global configuration file is that it is at least visible to the user, or at least is more visible than a code change.

In contrast to your experience, I have had numerous problems with trying to make changes to configurations which I know that our users both need and will be unable to make themselves. It isn't possible at the first release of a piece of software to know for certain everything that might need to be configured or be configurable at some point in the future, so it is useful to have a mechanism whereby global configuration changes can be made if necessary, rather than simply saying that global configuration changes are always a bad thing and should never happen. Yes, in an ideal world that might be the case, but in reality, stuff like that happens...

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

I think the fundamental difference here is that Void generally applies two basic tenets:

  1. Defer to upstream decisions. As a corollary, providing our own default configurations that are not shipped (and, at least implicitly, documented) is bad practice. We package a lot of different software and are certainly less experienced than the upstream sources in how to use all of it. Why should we impose our own preferences on users?
  2. Users should be reasonably knowledgeable in the principles of Linux and Unix administration. They should also be expected to understand how software may change from one release to the next. After all, they choose to use it. Consequently, we should not try to "improve" user experiences after they have installed and likely configured software to their liking.

I understand that Debian, in general, does not adhere to the first---Debian patches the hell out of everything it ships. I assume that Raspberry Pi carers to hobbyists that may not necessarily satisfy our second tenet. Thus, you and I approach this from a completely different angle.

Most of your needs would seem to be satisfied by the overridable default I've suggested as an alternative---most inexperienced users won't even create a config, so they inherit your changes automatically. Those that do could be served by an include directive or a snippet directory just as well. The advantage of my proposal is that it does not rely on automatic and non-obvious behavior.

My biggest objection to your automatic overlay proposal is not the desire to specify defaults, but the fact that it is not obvious from a glance at ~/.config/labwc/rc.xml where many settings even originate. Explicit is better than implicit!

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

I think we are indeed approaching this from completely different angles!

Your point 2) in particular is the polar opposite of the way we view our user base. My intention with RPiOS was that it should get out of the user's way in the same way as MacOS (or to a lesser extent, Windows) does - that the environment is a means to an end, not an end in itself, and that most users should not need to know the first thing about administering a Unix system. The aim is that someone who has never used Linux before can just boot a Pi to the desktop and find everything in there is recognisable and usable without any prior knowledge. (And I flatter myself that we have mostly succeeded in that...)

And in terms of deferring to upstream decisions - that would be fine if upstream generally made good usability decisions, but sadly that is far too seldom the case. My primary concern is usability, and far too much Linux software is written with usability way down the list of priorities.

So yes, we are very much coming at this from different directions. I need to be able to make the changes that I know users both need and will be unable in most cases to make themselves. In some cases, those changes will upset the more technical users who do know how to - and hence have - configured their systems, but by the same token, that set of users are more likely to be able to recover from said upsets themselves.

The themerc_override file already exists and does all I need to there. My main concern is the contents of rc.xml, and on playing with it this afternoon, I am pretty certain I can achieve all I need to with a few relatively trivial code changes to rcxml.c anyway; I would prefer to be able to do it with an overrideable global file, but as long as I can set the defaults to what I consider to be the optimal setting (mostly setting theme, fonts and a few modifications to keybindings) that is really all I need to do.

I also need to consider how to handle autostart, as I need to autostart panel, desktop etc - again, a global default file would be optimal, but I'm sure there will be other ways to do it.

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

Your view of users, many of whom may be "unable [...] to make" changes on their own, suggests that those users will lack any user-specific configruration. In that case, the mere existence of ~/.config/labwc/rc.xml (or autostart, environment or anything else) ought to be sufficient to conclude that the user is knowledgable and capable of managing the configuration. Thus, when loading a configuration,

  • Create the empty configuration object.
  • Apply any documented default values.
  • If ${XDG_CONFIG_HOME:-${HOME}/.config}/labwc/rc.xml exists, parse it.
  • Otherwise, if ${XDG_CONFIG_DIRS:-/etc/xdg}/labwc/rc.xml exists, parse it.
  • Use the parsed file (if any) to populate the configuration.

Likewise for loading environment or running autostart.

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

Your view of users, many of whom may be "unable [...] to make" changes on their own, suggests that those users will lack any user-specific configruration.

Not the case, sadly. I provide GUI tools to enable users to customise settings which they would otherwise need to edit configuration files to change. I don't expect users to be manually editing config files; I do expect them to be able to change some settings.

So your approach above doesn't work, as the existence of a file in .config does not imply that said file contains all settings.

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

That's an argument better suited to a ~/.config/labwc/rc.xml.d snippet directory and telling your GUI utility to dump a file in there, not making it impossible for users who know what they're doing to replace a system-provided configuration without overriding every single parameter the admin or distribution packager sets. Remember that not all users will have administrative permissions, and they may be unable to control what goes into /etc/xdg.

You want to think for your users, but labwc by design seems to target users who prefer to think for themselves. Destkop environments like macOS or GNOME "get out of the way" for inexperienced users because they impose very opinionated behavior automatically.

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

not making it impossible for users who know what they're doing to replace a system-provided configuration without overriding every single parameter the admin or distribution packager sets.

But that's not what I have proposed! All I am proposing is a mechanism whereby I as the distributor can adjust some of the config values set by the original authors to different defaults. From the user's point of view, they will no more have to "override every single parameter" than they would now. Worst-case is that they might want to override a different set of parameters - because some of the defaults I have changed them to may be ones they want, and some of them may be ones they don't want - but I really can't see that as being some huge imposition. (Not least because the changes I make are invariably ones which I believe make the system better to use, not worse...)

I think we are going around in circles here.

I am going to create some mechanism to change the defaults for labwc, because I need it for my use case. The main purpose of opening this issue was to see if that mechanism was something that would be regarded as useful upstream - if it isn't, fine - I shall simply fork the code. It would be easier if I didn't have to do that - and from my personal experience, such a feature does solve far more problems than it creates - but if others think it is a bad thing, then fair enough.

I can achieve what I need by a simple patch to the defaults in the code, which is much less work than the alternatives.

@Consolatis
Copy link
Member

but labwc by design seems to target users who prefer to think for themselves.

Based on the definition of that group earlier in this thread this is indeed our main target group currently. However, making labwc easier to use for non technical users is also important in my opinion. That is why we for example do not require any configuration at all and instead have a basic set of defaults for theme and key- + mousebinds. There is also https://github.com/labwc/labwc-tweaks for basically the same reason (although that one is not technically part of labwc).

Balancing these two use-cases can be tricky sometimes. I do understand the argument of not being able to (easily) overwrite a system config when not having root permissions on the system. I also do understand the other side.

In my experience (as a long term Debian users, currently Armbian) config files in /etc/ are sometimes kind of annoying because they are somewhat shared between the package maintainer and the (root) user. Modifying a config in /etc/ and than having a package update it often causes issues in either direction.

Just thinking out loud here:

  • we could add a labwc argument to prevent / load a /etc/xdg/labwc/rc.xml file before parsing the user one (opt-in or opt-out)
  • we could go with some kind of <include> variant which would also allow to make the config itself more modular (so it would also cover another use-case). In this case the distro could add some pam stuff to ensure that an empty rc.xml file is created (when none exists on login) that only contains a <include> statement for the system wide config.

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024
  • we could add a labwc argument to prevent / load a /etc/xdg/labwc/rc.xml file before parsing the user one (opt-in or opt-out)

That would definitely work for me.

@ahesford
Copy link
Member
ahesford commented Jan 4, 2024

The primary difference between reading /etc/xdg to replace in-application defaults and my proposed alternatives is that things like mouse and key bindings explicitly require opt-in with a <default /> tag the instant you create an rc.xml with any keybindings of your own.

The list of configuration items which have defaults is finite and well-defined in the documentation, so it's easy for users to figure out what they might want to override. On the contrary, the list of keyboard and mouse bindings that might be placed in /etc/xdg is boundless. Users in the know therefore become responsible for diffing their configuration with whatever the administrator allows to be specified, and might have to itemize a bunch of no-op bindings just to get back to the original configuration.

A command-line argument to switch between merging and overriding configurations seems OK, but I'll argue that any time a distribution puports to think for its users, that should be an opt-in action. The distribution can just launch labwc --merge-configs by default if that behavior should be shipped.

@spl237
Copy link
Contributor Author
spl237 commented Jan 4, 2024

but I'll argue that any time a distribution puports to think for its users, that should be an opt-in action.

As above - that depends on which users your distribution is aimed at. In many cases, that question cannot be phrased in a way in which it is even understandable to a non-technical user.

Many years ago I read a set of UI design guidelines which included the suggestion that "giving the user an option should never be a substitute for the designer making a good decision up front". That is a fundamental philosophy of any UI I design.

@johanmalm
Copy link
Collaborator
johanmalm commented Jan 4, 2024

Thank you for this discussion. It is an important one.

Let me be clear up front: I identify and sympathise with both positions. And I don't say that as a cop out, I carry the emotional baggage from both. For my own setup, I prefer an Arch vanilla approach where I'm more in control of my config files (lazy wording but you know what I mean) and get frustrated on other distros or bigger Desktop Environments when I don't understand config precedence or it changes unexpectedly. However, having been part of the BunsenLabs core team, I'm quite awake to the dilemma. BunsenLabs is a heaviliy configured debian derivative based on Openbox+tint2+picom+conky+nitrogen+etc. There were times when I/we lived with config related issues for long periods when on the whole it would have been better for users if we could have fixed those by changing files in /etc/....

AFAIR the software I used with Openbox setups varied a lot on whether they: (a) define that only the file under the most important base directory should be used, or (b) define rules for merging the information from the different files.

I think either is correct iaw XDG spec. See last paragraph of:
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html

When I first started writing labwc I was very much on my own, so didn't have any discussion on these things and therefore just did what took my fance (which happened to be option (a) above). I did implement XDG Base Dir support though and even split $XDG_CONFIG_DIRS on colon 😄

prefixes = g_strsplit(prefix, ":", -1);

My opinion is that we ought to be flexible enough to support the requirements of both positions because they are both valid. Also, I like distros such as Raspian/LXQt/Lubuntu/BunsenLabs and would like to think that labwc is (or could become) a viable option for them without compromising our philosophy.

I therefore propose that we support:

(a) The current default behaviour as is (i.e. only the file under the most important base directory should be used)
(b) Optionally merge the information from the different files. I don't mind how we make it optional (command line, env var or compile time option). Again, I don't mind if we apply this to all/any of rc.xml, menu.xml, autostart, environment and themerc-override. I suspect there is a valid use case for all.

I do think though that when the command-line option -C is given, we ought to just use one directory with no fallback, to make debugging easier.

I haven't given any thought to implementation details. Guess we'd have to iterate over the XDG base dirs in the opposite direction and load rc.xml et al multiple times before running post_processing(). Probably not a big deal.

Ref:

  • labwc/src/common/dir.c

    Lines 20 to 26 in 6cf19d1

    static struct dir config_dirs[] = {
    { "XDG_CONFIG_HOME", "labwc" },
    { "HOME", ".config/labwc" },
    { "XDG_CONFIG_DIRS", "labwc" },
    { NULL, "/etc/xdg/labwc" },
    { NULL, NULL }
    };

I can't find any reference to system vs user configuration of this kind in the documentation

@johanmalm
Copy link
Collaborator

PS. For this type of stuff we really ought to be able to find an in-tree solution to avoid nugatory work. If you (@spl237) want to do some really wild stuff (subjective of course) then we might have to go out-of-tree, but that should only be after prolonged discussion/consideration in my opinion.

@spl237
Copy link
Contributor Author
spl237 commented Jan 5, 2024

I've submitted a PR with some code which seems to work to allow hierarchical loading of rc.xml, which is the main file in which I need to have specific defaults which are then modified by user-made settings.

Guess we'd have to iterate over the XDG base dirs in the opposite direction and load rc.xml et al multiple times before running post_processing().

Which is pretty much exactly what I did... ;)

I'm not expecting this to be the correct solution, necessarily, but it's an example of something which works for what I need.

johanmalm added a commit to johanmalm/labwc that referenced this issue Jan 17, 2024
Add the -m|--merge-config command line option to iterate backwards over
XDG Base Dir paths and read config/theme files multiple times.

For example if both ~/.config/labwc/rc.xml and /etc/xdg/labwc/rc.xml
exist, the latter will be read first and then the former (if
--merge-config is enabled).

When $XDG_CONFIG_HOME is defined, make it replace (not augment)
$HOME/.config. Similarly, make $XDG_CONFIG_DIRS replace /etc/xdg when
defined.

XDG Base Dir Spec does not specify whether or not an application (or a
compositor!) should (a) define that only the file under the most important
base directory should be used, or (b) define rules for merging the
information from the different files.

ref: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html

In the case of labwc there is a use-case for both positions, just to be
clear, the default behaviour, described by position (a) above, does NOT
change.

This change affects the following config/theme files:
  - rc.xml
  - menu.xml
  - autostart
  - environment
  - themerc
  - themerc-override
  - Theme buttons, for example max.xbm

Instead of caching global config/theme directories, create lists of paths
(e.g.  '/home/foo/.config/labwc/rc.xml', '/etc/xdg/labwc/rc.xml', etc).
This creates more common parsing logic and just reversing the direction
of iteration and breaks early if config-merge is not wanted.

Enable better fallback for themes. For example if a particular theme does
not exist in $HOME/.local/share/themes, it will be searched for in
~/.themes/ and so on. This also applies to theme buttons which now
fallback on an individual basis.

Avoid using stat() in most situations and just go straight to fopen().

Fixes labwc#1406
johanmalm added a commit to johanmalm/labwc that referenced this issue Jan 18, 2024
Add the -m|--merge-config command line option to iterate backwards over
XDG Base Dir paths and read config/theme files multiple times.

For example if both ~/.config/labwc/rc.xml and /etc/xdg/labwc/rc.xml
exist, the latter will be read first and then the former (if
--merge-config is enabled).

When $XDG_CONFIG_HOME is defined, make it replace (not augment)
$HOME/.config. Similarly, make $XDG_CONFIG_DIRS replace /etc/xdg when
defined.

XDG Base Dir Spec does not specify whether or not an application (or a
compositor!) should (a) define that only the file under the most important
base directory should be used, or (b) define rules for merging the
information from the different files.

ref: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html

In the case of labwc there is a use-case for both positions, just to be
clear, the default behaviour, described by position (a) above, does NOT
change.

This change affects the following config/theme files:
  - rc.xml
  - menu.xml
  - autostart
  - environment
  - themerc
  - themerc-override
  - Theme buttons, for example max.xbm

Instead of caching global config/theme directories, create lists of paths
(e.g.  '/home/foo/.config/labwc/rc.xml', '/etc/xdg/labwc/rc.xml', etc).
This creates more common parsing logic and just reversing the direction
of iteration and breaks early if config-merge is not wanted.

Enable better fallback for themes. For example if a particular theme does
not exist in $HOME/.local/share/themes, it will be searched for in
~/.themes/ and so on. This also applies to theme buttons which now
fallback on an individual basis.

Avoid using stat() in most situations and just go straight to fopen().

Fixes labwc#1406
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants