76 lines
2.5 KiB
Rust
76 lines
2.5 KiB
Rust
use clap::{CommandFactory, ValueEnum};
|
|
use clap_complete::{Shell, generate_to};
|
|
use std::{env, ffi::OsString, fs, io::Error, path::PathBuf};
|
|
|
|
include!("src/cli/mod.rs");
|
|
|
|
fn shell_name(shell: Shell) -> String {
|
|
shell
|
|
.to_possible_value()
|
|
.map(|v| v.get_name().to_owned())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn non_empty(name: &str) -> Option<OsString> {
|
|
env::var_os(name).filter(|v| !v.is_empty())
|
|
}
|
|
|
|
fn install_dir(shell: Shell) -> Option<(PathBuf, bool)> {
|
|
let per_shell = format!("SHELL_COMPLETIONS_DIR_{}", shell_name(shell).to_uppercase());
|
|
|
|
if let Some(dir) = non_empty(&per_shell).or_else(|| non_empty("SHELL_COMPLETIONS_DIR")) {
|
|
return Some((PathBuf::from(dir), true));
|
|
}
|
|
non_empty("OUT_DIR").map(|dir| (PathBuf::from(dir), false))
|
|
}
|
|
|
|
fn main() -> Result<(), Error> {
|
|
// naming any rerun-if condition replaces cargo's default of re-running the
|
|
// script whenever anything in the package changed, so everything that
|
|
// shapes a completion script has to be named here. without them an
|
|
// installed script goes stale against the binary it completes
|
|
println!("cargo::rerun-if-changed=build.rs");
|
|
println!("cargo::rerun-if-changed=src/cli");
|
|
println!("cargo::rerun-if-changed=Cargo.toml");
|
|
|
|
println!("cargo::rerun-if-env-changed=SHELL_COMPLETIONS_DIR");
|
|
for shell in Shell::value_variants() {
|
|
println!(
|
|
"cargo::rerun-if-env-changed=SHELL_COMPLETIONS_DIR_{}",
|
|
shell_name(*shell).to_uppercase()
|
|
);
|
|
}
|
|
|
|
let mut cmd = ahab::Ahab::command();
|
|
|
|
for shell in Shell::value_variants() {
|
|
let Some((dir, requested)) = install_dir(*shell) else {
|
|
continue;
|
|
};
|
|
|
|
// a build script's working directory is the package root, so a relative
|
|
// dir would quietly install into the source tree and one holding `..`
|
|
// somewhere else again. only a path that says where it means is taken
|
|
if requested && !dir.is_absolute() {
|
|
return Err(Error::other(format!(
|
|
"the completions directory must be an absolute path, not {}",
|
|
dir.display()
|
|
)));
|
|
}
|
|
|
|
fs::create_dir_all(&dir)
|
|
.map_err(|e| Error::other(format!("creating {}: {e}", dir.display())))?;
|
|
let path = generate_to(*shell, &mut cmd, env!("CARGO_PKG_NAME"), &dir)?;
|
|
|
|
if requested {
|
|
println!(
|
|
"cargo::warning=installed {} completion: {}",
|
|
shell_name(*shell),
|
|
path.display()
|
|
);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|