start_command/
execution_env.rs1use crate::isolation::isolation_log::shell_quote;
11
12pub const EXECUTION_ID_ENV: &str = "START_EXECUTION_ID";
13pub const SESSION_NAME_ENV: &str = "START_SESSION_NAME";
14pub const ATTEMPT_ENV: &str = "START_ATTEMPT";
15
16pub type ExecutionEnv = Vec<(String, String)>;
18
19pub fn build_execution_env(
21 execution_id: Option<&str>,
22 session_name: Option<&str>,
23 attempt: u64,
24) -> ExecutionEnv {
25 let Some(execution_id) = execution_id.filter(|id| !id.is_empty()) else {
26 return Vec::new();
27 };
28 vec![
29 (EXECUTION_ID_ENV.into(), execution_id.into()),
30 (SESSION_NAME_ENV.into(), session_name.unwrap_or("").into()),
31 (ATTEMPT_ENV.into(), attempt.max(1).to_string()),
32 ]
33}
34
35pub fn execution_env_from_options(options: &crate::isolation::IsolationOptions) -> ExecutionEnv {
38 build_execution_env(
39 options.uuid.as_deref().or(options.execution_id.as_deref()),
40 options.session.as_deref(),
41 options.attempt_number,
42 )
43}
44
45pub fn execution_env_assignments(env: &ExecutionEnv) -> Vec<String> {
47 env.iter()
48 .map(|(key, value)| format!("{}={}", key, value))
49 .collect()
50}
51
52pub fn build_execution_env_export(env: &ExecutionEnv) -> String {
54 if env.is_empty() {
55 return String::new();
56 }
57 let assignments: Vec<String> = env
58 .iter()
59 .map(|(key, value)| format!("{}={}", key, shell_quote(value)))
60 .collect();
61 format!("export {}", assignments.join(" "))
62}
63
64pub fn prefix_with_execution_env(command: &str, env: &ExecutionEnv) -> String {
68 let statement = build_execution_env_export(env);
69 if statement.is_empty() {
70 command.to_string()
71 } else {
72 format!("{}; {}", statement, command)
73 }
74}
75
76pub fn is_nested_launch_of(execution_id: &str, env_execution_id: Option<&str>) -> bool {
80 !execution_id.is_empty() && env_execution_id == Some(execution_id)
81}
82
83pub fn inherited_attempt(value: Option<&str>) -> u64 {
85 value
86 .and_then(|v| v.trim().parse::<u64>().ok())
87 .filter(|n| *n > 0)
88 .unwrap_or(1)
89}