Skip to content

Commit

Permalink
Jump through some hoops in order not to package NuGet dlls inside Chisel
Browse files Browse the repository at this point in the history
  • Loading branch information
0xced committed Mar 25, 2024
1 parent 5b00b20 commit e55dde6
Showing 1 changed file with 109 additions and 42 deletions.
151 changes: 109 additions & 42 deletions src/Chisel/SdkAssemblyResolver.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,125 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Chisel;

/// <summary>
/// Resolves assemblies by looking in the latest installed dotnet SDK directory.
/// Resolves assemblies by looking in the right place.
/// So that there's no need to package <c>NuGet.ProjectModel.dll</c>, <c>NuGet.LibraryModel.dll</c> and <c>NuGet.Versioning.dll</c> inside Chisel.
/// </summary>
/// <remarks>
/// To understand when this is required, go to Rider settings -> Build, Execution, Deployment -> Toolset and Build then choose
/// <c>C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe</c> instead of the auto detected <c>C:\Program Files\dotnet\sdk\8.0.200\MSBuild.dll</c>
/// </remarks>
internal static class SdkAssemblyResolver
{
public static Assembly? ResolveAssembly(object sender, ResolveEventArgs args)
{
var dotnet = "dotnet";
var log = DebugLog;

try
{
if (sender is ValueTuple<string, Action<string>> tuple)
{
dotnet = tuple.Item1;
log = tuple.Item2;
}

var assemblyName = new AssemblyName(args.Name);
var assemblyFileName = $"{assemblyName.Name}.dll";
log($"ResolveAssembly({assemblyName})");

var directories = GetNuGetDirectories(sender as AppDomain, assemblyFileName, dotnet, log);
foreach (var directory in directories)
{
var assemblyFile = new FileInfo(Path.Combine(directory, assemblyFileName));
if (assemblyFile.Exists)
{
log($"Loading {assemblyFile.FullName}");
try
{
var assembly = Assembly.LoadFile(assemblyFile.FullName);
log($"Loaded {assembly}");
return assembly;
}
catch (Exception exception)
{
log($"Failed to load {assemblyFile.FullName}: {exception}");
}
}

log($"Assembly {assemblyFile.FullName} not found");
}

return null;
}
catch (Exception exception)
{
log($"Unexpected exception: {exception}");
return null;
}
}

private static IEnumerable<string> GetNuGetDirectories(AppDomain? appDomain, string assemblyFileName, string dotnet, Action<string> log)
{
var nugetDirectories = new HashSet<string>();

var loadedAssemblies = appDomain?.GetAssemblies().Where(e => e.GetName().Name.StartsWith("NuGet.")).ToList() ?? [];
foreach (var (assembly, i) in loadedAssemblies.Select((e, i) => (e, i + 1)))
{
log($"Loaded NuGet assembly ({i}/{loadedAssemblies.Count}): {assembly} @ {assembly.Location}");
}

var loadedDirectories = loadedAssemblies.Select(e => Path.GetDirectoryName(e.Location)).Distinct().ToList();
foreach (var (directory, i) in loadedDirectories.Select((e, i) => (e, i + 1)))
{
nugetDirectories.Add(directory);
log($"Loaded NuGet directory ({i}/{loadedDirectories.Count}): {directory}");
}

if (nugetDirectories.Count > 0)
{
return nugetDirectories;
}

var dotnetSdkDirectory = GetDotnetSdkDirectory(dotnet, log);
if (dotnetSdkDirectory?.Exists == true)
{
var toolsDirectory = Path.Combine(dotnetSdkDirectory.FullName, "Sdks", "Microsoft.NET.Sdk", "tools");
if (Directory.Exists(toolsDirectory))
{
log($"Searching for {assemblyFileName} in {toolsDirectory} (recursively)");
foreach (var assemblyFilePath in Directory.EnumerateFiles(toolsDirectory, assemblyFileName, SearchOption.AllDirectories))
{
var nugetDirectory = Path.GetDirectoryName(assemblyFilePath);
nugetDirectories.Add(nugetDirectory);
}
}
else
{
log($"{toolsDirectory} not found");
}
}

foreach (var (directory, i) in nugetDirectories.Select((e, i) => (e, i + 1)))
{
log($"NuGet directory ({i}/{nugetDirectories.Count}): {directory}");
}

if (nugetDirectories.Count == 0)
{
log("NuGet directory not found");
}

return nugetDirectories;
}

private static readonly Regex SdkRegex = new(@"(.*) \[(.*)\]", RegexOptions.Compiled);

private static DirectoryInfo? GetDotnetSdkDirectory(string dotnet, Action<string> log)
Expand Down Expand Up @@ -51,47 +159,6 @@ internal static class SdkAssemblyResolver
return dotnetSdkDirectory;
}

public static Assembly? ResolveAssembly(object sender, ResolveEventArgs args)
{
var dotnet = "dotnet";
var log = DebugLog;

try
{
if (sender is ValueTuple<string, Action<string>> tuple)
{
dotnet = tuple.Item1;
log = tuple.Item2;
}

var dotnetSdkDirectory = GetDotnetSdkDirectory(dotnet, log);
if (dotnetSdkDirectory is not { Exists: true })
{
return null;
}

var assemblyName = new AssemblyName(args.Name);
log($"ResolveAssembly({assemblyName})");

var assemblyFile = Path.Combine(dotnetSdkDirectory.FullName, $"{assemblyName.Name}.dll");
if (File.Exists(assemblyFile))
{
log($"Loading {assemblyFile}");
var assembly = Assembly.LoadFrom(assemblyFile);
log($"Loaded {assembly}");
return assembly;
}

log($"Assembly not found: {assemblyFile}");
return null;
}
catch (Exception exception)
{
log($"Unexpected exception: {exception}");
return null;
}
}

private static void DebugLog(string message)
{
var debugFile = Environment.GetEnvironmentVariable("CHISEL_DEBUG_FILE");
Expand Down

0 comments on commit e55dde6

Please sign in to comment.