1use std::{
10 io,
11 path::{Path, PathBuf},
12 process::ExitStatus,
13};
14
15use guppy::errors::Error as GuppyError;
16use guppy::graph::PackageLink;
17use thiserror::Error;
18use toml_edit::TomlError as TomlEditError;
19use url::ParseError;
20
21use super::DependencyType;
22
23#[derive(Debug, Error)]
25pub enum Error {
26 #[error(transparent)]
28 WorkspaceError(WorkspaceError),
29
30 #[error("Workspace has at least one cycle that includes as least {crate1} and {crate2}")]
32 WorkspaceCycles {
33 crate1: String,
35
36 crate2: String,
38 },
39
40 #[error("Unable to write to the output")]
42 OutputError(#[source] io::Error),
43
44 #[error("Conditions for a release are not satisfied: {reason}")]
46 VerifyError {
47 reason: String,
49 },
50
51 #[error("{typ} of {from} on {to} prevents publication of {from}")]
55 BadDependancy {
56 from: String,
58
59 to: String,
61
62 typ: DependencyType,
64 },
65
66 #[error("Unable to read file {}", path.display())]
68 FileReadError {
69 #[source]
71 inner: io::Error,
72
73 path: PathBuf,
75 },
76
77 #[error("Unable to write file {}", path.display())]
79 FileWriteError {
80 #[source]
82 inner: io::Error,
83
84 path: PathBuf,
86 },
87
88 #[error(transparent)]
90 TomlError(TomlError),
91
92 #[error("Unexpected contents of {manifest_path}")]
94 CargoTomlError {
95 #[source]
97 inner: CargoTomlError,
98
99 manifest_path: PathBuf,
101 },
102
103 #[error("Unable to run \"cargo publish\" for {manifest_path}")]
105 CargoPublish {
106 #[source]
108 inner: io::Error,
109
110 manifest_path: PathBuf,
112 },
113
114 #[error("\"cargo publish\" exited with a failure for {manifest_path}: {status}")]
116 CargoPublishStatus {
117 status: ExitStatus,
119
120 manifest_path: PathBuf,
122 },
123
124 #[error(transparent)]
126 UrlError(UrlError),
127
128 #[error(transparent)]
130 WriteReleaseError(WriteReleaseError),
131}
132
133pub type Result<T> = std::result::Result<T, Error>;
135
136#[derive(Debug, Error)]
138#[error("Unable to parse the workspace structure starting at {manifest_path}")]
139pub struct WorkspaceError {
140 #[source]
141 metadata_error: GuppyError,
142 manifest_path: PathBuf,
143}
144
145#[derive(Debug, Error)]
147#[error("Unable to parse {} as a TOML file", path.display())]
148pub struct TomlError {
149 #[source]
150 inner: TomlEditError,
151 path: PathBuf,
152}
153
154#[derive(Debug, Error)]
156pub enum CargoTomlError {
157 #[error("Unable to locate expected table {table_name}")]
159 NoTable {
160 table_name: String,
162 },
163
164 #[error("Unable to located expected value {value_name}")]
166 NoValue {
167 value_name: String,
169 },
170
171 #[error("Unable to set the version for {name} to {version}")]
173 SetVersion {
174 name: String,
176
177 version: String,
179 },
180}
181
182#[derive(Debug, Error)]
184#[error("Unable to parse url for displaying release record.")]
185pub struct UrlError {
186 #[source]
187 inner: ParseError,
188}
189
190#[derive(Debug, Error)]
192#[error("Unable to write the release record for {main_crate} as JSON.")]
193pub struct WriteReleaseError {
194 #[source]
195 inner: serde_json::Error,
196
197 main_crate: String,
198}
199
200impl Error {
201 pub(crate) fn workspace_error(metadata_error: GuppyError, manifest_path: PathBuf) -> Error {
202 Error::WorkspaceError(WorkspaceError {
203 metadata_error,
204 manifest_path,
205 })
206 }
207
208 pub(crate) fn output_error(inner: io::Error) -> Error {
209 Error::OutputError(inner)
210 }
211
212 pub(crate) fn verify_error(reason: impl Into<String>) -> Error {
213 Error::VerifyError {
214 reason: reason.into(),
215 }
216 }
217
218 pub(crate) fn bad_dependency(link: &PackageLink, typ: DependencyType) -> Error {
219 Error::BadDependancy {
220 from: link.from().name().to_string(),
221 to: link.to().name().to_string(),
222 typ,
223 }
224 }
225
226 pub(crate) fn file_read_error(inner: io::Error, path: impl AsRef<Path>) -> Error {
227 Error::FileReadError {
228 inner,
229 path: path.as_ref().to_owned(),
230 }
231 }
232
233 pub(crate) fn file_write_error(inner: io::Error, path: impl AsRef<Path>) -> Error {
234 Error::FileWriteError {
235 inner,
236 path: path.as_ref().to_owned(),
237 }
238 }
239
240 pub(crate) fn toml_error(inner: TomlEditError, path: impl AsRef<Path>) -> Error {
241 Error::TomlError(TomlError {
242 inner,
243 path: path.as_ref().to_owned(),
244 })
245 }
246
247 pub(crate) fn cargo_publish(inner: io::Error, manifest_path: &Path) -> Error {
248 Error::CargoPublish {
249 inner,
250 manifest_path: manifest_path.to_owned(),
251 }
252 }
253
254 pub(crate) fn cargo_publish_status(status: ExitStatus, manifest_path: &Path) -> Error {
255 Error::CargoPublishStatus {
256 status,
257 manifest_path: manifest_path.to_owned(),
258 }
259 }
260
261 pub(crate) fn url_parse_error(inner: ParseError) -> Error {
262 Error::UrlError(UrlError { inner })
263 }
264
265 pub(crate) fn write_release_error(inner: serde_json::Error, main_crate: &str) -> Error {
266 Error::WriteReleaseError(WriteReleaseError {
267 inner,
268 main_crate: main_crate.to_owned(),
269 })
270 }
271
272 pub(crate) fn cycle_error(crate1: &str, crate2: &str) -> Error {
273 Error::WorkspaceCycles {
274 crate1: crate1.to_owned(),
275 crate2: crate2.to_owned(),
276 }
277 }
278}
279
280impl CargoTomlError {
281 pub(crate) fn no_table(table: &str) -> Self {
282 Self::NoTable {
283 table_name: table.to_owned(),
284 }
285 }
286
287 pub(crate) fn no_value(value: &str) -> Self {
288 Self::NoValue {
289 value_name: value.to_owned(),
290 }
291 }
292
293 pub(crate) fn set_version(name: &str, version: &str) -> Self {
294 Self::SetVersion {
295 name: name.to_owned(),
296 version: version.to_owned(),
297 }
298 }
299
300 pub(crate) fn into_error(self, path: impl AsRef<Path>) -> Error {
301 Error::CargoTomlError {
302 inner: self,
303 manifest_path: path.as_ref().to_owned(),
304 }
305 }
306}