Skip to main content

treeboot_core/
status.rs

1use std::path::PathBuf;
2
3use serde::Serialize;
4
5use crate::check::WorktreeSnapshot;
6use crate::context;
7use crate::{
8    Config, EnvironmentInput, IgnoredInitScript, InitScriptDiscovery, Result, Worktree,
9    WorktreeOptions,
10};
11
12/// Options for inspecting treeboot discovery status.
13#[derive(Debug, Clone, Default, PartialEq, Eq)]
14pub struct StatusOptions {
15    /// Directory from which status discovery starts.
16    pub cwd: Option<PathBuf>,
17    /// Overrides the root checkout used for discovery.
18    pub root: Option<PathBuf>,
19    /// Explicit environment input used for compatibility discovery.
20    pub environment: EnvironmentInput,
21    /// Uses one specific config file instead of config discovery.
22    pub config: Option<PathBuf>,
23    /// Skips init script discovery.
24    pub no_init_script: bool,
25}
26
27/// Init script discovery status for a worktree.
28#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
29#[serde(tag = "status", rename_all = "snake_case")]
30pub enum InitScriptStatus {
31    /// Init script discovery was skipped by options.
32    Skipped,
33    /// No executable init script was found.
34    NotFound {
35        /// Existing init script paths that were ignored.
36        ignored: Vec<IgnoredInitScript>,
37    },
38    /// An executable init script was found.
39    Found {
40        /// Init script path.
41        path: PathBuf,
42    },
43}
44
45/// Result summary for a `treeboot status` invocation.
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct StatusReport {
48    /// Runtime context discovered for the current worktree.
49    pub context: Worktree,
50    /// Init script discovery result.
51    pub init_script: InitScriptStatus,
52    /// Selected config path, when one was requested or discovered.
53    pub config: Option<PathBuf>,
54}
55
56/// Serializable result summary for a `treeboot status` invocation.
57#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
58pub struct StatusSnapshotReport {
59    /// Runtime context snapshot discovered for the current worktree.
60    pub context: WorktreeSnapshot,
61    /// Init script discovery result.
62    pub init_script: InitScriptStatus,
63    /// Selected config path, when one was requested or discovered.
64    pub config: Option<PathBuf>,
65}
66
67impl From<&StatusReport> for StatusSnapshotReport {
68    fn from(report: &StatusReport) -> Self {
69        Self {
70            context: WorktreeSnapshot::from(&report.context),
71            init_script: report.init_script.clone(),
72            config: report.config.clone(),
73        }
74    }
75}
76
77/// Inspects worktree, root, init script, and config discovery status.
78///
79/// This function does not execute init scripts, parse config, or run configured
80/// commands.
81///
82/// # Errors
83///
84/// Returns an error if context discovery fails or a requested config file does
85/// not exist.
86pub fn inspect_status(options: StatusOptions) -> Result<StatusReport> {
87    let context = context::resolve(&WorktreeOptions {
88        cwd: options.cwd,
89        root: options.root,
90        environment: options.environment,
91    })?;
92    let init_script = if options.no_init_script || options.config.is_some() {
93        InitScriptStatus::Skipped
94    } else {
95        inspect_init_script(&context)
96    };
97    let config = Config::discover_path(&context, options.config.as_deref())?;
98
99    Ok(StatusReport {
100        context,
101        init_script,
102        config,
103    })
104}
105
106/// Inspects worktree, root, init script, and config discovery status as a
107/// serializable snapshot.
108///
109/// This function does not execute init scripts, parse config, or run configured
110/// commands.
111///
112/// # Errors
113///
114/// Returns an error if context discovery fails or a requested config file does
115/// not exist.
116pub fn inspect_status_snapshot(options: StatusOptions) -> Result<StatusSnapshotReport> {
117    inspect_status(options).map(|report| StatusSnapshotReport::from(&report))
118}
119
120fn inspect_init_script(context: &Worktree) -> InitScriptStatus {
121    let scripts = InitScriptDiscovery::discover(context);
122
123    if let Some(path) = scripts.executable {
124        InitScriptStatus::Found { path }
125    } else {
126        InitScriptStatus::NotFound {
127            ignored: scripts.ignored,
128        }
129    }
130}