shell_compose/
justfile.rs

1use serde::Deserialize;
2use std::collections::HashMap;
3use std::process::Command;
4use thiserror::Error;
5
6pub struct Justfile {
7    justfile: JustfileDump,
8}
9
10/// Output of `just --dump --dump-format json`
11#[derive(Deserialize, Debug)]
12struct JustfileDump {
13    // aliases: {},
14    // assignments: {},
15    // doc: null,
16    // first: Option<String>,
17    // groups: [],
18    // modules: {},
19    recipes: HashMap<String, JustfileRecipe>,
20    // settings: HashMap<String, serde_json::Value>,
21    //   "allow_duplicate_recipes": false,
22    //   "allow_duplicate_variables": false,
23    //   "dotenv_filename": null,
24    //   "dotenv_load": false,
25    //   "dotenv_path": null,
26    //   "dotenv_required": false,
27    //   "export": false,
28    //   "fallback": false,
29    //   "ignore_comments": false,
30    //   "positional_arguments": false,
31    //   "quiet": false,
32    //   "shell": null,
33    //   "tempdir": null,
34    //   "unstable": false,
35    //   "windows_powershell": false,
36    //   "windows_shell": null,
37    //   "working_directory": null
38    //  unexports: [],
39    //  warnings: []
40}
41
42#[derive(Deserialize, Debug)]
43struct JustfileRecipe {
44    attributes: Vec<HashMap<String, String>>,
45    //   "group": "autostart"
46    // body: [...],
47    // dependencies: [],
48    // doc: null,
49    name: String,
50    // namepath: String,
51    // parameters: [],
52    // priors: 0,
53    // private: false,
54    // quiet: false,
55    // shebang: true
56}
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}