docker_wrapper/compose/
version.rs

1//! Docker Compose version command implementation.
2
3use crate::compose::{ComposeCommandV2 as ComposeCommand, ComposeConfig};
4use crate::error::Result;
5use async_trait::async_trait;
6use serde::Deserialize;
7
8/// Docker Compose version command
9///
10/// Show Docker Compose version information.
11#[derive(Debug, Clone, Default)]
12pub struct ComposeVersionCommand {
13    /// Base configuration
14    pub config: ComposeConfig,
15    /// Format output (pretty, json)
16    pub format: Option<VersionFormat>,
17    /// Short output
18    pub short: bool,
19}
20
21/// Version output format
22#[derive(Debug, Clone, Copy)]
23pub enum VersionFormat {
24    /// Pretty format (default)
25    Pretty,
26    /// JSON format
27    Json,
28}
29
30impl VersionFormat {
31    /// Convert to command line argument
32    #[must_use]
33    pub fn as_arg(&self) -> &str {
34        match self {
35            Self::Pretty => "pretty",
36            Self::Json => "json",
37        }
38    }
39}
40
41/// Version information
42#[derive(Debug, Clone, Deserialize)]
43#[serde(rename_all = "PascalCase")]
44pub struct VersionInfo {
45    /// Compose version
46    pub version: String,
47}
48
49/// Result from version command
50#[derive(Debug, Clone)]
51pub struct VersionResult {
52    /// Version information
53    pub info: Option<VersionInfo>,
54    /// Raw output
55    pub raw_output: String,
56}
57
58impl ComposeVersionCommand {
59    /// Create a new version command
60    #[must_use]
61    pub fn new() -> Self {
62        Self::default()
63    }
64
65    /// Set output format
66    #[must_use]
67    pub fn format(mut self, format: VersionFormat) -> Self {
68        self.format = Some(format);
69        self
70    }
71
72    /// Set output format to JSON
73    #[must_use]
74    pub fn format_json(mut self) -> Self {
75        self.format = Some(VersionFormat::Json);
76        self
77    }
78
79    /// Enable short output
80    #[must_use]
81    pub fn short(mut self) -> Self {
82        self.short = true;
83        self
84    }
85
86    fn build_args(&self) -> Vec<String> {
87        let mut args = vec!["version".to_string()];
88
89        // Add flags
90        if self.short {
91            args.push("--short".to_string());
92        }
93
94        // Add format
95        if let Some(format) = &self.format {
96            args.push("--format".to_string());
97            args.push(format.as_arg().to_string());
98        }
99
100        args
101    }
102}
103
104#[async_trait]
105impl ComposeCommand for ComposeVersionCommand {
106    type Output = VersionResult;
107
108    fn get_config(&self) -> &ComposeConfig {
109        &self.config
110    }
111
112    fn get_config_mut(&mut self) -> &mut ComposeConfig {
113        &mut self.config
114    }
115
116    async fn execute_compose(&self, args: Vec<String>) -> Result<Self::Output> {
117        let output = self.execute_compose_command(args).await?;
118
119        // Parse JSON output if format is JSON
120        let info = if matches!(self.format, Some(VersionFormat::Json)) {
121            serde_json::from_str(&output.stdout).ok()
122        } else {
123            None
124        };
125
126        Ok(VersionResult {
127            info,
128            raw_output: output.stdout,
129        })
130    }
131
132    async fn execute(&self) -> Result<Self::Output> {
133        let args = self.build_args();
134        self.execute_compose(args).await
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn test_version_command_basic() {
144        let cmd = ComposeVersionCommand::new();
145        let args = cmd.build_args();
146        assert_eq!(args[0], "version");
147    }
148
149    #[test]
150    fn test_version_command_with_format() {
151        let cmd = ComposeVersionCommand::new().format_json();
152        let args = cmd.build_args();
153        assert!(args.contains(&"--format".to_string()));
154        assert!(args.contains(&"json".to_string()));
155    }
156
157    #[test]
158    fn test_version_command_with_short() {
159        let cmd = ComposeVersionCommand::new().short();
160        let args = cmd.build_args();
161        assert!(args.contains(&"--short".to_string()));
162    }
163}