private static string CleanseSDKTypeDocumentation(string documentation) { bool isFirst = true; var modified = DocumentationUtils.ProcessLines(documentation, l => { string t = l; if (t.StartsWith(SDKLeadingSpaces, StringComparison.Ordinal)) { t = t.Substring(SDKLeadingSpaces.Length); } if (isFirst) { isFirst = false; if (t.StartsWith(SDKTypeFirstLineStart, StringComparison.Ordinal) && t.EndsWith(SDKTypeFirstLineEnd, StringComparison.Ordinal)) { return(null); } } return(t); }); string xml = RemoveOuterParaTag(modified); return(xml); }
protected override void GenerateHelper() { base.GenerateHelper(); if (string.IsNullOrEmpty(SDKHelpRoot)) { SDKHelpRoot = "http://docs.aws.amazon.com/sdkfornet/v3/apidocs/"; } else if (!SDKHelpRoot.EndsWith("/")) { SDKHelpRoot = SDKHelpRoot + "/"; } Console.WriteLine("Generating web help documentation:"); Console.WriteLine(".... SDK help base URI set to {0}", SDKHelpRoot); Console.WriteLine(".... writing doc output to {0}", OutputFolder); var buildLogsPath = Path.Combine(this.Options.RootPath, "logs"); if (!Directory.Exists(buildLogsPath)) { Directory.CreateDirectory(buildLogsPath); } var logFile = Path.Combine(buildLogsPath, Name + ".dll-WebHelp.log"); var oldWriter = Console.Out; try { using (var consoleWriter = new StreamWriter(File.OpenWrite(logFile))) { Console.SetOut(consoleWriter); CleanWebHelpOutputFolder(OutputFolder); CopyWebHelpStaticFiles(OutputFolder); CreateVersionInfoFile(Path.Combine(OutputFolder, "items")); var tocWriter = new TOCWriter(Options, OutputFolder); tocWriter.AddFixedSection(); Parallel.ForEach(CmdletTypes, (cmdletType) => { var(moduleName, serviceName) = DetermineCmdletServiceOwner(cmdletType); var cmdletInfo = InspectCmdletAttributes(cmdletType); string synopsis = null; if (cmdletInfo.AWSCmdletAttribute == null) { Console.WriteLine("Unable to find AWSCmdletAttribute for type " + cmdletType.FullName); } else { var cmdletReturnAttributeType = cmdletInfo.AWSCmdletAttribute.GetType(); synopsis = cmdletReturnAttributeType.GetProperty("Synopsis").GetValue(cmdletInfo.AWSCmdletAttribute, null) as string; } foreach (var cmdletAttribute in cmdletInfo.CmdletAttributes) { var typeDocumentation = DocumentationUtils.GetTypeDocumentation(cmdletType, AssemblyDocumentation); typeDocumentation = DocumentationUtils.FormatXMLForPowershell(typeDocumentation, true); Console.WriteLine($"Cmdlet = {cmdletType.FullName}"); Console.WriteLine($"Documentation = {typeDocumentation}"); var cmdletName = cmdletAttribute.VerbName + "-" + cmdletAttribute.NounName; var allProperties = GetRootSimpleProperties(cmdletType); var parameterPartitioning = new CmdletParameterSetPartitions(allProperties, cmdletAttribute.DefaultParameterSetName); var serviceAbbreviation = GetServiceAbbreviation(cmdletType); var cmdletPageWriter = new CmdletPageWriter(Options, OutputFolder, serviceName, moduleName, cmdletName); WriteDetails(cmdletPageWriter, typeDocumentation, synopsis, cmdletInfo.AWSCmdletAttribute); WriteSyntax(cmdletPageWriter, cmdletName, parameterPartitioning); WriteParameters(cmdletPageWriter, cmdletName, allProperties, false); WriteParameters(cmdletPageWriter, cmdletName, allProperties, true); WriteOutputs(cmdletPageWriter, cmdletInfo.AWSCmdletOutputAttributes); WriteNotes(cmdletPageWriter); WriteExamples(cmdletPageWriter, cmdletName); WriteRelatedLinks(cmdletPageWriter, serviceAbbreviation, cmdletName); cmdletPageWriter.Write(); lock (tocWriter) { var legacyAlias = InspectForLegacyAliasAttribution(moduleName, cmdletName, cmdletInfo.AWSCmdletAttribute); tocWriter.AddServiceCmdlet(moduleName, serviceName, cmdletName, cmdletPageWriter.GetTOCID(), synopsis, legacyAlias); } } }); tocWriter.Write(); WriteLegacyAliasesPage(); } } finally { Console.SetOut(oldWriter); } }
public static string FormatXMLForPowershell(string xml, bool forWebUse = false) { var sb = new StringBuilder(); using (var reader = new XmlTextReader(xml, XmlNodeType.Element, null)) { while (reader.Read()) { var type = reader.NodeType; var name = reader.Name.ToLowerInvariant(); var value = reader.Value; if (type == XmlNodeType.Element) { switch (name) { case "ul": case "ol": if (!forWebUse) { sb.AppendLine(); } else { sb.AppendFormat("<{0}>", name); } break; case "li": if (!forWebUse) { sb.AppendLine(); sb.Append(" -"); } else { sb.AppendFormat("<{0}>", name); } break; // very temp hack for ElastiCache in 2.3.5.0 release -- this is the only known set of table elements, // we want them in web help but not maml docs case "table": if (!forWebUse) { sb.Append(newAvailabilityZonesTableReplacement); do { reader.Read(); } while (!reader.Name.Equals("table", StringComparison.OrdinalIgnoreCase)); } else { sb.AppendFormat("<{0}>", name); } break; case "th": case "tr": case "td": case "div": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "dl": case "dt": case "dd": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "strong": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "pre": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "link": case "filename": case "replaceable": case "seealso": break; default: if (!HandleElement(sb, reader, name, forWebUse)) { throw new InvalidOperationException("Unsupported node of type " + name + ". Full XML: " + xml); } break; } } else if (type == XmlNodeType.EndElement) { switch (name) { case "li": if (!forWebUse) { sb.AppendLine(); } else { sb.AppendFormat("</{0}>", name); } break; case "ul": case "ol": if (!forWebUse) { sb.AppendLine(); sb.AppendLine(); } else { sb.AppendFormat("</{0}>", name); } break; // very temp hack for ElastiCache in 2.3.5.0 release -- this is the only known set of table elements, // we want them in web help but not maml docs case "table": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "th": case "tr": case "td": case "div": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "dl": case "dt": case "dd": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "strong": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "pre": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "link": case "filename": case "replaceable": case "seealso": break; default: if (!HandleEndElement(sb, name, forWebUse)) { throw new InvalidOperationException("Unsupported node of type " + name + ". Full XML: " + xml); } break; } } else if (type == XmlNodeType.Text) { sb.Append(System.Net.WebUtility.HtmlEncode(value)); } } string composed = sb.ToString(); string final = DocumentationUtils.ProcessLines(composed, l => l, compressConsequitiveNonemptyLines: true, compressConsequitiveEmptyLines: true, skipEmptyLines: true); return(final); } }
private void WriteExamples(XmlWriter writer, string cmdletName) { XmlDocument document; if (!ExamplesCache.TryGetValue(cmdletName, out document)) { Console.WriteLine("NO EXAMPLES - {0}", cmdletName); return; } var set = document.SelectSingleNode("examples"); if (set == null || !set.HasChildNodes) { Console.WriteLine("NO EXAMPLES - {0} (file present but empty)", cmdletName); return; } writer.WriteStartElement("examples"); { int exampleIndex = 1; var examples = set.SelectNodes("example"); foreach (XmlNode example in examples) { writer.WriteStartElement("example"); { writer.WriteElementString("title", string.Format(exampleTitleFormat, exampleIndex)); { // code tag CANNOT HAVE PARA TAGS var code = example.SelectSingleNode("code"); if (code == null) { Logger.LogError("Unable to find examples <code> tag for cmdlet " + cmdletName); } writer.WriteRawElementString("code", code.InnerXml); // remarks tag MUST HAVE PARA TAGS var description = example.SelectSingleNode("description"); if (description == null) { Logger.LogError("Unable to find examples <description> tag for cmdlet " + cmdletName); } var correctedText = DocumentationUtils.ProcessLines(description.InnerXml, s => string.Format("<para>{0}</para>", s)); // we use br/ tags to format the description for webhelp, for native help we can replace // with simple newlines correctedText = correctedText.Replace("<br />", "\n"); // xml handler shows us <br/> as <br /> // <url>link</url> elements are stripped to leave the inner link text for the user to copy/paste // (web help converts these to <a href="link" />) correctedText = correctedText.Replace("<url>", ""); correctedText = correctedText.Replace("</url>", ""); var remarks = string.Format(remarksFormat, correctedText); writer.WriteUnescapedElementString("remarks", remarks); } } writer.WriteEndElement(); exampleIndex++; } } writer.WriteEndElement(); }
protected override void GenerateHelper() { Console.WriteLine("Generating Native PowerShell help (Get-Help) documentation file"); base.GenerateHelper(); var buildLogsPath = Path.Combine(this.Options.RootPath, "logs"); if (!Directory.Exists(buildLogsPath)) { Directory.CreateDirectory(buildLogsPath); } var logFilename = Path.Combine(buildLogsPath, Name + ".dll-Help.log"); var oldWriter = Console.Out; try { using (var consoleWriter = new StreamWriter(File.OpenWrite(logFilename))) { Console.SetOut(consoleWriter); var outputFile = Path.Combine(this.OutputFolder, Name + PsHelpFilenameTail); var settings = new XmlWriterSettings { Indent = true }; using (var psHelpWriter = new XmlTextWriter(outputFile, Encoding.UTF8)) { psHelpWriter.Formatting = Formatting.Indented; psHelpWriter.WriteStartElement("helpItems"); psHelpWriter.WriteAttributeString("schema", "maml"); Parallel.ForEach(CmdletTypes, (cmdletType) => { CmdletInfo cmdletInfo = InspectCmdletAttributes(cmdletType); using (StringWriter sectionWriter = new StringWriter()) using (var sectionXmlWriter = XmlWriter.Create(sectionWriter, new XmlWriterSettings() { OmitXmlDeclaration = true, ConformanceLevel = ConformanceLevel.Fragment, CloseOutput = true })) { string synopsis = null; if (cmdletInfo.AWSCmdletAttribute == null) { Console.WriteLine("Unable to find AWSCmdletAttribute for type " + cmdletType.FullName); } else { var cmdletReturnAttributeType = cmdletInfo.AWSCmdletAttribute.GetType(); synopsis = cmdletReturnAttributeType.GetProperty("Synopsis").GetValue(cmdletInfo.AWSCmdletAttribute, null) as string; } foreach (var cmdletAttribute in cmdletInfo.CmdletAttributes) { sectionXmlWriter.WriteStartElement("command"); sectionXmlWriter.WriteAttributeString("xmlns", "maml", null, "http://schemas.microsoft.com/maml/2004/10"); sectionXmlWriter.WriteAttributeString("xmlns", "command", null, "http://schemas.microsoft.com/maml/dev/command/2004/10"); sectionXmlWriter.WriteAttributeString("xmlns", "dev", null, "http://schemas.microsoft.com/maml/dev/2004/10"); { var typeDocumentation = DocumentationUtils.GetTypeDocumentation(cmdletType, AssemblyDocumentation); typeDocumentation = DocumentationUtils.FormatXMLForPowershell(typeDocumentation); Console.WriteLine($"Cmdlet = {cmdletType.FullName}"); Console.WriteLine($"Documentation = {typeDocumentation}"); var cmdletName = cmdletAttribute.VerbName + "-" + cmdletAttribute.NounName; var allProperties = GetRootSimpleProperties(cmdletType); var parameterPartitioning = new CmdletParameterSetPartitions(allProperties, cmdletAttribute.DefaultParameterSetName); var serviceAbbreviation = GetServiceAbbreviation(cmdletType); WriteDetails(sectionXmlWriter, cmdletAttribute, typeDocumentation, cmdletName, synopsis); WriteSyntax(sectionXmlWriter, cmdletName, parameterPartitioning); WriteParameters(sectionXmlWriter, cmdletName, allProperties); WriteReturnValues(sectionXmlWriter, cmdletInfo.AWSCmdletOutputAttributes); WriteRelatedLinks(sectionXmlWriter, serviceAbbreviation, cmdletName); WriteExamples(sectionXmlWriter, cmdletName); } sectionXmlWriter.WriteEndElement(); } sectionXmlWriter.Close(); lock (psHelpWriter) { psHelpWriter.WriteRaw(sectionWriter.ToString()); } } }); psHelpWriter.WriteEndElement(); } Console.WriteLine($"Verifying help file {outputFile} using XmlDocument..."); try { var document = new XmlDocument(); document.Load(outputFile); } catch (Exception e) { Logger.LogError(e, $"Error when loading file {outputFile} as XmlDocument"); } } } finally { Console.SetOut(oldWriter); } }
protected override void GenerateHelper() { Console.WriteLine("Generating Native PowerShell help (Get-Help) documentation file"); base.GenerateHelper(); var buildLogsPath = Path.Combine(this.Options.RootPath, "logs"); if (!Directory.Exists(buildLogsPath)) { Directory.CreateDirectory(buildLogsPath); } var logFilename = Path.Combine(buildLogsPath, Name + ".dll-Help.log"); var oldWriter = Console.Out; try { using (var consoleWriter = new StreamWriter(File.OpenWrite(logFilename))) { Console.SetOut(consoleWriter); var outputFile = Path.Combine(this.OutputFolder, Name + PsHelpFilenameTail); var settings = new XmlWriterSettings { Indent = true }; using (var psHelpWriter = new XmlTextWriter(outputFile, Encoding.UTF8)) { psHelpWriter.Formatting = Formatting.Indented; psHelpWriter.WriteStartElement("helpItems"); psHelpWriter.WriteAttributeString("schema", "maml"); foreach (var cmdletType in CmdletTypes) { InspectCmdletAttributes(cmdletType); string synopsis = null; if (AWSCmdletAttribute == null) { Console.WriteLine("Unable to find AWSCmdletAttribute for type " + cmdletType.FullName); } else { var cmdletReturnAttributeType = AWSCmdletAttribute.GetType(); synopsis = cmdletReturnAttributeType.GetProperty("Synopsis").GetValue(AWSCmdletAttribute, null) as string; } foreach (var cmdletAttribute in CmdletAttributes) { psHelpWriter.WriteStartElement("command"); psHelpWriter.WriteAttributeString("xmlns", "maml", null, "http://schemas.microsoft.com/maml/2004/10"); psHelpWriter.WriteAttributeString("xmlns", "command", null, "http://schemas.microsoft.com/maml/dev/command/2004/10"); psHelpWriter.WriteAttributeString("xmlns", "dev", null, "http://schemas.microsoft.com/maml/dev/2004/10"); { var hasDynamicParams = DynamicParamsType.IsAssignableFrom(cmdletType); var typeDocumentation = DocumentationUtils.GetTypeDocumentation(cmdletType, AssemblyDocumentation); typeDocumentation = DocumentationUtils.FormatXMLForPowershell(typeDocumentation); Console.WriteLine("Cmdlet = {0}", cmdletType.FullName); if (hasDynamicParams) { Console.WriteLine("This cmdlet has dynamic parameters!"); } Console.WriteLine("Documentation = {0}", typeDocumentation); var cmdletName = cmdletAttribute.VerbName + "-" + cmdletAttribute.NounName; var allProperties = GetRootSimpleProperties(cmdletType); var parameterPartitioning = new CmdletParameterSetPartitions(allProperties, cmdletAttribute.DefaultParameterSetName); var serviceAbbreviation = GetServiceAbbreviation(cmdletType); WriteDetails(psHelpWriter, cmdletAttribute, typeDocumentation, cmdletName, synopsis); WriteSyntax(psHelpWriter, cmdletName, parameterPartitioning); WriteParameters(psHelpWriter, cmdletName, allProperties); WriteReturnValues(psHelpWriter, AWSCmdletOutputAttributes); WriteRelatedLinks(psHelpWriter, serviceAbbreviation, cmdletName); WriteExamples(psHelpWriter, cmdletName); } psHelpWriter.WriteEndElement(); } } psHelpWriter.WriteEndElement(); } Console.WriteLine("Verifying help file {0} using XmlDocument...", outputFile); try { var document = new XmlDocument(); document.Load(outputFile); } catch (Exception e) { Logger.LogError(e, "Error when loading file {0} as XmlDocument", outputFile); } } } finally { Console.SetOut(oldWriter); } }
public static string FormatXMLForPowershell(string xml, bool forWebUse = false) { var sb = new StringBuilder(); using (var reader = new XmlTextReader(xml, XmlNodeType.Element, null)) { while (reader.Read()) { var type = reader.NodeType; var name = reader.Name.ToLowerInvariant(); var value = reader.Value; if (type == XmlNodeType.Element) { switch (name) { case "ul": case "ol": if (!forWebUse) { sb.AppendLine(); } else { sb.AppendFormat("<{0}>", name); } break; case "li": if (!forWebUse) { sb.AppendLine(); sb.Append(" -"); } else { sb.AppendFormat("<{0}>", name); } break; // very temp hack for ElastiCache in 2.3.5.0 release -- this is the only known set of table elements, // we want them in web help but not maml docs case "table": if (!forWebUse) { sb.Append(newAvailabilityZonesTableReplacement); do { reader.Read(); } while (!reader.Name.Equals("table", StringComparison.OrdinalIgnoreCase)); } else { sb.AppendFormat("<{0}>", name); } break; case "th": case "tr": case "td": case "div": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "dl": case "dt": case "dd": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "strong": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "pre": if (forWebUse) { sb.AppendFormat("<{0}>", name); } break; case "link": case "filename": case "replaceable": case "seealso": break; default: if (!HandleElement(sb, reader, name, forWebUse)) { throw new InvalidOperationException("Unsupported node of type " + name + ". Full XML: " + xml); } break; } } else if (type == XmlNodeType.EndElement) { switch (name) { case "li": if (!forWebUse) { sb.AppendLine(); } else { sb.AppendFormat("</{0}>", name); } break; case "ul": case "ol": if (!forWebUse) { sb.AppendLine(); sb.AppendLine(); } else { sb.AppendFormat("</{0}>", name); } break; // very temp hack for ElastiCache in 2.3.5.0 release -- this is the only known set of table elements, // we want them in web help but not maml docs case "table": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "th": case "tr": case "td": case "div": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "dl": case "dt": case "dd": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "strong": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "pre": if (forWebUse) { sb.AppendFormat("</{0}>", name); } break; case "link": case "filename": case "replaceable": case "seealso": break; default: if (!HandleEndElement(sb, name, forWebUse)) { throw new InvalidOperationException("Unsupported node of type " + name + ". Full XML: " + xml); } break; } } else if (type == XmlNodeType.Text) { // XmlReader unescapes by default, with no apparent option to turn off - so docs // that have escaped <> characters can form invalid xml when doc writers use them // to illustrate replaced values in a string. This test makes sure we don't have // any unclosed tags and if we do, re-escapes the string. try { var x = new XmlDocument(); // need dummy outer tags for the purposes of LoadXml x.LoadXml("<a>" + value + "</a>"); } catch { value = value.Replace("<", "<").Replace(">", ">"); } sb.Append(value); } } string composed = sb.ToString(); string final = DocumentationUtils.ProcessLines(composed, l => l, compressConsequitiveNonemptyLines: true, compressConsequitiveEmptyLines: true, skipEmptyLines: true); return(final); } }