mirror of
https://github.com/sergi0g/cup.git
synced 2025-11-17 09:33:38 -05:00
Refactor logging, create context for passing around between functions instead of config
This commit is contained in:
47
src/check.rs
47
src/check.rs
@@ -3,21 +3,19 @@ use itertools::Itertools;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
debug,
|
||||
docker::get_images_from_docker_daemon,
|
||||
http::Client,
|
||||
registry::{check_auth, get_token},
|
||||
structs::{image::Image, update::Update},
|
||||
utils::request::{get_response_body, parse_json},
|
||||
warn,
|
||||
Context,
|
||||
};
|
||||
|
||||
/// Fetches image data from other Cup instances
|
||||
async fn get_remote_updates(servers: &FxHashMap<String, String>, client: &Client) -> Vec<Update> {
|
||||
async fn get_remote_updates(ctx: &Context, client: &Client) -> Vec<Update> {
|
||||
let mut remote_images = Vec::new();
|
||||
|
||||
let handles: Vec<_> = servers
|
||||
let handles: Vec<_> = ctx.config.servers
|
||||
.iter()
|
||||
.map(|(name, url)| async {
|
||||
let url = if url.starts_with("http://") || url.starts_with("https://") {
|
||||
@@ -28,7 +26,7 @@ async fn get_remote_updates(servers: &FxHashMap<String, String>, client: &Client
|
||||
match client.get(&url, vec![], false).await {
|
||||
Ok(response) => {
|
||||
if response.status() != 200 {
|
||||
warn!("GET {}: Failed to fetch updates from server. Server returned invalid response code: {}",url,response.status());
|
||||
ctx.logger.warn(format!("GET {}: Failed to fetch updates from server. Server returned invalid response code: {}",url,response.status()));
|
||||
return Vec::new();
|
||||
}
|
||||
let json = parse_json(&get_response_body(response).await);
|
||||
@@ -48,7 +46,7 @@ async fn get_remote_updates(servers: &FxHashMap<String, String>, client: &Client
|
||||
Vec::new()
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to fetch updates from server. {}", e);
|
||||
ctx.logger.warn(format!("Failed to fetch updates from server. {}", e));
|
||||
Vec::new()
|
||||
},
|
||||
}
|
||||
@@ -63,12 +61,12 @@ async fn get_remote_updates(servers: &FxHashMap<String, String>, client: &Client
|
||||
}
|
||||
|
||||
/// Returns a list of updates for all images passed in.
|
||||
pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> Vec<Update> {
|
||||
let client = Client::new();
|
||||
pub async fn get_updates(references: &Option<Vec<String>>, ctx: &Context) -> Vec<Update> {
|
||||
let client = Client::new(ctx);
|
||||
|
||||
// Get local images
|
||||
debug!(config.debug, "Retrieving images to be checked");
|
||||
let mut images = get_images_from_docker_daemon(config, references).await;
|
||||
ctx.logger.debug("Retrieving images to be checked");
|
||||
let mut images = get_images_from_docker_daemon(ctx, references).await;
|
||||
|
||||
// Add extra images from references
|
||||
if let Some(refs) = references {
|
||||
@@ -82,18 +80,17 @@ pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> V
|
||||
}
|
||||
|
||||
// Get remote images from other servers
|
||||
let remote_updates = if !config.servers.is_empty() {
|
||||
debug!(config.debug, "Fetching updates from remote servers");
|
||||
get_remote_updates(&config.servers, &client).await
|
||||
let remote_updates = if !ctx.config.servers.is_empty() {
|
||||
ctx.logger.debug("Fetching updates from remote servers");
|
||||
get_remote_updates(ctx, &client).await
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
debug!(
|
||||
config.debug,
|
||||
ctx.logger.debug(format!(
|
||||
"Checking {:?}",
|
||||
images.iter().map(|image| &image.reference).collect_vec()
|
||||
);
|
||||
));
|
||||
|
||||
// Get a list of unique registries our images belong to. We are unwrapping the registry because it's guaranteed to be there.
|
||||
let registries: Vec<&String> = images
|
||||
@@ -104,7 +101,7 @@ pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> V
|
||||
|
||||
// Create request client. All network requests share the same client for better performance.
|
||||
// This client is also configured to retry a failed request up to 3 times with exponential backoff in between.
|
||||
let client = Client::new();
|
||||
let client = Client::new(ctx);
|
||||
|
||||
// Create a map of images indexed by registry. This solution seems quite inefficient, since each iteration causes a key to be looked up. I can't find anything better at the moment.
|
||||
let mut image_map: FxHashMap<&String, Vec<&Image>> = FxHashMap::default();
|
||||
@@ -119,12 +116,12 @@ pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> V
|
||||
// Retrieve an authentication token (if required) for each registry.
|
||||
let mut tokens: FxHashMap<&str, Option<String>> = FxHashMap::default();
|
||||
for registry in registries {
|
||||
let credentials = if let Some(registry_config) = config.registries.get(registry) {
|
||||
let credentials = if let Some(registry_config) = ctx.config.registries.get(registry) {
|
||||
®istry_config.authentication
|
||||
} else {
|
||||
&None
|
||||
};
|
||||
match check_auth(registry, config, &client).await {
|
||||
match check_auth(registry, ctx, &client).await {
|
||||
Some(auth_url) => {
|
||||
let token = get_token(
|
||||
image_map.get(registry).unwrap(),
|
||||
@@ -141,9 +138,10 @@ pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> V
|
||||
}
|
||||
}
|
||||
|
||||
debug!(config.debug, "Tokens: {:?}", tokens);
|
||||
ctx.logger.debug(format!("Tokens: {:?}", tokens));
|
||||
|
||||
let ignored_registries = config
|
||||
let ignored_registries = ctx
|
||||
.config
|
||||
.registries
|
||||
.iter()
|
||||
.filter_map(|(registry, registry_config)| {
|
||||
@@ -160,14 +158,15 @@ pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> V
|
||||
// Loop through images check for updates
|
||||
for image in &images {
|
||||
let is_ignored = ignored_registries.contains(&&image.parts.registry)
|
||||
|| config
|
||||
|| ctx
|
||||
.config
|
||||
.images
|
||||
.exclude
|
||||
.iter()
|
||||
.any(|item| image.reference.starts_with(item));
|
||||
if !is_ignored {
|
||||
let token = tokens.get(image.parts.registry.as_str()).unwrap();
|
||||
let future = image.check(token.as_deref(), config, &client);
|
||||
let future = image.check(token.as_deref(), ctx, &client);
|
||||
handles.push(future);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,6 @@ pub struct ImageConfig {
|
||||
pub struct Config {
|
||||
version: u8,
|
||||
pub agent: bool,
|
||||
#[serde(skip_deserializing)]
|
||||
pub debug: bool,
|
||||
pub images: ImageConfig,
|
||||
pub refresh_interval: Option<String>,
|
||||
pub registries: FxHashMap<String, RegistryConfig>,
|
||||
@@ -55,7 +53,6 @@ impl Config {
|
||||
Self {
|
||||
version: 3,
|
||||
agent: false,
|
||||
debug: false,
|
||||
images: ImageConfig::default(),
|
||||
refresh_interval: None,
|
||||
registries: FxHashMap::default(),
|
||||
|
||||
@@ -2,7 +2,7 @@ use bollard::{models::ImageInspect, ClientVersion, Docker};
|
||||
|
||||
use futures::future::join_all;
|
||||
|
||||
use crate::{config::Config, error, structs::image::Image};
|
||||
use crate::{error, structs::image::Image, Context};
|
||||
|
||||
fn create_docker_client(socket: Option<&str>) -> Docker {
|
||||
let client: Result<Docker, bollard::errors::Error> = match socket {
|
||||
@@ -38,10 +38,10 @@ fn create_docker_client(socket: Option<&str>) -> Docker {
|
||||
|
||||
/// Retrieves images from Docker daemon. If `references` is Some, return only the images whose references match the ones specified.
|
||||
pub async fn get_images_from_docker_daemon(
|
||||
config: &Config,
|
||||
ctx: &Context,
|
||||
references: &Option<Vec<String>>,
|
||||
) -> Vec<Image> {
|
||||
let client: Docker = create_docker_client(config.socket.as_deref());
|
||||
let client: Docker = create_docker_client(ctx.config.socket.as_deref());
|
||||
match references {
|
||||
Some(refs) => {
|
||||
let mut inspect_handles = Vec::with_capacity(refs.len());
|
||||
|
||||
20
src/http.rs
20
src/http.rs
@@ -4,7 +4,7 @@ use reqwest::Response;
|
||||
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
|
||||
|
||||
use crate::{error, warn};
|
||||
use crate::{error, Context};
|
||||
|
||||
pub enum RequestMethod {
|
||||
GET,
|
||||
@@ -23,16 +23,18 @@ impl Display for RequestMethod {
|
||||
/// A struct for handling HTTP requests. Takes care of the repetitive work of checking for errors, etc and exposes a simple interface
|
||||
pub struct Client {
|
||||
inner: ClientWithMiddleware,
|
||||
ctx: Context,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(ctx: &Context) -> Self {
|
||||
Self {
|
||||
inner: ClientBuilder::new(reqwest::Client::new())
|
||||
.with(RetryTransientMiddleware::new_with_policy(
|
||||
ExponentialBackoff::builder().build_with_max_retries(3),
|
||||
))
|
||||
.build(),
|
||||
ctx: ctx.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,14 +59,14 @@ impl Client {
|
||||
let status = response.status();
|
||||
if status == 404 {
|
||||
let message = format!("{} {}: Not found!", method, url);
|
||||
warn!("{}", message);
|
||||
self.ctx.logger.warn(&message);
|
||||
Err(message)
|
||||
} else if status == 401 {
|
||||
if ignore_401 {
|
||||
Ok(response)
|
||||
} else {
|
||||
let message = format!("{} {}: Unauthorized! Please configure authentication for this registry or if you have already done so, please make sure it is correct.", method, url);
|
||||
warn!("{}", message);
|
||||
self.ctx.logger.warn(&message);
|
||||
Err(message)
|
||||
}
|
||||
} else if status.as_u16() <= 400 {
|
||||
@@ -87,11 +89,11 @@ impl Client {
|
||||
Err(error) => {
|
||||
if error.is_connect() {
|
||||
let message = format!("{} {}: Connection failed!", method, url);
|
||||
warn!("{}", message);
|
||||
self.ctx.logger.warn(&message);
|
||||
Err(message)
|
||||
} else if error.is_timeout() {
|
||||
let message = format!("{} {}: Connection timed out!", method, url);
|
||||
warn!("{}", message);
|
||||
self.ctx.logger.warn(&message);
|
||||
Err(message)
|
||||
} else {
|
||||
error!(
|
||||
@@ -123,9 +125,3 @@ impl Client {
|
||||
self.request(url, RequestMethod::HEAD, headers, false).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Client {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
42
src/logging.rs
Normal file
42
src/logging.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => ({
|
||||
eprintln!("\x1b[31;1mERROR\x1b[0m {}", format!($($arg)*));
|
||||
std::process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
/// This struct mostly exists so we can print stuff without passing debug or raw every time.
|
||||
#[derive(Clone)]
|
||||
pub struct Logger {
|
||||
debug: bool,
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
impl Logger {
|
||||
pub fn new(debug: bool, raw: bool) -> Self {
|
||||
Self { debug, raw }
|
||||
}
|
||||
|
||||
pub fn warn(&self, msg: impl AsRef<str>) {
|
||||
if !self.raw {
|
||||
eprintln!("\x1b[33;1m WARN\x1b[0m {}", msg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info(&self, msg: impl AsRef<str>) {
|
||||
if !self.raw {
|
||||
println!("\x1b[36;1m INFO\x1b[0m {}", msg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug(&self, msg: impl AsRef<str>) {
|
||||
if self.debug {
|
||||
println!("\x1b[35;1mDEBUG\x1b[0m {}", msg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_raw(&mut self, raw: bool) {
|
||||
self.raw = raw
|
||||
}
|
||||
}
|
||||
26
src/main.rs
26
src/main.rs
@@ -4,6 +4,7 @@ use config::Config;
|
||||
use formatting::spinner::Spinner;
|
||||
#[cfg(feature = "cli")]
|
||||
use formatting::{print_raw_updates, print_updates};
|
||||
use logging::Logger;
|
||||
#[cfg(feature = "server")]
|
||||
use server::serve;
|
||||
use std::path::PathBuf;
|
||||
@@ -15,6 +16,7 @@ pub mod docker;
|
||||
#[cfg(feature = "cli")]
|
||||
pub mod formatting;
|
||||
pub mod http;
|
||||
pub mod logging;
|
||||
pub mod registry;
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
@@ -62,6 +64,12 @@ enum Commands {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
pub config: Config,
|
||||
pub logger: Logger,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let cli = Cli::parse();
|
||||
@@ -73,7 +81,10 @@ async fn main() {
|
||||
if let Some(socket) = cli.socket {
|
||||
config.socket = Some(socket)
|
||||
}
|
||||
config.debug = cli.debug;
|
||||
let mut ctx = Context {
|
||||
config,
|
||||
logger: Logger::new(cli.debug, false),
|
||||
};
|
||||
match &cli.command {
|
||||
#[cfg(feature = "cli")]
|
||||
Some(Commands::Check {
|
||||
@@ -82,23 +93,26 @@ async fn main() {
|
||||
raw,
|
||||
}) => {
|
||||
let start = SystemTime::now();
|
||||
match *raw || config.debug {
|
||||
if *raw {
|
||||
ctx.logger.set_raw(true);
|
||||
}
|
||||
match *raw || cli.debug {
|
||||
true => {
|
||||
let updates = get_updates(references, &config).await;
|
||||
let updates = get_updates(references, &ctx).await;
|
||||
print_raw_updates(&updates);
|
||||
}
|
||||
false => {
|
||||
let spinner = Spinner::new();
|
||||
let updates = get_updates(references, &config).await;
|
||||
let updates = get_updates(references, &ctx).await;
|
||||
spinner.succeed();
|
||||
print_updates(&updates, icons);
|
||||
info!("✨ Checked {} images in {}ms", updates.len(), start.elapsed().unwrap().as_millis());
|
||||
ctx.logger.info(format!("✨ Checked {} images in {}ms", updates.len(), start.elapsed().unwrap().as_millis()));
|
||||
}
|
||||
};
|
||||
}
|
||||
#[cfg(feature = "server")]
|
||||
Some(Commands::Serve { port }) => {
|
||||
let _ = serve(port, &config).await;
|
||||
let _ = serve(port, &ctx).await;
|
||||
}
|
||||
None => error!("Whoops! It looks like you haven't specified a command to run! Try `cup help` to see available options."),
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ use std::time::SystemTime;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
debug, error,
|
||||
error,
|
||||
http::Client,
|
||||
structs::{
|
||||
image::{DigestInfo, Image, VersionInfo},
|
||||
@@ -17,10 +16,11 @@ use crate::{
|
||||
},
|
||||
time::{elapsed, now},
|
||||
},
|
||||
Context,
|
||||
};
|
||||
|
||||
pub async fn check_auth(registry: &str, config: &Config, client: &Client) -> Option<String> {
|
||||
let protocol = get_protocol(registry, &config.registries);
|
||||
pub async fn check_auth(registry: &str, ctx: &Context, client: &Client) -> Option<String> {
|
||||
let protocol = get_protocol(registry, &ctx.config.registries);
|
||||
let url = format!("{}://{}/v2/", protocol, registry);
|
||||
let response = client.get(&url, Vec::new(), true).await;
|
||||
match response {
|
||||
@@ -45,15 +45,13 @@ pub async fn check_auth(registry: &str, config: &Config, client: &Client) -> Opt
|
||||
pub async fn get_latest_digest(
|
||||
image: &Image,
|
||||
token: Option<&str>,
|
||||
config: &Config,
|
||||
ctx: &Context,
|
||||
client: &Client,
|
||||
) -> Image {
|
||||
debug!(
|
||||
config.debug,
|
||||
"Checking for digest update to {}", image.reference
|
||||
);
|
||||
ctx.logger
|
||||
.debug(format!("Checking for digest update to {}", image.reference));
|
||||
let start = SystemTime::now();
|
||||
let protocol = get_protocol(&image.parts.registry, &config.registries);
|
||||
let protocol = get_protocol(&image.parts.registry, &ctx.config.registries);
|
||||
let url = format!(
|
||||
"{}://{}/v2/{}/manifests/{}",
|
||||
protocol, &image.parts.registry, &image.parts.repository, &image.parts.tag
|
||||
@@ -63,10 +61,10 @@ pub async fn get_latest_digest(
|
||||
|
||||
let response = client.head(&url, headers).await;
|
||||
let time = start.elapsed().unwrap().as_millis() as u32;
|
||||
debug!(
|
||||
config.debug,
|
||||
"Checked for digest update to {} in {}ms", image.reference, time
|
||||
);
|
||||
ctx.logger.debug(format!(
|
||||
"Checked for digest update to {} in {}ms",
|
||||
image.reference, time
|
||||
));
|
||||
match response {
|
||||
Ok(res) => match res.headers().get("docker-content-digest") {
|
||||
Some(digest) => {
|
||||
@@ -121,15 +119,13 @@ pub async fn get_latest_tag(
|
||||
image: &Image,
|
||||
base: &Version,
|
||||
token: Option<&str>,
|
||||
config: &Config,
|
||||
ctx: &Context,
|
||||
client: &Client,
|
||||
) -> Image {
|
||||
debug!(
|
||||
config.debug,
|
||||
"Checking for tag update to {}", image.reference
|
||||
);
|
||||
ctx.logger
|
||||
.debug(format!("Checking for tag update to {}", image.reference));
|
||||
let start = now();
|
||||
let protocol = get_protocol(&image.parts.registry, &config.registries);
|
||||
let protocol = get_protocol(&image.parts.registry, &ctx.config.registries);
|
||||
let url = format!(
|
||||
"{}://{}/v2/{}/tags/list",
|
||||
protocol, &image.parts.registry, &image.parts.repository,
|
||||
@@ -144,12 +140,11 @@ pub async fn get_latest_tag(
|
||||
let mut next_url = Some(url);
|
||||
|
||||
while next_url.is_some() {
|
||||
debug!(
|
||||
config.debug,
|
||||
ctx.logger.debug(format!(
|
||||
"{} has extra tags! Current number of valid tags: {}",
|
||||
image.reference,
|
||||
tags.len()
|
||||
);
|
||||
));
|
||||
let (new_tags, next) = match get_extra_tags(
|
||||
&next_url.unwrap(),
|
||||
headers.clone(),
|
||||
@@ -172,20 +167,19 @@ pub async fn get_latest_tag(
|
||||
next_url = next;
|
||||
}
|
||||
let tag = tags.iter().max();
|
||||
debug!(
|
||||
config.debug,
|
||||
ctx.logger.debug(format!(
|
||||
"Checked for tag update to {} in {}ms",
|
||||
image.reference,
|
||||
elapsed(start)
|
||||
);
|
||||
));
|
||||
match tag {
|
||||
Some(t) => {
|
||||
if t == base && image.digest_info.is_some() {
|
||||
// Tags are equal so we'll compare digests
|
||||
debug!(
|
||||
config.debug,
|
||||
"Tags for {} are equal, comparing digests.", image.reference
|
||||
);
|
||||
ctx.logger.debug(format!(
|
||||
"Tags for {} are equal, comparing digests.",
|
||||
image.reference
|
||||
));
|
||||
get_latest_digest(
|
||||
&Image {
|
||||
version_info: Some(VersionInfo {
|
||||
@@ -196,7 +190,7 @@ pub async fn get_latest_tag(
|
||||
..image.clone()
|
||||
},
|
||||
token,
|
||||
config,
|
||||
ctx,
|
||||
client,
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -18,14 +18,14 @@ use xitca_web::{
|
||||
|
||||
use crate::{
|
||||
check::get_updates,
|
||||
config::{Config, Theme},
|
||||
info,
|
||||
config::Theme,
|
||||
structs::update::Update,
|
||||
utils::{
|
||||
json::{to_full_json, to_simple_json},
|
||||
sort_update_vec::sort_update_vec,
|
||||
time::{elapsed, now},
|
||||
},
|
||||
Context,
|
||||
};
|
||||
|
||||
const HTML: &str = include_str!("static/index.html");
|
||||
@@ -46,13 +46,13 @@ const SORT_ORDER: [&str; 8] = [
|
||||
"unknown",
|
||||
]; // For Liquid rendering
|
||||
|
||||
pub async fn serve(port: &u16, config: &Config) -> std::io::Result<()> {
|
||||
info!("Starting server, please wait...");
|
||||
let data = ServerData::new(config).await;
|
||||
pub async fn serve(port: &u16, ctx: &Context) -> std::io::Result<()> {
|
||||
ctx.logger.info("Starting server, please wait...");
|
||||
let data = ServerData::new(ctx).await;
|
||||
let scheduler = JobScheduler::new().await.unwrap();
|
||||
let data = Arc::new(Mutex::new(data));
|
||||
let data_copy = data.clone();
|
||||
if let Some(interval) = &config.refresh_interval {
|
||||
if let Some(interval) = &ctx.config.refresh_interval {
|
||||
scheduler
|
||||
.add(
|
||||
Job::new_async(interval, move |_uuid, _lock| {
|
||||
@@ -67,14 +67,14 @@ pub async fn serve(port: &u16, config: &Config) -> std::io::Result<()> {
|
||||
.unwrap();
|
||||
}
|
||||
scheduler.start().await.unwrap();
|
||||
info!("Ready to start!");
|
||||
ctx.logger.info("Ready to start!");
|
||||
let mut app_builder = App::new()
|
||||
.with_state(data)
|
||||
.at("/api/v2/json", get(handler_service(api_simple)))
|
||||
.at("/api/v3/json", get(handler_service(api_full)))
|
||||
.at("/api/v2/refresh", get(handler_service(refresh)))
|
||||
.at("/api/v3/refresh", get(handler_service(refresh)));
|
||||
if !config.agent {
|
||||
if !ctx.config.agent {
|
||||
app_builder = app_builder
|
||||
.at("/", get(handler_service(_static)))
|
||||
.at("/*", get(handler_service(_static)));
|
||||
@@ -151,14 +151,14 @@ struct ServerData {
|
||||
raw_updates: Vec<Update>,
|
||||
simple_json: Value,
|
||||
full_json: Value,
|
||||
config: Config,
|
||||
ctx: Context,
|
||||
theme: &'static str,
|
||||
}
|
||||
|
||||
impl ServerData {
|
||||
async fn new(config: &Config) -> Self {
|
||||
async fn new(ctx: &Context) -> Self {
|
||||
let mut s = Self {
|
||||
config: config.clone(),
|
||||
ctx: ctx.clone(),
|
||||
template: String::new(),
|
||||
simple_json: Value::Null,
|
||||
full_json: Value::Null,
|
||||
@@ -171,14 +171,14 @@ impl ServerData {
|
||||
async fn refresh(&mut self) {
|
||||
let start = now();
|
||||
if !self.raw_updates.is_empty() {
|
||||
info!("Refreshing data");
|
||||
self.ctx.logger.info("Refreshing data");
|
||||
}
|
||||
let updates = sort_update_vec(&get_updates(&None, &self.config).await);
|
||||
info!(
|
||||
let updates = sort_update_vec(&get_updates(&None, &self.ctx).await);
|
||||
self.ctx.logger.info(format!(
|
||||
"✨ Checked {} images in {}ms",
|
||||
updates.len(),
|
||||
elapsed(start)
|
||||
);
|
||||
));
|
||||
self.raw_updates = updates;
|
||||
let template = liquid::ParserBuilder::with_stdlib()
|
||||
.build()
|
||||
@@ -193,7 +193,7 @@ impl ServerData {
|
||||
.to_string()
|
||||
.into();
|
||||
self.full_json["last_updated"] = self.simple_json["last_updated"].clone();
|
||||
self.theme = match &self.config.theme {
|
||||
self.theme = match &self.ctx.config.theme {
|
||||
Theme::Default => "neutral",
|
||||
Theme::Blue => "gray",
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::{
|
||||
config::Config,
|
||||
error,
|
||||
http::Client,
|
||||
registry::{get_latest_digest, get_latest_tag},
|
||||
structs::{status::Status, version::Version},
|
||||
utils::reference::split,
|
||||
Context,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -168,8 +168,20 @@ impl Image {
|
||||
.replacen("{}", &new_tag.minor.unwrap_or(0).to_string(), 1)
|
||||
.replacen("{}", &new_tag.patch.unwrap_or(0).to_string(), 1),
|
||||
// Throwing these in, because they're useful for the CLI output, however we won't (de)serialize them
|
||||
current_version: self.version_info.as_ref().unwrap().current_tag.to_string(),
|
||||
new_version: self.version_info.as_ref().unwrap().latest_remote_tag.as_ref().unwrap().to_string()
|
||||
current_version: self
|
||||
.version_info
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.current_tag
|
||||
.to_string(),
|
||||
new_version: self
|
||||
.version_info
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.latest_remote_tag
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
})
|
||||
}
|
||||
"digest" => {
|
||||
@@ -185,7 +197,7 @@ impl Image {
|
||||
})
|
||||
}
|
||||
"none" => UpdateInfo::None,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
},
|
||||
},
|
||||
error: self.error.clone(),
|
||||
@@ -197,11 +209,11 @@ impl Image {
|
||||
}
|
||||
|
||||
/// Checks if the image has an update
|
||||
pub async fn check(&self, token: Option<&str>, config: &Config, client: &Client) -> Self {
|
||||
pub async fn check(&self, token: Option<&str>, ctx: &Context, client: &Client) -> Self {
|
||||
match &self.version_info {
|
||||
Some(data) => get_latest_tag(self, &data.current_tag, token, config, client).await,
|
||||
Some(data) => get_latest_tag(self, &data.current_tag, token, ctx, client).await,
|
||||
None => match self.digest_info {
|
||||
Some(_) => get_latest_digest(self, token, config, client).await,
|
||||
Some(_) => get_latest_digest(self, token, ctx, client).await,
|
||||
None => unreachable!(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// Logging utilites
|
||||
|
||||
/// This macro is an alternative to panic. It prints the message you give it and exits the process with code 1, without printing a stack trace. Useful for when the program has to exit due to a user error or something unexpected which is unrelated to the program (e.g. a failed web request)
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => ({
|
||||
eprintln!("\x1b[31;1mERROR\x1b[0m {}", format!($($arg)*));
|
||||
std::process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
// A small macro to print in yellow as a warning
|
||||
#[macro_export]
|
||||
macro_rules! warn {
|
||||
($($arg:tt)*) => ({
|
||||
eprintln!("\x1b[33;1mWARN \x1b[0m {}", format!($($arg)*));
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! info {
|
||||
($($arg:tt)*) => ({
|
||||
println!("\x1b[36;1mINFO \x1b[0m {}", format!($($arg)*));
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! debug {
|
||||
($debg:expr, $($arg:tt)*) => ({
|
||||
if $debg {
|
||||
println!("\x1b[35;1mDEBUG\x1b[0m {}", format!($($arg)*));
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
pub mod json;
|
||||
pub mod link;
|
||||
pub mod logging;
|
||||
pub mod reference;
|
||||
pub mod request;
|
||||
pub mod sort_update_vec;
|
||||
|
||||
Reference in New Issue
Block a user