use crate::provenance::SUPPORTED_VERSION;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("the manifest isn't JSON (line {line}, column {column}): {reason}; generate it again")]
Syntax {
line: usize,
column: usize,
reason: String,
},
#[error(
"manifest_version {found}: this reader understands version {SUPPORTED_VERSION} only; generate the files with an Isoloom whose run manifest is version {SUPPORTED_VERSION}"
)]
Version {
found: String,
},
#[error("{path}: {reason}")]
Field {
path: String,
reason: String,
},
#[error("`{value}` isn't a valid {what}: {rule}")]
Pattern {
what: &'static str,
value: String,
rule: &'static str,
},
#[error("{value} is out of range: {what} goes from {min} to {max}")]
OutOfRange {
what: &'static str,
value: u64,
min: u64,
max: u64,
},
#[error(
"`{program}` is a shell or an interpreter, refused as a program: a step runs one tool without a shell; name the tool (`docker`), and pipe a guest script through `stdin`"
)]
ShellProgram {
program: String,
},
#[error("`{program}` isn't a bare tool name: write the tool's name alone (`docker`); the runner finds it on PATH")]
ProgramNotBare {
program: String,
},
#[error("an argv is empty: it needs at least its program")]
EmptyArgv,
#[error("a per-host argv names no host: give `default`, `linux`, `macos` or `windows`")]
NoHostArgv,
#[error("`{template}`: `${{secrets.…}}` is refused; a secret reaches a tool only through its slot's delivery, never on a command line")]
SecretPlaceholder {
template: String,
},
#[error(
"`{template}`: `${{{placeholder}}}` isn't a placeholder; the roots are run.name, run.dir, run.state_dir, run.provider, run.ssh_key, run.known_hosts, run.ssh_public_key, run.slot, params.<NAME>, outputs.<name>, published.<machine>.<port>, machine and value"
)]
UnknownPlaceholder {
template: String,
placeholder: String,
},
#[error("`{template}`: a `$` that starts no placeholder; write `$$` for a literal `$`")]
LoneDollar {
template: String,
},
#[error("`{template}`: a `${{` without its `}}`")]
UnclosedPlaceholder {
template: String,
},
#[error("a path is empty: name a file or a folder relative to the manifest's folder")]
EmptyPath,
#[error("`{path}` is absolute: paths are relative to the manifest's folder (or start at `${{run.state_dir}}`)")]
AbsolutePath {
path: String,
},
#[error("`{path}` has a `\\`: paths are `/`-separated on every host, and the runner converts them")]
Backslash {
path: String,
},
#[error("`{path}` goes up with `..`: a path stays inside the folder it is relative to")]
ParentPath {
path: String,
},
#[error("`{path}` isn't absolute: a path inside a machine starts with `/`")]
RelativeGuestPath {
path: String,
},
#[error("`{value}` isn't a network block: write an address and a prefix length (`10.30.0.0/24`)")]
Cidr {
value: String,
},
#[error("{what} is empty: it needs at least one")]
Empty {
what: &'static str,
},
#[error("`*` stands for every step on its own: list step ids, or `*` alone")]
MixedWildcard,
#[error("step `{id}`: {reason}")]
StepShape {
id: String,
reason: &'static str,
},
#[error("`native` names a Compose `service`, or a `vagrant` machine with its `vm_names`, not both")]
NativeShape,
#[error("a UDP port speaks neither HTTP nor TLS, which run over TCP: set `protocol` to `tcp`, or `http` and `tls` to false")]
PortProtocol,
#[error("hosts is empty: name the host operating systems the target runs from (`linux`, `macos`, `windows`)")]
NoHosts,
#[error("driver `{driver}` with an identity for `{identity}`: write the identity of the driver that runs the manifest")]
DriverIdentity {
driver: &'static str,
identity: &'static str,
},
#[error("{list}: step id `{id}` appears twice; ids are unique within a list")]
DuplicateStep {
list: String,
id: String,
},
#[error("{at}: no step `{step}` in this manifest")]
UnknownStep {
at: String,
step: String,
},
#[error("ready[{index}]: `{step}` isn't a step of lifecycle.up; `step_ok` names an up step")]
ReadyNotUp {
index: usize,
step: String,
},
#[error("machines: `{name}` appears twice")]
DuplicateMachine {
name: String,
},
#[error("machine `{machine}`: port `{port}` appears twice; a port's name is unique on its machine")]
DuplicatePort {
machine: String,
port: String,
},
#[error("{at}: no machine `{machine}` in this manifest")]
UnknownMachine {
at: String,
machine: String,
},
#[error("{at}: `${{published.{port}}}` names no published port; publish the port on that machine, or name one that is")]
UnknownPublished {
at: String,
port: String,
},
#[error("{at}: `${{params.{name}}}` names no param; declare it in `params`")]
UnknownParam {
at: String,
name: String,
},
#[error("{at}: `${{outputs.{name}}}` names no output; declare it in `outputs`")]
UnknownOutput {
at: String,
name: String,
},
#[error("{at}: `${{{root}}}` is bound only in {only}")]
PlaceholderOutOfPlace {
at: String,
root: &'static str,
only: &'static str,
},
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
impl Error {
#[must_use]
pub fn code(&self) -> &'static str {
match self {
Error::Syntax { .. } => "syntax",
Error::Version { .. } => "version",
Error::Field { .. } => "field",
Error::Pattern { .. } => "pattern",
Error::OutOfRange { .. } => "out_of_range",
Error::ShellProgram { .. } => "shell_program",
Error::ProgramNotBare { .. } => "program_not_bare",
Error::EmptyArgv => "empty_argv",
Error::NoHostArgv => "no_host_argv",
Error::SecretPlaceholder { .. } => "secret_placeholder",
Error::UnknownPlaceholder { .. } => "unknown_placeholder",
Error::LoneDollar { .. } => "lone_dollar",
Error::UnclosedPlaceholder { .. } => "unclosed_placeholder",
Error::EmptyPath => "empty_path",
Error::AbsolutePath { .. } => "absolute_path",
Error::Backslash { .. } => "backslash",
Error::ParentPath { .. } => "parent_path",
Error::RelativeGuestPath { .. } => "relative_guest_path",
Error::Cidr { .. } => "cidr",
Error::Empty { .. } => "empty",
Error::MixedWildcard => "mixed_wildcard",
Error::StepShape { .. } => "step_shape",
Error::NativeShape => "native_shape",
Error::PortProtocol => "port_protocol",
Error::NoHosts => "no_hosts",
Error::DriverIdentity { .. } => "driver_identity",
Error::DuplicateStep { .. } => "duplicate_step",
Error::UnknownStep { .. } => "unknown_step",
Error::ReadyNotUp { .. } => "ready_not_up",
Error::DuplicateMachine { .. } => "duplicate_machine",
Error::DuplicatePort { .. } => "duplicate_port",
Error::UnknownMachine { .. } => "unknown_machine",
Error::UnknownPublished { .. } => "unknown_published",
Error::UnknownParam { .. } => "unknown_param",
Error::UnknownOutput { .. } => "unknown_output",
Error::PlaceholderOutOfPlace { .. } => "placeholder_out_of_place",
}
}
}