This commit is contained in:
Alexey Golub
2019-07-30 23:08:08 +03:00
parent e7e47b1c9d
commit ed72571ddc
6 changed files with 82 additions and 92 deletions

View File

@@ -39,10 +39,15 @@ namespace CliFx
_commandHelpTextRenderer = commandHelpTextRenderer;
}
public CliApplication(ApplicationMetadata applicationMetadata, IReadOnlyList<Type> commandTypes)
public CliApplication(ApplicationMetadata applicationMetadata, IReadOnlyList<Type> commandTypes, IConsole console)
: this(applicationMetadata, commandTypes,
new SystemConsole(), new CommandInputParser(), new CommandSchemaResolver(),
new CommandFactory(), new CommandInitializer(), new CommandHelpTextRenderer())
console, new CommandInputParser(), new CommandSchemaResolver(),
new CommandFactory(), new CommandInitializer(), new CommandHelpTextRenderer(console))
{
}
public CliApplication(ApplicationMetadata applicationMetadata, IReadOnlyList<Type> commandTypes)
: this(applicationMetadata, commandTypes, new SystemConsole())
{
}
@@ -56,22 +61,14 @@ namespace CliFx
{
}
private IReadOnlyList<CommandSchema> GetAvailableCommandSchemas() =>
_commandTypes.Select(_commandSchemaResolver.GetCommandSchema).ToArray();
private CommandSchema GetMatchingCommandSchema(IReadOnlyList<CommandSchema> availableCommandSchemas, string commandName) =>
availableCommandSchemas.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase));
public async Task<int> RunAsync(IReadOnlyList<string> commandLineArguments)
{
try
{
var commandInput = _commandInputParser.ParseInput(commandLineArguments);
var availableCommandSchemas = GetAvailableCommandSchemas();
var matchingCommandSchema = GetMatchingCommandSchema(availableCommandSchemas, commandInput.CommandName);
var availableCommandSchemas = _commandSchemaResolver.GetCommandSchemas(_commandTypes);
var matchingCommandSchema = availableCommandSchemas.FindByName(commandInput.CommandName);
// Fail if there are no commands defined
if (!availableCommandSchemas.Any())
@@ -85,27 +82,31 @@ namespace CliFx
// Handle cases where requested command is not defined
if (matchingCommandSchema == null)
{
var isError = false;
// If specified a command - show error
if (commandInput.IsCommandSpecified())
{
isError = true;
_console.WithColor(ConsoleColor.Red,
c => c.Error.WriteLine($"Specified command [{commandInput.CommandName}] is not defined."));
}
// Get default command schema
var defaultCommandSchema = availableCommandSchemas.FirstOrDefault(c => c.IsDefault());
// Get parent command schema
var parentCommandSchema = availableCommandSchemas.FindParent(commandInput.CommandName);
// Use a stub if default command schema is not defined
if (defaultCommandSchema == null)
// Use a stub if parent command schema is not found
if (parentCommandSchema == null)
{
defaultCommandSchema = _commandSchemaResolver.GetCommandSchema(typeof(StubDefaultCommand));
availableCommandSchemas = availableCommandSchemas.Concat(new[] {defaultCommandSchema}).ToArray();
parentCommandSchema = _commandSchemaResolver.GetCommandSchema(typeof(StubDefaultCommand));
availableCommandSchemas = availableCommandSchemas.Concat(new[] { parentCommandSchema }).ToArray();
}
// Show help
_commandHelpTextRenderer.RenderHelpText(_applicationMetadata, availableCommandSchemas, defaultCommandSchema);
_commandHelpTextRenderer.RenderHelpText(_applicationMetadata, availableCommandSchemas, parentCommandSchema);
return commandInput.IsCommandSpecified() ? -1 : 0;
return isError ? -1 : 0;
}
// Show version if it was requested without specifying a command

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CliFx.Internal;
@@ -25,5 +26,48 @@ namespace CliFx.Models
}
public static bool IsDefault(this CommandSchema commandSchema) => commandSchema.Name.IsNullOrWhiteSpace();
public static CommandSchema FindByName(this IReadOnlyList<CommandSchema> commandSchemas, string commandName) =>
commandSchemas.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase));
public static CommandSchema FindParent(this IReadOnlyList<CommandSchema> commandSchemas, string commandName)
{
// If command has no name, it's the default command so it doesn't have a parent
if (commandName.IsNullOrWhiteSpace())
return null;
// Repeatedly cut off individual words from the name until we find a command with that name
var temp = commandName;
while (temp.Contains(" "))
{
temp = temp.SubstringUntilLast(" ");
var parent = commandSchemas.FindByName(temp);
if (parent != null)
return parent;
}
// If no parent is matched by name, then the parent is the default command
return commandSchemas.FirstOrDefault(c => c.IsDefault());
}
public static CommandOptionSchema FindByAlias(this IReadOnlyList<CommandOptionSchema> optionSchemas, string alias)
{
foreach (var optionSchema in optionSchemas)
{
var matchesByName =
!optionSchema.Name.IsNullOrWhiteSpace() &&
string.Equals(optionSchema.Name, alias, StringComparison.OrdinalIgnoreCase);
var matchesByShortName =
optionSchema.ShortName != null &&
string.Equals(optionSchema.ShortName.Value.AsString(), alias, StringComparison.OrdinalIgnoreCase);
if (matchesByName || matchesByShortName)
return optionSchema;
}
return null;
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CliFx.Internal;
using CliFx.Models;
@@ -16,11 +15,6 @@ namespace CliFx.Services
_console = console;
}
public CommandHelpTextRenderer()
: this(new SystemConsole())
{
}
private void RenderDescription(CommandSchema commandSchema)
{
if (commandSchema.Description.IsNullOrWhiteSpace())
@@ -170,7 +164,9 @@ namespace CliFx.Services
public void RenderHelpText(ApplicationMetadata applicationMetadata,
IReadOnlyList<CommandSchema> availableCommandSchemas, CommandSchema matchingCommandSchema)
{
var childCommandSchemas = GetChildCommandSchemas(availableCommandSchemas, matchingCommandSchema);
var childCommandSchemas = availableCommandSchemas
.Where(c => availableCommandSchemas.FindParent(c.Name) == matchingCommandSchema)
.ToArray();
// Render application info
if (matchingCommandSchema.IsDefault())
@@ -191,48 +187,9 @@ namespace CliFx.Services
public partial class CommandHelpTextRenderer
{
private static CommandSchema GetParentOrNull(CommandSchema commandSchema, IReadOnlyList<CommandSchema> availableCommandSchemas)
{
if (commandSchema.IsDefault())
return null;
var nameBuffer = commandSchema.Name;
while (nameBuffer.Contains(' '))
{
nameBuffer = nameBuffer.SubstringUntilLast(" ");
var parent = availableCommandSchemas.FirstOrDefault(c =>
string.Equals(c.Name, nameBuffer, StringComparison.OrdinalIgnoreCase));
if (parent != null)
return parent;
}
return availableCommandSchemas.FirstOrDefault(c => c.IsDefault());
}
private static IReadOnlyList<CommandSchema> GetChildCommandSchemas(IReadOnlyList<CommandSchema> availableCommandSchemas,
CommandSchema parentCommandSchema)
{
var result = new List<CommandSchema>();
foreach (var commandSchema in availableCommandSchemas)
{
if (commandSchema == parentCommandSchema)
continue;
if (GetParentOrNull(commandSchema, availableCommandSchemas) == parentCommandSchema)
result.Add(commandSchema);
}
return result;
}
private static string GetRelativeCommandName(CommandSchema commandSchema, CommandSchema parentCommandSchema)
{
if (parentCommandSchema.Name.IsNullOrWhiteSpace())
return commandSchema.Name;
return commandSchema.Name.Substring(parentCommandSchema.Name.Length + 1);
}
private static string GetRelativeCommandName(CommandSchema commandSchema, CommandSchema parentCommandSchema) =>
parentCommandSchema.Name.IsNullOrWhiteSpace()
? commandSchema.Name
: commandSchema.Name.Substring(parentCommandSchema.Name.Length + 1);
}
}

View File

@@ -21,25 +21,6 @@ namespace CliFx.Services
{
}
private CommandOptionSchema GetMatchingOptionSchema(CommandSchema commandSchema, CommandOptionInput optionInput)
{
foreach (var optionSchema in commandSchema.Options)
{
var matchesByName =
!optionSchema.Name.IsNullOrWhiteSpace() &&
string.Equals(optionSchema.Name, optionInput.Alias, StringComparison.OrdinalIgnoreCase);
var matchesByShortName =
optionSchema.ShortName != null &&
string.Equals(optionSchema.ShortName.Value.AsString(), optionInput.Alias, StringComparison.OrdinalIgnoreCase);
if (matchesByName || matchesByShortName)
return optionSchema;
}
return null;
}
public void InitializeCommand(ICommand command, CommandSchema schema, CommandInput input)
{
// Set command options
@@ -48,7 +29,7 @@ namespace CliFx.Services
var properties = new HashSet<CommandOptionSchema>();
foreach (var option in input.Options)
{
var optionSchema = GetMatchingOptionSchema(schema, option);
var optionSchema = schema.Options.FindByAlias(option.Alias);
if (optionSchema == null)
continue;

View File

@@ -1,9 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CliFx.Models;
namespace CliFx.Services
{
public static class Extensions
{
public static IReadOnlyList<CommandSchema> GetCommandSchemas(this ICommandSchemaResolver resolver,
IReadOnlyList<Type> commandTypes) =>
commandTypes.Select(resolver.GetCommandSchema).ToArray();
public static void WithColor(this IConsole console, ConsoleColor foregroundColor, Action<IConsole> action)
{
var lastForegroundColor = console.ForegroundColor;