forked from chocolatey/ChocolateyGUI
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(chocolatey#857) Load Chocolatey executable assembly
This commit makes changes to the assembly loader to load the installed Chocolatey executable as an assembly instead of the statically referenced DLL file
- Loading branch information
1 parent
0256e2f
commit 8cd59ad
Showing
9 changed files
with
481 additions
and
281 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
Source/ChocolateyGui.Common/Startup/AssemblyResolver.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// <copyright file="AssemblyResolver.cs" company="Chocolatey"> | ||
// Copyright 2017 - Present Chocolatey Software, LLC | ||
// Copyright 2014 - 2017 Rob Reynolds, the maintainers of Chocolatey, and RealDimensions Software, LLC | ||
// </copyright> | ||
|
||
using System; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Threading; | ||
using Serilog; | ||
|
||
namespace ChocolateyGui.Common.Startup | ||
{ | ||
public class AssemblyResolver | ||
{ | ||
private const int LOCKRESOLUTIONTIMEOUTSECONDS = 5; | ||
private static readonly object _lockObject = new object(); | ||
|
||
public static Assembly ResolveOrReloadChocolateyAssembly(string assemblyFileLocation) | ||
{ | ||
return ResolveOrLoadAssemblyInternal( | ||
"chocolatey", | ||
string.Empty, | ||
assemblyFileLocation, | ||
(assembly) => | ||
{ | ||
var assemblyName = assembly.GetName(); | ||
|
||
return string.Equals(assemblyName.Name, "chocolatey", StringComparison.OrdinalIgnoreCase) && | ||
assemblyName.Version != new Version(0, 10, 15, 0); // TODO: Should maybe be created automatically | ||
}); | ||
} | ||
|
||
/// <summary> | ||
/// Resolves or loads an assembly. If an assembly is already loaded, no need to reload it. | ||
/// </summary> | ||
/// <param name="assemblySimpleName">Simple Name of the assembly, such as "chocolatey"</param> | ||
/// <param name="publicKeyToken">The public key token.</param> | ||
/// <param name="assemblyFileLocation">The assembly file location. Typically the path to the DLL on disk.</param> | ||
/// <returns>An assembly</returns> | ||
/// <exception cref="Exception">Unable to enter synchronized code to determine assembly loading</exception> | ||
public static Assembly ResolveOrLoadAssembly(string assemblySimpleName, string publicKeyToken, string assemblyFileLocation) | ||
{ | ||
return ResolveOrLoadAssemblyInternal( | ||
assemblySimpleName, | ||
publicKeyToken, | ||
assemblyFileLocation, | ||
(assembly) => string.Equals(assembly.GetName().Name, assemblySimpleName, StringComparison.OrdinalIgnoreCase)); | ||
} | ||
|
||
public static bool IsPublicKeyToken(AssemblyName assemblyName, string expectedKeyToken) | ||
{ | ||
var publicKey = GetPublicKeyToken(assemblyName); | ||
|
||
return string.Equals(publicKey, expectedKeyToken, StringComparison.OrdinalIgnoreCase); | ||
} | ||
|
||
public static string GetPublicKeyToken(AssemblyName assemblyName) | ||
{ | ||
if (assemblyName == null) | ||
{ | ||
return string.Empty; | ||
} | ||
|
||
var publicKeyToken = assemblyName.GetPublicKeyToken(); | ||
|
||
if (publicKeyToken == null || publicKeyToken.Length == 0) | ||
{ | ||
return string.Empty; | ||
} | ||
|
||
return publicKeyToken.Select(x => x.ToString("x2")).Aggregate((x, y) => x + y); | ||
} | ||
|
||
private static Assembly ResolveOrLoadAssemblyInternal(string assemblySimpleName, string publicKeyToken, string assemblyFileLocation, Func<Assembly, bool> assemblyPredicate) | ||
{ | ||
var lockTaken = false; | ||
try | ||
{ | ||
Monitor.TryEnter(_lockObject, TimeSpan.FromSeconds(LOCKRESOLUTIONTIMEOUTSECONDS), ref lockTaken); | ||
} | ||
catch (Exception) | ||
{ | ||
throw new Exception("Unable to enter synchronized code to determine assembly loading"); | ||
} | ||
|
||
Assembly resolvedAssembly = null; | ||
if (lockTaken) | ||
{ | ||
try | ||
{ | ||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies().Where(assemblyPredicate)) | ||
{ | ||
if (string.IsNullOrWhiteSpace(publicKeyToken) || string.Equals(GetPublicKeyToken(assembly.GetName()), publicKeyToken, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
Log.Debug("Returning loaded assembly type for '{0}'", assemblySimpleName); | ||
|
||
resolvedAssembly = assembly; | ||
break; | ||
} | ||
} | ||
|
||
if (resolvedAssembly == null) | ||
{ | ||
Log.Debug("Loading up '{0}' assembly type from '{1}'", assemblySimpleName, assemblyFileLocation); | ||
|
||
// Reading the raw bytes and calling 'Load' causes an exception, as such we use LoadFrom instead. | ||
resolvedAssembly = Assembly.LoadFrom(assemblyFileLocation); | ||
} | ||
} | ||
finally | ||
{ | ||
Monitor.Pulse(_lockObject); | ||
Monitor.Exit(_lockObject); | ||
} | ||
} | ||
|
||
return resolvedAssembly; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.