/// <summary> /// This is used to create an assembly details instance from an XML element /// </summary> /// <param name="path">The path to the assembly</param> /// <param name="details">The XML element containing the details</param> /// <returns>The new assembly details item</returns> internal static AssemblyDetails FromXml(string path, XElement details) { string filename = details.Attribute("Filename").Value; if (!Path.IsPathRooted(filename)) { filename = Path.Combine(path, filename); } var ad = new AssemblyDetails { Filename = filename, Name = details.Attribute("Name").Value, Version = new Version(details.Attribute("Version").Value), Culture = (string)details.Attribute("Culture"), PublicKeyToken = (string)details.Attribute("PublicKeyToken"), IsIncluded = !details.Attributes("IsExcluded").Any() }; ad.Description = String.Format(CultureInfo.InvariantCulture, "{0}, Version={1}, Culture={2}, PublicKeyToken={3}", ad.Name, ad.Version, String.IsNullOrEmpty(ad.Culture) ? "neutral" : ad.Culture, String.IsNullOrEmpty(ad.PublicKeyToken) ? "null" : ad.PublicKeyToken); return(ad); }
/// <summary> /// This is used to find an assembly by name /// </summary> /// <param name="assemblyName">The assembly name without a path or extension or a strong name value. /// If a strong name value is specified, a "starts with" comparison on the description is used to see if /// the assembly is present in the framework. This allows for matches on strong names with processor /// architecture specified which we don't have. If only a name is given, just the name is compared. /// Comparisons are case-insensitive.</param> /// <returns>The assembly if found or null if not found</returns> public AssemblyDetails FindAssembly(string assemblyName) { AssemblyDetails ad = null; bool strongName = (assemblyName.IndexOf(',') != -1); foreach (var al in assemblyLocations) { if (strongName) { ad = al.IncludedAssemblies.FirstOrDefault(a => assemblyName.StartsWith(a.Description, StringComparison.OrdinalIgnoreCase) && File.Exists(a.Filename)); } else { ad = al.IncludedAssemblies.FirstOrDefault(a => assemblyName.Equals(a.Name, StringComparison.OrdinalIgnoreCase) && File.Exists(a.Filename)); } if (ad != null) { break; } } return(ad); }
//===================================================================== /// <summary> /// This is used to create an assembly details instance from an assembly name /// </summary> /// <param name="name">The assembly name information</param> /// <returns>The new assembly details item</returns> internal static AssemblyDetails FromAssemblyName(AssemblyName name) { Uri codeBase = new Uri(name.CodeBase); string location; if (codeBase.IsFile) { location = codeBase.LocalPath; } else { location = name.Name; } var ad = new AssemblyDetails { Filename = location, Name = name.Name, Version = name.Version, Culture = name.CultureInfo.ToString().ToLowerInvariant(), PublicKeyToken = String.Concat(name.GetPublicKeyToken().Select(c => c.ToString("x2", CultureInfo.InvariantCulture))), IsIncluded = true }; ad.Description = String.Format(CultureInfo.InvariantCulture, "{0}, Version={1}, Culture={2}, PublicKeyToken={3}", ad.Name, ad.Version, String.IsNullOrEmpty(ad.Culture) ? "neutral" : ad.Culture, String.IsNullOrEmpty(ad.PublicKeyToken) ? "null" : ad.PublicKeyToken); return(ad); }
//===================================================================== /// <summary> /// This is used to load the settings for an assembly location from an XML element /// </summary> /// <param name="location">The XML element containing the settings</param> /// <returns>The new assembly location item</returns> /// <remarks>If the location element is empty, the assembly details will be created by scanning the /// location for assemblies.</remarks> internal static AssemblyLocation FromXml(XElement location) { AssemblyLocation al = new AssemblyLocation(location.Attribute("Path").Value); foreach (var a in location.Descendants("AssemblyDetails")) { al.assemblyDetails.Add(AssemblyDetails.FromXml(al.Path, a)); } return(al); }
/// <summary> /// This is overridden to allow proper comparison of assembly detail objects /// </summary> /// <param name="obj">The object to which this instance is compared</param> /// <returns>Returns true if the object equals this instance, false if it does not</returns> public override bool Equals(object obj) { if (obj == null || obj.GetType() != this.GetType()) { return(false); } AssemblyDetails otherDetails = obj as AssemblyDetails; return(this.Description.Equals(otherDetails.Description, StringComparison.Ordinal)); }
//===================================================================== /// <summary> /// This can be used to load an empty location with information about the assemblies it contains /// </summary> /// <param name="clearAndRefresh">True to clear and refresh all file information or false to only remove /// assemblies that no longer exist and add new assemblies.</param> public void DetermineAssemblyDetails(bool clearAndRefresh) { if (clearAndRefresh) { assemblyDetails.Clear(); } if (!String.IsNullOrWhiteSpace(this.Path) && Directory.Exists(this.Path)) { HashSet <string> assemblyDescs = new HashSet <string>(assemblyDetails.Select(a => a.Description)); // Remove entries that are not there anymore foreach (var d in assemblyDetails.ToList()) { if (!File.Exists(d.Filename)) { assemblyDetails.Remove(d); } } // Add missing entries foreach (string assembly in Directory.EnumerateFiles(this.Path, "*.dll").Concat( Directory.EnumerateFiles(this.Path, "*.winmd"))) { try { var details = AssemblyDetails.FromAssemblyName(AssemblyName.GetAssemblyName(assembly)); if (!assemblyDescs.Contains(details.Description)) { assemblyDetails.Add(details); } } catch (BadImageFormatException ex) { // Ignore, not a .NET assembly System.Diagnostics.Debug.WriteLine(ex.FileName); } } } }
//===================================================================== /// <summary> /// This can be used to load an empty location with information about the assemblies it contains /// </summary> /// <param name="clearAndRefresh">True to clear and refresh all file information or false to only remove /// assemblies that no longer exist and add new assemblies.</param> public void DetermineAssemblyDetails(bool clearAndRefresh) { string version, assemblyName; if (clearAndRefresh) { assemblyDetails.Clear(); } if (!String.IsNullOrWhiteSpace(this.Path) && Directory.Exists(this.Path)) { HashSet <string> assemblyDescs = new HashSet <string>(assemblyDetails.Select(a => a.Description)); // Remove entries that are not there anymore foreach (var d in assemblyDetails.ToList()) { if (!File.Exists(d.Filename)) { assemblyDetails.Remove(d); } } // Add missing entries foreach (string assembly in Directory.EnumerateFiles(this.Path, "*.dll").Concat( Directory.EnumerateFiles(this.Path, "*.winmd"))) { try { var details = AssemblyDetails.FromAssemblyName(AssemblyName.GetAssemblyName(assembly)); if (!assemblyDescs.Contains(details.Description)) { assemblyDetails.Add(details); } } catch (BadImageFormatException ex) { // Ignore, not a .NET assembly System.Diagnostics.Debug.WriteLine(ex.FileName); } } // The SDK folders for .NETCore 5.0 are typically in one of two formats so this gets a bit ugly. foreach (string sdkFolder in Directory.EnumerateDirectories(this.Path)) { // RootFolder\AssemblyName\Version\ref\dotnet\ version = Directory.EnumerateDirectories(sdkFolder).Where( d => Char.IsDigit(d[d.LastIndexOf('\\') + 1])).OrderBy(d => d).LastOrDefault(); if (version != null) { assemblyName = IOPath.Combine(version, @"ref\dotnet", sdkFolder.Substring(sdkFolder.LastIndexOf('\\') + 1)); if (File.Exists(assemblyName + ".dll")) { assemblyName += ".dll"; } else if (File.Exists(assemblyName + ".winmd")) { assemblyName += ".winmd"; } else { assemblyName = null; } if (assemblyName != null) { var details = AssemblyDetails.FromAssemblyName( AssemblyName.GetAssemblyName(assemblyName)); if (!assemblyDescs.Contains(details.Description)) { assemblyDetails.Add(details); } continue; } } // RootFolder\AssemblyName\Version\ version = Directory.EnumerateDirectories(sdkFolder).Where( d => Char.IsDigit(d[d.LastIndexOf('\\') + 1])).OrderBy(d => d).LastOrDefault(); if (version != null) { assemblyName = IOPath.Combine(version, sdkFolder.Substring(sdkFolder.LastIndexOf('\\') + 1)); if (File.Exists(assemblyName + ".dll")) { assemblyName += ".dll"; } else if (File.Exists(assemblyName + ".winmd")) { assemblyName += ".winmd"; } else { assemblyName = null; } if (assemblyName != null) { var details = AssemblyDetails.FromAssemblyName( AssemblyName.GetAssemblyName(assemblyName)); if (!assemblyDescs.Contains(details.Description)) { assemblyDetails.Add(details); } } } } } }
/// <summary> /// This is used to create an assembly details instance from an XML element /// </summary> /// <param name="path">The path to the assembly</param> /// <param name="details">The XML element containing the details</param> /// <returns>The new assembly details item</returns> internal static AssemblyDetails FromXml(string path, XElement details) { var ad = new AssemblyDetails { Filename = Path.Combine(path, details.Attribute("Filename").Value), Name = details.Attribute("Name").Value, Version = new Version(details.Attribute("Version").Value), Culture = (string)details.Attribute("Culture"), PublicKeyToken = (string)details.Attribute("PublicKeyToken"), IsIncluded = !details.Attributes("IsExcluded").Any() }; ad.Description = String.Format(CultureInfo.InvariantCulture, "{0}, Version={1}, Culture={2}, PublicKeyToken={3}", ad.Name, ad.Version, String.IsNullOrEmpty(ad.Culture) ? "neutral" : ad.Culture, String.IsNullOrEmpty(ad.PublicKeyToken) ? "null" : ad.PublicKeyToken); return ad; }
//===================================================================== /// <summary> /// This is used to create an assembly details instance from an assembly name /// </summary> /// <param name="name">The assembly name information</param> /// <returns>The new assembly details item</returns> internal static AssemblyDetails FromAssemblyName(AssemblyName name) { Uri codeBase = new Uri(name.CodeBase); string location; if(codeBase.IsFile) location = codeBase.LocalPath; else location = name.Name; var ad = new AssemblyDetails { Filename = location, Name = name.Name, Version = name.Version, Culture = name.CultureInfo.ToString().ToLowerInvariant(), PublicKeyToken = String.Concat(name.GetPublicKeyToken().Select(c => c.ToString("x2", CultureInfo.InvariantCulture))), IsIncluded = true }; ad.Description = String.Format(CultureInfo.InvariantCulture, "{0}, Version={1}, Culture={2}, PublicKeyToken={3}", ad.Name, ad.Version, String.IsNullOrEmpty(ad.Culture) ? "neutral" : ad.Culture, String.IsNullOrEmpty(ad.PublicKeyToken) ? "null" : ad.PublicKeyToken); return ad; }