refactor: Switch to using miette for errors instead of anyhow (#198)

Switch to a better error crate that will allow setting help texts for
any error we want.
This commit is contained in:
Gerald Pinder 2024-07-05 21:55:43 -04:00 committed by GitHub
parent 784be9869a
commit 065fa193e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 364 additions and 143 deletions

146
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "addr2line"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [
"gimli",
]
[[package]] [[package]]
name = "adler" name = "adler"
version = "1.0.2" version = "1.0.2"
@ -148,6 +157,30 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "backtrace"
version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "backtrace-ext"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
dependencies = [
"backtrace",
]
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.21.7" version = "0.21.7"
@ -212,7 +245,6 @@ dependencies = [
name = "blue-build" name = "blue-build"
version = "0.8.11" version = "0.8.11"
dependencies = [ dependencies = [
"anyhow",
"blue-build-recipe", "blue-build-recipe",
"blue-build-template", "blue-build-template",
"blue-build-utils", "blue-build-utils",
@ -227,6 +259,7 @@ dependencies = [
"indicatif", "indicatif",
"lenient_semver", "lenient_semver",
"log", "log",
"miette",
"once_cell", "once_cell",
"open", "open",
"os_info", "os_info",
@ -249,12 +282,12 @@ dependencies = [
name = "blue-build-recipe" name = "blue-build-recipe"
version = "0.8.11" version = "0.8.11"
dependencies = [ dependencies = [
"anyhow",
"blue-build-utils", "blue-build-utils",
"chrono", "chrono",
"colored", "colored",
"indexmap 2.2.6", "indexmap 2.2.6",
"log", "log",
"miette",
"serde", "serde",
"serde_json", "serde_json",
"serde_yaml 0.9.34+deprecated", "serde_yaml 0.9.34+deprecated",
@ -293,6 +326,7 @@ dependencies = [
"indicatif-log-bridge", "indicatif-log-bridge",
"log", "log",
"log4rs", "log4rs",
"miette",
"nix", "nix",
"nu-ansi-term", "nu-ansi-term",
"once_cell", "once_cell",
@ -753,6 +787,12 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "gimli"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]] [[package]]
name = "git2" name = "git2"
version = "0.18.3" version = "0.18.3"
@ -924,6 +964,12 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "is_ci"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
[[package]] [[package]]
name = "is_debug" name = "is_debug"
version = "1.0.1" version = "1.0.1"
@ -1118,6 +1164,37 @@ version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "miette"
version = "7.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1"
dependencies = [
"backtrace",
"backtrace-ext",
"cfg-if",
"miette-derive",
"owo-colors",
"supports-color",
"supports-hyperlinks",
"supports-unicode",
"terminal_size",
"textwrap 0.16.1",
"thiserror",
"unicode-width",
]
[[package]]
name = "miette-derive"
version = "7.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.66",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@ -1234,6 +1311,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
name = "object"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.19.0" version = "1.19.0"
@ -1309,6 +1395,12 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "owo-colors"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.3" version = "0.12.3"
@ -1594,10 +1686,16 @@ dependencies = [
"crossterm", "crossterm",
"once_cell", "once_cell",
"termion", "termion",
"textwrap", "textwrap 0.15.2",
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.34" version = "0.38.34"
@ -1799,6 +1897,27 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "supports-color"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9829b314621dfc575df4e409e79f9d6a66a3bd707ab73f23cb4aa3a854ac854f"
dependencies = [
"is_ci",
]
[[package]]
name = "supports-hyperlinks"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0a1e5168041f5f3ff68ff7d95dcb9c8749df29f6e7e89ada40dd4c9de404ee"
[[package]]
name = "supports-unicode"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@ -1865,6 +1984,16 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "terminal_size"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
dependencies = [
"rustix",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "termion" name = "termion"
version = "1.5.6" version = "1.5.6"
@ -1888,6 +2017,17 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "textwrap"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
dependencies = [
"smawk",
"unicode-linebreak",
"unicode-width",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.61" version = "1.0.61"

View file

@ -10,7 +10,6 @@ categories = ["command-line-utilities"]
version = "0.8.11" version = "0.8.11"
[workspace.dependencies] [workspace.dependencies]
anyhow = "1"
chrono = "0.4" chrono = "0.4"
clap = "4" clap = "4"
colored = "2" colored = "2"
@ -19,6 +18,7 @@ indexmap = { version = "2", features = ["serde"] }
indicatif = { version = "0.17", features = ["improved_unicode"] } indicatif = { version = "0.17", features = ["improved_unicode"] }
indicatif-log-bridge = "0.2" indicatif-log-bridge = "0.2"
log = "0.4" log = "0.4"
miette = "7"
once_cell = "1" once_cell = "1"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
@ -73,14 +73,13 @@ shadow-rs = "0.26"
urlencoding = "2" urlencoding = "2"
users = "0.11" users = "0.11"
# Workspace dependencies
anyhow.workspace = true
chrono.workspace = true chrono.workspace = true
clap = { workspace = true, features = ["derive", "cargo", "unicode", "env"] } clap = { workspace = true, features = ["derive", "cargo", "unicode", "env"] }
colored.workspace = true colored.workspace = true
indexmap.workspace = true indexmap.workspace = true
indicatif.workspace = true indicatif.workspace = true
log.workspace = true log.workspace = true
miette = { workspace = true, features = ["fancy"] }
once_cell.workspace = true once_cell.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true

View file

@ -11,10 +11,10 @@ license.workspace = true
[dependencies] [dependencies]
blue-build-utils = { version = "=0.8.11", path = "../utils" } blue-build-utils = { version = "=0.8.11", path = "../utils" }
anyhow.workspace = true
chrono.workspace = true chrono.workspace = true
colored.workspace = true colored.workspace = true
log.workspace = true log.workspace = true
miette.workspace = true
indexmap.workspace = true indexmap.workspace = true
serde.workspace = true serde.workspace = true
serde_yaml.workspace = true serde_yaml.workspace = true

View file

@ -1,10 +1,10 @@
use std::{borrow::Cow, path::PathBuf, process}; use std::{borrow::Cow, path::PathBuf, process};
use anyhow::{bail, Result};
use blue_build_utils::syntax_highlighting::highlight_ser; use blue_build_utils::syntax_highlighting::highlight_ser;
use colored::Colorize; use colored::Colorize;
use indexmap::IndexMap; use indexmap::IndexMap;
use log::{error, trace, warn}; use log::{error, trace, warn};
use miette::{bail, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml::Value; use serde_yaml::Value;
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;

View file

@ -1,8 +1,8 @@
use std::{borrow::Cow, collections::HashSet, fs, path::Path}; use std::{borrow::Cow, collections::HashSet, fs, path::Path};
use anyhow::{Context, Result};
use blue_build_utils::constants::{CONFIG_PATH, RECIPE_PATH}; use blue_build_utils::constants::{CONFIG_PATH, RECIPE_PATH};
use log::{trace, warn}; use log::{trace, warn};
use miette::{Context, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -32,12 +32,14 @@ impl ModuleExt<'_> {
}; };
let file = fs::read_to_string(&file_path) let file = fs::read_to_string(&file_path)
.context(format!("Failed to open {}", file_path.display()))?; .into_diagnostic()
.with_context(|| format!("Failed to open {}", file_path.display()))?;
serde_yaml::from_str::<Self>(&file).map_or_else( serde_yaml::from_str::<Self>(&file).map_or_else(
|_| -> Result<Self> { |_| -> Result<Self> {
let module = serde_yaml::from_str::<Module>(&file) let module = serde_yaml::from_str::<Module>(&file)
.map_err(blue_build_utils::serde_yaml_err(&file))?; .map_err(blue_build_utils::serde_yaml_err(&file))
.into_diagnostic()?;
Ok(Self::builder().modules(vec![module]).build()) Ok(Self::builder().modules(vec![module]).build())
}, },
Ok, Ok,

View file

@ -1,6 +1,5 @@
use std::{borrow::Cow, env, fs, path::Path}; use std::{borrow::Cow, env, fs, path::Path};
use anyhow::{Context, 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_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, CI_PIPELINE_SOURCE, GITHUB_EVENT_NAME, GITHUB_REF_NAME, GITHUB_SHA, PR_EVENT_NUMBER,
@ -8,6 +7,7 @@ use blue_build_utils::constants::{
use chrono::Local; use chrono::Local;
use indexmap::IndexMap; use indexmap::IndexMap;
use log::{debug, trace, warn}; use log::{debug, trace, warn};
use miette::{Context, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml::Value; use serde_yaml::Value;
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -204,16 +204,20 @@ impl<'a> Recipe<'a> {
let file_path = if Path::new(path.as_ref()).is_absolute() { let file_path = if Path::new(path.as_ref()).is_absolute() {
path.as_ref().to_path_buf() path.as_ref().to_path_buf()
} else { } else {
std::env::current_dir()?.join(path.as_ref()) std::env::current_dir()
.into_diagnostic()?
.join(path.as_ref())
}; };
let file = fs::read_to_string(&file_path) let file = fs::read_to_string(&file_path)
.context(format!("Failed to read {}", file_path.display()))?; .into_diagnostic()
.with_context(|| format!("Failed to read {}", file_path.display()))?;
debug!("Recipe contents: {file}"); debug!("Recipe contents: {file}");
let mut recipe = serde_yaml::from_str::<Recipe>(&file) let mut recipe = serde_yaml::from_str::<Recipe>(&file)
.map_err(blue_build_utils::serde_yaml_err(&file))?; .map_err(blue_build_utils::serde_yaml_err(&file))
.into_diagnostic()?;
recipe.modules_ext.modules = Module::get_modules(&recipe.modules_ext.modules, None)?.into(); recipe.modules_ext.modules = Module::get_modules(&recipe.modules_ext.modules, None)?.into();

View file

@ -1,8 +1,8 @@
use std::{borrow::Cow, path::PathBuf}; use std::{borrow::Cow, path::PathBuf};
use anyhow::{bail, Result};
use blue_build_utils::syntax_highlighting::highlight_ser; use blue_build_utils::syntax_highlighting::highlight_ser;
use colored::Colorize; use colored::Colorize;
use miette::{bail, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;

View file

@ -1,8 +1,8 @@
use std::{borrow::Cow, fs, path::Path}; use std::{borrow::Cow, fs, path::Path};
use anyhow::{Context, Result};
use blue_build_utils::constants::{CONFIG_PATH, RECIPE_PATH}; use blue_build_utils::constants::{CONFIG_PATH, RECIPE_PATH};
use log::warn; use log::warn;
use miette::{Context, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -32,12 +32,14 @@ impl<'a> StagesExt<'a> {
}; };
let file = fs::read_to_string(&file_path) let file = fs::read_to_string(&file_path)
.context(format!("Failed to open {}", file_path.display()))?; .into_diagnostic()
.with_context(|| format!("Failed to open {}", file_path.display()))?;
serde_yaml::from_str::<Self>(&file).map_or_else( serde_yaml::from_str::<Self>(&file).map_or_else(
|_| -> Result<Self> { |_| -> Result<Self> {
let mut stage = serde_yaml::from_str::<Stage>(&file) let mut stage = serde_yaml::from_str::<Stage>(&file)
.map_err(blue_build_utils::serde_yaml_err(&file))?; .map_err(blue_build_utils::serde_yaml_err(&file))
.into_diagnostic()?;
if let Some(ref mut rf) = stage.required_fields { if let Some(ref mut rf) = stage.required_fields {
rf.modules_ext.modules = rf.modules_ext.modules =
Module::get_modules(&rf.modules_ext.modules, None)?.into(); Module::get_modules(&rf.modules_ext.modules, None)?.into();

View file

@ -28,12 +28,12 @@ pub trait BlueBuildCommand {
/// ///
/// # Errors /// # Errors
/// Can return an `anyhow` Error /// Can return an `anyhow` Error
fn try_run(&mut self) -> anyhow::Result<()>; fn try_run(&mut self) -> miette::Result<()>;
/// Runs the command and exits if there is an error. /// Runs the command and exits if there is an error.
fn run(&mut self) { fn run(&mut self) {
if let Err(e) = self.try_run() { if let Err(e) = self.try_run() {
error!("{e}"); error!("Failed:\n{e:?}");
std::process::exit(1); std::process::exit(1);
} }
std::process::exit(0); std::process::exit(0);

View file

@ -9,6 +9,7 @@ use clap_complete::Shell;
use colored::Colorize; use colored::Colorize;
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher}; use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
use log::{debug, error, trace}; use log::{debug, error, trace};
use miette::{IntoDiagnostic, Result};
use requestty::question::{completions, Completions}; use requestty::question::{completions, Completions};
use std::time::Duration; use std::time::Duration;
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -32,7 +33,7 @@ pub struct BugReportCommand {
} }
impl BlueBuildCommand for BugReportCommand { impl BlueBuildCommand for BugReportCommand {
fn try_run(&mut self) -> anyhow::Result<()> { fn try_run(&mut self) -> Result<()> {
debug!("Generating bug report for hash: {}\n", shadow::COMMIT_HASH); debug!("Generating bug report for hash: {}\n", shadow::COMMIT_HASH);
debug!("Shadow Versioning:\n{}", shadow::VERSION.trim()); debug!("Shadow Versioning:\n{}", shadow::VERSION.trim());
@ -51,7 +52,7 @@ impl BugReportCommand {
/// # Panics /// # Panics
/// ///
/// This function will panic if it fails to get the current shell or terminal version. /// This function will panic if it fails to get the current shell or terminal version.
pub fn create_bugreport(&self) -> anyhow::Result<()> { pub fn create_bugreport(&self) -> Result<()> {
let os_info = os_info::get(); let os_info = os_info::get();
let recipe = self.get_recipe(); let recipe = self.get_recipe();
@ -94,7 +95,7 @@ impl BugReportCommand {
if let Err(e) = open::that(&link) { if let Err(e) = open::that(&link) {
println!("Failed to open issue report in your browser: {e}"); println!("Failed to open issue report in your browser: {e}");
println!("Please copy the above report and open an issue manually, or try opening the following link:\n{link}"); println!("Please copy the above report and open an issue manually, or try opening the following link:\n{link}");
return Err(e.into()); return Err(e).into_diagnostic();
} }
} else { } else {
println!("{BUG_REPORT_WARNING_MESSAGE}"); println!("{BUG_REPORT_WARNING_MESSAGE}");
@ -125,7 +126,7 @@ impl BugReportCommand {
} }
} }
fn get_config_file(title: &str, message: &str) -> anyhow::Result<String> { fn get_config_file(title: &str, message: &str) -> Result<String> {
use std::path::Path; use std::path::Path;
let question = requestty::Question::input(title) let question = requestty::Question::input(title)
@ -147,7 +148,7 @@ fn get_config_file(title: &str, message: &str) -> anyhow::Result<String> {
Ok(_) => unreachable!(), Ok(_) => unreachable!(),
Err(e) => { Err(e) => {
trace!("Failed to get file: {}", e); trace!("Failed to get file: {}", e);
Err(e.into()) Err(e).into_diagnostic()
} }
} }
} }
@ -276,11 +277,8 @@ fn get_pkg_branch_tag() -> String {
format!("{} ({})", shadow::BRANCH, shadow::LAST_TAG) format!("{} ({})", shadow::BRANCH, shadow::LAST_TAG)
} }
fn generate_github_issue( fn generate_github_issue(environment: &Environment, recipe: &Option<Recipe>) -> Result<String> {
environment: &Environment, let recipe = serde_yaml::to_string(recipe).into_diagnostic()?;
recipe: &Option<Recipe>,
) -> anyhow::Result<String> {
let recipe = serde_yaml::to_string(recipe)?;
let github_template = GithubIssueTemplate::builder() let github_template = GithubIssueTemplate::builder()
.bb_version(shadow::PKG_VERSION) .bb_version(shadow::PKG_VERSION)
@ -299,7 +297,7 @@ fn generate_github_issue(
.terminal_version(environment.terminal_info.version.clone()) .terminal_version(environment.terminal_info.version.clone())
.build(); .build();
Ok(github_template.render()?) github_template.render().into_diagnostic()
} }
fn make_github_issue_link(body: &str) -> String { fn make_github_issue_link(body: &str) -> String {

View file

@ -4,7 +4,6 @@ use std::{
process::Command, process::Command,
}; };
use anyhow::{bail, Context, Result};
use blue_build_recipe::Recipe; use blue_build_recipe::Recipe;
use blue_build_utils::{ use blue_build_utils::{
constants::{ constants::{
@ -20,6 +19,7 @@ use blue_build_utils::{
use clap::Args; use clap::Args;
use colored::Colorize; use colored::Colorize;
use log::{debug, info, trace, warn}; use log::{debug, info, trace, warn};
use miette::{bail, Context, IntoDiagnostic, Result};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use crate::{ use crate::{
@ -330,7 +330,8 @@ impl BuildCommand {
.arg("-p") .arg("-p")
.arg(password) .arg(password)
.arg(registry) .arg(registry)
.output()?; .output()
.into_diagnostic()?;
if !login_output.status.success() { if !login_output.status.success() {
let err_output = String::from_utf8_lossy(&login_output.stderr); let err_output = String::from_utf8_lossy(&login_output.stderr);
@ -421,7 +422,8 @@ impl BuildCommand {
if !self.force && container_file_path.exists() { if !self.force && container_file_path.exists() {
let to_ignore_lines = [format!("/{CONTAINER_FILE}"), format!("/{CONTAINER_FILE}.*")]; let to_ignore_lines = [format!("/{CONTAINER_FILE}"), format!("/{CONTAINER_FILE}.*")];
let gitignore = fs::read_to_string(GITIGNORE_PATH) let gitignore = fs::read_to_string(GITIGNORE_PATH)
.context(format!("Failed to read {GITIGNORE_PATH}"))?; .into_diagnostic()
.with_context(|| format!("Failed to read {GITIGNORE_PATH}"))?;
let mut edited_gitignore = gitignore.clone(); let mut edited_gitignore = gitignore.clone();
@ -434,7 +436,10 @@ impl BuildCommand {
}) })
.try_for_each(|to_ignore| -> Result<()> { .try_for_each(|to_ignore| -> Result<()> {
let containerfile = fs::read_to_string(container_file_path) let containerfile = fs::read_to_string(container_file_path)
.context(format!("Failed to read {}", container_file_path.display()))?; .into_diagnostic()
.with_context(|| {
format!("Failed to read {}", container_file_path.display())
})?;
let has_label = containerfile let has_label = containerfile
.lines() .lines()
@ -467,7 +472,7 @@ impl BuildCommand {
})?; })?;
if edited_gitignore != gitignore { if edited_gitignore != gitignore {
fs::write(GITIGNORE_PATH, edited_gitignore.as_str())?; fs::write(GITIGNORE_PATH, edited_gitignore.as_str()).into_diagnostic()?;
} }
} }
@ -497,7 +502,8 @@ impl BuildCommand {
let output = Command::new("cosign") let output = Command::new("cosign")
.arg("public-key") .arg("public-key")
.arg("--key=env://COSIGN_PRIVATE_KEY") .arg("--key=env://COSIGN_PRIVATE_KEY")
.output()?; .output()
.into_diagnostic()?;
if !output.status.success() { if !output.status.success() {
bail!( bail!(
@ -506,9 +512,10 @@ impl BuildCommand {
); );
} }
let calculated_pub_key = String::from_utf8(output.stdout)?; let calculated_pub_key = String::from_utf8(output.stdout).into_diagnostic()?;
let found_pub_key = fs::read_to_string(COSIGN_PUB_PATH) let found_pub_key = fs::read_to_string(COSIGN_PUB_PATH)
.context(format!("Failed to read {COSIGN_PUB_PATH}"))?; .into_diagnostic()
.with_context(|| format!("Failed to read {COSIGN_PUB_PATH}"))?;
trace!("calculated_pub_key={calculated_pub_key},found_pub_key={found_pub_key}"); trace!("calculated_pub_key={calculated_pub_key},found_pub_key={found_pub_key}");
if calculated_pub_key.trim() == found_pub_key.trim() { if calculated_pub_key.trim() == found_pub_key.trim() {
@ -523,7 +530,8 @@ impl BuildCommand {
let output = Command::new("cosign") let output = Command::new("cosign")
.arg("public-key") .arg("public-key")
.arg(format!("--key={COSIGN_PRIV_PATH}")) .arg(format!("--key={COSIGN_PRIV_PATH}"))
.output()?; .output()
.into_diagnostic()?;
if !output.status.success() { if !output.status.success() {
bail!( bail!(
@ -532,9 +540,10 @@ impl BuildCommand {
); );
} }
let calculated_pub_key = String::from_utf8(output.stdout)?; let calculated_pub_key = String::from_utf8(output.stdout).into_diagnostic()?;
let found_pub_key = fs::read_to_string(COSIGN_PUB_PATH) let found_pub_key = fs::read_to_string(COSIGN_PUB_PATH)
.context(format!("Failed to read {COSIGN_PUB_PATH}"))?; .into_diagnostic()
.with_context(|| format!("Failed to read {COSIGN_PUB_PATH}"))?;
trace!("calculated_pub_key={calculated_pub_key},found_pub_key={found_pub_key}"); trace!("calculated_pub_key={calculated_pub_key},found_pub_key={found_pub_key}");
if calculated_pub_key.trim() == found_pub_key.trim() { if calculated_pub_key.trim() == found_pub_key.trim() {
@ -622,7 +631,8 @@ fn sign_images(image_name: &str, tag: Option<&str>) -> Result<()> {
.arg("sign") .arg("sign")
.arg("--recursive") .arg("--recursive")
.arg(&image_name_digest) .arg(&image_name_digest)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
info!("Successfully signed image!"); info!("Successfully signed image!");
@ -644,7 +654,8 @@ fn sign_images(image_name: &str, tag: Option<&str>) -> Result<()> {
.arg("--certificate-oidc-issuer") .arg("--certificate-oidc-issuer")
.arg(&cert_oidc) .arg(&cert_oidc)
.arg(&image_name_tag) .arg(&image_name_tag)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
bail!("Failed to verify image!"); bail!("Failed to verify image!");
@ -661,7 +672,8 @@ fn sign_images(image_name: &str, tag: Option<&str>) -> Result<()> {
.arg("sign") .arg("sign")
.arg("--recursive") .arg("--recursive")
.arg(&image_name_digest) .arg(&image_name_digest)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
info!("Successfully signed image!"); info!("Successfully signed image!");
@ -677,7 +689,8 @@ fn sign_images(image_name: &str, tag: Option<&str>) -> Result<()> {
.arg("--certificate-oidc-issuer") .arg("--certificate-oidc-issuer")
.arg(GITHUB_TOKEN_ISSUER_URL) .arg(GITHUB_TOKEN_ISSUER_URL)
.arg(&image_name_tag) .arg(&image_name_tag)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
bail!("Failed to verify image!"); bail!("Failed to verify image!");
@ -699,7 +712,8 @@ fn sign_priv_public_pair_env(image_digest: &str, image_name_tag: &str) -> Result
.arg("--key=env://COSIGN_PRIVATE_KEY") .arg("--key=env://COSIGN_PRIVATE_KEY")
.arg("--recursive") .arg("--recursive")
.arg(image_digest) .arg(image_digest)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
info!("Successfully signed image!"); info!("Successfully signed image!");
@ -713,7 +727,8 @@ fn sign_priv_public_pair_env(image_digest: &str, image_name_tag: &str) -> Result
.arg("verify") .arg("verify")
.arg(format!("--key={COSIGN_PUB_PATH}")) .arg(format!("--key={COSIGN_PUB_PATH}"))
.arg(image_name_tag) .arg(image_name_tag)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
bail!("Failed to verify image!"); bail!("Failed to verify image!");
@ -732,7 +747,8 @@ fn sign_priv_public_pair_file(image_digest: &str, image_name_tag: &str) -> Resul
.arg(format!("--key={COSIGN_PRIV_PATH}")) .arg(format!("--key={COSIGN_PRIV_PATH}"))
.arg("--recursive") .arg("--recursive")
.arg(image_digest) .arg(image_digest)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
info!("Successfully signed image!"); info!("Successfully signed image!");
@ -746,7 +762,8 @@ fn sign_priv_public_pair_file(image_digest: &str, image_name_tag: &str) -> Resul
.arg("verify") .arg("verify")
.arg(format!("--key={COSIGN_PUB_PATH}")) .arg(format!("--key={COSIGN_PUB_PATH}"))
.arg(image_name_tag) .arg(image_name_tag)
.status()? .status()
.into_diagnostic()?
.success() .success()
{ {
bail!("Failed to verify image!"); bail!("Failed to verify image!");

View file

@ -1,5 +1,6 @@
use clap::{Args, CommandFactory}; use clap::{Args, CommandFactory};
use clap_complete::{generate, Shell as CompletionShell}; use clap_complete::{generate, Shell as CompletionShell};
use miette::Result;
use crate::commands::BlueBuildArgs; use crate::commands::BlueBuildArgs;
@ -12,7 +13,7 @@ pub struct CompletionsCommand {
} }
impl BlueBuildCommand for CompletionsCommand { impl BlueBuildCommand for CompletionsCommand {
fn try_run(&mut self) -> anyhow::Result<()> { fn try_run(&mut self) -> Result<()> {
log::debug!("Generating completions for {}", self.shell); log::debug!("Generating completions for {}", self.shell);
generate( generate(

View file

@ -3,7 +3,6 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use anyhow::Result;
use blue_build_recipe::Recipe; use blue_build_recipe::Recipe;
use blue_build_template::{ContainerFileTemplate, Template}; use blue_build_template::{ContainerFileTemplate, Template};
use blue_build_utils::{ use blue_build_utils::{
@ -15,6 +14,7 @@ use blue_build_utils::{
}; };
use clap::{crate_version, Args}; use clap::{crate_version, Args};
use log::{debug, info, trace, warn}; use log::{debug, info, trace, warn};
use miette::{IntoDiagnostic, Result};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use crate::{drivers::Driver, shadow}; use crate::{drivers::Driver, shadow};
@ -104,7 +104,8 @@ impl GenerateCommand {
if self.display_full_recipe { if self.display_full_recipe {
if let Some(output) = self.output.as_ref() { if let Some(output) = self.output.as_ref() {
std::fs::write(output, serde_yaml::to_string(&recipe_de)?)?; std::fs::write(output, serde_yaml::to_string(&recipe_de).into_diagnostic()?)
.into_diagnostic()?;
} else { } else {
syntax_highlighting::print_ser(&recipe_de, "yml", self.syntax_theme)?; syntax_highlighting::print_ser(&recipe_de, "yml", self.syntax_theme)?;
} }
@ -132,12 +133,12 @@ impl GenerateCommand {
}) })
.build(); .build();
let output_str = template.render()?; let output_str = template.render().into_diagnostic()?;
if let Some(output) = self.output.as_ref() { if let Some(output) = self.output.as_ref() {
debug!("Templating to file {}", output.display()); debug!("Templating to file {}", output.display());
trace!("Containerfile:\n{output_str}"); trace!("Containerfile:\n{output_str}");
std::fs::write(output, output_str)?; std::fs::write(output, output_str).into_diagnostic()?;
} else { } else {
debug!("Templating to stdout"); debug!("Templating to stdout");
syntax_highlighting::print(&output_str, "Dockerfile", self.syntax_theme)?; syntax_highlighting::print(&output_str, "Dockerfile", self.syntax_theme)?;

View file

@ -4,11 +4,11 @@ use std::{
process::Command, process::Command,
}; };
use anyhow::{bail, Result};
use blue_build_recipe::Recipe; use blue_build_recipe::Recipe;
use blue_build_utils::constants::{ARCHIVE_SUFFIX, LOCAL_BUILD}; use blue_build_utils::constants::{ARCHIVE_SUFFIX, LOCAL_BUILD};
use clap::Args; use clap::Args;
use log::{debug, info, trace}; use log::{debug, info, trace};
use miette::{bail, IntoDiagnostic, Result};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use users::{Users, UsersCache}; use users::{Users, UsersCache};
@ -84,12 +84,16 @@ impl BlueBuildCommand for UpgradeCommand {
Command::new("rpm-ostree") Command::new("rpm-ostree")
.arg("upgrade") .arg("upgrade")
.arg("--reboot") .arg("--reboot")
.status()? .status()
.into_diagnostic()?
} else { } else {
info!("Upgrading image {image_name}"); info!("Upgrading image {image_name}");
trace!("rpm-ostree upgrade"); trace!("rpm-ostree upgrade");
Command::new("rpm-ostree").arg("upgrade").status()? Command::new("rpm-ostree")
.arg("upgrade")
.status()
.into_diagnostic()?
}; };
if status.success() { if status.success() {
@ -146,7 +150,8 @@ impl BlueBuildCommand for RebaseCommand {
.arg("rebase") .arg("rebase")
.arg("--reboot") .arg("--reboot")
.arg(rebase_url) .arg(rebase_url)
.status()? .status()
.into_diagnostic()?
} else { } else {
info!("Rebasing image {image_name}"); info!("Rebasing image {image_name}");
@ -154,7 +159,8 @@ impl BlueBuildCommand for RebaseCommand {
Command::new("rpm-ostree") Command::new("rpm-ostree")
.arg("rebase") .arg("rebase")
.arg(rebase_url) .arg(rebase_url)
.status()? .status()
.into_diagnostic()?
}; };
if status.success() { if status.success() {
@ -198,10 +204,10 @@ fn clean_local_build_dir(image_name: &str, rebase: bool) -> Result<()> {
if local_build_path.exists() { if local_build_path.exists() {
debug!("Cleaning out build dir {LOCAL_BUILD}"); debug!("Cleaning out build dir {LOCAL_BUILD}");
let entries = fs::read_dir(LOCAL_BUILD)?; let entries = fs::read_dir(LOCAL_BUILD).into_diagnostic()?;
for entry in entries { for entry in entries {
let entry = entry?; let entry = entry.into_diagnostic()?;
let path = entry.path(); let path = entry.path();
trace!("Found {}", path.display()); trace!("Found {}", path.display());
@ -211,7 +217,7 @@ fn clean_local_build_dir(image_name: &str, rebase: bool) -> Result<()> {
continue; continue;
} }
trace!("Removing {}", path.display()); trace!("Removing {}", path.display());
fs::remove_file(path)?; fs::remove_file(path).into_diagnostic()?;
} }
} }
} else { } else {
@ -219,7 +225,7 @@ fn clean_local_build_dir(image_name: &str, rebase: bool) -> Result<()> {
"Creating build output dir at {}", "Creating build output dir at {}",
local_build_path.display() local_build_path.display()
); );
fs::create_dir_all(local_build_path)?; fs::create_dir_all(local_build_path).into_diagnostic()?;
} }
Ok(()) Ok(())

View file

@ -4,7 +4,6 @@ use std::{
time::Duration, time::Duration,
}; };
use anyhow::{bail, Result};
use blue_build_recipe::Recipe; use blue_build_recipe::Recipe;
use blue_build_utils::{ use blue_build_utils::{
constants::{ARCHIVE_SUFFIX, LOCAL_BUILD, OCI_ARCHIVE, OSTREE_UNVERIFIED_IMAGE}, constants::{ARCHIVE_SUFFIX, LOCAL_BUILD, OCI_ARCHIVE, OSTREE_UNVERIFIED_IMAGE},
@ -14,6 +13,7 @@ use clap::Args;
use colored::Colorize; use colored::Colorize;
use indicatif::ProgressBar; use indicatif::ProgressBar;
use log::{debug, trace, warn}; use log::{debug, trace, warn};
use miette::{bail, IntoDiagnostic, Result};
use tempdir::TempDir; use tempdir::TempDir;
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -64,7 +64,7 @@ impl BlueBuildCommand for SwitchCommand {
bail!("There is a transaction in progress. Please cancel it using `rpm-ostree cancel`"); bail!("There is a transaction in progress. Please cancel it using `rpm-ostree cancel`");
} }
let tempdir = TempDir::new("oci-archive")?; let tempdir = TempDir::new("oci-archive").into_diagnostic()?;
trace!("{tempdir:?}"); trace!("{tempdir:?}");
BuildCommand::builder() BuildCommand::builder()
@ -144,7 +144,8 @@ impl SwitchCommand {
.status_image_ref_progress( .status_image_ref_progress(
format!("{}", archive_path.display()), format!("{}", archive_path.display()),
"Switching to new image", "Switching to new image",
)?; )
.into_diagnostic()?;
if !status.success() { if !status.success() {
bail!("Failed to switch to new image!"); bail!("Failed to switch to new image!");
@ -164,7 +165,11 @@ impl SwitchCommand {
progress.set_message(format!("Moving image archive to {}...", to.display())); progress.set_message(format!("Moving image archive to {}...", to.display()));
trace!("sudo mv {} {}", from.display(), to.display()); trace!("sudo mv {} {}", from.display(), to.display());
let status = Command::new("sudo").arg("mv").args([from, to]).status()?; let status = Command::new("sudo")
.arg("mv")
.args([from, to])
.status()
.into_diagnostic()?;
progress.finish_and_clear(); progress.finish_and_clear();
@ -191,9 +196,11 @@ impl SwitchCommand {
let output = String::from_utf8( let output = String::from_utf8(
Command::new("sudo") Command::new("sudo")
.args(["ls", LOCAL_BUILD]) .args(["ls", LOCAL_BUILD])
.output()? .output()
.into_diagnostic()?
.stdout, .stdout,
)?; )
.into_diagnostic()?;
trace!("{output}"); trace!("{output}");
@ -214,7 +221,8 @@ impl SwitchCommand {
let status = Command::new("sudo") let status = Command::new("sudo")
.args(["rm", "-f"]) .args(["rm", "-f"])
.arg(files) .arg(files)
.status()?; .status()
.into_diagnostic()?;
progress.finish_and_clear(); progress.finish_and_clear();
@ -230,7 +238,8 @@ impl SwitchCommand {
let status = Command::new("sudo") let status = Command::new("sudo")
.args(["mkdir", "-p", LOCAL_BUILD]) .args(["mkdir", "-p", LOCAL_BUILD])
.status()?; .status()
.into_diagnostic()?;
if !status.success() { if !status.success() {
bail!("Failed to create directory {LOCAL_BUILD}"); bail!("Failed to create directory {LOCAL_BUILD}");

View file

@ -10,10 +10,10 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use anyhow::{anyhow, bail, Result};
use blue_build_recipe::Recipe; use blue_build_recipe::Recipe;
use blue_build_utils::constants::IMAGE_VERSION_LABEL; use blue_build_utils::constants::IMAGE_VERSION_LABEL;
use log::{debug, info, trace}; use log::{debug, info, trace};
use miette::{bail, miette, Result};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use semver::{Version, VersionReq}; use semver::{Version, VersionReq};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -202,7 +202,7 @@ pub trait BuildDriver: Sync + Send {
let image = opts let image = opts
.image .image
.as_ref() .as_ref()
.ok_or_else(|| anyhow!("Image is required in order to tag"))?; .ok_or_else(|| miette!("Image is required in order to tag"))?;
debug!("Tagging all images"); debug!("Tagging all images");
for tag in opts.tags.as_ref() { for tag in opts.tags.as_ref() {
@ -369,13 +369,14 @@ impl Driver<'_> {
/// # Errors /// # Errors
/// Will error if the image doesn't have OS version info /// Will error if the image doesn't have OS version info
/// or we are unable to lock a mutex. /// or we are unable to lock a mutex.
///
/// # Panics
/// Panics if the mutex fails to lock.
pub fn get_os_version(recipe: &Recipe) -> Result<u64> { pub fn get_os_version(recipe: &Recipe) -> Result<u64> {
trace!("Driver::get_os_version({recipe:#?})"); trace!("Driver::get_os_version({recipe:#?})");
let image = format!("{}:{}", &recipe.base_image, &recipe.image_version); let image = format!("{}:{}", &recipe.base_image, &recipe.image_version);
let mut os_version_lock = OS_VERSION let mut os_version_lock = OS_VERSION.lock().expect("Should lock");
.lock()
.map_err(|e| anyhow!("Unable set OS_VERSION {e}"))?;
let entry = os_version_lock.get(&image); let entry = os_version_lock.get(&image);
@ -389,8 +390,9 @@ impl Driver<'_> {
let inspection = INSPECT_DRIVER.get_metadata(&inspect_opts)?; let inspection = INSPECT_DRIVER.get_metadata(&inspect_opts)?;
let os_version = inspection.get_version().ok_or_else(|| { let os_version = inspection.get_version().ok_or_else(|| {
anyhow!( miette!(
"Unable to get the OS version from the labels. Please check with the image author about using '{IMAGE_VERSION_LABEL}' to report the os version." help = format!("Please check with the image author about using '{IMAGE_VERSION_LABEL}' to report the os version."),
"Unable to get the OS version from the labels"
) )
})?; })?;
trace!("os_version: {os_version}"); trace!("os_version: {os_version}");

View file

@ -1,8 +1,8 @@
use std::process::Command; use std::process::Command;
use anyhow::{bail, Result};
use blue_build_utils::logging::CommandLogging; use blue_build_utils::logging::CommandLogging;
use log::{error, info, trace}; use log::{error, info, trace};
use miette::{bail, IntoDiagnostic, Result};
use semver::Version; use semver::Version;
use serde::Deserialize; use serde::Deserialize;
@ -33,10 +33,12 @@ impl DriverVersion for BuildahDriver {
let output = Command::new("buildah") let output = Command::new("buildah")
.arg("version") .arg("version")
.arg("--json") .arg("--json")
.output()?; .output()
.into_diagnostic()?;
let version_json: BuildahVersionJson = serde_json::from_slice(&output.stdout) let version_json: BuildahVersionJson = serde_json::from_slice(&output.stdout)
.inspect_err(|e| error!("{e}: {}", String::from_utf8_lossy(&output.stdout)))?; .inspect_err(|e| error!("{e}: {}", String::from_utf8_lossy(&output.stdout)))
.into_diagnostic()?;
trace!("{version_json:#?}"); trace!("{version_json:#?}");
Ok(version_json.version) Ok(version_json.version)
@ -62,7 +64,9 @@ impl BuildDriver for BuildahDriver {
.arg(opts.containerfile.as_ref()) .arg(opts.containerfile.as_ref())
.arg("-t") .arg("-t")
.arg(opts.image.as_ref()); .arg(opts.image.as_ref());
let status = command.status_image_ref_progress(&opts.image, "Building Image")?; let status = command
.status_image_ref_progress(&opts.image, "Building Image")
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully built {}", opts.image); info!("Successfully built {}", opts.image);
@ -80,7 +84,8 @@ impl BuildDriver for BuildahDriver {
.arg("tag") .arg("tag")
.arg(opts.src_image.as_ref()) .arg(opts.src_image.as_ref())
.arg(opts.dest_image.as_ref()) .arg(opts.dest_image.as_ref())
.status()?; .status()
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully tagged {}!", opts.dest_image); info!("Successfully tagged {}!", opts.dest_image);
@ -102,7 +107,9 @@ impl BuildDriver for BuildahDriver {
opts.compression_type.unwrap_or_default() opts.compression_type.unwrap_or_default()
)) ))
.arg(opts.image.as_ref()); .arg(opts.image.as_ref());
let status = command.status_image_ref_progress(&opts.image, "Pushing Image")?; let status = command
.status_image_ref_progress(&opts.image, "Pushing Image")
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully pushed {}!", opts.image); info!("Successfully pushed {}!", opts.image);
@ -129,7 +136,8 @@ impl BuildDriver for BuildahDriver {
.arg("-p") .arg("-p")
.arg(password) .arg(password)
.arg(registry) .arg(registry)
.output()?; .output()
.into_diagnostic()?;
if !output.status.success() { if !output.status.success() {
let err_out = String::from_utf8_lossy(&output.stderr); let err_out = String::from_utf8_lossy(&output.stderr);

View file

@ -6,7 +6,6 @@ use std::{
time::Duration, time::Duration,
}; };
use anyhow::{anyhow, bail, Result};
use blue_build_utils::{ use blue_build_utils::{
constants::{BB_BUILDKIT_CACHE_GHA, CONTAINER_FILE, DOCKER_HOST, SKOPEO_IMAGE}, constants::{BB_BUILDKIT_CACHE_GHA, CONTAINER_FILE, DOCKER_HOST, SKOPEO_IMAGE},
logging::{CommandLogging, Logger}, logging::{CommandLogging, Logger},
@ -14,6 +13,7 @@ use blue_build_utils::{
}; };
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use log::{info, trace, warn}; use log::{info, trace, warn};
use miette::{bail, IntoDiagnostic, Result};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use semver::Version; use semver::Version;
use serde::Deserialize; use serde::Deserialize;
@ -50,9 +50,7 @@ impl DockerDriver {
fn setup() -> Result<()> { fn setup() -> Result<()> {
trace!("DockerDriver::setup()"); trace!("DockerDriver::setup()");
let mut lock = DOCKER_SETUP let mut lock = DOCKER_SETUP.lock().expect("Should lock");
.lock()
.map_err(|e| anyhow!("Failed to lock DOCKER_SETUP: {e}"))?;
if *lock { if *lock {
drop(lock); drop(lock);
@ -64,13 +62,14 @@ impl DockerDriver {
.arg("buildx") .arg("buildx")
.arg("ls") .arg("ls")
.arg("--format={{.Name}}") .arg("--format={{.Name}}")
.output()?; .output()
.into_diagnostic()?;
if !ls_out.status.success() { if !ls_out.status.success() {
bail!("{}", String::from_utf8_lossy(&ls_out.stderr)); bail!("{}", String::from_utf8_lossy(&ls_out.stderr));
} }
let ls_out = String::from_utf8(ls_out.stdout)?; let ls_out = String::from_utf8(ls_out.stdout).into_diagnostic()?;
trace!("{ls_out}"); trace!("{ls_out}");
@ -82,7 +81,8 @@ impl DockerDriver {
.arg("--bootstrap") .arg("--bootstrap")
.arg("--driver=docker-container") .arg("--driver=docker-container")
.arg("--name=bluebuild") .arg("--name=bluebuild")
.output()?; .output()
.into_diagnostic()?;
if !create_out.status.success() { if !create_out.status.success() {
bail!("{}", String::from_utf8_lossy(&create_out.stderr)); bail!("{}", String::from_utf8_lossy(&create_out.stderr));
@ -105,9 +105,11 @@ impl DriverVersion for DockerDriver {
.arg("version") .arg("version")
.arg("-f") .arg("-f")
.arg("json") .arg("json")
.output()?; .output()
.into_diagnostic()?;
let version_json: DockerVersionJson = serde_json::from_slice(&output.stdout)?; let version_json: DockerVersionJson =
serde_json::from_slice(&output.stdout).into_diagnostic()?;
Ok(version_json.client.version) Ok(version_json.client.version)
} }
@ -129,7 +131,8 @@ impl BuildDriver for DockerDriver {
.arg("-f") .arg("-f")
.arg(opts.containerfile.as_ref()) .arg(opts.containerfile.as_ref())
.arg(".") .arg(".")
.status()?; .status()
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully built {}", opts.image); info!("Successfully built {}", opts.image);
@ -147,7 +150,8 @@ impl BuildDriver for DockerDriver {
.arg("tag") .arg("tag")
.arg(opts.src_image.as_ref()) .arg(opts.src_image.as_ref())
.arg(opts.dest_image.as_ref()) .arg(opts.dest_image.as_ref())
.status()?; .status()
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully tagged {}!", opts.dest_image); info!("Successfully tagged {}!", opts.dest_image);
@ -164,7 +168,8 @@ impl BuildDriver for DockerDriver {
let status = Command::new("docker") let status = Command::new("docker")
.arg("push") .arg("push")
.arg(opts.image.as_ref()) .arg(opts.image.as_ref())
.status()?; .status()
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully pushed {}!", opts.image); info!("Successfully pushed {}!", opts.image);
@ -191,7 +196,8 @@ impl BuildDriver for DockerDriver {
.arg("-p") .arg("-p")
.arg(password) .arg(password)
.arg(registry) .arg(registry)
.output()?; .output()
.into_diagnostic()?;
if !output.status.success() { if !output.status.success() {
let err_out = String::from_utf8_lossy(&output.stderr); let err_out = String::from_utf8_lossy(&output.stderr);
@ -287,7 +293,8 @@ impl BuildDriver for DockerDriver {
command.arg("."); command.arg(".");
if command if command
.status_image_ref_progress(&final_image, "Building Image")? .status_image_ref_progress(&final_image, "Building Image")
.into_diagnostic()?
.success() .success()
{ {
if opts.push { if opts.push {
@ -318,12 +325,14 @@ impl InspectDriver for DockerDriver {
); );
progress.enable_steady_tick(Duration::from_millis(100)); progress.enable_steady_tick(Duration::from_millis(100));
let output = self.run_output( let output = self
.run_output(
&RunOpts::builder() &RunOpts::builder()
.image(SKOPEO_IMAGE) .image(SKOPEO_IMAGE)
.args(&["inspect".to_string(), url.clone()]) .args(&["inspect".to_string(), url.clone()])
.build(), .build(),
)?; )
.into_diagnostic()?;
progress.finish(); progress.finish();
Logger::multi_progress().remove(&progress); Logger::multi_progress().remove(&progress);
@ -334,7 +343,7 @@ impl InspectDriver for DockerDriver {
bail!("Failed to inspect image {url}") bail!("Failed to inspect image {url}")
} }
Ok(serde_json::from_slice(&output.stdout)?) serde_json::from_slice(&output.stdout).into_diagnostic()
} }
} }

View file

@ -4,7 +4,6 @@ use std::{
time::Duration, time::Duration,
}; };
use anyhow::{bail, Result};
use blue_build_utils::{ use blue_build_utils::{
constants::SKOPEO_IMAGE, constants::SKOPEO_IMAGE,
logging::{CommandLogging, Logger}, logging::{CommandLogging, Logger},
@ -13,6 +12,7 @@ use blue_build_utils::{
use colored::Colorize; use colored::Colorize;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use miette::{bail, IntoDiagnostic, Result};
use semver::Version; use semver::Version;
use serde::Deserialize; use serde::Deserialize;
use tempdir::TempDir; use tempdir::TempDir;
@ -55,10 +55,12 @@ impl DriverVersion for PodmanDriver {
.arg("version") .arg("version")
.arg("-f") .arg("-f")
.arg("json") .arg("json")
.output()?; .output()
.into_diagnostic()?;
let version_json: PodmanVersionJson = serde_json::from_slice(&output.stdout) let version_json: PodmanVersionJson = serde_json::from_slice(&output.stdout)
.inspect_err(|e| error!("{e}: {}", String::from_utf8_lossy(&output.stdout)))?; .inspect_err(|e| error!("{e}: {}", String::from_utf8_lossy(&output.stdout)))
.into_diagnostic()?;
trace!("{version_json:#?}"); trace!("{version_json:#?}");
Ok(version_json.client.version) Ok(version_json.client.version)
@ -85,7 +87,9 @@ impl BuildDriver for PodmanDriver {
.arg("-t") .arg("-t")
.arg(opts.image.as_ref()) .arg(opts.image.as_ref())
.arg("."); .arg(".");
let status = command.status_image_ref_progress(&opts.image, "Building Image")?; let status = command
.status_image_ref_progress(&opts.image, "Building Image")
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully built {}", opts.image); info!("Successfully built {}", opts.image);
@ -103,7 +107,8 @@ impl BuildDriver for PodmanDriver {
.arg("tag") .arg("tag")
.arg(opts.src_image.as_ref()) .arg(opts.src_image.as_ref())
.arg(opts.dest_image.as_ref()) .arg(opts.dest_image.as_ref())
.status()?; .status()
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully tagged {}!", opts.dest_image); info!("Successfully tagged {}!", opts.dest_image);
@ -125,7 +130,9 @@ impl BuildDriver for PodmanDriver {
opts.compression_type.unwrap_or_default() opts.compression_type.unwrap_or_default()
)) ))
.arg(opts.image.as_ref()); .arg(opts.image.as_ref());
let status = command.status_image_ref_progress(&opts.image, "Pushing Image")?; let status = command
.status_image_ref_progress(&opts.image, "Pushing Image")
.into_diagnostic()?;
if status.success() { if status.success() {
info!("Successfully pushed {}!", opts.image); info!("Successfully pushed {}!", opts.image);
@ -152,7 +159,8 @@ impl BuildDriver for PodmanDriver {
.arg("-p") .arg("-p")
.arg(password) .arg(password)
.arg(registry) .arg(registry)
.output()?; .output()
.into_diagnostic()?;
if !output.status.success() { if !output.status.success() {
let err_out = String::from_utf8_lossy(&output.stderr); let err_out = String::from_utf8_lossy(&output.stderr);
@ -179,12 +187,14 @@ impl InspectDriver for PodmanDriver {
); );
progress.enable_steady_tick(Duration::from_millis(100)); progress.enable_steady_tick(Duration::from_millis(100));
let output = self.run_output( let output = self
.run_output(
&RunOpts::builder() &RunOpts::builder()
.image(SKOPEO_IMAGE) .image(SKOPEO_IMAGE)
.args(&["inspect".to_string(), url.clone()]) .args(&["inspect".to_string(), url.clone()])
.build(), .build(),
)?; )
.into_diagnostic()?;
progress.finish(); progress.finish();
Logger::multi_progress().remove(&progress); Logger::multi_progress().remove(&progress);
@ -194,7 +204,7 @@ impl InspectDriver for PodmanDriver {
} else { } else {
bail!("Failed to inspect image {url}"); bail!("Failed to inspect image {url}");
} }
Ok(serde_json::from_slice(&output.stdout)?) serde_json::from_slice(&output.stdout).into_diagnostic()
} }
} }

View file

@ -3,10 +3,10 @@ use std::{
time::Duration, time::Duration,
}; };
use anyhow::{bail, Result};
use blue_build_utils::logging::Logger; use blue_build_utils::logging::Logger;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use log::{debug, trace}; use log::{debug, trace};
use miette::{bail, IntoDiagnostic, Result};
use crate::image_metadata::ImageMetadata; use crate::image_metadata::ImageMetadata;
@ -36,7 +36,8 @@ impl InspectDriver for SkopeoDriver {
.arg("inspect") .arg("inspect")
.arg(&url) .arg(&url)
.stderr(Stdio::inherit()) .stderr(Stdio::inherit())
.output()?; .output()
.into_diagnostic()?;
progress.finish(); progress.finish();
Logger::multi_progress().remove(&progress); Logger::multi_progress().remove(&progress);
@ -46,6 +47,6 @@ impl InspectDriver for SkopeoDriver {
} else { } else {
bail!("Failed to inspect image {url}") bail!("Failed to inspect image {url}")
} }
Ok(serde_json::from_slice(&output.stdout)?) serde_json::from_slice(&output.stdout).into_diagnostic()
} }
} }

View file

@ -1,7 +1,7 @@
use std::{borrow::Cow, path::Path, process::Command}; use std::{borrow::Cow, path::Path, process::Command};
use anyhow::{bail, Result};
use log::trace; use log::trace;
use miette::{bail, IntoDiagnostic, Result};
use serde::Deserialize; use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -29,7 +29,8 @@ impl<'a> RpmOstreeStatus<'a> {
trace!("rpm-ostree status --json"); trace!("rpm-ostree status --json");
let output = Command::new("rpm-ostree") let output = Command::new("rpm-ostree")
.args(["status", "--json"]) .args(["status", "--json"])
.output()?; .output()
.into_diagnostic()?;
if !output.status.success() { if !output.status.success() {
bail!("Failed to get `rpm-ostree` status!"); bail!("Failed to get `rpm-ostree` status!");
@ -37,7 +38,7 @@ impl<'a> RpmOstreeStatus<'a> {
trace!("{}", String::from_utf8_lossy(&output.stdout)); trace!("{}", String::from_utf8_lossy(&output.stdout));
Ok(serde_json::from_slice(&output.stdout)?) serde_json::from_slice(&output.stdout).into_diagnostic()
} }
/// Checks if there is a transaction in progress. /// Checks if there is a transaction in progress.

View file

@ -9,6 +9,7 @@ license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1"
atty = "0.2" atty = "0.2"
base64 = "0.22.1" base64 = "0.22.1"
blake2 = "0.10.6" blake2 = "0.10.6"
@ -23,7 +24,6 @@ signal-hook = { version = "0.3.17", features = ["extended-siginfo"] }
syntect = "5" syntect = "5"
which = "6" which = "6"
anyhow.workspace = true
chrono.workspace = true chrono.workspace = true
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }
colored.workspace = true colored.workspace = true
@ -31,6 +31,7 @@ format_serde_error.workspace = true
indicatif.workspace = true indicatif.workspace = true
indicatif-log-bridge.workspace = true indicatif-log-bridge.workspace = true
log.workspace = true log.workspace = true
miette.workspace = true
once_cell.workspace = true once_cell.workspace = true
tempdir.workspace = true tempdir.workspace = true
serde.workspace = true serde.workspace = true

View file

@ -12,7 +12,6 @@ use std::{
time::Duration, time::Duration,
}; };
use anyhow::{anyhow, Result};
use base64::prelude::*; use base64::prelude::*;
use blake2::{ use blake2::{
digest::{Update, VariableOutput}, digest::{Update, VariableOutput},
@ -20,6 +19,7 @@ use blake2::{
}; };
use format_serde_error::SerdeError; use format_serde_error::SerdeError;
use log::trace; use log::trace;
use miette::{miette, IntoDiagnostic, Result};
use crate::constants::CONTAINER_FILE; use crate::constants::CONTAINER_FILE;
@ -35,14 +35,15 @@ pub fn check_command_exists(command: &str) -> Result<()> {
trace!("which {command}"); trace!("which {command}");
if Command::new("which") if Command::new("which")
.arg(command) .arg(command)
.output()? .output()
.into_diagnostic()?
.status .status
.success() .success()
{ {
trace!("Command {command} does exist"); trace!("Command {command} does exist");
Ok(()) Ok(())
} else { } else {
Err(anyhow!( Err(miette!(
"Command {command} doesn't exist and is required to build the image" "Command {command} doesn't exist and is required to build the image"
)) ))
} }
@ -69,9 +70,9 @@ pub fn serde_yaml_err(contents: &str) -> impl Fn(serde_yaml::Error) -> SerdeErro
/// ///
/// # Errors /// # Errors
/// Will error when retries have been expended. /// Will error when retries have been expended.
pub fn retry<V, F>(attempts: u8, delay: u64, f: F) -> anyhow::Result<V> pub fn retry<V, F>(attempts: u8, delay: u64, f: F) -> miette::Result<V>
where where
F: Fn() -> anyhow::Result<V>, F: Fn() -> miette::Result<V>,
{ {
let mut attempts = attempts; let mut attempts = attempts;
loop { loop {
@ -100,9 +101,9 @@ pub fn generate_containerfile_path<T: AsRef<Path>>(path: T) -> Result<PathBuf> {
const HASH_SIZE: usize = 8; const HASH_SIZE: usize = 8;
let mut buf = [0u8; HASH_SIZE]; let mut buf = [0u8; HASH_SIZE];
let mut hasher = Blake2bVar::new(HASH_SIZE)?; let mut hasher = Blake2bVar::new(HASH_SIZE).into_diagnostic()?;
hasher.update(path.as_ref().as_os_str().as_bytes()); hasher.update(path.as_ref().as_os_str().as_bytes());
hasher.finalize_variable(&mut buf)?; hasher.finalize_variable(&mut buf).into_diagnostic()?;
Ok(PathBuf::from(format!( Ok(PathBuf::from(format!(
"{CONTAINER_FILE}.{}", "{CONTAINER_FILE}.{}",

View file

@ -1,6 +1,6 @@
use anyhow::{anyhow, Result};
use clap::ValueEnum; use clap::ValueEnum;
use log::trace; use log::trace;
use miette::{miette, IntoDiagnostic, Result};
use serde::ser::Serialize; use serde::ser::Serialize;
use syntect::{dumps, easy::HighlightLines, highlighting::ThemeSet, parsing::SyntaxSet}; use syntect::{dumps, easy::HighlightLines, highlighting::ThemeSet, parsing::SyntaxSet};
@ -42,7 +42,8 @@ pub fn highlight(file: &str, file_type: &str, theme: Option<DefaultThemes>) -> R
dumps::from_uncompressed_data(include_bytes!(concat!( dumps::from_uncompressed_data(include_bytes!(concat!(
env!("OUT_DIR"), env!("OUT_DIR"),
"/docker_syntax.bin" "/docker_syntax.bin"
)))? )))
.into_diagnostic()?
} else { } else {
SyntaxSet::load_defaults_newlines() SyntaxSet::load_defaults_newlines()
}; };
@ -50,18 +51,18 @@ pub fn highlight(file: &str, file_type: &str, theme: Option<DefaultThemes>) -> R
let syntax = ss let syntax = ss
.find_syntax_by_extension(file_type) .find_syntax_by_extension(file_type)
.ok_or_else(|| anyhow!("Failed to get syntax"))?; .ok_or_else(|| miette!("Failed to get syntax"))?;
let mut h = HighlightLines::new( let mut h = HighlightLines::new(
syntax, syntax,
ts.themes ts.themes
.get(theme.unwrap_or_default().to_string().as_str()) .get(theme.unwrap_or_default().to_string().as_str())
.ok_or_else(|| anyhow!("Failed to get highlight theme"))?, .ok_or_else(|| miette!("Failed to get highlight theme"))?,
); );
let mut highlighted_lines: Vec<String> = vec![]; let mut highlighted_lines: Vec<String> = vec![];
for line in file.lines() { for line in file.lines() {
highlighted_lines.push(syntect::util::as_24_bit_terminal_escaped( highlighted_lines.push(syntect::util::as_24_bit_terminal_escaped(
&h.highlight_line(line, &ss)?, &h.highlight_line(line, &ss).into_diagnostic()?,
false, false,
)); ));
} }
@ -83,7 +84,11 @@ pub fn highlight_ser<T: Serialize + std::fmt::Debug>(
theme: Option<DefaultThemes>, theme: Option<DefaultThemes>,
) -> Result<String> { ) -> Result<String> {
trace!("syntax_highlighting::highlight_ser(file, {file_type}, {theme:?})"); trace!("syntax_highlighting::highlight_ser(file, {file_type}, {theme:?})");
highlight(serde_yaml::to_string(file)?.as_str(), file_type, theme) highlight(
serde_yaml::to_string(file).into_diagnostic()?.as_str(),
file_type,
theme,
)
} }
/// Prints the file with syntax highlighting. /// Prints the file with syntax highlighting.
@ -108,6 +113,10 @@ pub fn print_ser<T: Serialize + std::fmt::Debug>(
theme: Option<DefaultThemes>, theme: Option<DefaultThemes>,
) -> Result<()> { ) -> Result<()> {
trace!("syntax_highlighting::print_ser(file, {file_type}, {theme:?})"); trace!("syntax_highlighting::print_ser(file, {file_type}, {theme:?})");
print(serde_yaml::to_string(file)?.as_str(), file_type, theme)?; print(
serde_yaml::to_string(file).into_diagnostic()?.as_str(),
file_type,
theme,
)?;
Ok(()) Ok(())
} }