mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-24 19:08:18 +08:00
Fix command line parser to support quotes
--HG-- branch : dev
This commit is contained in:
parent
b2be561e3f
commit
f846335852
@ -10,10 +10,10 @@ namespace Orchard.Specs.Bindings {
|
||||
[Binding]
|
||||
public class CommandLine : BindingBase {
|
||||
[When(@"I execute >(.*)")]
|
||||
public void WhenIExecute(string commandLine) {
|
||||
public void WhenIExecute(string commandLine) {
|
||||
var details = new RequestDetails();
|
||||
Binding<WebAppHosting>().Host.Execute(() => {
|
||||
var args = commandLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var args = new CommandLineParser().Parse(commandLine);
|
||||
var parameters = new CommandParametersParser().Parse(args);
|
||||
var agent = new CommandHostAgent();
|
||||
var input = new StringReader("");
|
||||
|
@ -75,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Packaging", "Orchar
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCLI", "Tools\OrchardCli\OrchardCLI.csproj", "{71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Tests", "Tools\Orchard.Tests\Orchard.Tests.csproj", "{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -213,6 +215,10 @@ Global
|
||||
{71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -247,6 +253,7 @@ Global
|
||||
{33B1BC8D-E292-4972-A363-22056B207156} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
|
||||
{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
|
||||
{71A006E0-85BD-4CC4-ADF9-B548D5CA72A7} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
|
||||
{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
|
||||
{E65E5633-C0FF-453C-A906-481C14F969D6} = {E75A4CE4-CAA6-41E4-B951-33ACC60DC77C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
185
src/Tools/Orchard.Tests/CommandLineParserTests.cs
Normal file
185
src/Tools/Orchard.Tests/CommandLineParserTests.cs
Normal file
@ -0,0 +1,185 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Parameters;
|
||||
|
||||
namespace Orchard.Tests {
|
||||
[TestFixture]
|
||||
public class CommandLineParseTests {
|
||||
[Test]
|
||||
public void ParserUnderstandsSimpleArguments() {
|
||||
// a b cdef
|
||||
// => a
|
||||
// => b
|
||||
// => cdef
|
||||
var result = new CommandLineParser().Parse("a b cdef").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("a"));
|
||||
Assert.That(result[1], Is.EqualTo("b"));
|
||||
Assert.That(result[2], Is.EqualTo("cdef"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserIgnoresExtraSpaces() {
|
||||
// a b cdef
|
||||
// => a
|
||||
// => b
|
||||
// => cdef
|
||||
var result = new CommandLineParser().Parse(" a b cdef ").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("a"));
|
||||
Assert.That(result[1], Is.EqualTo("b"));
|
||||
Assert.That(result[2], Is.EqualTo("cdef"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserGroupsQuotedArguments() {
|
||||
// feature enable "a b cdef"
|
||||
// => feature
|
||||
// => enable
|
||||
// => a b cdef
|
||||
var result = new CommandLineParser().Parse("feature enable \"a b cdef\"").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo("a b cdef"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserUnderstandsQuotesInsideArgument() {
|
||||
// feature enable /foo:"a b cdef"
|
||||
// => feature
|
||||
// => enable
|
||||
// => /foo:a b cdef
|
||||
var result = new CommandLineParser().Parse("feature enable /foo:\"a b cdef\"").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo("/foo:a b cdef"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserBackslashEscapesQuote() {
|
||||
// feature enable \"a b cdef\"
|
||||
// => feature
|
||||
// => enable
|
||||
// => "a
|
||||
// => b
|
||||
// => cdef"
|
||||
var result = new CommandLineParser().Parse("feature enable \\\"a b cdef\\\"").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(5));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo("\"a"));
|
||||
Assert.That(result[3], Is.EqualTo("b"));
|
||||
Assert.That(result[4], Is.EqualTo("cdef\""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserBackslashDoesnotEscapeBackslash() {
|
||||
// feature enable \\a
|
||||
// => feature
|
||||
// => enable
|
||||
// => \\a
|
||||
var result = new CommandLineParser().Parse("feature enable \\\\a").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo("\\\\a"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserBackslashDoesnotEscapeOtherCharacters() {
|
||||
// feature enable \a
|
||||
// => feature
|
||||
// => enable
|
||||
// => \a
|
||||
var result = new CommandLineParser().Parse("feature enable \\a").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo("\\a"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserUnderstandsTrailingBackslash() {
|
||||
// feature enable \
|
||||
// => feature
|
||||
// => enable
|
||||
// => \
|
||||
var result = new CommandLineParser().Parse("feature enable \\").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo("\\"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserUnderstandsTrailingBackslash2() {
|
||||
// feature enable b\
|
||||
// => feature
|
||||
// => enable
|
||||
// => b\
|
||||
var result = new CommandLineParser().Parse("feature enable b\\").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo("b\\"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserUnderstandsEmptyArgument() {
|
||||
// feature enable ""
|
||||
// => feature
|
||||
// => enable
|
||||
// => <empty arg>
|
||||
var result = new CommandLineParser().Parse("feature enable \"\"").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserUnderstandsTrailingQuote() {
|
||||
// feature enable "
|
||||
// => feature
|
||||
// => enable
|
||||
// => <empty arg>
|
||||
var result = new CommandLineParser().Parse("feature enable \"").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(3));
|
||||
Assert.That(result[0], Is.EqualTo("feature"));
|
||||
Assert.That(result[1], Is.EqualTo("enable"));
|
||||
Assert.That(result[2], Is.EqualTo(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserUnderstandsEmptyArgument2() {
|
||||
// "
|
||||
// => <empty arg>
|
||||
var result = new CommandLineParser().Parse("\"").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(1));
|
||||
Assert.That(result[0], Is.EqualTo(""));
|
||||
}
|
||||
[Test]
|
||||
public void ParserUnderstandsEmptyArgument3() {
|
||||
// ""
|
||||
// => <empty arg>
|
||||
var result = new CommandLineParser().Parse("\"\"").ToList();
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Has.Count.EqualTo(1));
|
||||
Assert.That(result[0], Is.EqualTo(""));
|
||||
}
|
||||
}
|
||||
}
|
113
src/Tools/Orchard.Tests/Orchard.Tests.csproj
Normal file
113
src/Tools/Orchard.Tests/Orchard.Tests.csproj
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.Tests</RootNamespace>
|
||||
<AssemblyName>Orchard.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation />
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Moq, Version=4.0.812.4, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\lib\moq\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\lib\nunit\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="CommandLineParserTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Orchard\Orchard.csproj">
|
||||
<Project>{33B1BC8D-E292-4972-A363-22056B207156}</Project>
|
||||
<Name>Orchard</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
36
src/Tools/Orchard.Tests/Properties/AssemblyInfo.cs
Normal file
36
src/Tools/Orchard.Tests/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Orchad.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Orchard")]
|
||||
[assembly: AssemblyCopyright("Copyright © CodePlex Foundation 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("db4cb512-5c00-44c9-9173-7ede47af1967")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.5.0")]
|
||||
[assembly: AssemblyFileVersion("0.5.0")]
|
@ -77,6 +77,7 @@
|
||||
<Compile Include="HostContext\ICommandHostContextProvider.cs" />
|
||||
<Compile Include="Logger.cs" />
|
||||
<Compile Include="OrchardHost.cs" />
|
||||
<Compile Include="Parameters\CommandLineParser.cs" />
|
||||
<Compile Include="Parameters\ICommandParametersParser.cs" />
|
||||
<Compile Include="IOrchardParametersParser.cs" />
|
||||
<Compile Include="OrchardParameters.cs" />
|
||||
|
124
src/Tools/Orchard/Parameters/CommandLineParser.cs
Normal file
124
src/Tools/Orchard/Parameters/CommandLineParser.cs
Normal file
@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Orchard.Parameters {
|
||||
public interface ICommandLineParser {
|
||||
IEnumerable<string> Parse(string commandLine);
|
||||
}
|
||||
|
||||
public class CommandLineParser : ICommandLineParser {
|
||||
public IEnumerable<string> Parse(string commandLine) {
|
||||
return SplitArgs(commandLine);
|
||||
}
|
||||
|
||||
public 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 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 void ProcessQuote(State state) {
|
||||
state.MoveNext();
|
||||
while (!state.EOF) {
|
||||
if (state.Current == '"') {
|
||||
state.MoveNext();
|
||||
break;
|
||||
}
|
||||
state.AppendCurrent();
|
||||
state.MoveNext();
|
||||
}
|
||||
|
||||
state.AddArgument();
|
||||
}
|
||||
|
||||
private 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Orchard.Parameters;
|
||||
|
||||
namespace Orchard.ResponseFiles {
|
||||
public class ResponseLine : MarshalByRefObject {
|
||||
@ -24,48 +24,10 @@ namespace Orchard.ResponseFiles {
|
||||
Filename = filename,
|
||||
LineText = lineText,
|
||||
LineNumber = i,
|
||||
Args = SplitArgs(lineText).ToArray()
|
||||
Args = new CommandLineParser().Parse(lineText).ToArray()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> SplitArgs(string text) {
|
||||
var sb = new StringBuilder();
|
||||
bool inString = false;
|
||||
foreach (char ch in text) {
|
||||
switch(ch){
|
||||
case '"':
|
||||
if (inString) {
|
||||
inString = false;
|
||||
yield return sb.ToString();
|
||||
sb.Length = 0;
|
||||
}
|
||||
else {
|
||||
inString = true;
|
||||
sb.Length = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (sb.Length > 0) {
|
||||
yield return sb.ToString();
|
||||
sb.Length = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sb.Append(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there was anything accumulated
|
||||
if (sb.Length > 0) {
|
||||
yield return sb.ToString();
|
||||
sb.Length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ namespace OrchardCLI {
|
||||
|
||||
private int RunCommandInSession(CommandHostContext context, string command) {
|
||||
try {
|
||||
var args = new OrchardParametersParser().Parse(new CommandParametersParser().Parse(ResponseFileReader.SplitArgs(command)));
|
||||
var args = new OrchardParametersParser().Parse(new CommandParametersParser().Parse(new CommandLineParser().Parse(command)));
|
||||
return context.CommandHost.RunCommandInSession(_input, _output, context.Logger, args);
|
||||
}
|
||||
catch (AppDomainUnloadedException) {
|
||||
|
@ -98,6 +98,9 @@
|
||||
<Compile Include="..\Orchard\OrchardParametersParser.cs">
|
||||
<Link>OrchardParametersParser.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Orchard\Parameters\CommandLineParser.cs">
|
||||
<Link>Parameters\CommandLineParser.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Orchard\Parameters\CommandParameters.cs">
|
||||
<Link>Parameters\CommandParameters.cs</Link>
|
||||
</Compile>
|
||||
|
Loading…
Reference in New Issue
Block a user