Skip to content

Commit

Permalink
better error handling with anyhow
Browse files Browse the repository at this point in the history
and remove the script feature as it was completely buggy and I do not
have the patience to fix it.
  • Loading branch information
chmouel committed Jan 4, 2024
1 parent 3ef085c commit e317450
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 79 deletions.
7 changes: 7 additions & 0 deletions 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
23 changes: 0 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
76 changes: 20 additions & 56 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -21,7 +21,6 @@ struct RaffiConfig {
ifenvnotset: Option<String>,
ifexist: Option<String>,
disabled: Option<bool>,
script: Option<String>,
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -76,14 +75,19 @@ fn get_icon_map() -> HashMap<String, String> {
}

// read configuration from a yaml according to the if conditions
fn read_config(filename: &str) -> Vec<RaffiConfig> {
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<Vec<RaffiConfig>> {
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<RaffiConfig> = 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;
Expand Down Expand Up @@ -128,7 +132,7 @@ fn read_config(filename: &str) -> Vec<RaffiConfig> {
rafficonfigs.push(mc);
}
}
rafficonfigs
Ok(rafficonfigs)
}

fn find_binary(binary: String) -> bool {
Expand Down Expand Up @@ -209,80 +213,40 @@ fn make_fuzzel_input(rafficonfigs: &Vec<RaffiConfig>) -> 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");
if args.refresh_cache {
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()
.expect("cannot launch binary");
child.wait().expect("cannot wait for child");
}
}
Ok(())
}

0 comments on commit e317450

Please sign in to comment.