1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! What can stop a command.
use std::io;
use std::path::PathBuf;
/// The result of a command.
pub(crate) type Result<T> = std::result::Result<T, Error>;
/// Why a command failed.
#[derive(Debug, thiserror::Error)]
pub(crate) enum Error {
/// The build itself.
#[error(transparent)]
Build(#[from] mf2_build::Error),
/// A file could not be read or written.
#[error("{path}: {source}")]
Io {
/// The file.
path: PathBuf,
/// What the operating system said.
#[source]
source: io::Error,
},
/// The corpus has errors; they are already on stderr, so the command
/// only has to exit non-zero.
#[error("the corpus has errors")]
Corpus,
/// A catalog could not be read.
#[error("{path}: {source}")]
Catalog {
/// The catalog.
path: PathBuf,
/// What the reader said.
#[source]
source: mf2_catalog::CatalogError,
},
/// A catalog could not be decoded.
#[error("{path}: message {id}: {source}")]
Decode {
/// The catalog.
path: PathBuf,
/// Which message.
id: u32,
/// What the decoder said.
#[source]
source: mf2_catalog::DecodeError,
},
/// `cargo metadata` could not say what the i18n crate's features are.
#[error("{dir}: cargo metadata: {message}")]
Cargo {
/// The i18n crate.
dir: PathBuf,
/// What went wrong.
message: String,
},
/// `mf2 init` could not add `mf2` or `mf2-build` to an existing crate.
#[error("{dir}: {command}: {message}")]
CargoAdd {
/// The crate.
dir: PathBuf,
/// The command that failed.
command: String,
/// What went wrong.
message: String,
},
/// `--features` and the crate's `mf2` disagree on which functions exist,
/// so the catalogs would be built for another wasm than the one cargo
/// builds.
#[error(
"--features names {given} but cargo resolves {resolved} for mf2 in {krate}; \
the catalogs must be built for the functions the wasm is built with \
(drop --features to take cargo's)"
)]
FeatureMismatch {
/// The i18n crate's package name.
krate: String,
/// The catalog features `--features` names.
given: String,
/// The catalog features cargo resolves for the crate's `mf2`.
resolved: String,
},
/// An argument names something that is not there.
#[error("{0}")]
Usage(String),
}
impl Error {
/// An I/O error that names its file.
pub(crate) fn io(path: impl Into<PathBuf>, source: io::Error) -> Error {
Error::Io {
path: path.into(),
source,
}
}
}
/// Reads a file, naming it on failure.
pub(crate) fn read(path: &std::path::Path) -> Result<String> {
std::fs::read_to_string(path).map_err(|source| Error::io(path, source))
}
/// Reads a file's bytes, naming it on failure.
pub(crate) fn read_bytes(path: &std::path::Path) -> Result<Vec<u8>> {
std::fs::read(path).map_err(|source| Error::io(path, source))
}
/// Writes a file, naming it on failure, creating its directory.
pub(crate) fn write(path: &std::path::Path, bytes: impl AsRef<[u8]>) -> Result<()> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).map_err(|source| Error::io(parent, source))?;
}
std::fs::write(path, bytes).map_err(|source| Error::io(path, source))
}