1use clap::{Parser, Subcommand};
2
3use crate::{interfaces::ActionResult, Playbook};
4
5#[derive(Parser)]
6struct Args {
7 #[command(subcommand)]
8 command: Option<Commands>,
9}
10
11#[derive(Subcommand)]
12enum Commands {
13 About,
15 Source,
17}
18
19#[derive(Parser)]
20struct ArgsWithInput {
21 #[command(subcommand)]
22 command: CommandsWithInput,
23}
24
25#[derive(Subcommand)]
26enum CommandsWithInput {
27 About {
29 input: Option<String>,
31 },
32 Source,
34 Apply {
36 input: String,
38 },
39}
40
41fn print_about(playbook: &Playbook) {
42 println!("# Playbook: {}", playbook.name);
43 println!();
44 println!("{}", playbook.description);
45}
46
47pub fn run_cli(playbook: Playbook, source: &'static str) {
48 let args = Args::parse();
49 if let Some(cmd) = args.command {
50 match cmd {
51 Commands::About => print_about(&playbook),
52 Commands::Source => println!("{source}"),
53 }
54 } else if playbook.apply() == ActionResult::Fail {
55 std::process::exit(1);
56 }
57}
58
59impl From<Playbook> for Result<Playbook, String> {
60 fn from(value: Playbook) -> Self {
61 Ok(value)
62 }
63}
64
65pub fn run_cli_with_input<GetPlaybook>(
66 get_playbook: GetPlaybook,
67 input_help: &'static str,
68 source: &'static str,
69) where
70 GetPlaybook: FnOnce(&[u8]) -> Result<Playbook, String>,
71{
72 let args = ArgsWithInput::parse();
73 match args.command {
74 CommandsWithInput::About { input: Some(input) } => match get_playbook(input.as_bytes()) {
75 Ok(pb) => {
76 print_about(&pb);
77 println!();
78 println!("{input_help}");
79 }
80 Err(e) => {
81 println!("{e}");
82 std::process::exit(1);
83 }
84 },
85 CommandsWithInput::About { input: None } => {
86 println!("{input_help}");
87 }
88 CommandsWithInput::Source => println!("{source}"),
89 CommandsWithInput::Apply { input } => match get_playbook(input.as_bytes()) {
90 Ok(pb) => {
91 if pb.apply() == ActionResult::Fail {
92 std::process::exit(1);
93 }
94 }
95 Err(e) => {
96 println!("{e}");
97 std::process::exit(1);
98 }
99 },
100 };
101}