From b7353194746dbe0a86ab0a17cd48cd7aaafa5975 Mon Sep 17 00:00:00 2001 From: Didier Wenzek Date: Mon, 6 Jan 2025 17:15:37 +0100 Subject: [PATCH] fixup! Trigger tedge multicall with symlinks as well as sub-commands --- crates/core/tedge/src/main.rs | 70 ++++++++++++++++++++++++----- crates/core/tedge_agent/src/lib.rs | 6 --- crates/core/tedge_mapper/src/lib.rs | 6 --- crates/core/tedge_write/src/bin.rs | 6 --- 4 files changed, 58 insertions(+), 30 deletions(-) diff --git a/crates/core/tedge/src/main.rs b/crates/core/tedge/src/main.rs index 12b603daee7..03d004c299f 100644 --- a/crates/core/tedge/src/main.rs +++ b/crates/core/tedge/src/main.rs @@ -9,6 +9,7 @@ use clap::CommandFactory; use clap::FromArgMatches; use clap::Parser; use std::alloc; +use std::ffi::OsString; use std::future::Future; use std::io::IsTerminal; use std::path::PathBuf; @@ -35,7 +36,7 @@ fn main() -> anyhow::Result<()> { tedge_apt_plugin::run_and_exit(try_opt); } - let opt = parse_multicall_if_known(&executable_name); + let opt = parse_multicall(&executable_name, std::env::args_os()); match opt { TEdgeOptMulticall::Component(Component::TedgeMapper(opt)) => { let tedge_config = tedge_config::TEdgeConfig::load(&opt.common.config_dir)?; @@ -124,7 +125,11 @@ fn executable_name() -> Option { ) } -fn parse_multicall_if_known(executable_name: &Option) -> TEdgeOptMulticall { +fn parse_multicall(executable_name: &Option, args: Args) -> TEdgeOptMulticall +where + Args: IntoIterator, + Arg: Into + Clone, +{ let cmd = TEdgeOptMulticall::command(); let is_known_subcommand = executable_name @@ -133,7 +138,7 @@ fn parse_multicall_if_known(executable_name: &Option) -> TEdgeOptMultica let cmd = cmd.multicall(is_known_subcommand); let cmd2 = cmd.clone(); - match TEdgeOptMulticall::from_arg_matches(&cmd.get_matches()) { + match TEdgeOptMulticall::from_arg_matches(&cmd.get_matches_from(args)) { Ok(TEdgeOptMulticall::Tedge { cmd, common }) => redirect_if_multicall(cmd, common), Ok(t) => t, Err(e) => { @@ -148,15 +153,56 @@ fn parse_multicall_if_known(executable_name: &Option) -> TEdgeOptMultica // This method has to be kept in sync with TEdgeOpt::build_command fn redirect_if_multicall(cmd: TEdgeOpt, common: CommonArgs) -> TEdgeOptMulticall { match cmd { - TEdgeOpt::Mapper(opt) => { - TEdgeOptMulticall::Component(Component::TedgeMapper(opt.with_common_args(common))) - } - TEdgeOpt::Agent(opt) => { - TEdgeOptMulticall::Component(Component::TedgeAgent(opt.with_common_args(common))) - } - TEdgeOpt::Write(opt) => { - TEdgeOptMulticall::Component(Component::TedgeWrite(opt.with_common_args(common))) - } + TEdgeOpt::Mapper(opt) => TEdgeOptMulticall::Component(Component::TedgeMapper(opt)), + TEdgeOpt::Agent(opt) => TEdgeOptMulticall::Component(Component::TedgeAgent(opt)), + TEdgeOpt::Write(opt) => TEdgeOptMulticall::Component(Component::TedgeWrite(opt)), cmd => TEdgeOptMulticall::Tedge { cmd, common }, } } + +#[cfg(test)] +mod tests { + use crate::parse_multicall; + use crate::Component; + use crate::TEdgeOptMulticall; + use test_case::test_case; + + #[test] + fn launching_a_mapper() { + let exec = Some("tedge-mapper".to_string()); + let cmd = parse_multicall(&exec, ["tedge-mapper", "c8y"]); + assert!(matches!( + cmd, + TEdgeOptMulticall::Component(Component::TedgeMapper(_)) + )) + } + + #[test] + fn using_tedge_to_launch_a_mapper() { + let exec = Some("tedge".to_string()); + let cmd = parse_multicall(&exec, ["tedge", "mapper", "c8y"]); + assert!(matches!( + cmd, + TEdgeOptMulticall::Component(Component::TedgeMapper(_)) + )) + } + + #[test_case("tedge-mapper c8y --config-dir /some/dir")] + #[test_case("tedge-mapper --config-dir /some/dir c8y")] + #[test_case("tedge mapper c8y --config-dir /some/dir --debug")] + #[test_case("tedge mapper --config-dir /some/dir c8y --debug")] + #[test_case("tedge --config-dir /some/dir mapper c8y")] + // clap fails to raise an error here and takes the inner value for all global args + #[test_case("tedge --config-dir /oops mapper c8y --config-dir /some/dir")] + fn setting_config_dir(cmd_line: &'static str) { + let args: Vec<&str> = cmd_line.split(' ').collect(); + let exec = Some(args.get(0).unwrap().to_string()); + let cmd = parse_multicall(&exec, args); + match cmd { + TEdgeOptMulticall::Component(Component::TedgeMapper(mapper)) => { + assert_eq!(mapper.common.config_dir, "/some/dir") + } + _ => panic!(), + } + } +} diff --git a/crates/core/tedge_agent/src/lib.rs b/crates/core/tedge_agent/src/lib.rs index cc5e9c1a1e6..ad89fa4eb35 100644 --- a/crates/core/tedge_agent/src/lib.rs +++ b/crates/core/tedge_agent/src/lib.rs @@ -51,12 +51,6 @@ pub struct AgentOpt { pub mqtt_topic_root: Option>, } -impl AgentOpt { - pub fn with_common_args(self, common: CommonArgs) -> Self { - Self { common, ..self } - } -} - pub async fn run(agent_opt: AgentOpt) -> Result<(), anyhow::Error> { let tedge_config_location = tedge_config::TEdgeConfigLocation::from_custom_root(agent_opt.common.config_dir.clone()); diff --git a/crates/core/tedge_mapper/src/lib.rs b/crates/core/tedge_mapper/src/lib.rs index d4da8e9d88f..d1de6fe3efe 100644 --- a/crates/core/tedge_mapper/src/lib.rs +++ b/crates/core/tedge_mapper/src/lib.rs @@ -118,12 +118,6 @@ impl fmt::Display for MapperName { } } -impl MapperOpt { - pub fn with_common_args(self, common: CommonArgs) -> Self { - Self { common, ..self } - } -} - pub async fn run(mapper_opt: MapperOpt) -> anyhow::Result<()> { let mapper_name = mapper_opt.name.to_string(); let component = lookup_component(mapper_opt.name); diff --git a/crates/core/tedge_write/src/bin.rs b/crates/core/tedge_write/src/bin.rs index e95f8f8586b..76c355255bb 100644 --- a/crates/core/tedge_write/src/bin.rs +++ b/crates/core/tedge_write/src/bin.rs @@ -37,12 +37,6 @@ pub struct Args { common: CommonArgs, } -impl Args { - pub fn with_common_args(self, common: CommonArgs) -> Self { - Self { common, ..self } - } -} - pub fn run(args: Args) -> anyhow::Result<()> { log_init( "tedge-write",