shell_compose/
justfile.rs1use serde::Deserialize;
2use std::collections::HashMap;
3use std::process::Command;
4use thiserror::Error;
5
6pub struct Justfile {
7 justfile: JustfileDump,
8}
9
10#[derive(Deserialize, Debug)]
12struct JustfileDump {
13 recipes: HashMap<String, JustfileRecipe>,
20 }
41
42#[derive(Deserialize, Debug)]
43struct JustfileRecipe {
44 attributes: Vec<HashMap<String, String>>,
45 name: String,
50 }
57
58#[derive(Error, Debug)]
59pub enum JustfileError {
60 #[error("Error in calling just executable: {0}")]
61 SpawnError(#[from] std::io::Error),
62 #[error("Invalid characters in justfile: {0}")]
63 Utf8Error(#[from] std::string::FromUtf8Error),
64 #[error("justfile version mismatch: {0}")]
65 JsonError(#[from] serde_json::error::Error),
66}
67
68impl Justfile {
69 pub fn parse() -> Result<Self, JustfileError> {
70 let output = Command::new("just")
71 .args(["--dump", "--dump-format", "json"])
72 .output()?;
73 let jsonstr = String::from_utf8(output.stdout)?;
74 let justfile = serde_json::from_str(&jsonstr)?;
75 let just = Justfile { justfile };
76 Ok(just)
77 }
78 pub fn group_recipes(&self, group: &str) -> Vec<String> {
79 let recipes = self.justfile.recipes.values().filter(|recipe| {
80 recipe
81 .attributes
82 .iter()
83 .any(|attr| attr.get("group").map(|g| g == group).unwrap_or(false))
84 });
85 recipes.map(|recipe| recipe.name.clone()).collect()
86 }
87}