Skip to content

Commit

Permalink
Support loading repositories from files embedded in GirTool
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreeve committed Jul 5, 2024
1 parent 85416e1 commit afebae3
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 20 deletions.
31 changes: 31 additions & 0 deletions src/Generation/GirLoader/Helper/ChainedRepositoryResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Linq;

namespace GirLoader;

/// <summary>
/// Tries multiple repository resolvers, returning the first result found
/// </summary>
public class ChainedRepositoryResolver : IRepositoryResolver
{
private readonly IRepositoryResolver[] _resolvers;

public ChainedRepositoryResolver(IEnumerable<IRepositoryResolver> resolvers)
{
_resolvers = resolvers.ToArray();
}

public Input.Repository? ResolveRepository(string fileName)
{
foreach (var resolver in _resolvers)
{
var repository = resolver.ResolveRepository(fileName);
if (repository != null)
{
return repository;
}
}

return null;
}
}
25 changes: 25 additions & 0 deletions src/Generation/GirLoader/Helper/DirectoryRepositoryResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.IO;

namespace GirLoader;

/// <summary>
/// Resolves repository files from a local directory
/// </summary>
public class DirectoryRepositoryResolver : IRepositoryResolver
{
private readonly string _inputDirectory;

public DirectoryRepositoryResolver(string inputDirectory)
{
_inputDirectory = inputDirectory ?? throw new ArgumentNullException(nameof(inputDirectory));
}

public Input.Repository? ResolveRepository(string fileName)
{
var path = Path.Combine(_inputDirectory, fileName);
return File.Exists(path)
? new FileInfo(path).OpenRead().DeserializeGirInputModel()
: null;
}
}
33 changes: 33 additions & 0 deletions src/Generation/GirLoader/Helper/EmbeddedRepositoryResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.IO;
using System.Reflection;

namespace GirLoader;

public class EmbeddedRepositoryResolver : IRepositoryResolver
{
private readonly Assembly _assembly;
private readonly string _platformName;
private readonly string _assemblyName;

public EmbeddedRepositoryResolver(Assembly assembly, string platformName)
{
_assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
_platformName = platformName ?? throw new ArgumentNullException(nameof(platformName));
_assemblyName = _assembly.GetName().Name ?? throw new Exception("Could not get assembly name");
}

public Input.Repository? ResolveRepository(string fileName)
{
var resourceName = $"{_assemblyName}.{_platformName}.{fileName}";
try
{
using var stream = _assembly.GetManifestResourceStream(resourceName);
return stream?.DeserializeGirInputModel();
}
catch (FileNotFoundException)
{
return null;
}
}
}
9 changes: 9 additions & 0 deletions src/Generation/GirLoader/Helper/IRepositoryResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace GirLoader;

/// <summary>
/// Resolves input repository definitions from GIR file names
/// </summary>
public interface IRepositoryResolver
{
Input.Repository? ResolveRepository(string fileName);
}
15 changes: 5 additions & 10 deletions src/Generation/GirLoader/Helper/IncludeResolver.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
using System.IO;

namespace GirLoader;
namespace GirLoader;

public class IncludeResolver
{
private readonly string _inputDirectory;
private readonly IRepositoryResolver _repositoryResolver;

public IncludeResolver(string inputDirectory)
public IncludeResolver(IRepositoryResolver repositoryResolver)
{
_inputDirectory = inputDirectory;
_repositoryResolver = repositoryResolver;
}

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

var path = Path.Combine(_inputDirectory, fileName);
return File.Exists(path)
? new FileInfo(path).OpenRead().DeserializeGirInputModel()
: null;
return _repositoryResolver.ResolveRepository(fileName);
}
}
36 changes: 26 additions & 10 deletions src/Generation/GirTool/GenerateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ private static (DeserializedInput, DeserializedInput, DeserializedInput) LoadRep
DeserializedInput? macosRepositories = null;
DeserializedInput? windowsRepositories = null;

void SetLinuxRepositories() => linuxRepositories = DeserializeInput(searchPathLinux, input);
void SetMacosRepositories() => macosRepositories = DeserializeInput(searchPathMacos, input);
void SetWindowsRepositories() => windowsRepositories = DeserializeInput(searchPathWindows, input);
void SetLinuxRepositories() => linuxRepositories = DeserializeInput("linux", searchPathLinux, input);
void SetMacosRepositories() => macosRepositories = DeserializeInput("macos", searchPathMacos, input);
void SetWindowsRepositories() => windowsRepositories = DeserializeInput("windows", searchPathWindows, input);

if (disableAsync)
{
Expand All @@ -137,15 +137,14 @@ private static (DeserializedInput, DeserializedInput, DeserializedInput) LoadRep
return (linuxRepositories!, macosRepositories!, windowsRepositories!);
}

private static DeserializedInput DeserializeInput(string? searchPath, string[] input)
private static DeserializedInput DeserializeInput(string platformName, string? searchPath, string[] input)
{
if (searchPath is null)
return DeserializedInput.Empty();
var repositoryResolver = GetRepositoryResolver(platformName, searchPath);

var inputRepositories = input
.Select(x => Path.Join(searchPath, x))
.Where(File.Exists)
.Select(x => new FileInfo(x).OpenRead().DeserializeGirInputModel())
.Select(fileName => repositoryResolver.ResolveRepository(fileName))
.Where(inputRepository => inputRepository != null)
.Select(inputRepository => inputRepository!)
.ToList();

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

var includeResolver = new IncludeResolver(searchPath);
var includeResolver = new IncludeResolver(repositoryResolver);
var loader = new GirLoader.Loader(includeResolver.ResolveInclude);
var outputRepositories = loader.Load(inputRepositories).ToList();

return new DeserializedInput(outputRepositories, inputNamespaces);
}

private static IRepositoryResolver GetRepositoryResolver(string platformName, string? searchPath)
{
var assembly = typeof(GenerateCommand).Assembly;
var embeddedResolver = new EmbeddedRepositoryResolver(assembly, platformName);

if (searchPath == null)
{
return embeddedResolver;
}
else
{
var directoryResolver = new DirectoryRepositoryResolver(searchPath);
return new ChainedRepositoryResolver(
new IRepositoryResolver[] {directoryResolver, embeddedResolver});
}
}

private static string GetNamespaceName(GirModel.Namespace ns)
{
return $"{ns.Name}-{ns.Version}";
Expand Down
4 changes: 4 additions & 0 deletions src/Generation/GirTool/GirTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@
<ProjectReference Include="../Generator/Generator.csproj" />
<ProjectReference Include="../GirLoader/GirLoader.csproj" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="..\..\..\ext\gir-files\*\*.gir" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Collections.Generic;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace GirLoader.Test;

[TestClass, TestCategory("UnitTest")]
public class ChainedRepositoryResolverTests
{
[TestMethod]
public void ReturnsNullWhenNoRepositoryFound()
{
var resolver = new ChainedRepositoryResolver(new[]
{
new StubRepositoryResolver(new Dictionary<string, Input.Repository>())
});

var repository = resolver.ResolveRepository("GObject-2.0.gir");

repository.Should().BeNull();
}

[TestMethod]
public void ReturnsFirstResolvedRepositoryWhenMultipleMatch()
{
var resolver = new ChainedRepositoryResolver(new[]
{
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
{
{"GObject-2.0.gir", Helper.GetInputRepository("GObject", "2.1")},
}),
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
{
{"GObject-2.0.gir", Helper.GetInputRepository("GObject", "2.2")},
}),
});

var repository = resolver.ResolveRepository("GObject-2.0.gir");

repository.Should().NotBeNull();
repository!.Namespace.Should().NotBeNull();
repository.Namespace!.Version.Should().Be("2.1");
}

[TestMethod]
public void ReturnsRepositoryFromFallbackResolver()
{
var resolver = new ChainedRepositoryResolver(new[]
{
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
{
{"TestLibrary-1.0.gir", Helper.GetInputRepository("TestLibrary", "1.0")},
}),
new StubRepositoryResolver(new Dictionary<string, Input.Repository>
{
{"GObject-2.0.gir", Helper.GetInputRepository("GObject", "2.0")},
}),
});

var repository = resolver.ResolveRepository("GObject-2.0.gir");

repository.Should().NotBeNull();
repository!.Namespace.Should().NotBeNull();
repository.Namespace!.Name.Should().Be("GObject");
}

private class StubRepositoryResolver : IRepositoryResolver
{
private readonly IReadOnlyDictionary<string, Input.Repository> _repositories;

public StubRepositoryResolver(IReadOnlyDictionary<string, Input.Repository> repositories)
{
_repositories = repositories;
}

public Input.Repository? ResolveRepository(string fileName)
{
return _repositories.GetValueOrDefault(fileName);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.IO;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace GirLoader.Test;

[TestClass, TestCategory("UnitTest")]
public class DirectoryRepositoryResolverTests
{
[TestMethod]
public void CanLoadRepositoryFromDirectory()
{
using var directory = new DisposableTempDirectory();
var filePath = Path.Join(directory.DirectoryPath, "GObject-2.0.gir");
File.WriteAllText(filePath, Helper.GetInputRepositoryXml("GObject", "2.0"));

var resolver = new DirectoryRepositoryResolver(directory.DirectoryPath);

var repository = resolver.ResolveRepository("GObject-2.0.gir");

repository.Should().NotBeNull();
repository!.Namespace.Should().NotBeNull();
repository.Namespace!.Name.Should().Be("GObject");
}

[TestMethod]
public void ReturnsNullWhenFileNotFound()
{
using var directory = new DisposableTempDirectory();
var resolver = new DirectoryRepositoryResolver(directory.DirectoryPath);

var repository = resolver.ResolveRepository("GObject-2.0.gir");

repository.Should().BeNull();
}
}
22 changes: 22 additions & 0 deletions src/Tests/Generation/GirLoader.Tests/DisposableTempDirectory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.IO;

namespace GirLoader.Test;

public class DisposableTempDirectory : IDisposable
{
private readonly string _directoryPath;

public DisposableTempDirectory()
{
_directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(_directoryPath);
}

public string DirectoryPath => _directoryPath;

public void Dispose()
{
Directory.Delete(_directoryPath, recursive: true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace GirLoader.Test;

[TestClass, TestCategory("UnitTest")]
public class EmbeddedRepositoryResolverTests
{
[TestMethod]
public void CanLoadRepositoryFromEmbeddedResource()
{
var resolver = new EmbeddedRepositoryResolver(
typeof(EmbeddedRepositoryResolverTests).Assembly, "linux");

var repository = resolver.ResolveRepository("GObject-2.0.gir");

repository.Should().NotBeNull();
repository!.Namespace.Should().NotBeNull();
repository.Namespace!.Name.Should().Be("GObject");
}

[TestMethod]
public void ReturnsNullWhenEmbeddedResourceNotFound()
{
var resolver = new EmbeddedRepositoryResolver(
typeof(EmbeddedRepositoryResolverTests).Assembly, "linux");

var repository = resolver.ResolveRepository("TestLibrary-1.0.gir");

repository.Should().BeNull();
}
}
4 changes: 4 additions & 0 deletions src/Tests/Generation/GirLoader.Tests/GirLoader.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
<ItemGroup>
<ProjectReference Include="..\..\..\Generation\GirLoader\GirLoader.csproj" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="..\..\..\..\ext\gir-files\linux\GObject-2.0.gir" LogicalName="GirLoader.Tests.linux.GObject-2.0.gir" />
</ItemGroup>
</Project>
Loading

0 comments on commit afebae3

Please sign in to comment.