-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathCommandLineParser.cs
More file actions
127 lines (109 loc) · 4.31 KB
/
Copy pathCommandLineParser.cs
File metadata and controls
127 lines (109 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System;
using System.Collections.Generic;
using GitHub.DistributedTask.Logging;
using GitHub.Runner.Sdk;
//
// Pattern:
// cmd1 cmd2 --arg1 arg1val --aflag --arg2 arg2val
//
namespace GitHub.Runner.Common
{
public sealed class CommandLineParser
{
private ISecretMasker _secretMasker;
private Tracing _trace;
public List<string> Commands { get; }
public HashSet<string> Flags { get; }
public Dictionary<string, string> Args { get; }
public HashSet<string> SecretArgNames { get; }
private bool HasArgs { get; set; }
public CommandLineParser(IHostContext hostContext, string[] secretArgNames)
{
_secretMasker = hostContext.SecretMasker;
_trace = hostContext.GetTrace(nameof(CommandLineParser));
Commands = new List<string>();
Flags = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
Args = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
SecretArgNames = new HashSet<string>(secretArgNames ?? new string[0], StringComparer.OrdinalIgnoreCase);
}
public bool IsCommand(string name)
{
bool result = false;
if (Commands.Count > 0)
{
result = String.Equals(name, Commands[0], StringComparison.CurrentCultureIgnoreCase);
}
return result;
}
public void Parse(string[] args)
{
_trace.Info(nameof(Parse));
ArgUtil.NotNull(args, nameof(args));
_trace.Info("Parsing {0} args", args.Length);
string argScope = null;
foreach (string arg in args)
{
_trace.Info("parsing argument");
HasArgs = HasArgs || arg.StartsWith("--");
_trace.Info("HasArgs: {0}", HasArgs);
if (string.Equals(arg, "/?", StringComparison.Ordinal))
{
Flags.Add("help");
}
else if (!HasArgs)
{
_trace.Info("Adding Command: {0}", arg);
Commands.Add(arg.Trim());
}
else
{
// it's either an arg, an arg value or a flag
if (arg.StartsWith("--") && arg.Length > 2)
{
string argVal = arg.Substring(2);
_trace.Info("arg: {0}", argVal);
// this means two --args in a row which means previous was a flag
if (argScope != null)
{
_trace.Info("Adding flag: {0}", argScope);
Flags.Add(argScope.Trim());
}
argScope = argVal;
}
else if (!arg.StartsWith("-"))
{
// we found a value - check if we're in scope of an arg
if (argScope != null && !Args.ContainsKey(argScope = argScope.Trim()))
{
if (SecretArgNames.Contains(argScope))
{
_secretMasker.AddValue(arg);
}
_trace.Info("Adding option '{0}': '{1}'", argScope, arg);
// ignore duplicates - first wins - below will be val1
// --arg1 val1 --arg1 val1
Args.Add(argScope, arg);
argScope = null;
}
}
else
{
//
// ignoring the second value for an arg (val2 below)
// --arg val1 val2
// ignoring invalid things like empty - and --
// --arg val1 -- --flag
_trace.Info("Ignoring arg");
}
}
}
_trace.Verbose("done parsing arguments");
// handle last arg being a flag
if (argScope != null)
{
Flags.Add(argScope);
}
_trace.Verbose("Exiting parse");
}
}
}