2025-07-21 22:02:05 +02:00
|
|
|
// This Source Code Form is subject to the terms of
|
|
|
|
|
// the Mozilla Public License, v. 2.0. If a copy of the
|
|
|
|
|
// MPL was not distributed with this file, You can
|
|
|
|
|
// obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
2025-07-27 15:22:49 +02:00
|
|
|
use miette::Diagnostic;
|
2025-07-21 22:02:05 +02:00
|
|
|
use std::collections::HashMap;
|
2025-07-26 15:33:39 +02:00
|
|
|
use std::io;
|
2025-12-08 23:13:27 +01:00
|
|
|
use std::path::{Path, PathBuf, StripPrefixError};
|
2025-07-26 15:33:39 +02:00
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
|
/// Result type for repository operations
|
|
|
|
|
pub type Result<T> = std::result::Result<T, RepositoryError>;
|
|
|
|
|
|
|
|
|
|
/// Errors that can occur in repository operations
|
2026-01-18 14:30:05 +01:00
|
|
|
#[allow(clippy::result_large_err)]
|
2025-07-26 15:33:39 +02:00
|
|
|
#[derive(Debug, Error, Diagnostic)]
|
|
|
|
|
pub enum RepositoryError {
|
|
|
|
|
#[error("unsupported repository version: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::unsupported_version),
|
|
|
|
|
help("Supported repository versions: 4")
|
|
|
|
|
)]
|
|
|
|
|
UnsupportedVersion(u32),
|
|
|
|
|
|
|
|
|
|
#[error("repository not found at {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::not_found),
|
|
|
|
|
help("Check that the repository path exists and is accessible")
|
|
|
|
|
)]
|
|
|
|
|
NotFound(String),
|
|
|
|
|
|
|
|
|
|
#[error("publisher {0} not found")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::publisher_not_found),
|
|
|
|
|
help("Check that the publisher name is correct and exists in the repository")
|
|
|
|
|
)]
|
|
|
|
|
PublisherNotFound(String),
|
|
|
|
|
|
|
|
|
|
#[error("publisher {0} already exists")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::publisher_exists),
|
|
|
|
|
help("Use a different publisher name or remove the existing publisher first")
|
|
|
|
|
)]
|
|
|
|
|
PublisherExists(String),
|
|
|
|
|
|
|
|
|
|
#[error("failed to read repository configuration: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::config_read),
|
|
|
|
|
help("Check that the repository configuration file exists and is valid")
|
|
|
|
|
)]
|
|
|
|
|
ConfigReadError(String),
|
|
|
|
|
|
|
|
|
|
#[error("failed to write repository configuration: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::config_write),
|
|
|
|
|
help("Check that the repository directory is writable")
|
|
|
|
|
)]
|
|
|
|
|
ConfigWriteError(String),
|
|
|
|
|
|
2025-12-08 23:13:27 +01:00
|
|
|
#[error("failed to create directory {path}: {source}")]
|
2025-07-26 15:33:39 +02:00
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::directory_create),
|
|
|
|
|
help("Check that the parent directory exists and is writable")
|
|
|
|
|
)]
|
2025-12-08 23:13:27 +01:00
|
|
|
DirectoryCreateError {
|
|
|
|
|
path: PathBuf,
|
|
|
|
|
#[source]
|
|
|
|
|
source: io::Error,
|
|
|
|
|
},
|
2025-07-26 15:33:39 +02:00
|
|
|
|
2025-12-08 23:13:27 +01:00
|
|
|
#[error("failed to read file {path}: {source}")]
|
2025-07-26 15:33:39 +02:00
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::file_read),
|
|
|
|
|
help("Check that the file exists and is readable")
|
|
|
|
|
)]
|
2025-12-08 23:13:27 +01:00
|
|
|
FileReadError {
|
|
|
|
|
path: PathBuf,
|
|
|
|
|
#[source]
|
|
|
|
|
source: io::Error,
|
|
|
|
|
},
|
2025-07-26 15:33:39 +02:00
|
|
|
|
2025-12-08 23:13:27 +01:00
|
|
|
#[error("failed to write file {path}: {source}")]
|
2025-07-26 15:33:39 +02:00
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::file_write),
|
|
|
|
|
help("Check that the directory is writable")
|
|
|
|
|
)]
|
2025-12-08 23:13:27 +01:00
|
|
|
FileWriteError {
|
|
|
|
|
path: PathBuf,
|
|
|
|
|
#[source]
|
|
|
|
|
source: io::Error,
|
|
|
|
|
},
|
2025-07-26 15:33:39 +02:00
|
|
|
|
|
|
|
|
#[error("failed to parse JSON: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::json_parse),
|
|
|
|
|
help("Check that the JSON file is valid")
|
|
|
|
|
)]
|
|
|
|
|
JsonParseError(String),
|
|
|
|
|
|
|
|
|
|
#[error("failed to serialize JSON: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::json_serialize),
|
|
|
|
|
help("This is likely a bug in the code")
|
|
|
|
|
)]
|
|
|
|
|
JsonSerializeError(String),
|
|
|
|
|
|
|
|
|
|
#[error("I/O error: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::io),
|
|
|
|
|
help("Check system resources and permissions")
|
|
|
|
|
)]
|
|
|
|
|
IoError(#[from] io::Error),
|
|
|
|
|
|
|
|
|
|
#[error("other error: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::other),
|
|
|
|
|
help("See error message for details")
|
|
|
|
|
)]
|
|
|
|
|
Other(String),
|
|
|
|
|
|
|
|
|
|
#[error("JSON error: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::json_error),
|
|
|
|
|
help("Check the JSON format and try again")
|
|
|
|
|
)]
|
|
|
|
|
JsonError(String),
|
|
|
|
|
|
|
|
|
|
#[error("digest error: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::digest_error),
|
|
|
|
|
help("Check the digest format and try again")
|
|
|
|
|
)]
|
|
|
|
|
DigestError(String),
|
|
|
|
|
|
|
|
|
|
#[error(transparent)]
|
|
|
|
|
#[diagnostic(transparent)]
|
|
|
|
|
ActionError(#[from] ActionError),
|
|
|
|
|
|
|
|
|
|
#[error(transparent)]
|
|
|
|
|
#[diagnostic(transparent)]
|
2026-01-18 13:00:21 +01:00
|
|
|
CatalogError(Box<catalog::CatalogError>),
|
2025-07-26 15:33:39 +02:00
|
|
|
|
|
|
|
|
#[error("path prefix error: {0}")]
|
|
|
|
|
#[diagnostic(
|
|
|
|
|
code(ips::repository_error::path_prefix),
|
|
|
|
|
help("Check that the path is valid and within the expected directory")
|
|
|
|
|
)]
|
|
|
|
|
PathPrefixError(String),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Implement From for common error types
|
|
|
|
|
impl From<serde_json::Error> for RepositoryError {
|
|
|
|
|
fn from(err: serde_json::Error) -> Self {
|
|
|
|
|
RepositoryError::JsonError(err.to_string())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<DigestError> for RepositoryError {
|
|
|
|
|
fn from(err: DigestError) -> Self {
|
|
|
|
|
RepositoryError::DigestError(err.to_string())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<StripPrefixError> for RepositoryError {
|
|
|
|
|
fn from(err: StripPrefixError) -> Self {
|
|
|
|
|
RepositoryError::PathPrefixError(err.to_string())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 22:39:42 +01:00
|
|
|
// Implement From for rusqlite error types
|
|
|
|
|
impl From<rusqlite::Error> for RepositoryError {
|
|
|
|
|
fn from(err: rusqlite::Error) -> Self {
|
Introduce obsoleted package management system in IPS
- Add `obsoleted.rs` module to handle storing, metadata management, and operations for obsoleted packages.
- Implement commands for marking, listing, searching, restoring, exporting, and importing obsoleted packages (`pkg6repo`).
- Enhance `RepositoryError` with `From` implementations for various error types to manage database and serialization-related errors.
- Introduce reusable data structures for obsoleted package metadata and export representation.
- Update `Cargo.toml` and `Cargo.lock` to include new dependencies (`redb`, `bincode`, etc.).
- Document obsoleted package workflow and integration details in `doc/obsoleted_packages.md` for contributors.
- Refactor repository internals to integrate obsoleted package support without disrupting existing workflow.
- Add robust error handling, logging, and pagination for enhanced usability and scalability.
2025-07-29 16:16:12 +02:00
|
|
|
RepositoryError::Other(format!("Database error: {}", err))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-04 22:01:38 +02:00
|
|
|
pub mod catalog;
|
2025-12-09 12:49:25 +01:00
|
|
|
mod catalog_writer;
|
2025-12-22 20:10:17 +01:00
|
|
|
pub(crate) mod file_backend;
|
Introduce obsoleted package management system in IPS
- Add `obsoleted.rs` module to handle storing, metadata management, and operations for obsoleted packages.
- Implement commands for marking, listing, searching, restoring, exporting, and importing obsoleted packages (`pkg6repo`).
- Enhance `RepositoryError` with `From` implementations for various error types to manage database and serialization-related errors.
- Introduce reusable data structures for obsoleted package metadata and export representation.
- Update `Cargo.toml` and `Cargo.lock` to include new dependencies (`redb`, `bincode`, etc.).
- Document obsoleted package workflow and integration details in `doc/obsoleted_packages.md` for contributors.
- Refactor repository internals to integrate obsoleted package support without disrupting existing workflow.
- Add robust error handling, logging, and pagination for enhanced usability and scalability.
2025-07-29 16:16:12 +02:00
|
|
|
mod obsoleted;
|
2025-08-03 14:28:36 +02:00
|
|
|
pub mod progress;
|
2025-07-21 22:02:05 +02:00
|
|
|
mod rest_backend;
|
2026-02-04 22:39:42 +01:00
|
|
|
pub mod shard_sync;
|
|
|
|
|
pub mod sqlite_catalog;
|
2025-07-26 10:52:25 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests;
|
2025-07-21 22:02:05 +02:00
|
|
|
|
2025-07-26 15:33:39 +02:00
|
|
|
use crate::actions::ActionError;
|
|
|
|
|
use crate::digest::DigestError;
|
2025-07-27 15:22:49 +02:00
|
|
|
pub use catalog::{
|
|
|
|
|
CatalogAttrs, CatalogError, CatalogManager, CatalogOperationType, CatalogPart, UpdateLog,
|
|
|
|
|
};
|
2026-01-18 12:29:44 +01:00
|
|
|
pub use file_backend::{FileBackend, IndexEntry};
|
Introduce obsoleted package management system in IPS
- Add `obsoleted.rs` module to handle storing, metadata management, and operations for obsoleted packages.
- Implement commands for marking, listing, searching, restoring, exporting, and importing obsoleted packages (`pkg6repo`).
- Enhance `RepositoryError` with `From` implementations for various error types to manage database and serialization-related errors.
- Introduce reusable data structures for obsoleted package metadata and export representation.
- Update `Cargo.toml` and `Cargo.lock` to include new dependencies (`redb`, `bincode`, etc.).
- Document obsoleted package workflow and integration details in `doc/obsoleted_packages.md` for contributors.
- Refactor repository internals to integrate obsoleted package support without disrupting existing workflow.
- Add robust error handling, logging, and pagination for enhanced usability and scalability.
2025-07-29 16:16:12 +02:00
|
|
|
pub use obsoleted::{ObsoletedPackageManager, ObsoletedPackageMetadata};
|
2025-12-22 20:10:17 +01:00
|
|
|
pub use progress::{NoopProgressReporter, ProgressInfo, ProgressReporter};
|
2025-07-27 15:22:49 +02:00
|
|
|
pub use rest_backend::RestBackend;
|
2025-07-21 22:02:05 +02:00
|
|
|
|
|
|
|
|
/// Repository configuration filename
|
|
|
|
|
pub const REPOSITORY_CONFIG_FILENAME: &str = "pkg6.repository";
|
|
|
|
|
|
2025-12-09 14:23:55 +01:00
|
|
|
/// Options to control batched catalog rebuild behavior
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct BatchOptions {
|
|
|
|
|
/// Number of packages processed before flushing catalog parts to disk
|
|
|
|
|
pub batch_size: usize,
|
|
|
|
|
/// How many batches between fsync/flush points (reserved for future use)
|
|
|
|
|
pub flush_every_n: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for BatchOptions {
|
|
|
|
|
fn default() -> Self {
|
2025-12-22 20:10:17 +01:00
|
|
|
BatchOptions {
|
|
|
|
|
batch_size: 2000,
|
|
|
|
|
flush_every_n: 1,
|
|
|
|
|
}
|
2025-12-09 14:23:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-22 10:21:16 +02:00
|
|
|
/// Information about a publisher in a repository
|
2025-07-26 12:35:44 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
2025-07-22 10:21:16 +02:00
|
|
|
pub struct PublisherInfo {
|
|
|
|
|
/// Name of the publisher
|
|
|
|
|
pub name: String,
|
|
|
|
|
/// Number of packages from this publisher
|
|
|
|
|
pub package_count: usize,
|
|
|
|
|
/// Status of the publisher (e.g., "online", "offline")
|
|
|
|
|
pub status: String,
|
|
|
|
|
/// Last updated timestamp in ISO 8601 format
|
|
|
|
|
pub updated: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Information about a repository
|
2025-07-26 12:35:44 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
2025-07-22 10:21:16 +02:00
|
|
|
pub struct RepositoryInfo {
|
|
|
|
|
/// Information about publishers in the repository
|
|
|
|
|
pub publishers: Vec<PublisherInfo>,
|
2026-01-20 17:44:36 +01:00
|
|
|
/// Name of the default publisher, if any
|
|
|
|
|
pub default_publisher: Option<String>,
|
2025-07-22 10:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-22 11:57:24 +02:00
|
|
|
/// Information about a package in a repository
|
2025-07-26 12:35:44 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
2025-07-22 11:57:24 +02:00
|
|
|
pub struct PackageInfo {
|
2025-07-22 14:10:37 +02:00
|
|
|
/// FMRI (Fault Management Resource Identifier) of the package
|
|
|
|
|
pub fmri: crate::fmri::Fmri,
|
2025-07-22 11:57:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-23 22:39:49 +02:00
|
|
|
/// Contents of a package
|
2025-07-26 12:35:44 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
2025-07-23 22:39:49 +02:00
|
|
|
pub struct PackageContents {
|
|
|
|
|
/// Package identifier (name and version)
|
|
|
|
|
pub package_id: String,
|
|
|
|
|
/// Files in the package
|
|
|
|
|
pub files: Option<Vec<String>>,
|
|
|
|
|
/// Directories in the package
|
|
|
|
|
pub directories: Option<Vec<String>>,
|
|
|
|
|
/// Links in the package
|
|
|
|
|
pub links: Option<Vec<String>>,
|
|
|
|
|
/// Dependencies of the package
|
|
|
|
|
pub dependencies: Option<Vec<String>>,
|
|
|
|
|
/// Licenses in the package
|
|
|
|
|
pub licenses: Option<Vec<String>>,
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Repository version
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub enum RepositoryVersion {
|
|
|
|
|
V4 = 4,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for RepositoryVersion {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
RepositoryVersion::V4
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::convert::TryFrom<u32> for RepositoryVersion {
|
2025-07-26 15:33:39 +02:00
|
|
|
type Error = RepositoryError;
|
2025-07-21 22:02:05 +02:00
|
|
|
|
2025-07-26 15:33:39 +02:00
|
|
|
fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
|
2025-07-21 22:02:05 +02:00
|
|
|
match value {
|
|
|
|
|
4 => Ok(RepositoryVersion::V4),
|
2025-07-26 15:33:39 +02:00
|
|
|
_ => Err(RepositoryError::UnsupportedVersion(value)),
|
2025-07-21 22:02:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Repository configuration
|
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct RepositoryConfig {
|
|
|
|
|
pub version: RepositoryVersion,
|
|
|
|
|
pub publishers: Vec<String>,
|
|
|
|
|
pub properties: HashMap<String, String>,
|
2025-07-21 23:20:19 +02:00
|
|
|
pub default_publisher: Option<String>,
|
2025-07-21 22:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for RepositoryConfig {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
RepositoryConfig {
|
|
|
|
|
version: RepositoryVersion::default(),
|
|
|
|
|
publishers: Vec::new(),
|
|
|
|
|
properties: HashMap::new(),
|
2025-07-21 23:20:19 +02:00
|
|
|
default_publisher: None,
|
2025-07-21 22:02:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-26 10:34:45 +02:00
|
|
|
/// Repository trait for read-only operations
|
|
|
|
|
pub trait ReadableRepository {
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Open an existing repository
|
2025-07-26 12:54:01 +02:00
|
|
|
fn open<P: AsRef<Path>>(path: P) -> Result<Self>
|
|
|
|
|
where
|
|
|
|
|
Self: Sized;
|
|
|
|
|
|
2025-07-26 10:34:45 +02:00
|
|
|
/// Get repository information
|
|
|
|
|
fn get_info(&self) -> Result<RepositoryInfo>;
|
2025-07-26 12:54:01 +02:00
|
|
|
|
2025-07-26 10:34:45 +02:00
|
|
|
/// List packages in the repository
|
2025-07-26 12:54:01 +02:00
|
|
|
fn list_packages(
|
|
|
|
|
&self,
|
|
|
|
|
publisher: Option<&str>,
|
|
|
|
|
pattern: Option<&str>,
|
|
|
|
|
) -> Result<Vec<PackageInfo>>;
|
|
|
|
|
|
2025-07-26 10:34:45 +02:00
|
|
|
/// Show contents of packages
|
2025-07-26 12:54:01 +02:00
|
|
|
fn show_contents(
|
|
|
|
|
&self,
|
|
|
|
|
publisher: Option<&str>,
|
|
|
|
|
pattern: Option<&str>,
|
|
|
|
|
action_types: Option<&[String]>,
|
|
|
|
|
) -> Result<Vec<PackageContents>>;
|
|
|
|
|
|
2025-08-13 23:23:45 +02:00
|
|
|
/// Fetch a content payload identified by digest into the destination path.
|
|
|
|
|
/// Implementations should download/copy the payload to a temporary path,
|
|
|
|
|
/// verify integrity, and atomically move into `dest`.
|
2026-02-05 15:57:56 +01:00
|
|
|
fn fetch_payload(&self, publisher: &str, digest: &str, dest: &Path) -> Result<()>;
|
2025-08-13 23:23:45 +02:00
|
|
|
|
|
|
|
|
/// Fetch a package manifest by FMRI from the repository.
|
|
|
|
|
/// Implementations should retrieve and parse the manifest for the given
|
|
|
|
|
/// publisher and fully-qualified FMRI (name@version).
|
|
|
|
|
fn fetch_manifest(
|
2026-02-05 15:57:56 +01:00
|
|
|
&self,
|
2025-08-13 23:23:45 +02:00
|
|
|
publisher: &str,
|
|
|
|
|
fmri: &crate::fmri::Fmri,
|
|
|
|
|
) -> Result<crate::actions::Manifest>;
|
|
|
|
|
|
2026-01-20 20:16:58 +01:00
|
|
|
/// Fetch a package manifest as raw text by FMRI from the repository.
|
2026-02-05 15:57:56 +01:00
|
|
|
fn fetch_manifest_text(&self, publisher: &str, fmri: &crate::fmri::Fmri) -> Result<String>;
|
2026-01-20 20:16:58 +01:00
|
|
|
|
2025-07-26 10:34:45 +02:00
|
|
|
/// Search for packages in the repository
|
2025-07-26 12:54:01 +02:00
|
|
|
///
|
2025-07-26 10:34:45 +02:00
|
|
|
/// This method searches for packages in the repository using the search index.
|
|
|
|
|
/// It returns a list of packages that match the search query.
|
2025-07-26 12:54:01 +02:00
|
|
|
///
|
2025-07-26 10:34:45 +02:00
|
|
|
/// # Arguments
|
2025-07-26 12:54:01 +02:00
|
|
|
///
|
2025-07-26 10:34:45 +02:00
|
|
|
/// * `query` - The search query
|
|
|
|
|
/// * `publisher` - Optional publisher to limit the search to
|
|
|
|
|
/// * `limit` - Optional maximum number of results to return
|
2025-07-26 12:54:01 +02:00
|
|
|
fn search(
|
|
|
|
|
&self,
|
|
|
|
|
query: &str,
|
|
|
|
|
publisher: Option<&str>,
|
|
|
|
|
limit: Option<usize>,
|
|
|
|
|
) -> Result<Vec<PackageInfo>>;
|
2025-07-26 10:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Repository trait for write operations
|
|
|
|
|
pub trait WritableRepository {
|
|
|
|
|
/// Create a new repository at the specified path
|
2025-07-26 12:54:01 +02:00
|
|
|
fn create<P: AsRef<Path>>(path: P, version: RepositoryVersion) -> Result<Self>
|
|
|
|
|
where
|
|
|
|
|
Self: Sized;
|
|
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Save the repository configuration
|
|
|
|
|
fn save_config(&self) -> Result<()>;
|
2025-07-26 12:54:01 +02:00
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Add a publisher to the repository
|
|
|
|
|
fn add_publisher(&mut self, publisher: &str) -> Result<()>;
|
2025-07-26 12:54:01 +02:00
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Remove a publisher from the repository
|
|
|
|
|
fn remove_publisher(&mut self, publisher: &str, dry_run: bool) -> Result<()>;
|
2025-07-26 12:54:01 +02:00
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Set a repository property
|
|
|
|
|
fn set_property(&mut self, property: &str, value: &str) -> Result<()>;
|
2025-07-26 12:54:01 +02:00
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Set a publisher property
|
2025-07-26 12:54:01 +02:00
|
|
|
fn set_publisher_property(
|
|
|
|
|
&mut self,
|
|
|
|
|
publisher: &str,
|
|
|
|
|
property: &str,
|
|
|
|
|
value: &str,
|
|
|
|
|
) -> Result<()>;
|
|
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Rebuild repository metadata
|
2025-07-27 13:43:56 +02:00
|
|
|
fn rebuild(&self, publisher: Option<&str>, no_catalog: bool, no_index: bool) -> Result<()>;
|
2025-07-26 12:54:01 +02:00
|
|
|
|
2025-07-21 22:02:05 +02:00
|
|
|
/// Refresh repository metadata
|
2025-07-27 13:43:56 +02:00
|
|
|
fn refresh(&self, publisher: Option<&str>, no_catalog: bool, no_index: bool) -> Result<()>;
|
2025-07-26 12:54:01 +02:00
|
|
|
|
2025-07-21 23:20:19 +02:00
|
|
|
/// Set the default publisher for the repository
|
|
|
|
|
fn set_default_publisher(&mut self, publisher: &str) -> Result<()>;
|
2025-07-26 10:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Repository trait defining the interface for all repository backends
|
2025-07-26 12:54:01 +02:00
|
|
|
///
|
2025-07-26 10:34:45 +02:00
|
|
|
/// This trait combines both ReadableRepository and WritableRepository traits
|
|
|
|
|
/// for backward compatibility.
|
2025-07-26 12:54:01 +02:00
|
|
|
pub trait Repository: ReadableRepository + WritableRepository {}
|
2026-01-18 13:00:21 +01:00
|
|
|
|
|
|
|
|
impl From<catalog::CatalogError> for RepositoryError {
|
|
|
|
|
fn from(err: catalog::CatalogError) -> Self {
|
|
|
|
|
Self::CatalogError(Box::new(err))
|
|
|
|
|
}
|
|
|
|
|
}
|