🥇 export from upstream (bb29385)
This commit is contained in:
@@ -823,7 +823,8 @@ pub fn build_ssh_discovery(
|
|||||||
git_remote_hosts: &[String],
|
git_remote_hosts: &[String],
|
||||||
ssh_dir: &Path,
|
ssh_dir: &Path,
|
||||||
) -> Vec<SshDiscoveryEntry> {
|
) -> 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();
|
let mut map: BTreeMap<String, SshDiscoveryEntry> = BTreeMap::new();
|
||||||
|
|
||||||
// 1. Add SSH config blocks where user is git.
|
// 1. Add SSH config blocks where user is git.
|
||||||
@@ -831,19 +832,18 @@ pub fn build_ssh_discovery(
|
|||||||
if !block.is_git_user() {
|
if !block.is_git_user() {
|
||||||
continue;
|
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
|
let display_host = block
|
||||||
.hostname()
|
.hostname()
|
||||||
.unwrap_or_else(|| block.aliases.first().map(|s| s.as_str()).unwrap_or(""))
|
.unwrap_or(alias.as_str())
|
||||||
.to_string();
|
.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());
|
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,
|
display_host,
|
||||||
ssh_host_alias,
|
ssh_host_alias: Some(alias),
|
||||||
identity_file,
|
identity_file,
|
||||||
host_block: Some(block.clone()),
|
host_block: Some(block.clone()),
|
||||||
source: SshDiscoverySource::SshConfig,
|
source: SshDiscoverySource::SshConfig,
|
||||||
@@ -852,9 +852,13 @@ pub fn build_ssh_discovery(
|
|||||||
|
|
||||||
// 2. Process git remote hosts.
|
// 2. Process git remote hosts.
|
||||||
for git_host in git_remote_hosts {
|
for git_host in git_remote_hosts {
|
||||||
if let Some(entry) = map.get_mut(git_host.as_str()) {
|
// Check if this hostname matches any existing entry (by alias or display_host).
|
||||||
// Hostname already present via SSH config — upgrade source.
|
let existing_key = map.iter()
|
||||||
entry.source = SshDiscoverySource::Both;
|
.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 {
|
} else {
|
||||||
// Check if any SSH block has this git_host as an alias.
|
// Check if any SSH block has this git_host as an alias.
|
||||||
let alias_match = ssh_blocks.iter().find(|b| {
|
let alias_match = ssh_blocks.iter().find(|b| {
|
||||||
@@ -862,24 +866,9 @@ pub fn build_ssh_discovery(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Some(block) = alias_match {
|
if let Some(block) = alias_match {
|
||||||
// The display_host should already be in the map via step 1, but just in case
|
let alias = block.aliases.first().cloned().unwrap_or_default();
|
||||||
// the block wasn't added (e.g., HostName was set and we keyed on HostName),
|
if let Some(existing) = map.get_mut(&alias) {
|
||||||
// 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) {
|
|
||||||
existing.source = SshDiscoverySource::Both;
|
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 {
|
} else {
|
||||||
// No SSH config match — pure git remote entry.
|
// No SSH config match — pure git remote entry.
|
||||||
@@ -1310,6 +1299,37 @@ Host myserver
|
|||||||
assert!(gitlab.ssh_host_alias.is_none());
|
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 --
|
// -- has_legacy_ssh_mount tests --
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user