### Getting Started with whoami Source: https://nexte.st/rustdoc/whoami?search= This example demonstrates how to use most of the public functions provided by the whoami crate to get various pieces of information about the user and their environment. ```APIDOC ## Getting Started Using the whoami crate is super easy! All of the public items are simple functions with no parameters that return `String`s or `OsString`s (with the exception of `desktop_env()`, `platform()`, and `cpu_arch()`, which return enums, and `lang_prefs()` that returns `LanguagePreferences`). The following example shows how to use all of the functions (except those that return `OsString`): ```rust println!( "User's Language whoami::lang_prefs(): {}", whoami::lang_prefs().unwrap_or_default(), ); println!( "User's Name whoami::realname(): {}", whoami::realname().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::username(): {}", whoami::username().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::account(): {}", whoami::account().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Pretty Name whoami::devicename(): {}", whoami::devicename().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Hostname whoami::hostname(): {}", whoami::hostname().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Platform whoami::platform(): {}", whoami::platform(), ); println!( "Device's OS Distro whoami::distro(): {}", whoami::distro().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Desktop Env. whoami::desktop_env(): {}", whoami::desktop_env () .map(|e| e.to_string()) .unwrap_or_else(|| "".to_string()), ); println!( "Device's CPU Arch whoami::cpu_arch(): {}", whoami::cpu_arch(), ); ``` ``` -------------------------------- ### Getting Started with Whoami Source: https://nexte.st/rustdoc/src/whoami/lib.rs.html This example demonstrates how to use the various functions provided by the whoami crate to get information about the user and their environment. It covers language preferences, real name, username, account name, device name, hostname, platform, distribution, desktop environment, and CPU architecture. ```APIDOC ## Getting Started Using the whoami crate is super easy! All of the public items are simple functions with no parameters that return [`String`]s or [`OsString`]s (with the exception of [`desktop_env()`], [`platform()`], and [`cpu_arch()`], which return enums, and [`lang_prefs()`] that returns [`LanguagePreferences`]). The following example shows how to use all of the functions (except those that return [`OsString`]): ```rust println!( "User's Language whoami::lang_prefs(): {}", whoami::lang_prefs().unwrap_or_default(), ); println!( "User's Name whoami::realname(): {}", whoami::realname().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::username(): {}", whoami::username().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::account(): {}", whoami::account().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Pretty Name whoami::devicename(): {}", whoami::devicename().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Hostname whoami::hostname(): {}", whoami::hostname().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Platform whoami::platform(): {}", whoami::platform(), ); println!( "Device's OS Distro whoami::distro(): {}", whoami::distro().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Desktop Env. whoami::desktop_env(): {}", whoami::desktop_env() .map(|e| e.to_string()) .unwrap_or_else(|| "".to_string()), ); println!( "Device's CPU Arch whoami::cpu_arch(): {}", whoami::cpu_arch(), ); ``` [`OsString`]: std::ffi::OsString [`String`]: std::string::String ``` -------------------------------- ### Getting Started with Whoami Source: https://nexte.st/rustdoc/whoami This example demonstrates how to use various functions from the whoami crate to retrieve user and system information. It covers functions for language preferences, user names, device details, operating system, desktop environment, and CPU architecture. ```APIDOC ## Getting Started Using the whoami crate is super easy! All of the public items are simple functions with no parameters that return `String`s or `OsString`s (with the exception of `desktop_env()`, `platform()`, and `cpu_arch()`, which return enums, and `lang_prefs()` that returns `LanguagePreferences`). The following example shows how to use all of the functions (except those that return `OsString`): ```rust println!( "User's Language whoami::lang_prefs(): {!\n}", whoami::lang_prefs().unwrap_or_default(), ); println!( "User's Name whoami::realname(): {!\n}", whoami::realname().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::username(): {!\n}", whoami::username().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::account(): {!\n}", whoami::account().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Pretty Name whoami::devicename(): {!\n}", whoami::devicename().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Hostname whoami::hostname(): {!\n}", whoami::hostname().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Platform whoami::platform(): {!\n}", whoami::platform(), ); println!( "Device's OS Distro whoami::distro(): {!\n}", whoami::distro().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Desktop Env. whoami::desktop_env(): {!\n}", whoami::desktop_env() .map(|e| e.to_string()) .unwrap_or_else(|| "".to_string()), ); println!( "Device's CPU Arch whoami::cpu_arch(): {!\n}", whoami::cpu_arch(), ); ``` ``` -------------------------------- ### Display Setup Script Start Source: https://nexte.st/rustdoc/src/nextest_runner/reporter/displayer/imp.rs.html Formats and displays the start of a setup script execution. It indicates the 'SETUP' phase and provides an index for the script being run. ```rust writeln!( writer, "{:>12} [{:>9}] {}", "SETUP".style(self.styles.pass), // index + 1 so that it displays as e.g. "1/2" and "2/2". ``` -------------------------------- ### Profile Script Setup Examples Source: https://nexte.st/docs/configuration/reference Define the setup script(s) to run for a profile. This can be a single script name or an array of script names. ```toml setup = "my-setup" ``` ```toml setup = ["setup1", "setup2"] ``` -------------------------------- ### Setup Script Command Examples Source: https://nexte.st/docs/configuration/reference Configure the command to execute for setup scripts. Can be a string, an array of strings, or an object for more complex command-line arguments. ```toml command = "echo hello" ``` ```toml command = ["cargo", "run", "--bin", "setup"] ``` ```toml command = { command-line = "debug/my-setup", relative-to = "target" } ``` -------------------------------- ### Get Setup Scripts Source: https://nexte.st/rustdoc/src/nextest_runner/config/core/imp.rs?search= Returns a slice of deserialized profile script configurations for setup. ```rust pub(in crate::config) fn setup_scripts(&self) -> &[DeserializedProfileScriptConfig] { &self.scripts } ``` -------------------------------- ### Get Pluralized Setup Script String Source: https://nexte.st/rustdoc/nextest_runner/helpers/plural/fn.setup_scripts_str.html Returns 'setup script' if the count is 1, otherwise returns 'setup scripts'. This is useful for generating user-facing messages. ```rust pub fn setup_scripts_str(count: usize) -> &'static str ``` -------------------------------- ### Define Wrapper and Setup Scripts Source: https://nexte.st/rustdoc/src/nextest_runner/config/scripts/imp.rs?search=u32+-%3E+bool Configure wrapper and setup scripts within the `[scripts.wrapper]` and `[[profile.*.scripts]]` sections. This example shows a 'wrapper-script' and a 'setup-script' used in different profiles. ```toml [scripts.wrapper.wrapper-script] command = 'echo wrapper' [[profile.default.scripts]] platform = 'cfg(unix)' setup = ['wrapper-script'] list-wrapper = 'setup-script' [[profile.ci.scripts]] platform = 'cfg(unix)' setup = 'wrapper-script' run-wrapper = 'setup-script' ``` -------------------------------- ### RunStats Setup Script Failure Examples Source: https://nexte.st/rustdoc/src/nextest_runner/reporter/displayer/progress.rs?search=std%3A%3Avec Examples showcasing `RunStats` with setup script failures, including one setup script failed, one setup script execution failed, and one setup script timed out. These are used to verify the reporting of setup script related issues. ```rust RunStats { initial_run_count: 30, setup_scripts_failed: 1, cancel_reason: Some(CancelReason::SetupScriptFailure), ..RunStats::default() } ``` ```rust RunStats { initial_run_count: 35, setup_scripts_exec_failed: 1, cancel_reason: Some(CancelReason::SetupScriptFailure), ..RunStats::default() } ``` ```rust RunStats { initial_run_count: 40, setup_scripts_timed_out: 1, cancel_reason: Some(CancelReason::SetupScriptFailure), ..RunStats::default() } ``` -------------------------------- ### Getting Started with whoami Source: https://nexte.st/rustdoc/whoami?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates how to use various functions from the whoami crate to get user and environment details. Most functions return Option or Option and handle potential errors gracefully. ```APIDOC ## Getting Started Using the whoami crate is super easy! All of the public items are simple functions with no parameters that return `String`s or `OsString`s (with the exception of `desktop_env()`, `platform()`, and `cpu_arch()`, which return enums, and `lang_prefs()` that returns `LanguagePreferences`). The following example shows how to use all of the functions (except those that return `OsString`): ```rust println!( "User's Language whoami::lang_prefs(): {}", whoami::lang_prefs().unwrap_or_default(), ); println!( "User's Name whoami::realname(): {}", whoami::realname().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::username(): {}", whoami::username().unwrap_or_else(|_| "".to_string()), ); println!( "User's Username whoami::account(): {}", whoami::account().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Pretty Name whoami::devicename(): {}", whoami::devicename().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Hostname whoami::hostname(): {}", whoami::hostname().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Platform whoami::platform(): {}", whoami::platform(), ); println!( "Device's OS Distro whoami::distro(): {}", whoami::distro().unwrap_or_else(|_| "".to_string()), ); println!( "Device's Desktop Env. whoami::desktop_env(): {}", whoami::desktop_env() .map(|e| e.to_string()) .unwrap_or_else(|| "".to_string()), ); println!( "Device's CPU Arch whoami::cpu_arch(): {}", whoami::cpu_arch(), ); ``` ``` -------------------------------- ### Write Setup Script Event with Terminating State Source: https://nexte.st/rustdoc/src/nextest_runner/reporter/displayer/imp.rs?search=u32+-%3E+bool This example shows how to write a setup script event where the script is terminating. It includes the script's PID, time taken, and the reason for termination, such as a signal. ```rust reporter .write_event(&TestEvent { timestamp: Local::now().into(), elapsed: Duration::ZERO, kind: TestEventKind::InfoResponse { index: 2, total: 21, response: InfoResponse::SetupScript(SetupScriptInfoResponse { stress_index: None, script_id: ScriptId::new(SmolStr::new("setup-terminating")) .unwrap(), program: "setup-terminating".to_owned(), args: args.clone(), state: UnitState::Terminating(UnitTerminatingState { pid: 5094, time_taken: Duration::from_millis(1234), reason: UnitTerminateReason::Signal, }), }), }, }) ``` -------------------------------- ### Display Setup Script Execution Source: https://nexte.st/rustdoc/src/nextest_runner/reporter/displayer/imp.rs?search= Formats and displays the start of a setup script execution, including its index within a sequence and the total number of scripts. ```rust TestEventKind::SetupScriptStarted { stress_index, index, total, script_id, program, args, .. } => { writeln!( writer, "{:>12} [{:>9}]", "SETUP".style(self.styles.pass), // index + 1 so that it displays as e.g. "1/2" and "2/2". format!("{}/{}", index + 1, total), ); } ``` -------------------------------- ### Setup Script Slow Timeout Examples Source: https://nexte.st/docs/configuration/reference Configure the slow timeout for setup scripts. This can be a simple duration string or an object with more detailed period, terminate-after, and grace-period settings. ```toml slow-timeout = "30s" ``` ```toml slow-timeout = { period = "60s", terminate-after = 1, grace-period = "5s" } ``` -------------------------------- ### Handle Executor Setup Script Started Event Source: https://nexte.st/rustdoc/src/nextest_runner/runner/dispatcher.rs?search=u32+-%3E+bool Manages the 'SetupScriptStarted' event from the executor. It checks for cancellation, sends a request channel to the test task, and initiates a new setup script if the run is not cancelled. ```rust InternalEvent::Executor(ExecutorEvent::SetupScriptStarted { stress_index, script_id, config, program, index, total, req_rx_tx, }) => { if self.run_stats.cancel_reason.is_some() { // The run has been cancelled: don't start any new units. return HandleEventResponse::None; } let (req_tx, req_rx) = unbounded_channel(); // Write the status line before unblocking the executor (same // reasoning as the Started case below). self.basic_callback(TestEventKind::SetupScriptStarted { stress_index, index, total, script_id: script_id.clone(), program, args: config.command.args.clone(), no_capture: config.no_capture(), }); match req_rx_tx.send(req_rx) { Ok(_) => {} // Successfully sent the channel Err(_) => { // The test task died? debug!(?script_id, "test task died, ignoring"); return HandleEventResponse::None; } } self.new_setup_script(script_id, config, index, total, req_tx); HandleEventResponse::None } ``` -------------------------------- ### Handle Setup Script Started Event Source: https://nexte.st/rustdoc/src/nextest_runner/runner/dispatcher.rs.html Manages the `InternalEvent::Executor(ExecutorEvent::SetupScriptStarted)` event. It checks for cancellation, prepares a channel for communication, sends a `TestEventKind::SetupScriptStarted` callback, and initiates the new setup script. ```rust InternalEvent::Executor(ExecutorEvent::SetupScriptStarted { stress_index, script_id, config, program, index, total, req_rx_tx, }) => { if self.run_stats.cancel_reason.is_some() { // The run has been cancelled: don't start any new units. return HandleEventResponse::None; } let (req_tx, req_rx) = unbounded_channel(); // Write the status line before unblocking the executor (same // reasoning as the Started case below). self.basic_callback(TestEventKind::SetupScriptStarted { stress_index, index, total, script_id: script_id.clone(), program, args: config.command.args.clone(), no_capture: config.no_capture(), }); match req_rx_tx.send(req_rx) { Ok(_) => {} // Channel sent successfully Err(_) => { // The test task died? debug!(?script_id, "test task died, ignoring"); return HandleEventResponse::None; } } self.new_setup_script(script_id, config, index, total, req_tx); HandleEventResponse::None } ``` -------------------------------- ### USDT Setup Script Start Probe Macro Source: https://nexte.st/rustdoc/src/nextest_runner/usdt.rs?search= Defines the macro for the `setup__script__start` USDT probe, capturing setup script start details. ```rust $crate::usdt::usdt_probes::setup__script__start!(|| { let probe = $crate::usdt::UsdtSetupScriptStart { $($tt)* }; let id = probe.id.clone(); let script_id = probe.script_id.clone(); let pid = probe.pid; (probe, id, script_id, pid) }) ``` -------------------------------- ### Enable Setup Scripts with Test Queries Source: https://nexte.st/rustdoc/src/nextest_runner/config/scripts/imp.rs Demonstrates enabling setup scripts by creating `TestQuery` objects that match specific binaries and test cases. This is useful for conditionally running scripts. ```rust let nextest_config_result = NextestConfig::from_sources( graph.workspace().root(), &pcx, None, &tool_config_files, &btreeset! { ConfigExperimental::SetupScripts }, ) .expect("config is valid"); let profile = nextest_config_result .profile("default") .expect("valid profile name") .apply_build_platforms(&build_platforms()); // This query matches the foo and bar scripts. let host_binary_query = binary_query(&graph, package_id, "lib", "my-binary", BuildPlatform::Host); let test_name = TestCaseName::new("script1"); let query = TestQuery { binary_query: host_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 2, "two scripts should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "foo", "first script should be foo" ); assert_eq!( scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "bar", "second script should be bar" ); let target_binary_query = binary_query( &graph, package_id, "lib", "my-binary", BuildPlatform::Target, ); // This query matches the baz script. let test_name = TestCaseName::new("script2"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "baz", "first script should be baz" ); // This query matches the baz, foo and tool scripts (but note the order). let test_name = TestCaseName::new("script3"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 3, "three scripts should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "@tool:my-tool:toolscript", "first script should be toolscript" ); assert_eq!( scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "foo", "second script should be foo" ); assert_eq!( scripts.enabled_scripts.get_index(2).unwrap().0.as_str(), "baz", "third script should be baz" ); // This query matches the qux script. let test_name = TestCaseName::new("script4"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "qux", "first script should be qux" ); assert_eq!( scripts .enabled_scripts .get_index(0) .unwrap() .1 .config .command .env .get("MODE"), Some("qux_mode"), "first script should be passed environment variable MODE with value qux_mode", ); ``` -------------------------------- ### Querying Setup Scripts with Nextest Source: https://nexte.st/rustdoc/src/nextest_runner/config/scripts/imp.rs?search=std%3A%3Avec Demonstrates how to query for and enable setup scripts based on binary targets and test names. Shows how to verify the enabled scripts and their associated environment variables. ```rust let nextest_config_result = NextestConfig::from_sources( graph.workspace().root(), &pcx, None, &tool_config_files, &btreeset! { ConfigExperimental::SetupScripts }, ) .expect("config is valid"); let profile = nextest_config_result .profile("default") .expect("valid profile name") .apply_build_platforms(&build_platforms()); // This query matches the foo and bar scripts. let host_binary_query = binary_query(&graph, package_id, "lib", "my-binary", BuildPlatform::Host); let test_name = TestCaseName::new("script1"); let query = TestQuery { binary_query: host_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 2, "two scripts should be enabled"); assert_eq!(scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "foo", "first script should be foo"); assert_eq!(scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "bar", "second script should be bar"); let target_binary_query = binary_query( &graph, package_id, "lib", "my-binary", BuildPlatform::Target, ); // This query matches the baz script. let test_name = TestCaseName::new("script2"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!(scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "baz", "first script should be baz"); // This query matches the baz, foo and tool scripts (but note the order). let test_name = TestCaseName::new("script3"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 3, "three scripts should be enabled"); assert_eq!(scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "@tool:my-tool:toolscript", "first script should be toolscript"); assert_eq!(scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "foo", "second script should be foo"); assert_eq!(scripts.enabled_scripts.get_index(2).unwrap().0.as_str(), "baz", "third script should be baz"); // This query matches the qux script. let test_name = TestCaseName::new("script4"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!(scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "qux", "first script should be qux"); assert_eq!(scripts.enabled_scripts.get_index(0).unwrap().1.config.command.env.get("MODE"), Some("qux_mode"), "first script should be passed environment variable MODE with value qux_mode"); ``` -------------------------------- ### Start Command and Get Handle Source: https://nexte.st/rustdoc/src/duct/lib.rs?search=std%3A%3Avec Spawns a child process and returns a Handle, allowing for asynchronous management of the process. The Handle can be shared across threads. This is analogous to `std::process::Command::spawn`. Ensure the command is not run on Windows, as this example is platform-specific. ```rust # use duct::cmd; # fn main() { # if cfg!(not(windows)) { let handle = cmd!("echo", "hi").stdout_capture().start().unwrap(); let output = handle.wait().unwrap(); assert_eq!(b"hi\n".to_vec(), output.stdout); # } # } ``` -------------------------------- ### Querying Setup Scripts with Experimental Feature Source: https://nexte.st/rustdoc/src/nextest_runner/config/scripts/imp.rs?search=u32+-%3E+bool Demonstrates how to enable and query setup scripts when an experimental feature is active. It shows how different queries match various scripts based on binary and test case names. ```rust let nextest_config_result = NextestConfig::from_sources( graph.workspace().root(), &pcx, None, &tool_config_files, &btreeset! { ConfigExperimental::SetupScripts }, ) .expect("config is valid"); let profile = nextest_config_result .profile("default") .expect("valid profile name") .apply_build_platforms(&build_platforms()); // This query matches the foo and bar scripts. let host_binary_query = binary_query(&graph, package_id, "lib", "my-binary", BuildPlatform::Host); let test_name = TestCaseName::new("script1"); let query = TestQuery { binary_query: host_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 2, "two scripts should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "foo", "first script should be foo" ); assert_eq!( scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "bar", "second script should be bar" ); let target_binary_query = binary_query( &graph, package_id, "lib", "my-binary", BuildPlatform::Target, ); // This query matches the baz script. let test_name = TestCaseName::new("script2"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "baz", "first script should be baz" ); // This query matches the baz, foo and tool scripts (but note the order). let test_name = TestCaseName::new("script3"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 3, "three scripts should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "@tool:my-tool:toolscript", "first script should be toolscript" ); assert_eq!( scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "foo", "second script should be foo" ); assert_eq!( scripts.enabled_scripts.get_index(2).unwrap().0.as_str(), "baz", "third script should be baz" ); // This query matches the qux script. let test_name = TestCaseName::new("script4"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "qux", "first script should be qux" ); assert_eq!( scripts .enabled_scripts .get_index(0) .unwrap() .1 .config .command .env .get("MODE"), Some("qux_mode"), "first script should be passed environment variable MODE with value qux_mode" ); ``` -------------------------------- ### Get Delay Before Start Source: https://nexte.st/rustdoc/src/nextest_runner/runner/executor.rs?search=u32+-%3E+bool Retrieves the configured delay before starting the test execution. ```rust pub(super) fn delay_before_start(&self) -> Duration { self.delay_before_start } ``` -------------------------------- ### Emit Setup Script Started Event Source: https://nexte.st/rustdoc/src/nextest_runner/record/chrome_trace.rs Emits a Chrome Trace event when a setup script begins execution. This ensures metadata events are present and logs the script's start. ```rust self.emit_begin( SETUP_SCRIPT_PID, tid, &name, Category::SetupScript, ts_us, None, ); ``` -------------------------------- ### Configure Standard I/O for Setup Script Source: https://nexte.st/rustdoc/src/nextest_runner/runner/executor.rs?search=u32+-%3E+bool Sets up stdin, stdout, and stderr for the setup script's command. Stdout and stderr are piped if capture is enabled and configured. ```rust command_mut.stdin(Stdio::null()); // The --no-capture CLI argument overrides the config. if self.capture_strategy != CaptureStrategy::None { if script.config.capture_stdout { command_mut.stdout(std::process::Stdio::piped()); } if script.config.capture_stderr { command_mut.stderr(std::process::Stdio::piped()); } } ``` -------------------------------- ### Handle Setup Script Execution and Timeouts Source: https://nexte.st/rustdoc/src/nextest_runner/runner/executor.rs?search=u32+-%3E+bool This snippet shows how to execute a setup script and handle its completion or timeout. It includes logic for marking a script as slow, sending notifications, and attempting to terminate the script if it exceeds the allowed time. ```rust let (res, leak_info) = { let res = loop { tokio::select! { () = child_acc.fill_buf(), if !child_acc.fds.is_done() => {} res = child.wait() => { // The setup script finished executing. break res; } _ = &mut interval_sleep, if status.is_none() => { // Mark the script as slow. cx.slow_after = Some(slow_timeout.period); timeout_hit += 1; let will_terminate = if let Some(terminate_after) = slow_timeout.terminate_after { NonZeroUsize::new(timeout_hit as usize) .expect("timeout_hit was just incremented") >= terminate_after } else { false }; if !slow_timeout.grace_period.is_zero() { let _ = resp_tx.send(script.slow_event( // Pass in the slow timeout period times timeout_hit, since // stopwatch.elapsed() tends to be slightly longer. timeout_hit * slow_timeout.period, will_terminate.then_some(slow_timeout.grace_period), )); } if will_terminate { // Attempt to terminate the slow script. As there is // a race between shutting down a slow test and its // own completion, we silently ignore errors to // avoid printing false warnings. // // The return result of terminate_child is not used // here, since it is always marked as a timeout. _ = super::os::terminate_child( &cx, &mut child, &mut child_acc, child_pid_for_kill, InternalTerminateReason::Timeout, stopwatch, req_rx, job.as_ref(), slow_timeout.grace_period, ).await; status = Some(ExecutionResult::Timeout { result: slow_timeout.on_timeout }); if slow_timeout.grace_period.is_zero() { break child.wait().await; } // Don't break here to give the wait task a chance to finish. } else { interval_sleep.as_mut().reset_last_duration(); } } recv = req_rx.recv() => { // The sender stays open longer than the whole loop, and the buffer is big // enough for all messages ever sent through this channel, so a RecvError // should never happen. let req = recv.expect("a RecvError should never happen here"); match req { RunUnitRequest::Signal(req) => { #[cfg_attr(not(windows), expect(unused_variables))] let res = handle_signal_request( &cx, &mut child, &mut child_acc, child_pid_for_kill, self.interceptor.should_send_sigtstp(), req, stopwatch, interval_sleep.as_mut(), req_rx, job.as_ref(), slow_timeout.grace_period ).await; // On Unix, the signal the process exited with // will be picked up by child.wait. On Windows, // termination by job object will show up as } } } }; }; // ... rest of the code ... }; ``` -------------------------------- ### Firing USDT Probe for Setup Script Start Source: https://nexte.st/rustdoc/src/nextest_runner/runner/executor.rs?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Triggers a User-level Statically Defined Trace (USDT) probe to signal the start of a setup script execution. This includes various metadata about the script and run. ```rust crate::fire_usdt!(UsdtSetupScriptStart { id: script .script_id .unique_id(self.run_id, script.stress_index.map(|s| s.current)), run_id: self.run_id, script_id: script.script_id.to_string(), pid: child_pid, program: script.program.clone(), args: script.config.command.args.clone(), stress_current: script.stress_index.map(|s| s.current), stress_total: script.stress_index.and_then(|s| s.total_get()), }); ``` -------------------------------- ### Setup Scripts Source: https://nexte.st/rustdoc/src/nextest_runner/config/core/imp.rs?search= Returns the list of setup scripts. ```APIDOC ## setup_scripts ### Description Returns the list of setup scripts. ### Method `pub fn setup_scripts(&self, test_list: &TestList<'_>) -> SetupScripts<'_>` ``` -------------------------------- ### Manage Running Setup Script Source: https://nexte.st/rustdoc/src/nextest_runner/runner/dispatcher.rs?search=std%3A%3Avec Manages the state of a running setup script, ensuring only one is active at a time. Use when starting or finishing a setup script. ```rust fn finish_setup_script(&mut self) { let prev = self.running_setup_script.take(); debug_assert!( prev.is_some(), "existing setup script expected, but already exists: {prev:?}", ); } ``` ```rust fn new_setup_script( &mut self, id: SetupScriptId<'a>, config: SetupScriptConfig<'a>, index: usize, total: usize, req_tx: UnboundedSender>, ) { let prev = self.running_setup_script.replace(ContextSetupScript { id, config, index, total, req_tx, }); debug_assert!( prev.is_none(), "new setup script expected, but already exists: {prev:?}", ); } ``` -------------------------------- ### Enable Setup Scripts with Experimental Feature Source: https://nexte.st/rustdoc/src/nextest_runner/config/scripts/imp.rs.html Demonstrates enabling setup scripts by including `ConfigExperimental::SetupScripts` in the configuration. This snippet shows how to query for scripts based on binary and test case names, verifying that the correct scripts are enabled. ```rust let nextest_config_result = NextestConfig::from_sources( graph.workspace().root(), &pcx, None, &tool_config_files, &btreeset! { ConfigExperimental::SetupScripts }, ) .expect("config is valid"); let profile = nextest_config_result .profile("default") .expect("valid profile name") .apply_build_platforms(&build_platforms()); // This query matches the foo and bar scripts. let host_binary_query = binary_query(&graph, package_id, "lib", "my-binary", BuildPlatform::Host); let test_name = TestCaseName::new("script1"); let query = TestQuery { binary_query: host_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 2, "two scripts should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "foo", "first script should be foo" ); assert_eq!( scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "bar", "second script should be bar" ); let target_binary_query = binary_query( &graph, package_id, "lib", "my-binary", BuildPlatform::Target, ); // This query matches the baz script. let test_name = TestCaseName::new("script2"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "baz", "first script should be baz" ); // This query matches the baz, foo and tool scripts (but note the order). let test_name = TestCaseName::new("script3"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 3, "three scripts should be enabled"); assert_eq!( scripts.enabled_scripts.get_index(0).unwrap().0.as_str(), "@tool:my-tool:toolscript", "first script should be toolscript" ); assert_eq!( scripts.enabled_scripts.get_index(1).unwrap().0.as_str(), "foo", "second script should be foo" ); assert_eq!( scripts.enabled_scripts.get_index(2).unwrap().0.as_str(), "baz", "third script should be baz" ); // This query matches the qux script. let test_name = TestCaseName::new("script4"); let query = TestQuery { binary_query: target_binary_query.to_query(), test_name: &test_name, }; let scripts = SetupScripts::new_with_queries(&profile, std::iter::once(query)); assert_eq!(scripts.len(), 1, "one script should be enabled"); assert_eq!( scripts .enabled_scripts .get_index(0) .unwrap() .0.as_str(), "qux", "first script should be qux" ); assert_eq!( scripts .enabled_scripts .get_index(0) .unwrap() .1 .config .command .env .get("MODE"), Some("qux_mode"), "first script should be passed environment variable MODE with value qux_mode" ); ``` -------------------------------- ### Emit Setup Script End Event Source: https://nexte.st/rustdoc/src/nextest_runner/record/chrome_trace.rs?search= Emits a 'Setup Script End' event for Chrome Trace. Validates that a corresponding 'Setup Script Start' event was seen. This is called when a setup script finishes. ```rust } => { // Validate that a matching SetupScriptStarted was seen. if !self.running_scripts.contains_key(&index) { return Err(ChromeTraceError::MissingScriptStart { script_id: script_id.clone(), }); } let tid = index as u64 + TID_OFFSET; let script_id_str = script_id.as_identifier().as_str().to_string(); let script_name = script_id.to_string(); let end_args = ChromeTraceArgs::SetupScriptEnd(SetupScriptEndArgs { script_id: script_id_str, time_taken_ms: duration_to_millis(run_status.time_taken), result: run_status.result.clone(), is_slow: run_status.is_slow, stress_index: stress_index.as_ref().map(StressIndexArgs::new), error: run_status.error_summary.as_ref().map(ErrorSummaryArgs::new), }); self.emit_end( SETUP_SCRIPT_PID, tid, &script_name, Category::SetupScript, end_us, Some(end_args), ); self.running_script_count = self.running_script_count.saturating_sub(1); self.emit_counter_event(end_us); self.running_scripts.remove(&index); } ``` -------------------------------- ### Example CLI usage and output Source: https://nexte.st/rustdoc/clap/index.html Demonstrates how to use the defined CLI arguments and shows the expected output for help and a basic command execution. Placeholders are used for version and platform-specific extensions. ```bash $ demo --help A simple to use, efficient, and full-featured Command Line Argument Parser Usage: demo[EXE] [OPTIONS] --name Options: -n, --name Name of the person to greet -c, --count Number of times to greet [default: 1] -h, --help Print help -V, --version Print version $ demo --name Me Hello Me! ``` -------------------------------- ### Execute Setup Script Future Source: https://nexte.st/rustdoc/src/nextest_runner/runner/executor.rs?search=u32+-%3E+bool Defines an asynchronous future to execute a setup script. It handles sending setup script start events, receiving setup requests, running the script, and sending completion events. ```rust let script_fut = async move { let (req_rx_tx, req_rx_rx) = oneshot::channel(); let _ = this_resp_tx.send(ExecutorEvent::SetupScriptStarted { stress_index, script_id: script_id.clone(), config, program: program.clone(), index, total, req_rx_tx, }); let mut req_rx = match req_rx_rx.await { Ok(req_rx) => req_rx, Err(_) => { // The receiver was dropped -- the dispatcher has // signaled that this unit should exit. return None; } }; let packet = SetupScriptPacket { stress_index, script_id: script_id.clone(), config, program: program.clone(), }; let status = self .run_setup_script(packet, &this_resp_tx, &mut req_rx) .await; // Drain the request receiver, responding to any final requests // that may have been sent. drain_req_rx(req_rx, UnitExecuteStatus::SetupScript(&status)); let status = status.into_external(); let env_map = status.env_map.clone(); let _ = this_resp_tx.send(ExecutorEvent::SetupScriptFinished { stress_index, script_id, config, program, index, total, status, }); env_map.map(|env_map| (script, env_map)) }; ``` -------------------------------- ### Handle SetupScriptStarted Event Source: https://nexte.st/rustdoc/src/nextest_runner/runner/dispatcher.rs?search=std%3A%3Avec Handles the start of a setup script, including checking for cancellation, creating channels, and reporting the event. If the run is cancelled, it returns early. ```rust InternalEvent::Executor(ExecutorEvent::SetupScriptStarted { stress_index, script_id, config, program, index, total, req_rx_tx, }) => { if self.run_stats.cancel_reason.is_some() { // The run has been cancelled: don't start any new units. return HandleEventResponse::None; } let (req_tx, req_rx) = unbounded_channel(); // Write the status line before unblocking the executor (same // reasoning as the Started case below). self.basic_callback(TestEventKind::SetupScriptStarted { stress_index, index, total, script_id: script_id.clone(), program, args: config.command.args.clone(), no_capture: config.no_capture(), }); match req_rx_tx.send(req_rx) { Ok(_) => {} // Successfully sent the receiver Err(_) => { // The test task died? debug!(?script_id, "test task died, ignoring"); return HandleEventResponse::None; } } self.new_setup_script(script_id, config, index, total, req_tx); HandleEventResponse::None } ``` -------------------------------- ### Get Reader Handle for Command Output Source: https://nexte.st/rustdoc/src/duct/lib.rs?search=std%3A%3Avec Starts a command and returns a ReaderHandle attached to its stdout. This allows for streaming output directly without a background thread. It's recommended to create only one ReaderHandle at a time to prevent child processes from blocking. Ensure the command is not run on Windows, as this example is platform-specific. ```rust # use duct::cmd; # use std::io::prelude::*; # fn main() { # if cfg!(not(windows)) { let mut reader = cmd!("echo", "hi").reader().unwrap(); let mut stdout = Vec::new(); reader.read_to_end(&mut stdout).unwrap(); assert_eq!(b"hi\n".to_vec(), stdout); # } # } ```