1use docker_image_pusher::{
6 AuthConfig, cli::operation_mode::OperationMode, error::Result,
7 image::image_manager::ImageManager, registry::RegistryClientBuilder,
8};
9
10#[tokio::main]
11async fn main() -> Result<()> {
12 println!("🚀 Docker Image Pusher - Push to Aliyun Registry Demo");
13 println!("=======================================================");
14
15 let aliyun_registry = "registry.cn-beijing.aliyuncs.com";
17 let aliyun_username = "canny_best@163.com";
18 let aliyun_password = "ra201222";
19
20 let source_repository = "yoce/cblt";
22 let source_reference = "yoce";
23
24 let target_repository = "yoce/cblt";
26 let target_reference = "push-test";
27 let cache_dir = ".cache_demo";
28
29 println!("📥 Configuration:");
30 println!(
31 " Source (Cache): {}/{}",
32 source_repository, source_reference
33 );
34 println!(" Target Registry: {}", aliyun_registry);
35 println!(" Target Repository: {}", target_repository);
36 println!(" Target Reference: {}", target_reference);
37 println!(" Cache Directory: {}", cache_dir);
38 println!(" Username: {}", aliyun_username);
39 println!();
40
41 check_cache_exists(cache_dir, source_repository, source_reference).await?;
43
44 println!("🔧 Creating ImageManager...");
46 let mut image_manager = ImageManager::new(Some(cache_dir), true)?;
47 println!("✅ ImageManager created successfully");
48
49 println!("📋 Copying cached image to target repository name...");
51 copy_image_in_cache(
52 cache_dir,
53 source_repository,
54 source_reference,
55 target_repository,
56 target_reference,
57 )
58 .await?;
59 println!("✅ Image copied in cache");
60
61 println!("🌐 Building Registry Client for Aliyun...");
63 let client = RegistryClientBuilder::new(format!("https://{}", aliyun_registry))
64 .with_timeout(3600)
65 .with_skip_tls(false)
66 .with_verbose(true)
67 .build()?;
68 println!("✅ Registry Client built successfully");
69
70 println!("🔐 Authenticating with Aliyun registry...");
72 let auth_config = AuthConfig::new(aliyun_username.to_string(), aliyun_password.to_string());
73 let auth_token = client
74 .authenticate_for_repository(&auth_config, target_repository)
75 .await?;
76 println!("✅ Authentication successful");
77
78 let mode = OperationMode::PushFromCacheUsingManifest {
80 repository: target_repository.to_string(),
81 reference: target_reference.to_string(),
82 };
83
84 println!("📋 Operation Mode: {}", mode.description());
85 println!();
86
87 println!("🔄 Starting push to Aliyun operation...");
89 println!(
90 "🎯 Target: {}/{}/{}",
91 aliyun_registry, target_repository, target_reference
92 );
93
94 match image_manager
95 .execute_operation(&mode, Some(&client), auth_token.as_deref())
96 .await
97 {
98 Ok(()) => {
99 println!("✅ Push to Aliyun operation completed successfully!");
100 println!(
101 "🎯 Image pushed to: {}/{}/{}",
102 aliyun_registry, target_repository, target_reference
103 );
104 println!("🔍 You can verify the upload in Aliyun Console:");
105 println!(" https://cr.console.aliyun.com");
106
107 verify_push_result(&client, target_repository, target_reference, &auth_token).await;
109 }
110 Err(e) => {
111 eprintln!("❌ Push to Aliyun operation failed: {}", e);
112 eprintln!("💡 Possible solutions:");
113 eprintln!(" - Check Aliyun credentials and permissions");
114 eprintln!(" - Verify repository name format (namespace/repo)");
115 eprintln!(" - Check network connectivity to Aliyun registry");
116 eprintln!(" - Ensure the repository exists in Aliyun console");
117 eprintln!(" - Check if the namespace 'yoce' exists");
118 std::process::exit(1);
119 }
120 }
121
122 Ok(())
123}
124
125async fn check_cache_exists(cache_dir: &str, repository: &str, reference: &str) -> Result<()> {
126 println!("🔍 Checking cache for source image...");
127
128 if !std::path::Path::new(cache_dir).exists() {
129 eprintln!("❌ Cache directory not found: {}", cache_dir);
130 std::process::exit(1);
131 }
132
133 let index_path = format!("{}/index.json", cache_dir);
134 if !std::path::Path::new(&index_path).exists() {
135 eprintln!("❌ Cache index not found: {}", index_path);
136 std::process::exit(1);
137 }
138
139 let manifest_path = format!("{}/manifests/{}/{}", cache_dir, repository, reference);
140 if !std::path::Path::new(&manifest_path).exists() {
141 eprintln!("❌ Manifest not found in cache: {}", manifest_path);
142 std::process::exit(1);
143 }
144
145 println!(
146 "✅ Source image found in cache: {}/{}",
147 repository, reference
148 );
149 Ok(())
150}
151
152async fn verify_push_result(
153 client: &docker_image_pusher::registry::RegistryClient,
154 repository: &str,
155 reference: &str,
156 auth_token: &Option<String>,
157) {
158 println!();
159 println!("🔍 Verifying push result...");
160
161 match client
163 .pull_manifest(repository, reference, auth_token)
164 .await
165 {
166 Ok(manifest_data) => {
167 println!("✅ Manifest successfully retrieved from Aliyun registry");
168 println!("📊 Manifest size: {} bytes", manifest_data.len());
169
170 if let Ok(manifest) = serde_json::from_slice::<serde_json::Value>(&manifest_data) {
172 if let Some(layers) = manifest.get("layers").and_then(|v| v.as_array()) {
173 println!("📦 Number of layers: {}", layers.len());
174 }
175 if let Some(media_type) = manifest.get("mediaType").and_then(|v| v.as_str()) {
176 println!("📋 Media type: {}", media_type);
177 }
178 }
179 }
180 Err(e) => {
181 eprintln!("⚠️ Could not verify manifest: {}", e);
182 }
183 }
184
185 match client.list_tags(repository, auth_token).await {
187 Ok(tags) => {
188 println!("🏷️ Available tags: {:?}", tags);
189 }
190 Err(e) => {
191 eprintln!("⚠️ Could not list tags: {}", e);
192 }
193 }
194}
195
196async fn copy_image_in_cache(
197 cache_dir: &str,
198 src_repo: &str,
199 src_ref: &str,
200 dst_repo: &str,
201 dst_ref: &str,
202) -> Result<()> {
203 use std::fs;
204 use std::path::Path;
205
206 let index_path = format!("{}/index.json", cache_dir);
208 let index_content = fs::read_to_string(&index_path)?;
209 let mut index: serde_json::Value = serde_json::from_str(&index_content)?;
210
211 let src_key = format!("{}/{}", src_repo, src_ref);
212 let dst_key = format!("{}/{}", dst_repo, dst_ref);
213
214 if let Some(src_entry) = index.get(&src_key).cloned() {
216 let mut dst_entry = src_entry;
217
218 if let Some(obj) = dst_entry.as_object_mut() {
220 obj.insert(
221 "repository".to_string(),
222 serde_json::Value::String(dst_repo.to_string()),
223 );
224 obj.insert(
225 "reference".to_string(),
226 serde_json::Value::String(dst_ref.to_string()),
227 );
228
229 let new_manifest_path = format!("{}/manifests/{}/{}", cache_dir, dst_repo, dst_ref);
230 obj.insert(
231 "manifest_path".to_string(),
232 serde_json::Value::String(new_manifest_path.clone()),
233 );
234
235 if let Some(parent) = Path::new(&new_manifest_path).parent() {
237 fs::create_dir_all(parent)?;
238 }
239
240 let src_manifest_path = format!("{}/manifests/{}/{}", cache_dir, src_repo, src_ref);
242 fs::copy(&src_manifest_path, &new_manifest_path)?;
243 }
244
245 index.as_object_mut().unwrap().insert(dst_key, dst_entry);
247
248 let updated_index = serde_json::to_string_pretty(&index)?;
250 fs::write(&index_path, updated_index)?;
251
252 println!(
253 "✅ Copied {}/{} -> {}/{} in cache",
254 src_repo, src_ref, dst_repo, dst_ref
255 );
256 Ok(())
257 } else {
258 Err(docker_image_pusher::error::RegistryError::Validation(
259 format!("Source image {}/{} not found in cache", src_repo, src_ref),
260 ))
261 }
262}