pub fn stale_host(hint: &str) -> String {
let trimmed = hint.trim().trim_end_matches('.');
if trimmed.is_empty() {
"Stale host.".to_string()
} else {
format!("Stale host. {}.", trimmed)
}
}
pub fn copied_ssh_command(alias: &str) -> String {
format!("Copied SSH command for {}.", alias)
}
pub fn copied_config_block(alias: &str) -> String {
format!("Copied config block for {}.", alias)
}
pub fn showing_unreachable(count: usize) -> String {
format!(
"Showing {} unreachable host{}.",
count,
if count == 1 { "" } else { "s" }
)
}
pub fn sorted_by(label: &str) -> String {
format!("Sorted by {}.", label)
}
pub fn sorted_by_save_failed(label: &str, e: &impl std::fmt::Display) -> String {
format!("Sorted by {}. (save failed: {})", label, e)
}
pub fn grouped_by(label: &str) -> String {
format!("Grouped by {}.", label)
}
pub fn grouped_by_save_failed(label: &str, e: &impl std::fmt::Display) -> String {
format!("Grouped by {}. (save failed: {})", label, e)
}
pub const UNGROUPED: &str = "Ungrouped.";
pub fn ungrouped_save_failed(e: &impl std::fmt::Display) -> String {
format!("Ungrouped. (save failed: {})", e)
}
pub const GROUPED_BY_TAG: &str = "Grouped by tag.";
pub fn grouped_by_tag_save_failed(e: &impl std::fmt::Display) -> String {
format!("Grouped by tag. (save failed: {})", e)
}
pub fn host_restored(alias: &str) -> String {
format!("{} is back from the dead.", alias)
}
pub fn restored_tags(count: usize) -> String {
format!(
"Restored tags on {} host{}.",
count,
if count == 1 { "" } else { "s" }
)
}
pub const NOTHING_TO_UNDO: &str = "Nothing to undo.";
pub const NO_IMPORTABLE_HOSTS: &str = "No importable hosts in known_hosts.";
pub const NO_STALE_HOSTS: &str = "No stale hosts.";
pub const NO_HOST_SELECTED: &str = "No host selected.";
pub const NO_HOSTS_TO_RUN: &str = "No hosts to run on.";
pub const NO_HOSTS_TO_TAG: &str = "No hosts to tag.";
pub const PING_FIRST: &str = "Ping first (p/P), then filter with !.";
pub const PINGING_ALL: &str = "Pinging all the things...";
pub const ESC_QUIT_HINT: &str = "Nothing to cancel. Press q to quit.";
pub fn included_file_edit(name: &str) -> String {
format!("{} is in an included file. Edit it there.", name)
}
pub fn included_file_delete(name: &str) -> String {
format!("{} is in an included file. Delete it there.", name)
}
pub fn included_file_clone(name: &str) -> String {
format!("{} is in an included file. Clone it there.", name)
}
pub fn included_host_lives_in(alias: &str, path: &impl std::fmt::Display) -> String {
format!("{} lives in {}. Edit it there.", alias, path)
}
pub fn included_host_clone_there(alias: &str, path: &impl std::fmt::Display) -> String {
format!("{} lives in {}. Clone it there.", alias, path)
}
pub fn included_host_tag_there(alias: &str, path: &impl std::fmt::Display) -> String {
format!("{} is included from {}. Tag it there.", alias, path)
}
pub const HOST_NOT_FOUND_IN_CONFIG: &str = "Host not found in config.";
pub const SMART_PARSED: &str = "Smart-parsed that for you. Check the fields.";
pub const LOOKS_LIKE_ADDRESS: &str = "Looks like an address. Suggested as Host.";
pub const HOST_ALIAS_EMPTY: &str = "Alias can't be empty. Every host needs a name!";
pub const HOST_PATTERN_EMPTY: &str = "Pattern can't be empty.";
pub const HOST_PATTERN_NEEDS_WILDCARD: &str =
"Pattern needs a wildcard (*, ?, [) or multiple hosts.";
pub const HOST_ALIAS_WHITESPACE: &str = "Alias can't contain whitespace. Keep it simple.";
pub const HOST_ALIAS_HASH: &str =
"Alias can't contain '#'. That's a comment character in SSH config.";
pub const HOST_ALIAS_PATTERN_CHARS: &str =
"Alias can't contain pattern characters. That creates a match pattern, not a host.";
pub const HOST_HOSTNAME_EMPTY: &str = "Hostname can't be empty. Where should we connect to?";
pub const HOST_HOSTNAME_WHITESPACE: &str = "Hostname can't contain whitespace.";
pub const HOST_PORT_INVALID: &str = "That's not a port number. Ports are 1-65535, not poetry.";
pub const HOST_PORT_ZERO: &str = "Port 0? Bold choice, but no. Try 1-65535.";
pub const HOST_VAULT_ROLE_INVALID: &str = "Vault SSH role: only letters, digits, /, _ and - \
are allowed (e.g. ssh-client-signer/sign/my-role).";
pub const HOST_VAULT_ADDR_INVALID: &str = "Vault SSH address: must be a non-empty URL \
without spaces or control characters (e.g. http://127.0.0.1:8200).";
pub fn field_control_chars(name: &str) -> String {
format!(
"{} contains control characters. That's not going to work.",
name
)
}
pub fn pattern_already_exists(alias: &str) -> String {
format!("Pattern '{}' already exists.", alias)
}
pub fn host_alias_already_exists(alias: &str) -> String {
format!("'{}' already exists. Aliases must be unique.", alias)
}
pub const PATTERN_NO_LONGER_EXISTS: &str = "Pattern no longer exists.";
pub const HOST_NO_LONGER_EXISTS: &str = "Host no longer exists.";
pub fn cert_path_resolve_failed(e: &impl std::fmt::Display) -> String {
format!("Failed to resolve cert path: {}", e)
}
pub fn welcome_aboard(alias: &str) -> String {
format!("Welcome aboard, {}!", alias)
}
pub const BULK_TAG_NO_HOSTS_SELECTED: &str = "No hosts selected.";
pub fn bulk_tag_apply_status(
changed_hosts: usize,
added: usize,
removed: usize,
skipped_included: usize,
) -> String {
let mut parts: Vec<String> = Vec::new();
if changed_hosts > 0 {
let host_word = if changed_hosts == 1 { "" } else { "s" };
let mut head = format!("Updated {} host{}", changed_hosts, host_word);
let mut delta = Vec::new();
if added > 0 {
delta.push(format!("+{}", added));
}
if removed > 0 {
delta.push(format!("-{}", removed));
}
if !delta.is_empty() {
head = format!("{} ({})", head, delta.join(" "));
}
parts.push(head);
}
if skipped_included > 0 {
let file_word = if skipped_included == 1 { "" } else { "s" };
parts.push(format!(
"skipped {} in include file{}",
skipped_included, file_word
));
}
parts.join(". ")
}
pub fn goodbye_host(alias: &str) -> String {
format!("Goodbye, {}. We barely knew ye. (u to undo)", alias)
}
pub fn host_not_found(alias: &str) -> String {
format!("Host '{}' not found.", alias)
}
pub fn siblings_stripped(alias: &str, sibling_count: usize) -> String {
if sibling_count == 1 {
format!(
"Stripped {}. 1 sibling alias kept its shared config.",
alias
)
} else {
format!(
"Stripped {}. {} sibling aliases kept their shared config.",
alias, sibling_count
)
}
}
pub fn confirm_delete_siblings_note(siblings: &[String]) -> String {
let shown: Vec<&str> = siblings.iter().take(3).map(String::as_str).collect();
let tail = if siblings.len() > shown.len() {
format!(" +{} more", siblings.len() - shown.len())
} else {
String::new()
};
format!("Siblings kept: {}{}", shown.join(", "), tail)
}
pub fn cert_cleanup_warning(path: &impl std::fmt::Display, e: &impl std::fmt::Display) -> String {
format!("Warning: failed to clean up Vault SSH cert {}: {}", path, e)
}
pub const CLONED_VAULT_CLEARED: &str = "Cloned. Vault SSH role cleared on copy.";
pub fn config_repaired(groups: usize, orphaned: usize) -> String {
format!(
"Repaired SSH config ({} absorbed, {} orphaned group headers).",
groups, orphaned
)
}
pub fn no_exact_match(alias: &str) -> String {
format!("No exact match for '{}'. Here's what we found.", alias)
}
pub fn group_pref_reset_failed(e: &impl std::fmt::Display) -> String {
format!("Group preference reset. (save failed: {})", e)
}
pub fn host_key_remove_failed(stderr: &str) -> String {
format!("Failed to remove host key: {}", stderr)
}
pub fn ssh_keygen_failed(e: &impl std::fmt::Display) -> String {
format!("Failed to run ssh-keygen: {}", e)
}
pub fn removed_host_key(hostname: &str) -> String {
format!("Removed host key for {}. Reconnecting...", hostname)
}
pub fn tagged_host(alias: &str, count: usize) -> String {
format!(
"Tagged {} with {} label{}.",
alias,
count,
if count == 1 { "" } else { "s" }
)
}
#[cfg(test)]
mod stale_host_tests {
use super::stale_host;
#[test]
fn empty_hint_returns_bare_sentence() {
assert_eq!(stale_host(""), "Stale host.");
}
#[test]
fn empty_after_trim_returns_bare_sentence() {
assert_eq!(stale_host(" "), "Stale host.");
}
#[test]
fn provider_hint_is_appended_with_space_and_period() {
assert_eq!(
stale_host("Gone from DigitalOcean"),
"Stale host. Gone from DigitalOcean."
);
}
#[test]
fn trailing_period_in_hint_is_not_doubled() {
assert_eq!(
stale_host("Gone from DigitalOcean."),
"Stale host. Gone from DigitalOcean."
);
}
#[test]
fn leading_space_in_hint_is_trimmed() {
assert_eq!(stale_host(" Gone from AWS"), "Stale host. Gone from AWS.");
}
}