using System; using System.Collections.Generic; using System.Linq; using System.Xml; using System.IO; using AWSPowerShellGenerator.Generators; using System.Reflection; using AWSPowerShellGenerator.Utils; namespace AWSPowerShellGenerator { /// /// Generation controller for the AWS PowerShell tools. /// public class Generator { private long? _startTimeTicks; const string ModulesSubFolder = "modules"; const string DeploymentArtifactsSubFolder = "Deployment"; string DocBuildOutputSubFolder => Path.Combine("DocDeployment", "docs"); internal const string AWSPowerShellDllName = "AWSPowerShell.NetCore"; internal const string AWSPowerShellCommonDllName = "AWS.Tools.Common"; const string AWSPowerShellModuleName = "AWSPowerShell"; // Varies depending on editon and configuration internal string BinSubFolder { get; private set; } /// /// How long the generation tasks took. /// public TimeSpan Duration { get { if (!_startTimeTicks.HasValue) throw new InvalidOperationException("Execute(...) method has not been called, no run duration data available"); return new TimeSpan(DateTime.Now.Ticks - _startTimeTicks.Value); } } /// /// Runs one or more generation tasks. /// /// public void Execute(GeneratorOptions options) { // this is just to record the run duration, so we can monitor and optimize // build-time perf _startTimeTicks = DateTime.Now.Ticks; if (options.Tasks == null || options.Tasks.Count == 0) throw new Exception("No tasks specified for the generator to run"); if (options.Verbose) { // todo: echo out generator options } #if DEBUG var configuration = "Debug"; #else var configuration = "Release"; #endif BinSubFolder = Path.Combine("bin", configuration, options.TargetFramework); var fqRootPath = options.RootPath; var sdkAssembliesFolder = options.SdkAssembliesFolder; var awsPowerShellSourcePath = Path.Combine(fqRootPath, ModulesSubFolder, AWSPowerShellModuleName); var deploymentArtifactsPath = Path.Combine(fqRootPath, options.GetEditionOutputFolder(DeploymentArtifactsSubFolder)); if (options.ShouldRunTask(GeneratorTasknames.GenerateCmdlets)) { Console.WriteLine("Executing task 'GenerateCmdlets'"); var cmdletGenerator = new CmdletGenerator { SdkAssembliesFolder = sdkAssembliesFolder, OutputFolder = awsPowerShellSourcePath, Options = options }; cmdletGenerator.Generate(); // Note: the remaining tasks rely on having a built copy of the AWSPowerShell module, // so we exit so that a build can take place and the generator then re-run with the // new tasks Console.WriteLine("Task 'GenerateCmdlets' complete, exiting..."); return; } var basePath = string.IsNullOrEmpty(options.BuiltModulesLocation) ? Path.Combine(awsPowerShellSourcePath, BinSubFolder) : options.BuiltModulesLocation; var awsPsXmlPath = Path.Combine(basePath, options.AssemblyName + ".XML"); var awsPsDllPath = Path.Combine(basePath, options.AssemblyName + ".dll"); var awsPowerShellAssembly = Assembly.LoadFrom(awsPsDllPath); if (options.ShouldRunTask(GeneratorTasknames.GenerateFormats)) { Console.WriteLine("Executing task 'GenerateFormats'"); bool includeCore = options.AssemblyName.Equals(AWSPowerShellDllName, StringComparison.OrdinalIgnoreCase) || options.AssemblyName.Equals(AWSPowerShellCommonDllName, StringComparison.OrdinalIgnoreCase); var targetAssemblies = new List { awsPowerShellAssembly }; var sdkAssemblies = awsPowerShellAssembly.GetReferencedAssemblies() .Where(assembly => assembly.Name.StartsWith("AWSSDK.", StringComparison.OrdinalIgnoreCase) && (includeCore || !assembly.Name.Equals("AWSSDK.Core", StringComparison.OrdinalIgnoreCase))) .ToArray(); targetAssemblies.AddRange(sdkAssemblies.Select(assembly => Assembly.LoadFrom(Path.Combine(sdkAssembliesFolder, GenerationSources.DotNetPlatformNetStandard20, assembly.Name + ".dll")))); targetAssemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().Where(assembly => sdkAssemblies.Contains(assembly.GetName()))); var formatsGenerator = new FormatGenerator { OutputFolder = basePath, Name = options.AssemblyName, TargetAssemblies = targetAssemblies, Options = options }; formatsGenerator.Generate(); } if (options.ShouldRunTask(GeneratorTasknames.GeneratePsHelp)) { Console.WriteLine("Executing task 'GeneratePshelp'"); var cmdletDocumentation = new XmlDocument(); cmdletDocumentation.Load(awsPsXmlPath); // For modular versions of AWS Tools module, load additional help for common parameters defined in AWS.Tools.Common. LoadCommonParameterHelpForModularVersion(options, basePath, cmdletDocumentation); var pshelpGenerator = new PsHelpGenerator { CmdletAssembly = awsPowerShellAssembly, AssemblyDocumentation = cmdletDocumentation, Name = options.AssemblyName, OutputFolder = basePath, Options = options }; pshelpGenerator.Generate(); } if (options.ShouldRunTask(GeneratorTasknames.GenerateWebHelp)) { Console.WriteLine("Executing task 'GenerateWebhelp'"); var cmdletDocumentation = new XmlDocument(); cmdletDocumentation.Load(awsPsXmlPath); string docOutputFolder; if (string.IsNullOrEmpty(options.DocOutputFolder)) docOutputFolder = Path.Combine(fqRootPath, DocBuildOutputSubFolder); else docOutputFolder = options.DocOutputFolder; var webhelpGenerator = new WebHelpGenerator { CmdletAssembly = awsPowerShellAssembly, AssemblyDocumentation = cmdletDocumentation, Name = AWSPowerShellModuleName, OutputFolder = docOutputFolder, CNNorth1RegionDocsDomain = options.CNNorth1RegionDocsDomain, Options = options }; webhelpGenerator.Generate(); } } private static void LoadCommonParameterHelpForModularVersion(GeneratorOptions options, string basePath, XmlDocument cmdletDocumentation) { if (options.AssemblyName.StartsWith("AWS.Tools", StringComparison.OrdinalIgnoreCase)) { string membersXpath = "doc/members"; // Include help for parameters defined in AWS.Tools.Common. string awsToolsCommonHelpXmlPath = Path.Combine(basePath, "AWS.Tools.Common.XML"); if (!File.Exists(awsToolsCommonHelpXmlPath)) { Console.WriteLine(string.Format("WARNING: Unable to find file {0} to load help for common parameters.", awsToolsCommonHelpXmlPath)); return; } var awsToolsCommonDocumentation = new XmlDocument(); awsToolsCommonDocumentation.Load(awsToolsCommonHelpXmlPath); var awsToolsCommonDocMembersNode = awsToolsCommonDocumentation.SelectSingleNode(membersXpath); if (awsToolsCommonDocMembersNode?.ChildNodes.Count > 0) { var cmdletDocMembersNode = cmdletDocumentation.SelectSingleNode(membersXpath); foreach (XmlNode commonChildMemberNode in awsToolsCommonDocMembersNode.ChildNodes) { XmlNode importedNode = cmdletDocMembersNode.OwnerDocument.ImportNode(commonChildMemberNode, true); cmdletDocMembersNode.AppendChild(importedNode); } } } } } }