private static void CreateNodeDocs(XmlElement Root, string OutputDir, string SourceDir, SaxonXform ClassXform, string tag) { XmlNodeList nodeList = Root.GetElementsByTagName(tag); foreach (XmlNode item in nodeList) { string ClassTitle = item["id"].InnerText; string ClassFolder = Path.Combine(SourceDir, $"{ClassTitle}\\"); // Skip generation of a separate class instance for the enum/struct group classes if (ClassTitle.Equals("UEnum") || ClassTitle.Equals("UUserDefinedEnum") || ClassTitle.Equals("UScriptStruct") || ClassTitle.Equals("UUserDefinedStruct")) { continue; } string OutputClassDir = Path.Combine(OutputDir, ClassTitle); SafeCreateDirectory(OutputClassDir); string OutputClassPath = Path.Combine(OutputClassDir, $"{ClassTitle}.html"); ClassXform.TransformXml(Path.Combine(ClassFolder, $"{ClassTitle}.xml"), OutputClassPath); //Copy the images for this class to the output directory CopyWholeDirectory(Path.Combine(ClassFolder, "img"), Path.Combine(OutputClassDir, "img")); } }
static void Main(string[] args) { List <string> ArgumentList = new List <string>(args); Console.WriteLine("KantanDocGen invoked with arguments:"); foreach (string Arg in ArgumentList) { Console.WriteLine(Arg); } string DocsTitle = ParseArgumentValue(ArgumentList, "-name=", null); if (DocsTitle == null) { Console.WriteLine("KantanDocGen: Error: Documentation title (-name=) required. Aborting."); return; } // Get the default paths // If unspecified, assume the directory containing our binary is one level below the base directory string DocGenBaseDir = ParseArgumentDirectory(ArgumentList, "-basedir=", Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "..")); string OutputRoot = ParseArgumentDirectory(ArgumentList, "-outputdir=", Directory.GetCurrentDirectory()); string OutputDir = Path.Combine(OutputRoot, DocsTitle); //string MsxslPath = ParseArgumentPath(ArgumentList, "-xslproc=", Path.Combine(EngineDir, "Binaries/ThirdParty/Msxsl/msxsl.exe")); // Xsl transform files - if not specified explicitly, look for defaults relative to base directory string IndexTransformPath = ParseArgumentPath(ArgumentList, "-indexxsl=", Path.Combine(DocGenBaseDir, "xslt/index_xform.xsl")); string ClassTransformPath = ParseArgumentPath(ArgumentList, "-classxsl=", Path.Combine(DocGenBaseDir, "xslt/class_docs_xform.xsl")); string NodeTransformPath = ParseArgumentPath(ArgumentList, "-nodexsl=", Path.Combine(DocGenBaseDir, "xslt/node_docs_xform.xsl")); bool bFromIntermediate = ArgumentList.Contains("-fromintermediate"); string IntermediateDir; if (bFromIntermediate) { // Intermediate docs already created, we need to have been passed an intermediate directory to locate them IntermediateDir = ParseArgumentDirectory(ArgumentList, "-intermediatedir=", null); if (IntermediateDir == null) { Console.WriteLine("KantanDocGen: Error: -fromintermediate requires -intermediatedir to be set. Aborting."); return; } if (!Directory.Exists(IntermediateDir)) { Console.WriteLine("KantanDocGen: Error: Specified intermediate directory not found. Aborting."); return; } } else { // @TODO: This doesn't work, since commandlet cannot create Slate windows! // Can reenable this path if manage to get a Program target type to build against the engine. Console.WriteLine("KantanDocGen: Error: Calling without -fromintermediate currently not supported. Use the KantanDocGen engine plugin to generate documentation."); return; /* IntermediateDir = ParseArgumentDirectory(ArgumentList, "-intermediatedir=", Path.Combine(EngineDir, "Intermediate\\KantanDocGen")); * * // Need to generate intermediate docs first * // Run editor commandlet to generate XML and image files * string EditorPath = Path.Combine(EngineDir, "Binaries\\Win64\\UE4Editor-Cmd.exe"); * if (!RunXmlDocGenCommandlet(EngineDir, EditorPath, IntermediateDir)) * { * return; * } */ } const bool bCleanOutput = true; bool bHardClean = ArgumentList.Contains("-cleanoutput"); if (bCleanOutput) { // If the output directory exists, attempt to delete it (this will fail if bHardClean is false and the directory contains files/subfolders) if (Directory.Exists(OutputDir)) { try { Directory.Delete(OutputDir, bHardClean); } catch (Exception) { Console.WriteLine("KantanDocGen: Error: Output directory '{0}' exists and not empty/couldn't delete. Remove and rerun, or specify -cleanoutput (If running from plugin console, add 'clean' parameter).", OutputDir); return; } } } //var XslXform = new MsxslXform(MsxslPath); var IndexXform = new SaxonXform(); var ClassXform = new SaxonXform(); var NodeXform = new SaxonXform(); // Initialize the transformations if (!IndexXform.Initialize(IndexTransformPath, ProcessOutputReceived)) { Console.WriteLine("Error: Failed to initialize xslt processor."); return; } if (!ClassXform.Initialize(ClassTransformPath, ProcessOutputReceived)) { Console.WriteLine("Error: Failed to initialize xslt processor."); return; } if (!NodeXform.Initialize(NodeTransformPath, ProcessOutputReceived)) { Console.WriteLine("Error: Failed to initialize xslt processor."); return; } // Loop over all generated xml files and apply the transformation int Success = 0; int Failed = 0; // @TODO: Should iterate over index/class xml entries rather than enumerate files and directories var SubFolders = Directory.EnumerateDirectories(IntermediateDir); foreach (string Sub in SubFolders) { string ClassTitle = Path.GetFileName(Sub); string OutputClassDir = Path.Combine(OutputDir, ClassTitle); SafeCreateDirectory(OutputClassDir); string NodeDir = Path.Combine(Sub, "nodes"); if (Directory.Exists(NodeDir)) { string OutputNodesDir = Path.Combine(OutputClassDir, "nodes"); SafeCreateDirectory(OutputNodesDir); var InputFiles = Directory.EnumerateFiles(NodeDir, "*.xml", SearchOption.TopDirectoryOnly); foreach (string FilePath in InputFiles) { string FileTitle = Path.GetFileNameWithoutExtension(FilePath); string OutputPath = Path.Combine(OutputNodesDir, FileTitle + ".html"); string InputPath = FilePath; if (!NodeXform.TransformXml(InputPath, OutputPath)) { Console.WriteLine("Error: Xsl transform failed for file {0} - skipping.", InputPath); ++Failed; continue; } ++Success; } string OutputClassPath = Path.Combine(OutputClassDir, ClassTitle + ".html"); ClassXform.TransformXml(Path.Combine(Sub, ClassTitle + ".xml"), OutputClassPath); } // Copy the images for this class to the output directory CopyWholeDirectory(Path.Combine(Sub, "img"), Path.Combine(OutputClassDir, "img")); } string OutputIndexPath = Path.Combine(OutputDir, "index.html"); IndexXform.TransformXml(Path.Combine(IntermediateDir, "index.xml"), OutputIndexPath); CopyWholeDirectory(Path.Combine(DocGenBaseDir, "css"), Path.Combine(OutputDir, "css")); Console.WriteLine("KantanDocGen completed:"); Console.WriteLine("{0} node docs successfully transformed.", Success); Console.WriteLine("{0} failed.", Failed); }
static void Main(string[] args) { List <string> ArgumentList = new List <string>(args); Console.WriteLine("KantanDocGen invoked with arguments:"); foreach (string Arg in ArgumentList) { Console.WriteLine(Arg); } // Get the default paths // If unspecified, assume the directory containing our binary is one level below the base directory string DocGenBaseDir = ParseArgumentDirectory(ArgumentList, "-basedir=", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); string OutputDir = ParseArgumentDirectory(ArgumentList, "-outputdir=", Directory.GetCurrentDirectory()); //string MsxslPath = ParseArgumentPath(ArgumentList, "-xslproc=", Path.Combine(EngineDir, "Binaries/ThirdParty/Msxsl/msxsl.exe")); // Xsl transform files - if not specified explicitly, look for defaults relative to base directory string IndexTransformPath, ClassTransformPath, NodeTransformPath; IndexTransformPath = ParseArgumentPath(ArgumentList, "-indexxsl=", Path.Combine(DocGenBaseDir, "DeploymentFiles/xslt/index_xform.xsl")); ClassTransformPath = ParseArgumentPath(ArgumentList, "-classxsl=", Path.Combine(DocGenBaseDir, "DeploymentFiles/xslt/class_docs_xform.xsl")); NodeTransformPath = ParseArgumentPath(ArgumentList, "-nodexsl=", Path.Combine(DocGenBaseDir, "DeploymentFiles/xslt/node_docs_xform.xsl")); string SourceDir; // Intermediate docs already created, we need to have been passed an intermediate directory to locate them SourceDir = ParseArgumentDirectory(ArgumentList, "-sourcedir=", null); if (SourceDir == null) { Console.WriteLine("KantanDocGen: Error: -sourcedir is required. Aborting."); return; } if (!Directory.Exists(SourceDir)) { Console.WriteLine("KantanDocGen: Error: Specified source directory not found. Aborting."); return; } const bool bCleanOutput = true; bool bHardClean = ArgumentList.Contains("-cleanoutput"); if (bCleanOutput) { // If the output directory exists, attempt to delete it (this will fail if bHardClean is false and the directory contains files/subfolders) if (Directory.Exists(OutputDir)) { try { Directory.Delete(OutputDir, true); } catch (Exception) { Console.WriteLine("KantanDocGen: Error: Output directory '{0}' exists and not empty/couldn't delete. Remove and rerun, or specify -cleanoutput (If running from plugin console, add 'clean' parameter).", OutputDir); return; } } } // Loop over all generated xml files and apply the transformation int Success = 0; int Failed = 0; XmlDocument indexXMLDoc = new XmlDocument(); indexXMLDoc.Load(Path.Combine(SourceDir, "index.xml")); XmlElement indexRoot = indexXMLDoc.DocumentElement; foreach (XmlNode item in indexRoot.GetElementsByTagName("class")) { string ClassTitle = item["id"].InnerText; string ClassFolder = Path.Combine(SourceDir, $"{ClassTitle}\\"); string NodeDir = Path.Combine(ClassFolder, "nodes\\"); XmlDocument doc = new XmlDocument(); doc.Load(Path.Combine(ClassFolder, $"{ClassTitle}.xml")); XmlElement root = doc.DocumentElement; //XmlNode nodesNode = root.SelectSingleNode("descendant::nodes"); root.RemoveChild(root.LastChild); if (Directory.Exists(NodeDir)) { XmlElement functionListElement = doc.CreateElement("FunctionList"); var InputFiles = Directory.EnumerateFiles(NodeDir, "*.xml", SearchOption.TopDirectoryOnly); foreach (string FilePath in InputFiles) { XmlElement functionRoot = doc.CreateElement("Function"); XmlDocument functionDoc = new XmlDocument(); functionDoc.Load(FilePath); foreach (XmlNode childElement in functionDoc.DocumentElement.ChildNodes) { //XmlNode nodeCopy = childElement.CloneNode(true); XmlNode nodeCopy = doc.ImportNode(childElement, true); functionRoot.AppendChild(nodeCopy); } doc.ImportNode(functionRoot, true); functionListElement.AppendChild(functionRoot); ++Success; } root.AppendChild(functionListElement); doc.Save(Path.Combine(ClassFolder, $"{ClassTitle}.xml")); } XmlElement saveGame = indexXMLDoc.CreateElement("savegame"); saveGame.InnerText = doc.DocumentElement["savegame"].InnerText; item.AppendChild(saveGame); XmlElement refactor = indexXMLDoc.CreateElement("refactor"); refactor.InnerText = doc.DocumentElement["refactor"].InnerText; item.AppendChild(refactor); XmlElement shortTooltip = indexXMLDoc.CreateElement("short_tooltip"); shortTooltip.InnerText = doc.DocumentElement["short_tooltip"].InnerText; item.AppendChild(shortTooltip); XmlElement native = indexXMLDoc.CreateElement("native"); native.InnerText = doc.DocumentElement["native"].InnerText; item.AppendChild(native); } string nativeEnumPath = Path.Combine(SourceDir, "UEnum\\UEnum.xml"); AddEnums(nativeEnumPath, ref indexXMLDoc, true); string bpEnumPath = Path.Combine(SourceDir, "UUserDefinedEnum\\UUserDefinedEnum.xml"); AddEnums(bpEnumPath, ref indexXMLDoc, false); string nativeStructPath = Path.Combine(SourceDir, "UScriptStruct\\UScriptStruct.xml"); AddStructs(nativeStructPath, ref indexXMLDoc, true); string bpStructPath = Path.Combine(SourceDir, "UUserDefinedStruct\\UUserDefinedStruct.xml"); AddStructs(bpStructPath, ref indexXMLDoc, false); indexXMLDoc.Save(Path.Combine(SourceDir, "index_adjusted.xml")); SafeCreateDirectory(OutputDir); string OutputIndexPath = Path.Combine(OutputDir, "index.html"); var IndexXform = new SaxonXform(); var ClassXform = new SaxonXform(); var NodeXform = new SaxonXform(); // Initialize the transformations if (!IndexXform.Initialize(IndexTransformPath, ProcessOutputReceived)) { Console.WriteLine("Error: Failed to initialize xslt processor."); return; } if (!ClassXform.Initialize(ClassTransformPath, ProcessOutputReceived)) { Console.WriteLine("Error: Failed to initialize xslt processor."); return; } if (!NodeXform.Initialize(NodeTransformPath, ProcessOutputReceived)) { Console.WriteLine("Error: Failed to initialize xslt processor."); return; } IndexXform.TransformXml(Path.Combine(SourceDir, "index_adjusted.xml"), OutputIndexPath); // @TODO: Should iterate over index/class xml entries rather than enumerate files and directories var SubFolders = Directory.EnumerateDirectories(SourceDir); CreateNodeDocs(indexRoot, OutputDir, SourceDir, ClassXform, "class"); CreateNodeDocs(indexRoot, OutputDir, SourceDir, ClassXform, "enum"); CreateNodeDocs(indexRoot, OutputDir, SourceDir, ClassXform, "struct"); //debug CopyWholeDirectory(Path.Combine(DocGenBaseDir, "DeploymentFiles/css"), Path.Combine(OutputDir, "css")); CopyWholeDirectory(Path.Combine(DocGenBaseDir, "DeploymentFiles/img"), Path.Combine(OutputDir, "img")); CopyWholeDirectory(Path.Combine(DocGenBaseDir, "DeploymentFiles/javascript"), Path.Combine(OutputDir, "javascript")); Console.WriteLine("KantanDocGen completed:"); Console.WriteLine("{0} node docs successfully transformed.", Success); Console.WriteLine("{0} failed.", Failed); }