From 7276a065ad5a8ebf4bc1da274c182c95aded7ca1 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 3 Feb 2020 11:28:31 +0100 Subject: [PATCH 1/3] Start of useful Nix-related functions. --- src/main.rs | 1 + src/nix.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/nix.rs diff --git a/src/main.rs b/src/main.rs index 9c4a0d3..6a165c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod cmds; mod config; mod env; mod error; +mod nix; mod status; mod sums; diff --git a/src/nix.rs b/src/nix.rs new file mode 100644 index 0000000..c8f98d1 --- /dev/null +++ b/src/nix.rs @@ -0,0 +1,59 @@ +use std::env::var_os; +use std::path::PathBuf; + +// Find the system-wide nix.conf according to the same rules that Nix uses. +// +// nix.conf(5) has this to say: +// +// Nix reads settings from two configuration files: +// +// - The system-wide configuration file sysconfdir/nix/nix.conf (i.e. +// /etc/nix/nix.conf on most systems), or $NIX_CONF_DIR/nix.conf if +// NIX_CONF_DIR is set. +// +// - The user configuration file $XDG_CONFIG_HOME/nix/nix.conf, or +// ~/.config/nix/nix.conf if XDG_CONFIG_HOME is not set. +// +fn find_system_nix_conf() -> PathBuf { + match var_os("NIX_CONF_DIF") { + Some(nix_conf_dir) => { + // Nix doesn't care if this file exists or not, so we don't either. + PathBuf::from(nix_conf_dir).join("nix.conf") + } + None => { + // It doesn't seem possible or at least obvious how to find out what + // Nix's notion of `sysconfdir` is, so we assume it's /etc for now. + PathBuf::from("/etc/nix/nix.conf") + } + } +} + +// nix.conf(5) explains its format: +// +// The configuration files consist of `name = value` pairs, one per line. +// Other files can be included with a line like `include` path, where `path` +// is interpreted relative to the current conf file and a missing file is an +// error unless `!include` is used instead. Comments start with a # character. +// Here is an example configuration file: +// +// keep-outputs = true # Nice for developers +// keep-derivations = true # Idem +// +// Reading the code for Nix's applyConfigFile clarifies some things: +// +// - When it says "one per line" it means it: there is no way to break +// a setting over multiple lines. +// +// - Characters cannot be escaped, strings cannot be quoted. +// +// - When using include or !include, the filename is used as-is. It cannot +// contain whitespace; that would result in an error. +// +// - Options can contain whitespace (" \r\t") but each run of whitespace is +// normalized into a single space. +// +// - Everything is bytes; there's no encoding or decoding using character sets. +// +// - Included files can be relative paths. These are resolved relative to the +// directory of the file being read. +// From 00c453118961d1abddfd9c924e0c292b3d1204f1 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 3 Feb 2020 12:40:52 +0100 Subject: [PATCH 2/3] Load nix_conf_dir from .firstaide.toml. --- src/config.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/config.rs b/src/config.rs index f7ed361..dd802e6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -52,6 +52,7 @@ pub struct Config { pub build_exe: PathBuf, pub watch_exe: PathBuf, pub direnv_exe: PathBuf, + pub nix_conf_dir: PathBuf, pub parent_dir: PathBuf, pub self_exe: PathBuf, pub messages: Messages, @@ -63,11 +64,32 @@ struct ConfigData { build_exe: PathBuf, watch_exe: PathBuf, #[serde(default)] + nix_conf_dir: NixConfDir, + #[serde(default)] parent_dir: ParentDir, #[serde(default)] messages: Messages, } +#[derive(Debug, Deserialize)] +pub struct NixConfDir(pub PathBuf); + +impl Default for NixConfDir { + fn default() -> Self { + // From nix.conf(5): this is the "system-wide configuration file + // sysconfdir/nix/nix.conf". However,it doesn't seem possible or at + // least obvious how to find out what Nix's notion of `sysconfdir` is, + // so we assume it's /etc for now. + Self("/etc/nix".into()) + } +} + +impl AsRef for NixConfDir { + fn as_ref(&self) -> &Path { + &self.0 + } +} + #[derive(Debug, Deserialize)] pub struct ParentDir(pub PathBuf); @@ -124,6 +146,7 @@ impl Config { build_exe: datum_dir.join(config_data.build_exe).absolutize()?, watch_exe: datum_dir.join(config_data.watch_exe).absolutize()?, direnv_exe: search_path("direnv").ok_or(Error::DirenvNotFound)?, + nix_conf_dir: datum_dir.join(config_data.nix_conf_dir).absolutize()?, parent_dir: datum_dir.join(config_data.parent_dir).absolutize()?, self_exe: env::current_exe()?, messages: config_data.messages, From c7f374a8252b6bc54ce5521be77bcdf834623d44 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 5 Feb 2020 19:13:18 +0100 Subject: [PATCH 3/3] Notes on when to write out a new nix.conf. --- src/cmds/hook.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cmds/hook.rs b/src/cmds/hook.rs index fd1bebd..3f72ffb 100644 --- a/src/cmds/hook.rs +++ b/src/cmds/hook.rs @@ -179,6 +179,16 @@ pub fn run(args: &clap::ArgMatches) -> Result { } }; + // Write out a nix.conf in some situations. + // + // NIX_CONF_DIR nix_conf_dir What to do? + // Nothing + // /some/thing Write new nix.conf, include /etc/nix/nix.conf, then /some/thing. + // /some/thing Nothing + // /some/thing1 /some/thing2 Write new nix.conf, include /some/thing1, then /some/thing2. + + + writeln!(&mut handle, "}} # End.")?; Ok(0)