//===================================================================== /// <summary> /// Main program entry point /// </summary> /// <param name="args">Command line arguments</param> /// <returns>Zero on success or non-zero on failure</returns> public static int Main(string[] args) { string path, version, framework = null, assemblyPath, typeName; // Write banner ConsoleApplication.WriteBanner(); // Specify options OptionCollection options = new OptionCollection(); options.Add(new SwitchOption("?", "Show this help page.")); options.Add(new StringOption("out", "Specify an output file. If unspecified, output goes to the " + "console.", "outputFilePath")); options.Add(new StringOption("config", "Specify a configuration file. If unspecified, " + "MRefBuilder.config is used", "configFilePath")); options.Add(new ListOption("dep", "Specify assemblies to load for dependencies.", "dependencyAssembly")); options.Add(new BooleanOption("internal", "Specify whether to document internal as well as " + "externally exposed APIs. *** DEPRECATED: Use the visibility settings in the MRefBuilder.config " + "file instead which provide finer grained control over the exposed API members.")); // Process options ParseArgumentsResult results = options.ParseArguments(args); if (results.Options["?"].IsPresent) { Console.WriteLine("MRefBuilder [options] assemblies"); options.WriteOptionSummary(Console.Out); return(1); } // Check for invalid options if (!results.Success) { results.WriteParseErrors(Console.Out); return(1); } // Check for missing or extra assembly directories if (results.UnusedArguments.Count < 1) { Console.WriteLine("Specify at least one assembly to reflect."); return(1); } // Load the configuration file XPathDocument config; string configDirectory = ComponentUtilities.ToolsFolder, configFile = Path.Combine(ComponentUtilities.ToolsFolder, "MRefBuilder.config"); if (results.Options["config"].IsPresent) { configFile = (string)results.Options["config"].Value; configDirectory = Path.GetDirectoryName(configFile); } try { config = new XPathDocument(configFile); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to read " + "the configuration file '{0}'. The error message is: {1}", configFile, e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to read " + "the configuration file '{0}'. The error message is: {1}", configFile, e.Message); return(1); } catch (XmlException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "The configuration file '{0}' is not " + "well-formed. The error message is: {1}", configFile, e.Message); return(1); } // Adjust the target platform XPathNodeIterator platformNodes = config.CreateNavigator().Select("/configuration/dduetools/platform"); if (platformNodes.MoveNext()) { XPathNavigator platformNode = platformNodes.Current; version = platformNode.GetAttribute("version", String.Empty); path = platformNode.GetAttribute("path", String.Empty); // !EFW - Added support for the new platform attributes and the framework XML file if (!String.IsNullOrEmpty(version) && !String.IsNullOrEmpty(path)) { // Set the framework using the legacy attributes. If set properly, they will document // other framework types but it uses the standard .NET assemblies which contain more // classes and methods that are not relevant to the other frameworks. path = Environment.ExpandEnvironmentVariables(path); if (!Directory.Exists(path)) { ConsoleApplication.WriteMessage(LogLevel.Error, "The specified target platform " + "directory '{0}' does not exist.", path); return(1); } if (version == "2.0") { TargetPlatform.SetToV2(path); } else if (version == "1.1") { TargetPlatform.SetToV1_1(path); } else if (version == "1.0") { TargetPlatform.SetToV1(path); } else { ConsoleApplication.WriteMessage(LogLevel.Error, "Unknown target platform " + "version '{0}'.", version); return(1); } } else { // Use the new framework definition file framework = platformNode.GetAttribute("framework", String.Empty); if (!String.IsNullOrEmpty(framework) && !String.IsNullOrEmpty(version)) { TargetPlatform.SetFrameworkInformation(framework, version); } else { ConsoleApplication.WriteMessage(LogLevel.Error, "Unknown target framework " + "version '{0} {1}'.", framework, version); return(1); } } } // Create an API member namer ApiNamer namer; // Apply a different naming method to assemblies using the Windows Store or Windows Phone frameworks if (framework == ".NETCore" || framework == ".NETPortable" || framework == "WindowsPhone" || framework == "WindowsPhoneApp") { namer = new WindowsStoreAndPhoneNamer(); } else { namer = new OrcasNamer(); } XPathNavigator namerNode = config.CreateNavigator().SelectSingleNode("/configuration/dduetools/namer"); if (namerNode != null) { assemblyPath = namerNode.GetAttribute("assembly", String.Empty); typeName = namerNode.GetAttribute("type", String.Empty); assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } try { Assembly assembly = Assembly.LoadFrom(assemblyPath); namer = (ApiNamer)assembly.CreateInstance(typeName); if (namer == null) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (BadImageFormatException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The component assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(1); } catch (TypeLoadException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (MissingMethodException) { ConsoleApplication.WriteMessage(LogLevel.Error, "No appropriate constructor exists for " + "the type'{0}' in the component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (TargetInvocationException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while initializing the " + "type '{0}' in the component assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(1); } catch (InvalidCastException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' in the component assembly " + "'{1}' is not a component type.", typeName, assemblyPath); return(1); } } // Create a resolver AssemblyResolver resolver = new AssemblyResolver(); XPathNavigator resolverNode = config.CreateNavigator().SelectSingleNode("/configuration/dduetools/resolver"); if (resolverNode != null) { assemblyPath = resolverNode.GetAttribute("assembly", String.Empty); typeName = resolverNode.GetAttribute("type", String.Empty); assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } try { Assembly assembly = Assembly.LoadFrom(assemblyPath); resolver = (AssemblyResolver)assembly.CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, null, new object[1] { resolverNode }, null, null); if (resolver == null) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (BadImageFormatException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The component assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(1); } catch (TypeLoadException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (MissingMethodException) { ConsoleApplication.WriteMessage(LogLevel.Error, "No appropriate constructor exists for " + "the type'{0}' in the component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (TargetInvocationException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while initializing the " + "type '{0}' in the component assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(1); } catch (InvalidCastException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' in the component assembly " + "'{1}' is not a component type.", typeName, assemblyPath); return(1); } } resolver.UnresolvedAssemblyReference += UnresolvedAssemblyReferenceHandler; // Get a text writer for output TextWriter output = Console.Out; if (results.Options["out"].IsPresent) { string file = (string)results.Options["out"].Value; try { output = new StreamWriter(file, false, Encoding.UTF8); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to " + "create an output file. The error message is: {0}", e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to " + "create an output file. The error message is: {0}", e.Message); return(1); } } // Dependency directory string[] dependencies = new string[0]; if (results.Options["dep"].IsPresent) { dependencies = (string[])results.Options["dep"].Value; } try { // Create a builder ApiVisitor = new ManagedReflectionWriter(output, namer, resolver, new ApiFilter(config.CreateNavigator().SelectSingleNode("/configuration/dduetools"))); // If the deprecated /internal+ option is used, expose everything via the filter to mimic the // behavior of prior versions. if (results.Options["internal"].IsPresent && (bool)results.Options["internal"].Value) { ApiVisitor.ApiFilter.IncludeAttributes = ApiVisitor.ApiFilter.IncludeExplicitInterfaceImplementations = ApiVisitor.ApiFilter.IncludePrivates = ApiVisitor.ApiFilter.IncludePrivateFields = ApiVisitor.ApiFilter.IncludeInternals = ApiVisitor.ApiFilter.IncludeProtected = ApiVisitor.ApiFilter.IncludeSealedProtected = ApiVisitor.ApiFilter.IncludeInheritedMembers = ApiVisitor.ApiFilter.IncludeInheritedFrameworkMembers = ApiVisitor.ApiFilter.IncludeInheritedFrameworkPrivateMembers = ApiVisitor.ApiFilter.IncludeInheritedFrameworkInternalMembers = ApiVisitor.ApiFilter.IncludeNoPIATypes = true; ApiVisitor.ApiFilter.IncludeProtectedInternalAsProtected = false; } // Register add-ins to the builder XPathNodeIterator addinNodes = config.CreateNavigator().Select("/configuration/dduetools/addins/addin"); foreach (XPathNavigator addinNode in addinNodes) { assemblyPath = addinNode.GetAttribute("assembly", String.Empty); typeName = addinNode.GetAttribute("type", String.Empty); assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } try { Assembly assembly = Assembly.LoadFrom(assemblyPath); MRefBuilderAddIn addin = (MRefBuilderAddIn)assembly.CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, null, new object[2] { ApiVisitor, addinNode }, null, null); if (addin == null) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in " + "the add-in assembly '{1}'.", typeName, assemblyPath); return(1); } } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the add-in assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (BadImageFormatException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The add-in assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(1); } catch (TypeLoadException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "add-in assembly '{1}'.", typeName, assemblyPath); return(1); } catch (MissingMethodException) { ConsoleApplication.WriteMessage(LogLevel.Error, "No appropriate constructor exists " + "for the type '{0}' in the add-in assembly '{1}'.", typeName, assemblyPath); return(1); } catch (TargetInvocationException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while initializing " + "the type '{0}' in the add-in assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(1); } catch (InvalidCastException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' in the add-in " + "assembly '{1}' is not an MRefBuilderAddIn type.", typeName, assemblyPath); return(1); } } // Load dependencies foreach (string dependency in dependencies) { try { // Expand environment variables path = Environment.ExpandEnvironmentVariables(dependency); // If x86 but it didn't exist, assume it's a 32-bit system and change the name if (path.IndexOf("%ProgramFiles(x86)%", StringComparison.Ordinal) != -1) { path = Environment.ExpandEnvironmentVariables(path.Replace("(x86)", String.Empty)); } ApiVisitor.LoadAccessoryAssemblies(path); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while loading " + "dependency assemblies. The error message is: {0}", e.Message); return(1); } } // Parse the assemblies foreach (string dllPath in results.UnusedArguments) { try { // Expand environment variables path = Environment.ExpandEnvironmentVariables(dllPath); // If x86 but it didn't exist, assume it's a 32-bit system and change the name if (path.IndexOf("%ProgramFiles(x86)%", StringComparison.Ordinal) != -1) { path = Environment.ExpandEnvironmentVariables(path.Replace("(x86)", String.Empty)); } ApiVisitor.LoadAssemblies(path); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while loading " + "assemblies for reflection. The error message is: {0}", e.Message); return(1); } } ConsoleApplication.WriteMessage(LogLevel.Info, "Loaded {0} assemblies for reflection and " + "{1} dependency assemblies.", ApiVisitor.Assemblies.Count(), ApiVisitor.AccessoryAssemblies.Count()); ApiVisitor.VisitApis(); if (ApiVisitor.Canceled) { ConsoleApplication.WriteMessage(LogLevel.Error, "MRefBuilder task canceled"); } else { ConsoleApplication.WriteMessage(LogLevel.Info, "Wrote information on {0} namespaces, " + "{1} types, and {2} members", ApiVisitor.Namespaces.Count(), ApiVisitor.Types.Count(), ApiVisitor.Members.Count()); } } finally { if (ApiVisitor != null) { ApiVisitor.Dispose(); } if (results.Options["out"].IsPresent) { output.Close(); } } return((ApiVisitor != null && ApiVisitor.Canceled) ? 2 : 0); }
/// <summary> /// Main program entry point (MSBuild task) /// </summary> /// <param name="args">Command line arguments</param> /// <returns>Zero on success or non-zero on failure</returns> public static int MainEntryPoint(string[] args) { string path, version, framework = null, assemblyPath, typeName; // Write banner ConsoleApplication.WriteBanner(); // Specify options OptionCollection options = new OptionCollection { new SwitchOption("?", "Show this help page."), new StringOption("out", "Specify an output file. If unspecified, output goes to the console.", "outputFilePath"), new StringOption("config", "Specify a configuration file. If unspecified, MRefBuilder.config is used", "configFilePath"), new ListOption("dep", "Specify assemblies to load for dependencies.", "dependencyAssembly") }; // Process options ParseArgumentsResult results = options.ParseArguments(args); if (results.Options["?"].IsPresent) { Console.WriteLine("MRefBuilder [options] assemblies"); options.WriteOptionSummary(Console.Out); return(1); } // Check for invalid options if (!results.Success) { results.WriteParseErrors(Console.Out); return(1); } // Check for missing or extra assembly directories if (results.UnusedArguments.Count < 1) { Console.WriteLine("Specify at least one assembly to reflect."); return(1); } // Load the configuration file XPathDocument config; XPathNavigator configNav; string configDirectory = ComponentUtilities.ToolsFolder, configFile = Path.Combine(ComponentUtilities.ToolsFolder, "MRefBuilder.config"); if (results.Options["config"].IsPresent) { configFile = (string)results.Options["config"].Value; configDirectory = Path.GetDirectoryName(configFile); } try { config = new XPathDocument(configFile); configNav = config.CreateNavigator(); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to read " + "the configuration file '{0}'. The error message is: {1}", configFile, e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to read " + "the configuration file '{0}'. The error message is: {1}", configFile, e.Message); return(1); } catch (XmlException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "The configuration file '{0}' is not " + "well-formed. The error message is: {1}", configFile, e.Message); return(1); } // Adjust the target platform var platformNode = configNav.SelectSingleNode("/configuration/dduetools/platform"); if (platformNode == null) { ConsoleApplication.WriteMessage(LogLevel.Error, "A platform element is required to define the " + "framework type and version to use."); return(1); } // !EFW - Use the framework definition file to load core framework assembly reference information version = platformNode.GetAttribute("version", String.Empty); framework = platformNode.GetAttribute("framework", String.Empty); // Get component locations used to find additional reflection data definition files List <string> componentFolders = new List <string>(); var locations = configNav.SelectSingleNode("/configuration/dduetools/componentLocations"); if (locations != null) { foreach (XPathNavigator folder in locations.Select("location/@folder")) { if (!String.IsNullOrWhiteSpace(folder.Value) && Directory.Exists(folder.Value)) { componentFolders.Add(folder.Value); } } } // Get the dependencies string[] dependencies = Array.Empty <string>(); if (results.Options["dep"].IsPresent) { dependencies = (string[])results.Options["dep"].Value; } if (!String.IsNullOrEmpty(framework) && !String.IsNullOrEmpty(version)) { var coreNames = new HashSet <string>(new[] { "netstandard", "mscorlib", "System.Runtime" }, StringComparer.OrdinalIgnoreCase); var coreFrameworkAssemblies = results.UnusedArguments.Concat(dependencies).Where(d => coreNames.Contains(Path.GetFileNameWithoutExtension(d))); TargetPlatform.SetFrameworkInformation(framework, version, componentFolders, coreFrameworkAssemblies); } else { ConsoleApplication.WriteMessage(LogLevel.Error, "Unknown target framework version '{0} {1}'.", framework, version); return(1); } // Create an API member namer ApiNamer namer; // Apply a different naming method to assemblies using these frameworks if (framework == PlatformType.DotNetCore || framework == PlatformType.DotNetPortable || framework == PlatformType.WindowsPhone || framework == PlatformType.WindowsPhoneApp) { namer = new WindowsStoreAndPhoneNamer(); } else { namer = new OrcasNamer(); } XPathNavigator namerNode = configNav.SelectSingleNode("/configuration/dduetools/namer"); if (namerNode != null) { assemblyPath = namerNode.GetAttribute("assembly", String.Empty); typeName = namerNode.GetAttribute("type", String.Empty); assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } try { Assembly assembly = Assembly.LoadFrom(assemblyPath); namer = (ApiNamer)assembly.CreateInstance(typeName); if (namer == null) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (BadImageFormatException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The component assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(1); } catch (TypeLoadException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (MissingMethodException) { ConsoleApplication.WriteMessage(LogLevel.Error, "No appropriate constructor exists for " + "the type'{0}' in the component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (TargetInvocationException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while initializing the " + "type '{0}' in the component assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(1); } catch (InvalidCastException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' in the component assembly " + "'{1}' is not a component type.", typeName, assemblyPath); return(1); } } // Create a resolver AssemblyResolver resolver = new AssemblyResolver(); XPathNavigator resolverNode = configNav.SelectSingleNode("/configuration/dduetools/resolver"); if (resolverNode != null) { assemblyPath = resolverNode.GetAttribute("assembly", String.Empty); typeName = resolverNode.GetAttribute("type", String.Empty); assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } try { Assembly assembly = Assembly.LoadFrom(assemblyPath); resolver = (AssemblyResolver)assembly.CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, null, new object[1] { resolverNode }, null, null); if (resolver == null) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (BadImageFormatException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The component assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(1); } catch (TypeLoadException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (MissingMethodException) { ConsoleApplication.WriteMessage(LogLevel.Error, "No appropriate constructor exists for " + "the type'{0}' in the component assembly '{1}'.", typeName, assemblyPath); return(1); } catch (TargetInvocationException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while initializing the " + "type '{0}' in the component assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(1); } catch (InvalidCastException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' in the component assembly " + "'{1}' is not a component type.", typeName, assemblyPath); return(1); } } resolver.UnresolvedAssemblyReference += UnresolvedAssemblyReferenceHandler; // Get a text writer for output TextWriter output = Console.Out; if (results.Options["out"].IsPresent) { string file = (string)results.Options["out"].Value; try { output = new StreamWriter(file, false, Encoding.UTF8); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to " + "create an output file. The error message is: {0}", e.Message); return(1); } catch (UnauthorizedAccessException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while attempting to " + "create an output file. The error message is: {0}", e.Message); return(1); } } try { // Create a writer string sourceCodeBasePath = (string)configNav.Evaluate( "string(/configuration/dduetools/sourceContext/@basePath)"); bool warnOnMissingContext = false; if (!String.IsNullOrWhiteSpace(sourceCodeBasePath)) { warnOnMissingContext = (bool)configNav.Evaluate( "boolean(/configuration/dduetools/sourceContext[@warnOnMissingSourceContext='true'])"); } else { ConsoleApplication.WriteMessage(LogLevel.Info, "No source code context base path " + "specified. Source context information is unavailable."); } ApiVisitor = new ManagedReflectionWriter(output, namer, resolver, sourceCodeBasePath, warnOnMissingContext, new ApiFilter(configNav.SelectSingleNode("/configuration/dduetools"))); // Register add-ins to the builder XPathNodeIterator addinNodes = configNav.Select("/configuration/dduetools/addins/addin"); foreach (XPathNavigator addinNode in addinNodes) { assemblyPath = addinNode.GetAttribute("assembly", String.Empty); typeName = addinNode.GetAttribute("type", String.Empty); assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } try { Assembly assembly = Assembly.LoadFrom(assemblyPath); MRefBuilderAddIn addin = (MRefBuilderAddIn)assembly.CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, null, new object[2] { ApiVisitor, addinNode }, null, null); if (addin == null) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in " + "the add-in assembly '{1}'.", typeName, assemblyPath); return(1); } } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the add-in assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(1); } catch (BadImageFormatException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The add-in assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(1); } catch (TypeLoadException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "add-in assembly '{1}'.", typeName, assemblyPath); return(1); } catch (MissingMethodException) { ConsoleApplication.WriteMessage(LogLevel.Error, "No appropriate constructor exists " + "for the type '{0}' in the add-in assembly '{1}'.", typeName, assemblyPath); return(1); } catch (TargetInvocationException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while initializing " + "the type '{0}' in the add-in assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(1); } catch (InvalidCastException) { ConsoleApplication.WriteMessage(LogLevel.Error, "The type '{0}' in the add-in " + "assembly '{1}' is not an MRefBuilderAddIn type.", typeName, assemblyPath); return(1); } } // Load dependencies foreach (string dependency in dependencies) { try { // Expand environment variables path = Environment.ExpandEnvironmentVariables(dependency); // If x86 but it didn't exist, assume it's a 32-bit system and change the name if (path.IndexOf("%ProgramFiles(x86)%", StringComparison.Ordinal) != -1) { path = Environment.ExpandEnvironmentVariables(path.Replace("(x86)", String.Empty)); } ApiVisitor.LoadAccessoryAssemblies(path); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while loading " + "dependency assemblies. The error message is: {0}", e.Message); return(1); } } // Parse the assemblies foreach (string dllPath in results.UnusedArguments.OrderBy(d => d.IndexOf("System.Runtime.dll", StringComparison.OrdinalIgnoreCase) != -1 ? 0 : d.IndexOf("netstandard.dll", StringComparison.OrdinalIgnoreCase) != -1 ? 1 : d.IndexOf("mscorlib.dll", StringComparison.OrdinalIgnoreCase) != -1 ? 2 : 3)) { try { // Expand environment variables path = Environment.ExpandEnvironmentVariables(dllPath); // If x86 but it didn't exist, assume it's a 32-bit system and change the name if (path.IndexOf("%ProgramFiles(x86)%", StringComparison.Ordinal) != -1) { path = Environment.ExpandEnvironmentVariables(path.Replace("(x86)", String.Empty)); } ApiVisitor.LoadAssemblies(path); } catch (IOException e) { ConsoleApplication.WriteMessage(LogLevel.Error, "An error occurred while loading " + "assemblies for reflection. The error message is: {0}", e.Message); return(1); } } ConsoleApplication.WriteMessage(LogLevel.Info, "Loaded {0} assemblies for reflection and " + "{1} dependency assemblies.", ApiVisitor.Assemblies.Count(), ApiVisitor.AccessoryAssemblies.Count()); ApiVisitor.VisitApis(); if (ApiVisitor.Canceled) { ConsoleApplication.WriteMessage(LogLevel.Error, "MRefBuilder task canceled"); } else { ConsoleApplication.WriteMessage(LogLevel.Info, "Wrote information on {0} namespaces, " + "{1} types, and {2} members", ApiVisitor.NamespaceCount, ApiVisitor.TypeCount, ApiVisitor.MemberCount); } } finally { if (ApiVisitor != null) { ApiVisitor.Dispose(); } if (results.Options["out"].IsPresent) { output.Close(); } } return((ApiVisitor != null && ApiVisitor.Canceled) ? 2 : 0); }
//===================================================================== /// <summary> /// Main program entry point (MSBuild task) /// </summary> /// <returns>True on success or false failure</returns> public bool GenerateReflectionInformation() { string path, version, framework = null, assemblyPath, typeName; // Load the configuration file XPathDocument config; XPathNavigator configNav; string configDirectory = Path.GetDirectoryName(this.ConfigurationFile); try { config = new XPathDocument(this.ConfigurationFile); configNav = config.CreateNavigator(); } catch (IOException e) { this.WriteMessage(LogLevel.Error, "An error occurred while attempting to read " + "the configuration file '{0}'. The error message is: {1}", this.ConfigurationFile, e.Message); return(false); } catch (UnauthorizedAccessException e) { this.WriteMessage(LogLevel.Error, "An error occurred while attempting to read " + "the configuration file '{0}'. The error message is: {1}", this.ConfigurationFile, e.Message); return(false); } catch (XmlException e) { this.WriteMessage(LogLevel.Error, "The configuration file '{0}' is not " + "well-formed. The error message is: {1}", this.ConfigurationFile, e.Message); return(false); } // Adjust the target platform var platformNode = configNav.SelectSingleNode("/configuration/dduetools/platform"); if (platformNode == null) { this.WriteMessage(LogLevel.Error, "A platform element is required to define the " + "framework type and version to use."); return(false); } // !EFW - Use the framework definition file to load core framework assembly reference information version = platformNode.GetAttribute("version", String.Empty); framework = platformNode.GetAttribute("framework", String.Empty); // Get component locations used to find additional reflection data definition files List <string> componentFolders = new List <string>(); var locations = configNav.SelectSingleNode("/configuration/dduetools/componentLocations"); if (locations != null) { foreach (XPathNavigator folder in locations.Select("location/@folder")) { if (!String.IsNullOrWhiteSpace(folder.Value) && Directory.Exists(folder.Value)) { componentFolders.Add(folder.Value); } } } // Get the dependencies var dependencies = new List <string>(); if (this.References != null) { dependencies.AddRange(this.References.Select(r => r.ItemSpec)); } if (!String.IsNullOrEmpty(framework) && !String.IsNullOrEmpty(version)) { var coreNames = new HashSet <string>(new[] { "netstandard", "mscorlib", "System.Runtime" }, StringComparer.OrdinalIgnoreCase); var coreFrameworkAssemblies = this.Assemblies.Select(a => a.ItemSpec).Concat(dependencies).Where( d => coreNames.Contains(Path.GetFileNameWithoutExtension(d))); TargetPlatform.SetFrameworkInformation(framework, version, componentFolders, coreFrameworkAssemblies); } else { this.WriteMessage(LogLevel.Error, "Unknown target framework version '{0} {1}'.", framework, version); return(false); } // Create an API member namer ApiNamer namer; // Apply a different naming method to assemblies using these frameworks if (framework == PlatformType.DotNetCore || framework == PlatformType.DotNetPortable || framework == PlatformType.WindowsPhone || framework == PlatformType.WindowsPhoneApp) { namer = new WindowsStoreAndPhoneNamer(); } else { namer = new OrcasNamer(); } XPathNavigator namerNode = configNav.SelectSingleNode("/configuration/dduetools/namer"); if (namerNode != null) { assemblyPath = namerNode.GetAttribute("assembly", String.Empty); typeName = namerNode.GetAttribute("type", String.Empty); if (!String.IsNullOrWhiteSpace(assemblyPath)) { assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } } try { Assembly assembly = !String.IsNullOrWhiteSpace(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : Assembly.GetExecutingAssembly(); namer = (ApiNamer)assembly.CreateInstance(typeName); if (namer == null) { this.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assembly.Location); return(false); } } catch (IOException e) { this.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(false); } catch (UnauthorizedAccessException e) { this.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(false); } catch (BadImageFormatException) { this.WriteMessage(LogLevel.Error, "The component assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(false); } catch (TypeLoadException) { this.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(false); } catch (MissingMethodException) { this.WriteMessage(LogLevel.Error, "No appropriate constructor exists for " + "the type'{0}' in the component assembly '{1}'.", typeName, assemblyPath); return(false); } catch (TargetInvocationException e) { this.WriteMessage(LogLevel.Error, "An error occurred while initializing the " + "type '{0}' in the component assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(false); } catch (InvalidCastException) { this.WriteMessage(LogLevel.Error, "The type '{0}' in the component assembly " + "'{1}' is not a component type.", typeName, assemblyPath); return(false); } } // Create a resolver AssemblyResolver resolver = new AssemblyResolver(); XPathNavigator resolverNode = configNav.SelectSingleNode("/configuration/dduetools/resolver"); if (resolverNode != null) { assemblyPath = resolverNode.GetAttribute("assembly", String.Empty); typeName = resolverNode.GetAttribute("type", String.Empty); if (!String.IsNullOrWhiteSpace(assemblyPath)) { assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } } try { Assembly assembly = !String.IsNullOrWhiteSpace(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : Assembly.GetExecutingAssembly(); resolver = (AssemblyResolver)assembly.CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, null, new object[1] { resolverNode }, null, null); if (resolver == null) { this.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assembly.Location); return(false); } } catch (IOException e) { this.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(false); } catch (UnauthorizedAccessException e) { this.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the component assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(false); } catch (BadImageFormatException) { this.WriteMessage(LogLevel.Error, "The component assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(false); } catch (TypeLoadException) { this.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "component assembly '{1}'.", typeName, assemblyPath); return(false); } catch (MissingMethodException) { this.WriteMessage(LogLevel.Error, "No appropriate constructor exists for " + "the type'{0}' in the component assembly '{1}'.", typeName, assemblyPath); return(false); } catch (TargetInvocationException e) { this.WriteMessage(LogLevel.Error, "An error occurred while initializing the " + "type '{0}' in the component assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(false); } catch (InvalidCastException) { this.WriteMessage(LogLevel.Error, "The type '{0}' in the component assembly " + "'{1}' is not a component type.", typeName, assemblyPath); return(false); } } resolver.MessageLogger = (lvl, msg) => this.WriteMessage(lvl, msg); resolver.UnresolvedAssemblyReference += UnresolvedAssemblyReferenceHandler; // Get a text writer for output TextWriter output; try { output = new StreamWriter(this.ReflectionFilename, false, Encoding.UTF8); } catch (IOException e) { this.WriteMessage(LogLevel.Error, "An error occurred while attempting to " + "create an output file. The error message is: {0}", e.Message); return(false); } catch (UnauthorizedAccessException e) { this.WriteMessage(LogLevel.Error, "An error occurred while attempting to " + "create an output file. The error message is: {0}", e.Message); return(false); } try { // Create a writer string sourceCodeBasePath = (string)configNav.Evaluate( "string(/configuration/dduetools/sourceContext/@basePath)"); bool warnOnMissingContext = false; if (!String.IsNullOrWhiteSpace(sourceCodeBasePath)) { warnOnMissingContext = (bool)configNav.Evaluate( "boolean(/configuration/dduetools/sourceContext[@warnOnMissingSourceContext='true'])"); } else { this.WriteMessage(LogLevel.Info, "No source code context base path " + "specified. Source context information is unavailable."); } apiVisitor = new ManagedReflectionWriter(output, namer, resolver, sourceCodeBasePath, warnOnMissingContext, new ApiFilter(configNav.SelectSingleNode("/configuration/dduetools"))) { MessageLogger = (lvl, msg) => this.WriteMessage(lvl, msg) }; // Register add-ins to the builder XPathNodeIterator addinNodes = configNav.Select("/configuration/dduetools/addins/addin"); foreach (XPathNavigator addinNode in addinNodes) { assemblyPath = addinNode.GetAttribute("assembly", String.Empty); typeName = addinNode.GetAttribute("type", String.Empty); if (!String.IsNullOrWhiteSpace(assemblyPath)) { assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); if (!Path.IsPathRooted(assemblyPath)) { assemblyPath = Path.Combine(configDirectory, assemblyPath); } } try { Assembly assembly = !String.IsNullOrWhiteSpace(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : Assembly.GetExecutingAssembly(); MRefBuilderAddIn addin = (MRefBuilderAddIn)assembly.CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, null, new object[2] { apiVisitor, addinNode }, null, null); if (addin == null) { this.WriteMessage(LogLevel.Error, "The type '{0}' was not found in " + "the add-in assembly '{1}'.", typeName, assembly.Location); return(false); } } catch (IOException e) { this.WriteMessage(LogLevel.Error, "A file access error occurred while " + "attempting to load the add-in assembly '{0}'. The error message is: {1}", assemblyPath, e.Message); return(false); } catch (BadImageFormatException) { this.WriteMessage(LogLevel.Error, "The add-in assembly '{0}' is not a " + "valid managed assembly.", assemblyPath); return(false); } catch (TypeLoadException) { this.WriteMessage(LogLevel.Error, "The type '{0}' was not found in the " + "add-in assembly '{1}'.", typeName, assemblyPath); return(false); } catch (MissingMethodException) { this.WriteMessage(LogLevel.Error, "No appropriate constructor exists " + "for the type '{0}' in the add-in assembly '{1}'.", typeName, assemblyPath); return(false); } catch (TargetInvocationException e) { this.WriteMessage(LogLevel.Error, "An error occurred while initializing " + "the type '{0}' in the add-in assembly '{1}'. The error message and stack trace " + "follows: {2}", typeName, assemblyPath, e.InnerException); return(false); } catch (InvalidCastException) { this.WriteMessage(LogLevel.Error, "The type '{0}' in the add-in " + "assembly '{1}' is not an MRefBuilderAddIn type.", typeName, assemblyPath); return(false); } } // Load dependencies foreach (string dependency in dependencies) { try { // Expand environment variables path = Environment.ExpandEnvironmentVariables(dependency); // If x86 but it didn't exist, assume it's a 32-bit system and change the name if (path.IndexOf("%ProgramFiles(x86)%", StringComparison.Ordinal) != -1) { path = Environment.ExpandEnvironmentVariables(path.Replace("(x86)", String.Empty)); } apiVisitor.LoadAccessoryAssemblies(path); } catch (IOException e) { this.WriteMessage(LogLevel.Error, "An error occurred while loading " + "dependency assemblies. The error message is: {0}", e.Message); return(false); } } // Parse the assemblies foreach (string dllPath in this.Assemblies.Select(a => a.ItemSpec).OrderBy(d => d.IndexOf("System.Runtime.dll", StringComparison.OrdinalIgnoreCase) != -1 ? 0 : d.IndexOf("netstandard.dll", StringComparison.OrdinalIgnoreCase) != -1 ? 1 : d.IndexOf("mscorlib.dll", StringComparison.OrdinalIgnoreCase) != -1 ? 2 : 3)) { try { // Expand environment variables path = Environment.ExpandEnvironmentVariables(dllPath); // If x86 but it didn't exist, assume it's a 32-bit system and change the name if (path.IndexOf("%ProgramFiles(x86)%", StringComparison.Ordinal) != -1) { path = Environment.ExpandEnvironmentVariables(path.Replace("(x86)", String.Empty)); } apiVisitor.LoadAssemblies(path); } catch (IOException e) { this.WriteMessage(LogLevel.Error, "An error occurred while loading " + "assemblies for reflection. The error message is: {0}", e.Message); return(false); } } this.WriteMessage(LogLevel.Info, "Loaded {0} assemblies for reflection and " + "{1} dependency assemblies.", apiVisitor.Assemblies.Count(), apiVisitor.AccessoryAssemblies.Count()); apiVisitor.VisitApis(); if (apiVisitor.Canceled) { this.WriteMessage(LogLevel.Error, "MRefBuilder task canceled"); } else { this.WriteMessage(LogLevel.Info, "Wrote information on {0} namespaces, " + "{1} types, and {2} members", apiVisitor.NamespaceCount, apiVisitor.TypeCount, apiVisitor.MemberCount); this.WriteMessage(LogLevel.Info, "Merging duplicate type and member information"); var(mergedTypes, mergedMembers) = apiVisitor.MergeDuplicateReflectionData(this.ReflectionFilename); this.WriteMessage(LogLevel.Info, "Merged {0} duplicate type(s) and {1} " + "duplicate member(s)", mergedTypes, mergedMembers); } } finally { if (apiVisitor != null) { apiVisitor.Dispose(); } if (output != null) { output.Close(); } } return(apiVisitor != null && !apiVisitor.Canceled); }