Skip to content

Commit 881c473

Browse files
committed
Support loading repositories from files embedded in GirTool
1 parent 85416e1 commit 881c473

13 files changed

+325
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace GirLoader;
5+
6+
/// <summary>
7+
/// Tries multiple repository resolvers, returning the first result found
8+
/// </summary>
9+
public class ChainedRepositoryResolver : IRepositoryResolver
10+
{
11+
private readonly IRepositoryResolver[] _resolvers;
12+
13+
public ChainedRepositoryResolver(IEnumerable<IRepositoryResolver> resolvers)
14+
{
15+
_resolvers = resolvers.ToArray();
16+
}
17+
18+
public Input.Repository? ResolveRepository(string fileName)
19+
{
20+
foreach (var resolver in _resolvers)
21+
{
22+
var repository = resolver.ResolveRepository(fileName);
23+
if (repository != null)
24+
{
25+
return repository;
26+
}
27+
}
28+
29+
return null;
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace GirLoader;
5+
6+
/// <summary>
7+
/// Resolves repository files from a local directory
8+
/// </summary>
9+
public class DirectoryRepositoryResolver : IRepositoryResolver
10+
{
11+
private readonly string _inputDirectory;
12+
13+
public DirectoryRepositoryResolver(string inputDirectory)
14+
{
15+
_inputDirectory = inputDirectory ?? throw new ArgumentNullException(nameof(inputDirectory));
16+
}
17+
18+
public Input.Repository? ResolveRepository(string fileName)
19+
{
20+
var path = Path.Combine(_inputDirectory, fileName);
21+
if (File.Exists(path))
22+
{
23+
using var fileStream = new FileInfo(path).OpenRead();
24+
return fileStream.DeserializeGirInputModel();
25+
}
26+
else
27+
{
28+
return null;
29+
}
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.IO;
3+
using System.Reflection;
4+
5+
namespace GirLoader;
6+
7+
public class EmbeddedRepositoryResolver : IRepositoryResolver
8+
{
9+
private readonly Assembly _assembly;
10+
private readonly string _platformName;
11+
private readonly string _assemblyName;
12+
13+
public EmbeddedRepositoryResolver(Assembly assembly, string platformName)
14+
{
15+
_assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
16+
_platformName = platformName ?? throw new ArgumentNullException(nameof(platformName));
17+
_assemblyName = _assembly.GetName().Name ?? throw new Exception("Could not get assembly name");
18+
}
19+
20+
public Input.Repository? ResolveRepository(string fileName)
21+
{
22+
var resourceName = $"{_assemblyName}.{_platformName}.{fileName}";
23+
try
24+
{
25+
using var stream = _assembly.GetManifestResourceStream(resourceName);
26+
return stream?.DeserializeGirInputModel();
27+
}
28+
catch (FileNotFoundException)
29+
{
30+
return null;
31+
}
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace GirLoader;
2+
3+
/// <summary>
4+
/// Resolves input repository definitions from GIR file names
5+
/// </summary>
6+
public interface IRepositoryResolver
7+
{
8+
Input.Repository? ResolveRepository(string fileName);
9+
}
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
1-
using System.IO;
2-
3-
namespace GirLoader;
1+
namespace GirLoader;
42

53
public class IncludeResolver
64
{
7-
private readonly string _inputDirectory;
5+
private readonly IRepositoryResolver _repositoryResolver;
86

9-
public IncludeResolver(string inputDirectory)
7+
public IncludeResolver(IRepositoryResolver repositoryResolver)
108
{
11-
_inputDirectory = inputDirectory;
9+
_repositoryResolver = repositoryResolver;
1210
}
1311

1412
public Input.Repository? ResolveInclude(Output.Include include)
1513
{
1614
var fileName = $"{include.Name}-{include.Version}.gir";
1715

18-
var path = Path.Combine(_inputDirectory, fileName);
19-
return File.Exists(path)
20-
? new FileInfo(path).OpenRead().DeserializeGirInputModel()
21-
: null;
16+
return _repositoryResolver.ResolveRepository(fileName);
2217
}
2318
}

src/Generation/GirTool/GenerateCommand.cs

+26-10
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ private static (DeserializedInput, DeserializedInput, DeserializedInput) LoadRep
115115
DeserializedInput? macosRepositories = null;
116116
DeserializedInput? windowsRepositories = null;
117117

118-
void SetLinuxRepositories() => linuxRepositories = DeserializeInput(searchPathLinux, input);
119-
void SetMacosRepositories() => macosRepositories = DeserializeInput(searchPathMacos, input);
120-
void SetWindowsRepositories() => windowsRepositories = DeserializeInput(searchPathWindows, input);
118+
void SetLinuxRepositories() => linuxRepositories = DeserializeInput("linux", searchPathLinux, input);
119+
void SetMacosRepositories() => macosRepositories = DeserializeInput("macos", searchPathMacos, input);
120+
void SetWindowsRepositories() => windowsRepositories = DeserializeInput("windows", searchPathWindows, input);
121121

122122
if (disableAsync)
123123
{
@@ -137,15 +137,14 @@ private static (DeserializedInput, DeserializedInput, DeserializedInput) LoadRep
137137
return (linuxRepositories!, macosRepositories!, windowsRepositories!);
138138
}
139139

140-
private static DeserializedInput DeserializeInput(string? searchPath, string[] input)
140+
private static DeserializedInput DeserializeInput(string platformName, string? searchPath, string[] input)
141141
{
142-
if (searchPath is null)
143-
return DeserializedInput.Empty();
142+
var repositoryResolver = GetRepositoryResolver(platformName, searchPath);
144143

145144
var inputRepositories = input
146-
.Select(x => Path.Join(searchPath, x))
147-
.Where(File.Exists)
148-
.Select(x => new FileInfo(x).OpenRead().DeserializeGirInputModel())
145+
.Select(fileName => repositoryResolver.ResolveRepository(fileName))
146+
.Where(inputRepository => inputRepository != null)
147+
.Select(inputRepository => inputRepository!)
149148
.ToList();
150149

151150
// Get the namespaces corresponding to the input gir files.
@@ -154,13 +153,30 @@ private static DeserializedInput DeserializeInput(string? searchPath, string[] i
154153
.Select(repository => repository.Namespace == null ? "" : GetNamespaceName(repository.Namespace))
155154
.ToList();
156155

157-
var includeResolver = new IncludeResolver(searchPath);
156+
var includeResolver = new IncludeResolver(repositoryResolver);
158157
var loader = new GirLoader.Loader(includeResolver.ResolveInclude);
159158
var outputRepositories = loader.Load(inputRepositories).ToList();
160159

161160
return new DeserializedInput(outputRepositories, inputNamespaces);
162161
}
163162

163+
private static IRepositoryResolver GetRepositoryResolver(string platformName, string? searchPath)
164+
{
165+
var assembly = typeof(GenerateCommand).Assembly;
166+
var embeddedResolver = new EmbeddedRepositoryResolver(assembly, platformName);
167+
168+
if (searchPath == null)
169+
{
170+
return embeddedResolver;
171+
}
172+
else
173+
{
174+
var directoryResolver = new DirectoryRepositoryResolver(searchPath);
175+
return new ChainedRepositoryResolver(
176+
new IRepositoryResolver[] { directoryResolver, embeddedResolver });
177+
}
178+
}
179+
164180
private static string GetNamespaceName(GirModel.Namespace ns)
165181
{
166182
return $"{ns.Name}-{ns.Version}";

src/Generation/GirTool/GirTool.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@
99
<ProjectReference Include="../Generator/Generator.csproj" />
1010
<ProjectReference Include="../GirLoader/GirLoader.csproj" />
1111
</ItemGroup>
12+
13+
<ItemGroup>
14+
<EmbeddedResource Include="..\..\..\ext\gir-files\*\*.gir" />
15+
</ItemGroup>
1216
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System.Collections.Generic;
2+
using FluentAssertions;
3+
using Microsoft.VisualStudio.TestTools.UnitTesting;
4+
5+
namespace GirLoader.Test;
6+
7+
[TestClass, TestCategory("UnitTest")]
8+
public class ChainedRepositoryResolverTests
9+
{
10+
[TestMethod]
11+
public void ReturnsNullWhenNoRepositoryFound()
12+
{
13+
var resolver = new ChainedRepositoryResolver(new[]
14+
{
15+
new StubRepositoryResolver(new Dictionary<string, Input.Repository>())
16+
});
17+
18+
var repository = resolver.ResolveRepository("GObject-2.0.gir");
19+
20+
repository.Should().BeNull();
21+
}
22+
23+
[TestMethod]
24+
public void ReturnsFirstResolvedRepositoryWhenMultipleMatch()
25+
{
26+
var resolver = new ChainedRepositoryResolver(new[]
27+
{
28+
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
29+
{
30+
{"GObject-2.0.gir", Helper.GetInputRepository("GObject", "2.1")},
31+
}),
32+
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
33+
{
34+
{"GObject-2.0.gir", Helper.GetInputRepository("GObject", "2.2")},
35+
}),
36+
});
37+
38+
var repository = resolver.ResolveRepository("GObject-2.0.gir");
39+
40+
repository.Should().NotBeNull();
41+
repository!.Namespace.Should().NotBeNull();
42+
repository.Namespace!.Version.Should().Be("2.1");
43+
}
44+
45+
[TestMethod]
46+
public void ReturnsRepositoryFromFallbackResolver()
47+
{
48+
var resolver = new ChainedRepositoryResolver(new[]
49+
{
50+
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
51+
{
52+
{"TestLibrary-1.0.gir", Helper.GetInputRepository("TestLibrary", "1.0")},
53+
}),
54+
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
55+
{
56+
{"GObject-2.0.gir", Helper.GetInputRepository("GObject", "2.0")},
57+
}),
58+
});
59+
60+
var repository = resolver.ResolveRepository("GObject-2.0.gir");
61+
62+
repository.Should().NotBeNull();
63+
repository!.Namespace.Should().NotBeNull();
64+
repository.Namespace!.Name.Should().Be("GObject");
65+
}
66+
67+
private class StubRepositoryResolver : IRepositoryResolver
68+
{
69+
private readonly IReadOnlyDictionary<string, Input.Repository> _repositories;
70+
71+
public StubRepositoryResolver(IReadOnlyDictionary<string, Input.Repository> repositories)
72+
{
73+
_repositories = repositories;
74+
}
75+
76+
public Input.Repository? ResolveRepository(string fileName)
77+
{
78+
return _repositories.GetValueOrDefault(fileName);
79+
}
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.IO;
2+
using FluentAssertions;
3+
using Microsoft.VisualStudio.TestTools.UnitTesting;
4+
5+
namespace GirLoader.Test;
6+
7+
[TestClass, TestCategory("UnitTest")]
8+
public class DirectoryRepositoryResolverTests
9+
{
10+
[TestMethod]
11+
public void CanLoadRepositoryFromDirectory()
12+
{
13+
using var directory = new DisposableTempDirectory();
14+
var filePath = Path.Join(directory.DirectoryPath, "GObject-2.0.gir");
15+
File.WriteAllText(filePath, Helper.GetInputRepositoryXml("GObject", "2.0"));
16+
17+
var resolver = new DirectoryRepositoryResolver(directory.DirectoryPath);
18+
19+
var repository = resolver.ResolveRepository("GObject-2.0.gir");
20+
21+
repository.Should().NotBeNull();
22+
repository!.Namespace.Should().NotBeNull();
23+
repository.Namespace!.Name.Should().Be("GObject");
24+
}
25+
26+
[TestMethod]
27+
public void ReturnsNullWhenFileNotFound()
28+
{
29+
using var directory = new DisposableTempDirectory();
30+
var resolver = new DirectoryRepositoryResolver(directory.DirectoryPath);
31+
32+
var repository = resolver.ResolveRepository("GObject-2.0.gir");
33+
34+
repository.Should().BeNull();
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace GirLoader.Test;
5+
6+
public class DisposableTempDirectory : IDisposable
7+
{
8+
private readonly string _directoryPath;
9+
10+
public DisposableTempDirectory()
11+
{
12+
_directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
13+
Directory.CreateDirectory(_directoryPath);
14+
}
15+
16+
public string DirectoryPath => _directoryPath;
17+
18+
public void Dispose()
19+
{
20+
Directory.Delete(_directoryPath, recursive: true);
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using FluentAssertions;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
4+
namespace GirLoader.Test;
5+
6+
[TestClass, TestCategory("UnitTest")]
7+
public class EmbeddedRepositoryResolverTests
8+
{
9+
[TestMethod]
10+
public void CanLoadRepositoryFromEmbeddedResource()
11+
{
12+
var resolver = new EmbeddedRepositoryResolver(
13+
typeof(EmbeddedRepositoryResolverTests).Assembly, "linux");
14+
15+
var repository = resolver.ResolveRepository("GObject-2.0.gir");
16+
17+
repository.Should().NotBeNull();
18+
repository!.Namespace.Should().NotBeNull();
19+
repository.Namespace!.Name.Should().Be("GObject");
20+
}
21+
22+
[TestMethod]
23+
public void ReturnsNullWhenEmbeddedResourceNotFound()
24+
{
25+
var resolver = new EmbeddedRepositoryResolver(
26+
typeof(EmbeddedRepositoryResolverTests).Assembly, "linux");
27+
28+
var repository = resolver.ResolveRepository("TestLibrary-1.0.gir");
29+
30+
repository.Should().BeNull();
31+
}
32+
}

src/Tests/Generation/GirLoader.Tests/GirLoader.Tests.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@
55
<ItemGroup>
66
<ProjectReference Include="..\..\..\Generation\GirLoader\GirLoader.csproj" />
77
</ItemGroup>
8+
9+
<ItemGroup>
10+
<EmbeddedResource Include="..\..\..\..\ext\gir-files\linux\GObject-2.0.gir" LogicalName="GirLoader.Tests.linux.GObject-2.0.gir" />
11+
</ItemGroup>
812
</Project>

0 commit comments

Comments
 (0)