Skip to content

Commit 4a31075

Browse files
committed
build(common): modernize build logic and update GitVersion to 6.7.0
Relocate build paths to /tmp for restricted environments and optimize process argument escaping using SearchValues and spans.
1 parent 9f7d312 commit 4a31075

File tree

6 files changed

+87
-70
lines changed

6 files changed

+87
-70
lines changed

build/common/Context/DockerBuildContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ public class DockerBuildContext(ICakeContext context) : BuildContextBase(context
66
{
77
public bool IsDockerOnLinux { get; set; }
88

9-
public IEnumerable<DockerImage> Images { get; set; } = new List<DockerImage>();
9+
public IEnumerable<DockerImage> Images { get; set; } = [];
1010
public DockerRegistry DockerRegistry { get; set; }
11-
public ICollection<Architecture> Architectures { get; set; } = new List<Architecture>();
11+
public ICollection<Architecture> Architectures { get; set; } = [];
1212
}
1313

build/common/Lifetime/DockerBuildLifetime.cs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,23 @@ public override void Setup(TContext context, ISetupContext info)
1818
var dotnetVersion = context.Argument(Arguments.DotnetVersion, string.Empty).ToLower();
1919
var dockerDistro = context.Argument(Arguments.DockerDistro, string.Empty).ToLower();
2020

21-
var versions = string.IsNullOrWhiteSpace(dotnetVersion)
22-
? Constants.DotnetVersions
23-
: string.Equals(dotnetVersion, "lts-latest", StringComparison.OrdinalIgnoreCase)
24-
? [Constants.DotnetLtsLatest]
25-
: [dotnetVersion];
26-
27-
var distros = string.IsNullOrWhiteSpace(dockerDistro)
28-
? Constants.DockerDistros
29-
: string.Equals(dockerDistro, "distro-latest", StringComparison.OrdinalIgnoreCase)
30-
? [Constants.AlpineLatest]
31-
: [dockerDistro];
32-
33-
var architectures = context.HasArgument(Arguments.Architecture) ? context.Arguments<Architecture>(Arguments.Architecture) : Constants.ArchToBuild;
21+
var versions = dotnetVersion switch
22+
{
23+
_ when dotnetVersion.IsNullOrWhiteSpace() => Constants.DotnetVersions,
24+
_ when dotnetVersion.IsEqualInvariant("lts-latest") => [Constants.DotnetLtsLatest],
25+
_ => [dotnetVersion]
26+
};
27+
28+
var distros = dockerDistro switch
29+
{
30+
_ when dockerDistro.IsNullOrWhiteSpace() => Constants.DockerDistros,
31+
_ when dockerDistro.IsEqualInvariant("distro-latest") => [Constants.AlpineLatest],
32+
_ => [dockerDistro]
33+
};
34+
35+
var architectures = context.HasArgument(Arguments.Architecture)
36+
? context.Arguments<Architecture>(Arguments.Architecture)
37+
: Constants.ArchToBuild;
3438
var platformArch = context.IsRunningOnAmd64() ? Architecture.Amd64 : Architecture.Arm64;
3539

3640
var registry = dockerRegistry == DockerRegistry.DockerHub ? Constants.DockerHubRegistry : Constants.GitHubContainerRegistry;

build/common/Tasks/Default.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public override void Run(ICakeContext context)
2525
context.Information($"# {task.GetTaskDescription()}");
2626

2727
var taskName = task.GetTaskName();
28-
string target = taskName != nameof(Default) ? $"-Target {taskName}" : string.Empty;
28+
var target = taskName != nameof(Default) ? $"-Target {taskName}" : string.Empty;
2929
context.Information($" ./build.ps1 -Stage {entryAssembly?.GetName().Name} {target} {arguments}\n");
3030
}
3131
}

build/common/Utilities/DockerContextExtensions.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static class DockerContextExtensions
2020
"org.opencontainers.image.licenses=MIT",
2121
"org.opencontainers.image.source=https://github.com/GitTools/GitVersion.git",
2222
"org.opencontainers.image.documentation=https://gitversion.net/docs/usage/docker",
23-
$"org.opencontainers.image.created={DateTime.UtcNow:O}",
23+
$"org.opencontainers.image.created={DateTime.UtcNow:O}"
2424
];
2525

2626
extension(BuildContextBase context)
@@ -156,14 +156,14 @@ public void DockerTestImage(DockerImage dockerImage)
156156
var tags = context.GetDockerTags(dockerImage, dockerImage.Architecture);
157157
foreach (var tag in tags)
158158
{
159-
context.DockerTestRun(tag, dockerImage.Architecture, "/repo", ["/showvariable", "FullSemver", "/nocache"]);
159+
context.DockerTestRun(tag, dockerImage.Architecture, "/tmp/repo", "/showvariable", "FullSemver", "/nocache");
160160
}
161161
}
162162

163163
public void DockerTestArtifact(DockerImage dockerImage, string cmd)
164164
{
165165
var tag = $"{dockerImage.DockerImageName()}:{dockerImage.Distro}-sdk-{dockerImage.TargetFramework}";
166-
context.DockerTestRun(tag, dockerImage.Architecture, "sh", [cmd]);
166+
context.DockerTestRun(tag, dockerImage.Architecture, "sh", cmd);
167167
}
168168

169169
private void DockerTestRun(string image, Architecture arch, string command,
@@ -189,7 +189,7 @@ private IEnumerable<string> GetDockerTags(DockerImage dockerImage,
189189
var tags = new List<string>
190190
{
191191
$"{name}:{context.Version.Version}-{distro}-{targetFramework}",
192-
$"{name}:{context.Version.SemVersion}-{distro}-{targetFramework}",
192+
$"{name}:{context.Version.SemVersion}-{distro}-{targetFramework}"
193193
};
194194

195195
if (distro == Constants.DockerDistroLatest && targetFramework == Constants.DotnetLtsLatest)
@@ -204,7 +204,7 @@ private IEnumerable<string> GetDockerTags(DockerImage dockerImage,
204204
$"{name}:latest",
205205
$"{name}:latest-{targetFramework}",
206206
$"{name}:latest-{distro}",
207-
$"{name}:latest-{distro}-{targetFramework}",
207+
$"{name}:latest-{distro}-{targetFramework}"
208208
]);
209209
}
210210
}

build/common/Utilities/Extensions.cs

Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
using System.Buffers;
2+
13
namespace Common.Utilities;
24

35
#pragma warning disable S1144
46
public static class Extensions
57
{
6-
private static readonly char[] CharsThatRequireQuoting = [' ', '"'];
7-
private static readonly char[] CharsThatRequireEscaping = ['\\', '"'];
8+
private static readonly SearchValues<char> CharsRequiringQuoting = SearchValues.Create(' ', '"');
9+
private static readonly SearchValues<char> CharsRequiringEscaping = SearchValues.Create('\\', '"');
810

911
extension(Assembly assembly)
1012
{
@@ -63,57 +65,68 @@ public static DirectoryPath GetRootDirectory()
6365
public string ToSuffix() => arch.ToString().ToLower();
6466
}
6567

66-
extension(string literalValue)
68+
extension(string value)
69+
{
70+
public bool IsNullOrWhiteSpace() =>
71+
string.IsNullOrWhiteSpace(value);
72+
73+
public bool IsEqualInvariant(string other) =>
74+
string.Equals(value, other, StringComparison.InvariantCulture);
75+
}
76+
77+
/// <summary>
78+
/// Escapes arbitrary values so that the process receives the exact string you intend and injection is impossible.
79+
/// Spec: https://msdn.microsoft.com/en-us/library/bb776391.aspx
80+
/// </summary>
81+
public static string EscapeProcessArgument(this string literalValue, bool alwaysQuote = false)
6782
{
68-
/// <summary>
69-
/// Escapes arbitrary values so that the process receives the exact string you intend and injection is impossible.
70-
/// Spec: https://msdn.microsoft.com/en-us/library/bb776391.aspx
71-
/// </summary>
72-
public string EscapeProcessArgument(bool alwaysQuote = false)
83+
if (string.IsNullOrEmpty(literalValue)) return "\"\"";
84+
85+
if (literalValue.AsSpan().IndexOfAny(CharsRequiringQuoting) == -1) // Happy path
7386
{
74-
if (string.IsNullOrEmpty(literalValue)) return "\"\"";
87+
if (!alwaysQuote) return literalValue;
88+
if (literalValue[^1] != '\\') return $"\"{literalValue}\"";
89+
}
7590

76-
if (literalValue.IndexOfAny(CharsThatRequireQuoting) == -1) // Happy path
77-
{
78-
if (!alwaysQuote) return literalValue;
79-
if (literalValue[^1] != '\\') return "\"" + literalValue + "\"";
80-
}
91+
return BuildEscapedArgument(literalValue);
92+
}
93+
94+
private static string BuildEscapedArgument(string s)
95+
{
96+
var sb = new StringBuilder(s.Length + 8).Append('"');
97+
var nextPosition = 0;
8198

82-
var sb = new StringBuilder(literalValue.Length + 8).Append('"');
99+
while (true)
100+
{
101+
var relativeIndex = s.AsSpan(nextPosition).IndexOfAny(CharsRequiringEscaping);
102+
if (relativeIndex == -1) break;
83103

84-
var nextPosition = 0;
85-
while (true)
86-
{
87-
var nextEscapeChar = literalValue.IndexOfAny(CharsThatRequireEscaping, nextPosition);
88-
if (nextEscapeChar == -1) break;
89-
90-
sb.Append(literalValue, nextPosition, nextEscapeChar - nextPosition);
91-
nextPosition = nextEscapeChar + 1;
92-
93-
switch (literalValue[nextEscapeChar])
94-
{
95-
case '"':
96-
sb.Append("\\\"");
97-
break;
98-
case '\\':
99-
var numBackslashes = 1;
100-
while (nextPosition < literalValue.Length && literalValue[nextPosition] == '\\')
101-
{
102-
numBackslashes++;
103-
nextPosition++;
104-
}
105-
if (nextPosition == literalValue.Length || literalValue[nextPosition] == '"')
106-
numBackslashes <<= 1;
107-
108-
for (; numBackslashes != 0; numBackslashes--)
109-
sb.Append('\\');
110-
break;
111-
}
112-
}
104+
var nextEscapeChar = nextPosition + relativeIndex;
105+
sb.Append(s, nextPosition, relativeIndex);
106+
nextPosition = nextEscapeChar + 1;
113107

114-
sb.Append(literalValue, nextPosition, literalValue.Length - nextPosition).Append('"');
115-
return sb.ToString();
108+
if (s[nextEscapeChar] == '"')
109+
sb.Append("\\\"");
110+
else
111+
nextPosition = AppendEscapedBackslashes(sb, s, nextPosition);
116112
}
113+
114+
return sb.Append(s, nextPosition, s.Length - nextPosition).Append('"').ToString();
115+
}
116+
117+
private static int AppendEscapedBackslashes(StringBuilder sb, string s, int nextPosition)
118+
{
119+
var numBackslashes = 1;
120+
while (nextPosition < s.Length && s[nextPosition] == '\\')
121+
{
122+
numBackslashes++;
123+
nextPosition++;
124+
}
125+
if (nextPosition == s.Length || s[nextPosition] == '"')
126+
numBackslashes <<= 1;
127+
128+
sb.Append('\\', numBackslashes);
129+
return nextPosition;
117130
}
118131
}
119132
#pragma warning restore S1144

build/docker/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
ARG REGISTRY='docker.io'
22
ARG DISTRO='debian.12'
33
ARG DOTNET_VERSION='8.0'
4-
ARG VERSION='6.4.0'
4+
ARG VERSION='6.7.0'
55

6-
FROM $REGISTRY/gittools/build-images:$DISTRO-sdk-$DOTNET_VERSION as installer
6+
FROM $REGISTRY/gittools/build-images:$DISTRO-sdk-$DOTNET_VERSION AS installer
77
ARG nugetFolder
88
ARG VERSION
99

10-
WORKDIR /nuget
10+
WORKDIR /tmp/nuget
1111
COPY $nugetFolder/ ./
1212
RUN dotnet tool install GitVersion.Tool --version $VERSION --tool-path /tmp/tools --add-source .
1313

0 commit comments

Comments
 (0)