Skip to content

Commit ad6f152

Browse files
committed
Refactor globbing resolution to support IFileSystem abstraction
Reorganized globbing-related logic into the FileSystemGlobbing namespace. Introduced IFileSystem integration in GlobbingResolver and new wrapper classes for directory and file handling. Simplified service configuration using GitVersionAppModule.
1 parent 937dc2e commit ad6f152

12 files changed

+245
-26
lines changed

new-cli/GitVersion.Common/GitVersion.Common.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<ItemGroup>
33
<PackageReference Include="Polly" />
4+
<PackageReference Include="System.IO.Abstractions" />
45
</ItemGroup>
56
<ItemGroup>
67
<Compile Include="..\..\src\GitVersion.Core\Core\Abstractions\IEnvironment.cs" Link="Infrastructure\%(Filename)%(Extension)" />

src/GitVersion.App.Tests/ArgumentParserOnBuildServerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using GitVersion.Agents;
22
using GitVersion.Core.Tests.Helpers;
3+
using GitVersion.Extensions;
34
using GitVersion.OutputVariables;
45
using Microsoft.Extensions.DependencyInjection;
56

@@ -15,8 +16,7 @@ public void SetUp()
1516
{
1617
var sp = ConfigureServices(services =>
1718
{
18-
services.AddSingleton<IArgumentParser, ArgumentParser>();
19-
services.AddSingleton<IGlobbingResolver, GlobbingResolver>();
19+
services.AddModule(new GitVersionAppModule());
2020
services.AddSingleton<ICurrentBuildAgent, MockBuildAgent>();
2121
});
2222
this.argumentParser = sp.GetRequiredService<IArgumentParser>();

src/GitVersion.App.Tests/ArgumentParserTests.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.IO.Abstractions;
22
using GitVersion.Configuration;
33
using GitVersion.Core.Tests.Helpers;
4+
using GitVersion.Extensions;
45
using GitVersion.Helpers;
56
using GitVersion.Logging;
67
using GitVersion.VersionCalculation;
@@ -18,11 +19,7 @@ public class ArgumentParserTests : TestBase
1819
[SetUp]
1920
public void SetUp()
2021
{
21-
var sp = ConfigureServices(services =>
22-
{
23-
services.AddSingleton<IArgumentParser, ArgumentParser>();
24-
services.AddSingleton<IGlobbingResolver, GlobbingResolver>();
25-
});
22+
var sp = ConfigureServices(services => services.AddModule(new GitVersionAppModule()));
2623
this.environment = sp.GetRequiredService<IEnvironment>();
2724
this.argumentParser = sp.GetRequiredService<IArgumentParser>();
2825
this.fileSystem = sp.GetRequiredService<IFileSystem>();

src/GitVersion.App/ArgumentParser.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.IO.Abstractions;
22
using GitVersion.Agents;
33
using GitVersion.Extensions;
4+
using GitVersion.FileSystemGlobbing;
45
using GitVersion.Helpers;
56
using GitVersion.Logging;
67
using GitVersion.OutputVariables;
@@ -152,11 +153,9 @@ private IEnumerable<string> ResolveFiles(string workingDirectory, ISet<string>?
152153

153154
foreach (var file in assemblyInfoFiles)
154155
{
155-
var paths = this.globbingResolver.Resolve(workingDirectory, file);
156-
157-
foreach (var path in paths)
156+
foreach (var path in this.globbingResolver.Resolve(workingDirectory, file))
158157
{
159-
yield return FileSystemHelper.Path.GetFullPath(FileSystemHelper.Path.Combine(workingDirectory, path));
158+
yield return path;
160159
}
161160
}
162161
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System.IO.Abstractions;
2+
3+
namespace GitVersion.FileSystemGlobbing;
4+
5+
internal sealed class DirectoryInfoGlobbingWrapper
6+
: Microsoft.Extensions.FileSystemGlobbing.Abstractions.DirectoryInfoBase
7+
{
8+
private readonly IFileSystem fileSystem;
9+
private readonly IDirectoryInfo directoryInfo;
10+
private readonly bool isParentPath;
11+
12+
public DirectoryInfoGlobbingWrapper(IFileSystem fileSystem, IDirectoryInfo directoryInfo)
13+
: this(fileSystem, directoryInfo, isParentPath: false)
14+
{
15+
}
16+
17+
private DirectoryInfoGlobbingWrapper(
18+
IFileSystem fileSystem,
19+
IDirectoryInfo directoryInfo,
20+
bool isParentPath
21+
)
22+
{
23+
this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
24+
this.directoryInfo = directoryInfo ?? throw new ArgumentNullException(nameof(directoryInfo));
25+
this.isParentPath = isParentPath;
26+
}
27+
28+
public override string Name => this.isParentPath ? ".." : this.directoryInfo.Name;
29+
30+
public override string FullName => this.directoryInfo.FullName;
31+
32+
public override Microsoft.Extensions.FileSystemGlobbing.Abstractions.DirectoryInfoBase? ParentDirectory =>
33+
this.directoryInfo.Parent is null
34+
? null
35+
: new DirectoryInfoGlobbingWrapper(this.fileSystem, this.directoryInfo.Parent);
36+
37+
public override IEnumerable<Microsoft.Extensions.FileSystemGlobbing.Abstractions.FileSystemInfoBase> EnumerateFileSystemInfos()
38+
{
39+
if (this.directoryInfo.Exists)
40+
{
41+
IEnumerable<IFileSystemInfo> fileSystemInfos;
42+
try
43+
{
44+
fileSystemInfos = this.directoryInfo.EnumerateFileSystemInfos(
45+
"*",
46+
SearchOption.TopDirectoryOnly
47+
);
48+
}
49+
catch (DirectoryNotFoundException)
50+
{
51+
yield break;
52+
}
53+
54+
foreach (var fileSystemInfo in fileSystemInfos)
55+
{
56+
yield return fileSystemInfo switch
57+
{
58+
IDirectoryInfo info => new DirectoryInfoGlobbingWrapper(this.fileSystem, info),
59+
IFileInfo info => new FileInfoGlobbingWrapper(this.fileSystem, info),
60+
_ => new FileSystemInfoGlobbingWrapper(this.fileSystem, fileSystemInfo),
61+
};
62+
}
63+
}
64+
}
65+
66+
public override Microsoft.Extensions.FileSystemGlobbing.Abstractions.DirectoryInfoBase? GetDirectory(string path)
67+
{
68+
var parentPath = string.Equals(path, "..", StringComparison.Ordinal);
69+
70+
if (parentPath)
71+
{
72+
return new DirectoryInfoGlobbingWrapper(
73+
this.fileSystem,
74+
this.fileSystem.DirectoryInfo.New(this.fileSystem.Path.Combine(this.directoryInfo.FullName, path)),
75+
parentPath
76+
);
77+
}
78+
79+
var dirs = this.directoryInfo.GetDirectories(path);
80+
81+
return dirs switch
82+
{
83+
{ Length: 1 } => new DirectoryInfoGlobbingWrapper(this.fileSystem, dirs[0], parentPath),
84+
{ Length: 0 } => null,
85+
_ => throw new InvalidOperationException($"More than one sub directories are found under {this.directoryInfo.FullName} with name {path}."),
86+
};
87+
}
88+
89+
public override Microsoft.Extensions.FileSystemGlobbing.Abstractions.FileInfoBase GetFile(string path)
90+
=> new FileInfoGlobbingWrapper(
91+
this.fileSystem,
92+
this.fileSystem.FileInfo.New(this.fileSystem.Path.Combine(FullName, path))
93+
);
94+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.IO.Abstractions;
2+
using GitVersion.Extensions;
3+
4+
namespace GitVersion.FileSystemGlobbing;
5+
6+
/// <summary>
7+
/// Initialize a new instance
8+
/// </summary>
9+
/// <param name="fileSystem">The filesystem</param>
10+
/// <param name="fileInfo">The file</param>
11+
internal sealed class FileInfoGlobbingWrapper(IFileSystem fileSystem, IFileInfo fileInfo)
12+
: Microsoft.Extensions.FileSystemGlobbing.Abstractions.FileInfoBase
13+
{
14+
private readonly IFileSystem fileSystem = fileSystem.NotNull();
15+
private readonly IFileInfo fileInfo = fileInfo.NotNull();
16+
17+
/// <inheritdoc />
18+
public override string Name => this.fileInfo.Name;
19+
20+
/// <inheritdoc />
21+
public override string FullName => this.fileInfo.FullName;
22+
23+
/// <inheritdoc />
24+
public override Microsoft.Extensions.FileSystemGlobbing.Abstractions.DirectoryInfoBase? ParentDirectory =>
25+
this.fileInfo.Directory is null
26+
? null
27+
: new DirectoryInfoGlobbingWrapper(this.fileSystem, this.fileInfo.Directory);
28+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.IO.Abstractions;
2+
using GitVersion.Extensions;
3+
4+
namespace GitVersion.FileSystemGlobbing;
5+
6+
internal sealed class FileSystemInfoGlobbingWrapper(IFileSystem fileSystem, IFileSystemInfo fileSystemInfo) : Microsoft.Extensions.FileSystemGlobbing.Abstractions.FileSystemInfoBase
7+
{
8+
private readonly IFileSystem fileSystem = fileSystem.NotNull();
9+
private readonly IFileSystemInfo fileSystemInfo = fileSystemInfo.NotNull();
10+
11+
public override string Name => this.fileSystemInfo.Name;
12+
13+
public override string FullName => this.fileSystemInfo.FullName;
14+
15+
public override Microsoft.Extensions.FileSystemGlobbing.Abstractions.DirectoryInfoBase ParentDirectory =>
16+
new DirectoryInfoGlobbingWrapper(
17+
this.fileSystem,
18+
this.fileSystem.DirectoryInfo.New(this.fileSystemInfo.FullName)
19+
);
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.IO.Abstractions;
2+
using GitVersion.Extensions;
3+
using Microsoft.Extensions.FileSystemGlobbing;
4+
5+
namespace GitVersion.FileSystemGlobbing;
6+
7+
internal class GlobbingResolver(IFileSystem fileSystem) : IGlobbingResolver
8+
{
9+
private readonly IFileSystem fileSystem = fileSystem.NotNull();
10+
11+
public IEnumerable<string> Resolve(string workingDirectory, string pattern)
12+
{
13+
var matcher = new Matcher(StringComparison.OrdinalIgnoreCase);
14+
matcher.AddInclude(pattern);
15+
return matcher.GetResultsInFullPath(this.fileSystem, workingDirectory);
16+
}
17+
}

src/GitVersion.App/IGlobbingResolver.cs renamed to src/GitVersion.App/FileSystemGlobbing/IGlobbingResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace GitVersion;
1+
namespace GitVersion.FileSystemGlobbing;
22

33
internal interface IGlobbingResolver
44
{
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System.IO.Abstractions;
2+
using Microsoft.Extensions.FileSystemGlobbing;
3+
4+
namespace GitVersion.FileSystemGlobbing;
5+
6+
internal static class MatcherExtensions
7+
{
8+
public static PatternMatchingResult Execute(
9+
this Matcher matcher,
10+
IFileSystem fileSystem,
11+
string directoryPath
12+
)
13+
{
14+
ArgumentNullException.ThrowIfNull(matcher);
15+
ArgumentNullException.ThrowIfNull(fileSystem);
16+
17+
return Execute(matcher, fileSystem, fileSystem.DirectoryInfo.New(directoryPath));
18+
}
19+
20+
private static PatternMatchingResult Execute(
21+
this Matcher matcher,
22+
IFileSystem fileSystem,
23+
IDirectoryInfo directoryInfo
24+
)
25+
{
26+
ArgumentNullException.ThrowIfNull(matcher);
27+
ArgumentNullException.ThrowIfNull(fileSystem);
28+
ArgumentNullException.ThrowIfNull(directoryInfo);
29+
30+
return matcher.Execute(new DirectoryInfoGlobbingWrapper(fileSystem, directoryInfo));
31+
}
32+
33+
public static IEnumerable<string> GetResultsInFullPath(
34+
this Matcher matcher,
35+
IFileSystem fileSystem,
36+
string directoryPath
37+
)
38+
{
39+
ArgumentNullException.ThrowIfNull(matcher);
40+
ArgumentNullException.ThrowIfNull(fileSystem);
41+
42+
return GetResultsInFullPath(
43+
matcher,
44+
fileSystem,
45+
fileSystem.DirectoryInfo.New(directoryPath)
46+
);
47+
}
48+
49+
private static IEnumerable<string> GetResultsInFullPath(
50+
this Matcher matcher,
51+
IFileSystem fileSystem,
52+
IDirectoryInfo directoryInfo
53+
)
54+
{
55+
ArgumentNullException.ThrowIfNull(matcher);
56+
ArgumentNullException.ThrowIfNull(fileSystem);
57+
ArgumentNullException.ThrowIfNull(directoryInfo);
58+
59+
var matches = Execute(matcher, fileSystem, directoryInfo);
60+
61+
if (!matches.HasMatches)
62+
{
63+
return EmptyStringsEnumerable;
64+
}
65+
66+
var fsPath = fileSystem.Path;
67+
var directoryFullName = directoryInfo.FullName;
68+
69+
return matches.Files.Select(GetFullPath);
70+
71+
string GetFullPath(FilePatternMatch match) =>
72+
fsPath.GetFullPath(fsPath.Combine(directoryFullName, match.Path));
73+
}
74+
75+
private static readonly IEnumerable<string> EmptyStringsEnumerable = [];
76+
}

0 commit comments

Comments
 (0)