snix_cli/
args.rs

1use std::path::PathBuf;
2
3use clap::Parser;
4use snix_store::utils::ServiceUrlsMemory;
5use url::Url;
6
7/// Provides a CLI interface to trigger evaluation using snix-eval.
8///
9/// Uses configured snix-{ca,}store and snix-build components,
10/// and by default a set of builtins similar to these present in Nix.
11///
12/// None of the stores available add to the local `/nix/store` location.
13///
14/// The CLI interface is not stable and subject to change.
15#[derive(Parser, Clone)]
16pub struct Args {
17    /// Path to a script to evaluate
18    pub script: Option<PathBuf>,
19
20    #[clap(long, short = 'E')]
21    pub expr: Option<String>,
22
23    /// Dump the raw AST to stdout before interpreting
24    #[clap(long, env = "SNIX_DISPLAY_AST")]
25    pub display_ast: bool,
26
27    /// Dump the bytecode to stdout before evaluating
28    #[clap(long, env = "SNIX_DUMP_BYTECODE")]
29    pub dump_bytecode: bool,
30
31    /// Trace the runtime of the VM
32    #[clap(long, env = "SNIX_TRACE_RUNTIME")]
33    pub trace_runtime: bool,
34
35    /// Capture the time (relative to the start time of evaluation) of all events traced with
36    /// `--trace-runtime`
37    #[clap(long, env = "SNIX_TRACE_RUNTIME_TIMING", requires("trace_runtime"))]
38    pub trace_runtime_timing: bool,
39
40    /// Only compile, but do not execute code. This will make Snix act
41    /// sort of like a linter.
42    #[clap(long)]
43    pub compile_only: bool,
44
45    /// Don't print warnings.
46    #[clap(long)]
47    pub no_warnings: bool,
48
49    /// Additional entries to the Nix expression search path, a colon-separated list of directories
50    /// used to resolve `<...>`-style lookup paths.
51    ///
52    /// This option may be given multiple times. Paths added through -I take precedence over
53    /// NIX_PATH.
54    #[clap(long = "extra-nix-path", short = 'I', action = clap::ArgAction::Append)]
55    pub extra_nix_paths: Option<Vec<String>>,
56
57    /// Print "raw" (unquoted) output.
58    #[clap(long)]
59    pub raw: bool,
60
61    /// Strictly evaluate values, traversing them and forcing e.g.
62    /// elements of lists and attribute sets before printing the
63    /// return value.
64    #[clap(long)]
65    pub strict: bool,
66
67    #[clap(flatten)]
68    pub service_addrs: ServiceUrlsMemory,
69
70    #[arg(long, env, default_value = "dummy://")]
71    pub build_service_addr: String,
72
73    /// An optional path in which Derivations encountered during evaluation
74    /// are dumped into, after evaluation. If it doesn't exist, the directory is created.
75    ///
76    /// Files dumped there are named like they would show up in `/nix/store`,
77    /// if produced by Nix. Existing files are not overwritten.
78    ///
79    /// This is only for debugging and diffing purposes for post-eval inspection;
80    /// Snix does not read from these.
81    #[clap(long)]
82    pub drv_dumpdir: Option<PathBuf>,
83
84    /// A list of web servers used by builtins.fetchurl to obtain files by hash.
85    /// Given a hash algorithm ha and a base-16 hash h, Nix will try to download the file
86    /// from hashed-mirror/ha/h. This allows files to be downloaded even if they have
87    /// disappeared from their original URI.
88    #[clap(long, default_values_t = [Url::parse("https://tarballs.nixos.org/").unwrap()])]
89    pub hashed_mirrors: Vec<Url>,
90}
91
92impl Args {
93    pub fn nix_path(&self) -> Option<String> {
94        resolve_nix_path(std::env::var("NIX_PATH"), &self.extra_nix_paths)
95    }
96}
97
98fn resolve_nix_path(
99    nix_path: Result<String, std::env::VarError>,
100    extra_nix_paths: &Option<Vec<String>>,
101) -> Option<String> {
102    let nix_path_option = nix_path.ok().filter(|string| !string.is_empty());
103    let extra_nix_paths_option = extra_nix_paths.to_owned().map(|vec| vec.join(":"));
104    match (nix_path_option, extra_nix_paths_option) {
105        (Some(nix_path), Some(mut extra_nix_paths)) => {
106            extra_nix_paths.push(':');
107            Some(extra_nix_paths + &nix_path)
108        }
109        (nix_path_option, extra_nix_paths_option) => nix_path_option.or(extra_nix_paths_option),
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::resolve_nix_path;
116
117    #[test]
118    fn test_resolve_nix_path() {
119        let nix_path = Ok("/nixpath1:nixpath2=/nixpath2".to_owned());
120        let extra_nix_paths = Some(vec!["/extra1".to_owned(), "extra2=/extra2".to_owned()]);
121        let expected = Some("/extra1:extra2=/extra2:/nixpath1:nixpath2=/nixpath2".to_owned());
122        let actual = resolve_nix_path(nix_path, &extra_nix_paths);
123        assert!(actual == expected);
124        let nix_path = Err(std::env::VarError::NotPresent);
125        let extra_nix_paths = Some(vec!["/extra1".to_owned(), "extra2=/extra2".to_owned()]);
126        let expected = Some("/extra1:extra2=/extra2".to_owned());
127        let actual = resolve_nix_path(nix_path, &extra_nix_paths);
128        assert!(actual == expected);
129        let nix_path = Ok("/nixpath1:nixpath2=/nixpath2".to_owned());
130        let extra_nix_paths = None;
131        let expected = Some("/nixpath1:nixpath2=/nixpath2".to_owned());
132        let actual = resolve_nix_path(nix_path, &extra_nix_paths);
133        assert!(actual == expected);
134        let nix_path = Err(std::env::VarError::NotPresent);
135        let extra_nix_paths = None;
136        let expected = None;
137        let actual = resolve_nix_path(nix_path, &extra_nix_paths);
138        assert!(actual == expected);
139    }
140}