Skip to content

Commit 82ff677

Browse files
jeckersbclaude
authored andcommitted
system-reinstall-bootc: Add context annotations to Result-returning functions
Add #[context()] attribute macro to all functions that return Result to improve error reporting. This includes adding the fn-error-context dependency and importing the context macro in all relevant modules. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: John Eckersberg <[email protected]>
1 parent 4d56384 commit 82ff677

File tree

9 files changed

+33
-0
lines changed

9 files changed

+33
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/system-reinstall-bootc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ bootc-utils = { package = "bootc-internal-utils", path = "../utils", version = "
2222
anstream = { workspace = true }
2323
anyhow = { workspace = true }
2424
clap = { workspace = true, features = ["derive"] }
25+
fn-error-context = { workspace = true }
2526
indoc = { workspace = true }
2627
log = { workspace = true }
2728
rustix = { workspace = true }

crates/system-reinstall-bootc/src/btrfs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use anyhow::Result;
22
use bootc_mount::Filesystem;
3+
use fn_error_context::context;
34

5+
#[context("check_root_siblings")]
46
pub(crate) fn check_root_siblings() -> Result<Vec<String>> {
57
let mounts = bootc_mount::run_findmnt(&[], None)?;
68
let problem_filesystems: Vec<String> = mounts

crates/system-reinstall-bootc/src/config/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::{fs::File, io::BufReader};
22

33
use anyhow::{Context, Result};
44
use bootc_utils::PathQuotedDisplay;
5+
use fn_error_context::context;
56
use serde::{Deserialize, Serialize};
67

78
mod cli;
@@ -17,6 +18,7 @@ pub(crate) struct ReinstallConfig {
1718
}
1819

1920
impl ReinstallConfig {
21+
#[context("load")]
2022
pub fn load() -> Result<Option<Self>> {
2123
let Some(config) = std::env::var_os(CONFIG_VAR) else {
2224
return Ok(None);

crates/system-reinstall-bootc/src/lvm.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::process::Command;
33
use anyhow::Result;
44
use bootc_mount::run_findmnt;
55
use bootc_utils::{CommandRunExt, ResultExt};
6+
use fn_error_context::context;
67
use serde::Deserialize;
78

89
#[derive(Debug, Deserialize)]
@@ -23,6 +24,7 @@ pub(crate) struct LogicalVolume {
2324
vg_name: String,
2425
}
2526

27+
#[context("parse_volumes")]
2628
pub(crate) fn parse_volumes(group: Option<&str>) -> Result<Vec<LogicalVolume>> {
2729
if which::which("podman").is_err() {
2830
tracing::debug!("lvs binary not found. Skipping logical volume check.");
@@ -46,6 +48,7 @@ pub(crate) fn parse_volumes(group: Option<&str>) -> Result<Vec<LogicalVolume>> {
4648
.collect())
4749
}
4850

51+
#[context("check_root_siblings")]
4952
pub(crate) fn check_root_siblings() -> Result<Vec<String>> {
5053
let all_volumes = parse_volumes(None)?;
5154

crates/system-reinstall-bootc/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use anyhow::{ensure, Context, Result};
44
use bootc_utils::CommandRunExt;
55
use clap::Parser;
6+
use fn_error_context::context;
67
use rustix::process::getuid;
78

89
mod btrfs;
@@ -29,6 +30,7 @@ struct Opts {
2930
// Note if we ever add any other options here,
3031
}
3132

33+
#[context("run")]
3234
fn run() -> Result<()> {
3335
// We historically supported an environment variable providing a config to override the image, so
3436
// keep supporting that. I'm considering deprecating that though.

crates/system-reinstall-bootc/src/podman.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ use crate::prompt;
33
use super::ROOT_KEY_MOUNT_POINT;
44
use anyhow::{ensure, Context, Result};
55
use bootc_utils::CommandRunExt;
6+
use fn_error_context::context;
67
use std::process::Command;
78
use which::which;
89

10+
#[context("bootc_has_clean")]
911
fn bootc_has_clean(image: &str) -> Result<bool> {
1012
let output = Command::new("podman")
1113
.args([
@@ -22,6 +24,7 @@ fn bootc_has_clean(image: &str) -> Result<bool> {
2224
Ok(stdout_str.contains("--cleanup"))
2325
}
2426

27+
#[context("reinstall_command")]
2528
pub(crate) fn reinstall_command(image: &str, ssh_key_file: &str) -> Result<Command> {
2629
let mut podman_command_and_args = [
2730
// We use podman to run the bootc container. This might change in the future to remove the
@@ -108,6 +111,7 @@ fn image_exists_command(image: &str) -> Command {
108111
command
109112
}
110113

114+
#[context("pull_if_not_present")]
111115
pub(crate) fn pull_if_not_present(image: &str) -> Result<()> {
112116
let result = image_exists_command(image).status()?;
113117

@@ -136,6 +140,7 @@ const fn podman_install_script_path() -> &'static str {
136140
}
137141
}
138142

143+
#[context("ensure_podman_installed")]
139144
pub(crate) fn ensure_podman_installed() -> Result<()> {
140145
if which("podman").is_ok() {
141146
return Ok(());

crates/system-reinstall-bootc/src/prompt.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ macro_rules! println_flush {
1111

1212
use crate::{btrfs, lvm, prompt, users::get_all_users_keys};
1313
use anyhow::{ensure, Context, Result};
14+
use fn_error_context::context;
1415

1516
use crossterm::event::{self, Event};
1617
use std::time::Duration;
@@ -19,6 +20,7 @@ const NO_SSH_PROMPT: &str = "None of the users on this system found have authori
1920
if your image doesn't use cloud-init or other means to set up users, \
2021
you may not be able to log in after reinstalling. Do you want to continue?";
2122

23+
#[context("prompt_single_user")]
2224
fn prompt_single_user(user: &crate::users::UserKeys) -> Result<Vec<&crate::users::UserKeys>> {
2325
let prompt = indoc::formatdoc! {
2426
"Found only one user ({user}) with {num_keys} SSH authorized keys.
@@ -32,6 +34,7 @@ fn prompt_single_user(user: &crate::users::UserKeys) -> Result<Vec<&crate::users
3234
Ok(if answer { vec![&user] } else { vec![] })
3335
}
3436

37+
#[context("prompt_user_selection")]
3538
fn prompt_user_selection(
3639
all_users: &[crate::users::UserKeys],
3740
) -> Result<Vec<&crate::users::UserKeys>> {
@@ -55,6 +58,7 @@ fn prompt_user_selection(
5558
.collect())
5659
}
5760

61+
#[context("reboot")]
5862
pub(crate) fn reboot() -> Result<()> {
5963
let delay_seconds = 10;
6064
println_flush!(
@@ -79,6 +83,7 @@ pub(crate) fn reboot() -> Result<()> {
7983

8084
/// Temporary safety mechanism to stop devs from running it on their dev machine. TODO: Discuss
8185
/// final prompting UX in https://github.com/bootc-dev/bootc/discussions/1060
86+
#[context("temporary_developer_protection_prompt")]
8287
pub(crate) fn temporary_developer_protection_prompt() -> Result<()> {
8388
// Print an empty line so that the warning stands out from the rest of the output
8489
println_flush!();
@@ -94,6 +99,7 @@ pub(crate) fn temporary_developer_protection_prompt() -> Result<()> {
9499
Ok(())
95100
}
96101

102+
#[context("ask_yes_no")]
97103
pub(crate) fn ask_yes_no(prompt: &str, default: bool) -> Result<bool> {
98104
dialoguer::Confirm::new()
99105
.with_prompt(prompt)
@@ -114,6 +120,7 @@ pub(crate) fn press_enter() {
114120
}
115121
}
116122

123+
#[context("mount_warning")]
117124
pub(crate) fn mount_warning() -> Result<()> {
118125
let mut mounts = btrfs::check_root_siblings()?;
119126
mounts.extend(lvm::check_root_siblings()?);
@@ -138,6 +145,7 @@ pub(crate) fn mount_warning() -> Result<()> {
138145
/// The keys are stored in a temporary file which is passed to
139146
/// the podman run invocation to be used by
140147
/// `bootc install to-existing-root --root-ssh-authorized-keys`
148+
#[context("get_ssh_keys")]
141149
pub(crate) fn get_ssh_keys(temp_key_file_path: &str) -> Result<()> {
142150
let users = get_all_users_keys()?;
143151
if users.is_empty() {

crates/system-reinstall-bootc/src/users.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::{Context, Result};
22
use bootc_utils::CommandRunExt;
33
use bootc_utils::PathQuotedDisplay;
4+
use fn_error_context::context;
45
use openssh_keys::PublicKey;
56
use rustix::fs::Uid;
67
use rustix::process::geteuid;
@@ -17,13 +18,15 @@ use std::os::unix::process::CommandExt;
1718
use std::process::Command;
1819
use uzers::os::unix::UserExt;
1920

21+
#[context("loginctl_users")]
2022
fn loginctl_users() -> Result<BTreeSet<String>> {
2123
let loginctl_raw_output = loginctl_run_compat()?;
2224

2325
loginctl_parse(loginctl_raw_output)
2426
}
2527

2628
/// See [`test::test_parse_lsblk`] for example loginctl output
29+
#[context("loginctl_parse")]
2730
fn loginctl_parse(users: Value) -> Result<BTreeSet<String>> {
2831
users
2932
.as_array()
@@ -47,6 +50,7 @@ fn loginctl_parse(users: Value) -> Result<BTreeSet<String>> {
4750
}
4851

4952
/// Run `loginctl` with some compatibility maneuvers to get JSON output
53+
#[context("loginctl_run_compat")]
5054
fn loginctl_run_compat() -> Result<Value> {
5155
let mut command = Command::new("loginctl");
5256
command.arg("list-sessions").arg("--output").arg("json");
@@ -71,6 +75,7 @@ struct UidChange {
7175
}
7276

7377
impl UidChange {
78+
#[context("new")]
7479
fn new(change_to_uid: Uid) -> Result<Self> {
7580
let (uid, euid) = (getuid(), geteuid());
7681
set_thread_res_uid(uid, change_to_uid, euid).context("setting effective uid failed")?;
@@ -115,6 +120,7 @@ struct SshdConfig<'a> {
115120
}
116121

117122
impl<'a> SshdConfig<'a> {
123+
#[context("parse")]
118124
pub fn parse(sshd_output: &'a str) -> Result<SshdConfig<'a>> {
119125
let config = sshd_output
120126
.lines()
@@ -138,6 +144,7 @@ impl<'a> SshdConfig<'a> {
138144
}
139145
}
140146

147+
#[context("get_keys_from_files")]
141148
fn get_keys_from_files(user: &uzers::User, keyfiles: &Vec<&str>) -> Result<Vec<PublicKey>> {
142149
let home_dir = user.home_dir();
143150
let mut user_authorized_keys: Vec<PublicKey> = Vec::new();
@@ -170,6 +177,7 @@ fn get_keys_from_files(user: &uzers::User, keyfiles: &Vec<&str>) -> Result<Vec<P
170177
Ok(user_authorized_keys)
171178
}
172179

180+
#[context("get_keys_from_command")]
173181
fn get_keys_from_command(command: &str, command_user: &str) -> Result<Vec<PublicKey>> {
174182
let user_config = uzers::get_user_by_name(command_user).context(format!(
175183
"authorized_keys_command_user {command_user} not found"
@@ -184,6 +192,7 @@ fn get_keys_from_command(command: &str, command_user: &str) -> Result<Vec<Public
184192
Ok(keys)
185193
}
186194

195+
#[context("get_all_users_keys")]
187196
pub(crate) fn get_all_users_keys() -> Result<Vec<UserKeys>> {
188197
let loginctl_user_names = loginctl_users().context("enumerate users")?;
189198

0 commit comments

Comments
 (0)