Files
CliFx/CliFx/CliApplicationBuilder.cs
Alexey Golub bed22b6500 Refactor (#56)
2020-05-23 18:45:07 +03:00

201 lines
7.0 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using CliFx.Domain;
using CliFx.Internal;
namespace CliFx
{
/// <summary>
/// Builds an instance of <see cref="CliApplication"/>.
/// </summary>
public partial class CliApplicationBuilder
{
private readonly HashSet<Type> _commandTypes = new HashSet<Type>();
private bool _isDebugModeAllowed = true;
private bool _isPreviewModeAllowed = true;
private string? _title;
private string? _executableName;
private string? _versionText;
private string? _description;
private IConsole? _console;
private ITypeActivator? _typeActivator;
/// <summary>
/// Adds a command of specified type to the application.
/// </summary>
public CliApplicationBuilder AddCommand(Type commandType)
{
_commandTypes.Add(commandType);
return this;
}
/// <summary>
/// Adds multiple commands to the application.
/// </summary>
public CliApplicationBuilder AddCommands(IEnumerable<Type> commandTypes)
{
foreach (var commandType in commandTypes)
AddCommand(commandType);
return this;
}
/// <summary>
/// Adds commands from the specified assembly to the application.
/// Only adds public valid command types.
/// </summary>
public CliApplicationBuilder AddCommandsFrom(Assembly commandAssembly)
{
foreach (var commandType in commandAssembly.ExportedTypes.Where(CommandSchema.IsCommandType))
AddCommand(commandType);
return this;
}
/// <summary>
/// Adds commands from the specified assemblies to the application.
/// Only adds public valid command types.
/// </summary>
public CliApplicationBuilder AddCommandsFrom(IEnumerable<Assembly> commandAssemblies)
{
foreach (var commandAssembly in commandAssemblies)
AddCommandsFrom(commandAssembly);
return this;
}
/// <summary>
/// Adds commands from the calling assembly to the application.
/// Only adds public valid command types.
/// </summary>
public CliApplicationBuilder AddCommandsFromThisAssembly() => AddCommandsFrom(Assembly.GetCallingAssembly());
/// <summary>
/// Specifies whether debug mode (enabled with [debug] directive) is allowed in the application.
/// </summary>
public CliApplicationBuilder AllowDebugMode(bool isAllowed = true)
{
_isDebugModeAllowed = isAllowed;
return this;
}
/// <summary>
/// Specifies whether preview mode (enabled with [preview] directive) is allowed in the application.
/// </summary>
public CliApplicationBuilder AllowPreviewMode(bool isAllowed = true)
{
_isPreviewModeAllowed = isAllowed;
return this;
}
/// <summary>
/// Sets application title, which appears in the help text.
/// </summary>
public CliApplicationBuilder UseTitle(string title)
{
_title = title;
return this;
}
/// <summary>
/// Sets application executable name, which appears in the help text.
/// </summary>
public CliApplicationBuilder UseExecutableName(string executableName)
{
_executableName = executableName;
return this;
}
/// <summary>
/// Sets application version text, which appears in the help text and when the user requests version information.
/// </summary>
public CliApplicationBuilder UseVersionText(string versionText)
{
_versionText = versionText;
return this;
}
/// <summary>
/// Sets application description, which appears in the help text.
/// </summary>
public CliApplicationBuilder UseDescription(string? description)
{
_description = description;
return this;
}
/// <summary>
/// Configures the application to use the specified implementation of <see cref="IConsole"/>.
/// </summary>
public CliApplicationBuilder UseConsole(IConsole console)
{
_console = console;
return this;
}
/// <summary>
/// Configures the application to use the specified implementation of <see cref="ITypeActivator"/>.
/// </summary>
public CliApplicationBuilder UseTypeActivator(ITypeActivator typeActivator)
{
_typeActivator = typeActivator;
return this;
}
/// <summary>
/// Configures the application to use the specified function for activating types.
/// </summary>
public CliApplicationBuilder UseTypeActivator(Func<Type, object> typeActivator) =>
UseTypeActivator(new DelegateTypeActivator(typeActivator));
/// <summary>
/// Creates an instance of <see cref="CliApplication"/> using configured parameters.
/// Default values are used in place of parameters that were not specified.
/// </summary>
public CliApplication Build()
{
_title ??= TryGetDefaultTitle() ?? "App";
_executableName ??= TryGetDefaultExecutableName() ?? "app";
_versionText ??= TryGetDefaultVersionText() ?? "v1.0";
_console ??= new SystemConsole();
_typeActivator ??= new DefaultTypeActivator();
var metadata = new ApplicationMetadata(_title, _executableName, _versionText, _description);
var configuration = new ApplicationConfiguration(_commandTypes.ToArray(), _isDebugModeAllowed, _isPreviewModeAllowed);
return new CliApplication(metadata, configuration, _console, _typeActivator);
}
}
public partial class CliApplicationBuilder
{
private static readonly Lazy<Assembly?> LazyEntryAssembly = new Lazy<Assembly?>(Assembly.GetEntryAssembly);
// Entry assembly is null in tests
private static Assembly? EntryAssembly => LazyEntryAssembly.Value;
private static string? TryGetDefaultTitle() => EntryAssembly?.GetName().Name;
private static string? TryGetDefaultExecutableName()
{
var entryAssemblyLocation = EntryAssembly?.Location;
// The assembly can be an executable or a dll, depending on how it was packaged
var isDll = string.Equals(Path.GetExtension(entryAssemblyLocation), ".dll", StringComparison.OrdinalIgnoreCase);
return isDll
? "dotnet " + Path.GetFileName(entryAssemblyLocation)
: Path.GetFileNameWithoutExtension(entryAssemblyLocation);
}
private static string? TryGetDefaultVersionText() =>
EntryAssembly != null
? $"v{EntryAssembly.GetName().Version.ToSemanticString()}"
: null;
}
}