mirror of
https://codeberg.org/icewind/haze.git
synced 2026-10-01 08:44:09 +02:00
This will create a dedicated worktree for the instance. App listed to be enabled will also benefit from their own worktrees. The worktree is cleanup when the instance is destroyed.
276 lines
8.7 KiB
Rust
276 lines
8.7 KiB
Rust
use crate::args::{HazeCommand, SubCommand};
|
|
use crate::database::DatabaseFamily;
|
|
use crate::php::PhpVersion;
|
|
use crate::service::ServiceType;
|
|
use owo_colors::colors::xterm::Gray;
|
|
use owo_colors::OwoColorize;
|
|
use strum::{EnumMessage, EnumProperty, IntoEnumIterator};
|
|
|
|
pub fn help(command: Option<&dyn SubCommand>) {
|
|
if let Some(command) = command {
|
|
subcommand_help(command);
|
|
} else {
|
|
println!(
|
|
"{} {} {}",
|
|
"Usage:".bright_yellow().bold(),
|
|
"haze".blue(),
|
|
"[filter] <COMMAND> [arguments]".green()
|
|
);
|
|
println!();
|
|
println!("{}", "Commands:".yellow().bold());
|
|
let max_command_len = HazeCommand::iter()
|
|
.map(|command| <&'static str>::from(command).len())
|
|
.max()
|
|
.unwrap();
|
|
let max_doc_len = HazeCommand::iter()
|
|
.map(|command| {
|
|
command
|
|
.get_documentation()
|
|
.unwrap_or_default()
|
|
.split('\n')
|
|
.next()
|
|
.unwrap()
|
|
.len()
|
|
})
|
|
.max()
|
|
.unwrap();
|
|
|
|
for command in HazeCommand::iter() {
|
|
let command: HazeCommand = command;
|
|
let command_str = <&'static str>::from(command);
|
|
let mut len = command_str.len();
|
|
if command_str.starts_with("--") {
|
|
len -= 2;
|
|
}
|
|
let doc: &str = command.get_documentation().unwrap_or_default();
|
|
let doc = doc.split('\n').next().unwrap();
|
|
println!(
|
|
" {}{} {}{} {}",
|
|
command.blue(),
|
|
" ".repeat(max_command_len - len),
|
|
doc,
|
|
" ".repeat(max_doc_len - doc.len()),
|
|
if command.allows_filter() {
|
|
"- supports filter".fg::<Gray>()
|
|
} else {
|
|
"".fg::<Gray>()
|
|
},
|
|
);
|
|
}
|
|
println!();
|
|
println!(
|
|
"See {} {} for more information about a {}",
|
|
"haze help".blue(),
|
|
"<COMMAND>".green(),
|
|
"<COMMAND>".green()
|
|
);
|
|
}
|
|
}
|
|
|
|
fn subcommand_help(command: &dyn SubCommand) {
|
|
println!("{}", command.get_documentation().unwrap_or_default());
|
|
println!();
|
|
print!(
|
|
"{} {}{}{} {}",
|
|
"Usage:".bright_yellow().bold(),
|
|
"haze".blue(),
|
|
if command.allows_filter() {
|
|
" [filter]".green()
|
|
} else {
|
|
"".green()
|
|
},
|
|
command.parent().blue(),
|
|
command.blue(),
|
|
);
|
|
|
|
let instance_args = command.get_bool("InstanceArgs").unwrap_or_default();
|
|
if instance_args {
|
|
print!(" {}", "[php version]".green());
|
|
print!(" {}", "[database type]".green());
|
|
print!(" {}", "[services]".green());
|
|
print!(" {}", "[vX.Y.Z]".green());
|
|
print!(" {}", "[--name <name>]".green());
|
|
print!(" {}", "[--detach]".green());
|
|
}
|
|
|
|
let args = if let Some(args) = command.get_str("Args") {
|
|
let args: &str = args;
|
|
print!(" {}", "[arguments]".green());
|
|
args.strip_prefix("[")
|
|
.unwrap_or(args)
|
|
.split(" [")
|
|
.filter_map(|arg| arg.split_once("] "))
|
|
.collect::<Vec<_>>()
|
|
} else {
|
|
vec![]
|
|
};
|
|
println!();
|
|
|
|
println!();
|
|
if instance_args {
|
|
println!("{}", "Php versions:".yellow().bold());
|
|
for php in PhpVersion::supported_versions() {
|
|
println!(" {}", php.blue());
|
|
}
|
|
println!();
|
|
|
|
println!("{}", "Database types:".yellow().bold());
|
|
let max_db_len = DatabaseFamily::iter()
|
|
.map(|service| service.to_string().len())
|
|
.max()
|
|
.unwrap_or_default();
|
|
|
|
for db in DatabaseFamily::iter() {
|
|
let db: DatabaseFamily = db;
|
|
let db_str: &'static str = db.into();
|
|
let versions = match db.get_str("Versions") {
|
|
Some(versions) => {
|
|
let versions: Vec<_> = versions
|
|
.split(' ')
|
|
.map(|version| format!("{}{}{}", db.blue(), ":".blue(), version.blue()))
|
|
.collect();
|
|
Some(versions.join(", "))
|
|
}
|
|
None => None,
|
|
};
|
|
|
|
print!(" {}{} ", db.blue(), " ".repeat(max_db_len - db_str.len()));
|
|
if let Some(versions) = versions {
|
|
println!("supported versions: {versions}");
|
|
} else {
|
|
println!();
|
|
}
|
|
}
|
|
println!();
|
|
|
|
println!("{}", "Services:".yellow().bold());
|
|
let max_service_len = ServiceType::iter()
|
|
.map(|service| service.to_string().len())
|
|
.max()
|
|
.unwrap_or_default();
|
|
for service in ServiceType::iter() {
|
|
let service: ServiceType = service;
|
|
let service_str: &'static str = service.into();
|
|
println!(
|
|
" {}{} {}",
|
|
service.blue(),
|
|
" ".repeat(max_service_len - service_str.len()),
|
|
service.get_documentation().unwrap_or_default(),
|
|
);
|
|
}
|
|
println!();
|
|
|
|
println!("{}", "Options:".yellow().bold());
|
|
println!(
|
|
" {} name the instance instead of generating a random name",
|
|
"--name <name>".blue()
|
|
);
|
|
println!(
|
|
" {} give the instance its own worktree of the sources",
|
|
"--detach".blue()
|
|
);
|
|
}
|
|
|
|
if let Some(sub_commands) = command.sub_commands() {
|
|
println!();
|
|
println!("{}", "Commands:".yellow().bold());
|
|
let max_command_len = command
|
|
.sub_commands()
|
|
.unwrap()
|
|
.map(|sub_command| sub_command.to_string().len())
|
|
.max()
|
|
.unwrap();
|
|
let max_doc_len = command
|
|
.sub_commands()
|
|
.unwrap()
|
|
.map(|sub_command| {
|
|
sub_command
|
|
.get_documentation()
|
|
.unwrap_or_default()
|
|
.split('\n')
|
|
.next()
|
|
.unwrap()
|
|
.len()
|
|
})
|
|
.max()
|
|
.unwrap();
|
|
|
|
for sub_command in sub_commands {
|
|
let command_str = sub_command.to_string();
|
|
let mut len = command_str.len();
|
|
if command_str.starts_with("--") {
|
|
len -= 2;
|
|
}
|
|
let doc: &str = sub_command.get_documentation().unwrap_or_default();
|
|
let doc = doc.split('\n').next().unwrap();
|
|
println!(
|
|
" {}{} {}{} {}",
|
|
sub_command.blue(),
|
|
" ".repeat(max_command_len - len),
|
|
doc,
|
|
" ".repeat(max_doc_len - doc.len()),
|
|
if sub_command.allows_filter() {
|
|
"- supports filter".fg::<Gray>()
|
|
} else {
|
|
"".fg::<Gray>()
|
|
},
|
|
);
|
|
}
|
|
println!();
|
|
println!(
|
|
"See {} {} {} for more information about a {}",
|
|
"haze help".blue(),
|
|
command.blue(),
|
|
"<COMMAND>".green(),
|
|
"<COMMAND>".green()
|
|
);
|
|
}
|
|
|
|
println!();
|
|
if !args.is_empty() {
|
|
let max_arg_len = args
|
|
.iter()
|
|
.map(|(arg, _)| arg.len())
|
|
.max()
|
|
.unwrap_or_default();
|
|
println!("{}", "Arguments:".yellow().bold());
|
|
for (arg, desc) in args {
|
|
println!(
|
|
" {}{}{}{} {}",
|
|
"[".green(),
|
|
arg.green(),
|
|
"]".green(),
|
|
" ".repeat(max_arg_len - arg.len()),
|
|
desc
|
|
);
|
|
}
|
|
}
|
|
|
|
if let Some(details) = command.get_str("Details") {
|
|
println!("{}", format_details(details));
|
|
}
|
|
}
|
|
|
|
fn format_details(details: &str) -> String {
|
|
use std::fmt::Write;
|
|
let mut result = String::with_capacity(details.len());
|
|
for (i, part) in details.split("</").enumerate() {
|
|
let part = if i > 0 {
|
|
// strip the remaining close tag from the previous part
|
|
part.split_once('>').map(|(_, part)| part).unwrap_or(part)
|
|
} else {
|
|
part
|
|
};
|
|
let (head, tail) = part.split_once('<').unwrap_or((part, ""));
|
|
result.push_str(head);
|
|
if let Some((tag, content)) = tail.split_once('>') {
|
|
match tag {
|
|
"literal" => write!(&mut result, "{}", content.blue()).unwrap(),
|
|
"arg" => write!(&mut result, "{}", content.green()).unwrap(),
|
|
"yellow" => write!(&mut result, "{}", content.bright_yellow()).unwrap(),
|
|
_ => write!(&mut result, "{content}").unwrap(),
|
|
}
|
|
}
|
|
}
|
|
result
|
|
}
|