docker_image_pusher/cli/
operation_mode.rs

1//! 操作模式定义 - 4种核心模式的统一抽象
2
3use crate::error::{RegistryError, Result};
4
5/// 4种核心操作模式
6#[derive(Debug, Clone)]
7pub enum OperationMode {
8    /// 模式1: 从repository拉取并缓存
9    PullAndCache {
10        repository: String,
11        reference: String,
12    },
13
14    /// 模式2: 从tar文件提取并缓存
15    ExtractAndCache {
16        tar_file: String,
17        repository: String,
18        reference: String,
19    },
20
21    /// 模式3: 从缓存推送(基于manifest)
22    PushFromCacheUsingManifest {
23        repository: String,
24        reference: String,
25    },
26
27    /// 模式4: 从缓存推送(基于tar) - 实际与模式3相同
28    PushFromCacheUsingTar {
29        repository: String,
30        reference: String,
31    },
32
33    /// 模式5: 直接从tar推送(无缓存)
34    PushFromTar {
35        tar_file: String,
36        repository: String,
37        reference: String,
38    },
39}
40
41impl OperationMode {
42    /// 获取模式描述
43    pub fn description(&self) -> &'static str {
44        match self {
45            OperationMode::PullAndCache { .. } => "Pull from registry and cache locally",
46            OperationMode::ExtractAndCache { .. } => "Extract from tar file and cache locally",
47            OperationMode::PushFromCacheUsingManifest { .. } => "Push from cache using manifest",
48            OperationMode::PushFromCacheUsingTar { .. } => "Push from cache using tar reference",
49            OperationMode::PushFromTar { .. } => "Push directly from tar file",
50        }
51    }
52
53    /// 检查是否需要Registry客户端
54    pub fn requires_registry_client(&self) -> bool {
55        match self {
56            OperationMode::PullAndCache { .. } => true,
57            OperationMode::ExtractAndCache { .. } => false,
58            OperationMode::PushFromCacheUsingManifest { .. } => true,
59            OperationMode::PushFromCacheUsingTar { .. } => true,
60            OperationMode::PushFromTar { .. } => true,
61        }
62    }
63
64    /// 获取目标repository和reference
65    pub fn get_target(&self) -> (&str, &str) {
66        match self {
67            OperationMode::PullAndCache {
68                repository,
69                reference,
70            } => (repository, reference),
71            OperationMode::ExtractAndCache {
72                repository,
73                reference,
74                ..
75            } => (repository, reference),
76            OperationMode::PushFromCacheUsingManifest {
77                repository,
78                reference,
79            } => (repository, reference),
80            OperationMode::PushFromCacheUsingTar {
81                repository,
82                reference,
83            } => (repository, reference),
84            OperationMode::PushFromTar {
85                repository,
86                reference,
87                ..
88            } => (repository, reference),
89        }
90    }
91
92    /// 获取源信息(如果适用)
93    pub fn get_source(&self) -> Option<&str> {
94        match self {
95            OperationMode::ExtractAndCache { tar_file, .. } => Some(tar_file),
96            OperationMode::PushFromTar { tar_file, .. } => Some(tar_file),
97            _ => None,
98        }
99    }
100
101    /// 验证操作模式参数
102    pub fn validate(&self) -> Result<()> {
103        match self {
104            OperationMode::PullAndCache {
105                repository,
106                reference,
107            } => Self::validate_repository_reference(repository, reference),
108            OperationMode::ExtractAndCache {
109                tar_file,
110                repository,
111                reference,
112            } => {
113                Self::validate_tar_file(tar_file)?;
114                Self::validate_repository_reference(repository, reference)
115            }
116            OperationMode::PushFromCacheUsingManifest {
117                repository,
118                reference,
119            }
120            | OperationMode::PushFromCacheUsingTar {
121                repository,
122                reference,
123            } => Self::validate_repository_reference(repository, reference),
124            OperationMode::PushFromTar {
125                tar_file,
126                repository,
127                reference,
128            } => {
129                Self::validate_tar_file(tar_file)?;
130                Self::validate_repository_reference(repository, reference)
131            }
132        }
133    }
134
135    fn validate_repository_reference(repository: &str, reference: &str) -> Result<()> {
136        if repository.is_empty() {
137            return Err(RegistryError::Validation(
138                "Repository cannot be empty".to_string(),
139            ));
140        }
141        if reference.is_empty() {
142            return Err(RegistryError::Validation(
143                "Reference cannot be empty".to_string(),
144            ));
145        }
146
147        // 验证repository格式(基本验证)
148        if repository.contains("..") || repository.starts_with('/') || repository.ends_with('/') {
149            return Err(RegistryError::Validation(format!(
150                "Invalid repository format: {}",
151                repository
152            )));
153        }
154
155        Ok(())
156    }
157
158    fn validate_tar_file(tar_file: &str) -> Result<()> {
159        if tar_file.is_empty() {
160            return Err(RegistryError::Validation(
161                "Tar file path cannot be empty".to_string(),
162            ));
163        }
164
165        let path = std::path::Path::new(tar_file);
166        if !path.exists() {
167            return Err(RegistryError::Validation(format!(
168                "Tar file does not exist: {}",
169                tar_file
170            )));
171        }
172
173        if !path.is_file() {
174            return Err(RegistryError::Validation(format!(
175                "Path is not a file: {}",
176                tar_file
177            )));
178        }
179
180        Ok(())
181    }
182
183    /// 检查是否为推送操作
184    pub fn is_push_operation(&self) -> bool {
185        matches!(
186            self,
187            OperationMode::PushFromCacheUsingManifest { .. }
188                | OperationMode::PushFromCacheUsingTar { .. }
189                | OperationMode::PushFromTar { .. }
190        )
191    }
192
193    /// 检查是否为缓存操作
194    pub fn is_cache_operation(&self) -> bool {
195        matches!(
196            self,
197            OperationMode::PullAndCache { .. } | OperationMode::ExtractAndCache { .. }
198        )
199    }
200
201    /// 检查是否需要访问tar文件
202    pub fn requires_tar_file(&self) -> bool {
203        matches!(
204            self,
205            OperationMode::ExtractAndCache { .. } | OperationMode::PushFromTar { .. }
206        )
207    }
208}
209
210impl std::fmt::Display for OperationMode {
211    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212        match self {
213            OperationMode::PullAndCache {
214                repository,
215                reference,
216            } => {
217                write!(f, "Pull {}:{} from registry", repository, reference)
218            }
219            OperationMode::ExtractAndCache {
220                tar_file,
221                repository,
222                reference,
223            } => {
224                write!(
225                    f,
226                    "Extract {} to cache as {}:{}",
227                    tar_file, repository, reference
228                )
229            }
230            OperationMode::PushFromCacheUsingManifest {
231                repository,
232                reference,
233            } => {
234                write!(f, "Push {}:{} from cache (manifest)", repository, reference)
235            }
236            OperationMode::PushFromCacheUsingTar {
237                repository,
238                reference,
239            } => {
240                write!(f, "Push {}:{} from cache (tar)", repository, reference)
241            }
242            OperationMode::PushFromTar {
243                tar_file,
244                repository,
245                reference,
246            } => {
247                write!(
248                    f,
249                    "Push {} directly as {}:{}",
250                    tar_file, repository, reference
251                )
252            }
253        }
254    }
255}