Skip to main content

kcode_rust_libs/
error.rs

1use std::error::Error as StdError;
2use std::fmt;
3use std::io;
4use std::path::PathBuf;
5
6use crate::CheckResult;
7
8/// The result type returned by this crate.
9pub type Result<T> = std::result::Result<T, Error>;
10
11/// An error that prevented a Rust library operation, validation run, or publication.
12#[derive(Debug)]
13pub enum Error {
14    InvalidRustLibName(String),
15    InvalidRustLibPath {
16        path: String,
17        reason: &'static str,
18    },
19    RustLibAlreadyExists(String),
20    RustLibNotFound(String),
21    RustLibIsNotDirectory(String),
22    DuplicateWritePath(String),
23    NonUtf8Path(PathBuf),
24    NonUtf8File(PathBuf),
25    SymlinkNotAllowed(PathBuf),
26    UnsupportedFileType(PathBuf),
27    RootsOverlap {
28        rust_libs_root: PathBuf,
29        work_root: PathBuf,
30    },
31    MissingRequiredFile(&'static str),
32    InvalidVersion(String),
33    InvalidCargoManifest(String),
34    VersionMismatch {
35        version_file: String,
36        cargo_manifest: String,
37    },
38    InvalidRegistryToken,
39    CheckFailed(CheckResult),
40    Io {
41        action: &'static str,
42        path: PathBuf,
43        source: io::Error,
44    },
45    Sandbox {
46        stage: String,
47        message: String,
48    },
49    Publish(String),
50}
51
52impl Error {
53    pub(crate) fn io(action: &'static str, path: impl Into<PathBuf>, source: io::Error) -> Self {
54        Self::Io {
55            action,
56            path: path.into(),
57            source,
58        }
59    }
60}
61
62impl fmt::Display for Error {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Self::InvalidRustLibName(name) => write!(
66                f,
67                "invalid Rust library name {name:?}; use ASCII letters, digits, '-' or '_'"
68            ),
69            Self::InvalidRustLibPath { path, reason } => {
70                write!(f, "invalid Rust library path {path:?}: {reason}")
71            }
72            Self::RustLibAlreadyExists(name) => {
73                write!(f, "Rust library {name:?} already exists")
74            }
75            Self::RustLibNotFound(name) => write!(f, "Rust library {name:?} was not found"),
76            Self::RustLibIsNotDirectory(name) => {
77                write!(f, "Rust library {name:?} is not a directory")
78            }
79            Self::DuplicateWritePath(path) => {
80                write!(f, "write batch contains duplicate path {path:?}")
81            }
82            Self::NonUtf8Path(path) => {
83                write!(
84                    f,
85                    "Rust library contains a non-UTF-8 path: {}",
86                    path.display()
87                )
88            }
89            Self::NonUtf8File(path) => {
90                write!(f, "Rust library file is not UTF-8: {}", path.display())
91            }
92            Self::SymlinkNotAllowed(path) => {
93                write!(
94                    f,
95                    "Rust library symlinks are not allowed: {}",
96                    path.display()
97                )
98            }
99            Self::UnsupportedFileType(path) => write!(
100                f,
101                "Rust library entry is not a regular file or directory: {}",
102                path.display()
103            ),
104            Self::RootsOverlap {
105                rust_libs_root,
106                work_root,
107            } => write!(
108                f,
109                "Rust libraries root ({}) and work root ({}) must not overlap",
110                rust_libs_root.display(),
111                work_root.display()
112            ),
113            Self::MissingRequiredFile(path) => {
114                write!(f, "Rust library is missing required file {path}")
115            }
116            Self::InvalidVersion(value) => write!(
117                f,
118                "invalid Cargo.toml [package].version {value:?}; expected canonical major.minor.patch"
119            ),
120            Self::InvalidCargoManifest(message) => {
121                write!(f, "invalid Cargo.toml: {message}")
122            }
123            Self::VersionMismatch {
124                version_file,
125                cargo_manifest,
126            } => write!(
127                f,
128                "version {version_file} does not match Cargo.toml package version {cargo_manifest}"
129            ),
130            Self::InvalidRegistryToken => f.write_str("crates.io registry token is empty"),
131            Self::CheckFailed(result) => {
132                if let Some(stage) = result.failure() {
133                    write!(
134                        f,
135                        "Rust library cannot be published because its {} check failed",
136                        stage.stage
137                    )
138                } else {
139                    f.write_str(
140                        "Rust library cannot be published because its full check did not pass",
141                    )
142                }
143            }
144            Self::Io {
145                action,
146                path,
147                source,
148            } => write!(f, "failed to {action} {}: {source}", path.display()),
149            Self::Sandbox { stage, message } => {
150                write!(f, "Podman failed during {stage}: {message}")
151            }
152            Self::Publish(message) => write!(f, "crates.io publication failed: {message}"),
153        }
154    }
155}
156
157impl StdError for Error {
158    fn source(&self) -> Option<&(dyn StdError + 'static)> {
159        match self {
160            Self::Io { source, .. } => Some(source),
161            _ => None,
162        }
163    }
164}