Skip to content

Commit 5ddadfc

Browse files
committed
bootspec: use our own error type
This makes it much less painful for consumers of the bootspec crate to handle any errors that may occur.
1 parent 905d8d1 commit 5ddadfc

File tree

7 files changed

+120
-36
lines changed

7 files changed

+120
-36
lines changed

Cargo.lock

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

bootspec/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ authors = ["Graham Christensen <[email protected]>", "Cole Helbling <co
1313
[dependencies]
1414
serde = { version = "1.0.152", features = ["derive"] }
1515
serde_json = "1.0.91"
16+
thiserror = "1.0.40"
1617

1718
[dev-dependencies]
1819
tempfile = "3.5.0"

bootspec/src/error.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use std::path::PathBuf;
2+
3+
#[derive(Debug, thiserror::Error)]
4+
pub enum BootspecError {
5+
#[error("failed to synthesize: {0}")]
6+
Synthesize(#[from] SynthesizeError),
7+
#[error(transparent)]
8+
Io(#[from] std::io::Error),
9+
#[error("{0} had an invalid file name")]
10+
InvalidFileName(PathBuf),
11+
#[error("{0} contained invalid UTF8")]
12+
InvalidUtf8(PathBuf),
13+
}
14+
15+
#[derive(Debug, thiserror::Error)]
16+
pub enum SynthesizeError {
17+
#[error("unsupported schema version {0}")]
18+
UnsupportedVersion(u64),
19+
#[error("failed to canonicalize {path}: {err}")]
20+
Canonicalize {
21+
path: PathBuf,
22+
#[source]
23+
err: std::io::Error,
24+
},
25+
#[error("failed to read {path}: {err}")]
26+
ReadPath {
27+
path: PathBuf,
28+
#[source]
29+
err: std::io::Error,
30+
},
31+
#[error("could not find kernel version dir in {0}")]
32+
MissingKernelVersionDir(PathBuf),
33+
}

bootspec/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
mod deser;
2+
pub mod error;
23
pub mod generation;
34
pub mod v1;
45

56
use std::collections::HashMap;
6-
use std::error::Error;
77
use std::fmt;
88
use std::path::{Path, PathBuf};
99

1010
use serde::{Deserialize, Serialize};
1111

12+
use crate::error::{BootspecError, SynthesizeError};
1213
use crate::generation::Generation;
1314

1415
#[doc(hidden)]
15-
pub type Result<T, E = Box<dyn Error + Send + Sync + 'static>> = core::result::Result<T, E>;
16+
pub(crate) type Result<T, E = BootspecError> = core::result::Result<T, E>;
1617

1718
/// A wrapper type describing the name of a NixOS specialisation.
1819
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
@@ -85,9 +86,9 @@ impl BootJson {
8586
Generation::V1(generation)
8687
}
8788
v => {
88-
return Err(
89-
format!("Cannot synthesize for unsupported schema version {}", v).into(),
90-
)
89+
return Err(BootspecError::Synthesize(
90+
SynthesizeError::UnsupportedVersion(v),
91+
))
9192
}
9293
};
9394

bootspec/src/v1.rs

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
55

66
use serde::{Deserialize, Serialize};
77

8+
use crate::error::{BootspecError, SynthesizeError};
89
use crate::{Result, SpecialisationName, SystemConfigurationRoot};
910

1011
/// The V1 bootspec schema version.
@@ -40,9 +41,9 @@ impl GenerationV1 {
4041
let specialisation = specialisation?;
4142
let name = specialisation
4243
.file_name()
43-
.ok_or("Could not get name of specialisation dir")?
44+
.ok_or(BootspecError::InvalidFileName(specialisation.clone()))?
4445
.to_str()
45-
.ok_or("Specialisation dir name was invalid UTF8")?;
46+
.ok_or(BootspecError::InvalidUtf8(specialisation.clone()))?;
4647
let toplevel = fs::canonicalize(generation_path.join("specialisation").join(name))?;
4748

4849
specialisations.insert(
@@ -92,29 +93,54 @@ impl BootSpecV1 {
9293
pub(crate) fn synthesize(generation: &Path) -> Result<Self> {
9394
let generation = generation
9495
.canonicalize()
95-
.map_err(|e| format!("Failed to canonicalize generation dir:\n{}", e))?;
96-
97-
let system_version = fs::read_to_string(generation.join("nixos-version"))
98-
.map_err(|e| format!("Failed to read system version:\n{}", e))?;
99-
100-
let system = fs::read_to_string(generation.join("system"))
101-
.map_err(|e| format!("Failed to read system double:\n{}", e))?;
102-
103-
let kernel = fs::canonicalize(generation.join("kernel-modules/bzImage"))
104-
.map_err(|e| format!("Failed to canonicalize the kernel:\n{}", e))?;
105-
106-
let kernel_modules = fs::canonicalize(generation.join("kernel-modules/lib/modules"))
107-
.map_err(|e| format!("Failed to canonicalize the kernel modules dir:\n{}", e))?;
108-
let versioned_kernel_modules = fs::read_dir(kernel_modules)
109-
.map_err(|e| format!("Failed to read kernel modules dir:\n{}", e))?
96+
.map_err(|e| SynthesizeError::Canonicalize {
97+
path: generation.to_path_buf(),
98+
err: e,
99+
})?;
100+
101+
let version_file = generation.join("nixos-version");
102+
let system_version =
103+
fs::read_to_string(version_file.clone()).map_err(|e| SynthesizeError::ReadPath {
104+
path: version_file,
105+
err: e,
106+
})?;
107+
108+
let system_file = generation.join("system");
109+
let system =
110+
fs::read_to_string(system_file.clone()).map_err(|e| SynthesizeError::ReadPath {
111+
path: system_file,
112+
err: e,
113+
})?;
114+
115+
let kernel_file = generation.join("kernel-modules/bzImage");
116+
let kernel =
117+
fs::canonicalize(kernel_file.clone()).map_err(|e| SynthesizeError::Canonicalize {
118+
path: kernel_file,
119+
err: e,
120+
})?;
121+
122+
let kernel_modules_path = generation.join("kernel-modules/lib/modules");
123+
let kernel_modules = fs::canonicalize(kernel_modules_path.clone()).map_err(|e| {
124+
SynthesizeError::Canonicalize {
125+
path: kernel_modules_path,
126+
err: e,
127+
}
128+
})?;
129+
let versioned_kernel_modules = fs::read_dir(kernel_modules.clone())
130+
.map_err(|e| SynthesizeError::ReadPath {
131+
path: kernel_modules.clone(),
132+
err: e,
133+
})?
110134
.map(|res| res.map(|e| e.path()))
111135
.next()
112-
.ok_or("Could not find kernel version dir")??;
136+
.ok_or(SynthesizeError::MissingKernelVersionDir(kernel_modules))??;
113137
let kernel_version = versioned_kernel_modules
114138
.file_name()
115-
.ok_or("Could not get name of kernel version dir")?
139+
.ok_or(BootspecError::InvalidFileName(
140+
versioned_kernel_modules.clone(),
141+
))?
116142
.to_str()
117-
.ok_or("Kernel version dir name was invalid UTF8")?;
143+
.ok_or(BootspecError::InvalidUtf8(versioned_kernel_modules.clone()))?;
118144

119145
let kernel_params: Vec<String> = fs::read_to_string(generation.join("kernel-params"))?
120146
.split(' ')
@@ -125,10 +151,12 @@ impl BootSpecV1 {
125151

126152
let initrd_path = generation.join("initrd");
127153
let initrd = if initrd_path.exists() {
128-
Some(
129-
fs::canonicalize(initrd_path)
130-
.map_err(|e| format!("Failed to canonicalize the initrd:\n{}", e))?,
131-
)
154+
Some(fs::canonicalize(initrd_path.clone()).map_err(|e| {
155+
SynthesizeError::Canonicalize {
156+
path: initrd_path,
157+
err: e,
158+
}
159+
})?)
132160
} else {
133161
None
134162
};

synthesize/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fs;
22
use std::io::{self, Write};
33
use std::path::PathBuf;
44

5-
use bootspec::{BootJson, Result};
5+
use bootspec::BootJson;
66

77
#[derive(clap::Parser)]
88
struct Cli {
@@ -12,7 +12,7 @@ struct Cli {
1212
version: u64,
1313
}
1414

15-
fn main() -> Result<()> {
15+
fn main() -> Result<(), Box<dyn std::error::Error>> {
1616
if let Err(e) = self::cli() {
1717
writeln!(io::stderr(), "{}", e)?;
1818

@@ -22,7 +22,7 @@ fn main() -> Result<()> {
2222
Ok(())
2323
}
2424

25-
fn cli() -> Result<()> {
25+
fn cli() -> Result<(), Box<dyn std::error::Error>> {
2626
let args: Cli = clap::Parser::parse();
2727
let generation_dir = args.generation_dir;
2828
let out_path = args.out_path;

validate/src/main.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use std::fs;
22
use std::io::{self, Write};
33
use std::path::PathBuf;
44

5-
use bootspec::{BootJson, Result};
5+
use bootspec::BootJson;
66

7-
fn main() -> Result<()> {
7+
fn main() -> Result<(), Box<dyn std::error::Error>> {
88
if let Err(e) = self::cli() {
99
writeln!(io::stderr(), "{}", e)?;
1010

@@ -14,7 +14,7 @@ fn main() -> Result<()> {
1414
Ok(())
1515
}
1616

17-
fn cli() -> Result<()> {
17+
fn cli() -> Result<(), Box<dyn std::error::Error>> {
1818
let Args { bootspec_path } = parse_args()?;
1919

2020
let contents = fs::read_to_string(&bootspec_path)?;
@@ -46,7 +46,7 @@ pub struct Args {
4646
pub bootspec_path: PathBuf,
4747
}
4848

49-
fn parse_args() -> Result<Args> {
49+
fn parse_args() -> Result<Args, Box<dyn std::error::Error>> {
5050
let mut args = std::env::args().skip(1);
5151

5252
if args.len() != 1 {

0 commit comments

Comments
 (0)