mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-22 03:37:25 +08:00
Implementation of the command handler for recipes. Recipes now can execute commands.
--HG-- branch : recipe
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Orchard.Commands;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Models;
|
||||
@@ -8,7 +11,12 @@ using Orchard.Recipes.Services;
|
||||
|
||||
namespace Orchard.Recipes.RecipeHandlers {
|
||||
public class CommandRecipeHandler : IRecipeHandler {
|
||||
public CommandRecipeHandler () {
|
||||
private readonly ICommandManager _commandManager;
|
||||
private readonly CommandParser _commandParser;
|
||||
|
||||
public CommandRecipeHandler (ICommandManager commandManager) {
|
||||
_commandManager = commandManager;
|
||||
_commandParser = new CommandParser();
|
||||
Logger = NullLogger.Instance;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
@@ -34,8 +42,158 @@ namespace Orchard.Recipes.RecipeHandlers {
|
||||
.Split(new[] {"\r\n", "\n"}, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(commandEntry => commandEntry.Trim());
|
||||
|
||||
// run commands.
|
||||
foreach (var command in commands) {
|
||||
if (!String.IsNullOrEmpty(command)) {
|
||||
var commandParameters = _commandParser.ParseCommandParameters(command);
|
||||
var input = new StringReader("");
|
||||
var output = new StringWriter();
|
||||
_commandManager.Execute(new CommandParameters { Arguments = commandParameters.Arguments, Input = input, Output = output, Switches = commandParameters.Switches });
|
||||
}
|
||||
}
|
||||
|
||||
recipeContext.Executed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Utility class for parsing lines of commands.
|
||||
class CommandParser {
|
||||
public CommandParameters ParseCommandParameters(string command) {
|
||||
var args = SplitArgs(command);
|
||||
var arguments = new List<string>();
|
||||
var result = new CommandParameters {
|
||||
Switches = new Dictionary<string, string>()
|
||||
};
|
||||
|
||||
foreach (var arg in args) {
|
||||
// Switch?
|
||||
if (arg[0] == '/') {
|
||||
int index = arg.IndexOf(':');
|
||||
var switchName = (index < 0 ? arg.Substring(1) : arg.Substring(1, index - 1));
|
||||
var switchValue = (index < 0 || index >= arg.Length ? string.Empty : arg.Substring(index + 1));
|
||||
|
||||
if (string.IsNullOrEmpty(switchName))
|
||||
{
|
||||
throw new ArgumentException(string.Format("Invalid switch syntax: \"{0}\". Valid syntax is /<switchName>[:<switchValue>].", arg));
|
||||
}
|
||||
|
||||
result.Switches.Add(switchName, switchValue);
|
||||
}
|
||||
else {
|
||||
arguments.Add(arg);
|
||||
}
|
||||
}
|
||||
|
||||
result.Arguments = arguments;
|
||||
return result;
|
||||
}
|
||||
|
||||
class State {
|
||||
private readonly string _commandLine;
|
||||
private readonly StringBuilder _stringBuilder;
|
||||
private readonly List<string> _arguments;
|
||||
private int _index;
|
||||
|
||||
public State(string commandLine) {
|
||||
_commandLine = commandLine;
|
||||
_stringBuilder = new StringBuilder();
|
||||
_arguments = new List<string>();
|
||||
}
|
||||
|
||||
public StringBuilder StringBuilder { get { return _stringBuilder; } }
|
||||
public bool EOF { get { return _index >= _commandLine.Length; } }
|
||||
public char Current { get { return _commandLine[_index]; } }
|
||||
public IEnumerable<string> Arguments { get { return _arguments; } }
|
||||
|
||||
public void AddArgument() {
|
||||
_arguments.Add(StringBuilder.ToString());
|
||||
StringBuilder.Clear();
|
||||
}
|
||||
|
||||
public void AppendCurrent() {
|
||||
StringBuilder.Append(Current);
|
||||
}
|
||||
|
||||
public void Append(char ch) {
|
||||
StringBuilder.Append(ch);
|
||||
}
|
||||
|
||||
public void MoveNext() {
|
||||
if (!EOF)
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement the same logic as found at
|
||||
/// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
/// The 3 special characters are quote, backslash and whitespaces, in order
|
||||
/// of priority.
|
||||
/// The semantics of a quote is: whatever the state of the lexer, copy
|
||||
/// all characters verbatim until the next quote or EOF.
|
||||
/// The semantics of backslash is: If the next character is a backslash or a quote,
|
||||
/// copy the next character. Otherwise, copy the backslash and the next character.
|
||||
/// The semantics of whitespace is: end the current argument and move on to the next one.
|
||||
/// </summary>
|
||||
private static IEnumerable<string> SplitArgs(string commandLine) {
|
||||
var state = new State(commandLine);
|
||||
while (!state.EOF) {
|
||||
switch (state.Current) {
|
||||
case '"':
|
||||
ProcessQuote(state);
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
ProcessBackslash(state);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (state.StringBuilder.Length > 0)
|
||||
state.AddArgument();
|
||||
state.MoveNext();
|
||||
break;
|
||||
|
||||
default:
|
||||
state.AppendCurrent();
|
||||
state.MoveNext();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (state.StringBuilder.Length > 0)
|
||||
state.AddArgument();
|
||||
return state.Arguments;
|
||||
}
|
||||
|
||||
private static void ProcessQuote(State state) {
|
||||
state.MoveNext();
|
||||
while (!state.EOF) {
|
||||
if (state.Current == '"') {
|
||||
state.MoveNext();
|
||||
break;
|
||||
}
|
||||
state.AppendCurrent();
|
||||
state.MoveNext();
|
||||
}
|
||||
|
||||
state.AddArgument();
|
||||
}
|
||||
|
||||
private static void ProcessBackslash(State state) {
|
||||
state.MoveNext();
|
||||
if (state.EOF) {
|
||||
state.Append('\\');
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.Current == '"') {
|
||||
state.Append('"');
|
||||
state.MoveNext();
|
||||
}
|
||||
else {
|
||||
state.Append('\\');
|
||||
state.AppendCurrent();
|
||||
state.MoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -240,18 +240,12 @@ namespace Orchard.Setup.Services {
|
||||
var cultureManager = environment.Resolve<ICultureManager>();
|
||||
cultureManager.AddCulture("en-US");
|
||||
|
||||
var contentManager = environment.Resolve<IContentManager>();
|
||||
|
||||
// this needs to exit the standalone environment? rework this process entirely?
|
||||
// simulate installation-time module activation events
|
||||
//var hackInstallationGenerator = environment.Resolve<IHackInstallationGenerator>();
|
||||
//hackInstallationGenerator.GenerateInstallEvents();
|
||||
|
||||
var recipeManager = environment.Resolve<IRecipeManager>();
|
||||
if (context.Recipe != null) {
|
||||
recipeManager.Execute(Recipes().Where(r => r.Name == context.Recipe).FirstOrDefault());
|
||||
}
|
||||
|
||||
var contentManager = environment.Resolve<IContentManager>();
|
||||
// If "Orchard.Widgets" is enabled, setup default layers and widgets
|
||||
var extensionManager = environment.Resolve<IExtensionManager>();
|
||||
var shellDescriptor = environment.Resolve<ShellDescriptor>();
|
||||
|
Reference in New Issue
Block a user