solana/runtime/src/snapshot_utils/archive_format.rs

177 lines
5.4 KiB
Rust

use {
std::{fmt, str::FromStr},
strum::Display,
};
pub const SUPPORTED_ARCHIVE_COMPRESSION: &[&str] = &["bz2", "gzip", "zstd", "lz4", "tar", "none"];
pub const DEFAULT_ARCHIVE_COMPRESSION: &str = "zstd";
pub const TAR_BZIP2_EXTENSION: &str = "tar.bz2";
pub const TAR_GZIP_EXTENSION: &str = "tar.gz";
pub const TAR_ZSTD_EXTENSION: &str = "tar.zst";
pub const TAR_LZ4_EXTENSION: &str = "tar.lz4";
pub const TAR_EXTENSION: &str = "tar";
/// The different archive formats used for snapshots
#[derive(Copy, Clone, Debug, Eq, PartialEq, Display)]
pub enum ArchiveFormat {
TarBzip2,
TarGzip,
TarZstd,
TarLz4,
Tar,
}
impl ArchiveFormat {
/// Get the file extension for the ArchiveFormat
pub fn extension(&self) -> &str {
match self {
ArchiveFormat::TarBzip2 => TAR_BZIP2_EXTENSION,
ArchiveFormat::TarGzip => TAR_GZIP_EXTENSION,
ArchiveFormat::TarZstd => TAR_ZSTD_EXTENSION,
ArchiveFormat::TarLz4 => TAR_LZ4_EXTENSION,
ArchiveFormat::Tar => TAR_EXTENSION,
}
}
pub fn from_cli_arg(archive_format_str: &str) -> Option<ArchiveFormat> {
match archive_format_str {
"bz2" => Some(ArchiveFormat::TarBzip2),
"gzip" => Some(ArchiveFormat::TarGzip),
"zstd" => Some(ArchiveFormat::TarZstd),
"lz4" => Some(ArchiveFormat::TarLz4),
"tar" | "none" => Some(ArchiveFormat::Tar),
_ => None,
}
}
}
// Change this to `impl<S: AsRef<str>> TryFrom<S> for ArchiveFormat [...]`
// once this Rust bug is fixed: https://github.com/rust-lang/rust/issues/50133
impl TryFrom<&str> for ArchiveFormat {
type Error = ParseError;
fn try_from(extension: &str) -> Result<Self, Self::Error> {
match extension {
TAR_BZIP2_EXTENSION => Ok(ArchiveFormat::TarBzip2),
TAR_GZIP_EXTENSION => Ok(ArchiveFormat::TarGzip),
TAR_ZSTD_EXTENSION => Ok(ArchiveFormat::TarZstd),
TAR_LZ4_EXTENSION => Ok(ArchiveFormat::TarLz4),
TAR_EXTENSION => Ok(ArchiveFormat::Tar),
_ => Err(ParseError::InvalidExtension(extension.to_string())),
}
}
}
impl FromStr for ArchiveFormat {
type Err = ParseError;
fn from_str(extension: &str) -> Result<Self, Self::Err> {
Self::try_from(extension)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ParseError {
InvalidExtension(String),
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ParseError::InvalidExtension(extension) => {
write!(f, "Invalid archive extension: {extension}")
}
}
}
}
#[cfg(test)]
mod tests {
use {super::*, std::iter::zip};
const INVALID_EXTENSION: &str = "zip";
#[test]
fn test_extension() {
assert_eq!(ArchiveFormat::TarBzip2.extension(), TAR_BZIP2_EXTENSION);
assert_eq!(ArchiveFormat::TarGzip.extension(), TAR_GZIP_EXTENSION);
assert_eq!(ArchiveFormat::TarZstd.extension(), TAR_ZSTD_EXTENSION);
assert_eq!(ArchiveFormat::TarLz4.extension(), TAR_LZ4_EXTENSION);
assert_eq!(ArchiveFormat::Tar.extension(), TAR_EXTENSION);
}
#[test]
fn test_try_from() {
assert_eq!(
ArchiveFormat::try_from(TAR_BZIP2_EXTENSION),
Ok(ArchiveFormat::TarBzip2)
);
assert_eq!(
ArchiveFormat::try_from(TAR_GZIP_EXTENSION),
Ok(ArchiveFormat::TarGzip)
);
assert_eq!(
ArchiveFormat::try_from(TAR_ZSTD_EXTENSION),
Ok(ArchiveFormat::TarZstd)
);
assert_eq!(
ArchiveFormat::try_from(TAR_LZ4_EXTENSION),
Ok(ArchiveFormat::TarLz4)
);
assert_eq!(
ArchiveFormat::try_from(TAR_EXTENSION),
Ok(ArchiveFormat::Tar)
);
assert_eq!(
ArchiveFormat::try_from(INVALID_EXTENSION),
Err(ParseError::InvalidExtension(INVALID_EXTENSION.to_string()))
);
}
#[test]
fn test_from_str() {
assert_eq!(
ArchiveFormat::from_str(TAR_BZIP2_EXTENSION),
Ok(ArchiveFormat::TarBzip2)
);
assert_eq!(
ArchiveFormat::from_str(TAR_GZIP_EXTENSION),
Ok(ArchiveFormat::TarGzip)
);
assert_eq!(
ArchiveFormat::from_str(TAR_ZSTD_EXTENSION),
Ok(ArchiveFormat::TarZstd)
);
assert_eq!(
ArchiveFormat::from_str(TAR_LZ4_EXTENSION),
Ok(ArchiveFormat::TarLz4)
);
assert_eq!(
ArchiveFormat::from_str(TAR_EXTENSION),
Ok(ArchiveFormat::Tar)
);
assert_eq!(
ArchiveFormat::from_str(INVALID_EXTENSION),
Err(ParseError::InvalidExtension(INVALID_EXTENSION.to_string()))
);
}
#[test]
fn test_from_cli_arg() {
let golden = [
Some(ArchiveFormat::TarBzip2),
Some(ArchiveFormat::TarGzip),
Some(ArchiveFormat::TarZstd),
Some(ArchiveFormat::TarLz4),
Some(ArchiveFormat::Tar),
Some(ArchiveFormat::Tar),
];
for (arg, expected) in zip(SUPPORTED_ARCHIVE_COMPRESSION.iter(), golden.into_iter()) {
assert_eq!(ArchiveFormat::from_cli_arg(arg), expected);
}
assert_eq!(ArchiveFormat::from_cli_arg("bad"), None);
}
}