Reapply "First Commit"

This reverts commit 3a6783ff7b.
This commit is contained in:
qwsdcvghyu89
2025-09-21 15:03:14 +10:00
parent 3a6783ff7b
commit cd823abb02
72 changed files with 2686 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/.idea.aeqw89.tools.Publish.iml
/modules.xml
/contentModel.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+16
View File
@@ -0,0 +1,16 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aeqw89.tools.Publish", "aeqw89.tools.Publish\aeqw89.tools.Publish.csproj", "{B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
+15
View File
@@ -0,0 +1,15 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAnsiConsole_002EProgress_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fdee75199bd7f4e4a2bb293543ad2c1253b9c56264e6fdffab4899034b7719_003FAnsiConsole_002EProgress_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArrayPool_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F5259d3b492565eee74334a7de8f55cbaac1fe860ecd250567891931a1ab5b7e_003FArrayPool_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultInterpolatedStringHandler_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fc1c946eaa6d8ddaaea1b63e936ca8ed2791d9316c5b025a41d445891e8a59ecd_003FDefaultInterpolatedStringHandler_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFuture_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fb3575a2f41d7c2dbfaa36e866b8a361e11dd7223ff82bc574c1d5d4b7522f735_003FFuture_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANullable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F5acc345db3c207bc9d886a36ff14867ef8d65557432172c2a42f19aeac04d1b_003FNullable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AProgress_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F7f89a44745816a6105c5c96e548498e2d547204f83da6edda3cab60eb8d_003FProgress_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APropertyGroup_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ff5392c5f367041ba8e794f98b06cb6077600_003F2f_003Fadc006bd_003FPropertyGroup_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatusExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Feb70c9cd7f45242ff2973d4ddaf8db9ec74adb5a26b1542297adfb8d71fbb9_003FStatusExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatus_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F55afacaa275eb9aa8aadbc1420aeb0c378a73abed5ec3382898d9b1a9692fa_003FStatus_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AString_002EManipulation_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe75a5575ba872c8ea754c015cb363850e6c661f39569712d5b74aaca67263c_003FString_002EManipulation_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStyleParser_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F3fb093e29c135ccd8c61d19abd9ba8e2f7392926c5b44566ea41bf3f69ca195_003FStyleParser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fc7102cd0ffb8973777e61b1942c3fffac7e14016a511d055c3adf73ff91748_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=aeqw89_002Etools_002EPublish_002FExceptions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>
View File
+7
View File
@@ -0,0 +1,7 @@
using System.Xml;
namespace aeqw89.tools.Publish;
internal sealed class Content : Item {
public Content(XmlElement node) : base(node) { }
}
+224
View File
@@ -0,0 +1,224 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace aeqw89.tools.Publish {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Exceptions {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Exceptions() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("aeqw89.tools.Publish.Exceptions", typeof(Exceptions).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to The cloud host &apos;{0}&apos; is not an entry on this user&apos;s config file..
/// </summary>
internal static string cloud_host_not_found {
get {
return ResourceManager.GetString("cloud_host_not_found", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The mode &apos;{0}&apos; is invalid, the valid modes are [overwrite|increment].
/// </summary>
internal static string could_not_parse_mode {
get {
return ResourceManager.GetString("could_not_parse_mode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The increment target &apos;{0}&apos; is invalid, the valid increment targets are [patch|minor|patch].
/// </summary>
internal static string could_not_parse_target {
get {
return ResourceManager.GetString("could_not_parse_target", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The &apos;dotnet nuget push&apos; command failed with error message &apos;{0}&apos;.
/// </summary>
internal static string dotnet_nuget_push_failure {
get {
return ResourceManager.GetString("dotnet_nuget_push_failure", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to pack; ensure that &apos;dotnet build&apos; succeeds before running this program..
/// </summary>
internal static string dotnet_pack_failure {
get {
return ResourceManager.GetString("dotnet_pack_failure", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not delete temporary directory &apos;{0}&apos; due to error &apos;{1}&apos;.
/// </summary>
internal static string failed_to_clean_up {
get {
return ResourceManager.GetString("failed_to_clean_up", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failde to prepare an upload directory on the path {0} for the remote host &apos;{1}&apos;, after being detected as a {2} host. Server error is &apos;{3}&apos;.
/// </summary>
internal static string failed_to_prepare_server_directory {
get {
return ResourceManager.GetString("failed_to_prepare_server_directory", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The flag &apos;{0}&apos; requires exactly &apos;{1}&apos; parameters. You have entered &apos;{2}&apos;..
/// </summary>
internal static string flag_parameter_length_incorrect {
get {
return ResourceManager.GetString("flag_parameter_length_incorrect", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The &apos;{0}&apos; flag requires that argument with index &apos;{1}&apos; be of type &apos;{2}&apos;. You have entered &apos;{3}&apos; which has failed to be converted..
/// </summary>
internal static string flag_parameter_type_incorrect {
get {
return ResourceManager.GetString("flag_parameter_type_incorrect", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The directory &apos;{0}&apos; contains multiple .csproj files; this tool can only process one at a time..
/// </summary>
internal static string found_multiple_csproj {
get {
return ResourceManager.GetString("found_multiple_csproj", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Something went wrong loading this file; {0}.
/// </summary>
internal static string generic_error {
get {
return ResourceManager.GetString("generic_error", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You must specify at least one destination..
/// </summary>
internal static string missing_destinations {
get {
return ResourceManager.GetString("missing_destinations", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You must specify an increment target if you specified an increment mode; allowed increment targets are [patch|minor|major].
/// </summary>
internal static string missing_increment_target {
get {
return ResourceManager.GetString("missing_increment_target", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You must specify a mode; allowed modes are [overwrite|increment].
/// </summary>
internal static string missing_mode {
get {
return ResourceManager.GetString("missing_mode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No project file was found within the current directory..
/// </summary>
internal static string no_project_in_directory {
get {
return ResourceManager.GetString("no_project_in_directory", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The project file &apos;{0}&apos; is irreparable becuase it is missing a &apos;{1}&apos; property, and the value cannot be guessed..
/// </summary>
internal static string project_file_irreparable {
get {
return ResourceManager.GetString("project_file_irreparable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Something went wrong; an attempt was made to load a non .csproj file as a project file..
/// </summary>
internal static string tried_loading_non_csproj_file {
get {
return ResourceManager.GetString("tried_loading_non_csproj_file", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The version string &apos;{0}&apos; is in an unidentifiable format..
/// </summary>
internal static string version_string_not_formatted_correctly {
get {
return ResourceManager.GetString("version_string_not_formatted_correctly", resourceCulture);
}
}
}
}
+75
View File
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="missing_mode" xml:space="preserve">
<value>You must specify a mode; allowed modes are [overwrite|increment]</value>
</data>
<data name="could_not_parse_mode" xml:space="preserve">
<value>The mode '{0}' is invalid, the valid modes are [overwrite|increment]</value>
</data>
<data name="could_not_parse_target" xml:space="preserve">
<value>The increment target '{0}' is invalid, the valid increment targets are [patch|minor|patch]</value>
</data>
<data name="missing_increment_target" xml:space="preserve">
<value>You must specify an increment target if you specified an increment mode; allowed increment targets are [patch|minor|major]</value>
</data>
<data name="missing_destinations" xml:space="preserve">
<value>You must specify at least one destination.</value>
</data>
<data name="no_project_in_directory" xml:space="preserve">
<value>No project file was found within the current directory.</value>
</data>
<data name="flag_parameter_length_incorrect" xml:space="preserve">
<value>The flag '{0}' requires exactly '{1}' parameters. You have entered '{2}'.</value>
</data>
<data name="flag_parameter_type_incorrect" xml:space="preserve">
<value>The '{0}' flag requires that argument with index '{1}' be of type '{2}'. You have entered '{3}' which has failed to be converted.</value>
</data>
<data name="version_string_not_formatted_correctly" xml:space="preserve">
<value>The version string '{0}' is in an unidentifiable format.</value>
</data>
<data name="tried_loading_non_csproj_file" xml:space="preserve">
<value>Something went wrong; an attempt was made to load a non .csproj file as a project file.</value>
</data>
<data name="generic_error" xml:space="preserve">
<value>Something went wrong loading this file; {0}</value>
</data>
<data name="found_multiple_csproj" xml:space="preserve">
<value>The directory '{0}' contains multiple .csproj files; this tool can only process one at a time.</value>
</data>
<data name="project_file_irreparable" xml:space="preserve">
<value>The project file '{0}' is irreparable becuase it is missing a '{1}' property, and the value cannot be guessed.</value>
</data>
<data name="dotnet_pack_failure" xml:space="preserve">
<value>Failed to pack; ensure that 'dotnet build' succeeds before running this program.</value>
</data>
<data name="failed_to_clean_up" xml:space="preserve">
<value>Could not delete temporary directory '{0}' due to error '{1}'</value>
</data>
<data name="cloud_host_not_found" xml:space="preserve">
<value>The cloud host '{0}' is not an entry on this user's config file.</value>
</data>
<data name="failed_to_prepare_server_directory" xml:space="preserve">
<value>Failde to prepare an upload directory on the path {0} for the remote host '{1}', after being detected as a {2} host. Server error is '{3}'</value>
</data>
<data name="dotnet_nuget_push_failure" xml:space="preserve">
<value>The 'dotnet nuget push' command failed with error message '{0}'</value>
</data>
</root>
+7
View File
@@ -0,0 +1,7 @@
namespace aeqw89.tools.Publish;
public enum IncrementTarget {
Patch,
Minor,
Major,
}
+55
View File
@@ -0,0 +1,55 @@
using System.Xml;
namespace aeqw89.tools.Publish;
internal class Item {
public string ElementName { get; protected set; }
public string Include {
get => Node.GetAttribute("Include");
set => Node.SetAttribute("Include", value);
}
public string Version {
get => Node.GetAttribute("Version");
set => Node.SetAttribute("Version", value);
}
public string? Value {
get => Node.InnerText;
set { Node.InnerText = value ?? string.Empty; }
}
public XmlElement Node { get; }
protected Item(XmlElement node) {
Node = node;
ElementName = node.Name;
}
public static Item FromElement(XmlElement element) {
return element.Name switch {
"PackageReference" => new PackageReference(element),
"ProjectReference" => new ProjectReference(element),
"Content" => new Content(element),
_ => new Item(element),
};
}
public void AddChild(Item child) {
var imported = Node.OwnerDocument!.ImportNode(child.Node, true);
Node.AppendChild(imported);
}
public string? GetAttribute(string name) => Node.HasAttribute(name) ? Node.GetAttribute(name) : null;
public void SetAttribute(string name, string? value) {
if (value is null) {
if (Node.HasAttribute(name)) Node.RemoveAttribute(name);
return;
}
Node.SetAttribute(name, value);
}
public IEnumerable<Item> GetChildElements() {
foreach (var e in Node.ChildNodes.OfType<XmlElement>())
yield return new Item(e);
}
}
+26
View File
@@ -0,0 +1,26 @@
using System.Xml;
namespace aeqw89.tools.Publish;
internal class ItemGroup {
private readonly XmlElement _element;
public List<Item> Items { get; }
public void Remove() {
_element.ParentNode!.RemoveChild(_element);
}
public ItemGroup(XmlElement element) {
_element = element;
Items = element.ChildNodes
.OfType<XmlElement>()
.Select(Item.FromElement)
.ToList();
}
public void Add(Item item) {
var imported = _element.OwnerDocument!.ImportNode(item.Node, true);
_element.AppendChild(imported);
Items.Add(Item.FromElement((XmlElement)imported));
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace aeqw89.tools.Publish;
public enum Mode {
Overwrite,
Increment,
}
+30
View File
@@ -0,0 +1,30 @@
using System.Xml;
namespace aeqw89.tools.Publish;
internal sealed class PackageReference : Item {
public PackageReference(XmlElement node) : base(node) { }
// inside PackageReference
public string? GetPackageVersion() {
// Prefer attribute, then child <Version>
var attr = GetAttribute("Version");
if (!string.IsNullOrEmpty(attr)) return attr;
var child = Node.SelectSingleNode("./Version") as XmlElement;
return child?.InnerText;
}
public void SetPackageVersion(string? version) {
if (Node.HasAttribute("Version") || (Node.SelectSingleNode("./Version") == null)) {
// If attribute exists (or no child yet), use attribute
SetAttribute("Version", version);
return;
}
// Else write to existing child <Version>
var child = (XmlElement)Node.SelectSingleNode("./Version")!;
child.InnerText = version ?? string.Empty;
}
}
@@ -0,0 +1,6 @@
namespace aeqw89.tools.Publish;
public enum PrivateAssetsValue {
All,
None,
}
+473
View File
@@ -0,0 +1,473 @@
using System.Collections;
using System.Diagnostics;
using Renci.SshNet;
using Spectre.Console;
using Spectre.Console.Cli;
using VsTools.Projects;
namespace aeqw89.tools.Publish;
/*
* Structure of the program:
* - publish (executable)
* - overwrite
* - destinations
* - flags
* - increment
* - patch|minor|major
* - destinations
* - flags
* e.g. publish overwrite|increment [patch|minor|major] destinations [flags]
*/
public static class Program {
public static Mode Mode { get; set; }
public static IncrementTarget? Target { get; set; }
public static string[] Destinations { get; set; }
public static Dictionary<string, string[]> Flags { get; set; }
public static bool Verbose { get; set; } = false;
public static void ReadArgs(string[] args) {
if (args.Length < 1) {
ShowError(Exceptions.missing_mode.EscapeMarkup());
ShowHelp();
return;
}
Mode = args[0] switch {
"overwrite" => Mode.Overwrite,
"increment" => Mode.Increment,
_ => (Mode)(-1)
};
if (Mode == (Mode)(-1)) {
ShowError(Exceptions.could_not_parse_mode.EscapeMarkup(), args[0].EscapeMarkup());
ShowHelp();
return;
}
if (args.Length < 2) {
if (Mode == Mode.Increment)
ShowError(Exceptions.missing_increment_target.EscapeMarkup());
else if (Mode == Mode.Overwrite)
ShowError(Exceptions.missing_destinations.EscapeMarkup());
ShowHelp();
return;
}
Destinations = args[1..];
Flags = [];
if (Mode == Mode.Increment) {
if (args.Length < 3) {
ShowError(Exceptions.missing_destinations.EscapeMarkup());
ShowHelp();
return;
}
Destinations = args[2..];
Target = args[1] switch {
"patch" => IncrementTarget.Patch,
"minor" => IncrementTarget.Minor,
"major" => IncrementTarget.Major,
_ => (IncrementTarget)(-1)
};
if (Target == (IncrementTarget)(-1)) {
ShowError(Exceptions.could_not_parse_target.EscapeMarkup(), args[1].EscapeMarkup());
ShowHelp();
return;
}
}
string? firstFlag = Destinations.FirstOrDefault(x => x.StartsWith('-'));
if (firstFlag == null) return;
string[] flags = Destinations.SkipWhile(x => x != firstFlag).ToArray();
Flags = ReadFlags(flags);
Destinations = Destinations.TakeWhile(x => x != firstFlag).ToArray();
Verbose = Flags.ContainsKey("--verbose") || Flags.ContainsKey("-v");
}
private static Dictionary<string, string[]> ReadFlags(string[] flags) {
Dictionary<string, string[]> result = [];
List<string> collected = [];
string lastKey = flags[0];
if (flags.Length == 1)
result[lastKey] = [];
foreach (var flag in flags.Skip(1)) {
if (flag.StartsWith('-')) {
result[lastKey] = collected.ToArray();
collected = [];
lastKey = flag;
} else
collected.Add(flag);
}
return result;
}
public static async Task Main(string[] args) {
ReadArgs(args);
string packageId = "";
string version = "";
var result = AnsiConsole.Status()
.Spinner(Spinner.Known.Dots)
.Start<bool>("Preparing project", ctx => {
ctx.Status = "Locating project file";
if (!ProjectFile.TryLoad(Environment.CurrentDirectory, out var projectFile, out var error)) {
ShowError(error.EscapeMarkup());
return false;
}
packageId = projectFile.GetPackageId();
try {
projectFile.Backup();
if (Verbose)
AnsiConsole.WriteLine(
$"Created project file backup at {projectFile.GetDefaultBackupLocation()}");
ctx.Status = "Repairing project file";
if (!Flags.ContainsKey("--skip-repair"))
if (!projectFile.TryRepair(out error)) {
ShowError(error.EscapeMarkup());
projectFile.Restore();
return false;
}
if (Mode == Mode.Increment && !Flags.ContainsKey("--simulate")) {
int delta = 1;
if (Flags.TryGetValue("--delta", out var deltaStrings)) {
if (deltaStrings.Length != 1) {
ShowError(Exceptions.flag_parameter_length_incorrect.EscapeMarkup(), "--delta", 1,
deltaStrings.Length);
projectFile.Restore();
ShowHelp();
return false;
}
if (!int.TryParse(deltaStrings[0], out delta)) {
ShowError(Exceptions.flag_parameter_type_incorrect.EscapeMarkup(), "--delta", 0, nameof(Int32),
deltaStrings[0]);
projectFile.Restore();
ShowHelp();
return false;
}
}
ctx.Status = "Updating version";
var version = projectFile.GetVersion();
version = ChangeVersion(version,
Target == IncrementTarget.Patch ? delta : 0,
Target == IncrementTarget.Minor ? delta : 0,
Target == IncrementTarget.Major ? delta : 0,
(x, y) => x + y);
projectFile.SetVersion(version);
}
}
catch (Exception e) {
ShowError(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup());
projectFile.Restore();
return false;
}
version = projectFile.GetVersion();
if (!Flags.ContainsKey("--simulate")) {
try {
var packageReferences = projectFile.GetPackageReferences();
foreach (var reference in packageReferences.Where(x => !projectFile.IsTransitive(x)))
projectFile.SetPrivateAssets(reference, PrivateAssetsValue.All);
foreach (var reference in packageReferences.Where(x => projectFile.IsTransitive(x)))
projectFile.RemovePackage(reference);
HashSet<string> visited = [];
var projectReferences = new Queue<Item>(projectFile.GetProjectReferences().Cast<Item>());
while (projectReferences.Count != 0) {
var reference = projectReferences.Dequeue();
visited.Add(reference.Include);
if (Verbose)
AnsiConsole.WriteLine($"Processing project reference {reference.Include} out of {visited.Count} so far");
projectFile.SetPrivateAssets(reference, PrivateAssetsValue.All);
string pathToReferencedProjectFile = projectFile.GetAbsoluteIncludePath(reference);
if (!ProjectFile.TryLoad(pathToReferencedProjectFile, out var referencedProjectFile,
out error)) {
ShowError(error.EscapeMarkup());
projectFile.Restore();
return false;
}
var referencedPackageReferences = referencedProjectFile.GetPackageReferences();
foreach (var package in referencedPackageReferences) {
if (Verbose)
AnsiConsole.WriteLine($"Hoisting package {package.Include} from {pathToReferencedProjectFile}");
var hoisted = projectFile.AddPackage(package);
projectFile.SetTransitive(hoisted, true);
projectFile.SetPrivateAssets(hoisted, PrivateAssetsValue.None);
referencedProjectFile.SetPrivateAssets(package, PrivateAssetsValue.All);
}
var referencedProjectReferences = referencedProjectFile.GetProjectReferences();
foreach (var project in referencedProjectReferences) {
if (!visited.Contains(project.Include))
projectReferences.Enqueue(project);
}
}
} catch (Exception e) {
ShowError(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup());
projectFile.Restore();
return false;
}
}
projectFile.Save();
return true;
});
if (!result) {
return;
}
var outDir = Path.GetRandomFileName();
result = AnsiConsole.Status()
.Spinner(Spinner.Known.Dots)
.Start<bool>("Creating package with 'dotnet pack' ", ctx => {
var p = Process.Start(new ProcessStartInfo() {
FileName = "dotnet",
Arguments = $"pack -o {outDir}",
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = Verbose,
RedirectStandardOutput = !Verbose,
RedirectStandardError = !Verbose
});
p?.WaitForExit();
return p?.ExitCode == 0;
});
if (!result) {
ShowError(Exceptions.dotnet_pack_failure.EscapeMarkup());
return;
}
var package = Directory.GetFiles(outDir, "*.nupkg").FirstOrDefault();
if (package == null) {
ShowError(Exceptions.generic_error.EscapeMarkup());
return;
}
var inMemory = await File.ReadAllBytesAsync(package);
var size = new FileInfo(package).Length;
const long bufferSize = 80 * 1024; // 80 KB
try {
await AnsiConsole.Progress()
.AutoClear(true)
.HideCompleted(true)
.Columns(new ProgressColumn[] {
new TaskDescriptionColumn(),
new ProgressBarColumn()
.RemainingStyle(Style.Parse("dim gray slowblink"))
.CompletedStyle(Style.Parse("green strikethrough"))
.FinishedStyle("green strikethrough"),
new DownloadedColumn(),
new RemainingTimeColumn(),
new TransferSpeedColumn(),
})
.StartAsync(async ctx => {
await Parallel.ForEachAsync(Destinations, new ParallelOptions() {
MaxDegreeOfParallelism = Environment.ProcessorCount,
}, async (dest, ct) => {
using var reader = new MemoryStream(inMemory);
var task = ctx.AddTask(dest, new ProgressTaskSettings() {
MaxValue = size
});
if (dest.StartsWith("local-")) {
var name = dest[("local-".Length)..];
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
name, Path.GetFileName(package));
if (!Directory.Exists(Path.GetDirectoryName(path)))
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
await using var writer = File.OpenWrite(path);
var buffer = new byte[bufferSize];
int read;
do {
read = await reader.ReadAsync(buffer, ct);
writer.Write(buffer, 0, read);
task.Increment(read);
} while (read > 0);
}
else if (dest.StartsWith("cloud-")) {
var name = dest[("cloud-".Length)..];
var connectionTask = ctx.AddTaskBefore($"Preparing cloud-{name}", new ProgressTaskSettings() {
MaxValue = 100
}, task);
if (!SshHosts.TryGetHost(name, out var host)) {
ShowError(Exceptions.cloud_host_not_found.EscapeMarkup(), name);
return;
}
var connectionInfo = SshHosts.GetConnection(name);
using var sshClient = new SshClient(connectionInfo);
if (!sshClient.IsConnected)
await sshClient.ConnectAsync(ct);
connectionTask.Increment(33);
var winC = sshClient.RunCommand("cmd /c ver");
var othC = sshClient.RunCommand("uname -s");
var os = (winC.ExitStatus, othC.ExitStatus) switch {
(0, _) => "windows",
(_, 0) => "linux",
_ => "unknown"
};
string remoteDirectory;
string packageFileDirectory;
if (os == "windows") {
var userDirC = sshClient.RunCommand("cmd /c echo %USERPROFILE%");
if (userDirC.ExitStatus != 0) {
ShowError(Exceptions.failed_to_prepare_server_directory, "n/a", name, os, userDirC.Result);
return;
}
var userDir = userDirC.Result.Trim();
remoteDirectory = RemotePath.Combine(RemoteOs.Windows,userDir, "dotnet-packages");
packageFileDirectory = RemotePath.Combine(RemoteOs.Windows, remoteDirectory, Path.GetFileName(package));
var mkdirC = sshClient.RunCommand($"cmd /c if not exist \"{remoteDirectory}\" mkdir \"{remoteDirectory}\"");
if (mkdirC.ExitStatus != 0) {
ShowError(Exceptions.failed_to_prepare_server_directory, remoteDirectory, name, os, mkdirC.Result);
return;
}
}
else if (os == "linux") {
var homeDirC = sshClient.RunCommand("printf %s \"$HOME\"");
if (homeDirC.ExitStatus != 0) {
ShowError(Exceptions.failed_to_prepare_server_directory, "n/a", name, os, homeDirC.Result);
return;
}
var homeDir = homeDirC.Result.Trim(); // no CRLF on unix, but Trim() is safest
remoteDirectory = RemotePath.Combine(RemoteOs.Unix, homeDir, ".dotnet-packages");
packageFileDirectory = RemotePath.Combine(RemoteOs.Unix, remoteDirectory, Path.GetFileName(package));
// Use -p and single quotes to handle spaces safely
var mkdirC = sshClient.RunCommand($"mkdir -p '{remoteDirectory}'");
if (mkdirC.ExitStatus != 0) {
ShowError(Exceptions.failed_to_prepare_server_directory, remoteDirectory, name, os, mkdirC.Result);
return;
}
}
else {
ShowError(Exceptions.failed_to_prepare_server_directory, "n/a", name, os, "Unsupported OS");
return;
}
connectionTask.Increment(33);
sshClient.Disconnect();
using var client = new SftpClient(connectionInfo);
if (!client.IsConnected)
await client.ConnectAsync(ct);
connectionTask.Increment(33);
connectionTask.StopTask();
await using var writer = client.OpenWrite(packageFileDirectory);
byte[] buffer = new byte[bufferSize];
int read;
do {
read = await reader.ReadAsync(buffer, ct);
writer.Write(buffer, 0, read);
task.Increment(read);
} while (read > 0);
}
else if (dest == "github") {
var p = Process.Start(new ProcessStartInfo() {
FileName = "dotnet",
Arguments = $"nuget push {package} --source github",
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = false,
RedirectStandardOutput = !Verbose,
RedirectStandardError = !Verbose
});
if (p == null) {
ShowError(Exceptions.generic_error.EscapeMarkup());
}
task.Increment(size / 2);
if (p != null)
await p.WaitForExitAsync(ct);
if (p?.ExitCode != 0) {
ShowError(Exceptions.dotnet_nuget_push_failure, p.ExitCode);
}
task.Increment(size / 2);
}
task.StopTask();
});
});
}
finally {
try {
Directory.Delete(outDir, true);
}
catch (Exception e) {
ShowError(string.Format(Exceptions.failed_to_clean_up.EscapeMarkup(), outDir.EscapeMarkup(), e.ToString().EscapeMarkup()));
}
}
AnsiConsole.MarkupLine("Completed processing of all destinations.");
AnsiConsole.MarkupLine("Example usage:\n\t <PackageReference Include=\"{0}\" Version=\"{1}\" />".EscapeMarkup(), packageId, version);
}
/// <summary>
/// Updates the version string by applying the specified operation to the major, minor, and patch components of the version.
/// </summary>
/// <param name="version">The current version string in the format "major.minor.patch[-tag]".</param>
/// <param name="patch">The value to apply to the patch component.</param>
/// <param name="minor">The value to apply to the minor component.</param>
/// <param name="major">The value to apply to the major component.</param>
/// <param name="operation">A function that defines the adjustment operation to be performed on each version component.</param>
/// <returns>A new version string with the updated major, minor, and patch components, preserving any existing tag.</returns>
/// <exception cref="Exception">Thrown if the version string is not in the correct format.</exception>
private static string ChangeVersion(string version, int patch, int minor, int major,
Func<int, int, int> operation) {
string[] split = version.Split('.');
if (split.Length != 3) {
throw new Exception(string.Format(Exceptions.version_string_not_formatted_correctly, version));
}
string tag = "";
if (split[2].Contains('-')) {
var split2 = split[2].Split('-');
split[2] = split2[0];
tag = "-" + split2[1];
}
if (split.Any(x => !int.TryParse(x, out _)))
throw new Exception(string.Format(Exceptions.version_string_not_formatted_correctly, version));
int[] parsedVersion = split.Select(int.Parse).ToArray();
return
$"{operation(parsedVersion[0], major)}.{operation(parsedVersion[1], minor)}.{operation(parsedVersion[2], patch)}{tag}";
}
private static void ShowError(string message, params object[] args) {
AnsiConsole.MarkupLine($"[bold red]{message}[/]", args);
}
private static void ShowHelp() {
AnsiConsole.Markup(("Usage: publish overwrite|increment [patch|minor|major] destinations [flags]\n" +
"\t if mode: overwrite destinations [flags]\n" +
"\t if mode: increment patch|minor|major [flags]\n").EscapeMarkup());
}
}
+54
View File
@@ -0,0 +1,54 @@
using System.Xml;
namespace aeqw89.tools.Publish;
internal class Project {
public string Path { get; }
private XmlDocument Document { get; }
public List<PropertyGroup> PropertyGroups { get; }
public List<ItemGroup> ItemGroups { get; }
private Project(string path, XmlDocument doc) {
Path = path;
Document = doc;
// Build PropertyGroups
PropertyGroups = doc.DocumentElement!
.SelectNodes("./PropertyGroup")!
.OfType<XmlElement>()
.Select(e => new PropertyGroup(e))
.ToList();
// Build ItemGroups (+ their Items)
ItemGroups = doc.DocumentElement!
.SelectNodes("./ItemGroup")!
.OfType<XmlElement>()
.Select(e => new ItemGroup(e))
.ToList();
// Ensure at least one ItemGroup exists (some csprojs omit it until first item is added)
if (ItemGroups.Count == 0) {
var ig = doc.CreateElement("ItemGroup", doc.DocumentElement!.NamespaceURI);
doc.DocumentElement!.AppendChild(ig);
ItemGroups.Add(new ItemGroup((XmlElement)ig));
}
}
public static Project Load(string path) {
var doc = new XmlDocument();
doc.PreserveWhitespace = false;
doc.Load(path);
return new Project(path, doc);
}
public void Save() {
var settings = new XmlWriterSettings {
Indent = true,
IndentChars = " ",
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Replace
};
using var writer = XmlWriter.Create(Path, settings);
Document.Save(writer);
}
}
+216
View File
@@ -0,0 +1,216 @@
using System.Diagnostics.CodeAnalysis;
using System.Xml;
namespace aeqw89.tools.Publish;
// -------------------------------------------------------------------------------------------------
// Minimal replacements for VsTools.Projects so ProjectFile can keep its public surface intact
// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------
// Your original public surface, now backed by System.Xml
// -------------------------------------------------------------------------------------------------
internal class ProjectFile {
public Project Project { get; private set; }
public string Path { get; private set; }
private PropertyGroup MainPropertyGroup { get; set; }
private ProjectFile(Project project, string path) {
MainPropertyGroup = project.PropertyGroups.FirstOrDefault()!;
Project = project;
Path = path;
}
public static bool TryLoad(string path, [NotNullWhen(true)] out ProjectFile? projectFile, [NotNullWhen(false)] out string? error) {
projectFile = null;
error = null;
if (!path.EndsWith(".csproj")) {
if (!Directory.Exists(path)) {
error = Exceptions.tried_loading_non_csproj_file;
return false;
}
var csproj = Directory.EnumerateFiles(path, "*.csproj", SearchOption.TopDirectoryOnly).ToArray();
if (csproj.Length == 0) {
error = Exceptions.no_project_in_directory;
return false;
}
if (csproj.Length > 1) {
error = Exceptions.found_multiple_csproj;
return false;
}
path = csproj[0];
}
try {
projectFile = new ProjectFile(Project.Load(path), path);
return true;
}
catch (Exception e) {
error = string.Format(Exceptions.generic_error, e);
return false;
}
}
public void Backup(string? backupPath = null) {
backupPath ??= Path + ".bak";
File.Copy(Path, backupPath, true);
}
public string GetDefaultBackupLocation() => Path + ".bak";
public bool Restore(string? backupPath = null) {
backupPath ??= GetDefaultBackupLocation();
if (!File.Exists(backupPath)) return false;
File.Copy(backupPath, Path, true);
return true;
}
public void Save() {
// Check for empty property or item groups
foreach (var ig in Project.ItemGroups.ToList().Where(ig => ig.Items.Count == 0)) {
ig.Remove();
}
foreach (var pg in Project.PropertyGroups.ToList().Where(pg => pg.Count == 0)) {
pg.Remove();
}
Project.Save();
}
public bool TryRepair([NotNullWhen(false)] out string? error) {
// Ensure we have a PropertyGroup with TargetFramework
if (MainPropertyGroup?.HasProperty("TargetFramework") != true) {
if (!Project.PropertyGroups.Any(x => x.HasProperty("TargetFramework"))) {
error = string.Format(Exceptions.project_file_irreparable, Path, "TargetFramework");
return false;
}
MainPropertyGroup = Project.PropertyGroups.First(x => x.HasProperty("TargetFramework"));
}
List<string> failed = [];
void set(string key, string value, bool required = false) {
if (!MainPropertyGroup.HasProperty(key) || string.IsNullOrEmpty(MainPropertyGroup.GetProperty(key))) {
if (required) {
failed.Add(key);
return;
}
MainPropertyGroup.SetProperty(key, value);
}
}
set("Version", "1.0.0");
set("Title", System.IO.Path.GetFileNameWithoutExtension(Path));
set("Authors", "");
set("Company", "");
set("Description", "");
set("PackageProjectUrl", "", required: false);
set("RepositoryUrl", "", required: true);
set("PackageId", "", required: true);
if (failed.Count > 0) {
error = string.Format(Exceptions.project_file_irreparable, Path, string.Join(", ", failed));
return false;
}
error = null;
return true;
}
public List<PackageReference> GetPackageReferences() {
return Project.ItemGroups
.SelectMany(g => g.Items)
.Where(i => i.ElementName == "PackageReference")
.OfType<PackageReference>()
.ToList();
}
public List<ProjectReference> GetProjectReferences() {
return Project.ItemGroups
.SelectMany(g => g.Items)
.Where(i => i.ElementName == "ProjectReference")
.OfType<ProjectReference>()
.ToList();
}
public List<Content> GetPackageDependencies() {
return Project.ItemGroups
.SelectMany(g => g.Items)
.Where(i => i.ElementName == "Content")
.OfType<Content>()
.ToList();
}
private void CreateOrUpdateChild(Item item, string childName, string value) {
var child = item.Node.SelectSingleNode(childName) as XmlElement;
if (child != null) {
child.InnerText = value;
return;
}
child = item.Node.OwnerDocument!.CreateElement(childName, item.Node.NamespaceURI);
child.InnerText = value;
item.Node.AppendChild(child);
}
public string GetPackageId() {
return MainPropertyGroup.GetProperty("PackageId");
}
public void SetPrivateAssets(Item item, PrivateAssetsValue value) {
if (value == PrivateAssetsValue.None) {
var child = item.Node.SelectSingleNode("./PrivateAssets") as XmlElement;
if (child != null)
item.Node.RemoveChild(child);
return;
}
CreateOrUpdateChild(item, "PrivateAssets", value.ToString().ToLowerInvariant());
}
public void SetTransitive(Item item, bool value)
=> CreateOrUpdateChild(item, "Transitive", value.ToString().ToLowerInvariant());
public bool IsTransitive(Item item) {
var transitive = item.Node.SelectSingleNode("./Transitive") as XmlElement;
return transitive?.InnerText == "true";
}
public string GetAbsoluteIncludePath(Item item) {
return System.IO.Path.GetFullPath(item.Include);
}
public Item AddPackage(Item otherPackage) {
var allItems = Project.ItemGroups.SelectMany(x => x.Items);
var existing = allItems.FirstOrDefault(x =>
x.ElementName == "PackageReference" && x.Include == otherPackage.Include);
if (existing != null) return existing;
var itemGroup = Project.ItemGroups.First();
// Import the original XmlElement to preserve Version (attr or child) and any metadata
itemGroup.Add(otherPackage);
return itemGroup.Items.Last();
}
public bool RemovePackage(Item otherPackage) {
var grp = Project.ItemGroups
.FirstOrDefault(g => g.Items.Any(y => y.ElementName == "PackageReference" && y.Include == otherPackage.Include));
var pkg = grp?.Items.FirstOrDefault(x => x.ElementName == otherPackage.ElementName && x.Include == otherPackage.Include);
if (pkg == null) return false;
pkg.Node.ParentNode!.RemoveChild(pkg.Node);
grp!.Items.Remove(pkg);
return true;
}
public string GetVersion() => MainPropertyGroup.GetProperty("Version");
public void SetVersion(string version) => MainPropertyGroup.SetProperty("Version", version);
}
+7
View File
@@ -0,0 +1,7 @@
using System.Xml;
namespace aeqw89.tools.Publish;
internal sealed class ProjectReference : Item {
public ProjectReference(XmlElement node) : base(node) { }
}
+28
View File
@@ -0,0 +1,28 @@
using System.Xml;
namespace aeqw89.tools.Publish;
internal class PropertyGroup {
private readonly XmlElement _element;
public PropertyGroup(XmlElement element) => _element = element;
public bool HasProperty(string name) => _element.SelectSingleNode($"./{name}") is XmlElement;
public string GetProperty(string name) {
var node = _element.SelectSingleNode($"./{name}") as XmlElement;
return node?.InnerText ?? string.Empty;
}
public void SetProperty(string name, string value) {
var node = _element.SelectSingleNode($"./{name}") as XmlElement;
if (node == null) {
node = _element.OwnerDocument!.CreateElement(name, _element.NamespaceURI);
_element.AppendChild(node);
}
node.InnerText = value ?? string.Empty;
}
public int Count => _element.ChildNodes.OfType<XmlElement>().Count();
public void Remove() => _element.ParentNode!.RemoveChild(_element);
}
+90
View File
@@ -0,0 +1,90 @@
// Required namespaces: System, System.Linq, System.Text.RegularExpressions
using System.Text.RegularExpressions;
namespace aeqw89.tools.Publish;
public enum RemoteOs { Windows, Unix }
public static partial class RemotePath
{
public static string Combine(RemoteOs os, params string[] parts)
{
if (parts == null || parts.Length == 0) return string.Empty;
// Normalize null/empty segments and trim whitespace
var cleaned = parts.Where(p => !string.IsNullOrWhiteSpace(p))
.Select(p => p.Trim())
.ToArray();
if (cleaned.Length == 0) return string.Empty;
return os == RemoteOs.Windows
? CombineWindows(cleaned)
: CombineUnix(cleaned);
}
private static string CombineUnix(string[] parts)
{
// Keep a single leading '/' if the first segment is rooted
bool rooted = parts[0].StartsWith("/", StringComparison.Ordinal);
var body = parts.Select((p, i) =>
{
var s = p.Replace("\\", "/");
// Trim both ends except preserve leading '/' only for first segment
if (i == 0)
return s.TrimEnd('/');
return s.Trim('/'); // internal segments never carry separators
})
.Where(s => s.Length > 0)
.ToArray();
var joined = string.Join("/", body);
return rooted ? (joined.StartsWith("/") ? joined : "/" + joined) : joined;
}
private static string CombineWindows(string[] parts)
{
// Windows separators are backslashes for cmd.exe/PowerShell paths.
// Preserve drive letters like "C:" and UNC roots like "\\server".
var first = parts[0].Replace("/", "\\").Trim();
var rest = parts.Skip(1)
.Select(p => p.Replace("/", "\\").Trim('\\'))
.Where(s => s.Length > 0)
.ToArray();
// Detect UNC root (\\server\share...) or device prefix (\\?\ or \\.\)
bool isUncOrDevice = first.StartsWith(@"\\", StringComparison.Ordinal);
bool isDrive = IsDrive().IsMatch(first);
if (isUncOrDevice)
{
// Keep exactly two leading backslashes; trim trailing ones
first = @"\\" + first.TrimStart('\\').TrimEnd('\\');
}
else if (isDrive)
{
// Normalize "C:" or "C:\" to "C:\"
first = first.Length == 2 ? first + "\\" : first;
}
else
{
// For relative first segment, strip surrounding slashes
first = first.Trim('\\');
}
string joined = rest.Length > 0
? first + (first.EndsWith("\\") ? "" : "\\") + string.Join("\\", rest)
: first;
// Collapse any accidental doubles that can appear from user input (but keep UNC prefix)
if (!joined.StartsWith(@"\\"))
joined = Collapse().Replace(joined, @"\");
return joined;
}
[System.Text.RegularExpressions.GeneratedRegex(@"^[A-Za-z]:\\?$")]
private static partial System.Text.RegularExpressions.Regex IsDrive();
[GeneratedRegex(@"\\{2,}")]
private static partial Regex Collapse();
}
+423
View File
@@ -0,0 +1,423 @@
// Required namespaces:
// System, System.IO, System.Linq, System.Text, System.Text.RegularExpressions, System.Collections.Generic, Renci.SshNet
using System.Text;
using System.Text.RegularExpressions;
namespace aeqw89.tools.Publish;
public record Host(
string Name,
string Hostname,
string User,
string Password,
int Port,
List<string> IdentityFiles,
Renci.SshNet.ProxyTypes? ProxyType,
string? ProxyHost,
int? ProxyPort,
string? ProxyUser,
string? ProxyPassword
);
public static class SshHosts {
public static List<Host> Hosts { get; set; }
static SshHosts() {
Hosts = new List<Host>();
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".ssh",
"config"
);
if (!File.Exists(path)) return;
var lines = File.ReadAllLines(path);
string[]? currentNames = null;
string? currentHostName = null;
string? currentUser = null;
string? currentPassword = null;
int? currentPort = null;
List<string>? currentIdentityFiles = null;
// Proxy (explicit)
Renci.SshNet.ProxyTypes? currentProxyType = null;
string? currentProxyHost = null;
int? currentProxyPort = null;
string? currentProxyUser = null;
string? currentProxyPassword = null;
// Proxy (derived from ProxyCommand)
string? currentProxyCommand = null;
void ResetBlock()
{
currentNames = null;
currentHostName = null;
currentUser = null;
currentPassword = null;
currentPort = null;
currentIdentityFiles = null;
currentProxyType = null;
currentProxyHost = null;
currentProxyPort = null;
currentProxyUser = null;
currentProxyPassword = null;
currentProxyCommand = null;
}
void MaybeDeriveProxyFromProxyCommand()
{
if (string.IsNullOrWhiteSpace(currentProxyCommand)) return;
if (currentProxyType != null && currentProxyHost != null && currentProxyPort != null) return;
// Very common forms:
// nc -x host:port -X 5 %h %p (SOCKS5)
// nc -x host:port -X 4 %h %p (SOCKS4)
// nc -x host:port %h %p (default: treat as SOCKS5)
// nc -X connect -x host:port %h %p (HTTP CONNECT)
// connect -S host:port %h %p (treat as SOCKS5)
var s = currentProxyCommand;
// host:port extraction
var hp = Regex.Match(s, @"(?:(?:-x|-S)\s+|\s)([A-Za-z0-9.\-]+):(\d{1,5})");
if (hp.Success) {
currentProxyHost ??= hp.Groups[1].Value;
if (int.TryParse(hp.Groups[2].Value, out var pp) && pp > 0 && pp <= 65535)
currentProxyPort ??= pp;
}
// type extraction
if (Regex.IsMatch(s, @"-X\s+5\b", RegexOptions.IgnoreCase))
currentProxyType ??= Renci.SshNet.ProxyTypes.Socks5;
else if (Regex.IsMatch(s, @"-X\s+4\b", RegexOptions.IgnoreCase))
currentProxyType ??= Renci.SshNet.ProxyTypes.Socks4;
else if (Regex.IsMatch(s, @"-X\s+connect\b", RegexOptions.IgnoreCase))
currentProxyType ??= Renci.SshNet.ProxyTypes.Http;
else if (s.Contains("connect ", System.StringComparison.OrdinalIgnoreCase))
currentProxyType ??= Renci.SshNet.ProxyTypes.Http;
else if (s.Contains("nc ", System.StringComparison.OrdinalIgnoreCase))
currentProxyType ??= Renci.SshNet.ProxyTypes.Socks5;
// If we still don't have enough, leave proxy unset.
}
void Flush()
{
if (currentNames == null || currentNames.Length == 0) {
ResetBlock();
return;
}
// Try deriving proxy from ProxyCommand if explicit values weren't set
MaybeDeriveProxyFromProxyCommand();
foreach (var n in currentNames) {
var hn = string.IsNullOrWhiteSpace(currentHostName) ? n : currentHostName!;
var idFiles = new List<string>();
if (currentIdentityFiles != null) {
foreach (var f in currentIdentityFiles) idFiles.Add(ExpandPath(f));
}
Hosts.Add(new Host(
Name: n,
Hostname: hn,
User: currentUser ?? string.Empty,
Password: currentPassword ?? string.Empty,
Port: currentPort ?? 22,
IdentityFiles: idFiles,
ProxyType: currentProxyType,
ProxyHost: currentProxyHost,
ProxyPort: currentProxyPort,
ProxyUser: currentProxyUser,
ProxyPassword: currentProxyPassword
));
}
ResetBlock();
}
foreach (var raw in lines) {
var line = raw.Trim();
if (line.Length == 0 || line.StartsWith("#")) continue;
int idx = line.IndexOfAny(new[] { ' ', '\t' });
string key, value;
if (idx < 0) {
key = line;
value = string.Empty;
} else {
key = line[..idx];
value = line[idx..].Trim();
}
switch (key.ToLowerInvariant()) {
case "host":
Flush();
currentNames = SplitArgs(value).ToArray();
break;
case "hostname":
if (currentNames != null) currentHostName = value;
break;
case "user":
if (currentNames != null) currentUser = value;
break;
case "password":
// Non-standard; supported here as a convenience (used for password auth or key passphrase)
if (currentNames != null) currentPassword = value;
break;
case "port":
if (currentNames != null && int.TryParse(value, out var p) && p > 0 && p <= 65535)
currentPort = p;
break;
case "identityfile":
if (currentNames != null) {
currentIdentityFiles ??= new List<string>();
foreach (var f in SplitArgs(value)) {
if (!string.IsNullOrWhiteSpace(f)) currentIdentityFiles.Add(f);
}
}
break;
// --- Proxy settings (explicit custom keys) ---
case "proxytype":
if (currentNames != null) {
var v = value.ToLowerInvariant();
currentProxyType =
v switch {
"socks5" or "socks" or "socks5h" => Renci.SshNet.ProxyTypes.Socks5,
"socks4" => Renci.SshNet.ProxyTypes.Socks4,
"http" or "https" or "connect" => Renci.SshNet.ProxyTypes.Http,
_ => currentProxyType
};
}
break;
case "proxyhost":
if (currentNames != null) currentProxyHost = value;
break;
case "proxyport":
if (currentNames != null && int.TryParse(value, out var prxP) && prxP > 0 && prxP <= 65535)
currentProxyPort = prxP;
break;
case "proxyuser":
if (currentNames != null) currentProxyUser = value;
break;
case "proxypassword":
if (currentNames != null) currentProxyPassword = value;
break;
// --- OpenSSH-style hints we try to interpret ---
case "proxycommand":
if (currentNames != null) currentProxyCommand = value;
break;
// (Note: ProxyJump is non-trivial to replicate in SSH.NET; not parsed here.)
default:
break;
}
}
Flush();
}
// Builds a ConnectionInfo from a parsed host, ensuring all ~/.ssh private keys are tried.
private static Renci.SshNet.ConnectionInfo BuildConnection(Host h) {
var authMethods = new List<Renci.SshNet.AuthenticationMethod>();
// 1) Collect candidate key file paths: from config + everything that looks like a private key in ~/.ssh
var keyPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var f in h.IdentityFiles)
if (!string.IsNullOrWhiteSpace(f))
keyPaths.Add(f);
foreach (var f in EnumerateAllSshPrivateKeys())
keyPaths.Add(f);
// 2) Load keys (try with passphrase, then without)
var pkFiles = new List<Renci.SshNet.PrivateKeyFile>();
foreach (var p in keyPaths) {
if (!File.Exists(p)) continue;
try {
if (!string.IsNullOrEmpty(h.Password)) {
try {
pkFiles.Add(new Renci.SshNet.PrivateKeyFile(p, h.Password));
continue;
}
catch { /* fall through to try without passphrase */
}
}
pkFiles.Add(new Renci.SshNet.PrivateKeyFile(p));
}
catch { /* skip unreadable/unparsable key */
}
}
if (pkFiles.Count > 0)
authMethods.Add(new Renci.SshNet.PrivateKeyAuthenticationMethod(h.User, pkFiles.ToArray()));
// 3) Optional password auth (remote account password)
if (!string.IsNullOrEmpty(h.Password))
authMethods.Add(new Renci.SshNet.PasswordAuthenticationMethod(h.User, h.Password));
if (authMethods.Count == 0)
throw new InvalidOperationException($"No authentication methods available for host '{h.Name}'.");
// 4) Proxy-aware ConnectionInfo
if (h.ProxyType.HasValue && !string.IsNullOrWhiteSpace(h.ProxyHost) && h.ProxyPort.HasValue) {
return new Renci.SshNet.ConnectionInfo(
h.Hostname,
h.Port,
h.User,
h.ProxyType.Value,
h.ProxyHost!,
h.ProxyPort.Value,
h.ProxyUser,
h.ProxyPassword,
authMethods.ToArray()
);
}
return new Renci.SshNet.ConnectionInfo(h.Hostname, h.Port, h.User, authMethods.ToArray());
}
// Enumerate everything in ~/.ssh that *looks* like a private key.
// Skips obvious non-keys like *.pub, known_hosts, config, and directories.
private static IEnumerable<string> EnumerateAllSshPrivateKeys() {
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var sshDir = Path.Combine(home, ".ssh");
if (!Directory.Exists(sshDir)) yield break;
// Common private key basenames to prioritize
var preferred = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {
"id_rsa", "id_ecdsa", "id_ed25519", "id_dsa"
};
// First yield preferred names if present
foreach (var name in preferred) {
var p = Path.Combine(sshDir, name);
if (File.Exists(p)) yield return p;
}
// Then yield everything else that looks like a key
foreach (var file in Directory.EnumerateFiles(sshDir)) {
var name = Path.GetFileName(file);
// Skip ones we already yielded
if (preferred.Contains(name)) continue;
// Exclude common non-key files and public keys
if (name.EndsWith(".pub", StringComparison.OrdinalIgnoreCase)) continue;
if (name.Equals("config", StringComparison.OrdinalIgnoreCase)) continue;
if (name.Equals("known_hosts", StringComparison.OrdinalIgnoreCase)) continue;
if (name.Equals("authorized_keys", StringComparison.OrdinalIgnoreCase)) continue;
if (name.EndsWith(".crt", StringComparison.OrdinalIgnoreCase)) continue;
if (name.EndsWith(".csr", StringComparison.OrdinalIgnoreCase)) continue;
if (name.EndsWith(".pem.pub", StringComparison.OrdinalIgnoreCase)) continue; // guard for odd combos
if (name.EndsWith(".txt", StringComparison.OrdinalIgnoreCase)) continue;
if (name.EndsWith(".conf", StringComparison.OrdinalIgnoreCase)) continue;
// Heuristic: accept files with no extension, or with .key/.pem
var ext = Path.GetExtension(name);
if (string.IsNullOrEmpty(ext) ||
ext.Equals(".key", StringComparison.OrdinalIgnoreCase) ||
ext.Equals(".pem", StringComparison.OrdinalIgnoreCase)) {
yield return file;
}
}
}
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.");
}
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 Renci.SshNet.ConnectionInfo GetConnection(string name)
{
var h = Get(name);
return BuildConnection(h);
}
public static bool TryGetConnection(string name, out Renci.SshNet.ConnectionInfo connectionInfo)
{
if (TryGetHost(name, out var h)) {
try {
connectionInfo = BuildConnection(h);
return true;
} catch {
// If auth material is unusable, return false.
}
}
connectionInfo = default!;
return false;
}
// --- Helpers ---
// Splits a value into whitespace-delimited tokens while respecting double/single quotes.
static IEnumerable<string> SplitArgs(string input)
{
if (string.IsNullOrWhiteSpace(input)) yield break;
bool inSingle = false, inDouble = false;
var sb = new StringBuilder();
for (int i = 0; i < input.Length; i++) {
char c = input[i];
if (c == '"' && !inSingle) { inDouble = !inDouble; continue; }
if (c == '\'' && !inDouble) { inSingle = !inSingle; continue; }
if (!inSingle && !inDouble && char.IsWhiteSpace(c)) {
if (sb.Length > 0) { yield return sb.ToString(); sb.Clear(); }
} else {
sb.Append(c);
}
}
if (sb.Length > 0) yield return sb.ToString();
}
// Expands leading "~" to user home. Leaves %h, %r, etc. untouched.
static string ExpandPath(string p)
{
if (string.IsNullOrEmpty(p)) return p;
if (p == "~") return Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
if (p.StartsWith("~/")) {
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
return Path.Combine(home, p[2..]);
}
return p;
}
}
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.51.2-preview.0.1" />
<PackageReference Include="Spectre.Console.Cli" Version="0.51.2-preview.0.1" />
<PackageReference Include="SSH.NET" Version="2025.0.0" />
<PackageReference Include="VsTools.Projects" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Exceptions.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Exceptions.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Exceptions.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Exceptions.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>
@@ -0,0 +1,176 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v9.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v9.0": {
"aeqw89.tools.Publish/1.0.0": {
"dependencies": {
"SSH.NET": "2025.0.0",
"Spectre.Console": "0.51.2-preview.0.1",
"Spectre.Console.Cli": "0.51.2-preview.0.1",
"VsTools.Projects": "1.2.0"
},
"runtime": {
"aeqw89.tools.Publish.dll": {}
}
},
"BouncyCastle.Cryptography/2.5.1": {
"runtime": {
"lib/net6.0/BouncyCastle.Cryptography.dll": {
"assemblyVersion": "2.0.0.0",
"fileVersion": "2.5.1.28965"
}
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
"runtime": {
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
"assemblyVersion": "8.0.0.0",
"fileVersion": "8.0.1024.46610"
}
}
},
"Microsoft.Extensions.Logging.Abstractions/8.0.3": {
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
"assemblyVersion": "8.0.0.0",
"fileVersion": "8.0.1325.6609"
}
}
},
"Spectre.Console/0.51.2-preview.0.1": {
"runtime": {
"lib/net9.0/Spectre.Console.dll": {
"assemblyVersion": "0.0.0.0",
"fileVersion": "0.51.2.0"
}
}
},
"Spectre.Console.Cli/0.51.2-preview.0.1": {
"dependencies": {
"Spectre.Console": "0.51.2-preview.0.1"
},
"runtime": {
"lib/net9.0/Spectre.Console.Cli.dll": {
"assemblyVersion": "0.0.0.0",
"fileVersion": "0.51.2.0"
}
},
"resources": {
"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": {
"dependencies": {
"BouncyCastle.Cryptography": "2.5.1",
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
},
"runtime": {
"lib/net9.0/Renci.SshNet.dll": {
"assemblyVersion": "2025.0.0.1",
"fileVersion": "2025.0.0.1"
}
}
},
"VsTools.Projects/1.2.0": {
"runtime": {
"lib/netstandard2.0/VsTools.Projects.dll": {
"assemblyVersion": "1.2.0.0",
"fileVersion": "1.2.0.0"
}
}
}
}
},
"libraries": {
"aeqw89.tools.Publish/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"BouncyCastle.Cryptography/2.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-zy8TMeTP+1FH2NrLaNZtdRbBdq7u5MI+NFZQOBSM69u5RFkciinwzV2eveY6Kjf5MzgsYvvl6kTStsj3JrXqkg==",
"path": "bouncycastle.cryptography/2.5.1",
"hashPath": "bouncycastle.cryptography.2.5.1.nupkg.sha512"
},
"Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==",
"path": "microsoft.extensions.dependencyinjection.abstractions/8.0.2",
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512"
},
"Microsoft.Extensions.Logging.Abstractions/8.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==",
"path": "microsoft.extensions.logging.abstractions/8.0.3",
"hashPath": "microsoft.extensions.logging.abstractions.8.0.3.nupkg.sha512"
},
"Spectre.Console/0.51.2-preview.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-eTojiXsispvwl5i3o6BsBt0fV7pn+jsJ3nbQVCTCwBoYbeczNO2w7wjPfB2Tx+Y5+mplLEtSFi5Mp0aFZSP3tA==",
"path": "spectre.console/0.51.2-preview.0.1",
"hashPath": "spectre.console.0.51.2-preview.0.1.nupkg.sha512"
},
"Spectre.Console.Cli/0.51.2-preview.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-sgcQ28dkBJG66JU+BI/vhXvgqYOS+0S2OaW5sYkpShk0MzHO2hnnyg8Ef636NG6U+OmIALVZ69CP3oImeUUrag==",
"path": "spectre.console.cli/0.51.2-preview.0.1",
"hashPath": "spectre.console.cli.0.51.2-preview.0.1.nupkg.sha512"
},
"SSH.NET/2025.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-AKYbB+q2zFkNQbBFx5gXdv+Wje0baBtADQ35WnMKi4bg1ka74wTQtWoPd+fOWcydohdfsD0nfT8ErMOAPxtSfA==",
"path": "ssh.net/2025.0.0",
"hashPath": "ssh.net.2025.0.0.nupkg.sha512"
},
"VsTools.Projects/1.2.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Zja9D1HlSi+6goiAYUkcuE1dUC7MyoU4ZiXCNMcQ6JFNloHpwO8ne7cATi4jeMco56TB3Trzv+vtAiK4jDydlw==",
"path": "vstools.projects/1.2.0",
"hashPath": "vstools.projects.1.2.0.nupkg.sha512"
}
}
}
@@ -0,0 +1,12 @@
{
"runtimeOptions": {
"tfm": "net9.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "9.0.0"
},
"configProperties": {
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}
@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0")]
@@ -0,0 +1,22 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
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.AssemblyProductAttribute("aeqw89.tools.Publish")]
[assembly: System.Reflection.AssemblyTitleAttribute("aeqw89.tools.Publish")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.
@@ -0,0 +1 @@
e3dc9f23098d7e7631e5f51a024428b60b92087a4a264306a861bae3c79e94dd
@@ -0,0 +1,15 @@
is_global = true
build_property.TargetFramework = net9.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = aeqw89.tools.Publish
build_property.ProjectDir = C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.EffectiveAnalysisLevelStyle = 9.0
build_property.EnableCodeStyleSeverity =
@@ -0,0 +1,8 @@
// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;
@@ -0,0 +1 @@
5d197b168fe8c90856a81b99d1fce6aff6057143a768436bb5102085caca4cb0
@@ -0,0 +1,35 @@
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.exe
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.deps.json
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.runtimeconfig.json
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.pdb
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Spectre.Console.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Spectre.Console.Cli.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\de\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\es\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\fr\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\it\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\ja\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\ko\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\pt\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\ru\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\sv\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\zh-Hans\Spectre.Console.Cli.resources.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.csproj.AssemblyReference.cache
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.Exceptions.resources
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.csproj.GenerateResource.cache
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.GeneratedMSBuildEditorConfig.editorconfig
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.AssemblyInfoInputs.cache
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.AssemblyInfo.cs
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.csproj.CoreCompileInputs.cache
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.t.65D2674F.Up2Date
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\refint\aeqw89.tools.Publish.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.pdb
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.genruntimeconfig.cache
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\ref\aeqw89.tools.Publish.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\VsTools.Projects.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\BouncyCastle.Cryptography.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Microsoft.Extensions.Logging.Abstractions.dll
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Renci.SshNet.dll
@@ -0,0 +1 @@
168cdf600308143eb70e75e0de49fe275399afb34dc3d60504d380fe24fdc670
Binary file not shown.
@@ -0,0 +1,86 @@
{
"format": 1,
"restore": {
"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj": {}
},
"projects": {
"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj": {
"version": "1.0.0",
"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",
"packagesPath": "C:\\Users\\qwsdc\\.nuget\\packages\\",
"outputPath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\",
"projectStyle": "PackageReference",
"configFilePaths": [
"C:\\Users\\qwsdc\\AppData\\Roaming\\NuGet\\NuGet.Config"
],
"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"
}
}
}
}
}
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<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>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\qwsdc\.nuget\packages\" />
</ItemGroup>
</Project>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.3\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.3\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
</ImportGroup>
</Project>
@@ -0,0 +1,464 @@
{
"version": 3,
"targets": {
"net9.0": {
"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": {}
}
},
"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": {}
}
}
}
},
"libraries": {
"BouncyCastle.Cryptography/2.5.1": {
"sha512": "zy8TMeTP+1FH2NrLaNZtdRbBdq7u5MI+NFZQOBSM69u5RFkciinwzV2eveY6Kjf5MzgsYvvl6kTStsj3JrXqkg==",
"type": "package",
"path": "bouncycastle.cryptography/2.5.1",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.md",
"README.md",
"bouncycastle.cryptography.2.5.1.nupkg.sha512",
"bouncycastle.cryptography.nuspec",
"lib/net461/BouncyCastle.Cryptography.dll",
"lib/net461/BouncyCastle.Cryptography.xml",
"lib/net6.0/BouncyCastle.Cryptography.dll",
"lib/net6.0/BouncyCastle.Cryptography.xml",
"lib/netstandard2.0/BouncyCastle.Cryptography.dll",
"lib/netstandard2.0/BouncyCastle.Cryptography.xml",
"packageIcon.png"
]
},
"Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
"sha512": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==",
"type": "package",
"path": "microsoft.extensions.dependencyinjection.abstractions/8.0.2",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT",
"buildTransitive/net461/Microsoft.Extensions.DependencyInjection.Abstractions.targets",
"buildTransitive/net462/_._",
"buildTransitive/net6.0/_._",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.Abstractions.targets",
"lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512",
"microsoft.extensions.dependencyinjection.abstractions.nuspec",
"useSharedDesignerContext.txt"
]
},
"Microsoft.Extensions.Logging.Abstractions/8.0.3": {
"sha512": "dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==",
"type": "package",
"path": "microsoft.extensions.logging.abstractions/8.0.3",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT",
"analyzers/dotnet/roslyn3.11/cs/Microsoft.Extensions.Logging.Generators.dll",
"analyzers/dotnet/roslyn3.11/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/Microsoft.Extensions.Logging.Generators.dll",
"analyzers/dotnet/roslyn4.0/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Logging.Generators.dll",
"analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
"buildTransitive/net461/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/net462/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.targets",
"lib/net462/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net462/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net6.0/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/net7.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net7.0/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml",
"microsoft.extensions.logging.abstractions.8.0.3.nupkg.sha512",
"microsoft.extensions.logging.abstractions.nuspec",
"useSharedDesignerContext.txt"
]
},
"Spectre.Console/0.51.2-preview.0.1": {
"sha512": "eTojiXsispvwl5i3o6BsBt0fV7pn+jsJ3nbQVCTCwBoYbeczNO2w7wjPfB2Tx+Y5+mplLEtSFi5Mp0aFZSP3tA==",
"type": "package",
"path": "spectre.console/0.51.2-preview.0.1",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net8.0/Spectre.Console.dll",
"lib/net8.0/Spectre.Console.xml",
"lib/net9.0/Spectre.Console.dll",
"lib/net9.0/Spectre.Console.xml",
"lib/netstandard2.0/Spectre.Console.dll",
"lib/netstandard2.0/Spectre.Console.xml",
"logo.png",
"spectre.console.0.51.2-preview.0.1.nupkg.sha512",
"spectre.console.nuspec"
]
},
"Spectre.Console.Cli/0.51.2-preview.0.1": {
"sha512": "sgcQ28dkBJG66JU+BI/vhXvgqYOS+0S2OaW5sYkpShk0MzHO2hnnyg8Ef636NG6U+OmIALVZ69CP3oImeUUrag==",
"type": "package",
"path": "spectre.console.cli/0.51.2-preview.0.1",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net8.0/Spectre.Console.Cli.dll",
"lib/net8.0/Spectre.Console.Cli.xml",
"lib/net8.0/de/Spectre.Console.Cli.resources.dll",
"lib/net8.0/es/Spectre.Console.Cli.resources.dll",
"lib/net8.0/fr/Spectre.Console.Cli.resources.dll",
"lib/net8.0/it/Spectre.Console.Cli.resources.dll",
"lib/net8.0/ja/Spectre.Console.Cli.resources.dll",
"lib/net8.0/ko/Spectre.Console.Cli.resources.dll",
"lib/net8.0/pt/Spectre.Console.Cli.resources.dll",
"lib/net8.0/ru/Spectre.Console.Cli.resources.dll",
"lib/net8.0/sv/Spectre.Console.Cli.resources.dll",
"lib/net8.0/zh-Hans/Spectre.Console.Cli.resources.dll",
"lib/net9.0/Spectre.Console.Cli.dll",
"lib/net9.0/Spectre.Console.Cli.xml",
"lib/net9.0/de/Spectre.Console.Cli.resources.dll",
"lib/net9.0/es/Spectre.Console.Cli.resources.dll",
"lib/net9.0/fr/Spectre.Console.Cli.resources.dll",
"lib/net9.0/it/Spectre.Console.Cli.resources.dll",
"lib/net9.0/ja/Spectre.Console.Cli.resources.dll",
"lib/net9.0/ko/Spectre.Console.Cli.resources.dll",
"lib/net9.0/pt/Spectre.Console.Cli.resources.dll",
"lib/net9.0/ru/Spectre.Console.Cli.resources.dll",
"lib/net9.0/sv/Spectre.Console.Cli.resources.dll",
"lib/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/Spectre.Console.Cli.dll",
"lib/netstandard2.0/Spectre.Console.Cli.xml",
"lib/netstandard2.0/de/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/es/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/fr/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/it/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/ja/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/ko/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/pt/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/ru/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/sv/Spectre.Console.Cli.resources.dll",
"lib/netstandard2.0/zh-Hans/Spectre.Console.Cli.resources.dll",
"logo.png",
"spectre.console.cli.0.51.2-preview.0.1.nupkg.sha512",
"spectre.console.cli.nuspec"
]
},
"SSH.NET/2025.0.0": {
"sha512": "AKYbB+q2zFkNQbBFx5gXdv+Wje0baBtADQ35WnMKi4bg1ka74wTQtWoPd+fOWcydohdfsD0nfT8ErMOAPxtSfA==",
"type": "package",
"path": "ssh.net/2025.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"SS-NET-icon-h500.png",
"lib/net462/Renci.SshNet.dll",
"lib/net462/Renci.SshNet.xml",
"lib/net8.0/Renci.SshNet.dll",
"lib/net8.0/Renci.SshNet.xml",
"lib/net9.0/Renci.SshNet.dll",
"lib/net9.0/Renci.SshNet.xml",
"lib/netstandard2.0/Renci.SshNet.dll",
"lib/netstandard2.0/Renci.SshNet.xml",
"lib/netstandard2.1/Renci.SshNet.dll",
"lib/netstandard2.1/Renci.SshNet.xml",
"ssh.net.2025.0.0.nupkg.sha512",
"ssh.net.nuspec"
]
},
"VsTools.Projects/1.2.0": {
"sha512": "Zja9D1HlSi+6goiAYUkcuE1dUC7MyoU4ZiXCNMcQ6JFNloHpwO8ne7cATi4jeMco56TB3Trzv+vtAiK4jDydlw==",
"type": "package",
"path": "vstools.projects/1.2.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net452/VsTools.Projects.dll",
"lib/net462/VsTools.Projects.dll",
"lib/net48/VsTools.Projects.dll",
"lib/netstandard2.0/VsTools.Projects.dll",
"vstools.projects.1.2.0.nupkg.sha512",
"vstools.projects.nuspec"
]
}
},
"projectFileDependencyGroups": {
"net9.0": [
"SSH.NET >= 2025.0.0",
"Spectre.Console >= 0.51.2-preview.0.1",
"Spectre.Console.Cli >= 0.51.2-preview.0.1",
"VsTools.Projects >= 1.2.0"
]
},
"packageFolders": {
"C:\\Users\\qwsdc\\.nuget\\packages\\": {}
},
"project": {
"version": "1.0.0",
"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",
"packagesPath": "C:\\Users\\qwsdc\\.nuget\\packages\\",
"outputPath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\",
"projectStyle": "PackageReference",
"configFilePaths": [
"C:\\Users\\qwsdc\\AppData\\Roaming\\NuGet\\NuGet.Config"
],
"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"
}
}
}
}
@@ -0,0 +1,16 @@
{
"version": 2,
"dgSpecHash": "KOrx7rOcVCU=",
"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\\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"
],
"logs": []
}
@@ -0,0 +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"}}
@@ -0,0 +1 @@
17584140259343453
@@ -0,0 +1 @@
17584254157830058