Skip to content

Commit

Permalink
Fix Asp.Net Core folder search (#137)
Browse files Browse the repository at this point in the history
Support for lookup of Asp.Net Core shared folder without exact version number match
  • Loading branch information
ebjornset authored Nov 10, 2024
1 parent fb9420c commit 52cecf5
Show file tree
Hide file tree
Showing 19 changed files with 170 additions and 44 deletions.
39 changes: 23 additions & 16 deletions build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,15 @@ public partial class Build : NukeBuild
.Produces(UnitTestsResultsDirectory)
.Executes(() =>
{
DotNetTest(c => c
.SetConfiguration(Configuration)
.EnableNoBuild()
.SetDataCollector("XPlat Code Coverage;Format=opencover")
.CombineWith(SourceDirectory.GlobFiles("**/*.UTests.csproj"), (settings, path) =>
settings.SetProjectFile(path)), degreeOfParallelism: 4, completeOnFailure: true);
foreach (var dotNetVersion in DotNetVersions) {
DotNetTest(c => c
.SetConfiguration(Configuration)
.SetFramework(dotNetVersion)
.EnableNoBuild()
.SetDataCollector("XPlat Code Coverage;Format=opencover")
.CombineWith(SourceDirectory.GlobFiles("**/*.UTests.csproj"), (settings, path) =>
settings.SetProjectFile(path)), degreeOfParallelism: 4, completeOnFailure: true);
}
});

internal Target Pack => _ => _
Expand Down Expand Up @@ -200,16 +203,19 @@ public partial class Build : NukeBuild
.SetConfigFile(Path.Combine(Path.Combine(workingDirectory, "Properties"), "NuGet.Config"))
);
// Run the ITests in "dotnet tool" mode
DotNetTest(c => c
.SetConfiguration(Configuration)
.EnableNoBuild()
.SetDataCollector("XPlat Code Coverage;Format=opencover")
.CombineWith(SourceDirectory.GlobFiles("**/*.ITests.csproj"), (settings, path) =>
settings
.SetProjectFile(path)
.SetProcessEnvironmentVariable("DryGen.ITests.ToolInvocationSteps.RunAsTool", "some value")
.SetProcessEnvironmentVariable("DryGen.ITests.ToolInvocationSteps.WorkingDirectory", workingDirectory))
, degreeOfParallelism: 4, completeOnFailure: true);
foreach (var dotNetVersion in DotNetVersions) {
DotNetTest(c => c
.SetConfiguration(Configuration)
.SetFramework(dotNetVersion)
.EnableNoBuild()
.SetDataCollector("XPlat Code Coverage;Format=opencover")
.CombineWith(SourceDirectory.GlobFiles("**/*.ITests.csproj"), (settings, path) =>
settings
.SetProjectFile(path)
.SetProcessEnvironmentVariable("DryGen.ITests.ToolInvocationSteps.RunAsTool", "some value")
.SetProcessEnvironmentVariable("DryGen.ITests.ToolInvocationSteps.WorkingDirectory", workingDirectory))
, degreeOfParallelism: 4, completeOnFailure: true);
}
});

internal Target GenerateDocs => _ => _
Expand Down Expand Up @@ -445,4 +451,5 @@ private static void LogChangesAndFailIfGitWorkingCopyIsNotClean()
private const string PwshVersion = "7.4.5";
private const string DocfxPackageName = "docfx";
private const string DocfxVersion = "2.77.0";
private readonly string[] DotNetVersions = ["net8.0", "net9.0"];
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
> [!IMPORTANT]
> In v 2.x .Net 6 and .Net 7 will no longer be supported, since they're no longer supported by Microsoft.
### Improvements in this version
## Prerelease 2
## Improvements in this version
### Prerelease 3
- Fixed an issue where the lookup of the Asp.Net Core shared folder failed if the version number for .Net and Asp.Net Core was not exactly the same.
- E.g. for .Net 9 RC 2 where the Asp.Net Core version number was 9.0.0-rc.2.24474.3, but the .Net version number was 9.0.0-rc.2.24473.5
### Prerelease 2
- Added support for .Net 9
- Added support for generating many to many associations in `mermaid-class-diagram-from-csharp`.
- Added support for generating many to many relations in `mermaid-er-diagram-from-csharp`.
- Added support for `include-exception-stacktrace` in `verbs-from-options-file`.
## Prerelease 1 (2024-10-29)
### Prerelease 1 (2024-10-29)
- Fixed an issue where `mermaid-er-diagram-from-efcore` would fail when an input assebly referenced Asp.Net Core.
- Ie the .csproj file contained `<Project Sdk="Microsoft.NET.Sdk.Web">` or `<FrameworkReference Include="Microsoft.AspNetCore.App|All">` or referenced such an assembly.
- Ie the .csproj file contained `<Project Sdk="Microsoft.NET.Sdk.Web">` or `<FrameworkReference Include="Microsoft.AspNetCore.App|All"/>` or referenced such an assembly.
- Added support for generating many to many relations in `mermaid-er-diagram-from-efcore`.
- Switched to [docfx](https://dotnet.github.io/docfx/) for generating the documentation.
- docfx uses .Net, so Ruby is no longer needed in the development toolchain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,7 @@ private static void RemoveSynteticSchemaProperty(JsonSchema jsonSchema)
{
// Hack to get rid of the syntetic $schema property we must use if we want additionalProperties = false in the topmost object
const string schemaPropertyName = "$schema";
if (jsonSchema.Properties.ContainsKey(schemaPropertyName))
{
jsonSchema.Properties.Remove(schemaPropertyName);
}
jsonSchema.Properties.Remove(schemaPropertyName);
}

private static async Task<JsonSchema> LoadJsonSchemaFromFile(string? jsonSchemaFileName, JsonSchemaFileFormat jsonSchemaFileFormat)
Expand Down
8 changes: 4 additions & 4 deletions src/DryGen.CodeCompiler/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static Assembly CompileCodeToMemory(this string csharpCode, params Assemb
using var ms = new MemoryStream();
csharpCode.CompileCodeToStream(assemblyName, ms, referencedAssemblies);
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
var assembly = Assembly.Load(ms.ToArray());
return assembly;
}

Expand Down Expand Up @@ -55,12 +55,12 @@ public static void CompileCodeToStream(this string csharpCode, string assemblyNa
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
EmitResult compilationResult = compilation.Emit(stream);
ThrowExceptionIfCompilationFailed(compilationResult);
var compilationResult = compilation.Emit(stream);
compilationResult.ThrowExceptionIfCompilationFailed();
}

[ExcludeFromCodeCoverage] //This should in theory never happen in a normal test run, only when we develop new tests that compiles C# code
private static void ThrowExceptionIfCompilationFailed(EmitResult compilationResult)
private static void ThrowExceptionIfCompilationFailed(this EmitResult compilationResult)
{
if (!compilationResult.Success)
{
Expand Down
6 changes: 6 additions & 0 deletions src/DryGen.Core/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,10 @@ public static T AsNonNull<T>(this T? value) where T : class
ArgumentNullException.ThrowIfNull(value);
return value;
}

public static string AsLinuxPath(this string path)
{
return path.Replace("\\", "/");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private static ClassDiagramClass[] ConvertExtensionMethodsToInstanceMethodsOnKno
return classDiagramClasses.Except(removedExtensionClasses).ToArray();
}

private static void GenerateClassAssociationsCompositionsAndAggregations(IDictionary<Type, ClassDiagramClass> classLookup, ClassDiagramClass classDiagramClass)
private static void GenerateClassAssociationsCompositionsAndAggregations(Dictionary<Type, ClassDiagramClass> classLookup, ClassDiagramClass classDiagramClass)
{
foreach (var property in classDiagramClass.Type.GetProperties(
BindingFlags.Instance |
Expand Down Expand Up @@ -179,7 +179,7 @@ private static void GenerateClassInheritanceOrRealizationForInterfaces(Dictionar
}
}

private static void GenerateClassInheritanceForBaseType(IDictionary<Type, ClassDiagramClass> classLookup, ClassDiagramClass classDiagramClass)
private static void GenerateClassInheritanceForBaseType(Dictionary<Type, ClassDiagramClass> classLookup, ClassDiagramClass classDiagramClass)
{
if (classDiagramClass.Type.IsInterface)
{
Expand Down
43 changes: 43 additions & 0 deletions src/DryGen/AspNetCoreSharedFolderResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.IO;
using System.Linq;
using DryGen.Core;

namespace DryGen;

public class AspNetCoreSharedFolderResolver(string dotNetRuntimeDirectory)
{
public string DotNetRuntimeDirectory => dotNetRuntimeDirectory.AsLinuxPath().TrimEnd('/');

public AspNetCoreSharedFolderResolver() : this(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory())
{
}

public string? Resolve()
{
var result = DotNetRuntimeDirectory.Replace("Microsoft.NETCore.App", "Microsoft.AspNetCore.App");
if (Directory.Exists(result))
{
return result.AsLinuxPath();
}
var dotNetRuntimeVersion = new DirectoryInfo(result).Name;
var baseAspNetDirectory = new DirectoryInfo(result[..result.LastIndexOf('/')]).AsNonNull();
var bestCandidate = baseAspNetDirectory.GetDirectories().Where(x => IsCandidate(x.Name, dotNetRuntimeVersion)).OrderByDescending(x => x.Name).FirstOrDefault();
return bestCandidate?.FullName.AsLinuxPath();
}

private static bool IsCandidate(string aspNetCoreVersion, string dotNetRuntimeVersion)
{
var dotNetRuntimeVersionParts = dotNetRuntimeVersion.Split(".").AsNonNull();
var aspNetCoreVersionParts = aspNetCoreVersion.Split(".").AsNonNull();
for (var i = 0; i < dotNetRuntimeVersionParts.Length; i++)
{
if (i >= aspNetCoreVersionParts.Length) {
continue;
}
if (aspNetCoreVersionParts[i] == dotNetRuntimeVersionParts[i]) {
return true;
}
}
return false;
}
}
2 changes: 1 addition & 1 deletion src/DryGen/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ private Assembly LoadAsseblyFromFile(string? inputFile)
{
throw new OptionsException("Input file must be specified as the option -i/--input-file on the command line, or as input-file in the option file.");
}
return new InternalAssemblyLoadContext(inputFile, useAssemblyLoadContextDefault).Load();
return new InternalAssemblyLoadContext(inputFile, useAssemblyLoadContextDefault, new AspNetCoreSharedFolderResolver()).Load();
}

private static TreeShakingDiagramFilter GetMermaidDiagramTreeShakingFilter(IEnumerable<string>? treeShakingRoots)
Expand Down
12 changes: 6 additions & 6 deletions src/DryGen/InternalAssemblyLoadContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ internal class InternalAssemblyLoadContext : AssemblyLoadContext

private AssemblyLoadContext AssemblyLoadContext => useAssemblyLoadContextDefault ? Default : this;

internal InternalAssemblyLoadContext(string inputFile, bool useAssemblyLoadContextDefault)
internal InternalAssemblyLoadContext(string inputFile, bool useAssemblyLoadContextDefault, AspNetCoreSharedFolderResolver aspNetCoreSharedFolderResolver)
{
this.inputFile = inputFile;
this.useAssemblyLoadContextDefault = useAssemblyLoadContextDefault;
var inputDirectory = Path.GetDirectoryName(inputFile) ?? throw new OptionsException($"Could not determine directory from inputFile '{inputFile}'");
var runtimeDirectory = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
var aspNetCoreDirectoryApp = runtimeDirectory.Replace("Microsoft.NETCore.App", "Microsoft.AspNetCore.App");
var aspNetCoreDirectoryAll = runtimeDirectory.Replace("Microsoft.NETCore.App", "Microsoft.AspNetCore.All");
searchDirectories = new[] { inputDirectory, aspNetCoreDirectoryApp, aspNetCoreDirectoryAll, runtimeDirectory };
var aspNetCoreDirectoryApp = aspNetCoreSharedFolderResolver.Resolve();
searchDirectories = string.IsNullOrEmpty(aspNetCoreDirectoryApp)
? [inputDirectory, aspNetCoreSharedFolderResolver.DotNetRuntimeDirectory]
: [inputDirectory, aspNetCoreDirectoryApp, aspNetCoreSharedFolderResolver.DotNetRuntimeDirectory];
}

internal Assembly Load()
Expand All @@ -35,7 +35,7 @@ internal Assembly Load()
{
foreach (var extension in new[] { ".dll", ".exe" })
{
foreach(var loadDirectory in searchDirectories)
foreach (var loadDirectory in searchDirectories)
{
var assemblyFileName = $"{loadDirectory}{Path.DirectorySeparatorChar}{assemblyName.Name}{extension}";
if (File.Exists(assemblyFileName))
Expand Down
1 change: 1 addition & 0 deletions src/develop/DryGen.Docs/ExamplesFileGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using DryGen.Core;

namespace DryGen.Docs;

Expand Down
6 changes: 1 addition & 5 deletions src/develop/DryGen.Docs/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Globalization;
using System.IO;
using System.Linq;
using DryGen.Core;

namespace DryGen.Docs;

Expand Down Expand Up @@ -68,11 +69,6 @@ public static string AsGeneratedVerbsDirectoryCreated(this string rootDirectory)
return Path.Combine(rootDirectory.AsGeneratedDirectory(), "verbs").AsLinuxPath().CreateDirectories();
}

public static string AsLinuxPath(this string path)
{
return path.Replace("\\", "/");
}

public static string AsRelativePathOf(this string directory, string rootDirectory)
{
return Path.GetRelativePath(rootDirectory, directory).AsLinuxPath();
Expand Down
1 change: 1 addition & 0 deletions src/develop/DryGen.Docs/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CommandLine;
using DryGen.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
Expand Down
1 change: 1 addition & 0 deletions src/develop/DryGen.Docs/ReleaseNotesFileGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using DryGen.Core;

namespace DryGen.Docs;

Expand Down
2 changes: 1 addition & 1 deletion src/develop/DryGen.ITests/DryGen.ITests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Packable>false</Packable>
</PropertyGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/develop/DryGen.UTests/DryGen.UTests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Packable>false</Packable>
</PropertyGroup>

Expand Down
20 changes: 20 additions & 0 deletions src/develop/DryGen.UTests/Features/DotNetSharedFolders.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Feature: .Net shared folders
To be able to use dry-gen with assemblies located in the .Net shared folders
As a dry-gen user
I should get the Asp.Net Core shared folder name resolved by the .Net shared folder

Scenario: Resolve Asp.Net Core shared folders from .Net version
Given the base .Net shared folder is 'Microsoft.NETCore.App'
Given these .Net shared folder paths
| Base folder | Sub folder |
| Microsoft.NETCore.App | <.Net version> |
| Microsoft.AspNetCore.App | <Asp.Net Core version 1> |
| Microsoft.AspNetCore.App | <Asp.Net Core version 2> |
When I resolve the Asp.Net Core shared folder with .Net version '<.Net version>'
Then I should get the folder Asp.Net Core shared folder 'Microsoft.AspNetCore.App/<Asp.Net Core version found>'

Examples:
| .Net version | Asp.Net Core version 1 | Asp.Net Core version 2 | Asp.Net Core version found |
| 8.0.10 | 6.0.30 | 8.0.10 | 8.0.10 |
| 9.0.0-rc.2.24473.5 | 8.0.10 | 9.0.0-rc.2.24474.3 | 9.0.0-rc.2.24474.3 |
| 9.0.0-rc.2.24473.5/ | 8.0.10 | 9.0.0-rc.2.24474.3 | 9.0.0-rc.2.24474.3 |
49 changes: 49 additions & 0 deletions src/develop/DryGen.UTests/Steps/DotNetSharedFoldersSteps.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.IO;
using DryGen.Core;
using DryGen.DevUtils.Helpers;
using FluentAssertions;
using Reqnroll;

namespace DryGen.UTests.Steps;

[Binding]
public sealed class DotNetSharedFoldersSteps
{
private readonly RootDirectoryContext rootDirectoryContext;
private string? aspNetSharedFolder;
private string? dotNetSharedFolder;

public DotNetSharedFoldersSteps(RootDirectoryContext rootDirectoryContext)
{
this.rootDirectoryContext = rootDirectoryContext;
}

[Given(@"the base .Net shared folder is '([^']*)'")]
public void GivenTheBaseDotNetShareFolderIs(string dotNetSharedFolder)
{
this.dotNetSharedFolder = dotNetSharedFolder;
}

[Given(@"these .Net shared folder paths")]
public void GivenTheseDotNetSharedFolders(Table table)
{
table.Header.Count.Should().Be(2);
foreach(var row in table.Rows) {
rootDirectoryContext.BuldSubDirectory(rootDirectory => Path.Combine(rootDirectory, Path.Combine(row[0], row[1])));
}
}

[When(@"I resolve the Asp.Net Core shared folder with .Net version '([^']*)'")]
public void WhenIResolveTheAspDotNetCoreSharedFolderWithDotNetVersion(string dotNetVersion)
{
var dotNetRuntimeDirectory = Path.Combine(rootDirectoryContext.RootDirectory, Path.Combine(dotNetSharedFolder.AsNonNull(), dotNetVersion));
aspNetSharedFolder = new AspNetCoreSharedFolderResolver(dotNetRuntimeDirectory).Resolve();
}

[Then(@"I should get the folder Asp.Net Core shared folder '([^']*)'")]
public void ThenIShouldGetTheFolderAspDotNetCoreSharedFolder(string expected)
{
expected = expected.AsLinuxPath();
aspNetSharedFolder.Should().EndWith(expected);
}
}
1 change: 1 addition & 0 deletions src/develop/DryGen.UTests/Steps/ExamplesSteps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO;
using Reqnroll;
using DryGen.DevUtils.Helpers;
using DryGen.Core;

namespace DryGen.UTests.Steps;

Expand Down
1 change: 1 addition & 0 deletions src/develop/DryGen.UTests/Steps/ReleaseNotesSteps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Reqnroll;
using DryGen.DevUtils.Helpers;
using FluentAssertions;
using DryGen.Core;

namespace DryGen.UTests.Steps;

Expand Down

0 comments on commit 52cecf5

Please sign in to comment.