/// <summary> /// Represents a single service, supported on one or more platforms, that we will be /// generating documentation for. /// </summary> /// <param name="assemblyPath"> /// The full path and filename of the assembly. The .Net platform for the assembly /// is assumed to be the name of the folder containing the assembly. The name of the /// service will be inferred from the name pattern of the assembly. /// </param> /// <param name="outputFolderRoot"> /// The root output folder that the artifacts should be placed in. A further subfolder /// representing the service (or 'core' if the assembly is the runtime) is added. /// </param> /// <param name="allPlatforms">The set of platform subfolders to use to discover ndoc tables</param> /// <param name="options">The user options governing doc generation</param> /// <param name="useAppDomain"></param> public GenerationManifest(string assemblyPath, string outputFolderRoot, IEnumerable<string> allPlatforms, GeneratorOptions options, bool useAppDomain) { AssemblyPath = Path.GetFullPath(assemblyPath); var assemblyName = Path.GetFileNameWithoutExtension(AssemblyPath); ServiceName = assemblyName.StartsWith(AWSAssemblyNamePrefix + ".", StringComparison.OrdinalIgnoreCase) ? assemblyName.Substring(AWSAssemblyNamePrefix.Length + 1) : assemblyName; Options = options; AssemblyWrapper = CreateAssemblyWrapper(AssemblyPath, useAppDomain); OutputFolder = Path.GetFullPath(outputFolderRoot); foreach(var platform in allPlatforms) { NDocUtilities.LoadDocumentation(assemblyName, ServiceName, platform, options); } if (Options.Verbose) { Trace.WriteLine("\tConstructed GenerationManifest:"); Trace.WriteLine(String.Format("\t...AssemblyPath: {0}", AssemblyPath)); Trace.WriteLine(String.Format("\t...ServiceName: {0}", ServiceName)); Trace.WriteLine(String.Format("\t...OutputFolder: {0}", OutputFolder)); } }
public static void LoadDocumentation(string assemblyName, string serviceName, string platform, GeneratorOptions options) { string docId = null; var ndocFilename = assemblyName + ".xml"; var platformSpecificNdocFile = Path.Combine(options.SDKAssembliesRoot, platform, ndocFilename); if (File.Exists(platformSpecificNdocFile)) { docId = GenerateDocId(serviceName, platform); _ndocCache.Add(docId, CreateNDocTable(platformSpecificNdocFile, serviceName, options)); } }
private static IDictionary<string, XElement> CreateNDocTable(string filePath, string serviceName, GeneratorOptions options) { var dict = new Dictionary<string, XElement>(); var document = LoadAssemblyDocumentationWithSamples(filePath, options.CodeSamplesRootFolder, serviceName); PreprocessCodeBlocksToPreTags(options, document); foreach (var element in document.XPathSelectElements("//members/member")) { var xattribute = element.Attributes().FirstOrDefault(x => x.Name.LocalName == "name"); if (xattribute == null) continue; dict[xattribute.Value] = element; } return dict; }
/// <summary> /// Represents a single service, supported on one or more platforms, that we will be /// generating documentation for. /// </summary> /// <param name="assemblyPath"> /// The full path and filename of the assembly. The .Net platform for the assembly /// is assumed to be the name of the folder containing the assembly. The name of the /// service will be inferred from the name pattern of the assembly. /// </param> /// <param name="outputFolderRoot"> /// The root output folder that the artifacts should be placed in. A further subfolder /// representing the service (or 'core' if the assembly is the runtime) is added. /// </param> /// <param name="allPlatforms">The set of platform subfolders to use to discover ndoc tables</param> /// <param name="options">The user options governing doc generation</param> /// <param name="useAppDomain"></param> public GenerationManifest(string assemblyPath, string outputFolderRoot, IEnumerable<string> allPlatforms, GeneratorOptions options, bool useAppDomain) { AssemblyPath = Path.GetFullPath(assemblyPath); Options = options; AssemblyWrapper = CreateAssemblyWrapper(AssemblyPath, useAppDomain); OutputFolder = Path.GetFullPath(outputFolderRoot); var assemblyName = Path.GetFileNameWithoutExtension(AssemblyPath); ServiceName = assemblyName.StartsWith(AWSAssemblyNamePrefix + ".", StringComparison.OrdinalIgnoreCase) ? assemblyName.Substring(AWSAssemblyNamePrefix.Length+1) : assemblyName; NDocTables = new Dictionary<string, IDictionary<string, XElement>>(); var ndocFilename = assemblyName + ".xml"; foreach (var p in allPlatforms) { var platformSpecificNdocFile = Path.Combine(Options.SDKAssembliesRoot, p, ndocFilename); if (File.Exists(platformSpecificNdocFile)) { var platformNDoc = CreateNDocTable(platformSpecificNdocFile); NDocTables.Add(p, platformNDoc); } } if (Options.Verbose) { Trace.WriteLine("\tConstructed GenerationManifest:"); Trace.WriteLine(String.Format("\t...AssemblyPath: {0}", AssemblyPath)); Trace.WriteLine(String.Format("\t...ServiceName: {0}", ServiceName)); Trace.WriteLine(String.Format("\t...OutputFolder: {0}", OutputFolder)); } }
public static void PreprocessCodeBlocksToPreTags(GeneratorOptions options, XDocument doc) { var nodesToRemove = new List<XElement>(); var codeNodes = doc.XPathSelectElements("//code"); foreach (var codeNode in codeNodes) { string processedCodeSample = null; var xattribute = codeNode.Attributes().FirstOrDefault(x => x.Name.LocalName == "source"); if (xattribute != null) { var sourceRelativePath = xattribute.Value; xattribute = codeNode.Attributes().FirstOrDefault(x => x.Name.LocalName == "region"); if (xattribute == null) continue; var regionName = xattribute.Value; var samplePath = FindSampleCodePath(options.CodeSamplesRootFolder, sourceRelativePath); if (samplePath == null) { Console.Error.WriteLine("Error finding sample path for {0}", sourceRelativePath); continue; } var content = File.ReadAllText(samplePath); var startPos = content.IndexOf("#region " + regionName); if (startPos == -1) { Console.Error.WriteLine("Error finding region for {0}", regionName); continue; } startPos = content.IndexOf('\n', startPos); var endPos = content.IndexOf("#endregion", startPos); processedCodeSample = content.Substring(startPos, endPos - startPos); } else { processedCodeSample = codeNode.Value; } if (processedCodeSample != null && processedCodeSample.IndexOf('\n') > -1) { processedCodeSample = LeftJustifyCodeBlocks(processedCodeSample); var preElement = new XElement("pre", processedCodeSample); preElement.SetAttributeValue("class", "brush: csharp"); codeNode.AddAfterSelf(preElement); nodesToRemove.Add(codeNode); string title = null; xattribute = codeNode.Attributes().FirstOrDefault(x => x.Name.LocalName == "title"); if (xattribute != null) title = xattribute.Value; if (title != null) { var titleElement = new XElement("h4", title); titleElement.SetAttributeValue("class", "csharp-code-sample-title"); preElement.AddBeforeSelf(titleElement); } } } nodesToRemove.ForEach(x => x.Remove()); }
/// <summary> /// Runs the doc generator to produce or update a consistent documentation /// set for the SDK. /// </summary> /// <param name="options"></param> /// <returns>0 on successful completion</returns> public int Execute(GeneratorOptions options) { // this is just to record the run duration, so we can monitor and optimize // build-time perf _startTimeTicks = DateTime.Now.Ticks; Options = options; Trace.Listeners.Add(new ConditionalConsoleTraceListener(Options.Verbose)); if (Options.TestMode) SetOptionsForTestMode(); if (string.IsNullOrEmpty(Options.SDKAssembliesRoot)) { Info("ERROR: SDKAssembliesRoot option not set"); return -1; } if (Options.Verbose) { Info("Starting generation with options:"); Info("...TestMode: {0}", Options.TestMode); Info("...Clean: {0}", Options.Clean); Info("...WriteStaticContent: {0}", Options.WriteStaticContent); Info("...WaitOnExit: {0}", Options.WaitOnExit); Info(""); Info("...SDKAssembliesRoot: {0}", Options.SDKAssembliesRoot); Info("...OutputFolder: {0}", Options.OutputFolder); Info("...Platform: {0}", Options.Platform); Info("...Services: {0}", string.Join(",", Options.Services)); Info("...CodeSamplesRootFolder: {0}", Options.CodeSamplesRootFolder); Info(""); } if (options.Clean) FileUtilties.CleanFolder(options.OutputFolder, true); if (!Directory.Exists(options.OutputFolder)) Directory.CreateDirectory(options.OutputFolder); // use the sdk root and primary platform to determine the set of // service manifests to process var manifests = ConstructGenerationManifests(); // and process them to produce the doc set Info("Processing manifests..."); foreach (var m in manifests) { m.Generate(); } // finish up by outputting/updating the TOC and emitting the static doc framework content if requested // we try and generate the toc based on the .Net 4.5 platform by preference, falling back as necessary GenerateTableOfContents(manifests); CopyVersionInfoManifest(); if (options.WriteStaticContent) { Info("Generating/copying static content:"); Info("...creating landing page"); var lpWriter = new LandingPageWriter(options); lpWriter.Write(); Info("...copying static resources"); var sourceLocation = Directory.GetParent(typeof(SdkDocGenerator).Assembly.Location).FullName; FileUtilties.FolderCopy(Path.Combine(sourceLocation, "output-files"), options.OutputFolder, true); } return 0; }
/// <summary> /// Runs the doc generator to produce or update a consistent documentation /// set for the SDK. /// </summary> /// <param name="options"></param> /// <returns>0 on successful completion</returns> public int Execute(GeneratorOptions options) { // this is just to record the run duration, so we can monitor and optimize // build-time perf _startTimeTicks = DateTime.Now.Ticks; Options = options; Trace.Listeners.Add(new ConditionalConsoleTraceListener(Options.Verbose)); if (Options.TestMode) SetOptionsForTestMode(); if (string.IsNullOrEmpty(Options.SDKAssembliesRoot)) { Info("ERROR: SDKAssembliesRoot option not set"); return -1; } if (Options.Verbose) { Info("Starting generation with options:"); Info("...TestMode: {0}", Options.TestMode); Info("...Clean: {0}", Options.Clean); Info("...WriteStaticContent: {0}", Options.WriteStaticContent); Info("...WaitOnExit: {0}", Options.WaitOnExit); Info(""); Info("...SDKAssembliesRoot: {0}", Options.SDKAssembliesRoot); Info("...OutputFolder: {0}", Options.OutputFolder); Info("...Platform: {0}", Options.Platform); Info("...Services: {0}", string.Join(",", Options.Services)); Info("...CodeSamplesRootFolder: {0}", Options.CodeSamplesRootFolder); Info(""); } if (options.Clean) FileUtilties.CleanFolder(options.OutputFolder, true); if (!Directory.Exists(options.OutputFolder)) Directory.CreateDirectory(options.OutputFolder); // use the sdk root and primary platform to determine the set of // service manifests to process var manifests = ConstructGenerationManifests(); // We want to aggregate all types(such as AmazonS3Config) under Amazon namespace before generating docs for Core. // Currently, the doc generator will stomp over files with conflicting namespaces across dll. If we encounter manifest // for Core, stash all its types and process it last. List<string> namespacesToIgnore = new List<string> { "Amazon", "Amazon.Util", "Amazon.Runtime", "Amazon.Runtime.SharedInterfaces" }; GenerationManifest coreManifest = null; PartialTypeProvider additionalTypeProvider = new PartialTypeProvider(null); foreach (var m in manifests) { if (m.ServiceName.Equals("Core", StringComparison.InvariantCultureIgnoreCase)) { coreManifest = m; continue; } m.Generate(namespacesToIgnore); foreach(var namespaceName in namespacesToIgnore) { additionalTypeProvider.ProcessTypes(m.AssemblyWrapper.GetTypesForNamespace(namespaceName)); } } coreManifest.AssemblyWrapper.SetSecondaryTypeProvider(additionalTypeProvider); coreManifest.Generate(null); // finish up by outputting/updating the TOC and emitting the static doc framework content if requested // we try and generate the toc based on the .Net 4.5 platform by preference, falling back as necessary GenerateTableOfContents(manifests); CopyVersionInfoManifest(); if (options.WriteStaticContent) { Info("Generating/copying static content:"); Info("...creating landing page"); var lpWriter = new LandingPageWriter(options); lpWriter.Write(); Info("...copying static resources"); var sourceLocation = Directory.GetParent(typeof(SdkDocGenerator).Assembly.Location).FullName; FileUtilties.FolderCopy(Path.Combine(sourceLocation, "output-files"), options.OutputFolder, true); } return 0; }
private static IDictionary <string, XElement> CreateNDocTable(string filePath, string serviceName, GeneratorOptions options) { var dict = new Dictionary <string, XElement>(); var document = LoadAssemblyDocumentationWithSamples(filePath, options.CodeSamplesRootFolder, serviceName); PreprocessCodeBlocksToPreTags(options, document); foreach (var element in document.XPathSelectElements("//members/member")) { var xattribute = element.Attributes().FirstOrDefault(x => x.Name.LocalName == "name"); if (xattribute == null) { continue; } dict[xattribute.Value] = element; } return(dict); }
public static void PreprocessCodeBlocksToPreTags(GeneratorOptions options, XDocument doc) { var nodesToRemove = new List <XElement>(); var codeNodes = doc.XPathSelectElements("//code"); foreach (var codeNode in codeNodes) { string processedCodeSample = null; var xattribute = codeNode.Attributes().FirstOrDefault(x => x.Name.LocalName == "source"); if (xattribute != null) { var sourceRelativePath = xattribute.Value; xattribute = codeNode.Attributes().FirstOrDefault(x => x.Name.LocalName == "region"); if (xattribute == null) { continue; } var regionName = xattribute.Value; var samplePath = FindSampleCodePath(options.CodeSamplesRootFolder, sourceRelativePath); if (samplePath == null) { Console.Error.WriteLine("Error finding sample path for {0}", sourceRelativePath); continue; } var content = File.ReadAllText(samplePath); var startPos = content.IndexOf("#region " + regionName); if (startPos == -1) { Console.Error.WriteLine("Error finding region for {0}", regionName); continue; } startPos = content.IndexOf('\n', startPos); var endPos = content.IndexOf("#endregion", startPos); var sampleCode = content.Substring(startPos, endPos - startPos); processedCodeSample = HttpUtility.HtmlEncode(sampleCode); } else { processedCodeSample = HttpUtility.HtmlEncode(codeNode.Value); } if (processedCodeSample != null && processedCodeSample.IndexOf('\n') > -1) { processedCodeSample = LeftJustifyCodeBlocks(processedCodeSample); var preElement = new XElement("pre", processedCodeSample); preElement.SetAttributeValue("class", "brush: csharp"); codeNode.AddAfterSelf(preElement); nodesToRemove.Add(codeNode); string title = null; xattribute = codeNode.Attributes().FirstOrDefault(x => x.Name.LocalName == "title"); if (xattribute != null) { title = xattribute.Value; } if (title != null) { var titleElement = new XElement("h4", title); titleElement.SetAttributeValue("class", "csharp-code-sample-title"); preElement.AddBeforeSelf(titleElement); } } } nodesToRemove.ForEach(x => x.Remove()); }
public static void LoadDocumentation(string assemblyName, string serviceName, string platform, GeneratorOptions options) { var ndocFilename = assemblyName + ".xml"; var platformSpecificNdocFile = Path.Combine(options.SDKAssembliesRoot, platform, ndocFilename); if (File.Exists(platformSpecificNdocFile)) { var docId = GenerateDocId(serviceName, platform); _ndocCache.Add(docId, CreateNDocTable(platformSpecificNdocFile, serviceName, options)); } }
/// <summary> /// Runs the doc generator to produce or update a consistent documentation /// set for the SDK. /// </summary> /// <param name="options"></param> /// <returns>0 on successful completion</returns> public int Execute(GeneratorOptions options) { // this is just to record the run duration, so we can monitor and optimize // build-time perf _startTimeTicks = DateTime.Now.Ticks; Options = options; Trace.Listeners.Add(new ConditionalConsoleTraceListener(Options.Verbose)); if (Options.TestMode) { SetOptionsForTestMode(); } if (string.IsNullOrEmpty(Options.SDKAssembliesRoot)) { Info("ERROR: SDKAssembliesRoot option not set"); return(-1); } if (Options.Verbose) { Info("Starting generation with options:"); Info("...TestMode: {0}", Options.TestMode); Info("...Clean: {0}", Options.Clean); Info("...WriteStaticContent: {0}", Options.WriteStaticContent); Info("...WaitOnExit: {0}", Options.WaitOnExit); Info(""); Info("...SDKAssembliesRoot: {0}", Options.SDKAssembliesRoot); Info("...OutputFolder: {0}", Options.OutputFolder); Info("...Platform: {0}", Options.Platform); Info("...Services: {0}", string.Join(",", Options.Services)); Info("...CodeSamplesRootFolder: {0}", Options.CodeSamplesRootFolder); Info(""); } if (options.Clean) { FileUtilties.CleanFolder(options.OutputFolder, true); } if (!Directory.Exists(options.OutputFolder)) { Directory.CreateDirectory(options.OutputFolder); } // use the sdk root and primary platform to determine the set of // service manifests to process var manifests = ConstructGenerationManifests(); TOCWriter = new TOCWriter(options); GenerationManifest coreManifest = null; DeferredTypesProvider deferredTypes = new DeferredTypesProvider(null); foreach (var m in manifests) { if (m.ServiceName.Equals("Core", StringComparison.InvariantCultureIgnoreCase)) { coreManifest = m; continue; } m.Generate(deferredTypes, TOCWriter); } // now all service assemblies are processed, handle core plus any types in those assemblies that // we elected to defer until we processed core. coreManifest.ManifestAssemblyContext.SdkAssembly.DeferredTypesProvider = deferredTypes; coreManifest.Generate(null, TOCWriter); Info("Generating table of contents entries..."); TOCWriter.Write(); CopyVersionInfoManifest(); if (options.WriteStaticContent) { Info("Generating/copying static content:"); Info("...creating landing page"); var lpWriter = new LandingPageWriter(options); lpWriter.Write(); Info("...copying static resources"); var sourceLocation = Directory.GetParent(typeof(SdkDocGenerator).Assembly.Location).FullName; FileUtilties.FolderCopy(Path.Combine(sourceLocation, "output-files"), options.OutputFolder, true); } // Write out all the redirect rules for doc cross-linking. using (Stream stream = File.Open(Path.Combine(options.OutputFolder, SDKDocRedirectWriter.RedirectFileName), FileMode.Create)) { SDKDocRedirectWriter.Write(stream); } return(0); }
private CommandArguments() { ParsedOptions = new GeneratorOptions(); }
/// <summary> /// Runs the doc generator to produce or update a consistent documentation /// set for the SDK. /// </summary> /// <param name="options"></param> /// <returns>0 on successful completion</returns> public int Execute(GeneratorOptions options) { // this is just to record the run duration, so we can monitor and optimize // build-time perf _startTimeTicks = DateTime.Now.Ticks; Options = options; Trace.Listeners.Add(new ConditionalConsoleTraceListener(Options.Verbose)); if (Options.TestMode) { SetOptionsForTestMode(); } if (string.IsNullOrEmpty(Options.SDKAssembliesRoot)) { Info("ERROR: SDKAssembliesRoot option not set"); return(-1); } if (Options.Verbose) { Info("Starting generation with options:"); Info("...TestMode: {0}", Options.TestMode); Info("...Clean: {0}", Options.Clean); Info("...WriteStaticContent: {0}", Options.WriteStaticContent); Info("...WaitOnExit: {0}", Options.WaitOnExit); Info(""); Info("...SDKAssembliesRoot: {0}", Options.SDKAssembliesRoot); Info("...OutputFolder: {0}", Options.OutputFolder); Info("...Platform: {0}", Options.Platform); Info("...Services: {0}", string.Join(",", Options.Services)); Info("...CodeSamplesRootFolder: {0}", Options.CodeSamplesRootFolder); Info(""); } if (options.Clean) { FileUtilties.CleanFolder(options.OutputFolder, true); } if (!Directory.Exists(options.OutputFolder)) { Directory.CreateDirectory(options.OutputFolder); } // use the sdk root and primary platform to determine the set of // service manifests to process var manifests = ConstructGenerationManifests(); // We want to aggregate all types(such as AmazonS3Config) under Amazon namespace before generating docs for Core. // Currently, the doc generator will stomp over files with conflicting namespaces across dll. If we encounter manifest // for Core, stash all its types and process it last. List <string> namespacesToIgnore = new List <string> { "Amazon", "Amazon.Util", "Amazon.Runtime", "Amazon.Runtime.SharedInterfaces" }; GenerationManifest coreManifest = null; PartialTypeProvider additionalTypeProvider = new PartialTypeProvider(null); foreach (var m in manifests) { if (m.ServiceName.Equals("Core", StringComparison.InvariantCultureIgnoreCase)) { coreManifest = m; continue; } m.Generate(namespacesToIgnore); foreach (var namespaceName in namespacesToIgnore) { additionalTypeProvider.ProcessTypes(m.AssemblyWrapper.GetTypesForNamespace(namespaceName)); } } coreManifest.AssemblyWrapper.SetSecondaryTypeProvider(additionalTypeProvider); coreManifest.Generate(null); // finish up by outputting/updating the TOC and emitting the static doc framework content if requested // we try and generate the toc based on the .Net 4.5 platform by preference, falling back as necessary GenerateTableOfContents(manifests); CopyVersionInfoManifest(); if (options.WriteStaticContent) { Info("Generating/copying static content:"); Info("...creating landing page"); var lpWriter = new LandingPageWriter(options); lpWriter.Write(); Info("...copying static resources"); var sourceLocation = Directory.GetParent(typeof(SdkDocGenerator).Assembly.Location).FullName; FileUtilties.FolderCopy(Path.Combine(sourceLocation, "output-files"), options.OutputFolder, true); } // Write out all the redirect rules for doc cross-linking. using (Stream stream = File.Open(Path.Combine(options.OutputFolder, SDKDocRedirectWriter.RedirectFileName), FileMode.Create)) { SDKDocRedirectWriter.Write(stream); } return(0); }
/// <summary> /// Runs the doc generator to produce or update a consistent documentation /// set for the SDK. /// </summary> /// <param name="options"></param> /// <returns>0 on successful completion</returns> public int Execute(GeneratorOptions options) { // this is just to record the run duration, so we can monitor and optimize // build-time perf _startTimeTicks = DateTime.Now.Ticks; Options = options; Trace.Listeners.Add(new ConditionalConsoleTraceListener(Options.Verbose)); if (Options.TestMode) { SetOptionsForTestMode(); } if (string.IsNullOrEmpty(Options.SDKAssembliesRoot)) { Info("ERROR: SDKAssembliesRoot option not set"); return(-1); } if (Options.Verbose) { Info("Starting generation with options:"); Info("...TestMode: {0}", Options.TestMode); Info("...Clean: {0}", Options.Clean); Info("...WriteStaticContent: {0}", Options.WriteStaticContent); Info("...WaitOnExit: {0}", Options.WaitOnExit); Info(""); Info("...SDKAssembliesRoot: {0}", Options.SDKAssembliesRoot); Info("...OutputFolder: {0}", Options.OutputFolder); Info("...Platform: {0}", Options.Platform); Info("...Services: {0}", string.Join(",", Options.Services)); Info("...CodeSamplesRootFolder: {0}", Options.CodeSamplesRootFolder); Info(""); } if (options.Clean) { FileUtilties.CleanFolder(options.OutputFolder, true); } if (!Directory.Exists(options.OutputFolder)) { Directory.CreateDirectory(options.OutputFolder); } // use the sdk root and primary platform to determine the set of // service manifests to process var manifests = ConstructGenerationManifests(); // and process them to produce the doc set Info("Processing manifests..."); foreach (var m in manifests) { m.Generate(); } // finish up by outputting/updating the TOC and emitting the static doc framework content if requested // we try and generate the toc based on the .Net 4.5 platform by preference, falling back as necessary GenerateTableOfContents(manifests); CopyVersionInfoManifest(); if (options.WriteStaticContent) { Info("Generating/copying static content:"); Info("...creating landing page"); var lpWriter = new LandingPageWriter(options); lpWriter.Write(); Info("...copying static resources"); var sourceLocation = Directory.GetParent(typeof(SdkDocGenerator).Assembly.Location).FullName; FileUtilties.FolderCopy(Path.Combine(sourceLocation, "output-files"), options.OutputFolder, true); } return(0); }