[pbs-devel] applied-series: [PATCH proxmox 1/6] apt-api-types: new crate

Wolfgang Bumiller w.bumiller at proxmox.com
Tue Jul 9 08:18:27 CEST 2024


From: Dietmar Maurer <dietmar at proxmox.com>

Signed-off-by: Dietmar Maurer <dietmar at proxmox.com>
---
 Cargo.toml                                 |   2 +
 proxmox-apt-api-types/Cargo.toml           |  15 +
 proxmox-apt-api-types/debian/changelog     |   5 +
 proxmox-apt-api-types/debian/control       |  42 ++
 proxmox-apt-api-types/debian/copyright     |  18 +
 proxmox-apt-api-types/debian/debcargo.toml |   7 +
 proxmox-apt-api-types/src/lib.rs           | 442 +++++++++++++++++++++
 7 files changed, 531 insertions(+)
 create mode 100644 proxmox-apt-api-types/Cargo.toml
 create mode 100644 proxmox-apt-api-types/debian/changelog
 create mode 100644 proxmox-apt-api-types/debian/control
 create mode 100644 proxmox-apt-api-types/debian/copyright
 create mode 100644 proxmox-apt-api-types/debian/debcargo.toml
 create mode 100644 proxmox-apt-api-types/src/lib.rs

diff --git a/Cargo.toml b/Cargo.toml
index 48fa77b6..15556670 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,6 +5,7 @@ members = [
     "proxmox-acme-api",
     "proxmox-api-macro",
     "proxmox-apt",
+    "proxmox-apt-api-types",
     "proxmox-async",
     "proxmox-auth-api",
     "proxmox-borrow",
@@ -111,6 +112,7 @@ zstd = { version = "0.12", features = [ "bindgen" ] }
 # workspace dependencies
 proxmox-acme = {  version = "0.5.2", path = "proxmox-acme", default-features = false }
 proxmox-api-macro = { version = "1.0.8", path = "proxmox-api-macro" }
+proxmox-apt-api-types = { version = "1.0.0", path = "proxmox-apt-api-types" }
 proxmox-auth-api = { version = "0.4.0", path = "proxmox-auth-api" }
 proxmox-async = { version = "0.4.1", path = "proxmox-async" }
 proxmox-compression = { version = "0.2.0", path = "proxmox-compression" }
diff --git a/proxmox-apt-api-types/Cargo.toml b/proxmox-apt-api-types/Cargo.toml
new file mode 100644
index 00000000..e2ab46ad
--- /dev/null
+++ b/proxmox-apt-api-types/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "proxmox-apt-api-types"
+version = "1.0.0"
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+exclude.workspace = true
+description = "APT API type definitions."
+
+[dependencies]
+anyhow.workspace = true
+serde = { workspace = true, features = ["derive"] }
+proxmox-schema = { workspace = true, features = ["api-macro"] }
+proxmox-config-digest.workspace = true
diff --git a/proxmox-apt-api-types/debian/changelog b/proxmox-apt-api-types/debian/changelog
new file mode 100644
index 00000000..32221867
--- /dev/null
+++ b/proxmox-apt-api-types/debian/changelog
@@ -0,0 +1,5 @@
+rust-proxmox-apt-api-types (1.0.0-1) bookworm; urgency=medium
+
+  * initial release
+
+ -- Proxmox Support Team <support at proxmox.com>  Thu, 27 Jun 2024 13:14:23 +0200
diff --git a/proxmox-apt-api-types/debian/control b/proxmox-apt-api-types/debian/control
new file mode 100644
index 00000000..708e8c4b
--- /dev/null
+++ b/proxmox-apt-api-types/debian/control
@@ -0,0 +1,42 @@
+Source: rust-proxmox-apt-api-types
+Section: rust
+Priority: optional
+Build-Depends: debhelper (>= 12),
+ dh-cargo (>= 25),
+ cargo:native <!nocheck>,
+ rustc:native <!nocheck>,
+ libstd-rust-dev <!nocheck>,
+ librust-anyhow-1+default-dev <!nocheck>,
+ librust-proxmox-config-digest-0.1+default-dev <!nocheck>,
+ librust-proxmox-schema-3+api-macro-dev (>= 3.1.1-~~) <!nocheck>,
+ librust-proxmox-schema-3+default-dev (>= 3.1.1-~~) <!nocheck>,
+ librust-serde-1+default-dev <!nocheck>,
+ librust-serde-1+derive-dev <!nocheck>
+Maintainer: Proxmox Support Team <support at proxmox.com>
+Standards-Version: 4.6.2
+Vcs-Git: git://git.proxmox.com/git/proxmox-apt.git
+Vcs-Browser: https://git.proxmox.com/?p=proxmox-apt.git
+X-Cargo-Crate: proxmox-apt-api-types
+Rules-Requires-Root: no
+
+Package: librust-proxmox-apt-api-types-dev
+Architecture: any
+Multi-Arch: same
+Depends:
+ ${misc:Depends},
+ librust-anyhow-1+default-dev,
+ librust-proxmox-config-digest-0.1+default-dev,
+ librust-proxmox-schema-3+api-macro-dev (>= 3.1.1-~~),
+ librust-proxmox-schema-3+default-dev (>= 3.1.1-~~),
+ librust-serde-1+default-dev,
+ librust-serde-1+derive-dev
+Provides:
+ librust-proxmox-apt-api-types+default-dev (= ${binary:Version}),
+ librust-proxmox-apt-api-types-1-dev (= ${binary:Version}),
+ librust-proxmox-apt-api-types-1+default-dev (= ${binary:Version}),
+ librust-proxmox-apt-api-types-1.0-dev (= ${binary:Version}),
+ librust-proxmox-apt-api-types-1.0+default-dev (= ${binary:Version}),
+ librust-proxmox-apt-api-types-1.0.0-dev (= ${binary:Version}),
+ librust-proxmox-apt-api-types-1.0.0+default-dev (= ${binary:Version})
+Description: APT API type definitions - Rust source code
+ Source code for Debianized Rust crate "proxmox-apt-api-types"
diff --git a/proxmox-apt-api-types/debian/copyright b/proxmox-apt-api-types/debian/copyright
new file mode 100644
index 00000000..b227c290
--- /dev/null
+++ b/proxmox-apt-api-types/debian/copyright
@@ -0,0 +1,18 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files:
+ *
+Copyright: 2019 - 2024 Proxmox Server Solutions GmbH <support at proxmox.com>
+License: AGPL-3.0-or-later
+ This program is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option) any
+ later version.
+ .
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU Affero General Public License along
+ with this program. If not, see <https://www.gnu.org/licenses/>.
diff --git a/proxmox-apt-api-types/debian/debcargo.toml b/proxmox-apt-api-types/debian/debcargo.toml
new file mode 100644
index 00000000..74e38540
--- /dev/null
+++ b/proxmox-apt-api-types/debian/debcargo.toml
@@ -0,0 +1,7 @@
+overlay = "."
+crate_src_path = ".."
+maintainer = "Proxmox Support Team <support at proxmox.com>"
+
+[source]
+vcs_git = "git://git.proxmox.com/git/proxmox-apt.git"
+vcs_browser = "https://git.proxmox.com/?p=proxmox-apt.git"
diff --git a/proxmox-apt-api-types/src/lib.rs b/proxmox-apt-api-types/src/lib.rs
new file mode 100644
index 00000000..3b6ac9e4
--- /dev/null
+++ b/proxmox-apt-api-types/src/lib.rs
@@ -0,0 +1,442 @@
+use std::fmt::Display;
+
+use anyhow::{bail, Error};
+use serde::{Deserialize, Serialize};
+
+use proxmox_config_digest::ConfigDigest;
+use proxmox_schema::api;
+
+#[api]
+#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "lowercase")]
+pub enum APTRepositoryFileType {
+    /// One-line-style format
+    List,
+    /// DEB822-style format
+    Sources,
+}
+
+impl TryFrom<&str> for APTRepositoryFileType {
+    type Error = Error;
+
+    fn try_from(file_type: &str) -> Result<Self, Error> {
+        match file_type {
+            "list" => Ok(APTRepositoryFileType::List),
+            "sources" => Ok(APTRepositoryFileType::Sources),
+            _ => bail!("invalid file type '{file_type}'"),
+        }
+    }
+}
+
+impl Display for APTRepositoryFileType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            APTRepositoryFileType::List => write!(f, "list"),
+            APTRepositoryFileType::Sources => write!(f, "sources"),
+        }
+    }
+}
+
+#[api]
+#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub enum APTRepositoryPackageType {
+    /// Debian package
+    Deb,
+    /// Debian source package
+    DebSrc,
+}
+
+impl TryFrom<&str> for APTRepositoryPackageType {
+    type Error = Error;
+
+    fn try_from(package_type: &str) -> Result<Self, Error> {
+        match package_type {
+            "deb" => Ok(APTRepositoryPackageType::Deb),
+            "deb-src" => Ok(APTRepositoryPackageType::DebSrc),
+            _ => bail!("invalid package type '{package_type}'"),
+        }
+    }
+}
+
+impl Display for APTRepositoryPackageType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            APTRepositoryPackageType::Deb => write!(f, "deb"),
+            APTRepositoryPackageType::DebSrc => write!(f, "deb-src"),
+        }
+    }
+}
+
+#[api(
+    properties: {
+        Key: {
+            description: "Option key.",
+            type: String,
+        },
+        Values: {
+            description: "Option values.",
+            type: Array,
+            items: {
+                description: "Value.",
+                type: String,
+            },
+        },
+    },
+)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")] // for consistency
+/// Additional options for an APT repository.
+/// Used for both single- and mutli-value options.
+pub struct APTRepositoryOption {
+    /// Option key.
+    pub key: String,
+    /// Option value(s).
+    pub values: Vec<String>,
+}
+
+#[api(
+    properties: {
+        Types: {
+            description: "List of package types.",
+            type: Array,
+            items: {
+                type: APTRepositoryPackageType,
+            },
+        },
+        URIs: {
+            description: "List of repository URIs.",
+            type: Array,
+            items: {
+                description: "Repository URI.",
+                type: String,
+            },
+        },
+        Suites: {
+            description: "List of distributions.",
+            type: Array,
+            items: {
+                description: "Package distribution.",
+                type: String,
+            },
+        },
+        Components: {
+            description: "List of repository components.",
+            type: Array,
+            items: {
+                description: "Repository component.",
+                type: String,
+            },
+        },
+        Options: {
+            type: Array,
+            optional: true,
+            items: {
+                type: APTRepositoryOption,
+            },
+        },
+        Comment: {
+            description: "Associated comment.",
+            type: String,
+            optional: true,
+        },
+        FileType: {
+            type: APTRepositoryFileType,
+        },
+        Enabled: {
+            description: "Whether the repository is enabled or not.",
+            type: Boolean,
+        },
+    },
+)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+/// Describes an APT repository.
+pub struct APTRepository {
+    /// List of package types.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub types: Vec<APTRepositoryPackageType>,
+
+    /// List of repository URIs.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    #[serde(rename = "URIs")]
+    pub uris: Vec<String>,
+
+    /// List of package distributions.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub suites: Vec<String>,
+
+    /// List of repository components.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub components: Vec<String>,
+
+    /// Additional options.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub options: Vec<APTRepositoryOption>,
+
+    /// Associated comment.
+    #[serde(default, skip_serializing_if = "String::is_empty")]
+    pub comment: String,
+
+    /// Format of the defining file.
+    pub file_type: APTRepositoryFileType,
+
+    /// Whether the repository is enabled or not.
+    pub enabled: bool,
+}
+
+#[api(
+    properties: {
+        "file-type": {
+            type: APTRepositoryFileType,
+        },
+        repositories: {
+            description: "List of APT repositories.",
+            type: Array,
+            items: {
+                type: APTRepository,
+            },
+        },
+        digest: {
+            type: ConfigDigest,
+            optional: true,
+        },
+    },
+)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Represents an abstract APT repository file.
+pub struct APTRepositoryFile {
+    /// The path to the file. If None, `contents` must be set directly.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub path: Option<String>,
+
+    /// The type of the file.
+    pub file_type: APTRepositoryFileType,
+
+    /// List of repositories in the file.
+    pub repositories: Vec<APTRepository>,
+
+    /// The file content, if already parsed.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub content: Option<String>,
+
+    /// Digest of the original contents.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub digest: Option<ConfigDigest>,
+}
+
+#[api]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Error type for problems with APT repository files.
+pub struct APTRepositoryFileError {
+    /// The path to the problematic file.
+    pub path: String,
+
+    /// The error message.
+    pub error: String,
+}
+
+impl Display for APTRepositoryFileError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "proxmox-apt error for '{}' - {}", self.path, self.error)
+    }
+}
+
+impl std::error::Error for APTRepositoryFileError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        None
+    }
+}
+
+#[api]
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Additional information for a repository.
+pub struct APTRepositoryInfo {
+    /// Path to the defining file.
+    #[serde(default, skip_serializing_if = "String::is_empty")]
+    pub path: String,
+
+    /// Index of the associated respository within the file (starting from 0).
+    pub index: usize,
+
+    /// The property from which the info originates (e.g. "Suites")
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub property: Option<String>,
+
+    /// Info kind (e.g. "warning")
+    pub kind: String,
+
+    /// Info message
+    pub message: String,
+}
+
+#[api(
+    properties: {
+        handle: {
+            description: "Handle referencing a standard repository.",
+            type: String,
+        },
+    },
+)]
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+/// Reference to a standard repository and configuration status.
+pub struct APTStandardRepository {
+    /// Handle referencing a standard repository.
+    pub handle: APTRepositoryHandle,
+
+    /// Configuration status of the associated repository, where `None` means
+    /// not configured, and `Some(bool)` indicates enabled or disabled.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub status: Option<bool>,
+
+    /// Display name of the repository.
+    pub name: String,
+
+    /// Description of the repository.
+    pub description: String,
+}
+
+#[api]
+#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+/// Handles for Proxmox repositories.
+pub enum APTRepositoryHandle {
+    /// The enterprise repository for production use.
+    Enterprise,
+    /// The repository that can be used without subscription.
+    NoSubscription,
+    /// The test repository.
+    Test,
+    /// Ceph Quincy enterprise repository.
+    CephQuincyEnterprise,
+    /// Ceph Quincy no-subscription repository.
+    CephQuincyNoSubscription,
+    /// Ceph Quincy test repository.
+    CephQuincyTest,
+    // TODO: Add separate enum for ceph releases and use something like
+    // `CephTest(CephReleaseCodename),` once the API macro supports it.
+    /// Ceph Reef enterprise repository.
+    CephReefEnterprise,
+    /// Ceph Reef no-subscription repository.
+    CephReefNoSubscription,
+    /// Ceph Reef test repository.
+    CephReefTest,
+}
+
+#[api()]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+/// Describes a package for which an update is available.
+pub struct APTUpdateInfo {
+    /// Package name
+    pub package: String,
+    /// Package title
+    pub title: String,
+    /// Package architecture
+    pub arch: String,
+    /// Human readable package description
+    pub description: String,
+    /// New version to be updated to
+    pub version: String,
+    /// Old version currently installed
+    pub old_version: String,
+    /// Package origin
+    pub origin: String,
+    /// Package priority in human-readable form
+    pub priority: String,
+    /// Package section
+    pub section: String,
+    /// Custom extra field for additional package information
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub extra_info: Option<String>,
+}
+
+#[api(
+    properties: {
+        notify: {
+            default: false,
+            optional: true,
+        },
+        quiet: {
+            default: false,
+            optional: true,
+        },
+    }
+)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+/// Options for APT update
+pub struct APTUpdateOptions {
+    /// Send notification mail about new package updates available to the email
+    /// address configured for 'root at pam').
+    pub notify: Option<bool>,
+    /// Only produces output suitable for logging, omitting progress indicators.
+    pub quiet: Option<bool>,
+}
+
+#[api(
+    properties: {
+        files: {
+            type: Array,
+            items: {
+                type: APTRepositoryFile,
+            },
+        },
+        errors: {
+            type: Array,
+            items: {
+                type: APTRepositoryFileError,
+            },
+        },
+        infos: {
+            type: Array,
+            items: {
+                type: APTRepositoryInfo,
+            },
+        },
+        "standard-repos": {
+            type: Array,
+            items: {
+                type: APTStandardRepository,
+            },
+        },
+        digest: {
+            type: ConfigDigest,
+        },
+    },
+)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Result from parsing the APT repository files in /etc/apt/.
+pub struct APTRepositoriesResult {
+    /// List of problematic files.
+    pub errors: Vec<APTRepositoryFileError>,
+    /// List of standard repositories and their configuration status.
+    pub standard_repos: Vec<APTStandardRepository>,
+    /// List of additional information/warnings about the repositories
+    pub infos: Vec<APTRepositoryInfo>,
+    /// List of parsed repository files.
+    pub files: Vec<APTRepositoryFile>,
+    pub digest: ConfigDigest,
+}
+
+#[api()]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+/// Options for the get changelog API.
+pub struct APTGetChangelogOptions {
+    /// Package name to get changelog of.
+    pub name: String,
+    /// Package version to get changelog of. Omit to use candidate version.
+    pub version: Option<String>,
+}
+
+#[api()]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+/// Options for the change repository API call
+pub struct APTChangeRepositoryOptions {
+    /// Whether the repository should be enabled or not.
+    pub enabled: Option<bool>,
+}
-- 
2.39.2





More information about the pbs-devel mailing list