use std::ffi::OsString;
use std::path::Path;
pub fn route(argv: Vec<OsString>, cli: &clap::Command) -> Vec<OsString> {
let Some(first) = argv.get(1) else {
return argv;
};
let Some(name) = first.to_str() else {
return argv;
};
let subcommand = name == "help" || cli.find_subcommand(name).is_some();
if name.starts_with('-') || subcommand || !is_script(Path::new(name)) {
return argv;
}
let mut out = Vec::with_capacity(argv.len() + 3);
out.push(argv[0].clone());
out.extend(["run", "--quiet"].map(OsString::from));
out.push(first.clone());
out.push(OsString::from("--"));
out.extend(argv.into_iter().skip(2));
out
}
fn is_script(path: &Path) -> bool {
if path.extension().is_some_and(|e| e == "b") {
return true;
}
path.is_file() && std::fs::read(path).is_ok_and(|bytes| is_blue_shebang(&bytes))
}
pub fn is_blue_shebang(text: &[u8]) -> bool {
let Some(rest) = text.strip_prefix(b"#!") else {
return false;
};
let line = rest.split(|b| *b == b'\n').next().unwrap_or_default();
String::from_utf8_lossy(line)
.split_whitespace()
.any(|word| Path::new(word).file_name().is_some_and(|n| n == "blue"))
}
#[cfg(test)]
mod tests {
use super::*;
use clap::CommandFactory;
fn routed(args: &[&str]) -> Vec<String> {
let argv = args.iter().map(OsString::from).collect();
route(argv, &crate::Cli::command())
.into_iter()
.map(|a| a.to_string_lossy().into_owned())
.collect()
}
#[test]
fn a_b_file_runs_quietly_with_its_arguments_verbatim() {
assert_eq!(
routed(&["blue", "x.b", "-q", "--", "a"]),
["blue", "run", "--quiet", "x.b", "--", "-q", "--", "a"]
);
}
#[test]
fn subcommands_flags_and_other_files_are_left_to_clap() {
for args in [
&["blue"][..],
&["blue", "test", "x.b"],
&["blue", "help"],
&["blue", "--version"],
&["blue", "Cargo.toml"],
] {
assert_eq!(routed(args), args, "{args:?}");
}
}
#[test]
fn a_shebang_names_blue_as_the_program_or_an_argument() {
for yes in [
"#!/usr/bin/env blue\n1",
"#!/usr/bin/env -S blue\n",
"#!/nix/store/x-blue/bin/blue",
] {
assert!(is_blue_shebang(yes.as_bytes()), "{yes}");
}
for no in [
"#!/usr/bin/env bluez\n",
"#!/bin/sh\nblue x.b\n",
"# blue\n",
"",
] {
assert!(!is_blue_shebang(no.as_bytes()), "{no}");
}
}
}