Skip to content
Permalink
Browse files

[NuGet] Restore inside assembly resolver to avoid deadlock and rewrot…

…e logging code
  • Loading branch information
xen2 committed Nov 25, 2018
1 parent 8e01c19 commit 99397c68e73ddb60fd253d8d3e8bdf2ef9833c83
Showing with 51 additions and 25 deletions.
  1. +51 −25 sources/shared/Xenko.NuGetResolver/NuGetAssemblyResolver.cs
@@ -2,6 +2,7 @@
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -22,92 +23,117 @@ namespace Xenko.Core.Assets.CompilerApp
{
class NuGetAssemblyResolver
{
static bool assembliesResolved;
static object assembliesLock = new object();
static List<string> assemblies;

[ModuleInitializer(-100000)]
internal static void __Initialize__()
{
var logger = new Logger();
var (request, result) = RestoreHelper.Restore(logger, Assembly.GetExecutingAssembly().GetName().Name, new VersionRange(new NuGetVersion(XenkoVersion.NuGetVersion))).Result;

List<string> assemblies = RestoreHelper.ListAssemblies(request, result);

// Note: we perform nuget restore inside the assembly resolver rather than top level module ctor (otherwise it freezes)
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
var aname = new AssemblyName(eventArgs.Name);
if (aname.Name.StartsWith("Microsoft.Build") && aname.Name != "Microsoft.Build.Locator")
return null;
var assemblyPath = assemblies.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == aname.Name);
if (assemblyPath != null)
if (!assembliesResolved)
{
lock (assembliesLock)
{
// Note: using NuGet will try to recursively resolve NuGet.*.resources.dll, so set assembliesResolved right away so that it bypasses everything
assembliesResolved = true;

var logger = new Logger();
var (request, result) = RestoreHelper.Restore(logger, Assembly.GetExecutingAssembly().GetName().Name, new VersionRange(new NuGetVersion(XenkoVersion.NuGetVersion))).Result;
if (!result.Success)
{
throw new InvalidOperationException($"Could not restore NuGet packages:{Environment.NewLine}{Environment.NewLine}{string.Join(Environment.NewLine, logger.Logs.Where(x => x.Level >= LogLevel.Warning).Select(x => $"[{x.Level}] {x.Message}"))}");
}

assemblies = RestoreHelper.ListAssemblies(request, result);
}
}

if (assemblies != null)
{
return Assembly.LoadFrom(assemblyPath);
var aname = new AssemblyName(eventArgs.Name);
if (aname.Name.StartsWith("Microsoft.Build") && aname.Name != "Microsoft.Build.Locator")
return null;
var assemblyPath = assemblies.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == aname.Name);
if (assemblyPath != null)
{
return Assembly.LoadFrom(assemblyPath);
}
}
return null;
};
}

public class Logger : ILogger
{
private List<string> logs = new List<string>();
private object logLock = new object();
public List<(LogLevel Level, string Message)> Logs { get; } = new List<(LogLevel, string)>();

public void LogDebug(string data)
{
logs.Add(data);
Log(LogLevel.Debug, data);
}

public void LogVerbose(string data)
{
logs.Add(data);
Log(LogLevel.Verbose, data);
}

public void LogInformation(string data)
{
Console.WriteLine(data);
logs.Add(data);
Log(LogLevel.Information, data);
}

public void LogMinimal(string data)
{
logs.Add(data);
Log(LogLevel.Minimal, data);
}

public void LogWarning(string data)
{
logs.Add(data);
Log(LogLevel.Warning, data);
}

public void LogError(string data)
{
logs.Add(data);
Log(LogLevel.Error, data);
}

public void LogInformationSummary(string data)
{
logs.Add(data);
Log(LogLevel.Information, data);
}

public void LogErrorSummary(string data)
{
logs.Add(data);
Log(LogLevel.Error, data);
}

public void Log(LogLevel level, string data)
{
logs.Add(data);
lock (logLock)
{
Debug.WriteLine($"[{level}] {data}");
Logs.Add((level, data));
}
}

public Task LogAsync(LogLevel level, string data)
{
logs.Add(data);
Log(level, data);
return Task.CompletedTask;
}

public void Log(ILogMessage message)
{
logs.Add(message.Message);
Log(message.Level, message.Message);
}

public Task LogAsync(ILogMessage message)
{
logs.Add(message.Message);
Log(message);
return Task.CompletedTask;
}
}

0 comments on commit 99397c6

Please sign in to comment.
You can’t perform that action at this time.