Skip to content

Commit 4cca352

Browse files
committed
Use cached Regex
1 parent cb9481a commit 4cca352

File tree

21 files changed

+522
-285
lines changed

21 files changed

+522
-285
lines changed

src/GitVersion.BuildAgents/Agents/AzurePipelines.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System.Text.RegularExpressions;
21
using GitVersion.Extensions;
32
using GitVersion.Logging;
43
using GitVersion.OutputVariables;
@@ -52,7 +51,7 @@ private static string ReplaceVariables(string buildNumberEnv, KeyValuePair<strin
5251
return replacement switch
5352
{
5453
null => buildNumberEnv,
55-
_ => buildNumberEnv.RegexReplace(pattern, replacement, RegexOptions.IgnoreCase)
54+
_ => buildNumberEnv.RegexReplace(pattern, replacement)
5655
};
5756
}
5857
}

src/GitVersion.Configuration/GitVersionConfiguration.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ internal sealed record GitVersionConfiguration : BranchConfiguration, IGitVersio
5050
public string? VersionInBranchPattern { get; internal set; }
5151

5252
[JsonIgnore]
53-
public Regex VersionInBranchRegex => versionInBranchRegex ??= new(GetVersionInBranchPattern(), RegexOptions.Compiled);
53+
public Regex VersionInBranchRegex
54+
=> versionInBranchRegex ??= RegexPatterns.Cache.GetOrAdd(GetVersionInBranchPattern());
5455
private Regex? versionInBranchRegex;
5556

5657
private string GetVersionInBranchPattern()
@@ -103,9 +104,7 @@ public string? NextVersion
103104
[JsonPropertyName("commit-date-format")]
104105
[JsonPropertyDescription($"The format to use when calculating the commit date. Defaults to '{DefaultCommitDateFormat}'. See [Standard Date and Time Format Strings](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings) and [Custom Date and Time Format Strings](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings).")]
105106
[JsonPropertyDefault(DefaultCommitDateFormat)]
106-
#if NET7_0_OR_GREATER
107-
[System.Diagnostics.CodeAnalysis.StringSyntax("DateTimeFormat")] // See https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.stringsyntaxattribute, https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.stringsyntaxattribute.datetimeformat?view=net-7.0#system-diagnostics-codeanalysis-stringsyntaxattribute-datetimeformat
108-
#endif
107+
[System.Diagnostics.CodeAnalysis.StringSyntax("DateTimeFormat")]
109108
public string? CommitDateFormat { get; internal set; }
110109

111110
[JsonPropertyName("merge-message-formats")]

src/GitVersion.Core/Configuration/EffectiveConfiguration.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,10 @@ public EffectiveConfiguration(IGitVersionConfiguration configuration, IBranchCon
9090
public string? AssemblyVersioningFormat { get; }
9191
public string? AssemblyFileVersioningFormat { get; }
9292

93-
/// <summary>
94-
/// Git tag prefix
95-
/// </summary>
9693
public string? TagPrefix { get; }
9794

9895
public Regex VersionInBranchRegex { get; }
9996

100-
/// <summary>
101-
/// Label to use when calculating SemVer
102-
/// </summary>
10397
public string? Label { get; }
10498

10599
public string? NextVersion { get; }

src/GitVersion.Core/Configuration/IBranchConfiguration.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Text.RegularExpressions;
1+
using GitVersion.Core;
2+
using GitVersion.Extensions;
23
using GitVersion.VersionCalculation;
34

45
namespace GitVersion.Configuration;
@@ -24,7 +25,15 @@ public interface IBranchConfiguration
2425
public string? RegularExpression { get; }
2526

2627
public bool IsMatch(string branchName)
27-
=> RegularExpression != null && Regex.IsMatch(branchName, RegularExpression, RegexOptions.IgnoreCase);
28+
{
29+
if (string.IsNullOrWhiteSpace(RegularExpression))
30+
{
31+
return false;
32+
}
33+
34+
var regex = RegexPatterns.Cache.GetOrAdd(RegularExpression);
35+
return regex.IsMatch(branchName);
36+
}
2837

2938
IReadOnlyCollection<string> SourceBranches { get; }
3039

src/GitVersion.Core/Core/MainlineBranchFinder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using System.Text.RegularExpressions;
21
using GitVersion.Common;
32
using GitVersion.Configuration;
3+
using GitVersion.Core;
44
using GitVersion.Extensions;
55
using GitVersion.Git;
66
using GitVersion.Logging;
@@ -47,10 +47,10 @@ public bool IsMainBranch(IBranchConfiguration value)
4747
if (value.RegularExpression == null)
4848
return false;
4949

50-
var mainlineRegex = value.RegularExpression;
50+
var regex = RegexPatterns.Cache.GetOrAdd(value.RegularExpression);
5151
var branchName = this.branch.Name.WithoutOrigin;
52-
var match = Regex.IsMatch(branchName, mainlineRegex);
53-
this.log.Info($"'{mainlineRegex}' {(match ? "matches" : "does not match")} '{branchName}'.");
52+
var match = regex.IsMatch(branchName);
53+
this.log.Info($"'{value.RegularExpression}' {(match ? "matches" : "does not match")} '{branchName}'.");
5454
return match;
5555
}
5656
}

src/GitVersion.Core/Core/RegexPatterns.cs

Lines changed: 162 additions & 41 deletions
Large diffs are not rendered by default.

src/GitVersion.Core/Core/SourceBranchFinder.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Text.RegularExpressions;
22
using GitVersion.Configuration;
3+
using GitVersion.Core;
34
using GitVersion.Extensions;
45
using GitVersion.Git;
56

@@ -18,7 +19,7 @@ public IEnumerable<IBranch> FindSourceBranchesOf(IBranch branch)
1819

1920
private class SourceBranchPredicate(IBranch branch, IGitVersionConfiguration configuration)
2021
{
21-
private readonly IEnumerable<string> sourceBranchRegexes = GetSourceBranchRegexes(branch, configuration);
22+
private readonly IEnumerable<Regex> sourceBranchRegexes = GetSourceBranchRegexes(branch, configuration);
2223

2324
public bool IsSourceBranch(INamedReference sourceBranchCandidate)
2425
{
@@ -27,15 +28,15 @@ public bool IsSourceBranch(INamedReference sourceBranchCandidate)
2728

2829
var branchName = sourceBranchCandidate.Name.WithoutOrigin;
2930

30-
return this.sourceBranchRegexes.Any(regex => Regex.IsMatch(branchName, regex));
31+
return this.sourceBranchRegexes.Any(regex => regex.IsMatch(branchName));
3132
}
3233

33-
private static IEnumerable<string> GetSourceBranchRegexes(INamedReference branch, IGitVersionConfiguration configuration)
34+
private static IEnumerable<Regex> GetSourceBranchRegexes(INamedReference branch, IGitVersionConfiguration configuration)
3435
{
3536
var currentBranchConfig = configuration.GetBranchConfiguration(branch.Name);
3637
if (currentBranchConfig.SourceBranches == null)
3738
{
38-
yield return ".*";
39+
yield return RegexPatterns.Cache.GetOrAdd(".*");
3940
}
4041
else
4142
{
@@ -44,7 +45,7 @@ private static IEnumerable<string> GetSourceBranchRegexes(INamedReference branch
4445
{
4546
var regex = branches[sourceBranch].RegularExpression;
4647
if (regex != null)
47-
yield return regex;
48+
yield return RegexPatterns.Cache.GetOrAdd(regex);
4849
}
4950
}
5051
}

src/GitVersion.Core/Extensions/ConfigurationExtensions.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Text.RegularExpressions;
1+
using GitVersion.Core;
22
using GitVersion.Extensions;
33
using GitVersion.Git;
44
using GitVersion.Helpers;
@@ -94,12 +94,12 @@ public static bool IsReleaseBranch(this IGitVersionConfiguration configuration,
9494
if (!configuration.RegularExpression.IsNullOrWhiteSpace() && !effectiveBranchName.IsNullOrEmpty())
9595
{
9696
effectiveBranchName = effectiveBranchName.RegexReplace("[^a-zA-Z0-9-_]", "-");
97-
var pattern = new Regex(configuration.RegularExpression, RegexOptions.IgnoreCase);
98-
var match = pattern.Match(effectiveBranchName);
97+
var regex = RegexPatterns.Cache.GetOrAdd(configuration.RegularExpression);
98+
var match = regex.Match(effectiveBranchName);
9999
if (match.Success)
100100
{
101101
// ReSharper disable once LoopCanBeConvertedToQuery
102-
foreach (var groupName in pattern.GetGroupNames())
102+
foreach (var groupName in regex.GetGroupNames())
103103
{
104104
label = label.Replace("{" + groupName + "}", match.Groups[groupName].Value);
105105
}
@@ -111,7 +111,8 @@ public static bool IsReleaseBranch(this IGitVersionConfiguration configuration,
111111
// Evaluate tag number pattern and append to prerelease tag, preserving build metadata
112112
if (!configuration.LabelNumberPattern.IsNullOrEmpty() && !effectiveBranchName.IsNullOrEmpty())
113113
{
114-
var match = Regex.Match(effectiveBranchName, configuration.LabelNumberPattern);
114+
var regex = RegexPatterns.Cache.GetOrAdd(configuration.LabelNumberPattern);
115+
var match = regex.Match(effectiveBranchName);
115116
var numberGroup = match.Groups["number"];
116117
if (numberGroup.Success)
117118
{
Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1+
using System.Collections.Concurrent;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Text.RegularExpressions;
4+
15
namespace GitVersion.Extensions;
26

37
public static class DictionaryExtensions
48
{
5-
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, Func<TValue> getValue)
9+
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TValue> getValue) where TKey : notnull
610
{
7-
if (dict is null) throw new ArgumentNullException(nameof(dict));
8-
if (getValue is null) throw new ArgumentNullException(nameof(getValue));
11+
ArgumentNullException.ThrowIfNull(dict);
12+
ArgumentNullException.ThrowIfNull(getValue);
913

10-
if (!dict.TryGetValue(key, out var value))
11-
{
12-
value = getValue();
13-
dict.Add(key, value);
14-
}
14+
if (dict.TryGetValue(key, out var value)) return value;
15+
value = getValue();
16+
dict.Add(key, value);
1517
return value;
1618
}
19+
20+
public static Regex GetOrAdd(this ConcurrentDictionary<string, Regex> dict, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern)
21+
{
22+
ArgumentNullException.ThrowIfNull(dict);
23+
ArgumentNullException.ThrowIfNull(pattern);
24+
25+
return dict.GetOrAdd(pattern, regex => new(regex, RegexOptions.IgnoreCase | RegexOptions.Compiled));
26+
}
1727
}

src/GitVersion.Core/Extensions/StringExtensions.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.Diagnostics.CodeAnalysis;
2-
using System.Text.RegularExpressions;
2+
using GitVersion.Core;
33

44
namespace GitVersion.Extensions;
55

@@ -11,7 +11,11 @@ public static void AppendLineFormat(this StringBuilder stringBuilder, string for
1111
stringBuilder.AppendLine();
1212
}
1313

14-
public static string RegexReplace(this string input, string pattern, string replace, RegexOptions options = RegexOptions.None) => Regex.Replace(input, pattern, replace, options);
14+
public static string RegexReplace(this string input, string pattern, string replace)
15+
{
16+
var regex = RegexPatterns.Cache.GetOrAdd(pattern);
17+
return regex.Replace(input, replace);
18+
}
1519

1620
public static bool IsEquivalentTo(this string self, string? other) =>
1721
string.Equals(self, other, StringComparison.OrdinalIgnoreCase);

0 commit comments

Comments
 (0)