forked from Proxmox/proxmox
apt: avoid direct impl on api types (use traits instead)
So that we can use api types from expternal crate proxmox-apt-api-types. Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
parent
960131925e
commit
e56e39185a
@ -9,6 +9,8 @@ use crate::repositories::repository::{
|
||||
APTRepository, APTRepositoryFileType, APTRepositoryPackageType,
|
||||
};
|
||||
|
||||
use crate::repositories::repository::APTRepositoryImpl;
|
||||
|
||||
use proxmox_schema::api;
|
||||
|
||||
mod list_parser;
|
||||
@ -116,13 +118,46 @@ pub struct APTRepositoryInfo {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl APTRepositoryFile {
|
||||
pub trait APTRepositoryFileImpl {
|
||||
/// Creates a new `APTRepositoryFile` without parsing.
|
||||
///
|
||||
/// If the file is hidden, the path points to a directory, or the extension
|
||||
/// is usually ignored by APT (e.g. `.orig`), `Ok(None)` is returned, while
|
||||
/// invalid file names yield an error.
|
||||
pub fn new<P: AsRef<Path>>(path: P) -> Result<Option<Self>, APTRepositoryFileError> {
|
||||
fn new<P: AsRef<Path>>(path: P) -> Result<Option<APTRepositoryFile>, APTRepositoryFileError>;
|
||||
|
||||
fn with_content(content: String, content_type: APTRepositoryFileType) -> Self;
|
||||
|
||||
/// Check if the file exists.
|
||||
fn exists(&self) -> bool;
|
||||
|
||||
fn read_with_digest(&self) -> Result<(Vec<u8>, [u8; 32]), APTRepositoryFileError>;
|
||||
|
||||
/// Create an `APTRepositoryFileError`.
|
||||
fn err(&self, error: Error) -> APTRepositoryFileError;
|
||||
|
||||
/// Parses the APT repositories configured in the file on disk, including
|
||||
/// disabled ones.
|
||||
///
|
||||
/// Resets the current repositories and digest, even on failure.
|
||||
fn parse(&mut self) -> Result<(), APTRepositoryFileError>;
|
||||
|
||||
/// Writes the repositories to the file on disk.
|
||||
///
|
||||
/// If a digest is provided, checks that the current content of the file still
|
||||
/// produces the same one.
|
||||
fn write(&self) -> Result<(), APTRepositoryFileError>;
|
||||
|
||||
/// Checks if old or unstable suites are configured and that the Debian security repository
|
||||
/// has the correct suite. Also checks that the `stable` keyword is not used.
|
||||
fn check_suites(&self, current_codename: DebianCodename) -> Vec<APTRepositoryInfo>;
|
||||
|
||||
/// Checks for official URIs.
|
||||
fn check_uris(&self) -> Vec<APTRepositoryInfo>;
|
||||
}
|
||||
|
||||
impl APTRepositoryFileImpl for APTRepositoryFile {
|
||||
fn new<P: AsRef<Path>>(path: P) -> Result<Option<Self>, APTRepositoryFileError> {
|
||||
let path: PathBuf = path.as_ref().to_path_buf();
|
||||
|
||||
let new_err = |path_string: String, err: &str| APTRepositoryFileError {
|
||||
@ -197,7 +232,7 @@ impl APTRepositoryFile {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn with_content(content: String, content_type: APTRepositoryFileType) -> Self {
|
||||
fn with_content(content: String, content_type: APTRepositoryFileType) -> Self {
|
||||
Self {
|
||||
file_type: content_type,
|
||||
content: Some(content),
|
||||
@ -207,8 +242,7 @@ impl APTRepositoryFile {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the file exists.
|
||||
pub fn exists(&self) -> bool {
|
||||
fn exists(&self) -> bool {
|
||||
if let Some(path) = &self.path {
|
||||
PathBuf::from(path).exists()
|
||||
} else {
|
||||
@ -216,7 +250,7 @@ impl APTRepositoryFile {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_with_digest(&self) -> Result<(Vec<u8>, [u8; 32]), APTRepositoryFileError> {
|
||||
fn read_with_digest(&self) -> Result<(Vec<u8>, [u8; 32]), APTRepositoryFileError> {
|
||||
if let Some(path) = &self.path {
|
||||
let content = std::fs::read(path).map_err(|err| self.err(format_err!("{}", err)))?;
|
||||
let digest = openssl::sha::sha256(&content);
|
||||
@ -233,19 +267,14 @@ impl APTRepositoryFile {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an `APTRepositoryFileError`.
|
||||
pub fn err(&self, error: Error) -> APTRepositoryFileError {
|
||||
fn err(&self, error: Error) -> APTRepositoryFileError {
|
||||
APTRepositoryFileError {
|
||||
path: self.path.clone().unwrap_or_default(),
|
||||
error: error.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the APT repositories configured in the file on disk, including
|
||||
/// disabled ones.
|
||||
///
|
||||
/// Resets the current repositories and digest, even on failure.
|
||||
pub fn parse(&mut self) -> Result<(), APTRepositoryFileError> {
|
||||
fn parse(&mut self) -> Result<(), APTRepositoryFileError> {
|
||||
self.repositories.clear();
|
||||
self.digest = None;
|
||||
|
||||
@ -269,11 +298,7 @@ impl APTRepositoryFile {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes the repositories to the file on disk.
|
||||
///
|
||||
/// If a digest is provided, checks that the current content of the file still
|
||||
/// produces the same one.
|
||||
pub fn write(&self) -> Result<(), APTRepositoryFileError> {
|
||||
fn write(&self) -> Result<(), APTRepositoryFileError> {
|
||||
let path = match &self.path {
|
||||
Some(path) => path,
|
||||
None => {
|
||||
@ -336,9 +361,7 @@ impl APTRepositoryFile {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if old or unstable suites are configured and that the Debian security repository
|
||||
/// has the correct suite. Also checks that the `stable` keyword is not used.
|
||||
pub fn check_suites(&self, current_codename: DebianCodename) -> Vec<APTRepositoryInfo> {
|
||||
fn check_suites(&self, current_codename: DebianCodename) -> Vec<APTRepositoryInfo> {
|
||||
let mut infos = vec![];
|
||||
|
||||
let path = match &self.path {
|
||||
@ -427,8 +450,7 @@ impl APTRepositoryFile {
|
||||
infos
|
||||
}
|
||||
|
||||
/// Checks for official URIs.
|
||||
pub fn check_uris(&self) -> Vec<APTRepositoryInfo> {
|
||||
fn check_uris(&self) -> Vec<APTRepositoryInfo> {
|
||||
let mut infos = vec![];
|
||||
|
||||
let path = match &self.path {
|
||||
|
@ -3,9 +3,9 @@ use std::iter::Iterator;
|
||||
|
||||
use anyhow::{bail, format_err, Error};
|
||||
|
||||
use crate::repositories::{APTRepository, APTRepositoryFileType, APTRepositoryOption};
|
||||
|
||||
use super::APTRepositoryParser;
|
||||
use crate::repositories::APTRepositoryImpl;
|
||||
use crate::repositories::{APTRepository, APTRepositoryFileType, APTRepositoryOption};
|
||||
|
||||
// TODO convert %-escape characters. Also adapt printing back accordingly,
|
||||
// because at least '%' needs to be re-escaped when printing.
|
||||
|
@ -3,6 +3,7 @@ use std::iter::Iterator;
|
||||
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
use crate::repositories::APTRepositoryImpl;
|
||||
use crate::repositories::{
|
||||
APTRepository, APTRepositoryFileType, APTRepositoryOption, APTRepositoryPackageType,
|
||||
};
|
||||
|
@ -4,17 +4,20 @@ use std::path::PathBuf;
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
mod repository;
|
||||
pub use repository::APTRepositoryImpl;
|
||||
pub use repository::{
|
||||
APTRepository, APTRepositoryFileType, APTRepositoryOption, APTRepositoryPackageType,
|
||||
};
|
||||
|
||||
mod file;
|
||||
pub use file::APTRepositoryFileImpl;
|
||||
pub use file::{APTRepositoryFile, APTRepositoryFileError, APTRepositoryInfo};
|
||||
|
||||
mod release;
|
||||
pub use release::{get_current_release_codename, DebianCodename};
|
||||
|
||||
mod standard;
|
||||
pub use standard::APTRepositoryHandleImpl;
|
||||
pub use standard::{APTRepositoryHandle, APTStandardRepository};
|
||||
|
||||
const APT_SOURCES_LIST_FILENAME: &str = "/etc/apt/sources.list";
|
||||
|
@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use proxmox_schema::api;
|
||||
|
||||
use crate::repositories::standard::APTRepositoryHandle;
|
||||
use crate::repositories::standard::APTRepositoryHandleImpl;
|
||||
|
||||
#[api]
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
@ -188,9 +189,41 @@ pub struct APTRepository {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl APTRepository {
|
||||
pub trait APTRepositoryImpl {
|
||||
/// Crates an empty repository.
|
||||
pub fn new(file_type: APTRepositoryFileType) -> Self {
|
||||
fn new(file_type: APTRepositoryFileType) -> Self;
|
||||
|
||||
/// Changes the `enabled` flag and makes sure the `Enabled` option for
|
||||
/// `APTRepositoryPackageType::Sources` repositories is updated too.
|
||||
fn set_enabled(&mut self, enabled: bool);
|
||||
|
||||
/// Makes sure that all basic properties of a repository are present and not obviously invalid.
|
||||
fn basic_check(&self) -> Result<(), Error>;
|
||||
|
||||
/// Checks if the repository is the one referenced by the handle.
|
||||
fn is_referenced_repository(
|
||||
&self,
|
||||
handle: APTRepositoryHandle,
|
||||
product: &str,
|
||||
suite: &str,
|
||||
) -> bool;
|
||||
|
||||
/// Guess the origin from the repository's URIs.
|
||||
///
|
||||
/// Intended to be used as a fallback for get_cached_origin.
|
||||
fn origin_from_uris(&self) -> Option<String>;
|
||||
|
||||
/// Get the `Origin:` value from a cached InRelease file.
|
||||
fn get_cached_origin(&self) -> Result<Option<String>, Error>;
|
||||
|
||||
/// Writes a repository in the corresponding format followed by a blank.
|
||||
///
|
||||
/// Expects that `basic_check()` for the repository was successful.
|
||||
fn write(&self, w: &mut dyn Write) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl APTRepositoryImpl for APTRepository {
|
||||
fn new(file_type: APTRepositoryFileType) -> Self {
|
||||
Self {
|
||||
types: vec![],
|
||||
uris: vec![],
|
||||
@ -203,9 +236,7 @@ impl APTRepository {
|
||||
}
|
||||
}
|
||||
|
||||
/// Changes the `enabled` flag and makes sure the `Enabled` option for
|
||||
/// `APTRepositoryPackageType::Sources` repositories is updated too.
|
||||
pub fn set_enabled(&mut self, enabled: bool) {
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.enabled = enabled;
|
||||
|
||||
if self.file_type == APTRepositoryFileType::Sources {
|
||||
@ -226,8 +257,7 @@ impl APTRepository {
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes sure that all basic properties of a repository are present and not obviously invalid.
|
||||
pub fn basic_check(&self) -> Result<(), Error> {
|
||||
fn basic_check(&self) -> Result<(), Error> {
|
||||
if self.types.is_empty() {
|
||||
bail!("missing package type(s)");
|
||||
}
|
||||
@ -267,8 +297,7 @@ impl APTRepository {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if the repository is the one referenced by the handle.
|
||||
pub fn is_referenced_repository(
|
||||
fn is_referenced_repository(
|
||||
&self,
|
||||
handle: APTRepositoryHandle,
|
||||
product: &str,
|
||||
@ -299,10 +328,7 @@ impl APTRepository {
|
||||
&& found_component
|
||||
}
|
||||
|
||||
/// Guess the origin from the repository's URIs.
|
||||
///
|
||||
/// Intended to be used as a fallback for get_cached_origin.
|
||||
pub fn origin_from_uris(&self) -> Option<String> {
|
||||
fn origin_from_uris(&self) -> Option<String> {
|
||||
for uri in self.uris.iter() {
|
||||
if let Some(host) = host_from_uri(uri) {
|
||||
if host == "proxmox.com" || host.ends_with(".proxmox.com") {
|
||||
@ -318,8 +344,7 @@ impl APTRepository {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get the `Origin:` value from a cached InRelease file.
|
||||
pub fn get_cached_origin(&self) -> Result<Option<String>, Error> {
|
||||
fn get_cached_origin(&self) -> Result<Option<String>, Error> {
|
||||
for uri in self.uris.iter() {
|
||||
for suite in self.suites.iter() {
|
||||
let mut file = release_filename(uri, suite, false);
|
||||
@ -353,10 +378,7 @@ impl APTRepository {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Writes a repository in the corresponding format followed by a blank.
|
||||
///
|
||||
/// Expects that `basic_check()` for the repository was successful.
|
||||
pub fn write(&self, w: &mut dyn Write) -> Result<(), Error> {
|
||||
fn write(&self, w: &mut dyn Write) -> Result<(), Error> {
|
||||
match self.file_type {
|
||||
APTRepositoryFileType::List => write_one_line(self, w),
|
||||
APTRepositoryFileType::Sources => write_stanza(self, w),
|
||||
|
@ -111,9 +111,26 @@ impl Display for APTRepositoryHandle {
|
||||
}
|
||||
}
|
||||
|
||||
impl APTRepositoryHandle {
|
||||
pub trait APTRepositoryHandleImpl {
|
||||
/// Get the description for the repository.
|
||||
pub fn description(self) -> String {
|
||||
fn description(self) -> String;
|
||||
/// Get the display name of the repository.
|
||||
fn name(self) -> String;
|
||||
/// Get the standard file path for the repository referenced by the handle.
|
||||
fn path(self, product: &str) -> String;
|
||||
/// Get package type, possible URIs and the component associated with the handle.
|
||||
///
|
||||
/// The first URI is the preferred one.
|
||||
fn info(self, product: &str) -> (APTRepositoryPackageType, Vec<String>, String);
|
||||
/// Get the standard repository referenced by the handle.
|
||||
///
|
||||
/// An URI in the result is not '/'-terminated (under the assumption that no valid
|
||||
/// product name is).
|
||||
fn to_repository(self, product: &str, suite: &str) -> APTRepository;
|
||||
}
|
||||
|
||||
impl APTRepositoryHandleImpl for APTRepositoryHandle {
|
||||
fn description(self) -> String {
|
||||
match self {
|
||||
APTRepositoryHandle::Enterprise => {
|
||||
"This is the default, stable, and recommended repository, available for all \
|
||||
@ -155,8 +172,7 @@ impl APTRepositoryHandle {
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Get the display name of the repository.
|
||||
pub fn name(self) -> String {
|
||||
fn name(self) -> String {
|
||||
match self {
|
||||
APTRepositoryHandle::Enterprise => "Enterprise",
|
||||
APTRepositoryHandle::NoSubscription => "No-Subscription",
|
||||
@ -171,8 +187,7 @@ impl APTRepositoryHandle {
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Get the standard file path for the repository referenced by the handle.
|
||||
pub fn path(self, product: &str) -> String {
|
||||
fn path(self, product: &str) -> String {
|
||||
match self {
|
||||
APTRepositoryHandle::Enterprise => {
|
||||
format!("/etc/apt/sources.list.d/{}-enterprise.list", product)
|
||||
@ -188,10 +203,7 @@ impl APTRepositoryHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get package type, possible URIs and the component associated with the handle.
|
||||
///
|
||||
/// The first URI is the preferred one.
|
||||
pub fn info(self, product: &str) -> (APTRepositoryPackageType, Vec<String>, String) {
|
||||
fn info(self, product: &str) -> (APTRepositoryPackageType, Vec<String>, String) {
|
||||
match self {
|
||||
APTRepositoryHandle::Enterprise => (
|
||||
APTRepositoryPackageType::Deb,
|
||||
@ -259,11 +271,7 @@ impl APTRepositoryHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the standard repository referenced by the handle.
|
||||
///
|
||||
/// An URI in the result is not '/'-terminated (under the assumption that no valid
|
||||
/// product name is).
|
||||
pub fn to_repository(self, product: &str, suite: &str) -> APTRepository {
|
||||
fn to_repository(self, product: &str, suite: &str) -> APTRepository {
|
||||
let (package_type, uris, component) = self.info(product);
|
||||
|
||||
APTRepository {
|
||||
|
@ -8,6 +8,9 @@ use proxmox_apt::repositories::{
|
||||
check_repositories, get_current_release_codename, standard_repositories, APTRepositoryFile,
|
||||
APTRepositoryHandle, APTRepositoryInfo, APTStandardRepository, DebianCodename,
|
||||
};
|
||||
use proxmox_apt::repositories::{
|
||||
APTRepositoryFileImpl, APTRepositoryHandleImpl, APTRepositoryImpl,
|
||||
};
|
||||
|
||||
fn create_clean_directory(path: &PathBuf) -> Result<(), Error> {
|
||||
match std::fs::remove_dir_all(path) {
|
||||
|
Loading…
Reference in New Issue
Block a user