summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorKim Altintop <kim@eagain.io>2023-01-09 13:18:33 +0100
committerKim Altintop <kim@eagain.io>2023-01-09 13:18:33 +0100
commitd2f423521ec76406944ad83098ec33afe20c692b (patch)
treeafd86bcb088eebdd61ba4e52fa666ff0f41c42a2 /src/bin
This is it
Squashed commit of all the exploration history. Development starts here. Signed-off-by: Kim Altintop <kim@eagain.io>
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/it.rs181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/bin/it.rs b/src/bin/it.rs
new file mode 100644
index 0000000..e6d5d4c
--- /dev/null
+++ b/src/bin/it.rs
@@ -0,0 +1,181 @@
+// Copyright © 2022 Kim Altintop <kim@eagain.io>
+// SPDX-License-Identifier: GPL-2.0-only WITH openvpn-openssl-exception
+
+use std::{
+ io,
+ path::PathBuf,
+};
+
+use clap::ValueHint;
+use clap_complete::Shell;
+
+static OUTPUT: it::Output = it::Output;
+
+fn main() -> it::Result<()> {
+ use clap::Parser as _;
+
+ log::set_logger(&OUTPUT)?;
+ log::set_max_level(
+ std::env::var("RUST_LOG")
+ .ok()
+ .and_then(|v| v.parse().ok())
+ .unwrap_or(log::LevelFilter::Info),
+ );
+
+ let cli = It::parse();
+ match cli.cmd {
+ Cmd::Cmd(cmd) => cmd
+ .run()
+ .and_then(|o| render(o, cli.compact))
+ .or_else(|e| e.downcast::<it::cmd::Aborted>().map(|_aborted| ())),
+ Cmd::Hidden(cmd) => match cmd {
+ Hidden::Man { out } => hidden::mangen(&out),
+ Hidden::Completions { shell, out } => hidden::completions(shell, out.as_deref()),
+ },
+ }
+}
+
+/// it: zero-g git
+#[derive(Debug, clap::Parser)]
+#[clap(author, version, about, propagate_version = true, max_term_width = 100)]
+struct It {
+ /// Path to the git repository containing the drop state
+ #[clap(
+ long,
+ value_parser,
+ value_name = "DIR",
+ env = "GIT_DIR",
+ default_value_os_t = std::env::current_dir().unwrap(),
+ value_hint = ValueHint::DirPath,
+ global = true,
+ )]
+ git_dir: PathBuf,
+ /// Do not pretty-print the output
+ #[clap(long, value_parser, default_value_t = false, global = true)]
+ compact: bool,
+ #[clap(subcommand)]
+ cmd: Cmd,
+}
+
+fn render(output: it::cmd::Output, compact: bool) -> it::Result<()> {
+ use it::cmd::Output::*;
+
+ let go = |v| {
+ let out = io::stdout();
+ if compact {
+ serde_json::to_writer(out, &v)
+ } else {
+ serde_json::to_writer_pretty(out, &v)
+ }
+ };
+
+ match output {
+ Val(v) => go(v)?,
+ Iter(i) => {
+ for v in i {
+ let v = v?;
+ go(v)?;
+ println!();
+ }
+ },
+ }
+
+ Ok(())
+}
+
+#[derive(Debug, clap::Subcommand)]
+#[allow(clippy::large_enum_variant)]
+enum Cmd {
+ #[clap(flatten)]
+ Cmd(it::Cmd),
+ #[clap(flatten)]
+ Hidden(Hidden),
+}
+
+#[derive(Debug, clap::Subcommand)]
+#[clap(hide = true)]
+enum Hidden {
+ /// Generate man pages
+ #[clap(hide = true)]
+ Man {
+ /// Output to this directory
+ #[clap(
+ value_parser,
+ default_value = "man",
+ value_name = "DIR",
+ value_hint = ValueHint::DirPath,
+ )]
+ out: PathBuf,
+ },
+ /// Generate shell completions
+ #[clap(hide = true)]
+ Completions {
+ /// The shell to generate completions for
+ #[clap(value_parser)]
+ shell: Shell,
+ /// Output file (stdout if not set)
+ #[clap(value_parser, value_name = "FILE", value_hint = ValueHint::FilePath)]
+ out: Option<PathBuf>,
+ },
+}
+
+mod hidden {
+ use std::{
+ fs::File,
+ io,
+ path::Path,
+ };
+
+ use clap::CommandFactory as _;
+ use clap_complete::Shell;
+ use clap_mangen::Man;
+
+ pub fn mangen(out: &Path) -> it::Result<()> {
+ std::fs::create_dir_all(out)?;
+ let it = super::It::command();
+ for cmd in it.get_subcommands() {
+ if cmd.get_name() == "dev" {
+ continue;
+ }
+ for sub in cmd.get_subcommands() {
+ let name = format!("{}-{}-{}", it.get_name(), cmd.get_name(), sub.get_name());
+ let filename = out.join(&name).with_extension("1");
+
+ let the_cmd = sub.clone().name(&name);
+ let man = Man::new(the_cmd)
+ .title(name.to_uppercase())
+ .section("1")
+ .manual("It Manual");
+
+ eprintln!("Generating {}...", filename.display());
+ man.render(
+ &mut File::options()
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(&filename)?,
+ )?;
+ }
+ }
+
+ Ok(())
+ }
+
+ pub fn completions(shell: Shell, out: Option<&Path>) -> it::Result<()> {
+ match out {
+ Some(path) => {
+ let mut out = File::options()
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(path)?;
+ clap_complete::generate(shell, &mut super::It::command(), "it", &mut out);
+ },
+ None => {
+ clap_complete::generate(shell, &mut super::It::command(), "it", &mut io::stdout());
+ },
+ }
+
+ Ok(())
+ }
+}