Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve dependencies from GAC #951

Merged
merged 1 commit into from
Aug 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,24 @@ public string[] GetFullPathToDependentAssemblies(string assemblyPath, out IList<
Assembly assembly = null;
try
{
EqtTrace.Verbose($"AssemblyLoadWorker.GetFullPathToDependentAssemblies: Reflection loading {assemblyPath}.");

// First time we load in LoadFromContext to avoid issues.
assembly = this.assemblyUtility.ReflectionOnlyLoadFrom(assemblyPath);
}
catch (Exception ex)
{
EqtTrace.Error($"AssemblyLoadWorker.GetFullPathToDependentAssemblies: Reflection loading of {assemblyPath} failed:");
EqtTrace.Error(ex);

warnings.Add(ex.Message);
return new string[0]; // Otherwise just return no dependencies.
}

Debug.Assert(assembly != null, "assembly");

List<string> result = new List<string>();
List<string> visitedAssemblies = new List<string>();
HashSet<string> visitedAssemblies = new HashSet<string>();

visitedAssemblies.Add(assembly.FullName);

Expand Down Expand Up @@ -149,9 +154,11 @@ private string GetTargetFrameworkStringFromAssembly(Assembly assembly)
/// <param name="result"> The result. </param>
/// <param name="visitedAssemblies"> The visited Assemblies. </param>
/// <param name="warnings"> The warnings. </param>
private void ProcessChildren(Assembly assembly, IList<string> result, IList<string> visitedAssemblies, IList<string> warnings)
private void ProcessChildren(Assembly assembly, IList<string> result, ISet<string> visitedAssemblies, IList<string> warnings)
{
Debug.Assert(assembly != null, "assembly");

EqtTrace.Verbose($"AssemblyLoadWorker.GetFullPathToDependentAssemblies: Processing assembly {assembly.FullName}.");
foreach (AssemblyName reference in assembly.GetReferencedAssemblies())
{
this.GetDependentAssembliesInternal(reference.FullName, result, visitedAssemblies, warnings);
Expand All @@ -161,6 +168,7 @@ private void ProcessChildren(Assembly assembly, IList<string> result, IList<stri
var modules = new Module[0];
try
{
EqtTrace.Verbose($"AssemblyLoadWorker.GetFullPathToDependentAssemblies: Getting modules of {assembly.FullName}.");
modules = assembly.GetModules();
}
catch (FileNotFoundException e)
Expand Down Expand Up @@ -192,13 +200,12 @@ private void ProcessChildren(Assembly assembly, IList<string> result, IList<stri
continue;
}

if (visitedAssemblies.Contains(m.Name))
if (!visitedAssemblies.Add(m.Name))
{
// The assembly was already in the set, meaning that we already visited it.
continue;
}

visitedAssemblies.Add(m.Name);

if (!File.Exists(m.FullyQualifiedName))
{
string warning = string.Format(CultureInfo.CurrentCulture, Resource.MissingDeploymentDependencyWithoutReason, m.FullyQualifiedName);
Expand All @@ -219,20 +226,21 @@ private void ProcessChildren(Assembly assembly, IList<string> result, IList<stri
/// <param name="visitedAssemblies"> The visited Assemblies. </param>
/// <param name="warnings"> The warnings. </param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
private void GetDependentAssembliesInternal(string assemblyString, IList<string> result, IList<string> visitedAssemblies, IList<string> warnings)
private void GetDependentAssembliesInternal(string assemblyString, IList<string> result, ISet<string> visitedAssemblies, IList<string> warnings)
{
Debug.Assert(!string.IsNullOrEmpty(assemblyString), "assemblyString");

if (visitedAssemblies.Contains(assemblyString))
if (!visitedAssemblies.Add(assemblyString))
{
// The assembly was already in the hashset, so we already visited it.
return;
}

visitedAssemblies.Add(assemblyString);

Assembly assembly = null;
try
{
EqtTrace.Verbose($"AssemblyLoadWorker.GetDependentAssembliesInternal: Reflection loading {assemblyString}.");

string postPolicyAssembly = AppDomain.CurrentDomain.ApplyPolicy(assemblyString);
Debug.Assert(!string.IsNullOrEmpty(postPolicyAssembly), "postPolicyAssembly");

Expand All @@ -241,17 +249,15 @@ private void GetDependentAssembliesInternal(string assemblyString, IList<string>
}
catch (Exception ex)
{
EqtTrace.Error($"AssemblyLoadWorker.GetDependentAssembliesInternal: Reflection loading {assemblyString} failed:.");
EqtTrace.Error(ex);

string warning = string.Format(CultureInfo.CurrentCulture, Resource.MissingDeploymentDependency, assemblyString, ex.Message);
warnings.Add(warning);
return;
}

// As soon as we find GAC or internal assembly we do not look further.
if (assembly.GlobalAssemblyCache)
{
return;
}

EqtTrace.Verbose($"AssemblyLoadWorker.GetDependentAssembliesInternal: Assembly {assemblyString} was added as dependency.");
result.Add(assembly.Location);

this.ProcessChildren(assembly, result, visitedAssemblies, warnings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ internal virtual string[] GetFullPathToDependentAssemblies(string assemblyPath,
EqtTrace.InfoIf(EqtTrace.IsInfoEnabled, "AssemblyDependencyFinder.GetDependentAssemblies: start.");

AppDomainSetup setupInfo = new AppDomainSetup();
setupInfo.ApplicationBase = Path.GetDirectoryName(Path.GetFullPath(assemblyPath));
var dllDirectory = Path.GetDirectoryName(Path.GetFullPath(assemblyPath));
setupInfo.ApplicationBase = dllDirectory;

Debug.Assert(string.IsNullOrEmpty(configFile) || File.Exists(configFile), "Config file is specified but does not exist: {0}", configFile);

Expand Down Expand Up @@ -227,7 +228,18 @@ internal virtual string[] GetFullPathToDependentAssemblies(string assemblyPath,

EqtTrace.InfoIf(EqtTrace.IsInfoEnabled, "AssemblyDependencyFinder.GetDependentAssemblies: loaded the worker.");

return worker.GetFullPathToDependentAssemblies(assemblyPath, out warnings);
var allDependencies = worker.GetFullPathToDependentAssemblies(assemblyPath, out warnings);
var dependenciesFromDllDirectory = new List<string>();
var dllDirectoryUppercase = dllDirectory.ToUpperInvariant();
foreach (var dependency in allDependencies)
{
if (dependency.ToUpperInvariant().Contains(dllDirectoryUppercase))
{
dependenciesFromDllDirectory.Add(dependency);
}
}

return dependenciesFromDllDirectory.ToArray();
}
}
finally
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ private void AddDependencies(string testSource, string configFile, IList<Deploym
Debug.Assert(deploymentItems != null, "deploymentItems should not be null.");
Debug.Assert(Path.IsPathRooted(testSource), "path should be rooted.");

var sw = Stopwatch.StartNew();

// Note: if this is not an assembly we simply return empty array, also:
// we do recursive search and report missing.
string[] references = this.AssemblyUtility.GetFullPathToDependentAssemblies(testSource, configFile, out var warningList);
Expand All @@ -230,6 +232,7 @@ private void AddDependencies(string testSource, string configFile, IList<Deploym
if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info("DeploymentManager: Source:{0} has following references", testSource);
EqtTrace.Info("DeploymentManager: Resolving dependencies took {0} ms", sw.ElapsedMilliseconds);
}

foreach (string reference in references)
Expand Down