diff --git a/Cargo.lock b/Cargo.lock index 2e96b6d..8ad9cc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + [[package]] name = "bitflags" version = "1.3.2" @@ -118,6 +124,7 @@ dependencies = [ name = "raffi" version = "0.3.0" dependencies = [ + "anyhow", "gumdrop", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index e94f2ad..74d1d63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ documentation = "https://github.com/chmouel/raffi" repository = "https://github.com/chmouel/raffi" [dependencies] +anyhow = "1.0.79" gumdrop = { version = "0.8.1" } serde = { version = "1.0.194", features = ["derive"] } serde_json = "1.0.110" diff --git a/README.md b/README.md index 1842e85..f1bda0a 100644 --- a/README.md +++ b/README.md @@ -112,29 +112,6 @@ firefox: icons are searched in /usr/share/icons, /usr/share/pixmaps, $HOME/.local/share/icons or in $XDG_DATA_HOME if set and matched to the icon name. You can as well specify the full path in there. -* **script**: If you want to run a script instead of a binary, you can embed a - script directly in the configuration like this: - - ```yaml - script: | - #!/usr/bin/env python3 - import os - os.system("app_to_run") - ``` - - or another example using bash, comining multiple commands: - - ```yaml - script: | - #!/usr/bin/env bash - kitty --class kitty-multi --session multi.session & - swaymsg -t get_tree | jq -r 'recurse(.nodes[]?) | select(.app_id=="kitty-multi") | .id' | xargs -I{} swaymsg "[con_id={}] layout splith" - ``` - - The interpreter in the shbang are respected, if you don't specify a shbang - the script will be run with `/usr/bin/env bash` - - **You need a description for script configuration to be displayed in the launcher** ### Conditions diff --git a/src/main.rs b/src/main.rs index d8c5595..bdebfa1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,13 +2,13 @@ use std::{ collections::HashMap, fs::File, io::{Read, Write}, - os::unix::fs::PermissionsExt, process::{Command, Stdio}, }; use gumdrop::Options; use serde::Deserialize; use serde_yaml::Value; +use anyhow::{Result, Context, Ok}; #[derive(Deserialize)] struct RaffiConfig { @@ -21,7 +21,6 @@ struct RaffiConfig { ifenvnotset: Option, ifexist: Option, disabled: Option, - script: Option, } #[derive(Deserialize)] @@ -76,14 +75,19 @@ fn get_icon_map() -> HashMap { } // read configuration from a yaml according to the if conditions -fn read_config(filename: &str) -> Vec { - let file = - File::open(filename).unwrap_or_else(|_| panic!("cannot open config file {filename}")); - let config: Config = serde_yaml::from_reader(file).expect("cannot parse yaml"); +fn read_config(filename: &str) -> Result> { + let file = File::open(filename).context(format!("cannot open config file {}", filename))?; + let config: Config = serde_yaml::from_reader(file).context(format!( + "cannot parse config file {}", + filename + ))?; let mut rafficonfigs: Vec = Vec::new(); for (_, value) in config.toplevel { if value.is_mapping() { - let mut mc: RaffiConfig = serde_yaml::from_value(value).unwrap(); + let mut mc: RaffiConfig = serde_yaml::from_value(value).context(format!( + "cannot parse config file {}", + filename + ))?; if let Some(disabled) = mc.disabled { if disabled { continue; @@ -128,7 +132,7 @@ fn read_config(filename: &str) -> Vec { rafficonfigs.push(mc); } } - rafficonfigs + Ok(rafficonfigs) } fn find_binary(binary: String) -> bool { @@ -209,11 +213,12 @@ fn make_fuzzel_input(rafficonfigs: &Vec) -> String { ret } -fn main() { +fn main() -> Result<()> { let args = Args::parse_args_default_or_exit(); let home = std::env::var("HOME").unwrap(); - let xdg_config_home = std::env::var("XDG_CONFIG_HOME").unwrap_or(format!("{home}/.config")); + let xdg_config_home = std::env::var("XDG_CONFIG_HOME").unwrap_or_else(|_| format!("{}/.config", home)); + let configfile = args .configfile .unwrap_or(xdg_config_home + "/raffi/raffi.yaml"); @@ -221,63 +226,21 @@ fn main() { let icon_map = get_icon_map(); save_to_cache_file(&icon_map); } - let rafficonfigs = read_config(configfile.as_str()); + let rafficonfigs = read_config(&configfile)?; let inputs = make_fuzzel_input(&rafficonfigs); let ret = run_fuzzel_with_input(inputs); let chosen = ret.split(':').last().unwrap().trim(); for mc in rafficonfigs { - if mc.description.unwrap_or(mc.binary.clone().unwrap()) == chosen { + if mc.description.unwrap_or_else(|| mc.binary.clone().unwrap()) == chosen { if args.print_only { // print the command to stdout with args println!( "{} {}", mc.binary.unwrap(), - mc.args.unwrap_or(vec![]).join(" ") + mc.args.unwrap_or_else(|| vec![]).join(" ") ); - return; + return Ok(()); } - if let Some(mut script) = mc.script { - // check first line for an interpreter and then write script as temporary file, set as executable and run - let mut lines = script.lines(); - let first_line = lines.next().unwrap(); - if !first_line.starts_with("#!") { - script = "#!/usr/bin/env sh\n".to_string() + &script; - } - let mut script_file = tempfile::NamedTempFile::new().unwrap(); - script_file - .write_all(script.as_bytes()) - .expect("cannot write to tempfile"); - // set temp file as executable - let _set_permissions = script_file - .as_file() - .set_permissions(std::fs::Permissions::from_mode(0o755)); - let path = script_file - .into_temp_path() - .keep() - .expect("cannot keep tempfile") - .as_path() - .to_str() - .unwrap() - .to_string(); - - // execute the temp file - let mut child = Command::new(path) - .args(mc.args.unwrap_or(vec![])) - .spawn() - .expect("cannot launch script"); - child.wait().expect("cannot wait for child"); - return; - } - - // let mut script_file = tempfile::NamedTempFile::new().unwrap(); - // script_file - // .write_all(script.as_bytes()) - // .expect("cannot write to tempfile"); - // let mut child = Command::new("sh") - // .args(["-c", script.as_str()]) - // .spawn() - // .expect("cannot launch script"); - // child.wait().expect("cannot wait for child"); let mut child = Command::new(mc.binary.unwrap()) .args(mc.args.unwrap_or(vec![])) .spawn() @@ -285,4 +248,5 @@ fn main() { child.wait().expect("cannot wait for child"); } } + Ok(()) }