Nuke.Cola
Loading...
Searching...
No Matches
ArgumentStringHandlerEx.cs
1using System.Runtime.CompilerServices;
2using Nuke.Common;
3using Nuke.Common.IO;
4using Nuke.Common.Tooling;
5using Nuke.Common.Utilities;
6
8
9/// <summary>
10/// <para>
11/// An interpolated string handler used for comfortably set program arguments. It is an iteration over Nuke's own
12/// `ArgumentStringHandler`. This "Ex" version will not use double quotes automatically making its output more
13/// predictable than Nuke's handler. However, it supports explicit quoting with the `:quote`/`q` and `:singleQuote`/`sq`
14/// format specifiers.
15/// </para>
16/// <para>
17/// `ArgumentStringHandlerEx` also has the following additional features
18/// </para>
19/// <list type="bullet">
20/// <item>Collapse multiline text into a single line joined with space</item>
21/// <item>
22/// Interpret ValueTuples with 2 items as optional parameters. If the second value is empty, the first value
23/// will not expand either. The "key" and "value" are concatenated together directly upon expansion. All format
24/// specifiers work and applied only to "value".
25/// </item>
26/// </list>
27/// </summary>
28[InterpolatedStringHandler]
29public ref struct ArgumentStringHandlerEx
30{
31 private DefaultInterpolatedStringHandler _builder;
32 private readonly List<string> _secretValues;
33
34 public static string Render(ArgumentStringHandlerEx input)
35 {
36 return input.ToStringAndClear();
37 }
38
40 int literalLength,
41 int formattedCount,
42 out bool handlerIsValid)
43 {
44 _builder = new(literalLength, formattedCount);
45 _secretValues = new();
46 handlerIsValid = true;
47 }
48
49 public static implicit operator ArgumentStringHandlerEx(string value)
50 {
51 return $"{value.AsSingleLine()}";
52 }
53
54 public void AppendLiteral(string value)
55 {
56 _builder.AppendLiteral(value);
57 }
58
59 public void AppendFormatted(object? obj, int alignment = 0, string? format = null)
60 {
61 switch (obj)
62 {
63 case string value:
64 (value, format) = GetObjectString(value, alignment, format);
65 AppendFormatted(value, alignment, format);
66 break;
67 case IAbsolutePathHolder holder: AppendFormatted(holder, alignment, format); break;
68 case (string, ""): return;
69 case (string, null): return;
70 case (string param, {} arg and not ""):
71 (var stringArg, format) = GetObjectString(arg, alignment, format);
72 AppendFormatted(param + stringArg, alignment, format);
73 break;
74 default: AppendFormatted(obj?.ToString(), alignment, format); break;
75 }
76 }
77
78 private (string output, string? format) GetObjectString(object? obj, int alignment = 0, string? format = null)
79 {
80 switch (obj)
81 {
82 case string value:
83 value = value.AsSingleLine();
84 switch (format)
85 {
86 case "r":
87 case "secret":
88 _secretValues.Add(value);
89 break;
90
91 case "dn":
92 case "q":
93 case "quote":
94 case "doubleQuote":
95 (value, format) = (value.DoubleQuoteIfNeeded(), null);
96 break;
97
98 case "sn":
99 case "sq":
100 case "singleQuote":
101 (value, format) = (value.SingleQuoteIfNeeded(), null);
102 break;
103
104 case "nq": format = null; break;
105 }
106 return (value, format);
107
108 case IAbsolutePathHolder holder:
109 return (holder.Path, format ?? AbsolutePath.DoubleQuoteIfNeeded);
110
111 default: return (obj?.ToString() ?? "", format);
112 }
113 }
114
115 private void AppendFormatted(string? value, int alignment, string? format)
116 {
117 _builder.AppendFormatted(value, alignment, format);
118 }
119
120 private void AppendFormatted(IAbsolutePathHolder? holder, int alignment, string? format)
121 {
122 _builder.AppendFormatted(holder?.Path, alignment, format ?? AbsolutePath.DoubleQuoteIfNeeded);
123 }
124
125 public string ToStringAndClear()
126 {
127 var value = _builder.ToStringAndClear().AsSingleLine();
128
129 return value.Length > 1 && value.IndexOf(value: '"', startIndex: 1) == value.Length - 1
130 ? value.TrimMatchingDoubleQuotes()
131 : value;
132 }
133
134 public Func<string, string> GetFilter()
135 {
136 var secretValues = _secretValues;
137 return x => secretValues.Aggregate(x, (arguments, value) => arguments.Replace(value, "[REDACTED]"));
138 }
139}