🥇 export from upstream (bb29385)
This commit is contained in:
@@ -823,7 +823,8 @@ pub fn build_ssh_discovery(
|
||||
git_remote_hosts: &[String],
|
||||
ssh_dir: &Path,
|
||||
) -> Vec<SshDiscoveryEntry> {
|
||||
// Keyed by display_host for deduplication and sorted output.
|
||||
// Keyed by Host alias (not resolved HostName) to preserve distinct blocks
|
||||
// that point to the same server with different keys.
|
||||
let mut map: BTreeMap<String, SshDiscoveryEntry> = BTreeMap::new();
|
||||
|
||||
// 1. Add SSH config blocks where user is git.
|
||||
@@ -831,19 +832,18 @@ pub fn build_ssh_discovery(
|
||||
if !block.is_git_user() {
|
||||
continue;
|
||||
}
|
||||
// display_host = HostName directive, or first alias as fallback.
|
||||
let alias = match block.aliases.first() {
|
||||
Some(a) => a.clone(),
|
||||
None => continue,
|
||||
};
|
||||
let display_host = block
|
||||
.hostname()
|
||||
.unwrap_or_else(|| block.aliases.first().map(|s| s.as_str()).unwrap_or(""))
|
||||
.unwrap_or(alias.as_str())
|
||||
.to_string();
|
||||
if display_host.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let ssh_host_alias = block.aliases.first().cloned();
|
||||
let identity_file = block.identity_file().map(|s| s.to_string());
|
||||
map.entry(display_host.clone()).or_insert_with(|| SshDiscoveryEntry {
|
||||
map.entry(alias.clone()).or_insert_with(|| SshDiscoveryEntry {
|
||||
display_host,
|
||||
ssh_host_alias,
|
||||
ssh_host_alias: Some(alias),
|
||||
identity_file,
|
||||
host_block: Some(block.clone()),
|
||||
source: SshDiscoverySource::SshConfig,
|
||||
@@ -852,9 +852,13 @@ pub fn build_ssh_discovery(
|
||||
|
||||
// 2. Process git remote hosts.
|
||||
for git_host in git_remote_hosts {
|
||||
if let Some(entry) = map.get_mut(git_host.as_str()) {
|
||||
// Hostname already present via SSH config — upgrade source.
|
||||
entry.source = SshDiscoverySource::Both;
|
||||
// Check if this hostname matches any existing entry (by alias or display_host).
|
||||
let existing_key = map.iter()
|
||||
.find(|(_, e)| e.display_host == *git_host || e.ssh_host_alias.as_deref() == Some(git_host))
|
||||
.map(|(k, _)| k.clone());
|
||||
|
||||
if let Some(key) = existing_key {
|
||||
map.get_mut(&key).unwrap().source = SshDiscoverySource::Both;
|
||||
} else {
|
||||
// Check if any SSH block has this git_host as an alias.
|
||||
let alias_match = ssh_blocks.iter().find(|b| {
|
||||
@@ -862,24 +866,9 @@ pub fn build_ssh_discovery(
|
||||
});
|
||||
|
||||
if let Some(block) = alias_match {
|
||||
// The display_host should already be in the map via step 1, but just in case
|
||||
// the block wasn't added (e.g., HostName was set and we keyed on HostName),
|
||||
// upgrade source on whichever entry owns this block's alias.
|
||||
let display = block
|
||||
.hostname()
|
||||
.unwrap_or_else(|| block.aliases.first().map(|s| s.as_str()).unwrap_or(""))
|
||||
.to_string();
|
||||
if let Some(existing) = map.get_mut(&display) {
|
||||
let alias = block.aliases.first().cloned().unwrap_or_default();
|
||||
if let Some(existing) = map.get_mut(&alias) {
|
||||
existing.source = SshDiscoverySource::Both;
|
||||
} else {
|
||||
// Shouldn't normally happen, but handle gracefully.
|
||||
map.insert(display.clone(), SshDiscoveryEntry {
|
||||
display_host: display,
|
||||
ssh_host_alias: block.aliases.first().cloned(),
|
||||
identity_file: block.identity_file().map(|s| s.to_string()),
|
||||
host_block: Some(block.clone()),
|
||||
source: SshDiscoverySource::Both,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// No SSH config match — pure git remote entry.
|
||||
@@ -1310,6 +1299,37 @@ Host myserver
|
||||
assert!(gitlab.ssh_host_alias.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn discover_preserves_distinct_aliases_for_same_hostname() {
|
||||
use crate::ssh_config::parse_ssh_config;
|
||||
let ssh_config_text = "\
|
||||
Host sparkle.g4b.org
|
||||
Hostname git.g4b.org
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_rsa_sparkle
|
||||
|
||||
Host git.g4b.org
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_rsa
|
||||
";
|
||||
let blocks = parse_ssh_config(ssh_config_text);
|
||||
let git_remote_hosts = vec!["git.g4b.org".to_string()];
|
||||
let ssh_dir = Path::new("/nonexistent/.ssh");
|
||||
|
||||
let entries = build_ssh_discovery(&blocks, &git_remote_hosts, ssh_dir);
|
||||
|
||||
assert_eq!(entries.len(), 2, "both aliases should be preserved");
|
||||
|
||||
let sparkle = entries.iter().find(|e| e.ssh_host_alias.as_deref() == Some("sparkle.g4b.org")).unwrap();
|
||||
assert_eq!(sparkle.display_host, "git.g4b.org");
|
||||
assert_eq!(sparkle.identity_file.as_deref(), Some("~/.ssh/id_rsa_sparkle"));
|
||||
|
||||
let direct = entries.iter().find(|e| e.ssh_host_alias.as_deref() == Some("git.g4b.org")).unwrap();
|
||||
assert_eq!(direct.display_host, "git.g4b.org");
|
||||
assert_eq!(direct.identity_file.as_deref(), Some("~/.ssh/id_rsa"));
|
||||
assert_eq!(direct.source, SshDiscoverySource::Both);
|
||||
}
|
||||
|
||||
// -- has_legacy_ssh_mount tests --
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user