diff --git a/src/Orchard.Tests/Commands/CommandHandlerDescriptorBuilderTests.cs b/src/Orchard.Tests/Commands/CommandHandlerDescriptorBuilderTests.cs index 8a3e8fa48..a3e2ca821 100644 --- a/src/Orchard.Tests/Commands/CommandHandlerDescriptorBuilderTests.cs +++ b/src/Orchard.Tests/Commands/CommandHandlerDescriptorBuilderTests.cs @@ -16,8 +16,8 @@ namespace Orchard.Tests.Commands { Assert.That(descriptor.Commands.Count(), Is.EqualTo(4)); Assert.That(descriptor.Commands.Single(d => d.Name == "FooBar"), Is.Not.Null); Assert.That(descriptor.Commands.Single(d => d.Name == "FooBar").MethodInfo, Is.EqualTo(typeof(MyCommand).GetMethod("FooBar"))); - Assert.That(descriptor.Commands.Single(d => d.Name == "Whereslou"), Is.Not.Null); - Assert.That(descriptor.Commands.Single(d => d.Name == "Whereslou").MethodInfo, Is.EqualTo(typeof(MyCommand).GetMethod("FooBar2"))); + Assert.That(descriptor.Commands.Single(d => d.Name == "MyCommand"), Is.Not.Null); + Assert.That(descriptor.Commands.Single(d => d.Name == "MyCommand").MethodInfo, Is.EqualTo(typeof(MyCommand).GetMethod("FooBar2"))); Assert.That(descriptor.Commands.Single(d => d.Name == "Foo Bar"), Is.Not.Null); Assert.That(descriptor.Commands.Single(d => d.Name == "Foo Bar").MethodInfo, Is.EqualTo(typeof(MyCommand).GetMethod("Foo_Bar"))); Assert.That(descriptor.Commands.Single(d => d.Name == "Foo_Bar"), Is.Not.Null); @@ -28,14 +28,14 @@ namespace Orchard.Tests.Commands { public void FooBar() { } - [OrchardCommand("Whereslou")] + [CommandName("MyCommand")] public void FooBar2() { } public void Foo_Bar() { } - [OrchardCommand("Foo_Bar")] + [CommandName("Foo_Bar")] public void Foo_Bar3() { } } diff --git a/src/Orchard.Tests/Commands/CommandHandlerTests.cs b/src/Orchard.Tests/Commands/CommandHandlerTests.cs index b1e78dcb5..8e994dd8b 100644 --- a/src/Orchard.Tests/Commands/CommandHandlerTests.cs +++ b/src/Orchard.Tests/Commands/CommandHandlerTests.cs @@ -180,7 +180,7 @@ namespace Orchard.Tests.Commands { return "Command Foo Executed"; } - [OrchardCommand("Bar")] + [CommandName("Bar")] public string Hello() { return "Hello World!"; } diff --git a/src/Orchard/Commands/Builtin/HelpCommand.cs b/src/Orchard/Commands/Builtin/HelpCommand.cs index 1a152102e..73aced3c8 100644 --- a/src/Orchard/Commands/Builtin/HelpCommand.cs +++ b/src/Orchard/Commands/Builtin/HelpCommand.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Autofac.Features.Metadata; +using Orchard.Localization; namespace Orchard.Commands.Builtin { public class HelpCommand : DefaultOrchardCommandHandler { @@ -11,13 +12,32 @@ namespace Orchard.Commands.Builtin { _commandManager = commandManager; } - [OrchardCommand("help commands")] - [CommandHelp("List all available commands")] - public void Commands() { + [CommandName("help commands")] + [CommandHelp("help commands: Display help text for all available commands")] + public void AllCommands() { + Context.Output.WriteLine(T("List of available commands:")); + Context.Output.WriteLine(T("---------------------------")); + var descriptors = _commandManager.GetCommandDescriptors(); foreach (var descriptor in descriptors) { - var helpText = string.IsNullOrEmpty(descriptor.HelpText) ? T("[no help text]") : T(descriptor.HelpText); - Context.Output.WriteLine("{0}: {1}", descriptor.Name, helpText); + Context.Output.WriteLine(GetHelpText(descriptor)); + } + } + + private LocalizedString GetHelpText(CommandDescriptor descriptor) { + return string.IsNullOrEmpty(descriptor.HelpText) ? T("[no help text]") : T(descriptor.HelpText); + } + + [CommandName("help")] + [CommandHelp("help : Display help text for ")] + public void SingleCommand(string[] commandNameStrings) { + string command = string.Join(" ", commandNameStrings); + var descriptor = _commandManager.GetCommandDescriptors().SingleOrDefault(d => string.Equals(command, d.Name, StringComparison.OrdinalIgnoreCase)); + if (descriptor == null) { + Context.Output.WriteLine(T("Command {0} doesn't exist").ToString(), command); + } + else { + Context.Output.WriteLine(GetHelpText(descriptor)); } } } diff --git a/src/Orchard/Commands/CommandHandlerDescriptorBuilder.cs b/src/Orchard/Commands/CommandHandlerDescriptorBuilder.cs index 3d82cc0b0..499e55775 100644 --- a/src/Orchard/Commands/CommandHandlerDescriptorBuilder.cs +++ b/src/Orchard/Commands/CommandHandlerDescriptorBuilder.cs @@ -32,9 +32,9 @@ namespace Orchard.Commands { } private string GetCommandName(MethodInfo methodInfo) { - var attributes = methodInfo.GetCustomAttributes(typeof(OrchardCommandAttribute), false/*inherit*/); + var attributes = methodInfo.GetCustomAttributes(typeof(CommandNameAttribute), false/*inherit*/); if (attributes != null && attributes.Any()) { - return attributes.Cast().Single().Command; + return attributes.Cast().Single().Command; } return methodInfo.Name.Replace('_', ' '); diff --git a/src/Orchard/Commands/CommandHostAgent.cs b/src/Orchard/Commands/CommandHostAgent.cs index 94c1da53b..cccccbff6 100644 --- a/src/Orchard/Commands/CommandHostAgent.cs +++ b/src/Orchard/Commands/CommandHostAgent.cs @@ -16,7 +16,7 @@ namespace Orchard.Commands { /// executing a single command. /// public class CommandHostAgent { - public void RunSingleCommand(TextReader input, TextWriter output, string tenant, string[] args, Dictionary switches) { + public int RunSingleCommand(TextReader input, TextWriter output, string tenant, string[] args, Dictionary switches) { try { var hostContainer = OrchardStarter.CreateHostContainer(MvcSingletons); var host = hostContainer.Resolve(); @@ -37,11 +37,15 @@ namespace Orchard.Commands { }; env.Resolve().Execute(parameters); } + + return 0; } catch (Exception e) { for(; e != null; e = e.InnerException) { - Console.WriteLine("Error: {0}", e.Message); + output.WriteLine("Error: {0}", e.Message); + output.WriteLine("{0}", e.StackTrace); } + return 5; } } diff --git a/src/Orchard/Commands/OrchardCommandAttribute.cs b/src/Orchard/Commands/CommandNameAttribute.cs similarity index 78% rename from src/Orchard/Commands/OrchardCommandAttribute.cs rename to src/Orchard/Commands/CommandNameAttribute.cs index a06ae6658..f5911b29c 100644 --- a/src/Orchard/Commands/OrchardCommandAttribute.cs +++ b/src/Orchard/Commands/CommandNameAttribute.cs @@ -2,10 +2,10 @@ namespace Orchard.Commands { [AttributeUsage(AttributeTargets.Method)] - public class OrchardCommandAttribute : Attribute { + public class CommandNameAttribute : Attribute { private readonly string _commandAlias; - public OrchardCommandAttribute(string commandAlias) { + public CommandNameAttribute(string commandAlias) { _commandAlias = commandAlias; } diff --git a/src/Orchard/Commands/DefaultCommandManager.cs b/src/Orchard/Commands/DefaultCommandManager.cs index c834a775a..a99c02996 100644 --- a/src/Orchard/Commands/DefaultCommandManager.cs +++ b/src/Orchard/Commands/DefaultCommandManager.cs @@ -13,8 +13,7 @@ namespace Orchard.Commands { } public void Execute(CommandParameters parameters) { - var matches = _handlers.SelectMany(h => MatchCommands(parameters, GetDescriptor(h.Metadata), h.Value)); - + var matches = MatchCommands(parameters); // Workaround autofac integration: module registration is currently run twice... //if (matches.Count() == 1) { @@ -32,18 +31,27 @@ namespace Orchard.Commands { } public IEnumerable GetCommandDescriptors() { - return _handlers.SelectMany(h => GetDescriptor(h.Metadata).Commands); + return _handlers + .SelectMany(h => GetDescriptor(h.Metadata).Commands) + // Workaround autofac integration: module registration is currently run twice... + .Distinct(new CommandsComparer()); } - private class Match { - public CommandContext Context { get; set; } - public Func CommandHandlerFactory { get; set; } + private IEnumerable MatchCommands(CommandParameters parameters) { + foreach (var argCount in Enumerable.Range(1, parameters.Arguments.Count()).Reverse()) { + int count = argCount; + var matches = _handlers.SelectMany(h => MatchCommands(parameters, count, GetDescriptor(h.Metadata), h.Value)); + if (matches.Any()) + return matches; + } + + return Enumerable.Empty(); } - private static IEnumerable MatchCommands(CommandParameters parameters, CommandHandlerDescriptor descriptor, Func handlerFactory) { + private static IEnumerable MatchCommands(CommandParameters parameters, int argCount, CommandHandlerDescriptor descriptor, Func handlerFactory) { foreach (var commandDescriptor in descriptor.Commands) { - string[] names = commandDescriptor.Name.Split(' '); - if (!parameters.Arguments.Take(names.Count()).SequenceEqual(names, StringComparer.OrdinalIgnoreCase)) { + var names = commandDescriptor.Name.Split(' '); + if (!parameters.Arguments.Take(argCount).SequenceEqual(names, StringComparer.OrdinalIgnoreCase)) { // leading arguments not equal to command name continue; } @@ -51,7 +59,7 @@ namespace Orchard.Commands { yield return new Match { Context = new CommandContext { Arguments = parameters.Arguments.Skip(names.Count()), - Command = string.Join(" ",names), + Command = string.Join(" ", names), CommandDescriptor = commandDescriptor, Input = parameters.Input, Output = parameters.Output, @@ -65,5 +73,20 @@ namespace Orchard.Commands { private static CommandHandlerDescriptor GetDescriptor(IDictionary metadata) { return ((CommandHandlerDescriptor)metadata[typeof(CommandHandlerDescriptor).FullName]); } + + private class Match { + public CommandContext Context { get; set; } + public Func CommandHandlerFactory { get; set; } + } + + public class CommandsComparer : IEqualityComparer { + public bool Equals(CommandDescriptor x, CommandDescriptor y) { + return x.MethodInfo.Equals(y.MethodInfo); + } + + public int GetHashCode(CommandDescriptor obj) { + return obj.MethodInfo.GetHashCode(); + } + } } } diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 67e763a87..15e4cd7bf 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -146,7 +146,7 @@ - + diff --git a/src/Tools/Orchard/Host/CommandHost.cs b/src/Tools/Orchard/Host/CommandHost.cs index 3a5d01ea0..623cf49bb 100644 --- a/src/Tools/Orchard/Host/CommandHost.cs +++ b/src/Tools/Orchard/Host/CommandHost.cs @@ -19,14 +19,16 @@ namespace Orchard.Host { //TODO } - public void RunCommand(OrchardParameters args) { + public int RunCommand(OrchardParameters args) { var agent = Activator.CreateInstance("Orchard.Framework", "Orchard.Commands.CommandHostAgent").Unwrap(); - agent.GetType().GetMethod("RunSingleCommand").Invoke(agent, new object[] { + int result = (int)agent.GetType().GetMethod("RunSingleCommand").Invoke(agent, new object[] { Console.In, Console.Out, args.Tenant, args.Arguments.ToArray(), args.Switches}); + + return result; } } } \ No newline at end of file diff --git a/src/Tools/Orchard/Program.cs b/src/Tools/Orchard/Program.cs index 4fd6e57f1..7837cce6d 100644 --- a/src/Tools/Orchard/Program.cs +++ b/src/Tools/Orchard/Program.cs @@ -18,11 +18,11 @@ namespace Orchard { _args = args; } - static void Main(string[] args) { - new Program(args).Run(); + static int Main(string[] args) { + return new Program(args).Run(); } - public void Run() { + public int Run() { // Parse command line arguments var arguments = new OrchardParametersParser().Parse(new CommandParametersParser().Parse(_args)); @@ -51,7 +51,7 @@ namespace Orchard { if (arguments.Verbose) { Console.WriteLine("Executing command in ASP.NET AppDomain"); } - host.RunCommand(arguments); + return host.RunCommand(arguments); } private DirectoryInfo GetOrchardDirectory(string directory) {