Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/agama-files/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition.workspace = true
agama-software = { version = "0.1.0", path = "../agama-software" }
agama-utils = { path = "../agama-utils" }
async-trait = "0.1.89"
strum = "0.27.2"
tempfile = "3.23.0"
thiserror = "2.0.17"
tokio = { version = "1.48.0", features = ["sync"] }
Expand Down
29 changes: 22 additions & 7 deletions rust/agama-files/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const NM_RESOLV_CONF_PATH: &str = "run/NetworkManager/resolv.conf";

/// Implements the logic to run a script.
///
/// It takes care of running the script, reporting errors (and asking whether to retry) and write
/// It takes care of running the script, reporting errors (and asking whether to retry) and writing
/// the logs.
pub struct ScriptsRunner {
progress: Handler<progress::Service>,
Expand Down Expand Up @@ -94,7 +94,8 @@ impl ScriptsRunner {
///
/// * `scripts`: scripts to run.
pub async fn run(&self, scripts: &[&Script]) -> Result<(), Error> {
self.start_progress(scripts);
let scripts: Vec<_> = self.find_scripts_to_run(&scripts);
self.start_progress(&scripts);

let mut resolv_linked = false;
if scripts.iter().any(|s| s.chroot()) {
Expand Down Expand Up @@ -122,12 +123,9 @@ impl ScriptsRunner {
///
/// If the script fails, it asks the user whether it should try again.
async fn run_script(&self, script: &Script) -> Result<(), Error> {
loop {
let path = self
.workdir
.join(script.group().to_string())
.join(script.name());
let path = self.workdir.join(script.relative_script_path());

loop {
let Err(error) = self.run_command(&path, script.chroot()).await else {
return Ok(());
};
Expand Down Expand Up @@ -215,6 +213,23 @@ impl ScriptsRunner {
_ = self.progress.cast(progress_action);
}

/// Returns the scripts to run from the given collection
///
/// It exclues any script that already ran.
fn find_scripts_to_run<'a>(&self, scripts: &[&'a Script]) -> Vec<&'a Script> {
scripts
.into_iter()
.filter(|s| {
let stdout_file = self
.workdir
.join(s.relative_script_path())
.with_extension("stdout");
!std::fs::exists(stdout_file).unwrap_or(false)
})
.cloned()
.collect()
}

/// Reads the last n bytes of the file and returns them as a string.
fn read_n_last_bytes(path: &Path, n_bytes: u64) -> io::Result<String> {
let mut file = File::open(path)?;
Expand Down
11 changes: 9 additions & 2 deletions rust/agama-files/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ use agama_software::{self as software, Resolvable, ResolvableType};
use agama_utils::{
actor::{self, Actor, Handler, MessageHandler},
api::files::{
scripts::{self, ScriptsRepository},
scripts::{self, ScriptsGroup, ScriptsRepository},
user_file, ScriptsConfig, UserFile,
},
progress, question,
};
use async_trait::async_trait;
use strum::IntoEnumIterator;
use tokio::sync::Mutex;

use crate::{message, ScriptsRunner};
Expand Down Expand Up @@ -128,9 +129,15 @@ impl Service {
Starter::new(progress, questions, software)
}

/// Clear the scripts.
///
/// Keep the pre-scripts because they are expected to run as soon as they are imported.
pub async fn clear_scripts(&mut self) -> Result<(), Error> {
let mut repo = self.scripts.lock().await;
repo.clear()?;
let groups: Vec<_> = ScriptsGroup::iter()
.filter(|g| g != &ScriptsGroup::Pre)
.collect();
repo.clear(groups.as_slice())?;
Ok(())
}

Expand Down
43 changes: 0 additions & 43 deletions rust/agama-manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,25 +135,6 @@ mod test {
Ok(())
}

#[test_context(Context)]
#[tokio::test]
async fn test_update_config_without_product(ctx: &mut Context) {
let input_config = Config {
l10n: Some(l10n::Config {
locale: Some("es_ES.UTF-8".to_string()),
keymap: Some("es".to_string()),
timezone: Some("Atlantic/Canary".to_string()),
}),
..Default::default()
};

let error = ctx
.handler
.call(message::SetConfig::new(input_config.clone()))
.await;
assert!(matches!(error, Err(crate::service::Error::MissingProduct)));
}

#[test_context(Context)]
#[tokio::test]
async fn test_patch_config(ctx: &mut Context) -> Result<(), Error> {
Expand Down Expand Up @@ -184,28 +165,4 @@ mod test {

Ok(())
}

#[test_context(Context)]
#[tokio::test]
async fn test_patch_config_without_product(ctx: &mut Context) -> Result<(), Error> {
let input_config = Config {
l10n: Some(l10n::Config {
keymap: Some("es".to_string()),
..Default::default()
}),
..Default::default()
};

let result = ctx
.handler
.call(message::UpdateConfig::new(input_config.clone()))
.await;
assert!(matches!(result, Err(crate::service::Error::MissingProduct)));

let extended_config = ctx.handler.call(message::GetExtendedConfig).await?;
let l10n_config = extended_config.l10n.unwrap();
assert_eq!(l10n_config.keymap, Some("us".to_string()));

Ok(())
}
}
Loading
Loading