docker_image_pusher/cli/
runner.rs1use crate::{
4 cli::Args,
5 config::AppConfig,
6 error::Result,
7 image::parser::ImageParser,
8 registry::{client::RegistryClient, auth::Auth},
9};
10use std::path::Path;
11
12pub struct Runner {
13 config: AppConfig,
14}
15
16impl Runner {
17 pub fn new(args: Args) -> Result<Self> {
18 let config = AppConfig::new(
19 args.repository_url,
20 args.file,
21 args.username,
22 args.password,
23 args.chunk_size,
24 args.concurrency,
25 args.skip_tls,
26 args.verbose,
27 )?;
28
29 Ok(Self { config })
30 }
31
32 pub async fn run(self) -> Result<()> {
33 self.print_configuration();
34
35 let auth_token = self.authenticate().await?;
36
37 let client = self.create_registry_client(auth_token)?;
38 client.check_registry_version().await?;
39
40 let mut image_info = self.parse_image().await?;
41 self.override_target_info(&mut image_info);
42
43 self.print_image_info(&image_info);
44
45 client.upload_image_with_info(
46 Path::new(&self.config.tar_file_path),
47 &image_info
48 ).await?;
49
50 println!("\n=== Image Push Completed Successfully! ===");
51 Ok(())
52 }
53
54 fn print_configuration(&self) {
55 println!("=== Docker Image Pusher Starting ===");
56 println!("Configuration:");
57 println!(" Registry: {}", self.config.registry.url);
58 println!(" Repository: {}", self.config.registry.repository);
59 println!(" Tag: {}", self.config.registry.tag);
60 println!(" File: {}", self.config.tar_file_path);
61 println!(" Chunk size: {} bytes", self.config.upload.chunk_size);
62 println!(" Concurrency: {}", self.config.upload.concurrency);
63 }
64
65 async fn authenticate(&self) -> Result<Option<String>> {
66 if self.config.has_auth() {
67 println!(" Authentication: enabled");
68 println!("\n=== Authenticating ===");
69
70 let auth = Auth::new(&self.config.registry.url, self.config.registry.skip_tls)?;
71
72 if let (Some(username), Some(password)) = (&self.config.auth.username, &self.config.auth.password) {
73 auth.login(username, password).await
74 } else {
75 Ok(None)
76 }
77 } else {
78 println!(" Authentication: disabled");
79 Ok(None)
80 }
81 }
82
83 fn create_registry_client(&self, auth_token: Option<String>) -> Result<RegistryClient> {
84 println!("\n=== Creating Registry Client ===");
85 RegistryClient::builder(self.config.registry.url.clone())
86 .with_auth(self.config.auth.clone())
87 .with_auth_token(auth_token)
88 .with_skip_tls(self.config.registry.skip_tls)
89 .build()
90 }
91
92 async fn parse_image(&self) -> Result<crate::image::parser::ImageInfo> {
93 println!("\n=== Parsing Docker Image Tar ===");
94 let image_path = Path::new(&self.config.tar_file_path);
95 let parser = ImageParser::new();
96 parser.parse_tar_file(image_path).await
97 }
98
99 fn override_target_info(&self, image_info: &mut crate::image::parser::ImageInfo) {
100 image_info.repository = self.config.registry.repository.clone();
101 image_info.tag = self.config.registry.tag.clone();
102 }
103
104 fn print_image_info(&self, image_info: &crate::image::parser::ImageInfo) {
105 println!("Image info:");
106 println!(" Target Repository: {}", image_info.repository);
107 println!(" Target Tag: {}", image_info.tag);
108 println!(" Layers: {} found", image_info.layers.len());
109 for (i, layer) in image_info.layers.iter().enumerate() {
110 println!(" Layer {}: {} ({})", i + 1, layer.digest, layer.size);
111 }
112 }
113}