From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v5 proxmox-backup 2/5] api types: introduce `BackupArchiveName` type
Date: Fri, 22 Nov 2024 11:30:08 +0100 [thread overview]
Message-ID: <20241122103011.165010-3-c.ebner@proxmox.com> (raw)
In-Reply-To: <20241122103011.165010-1-c.ebner@proxmox.com>
Introduces a dedicated wrapper type to be used for backup archive
names instead of plain strings and associated helper methods for
archive type checks and archive name mappings.
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
changes since version 4:
- rebased onto current master
pbs-api-types/src/datastore.rs | 153 ++++++++++++++++++++++++++++++++-
1 file changed, 152 insertions(+), 1 deletion(-)
diff --git a/pbs-api-types/src/datastore.rs b/pbs-api-types/src/datastore.rs
index 3b9c206db..105984554 100644
--- a/pbs-api-types/src/datastore.rs
+++ b/pbs-api-types/src/datastore.rs
@@ -1,5 +1,7 @@
+use std::convert::{AsRef, TryFrom};
use std::fmt;
use std::path::{Path, PathBuf};
+use std::str::FromStr;
use anyhow::{bail, format_err, Error};
use const_format::concatcp;
@@ -1645,7 +1647,7 @@ impl BackupGroupDeleteStats {
}
}
-#[derive(PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
/// Allowed variants of backup archives to be contained in a snapshot's manifest
pub enum ArchiveType {
FixedIndex,
@@ -1664,4 +1666,153 @@ impl ArchiveType {
};
Ok(archive_type)
}
+
+ pub fn extension(&self) -> &'static str {
+ match self {
+ ArchiveType::DynamicIndex => "didx",
+ ArchiveType::FixedIndex => "fidx",
+ ArchiveType::Blob => "blob",
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq)]
+/// Name of archive files contained in snapshot's manifest
+pub struct BackupArchiveName {
+ // archive name including the `.fidx`, `.didx` or `.blob` archive type extension
+ name: String,
+ // archive type parsed based on given extension
+ ty: ArchiveType,
+}
+
+impl fmt::Display for BackupArchiveName {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{name}", name = self.name)
+ }
+}
+
+serde_plain::derive_deserialize_from_fromstr!(BackupArchiveName, "archive name");
+
+impl FromStr for BackupArchiveName {
+ type Err = Error;
+
+ fn from_str(name: &str) -> Result<Self, Self::Err> {
+ Self::try_from(name)
+ }
+}
+
+serde_plain::derive_serialize_from_display!(BackupArchiveName);
+
+impl TryFrom<&str> for BackupArchiveName {
+ type Error = anyhow::Error;
+
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
+ let (name, ty) = Self::parse_archive_type(value)?;
+ Ok(Self { name, ty })
+ }
+}
+
+impl AsRef<str> for BackupArchiveName {
+ fn as_ref(&self) -> &str {
+ &self.name
+ }
+}
+
+impl BackupArchiveName {
+ pub fn from_path(path: impl AsRef<Path>) -> Result<Self, Error> {
+ let path = path.as_ref();
+ if path.as_os_str().as_encoded_bytes().last() == Some(&b'/') {
+ bail!("invalid archive name, got directory");
+ }
+ let file_name = path
+ .file_name()
+ .ok_or_else(|| format_err!("invalid archive name"))?;
+ let name = file_name
+ .to_str()
+ .ok_or_else(|| format_err!("archive name not valid UTF-8"))?;
+
+ Self::try_from(name)
+ }
+
+ pub fn catalog() -> Self {
+ // Note: .pcat1 => Proxmox Catalog Format version 1
+ Self {
+ name: "catalog.pcat1.didx".to_string(),
+ ty: ArchiveType::DynamicIndex,
+ }
+ }
+
+ pub fn manifest() -> Self {
+ Self {
+ name: "index.json.blob".to_string(),
+ ty: ArchiveType::Blob,
+ }
+ }
+
+ pub fn client_log() -> Self {
+ Self {
+ name: "client.log.blob".to_string(),
+ ty: ArchiveType::Blob,
+ }
+ }
+
+ pub fn encrypted_key() -> Self {
+ Self {
+ name: "rsa-encrypted.key.blob".to_string(),
+ ty: ArchiveType::Blob,
+ }
+ }
+
+ pub fn archive_type(&self) -> ArchiveType {
+ self.ty.clone()
+ }
+
+ pub fn ends_with(&self, postfix: &str) -> bool {
+ self.name.ends_with(postfix)
+ }
+
+ pub fn has_pxar_filename_extension(&self) -> bool {
+ self.name.ends_with(".pxar.didx")
+ || self.name.ends_with(".mpxar.didx")
+ || self.name.ends_with(".ppxar.didx")
+ }
+
+ pub fn without_type_extension(&self) -> String {
+ self.name
+ .strip_suffix(&format!(".{ext}", ext = self.ty.extension()))
+ .unwrap()
+ .into()
+ }
+
+ fn parse_archive_type(archive_name: &str) -> Result<(String, ArchiveType), Error> {
+ // Detect archive type via given server archive name type extension, if present
+ if let Ok(archive_type) = ArchiveType::from_path(archive_name) {
+ return Ok((archive_name.into(), archive_type));
+ }
+
+ // No server archive name type extension in archive name, map based on extension
+ let archive_type = match Path::new(archive_name)
+ .extension()
+ .and_then(|ext| ext.to_str())
+ {
+ Some("pxar") => ArchiveType::DynamicIndex,
+ Some("mpxar") => ArchiveType::DynamicIndex,
+ Some("ppxar") => ArchiveType::DynamicIndex,
+ Some("pcat1") => ArchiveType::DynamicIndex,
+ Some("img") => ArchiveType::FixedIndex,
+ Some("json") => ArchiveType::Blob,
+ Some("key") => ArchiveType::Blob,
+ Some("log") => ArchiveType::Blob,
+ _ => bail!("failed to parse archive type for '{archive_name}'"),
+ };
+
+ Ok((
+ format!("{archive_name}.{ext}", ext = archive_type.extension()),
+ archive_type,
+ ))
+ }
+}
+
+impl ApiType for BackupArchiveName {
+ const API_SCHEMA: Schema = BACKUP_ARCHIVE_NAME_SCHEMA;
}
--
2.39.5
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
next prev parent reply other threads:[~2024-11-22 10:30 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-22 10:30 [pbs-devel] [PATCH v5 proxmox-backup 0/5] introduce dedcated archive name api type Christian Ebner
2024-11-22 10:30 ` [pbs-devel] [PATCH v5 proxmox-backup 1/5] datastore: move `ArchiveType` to api types Christian Ebner
2024-11-22 10:30 ` Christian Ebner [this message]
2024-11-22 10:30 ` [pbs-devel] [PATCH v5 proxmox-backup 3/5] client/server: use dedicated api type for all archive names Christian Ebner
2024-11-22 10:30 ` [pbs-devel] [PATCH v5 proxmox-backup 4/5] client: drop unused parse_archive_type helper Christian Ebner
2024-11-22 10:30 ` [pbs-devel] [PATCH v5 proxmox-backup 5/5] api types: add unit tests for backup archive name parsing Christian Ebner
2024-11-22 12:49 ` [pbs-devel] applied-series: [PATCH v5 proxmox-backup 0/5] introduce dedcated archive name api type Fabian Grünbichler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241122103011.165010-3-c.ebner@proxmox.com \
--to=c.ebner@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.