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

Config file management #7

Open
spacekookie opened this Issue Feb 20, 2018 · 67 comments

Comments

Projects
None yet
@spacekookie
Copy link
Collaborator

spacekookie commented Feb 20, 2018

(moderated summary by WG)

Context

Plan of Action

In-ecosystem resources

External inspiration

Challenges

  • Cross platform paths in config files. See also #10
  • Integrating information from environment, command line arguments, defaults, and cascading config files
  • Every existing applications is probably littered with special cases, migration schemes and special rules how settings are handled. I'm not sure it is possible to encode all this into an API without making it extremely hard to use.
  • Good error messages, see serde-rs/serde#1184

@spacekookie's original poist

In the first meeting, we discussed the task of file management on different platforms (particularly configurations) and how it can be made better.

@Eijebong summarised it like this

If I need a config file, I don't want to know that it should be ${XDG_CONFIG:${XDG_HOME}/.config:/home/${user}/.config on linux, %AppDir%/App/ on windows and something else on osx [...]

There is a crate for "determing system configuration" (app-dirs-rs) but it seems unmaintained and not up to date

@spacekookie spacekookie changed the title File Management Config file management Feb 20, 2018

@killercup

This comment has been minimized.

Copy link
Collaborator

killercup commented Feb 20, 2018

The configure crate by @withoutboats abstract about configuration in general (as the name suggests), but doesn't seem to have an adapter for configuration files right now (except for Cargo.toml, but that's not the use case we have in mind I guess).

@kbknapp

This comment has been minimized.

Copy link
Collaborator

kbknapp commented Feb 20, 2018

I think it'd good to lay out some requirements for a crate(s) that would fill this gap:

  • Accepts a file name to either load/save
  • Abstracts away platform specific paths (i.e. as the application developer I only want to say, "myapp.conf" and have the crate handle where and how "myapp.conf" gets loaded/saved

I'd be OK with having multiple sub crates for various platforms, and then a "parent" crate that allows abstracting over the platform where all I do is specify a file name I want to load/save.

@kbknapp

This comment has been minimized.

Copy link
Collaborator

kbknapp commented Feb 20, 2018

Bonus if the crate can allow me to search custom directories, or tweak the order (on platforms where applicable).

@withoutboats

This comment has been minimized.

Copy link

withoutboats commented Feb 20, 2018

but doesn't seem to have an adapter for configuration files right now (except for Cargo.toml, but that's not the use case we have in mind I guess).

Nope, the configure crate's default "source" is definitely designed for use cases where the person configuring the application is also the author - such as network services. However, the intent is for libraries to use configure, so that the application author can have total control over the source of configuration.

A configuration source that integrates with configure and is designed for CLIs would be a great addition, and possibly one I'd be interested in upstreaming into configure proper.

@yoshuawuyts

This comment has been minimized.

Copy link
Collaborator

yoshuawuyts commented Feb 21, 2018

I'm thinking this issue might be part of a bigger topic.

  • How do we store user-created configuration files cross-platform? (So far this issue has only touched on this one specifically. E.g. Linux $HOME/.config)
  • Where do we store temporary files cross-platform? (Does not need to persist between boots, e.g. Linux /tmp.).
  • How do we store essential user data files cross-platform? (Stuff like login tokens, usually generated by applications. E.g. $HOME/.local on Linux.)
  • How do we store non-essential data files cross-platform? (Needs to persist between boots, e.g. Linux $HOME/.cache.)

It's probably uncommon for a single application to use all of these, but one or more should be common enough. It feels like these questions are part of the same problem; perhaps it might be useful to consider all of these questions as part of this discussion?

@spacekookie

This comment has been minimized.

Copy link
Collaborator Author

spacekookie commented Feb 21, 2018

For the question of temporary files there is already a crate which seems to do its job quite nicely (though I've only used it in limited scenarios so far, maybe it can be improved!)

As for the rest…I think it would be pretty cool if we could create (or find and improve existing) crates that mirror the same behaviour for other configuration, essential and non-essential data files as well.

It should be as simple as saying Configdir::new("my_app_name") and being able to write and read configurations from it.

Edit Just as I hit "Comment" I found this crate here

@killercup

This comment has been minimized.

Copy link
Collaborator

killercup commented Feb 21, 2018

Hi, @soc! The Rust CLI working group is talking about cross-platform configuration file management and your directories crate has come up. Looking at your Github profile, I see you have a Java directories package as well, so you seem have some expertise in this area. Wanna chime in here? :)

@soc

This comment has been minimized.

Copy link

soc commented Feb 21, 2018

@killercup Sure, how can I help?

@killercup

This comment has been minimized.

Copy link
Collaborator

killercup commented Feb 21, 2018

@soc awesome! We were currently doing some research about the status quo of crates that are useful when writing CLI tools, work cross-platform and are maintained. For example, we want to come up with a good story around how to easily configure a CLI tool—with config files, env vars, and CLI flags. This issue is focussing on the handling of config files. @kbknapp already listed some good requirements in #7 (comment).

Do you think directories is a good foundation here? What are your plans for it? Can we help you get it to 1.0? :)

(@spacekookie and @yoshuawuyts probably have more to say!)

@soc

This comment has been minimized.

Copy link

soc commented Feb 22, 2018

For example, we want to come up with a good story around how to easily configure a CLI tool—with config files, env vars, and CLI flags.

directories is intentionally focused solely on dealing with operating system defaults.
The reasoning for this is not because I believe that other venues for configuration are not important, but to provide the most minimal, focused and stable API I can get away with.

For instance, when dealing with CLI flags, the first issue you have is that of style (-h and --help vs. -help; -xyz vs -x, -y, -z; key=value vs. key value; and that's just Linux/macOS ... Windows has its own, different rules with /h etc.).
There is potentially a lot of complexity and moving parts involved when trying to provide an CLI interface that makes everyone happy.

Do you think directories is a good foundation here?

I do think that directories is a good foundation for dealing with the operating system standards part of your goals.

I believe that dealing with CLI flags should probably be done in a separate library, or in a way more specific to the individual application's needs, because dealing with CLI flags is very application-specific.

In the end individual applications already need to have some custom code anyway to deal with migrating from storing their data directly in $HOME to following the platform standards. Dealing with CLI flags will probably be the same.

That's why directories only tells developers which directories they should be using, but does not get involved with creating directories itself, or making decisions about the priority of multiple directories (for instance platform defaults vs. CLI flags vs. config files).

Application-specific code will be required to handle such issues, and I want directories to avoid getting involved in that: Often the cost of complexity to solve such issues in a general fashion in a library is way higher than dealing with it on the application side, especially when handling (legacy) applications with their own folder in $HOME – without breaking things for existing users.

Here is an example of an application that makes use of directories (the JVM version) and deals with migration compatibility, property files, and application-specific env vars: coursier/coursier#676.

What are your plans for it? Can we help you get it to 1.0? :)

My plan is to declare it as stable as fast as possible. I think the main blockers are

  • having more people use and test it, to make sure it works
  • a thorough review of the decisions made concerning the various paths chosen (by someone who isn't me): soc/directories-rs#2
  • a review of the Windows-specific code: soc/directories-rs#1
@soc

This comment has been minimized.

Copy link

soc commented Feb 22, 2018

I have created tickets for the remaining issues I mentioned: soc/directories-rs#1 and soc/directories-rs#2.

@soc

This comment has been minimized.

Copy link

soc commented Feb 22, 2018

A more general note: There is a vast difference between selecting and standardizing on crates that provide certain functionality (like CLI parsing, config file parsing) and having one standardized way of handling application configuration:

With the former you probably get crates that do almost everything and allow configuration of almost everything.

With the latter, you want to be highly selective and make actual choices how things can be specified, and not allow a free for all in terms of decisions a developer can make.

@killercup

This comment has been minimized.

Copy link
Collaborator

killercup commented Feb 22, 2018

As you've noticed, I've opened some issues at directories-rs. I'd hold off on releasing a 1.0 before there are some consumers of the crate.


There is a vast difference between selecting and standardizing on crates that provide certain functionality (like CLI parsing, config file parsing) and having one standardized way of handling application configuration

Absolutely. We already have some great libraries for CLI args, and I'd love to have an equally as good story for dealing with config files. That is not one crate – it's several build on top of and complementing each other :)

(We'll hopefully see more concrete proposals for this in #6!)

@spacekookie

This comment has been minimized.

Copy link
Collaborator Author

spacekookie commented Feb 22, 2018

I think the focus should be less on a config file format and more on an API to get to those files. As a developer I might still want to be able to chose a format, say json or toml or ini via whatever serde backend exists to read/ write my configuration files. But I don't want to have to worry about where to put it.

Not sure why you brought up CLI parsing. Although thinking about it now, I'm not sure how clap.rs handles windows arguments 😅

I haven't had a chance to play around with your crate yet but from the README it looks like it already exposes pretty much all the directory paths we might be interested in. At that point it becomes a question of making the API more ergonomic. i.e. maybe there could be a function to easily list configuration files for the given application (or None if there are none), etc

@killercup

This comment has been minimized.

Copy link
Collaborator

killercup commented Feb 22, 2018

Not sure why you brought up CLI parsing.

I brought it up, sorry :)

So, I've been thinking about what an all-around config solution might look like. We should not implement such a thing right now, but discuss what needs to happen to get there!


Here's a small proposal that integrates ideas from clap (v3, this is future!) and configure to get the discussion going:

#[derive(Debug, Deserialize, Clap, Configure)]
#[config(prefix = "diesel")]
struct Args {
    #[clap(short = "q", long = "quiet")]
    quiet: bool,
    #[clap(long = "database-url")]
    database_url: bool,
    #[clap(subcommands)]
    command: DieselCliCommand, // an enum defining subcommands with their own fields and attributes
}

fn main() {
    let args = Args::configure()
        .read_from(configure::adaptors::config_file::toml("diesel_cli.toml")) // Invokes serde
        .read_from(configure::adaptors::env_file()) //  dotenv
        .read_from(configure::adaptors::env()) // std::env
        .read_from(configure::adaptors::clap_auto_init()); // Clap incl. early exit on `-h` and stuff like that
}

You can then:

  • pass --database-url=something.sqlite
  • execute the program with env DIESEL_DATABASE_URL=something.sqlite
  • Have a .env file with DIESEL_DATABASE_URL=something.sqlite
  • Have a ~/.config/diesel_cli.toml file

Is that approximately the direction in which you want to go? What needs to happen to get there?

@TeXitoi

This comment has been minimized.

Copy link

TeXitoi commented Feb 22, 2018

I think the CLI/conf/env story should be in another issue.

@killercup

This comment has been minimized.

Copy link
Collaborator

killercup commented Feb 22, 2018

Sure, that was just for inspiration and to set some context. (If you have other use cases/ideas, please tell us :))

@TeXitoi

This comment has been minimized.

Copy link

TeXitoi commented Feb 22, 2018

I have a couple of request in the structopt issues about that (no ideas, but persons wanting something like #7 (comment))

@kbknapp

This comment has been minimized.

Copy link
Collaborator

kbknapp commented Feb 22, 2018

Like @spacekookie said, I think it should focus on abstracting over platform specific issues and not on the format, or providing "key->value" style API.

As the application writer, I want to just specify a file name, and let this crate handle where to store it. I then worry about formats, reading/writing, etc.

Then later on someone could write a generic crate to abstract over this configure crate, using something like serde to give a key->value style API.

Here's how I see the crate structure playing out (note, the crate names are just generic and not referring to anything existing right now).

config

@Screwtapello

This comment has been minimized.

Copy link

Screwtapello commented Mar 2, 2018

At a former employer, I wrote a config file management library (in Python) that turned out to be popular with my fellow developers (because it was easy to add to an existing project) and with our operations staff (because all our tools worked the same way, and the configuration was flexible enough for most of our use-cases). It worked like this:

  • an application would include a configuration file containing all the generic defaults, in the Python ConfigParser format (basically, an INI file)
  • the application calls into the library, passing the application name and the defaults file
  • the library reads the defaults
  • the library reads /etc/xdg/$appname/config.cfg (the standard XDG system-wide config directory, if it exists) and overlays those settings on top of the defaults
  • the library reads ~/.config/$appname/config.cfg (the standard XDG per-user config directory, if it exists` and overlays those settings on top of the defaults
  • For each section and key in the combined configuration, the library would build a string like $appname_$section_$key and upper-case it. If an environment variable with that name existed, its value would replace the value loaded from the config files
  • the library returns the fully-populated configuration data to the application

Pros:

  • The application only needs to call a single function.
  • The defaults file can contain all the possible config settings, example values and even documentation for them
    • maybe not the best possible location for such things, but still better than "scattered across the application in each bit of code that reads a config variable"
  • System-wide configuration is useful for provisioning tools like Ansible/Puppet/Chef/etc. that deploy the tool to automatically configure it to work on that host (for example, setting a default HTTP proxy, or picking a geographically close rendezvous server)
  • Per-user configuration means users can set things up the way they like them
  • Environment variable configuration means one tool can launch another tool and force some configuration option it needs (like output format, or log file name)
  • At each stage, you can override some defaults without replacing all of them
    • for example, you can use Ansible/Puppet/Chef/etc. to change the "default HTTP proxy" in the system-wide config without worrying about users who have created their own config missing out
  • Because the INI format is limited, overlaying configuration files is simple, with predictable results

Cons:

  • It can be difficult to fit an application's configuration needs into the limited vocabulary of INI files
  • With no configuration schema, the application has to do all the deserialization/validation work itself
  • If a config section foo has key bar_baz, and section foo_bar has key baz, both will be mapped to the environment variable $appname_FOO_BAR_BAZ and there isn't really any way around that.
  • There's no good way to extend this to CLI parsing, not least because it would be impossible to generate decent --help output from the limited information we have

If I were to attempt something similar in Rust:

  • I'd try to find a way to build it around a configuration schema object (following the model of serde and structopt) instead of tossing around raw config files
  • I'd probably leave the environment-variable config the same; it's clunky but we didn't need it very often, so it wasn't a problem in practice
  • I'd absolutely 100% require the ability to overlay config files for different sources, though—I don't know how that would work exactly with richer data formats than INI, but I'd have to find a way
@Screwtapello

This comment has been minimized.

Copy link

Screwtapello commented Mar 2, 2018

I think the focus should be less on a config file format and more on an API to get to those files.

One reason to consider a standard config file format, or at least a standard config data model: on Windows, perhaps the standard configuration source could/should be the Registry, rather than the filesystem?

@soc

This comment has been minimized.

Copy link

soc commented Mar 2, 2018

After some research on that, it seems that most developers recommend and prefer files over the registry:

@derekdreery

This comment has been minimized.

Copy link

derekdreery commented Mar 2, 2018

Since this thread is about the location of config files rather than their contents this may be a bit off topic, but here goes anyway:

Similar to how structopt works, I'd love to do

#[derive(Structconfig)]
pub struct Config {
    timeout: u8
    #[structconfig(name="retries", default=3)]
    no_of_retries: u8,
    files: Vec<PathBuf>,
}

and have all the config stuff taken care of for me!

Edit:

I'd try to find a way to build it around a configuration schema object (following the model of serde and structopt) instead of tossing around raw config files

Didn't see that it had already been suggested.

@derekdreery

This comment has been minimized.

Copy link

derekdreery commented Mar 2, 2018

@Screwtapello

How did your code deal with first run, if there wasn't a config file? Did it assume you wanted to use the defaults, or did it exit and prompt you to create a config file? (or did it walk you through creating the config file interactively?)

@Screwtapello

This comment has been minimized.

Copy link

Screwtapello commented Mar 2, 2018

@derekdreery

At first run, it would use the defaults. For the various tools we created, every config option always had a sensible out-of-the-box default. Things the program absolutely could not know without asking would generally be command-line arguments, not config options.

It's a big world, and I'm sure there's some potential config options that cannot possibly have a sensible default, but I can't think of one right now. If anyone has an example, I'd love to hear it.

@epage

This comment has been minimized.

Copy link
Collaborator

epage commented Mar 9, 2018

Another aspect of config management to consider is passwords. Looks like there is a keyring crate that could use some polish and advertising.

@kalefranz

This comment has been minimized.

Copy link

kalefranz commented Mar 13, 2018

Hey everyone. I'm the current dev lead of conda, which is a cross-platform, system-level package manager. Currently written in python--but we're in the initial stages of considering transitioning key pieces to rust.

Just wanted to add to this discussion how we do configuration, because it's been powerful and has worked out very well. It's also very similar to what @Screwtapello described.

For each invocation of our executable, we build up a configuration context object from four sources of configuration information:

  1. hard-coded default values
  2. (potentially multiple) configuration files, including support for files in ".d" directories
  3. environment variables
  4. command line flags

These are linearized in a way that the configuration sources conceptually closest to the process invocation take precedence. That is, if a configuration parameter is provided as a CLI flag, but also provided in a configuration file, the CLI-provided value would win. I guess the insight here is that most CLI applications deal with at least one configuration file, environment variables, and CLI flags anyway, and we've just realized that they all represent basically the same type of information, and can be generalized and unified.

One capability that was especially important for us to add was the ability for sysadmins to lock down configuration for the entire system in "lower-level" read-only files. As we merge the sources of configuration information, we provide a flag sort of like the css !important that lets the lower-level value be the final value.

I don't want to go into too much detail here. There's a blog post with more details, including how we deal with merging sequence and map-type configuration parameters. I did want to point all this out though as support for the usefulness of what @Screwtapello described.

@Screwtapello

This comment has been minimized.

Copy link

Screwtapello commented Mar 13, 2018

As we merge the sources of configuration information, we provide a flag sort of like the css !important that lets the lower-level value be the final value.

An alternative model that achieves the same goal is to have separate "config" and "override" files:

  • system-wide config
    • per-user config
      • environment variables and command-line flags
    • per-user overrides
  • system-wide overrides

The advantage over an !important flag is that you don't need special syntax in your config-file format (and therefore serde, etc.) while the disadvantage is that you have nearly twice as many config locations to document, and for users to check when diagnosing surprising behaviour.

@epage

This comment has been minimized.

Copy link
Collaborator

epage commented Mar 23, 2018

@i30817 is your concern with reading/writing a config file on the same system or sharing config files across systems?

If sharing across systems, can you give more concrete details so we can flesh out what the requirements are for this?

@i30817

This comment has been minimized.

Copy link

i30817 commented Mar 23, 2018

sharing across systems. Common usecase is placing user readable/writable cfg files which contain relative paths to some dir (of a portable app or app that can be made portable like firefox, or dolphin or retroarch) in a flash drive.

Supposedly users can use 'a/relative/path' syntax in windows. In practice, nearly all C and C++ programs/fileformat parsers blow up with this kind of relative path because they only ifdef _WIN32 '\' else '/' etc.

There are complications with forbidden characters that are legal on one platform but not in another (unix to windows mostly).

The vast majority of user made inputs to paths accepts both relative and absolute (when that is poison to moving systems). Which is kind of terrible, because the only way a user will get to have portable files is to use relative paths when possible but every cfg file and nearly all commands are determined to let the input be generalized to absolute paths.

It would be nice if the cfg format generalized a 'relative to the cfg dir' path function/standard requiring a user readable relative path with '/', and returns a (current platform) normalized absolute to the cfg (optionally with another absolute parent dir overload?).

In my mind this means early validation and early failure of corner cases and usecases that the user might have decided are 'necessary' (placing a absolute path, spaces without quotes, using a 'forbidden' character from OSes (besides '/' and closed quotes) on the 'relative path' etc).

I wouldn't actually mind if there is also another clearly marked function that parses 'exotic' relative or absolute paths for the current running platform without this harsh early failure though (ie things like c:\home/relativejoin or a/relative), it should help to prevent the ifdef idiocy above. But that's basically the stdlib job and a library for cfg should promote the portable case.

The only thing i'd regret is that this hack would also be useful for fileformats that insist on user readable paths like .cue for example, not only cfgs and might not be reinvented by several implementations like cue parsers in a attempt at 'generality'. But as long as PathBuf can deal with "a/relative with space" path on Windows, the very worst case is avoided for those formats because programmer laziness works for correctness here (unlike in C). But for cfg i believe you can do better, thus this request to make the 'default' path entries return a path relative to the cfg that is OS portable or fail hard (this could also be a constructor setting i guess).

@Dylan-DPC

This comment has been minimized.

Copy link
Collaborator

Dylan-DPC commented Apr 7, 2018

We have opened a "RFC-lite" on confy with reference to this. Do leave your feedback.

@sharkdp

This comment has been minimized.

Copy link

sharkdp commented May 24, 2018

The directories crate has been mentioned a few times in this ticket. I have recently started to use it in one of my command-line tools and now this issue came up: sharkdp/bat#151. Do people here have any opinion on this? Should command-line tools on macOS use ~/Library/Preferences or ~/.config?

@soc

This comment has been minimized.

Copy link

soc commented May 24, 2018

@i30817 Interesting, I played with exactly this idea a few weeks ago:

  • Have one standard serialization format used to read/write paths from/to config riles
  • Rule out "dangerous" characters in paths
  • Provide absolute path placeholders (e. g. you can say "this is an absolute path starting from e. g. the OS' config directory" and have it return the appropriate absolute directory for each platform) so that one can share config files with paths across operating systems.
@i30817

This comment has been minimized.

Copy link

i30817 commented May 24, 2018

Yeah, well i reconsidered point 2 myself. I don't mind it being a warning during development, but i don't think it should be forced. Especially since most cli config paths are not controlled by devs but by the user and sometimes they themselves don't control what another tool/user named the files (imagine a file database that is using utf-8). Now i'm thinking that it should be a option to emit a warning about it, but not a 'kill the whole program' error.

@soc

This comment has been minimized.

Copy link

soc commented May 24, 2018

Yeah ... my approach comes with the expectation that developers are in control of their config file names. I think that's a reasonable assumption in 90% of the cases.

In general, I think there is no having the cake and eating it: either you rule out the various OS' filesystem craziness, or you allow it and have the complexity go through the roof.

I think there is value in having some crate that says "if you don't depend on the crazy parts of Windows path handling, this crate makes your life way easier".

@i30817

This comment has been minimized.

Copy link

i30817 commented May 24, 2018

It's true that is a concern more of other files that interact more with user paths that the typical config file (though 'last used recent path' in unix is a frequent exception), but i'm thinking that point 1 and 3 are sufficiently valuable that you want to give the ability for them to be used in those paths.

@soc

This comment has been minimized.

Copy link

soc commented May 24, 2018

@sharkdp It would be even more correct to use Apple's plist format if you write configuration to ~/Library/Preferences, but that's why the API avoids making any judgement on what you do with the paths directories gives you.

(If I have some time in the future, I'd love to propose some RFC for Redox that overhauls config handling (using a config: scheme) there and extend directories to support it.)

@i30817 I pushed https://github.com/soc/paths-rs which is a rough sketch of my approach.

@pickfire

This comment has been minimized.

Copy link

pickfire commented Jul 10, 2018

https://crates.io/crates/dirs looks like a good choice for me even with it's limited features but the API is a lot simpler compared to https://crates.io/crates/directories.

@soc

This comment has been minimized.

Copy link

soc commented Jul 10, 2018

Yes, that's intentional, dirs just exposes individual functions, but if you want to derive paths for applications then you should absolutely use directories' ProjectDirs instead.

@tvannahl tvannahl referenced this issue Jul 27, 2018

Closed

First draft of CLI website #46

2 of 2 tasks complete
@kbd

This comment has been minimized.

Copy link

kbd commented Nov 15, 2018

Should command-line tools on macOS use ~/Library/Preferences or ~/.config?

I would strongly expect any command line tool to use XDG standard location for config. There is no command line tool I know of that stores its config in ~/Library/Preferences. I know I'm not alone in source-controlling my dotfiles in ~/.config -- while not source-controlling anything in ~/Library/Preferences -- so storing config in ~/Library/Preferences makes that less convenient.

Besides the lack of consistency in storing things in one location on Linux and another on Mac, if Rust utilities alone start storing things in ~/Library/Preferences it's going to be a Java Swing-style uncanny-valley sign of "this is a Rust app".

@soc

This comment has been minimized.

Copy link

soc commented Nov 16, 2018

@kbd As a bit of data: dirs and directories have been out for a while, and I have received no complaints about those libraries adhering to macOS conventions in general.

@lavifb

This comment has been minimized.

Copy link

lavifb commented Dec 7, 2018

I would like to second @kbd. Command line tools are often cross-platform for *nix and as a result the config files are stored similarly to the way they do on Linux, at ~/.config. It doesn't make much sense to store them in a harder to reach and less *nix-y place like ~/Library/Preferences.

@reitermarkus

This comment has been minimized.

Copy link

reitermarkus commented Dec 28, 2018

I can only confirm what @kbd and @lavifb are saying. I have yet to see a CLI tool which uses ~/Library/Preferences for configuration files.

@bitwalker

This comment has been minimized.

Copy link

bitwalker commented Feb 4, 2019

Just wanted to chime in with my two cents here as well, this actually caught me off guard recently with a tool I was using, llvmenv, which I was making some changes to. It instructed me (and I would've expected no different) to put files in $XDG_CONFIG_HOME/llvmenv, and that a variety of other associated files (cache, data) would be put in other XDG directories accordingly. I did so, but the tool wasn't picking up my config, and I assumed it was a bug of some kind. It was only after I dug through llvmenv, traced through to dirs, that I realized what was going on. It is highly unusual in my experience to find command line tooling with support for XDG that does not honor it on macOS - so unusual that I don't think the author of that tool even realized this was happening on macOS.

If the default directories end up in ~/Library or wherever, then I think it should be a convention that if the XDG_* env vars are set, that those directories are used instead. If they are set, that is a strong indication that the user expects those paths to be used in place of whatever other conventions the OS uses.

I basically never assume configs or other data associated with my shell environment are going to end up anywhere other than in the XDG base directories I have set, or in the worst case, my home directory - but I would never even think to look in ~/Library/Preferences for that kind of thing.

For tooling I build, I certainly will be overriding this behaviour in dirs or any other such library I use so that XDG is always honored first.

@soc

This comment has been minimized.

Copy link

soc commented Mar 31, 2019

I closed soc/directories-rs#47, please have a look at the explanation in soc/directories-rs#47 (comment) for details.

In this case, ~/Library/Caches is the problem.

In general, if I had a buck for every time I heard "I shouldn't need to follow the platform's standards because of X" I could have retired multiple times already. Stuff like this is way we can't have nice things.

@sharkdp

This comment has been minimized.

Copy link

sharkdp commented Apr 4, 2019

@soc I understand that you do not want to include this in directories-rs, which probably also targets other (GUI) applications.

However, as we have heard from multiple people in this thread (and multiple people in bats issue tracker), the official standard (~/Library/Preferences) on MacOS does not seem to be followed by any command line applications, whereas the XDG-standard seems to be used quite a lot. In this case, I'd rather listen to the actual users and follow what other command-line applications do, instead of following the "official standard". This is why I feel that there is a need for a directories-rs-like library that uses the XDG-standard on both Linux/MacOS and the "Known Folders" on Windows.

@lavifb

This comment has been minimized.

Copy link

lavifb commented Apr 4, 2019

Also I'm not sure I understand the cache problem. Is it a big problem that cached files for CLI apps might be backed up? CLI caches do not tend to be that big in my experience.

But even if it were a big problem, this is not a reason config files can't be placed in ~/.config. People don't manually look at or edit caches very often. Config files, on the other hand, are very important especially in CLI applications. There is often no other way to configure these apps. Placing these files in a convenient and generally agreed upon location for users shouldn't be dismissed out of hand.

@soc

This comment has been minimized.

Copy link

soc commented Apr 4, 2019

@sharkdp

However, as we have heard from multiple people in this thread (and multiple people in bats issue tracker), the official standard (~/Library/Preferences) on MacOS does not seem to be followed by any command line applications, whereas the XDG-standard seems to be used quite a lot. In this case, I'd rather listen to the actual users and follow what other command-line applications do, instead of following the "official standard".

The difference between Linux and macOS is that Linux is a system written by developers, for developers.

On the other hand., macOS is built by Apple, owned by Apple and controlled by Apple. The opinions of developers frankly doesn't matter on macOS – they are not calling the shots. If Apple ever decides to clamp down on applications not following their rules, I'm not going to take responsibility for the ensuing breakage.

Just as a reminder,

does not seem to be followed by any command line applications

is an excuse I heard more often than I care to count on Linux, too.

directories-rs does exactly what it says on the tin: it follows the platforms standards.

@soc

This comment has been minimized.

Copy link

soc commented Apr 4, 2019

@lavifb

Is it a big problem that cached files for CLI apps might be backed up? CLI caches do not tend to be that big in my experience.

Pretty much every dependency manager on this planet is a CLI app. Have a look at the caches of Maven, npm or cargo. The cache directories are huge.

@lavifb

This comment has been minimized.

Copy link

lavifb commented Apr 4, 2019

@lavifb

Is it a big problem that cached files for CLI apps might be backed up? CLI caches do not tend to be that big in my experience.

Pretty much every dependency manager on this planet is a CLI app. Have a look at the caches of Maven, npm or cargo. The cache directories are huge.

But all of those store cache in the home dir on MacOS:

More importantly, their config files are not buried somewhere deep in preferences but are all easily accessible in the home dir.

@soc

This comment has been minimized.

Copy link

soc commented Apr 4, 2019

Yes, I hope you now understand the issue with that (on both Linux and macOS).

@lavifb

This comment has been minimized.

Copy link

lavifb commented Apr 4, 2019

@soc
I think we just have different philosophies for this kind of library. Thanks for explaining your reasoning

@sharkdp

This is why I feel that there is a need for a directories-rs-like library that uses the XDG-standard on both Linux/MacOS and the "Known Folders" on Windows.

I do, however, think there is room for another crate that makes a different tradeoff here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.