mirror of
https://github.com/sergi0g/cup.git
synced 2025-11-14 16:13:48 -05:00
Rustfmt
This commit is contained in:
31
src/check.rs
31
src/check.rs
@@ -1,9 +1,17 @@
|
|||||||
use std::{collections::{HashMap, HashSet}, sync::Mutex};
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
sync::Mutex,
|
||||||
|
};
|
||||||
|
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
|
||||||
use json::JsonValue;
|
use json::JsonValue;
|
||||||
|
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||||
|
|
||||||
use crate::{docker::get_images_from_docker_daemon, image::Image, registry::{check_auth, get_token, get_latest_digests}, utils::unsplit_image};
|
use crate::{
|
||||||
|
docker::get_images_from_docker_daemon,
|
||||||
|
image::Image,
|
||||||
|
registry::{check_auth, get_latest_digests, get_token},
|
||||||
|
utils::unsplit_image,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
use crate::docker::get_image_from_docker_daemon;
|
use crate::docker::get_image_from_docker_daemon;
|
||||||
@@ -25,7 +33,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_updates(socket: Option<String>, config: &JsonValue) -> Vec<(String, Option<bool>)> {
|
pub async fn get_all_updates(
|
||||||
|
socket: Option<String>,
|
||||||
|
config: &JsonValue,
|
||||||
|
) -> Vec<(String, Option<bool>)> {
|
||||||
let image_map_mutex: Mutex<HashMap<String, &Option<String>>> = Mutex::new(HashMap::new());
|
let image_map_mutex: Mutex<HashMap<String, &Option<String>>> = Mutex::new(HashMap::new());
|
||||||
let local_images = get_images_from_docker_daemon(socket).await;
|
let local_images = get_images_from_docker_daemon(socket).await;
|
||||||
local_images.par_iter().for_each(|image| {
|
local_images.par_iter().for_each(|image| {
|
||||||
@@ -44,7 +55,10 @@ pub async fn get_all_updates(socket: Option<String>, config: &JsonValue) -> Vec<
|
|||||||
.par_iter()
|
.par_iter()
|
||||||
.filter(|image| &image.registry == registry)
|
.filter(|image| &image.registry == registry)
|
||||||
.collect();
|
.collect();
|
||||||
let credentials = config["authentication"][registry].clone().take_string().or(None);
|
let credentials = config["authentication"][registry]
|
||||||
|
.clone()
|
||||||
|
.take_string()
|
||||||
|
.or(None);
|
||||||
let mut latest_images = match check_auth(registry, config) {
|
let mut latest_images = match check_auth(registry, config) {
|
||||||
Some(auth_url) => {
|
Some(auth_url) => {
|
||||||
let token = get_token(images.clone(), &auth_url, &credentials);
|
let token = get_token(images.clone(), &auth_url, &credentials);
|
||||||
@@ -72,7 +86,10 @@ pub async fn get_all_updates(socket: Option<String>, config: &JsonValue) -> Vec<
|
|||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
pub async fn get_update(image: &str, socket: Option<String>, config: &JsonValue) -> Option<bool> {
|
pub async fn get_update(image: &str, socket: Option<String>, config: &JsonValue) -> Option<bool> {
|
||||||
let local_image = get_image_from_docker_daemon(socket, image).await;
|
let local_image = get_image_from_docker_daemon(socket, image).await;
|
||||||
let credentials = config["authentication"][&local_image.registry].clone().take_string().or(None);
|
let credentials = config["authentication"][&local_image.registry]
|
||||||
|
.clone()
|
||||||
|
.take_string()
|
||||||
|
.or(None);
|
||||||
let token = match check_auth(&local_image.registry, config) {
|
let token = match check_auth(&local_image.registry, config) {
|
||||||
Some(auth_url) => get_token(vec![&local_image], &auth_url, &credentials),
|
Some(auth_url) => get_token(vec![&local_image], &auth_url, &credentials),
|
||||||
None => String::new(),
|
None => String::new(),
|
||||||
@@ -85,4 +102,4 @@ pub async fn get_update(image: &str, socket: Option<String>, config: &JsonValue)
|
|||||||
Some(d) => Some(d != &local_image.digest.unwrap()),
|
Some(d) => Some(d != &local_image.digest.unwrap()),
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
use bollard::{
|
use bollard::{secret::ImageSummary, ClientVersion, Docker};
|
||||||
secret::ImageSummary,
|
|
||||||
ClientVersion, Docker,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
use bollard::secret::ImageInspect;
|
use bollard::secret::ImageInspect;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ pub fn print_update(name: &str, has_update: &Option<bool>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_raw_update(name: &str, has_update: &Option<bool>) {
|
pub fn print_raw_update(name: &str, has_update: &Option<bool>) {
|
||||||
let result = object! {images: {[name]: *has_update}} ;
|
let result = object! {images: {[name]: *has_update}};
|
||||||
println!("{}", result);
|
println!("{}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
src/main.rs
10
src/main.rs
@@ -1,8 +1,8 @@
|
|||||||
|
#[cfg(feature = "cli")]
|
||||||
|
use check::{get_all_updates, get_update};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
use formatting::{print_raw_update, print_raw_updates, print_update, print_updates, Spinner};
|
use formatting::{print_raw_update, print_raw_updates, print_update, print_updates, Spinner};
|
||||||
#[cfg(feature = "cli")]
|
|
||||||
use check::{get_all_updates, get_update};
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use server::serve;
|
use server::serve;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -10,13 +10,13 @@ use utils::load_config;
|
|||||||
|
|
||||||
pub mod check;
|
pub mod check;
|
||||||
pub mod docker;
|
pub mod docker;
|
||||||
pub mod image;
|
|
||||||
pub mod registry;
|
|
||||||
pub mod utils;
|
|
||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
pub mod formatting;
|
pub mod formatting;
|
||||||
|
pub mod image;
|
||||||
|
pub mod registry;
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
|
|||||||
@@ -9,33 +9,45 @@ use http_auth::parse_challenges;
|
|||||||
use crate::{error, image::Image, warn};
|
use crate::{error, image::Image, warn};
|
||||||
|
|
||||||
pub fn check_auth(registry: &str, config: &JsonValue) -> Option<String> {
|
pub fn check_auth(registry: &str, config: &JsonValue) -> Option<String> {
|
||||||
let protocol = if config["insecure_registries"].contains(registry) { "http" } else { "https" };
|
let protocol = if config["insecure_registries"].contains(registry) {
|
||||||
|
"http"
|
||||||
|
} else {
|
||||||
|
"https"
|
||||||
|
};
|
||||||
let response = ureq::get(&format!("{}://{}/v2/", protocol, registry)).call();
|
let response = ureq::get(&format!("{}://{}/v2/", protocol, registry)).call();
|
||||||
match response {
|
match response {
|
||||||
Ok(_) => None,
|
Ok(_) => None,
|
||||||
Err(Error::Status(401, response)) => match response.header("www-authenticate") {
|
Err(Error::Status(401, response)) => match response.header("www-authenticate") {
|
||||||
Some(challenge) => Some(parse_www_authenticate(challenge)),
|
Some(challenge) => Some(parse_www_authenticate(challenge)),
|
||||||
None => error!("Unauthorized to access registry {} and no way to authenticate was provided", registry),
|
None => error!(
|
||||||
|
"Unauthorized to access registry {} and no way to authenticate was provided",
|
||||||
|
registry
|
||||||
|
),
|
||||||
},
|
},
|
||||||
Err(Error::Transport(error)) => {
|
Err(Error::Transport(error)) => {
|
||||||
match error.kind() {
|
match error.kind() {
|
||||||
ErrorKind::Dns => {
|
ErrorKind::Dns => {
|
||||||
warn!("Failed to lookup the IP of the registry, retrying.");
|
warn!("Failed to lookup the IP of the registry, retrying.");
|
||||||
return check_auth(registry, config)
|
return check_auth(registry, config);
|
||||||
}, // If something goes really wrong, this can get stuck in a loop
|
} // If something goes really wrong, this can get stuck in a loop
|
||||||
ErrorKind::ConnectionFailed => {
|
ErrorKind::ConnectionFailed => {
|
||||||
warn!("Connection probably timed out, retrying.");
|
warn!("Connection probably timed out, retrying.");
|
||||||
return check_auth(registry, config)
|
return check_auth(registry, config);
|
||||||
}, // Same here
|
} // Same here
|
||||||
_ => error!("{}", error)
|
_ => error!("{}", error),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(e) => error!("{}", e),
|
Err(e) => error!("{}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_latest_digest(image: &Image, token: Option<&String>, config: &JsonValue) -> Image {
|
pub fn get_latest_digest(image: &Image, token: Option<&String>, config: &JsonValue) -> Image {
|
||||||
let protocol = if config["insecure_registries"].contains(json::JsonValue::from(image.registry.clone())) { "http" } else { "https" };
|
let protocol =
|
||||||
|
if config["insecure_registries"].contains(json::JsonValue::from(image.registry.clone())) {
|
||||||
|
"http"
|
||||||
|
} else {
|
||||||
|
"https"
|
||||||
|
};
|
||||||
let mut request = ureq::head(&format!(
|
let mut request = ureq::head(&format!(
|
||||||
"{}://{}/v2/{}/manifests/{}",
|
"{}://{}/v2/{}/manifests/{}",
|
||||||
protocol, &image.registry, &image.repository, &image.tag
|
protocol, &image.registry, &image.repository, &image.tag
|
||||||
@@ -93,7 +105,11 @@ pub fn get_latest_digest(image: &Image, token: Option<&String>, config: &JsonVal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_latest_digests(images: Vec<&Image>, token: Option<&String>, config: &JsonValue) -> Vec<Image> {
|
pub fn get_latest_digests(
|
||||||
|
images: Vec<&Image>,
|
||||||
|
token: Option<&String>,
|
||||||
|
config: &JsonValue,
|
||||||
|
) -> Vec<Image> {
|
||||||
let result: Mutex<Vec<Image>> = Mutex::new(Vec::new());
|
let result: Mutex<Vec<Image>> = Mutex::new(Vec::new());
|
||||||
images.par_iter().for_each(|&image| {
|
images.par_iter().for_each(|&image| {
|
||||||
let digest = get_latest_digest(image, token, config).digest;
|
let digest = get_latest_digest(image, token, config).digest;
|
||||||
@@ -111,13 +127,13 @@ pub fn get_token(images: Vec<&Image>, auth_url: &str, credentials: &Option<Strin
|
|||||||
for image in &images {
|
for image in &images {
|
||||||
final_url = format!("{}&scope=repository:{}:pull", final_url, image.repository);
|
final_url = format!("{}&scope=repository:{}:pull", final_url, image.repository);
|
||||||
}
|
}
|
||||||
let mut base_request = ureq::get(&final_url).set("Accept", "application/vnd.oci.image.index.v1+json"); // Seems to be unnecesarry. Will probably remove in the future
|
let mut base_request =
|
||||||
|
ureq::get(&final_url).set("Accept", "application/vnd.oci.image.index.v1+json"); // Seems to be unnecesarry. Will probably remove in the future
|
||||||
base_request = match credentials {
|
base_request = match credentials {
|
||||||
Some(creds) => base_request.set("Authorization", &format!("Basic {}", creds)),
|
Some(creds) => base_request.set("Authorization", &format!("Basic {}", creds)),
|
||||||
None => base_request
|
None => base_request,
|
||||||
};
|
};
|
||||||
let raw_response = match base_request.call()
|
let raw_response = match base_request.call() {
|
||||||
{
|
|
||||||
Ok(response) => match response.into_string() {
|
Ok(response) => match response.into_string() {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -128,15 +144,15 @@ pub fn get_token(images: Vec<&Image>, auth_url: &str, credentials: &Option<Strin
|
|||||||
match error.kind() {
|
match error.kind() {
|
||||||
ErrorKind::Dns => {
|
ErrorKind::Dns => {
|
||||||
warn!("Failed to lookup the IP of the registry, retrying.");
|
warn!("Failed to lookup the IP of the registry, retrying.");
|
||||||
return get_token(images, auth_url, credentials)
|
return get_token(images, auth_url, credentials);
|
||||||
}, // If something goes really wrong, this can get stuck in a loop
|
} // If something goes really wrong, this can get stuck in a loop
|
||||||
ErrorKind::ConnectionFailed => {
|
ErrorKind::ConnectionFailed => {
|
||||||
warn!("Connection probably timed out, retrying.");
|
warn!("Connection probably timed out, retrying.");
|
||||||
return get_token(images, auth_url, credentials)
|
return get_token(images, auth_url, credentials);
|
||||||
}, // Same here
|
} // Same here
|
||||||
_ => error!("Token request failed\n{}!", error)
|
_ => error!("Token request failed\n{}!", error),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Token request failed!\n{}", e)
|
error!("Token request failed!\n{}", e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,20 +43,44 @@ pub async fn serve(port: &u16, socket: Option<String>, config: JsonValue) -> std
|
|||||||
|
|
||||||
async fn _static(data: StateRef<'_, Arc<Mutex<ServerData>>>, path: PathRef<'_>) -> WebResponse {
|
async fn _static(data: StateRef<'_, Arc<Mutex<ServerData>>>, path: PathRef<'_>) -> WebResponse {
|
||||||
match path.0 {
|
match path.0 {
|
||||||
"/" => WebResponse::builder().header("Content-Type", "text/html").body(ResponseBody::from(HTML)).unwrap(),
|
"/" => WebResponse::builder()
|
||||||
"/assets/index.js" => WebResponse::builder().header("Content-Type", "text/javascript").body(ResponseBody::from(JS.replace("=\"neutral\"", &format!("=\"{}\"", data.lock().await.theme)))).unwrap(),
|
.header("Content-Type", "text/html")
|
||||||
"/assets/index.css" => WebResponse::builder().header("Content-Type", "text/css").body(ResponseBody::from(CSS)).unwrap(),
|
.body(ResponseBody::from(HTML))
|
||||||
"/favicon.ico" => WebResponse::builder().header("Content-Type", "image/vnd.microsoft.icon").body(ResponseBody::from(FAVICON_ICO)).unwrap(),
|
.unwrap(),
|
||||||
"/favicon.svg" => WebResponse::builder().header("Content-Type", "image/svg+xml").body(ResponseBody::from(FAVICON_SVG)).unwrap(),
|
"/assets/index.js" => WebResponse::builder()
|
||||||
"/apple-touch-icon.png" => WebResponse::builder().header("Content-Type", "image/png").body(ResponseBody::from(APPLE_TOUCH_ICON)).unwrap(),
|
.header("Content-Type", "text/javascript")
|
||||||
_ => WebResponse::builder().status(404).body(ResponseBody::from("Not found")).unwrap()
|
.body(ResponseBody::from(JS.replace(
|
||||||
|
"=\"neutral\"",
|
||||||
|
&format!("=\"{}\"", data.lock().await.theme),
|
||||||
|
)))
|
||||||
|
.unwrap(),
|
||||||
|
"/assets/index.css" => WebResponse::builder()
|
||||||
|
.header("Content-Type", "text/css")
|
||||||
|
.body(ResponseBody::from(CSS))
|
||||||
|
.unwrap(),
|
||||||
|
"/favicon.ico" => WebResponse::builder()
|
||||||
|
.header("Content-Type", "image/vnd.microsoft.icon")
|
||||||
|
.body(ResponseBody::from(FAVICON_ICO))
|
||||||
|
.unwrap(),
|
||||||
|
"/favicon.svg" => WebResponse::builder()
|
||||||
|
.header("Content-Type", "image/svg+xml")
|
||||||
|
.body(ResponseBody::from(FAVICON_SVG))
|
||||||
|
.unwrap(),
|
||||||
|
"/apple-touch-icon.png" => WebResponse::builder()
|
||||||
|
.header("Content-Type", "image/png")
|
||||||
|
.body(ResponseBody::from(APPLE_TOUCH_ICON))
|
||||||
|
.unwrap(),
|
||||||
|
_ => WebResponse::builder()
|
||||||
|
.status(404)
|
||||||
|
.body(ResponseBody::from("Not found"))
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn json(data: StateRef<'_, Arc<Mutex<ServerData>>>) -> WebResponse {
|
async fn json(data: StateRef<'_, Arc<Mutex<ServerData>>>) -> WebResponse {
|
||||||
WebResponse::new(ResponseBody::from(
|
WebResponse::new(ResponseBody::from(json::stringify(
|
||||||
json::stringify(data.lock().await.json.clone())
|
data.lock().await.json.clone(),
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn refresh(data: StateRef<'_, Arc<Mutex<ServerData>>>) -> WebResponse {
|
async fn refresh(data: StateRef<'_, Arc<Mutex<ServerData>>>) -> WebResponse {
|
||||||
@@ -69,7 +93,7 @@ struct ServerData {
|
|||||||
json: JsonValue,
|
json: JsonValue,
|
||||||
socket: Option<String>,
|
socket: Option<String>,
|
||||||
config: JsonValue,
|
config: JsonValue,
|
||||||
theme: &'static str
|
theme: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerData {
|
impl ServerData {
|
||||||
@@ -82,13 +106,15 @@ impl ServerData {
|
|||||||
},
|
},
|
||||||
raw_updates: Vec::new(),
|
raw_updates: Vec::new(),
|
||||||
config,
|
config,
|
||||||
theme: "neutral"
|
theme: "neutral",
|
||||||
};
|
};
|
||||||
s.refresh().await;
|
s.refresh().await;
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
async fn refresh(&mut self) {
|
async fn refresh(&mut self) {
|
||||||
let updates = sort_update_vec(&get_all_updates(self.socket.clone(), &self.config["authentication"]).await);
|
let updates = sort_update_vec(
|
||||||
|
&get_all_updates(self.socket.clone(), &self.config["authentication"]).await,
|
||||||
|
);
|
||||||
self.raw_updates = updates;
|
self.raw_updates = updates;
|
||||||
self.json = to_json(&self.raw_updates);
|
self.json = to_json(&self.raw_updates);
|
||||||
let last_updated = Local::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
|
let last_updated = Local::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ pub fn split_image(image: &str) -> (String, String, String) {
|
|||||||
match RE.captures(image) {
|
match RE.captures(image) {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
let registry = match c.name("registry") {
|
let registry = match c.name("registry") {
|
||||||
Some(registry) => registry.as_str().to_owned(),
|
Some(registry) => registry.as_str().to_owned(),
|
||||||
None => String::from("registry-1.docker.io"),
|
None => String::from("registry-1.docker.io"),
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
registry.clone(),
|
registry.clone(),
|
||||||
match c.name("repository") {
|
match c.name("repository") {
|
||||||
@@ -52,7 +52,7 @@ pub fn split_image(image: &str) -> (String, String, String) {
|
|||||||
Some(tag) => tag.as_str().to_owned(),
|
Some(tag) => tag.as_str().to_owned(),
|
||||||
None => String::from("latest"),
|
None => String::from("latest"),
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
None => error!("Failed to parse image {}", image),
|
None => error!("Failed to parse image {}", image),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user