Skip to content

Commit 986b692

Browse files
committed
Refactor the arguments enumeration
1 parent e952153 commit 986b692

File tree

8 files changed

+109
-138
lines changed

8 files changed

+109
-138
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
5+
namespace MGR.CommandLineParser
6+
{
7+
internal class Arguments
8+
{
9+
private readonly List<string> _arguments;
10+
private int _currentIndex = -1;
11+
public Arguments(IEnumerable<string> args)
12+
{
13+
_arguments = new List<string>(args);
14+
}
15+
16+
public void Revert()
17+
{
18+
if (_currentIndex == 0)
19+
{
20+
throw new InvalidOperationException("Unable to revert Arguments: it is already at the start.");
21+
}
22+
}
23+
24+
public bool Advance()
25+
{
26+
if (_arguments.Count == _currentIndex + 1)
27+
{
28+
return false;
29+
}
30+
_currentIndex++;
31+
ReplaceRspFileInCurrentPosition();
32+
return true;
33+
}
34+
35+
private void ReplaceRspFileInCurrentPosition()
36+
{
37+
var current = GetCurrent();
38+
if (current.StartsWith("@", StringComparison.CurrentCulture))
39+
{
40+
if (!current.StartsWith("@@", StringComparison.CurrentCulture))
41+
{
42+
var responseFileName = current.Remove(0, 1);
43+
if (Path.GetExtension(responseFileName) == ".rsp" && File.Exists(responseFileName))
44+
{
45+
var responseFileContent = File.ReadAllLines(responseFileName);
46+
_arguments.RemoveAt(_currentIndex);
47+
_arguments.InsertRange(_currentIndex, responseFileContent);
48+
ReplaceRspFileInCurrentPosition();
49+
return;
50+
}
51+
}
52+
var currentWithoutAt = current.Remove(0, 1);
53+
_arguments[_currentIndex] = currentWithoutAt;
54+
}
55+
}
56+
57+
58+
public string GetCurrent()
59+
{
60+
if (_currentIndex < 0 || _currentIndex >= _arguments.Count)
61+
{
62+
throw new ArgumentOutOfRangeException();
63+
}
64+
return _arguments[_currentIndex];
65+
}
66+
}
67+
}

src/MGR.CommandLineParser/Constants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ internal static class ExceptionMessages
1919

2020
internal static readonly Func<object, string, string> FormatParserOptionNotFoundForCommand =
2121
(commandName, optionName) => string.Format(CultureInfo.InvariantCulture, "There is no option '{1}' for the command '{0}'.", commandName, optionName);
22+
internal static readonly Func<object, string, string> FormatParserOptionValueNotFoundForCommand =
23+
(commandName, optionName) => string.Format(CultureInfo.InvariantCulture, "A value should be provided for option '{1}' for the command '{0}'.", commandName, optionName);
2224

2325
internal static readonly Func<object, string, string> FormatParserOptionValueRequired =
2426
(commandName, optionName) => string.Format(CultureInfo.InvariantCulture, "You should specified a value for the option '{1}' of the command '{0}'.", commandName, optionName);

src/MGR.CommandLineParser/Extensions/EnumerableExtensions.cs

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/MGR.CommandLineParser/Extensions/EnumeratorExtensions.cs

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/MGR.CommandLineParser/Parser.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,22 @@ internal Parser(IParserOptions parserOptions)
2222

2323
public string CommandLineName => _parserOptions.CommandLineName;
2424

25-
public ParsingResult Parse<TCommand>(IEnumerable<string> arguments, IServiceProvider serviceProvider) where TCommand : class, ICommand => ParseArguments(arguments, serviceProvider, (parserEngine, argumentsEnumerator) =>
26-
parserEngine.Parse<TCommand>(argumentsEnumerator));
25+
public ParsingResult Parse<TCommand>(IEnumerable<string> args, IServiceProvider serviceProvider) where TCommand : class, ICommand => ParseArguments(args, serviceProvider, (parserEngine, arguments) =>
26+
parserEngine.Parse<TCommand>(arguments));
2727

28-
public ParsingResult Parse(IEnumerable<string> arguments, IServiceProvider serviceProvider) => ParseArguments(arguments, serviceProvider, (parserEngine, argumentsEnumerator) =>
29-
parserEngine.Parse(argumentsEnumerator));
28+
public ParsingResult Parse(IEnumerable<string> args, IServiceProvider serviceProvider) => ParseArguments(args, serviceProvider, (parserEngine, arguments) =>
29+
parserEngine.Parse(arguments));
3030

31-
public ParsingResult ParseWithDefaultCommand<TCommand>(IEnumerable<string> arguments, IServiceProvider serviceProvider) where TCommand : class, ICommand => ParseArguments(arguments, serviceProvider, (parserEngine, argumentsEnumerator) =>
32-
parserEngine.ParseWithDefaultCommand<TCommand>(argumentsEnumerator));
31+
public ParsingResult ParseWithDefaultCommand<TCommand>(IEnumerable<string> args, IServiceProvider serviceProvider) where TCommand : class, ICommand => ParseArguments(args, serviceProvider, (parserEngine, arguments) =>
32+
parserEngine.ParseWithDefaultCommand<TCommand>(arguments));
3333

34-
private ParsingResult ParseArguments(IEnumerable<string> arguments, IServiceProvider serviceProvider, Func<ParserEngine, IEnumerator<string>, ParsingResult> callParse)
34+
private ParsingResult ParseArguments(IEnumerable<string> args, IServiceProvider serviceProvider, Func<ParserEngine, Arguments, ParsingResult> callParse)
3535
{
36-
if (arguments == null)
36+
if (args == null)
3737
{
3838
return new ParsingResult(null, null, CommandParsingResultCode.NoArgumentsProvided);
3939
}
40-
40+
var arguments = new Arguments(args);
4141
var parserOptionsAccessor = serviceProvider.GetService<IParserOptionsAccessor>();
4242
parserOptionsAccessor.Current = _parserOptions;
4343
var loggerFactory = serviceProvider.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
@@ -46,9 +46,8 @@ private ParsingResult ParseArguments(IEnumerable<string> arguments, IServiceProv
4646
{
4747
logger.CreationOfParserEngine();
4848
var parserEngine = new ParserEngine(serviceProvider, loggerFactory);
49-
var argumentsEnumerator = arguments.GetArgumentsEnumerator();
5049

51-
var result = callParse(parserEngine, argumentsEnumerator);
50+
var result = callParse(parserEngine, arguments);
5251
return result;
5352
}
5453
}

src/MGR.CommandLineParser/ParserEngine.cs

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections.Generic;
32
using MGR.CommandLineParser.Command;
43
using MGR.CommandLineParser.Diagnostics;
54
using MGR.CommandLineParser.Extensibility;
@@ -20,13 +19,13 @@ internal ParserEngine(IServiceProvider serviceProvider, ILoggerFactory loggerFac
2019
_logger = loggerFactory.CreateLogger<LoggerCategory.Parser>();
2120
}
2221

23-
internal ParsingResult Parse<TCommand>(IEnumerator<string> argumentsEnumerator) where TCommand : class, ICommand
22+
internal ParsingResult Parse<TCommand>(Arguments arguments) where TCommand : class, ICommand
2423
{
2524
using (_logger.BeginParsingForSpecificCommandType(typeof(TCommand)))
2625
{
2726
var commandTypeProviders = _serviceProvider.GetServices<ICommandTypeProvider>();
2827
var commandType = commandTypeProviders.GetCommandType<TCommand>();
29-
var parsingResult = ParseImpl(argumentsEnumerator, commandType);
28+
var parsingResult = ParseImpl(arguments, commandType);
3029
if (parsingResult.ParsingResultCode == CommandParsingResultCode.NoCommandFound)
3130
{
3231
_logger.NoCommandFoundAfterSpecificParsing();
@@ -41,46 +40,47 @@ internal ParsingResult Parse<TCommand>(IEnumerator<string> argumentsEnumerator)
4140
}
4241
}
4342

44-
internal ParsingResult ParseWithDefaultCommand<TCommand>(IEnumerator<string> argumentsEnumerator)
43+
internal ParsingResult ParseWithDefaultCommand<TCommand>(Arguments arguments)
4544
where TCommand : class, ICommand
4645
{
4746
using (_logger.BeginParsingWithDefaultCommandType(typeof(TCommand)))
4847
{
49-
var commandName = argumentsEnumerator.GetNextCommandLineItem();
50-
if (commandName != null)
48+
if (arguments.Advance())
5149
{
50+
var commandName = arguments.GetCurrent();
5251
_logger.ArgumentProvidedWithDefaultCommandType(commandName);
5352
var commandTypeProviders = _serviceProvider.GetServices<ICommandTypeProvider>();
5453
var commandType = commandTypeProviders.GetCommandType(commandName);
5554
if (commandType != null)
5655
{
5756
_logger.CommandTypeFoundWithDefaultCommandType(commandName);
58-
return ParseImpl(argumentsEnumerator, commandType);
57+
return ParseImpl(arguments, commandType);
5958
}
6059

6160
_logger.NoCommandTypeFoundWithDefaultCommandType(commandName, typeof(TCommand));
62-
var withArgumentsCommandResult = Parse<TCommand>(argumentsEnumerator.PrefixWith(commandName));
61+
arguments.Revert();
62+
var withArgumentsCommandResult = Parse<TCommand>(arguments);
6363
return withArgumentsCommandResult;
6464

6565
}
6666

6767
_logger.NoArgumentProvidedWithDefaultCommandType(typeof(TCommand));
68-
var noArgumentsCommandResult = Parse<TCommand>(argumentsEnumerator);
68+
var noArgumentsCommandResult = Parse<TCommand>(arguments);
6969
return noArgumentsCommandResult;
7070
}
7171
}
7272

73-
internal ParsingResult Parse(IEnumerator<string> argumentsEnumerator)
73+
internal ParsingResult Parse(Arguments arguments)
7474
{
7575
_logger.ParseForNotAlreadyKnownCommand();
76-
var commandName = argumentsEnumerator.GetNextCommandLineItem();
77-
if (commandName == null)
76+
if (!arguments.Advance())
7877
{
7978
_logger.NoCommandNameForNotAlreadyKnownCommand();
8079
var helpWriter = _serviceProvider.GetRequiredService<IHelpWriter>();
8180
helpWriter.WriteCommandListing();
8281
return new ParsingResult(null, null, CommandParsingResultCode.NoCommandNameProvided);
8382
}
83+
var commandName = arguments.GetCurrent();
8484

8585
using (_logger.BeginParsingUsingCommandName(commandName))
8686
{
@@ -95,14 +95,14 @@ internal ParsingResult Parse(IEnumerator<string> argumentsEnumerator)
9595
}
9696

9797
_logger.CommandTypeFoundForNotAlreadyKnownCommand(commandName);
98-
return ParseImpl(argumentsEnumerator, commandType);
98+
return ParseImpl(arguments, commandType);
9999
}
100100

101101
}
102102

103-
private ParsingResult ParseImpl(IEnumerator<string> argumentsEnumerator, ICommandType commandType)
103+
private ParsingResult ParseImpl(Arguments arguments, ICommandType commandType)
104104
{
105-
var commandObjectBuilder = ExtractCommandLineOptions(commandType, argumentsEnumerator);
105+
var commandObjectBuilder = ExtractCommandLineOptions(commandType, arguments);
106106
if (commandObjectBuilder == null)
107107
{
108108
return new ParsingResult(null, null, CommandParsingResultCode.CommandParametersNotValid);
@@ -117,17 +117,14 @@ private ParsingResult ParseImpl(IEnumerator<string> argumentsEnumerator, IComman
117117
}
118118
return new ParsingResult(commandObjectBuilder.GenerateCommandObject(), null, CommandParsingResultCode.Success);
119119
}
120-
private ICommandObjectBuilder ExtractCommandLineOptions(ICommandType commandType, IEnumerator<string> argumentsEnumerator)
120+
121+
private ICommandObjectBuilder ExtractCommandLineOptions(ICommandType commandType, Arguments arguments)
121122
{
122123
var commandObjectBuilder = commandType.CreateCommandObjectBuilder(_serviceProvider);
123124
var alwaysPutInArgumentList = false;
124-
while (true)
125+
while (arguments.Advance())
125126
{
126-
var argument = argumentsEnumerator.GetNextCommandLineItem();
127-
if (argument == null)
128-
{
129-
break;
130-
}
127+
var argument = arguments.GetCurrent();
131128
if (argument.Equals(Constants.EndOfOptions))
132129
{
133130
alwaysPutInArgumentList = true;
@@ -166,7 +163,17 @@ private ICommandObjectBuilder ExtractCommandLineOptions(ICommandType commandType
166163

167164
if (option.ShouldProvideValue)
168165
{
169-
value = value ?? argumentsEnumerator.GetNextCommandLineItem();
166+
if (value == null)
167+
{
168+
if (!arguments.Advance())
169+
{
170+
var console = _serviceProvider.GetRequiredService<IConsole>();
171+
console.WriteLineError(Constants.ExceptionMessages.FormatParserOptionValueNotFoundForCommand(commandType.Metadata.Name, optionText));
172+
return null;
173+
}
174+
175+
value = arguments.GetCurrent();
176+
}
170177
}
171178

172179
option.AssignValue(value);

tests/MGR.CommandLineParser.UnitTests/Extensions/EnumeratorExtensionsTests.PrependWith.cs

Lines changed: 0 additions & 37 deletions
This file was deleted.

tests/MGR.CommandLineParser.UnitTests/Extensions/EnumeratorExtensionsTests.cs

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)