snix_cli/
args.rs

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