Mercurial > pub > bltoolkit
diff Tools/DocGen/Generator.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tools/DocGen/Generator.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,663 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml; + +using Rsdn.Framework.Formatting; + +namespace DocGen +{ + delegate FileAction FileActionHandler(string ext); + + partial class Generator + { + string _sourcePath; + string _destFolder; + FileActionHandler _fileAction; + + public void Generate( + FileItem createdFiles, + string templateFileName, + string[] path, + string destFolder, + string sourcePath, + bool cleanUp, + bool createIndex, + FileActionHandler fileAction) + { + _sourcePath = Path.GetFullPath(sourcePath); + _destFolder = Path.GetFullPath(destFolder); + _fileAction = fileAction; + + if (cleanUp) + CleanUp(); + + CreateDestFolder(); + + var template = File.ReadAllText(templateFileName); + + GenerateContent(createdFiles, template, path, createIndex); + } + + private void CreateDestFolder() + { + if (Directory.Exists(_destFolder) == false) + Directory.CreateDirectory(_destFolder); + } + + private void CleanUp() + { + if (Directory.Exists(_destFolder) == false) + return; + + Action<string> clean = null; clean = delegate(string path) + { + foreach (var file in Directory.GetFiles(path)) + if (Path.GetExtension(file).ToLower() != ".zip") + try { File.Delete(file); } catch {} + + foreach (var dir in Directory.GetDirectories(path)) + { + clean(dir); + try { Directory.Delete(dir); } catch {} + } + }; + + clean(_destFolder); + } + + static readonly Regex ct_item1 = new Regex(@"<ct_item\s*link\=(?<link>.*?)\s*label=['""](?<label>.*?)['""]\s*/>"); + static readonly Regex ct_item2 = new Regex(@"<ct_item\s*link\=(?<link>.*?)\s*label=['""](?<label>.*?)['""]\s*>(?<text>.*?)</ct_item>", RegexOptions.Singleline); + static readonly Regex ct_item3 = new Regex(@"<mt_item\s*link\=(?<link>.*?)\s*label=['""](?<label>.*?)['""]\s*>(?<text>.*?)</mt_item>", RegexOptions.Singleline); + static readonly Regex ct_item4 = new Regex(@"<ct_item2\s*link1\=(?<link1>.*?)\s*label1=['""](?<label1>.*?)['""]\s*link2\=(?<link2>.*?)\s*label2=['""](?<label2>.*?)['""]\s*/>", RegexOptions.Singleline); + static readonly Regex ct_item5 = new Regex(@"<ct_item3\s*link1\=(?<link1>.*?)\s*label1=['""](?<label1>.*?)['""]\s*link2\=(?<link2>.*?)\s*label2=['""](?<label2>.*?)['""]\s*link3\=(?<link3>.*?)\s*label3=['""](?<label3>.*?)['""]\s*/>", RegexOptions.Singleline); + + private bool GenerateContent( + FileItem createdFiles, string template, string[] path, bool createIndex) + { + var folder = string.Join("/", path); + var destFolder = Path.Combine(_destFolder, folder); + var backPath = ""; + + for (var i = 0; i < path.Length; i++) + backPath += "../"; + + var sourcePath = Path.Combine(_sourcePath, folder); + var sourceFiles = Directory.GetFiles(sourcePath); + + var files = new List<string>(); + var folders = new List<string>(); + + foreach (var fileName in sourceFiles) + { + var backLinks = GeneratePath(path, backPath, fileName); + + var destName = Path.Combine(destFolder, Path.GetFileName(fileName)); + var ext = Path.GetExtension(destName).ToLower(); + + Console.WriteLine(destName); + + switch (_fileAction(fileName)) + { + case FileAction.Skip: + break; + + case FileAction.Copy: + File.Copy(fileName, destName, true); + break; + + case FileAction.Process: + if (Directory.Exists(destFolder) == false) + Directory.CreateDirectory(destFolder); + + switch (ext) + { + case ".htm": + case ".html": + using (var sw = File.CreateText(destName)) + using (var sr = File.OpenText(fileName)) + { + var item = new FileItem { IsFile = true, Name = destName }; + createdFiles.Add(item); + + var source = sr.ReadToEnd(); + + source = source + .Replace("<ct_table>", "<table border='0' cellpadding='0' cellspacing='0'>") + .Replace("<ct_hr>", "<ct_mg><tr><td colspan='5' class='hr'><img width='1' height='1' alt=''/></td></tr><ct_mg>") + .Replace("<ct_text>", "<tr><td colspan='5'>") + .Replace("</ct_text>", "</td></tr><ct_mg>") + .Replace("<ct_mg>", "<tr><td colspan='5' class='sp'><img width='1' height='1' alt=''/></td></tr>") + .Replace("</ct_table>", "</table>") + ; + + source = ct_item1.Replace(source, @"<tr><td nowrap colspan='5'>• <a href=${link}>${label}</a></td></tr>"); + source = ct_item2.Replace(source, @"<tr><td nowrap>• <a href=${link}>${label}</a></td><td> </td><td class='j' colspan='3'>${text}</td></tr>"); + source = ct_item3.Replace(source, @"<tr><td nowrap class='p'>• <a href=${link}>${label}</a></td><td></td><td class='pj' colspan='3'>${text}</td></tr>"); + source = ct_item4.Replace(source, @"<tr><td nowrap>• <a href=${link1}>${label1}</a></td><td> </td><td nowrap colspan='3'>• <a href=${link2}>${label2}</a></td></tr>"); + source = ct_item5.Replace(source, @"<tr><td nowrap>• <a href=${link1}>${label1}</a></td><td> </td><td nowrap>• <a href=${link2}>${label2}</a></td><td> </td><td nowrap>• <a href=${link3}>${label3}</a></td></tr>"); + + if (_modifySourceLinks) + { + source = source + .Replace("href=\"..\\..\\..\\Source\\", "target=_blank href=\"/Source/") + .Replace("href='..\\..\\..\\Source\\", "target=_blank href='/Source/") + .Replace("<a href=\"http://", "<a target=_blank href=\"http://") + .Replace("<a href='http://", "<a target=_blank href='http://") + ; + } + + var title = item.Title; + + if (title == "index") + { + title = Path.GetFileName(Path.GetDirectoryName(fileName)); + + if (title != "content") + item.Title = title; + } + + source = GenerateSource(source, item); + title = item.Title; + + if (title.Length > 0 && _addDashToTitle) + title += " - "; + + sw.WriteLine(string.Format( + template, + source, + backPath, + backLinks, + title)); + + if (item.NoIndex == false) + { + source = source + .Replace("<span class='a'>", "") + .Replace("</span>", "") + .Replace("<", "<") + .Replace(">", ">") + ; + + foreach (var index in IndexItem.Index) + if (!item.NoIndexes.Contains(index.Name)) + foreach (var s in index.Text) + if (source.IndexOf(s) >= 0) + { + index.Files.Add(item); + break; + } + + foreach (var s in item.Indexes) + { + var index = IndexItem.Index.Find(i => i.Name == s); + + if (index == null) + IndexItem.Index.Add(new IndexItem(s)); + + if (index.Files.Contains(item) == false) + index.Files.Add(item); + } + } + } + + break; + + case ".cs": + using (var sw = File.CreateText(destName + ".htm")) + { + createdFiles.Add(new FileItem { IsFile = true, Name = destName + ".htm" }); + + var source = GenerateSource("<% " + fileName + " %>", null); + + sw.WriteLine(string.Format( + template, + source, + backPath, + backLinks, + Path.GetFileNameWithoutExtension(fileName) + " - ")); + } + break; + } + + files.Add(fileName); + + break; + } + } + + var dirs = Directory.GetDirectories(sourcePath); + var newPath = new string[path.Length + 1]; + + path.CopyTo(newPath, 0); + + foreach (var dir in dirs) + { + var dirList = dir.Split('/', '\\'); + var dirName = dirList[dirList.Length - 1]; + + // Skip Subversion folders. + // + if (dirName == "_svn" || dirName == ".svn") + continue; + + newPath[path.Length] = dirName; + + var item = new FileItem { IsFile = false, Name = dirName}; + + createdFiles.Add(item); + + if (GenerateContent(item, template, newPath, createIndex)) + folders.Add(dir); + } + + if (files.Count > 0 || folders.Count > 0) + { + var indexName = destFolder + "/index.htm"; + + if (createIndex && File.Exists(indexName) == false) + { + var str = ""; + + folders.Sort(); + + foreach (var s in folders) + str += string.Format("• <a href='{0}/index.htm'>{0}</a><br>\n", + Path.GetFileName(s)); + + if (str.Length > 0) + str += "<br>"; + + files.Sort(); + + foreach (var s in files) + str += string.Format( + s.EndsWith(".htm", true, CultureInfo.CurrentCulture) || + s.EndsWith(".html", true, CultureInfo.CurrentCulture)? + "• <a href='{0}'>{0}</a><br>": + "• <a href='{0}.htm'>{0}</a><br>\n", + Path.GetFileName(s)); + + _fileAction(indexName); + + using (var sw = File.CreateText(indexName)) + { + createdFiles.Add(new FileItem { IsFile = true, Name = indexName }); + + sw.WriteLine(string.Format( + template, + str, + backPath, + GeneratePath(path, backPath, "@@@").Replace(".@@@", ""), + Path.GetFileNameWithoutExtension(destFolder) + " - ")); + } + } + + return true; + } + + return false; + } + + private string GenerateSource(string text, FileItem item) + { + for (int + idx = text.IndexOf("<%"), + end = text.IndexOf("%>", idx + 2); + idx >= 0 && + end >= 0; + idx = text.IndexOf("<%", idx + 2), + end = text.IndexOf("%>", idx + 2)) + { + var startSource = text.Substring(0, idx); + var source = text.Substring(idx + 2, end - idx - 2).Trim(); + var command = "source"; + + var cmdIdx = source.IndexOf('#'); + + if (cmdIdx >= 0) + { + command = source.Substring(0, cmdIdx).Trim().ToLower(); + source = source.Substring(cmdIdx+1).Trim(); + } + + switch (command) + { + case "source" : source = GetSourceCodeFromPath(Path.Combine(_sourcePath, source), text); break; + case "rss" : source = GetNews (Path.Combine(_sourcePath, source)); break; + case "txt" : + case "cs" : + case "sql" : source = GetSourceCode(source, "." + command, text); break; + case "title" : item.Title = source; source = ""; break; + case "order" : item.SortOrder = int.Parse(source); source = ""; break; + case "group" : item.Group = source; source = ""; break; + case "index" : item.Indexes.Add(source); source = ""; break; + case "table" : source = GetTable(Path.Combine(_sourcePath, source)); break; + case "noindex" : + if (source.Length == 0) + item.NoIndex = true; + else + item.NoIndexes.Add(source); + + source = ""; + break; + + default : throw new InvalidOperationException(); + } + + text = startSource + source + text.Substring(end + 2); + } + + return text + .Replace(@"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=DBHost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE)));User Id=TestUser;Password=TestPassword;", "..."); + } + + private static string GetNews(string sourcePath) + { + var doc = new XmlDocument(); + + doc.Load(sourcePath); + + var html = "<table border='0' cellpadding='0' cellspacing='0'>"; + var @class = ""; + var i = 0; + + foreach (XmlNode item in doc.SelectNodes("rss/channel/item")) + { + html += string.Format(@" +<tr><td{0} colspan='2'><nobr><b>{1:MM/dd/yy}</nobr></b> <a href='{2}'>{3}</a></td></tr> +<tr><td> </td><td class='j'>{4}</td></tr> +", + @class, + DateTime.Parse(item.SelectSingleNode("pubDate").InnerText), + item.SelectSingleNode("link"). InnerText, + item.SelectSingleNode("title"). InnerText, + item.SelectSingleNode("description").InnerText); + + @class = " class='p'"; + + if (++i == 20) + break; + } + + html += "</table>"; + + return html; + } + + private static string GetSourceCode(string code, string ext, string source) + { + switch (ext) + { + case ".cpp": code = "[c]" + code + "[/c]"; break; + case ".cs": code = "[c#]" + code + "[/c#]"; break; + case ".vb": code = "[vb]" + code + "[/vb]"; break; + case ".xml": + case ".config": code = "[xml]" + code + "[/xml]"; break; + case ".sql": code = "[sql]" + code + "[/sql]"; break; + default : code = "[code]" + code + "[/code]"; break; + } + + code = code + .Replace("/*[", "[") + .Replace("]*/", "]") + ; + + code = new TextFormatter().Format(code, false); + + if (source.IndexOf("<a name='Person'></a>") >= 0) + code = code + .Replace("<Person>", "<<a class=m href=#Person>Person</a>>") + .Replace(", Person>", ", <a class=m href=#Person>Person</a>>") + .Replace(" Person ", " <a class='m' href=#Person>Person</a> ") + .Replace(" Person()", " <a class='m' href=#Person>Person</a>()") + .Replace("(Person ", "(<a class='m' href=#Person>Person</a> ") + ; + + return code + .Replace("\n", "\r\n") + .Replace("\r\r\n", "\r\n") + .Replace("<table width='96%'>", "<table width='100%' class='code'>") + .Replace("<pre>", "<pre class='code'>") + .Replace("[a]", "<span class='a'>") + .Replace("[/a]", "</span>") + .Replace("[link]", "<a ") + .Replace("[/link]", "</a>") + .Replace("[file]", "href='/Source/") + .Replace("[/file]", ".htm'>") + .Replace("<!--", "<span class='com'><!--") + .Replace("-->", "--></span>") + ; + } + + private static string GetSourceCodeFromPath(string sourcePath, string source) + { + var code = ""; + + using (var sr = File.OpenText(sourcePath)) + for (var s = sr.ReadLine(); s != null; s = sr.ReadLine()) + if (!s.StartsWith("//@") && !s.StartsWith("''@")) + code += s + "\n"; + + return GetSourceCode(code, Path.GetExtension(sourcePath).ToLower(), source); + } + + private static string GeneratePath(string[] path, string backPath, string fileName) + { + if (path.Length == 0) + return ""; + + var backLinks = ""; + var parent = ""; + var name = Path.GetFileNameWithoutExtension(fileName); + + switch (path[0]) + { + case "Doc": + backLinks += string.Format( + "<br><nobr> <small><a class='m' href='{0}Doc/index.htm'>Doc</a>", + backPath); + + for (var i = 1; i < path.Length; i++) + { + parent = ""; + + for (var j = i + 1; j < path.Length; j++) + parent += "../"; + + backLinks += string.Format(".<a class='m' href='{0}index.htm'>{1}</a>", parent, path[i]); + } + + if (name.ToLower() != "index") + { + backLinks += string.Format(".<a class='m' href='{0}{1}'>{2}</a>", + parent, Path.GetFileName(fileName), name); + } + + backLinks += "<small></nobr></br>"; + + break; + + case "Source": + backLinks += string.Format( + "<br><nobr> <small><a class='m' href='{0}Source/index.htm'>Source</a>", + backPath); + + for (var i = 1; i < path.Length; i++) + { + parent = ""; + + for (var j = i + 1; j < path.Length; j++) + parent += "../"; + + backLinks += string.Format(".<a class='m' href='{0}index.htm'>{1}</a>", parent, path[i]); + } + + if (name.ToLower() != "@@@") + { + backLinks += string.Format(".<a class='m' href='{0}{1}.htm'>{1}</a>", + parent, Path.GetFileName(fileName)); + } + + backLinks += "<small></nobr></br>"; + + break; + } + + return backLinks; + } + + class TableItem + { + public string Provider; + public string Feature; + public string Linq; + public string Implementation; + } + + static string _providerName; + + static TableItem GetTableItem(string line) + { + if (line.StartsWith("*")) + { + _providerName = line.Substring(1).Trim(); + return null; + } + + var ss = line.Replace("||", "$$$$$").Split('|'); + + if (ss.Length != 4) + throw new InvalidOperationException(line); + + var impl = ss[3].Trim().Replace("$$$$$", "||"); + + if (impl.StartsWith("#")) + { + impl = impl.Substring(impl.IndexOf(' ')).Replace("\\n", "\n").Replace("\\t", "\t").Trim(); + impl = GetSourceCode(impl, ".sql", ""); + } + + return new TableItem + { + Provider = _providerName, + Feature = ss[1].Trim().Replace("$$$$$", "||"), + Linq = ss[2].Trim().Replace("$$$$$", "||"), + Implementation = impl + }; + } + + static string GetTable(string sourcePath) + { + Console.WriteLine("table {0}", sourcePath); + + var lines = File.ReadAllLines(sourcePath); + var items = (from l in lines where l.Trim().Length > 0 select GetTableItem(l)).Where(i => i != null).ToList(); + var providers = (from i in items where i.Provider.Length > 0 group i by i.Provider into g select g.Key).ToList(); + var forall = (from i in items where i.Provider.Length == 0 select i).ToList(); + + foreach (var p in providers) + { + items.AddRange(from a in forall select new TableItem + { + Provider = p, + Feature = a.Feature, + Linq = a.Linq, + Implementation = a.Implementation + }); + } + + foreach (var i in forall) + items.Remove(i); + + var features = ( + from i in items + group i by new { i.Feature, i.Linq } into g + orderby g.Key.Feature, g.Key.Linq + select new + { + g.Key.Feature, + g.Key.Linq, + Providers = new string[providers.Count()] + } + ).ToList(); + + foreach (var f in features) + { + for (var i = 0; i < providers.Count; i++) + { + f.Providers[i] = ( + from it in items + where it.Provider == providers[i] && it.Feature == f.Feature && it.Linq == f.Linq + select it.Implementation + ).FirstOrDefault(); + } + } + + var s = "<table class='data bordered nowrappable'>\n<tr><th> </th><th>Linq</th>"; + + foreach (var p in providers) + s += "<th>" + p + "</th>"; + + s += "</tr>"; + + var byFeature = from f in features group f by f.Feature; + + foreach (var f in byFeature) + { + bool first = true; + + foreach (var l in f) + { + s += "<tr>"; + + if (first) + { + s += f.Count() == 1? "<td>": "<td rowspan=" + f.Count() + ">"; + s += f.Key + "</td>"; + first = false; + } + + s += "<td>" + l.Linq + "</td>"; + + var n = 0; + string p = null; + + for (var i = 0; i < l.Providers.Count(); i++) + { + if (l.Providers[i] == p) + n++; + else + { + if (n > 0) + { + s += n == 1? "<td": "<td colspan=" + n; + s += p == null ? " class=nosup>" : ">"; + s += p ?? "X"; + s += "</td>"; + } + + p = l.Providers[i]; + n = 1; + } + } + + if (n > 0) + { + s += n == 1? "<td": "<td colspan=" + n; + s += p == null ? " class=nosup>" : ">"; + s += p ?? "X"; + s += "</td>"; + } + + s += "</tr>\n"; + } + } + + return s + "</table>"; + } + } +}