Repository: Canop/bacon (language: rust)

Issue:
Respect `XDG_*` spec even on macos
First, thanks for `bacon`, I  have been trying it out today and its very cool !

`bacon --prefs` always puts its config file the default path for macOS and in `$HOME/.config/bacon/` on Linux. I would for it to respect the `XDG_CONFIG_HOME` env var on both (especially on macOS), it makes it very easy to then add it to a git repos for dotfiles.


Discussion / hints:
As for many Rust projects, I use the [directories-next](https://crates.io/crates/directories-next) crate to get those directories.

I'd rather not try to code myself this logic or add another fork of the xdg related code.

Can you have a look at this crate to see whether they would be willing to do the change, or accept a PR ?


I'll ask there, sorry for the noise
Sorry I wasn't clear. Your issue is perfectly valid. I'd just prefer you to check there's no solution at the directories-next side before we look for one in bacon.
In the meantime, this issue should stay open. Even if there's a fix in directories-next, we'll have to update the dependency and check it works.
Related: https://github.com/xdg-rs/dirs/issues/45
If there's no progress there, we should probably create a small wrapper crate for directories-next handling that `XDG_CONFIG_HOME` env var. The name of this crate won't be pretty though, given we're already at "next".

But why has there been no PR already ?
> If there's no progress there, we should probably create a small wrapper crate for directories-next handling that `XDG_CONFIG_HOME` env var. The name of this crate won't be pretty though, given we're already at "next".
> 
> But why has there been no PR already ?

Cause there is no solution, how the lib would decide if it must follow XDG or mac convention on a mac ? They need to decide what to do first. The current behaviour is correct in my eye.
> Cause there is no solution, how the lib would decide if it must follow XDG or mac convention on a mac ?

Another entry point in the API ? Something like a new type, `UnixXdg`, or a config option acting like a builder `.respect_unix_xdg_spec(true)` that is defined as `fn respect_unix_xdg_spec(self, doit: bool) -> Self` ? I'll see about doing a PR this evening if I can
An option to force a specific convention feel right.
Well, my PR on `dirs-rs` was refused :/
I was more thinking an option on bacon, bacon would either take the default or use the one the user asked. It would require something like `bacon --dirs xdg` and a crate that could make it simple to implement like `get_xdg_dirs()` function
At the very least, `bacon` should have a `--prefs <path>` to point at a global config file.
Something easier to do would be to support a `BACON_CONFIG` env var.
(also, evaluations of alternate crates, eg https://docs.rs/etcetera/latest/etcetera/ are welcome)

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc67320..39f0112 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 - new `exports` structure in configuration. New `analysis` export bound by default to `ctrl-e`. The old syntax defining locations export is still supported but won't appear in documentations anymore.
 - recognize panic location in test - Fix #208
 - `toggle-backtrace` accepts an optional level: `toggle-backtrace(1)` or `toggle-backtrace(full)` - Experimental - Fix #210
+- configuration can be passed in `BACON_PREFS` and `BACON_CONFIG` env vars - Fix #76
 
 <a name="v2.21.0"></a>
 ### v2.21.0 - 2024/09/14
diff --git a/src/cli.rs b/src/cli.rs
index 353834c..640ccce 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -73,6 +73,10 @@ pub fn run() -> anyhow::Result<()> {
         }
     }
 
+    if let Some(config) = Config::from_env("BACON_PREFS")? {
+        settings.apply_config(&config);
+    }
+
     let location = MissionLocation::new(&args)?;
     info!("mission location: {:#?}", &location);
 
@@ -102,6 +106,10 @@ pub fn run() -> anyhow::Result<()> {
         settings.apply_config(&config);
     }
 
+    if let Some(config) = Config::from_env("BACON_CONFIG")? {
+        settings.apply_config(&config);
+    }
+
     // args are applied after prefs, and package config so that they can override them
     settings.apply_args(&args);
 
diff --git a/src/config.rs b/src/config.rs
index 80857c1..36a063c 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -10,7 +10,7 @@ use {
     },
 };
 
-/// A configuration item which may be stored either as `bacon.toml`
+/// A configuration item which may be stored in various places, eg as `bacon.toml`
 /// along a `Cargo.toml` file or as `prefs.toml` in the xdg config directory.
 ///
 /// Leaf values are options (and not Default) so that they don't
@@ -66,6 +66,27 @@ impl Config {
         }
         Ok(conf)
     }
+    pub fn from_env(env_var_name: &str) -> Result<Option<Self>> {
+        let Some(path) = std::env::var_os(env_var_name) else {
+            return Ok(None);
+        };
+        let path = Path::new(&path);
+        if !path.exists() {
+            // some users may want to use an env var to point to a file that may not always exist
+            // so we don't bail here
+            warn!(
+                "Env var {:?} points to file {:?} which does not exist",
+                env_var_name, path
+            );
+            return Ok(None);
+        }
+        let config = Self::from_path(path)?;
+        debug!(
+            "Loaded config at {:?} as specified in env var {:?}",
+            path, env_var_name
+        );
+        Ok(Some(config))
+    }
     pub fn default_package_config() -> Self {
         toml::from_str(DEFAULT_PACKAGE_CONFIG).unwrap()
     }
diff --git a/website/docs/config.md b/website/docs/config.md
index 503a5a7..88ccb04 100644
--- a/website/docs/config.md
+++ b/website/docs/config.md
@@ -1,14 +1,21 @@
 
 # Configuration Files
 
-The behavior of bacon is defined by a global `prefs.toml` file and project specific `bacon.toml` files.
-
-All configuration files are optional but you'll soon need specific jobs for your targets, examples, etc.
+All configuration files are optional but you'll probably need specific jobs for your targets, examples, etc.
 
 All accept the same properties (preferences, keybindings, jobs, etc.).
-The properties of the global `prefs.toml` file are overriden by the workspace level `bacon.toml` file, then by the package level `bacon.toml` file.
 
-When you modified those files and bacon evolved since, you may want to have a look at the current default ones and pick the changes you like:
+Bacon loads its default configuration then, in order:
+
+* the global `prefs.toml` ([global preferences](#global-preferences))
+* the file whose path is in environment variable `BACON_PREFS`
+* the workspace level `bacon.toml` file
+* the package level `bacon.toml` file ([project settings](#project-settings))
+* the file whose path is in environment variable `BACON_CONFIG`
+
+Each configuration file overrides the properties of previously loaded ones.
+
+When you modified those files and bacon evolved since, you may want to have a look at the current default ones:
 
 * [Current default prefs.toml](https://raw.githubusercontent.com/Canop/bacon/main/defaults/default-prefs.toml)
 * [Current default bacon.toml](https://raw.githubusercontent.com/Canop/bacon/main/defaults/default-bacon.toml)


Test patch: