From 016ec8b1862480429a8687db65afce155ca967cc Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Sun, 24 Apr 2022 23:45:10 +0300 Subject: [PATCH] Make default executable name resolution smarter --- CliFx/CliApplicationBuilder.cs | 45 ++++++++++++++++++++-------------- CliFx/Utils/EnvironmentEx.cs | 20 +++++++++++++++ Readme.md | 4 +-- 3 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 CliFx/Utils/EnvironmentEx.cs diff --git a/CliFx/CliApplicationBuilder.cs b/CliFx/CliApplicationBuilder.cs index d53dfca..b4a72b8 100644 --- a/CliFx/CliApplicationBuilder.cs +++ b/CliFx/CliApplicationBuilder.cs @@ -6,6 +6,7 @@ using System.Reflection; using CliFx.Attributes; using CliFx.Infrastructure; using CliFx.Schema; +using CliFx.Utils; using CliFx.Utils.Extensions; namespace CliFx; @@ -21,7 +22,7 @@ public partial class CliApplicationBuilder private bool _isPreviewModeAllowed = true; private string? _title; private string? _executableName; - private string? _versionText; + private string? _version; private string? _description; private IConsole? _console; private ITypeActivator? _typeActivator; @@ -144,7 +145,7 @@ public partial class CliApplicationBuilder /// public CliApplicationBuilder SetVersion(string version) { - _versionText = version; + _version = version; return this; } @@ -189,7 +190,7 @@ public partial class CliApplicationBuilder var metadata = new ApplicationMetadata( _title ?? GetDefaultTitle(), _executableName ?? GetDefaultExecutableName(), - _versionText ?? GetDefaultVersionText(), + _version ?? GetDefaultVersionText(), _description ); @@ -210,14 +211,9 @@ public partial class CliApplicationBuilder public partial class CliApplicationBuilder { - private static readonly Lazy EntryAssemblyLazy = new(Assembly.GetEntryAssembly); - - // Entry assembly can be null, for example in tests - private static Assembly? EntryAssembly => EntryAssemblyLazy.Value; - private static string GetDefaultTitle() { - var entryAssemblyName = EntryAssembly?.GetName().Name; + var entryAssemblyName = EnvironmentEx.EntryAssembly?.GetName().Name; if (string.IsNullOrWhiteSpace(entryAssemblyName)) return "App"; @@ -226,26 +222,39 @@ public partial class CliApplicationBuilder private static string GetDefaultExecutableName() { - var entryAssemblyLocation = EntryAssembly?.Location; + var entryAssemblyLocation = EnvironmentEx.EntryAssembly?.Location; if (string.IsNullOrWhiteSpace(entryAssemblyLocation)) return "app"; - // The assembly can be an .exe or a .dll, depending on how it was packaged + // If the application was launched via matching EXE apphost, use that as the executable name + var isLaunchedViaAppHost = string.Equals( + EnvironmentEx.ProcessPath, + Path.ChangeExtension(entryAssemblyLocation, ".exe"), + StringComparison.OrdinalIgnoreCase + ); + + if (isLaunchedViaAppHost) + return Path.GetFileNameWithoutExtension(entryAssemblyLocation); + + // Otherwise, use the entry assembly as the executable name. + // Prefix it with `dotnet` if it's a DLL file. var isDll = string.Equals( Path.GetExtension(entryAssemblyLocation), ".dll", StringComparison.OrdinalIgnoreCase ); - var name = isDll + return isDll ? "dotnet " + Path.GetFileName(entryAssemblyLocation) : Path.GetFileNameWithoutExtension(entryAssemblyLocation); - - return name; } - private static string GetDefaultVersionText() => - EntryAssembly is not null - ? "v" + EntryAssembly.GetName().Version.ToSemanticString() - : "v1.0"; + private static string GetDefaultVersionText() + { + var entryAssemblyVersion = EnvironmentEx.EntryAssembly?.GetName().Version; + if (entryAssemblyVersion is null) + return "v1.0"; + + return "v" + entryAssemblyVersion.ToSemanticString(); + } } \ No newline at end of file diff --git a/CliFx/Utils/EnvironmentEx.cs b/CliFx/Utils/EnvironmentEx.cs new file mode 100644 index 0000000..63da903 --- /dev/null +++ b/CliFx/Utils/EnvironmentEx.cs @@ -0,0 +1,20 @@ +using System; +using System.Diagnostics; +using System.Reflection; + +namespace CliFx.Utils; + +internal static class EnvironmentEx +{ + private static readonly Lazy ProcessPathLazy = new(() => + { + using var process = Process.GetCurrentProcess(); + return process.MainModule?.FileName; + }); + + public static string? ProcessPath => ProcessPathLazy.Value; + + private static readonly Lazy EntryAssemblyLazy = new(Assembly.GetEntryAssembly); + + public static Assembly? EntryAssembly => EntryAssemblyLazy.Value; +} \ No newline at end of file diff --git a/Readme.md b/Readme.md index ed71b31..5eaca20 100644 --- a/Readme.md +++ b/Readme.md @@ -209,7 +209,7 @@ OPTIONS Overall, parameters and options are both used to consume input from the command line, but they differ in a few important ways: | | Parameter | Option | -| ------------------ | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | +|--------------------|--------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| | **Identification** | Positional (by relative order). | Nominal (by name or short name). | | **Requiredness** | Required by default. Only the last parameter can be configured to be optional. | Optional by default. Any option can be configured to be required without limitations. | | **Arity** | Only the last parameter can be bound to a non-scalar property (i.e. an array). | Any option can be bound to a non-scalar property without limitations. | @@ -721,4 +721,4 @@ var app = new CliApplicationBuilder() ## Etymology **CliFx** is made out of "Cli" for "Command Line Interface" and "Fx" for "Framework". -It's pronounced as "cliff ex". +It's pronounced as "cliff ex". \ No newline at end of file