use std::error::Error;
use std::fmt::{Display, Formatter, Result as FResult};
use std::path::PathBuf;
use brane_shr::errors::ErrorTrace as _;
use brane_shr::formatters::{BlockFormatter, PrettyListFormatter};
use reqwest::StatusCode;
use specifications::address::Address;
use specifications::container::{ContainerInfoError, Image, LocalContainerInfoError};
use specifications::package::{PackageInfoError, PackageKindError};
use specifications::version::{ParseError as VersionParseError, Version};
lazy_static! {
static ref CLI_LINE_SEPARATOR: String = (0..80).map(|_| '-').collect::<String>();
}
#[derive(Debug)]
pub enum CliError {
BuildError { err: BuildError },
CertsError { err: CertsError },
CheckError { err: CheckError },
DataError { err: DataError },
ImportError { err: ImportError },
InstanceError { err: InstanceError },
PackageError { err: PackageError },
RegistryError { err: RegistryError },
ReplError { err: ReplError },
RunError { err: RunError },
TestError { err: TestError },
VerifyError { err: VerifyError },
VersionError { err: VersionError },
UpgradeError { err: crate::upgrade::Error },
UtilError { err: UtilError },
OtherError { err: anyhow::Error },
PackageFileCanonicalizeError { path: PathBuf, err: std::io::Error },
WorkdirCanonicalizeError { path: PathBuf, err: std::io::Error },
IllegalPackageKind { kind: String, err: PackageKindError },
PackagePairParseError { raw: String, err: specifications::version::ParseError },
}
impl Display for CliError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use CliError::*;
match self {
BuildError { err } => write!(f, "{err}"),
CertsError { err } => write!(f, "{err}"),
CheckError { err } => write!(f, "{err}"),
DataError { err } => write!(f, "{err}"),
ImportError { err } => write!(f, "{err}"),
InstanceError { err } => write!(f, "{err}"),
PackageError { err } => write!(f, "{err}"),
RegistryError { err } => write!(f, "{err}"),
ReplError { err } => write!(f, "{err}"),
RunError { err } => write!(f, "{err}"),
TestError { err } => write!(f, "{err}"),
VerifyError { err } => write!(f, "{err}"),
VersionError { err } => write!(f, "{err}"),
UpgradeError { err } => write!(f, "{err}"),
UtilError { err } => write!(f, "{err}"),
OtherError { err } => write!(f, "{err}"),
PackageFileCanonicalizeError { path, .. } => write!(f, "Could not resolve package file path '{}'", path.display()),
WorkdirCanonicalizeError { path, .. } => write!(f, "Could not resolve working directory '{}'", path.display()),
IllegalPackageKind { kind, .. } => write!(f, "Illegal package kind '{kind}'"),
PackagePairParseError { raw, .. } => write!(f, "Could not parse '{raw}'"),
}
}
}
impl Error for CliError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use CliError::*;
match self {
BuildError { err } => err.source(),
CertsError { err } => err.source(),
CheckError { err } => err.source(),
DataError { err } => err.source(),
ImportError { err } => err.source(),
InstanceError { err } => err.source(),
PackageError { err } => err.source(),
RegistryError { err } => err.source(),
ReplError { err } => err.source(),
RunError { err } => err.source(),
TestError { err } => err.source(),
VerifyError { err } => err.source(),
VersionError { err } => err.source(),
UpgradeError { err } => err.source(),
UtilError { err } => err.source(),
OtherError { err } => err.source(),
PackageFileCanonicalizeError { err, .. } => Some(err),
WorkdirCanonicalizeError { err, .. } => Some(err),
IllegalPackageKind { err, .. } => Some(err),
PackagePairParseError { err, .. } => Some(err),
}
}
}
#[derive(Debug)]
pub enum BuildError {
ContainerInfoOpenError { file: PathBuf, err: std::io::Error },
ContainerInfoParseError { file: PathBuf, err: ContainerInfoError },
PackageDirError { err: UtilError },
OasDocumentParseError { file: PathBuf, err: anyhow::Error },
VersionParseError { err: VersionParseError },
PackageInfoFromOpenAPIError { err: anyhow::Error },
LockCreateError { name: String, err: brane_shr::fs::Error },
DockerfileStrWriteError { err: std::fmt::Error },
UnsafePath { path: PathBuf },
MissingExecutable { path: PathBuf },
DockerfileCreateError { path: PathBuf, err: std::io::Error },
DockerfileWriteError { path: PathBuf, err: std::io::Error },
ContainerDirCreateError { path: PathBuf, err: std::io::Error },
BraneletCanonicalizeError { path: PathBuf, err: std::io::Error },
BraneletCopyError { source: PathBuf, target: PathBuf, err: std::io::Error },
WdClearError { path: PathBuf, err: std::io::Error },
WdCreateError { path: PathBuf, err: std::io::Error },
LocalContainerInfoCreateError { err: LocalContainerInfoError },
WdSourceFileCanonicalizeError { path: PathBuf, err: std::io::Error },
WdTargetFileCanonicalizeError { path: PathBuf, err: std::io::Error },
WdDirCreateError { path: PathBuf, err: std::io::Error },
WdFileCopyError { source: PathBuf, target: PathBuf, err: std::io::Error },
WdDirReadError { path: PathBuf, err: std::io::Error },
WdDirEntryError { path: PathBuf, err: std::io::Error },
WdFileRenameError { source: PathBuf, target: PathBuf, err: std::io::Error },
WdFileCreateError { path: PathBuf, err: std::io::Error },
WdFileOpenError { path: PathBuf, err: std::io::Error },
WdFileReadError { path: PathBuf, err: std::io::Error },
WdFileWriteError { path: PathBuf, err: std::io::Error },
WdFileRemoveError { path: PathBuf, err: std::io::Error },
WdCompressionLaunchError { command: String, err: std::io::Error },
WdCompressionError { command: String, code: i32, stdout: String, stderr: String },
WdConfirmationError { err: dialoguer::Error },
OpenAPISerializeError { err: serde_yaml::Error },
OpenAPIFileCreateError { path: PathBuf, err: std::io::Error },
OpenAPIFileWriteError { path: PathBuf, err: std::io::Error },
BuildKitLaunchError { command: String, err: std::io::Error },
BuildKitError { command: String, code: i32, stdout: String, stderr: String },
ImageBuildLaunchError { command: String, err: std::io::Error },
ImageBuildError { command: String, code: i32 },
DigestError { err: brane_tsk::docker::Error },
PackageFileCreateError { err: PackageInfoError },
FileCleanupError { path: PathBuf, err: std::io::Error },
DirCleanupError { path: PathBuf, err: std::io::Error },
CleanupError { path: PathBuf, err: std::io::Error },
ImageTarOpenError { path: PathBuf, err: std::io::Error },
ImageTarEntriesError { path: PathBuf, err: std::io::Error },
ManifestParseError { path: PathBuf, err: serde_json::Error },
ManifestNotOneEntry { path: PathBuf, n: usize },
ManifestInvalidConfigBlob { path: PathBuf, config: String },
NoManifest { path: PathBuf },
DigestFileCreateError { path: PathBuf, err: std::io::Error },
DigestFileWriteError { path: PathBuf, err: std::io::Error },
HostArchError { err: specifications::arch::ArchError },
}
impl Display for BuildError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use BuildError::*;
match self {
ContainerInfoOpenError { file, .. } => write!(f, "Could not open the container info file '{}'", file.display()),
ContainerInfoParseError { file, .. } => write!(f, "Could not parse the container info file '{}'", file.display()),
PackageDirError { .. } => write!(f, "Could not create package directory"),
OasDocumentParseError { file, .. } => write!(f, "Could not parse the OAS Document '{}'", file.display()),
VersionParseError { .. } => write!(f, "Could not parse OAS Document version number"),
PackageInfoFromOpenAPIError { .. } => write!(f, "Could not convert the OAS Document into a Package Info file"),
LockCreateError { name, .. } => write!(f, "Failed to create lockfile for package '{name}'"),
DockerfileStrWriteError { .. } => write!(f, "Could not write to the internal DockerFile"),
UnsafePath { path } => write!(
f,
"File '{}' tries to escape package working directory; consider moving Brane's working directory up (using --workdir) and avoid '..'",
path.display()
),
MissingExecutable { path } => write!(f, "Could not find the package entrypoint '{}'", path.display()),
DockerfileCreateError { path, .. } => write!(f, "Could not create Dockerfile '{}'", path.display()),
DockerfileWriteError { path, .. } => write!(f, "Could not write to Dockerfile '{}'", path.display()),
ContainerDirCreateError { path, .. } => write!(f, "Could not create container directory '{}'", path.display()),
BraneletCanonicalizeError { path, .. } => write!(f, "Could not resolve custom init binary path '{}'", path.display()),
BraneletCopyError { source, target, .. } => {
write!(f, "Could not copy custom init binary from '{}' to '{}'", source.display(), target.display())
},
WdClearError { path, .. } => write!(f, "Could not clear existing package working directory '{}'", path.display()),
WdCreateError { path, .. } => write!(f, "Could not create package working directory '{}'", path.display()),
LocalContainerInfoCreateError { .. } => write!(f, "Could not write local container info to container directory"),
WdSourceFileCanonicalizeError { path, .. } => write!(f, "Could not resolve file '{}' in the package info file", path.display()),
WdTargetFileCanonicalizeError { path, .. } => {
write!(f, "Could not resolve file '{}' in the package working directory", path.display())
},
WdDirCreateError { path, .. } => write!(f, "Could not create directory '{}' in the package working directory", path.display()),
WdDirEntryError { path, .. } => {
write!(f, "Could not read entry in directory '{}' in the package working directory", path.display())
},
WdDirReadError { path, .. } => write!(f, "Could not read directory '{}' in the package working directory", path.display()),
WdFileCopyError { source, target, .. } => {
write!(f, "Could not copy file '{}' to '{}' in the package working directory", source.display(), target.display())
},
WdFileRenameError { source, target, .. } => {
write!(f, "Could not rename file '{}' to '{}' in the package working directory", source.display(), target.display())
},
WdFileCreateError { path, .. } => write!(f, "Could not create new file '{}' in the package working directory", path.display()),
WdFileOpenError { path, .. } => write!(f, "Could not open file '{}' in the package working directory", path.display()),
WdFileReadError { path, .. } => write!(f, "Could not read from file '{}' in the package working directory", path.display()),
WdFileWriteError { path, .. } => write!(f, "Could not write to file '{}' in the package working directory", path.display()),
WdFileRemoveError { path, .. } => write!(f, "Could not remove file '{}' in the package working directory", path.display()),
WdCompressionLaunchError { command, .. } => write!(f, "Could not run command '{command}' to compress working directory"),
WdCompressionError { command, code, stdout, stderr } => write!(
f,
"Command '{}' to compress working directory returned exit code {}:\n\nstdout:\n{}\n{}\n{}\n\nstderr:\n{}\n{}\n{}\n\n",
command, code, *CLI_LINE_SEPARATOR, stdout, *CLI_LINE_SEPARATOR, *CLI_LINE_SEPARATOR, stderr, *CLI_LINE_SEPARATOR
),
WdConfirmationError { .. } => write!(f, "Failed to ask the user (you!) for consent"),
OpenAPISerializeError { .. } => write!(f, "Could not re-serialize OpenAPI document"),
OpenAPIFileCreateError { path, .. } => write!(f, "Could not create OpenAPI file '{}'", path.display()),
OpenAPIFileWriteError { path, .. } => write!(f, "Could not write to OpenAPI file '{}'", path.display()),
BuildKitLaunchError { command, .. } => {
write!(f, "Could not determine if Docker & BuildKit are installed: failed to run command '{command}'")
},
BuildKitError { command, code, stdout, stderr } => write!(
f,
"Could not run a Docker BuildKit (command '{}' returned exit code {}): is BuildKit \
installed?\n\nstdout:\n{}\n{}\n{}\n\nstderr:\n{}\n{}\n{}\n\n",
command, code, *CLI_LINE_SEPARATOR, stdout, *CLI_LINE_SEPARATOR, *CLI_LINE_SEPARATOR, stderr, *CLI_LINE_SEPARATOR
),
ImageBuildLaunchError { command, .. } => write!(f, "Could not run command '{command}' to build the package image"),
ImageBuildError { command, code } => write!(f, "Command '{command}' to build the package image returned exit code {code}"),
DigestError { .. } => write!(f, "Could not get Docker image digest"),
PackageFileCreateError { .. } => write!(f, "Could not write package info to build directory"),
FileCleanupError { path, .. } => write!(f, "Could not clean file '{}' from build directory", path.display()),
DirCleanupError { path, .. } => write!(f, "Could not clean directory '{}' from build directory", path.display()),
CleanupError { path, .. } => write!(f, "Could not clean build directory '{}'", path.display()),
ImageTarOpenError { path, .. } => write!(f, "Could not open the built image.tar ('{}')", path.display()),
ImageTarEntriesError { path, .. } => write!(f, "Could get entries in the built image.tar ('{}')", path.display()),
ManifestParseError { path, .. } => write!(f, "Could not parse extracted Docker manifest '{}'", path.display()),
ManifestNotOneEntry { path, n } => {
write!(f, "Extracted Docker manifest '{}' has an incorrect number of entries: got {}, expected 1", path.display(), n)
},
ManifestInvalidConfigBlob { path, config } => write!(
f,
"Extracted Docker manifest '{}' has an incorrect path to the config blob: got {}, expected it to start with 'blobs/sha256/'",
path.display(),
config
),
NoManifest { path } => write!(f, "Built image.tar ('{}') does not contain a manifest.json", path.display()),
DigestFileCreateError { path, .. } => write!(f, "Could not open digest file '{}'", path.display()),
DigestFileWriteError { path, .. } => write!(f, "Could not write to digest file '{}'", path.display()),
HostArchError { .. } => write!(f, "Could not get host architecture"),
}
}
}
impl Error for BuildError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use BuildError::*;
match self {
ContainerInfoOpenError { err, .. } => Some(err),
ContainerInfoParseError { err, .. } => Some(err),
PackageDirError { err } => Some(err),
OasDocumentParseError { err, .. } => Some(&**err),
VersionParseError { err } => Some(err),
PackageInfoFromOpenAPIError { err } => Some(&**err),
LockCreateError { err, .. } => Some(err),
DockerfileStrWriteError { err, .. } => Some(err),
UnsafePath { .. } => None,
MissingExecutable { .. } => None,
DockerfileCreateError { err, .. } => Some(err),
DockerfileWriteError { err, .. } => Some(err),
ContainerDirCreateError { err, .. } => Some(err),
BraneletCanonicalizeError { err, .. } => Some(err),
BraneletCopyError { err, .. } => Some(err),
WdClearError { err, .. } => Some(err),
WdCreateError { err, .. } => Some(err),
LocalContainerInfoCreateError { err } => Some(err),
WdSourceFileCanonicalizeError { err, .. } => Some(err),
WdTargetFileCanonicalizeError { err, .. } => Some(err),
WdDirCreateError { err, .. } => Some(err),
WdFileCopyError { err, .. } => Some(err),
WdDirReadError { err, .. } => Some(err),
WdDirEntryError { err, .. } => Some(err),
WdFileRenameError { err, .. } => Some(err),
WdFileCreateError { err, .. } => Some(err),
WdFileOpenError { err, .. } => Some(err),
WdFileReadError { err, .. } => Some(err),
WdFileWriteError { err, .. } => Some(err),
WdFileRemoveError { err, .. } => Some(err),
WdCompressionLaunchError { err, .. } => Some(err),
WdCompressionError { .. } => None,
WdConfirmationError { err } => Some(err),
OpenAPISerializeError { err } => Some(err),
OpenAPIFileCreateError { err, .. } => Some(err),
OpenAPIFileWriteError { err, .. } => Some(err),
BuildKitLaunchError { err, .. } => Some(err),
BuildKitError { .. } => None,
ImageBuildLaunchError { err, .. } => Some(err),
ImageBuildError { .. } => None,
DigestError { err } => Some(err),
PackageFileCreateError { err } => Some(err),
FileCleanupError { err, .. } => Some(err),
DirCleanupError { err, .. } => Some(err),
CleanupError { err, .. } => Some(err),
ImageTarOpenError { err, .. } => Some(err),
ImageTarEntriesError { err, .. } => Some(err),
ManifestParseError { err, .. } => Some(err),
ManifestNotOneEntry { .. } => None,
ManifestInvalidConfigBlob { .. } => None,
NoManifest { .. } => None,
DigestFileCreateError { err, .. } => Some(err),
DigestFileWriteError { err, .. } => Some(err),
HostArchError { err } => Some(err),
}
}
}
#[derive(Debug)]
pub enum CertsError {
ActiveInstanceNotASoftlinkError { path: PathBuf },
CertParseError { path: PathBuf, i: usize, err: x509_parser::nom::Err<x509_parser::error::X509Error> },
CertExtensionsError { path: PathBuf, i: usize, err: x509_parser::error::X509Error },
CertNoKeyUsageError { path: PathBuf, i: usize },
CertAmbigiousUsageError { path: PathBuf, i: usize },
CertNoUsageError { path: PathBuf, i: usize },
CertIssuerCaError { path: PathBuf, i: usize, err: x509_parser::error::X509Error },
InstanceDirError { err: UtilError },
UnknownInstance { name: String },
ActiveInstanceReadError { err: InstanceError },
InstancePathError { name: String, err: InstanceError },
PemLoadError { path: PathBuf, err: brane_cfg::certs::Error },
NoCaCert,
NoClientCert,
NoClientKey,
NoDomainName,
ConfirmationError { err: dialoguer::Error },
CertsDirNotADir { path: PathBuf },
CertsDirRemoveError { path: PathBuf, err: std::io::Error },
CertsDirCreateError { path: PathBuf, err: std::io::Error },
FileOpenError { what: &'static str, path: PathBuf, err: std::io::Error },
FileWriteError { what: &'static str, path: PathBuf, err: std::io::Error },
InstancesDirError { err: UtilError },
DirReadError { what: &'static str, path: PathBuf, err: std::io::Error },
DirEntryReadError { what: &'static str, path: PathBuf, entry: usize, err: std::io::Error },
}
impl Display for CertsError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use CertsError::*;
match self {
ActiveInstanceNotASoftlinkError { path } => write!(f, "Active instance link '{}' exists but is not a symlink", path.display()),
CertParseError { path, i, .. } => write!(f, "Failed to parse certificate {} in file '{}'", i, path.display()),
CertExtensionsError { path, i, .. } => write!(f, "Failed to get extensions in certificate {} in file '{}'", i, path.display()),
CertNoKeyUsageError { path, i } => {
write!(f, "Certificate {} in file '{}' does not have key usage defined (extension)", i, path.display())
},
CertAmbigiousUsageError { path, i } => {
write!(f, "Certificate {} in file '{}' has both Digital Signature and CRL Sign flags set (ambigious usage)", i, path.display())
},
CertNoUsageError { path, i } => write!(
f,
"Certificate {} in file '{}' has neither Digital Signature, nor CRL Sign flags set (cannot determine usage)",
i,
path.display()
),
CertIssuerCaError { path, i, .. } => {
write!(f, "Failed to get the CA field in the issuer field of certificate {} in file '{}'", i, path.display())
},
InstanceDirError { .. } => write!(f, "Failed to get instance directory"),
UnknownInstance { name } => write!(f, "Unknown instance '{name}'"),
ActiveInstanceReadError { .. } => write!(f, "Failed to read active instance"),
InstancePathError { name, .. } => write!(f, "Failed to get instance path for instance '{name}'"),
PemLoadError { path, .. } => write!(f, "Failed to load PEM file '{}'", path.display()),
NoCaCert => write!(f, "No CA certificate given (specify at least one certificate that has 'CRL Sign' key usage flag set)"),
NoClientCert => {
write!(f, "No client certificate given (specify at least one certificate that has 'Digital Signature' key usage flag set)")
},
NoClientKey => write!(f, "No client private key given (specify at least one private key)"),
NoDomainName => write!(f, "Location name not specified in certificates; specify the target location name manually using '--domain'"),
ConfirmationError { .. } => {
write!(f, "Failed to ask the user (you!) for confirmation (if you are sure, you can skip this step by using '--force')")
},
CertsDirNotADir { path } => write!(f, "Certificate directory '{}' exists but is not a directory", path.display()),
CertsDirRemoveError { path, .. } => write!(f, "Failed to remove certificate directory '{}'", path.display()),
CertsDirCreateError { path, .. } => write!(f, "Failed to create certificate directory '{}'", path.display()),
FileOpenError { what, path, .. } => write!(f, "Failed to open {} file '{}' for appending", what, path.display()),
FileWriteError { what, path, .. } => write!(f, "Failed to write to {} file '{}'", what, path.display()),
InstancesDirError { .. } => write!(f, "Failed to get instances directory"),
DirReadError { what, path, .. } => write!(f, "Failed to read {} directory '{}'", what, path.display()),
DirEntryReadError { what, path, entry, .. } => {
write!(f, "Failed to read entry {} in {} directory '{}'", entry, what, path.display())
},
}
}
}
impl Error for CertsError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use CertsError::*;
match self {
ActiveInstanceNotASoftlinkError { .. } => None,
CertParseError { err, .. } => Some(err),
CertExtensionsError { err, .. } => Some(err),
CertNoKeyUsageError { .. } => None,
CertAmbigiousUsageError { .. } => None,
CertNoUsageError { .. } => None,
CertIssuerCaError { err, .. } => Some(err),
InstanceDirError { err } => Some(err),
UnknownInstance { .. } => None,
ActiveInstanceReadError { err } => Some(err),
InstancePathError { err, .. } => Some(err),
PemLoadError { err, .. } => Some(err),
NoCaCert => None,
NoClientCert => None,
NoClientKey => None,
NoDomainName => None,
ConfirmationError { err } => Some(err),
CertsDirNotADir { .. } => None,
CertsDirRemoveError { err, .. } => Some(err),
CertsDirCreateError { err, .. } => Some(err),
FileOpenError { err, .. } => Some(err),
FileWriteError { err, .. } => Some(err),
InstancesDirError { err } => Some(err),
DirReadError { err, .. } => Some(err),
DirEntryReadError { err, .. } => Some(err),
}
}
}
#[derive(Debug)]
pub enum CheckError {
ActiveInstanceInfoLoad { err: InstanceError },
AstCompile { input: String },
DataIndexRetrieve { url: String, err: brane_tsk::api::Error },
DriverCheck { address: Address, err: tonic::Status },
DriverConnect { address: Address, err: specifications::driving::DriverServiceError },
InputFileRead { path: PathBuf, err: std::io::Error },
InputStdinRead { err: std::io::Error },
PackageIndexRetrieve { url: String, err: brane_tsk::api::Error },
WorkflowCompile { input: String, err: Box<Self> },
WorkflowSerialize { input: String, err: serde_json::Error },
}
impl Display for CheckError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use CheckError::*;
match self {
ActiveInstanceInfoLoad { .. } => write!(f, "Failed to get currently active instance"),
AstCompile { input } => write!(f, "Failed to compile workflow '{input}' (see output above)"),
DataIndexRetrieve { url, .. } => write!(f, "Failed to retrieve data index from '{url}'"),
DriverCheck { address, .. } => write!(f, "Failed to send CheckRequest to driver '{address}'"),
DriverConnect { address, .. } => write!(f, "Failed to connect to driver '{address}'"),
InputFileRead { path, .. } => write!(f, "Failed to read input file '{}'", path.display()),
InputStdinRead { .. } => write!(f, "Failed to read input from stdin"),
PackageIndexRetrieve { url, .. } => write!(f, "Failed to retrieve package index from '{url}'"),
WorkflowCompile { input, .. } => write!(f, "Failed to compile workflow '{input}'"),
WorkflowSerialize { input, .. } => write!(f, "Failed to serialize workflow '{input}'"),
}
}
}
impl Error for CheckError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use CheckError::*;
match self {
ActiveInstanceInfoLoad { err } => Some(err),
AstCompile { .. } => None,
DataIndexRetrieve { err, .. } => Some(err),
DriverCheck { err, .. } => Some(err),
DriverConnect { err, .. } => Some(err),
InputFileRead { err, .. } => Some(err),
InputStdinRead { err } => Some(err),
PackageIndexRetrieve { err, .. } => Some(err),
WorkflowCompile { err, .. } => Some(err),
WorkflowSerialize { err, .. } => Some(err),
}
}
}
#[derive(Debug)]
pub enum DataError {
RequestError { what: &'static str, address: String, err: reqwest::Error },
RequestFailure { address: String, code: StatusCode, message: Option<String> },
ResponseTextError { address: String, err: reqwest::Error },
FileReadError { what: &'static str, path: PathBuf, err: std::io::Error },
CertsDirError { err: CertsError },
IdentityFileError { path: PathBuf, err: reqwest::Error },
CertificateError { path: PathBuf, err: reqwest::Error },
DirNotADirError { what: &'static str, path: PathBuf },
DirRemoveError { what: &'static str, path: PathBuf, err: std::io::Error },
DirCreateError { what: &'static str, path: PathBuf, err: std::io::Error },
TempDirError { err: std::io::Error },
DatasetDirError { name: String, err: UtilError },
ProxyCreateError { address: String, err: reqwest::Error },
ClientCreateError { err: reqwest::Error },
DownloadStreamError { address: String, err: reqwest::Error },
TarCreateError { path: PathBuf, err: std::io::Error },
TarWriteError { path: PathBuf, err: std::io::Error },
TarExtractError { err: brane_shr::fs::Error },
DatasetsError { err: UtilError },
LocalDataIndexError { err: brane_tsk::local::Error },
AssetFileError { path: PathBuf, err: specifications::data::AssetInfoError },
FileCanonicalizeError { path: PathBuf, err: std::io::Error },
FileNotFoundError { path: PathBuf },
FileNotAFileError { path: PathBuf },
DatasetDirCreateError { err: UtilError },
DuplicateDatasetError { name: String },
DataCopyError { err: brane_shr::fs::Error },
DataInfoWriteError { err: specifications::data::DataInfoError },
NoEqualsInKeyPair { raw: String },
InstanceInfoError { err: InstanceError },
ActiveInstanceReadError { err: InstanceError },
InstancePathError { name: String, err: InstanceError },
RemoteDataIndexError { address: String, err: brane_tsk::errors::ApiError },
DataSelectError { err: dialoguer::Error },
UnknownLocation { name: String },
UnknownDataset { name: String },
UnavailableDataset { name: String, locs: Vec<String> },
ConfirmationError { err: dialoguer::Error },
RemoveError { path: PathBuf, err: std::io::Error },
}
impl Display for DataError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use DataError::*;
match self {
RequestError { what, address, .. } => write!(f, "Failed to send {what} request to '{address}'"),
RequestFailure { address, code, message } => write!(
f,
"Request to '{}' failed with status code {} ({}){}",
address,
code,
code.canonical_reason().unwrap_or("???"),
if let Some(msg) = message { format!(": {msg}") } else { String::new() }
),
ResponseTextError { address, .. } => write!(f, "Failed to get body from response sent by '{address}' as text"),
FileReadError { what, path, .. } => write!(f, "Failed to read {} file '{}'", what, path.display()),
CertsDirError { .. } => write!(f, "Failed to get certificates directory for active instance"),
IdentityFileError { path, .. } => write!(f, "Failed to parse identity file '{}'", path.display()),
CertificateError { path, .. } => write!(f, "Failed to parse certificate '{}'", path.display()),
DirNotADirError { what, path } => write!(f, "{} directory '{}' is not a directory", what, path.display()),
DirRemoveError { what, path, .. } => write!(f, "Failed to remove {} directory '{}'", what, path.display()),
DirCreateError { what, path, .. } => write!(f, "Failed to create {} directory '{}'", what, path.display()),
TempDirError { .. } => write!(f, "Failed to create temporary directory"),
DatasetDirError { name, .. } => write!(f, "Failed to create dataset directory for dataset '{name}'"),
ProxyCreateError { address, .. } => write!(f, "Failed to create new proxy to '{address}'"),
ClientCreateError { .. } => write!(f, "Failed to create new client"),
DownloadStreamError { address, .. } => write!(f, "Failed to get next chunk in download stream from '{address}'"),
TarCreateError { path, .. } => write!(f, "Failed to create tarball file '{}'", path.display()),
TarWriteError { path, .. } => write!(f, "Failed to write to tarball file '{}'", path.display()),
TarExtractError { .. } => write!(f, "Failed to extract downloaded archive"),
DatasetsError { .. } => write!(f, "Failed to get datasets folder"),
LocalDataIndexError { .. } => write!(f, "Failed to get local data index"),
AssetFileError { path, .. } => write!(f, "Failed to load given asset file '{}'", path.display()),
FileCanonicalizeError { path, .. } => write!(f, "Failed to resolve path '{}'", path.display()),
FileNotFoundError { path } => write!(f, "Referenced file '{}' not found (are you using the correct working directory?)", path.display()),
FileNotAFileError { path } => write!(f, "Referenced file '{}' is not a file", path.display()),
DatasetDirCreateError { .. } => write!(f, "Failed to create target dataset directory in the Brane data folder"),
DuplicateDatasetError { name } => write!(f, "A dataset with the name '{name}' already exists locally"),
DataCopyError { .. } => write!(f, "Failed to data directory"),
DataInfoWriteError { .. } => write!(f, "Failed to write DataInfo file"),
NoEqualsInKeyPair { raw } => write!(f, "Missing '=' in key/value pair '{raw}'"),
InstanceInfoError { .. } => write!(f, "Could not read active instance info file"),
ActiveInstanceReadError { .. } => write!(f, "Failed to read active instance link"),
InstancePathError { name, .. } => write!(f, "Could not get path of instance '{name}'"),
RemoteDataIndexError { address, .. } => write!(f, "Failed to fetch remote data index from '{address}'"),
DataSelectError { .. } => write!(f, "Failed to ask the user (you!) to select a download location"),
UnknownLocation { name } => write!(f, "Unknown location '{name}'"),
UnknownDataset { name } => write!(f, "Unknown dataset '{name}'"),
UnavailableDataset { name, locs } => write!(
f,
"Dataset '{}' is unavailable{}",
name,
if !locs.is_empty() {
format!("; try {} instead", locs.iter().map(|l| format!("'{l}'")).collect::<Vec<String>>().join(", "))
} else {
String::new()
}
),
ConfirmationError { .. } => write!(f, "Failed to ask the user (you) for confirmation before removing a dataset"),
RemoveError { path, .. } => write!(f, "Failed to remove dataset directory '{}'", path.display()),
}
}
}
impl Error for DataError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use DataError::*;
match self {
RequestError { err, .. } => Some(err),
RequestFailure { .. } => None,
ResponseTextError { err, .. } => Some(err),
FileReadError { err, .. } => Some(err),
CertsDirError { .. } => None,
IdentityFileError { err, .. } => Some(err),
CertificateError { err, .. } => Some(err),
DirNotADirError { .. } => None,
DirRemoveError { err, .. } => Some(err),
DirCreateError { err, .. } => Some(err),
TempDirError { .. } => None,
DatasetDirError { err, .. } => Some(err),
ProxyCreateError { err, .. } => Some(err),
ClientCreateError { .. } => None,
DownloadStreamError { err, .. } => Some(err),
TarCreateError { err, .. } => Some(err),
TarWriteError { err, .. } => Some(err),
TarExtractError { .. } => None,
DatasetsError { .. } => None,
LocalDataIndexError { .. } => None,
AssetFileError { err, .. } => Some(err),
FileCanonicalizeError { err, .. } => Some(err),
FileNotFoundError { .. } => None,
FileNotAFileError { .. } => None,
DatasetDirCreateError { .. } => None,
DuplicateDatasetError { .. } => None,
DataCopyError { .. } => None,
DataInfoWriteError { .. } => None,
NoEqualsInKeyPair { .. } => None,
InstanceInfoError { .. } => None,
ActiveInstanceReadError { .. } => None,
InstancePathError { err, .. } => Some(err),
RemoteDataIndexError { err, .. } => Some(err),
DataSelectError { .. } => None,
UnknownLocation { .. } => None,
UnknownDataset { .. } => None,
UnavailableDataset { .. } => None,
ConfirmationError { .. } => None,
RemoveError { err, .. } => Some(err),
}
}
}
#[derive(Debug)]
pub enum ImportError {
TempDirError { err: std::io::Error },
TempDirCanonicalizeError { path: PathBuf, err: std::io::Error },
RepoCloneError { repo: String, target: PathBuf, err: brane_shr::fs::Error },
RepoEscapeError { path: PathBuf },
}
impl Display for ImportError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use ImportError::*;
match self {
TempDirError { .. } => write!(f, "Could not create temporary repository directory"),
TempDirCanonicalizeError { path, .. } => {
write!(f, "Could not resolve temporary directory path '{}'", path.display())
},
RepoCloneError { repo, target, .. } => {
write!(f, "Could not clone repository at '{}' to directory '{}'", repo, target.display())
},
RepoEscapeError { path } => write!(f, "Path '{}' points outside of repository folder", path.display()),
}
}
}
impl Error for ImportError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use ImportError::*;
match self {
TempDirError { err, .. } => Some(err),
TempDirCanonicalizeError { err, .. } => Some(err),
RepoCloneError { err, .. } => Some(err),
RepoEscapeError { .. } => None,
}
}
}
#[derive(Debug)]
pub enum InstanceError {
InstanceDirError { err: UtilError },
InstanceInfoOpenError { path: PathBuf, err: std::io::Error },
InstanceInfoReadError { path: PathBuf, err: std::io::Error },
InstanceInfoParseError { path: PathBuf, err: serde_yaml::Error },
InstanceInfoSerializeError { err: serde_yaml::Error },
InstanceInfoCreateError { path: PathBuf, err: std::io::Error },
InstanceInfoWriteError { path: PathBuf, err: std::io::Error },
IllegalInstanceName { raw: String, illegal_char: char },
AddressParseError { err: specifications::address::AddressError },
RequestError { address: String, err: reqwest::Error },
InstanceNotAliveError { address: String, code: StatusCode, err: Option<String> },
ConfirmationError { err: dialoguer::Error },
InstancesDirError { err: UtilError },
InstancesDirReadError { path: PathBuf, err: std::io::Error },
InstancesDirEntryReadError { path: PathBuf, entry: usize, err: std::io::Error },
ActiveInstanceTargetError { path: PathBuf, err: std::io::Error },
UnknownInstance { name: String },
InstanceNotADirError { path: PathBuf },
ActiveInstancePathError { err: UtilError },
ActiveInstanceNotAFileError { path: PathBuf },
ActiveInstanceReadError { path: PathBuf, err: std::io::Error },
ActiveInstanceRemoveError { path: PathBuf, err: std::io::Error },
ActiveInstanceCreateError { path: PathBuf, target: String, err: std::io::Error },
NoActiveInstance,
}
impl Display for InstanceError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use InstanceError::*;
match self {
InstanceDirError { .. } => write!(f, "Failed to get directory for instance"),
InstanceInfoOpenError { path, .. } => write!(f, "Failed to open instance info file '{}'", path.display()),
InstanceInfoReadError { path, .. } => write!(f, "Failed to read instance info file '{}'", path.display()),
InstanceInfoParseError { path, .. } => write!(f, "Failed to parse instance info file '{}' as valid YAML", path.display()),
InstanceInfoSerializeError { .. } => write!(f, "Failed to serialize instance info struct"),
InstanceInfoCreateError { path, .. } => write!(f, "Failed to create new info instance file '{}'", path.display()),
InstanceInfoWriteError { path, .. } => write!(f, "Failed to write to instance info file '{}'", path.display()),
IllegalInstanceName { raw, illegal_char } => {
write!(f, "Instance name '{raw}' contains illegal character '{illegal_char}' (use '--name' to override it with a custom one)")
},
AddressParseError { .. } => write!(f, "Failed to convert hostname to a valid address"),
RequestError { address, .. } => write!(
f,
"Failed to send request to the instance API at '{address}' (if this is something on your end, you may skip this check by providing \
'--unchecked')"
),
InstanceNotAliveError { address, code, err } => write!(
f,
"Remote instance at '{}' is not alive (returned {} ({}){})",
address,
code,
code.canonical_reason().unwrap_or("???"),
if let Some(err) = err { format!("\n\nResponse:\n{}\n", BlockFormatter::new(err)) } else { String::new() }
),
ConfirmationError { .. } => {
write!(f, "Failed to ask the user (you!) for confirmation (if you are sure, you can skip this step by using '--force')")
},
InstancesDirError { .. } => write!(f, "Failed to get the instances directory"),
InstancesDirReadError { path, .. } => write!(f, "Failed to read instances directory '{}'", path.display()),
InstancesDirEntryReadError { path, entry, .. } => {
write!(f, "Failed to read instances directory '{}' entry {}", path.display(), entry)
},
ActiveInstanceTargetError { path, .. } => write!(f, "Failed to get target of active instance link '{}'", path.display()),
UnknownInstance { name } => write!(f, "Unknown instance '{name}'"),
InstanceNotADirError { path } => write!(f, "Instance directory '{}' exists but is not a directory", path.display()),
ActiveInstancePathError { .. } => write!(f, "Failed to get active instance link path"),
ActiveInstanceNotAFileError { path } => write!(f, "Active instance link '{}' exists but is not a file", path.display()),
ActiveInstanceReadError { path, .. } => write!(f, "Failed to read active instance link '{}'", path.display()),
ActiveInstanceRemoveError { path, .. } => write!(f, "Failed to remove existing active instance link '{}'", path.display()),
ActiveInstanceCreateError { path, target, .. } => {
write!(f, "Failed to create active instance link '{}' to '{}'", path.display(), target)
},
NoActiveInstance => write!(f, "No active instance is set (run 'brane instance select' first)"),
}
}
}
impl Error for InstanceError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use InstanceError::*;
match self {
InstanceDirError { err, .. } => Some(err),
InstanceInfoOpenError { err, .. } => Some(err),
InstanceInfoReadError { err, .. } => Some(err),
InstanceInfoParseError { err, .. } => Some(err),
InstanceInfoSerializeError { err, .. } => Some(err),
InstanceInfoCreateError { err, .. } => Some(err),
InstanceInfoWriteError { err, .. } => Some(err),
IllegalInstanceName { .. } => None,
AddressParseError { err, .. } => Some(err),
RequestError { err, .. } => Some(err),
InstanceNotAliveError { .. } => None,
ConfirmationError { err, .. } => Some(err),
InstancesDirError { err, .. } => Some(err),
InstancesDirReadError { err, .. } => Some(err),
InstancesDirEntryReadError { err, .. } => Some(err),
ActiveInstanceTargetError { err, .. } => Some(err),
UnknownInstance { .. } => None,
InstanceNotADirError { .. } => None,
ActiveInstancePathError { err, .. } => Some(err),
ActiveInstanceNotAFileError { .. } => None,
ActiveInstanceReadError { err, .. } => Some(err),
ActiveInstanceRemoveError { err, .. } => Some(err),
ActiveInstanceCreateError { err, .. } => Some(err),
NoActiveInstance => None,
}
}
}
#[derive(Debug)]
pub enum PackageError {
UtilError { err: UtilError },
IndexError { err: brane_tsk::local::Error },
PackageVersionError { name: String, version: Version, err: UtilError },
PackageError { name: String, err: UtilError },
ConsentError { err: dialoguer::Error },
PackageRemoveError { name: String, version: Version, dir: PathBuf, err: std::io::Error },
VersionsError { name: String, dir: PathBuf, err: std::io::Error },
VersionParseError { name: String, raw: String, err: specifications::version::ParseError },
PackageInfoError { path: PathBuf, err: specifications::package::PackageInfoError },
PackageInfoNoDigest { path: PathBuf },
DockerRemoveError { image: Box<Image>, err: brane_tsk::errors::DockerError },
}
impl std::fmt::Display for PackageError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use self::PackageError::*;
match self {
UtilError { err } => write!(f, "{}", err.trace()),
IndexError { .. } => write!(f, "Failed to fetch a local package index"),
PackageVersionError { name, version, .. } => write!(f, "Package '{name}' does not exist or has no version {version}"),
PackageError { name, .. } => write!(f, "Package '{name}' does not exist"),
ConsentError { .. } => write!(f, "Failed to ask for your consent"),
PackageRemoveError { name, version, dir, .. } => {
write!(f, "Failed to remove package '{}' (version {}) at '{}'", name, version, dir.display())
},
VersionsError { name, dir, .. } => write!(f, "Failed to get versions of package '{}' (at '{}')", name, dir.display()),
VersionParseError { name, raw, .. } => write!(f, "Could not parse '{raw}' as a version for package '{name}'"),
PackageInfoError { path, .. } => write!(f, "Could not load package info file '{}'", path.display()),
PackageInfoNoDigest { path } => write!(f, "Package info file '{}' has no digest set", path.display()),
DockerRemoveError { image, .. } => {
write!(f, "Failed to remove image '{}' from the local Docker daemon", image.digest().unwrap_or("<no digest given>"))
},
}
}
}
impl std::error::Error for PackageError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use self::PackageError::*;
match self {
UtilError { .. } => None,
IndexError { err } => Some(err),
PackageVersionError { err, .. } => Some(err),
PackageError { err, .. } => Some(err),
ConsentError { err } => Some(err),
PackageRemoveError { err, .. } => Some(err),
VersionsError { err, .. } => Some(err),
VersionParseError { err, .. } => Some(err),
PackageInfoError { err, .. } => Some(err),
PackageInfoNoDigest { .. } => None,
DockerRemoveError { err, .. } => Some(err),
}
}
}
#[derive(Debug)]
pub enum RegistryError {
InstanceInfoError { err: InstanceError },
PullRequestError { url: String, err: reqwest::Error },
PullRequestFailure { url: String, status: reqwest::StatusCode },
MissingContentLength { url: String },
ContentLengthStrError { url: String, err: reqwest::header::ToStrError },
ContentLengthParseError { url: String, raw: String, err: std::num::ParseIntError },
PackageDownloadError { url: String, err: reqwest::Error },
PackageWriteError { url: String, path: PathBuf, err: std::io::Error },
PackageDirCreateError { path: PathBuf, err: std::io::Error },
PackageCopyError { source: PathBuf, target: PathBuf, err: std::io::Error },
GraphQLRequestError { url: String, err: reqwest::Error },
GraphQLResponseError { url: String, err: reqwest::Error },
KindParseError { url: String, raw: String, err: specifications::package::PackageKindError },
VersionParseError { url: String, raw: String, err: specifications::version::ParseError },
RequirementParseError { url: String, raw: String, err: serde_json::Error },
FunctionsParseError { url: String, raw: String, err: serde_json::Error },
TypesParseError { url: String, raw: String, err: serde_json::Error },
PackageInfoCreateError { path: PathBuf, err: std::io::Error },
PackageInfoWriteError { path: PathBuf, err: serde_yaml::Error },
NoPackageInfo { url: String },
PackagesDirError { err: UtilError },
VersionsError { name: String, err: brane_tsk::local::Error },
PackageDirError { name: String, version: Version, err: UtilError },
TempFileError { err: std::io::Error },
CompressionError { name: String, version: Version, path: PathBuf, err: std::io::Error },
PackageArchiveOpenError { path: PathBuf, err: std::io::Error },
UploadError { path: PathBuf, endpoint: String, err: reqwest::Error },
}
impl Display for RegistryError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use RegistryError::*;
match self {
InstanceInfoError { err } => write!(f, "{err}"),
PullRequestError { url, err } => write!(f, "Could not send the request to pull pacakge to '{url}': {err}"),
PullRequestFailure { url, status } => write!(
f,
"Request to pull package from '{}' was met with status code {} ({})",
url,
status.as_u16(),
status.canonical_reason().unwrap_or("???")
),
MissingContentLength { url } => write!(f, "Response from '{url}' did not have 'Content-Length' header set"),
ContentLengthStrError { url, err } => write!(f, "Could not convert content length received from '{url}' to string: {err}"),
ContentLengthParseError { url, raw, err } => {
write!(f, "Could not parse '{raw}' as a number (the content-length received from '{url}'): {err}")
},
PackageDownloadError { url, err } => write!(f, "Could not download package from '{url}': {err}"),
PackageWriteError { url, path, err } => write!(f, "Could not write package downloaded from '{}' to '{}': {}", url, path.display(), err),
PackageDirCreateError { path, err } => write!(f, "Could not create package directory '{}': {}", path.display(), err),
PackageCopyError { source, target, err } => {
write!(f, "Could not copy package from '{}' to '{}': {}", source.display(), target.display(), err)
},
GraphQLRequestError { url, err } => write!(f, "Could not send a GraphQL request to '{url}': {err}"),
GraphQLResponseError { url, err } => write!(f, "Could not get the GraphQL respones from '{url}': {err}"),
KindParseError { url, raw, err } => write!(f, "Could not parse '{raw}' (received from '{url}') as package kind: {err}"),
VersionParseError { url, raw, err } => write!(f, "Could not parse '{raw}' (received from '{url}') as package version: {err}"),
RequirementParseError { url, raw, err } => write!(f, "Could not parse '{raw}' (received from '{url}') as package requirement: {err}"),
FunctionsParseError { url, raw, err } => write!(f, "Could not parse '{raw}' (received from '{url}') as package functions: {err}"),
TypesParseError { url, raw, err } => write!(f, "Could not parse '{raw}' (received from '{url}') as package types: {err}"),
PackageInfoCreateError { path, err } => write!(f, "Could not create PackageInfo file '{}': {}", path.display(), err),
PackageInfoWriteError { path, err } => write!(f, "Could not write to PackageInfo file '{}': {}", path.display(), err),
NoPackageInfo { url } => write!(f, "Server '{url}' responded with empty response (is your name/version correct?)"),
PackagesDirError { err } => write!(f, "Could not resolve the packages directory: {err}"),
VersionsError { name, err } => write!(f, "Could not get version list for package '{name}': {err}"),
PackageDirError { name, version, err } => write!(f, "Could not resolve package directory of package '{name}' (version {version}): {err}"),
TempFileError { err } => write!(f, "Could not create a new temporary file: {err}"),
CompressionError { name, version, path, err } => {
write!(f, "Could not compress package '{}' (version {}) to '{}': {}", name, version, path.display(), err)
},
PackageArchiveOpenError { path, err } => write!(f, "Could not re-open compressed package archive '{}': {}", path.display(), err),
UploadError { path, endpoint, err } => {
write!(f, "Could not upload compressed package archive '{}' to '{}': {}", path.display(), endpoint, err)
},
}
}
}
impl Error for RegistryError {}
#[derive(Debug)]
pub enum ReplError {
ConfigDirCreateError { err: UtilError },
HistoryFileError { err: UtilError },
EditorCreateError { err: rustyline::error::ReadlineError },
InstanceInfoError { err: InstanceError },
InitializeError { what: &'static str, err: RunError },
RunError { what: &'static str, err: RunError },
ProcessError { what: &'static str, err: RunError },
}
impl Display for ReplError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use ReplError::*;
match self {
ConfigDirCreateError { .. } => write!(f, "Could not create the configuration directory for the REPL history"),
HistoryFileError { .. } => write!(f, "Could not get REPL history file location"),
EditorCreateError { .. } => write!(f, "Failed to create new rustyline editor"),
InstanceInfoError { .. } => write!(f, "Failed to load instance info file"),
InitializeError { what, .. } => write!(f, "Failed to initialize {what} and associated structures"),
RunError { what, .. } => write!(f, "Failed to execute workflow on {what}"),
ProcessError { what, .. } => write!(f, "Failed to process {what} workflow results"),
}
}
}
impl Error for ReplError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use ReplError::*;
match self {
ConfigDirCreateError { err } => Some(err),
HistoryFileError { err } => Some(err),
EditorCreateError { err } => Some(err),
InstanceInfoError { err } => Some(err),
InitializeError { err, .. } => Some(err),
RunError { err, .. } => Some(err),
ProcessError { err, .. } => Some(err),
}
}
}
#[derive(Debug)]
pub enum RunError {
WriteError { err: std::io::Error },
LocalPackageIndexError { err: brane_tsk::local::Error },
LocalDataIndexError { err: brane_tsk::local::Error },
PackagesDirError { err: UtilError },
DatasetsDirError { err: UtilError },
ResultsDirCreateError { err: std::io::Error },
InstanceInfoError { err: InstanceError },
ActiveInstanceReadError { err: InstanceError },
InstancePathError { name: String, err: InstanceError },
RemotePackageIndexError { address: String, err: brane_tsk::errors::ApiError },
RemoteDataIndexError { address: String, err: brane_tsk::errors::ApiError },
RemoteDelegatesError { address: String, err: DelegatesError },
ClientConnectError { address: String, err: specifications::driving::Error },
AppIdError { address: String, raw: String, err: Box<brane_tsk::errors::IdError> },
SessionCreateError { address: String, err: tonic::Status },
CompileError { what: String, errs: Vec<brane_ast::Error> },
WorkflowSerializeError { err: serde_json::Error },
CommandRequestError { address: String, err: tonic::Status },
ValueParseError { address: String, raw: String, err: serde_json::Error },
ExecDenied { err: Box<dyn Error> },
ExecError { err: Box<dyn Error> },
UnknownDataset { name: String },
UnavailableDataset { name: String, locs: Vec<String> },
DataDownloadError { err: DataError },
StdinReadError { err: std::io::Error },
FileReadError { path: PathBuf, err: std::io::Error },
LoginFileError { err: UtilError },
}
impl Display for RunError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use RunError::*;
match self {
WriteError { .. } => write!(f, "Failed to write to the given formatter"),
LocalPackageIndexError { .. } => write!(f, "Failed to fetch local package index"),
LocalDataIndexError { .. } => write!(f, "Failed to fetch local data index"),
PackagesDirError { .. } => write!(f, "Failed to get packages directory"),
DatasetsDirError { .. } => write!(f, "Failed to get datasets directory"),
ResultsDirCreateError { .. } => write!(f, "Failed to create new temporary directory as an intermediate result directory"),
InstanceInfoError { err } => write!(f, "{err}"),
ActiveInstanceReadError { .. } => write!(f, "Failed to read active instance link"),
InstancePathError { name, .. } => write!(f, "Could not get path of instance '{name}'"),
RemotePackageIndexError { address, .. } => write!(f, "Failed to fetch remote package index from '{address}'"),
RemoteDataIndexError { address, .. } => write!(f, "Failed to fetch remote data index from '{address}'"),
RemoteDelegatesError { address, .. } => write!(f, "Failed to fetch delegates map from '{address}'"),
ClientConnectError { address, .. } => write!(f, "Could not connect to remote Brane instance '{address}'"),
AppIdError { address, raw, .. } => write!(f, "Could not parse '{raw}' send by remote '{address}' as an application ID"),
SessionCreateError { address, .. } => {
write!(f, "Could not create new session with remote Brane instance '{address}': remote returned status")
},
CompileError { .. } => write!(f, "Compilation of workflow failed (see output above)"),
WorkflowSerializeError { .. } => write!(f, "Failed to serialize the compiled workflow"),
CommandRequestError { address, .. } => {
write!(f, "Could not run command on remote Brane instance '{address}': request failed: remote returned status")
},
ValueParseError { address, raw, .. } => write!(f, "Could not parse '{raw}' sent by remote '{address}' as a value"),
ExecDenied { .. } => write!(f, "Workflow was denied"),
ExecError { .. } => write!(f, "Failed to run workflow"),
UnknownDataset { name } => write!(f, "Unknown dataset '{name}'"),
UnavailableDataset { name, locs } => write!(
f,
"Unavailable dataset '{}'{}",
name,
if !locs.is_empty() {
format!("; it is available at {}", PrettyListFormatter::new(locs.iter().map(|l| format!("'{l}'")), "or"))
} else {
String::new()
}
),
DataDownloadError { .. } => write!(f, "Failed to download remote dataset"),
StdinReadError { .. } => write!(f, "Failed to read source from stdin"),
FileReadError { path, .. } => write!(f, "Failed to read source from file '{}'", path.display()),
LoginFileError { err } => write!(f, "{err}"),
}
}
}
impl Error for RunError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use RunError::*;
match self {
WriteError { err } => Some(err),
LocalPackageIndexError { err } => Some(err),
LocalDataIndexError { err } => Some(err),
PackagesDirError { err } => Some(err),
DatasetsDirError { err } => Some(err),
ResultsDirCreateError { err } => Some(err),
InstanceInfoError { err } => err.source(),
ActiveInstanceReadError { err } => Some(err),
InstancePathError { err, .. } => Some(err),
RemotePackageIndexError { err, .. } => Some(err),
RemoteDataIndexError { err, .. } => Some(err),
RemoteDelegatesError { err, .. } => Some(err),
ClientConnectError { err, .. } => Some(err),
AppIdError { err, .. } => Some(err),
SessionCreateError { err, .. } => Some(err),
CompileError { .. } => None,
WorkflowSerializeError { err } => Some(err),
CommandRequestError { err, .. } => Some(err),
ValueParseError { err, .. } => Some(err),
ExecDenied { err } => Some(&**err),
ExecError { err } => Some(&**err),
UnknownDataset { .. } => None,
UnavailableDataset { .. } => None,
DataDownloadError { err } => Some(err),
StdinReadError { err } => Some(err),
FileReadError { err, .. } => Some(err),
LoginFileError { err } => err.source(),
}
}
}
impl From<std::io::Error> for RunError {
#[inline]
fn from(value: std::io::Error) -> Self { RunError::WriteError { err: value } }
}
#[derive(Debug)]
pub enum TestError {
DataIndexError { err: brane_tsk::local::Error },
InputError { err: brane_tsk::input::Error },
TempDirError { err: std::io::Error },
DatasetUnavailable { name: String, locs: Vec<String> },
UnknownDataset { name: String },
PackagesDirError { err: UtilError },
DatasetsDirError { err: UtilError },
PackageDirError { name: String, version: Version, err: UtilError },
PackageInfoError { name: String, version: Version, err: specifications::package::PackageInfoError },
InitializeError { err: RunError },
RunError { err: RunError },
IntermediateResultFileReadError { path: PathBuf, err: std::io::Error },
}
impl Display for TestError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use TestError::*;
match self {
DataIndexError { err } => write!(f, "Failed to load local data index: {err}"),
InputError { err } => write!(f, "Failed to ask the user (you!) for input: {}", err.trace()),
TempDirError { err } => write!(f, "Failed to create temporary results directory: {err}"),
DatasetUnavailable { name, locs } => write!(
f,
"Dataset '{}' is unavailable{}",
name,
if !locs.is_empty() {
format!(
"; however, locations {} do (try to get download permission to those datasets)",
locs.iter().map(|l| format!("'{l}'")).collect::<Vec<String>>().join(", ")
)
} else {
String::new()
}
),
UnknownDataset { name } => write!(f, "Unknown dataset '{name}'"),
PackagesDirError { err } => write!(f, "Failed to get packages directory: {err}"),
DatasetsDirError { err } => write!(f, "Failed to get datasets directory: {err}"),
PackageDirError { name, version, err } => write!(f, "Failed to get directory of package '{name}' (version {version}): {err}"),
PackageInfoError { name, version, err } => write!(f, "Failed to read package info for package '{name}' (version {version}): {err}"),
InitializeError { err } => write!(f, "Failed to initialize offline VM: {err}"),
RunError { err } => write!(f, "Failed to run offline VM: {err}"),
IntermediateResultFileReadError { path, err } => write!(f, "Failed to read intermediate result file '{}': {}", path.display(), err),
}
}
}
impl Error for TestError {}
#[derive(Debug)]
pub enum VerifyError {
ConfigFailed { err: brane_cfg::infra::Error },
}
impl Display for VerifyError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use VerifyError::*;
match self {
ConfigFailed { err } => write!(f, "Failed to verify configuration: {err}"),
}
}
}
impl Error for VerifyError {}
#[derive(Debug)]
pub enum VersionError {
HostArchError { err: specifications::arch::ArchError },
VersionParseError { raw: String, err: specifications::version::ParseError },
InstanceInfoExistsError { err: InstanceError },
InstanceInfoError { err: InstanceError },
RequestError { url: String, err: reqwest::Error },
RequestFailure { url: String, status: reqwest::StatusCode },
RequestBodyError { url: String, err: reqwest::Error },
}
impl Display for VersionError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use VersionError::*;
match self {
HostArchError { err } => write!(f, "Could not get the host processor architecture: {err}"),
VersionParseError { raw, err } => write!(f, "Could parse '{raw}' as Version: {err}"),
InstanceInfoExistsError { err } => write!(f, "Could not check if active instance exists: {err}"),
InstanceInfoError { err } => write!(f, "{err}"),
RequestError { url, err } => write!(f, "Could not perform request to '{url}': {err}"),
RequestFailure { url, status } => {
write!(f, "Request to '{}' returned non-zero exit code {} ({})", url, status.as_u16(), status.canonical_reason().unwrap_or("<???>"))
},
RequestBodyError { url, err } => write!(f, "Could not get body from response from '{url}': {err}"),
}
}
}
impl Error for VersionError {}
#[derive(Debug)]
pub enum UtilError {
DockerConnectionFailed { err: bollard::errors::Error },
DockerVersionError { err: bollard::errors::Error },
DockerNoVersion,
IllegalDockerVersion { version: String, err: VersionParseError },
BuildxLaunchError { command: String, err: std::io::Error },
BuildxVersionNoParts { version: String },
BuildxVersionNoV { version: String },
IllegalBuildxVersion { version: String, err: VersionParseError },
DirectoryReadError { dir: PathBuf, err: std::io::Error },
UndeterminedPackageFile { dir: PathBuf },
PackageFileOpenError { file: PathBuf, err: std::io::Error },
PackageFileReadError { file: PathBuf, err: std::io::Error },
UndeterminedPackageKind { file: PathBuf },
UserConfigDirNotFound,
BraneConfigDirCreateError { path: PathBuf, err: std::io::Error },
BraneConfigDirNotFound { path: PathBuf },
HistoryFileCreateError { path: PathBuf, err: std::io::Error },
HistoryFileNotFound { path: PathBuf },
UserLocalDataDirNotFound,
BraneDataDirCreateError { path: PathBuf, err: std::io::Error },
BraneDataDirNotFound { path: PathBuf },
BranePackageDirCreateError { path: PathBuf, err: std::io::Error },
BranePackageDirNotFound { path: PathBuf },
BraneDatasetsDirCreateError { path: PathBuf, err: std::io::Error },
BraneDatasetsDirNotFound { path: PathBuf },
VersionsError { err: brane_tsk::errors::LocalError },
PackageDirCreateError { package: String, path: PathBuf, err: std::io::Error },
PackageDirNotFound { package: String, path: PathBuf },
VersionDirCreateError { package: String, version: Version, path: PathBuf, err: std::io::Error },
VersionDirNotFound { package: String, version: Version, path: PathBuf },
BraneDatasetDirCreateError { name: String, path: PathBuf, err: std::io::Error },
BraneDatasetDirNotFound { name: String, path: PathBuf },
BraneInstancesDirCreateError { path: PathBuf, err: std::io::Error },
BraneInstancesDirNotFound { path: PathBuf },
BraneInstanceDirCreateError { path: PathBuf, name: String, err: std::io::Error },
BraneInstanceDirNotFound { path: PathBuf, name: String },
InvalidBakeryName { name: String },
}
impl Display for UtilError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use UtilError::*;
match self {
DockerConnectionFailed { err } => write!(f, "Could not connect to local Docker instance: {err}"),
DockerVersionError { err } => write!(f, "Could not get version of the local Docker instance: {err}"),
DockerNoVersion => write!(f, "Local Docker instance doesn't report a version number"),
IllegalDockerVersion { version, err } => write!(f, "Local Docker instance reports unparseable version '{version}': {err}"),
BuildxLaunchError { command, err } => write!(f, "Could not run command '{command}' to get Buildx version information: {err}"),
BuildxVersionNoParts { version } => {
write!(f, "Illegal Buildx version '{version}': did not find second part (separted by spaces) with version number")
},
BuildxVersionNoV { version } => write!(f, "Illegal Buildx version '{version}': did not find 'v' prepending version number"),
IllegalBuildxVersion { version, err } => write!(f, "Buildx reports unparseable version '{version}': {err}"),
DirectoryReadError { dir, err } => write!(f, "Could not read from directory '{}': {}", dir.display(), err),
UndeterminedPackageFile { dir } => {
write!(f, "Could not determine package file in directory '{}'; specify it manually with '--file'", dir.display())
},
PackageFileOpenError { file, err } => write!(f, "Could not open package file '{}': {}", file.display(), err),
PackageFileReadError { file, err } => write!(f, "Could not read from package file '{}': {}", file.display(), err),
UndeterminedPackageKind { file } => {
write!(f, "Could not determine package from package file '{}'; specify it manually with '--kind'", file.display())
},
UserConfigDirNotFound => write!(f, "Could not find the user's config directory for your OS (reported as {})", std::env::consts::OS),
BraneConfigDirCreateError { path, err } => write!(f, "Could not create Brane config directory '{}': {}", path.display(), err),
BraneConfigDirNotFound { path } => write!(f, "Brane config directory '{}' not found", path.display()),
HistoryFileCreateError { path, err } => write!(f, "Could not create history file '{}' for the REPL: {}", path.display(), err),
HistoryFileNotFound { path } => write!(f, "History file '{}' for the REPL does not exist", path.display()),
UserLocalDataDirNotFound => {
write!(f, "Could not find the user's local data directory for your OS (reported as {})", std::env::consts::OS)
},
BraneDataDirCreateError { path, err } => write!(f, "Could not create Brane data directory '{}': {}", path.display(), err),
BraneDataDirNotFound { path } => write!(f, "Brane data directory '{}' not found", path.display()),
BranePackageDirCreateError { path, err } => write!(f, "Could not create Brane package directory '{}': {}", path.display(), err),
BranePackageDirNotFound { path } => write!(f, "Brane package directory '{}' not found", path.display()),
BraneDatasetsDirCreateError { path, err } => write!(f, "Could not create Brane datasets directory '{}': {}", path.display(), err),
BraneDatasetsDirNotFound { path } => write!(f, "Brane datasets directory '{}' not found", path.display()),
VersionsError { err } => write!(f, "Failed to read package versions: {err}"),
PackageDirCreateError { package, path, err } => {
write!(f, "Could not create directory for package '{}' (path: '{}'): {}", package, path.display(), err)
},
PackageDirNotFound { package, path } => write!(f, "Directory for package '{}' does not exist (path: '{}')", package, path.display()),
VersionDirCreateError { package, version, path, err } => {
write!(f, "Could not create directory for package '{}', version: {} (path: '{}'): {}", package, version, path.display(), err)
},
VersionDirNotFound { package, version, path } => {
write!(f, "Directory for package '{}', version: {} does not exist (path: '{}')", package, version, path.display())
},
BraneDatasetDirCreateError { name, path, err } => {
write!(f, "Could not create Brane dataset directory '{}' for dataset '{}': {}", path.display(), name, err)
},
BraneDatasetDirNotFound { name, path } => write!(f, "Brane dataset directory '{}' for dataset '{}' not found", path.display(), name),
BraneInstancesDirCreateError { path, err } => write!(f, "Failed to create Brane instance directory '{}': {}", path.display(), err),
BraneInstancesDirNotFound { path } => write!(f, "Brane instance directory '{}' not found", path.display()),
BraneInstanceDirCreateError { path, name, err } => {
write!(f, "Failed to create directory '{}' for new instance '{}': {}", path.display(), name, err)
},
BraneInstanceDirNotFound { path, name } => write!(f, "Brane instance directory '{}' for instance '{}' not found", path.display(), name),
InvalidBakeryName { name } => write!(f, "The given name '{name}' is not a valid name; expected alphanumeric or underscore characters"),
}
}
}
impl Error for UtilError {}
#[derive(Debug)]
pub enum DirError {
UserDirError { what: &'static str },
SoftlinkReadError { path: PathBuf, err: std::io::Error },
}
impl Display for DirError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use DirError::*;
match self {
UserDirError { what } => write!(f, "Failed to find user {} directory", what),
SoftlinkReadError { path, err } => write!(f, "Failed to read softlink '{}': {}", path.display(), err),
}
}
}
impl Error for DirError {}
#[derive(Debug)]
pub enum HostnameParseError {
IllegalSchemeChar { raw: String, c: char },
HostnameContainsPath { raw: String },
}
impl Display for HostnameParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use HostnameParseError::*;
match self {
IllegalSchemeChar { raw, c } => write!(f, "URL scheme '{raw}' contains illegal character '{c}'"),
HostnameContainsPath { raw } => write!(f, "Hostname '{raw}' is not just a hostname (it contains a nested path)"),
}
}
}
impl Error for HostnameParseError {}
#[derive(Debug)]
pub enum OfflineVmError {
PlanError { err: brane_tsk::errors::PlanError },
ExecError { err: brane_exe::Error },
}
impl Display for OfflineVmError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use OfflineVmError::*;
match self {
PlanError { err } => write!(f, "Failed to plan workflow: {err}"),
ExecError { err } => write!(f, "Failed to execute workflow: {err}"),
}
}
}
impl Error for OfflineVmError {}
#[derive(Debug)]
pub enum DelegatesError {
RequestError { address: String, err: reqwest::Error },
RequestFailure { address: String, code: StatusCode, message: Option<String> },
ResponseTextError { address: String, err: reqwest::Error },
ResponseParseError { address: String, raw: String, err: serde_json::Error },
}
impl Display for DelegatesError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use DelegatesError::*;
match self {
RequestError { address, err } => write!(f, "Failed to send delegates request to '{address}': {err}"),
RequestFailure { address, code, message } => write!(
f,
"Request to '{}' failed with status code {} ({}){}",
address,
code,
code.canonical_reason().unwrap_or("???"),
if let Some(msg) = message { format!(": {msg}") } else { String::new() }
),
ResponseTextError { address, err } => write!(f, "Failed to get body from response sent by '{address}' as text: {err}"),
ResponseParseError { address, raw, err } => {
write!(f, "Failed to parse response body '{raw}' sent by '{address}' as a delegate map: {err}")
},
}
}
}
impl Error for DelegatesError {}