refactor: Enable pedantic clippy lints
Updated files to comply with the new lint.
This commit is contained in:
parent
580c3d6ce7
commit
a54b78c8dc
19 changed files with 152 additions and 66 deletions
|
|
@ -27,6 +27,8 @@ suspicious = "warn"
|
|||
perf = "warn"
|
||||
style = "warn"
|
||||
nursery = "warn"
|
||||
pedantic = "warn"
|
||||
module_name_repetitions = "allow"
|
||||
|
||||
[package]
|
||||
name = "blue-build"
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ impl<'a> Module<'a> {
|
|||
self.get_module_type_list("containerfile", "snippets")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn print_module_context(&'a self) -> String {
|
||||
serde_json::to_string(self).unwrap_or_else(|e| {
|
||||
error!("Failed to parse module!!!!!: {e}");
|
||||
|
|
@ -80,6 +81,7 @@ impl<'a> Module<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_files_list(&'a self) -> Option<Vec<(String, String)>> {
|
||||
Some(
|
||||
self.config
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ impl ModuleExt<'_> {
|
|||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_akmods_info_list(&self, os_version: &str) -> Vec<AkmodsInfo> {
|
||||
trace!("get_akmods_image_list({self:#?}, {os_version})");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use std::{borrow::Cow, env, fs, path::Path};
|
||||
|
||||
use anyhow::Result;
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{
|
||||
CI_COMMIT_REF_NAME, CI_COMMIT_SHORT_SHA, CI_DEFAULT_BRANCH, CI_MERGE_REQUEST_IID,
|
||||
CI_PIPELINE_SOURCE, GITHUB_EVENT_NAME, GITHUB_REF_NAME, GITHUB_SHA, PR_EVENT_NUMBER,
|
||||
};
|
||||
use chrono::Local;
|
||||
use indexmap::IndexMap;
|
||||
use log::{debug, trace, warn};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use blue_build::commands::*;
|
||||
use blue_build::commands::{BlueBuildArgs, BlueBuildCommand, CommandArgs};
|
||||
use clap::Parser;
|
||||
use env_logger::WriteStyle;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
use blue_build_recipe::Recipe;
|
||||
use blue_build_template::{GithubIssueTemplate, Template};
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{
|
||||
BUG_REPORT_WARNING_MESSAGE, GITHUB_CHAR_LIMIT, LC_TERMINAL, LC_TERMINAL_VERSION, TERM_PROGRAM,
|
||||
TERM_PROGRAM_VERSION, UNKNOWN_SHELL, UNKNOWN_TERMINAL, UNKNOWN_VERSION,
|
||||
};
|
||||
use clap::Args;
|
||||
use clap_complete::Shell;
|
||||
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
|
||||
|
|
@ -82,7 +85,6 @@ impl BugReportCommand {
|
|||
.color(Colors::BrightWhiteFg)
|
||||
);
|
||||
|
||||
const WARNING_MESSAGE: &str = "Please copy the above report and open an issue manually.";
|
||||
let question = requestty::Question::confirm("anonymous")
|
||||
.message(
|
||||
"Forward the pre-filled report above to GitHub in your browser?"
|
||||
|
|
@ -103,11 +105,11 @@ impl BugReportCommand {
|
|||
return Err(e.into());
|
||||
}
|
||||
} else {
|
||||
println!("{WARNING_MESSAGE}");
|
||||
println!("{BUG_REPORT_WARNING_MESSAGE}");
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Will not open an issue in your browser! {WARNING_MESSAGE}");
|
||||
println!("Will not open an issue in your browser! {BUG_REPORT_WARNING_MESSAGE}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,13 @@ use std::{
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{
|
||||
ARCHIVE_SUFFIX, BUILD_ID_LABEL, CI_DEFAULT_BRANCH, CI_PROJECT_NAME, CI_PROJECT_NAMESPACE,
|
||||
CI_PROJECT_URL, CI_REGISTRY, CI_SERVER_HOST, CI_SERVER_PROTOCOL, CONTAINER_FILE, COSIGN_PATH,
|
||||
COSIGN_PRIVATE_KEY, GITHUB_REPOSITORY_OWNER, GITHUB_TOKEN, GITHUB_TOKEN_ISSUER_URL,
|
||||
GITHUB_WORKFLOW_REF, GITIGNORE_PATH, LABELED_ERROR_MESSAGE, NO_LABEL_ERROR_MESSAGE,
|
||||
RECIPE_PATH, SIGSTORE_ID_TOKEN,
|
||||
};
|
||||
use clap::Args;
|
||||
use colorized::{Color, Colors};
|
||||
use log::{debug, info, trace, warn};
|
||||
|
|
@ -165,7 +171,7 @@ impl BlueBuildCommand for BuildCommand {
|
|||
if !is_ignored {
|
||||
let containerfile = fs::read_to_string(container_file_path)?;
|
||||
let has_label = containerfile.lines().any(|line| {
|
||||
let label = format!("LABEL {}", BUILD_ID_LABEL);
|
||||
let label = format!("LABEL {BUILD_ID_LABEL}");
|
||||
line.to_string().trim().starts_with(&label)
|
||||
});
|
||||
|
||||
|
|
@ -184,8 +190,8 @@ impl BlueBuildCommand for BuildCommand {
|
|||
if let Ok(answer) = requestty::prompt_one(question) {
|
||||
if answer.as_bool().unwrap_or(false) {
|
||||
blue_build_utils::append_to_file(
|
||||
GITIGNORE_PATH,
|
||||
&format!("/{}", CONTAINER_FILE),
|
||||
&GITIGNORE_PATH,
|
||||
&format!("/{CONTAINER_FILE}"),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -229,7 +235,7 @@ impl BuildCommand {
|
|||
let image_name = self.generate_full_image_name(&recipe)?;
|
||||
|
||||
if self.push {
|
||||
self.login()?;
|
||||
Self::login()?;
|
||||
}
|
||||
|
||||
self.run_build(&image_name, &tags)?;
|
||||
|
|
@ -239,7 +245,7 @@ impl BuildCommand {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn login(&self) -> Result<()> {
|
||||
fn login() -> Result<()> {
|
||||
trace!("BuildCommand::login()");
|
||||
info!("Attempting to login to the registry");
|
||||
|
||||
|
|
@ -370,10 +376,10 @@ impl BuildCommand {
|
|||
strat.tag(&full_image, image_name, tag)?;
|
||||
|
||||
if self.push {
|
||||
let retry_count = if !self.no_retry_push {
|
||||
self.retry_count
|
||||
} else {
|
||||
let retry_count = if self.no_retry_push {
|
||||
0
|
||||
} else {
|
||||
self.retry_count
|
||||
};
|
||||
|
||||
debug!("Pushing all images");
|
||||
|
|
@ -427,33 +433,7 @@ fn sign_images(image_name: &str, tag: Option<&str>) -> Result<()> {
|
|||
(_, _, _, _, _, _, _, Ok(cosign_private_key))
|
||||
if !cosign_private_key.is_empty() && Path::new(COSIGN_PATH).exists() =>
|
||||
{
|
||||
info!("Signing image: {image_digest}");
|
||||
|
||||
trace!("cosign sign --key=env://COSIGN_PRIVATE_KEY {image_digest}");
|
||||
|
||||
if Command::new("cosign")
|
||||
.arg("sign")
|
||||
.arg("--key=env://COSIGN_PRIVATE_KEY")
|
||||
.arg(&image_digest)
|
||||
.status()?
|
||||
.success()
|
||||
{
|
||||
info!("Successfully signed image!");
|
||||
} else {
|
||||
bail!("Failed to sign image: {image_digest}");
|
||||
}
|
||||
|
||||
trace!("cosign verify --key {COSIGN_PATH} {image_name_tag}");
|
||||
|
||||
if !Command::new("cosign")
|
||||
.arg("verify")
|
||||
.arg(format!("--key={COSIGN_PATH}"))
|
||||
.arg(&image_name_tag)
|
||||
.status()?
|
||||
.success()
|
||||
{
|
||||
bail!("Failed to verify image!");
|
||||
}
|
||||
sign_priv_public_pair(&image_digest, &image_name_tag)?;
|
||||
}
|
||||
// Gitlab keyless
|
||||
(
|
||||
|
|
@ -541,6 +521,38 @@ fn sign_images(image_name: &str, tag: Option<&str>) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn sign_priv_public_pair(image_digest: &str, image_name_tag: &str) -> Result<()> {
|
||||
info!("Signing image: {image_digest}");
|
||||
|
||||
trace!("cosign sign --key=env://{COSIGN_PRIVATE_KEY} {image_digest}");
|
||||
|
||||
if Command::new("cosign")
|
||||
.arg("sign")
|
||||
.arg("--key=env://COSIGN_PRIVATE_KEY")
|
||||
.arg(image_digest)
|
||||
.status()?
|
||||
.success()
|
||||
{
|
||||
info!("Successfully signed image!");
|
||||
} else {
|
||||
bail!("Failed to sign image: {image_digest}");
|
||||
}
|
||||
|
||||
trace!("cosign verify --key {COSIGN_PATH} {image_name_tag}");
|
||||
|
||||
if !Command::new("cosign")
|
||||
.arg("verify")
|
||||
.arg(format!("--key={COSIGN_PATH}"))
|
||||
.arg(image_name_tag)
|
||||
.status()?
|
||||
.success()
|
||||
{
|
||||
bail!("Failed to verify image!");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_image_digest(image_name: &str, tag: Option<&str>) -> Result<String> {
|
||||
trace!("get_image_digest({image_name}, {tag:?})");
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{ARCHIVE_SUFFIX, LOCAL_BUILD};
|
||||
use clap::Args;
|
||||
use log::{debug, info, trace};
|
||||
use typed_builder::TypedBuilder;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||
use anyhow::Result;
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_template::{ContainerFileTemplate, Template};
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::RECIPE_PATH;
|
||||
use clap::Args;
|
||||
use log::{debug, info, trace};
|
||||
use typed_builder::TypedBuilder;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! The root library for blue-build.
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![allow(clippy::needless_raw_string_hashes)]
|
||||
|
||||
shadow_rs::shadow!(shadow);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ use std::{
|
|||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{
|
||||
IMAGE_VERSION_LABEL, RUN_PODMAN_SOCK, VAR_RUN_PODMAN_PODMAN_SOCK, VAR_RUN_PODMAN_SOCK,
|
||||
XDG_RUNTIME_DIR,
|
||||
};
|
||||
pub use credentials::Credentials;
|
||||
use log::{debug, error, info, trace};
|
||||
use once_cell::sync::Lazy;
|
||||
|
|
@ -94,17 +97,37 @@ static OS_VERSION: Lazy<Mutex<HashMap<String, String>>> = Lazy::new(|| Mutex::ne
|
|||
/// Allows agnostic building, tagging
|
||||
/// pushing, and login.
|
||||
pub trait BuildStrategy: Sync + Send {
|
||||
/// Runs the build logic for the strategy.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if the build fails.
|
||||
fn build(&self, image: &str) -> Result<()>;
|
||||
|
||||
/// Runs the tag logic for the strategy.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if the tagging fails.
|
||||
fn tag(&self, src_image: &str, image_name: &str, tag: &str) -> Result<()>;
|
||||
|
||||
/// Runs the push logic for the strategy
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if the push fails.
|
||||
fn push(&self, image: &str) -> Result<()>;
|
||||
|
||||
/// Runs the login logic for the strategy.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if login fails.
|
||||
fn login(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Allows agnostic inspection of images.
|
||||
pub trait InspectStrategy: Sync + Send {
|
||||
/// Gets the labels on an image tag.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if it is unable to get the labels.
|
||||
fn get_labels(&self, image_name: &str, tag: &str) -> Result<ImageInspection>;
|
||||
}
|
||||
|
||||
|
|
@ -121,12 +144,21 @@ pub struct Strategy<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Strategy<'a> {
|
||||
/// Initializes the Strategy with user provided credentials.
|
||||
///
|
||||
/// If you want to take advantage of a user's credentials,
|
||||
/// you will want to run init before trying to use any of
|
||||
/// the strategies.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if it is unable to set the user credentials.
|
||||
pub fn init(self) -> Result<()> {
|
||||
credentials::set_user_creds(self.username, self.password, self.registry)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the current build's UUID
|
||||
#[must_use]
|
||||
pub fn get_build_id() -> Uuid {
|
||||
*BUILD_ID
|
||||
}
|
||||
|
|
@ -141,14 +173,22 @@ impl<'a> Strategy<'a> {
|
|||
INSPECT_STRATEGY.clone()
|
||||
}
|
||||
|
||||
/// Get the current environment credentials.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if credentials don't exist.
|
||||
pub fn get_credentials() -> Result<&'static Credentials> {
|
||||
credentials::get_credentials()
|
||||
credentials::get()
|
||||
}
|
||||
|
||||
/// Retrieve the `os_version` for an image.
|
||||
///
|
||||
/// This gets cached for faster resolution if it's required
|
||||
/// in another part of the program.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if the image doesn't have OS version info
|
||||
/// or we are unable to lock a mutex.
|
||||
pub fn get_os_version(recipe: &Recipe) -> Result<String> {
|
||||
trace!("get_os_version({recipe:#?})");
|
||||
let image = format!("{}:{}", &recipe.base_image, &recipe.image_version);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl BuildStrategy for BuildahStrategy {
|
|||
|
||||
fn login(&self) -> Result<()> {
|
||||
let (registry, username, password) =
|
||||
credentials::get_credentials().map(|c| (&c.registry, &c.username, &c.password))?;
|
||||
credentials::get().map(|c| (&c.registry, &c.username, &c.password))?;
|
||||
|
||||
trace!("buildah login -u {username} -p [MASKED] {registry}");
|
||||
let output = Command::new("buildah")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::{env, sync::Mutex};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{
|
||||
CI_REGISTRY, CI_REGISTRY_PASSWORD, CI_REGISTRY_USER, GITHUB_ACTIONS, GITHUB_ACTOR, GITHUB_TOKEN,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
|
|
@ -44,9 +46,9 @@ static ENV_CREDENTIALS: Lazy<Option<Credentials>> = Lazy::new(|| {
|
|||
let (username, password, registry) = {
|
||||
USER_CREDS.lock().map_or((None, None, None), |creds| {
|
||||
(
|
||||
creds.username.as_ref().map(|s| s.to_owned()),
|
||||
creds.password.as_ref().map(|s| s.to_owned()),
|
||||
creds.registry.as_ref().map(|s| s.to_owned()),
|
||||
creds.username.as_ref().map(std::borrow::ToOwned::to_owned),
|
||||
creds.password.as_ref().map(std::borrow::ToOwned::to_owned),
|
||||
creds.registry.as_ref().map(std::borrow::ToOwned::to_owned),
|
||||
)
|
||||
})
|
||||
};
|
||||
|
|
@ -107,9 +109,9 @@ pub fn set_user_creds(
|
|||
let mut creds_lock = USER_CREDS
|
||||
.lock()
|
||||
.map_err(|e| anyhow!("Failed to set credentials: {e}"))?;
|
||||
creds_lock.username = username.map(|s| s.to_owned());
|
||||
creds_lock.password = password.map(|s| s.to_owned());
|
||||
creds_lock.registry = registry.map(|s| s.to_owned());
|
||||
creds_lock.username = username.map(std::borrow::ToOwned::to_owned);
|
||||
creds_lock.password = password.map(std::borrow::ToOwned::to_owned);
|
||||
creds_lock.registry = registry.map(std::borrow::ToOwned::to_owned);
|
||||
drop(creds_lock);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -118,7 +120,7 @@ pub fn set_user_creds(
|
|||
///
|
||||
/// # Errors
|
||||
/// Will error if there aren't any credentials available.
|
||||
pub fn get_credentials() -> Result<&'static Credentials> {
|
||||
pub fn get() -> Result<&'static Credentials> {
|
||||
ENV_CREDENTIALS
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("No credentials available"))
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::{
|
|||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{BB_BUILDKIT_CACHE_GHA, SKOPEO_IMAGE};
|
||||
use log::{info, trace};
|
||||
|
||||
use crate::image_inspection::ImageInspection;
|
||||
|
|
@ -83,7 +83,7 @@ impl BuildStrategy for DockerStrategy {
|
|||
|
||||
fn login(&self) -> Result<()> {
|
||||
let (registry, username, password) =
|
||||
credentials::get_credentials().map(|c| (&c.registry, &c.username, &c.password))?;
|
||||
credentials::get().map(|c| (&c.registry, &c.username, &c.password))?;
|
||||
|
||||
trace!("docker login -u {username} -p [MASKED] {registry}");
|
||||
let output = Command::new("docker")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Context;
|
||||
use anyhow::{bail, Result};
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::BUILD_ID_LABEL;
|
||||
use futures_util::StreamExt;
|
||||
use log::{debug, error};
|
||||
use log::{info, trace};
|
||||
|
|
@ -104,7 +104,7 @@ impl BuildStrategy for PodmanApiStrategy {
|
|||
trace!("PodmanApiStrategy::push({image})");
|
||||
|
||||
let (username, password, registry) =
|
||||
credentials::get_credentials().map(|c| (&c.username, &c.password, &c.registry))?;
|
||||
credentials::get().map(|c| (&c.username, &c.password, &c.registry))?;
|
||||
trace!("Retrieved creds for user {username} on registry {registry}");
|
||||
|
||||
self.rt.block_on(async {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ impl BuildStrategy for PodmanStrategy {
|
|||
|
||||
fn login(&self) -> Result<()> {
|
||||
let (registry, username, password) =
|
||||
credentials::get_credentials().map(|c| (&c.registry, &c.username, &c.password))?;
|
||||
credentials::get().map(|c| (&c.registry, &c.username, &c.password))?;
|
||||
|
||||
trace!("podman login -u {username} -p [MASKED] {registry}");
|
||||
let output = Command::new("podman")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use std::{borrow::Cow, env, fs, path::Path, process};
|
||||
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_utils::constants::*;
|
||||
use blue_build_utils::constants::{
|
||||
CI_PROJECT_NAME, CI_PROJECT_NAMESPACE, CI_REGISTRY, CI_SERVER_HOST, CI_SERVER_PROTOCOL,
|
||||
COSIGN_PATH, GITHUB_REPOSITORY_OWNER, GITHUB_RESPOSITORY, GITHUB_SERVER_URL,
|
||||
};
|
||||
use log::{debug, error, trace};
|
||||
use typed_builder::TypedBuilder;
|
||||
use uuid::Uuid;
|
||||
|
|
|
|||
|
|
@ -73,3 +73,5 @@ pub const NO_LABEL_ERROR_MESSAGE: &str =
|
|||
"It looks you have a Containerfile that has not been generated by BlueBuild. \
|
||||
Running `build` will override your Containerfile and add an entry to the .gitignore. \
|
||||
Do you want to continue?";
|
||||
pub const BUG_REPORT_WARNING_MESSAGE: &str =
|
||||
"Please copy the above report and open an issue manually.";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
pub mod command_output;
|
||||
pub mod constants;
|
||||
|
||||
use std::{io::Write, path::PathBuf, process::Command, thread, time::Duration};
|
||||
use std::{ffi::OsStr, io::Write, path::PathBuf, process::Command, thread, time::Duration};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use format_serde_error::SerdeError;
|
||||
|
|
@ -9,6 +9,10 @@ use log::{debug, trace};
|
|||
|
||||
pub use command_output::*;
|
||||
|
||||
/// Checks for the existance of a given command.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if the command doesn't exist.
|
||||
pub fn check_command_exists(command: &str) -> Result<()> {
|
||||
trace!("check_command_exists({command})");
|
||||
debug!("Checking if {command} exists");
|
||||
|
|
@ -29,9 +33,14 @@ pub fn check_command_exists(command: &str) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn append_to_file(file_path: &str, content: &str) -> Result<()> {
|
||||
trace!("append_to_file({file_path}, {content})");
|
||||
debug!("Appending {content} to {file_path}");
|
||||
/// Appends a string to a file.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if it fails to append to a file.
|
||||
pub fn append_to_file<T: Into<PathBuf> + AsRef<OsStr>>(file_path: &T, content: &str) -> Result<()> {
|
||||
let file_path: PathBuf = file_path.into();
|
||||
trace!("append_to_file({}, {content})", file_path.display());
|
||||
debug!("Appending {content} to {}", file_path.display());
|
||||
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.append(true)
|
||||
|
|
@ -42,6 +51,8 @@ pub fn append_to_file(file_path: &str, content: &str) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a serde error for displaying the file
|
||||
/// and where the error occurred.
|
||||
pub fn serde_yaml_err(contents: &str) -> impl Fn(serde_yaml::Error) -> SerdeError + '_ {
|
||||
|err: serde_yaml::Error| {
|
||||
let location = err.location();
|
||||
|
|
@ -57,10 +68,15 @@ pub fn serde_yaml_err(contents: &str) -> impl Fn(serde_yaml::Error) -> SerdeErro
|
|||
}
|
||||
}
|
||||
|
||||
pub fn retry<V, F>(mut attempts: u8, delay: u64, f: F) -> anyhow::Result<V>
|
||||
/// Performs a retry on a given closure with a given nubmer of attempts and delay.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error when retries have been expended.
|
||||
pub fn retry<V, F>(attempts: u8, delay: u64, f: F) -> anyhow::Result<V>
|
||||
where
|
||||
F: Fn() -> anyhow::Result<V>,
|
||||
{
|
||||
let mut attempts = attempts;
|
||||
loop {
|
||||
match f() {
|
||||
Ok(v) => return Ok(v),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue