5 Commits
Author SHA1 Message Date
qwsdcvghyu89 1f6da33b12 Improved logic. 2026-06-04 16:23:37 +10:00
riley 115801e161 Delete directory '.idea/.idea.aeqw89.tools.Publish/.idea' 2026-06-04 08:17:24 +02:00
riley 769aa027c2 Delete directory 'aeqw89.tools.Publish/bin/Debug/net9.0' 2026-06-04 08:17:13 +02:00
riley 31fc8e7853 Delete directory 'aeqw89.tools.Publish/obj' 2026-06-04 08:17:03 +02:00
qwsdcvghyu89 5467de0d1a Add version update logic and improve tool configuration
- Introduced `ChangeVersion` method for version manipulation based on major, minor, and patch increments.
- Updated .gitignore to include `obj/` directory.
- Added `Aigamo.ResXGenerator` dependency and configuration for ResX generation.
- Refactored argument parsing in `Program.cs` for improved readability and error handling.
- Cleaned up `Exceptions.resx` file format and extended comments for clarity.
2026-06-04 16:15:02 +10:00
62 changed files with 842 additions and 1414 deletions
-13
View File
@@ -1,13 +0,0 @@
# 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
@@ -1,4 +0,0 @@
<?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
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+2 -1
View File
@@ -1 +1,2 @@
bin/ bin/**
obj/**
+184
View File
@@ -0,0 +1,184 @@
using System.Diagnostics;
using System.Text;
using Renci.SshNet;
using Spectre.Console;
namespace aeqw89.tools.Publish;
sealed record DestinationContext(
ProgressTask Task,
ProgressContext ProgressContext,
MemoryStream Reader,
FileInfo PackageFile,
string Name,
long BufferSize,
long PackageSize
);
interface IDestination {
Task<Result<Success, ReadableError>> WaitForCompletion(CancellationToken ct = default);
}
sealed record LocalDestination(DestinationContext Context) : IDestination {
public async Task<Result<Success, ReadableError>> WaitForCompletion(CancellationToken ct = default) {
// Path = "$USER/local-%ctx.name/%pkg.filename"
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), Context.Name, Context.PackageFile.Name);
try {
Directory.CreateDirectory(Path.GetDirectoryName(path)!); // create the directory
await using var writer = File.OpenWrite(path);
var buffer = new byte[Context.BufferSize];
int read;
do {
read = await Context.Reader.ReadAsync(buffer, ct);
writer.Write(buffer, 0, read);
Context.Task.Increment(read);
} while (read > 0);
return Success.AsResult();
} catch (Exception e) {
return new ReadableError(string.Format(Exceptions.generic_error, e), false);
}
}
}
sealed record CloudDestiantion(DestinationContext Context) : IDestination {
public async Task<Result<Success, ReadableError>> WaitForCompletion(CancellationToken ct = default) {
var connectionTask = Context.ProgressContext.AddTaskBefore($"Preparing cloud-{Context.Name}",
new ProgressTaskSettings() {
MaxValue = 100
}, Context.Task);
if (!SshHosts.TryGetHost(Context.Name, out var host)) {
return new ReadableError(string.Format(Exceptions.cloud_host_not_found.EscapeMarkup(), Context.Name), false);
}
var connectionInfo = SshHosts.GetConnection(Context.Name);
using var sshClient = new SshClient(connectionInfo);
if (!sshClient.IsConnected)
await sshClient.ConnectAsync(ct);
connectionTask.Increment(33); // ? One-Third of the way done (connection success).
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) { // * missing env variable case (could not work out where to place packages in remote).
return new ReadableError(string.Format(Exceptions.failed_to_prepare_server_directory, "n/a", Context.PackageFile.Name, os,
userDirC.Result), false);
}
var userDir = userDirC.Result.Trim();
remoteDirectory = RemotePath.Combine(RemoteOs.Windows, userDir, "dotnet-packages");
packageFileDirectory = RemotePath.Combine(RemoteOs.Windows, remoteDirectory, Context.PackageFile.Name);
var mkdirC = sshClient.RunCommand($"cmd /c if not exist \"{remoteDirectory}\" mkdir \"{remoteDirectory}\"");
if (mkdirC.ExitStatus != 0) { // * MKDir error case (make directory command failed on remote).
return new ReadableError(string.Format(Exceptions.failed_to_prepare_server_directory, remoteDirectory, Context.PackageFile.Name, os,
mkdirC.Result), false);
}
}
else if (os == "linux") {
var homeDirC = sshClient.RunCommand("printf %s \"$HOME\"");
if (homeDirC.ExitStatus != 0) { // * missing env variable case 2 (could not work out where to place packages in remote).
return new ReadableError(string.Format(Exceptions.failed_to_prepare_server_directory, "n/a", Context.PackageFile.Name, os,
homeDirC.Result), false);
}
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,
Context.PackageFile.Name);
// Use -p and single quotes to handle spaces safely
var mkdirC = sshClient.RunCommand($"mkdir -p '{remoteDirectory}'");
if (mkdirC.ExitStatus != 0) { // * MKDir error case (make directory command failed on remote).
return new ReadableError(string.Format(Exceptions.failed_to_prepare_server_directory, remoteDirectory, Context.PackageFile.Name,
os, mkdirC.Result), false);
}
}
else {
return new ReadableError(string.Format(Exceptions.failed_to_prepare_server_directory, "n/a", Context.PackageFile.Name, os,
"Unsupported OS"), false); // * MacOS failure path (or other unrecognizable oses).
}
connectionTask.Increment(33); // ? Two-Thirds of the way done (directory located and ready).
sshClient.Disconnect();
using var client = new SftpClient(connectionInfo);
if (!client.IsConnected)
await client.ConnectAsync(ct);
connectionTask.Increment(33); // ? Connection task complete (now proceeding to upload task).
connectionTask.StopTask();
await using var writer = client.OpenWrite(packageFileDirectory);
byte[] buffer = new byte[Context.BufferSize];
int read;
do {
read = await Context.Reader.ReadAsync(buffer, ct);
writer.Write(buffer, 0, read);
Context.Task.Increment(read);
} while (read > 0);
return Success.AsResult();
}
}
sealed record GithubDestination(DestinationContext Context, bool Verbose = false) : IDestination {
public async Task<Result<Success, ReadableError>> WaitForCompletion(CancellationToken ct = default) {
var p = Process.Start(new ProcessStartInfo() {
FileName = "dotnet",
Arguments = $"nuget push \"{Context.PackageFile.FullName}\" --source github",
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
});
var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
StringBuilder errorLines = new();
p?.ErrorDataReceived += (sender, eventArgs) => {
cts.Cancel();
if (Verbose && eventArgs.Data != null)
AnsiConsole.WriteLine(eventArgs.Data);
errorLines.Append(eventArgs.Data);
};
p?.OutputDataReceived += (sender, eventArgs) => {
if (eventArgs.Data?.ToLower().Contains("press any key") == true)
cts.Cancel();
if (Verbose && eventArgs.Data != null)
AnsiConsole.WriteLine(eventArgs.Data);
};
p?.BeginOutputReadLine();
p?.BeginErrorReadLine();
Context.Task.Increment(Context.PackageSize / 2);
if (p != null)
try {
await (p?.WaitForExitAsync(cts.Token) ?? Task.CompletedTask);
}
catch (TaskCanceledException) {
p?.Kill();
}
if (p?.ExitCode != 0) {
Context.Task.StopTask();
return new ReadableError(errorLines.ToString().EscapeMarkup() + "\n" + string.Format(Exceptions.dotnet_nuget_push_failure, p?.ExitCode ?? -1), false);
}
Context.Task.Increment(Context.BufferSize / 2);
return Success.AsResult();
}
}
+127 -6
View File
@@ -1,75 +1,196 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <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"> Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element> </xsd:element>
</xsd:schema> </xsd:schema>
<resheader name="resmimetype"> <resheader name="resmimetype">
<value>text/microsoft-resx</value> <value>text/microsoft-resx</value>
</resheader> </resheader>
<resheader name="version"> <resheader name="version">
<value>1.3</value> <value>2.0</value>
</resheader> </resheader>
<resheader name="reader"> <resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="missing_mode" xml:space="preserve"> <data name="missing_mode" xml:space="preserve">
<value>You must specify a mode; allowed modes are [overwrite|increment]</value> <value>You must specify a mode; allowed modes are [overwrite|increment]</value>
<comment/>
</data> </data>
<data name="could_not_parse_mode" xml:space="preserve"> <data name="could_not_parse_mode" xml:space="preserve">
<value>The mode '{0}' is invalid, the valid modes are [overwrite|increment]</value> <value>The mode '{0}' is invalid, the valid modes are [overwrite|increment]</value>
<comment/>
</data> </data>
<data name="could_not_parse_target" xml:space="preserve"> <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> <value>The increment target '{0}' is invalid, the valid increment targets are [patch|minor|patch]</value>
<comment/>
</data> </data>
<data name="missing_increment_target" xml:space="preserve"> <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> <value>You must specify an increment target if you specified an increment mode; allowed increment targets are [patch|minor|major]</value>
<comment/>
</data> </data>
<data name="missing_destinations" xml:space="preserve"> <data name="missing_destinations" xml:space="preserve">
<value>You must specify at least one destination.</value> <value>You must specify at least one destination.</value>
<comment/>
</data> </data>
<data name="no_project_in_directory" xml:space="preserve"> <data name="no_project_in_directory" xml:space="preserve">
<value>No project file was found within the current directory.</value> <value>No project file was found within the current directory.</value>
<comment/>
</data> </data>
<data name="flag_parameter_length_incorrect" xml:space="preserve"> <data name="flag_parameter_length_incorrect" xml:space="preserve">
<value>The flag '{0}' requires exactly '{1}' parameters. You have entered '{2}'.</value> <value>The flag '{0}' requires exactly '{1}' parameters. You have entered '{2}'.</value>
<comment/>
</data> </data>
<data name="flag_parameter_type_incorrect" xml:space="preserve"> <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> <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>
<comment/>
</data> </data>
<data name="version_string_not_formatted_correctly" xml:space="preserve"> <data name="version_string_not_formatted_correctly" xml:space="preserve">
<value>The version string '{0}' is in an unidentifiable format.</value> <value>The version string '{0}' is in an unidentifiable format.</value>
<comment/>
</data> </data>
<data name="tried_loading_non_csproj_file" xml:space="preserve"> <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> <value>Something went wrong; an attempt was made to load a non .csproj file as a project file.</value>
<comment/>
</data> </data>
<data name="generic_error" xml:space="preserve"> <data name="generic_error" xml:space="preserve">
<value>Something went wrong loading this file; {0}</value> <value>Something went wrong loading this file; {0}</value>
<comment/>
</data> </data>
<data name="found_multiple_csproj" xml:space="preserve"> <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> <value>The directory '{0}' contains multiple .csproj files; this tool can only process one at a time.</value>
<comment/>
</data> </data>
<data name="project_file_irreparable" xml:space="preserve"> <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> <value>The project file '{0}' is irreparable becuase it is missing a '{1}' property, and the value cannot be guessed.</value>
<comment/>
</data> </data>
<data name="dotnet_pack_failure" xml:space="preserve"> <data name="dotnet_pack_failure" xml:space="preserve">
<value>Failed to pack with exit code '{0}'; ensure that 'dotnet build' succeeds before running this program.</value> <value>Failed to pack with exit code '{0}'; ensure that 'dotnet build' succeeds before running this program.</value>
<comment/>
</data> </data>
<data name="failed_to_clean_up" xml:space="preserve"> <data name="failed_to_clean_up" xml:space="preserve">
<value>Could not delete temporary directory '{0}' due to error '{1}'</value> <value>Could not delete temporary directory '{0}' due to error '{1}'</value>
<comment/>
</data> </data>
<data name="cloud_host_not_found" xml:space="preserve"> <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> <value>The cloud host '{0}' is not an entry on this user's config file.</value>
<comment/>
</data> </data>
<data name="failed_to_prepare_server_directory" xml:space="preserve"> <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> <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>
<comment/>
</data> </data>
<data name="dotnet_nuget_push_failure" xml:space="preserve"> <data name="dotnet_nuget_push_failure" xml:space="preserve">
<value>The 'dotnet nuget push' command failed with error message '{0}'</value> <value>The 'dotnet nuget push' command failed with error message '{0}'</value>
<comment/>
</data>
<data name="destination_unrecognizable" xml:space="preserve">
<value>The destination '{0}' is unrecognizable.</value>
<comment/>
</data> </data>
</root> </root>
+158 -418
View File
@@ -5,6 +5,7 @@ using Renci.SshNet;
using Spectre.Console; using Spectre.Console;
using aeqw89.xml.ProjectFile; using aeqw89.xml.ProjectFile;
namespace aeqw89.tools.Publish; namespace aeqw89.tools.Publish;
/* /*
@@ -20,74 +21,80 @@ namespace aeqw89.tools.Publish;
* e.g. publish overwrite|increment [patch|minor|major] destinations [flags] * e.g. publish overwrite|increment [patch|minor|major] destinations [flags]
*/ */
public static class Program { public static class Program {
public static Mode Mode { get; set; } const long BufferSize = 80 * 1024; // 80 KB
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 List<Action> RestoreActions { get; set; } = []; internal record RunContext(List<Action> RestoreActions, ArgValues Args, string TempDir) {
public void Restore(bool deleteTempDir = true) {
RestoreActions.ForEach(x => x());
public static void ReadArgs(string[] args) { if (deleteTempDir) {
if (args.Length < 1) { try {
ShowError(Exceptions.missing_mode.EscapeMarkup()); if (!Directory.Exists(TempDir)) return;
ShowHelp(); Directory.Delete(TempDir, true);
return; AnsiConsole.MarkupLine("[yellow]Cleaned up temporary directory[/]");
}
catch (Exception e) {
ShowError(string.Format(Exceptions.failed_to_clean_up.EscapeMarkup(), TempDir.EscapeMarkup(),
e.ToString().EscapeMarkup()));
}
} }
Mode = args[0] switch { RestoreActions.Clear();
}
}
internal record ArgValues(Mode Mode, string[] Destinations, Dictionary<string, string[]> Flags, bool Verbose, IncrementTarget? Target);
static Result<ArgValues, ReadableError> ReadArgs(string[] args) {
if (args.Length < 1) // not enough args (min = 2)
return new ReadableError(Exceptions.missing_mode.EscapeMarkup());
var mode = args[0].ToLower() switch {
"overwrite" => Mode.Overwrite, "overwrite" => Mode.Overwrite,
"increment" => Mode.Increment, "increment" => Mode.Increment,
_ => (Mode)(-1) _ => (Mode)(-1) // mode must be one of two values
}; };
if (Mode == (Mode)(-1)) { if (mode == (Mode)(-1)) // invalid mode
ShowError(Exceptions.could_not_parse_mode.EscapeMarkup(), args[0].EscapeMarkup()); return new ReadableError(string.Format(Exceptions.could_not_parse_mode.EscapeMarkup(), args[0].EscapeMarkup()));
ShowHelp();
return;
}
if (args.Length < 2) { if (args.Length < 2) // not enough args (min = 2)
if (Mode == Mode.Increment) return new ReadableError(mode switch {
ShowError(Exceptions.missing_increment_target.EscapeMarkup()); Mode.Increment => Exceptions.missing_increment_target.EscapeMarkup(),
else if (Mode == Mode.Overwrite) Mode.Overwrite => Exceptions.missing_destinations.EscapeMarkup(),
ShowError(Exceptions.missing_destinations.EscapeMarkup()); _ => throw new UnreachableException()
ShowHelp(); });
return;
}
Destinations = args[1..]; var destinations = args[1..]; // destinations is variarg.
Flags = []; Dictionary<string, string[]> flags = []; // flags is parsed last
if (Mode == Mode.Increment) { IncrementTarget? target = null;
if (args.Length < 3) { if (mode == Mode.Increment) {
ShowError(Exceptions.missing_destinations.EscapeMarkup()); if (args.Length < 3) // increment mode requires target version in addition to destinations
ShowHelp(); return new ReadableError(Exceptions.missing_destinations.EscapeMarkup());
return;
}
Destinations = args[2..]; destinations = args[2..]; // target is args[1] (args[0] is mode)
Target = args[1] switch { target = args[1].ToLower() switch {
"patch" => IncrementTarget.Patch, "patch" => IncrementTarget.Patch,
"minor" => IncrementTarget.Minor, "minor" => IncrementTarget.Minor,
"major" => IncrementTarget.Major, "major" => IncrementTarget.Major,
_ => (IncrementTarget)(-1) _ => (IncrementTarget)(-1)
}; };
if (Target == (IncrementTarget)(-1)) { if (target == (IncrementTarget)(-1)) // unrecognizable target entered
ShowError(Exceptions.could_not_parse_target.EscapeMarkup(), args[1].EscapeMarkup()); return new ReadableError(string.Format(Exceptions.could_not_parse_target.EscapeMarkup(), args[1].EscapeMarkup()));
ShowHelp();
return;
}
} }
string? firstFlag = Destinations.FirstOrDefault(x => x.StartsWith('-')); string? firstFlag = destinations.FirstOrDefault(x => x.StartsWith('-')); // find the first arg that starts with '-' signifying a flag.
if (firstFlag == null) return; if (firstFlag == null) // no flags case - return early.
string[] flags = Destinations.SkipWhile(x => x != firstFlag).ToArray(); return new Ok<ArgValues>(new ArgValues(mode, destinations, flags, false, target));
Flags = ReadFlags(flags); string[] flagsRaw = destinations.SkipWhile(x => x != firstFlag).ToArray(); // extract flags from destinations.
Destinations = Destinations.TakeWhile(x => x != firstFlag).ToArray(); flags = ReadFlags(flagsRaw); // get flags as dictionary to args (pattern is -flag0 [arg0] [arg1] -flag1 ...)
Verbose = Flags.ContainsKey("--verbose") || Flags.ContainsKey("-v"); destinations = destinations.TakeWhile(x => x != firstFlag).ToArray(); // remove flags from destinations.
bool verbose = flags.ContainsKey("--verbose") || flags.ContainsKey("-v"); // verbosity switch is extracted early.
return new Ok<ArgValues>(new ArgValues(mode, destinations, flags, verbose, target)); // return with fully parsed flags.
} }
private static Dictionary<string, string[]> ReadFlags(string[] flags) { private static Dictionary<string, string[]> ReadFlags(string[] flags) {
@@ -105,89 +112,66 @@ public static class Program {
collected.Add(flag); collected.Add(flag);
} }
result[lastKey] = collected.ToArray();
return result; return result;
} }
public static async Task Main(string[] args) { record ProjectResult(string PackageId, string Version);
ReadArgs(args); static async Task<Result<ProjectResult, ReadableError>> PrepareProject(RunContext rctx, StatusContext ctx) {
Console.CancelKeyPress += (sender, eventArgs) => {
RestoreActions.ForEach(x => x());
};
string packageId = "";
string version = "";
int destinationsProcessed = 0;
try {
var result = AnsiConsole.Status()
.Spinner(Spinner.Known.Dots)
.Start<bool>("Preparing project", ctx => {
ctx.Status = "Locating project file"; ctx.Status = "Locating project file";
if (!ProjectFile.TryLoad(Environment.CurrentDirectory, out var projectFile, out var error)) { if (!ProjectFile.TryLoad(Environment.CurrentDirectory, out var projectFile, out var error))
ShowError(error.EscapeMarkup()); return new ReadableError(error);
return false;
}
packageId = projectFile.GetPackageId(); string packageId = projectFile.GetPackageId();
string version;
try { try {
projectFile.Backup(); projectFile.Backup();
RestoreActions.Add(() => { rctx.RestoreActions.Add(() => {
projectFile.Restore(); projectFile.Restore();
AnsiConsole.MarkupLine("[yellow]Restored project file from backup.[/]"); AnsiConsole.MarkupLine("[yellow]Restored project file from backup.[/]");
}); });
if (Verbose) if (rctx.Args.Verbose)
AnsiConsole.WriteLine( AnsiConsole.WriteLine(
$"Created project file backup at {projectFile.GetDefaultBackupLocation()}"); $"Created project file backup at {projectFile.GetDefaultBackupLocation()}");
ctx.Status = "Repairing project file"; ctx.Status = "Repairing project file";
if (!Flags.ContainsKey("--skip-repair")) if (!rctx.Args.Flags.ContainsKey("--skip-repair"))
if (!projectFile.TryRepair(out error)) { if (!projectFile.TryRepair(out error)) {
ShowError(error.EscapeMarkup()); return new ReadableError(error.EscapeMarkup(), false);
projectFile.Restore();
return false;
} }
if (Mode == Mode.Increment && !Flags.ContainsKey("--simulate")) { if (rctx.Args.Mode == Mode.Increment && !rctx.Args.Flags.ContainsKey("--simulate")) {
int delta = 1; int delta = 1;
if (Flags.TryGetValue("--delta", out var deltaStrings)) { if (rctx.Args.Flags.TryGetValue("--delta", out var deltaStrings)) {
if (deltaStrings.Length != 1) { if (deltaStrings.Length != 1) {
ShowError(Exceptions.flag_parameter_length_incorrect.EscapeMarkup(), "--delta", 1, return new ReadableError(string.Format(Exceptions.flag_parameter_length_incorrect.EscapeMarkup(), "--delta", 1,
deltaStrings.Length); deltaStrings.Length));
projectFile.Restore();
ShowHelp();
return false;
} }
if (!int.TryParse(deltaStrings[0], out delta)) { if (!int.TryParse(deltaStrings[0], out delta)) {
ShowError(Exceptions.flag_parameter_type_incorrect.EscapeMarkup(), "--delta", 0, return new ReadableError(string.Format(Exceptions.flag_parameter_type_incorrect.EscapeMarkup(), "--delta", 0,
nameof(Int32), nameof(Int32),
deltaStrings[0]); deltaStrings[0]));
projectFile.Restore();
ShowHelp();
return false;
} }
} }
ctx.Status = "Updating version"; ctx.Status = "Updating version";
var version = projectFile.GetVersion(); version = projectFile.GetVersion();
version = ChangeVersion(version, delta, Target ?? IncrementTarget.Patch); version = ProjectFile.ChangeVersion(version, delta, rctx.Args.Target ?? IncrementTarget.Patch).Unwrap(rctx);
projectFile.SetVersion(version); projectFile.SetVersion(version);
} }
} }
catch (Exception e) { catch (Exception e) {
ShowError(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup()); return new ReadableError(string.Format(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup()), false);
RestoreActions.ForEach(x => x());
return false;
} }
version = projectFile.GetVersion(); version = projectFile.GetVersion();
if (!Flags.ContainsKey("--simulate")) { if (!rctx.Args.Flags.ContainsKey("--simulate")) {
try { try {
var packageReferences = projectFile.GetPackageReferences(); var packageReferences = projectFile.GetPackageReferences();
foreach (var reference in packageReferences.Where(x => !projectFile.IsTransitive(x))) foreach (var reference in packageReferences.Where(x => !projectFile.IsTransitive(x)))
@@ -201,22 +185,21 @@ public static class Program {
var reference = projectReferences.Dequeue(); var reference = projectReferences.Dequeue();
visited.Add(reference.Include); visited.Add(reference.Include);
if (Verbose) if (rctx.Args.Verbose)
AnsiConsole.WriteLine( AnsiConsole.WriteLine(
$"Processing project reference {reference.Include} out of {visited.Count} so far"); $"Processing project reference {reference.Include} out of {visited.Count} so far");
// if (Flags.ContainsKey("--force-private"))
projectFile.SetPrivateAssets(reference, PrivateAssetsValue.All); projectFile.SetPrivateAssets(reference, PrivateAssetsValue.All);
string pathToReferencedProjectFile = projectFile.GetAbsoluteIncludePath(reference); string pathToReferencedProjectFile = projectFile.GetAbsoluteIncludePath(reference);
if (!ProjectFile.TryLoad(pathToReferencedProjectFile, out var referencedProjectFile, if (!ProjectFile.TryLoad(pathToReferencedProjectFile, out var referencedProjectFile,
out error)) { out error)) {
ShowError(error.EscapeMarkup()); return new ReadableError(error.EscapeMarkup(), false);
RestoreActions.ForEach(x => x());
return false;
} }
var referencedPackageReferences = referencedProjectFile.GetPackageReferences(); var referencedPackageReferences = referencedProjectFile.GetPackageReferences();
foreach (var package in referencedPackageReferences) { foreach (var package in referencedPackageReferences) {
if (Verbose) if (rctx.Args.Verbose)
AnsiConsole.WriteLine( AnsiConsole.WriteLine(
$"Hoisting package {package.Include} from {pathToReferencedProjectFile}"); $"Hoisting package {package.Include} from {pathToReferencedProjectFile}");
var hoisted = projectFile.AddPackage(package); var hoisted = projectFile.AddPackage(package);
@@ -233,373 +216,130 @@ public static class Program {
} }
} }
catch (Exception e) { catch (Exception e) {
ShowError(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup()); return new ReadableError(string.Format(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup()), false);
RestoreActions.ForEach(x => x());
return false;
} }
} }
projectFile.Save(); projectFile.Save();
return true; return new Ok<ProjectResult>(new ProjectResult(packageId, version));
});
if (!result) {
return;
} }
var outDir = Path.GetRandomFileName(); static async Task<Result<Success, ReadableError>> PackProject(RunContext rctx, StatusContext ctx) {
RestoreActions.Add(() => { DataReceivedEventHandler dataHandler = rctx.Args.Verbose switch {
try { false => (_, _) => {},
if (!Directory.Exists(outDir)) return; true => (_ , e) => {
Directory.Delete(outDir, true); AnsiConsole.MarkupLine("[Packing]: " + e.Data?.EscapeMarkup() ?? string.Empty);
AnsiConsole.MarkupLine("[yellow]Cleaned up temporary directory[/]");
}
catch (Exception e) {
ShowError(string.Format(Exceptions.failed_to_clean_up.EscapeMarkup(), outDir.EscapeMarkup(),
e.ToString().EscapeMarkup()));
}
});
string processError = "";
var exitCode = await AnsiConsole.Status()
.Spinner(Spinner.Known.Dots)
.StartAsync<int>("Creating package with 'dotnet pack' ", async ctx => {
var p = Process.Start(new ProcessStartInfo() {
FileName = "dotnet",
Arguments = $"pack -o {outDir}",
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
});
CancellationTokenSource cts = new CancellationTokenSource();
StringBuilder errorLines = new();
p?.ErrorDataReceived += (sender, eventArgs) => {
cts.Cancel();
if (Verbose && eventArgs.Data != null)
AnsiConsole.WriteLine(eventArgs.Data);
};
bool success = false;
p?.OutputDataReceived += (sender, eventArgs) => {
if (eventArgs.Data?.ToLower().Contains("press any key") == true)
cts.Cancel();
if (Verbose && eventArgs.Data != null)
AnsiConsole.WriteLine(eventArgs.Data);
// Successfully created package 'C:\Users\qwsdc\source\repos\Beam\aeqw89.Beam\tozsxqaj.alp\Beam.1.0.0.nupkg'.
if (eventArgs.Data?.ToLower()
.Contains($"successfully created package '{Path.GetFullPath(outDir)}") == true) {
AnsiConsole.MarkupLine($"[bold]{eventArgs.Data}[/]");
success = true;
} }
}; };
var result = (await Shell.Dotnet.Pack(rctx.TempDir, dataHandler, dataHandler)).Unwrap(rctx);
p?.BeginOutputReadLine(); if (result.ExitCode != 0)
p?.BeginErrorReadLine(); return new ReadableError(result.Error + "\n" + string.Format(Exceptions.dotnet_pack_failure.EscapeMarkup(), result.ExitCode), false);
try { return Success.AsResult();
await (p?.WaitForExitAsync(cts.Token) ?? Task.CompletedTask);
}
catch (TaskCanceledException) {
p?.Kill();
} }
processError = errorLines.ToString().EscapeMarkup(); enum DestinationType {
return success == true ? 0 : p?.ExitCode ?? -1; Local,
}); Github,
Cloud
if (exitCode != 0) {
ShowError(processError.EscapeMarkup());
ShowError(Exceptions.dotnet_pack_failure.EscapeMarkup(), exitCode);
RestoreActions.ForEach(x => x());
return;
} }
if (Verbose) public static async Task Main(string[] args) {
AnsiConsole.MarkupLine("Successfully created package with exit code [green]{0}[/]. Processing destinations.", exitCode); ArgValues? parsed = ReadArgs(args).Unwrap();
if (parsed is null) return;
var package = Directory.GetFiles(outDir, "*.nupkg").FirstOrDefault(); RunContext rctx = new([], parsed, Path.GetRandomFileName());
if (package == null) {
ShowError(Exceptions.generic_error.EscapeMarkup());
RestoreActions.ForEach(x => x());
return;
}
var inMemory = await File.ReadAllBytesAsync(package); Console.CancelKeyPress += (sender, eventArgs) => {
var size = new FileInfo(package).Length; rctx.Restore();
const long bufferSize = 80 * 1024; // 80 KB };
try {
await AnsiConsole.Progress() var stager = new Stager(rctx);
.AutoClear(true)
.HideCompleted(false) ProjectResult? project = await stager.Spinner("Preparing project", PrepareProject);
.Columns(new ProgressColumn[] { if (project is null) return;
new TaskDescriptionColumn(),
new ProgressBarColumn() int destinationsProcessed = 0;
.RemainingStyle(Style.Parse("dim gray slowblink"))
.CompletedStyle(Style.Parse("green strikethrough")) var dotnetPackResult = await stager.Spinner("Creating package with 'dotnet pack'", PackProject);
.FinishedStyle("green strikethrough"), if (dotnetPackResult is null) return;
new DownloadedColumn(),
new RemainingTimeColumn(), if (rctx.Args.Verbose)
new TransferSpeedColumn(), AnsiConsole.MarkupLine("Successfully created package with exit code [green]{0}[/]. Processing destinations.", 0);
})
.StartAsync(async ctx => { var progress = stager.Progress();
await Parallel.ForEachAsync(Destinations, new ParallelOptions() { var task = progress.Run("push to destinations", async (rctx, ctx) => {
var pkg = await Shell.Dotnet.FindPackage(rctx.TempDir).Unwrap(rctx);
await Parallel.ForEachAsync(rctx.Args.Destinations, new ParallelOptions() {
MaxDegreeOfParallelism = Environment.ProcessorCount, MaxDegreeOfParallelism = Environment.ProcessorCount,
}, async (dest, ct) => { }, async (dest, ct) => {
using var reader = new MemoryStream(inMemory); using var reader = new MemoryStream(pkg.Read());
var task = ctx.AddTask(dest, new ProgressTaskSettings() { var task = ctx.AddTask(dest, new ProgressTaskSettings() {
MaxValue = size MaxValue = pkg.Size()
}); });
DestinationType destType;
if (dest.StartsWith("local-")) { if (dest.StartsWith("local-")) {
var name = dest[("local-".Length)..]; destType = DestinationType.Local;
var path = Path.Combine( } else if (dest.StartsWith("cloud-")) {
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), destType = DestinationType.Cloud;
name, Path.GetFileName(package)); } else if (dest == "github") {
if (!Directory.Exists(Path.GetDirectoryName(path))) destType = DestinationType.Github;
Directory.CreateDirectory(Path.GetDirectoryName(path)!); } else {
await using var writer = File.OpenWrite(path); lock(rctx) {
var buffer = new byte[bufferSize]; ShowError(string.Format(Exceptions.destination_unrecognizable, dest));
int read; ShowHelp();
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 = true,
RedirectStandardError = true
});
var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
StringBuilder errorLines = new();
p?.ErrorDataReceived += (sender, eventArgs) => {
cts.Cancel();
if (Verbose && eventArgs.Data != null)
AnsiConsole.WriteLine(eventArgs.Data);
errorLines.Append(eventArgs.Data);
};
p?.OutputDataReceived += (sender, eventArgs) => {
if (eventArgs.Data?.ToLower().Contains("press any key") == true)
cts.Cancel();
if (Verbose && eventArgs.Data != null)
AnsiConsole.WriteLine(eventArgs.Data);
};
p?.BeginOutputReadLine();
p?.BeginErrorReadLine();
if (p == null) {
ShowError(Exceptions.generic_error.EscapeMarkup());
}
task.Increment(size / 2);
if (p != null)
try {
await (p?.WaitForExitAsync(cts.Token) ?? Task.CompletedTask);
}
catch (TaskCanceledException) {
p?.Kill();
}
if (p?.ExitCode != 0) {
ShowError(errorLines.ToString().EscapeMarkup());
ShowError(Exceptions.dotnet_nuget_push_failure, p?.ExitCode ?? -1);
task.StopTask(); task.StopTask();
return; return;
} }
task.Increment(size / 2); var dctx = new DestinationContext(task, ctx, reader, pkg.FileInfo, destType switch {
} DestinationType.Cloud => dest["cloud-".Length..],
DestinationType.Github => dest["github".Length..],
DestinationType.Local => dest["local-".Length..]
}, BufferSize, pkg.Size());
IDestination destination = destType switch {
DestinationType.Local => new LocalDestination(dctx),
DestinationType.Github => new GithubDestination(dctx, rctx.Args.Verbose),
DestinationType.Cloud => new CloudDestiantion(dctx),
_ => throw new UnreachableException()
};
var result = await destination.WaitForCompletion(ct);
lock(rctx) {
if (result.Unwrap(rctx) is not null) {
Interlocked.Increment(ref destinationsProcessed); Interlocked.Increment(ref destinationsProcessed);
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()));
} }
} }
} task.StopTask();
catch(Exception e) { });
ShowError(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup());;
RestoreActions.ForEach(x => x()); return Success.AsResult();
} });
await task.Value;
if (destinationsProcessed == 0) { if (destinationsProcessed == 0) {
AnsiConsole.MarkupLine("[bold red]No destinations were processed. Reverting changes to project file.[/]"); AnsiConsole.MarkupLine("[bold red]No destinations were processed. Reverting changes to project file.[/]");
RestoreActions.ForEach(x => x()); rctx.Restore();
} }
else { else {
AnsiConsole.MarkupLine("Completed processing of all destinations."); AnsiConsole.MarkupLine("Completed processing of all destinations.");
AnsiConsole.MarkupLine( AnsiConsole.MarkupLine(
"Example usage:\n\t <PackageReference Include=\"{0}\" Version=\"{1}\" />".EscapeMarkup(), packageId, "Example usage:\n\t <PackageReference Include=\"{0}\" Version=\"{1}\" />".EscapeMarkup(), project.PackageId,
version); project.Version);
} }
} }
/// <summary> public static void ShowError(string message, params object[] args) {
/// 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 delta, IncrementTarget target) {
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();
switch (target) {
case IncrementTarget.Major:
parsedVersion[0] += delta;
parsedVersion[1] = 0;
parsedVersion[2] = 0;
break;
case IncrementTarget.Minor:
parsedVersion[1] += delta;
parsedVersion[2] = 0;
break;
case IncrementTarget.Patch:
parsedVersion[2] += delta;
break;
}
return
$"{parsedVersion[0]}.{parsedVersion[1]}.{parsedVersion[2]}{tag}";
}
private static void ShowError(string message, params object[] args) {
AnsiConsole.MarkupLine($"[bold red]{message}[/]", args); AnsiConsole.MarkupLine($"[bold red]{message}[/]", args);
} }
private static void ShowHelp() { public static void ShowHelp() {
AnsiConsole.Markup(("Usage: publish overwrite|increment [patch|minor|major] destinations [flags]\n" + AnsiConsole.Markup(("Usage: publish overwrite|increment [patch|minor|major] destinations [flags]\n" +
"\t if mode: overwrite destinations [flags]\n" + "\t if mode: overwrite destinations [flags]\n" +
"\t if mode: increment patch|minor|major [flags]\n").EscapeMarkup()); "\t if mode: increment patch|minor|major [flags]\n").EscapeMarkup());
+47
View File
@@ -218,4 +218,51 @@ internal class ProjectFile {
MainPropertyGroup.SetProperty("Version", version); MainPropertyGroup.SetProperty("Version", version);
MainPropertyGroup.SetProperty("PackageVersion", version); MainPropertyGroup.SetProperty("PackageVersion", 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>
public static Result<string, ReadableError> ChangeVersion(string version, int delta, IncrementTarget target) {
string[] split = version.Split('.');
if (split.Length != 3) {
return new ReadableError(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 _)))
return new ReadableError(string.Format(Exceptions.version_string_not_formatted_correctly, version));
int[] parsedVersion = split.Select(int.Parse).ToArray();
switch (target) {
case IncrementTarget.Major:
parsedVersion[0] += delta;
parsedVersion[1] = 0;
parsedVersion[2] = 0;
break;
case IncrementTarget.Minor:
parsedVersion[1] += delta;
parsedVersion[2] = 0;
break;
case IncrementTarget.Patch:
parsedVersion[2] += delta;
break;
}
return
$"{parsedVersion[0]}.{parsedVersion[1]}.{parsedVersion[2]}{tag}".Ok();
}
} }
+37
View File
@@ -0,0 +1,37 @@
using System.Diagnostics;
namespace aeqw89.tools.Publish;
record Success {
public static Ok<Success> AsResult() => new Ok<Success>(new Success());
}
record Ok<T>(T Value);
record ReadableError(string Reason, bool ShowHelp = true, bool RestoreContext = true);
union Result<T, E>(Ok<T>, E);
internal static class ResultExtensions {
public static T Unwrap<T>(this Result<T, ReadableError> result, Program.RunContext? rctx = null) {
switch (result) {
case Ok<T> r:
return r.Value;
case ReadableError error:
Program.ShowError(error.Reason);
if (error.ShowHelp) Program.ShowHelp();
if (error.RestoreContext) rctx?.Restore();
Environment.Exit(1);
throw new UnreachableException();
}
throw new UnreachableException();
}
public static async Task<T> Unwrap<T>(this Task<Result<T, ReadableError>> result, Program.RunContext? rctx = null) {
return (await result).Unwrap(rctx);
}
}
internal static class ObjectExtensions {
public static Ok<T> Ok<T>(this T any) {
return new Ok<T>(any);
}
}
+67
View File
@@ -0,0 +1,67 @@
using System.Diagnostics;
using System.Text;
using Spectre.Console;
namespace aeqw89.tools.Publish;
internal static class Shell {
internal record ShellResult(string Output, string Error, int ExitCode);
internal record PackageInfo(FileInfo FileInfo) {
byte[]? _inMemory = null;
public long Size() => FileInfo.Length;
public async Task<byte[]> ReadAsync() => _inMemory ??= await File.ReadAllBytesAsync(FileInfo.FullName);
public byte[] Read() => _inMemory ??= File.ReadAllBytes(FileInfo.FullName);
}
internal static class Dotnet {
internal static async Task<Result<PackageInfo, ReadableError>> FindPackage(string dir) {
var package = Directory.GetFiles(dir, "*.nupkg").FirstOrDefault();
if (package == null) return new ReadableError(Exceptions.generic_error.EscapeMarkup());
return new PackageInfo(new FileInfo(package)).Ok();
}
internal static async Task<Result<ShellResult, ReadableError>> Pack(string tempdir, DataReceivedEventHandler? stderr, DataReceivedEventHandler? stdout) {
var p = Process.Start(new ProcessStartInfo() {
FileName = "dotnet",
Arguments = $"pack -o {tempdir}",
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
});
StringBuilder errorLines = new();
StringBuilder outputLines = new();
CancellationTokenSource cts = new();
p?.ErrorDataReceived += stderr;
p?.ErrorDataReceived += (_, e) => {
cts.Cancel();
errorLines.Append(e.Data);
};
bool success = false;
p?.OutputDataReceived += stdout;
p?.OutputDataReceived += (_, e) => {
if (e.Data?.ToLower().Contains("press any key") == true)
cts.Cancel();
if (e.Data?.ToLower().Contains($"successfully created package '{Path.GetFullPath(tempdir)}") == true) {
success = true;
}
};
p?.BeginErrorReadLine();
p?.BeginOutputReadLine();
try {
await (p?.WaitForExitAsync(cts.Token) ?? Task.CompletedTask);
} catch (TaskCanceledException) {
p?.Kill();
} catch (Exception e) {
return new ReadableError(Exceptions.generic_error.EscapeMarkup(), false);
}
return new ShellResult(outputLines.ToString(), errorLines.ToString(), p!.ExitCode).Ok();
}
}
}
+47
View File
@@ -0,0 +1,47 @@
using System.Diagnostics;
using Spectre.Console;
using static aeqw89.tools.Publish.Program;
namespace aeqw89.tools.Publish;
internal record Stager(RunContext RunContext) {
public async Task<T?> Spinner<T>(string name, Func<RunContext, StatusContext, Task<Result<T, ReadableError>>> factory) {
try {
var result = AnsiConsole.Status()
.Spinner(Spectre.Console.Spinner.Known.Dots)
.Start(name, async ctx => await factory(RunContext, ctx));
return (await result).Unwrap(RunContext);
} catch (Exception e) {
ShowError(string.Format(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup()));
RunContext.Restore();
return default;
}
throw new UnreachableException();
}
public ProgressStager Progress() {
return new ProgressStager(RunContext, [], AnsiConsole.Progress()
.AutoClear(true)
.HideCompleted(false)
.Columns([
new TaskDescriptionColumn(),
new ProgressBarColumn()
.RemainingStyle(Style.Parse("dim gray slowblink"))
.CompletedStyle(Style.Parse("green strikethrough"))
.FinishedStyle("green strikethrough"),
new DownloadedColumn(),
new RemainingTimeColumn(),
new TransferSpeedColumn(),
]));
}
}
internal record TaskWithProgress<T>(string Name, Task<T> Value);
internal record ProgressStager(RunContext RunContext, Task[] Tasks, Progress Progress) {
public TaskWithProgress<T> Run<T>(string Name, Func<RunContext, ProgressContext, Task<T>> factory) {
return new(Name, Progress.StartAsync(async ctx => {
return await factory(RunContext, ctx);
}));
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace System.Runtime.CompilerServices {
public interface IUnion { }
[AttributeUsage(AttributeTargets.Class)]
public sealed class UnionAttribute : Attribute { }
}
@@ -10,6 +10,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="aeqw89.xml.ProjectFile" Version="1.0.3" /> <PackageReference Include="aeqw89.xml.ProjectFile" Version="1.0.3" />
<PackageReference Include="Aigamo.ResXGenerator" Version="4.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Spectre.Console" Version="0.51.2-preview.0.1" /> <PackageReference Include="Spectre.Console" Version="0.51.2-preview.0.1" />
<PackageReference Include="SSH.NET" Version="2025.0.0" /> <PackageReference Include="SSH.NET" Version="2025.0.0" />
</ItemGroup> </ItemGroup>
@@ -29,4 +33,8 @@
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<PropertyGroup>
<ResXGenerator_NullForgivingOperators>true</ResXGenerator_NullForgivingOperators>
</PropertyGroup>
</Project> </Project>
@@ -1,176 +0,0 @@
{
"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"
}
}
}
@@ -1,12 +0,0 @@
{
"runtimeOptions": {
"tfm": "net9.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "9.0.0"
},
"configProperties": {
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}
@@ -1,4 +0,0 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0")]
@@ -1,22 +0,0 @@
//------------------------------------------------------------------------------
// <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+b61d0836ac23522cf42987fbed9474a3bda3632e")]
[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.
@@ -1 +0,0 @@
7fc87e3000a58eaf1f393990c041ae903924d7e468beb21b7ca46d984853ce80
@@ -1,17 +0,0 @@
is_global = true
build_property.TargetFramework = net9.0
build_property.TargetFrameworkIdentifier = .NETCoreApp
build_property.TargetFrameworkVersion = v9.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 =
@@ -1,8 +0,0 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
@@ -1 +0,0 @@
5d197b168fe8c90856a81b99d1fce6aff6057143a768436bb5102085caca4cb0
@@ -1,36 +0,0 @@
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
C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.sourcelink.json
@@ -1 +0,0 @@
168cdf600308143eb70e75e0de49fe275399afb34dc3d60504d380fe24fdc670
Binary file not shown.
@@ -1,101 +0,0 @@
{
"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": {
"C:\\Users\\qwsdc\\packages": {},
"https://api.nuget.org/v3/index.json": {},
"https://nuget.pkg.github.com/qwsdcvghyu89/index.json": {}
},
"frameworks": {
"net9.0": {
"targetAlias": "net9.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "10.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, )"
},
"aeqw89.xml.ProjectFile": {
"target": "Package",
"version": "[1.0.3, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"downloadDependencies": [
{
"name": "Microsoft.AspNetCore.App.Ref",
"version": "[9.0.9, 9.0.9]"
},
{
"name": "Microsoft.NETCore.App.Host.win-x64",
"version": "[9.0.9, 9.0.9]"
},
{
"name": "Microsoft.NETCore.App.Ref",
"version": "[9.0.9, 9.0.9]"
},
{
"name": "Microsoft.WindowsDesktop.App.Ref",
"version": "[9.0.9, 9.0.9]"
}
],
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.100-rc.1.25451.107/PortableRuntimeIdentifierGraph.json"
}
}
}
}
}
@@ -1,15 +0,0 @@
<?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)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\qwsdc\.nuget\packages\" />
</ItemGroup>
</Project>
@@ -1,6 +0,0 @@
<?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>
@@ -1,377 +0,0 @@
{
"version": 3,
"targets": {
"net9.0": {
"aeqw89.xml.ProjectFile/1.0.3": {
"type": "package",
"compile": {
"lib/net9.0/aeqw89.xml.ProjectFile.dll": {}
},
"runtime": {
"lib/net9.0/aeqw89.xml.ProjectFile.dll": {}
}
},
"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"
}
}
},
"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"
}
}
}
}
},
"libraries": {
"aeqw89.xml.ProjectFile/1.0.3": {
"sha512": "AkCw9edHUg7G9/jAA/zSgwsz/nHnAs7gvs9tCslibNnzXTJOweflSsqO+GcoWVP5QGgU4DhgMrJQgUNY6EBXNQ==",
"type": "package",
"path": "aeqw89.xml.projectfile/1.0.3",
"files": [
".nupkg.metadata",
"aeqw89.xml.projectfile.1.0.3.nupkg.sha512",
"aeqw89.xml.projectfile.nuspec",
"lib/net9.0/aeqw89.xml.ProjectFile.dll"
]
},
"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"
]
},
"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"
]
}
},
"projectFileDependencyGroups": {
"net9.0": [
"SSH.NET >= 2025.0.0",
"Spectre.Console >= 0.51.2-preview.0.1",
"aeqw89.xml.ProjectFile >= 1.0.3"
]
},
"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": {
"C:\\Users\\qwsdc\\packages": {},
"https://api.nuget.org/v3/index.json": {},
"https://nuget.pkg.github.com/qwsdcvghyu89/index.json": {}
},
"frameworks": {
"net9.0": {
"targetAlias": "net9.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "10.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, )"
},
"aeqw89.xml.ProjectFile": {
"target": "Package",
"version": "[1.0.3, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"downloadDependencies": [
{
"name": "Microsoft.AspNetCore.App.Ref",
"version": "[9.0.9, 9.0.9]"
},
{
"name": "Microsoft.NETCore.App.Host.win-x64",
"version": "[9.0.9, 9.0.9]"
},
{
"name": "Microsoft.NETCore.App.Ref",
"version": "[9.0.9, 9.0.9]"
},
{
"name": "Microsoft.WindowsDesktop.App.Ref",
"version": "[9.0.9, 9.0.9]"
}
],
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.100-rc.1.25451.107/PortableRuntimeIdentifierGraph.json"
}
}
}
}
@@ -1,19 +0,0 @@
{
"version": 2,
"dgSpecHash": "lSSpLey1hfc=",
"success": true,
"projectFilePath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj",
"expectedPackageFiles": [
"C:\\Users\\qwsdc\\.nuget\\packages\\aeqw89.xml.projectfile\\1.0.3\\aeqw89.xml.projectfile.1.0.3.nupkg.sha512",
"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\\ssh.net\\2025.0.0\\ssh.net.2025.0.0.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.netcore.app.ref\\9.0.9\\microsoft.netcore.app.ref.9.0.9.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.windowsdesktop.app.ref\\9.0.9\\microsoft.windowsdesktop.app.ref.9.0.9.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.aspnetcore.app.ref\\9.0.9\\microsoft.aspnetcore.app.ref.9.0.9.nupkg.sha512",
"C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.netcore.app.host.win-x64\\9.0.9\\microsoft.netcore.app.host.win-x64.9.0.9.nupkg.sha512"
],
"logs": []
}
@@ -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","outputPath":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net9.0"],"sources":{"C:\\Users\\qwsdc\\packages":{},"https://api.nuget.org/v3/index.json":{},"https://nuget.pkg.github.com/qwsdcvghyu89/index.json":{}},"frameworks":{"net9.0":{"targetAlias":"net9.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"},"SdkAnalysisLevel":"10.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, )"},"aeqw89.xml.ProjectFile":{"target":"Package","version":"[1.0.3, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"downloadDependencies":[{"name":"Microsoft.AspNetCore.App.Ref","version":"[9.0.9, 9.0.9]"},{"name":"Microsoft.NETCore.App.Host.win-x64","version":"[9.0.9, 9.0.9]"},{"name":"Microsoft.NETCore.App.Ref","version":"[9.0.9, 9.0.9]"},{"name":"Microsoft.WindowsDesktop.App.Ref","version":"[9.0.9, 9.0.9]"}],"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\10.0.100-rc.1.25451.107/PortableRuntimeIdentifierGraph.json"}}
@@ -1 +0,0 @@
17584393464480743
@@ -1 +0,0 @@
17588788734490530