docker_image_pusher/cli/
runner.rs

1//! Application runner that orchestrates the image push process
2
3use 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}