From c50672e473339f47a426a1360c5436fde3f2ccdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Wed, 9 Oct 2024 13:46:57 +0100 Subject: [PATCH] refactor(rust): introduce a new "transfer" module * This module replaces the old "download" function. --- rust/agama-cli/src/lib.rs | 8 ++++---- rust/agama-cli/src/profile.rs | 19 +++-------------- rust/agama-lib/src/error.rs | 7 +++++-- rust/agama-lib/src/lib.rs | 1 + rust/agama-lib/src/transfer.rs | 37 ++++++++++++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 rust/agama-lib/src/transfer.rs diff --git a/rust/agama-cli/src/lib.rs b/rust/agama-cli/src/lib.rs index cc0b77f71c..42d265e557 100644 --- a/rust/agama-cli/src/lib.rs +++ b/rust/agama-cli/src/lib.rs @@ -30,9 +30,9 @@ mod progress; mod questions; use crate::error::CliError; -use agama_lib::error::ServiceError; -use agama_lib::manager::ManagerClient; -use agama_lib::progress::ProgressMonitor; +use agama_lib::{ + error::ServiceError, manager::ManagerClient, progress::ProgressMonitor, transfer::Transfer, +}; use auth::run as run_auth_cmd; use commands::Commands; use config::run as run_config_cmd; @@ -158,7 +158,7 @@ pub async fn run_command(cli: Cli) -> Result<(), ServiceError> { Commands::Questions(subcommand) => run_questions_cmd(subcommand).await?, Commands::Logs(subcommand) => run_logs_cmd(subcommand).await?, Commands::Auth(subcommand) => run_auth_cmd(subcommand).await?, - Commands::Download { url } => crate::profile::download(&url, std::io::stdout())?, + Commands::Download { url } => Transfer::get(&url, std::io::stdout())?, }; Ok(()) diff --git a/rust/agama-cli/src/profile.rs b/rust/agama-cli/src/profile.rs index e5cde79d9f..9585cb4c37 100644 --- a/rust/agama-cli/src/profile.rs +++ b/rust/agama-cli/src/profile.rs @@ -22,15 +22,15 @@ use agama_lib::{ auth::AuthToken, install_settings::InstallSettings, profile::{AutoyastProfile, ProfileEvaluator, ProfileValidator, ValidationResult}, + transfer::Transfer, Store as SettingsStore, }; use anyhow::Context; use clap::Subcommand; -use curl::easy::Easy; use std::os::unix::process::CommandExt; use std::{ fs::File, - io::{stdout, Write}, + io::stdout, path::{Path, PathBuf}, process::Command, }; @@ -78,19 +78,6 @@ pub enum ProfileCommands { }, } -pub fn download(url: &str, mut out_fd: impl Write) -> anyhow::Result<()> { - let mut handle = Easy::new(); - handle.url(url)?; - - let mut transfer = handle.transfer(); - transfer.write_function(|buf| - // unwrap here is ok, as we want to kill download if we failed to write content - Ok(out_fd.write(buf).unwrap()))?; - transfer.perform()?; - - Ok(()) -} - fn validate(path: &PathBuf) -> anyhow::Result<()> { let validator = ProfileValidator::default_schema()?; // let path = Path::new(&path); @@ -138,7 +125,7 @@ async fn import(url_string: String, dir: Option) -> anyhow::Result<()> AutoyastProfile::new(&url)?.read_into(output_fd)?; } else { // just download profile - download(&url_string, output_fd)?; + Transfer::get(&url_string, output_fd)?; } // exec shell scripts diff --git a/rust/agama-lib/src/error.rs b/rust/agama-lib/src/error.rs index ece6b685e3..380aaafd8d 100644 --- a/rust/agama-lib/src/error.rs +++ b/rust/agama-lib/src/error.rs @@ -18,12 +18,13 @@ // To contact SUSE LLC about this file by physical or electronic mail, you may // find current contact information at www.suse.com. -use curl; use serde_json; use std::io; use thiserror::Error; use zbus::{self, zvariant}; +use crate::transfer::TransferError; + #[derive(Error, Debug)] pub enum ServiceError { #[error("Cannot generate Agama logs: {0}")] @@ -66,12 +67,14 @@ pub enum ServiceError { // Specific error when something does not work as expected, but it is not user fault #[error("Internal error. Please report a bug and attach logs. Details: {0}")] InternalError(String), + #[error("Could not read the file: '{0}'")] + CouldNotTransferFile(#[from] TransferError), } #[derive(Error, Debug)] pub enum ProfileError { #[error("Could not read the profile")] - Unreachable(#[from] curl::Error), + Unreachable(#[from] TransferError), #[error("Jsonnet evaluation failed:\n{0}")] EvaluationError(String), #[error("I/O error")] diff --git a/rust/agama-lib/src/lib.rs b/rust/agama-lib/src/lib.rs index 5240814960..6c86b035a1 100644 --- a/rust/agama-lib/src/lib.rs +++ b/rust/agama-lib/src/lib.rs @@ -63,6 +63,7 @@ pub mod proxies; mod store; pub use store::Store; pub mod questions; +pub mod transfer; use crate::error::ServiceError; use reqwest::{header, Client}; diff --git a/rust/agama-lib/src/transfer.rs b/rust/agama-lib/src/transfer.rs new file mode 100644 index 0000000000..2566c93c7b --- /dev/null +++ b/rust/agama-lib/src/transfer.rs @@ -0,0 +1,37 @@ +//! File transfer API for Agama. +//! +//! Implement a file transfer API which, in the future, will support Agama specific URLs. Check the +//! YaST document about [URL handling in the +//! installer](https://github.com/yast/yast-installation/blob/master/doc/url.md) for further +//! information. +//! +//! At this point, it only supports those schemes supported by CURL. + +use std::io::Write; + +use curl::easy::Easy; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +pub struct TransferError(#[from] curl::Error); +pub type TransferResult = Result; + +/// File transfer API +pub struct Transfer {} + +impl Transfer { + /// Retrieves and writes the data from an URL + /// + /// * `url`: URL to get the data from. + /// * `out_fd`: where to write the data. + pub fn get(url: &str, mut out_fd: impl Write) -> TransferResult<()> { + let mut handle = Easy::new(); + handle.url(url)?; + + let mut transfer = handle.transfer(); + transfer.write_function(|buf| Ok(out_fd.write(buf).unwrap()))?; + transfer.perform()?; + Ok(()) + } +}