1use std::path::PathBuf;
2
3use clap::{Parser, crate_version};
4use snix_store::utils::ServiceUrlsMemory;
5use url::Url;
6
7fn make_version() -> String {
8 #[allow(unused_mut)]
9 let mut features = String::new();
10 #[cfg(feature = "otlp")]
11 {
12 features.push_str("+otlp");
13 }
14 #[cfg(feature = "tracing-chrome")]
15 {
16 features.push_str("+tracing-chrome");
17 }
18 #[cfg(feature = "tracing-tracy")]
19 {
20 features.push_str("+tracing-tracy");
21 }
22 #[cfg(feature = "xp-store-composition-cli")]
23 {
24 features.push_str("+xp-store-composition-cli");
25 }
26 if features.is_empty() {
27 String::from(crate_version!())
28 } else {
29 format!("{} ({features})", crate_version!())
30 }
31}
32
33#[derive(Parser, Clone)]
42#[command(version = make_version())]
43pub struct Args {
44 pub script: Option<PathBuf>,
46
47 #[clap(long, short = 'E')]
48 pub expr: Option<String>,
49
50 #[clap(long, env = "SNIX_DISPLAY_AST")]
52 pub display_ast: bool,
53
54 #[clap(long, env = "SNIX_DUMP_BYTECODE")]
56 pub dump_bytecode: bool,
57
58 #[clap(long, env = "SNIX_TRACE_RUNTIME")]
60 pub trace_runtime: bool,
61
62 #[clap(long, env = "SNIX_TRACE_RUNTIME_TIMING", requires("trace_runtime"))]
65 pub trace_runtime_timing: bool,
66
67 #[clap(long)]
70 pub compile_only: bool,
71
72 #[clap(long)]
74 pub no_warnings: bool,
75
76 #[clap(long = "extra-nix-path", short = 'I', action = clap::ArgAction::Append)]
82 pub extra_nix_paths: Option<Vec<String>>,
83
84 #[clap(long)]
86 pub raw: bool,
87
88 #[clap(long)]
92 pub strict: bool,
93
94 #[clap(flatten)]
95 pub service_addrs: ServiceUrlsMemory,
96
97 #[arg(long, env, default_value = "dummy:")]
98 pub build_service_addr: String,
99
100 #[clap(flatten)]
101 pub tracing_args: snix_tracing::TracingArgs,
102
103 #[clap(long)]
112 pub drv_dumpdir: Option<PathBuf>,
113
114 #[clap(long, default_values_t = [Url::parse("https://tarballs.nixos.org/").unwrap()])]
119 pub hashed_mirrors: Vec<Url>,
120}
121
122impl Args {
123 pub fn nix_path(&self) -> Option<String> {
124 resolve_nix_path(std::env::var("NIX_PATH"), &self.extra_nix_paths)
125 }
126}
127
128fn resolve_nix_path(
129 nix_path: Result<String, std::env::VarError>,
130 extra_nix_paths: &Option<Vec<String>>,
131) -> Option<String> {
132 let nix_path_option = nix_path.ok().filter(|string| !string.is_empty());
133 let extra_nix_paths_option = extra_nix_paths.to_owned().map(|vec| vec.join(":"));
134 match (nix_path_option, extra_nix_paths_option) {
135 (Some(nix_path), Some(mut extra_nix_paths)) => {
136 extra_nix_paths.push(':');
137 Some(extra_nix_paths + &nix_path)
138 }
139 (nix_path_option, extra_nix_paths_option) => nix_path_option.or(extra_nix_paths_option),
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::resolve_nix_path;
146
147 #[test]
148 fn test_resolve_nix_path() {
149 let nix_path = Ok("/nixpath1:nixpath2=/nixpath2".to_owned());
150 let extra_nix_paths = Some(vec!["/extra1".to_owned(), "extra2=/extra2".to_owned()]);
151 let expected = Some("/extra1:extra2=/extra2:/nixpath1:nixpath2=/nixpath2".to_owned());
152 let actual = resolve_nix_path(nix_path, &extra_nix_paths);
153 assert!(actual == expected);
154 let nix_path = Err(std::env::VarError::NotPresent);
155 let extra_nix_paths = Some(vec!["/extra1".to_owned(), "extra2=/extra2".to_owned()]);
156 let expected = Some("/extra1:extra2=/extra2".to_owned());
157 let actual = resolve_nix_path(nix_path, &extra_nix_paths);
158 assert!(actual == expected);
159 let nix_path = Ok("/nixpath1:nixpath2=/nixpath2".to_owned());
160 let extra_nix_paths = None;
161 let expected = Some("/nixpath1:nixpath2=/nixpath2".to_owned());
162 let actual = resolve_nix_path(nix_path, &extra_nix_paths);
163 assert!(actual == expected);
164 let nix_path = Err(std::env::VarError::NotPresent);
165 let extra_nix_paths = None;
166 let expected = None;
167 let actual = resolve_nix_path(nix_path, &extra_nix_paths);
168 assert!(actual == expected);
169 }
170}