[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