docker_image_pusher/
config.rs1use anyhow::{Result, anyhow};
4use serde::{Deserialize, Serialize};
5use std::env;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct RegistryConfig {
9 pub url: String,
10 pub repository: String,
11 pub tag: String,
12 pub skip_tls: bool,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct AuthConfig {
17 pub username: Option<String>,
18 pub password: Option<String>,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct UploadConfig {
23 pub chunk_size: usize,
24 pub concurrency: usize,
25 pub verbose: bool,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct AppConfig {
30 pub registry: RegistryConfig,
31 pub auth: AuthConfig,
32 pub upload: UploadConfig,
33 pub tar_file_path: String,
34}
35
36impl AppConfig {
37 pub fn new(
38 repository_url: String,
39 tar_file_path: String,
40 username: Option<String>,
41 password: Option<String>,
42 chunk_size: usize,
43 concurrency: usize,
44 skip_tls: bool,
45 verbose: bool,
46 ) -> Result<Self> {
47 let registry = RegistryConfig::parse_url(&repository_url, skip_tls)?;
48 let auth = AuthConfig { username, password };
49 let upload = UploadConfig { chunk_size, concurrency, verbose };
50
51 Ok(AppConfig {
52 registry,
53 auth,
54 upload,
55 tar_file_path,
56 })
57 }
58
59 pub fn has_auth(&self) -> bool {
60 self.auth.username.is_some() && self.auth.password.is_some()
61 }
62}
63
64impl RegistryConfig {
65 pub fn parse_url(url: &str, skip_tls: bool) -> Result<Self> {
66 let (protocol, remaining) = if let Some(pos) = url.find("://") {
68 (&url[..pos + 3], &url[pos + 3..])
69 } else {
70 ("https://", url)
71 };
72
73 let (host, path) = if let Some(pos) = remaining.find('/') {
74 (&remaining[..pos], &remaining[pos + 1..])
75 } else {
76 return Err(anyhow!("Invalid repository URL format. Expected: https://registry/project/repo:tag"));
77 };
78
79 let registry_url = format!("{}{}", protocol, host);
80
81 let (repository, tag) = if let Some(colon_pos) = path.rfind(':') {
82 (&path[..colon_pos], &path[colon_pos + 1..])
83 } else {
84 (path, "latest")
85 };
86
87 if repository.is_empty() {
88 return Err(anyhow!("Repository name cannot be empty"));
89 }
90
91 Ok(RegistryConfig {
92 url: registry_url,
93 repository: repository.to_string(),
94 tag: tag.to_string(),
95 skip_tls,
96 })
97 }
98}
99
100#[derive(Debug)]
101pub struct Config {
102 pub registry_address: String,
103 pub username: Option<String>,
104 pub password: Option<String>,
105 pub project: Option<String>,
106 pub skip_tls: bool,
107 pub chunk_size: usize,
108}
109
110impl Config {
111 pub fn new() -> Result<Self, &'static str> {
112 let registry_address = env::var("REGISTRY_ADDRESS").map_err(|_| "REGISTRY_ADDRESS not set")?;
113 let username = env::var("REGISTRY_USERNAME").ok();
114 let password = env::var("REGISTRY_PASSWORD").ok();
115 let project = env::var("REGISTRY_PROJECT").ok();
116 let skip_tls = env::var("SKIP_TLS").map_or(false, |v| v == "true");
117 let chunk_size = env::var("CHUNK_SIZE")
118 .map(|v| v.parse::<usize>().unwrap_or(1048576)) .unwrap_or(1048576); Ok(Config {
122 registry_address,
123 username,
124 password,
125 project,
126 skip_tls,
127 chunk_size,
128 })
129 }
130}