diff --git a/doc/cli_guidelines.md b/doc/cli_guidelines.md index ee6e1aa324..4e244455c0 100644 --- a/doc/cli_guidelines.md +++ b/doc/cli_guidelines.md @@ -192,6 +192,11 @@ There are pending questions. Please, answer questions first: agama questions. ## Non Interactive Mode -Commands should offer a `--non-interactive` option to make scripting possible. The non interactive mode should allow answering questions automatically. +There is a `questions` subcommand that support `mode` and `answers` subcommands. +The `mode` subcommand allows to set `interactive` and `non-interactive` modes. +The `answers` allows to pass a file with predefined answers. -TBD: Non interactive mode will be defined later in the next iteration. +~~~ +agama questions mode non-interactive +agama questions answers /tmp/answers.json +~~~ diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 0b77eada04..745095d4c7 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ "console", "convert_case", "indicatif", + "log", "serde", "serde_json", "serde_yaml", diff --git a/rust/agama-cli/Cargo.toml b/rust/agama-cli/Cargo.toml index 4b3078034b..38765fee9a 100644 --- a/rust/agama-cli/Cargo.toml +++ b/rust/agama-cli/Cargo.toml @@ -17,6 +17,7 @@ thiserror = "1.0.39" convert_case = "0.6.0" console = "0.15.7" anyhow = "1.0.71" +log = "0.4" [[bin]] name = "agama" diff --git a/rust/agama-cli/src/commands.rs b/rust/agama-cli/src/commands.rs index de2a386907..9c07516988 100644 --- a/rust/agama-cli/src/commands.rs +++ b/rust/agama-cli/src/commands.rs @@ -1,5 +1,6 @@ use crate::config::ConfigCommands; use crate::profile::ProfileCommands; +use crate::questions::QuestionsCommands; use clap::Subcommand; #[derive(Subcommand, Debug)] @@ -20,4 +21,7 @@ pub enum Commands { /// Autoinstallation profile handling #[command(subcommand)] Profile(ProfileCommands), + /// Questions handling + #[command(subcommand)] + Questions(QuestionsCommands), } diff --git a/rust/agama-cli/src/main.rs b/rust/agama-cli/src/main.rs index c3b05dde56..5baabc713c 100644 --- a/rust/agama-cli/src/main.rs +++ b/rust/agama-cli/src/main.rs @@ -6,6 +6,7 @@ mod error; mod printers; mod profile; mod progress; +mod questions; use crate::error::CliError; use agama_lib::error::ServiceError; @@ -17,6 +18,7 @@ use config::run as run_config_cmd; use printers::Format; use profile::run as run_profile_cmd; use progress::InstallerProgress; +use questions::run as run_questions_cmd; use std::{ process::{ExitCode, Termination}, thread::sleep, @@ -128,6 +130,7 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { let manager = build_manager().await?; block_on(install(&manager, 3)) } + Commands::Questions(subcommand) => block_on(run_questions_cmd(subcommand)), _ => unimplemented!(), } } diff --git a/rust/agama-cli/src/questions.rs b/rust/agama-cli/src/questions.rs new file mode 100644 index 0000000000..d0a22c1c00 --- /dev/null +++ b/rust/agama-cli/src/questions.rs @@ -0,0 +1,48 @@ +use agama_lib::connection; +use agama_lib::proxies::Questions1Proxy; +use anyhow::{Context, Ok}; +use clap::{Args, Subcommand, ValueEnum}; + +#[derive(Subcommand, Debug)] +pub enum QuestionsCommands { + /// Set mode for answering questions. + Mode(ModesArgs), +} + +#[derive(Args, Debug)] +pub struct ModesArgs { + #[arg(value_enum)] + value: Modes, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub enum Modes { + Interactive, + NonInteractive, +} +// TODO when more commands is added, refactor and add it to agama-lib and share a bit of functionality +async fn set_mode(value: Modes) -> anyhow::Result<()> { + match value { + Modes::NonInteractive => { + let connection = connection().await?; + let proxy = Questions1Proxy::new(&connection) + .await + .context("Failed to connect to Questions service")?; + + // TODO: how to print dbus error in that anyhow? + proxy + .use_default_answer() + .await + .context("Failed to set default answer")?; + } + Modes::Interactive => log::info!("not implemented"), //TODO do it + } + + Ok(()) +} + +pub async fn run(subcommand: QuestionsCommands) -> anyhow::Result<()> { + match subcommand { + QuestionsCommands::Mode(value) => set_mode(value.value).await, + } +} diff --git a/rust/agama-lib/src/proxies.rs b/rust/agama-lib/src/proxies.rs index d2f31e00da..d6678c0701 100644 --- a/rust/agama-lib/src/proxies.rs +++ b/rust/agama-lib/src/proxies.rs @@ -111,30 +111,32 @@ trait Locale1 { fn set_vconsole_keyboard(&self, value: &str) -> zbus::Result<()>; } -#[dbus_proxy( - interface = "org.opensuse.Agama.Questions1", - default_service = "org.opensuse.Agama.Questions1", - default_path = "/org/opensuse/Agama/Questions1" -)] +#[dbus_proxy(interface = "org.opensuse.Agama.Questions1", assume_defaults = true)] trait Questions1 { /// Delete method fn delete(&self, question: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>; /// New method #[dbus_proxy(name = "New")] - fn create( + fn new_generic( &self, + class: &str, text: &str, options: &[&str], - default_option: &[&str], + default_option: &str, + data: std::collections::HashMap<&str, &str>, ) -> zbus::Result; - /// NewLuksActivation method - fn new_luks_activation( + /// NewWithPassword method + fn new_with_password( &self, - device: &str, - label: &str, - size: &str, - attempt: u8, + class: &str, + text: &str, + options: &[&str], + default_option: &str, + data: std::collections::HashMap<&str, &str>, ) -> zbus::Result; + + /// UseDefaultAnswer method + fn use_default_answer(&self) -> zbus::Result<()>; } diff --git a/rust/agama-lib/src/questions.rs b/rust/agama-lib/src/questions.rs index d50c72f07e..b5e6b75970 100644 --- a/rust/agama-lib/src/questions.rs +++ b/rust/agama-lib/src/questions.rs @@ -43,6 +43,24 @@ impl GenericQuestion { } } + /// Gets object path of given question. It is useful as parameter + /// for deleting it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use agama_lib::questions::GenericQuestion; + /// let question = GenericQuestion::new( + /// 2, + /// "test_class".to_string(), + /// "Really?".to_string(), + /// vec!["Yes".to_string(), "No".to_string()], + /// "No".to_string(), + /// HashMap::new() + /// ); + /// assert_eq!(question.object_path(), "/org/opensuse/Agama/Questions1/2".to_string()); + /// ``` pub fn object_path(&self) -> String { format!("/org/opensuse/Agama/Questions1/{}", self.id) } diff --git a/rust/package/agama-cli.changes b/rust/package/agama-cli.changes index 77619c52e6..20902ea8d0 100644 --- a/rust/package/agama-cli.changes +++ b/rust/package/agama-cli.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Jul 18 13:32:04 UTC 2023 - Josef Reidinger + +- Add to CLI "questions" subcommand with mode option to set + interactive and non-interactive mode (gh#openSUSE/agama#668) + ------------------------------------------------------------------- Mon Jul 17 13:36:56 UTC 2023 - Imobach Gonzalez Sosa