tvix_cli/
args.rs

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