// Licensed to the .NET Foundation under one or more agreements.// The .NET Foundation licenses this file to you under the Apache 2.0 License.// See the LICENSE file in the project root for more information.using System;using System.Collections.Generic;using System.IO;using IKVM.Reflection;namespace IronPython.Compiler {internal class AssemblyResolver {private Universe _universe;private readonly List<string> _libpaths = new List<string>();private Version _mscorlibVersion;private Dictionary<string, string> _hintpaths = new Dictionary<string, string>();public AssemblyResolver(Universe universe, bool nostdlib, IEnumerable<string> references, IEnumerable<string> libpaths) {_universe = universe;_libpaths.Add(Environment.CurrentDirectory);_libpaths.AddRange(libpaths);if (!nostdlib) {_libpaths.Add(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory());}// items passed in via /lib:<path>foreach (string path in libpaths) {foreach (string dir in path.Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries)) {if (Directory.Exists(dir)) {_libpaths.Add(dir);} else {ConsoleOps.Warning("Directory specified ('{0}') by /lib: does not exist", dir);}}}string envLib = Environment.GetEnvironmentVariable("LIB");if (!string.IsNullOrEmpty(envLib)) {foreach (string dir in envLib.Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries)) {if (Directory.Exists(dir)) {_libpaths.Add(dir);} else {ConsoleOps.Warning("Directory specified ('{0}') in LIB does not exist", dir);}}}if (nostdlib) {_mscorlibVersion = LoadMscorlib(references).GetName().Version;} else {_mscorlibVersion = universe.Load("mscorlib").GetName().Version;}_universe.AssemblyResolve += _universe_AssemblyResolve;}private Assembly _universe_AssemblyResolve(object sender, IKVM.Reflection.ResolveEventArgs args) {AssemblyName name = new AssemblyName(args.Name);AssemblyName previousMatch = null;int previousMatchLevel = 0;foreach (Assembly asm in _universe.GetAssemblies()) {if (Match(asm.GetName(), name, ref previousMatch, ref previousMatchLevel)) {return asm;}}foreach (string file in FindAssemblyPath(name.Name + ".dll")) {if (Match(AssemblyName.GetAssemblyName(file), name, ref previousMatch, ref previousMatchLevel)) {return LoadFile(file);}}if (args.RequestingAssembly != null) {string path = Path.Combine(Path.GetDirectoryName(args.RequestingAssembly.Location), name.Name + ".dll");if (File.Exists(path) && Match(AssemblyName.GetAssemblyName(path), name, ref previousMatch, ref previousMatchLevel)) {return LoadFile(path);}}string hintpath;if (_hintpaths.TryGetValue(name.FullName, out hintpath)) {string path = Path.Combine(hintpath, name.Name + ".dll");if (File.Exists(path) && Match(AssemblyName.GetAssemblyName(path), name, ref previousMatch, ref previousMatchLevel)) {return LoadFile(path);}}if (previousMatch != null) {if (previousMatchLevel == 2) {ConsoleOps.Warning("assuming assembly reference '{0}' matches '{1}', you may need to supply runtime policy", previousMatch.FullName, name.FullName);return LoadFile(new Uri(previousMatch.CodeBase).LocalPath);} else if (args.RequestingAssembly != null) {ConsoleOps.Error(true, "Assembly '{0}' uses '{1}' which has a higher version than referenced assembly '{2}'", args.RequestingAssembly.FullName, name.FullName, previousMatch.FullName);} else {ConsoleOps.Error(true, "Assembly '{0}' was requested which is a higher version than referenced assembly '{1}'", name.FullName, previousMatch.FullName);}} else {ConsoleOps.Error(true, "unable to find assembly '{0}' {1}", args.Name, args.RequestingAssembly != null ? string.Format(" (a dependency of '{0}')", args.RequestingAssembly.FullName) : string.Empty);}return null;}private bool Match(AssemblyName assemblyDef, AssemblyName assemblyRef, ref AssemblyName bestMatch, ref int bestMatchLevel) {// Match levels:// 0 = no match// 1 = lower version match (i.e. not a suitable match, but used in error reporting: something was found but the version was too low)// 2 = higher version potential match (i.e. we can use this version, but if it is available the exact match will be preferred)//// If we find a perfect match, bestMatch is not changed but we return true to signal that the search can end right now.AssemblyComparisonResult result;_universe.CompareAssemblyIdentity(assemblyRef.FullName, false, assemblyDef.FullName, true, out result);switch (result) {case AssemblyComparisonResult.EquivalentFullMatch:case AssemblyComparisonResult.EquivalentPartialMatch:case AssemblyComparisonResult.EquivalentFXUnified:case AssemblyComparisonResult.EquivalentPartialFXUnified:case AssemblyComparisonResult.EquivalentPartialWeakNamed:case AssemblyComparisonResult.EquivalentWeakNamed:return true;case AssemblyComparisonResult.NonEquivalentPartialVersion:case AssemblyComparisonResult.NonEquivalentVersion:if (bestMatchLevel < 1) {bestMatchLevel = 1;bestMatch = assemblyDef;}return false;case AssemblyComparisonResult.EquivalentUnified:case AssemblyComparisonResult.EquivalentPartialUnified:if (bestMatchLevel < 2) {bestMatchLevel = 2;bestMatch = assemblyDef;}return false;case AssemblyComparisonResult.NonEquivalent:case AssemblyComparisonResult.Unknown:return false;default:throw new NotImplementedException();}}public bool ResolveReference(Dictionary<string, Assembly> cache, List<Assembly> references, string reference) {string[] files = Array.Empty<string>();try {string path = Path.GetDirectoryName(reference);files = Directory.GetFiles(path == "" ? "." : path, Path.GetFileName(reference));} catch (ArgumentException) {} catch (IOException) {}if (files.Length == 0) {Assembly asm = null;cache.TryGetValue(reference, out asm);if (asm == null) {foreach (string found in FindAssemblyPath(reference)) {asm = LoadFile(found);cache.Add(reference, asm);break;}}if (asm == null) {Console.Error.WriteLine("Error: reference not found: {0}", reference);return false;}references.Add(asm);} else {foreach (string file in files) {Assembly asm;if (!cache.TryGetValue(file, out asm)) {asm = LoadFile(file);}references.Add(asm);}}return true;}private Assembly LoadMscorlib(IEnumerable<string> references) {if (references != null) {foreach (string r in references) {try {if (AssemblyName.GetAssemblyName(r).Name == "mscorlib") {return LoadFile(r);}} catch {}}}foreach (string mscorlib in FindAssemblyPath("mscorlib.dll")) {return LoadFile(mscorlib);}ConsoleOps.Error(true, "unable to find mscorlib.dll");return null;}private void AddHintPath(string assemblyName, string path) {_hintpaths.Add(assemblyName, path);}private IEnumerable<string> FindAssemblyPath(string file) {if (Path.IsPathRooted(file)) {if (File.Exists(file)) {yield return file;}} else {foreach (string dir in _libpaths) {string path = Path.Combine(dir, file);if (File.Exists(path)) {yield return path;}// for legacy compat, we try again after appending .dllpath = Path.Combine(dir, file + ".dll");if (File.Exists(path)) {ConsoleOps.Warning("Found assembly '{0}' using legacy search rule, please append '.dll' to the reference", file);yield return path;}}}}private Assembly LoadFile(string path) {string ex = null;try {using (RawModule module = _universe.OpenRawModule(path)) {if (_mscorlibVersion != null) {// to avoid problems (i.e. weird exceptions), we don't allow assemblies to load that reference a newer version of mscorlibforeach (AssemblyName asmref in module.GetReferencedAssemblies()) {if (asmref.Name == "mscorlib" && asmref.Version > _mscorlibVersion) {ConsoleOps.Error(true, "unable to load assembly '{0}' as it depends on a higher version of mscorlib than the one currently loaded", path);}}}Assembly asm = _universe.LoadAssembly(module);if (asm.Location != module.Location && CanonicalizePath(asm.Location) != CanonicalizePath(module.Location)) {ConsoleOps.Warning("assembly '{0}' is ignored as previously loaded assembly '{1}' has the same identity '{2}'", path, asm.Location, asm.FullName);}return asm;}} catch (IOException x) {ex = x.Message;} catch (UnauthorizedAccessException x) {ex = x.Message;} catch (IKVM.Reflection.BadImageFormatException x) {ex = x.Message;}ConsoleOps.Error(true, "unable to load assembly '{0}'" + Environment.NewLine + " ({1})", path, ex);return null;}private static string CanonicalizePath(string path) {try {FileInfo fi = new FileInfo(path);if (fi.DirectoryName == null) {return path.Length > 1 && path[1] == ':' ? path.ToUpperInvariant() : path;}string dir = CanonicalizePath(fi.DirectoryName);string name = fi.Name;try {string[] arr = System.IO.Directory.GetFileSystemEntries(dir, name);if (arr.Length == 1) {name = arr[0];}} catch (UnauthorizedAccessException) {} catch (IOException) {}return Path.Combine(dir, name);} catch (UnauthorizedAccessException) {} catch (IOException) {} catch (System.Security.SecurityException) {} catch (NotSupportedException) {}return path;}}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。