summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorJesper Jensen <jesper@jnsn.dev>2026-02-06 15:26:39 +0100
committerJesper Jensen <jesper@jnsn.dev>2026-02-06 15:26:39 +0100
commitdfd1533b4a7953ab41e921a4cb563ff6bf120992 (patch)
tree652edde8d0297d1f07a7e6a24c47ce09832e4e3e /src/main.rs
parent6ef619e5ec2349a1598896b40f2e9ea5d0163a4f (diff)
Add support for dockerfile updating
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs78
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) {