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
5 changes: 3 additions & 2 deletions rust/Cargo.lock

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

5 changes: 2 additions & 3 deletions rust/agama-files/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,11 @@ impl ScriptsRunner {

/// Ancillary function to start the progress.
fn start_progress(&self, scripts: &[&Script]) {
let messages: Vec<_> = scripts
let steps: Vec<_> = scripts
.iter()
.map(|s| format!("Running user script '{}'", s.name()))
.collect();
let steps: Vec<_> = messages.iter().map(|s| s.as_ref()).collect();
let progress_action = progress::message::StartWithSteps::new(Scope::Files, &steps);
let progress_action = progress::message::StartWithSteps::new(Scope::Files, steps);
_ = self.progress.cast(progress_action);
}

Expand Down
1 change: 1 addition & 0 deletions rust/agama-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ serde_json = "1.0.140"
tracing = "0.1.41"
serde = { version = "1.0.228", features = ["derive"] }
serde_with = "3.16.1"
gettext-rs = { version = "0.7.7", features = ["gettext-system"] }

[dev-dependencies]
test-context = "0.4.1"
Expand Down
7 changes: 0 additions & 7 deletions rust/agama-manager/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ use agama_utils::{
};
use serde_json::Value;

/// Gets the installation status.
pub struct GetStatus;

impl Message for GetStatus {
type Reply = Status;
}

/// Gets the information of the underlying system.
#[derive(Debug)]
pub struct GetSystem;
Expand Down
157 changes: 124 additions & 33 deletions rust/agama-manager/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ use agama_utils::{
self, event,
files::scripts::ScriptsGroup,
manager::{self, LicenseContent},
status::State,
status::Stage,
Action, Config, Event, Issue, IssueMap, Proposal, Scope, Status, SystemInfo,
},
issue, licenses,
products::{self, ProductSpec},
progress, question,
};
use async_trait::async_trait;
use gettextrs::gettext;
use merge_struct::merge;
use network::NetworkSystemClient;
use serde_json::Value;
Expand Down Expand Up @@ -75,6 +76,8 @@ pub enum Error {
NetworkSystem(#[from] network::NetworkSystemError),
#[error(transparent)]
Hardware(#[from] hardware::Error),
#[error("Cannot dispatch this action in {current} stage (expected {expected}).")]
UnexpectedStage { current: Stage, expected: Stage },
}

pub struct Starter {
Expand Down Expand Up @@ -221,7 +224,6 @@ impl Starter {
};

let mut service = Service {
events: self.events,
questions: self.questions,
progress,
issues,
Expand All @@ -233,8 +235,6 @@ impl Starter {
products: products::Registry::default(),
licenses: licenses::Registry::default(),
hardware,
// FIXME: state is already used for service state.
state: State::Configuring,
config: Config::default(),
system: manager::SystemInfo::default(),
product: None,
Expand All @@ -258,10 +258,8 @@ pub struct Service {
licenses: licenses::Registry,
hardware: hardware::Registry,
product: Option<Arc<RwLock<ProductSpec>>>,
state: State,
config: Config,
system: manager::SystemInfo,
events: event::Sender,
}

impl Service {
Expand Down Expand Up @@ -424,25 +422,6 @@ impl Service {
Ok(())
}

async fn install(&mut self) -> Result<(), Error> {
self.state = State::Installing;
self.events.send(Event::StateChanged)?;
// TODO: translate progress steps.
self.progress
.call(progress::message::StartWithSteps::new(
Scope::Manager,
&["Installing l10n"],
))
.await?;
self.l10n.call(l10n::message::Install).await?;
self.progress
.call(progress::message::Finish::new(Scope::Manager))
.await?;
self.state = State::Finished;
self.events.send(Event::StateChanged)?;
Ok(())
}

fn set_product(&mut self, config: &Config) -> Result<(), Error> {
self.product = None;
self.update_product(config)
Expand Down Expand Up @@ -480,21 +459,26 @@ impl Service {
}
Ok(())
}

async fn check_stage(&self, expected: Stage) -> Result<(), Error> {
let current = self.progress.call(progress::message::GetStage).await?;
if current != expected {
return Err(Error::UnexpectedStage { expected, current });
}
Ok(())
}
}

impl Actor for Service {
type Error = Error;
}

#[async_trait]
impl MessageHandler<message::GetStatus> for Service {
impl MessageHandler<progress::message::GetStatus> for Service {
/// It returns the status of the installation.
async fn handle(&mut self, _message: message::GetStatus) -> Result<Status, Error> {
let progresses = self.progress.call(progress::message::Get).await?;
Ok(Status {
state: self.state.clone(),
progresses,
})
async fn handle(&mut self, message: progress::message::GetStatus) -> Result<Status, Error> {
let status = self.progress.call(message).await?;
Ok(status)
}
}

Expand Down Expand Up @@ -554,6 +538,7 @@ impl MessageHandler<message::GetConfig> for Service {
impl MessageHandler<message::SetConfig> for Service {
/// Sets the user configuration with the given values.
async fn handle(&mut self, message: message::SetConfig) -> Result<(), Error> {
self.check_stage(Stage::Configuring).await?;
self.set_config(message.config).await
}
}
Expand All @@ -577,6 +562,7 @@ impl MessageHandler<message::UpdateConfig> for Service {
/// It merges the current config with the given one. If some scope is missing in the given
/// config, then it keeps the values from the current config.
async fn handle(&mut self, message: message::UpdateConfig) -> Result<(), Error> {
self.check_stage(Stage::Configuring).await?;
let config = merge(&self.config, &message.config).map_err(|_| Error::MergeConfig)?;
let config = merge_network(config, message.config);
self.update_config(config).await
Expand Down Expand Up @@ -623,6 +609,8 @@ impl MessageHandler<message::GetLicense> for Service {
impl MessageHandler<message::RunAction> for Service {
/// It runs the given action.
async fn handle(&mut self, message: message::RunAction) -> Result<(), Error> {
self.check_stage(Stage::Configuring).await?;

match message.action {
Action::ConfigureL10n(config) => {
self.configure_l10n(config).await?;
Expand All @@ -634,7 +622,15 @@ impl MessageHandler<message::RunAction> for Service {
self.probe_storage().await?;
}
Action::Install => {
self.install().await?;
let action = InstallAction {
l10n: self.l10n.clone(),
network: self.network.clone(),
software: self.software.clone(),
storage: self.storage.clone(),
files: self.files.clone(),
progress: self.progress.clone(),
};
action.run();
}
}
Ok(())
Expand All @@ -653,6 +649,7 @@ impl MessageHandler<message::GetStorageModel> for Service {
impl MessageHandler<message::SetStorageModel> for Service {
/// It sets the storage model.
async fn handle(&mut self, message: message::SetStorageModel) -> Result<(), Error> {
self.check_stage(Stage::Configuring).await?;
Ok(self
.storage
.call(storage::message::SetConfigModel::new(message.model))
Expand All @@ -667,6 +664,7 @@ impl MessageHandler<message::SolveStorageModel> for Service {
&mut self,
message: message::SolveStorageModel,
) -> Result<Option<Value>, Error> {
self.check_stage(Stage::Configuring).await?;
Ok(self
.storage
.call(storage::message::SolveConfigModel::new(message.model))
Expand All @@ -679,7 +677,100 @@ impl MessageHandler<message::SolveStorageModel> for Service {
impl MessageHandler<software::message::SetResolvables> for Service {
/// It sets the software resolvables.
async fn handle(&mut self, message: software::message::SetResolvables) -> Result<(), Error> {
self.check_stage(Stage::Configuring).await?;
self.software.call(message).await?;
Ok(())
}
}

/// Implements the installation process.
///
/// This action runs on a separate Tokio task to prevent the manager from blocking.
struct InstallAction {
l10n: Handler<l10n::Service>,
network: NetworkSystemClient,
software: Handler<software::Service>,
storage: Handler<storage::Service>,
files: Handler<files::Service>,
progress: Handler<progress::Service>,
}

impl InstallAction {
/// Runs the installation process on a separate Tokio task.
pub fn run(mut self) {
tokio::spawn(async move {
if let Err(error) = self.install().await {
tracing::error!("Installation failed: {error}");
if let Err(error) = self
.progress
.call(progress::message::SetStage::new(Stage::Failed))
.await
{
tracing::error!(
"It was not possible to set the stage to {}: {error}",
Stage::Failed
);
}
}
});
}

async fn install(&mut self) -> Result<(), Error> {
// NOTE: consider a NextState message?
self.progress
.call(progress::message::SetStage::new(Stage::Installing))
.await?;

//
// Preparation
//
self.progress
.call(progress::message::StartWithSteps::new(
Scope::Manager,
vec![
gettext("Prepare the system"),
gettext("Install software"),
gettext("Configure the system"),
],
))
.await?;

self.storage.call(storage::message::Install).await?;
self.files
.call(files::message::RunScripts::new(
ScriptsGroup::PostPartitioning,
))
.await?;

//
// Installation
//
self.progress
.call(progress::message::Next::new(Scope::Manager))
.await?;
self.software.call(software::message::Install).await?;

//
// Configuration
//
self.progress
.call(progress::message::Next::new(Scope::Manager))
.await?;
self.l10n.call(l10n::message::Install).await?;
self.software.call(software::message::Finish).await?;
self.files.call(files::message::WriteFiles).await?;
self.storage.call(storage::message::Finish).await?;

//
// Finish progress and changes
//
self.progress
.call(progress::message::Finish::new(Scope::Manager))
.await?;

self.progress
.call(progress::message::SetStage::new(Stage::Finished))
.await?;
Ok(())
}
}
4 changes: 2 additions & 2 deletions rust/agama-server/src/server/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use agama_utils::{
question::{Question, QuestionSpec, UpdateQuestion},
Action, Config, IssueWithScope, Patch, Status, SystemInfo,
},
question,
progress, question,
};
use axum::{
extract::{Path, Query, State},
Expand Down Expand Up @@ -136,7 +136,7 @@ pub fn server_with_state(state: ServerState) -> Result<Router, ServiceError> {
)
)]
async fn get_status(State(state): State<ServerState>) -> ServerResult<Json<Status>> {
let status = state.manager.call(message::GetStatus).await?;
let status = state.manager.call(progress::message::GetStatus).await?;
Ok(Json(status))
}

Expand Down
2 changes: 1 addition & 1 deletion rust/agama-server/src/web/docs/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ impl ApiDocBuilder for ConfigApiDocBuilder {
.schema_from::<agama_utils::api::question::SelectionOption>()
.schema_from::<agama_utils::api::question::UpdateQuestion>()
.schema_from::<agama_utils::api::software::RepositoryConfig>()
.schema_from::<agama_utils::api::status::State>()
.schema_from::<agama_utils::api::status::Stage>()
.schema_from::<agama_utils::api::query::SolveStorageModel>()
.build()
}
Expand Down
9 changes: 5 additions & 4 deletions rust/agama-software/src/zypp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use agama_utils::{
products::ProductSpec,
progress, question,
};
use gettextrs::gettext;
use std::{collections::HashMap, path::Path};
use tokio::sync::{
mpsc::{self, UnboundedSender},
Expand Down Expand Up @@ -246,10 +247,10 @@ impl ZyppServer {

_ = progress.cast(progress::message::StartWithSteps::new(
Scope::Software,
&[
"Updating the list of repositories",
"Refreshing metadata from the repositories",
"Calculating the software proposal",
vec![
gettext("Updating the list of repositories"),
gettext("Refreshing metadata from the repositories"),
gettext("Calculating the software proposal"),
],
));
let old_state = self.read(zypp)?;
Expand Down
2 changes: 1 addition & 1 deletion rust/agama-storage/src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl Monitor {
return Err(Error::ProgressChangedData);
};
self.progress
.cast(progress::message::Set::new(progress_data.into()))?;
.cast(progress::message::SetProgress::new(progress_data.into()))?;

Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions rust/agama-utils/src/api/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use tokio::sync::broadcast;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Event {
// The state of the installation changed.
StateChanged,
// The stage of the installation changed.
StageChanged,
/// Progress changed.
ProgressChanged {
progress: Progress,
Expand Down
Loading
Loading