1 Commits
Author SHA1 Message Date
qwsdcvghyu89 ec8829bef2 Refactor SshHosts for immutability and improve retrieval methods 2025-09-21 15:58:10 +10:00
12 changed files with 268 additions and 27 deletions
+10 -18
View File
@@ -1,6 +1,8 @@
// Required namespaces:
// System, System.IO, System.Linq, System.Text, System.Text.RegularExpressions, System.Collections.Generic, Renci.SshNet
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Text.RegularExpressions;
@@ -21,10 +23,11 @@ public record Host(
);
public static class SshHosts {
public static List<Host> Hosts { get; set; }
private static ImmutableDictionary<string, Host> hosts;
public static IReadOnlyDictionary<string, Host> Hosts => hosts;
static SshHosts() {
Hosts = new List<Host>();
var hosts = new Dictionary<string, Host>();
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
@@ -124,7 +127,7 @@ public static class SshHosts {
foreach (var f in currentIdentityFiles) idFiles.Add(ExpandPath(f));
}
Hosts.Add(new Host(
hosts.Add(n, new Host(
Name: n,
Hostname: hn,
User: currentUser ?? string.Empty,
@@ -233,6 +236,7 @@ public static class SshHosts {
}
Flush();
SshHosts.hosts = hosts.ToImmutableDictionary();
}
// Builds a ConnectionInfo from a parsed host, ensuring all ~/.ssh private keys are tried.
@@ -345,23 +349,11 @@ public static class SshHosts {
public static Host Get(string name) {
for (int i = 0; i < Hosts.Count; i++) {
if (string.Equals(Hosts[i].Name, name, StringComparison.OrdinalIgnoreCase)) {
return Hosts[i];
}
}
throw new KeyNotFoundException($"SSH host '{name}' not found.");
return TryGetHost(name, out var h) ? h : throw new KeyNotFoundException($"SSH host '{name}' not found.");
}
public static bool TryGetHost(string name, out Host host) {
for (int i = 0; i < Hosts.Count; i++) {
if (string.Equals(Hosts[i].Name, name, StringComparison.OrdinalIgnoreCase)) {
host = Hosts[i];
return true;
}
}
host = default!;
return false;
public static bool TryGetHost(string name, [NotNullWhen(true)] out Host? host) {
return Hosts.TryGetValue(name, out host);
}
public static Renci.SshNet.ConnectionInfo GetConnection(string name)
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("aeqw89.tools.Publish")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+cd823abb020af62611aa6afe16e1ac5b49e961b0")]
[assembly: System.Reflection.AssemblyProductAttribute("aeqw89.tools.Publish")]
[assembly: System.Reflection.AssemblyTitleAttribute("aeqw89.tools.Publish")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
@@ -1 +1 @@
e3dc9f23098d7e7631e5f51a024428b60b92087a4a264306a861bae3c79e94dd
c58d819abcee216515191fe2fec7fe270f4c3f5f7e8de377d7c3810ae96fcc2a
@@ -1,4 +1,8 @@
is_global = true
build_property.EnableAotAnalyzer =
build_property.EnableSingleFileAnalyzer =
build_property.EnableTrimAnalyzer =
build_property.IncludeAllContentForSelfExtract =
build_property.TargetFramework = net9.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
@@ -20,6 +20,7 @@
"net9.0"
],
"sources": {
"C:\\Users\\qwsdc\\packages": {},
"https://api.nuget.org/v3/index.json": {},
"https://nuget.pkg.github.com/qwsdcvghyu89/index.json": {}
},
@@ -45,6 +46,12 @@
"net9.0": {
"targetAlias": "net9.0",
"dependencies": {
"Microsoft.NET.ILLink.Tasks": {
"suppressParent": "All",
"target": "Package",
"version": "[9.0.0, )",
"autoReferenced": true
},
"SSH.NET": {
"target": "Package",
"version": "[2025.0.0, )"
@@ -73,6 +80,12 @@
],
"assetTargetFallback": true,
"warn": true,
"downloadDependencies": [
{
"name": "Microsoft.NETCore.App.Host.linux-x64",
"version": "[9.0.0, 9.0.0]"
}
],
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
@@ -80,6 +93,11 @@
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.101/PortableRuntimeIdentifierGraph.json"
}
},
"runtimes": {
"linux-x64": {
"#import": []
}
}
}
}
@@ -7,9 +7,15 @@
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\qwsdc\.nuget\packages\</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.0</NuGetToolVersion>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.12.2</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\qwsdc\.nuget\packages\" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.net.illink.tasks\9.0.0\build\Microsoft.NET.ILLink.Tasks.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.illink.tasks\9.0.0\build\Microsoft.NET.ILLink.Tasks.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgMicrosoft_NET_ILLink_Tasks Condition=" '$(PkgMicrosoft_NET_ILLink_Tasks)' == '' ">C:\Users\qwsdc\.nuget\packages\microsoft.net.illink.tasks\9.0.0</PkgMicrosoft_NET_ILLink_Tasks>
</PropertyGroup>
</Project>
@@ -50,6 +50,155 @@
"buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets": {}
}
},
"Microsoft.NET.ILLink.Tasks/9.0.0": {
"type": "package",
"build": {
"build/Microsoft.NET.ILLink.Tasks.props": {}
}
},
"Spectre.Console/0.51.2-preview.0.1": {
"type": "package",
"compile": {
"lib/net9.0/Spectre.Console.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Spectre.Console.dll": {
"related": ".xml"
}
}
},
"Spectre.Console.Cli/0.51.2-preview.0.1": {
"type": "package",
"dependencies": {
"Spectre.Console": "0.51.2-preview.0.1"
},
"compile": {
"lib/net9.0/Spectre.Console.Cli.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Spectre.Console.Cli.dll": {
"related": ".xml"
}
},
"resource": {
"lib/net9.0/de/Spectre.Console.Cli.resources.dll": {
"locale": "de"
},
"lib/net9.0/es/Spectre.Console.Cli.resources.dll": {
"locale": "es"
},
"lib/net9.0/fr/Spectre.Console.Cli.resources.dll": {
"locale": "fr"
},
"lib/net9.0/it/Spectre.Console.Cli.resources.dll": {
"locale": "it"
},
"lib/net9.0/ja/Spectre.Console.Cli.resources.dll": {
"locale": "ja"
},
"lib/net9.0/ko/Spectre.Console.Cli.resources.dll": {
"locale": "ko"
},
"lib/net9.0/pt/Spectre.Console.Cli.resources.dll": {
"locale": "pt"
},
"lib/net9.0/ru/Spectre.Console.Cli.resources.dll": {
"locale": "ru"
},
"lib/net9.0/sv/Spectre.Console.Cli.resources.dll": {
"locale": "sv"
},
"lib/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll": {
"locale": "zh-Hans"
}
}
},
"SSH.NET/2025.0.0": {
"type": "package",
"dependencies": {
"BouncyCastle.Cryptography": "2.5.1",
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
},
"compile": {
"lib/net9.0/Renci.SshNet.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Renci.SshNet.dll": {
"related": ".xml"
}
}
},
"VsTools.Projects/1.2.0": {
"type": "package",
"compile": {
"lib/netstandard2.0/VsTools.Projects.dll": {}
},
"runtime": {
"lib/netstandard2.0/VsTools.Projects.dll": {}
}
}
},
"net9.0/linux-x64": {
"BouncyCastle.Cryptography/2.5.1": {
"type": "package",
"compile": {
"lib/net6.0/BouncyCastle.Cryptography.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net6.0/BouncyCastle.Cryptography.dll": {
"related": ".xml"
}
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
"type": "package",
"compile": {
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
"related": ".xml"
}
},
"build": {
"buildTransitive/net6.0/_._": {}
}
},
"Microsoft.Extensions.Logging.Abstractions/8.0.3": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
},
"compile": {
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
"related": ".xml"
}
},
"build": {
"buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets": {}
}
},
"Microsoft.NET.ILLink.Tasks/9.0.0": {
"type": "package",
"build": {
"build/Microsoft.NET.ILLink.Tasks.props": {}
}
},
"Spectre.Console/0.51.2-preview.0.1": {
"type": "package",
"compile": {
@@ -265,6 +414,57 @@
"useSharedDesignerContext.txt"
]
},
"Microsoft.NET.ILLink.Tasks/9.0.0": {
"sha512": "zAwp213evC3UkimtVXRb+Dlgc/40QG145nmZDtp2LO9zJJMfrp+i/87BnXN7tRXEA4liyzdFkjqG1HE8/RPb4A==",
"type": "package",
"path": "microsoft.net.illink.tasks/9.0.0",
"hasTools": true,
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"Sdk/Sdk.props",
"THIRD-PARTY-NOTICES.TXT",
"analyzers/dotnet/cs/ILLink.CodeFixProvider.dll",
"analyzers/dotnet/cs/ILLink.RoslynAnalyzer.dll",
"build/Microsoft.NET.ILLink.Analyzers.props",
"build/Microsoft.NET.ILLink.Tasks.props",
"build/Microsoft.NET.ILLink.targets",
"microsoft.net.illink.tasks.9.0.0.nupkg.sha512",
"microsoft.net.illink.tasks.nuspec",
"tools/net472/ILLink.Tasks.dll",
"tools/net472/ILLink.Tasks.dll.config",
"tools/net472/Mono.Cecil.Mdb.dll",
"tools/net472/Mono.Cecil.Pdb.dll",
"tools/net472/Mono.Cecil.Rocks.dll",
"tools/net472/Mono.Cecil.dll",
"tools/net472/Sdk/Sdk.props",
"tools/net472/System.Buffers.dll",
"tools/net472/System.Collections.Immutable.dll",
"tools/net472/System.Memory.dll",
"tools/net472/System.Numerics.Vectors.dll",
"tools/net472/System.Reflection.Metadata.dll",
"tools/net472/System.Runtime.CompilerServices.Unsafe.dll",
"tools/net472/build/Microsoft.NET.ILLink.Analyzers.props",
"tools/net472/build/Microsoft.NET.ILLink.Tasks.props",
"tools/net472/build/Microsoft.NET.ILLink.targets",
"tools/net9.0/ILLink.Tasks.deps.json",
"tools/net9.0/ILLink.Tasks.dll",
"tools/net9.0/Mono.Cecil.Mdb.dll",
"tools/net9.0/Mono.Cecil.Pdb.dll",
"tools/net9.0/Mono.Cecil.Rocks.dll",
"tools/net9.0/Mono.Cecil.dll",
"tools/net9.0/Sdk/Sdk.props",
"tools/net9.0/build/Microsoft.NET.ILLink.Analyzers.props",
"tools/net9.0/build/Microsoft.NET.ILLink.Tasks.props",
"tools/net9.0/build/Microsoft.NET.ILLink.targets",
"tools/net9.0/illink.deps.json",
"tools/net9.0/illink.dll",
"tools/net9.0/illink.runtimeconfig.json",
"useSharedDesignerContext.txt"
]
},
"Spectre.Console/0.51.2-preview.0.1": {
"sha512": "eTojiXsispvwl5i3o6BsBt0fV7pn+jsJ3nbQVCTCwBoYbeczNO2w7wjPfB2Tx+Y5+mplLEtSFi5Mp0aFZSP3tA==",
"type": "package",
@@ -374,6 +574,7 @@
},
"projectFileDependencyGroups": {
"net9.0": [
"Microsoft.NET.ILLink.Tasks >= 9.0.0",
"SSH.NET >= 2025.0.0",
"Spectre.Console >= 0.51.2-preview.0.1",
"Spectre.Console.Cli >= 0.51.2-preview.0.1",
@@ -399,6 +600,7 @@
"net9.0"
],
"sources": {
"C:\\Users\\qwsdc\\packages": {},
"https://api.nuget.org/v3/index.json": {},
"https://nuget.pkg.github.com/qwsdcvghyu89/index.json": {}
},
@@ -424,6 +626,12 @@
"net9.0": {
"targetAlias": "net9.0",
"dependencies": {
"Microsoft.NET.ILLink.Tasks": {
"suppressParent": "All",
"target": "Package",
"version": "[9.0.0, )",
"autoReferenced": true
},
"SSH.NET": {
"target": "Package",
"version": "[2025.0.0, )"
@@ -452,6 +660,12 @@
],
"assetTargetFallback": true,
"warn": true,
"downloadDependencies": [
{
"name": "Microsoft.NETCore.App.Host.linux-x64",
"version": "[9.0.0, 9.0.0]"
}
],
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
@@ -459,6 +673,11 @@
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.101/PortableRuntimeIdentifierGraph.json"
}
},
"runtimes": {
"linux-x64": {
"#import": []
}
}
}
}
+4 -2
View File
@@ -1,16 +1,18 @@
{
"version": 2,
"dgSpecHash": "KOrx7rOcVCU=",
"dgSpecHash": "XMPV4aaWYzc=",
"success": true,
"projectFilePath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj",
"expectedPackageFiles": [
"C:\\Users\\qwsdc\\.nuget\\packages\\bouncycastle.cryptography\\2.5.1\\bouncycastle.cryptography.2.5.1.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\8.0.2\\microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\8.0.3\\microsoft.extensions.logging.abstractions.8.0.3.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.net.illink.tasks\\9.0.0\\microsoft.net.illink.tasks.9.0.0.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\spectre.console\\0.51.2-preview.0.1\\spectre.console.0.51.2-preview.0.1.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\spectre.console.cli\\0.51.2-preview.0.1\\spectre.console.cli.0.51.2-preview.0.1.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\ssh.net\\2025.0.0\\ssh.net.2025.0.0.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\vstools.projects\\1.2.0\\vstools.projects.1.2.0.nupkg.sha512"
"C:\\Users\\qwsdc\\.nuget\\packages\\vstools.projects\\1.2.0\\vstools.projects.1.2.0.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.netcore.app.host.linux-x64\\9.0.0\\microsoft.netcore.app.host.linux-x64.9.0.0.nupkg.sha512"
],
"logs": []
}
@@ -1 +1 @@
"restore":{"projectUniqueName":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj","projectName":"aeqw89.tools.Publish","projectPath":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj","outputPath":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net9.0"],"sources":{"https://api.nuget.org/v3/index.json":{},"https://nuget.pkg.github.com/qwsdcvghyu89/index.json":{}},"frameworks":{"net9.0":{"targetAlias":"net9.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net9.0":{"targetAlias":"net9.0","dependencies":{"SSH.NET":{"target":"Package","version":"[2025.0.0, )"},"Spectre.Console":{"target":"Package","version":"[0.51.2-preview.0.1, )"},"Spectre.Console.Cli":{"target":"Package","version":"[0.51.2-preview.0.1, )"},"VsTools.Projects":{"target":"Package","version":"[1.2.0, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\9.0.101/PortableRuntimeIdentifierGraph.json"}}
"restore":{"projectUniqueName":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj","projectName":"aeqw89.tools.Publish","projectPath":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj","outputPath":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net9.0"],"sources":{"C:\\Users\\qwsdc\\packages":{},"https://api.nuget.org/v3/index.json":{},"https://nuget.pkg.github.com/qwsdcvghyu89/index.json":{}},"frameworks":{"net9.0":{"targetAlias":"net9.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net9.0":{"targetAlias":"net9.0","dependencies":{"SSH.NET":{"target":"Package","version":"[2025.0.0, )"},"Spectre.Console":{"target":"Package","version":"[0.51.2-preview.0.1, )"},"Spectre.Console.Cli":{"target":"Package","version":"[0.51.2-preview.0.1, )"},"VsTools.Projects":{"target":"Package","version":"[1.2.0, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\9.0.101/PortableRuntimeIdentifierGraph.json"}}
@@ -1 +1 @@
17584140259343453
17584342196004454
@@ -1 +1 @@
17584254157830058
17584333772830899