nu_test_support/harness/
deps.rs1use std::{
2 borrow::Cow,
3 path::PathBuf,
4 process::{Command, Stdio},
5};
6
7#[cfg(feature = "plugin")]
8use nu_protocol::ShellError;
9
10use crate::harness::{BUILD_PROFILE, BUILD_TARGET, TARGET_DIR};
11
12#[non_exhaustive]
13#[derive(derive_more::Debug, Clone, PartialEq, Eq, Hash)]
14pub struct Dependency<'a> {
15 pub bin_name: Cow<'a, str>,
17
18 #[debug("{:?}", format!("cargo build {build_args}"))]
22 build_args: Cow<'a, str>,
23
24 pub is_plugin: bool,
28}
29
30macro_rules! dependency {
31 ($dep:literal) => { pastey::paste! {
32 #[doc = concat!("`", $dep, "`.")]
34 #[doc = concat!("`cargo build --package ", $dep, "`.")]
37 pub const [<$dep:snake:upper>]: &'static Dependency<'static> = &[<$dep:snake:upper _DEP>];
40 static [<$dep:snake:upper _DEP>]: Dependency<'static> =
41 Dependency::new($dep, concat!("--package ", $dep));
42 }}
43}
44
45dependency!("nu");
46dependency!("nu_plugin_custom_values");
47dependency!("nu_plugin_example");
48dependency!("nu_plugin_formats");
49dependency!("nu_plugin_gstat");
50dependency!("nu_plugin_inc");
51dependency!("nu_plugin_polars");
52dependency!("nu_plugin_query");
53dependency!("nu_plugin_stress_internals");
54
55macro_rules! testbin_dependency {
56 ($bin:literal) => { pastey::paste! {
57 #[doc = concat!("`", $bin, "`.")]
59 #[doc = concat!("`cargo build --package testbins --bin ", $bin, "`.")]
62 pub const [< TESTBIN_$bin:snake:upper>]: &'static Dependency<'static> = &[<TESTBIN_ $bin:snake:upper _DEP>];
65 static [<TESTBIN_ $bin:snake:upper _DEP>]: Dependency<'static> =
66 Dependency::new($bin, concat!("--package testbins --bin ", $bin));
67 }}
68}
69
70testbin_dependency!("chop");
71testbin_dependency!("cococo");
72testbin_dependency!("echo_env");
73testbin_dependency!("echo_env_mixed");
74testbin_dependency!("echo_env_stderr");
75testbin_dependency!("echo_env_stderr_fail");
76testbin_dependency!("fail");
77testbin_dependency!("iecho");
78testbin_dependency!("input_bytes_length");
79testbin_dependency!("meow");
80testbin_dependency!("meowb");
81testbin_dependency!("nonu");
82testbin_dependency!("relay");
83testbin_dependency!("repeat_bytes");
84testbin_dependency!("repeater");
85
86impl Dependency<'static> {
87 const fn new(bin_name: &'static str, build_args: &'static str) -> Self {
88 Dependency {
89 bin_name: Cow::Borrowed(bin_name),
90 build_args: Cow::Borrowed(build_args),
91 is_plugin: bin_name.len() >= "nu_plugin".len()
92 && nu_utils::const_str::eq(bin_name.split_at("nu_plugin".len()).0, "nu_plugin"),
93 }
94 }
95
96 pub fn build_command(&self) -> Command {
97 let mut command = Command::new("cargo");
98 command
99 .arg("build")
100 .args(self.build_args.split(" "))
101 .stdout(Stdio::inherit())
102 .stderr(Stdio::inherit());
103
104 if BUILD_PROFILE != "debug" {
105 command.arg(format!("--profile={BUILD_PROFILE}"));
106 }
107
108 if let Some(target) = BUILD_TARGET {
109 command.arg(format!("--target={target}"));
110 }
111
112 for (key, _) in std::env::vars() {
114 #[rustfmt::skip]
115 match key.as_ref() {
116 "CARGO"
117 | "CARGO_MANIFEST_DIR"
118 | "CARGO_MANIFEST_PATH"
119 | "CARGO_MANIFEST_LINKS"
120 | "CARGO_CRATE_NAME"
121 | "CARGO_BIN_NAME"
122 | "OUT_DIR"
123 | "PROFILE"
124 | "OPT_LEVEL"
125 | "DEBUG"
126 | "HOST"
127 | "TARGET" => command.env_remove(key),
128
129 key if key.starts_with("CARGO_PKG_")
130 || key.starts_with("CARGO_CFG_")
131 || key.starts_with("CARGO_FEATURE_")
132 || key.starts_with("CARGO_BIN_EXE_")
133 || key.starts_with("DEP_") => command.env_remove(key),
134
135 _ => &mut command,
136 };
137 }
138
139 command
140 }
141
142 #[track_caller]
146 pub fn bin_dir(&self) -> PathBuf {
147 let target_dir = TARGET_DIR.get().expect("TARGET_DIR is not set");
148 match BUILD_TARGET {
149 Some(target) => target_dir.join(target).join(BUILD_PROFILE),
150 None => target_dir.join(BUILD_PROFILE),
151 }
152 }
153
154 #[track_caller]
158 pub fn path(&self) -> PathBuf {
159 #[cfg(not(windows))]
160 let bin_name = self.bin_name.as_ref();
161
162 #[cfg(windows)]
163 let bin_name = format!("{}.exe", self.bin_name.as_ref());
164
165 self.bin_dir().join(bin_name)
166 }
167
168 #[cfg(feature = "plugin")]
169 pub fn preload_plugin(&self) -> Result<PreloadedPlugin, ShellError> {
170 use nu_plugin_engine::{GetPlugin, PersistentPlugin};
171 use nu_protocol::{PluginIdentity, RegisteredPlugin};
172 use std::sync::Arc;
173
174 let filename = self.path();
175 let identity = PluginIdentity::new(filename, None).expect("valid plugin name");
176 let plugin = Arc::new(PersistentPlugin::new(identity.clone(), Default::default()));
177
178 let interface = plugin.clone().get_plugin(None)?;
179 let metadata = interface.get_metadata()?;
180 plugin.set_metadata(Some(metadata.clone()));
181 let signatures = Arc::from(interface.get_signature()?);
182 drop(interface);
183
184 Ok(PreloadedPlugin {
185 identity: Arc::new(identity),
186 plugin,
187 metadata,
188 signatures,
189 })
190 }
191}
192
193impl Ord for Dependency<'_> {
194 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
195 self.bin_name.cmp(&other.bin_name)
196 }
197}
198
199impl PartialOrd for Dependency<'_> {
200 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
201 Some(self.cmp(other))
202 }
203}
204
205#[cfg(feature = "plugin")]
206#[non_exhaustive]
207#[derive(Debug, Clone)]
208pub struct PreloadedPlugin {
209 pub(crate) identity: std::sync::Arc<nu_protocol::PluginIdentity>,
210 pub(crate) plugin: std::sync::Arc<nu_plugin_engine::PersistentPlugin>,
211 pub(crate) metadata: nu_protocol::PluginMetadata,
212 pub(crate) signatures: std::sync::Arc<[nu_protocol::PluginSignature]>,
213}