1use anyhow::{Context as _, Result};
12use clap::{
13 Parser as _,
14 error::{ContextKind, ContextValue},
15};
16use serde::Deserialize;
17use std::ffi::OsString;
18use std::path::Path;
19
20mod arg;
22mod settings;
24mod subcommand;
26mod utils;
28mod version;
30
31use arg::{Cli, Commands};
32
33#[derive(Debug, Clone, Default, Deserialize)]
34struct Options {
38 #[expect(dead_code, reason = "not implemented yet")]
39 val1: String,
41}
42
43#[expect(clippy::single_call_fn, reason = "better readability")]
45fn read_file(path: &Path) -> Result<Options> {
46 let _content =
47 fs_err::read_to_string(path).context(format!("Failed to read file: {}", path.display()))?;
48 let options: Options = Options::default();
49 Ok(options)
50}
51
52#[derive(Debug, Clone)]
53#[expect(dead_code, reason = "not implemented yet")]
56struct FilesystemOptions(Options);
57
58impl FilesystemOptions {
59 #[expect(clippy::single_call_fn, reason = "better readability")]
61 pub fn from_file(file: &Path) -> Result<Self> {
62 let options: Options = read_file(file)?;
63 Ok(Self(options))
64 }
65}
66
67#[inline]
86pub fn run<I, T>(args: I) -> Result<()>
87where
88 I: IntoIterator<Item = T>,
89 T: Into<OsString> + Clone,
90{
91 let cli = match Cli::try_parse_from(args) {
92 Ok(cli) => cli,
93 Err(mut err) => {
94 #[expect(clippy::single_match, reason = "better readability")]
95 #[expect(clippy::pattern_type_mismatch, reason = "I don't know")]
96 match err.get(ContextKind::InvalidSubcommand) {
97 Some(ContextValue::String(subcommand)) => match subcommand.as_str() {
98 "help" => {
99 err.insert(
100 ContextKind::InvalidSubcommand,
101 ContextValue::String("help".to_owned()),
102 );
103 }
104 "module" => {
105 err.insert(
106 ContextKind::InvalidSubcommand,
107 ContextValue::String("module".to_owned()),
108 );
109 }
110 _ => {}
111 },
112 _ => {}
113 }
114 err.exit()
115 }
116 };
117
118 let filesystem = if let Some(config_file) = cli.top_level.config_file.as_ref() {
119 Some(FilesystemOptions::from_file(config_file)?)
120 } else {
121 None
122 };
123
124 #[expect(clippy::todo, reason = "implement later")]
125 if let Some(_filesystem) = filesystem {
126 todo!("TODO: read as global settings");
127 }
128
129 let _global_settings = settings::GlobalSettings::resolve(&cli.top_level.global_args);
131
132 let result = match *cli.command {
133 #[expect(clippy::todo, reason = "implement later")]
134 Commands::Help(_help_args) => {
135 todo!("TODO: implement help command");
136 }
137 Commands::Module(module_args) => subcommand::module::module(module_args),
138 };
139 result.context("Failed to run command")
140}