diff options
| author | Jesper Jensen <jesper@jnsn.dev> | 2026-02-06 15:26:39 +0100 |
|---|---|---|
| committer | Jesper Jensen <jesper@jnsn.dev> | 2026-02-06 15:26:39 +0100 |
| commit | dfd1533b4a7953ab41e921a4cb563ff6bf120992 (patch) | |
| tree | 652edde8d0297d1f07a7e6a24c47ce09832e4e3e /src/main.rs | |
| parent | 6ef619e5ec2349a1598896b40f2e9ea5d0163a4f (diff) | |
Add support for dockerfile updating
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 78 |
1 files changed, 63 insertions, 15 deletions
diff --git a/src/main.rs b/src/main.rs index afb6e77..a4a731a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,13 @@ mod parser; mod version; mod docker; mod manifest; +mod dockerfile; use crate::parser::*; use crate::version::{VersionPattern, CompareOutcome}; use crate::docker::DockerRef; use crate::manifest::ManifestFile; +use crate::dockerfile::DockerfileFile; use base64::prelude::*; use rand::distr::{Alphanumeric, SampleString}; @@ -148,7 +150,13 @@ impl AuthState{ } } -fn perform_registry_request(registry: &str, url: &str, accept: &'static str, auth: &mut Auth) -> Result<ureq::http::Response<ureq::Body>, String> { +#[derive(Debug)] +enum RegistryError { + NotFound, + Other(String), +} + +fn perform_registry_request(registry: &str, url: &str, accept: &'static str, auth: &mut Auth) -> Result<ureq::http::Response<ureq::Body>, RegistryError> { let mut state = auth.states.get_mut(registry); let url = format!("https://{}{}", registry, &url); @@ -169,23 +177,29 @@ fn perform_registry_request(registry: &str, url: &str, accept: &'static str, aut if response.status() == 401 { if !authentication_retry { if let Some(ref mut state) = state { - state.authenticate(&response)?; + state.authenticate(&response).map_err(RegistryError::Other)?; authentication_retry = true; continue; } else { - return Err(format!("Server {} returned 401 but we have no credentials", registry)); + return Err(RegistryError::Other(format!("Server {} returned 401 but we have no credentials", registry))); } } else { - return Err(format!("Authentication failed")); + return Err(RegistryError::Other(format!("Authentication failed"))); } } if response.status() == 429 { - panic!(); + println!("Too many requests"); + std::thread::sleep(std::time::Duration::from_secs(8)); + continue; + } + + if response.status() == 404 { + return Err(RegistryError::NotFound); } if response.status() != 200 { - return Err(format!("Unexpected status code: {}", response.status())) + return Err(RegistryError::Other(format!("Unexpected status code: {}", response.status()))); } return Ok(response); @@ -225,7 +239,7 @@ fn update_images(db: &Connection, file: &str, auth: &mut Auth, img: DockerRef, e ", (registry, &image, time)).unwrap(); time }, - Err(_x) => panic!("Database Failure"), + Err(_x) => return Err("Database Failure".to_string()), }; @@ -236,7 +250,14 @@ fn update_images(db: &Connection, file: &str, auth: &mut Auth, img: DockerRef, e let mut url = format!("/v2/{}/tags/list", &image); loop { - let mut response = perform_registry_request(registry, &url, "application/vnd.oci.image.index.v1+json", auth).unwrap(); + let mut response = match perform_registry_request(registry, &url, "application/vnd.oci.image.index.v1+json", auth) { + Ok(r) => r, + Err(RegistryError::NotFound) => { + println!("Warning: image not found, skipping: {}", image); + return Ok(()); + }, + Err(RegistryError::Other(msg)) => return Err(msg), + }; let content_type = response.headers()["Content-Type"].to_str().unwrap(); if !content_type.starts_with("application/json") { @@ -286,7 +307,14 @@ fn update_images(db: &Connection, file: &str, auth: &mut Auth, img: DockerRef, e if let Some(ref digest) = img.digest { // Find the digest for the selected tag let url = format!("/v2/{}/manifests/{}", &file[img.image.clone()], tag.as_deref().unwrap_or("latest")); - let response = perform_registry_request(registry, &url, "application/vnd.oci.image.manifest.v1+json,application/vnd.oci.image.index.v1+json", auth).unwrap(); + let response = match perform_registry_request(registry, &url, "application/vnd.oci.image.manifest.v1+json,application/vnd.oci.image.index.v1+json", auth) { + Ok(r) => r, + Err(RegistryError::NotFound) => { + println!("Warning: image not found, skipping: {}", image); + return Ok(()); + }, + Err(RegistryError::Other(msg)) => return Err(msg), + }; let digest_string = response.headers()["docker-content-digest"].to_str().unwrap().to_string(); @@ -373,6 +401,24 @@ impl std::io::Write for Output { } } +fn is_dockerfile(path: &std::path::Path) -> bool { + if let Some(name) = path.file_name() { + if let Some(name) = name.to_str() { + return name == "Dockerfile" || name == "dockerfile"; + } + } + return false +} + +fn is_yaml(path: &std::path::Path) -> bool { + if let Some(ext) = path.extension() { + if let Some(ext) = ext.to_str() { + return ext == "yaml"; + } + } + return false +} + fn run_tool(db: &Connection, auth: &mut Auth, repos: &Vec<Repository>, mut infile_paths: Vec<std::path::PathBuf>, overwrite: bool) { for repo in repos { if repo.dest.exists() { @@ -462,10 +508,8 @@ fn run_tool(db: &Connection, auth: &mut Auth, repos: &Vec<Repository>, mut infil continue; } - if let Some(ext) = path.extension() { - if ext == "yaml" { - inpaths.push(path); - } + if is_yaml(&path) || is_dockerfile(&path) { + inpaths.push(path); } } } @@ -479,12 +523,16 @@ fn run_tool(db: &Connection, auth: &mut Auth, repos: &Vec<Repository>, mut infil let mut file_content = String::new(); file.read_to_string(&mut file_content).unwrap(); - let images = ManifestFile::parse(&file_content); + let images: Vec<std::ops::Range<usize>> = if is_dockerfile(&infile_path) { + DockerfileFile::parse(&file_content).image_refs + } else { + ManifestFile::parse(&file_content).image_tags + }; let mut failed = None; let mut edits = vec![]; - for ref image in images.image_tags { + for ref image in images { println!("Checking image {}", &file_content[image.clone()]); let image_ref = DockerRef::parse(&file_content, image); if let Err(msg) = update_images(db, &file_content, auth, image_ref, &mut edits) { |
