comparison Tools/DocGen/Generator.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 using System;
2 using System.Collections.Generic;
3 using System.Globalization;
4 using System.IO;
5 using System.Linq;
6 using System.Text.RegularExpressions;
7 using System.Xml;
8
9 using Rsdn.Framework.Formatting;
10
11 namespace DocGen
12 {
13 delegate FileAction FileActionHandler(string ext);
14
15 partial class Generator
16 {
17 string _sourcePath;
18 string _destFolder;
19 FileActionHandler _fileAction;
20
21 public void Generate(
22 FileItem createdFiles,
23 string templateFileName,
24 string[] path,
25 string destFolder,
26 string sourcePath,
27 bool cleanUp,
28 bool createIndex,
29 FileActionHandler fileAction)
30 {
31 _sourcePath = Path.GetFullPath(sourcePath);
32 _destFolder = Path.GetFullPath(destFolder);
33 _fileAction = fileAction;
34
35 if (cleanUp)
36 CleanUp();
37
38 CreateDestFolder();
39
40 var template = File.ReadAllText(templateFileName);
41
42 GenerateContent(createdFiles, template, path, createIndex);
43 }
44
45 private void CreateDestFolder()
46 {
47 if (Directory.Exists(_destFolder) == false)
48 Directory.CreateDirectory(_destFolder);
49 }
50
51 private void CleanUp()
52 {
53 if (Directory.Exists(_destFolder) == false)
54 return;
55
56 Action<string> clean = null; clean = delegate(string path)
57 {
58 foreach (var file in Directory.GetFiles(path))
59 if (Path.GetExtension(file).ToLower() != ".zip")
60 try { File.Delete(file); } catch {}
61
62 foreach (var dir in Directory.GetDirectories(path))
63 {
64 clean(dir);
65 try { Directory.Delete(dir); } catch {}
66 }
67 };
68
69 clean(_destFolder);
70 }
71
72 static readonly Regex ct_item1 = new Regex(@"<ct_item\s*link\=(?<link>.*?)\s*label=['""](?<label>.*?)['""]\s*/>");
73 static readonly Regex ct_item2 = new Regex(@"<ct_item\s*link\=(?<link>.*?)\s*label=['""](?<label>.*?)['""]\s*>(?<text>.*?)</ct_item>", RegexOptions.Singleline);
74 static readonly Regex ct_item3 = new Regex(@"<mt_item\s*link\=(?<link>.*?)\s*label=['""](?<label>.*?)['""]\s*>(?<text>.*?)</mt_item>", RegexOptions.Singleline);
75 static readonly Regex ct_item4 = new Regex(@"<ct_item2\s*link1\=(?<link1>.*?)\s*label1=['""](?<label1>.*?)['""]\s*link2\=(?<link2>.*?)\s*label2=['""](?<label2>.*?)['""]\s*/>", RegexOptions.Singleline);
76 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);
77
78 private bool GenerateContent(
79 FileItem createdFiles, string template, string[] path, bool createIndex)
80 {
81 var folder = string.Join("/", path);
82 var destFolder = Path.Combine(_destFolder, folder);
83 var backPath = "";
84
85 for (var i = 0; i < path.Length; i++)
86 backPath += "../";
87
88 var sourcePath = Path.Combine(_sourcePath, folder);
89 var sourceFiles = Directory.GetFiles(sourcePath);
90
91 var files = new List<string>();
92 var folders = new List<string>();
93
94 foreach (var fileName in sourceFiles)
95 {
96 var backLinks = GeneratePath(path, backPath, fileName);
97
98 var destName = Path.Combine(destFolder, Path.GetFileName(fileName));
99 var ext = Path.GetExtension(destName).ToLower();
100
101 Console.WriteLine(destName);
102
103 switch (_fileAction(fileName))
104 {
105 case FileAction.Skip:
106 break;
107
108 case FileAction.Copy:
109 File.Copy(fileName, destName, true);
110 break;
111
112 case FileAction.Process:
113 if (Directory.Exists(destFolder) == false)
114 Directory.CreateDirectory(destFolder);
115
116 switch (ext)
117 {
118 case ".htm":
119 case ".html":
120 using (var sw = File.CreateText(destName))
121 using (var sr = File.OpenText(fileName))
122 {
123 var item = new FileItem { IsFile = true, Name = destName };
124 createdFiles.Add(item);
125
126 var source = sr.ReadToEnd();
127
128 source = source
129 .Replace("<ct_table>", "<table border='0' cellpadding='0' cellspacing='0'>")
130 .Replace("<ct_hr>", "<ct_mg><tr><td colspan='5' class='hr'><img width='1' height='1' alt=''/></td></tr><ct_mg>")
131 .Replace("<ct_text>", "<tr><td colspan='5'>")
132 .Replace("</ct_text>", "</td></tr><ct_mg>")
133 .Replace("<ct_mg>", "<tr><td colspan='5' class='sp'><img width='1' height='1' alt=''/></td></tr>")
134 .Replace("</ct_table>", "</table>")
135 ;
136
137 source = ct_item1.Replace(source, @"<tr><td nowrap colspan='5'>&#8226; <a href=${link}>${label}</a></td></tr>");
138 source = ct_item2.Replace(source, @"<tr><td nowrap>&#8226; <a href=${link}>${label}</a></td><td>&nbsp;&nbsp;&nbsp;</td><td class='j' colspan='3'>${text}</td></tr>");
139 source = ct_item3.Replace(source, @"<tr><td nowrap class='p'>&#8226; <a href=${link}>${label}</a></td><td></td><td class='pj' colspan='3'>${text}</td></tr>");
140 source = ct_item4.Replace(source, @"<tr><td nowrap>&#8226; <a href=${link1}>${label1}</a></td><td>&nbsp;&nbsp;&nbsp;</td><td nowrap colspan='3'>&#8226; <a href=${link2}>${label2}</a></td></tr>");
141 source = ct_item5.Replace(source, @"<tr><td nowrap>&#8226; <a href=${link1}>${label1}</a></td><td>&nbsp;&nbsp;&nbsp;</td><td nowrap>&#8226; <a href=${link2}>${label2}</a></td><td>&nbsp;&nbsp;&nbsp;</td><td nowrap>&#8226; <a href=${link3}>${label3}</a></td></tr>");
142
143 if (_modifySourceLinks)
144 {
145 source = source
146 .Replace("href=\"..\\..\\..\\Source\\", "target=_blank href=\"/Source/")
147 .Replace("href='..\\..\\..\\Source\\", "target=_blank href='/Source/")
148 .Replace("<a href=\"http://", "<a target=_blank href=\"http://")
149 .Replace("<a href='http://", "<a target=_blank href='http://")
150 ;
151 }
152
153 var title = item.Title;
154
155 if (title == "index")
156 {
157 title = Path.GetFileName(Path.GetDirectoryName(fileName));
158
159 if (title != "content")
160 item.Title = title;
161 }
162
163 source = GenerateSource(source, item);
164 title = item.Title;
165
166 if (title.Length > 0 && _addDashToTitle)
167 title += " - ";
168
169 sw.WriteLine(string.Format(
170 template,
171 source,
172 backPath,
173 backLinks,
174 title));
175
176 if (item.NoIndex == false)
177 {
178 source = source
179 .Replace("<span class='a'>", "")
180 .Replace("</span>", "")
181 .Replace("&lt;", "<")
182 .Replace("&gt;", ">")
183 ;
184
185 foreach (var index in IndexItem.Index)
186 if (!item.NoIndexes.Contains(index.Name))
187 foreach (var s in index.Text)
188 if (source.IndexOf(s) >= 0)
189 {
190 index.Files.Add(item);
191 break;
192 }
193
194 foreach (var s in item.Indexes)
195 {
196 var index = IndexItem.Index.Find(i => i.Name == s);
197
198 if (index == null)
199 IndexItem.Index.Add(new IndexItem(s));
200
201 if (index.Files.Contains(item) == false)
202 index.Files.Add(item);
203 }
204 }
205 }
206
207 break;
208
209 case ".cs":
210 using (var sw = File.CreateText(destName + ".htm"))
211 {
212 createdFiles.Add(new FileItem { IsFile = true, Name = destName + ".htm" });
213
214 var source = GenerateSource("<% " + fileName + " %>", null);
215
216 sw.WriteLine(string.Format(
217 template,
218 source,
219 backPath,
220 backLinks,
221 Path.GetFileNameWithoutExtension(fileName) + " - "));
222 }
223 break;
224 }
225
226 files.Add(fileName);
227
228 break;
229 }
230 }
231
232 var dirs = Directory.GetDirectories(sourcePath);
233 var newPath = new string[path.Length + 1];
234
235 path.CopyTo(newPath, 0);
236
237 foreach (var dir in dirs)
238 {
239 var dirList = dir.Split('/', '\\');
240 var dirName = dirList[dirList.Length - 1];
241
242 // Skip Subversion folders.
243 //
244 if (dirName == "_svn" || dirName == ".svn")
245 continue;
246
247 newPath[path.Length] = dirName;
248
249 var item = new FileItem { IsFile = false, Name = dirName};
250
251 createdFiles.Add(item);
252
253 if (GenerateContent(item, template, newPath, createIndex))
254 folders.Add(dir);
255 }
256
257 if (files.Count > 0 || folders.Count > 0)
258 {
259 var indexName = destFolder + "/index.htm";
260
261 if (createIndex && File.Exists(indexName) == false)
262 {
263 var str = "";
264
265 folders.Sort();
266
267 foreach (var s in folders)
268 str += string.Format("&#8226; <a href='{0}/index.htm'>{0}</a><br>\n",
269 Path.GetFileName(s));
270
271 if (str.Length > 0)
272 str += "<br>";
273
274 files.Sort();
275
276 foreach (var s in files)
277 str += string.Format(
278 s.EndsWith(".htm", true, CultureInfo.CurrentCulture) ||
279 s.EndsWith(".html", true, CultureInfo.CurrentCulture)?
280 "&#8226; <a href='{0}'>{0}</a><br>":
281 "&#8226; <a href='{0}.htm'>{0}</a><br>\n",
282 Path.GetFileName(s));
283
284 _fileAction(indexName);
285
286 using (var sw = File.CreateText(indexName))
287 {
288 createdFiles.Add(new FileItem { IsFile = true, Name = indexName });
289
290 sw.WriteLine(string.Format(
291 template,
292 str,
293 backPath,
294 GeneratePath(path, backPath, "@@@").Replace(".@@@", ""),
295 Path.GetFileNameWithoutExtension(destFolder) + " - "));
296 }
297 }
298
299 return true;
300 }
301
302 return false;
303 }
304
305 private string GenerateSource(string text, FileItem item)
306 {
307 for (int
308 idx = text.IndexOf("<%"),
309 end = text.IndexOf("%>", idx + 2);
310 idx >= 0 &&
311 end >= 0;
312 idx = text.IndexOf("<%", idx + 2),
313 end = text.IndexOf("%>", idx + 2))
314 {
315 var startSource = text.Substring(0, idx);
316 var source = text.Substring(idx + 2, end - idx - 2).Trim();
317 var command = "source";
318
319 var cmdIdx = source.IndexOf('#');
320
321 if (cmdIdx >= 0)
322 {
323 command = source.Substring(0, cmdIdx).Trim().ToLower();
324 source = source.Substring(cmdIdx+1).Trim();
325 }
326
327 switch (command)
328 {
329 case "source" : source = GetSourceCodeFromPath(Path.Combine(_sourcePath, source), text); break;
330 case "rss" : source = GetNews (Path.Combine(_sourcePath, source)); break;
331 case "txt" :
332 case "cs" :
333 case "sql" : source = GetSourceCode(source, "." + command, text); break;
334 case "title" : item.Title = source; source = ""; break;
335 case "order" : item.SortOrder = int.Parse(source); source = ""; break;
336 case "group" : item.Group = source; source = ""; break;
337 case "index" : item.Indexes.Add(source); source = ""; break;
338 case "table" : source = GetTable(Path.Combine(_sourcePath, source)); break;
339 case "noindex" :
340 if (source.Length == 0)
341 item.NoIndex = true;
342 else
343 item.NoIndexes.Add(source);
344
345 source = "";
346 break;
347
348 default : throw new InvalidOperationException();
349 }
350
351 text = startSource + source + text.Substring(end + 2);
352 }
353
354 return text
355 .Replace(@"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=DBHost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE)));User Id=TestUser;Password=TestPassword;", "...");
356 }
357
358 private static string GetNews(string sourcePath)
359 {
360 var doc = new XmlDocument();
361
362 doc.Load(sourcePath);
363
364 var html = "<table border='0' cellpadding='0' cellspacing='0'>";
365 var @class = "";
366 var i = 0;
367
368 foreach (XmlNode item in doc.SelectNodes("rss/channel/item"))
369 {
370 html += string.Format(@"
371 <tr><td{0} colspan='2'><nobr><b>{1:MM/dd/yy}</nobr></b> <a href='{2}'>{3}</a></td></tr>
372 <tr><td>&nbsp;&nbsp;</td><td class='j'>{4}</td></tr>
373 ",
374 @class,
375 DateTime.Parse(item.SelectSingleNode("pubDate").InnerText),
376 item.SelectSingleNode("link"). InnerText,
377 item.SelectSingleNode("title"). InnerText,
378 item.SelectSingleNode("description").InnerText);
379
380 @class = " class='p'";
381
382 if (++i == 20)
383 break;
384 }
385
386 html += "</table>";
387
388 return html;
389 }
390
391 private static string GetSourceCode(string code, string ext, string source)
392 {
393 switch (ext)
394 {
395 case ".cpp": code = "[c]" + code + "[/c]"; break;
396 case ".cs": code = "[c#]" + code + "[/c#]"; break;
397 case ".vb": code = "[vb]" + code + "[/vb]"; break;
398 case ".xml":
399 case ".config": code = "[xml]" + code + "[/xml]"; break;
400 case ".sql": code = "[sql]" + code + "[/sql]"; break;
401 default : code = "[code]" + code + "[/code]"; break;
402 }
403
404 code = code
405 .Replace("/*[", "[")
406 .Replace("]*/", "]")
407 ;
408
409 code = new TextFormatter().Format(code, false);
410
411 if (source.IndexOf("<a name='Person'></a>") >= 0)
412 code = code
413 .Replace("&lt;Person&gt;", "&lt;<a class=m href=#Person>Person</a>&gt;")
414 .Replace(", Person&gt;", ", <a class=m href=#Person>Person</a>&gt;")
415 .Replace(" Person ", " <a class='m' href=#Person>Person</a> ")
416 .Replace(" Person()", " <a class='m' href=#Person>Person</a>()")
417 .Replace("(Person ", "(<a class='m' href=#Person>Person</a> ")
418 ;
419
420 return code
421 .Replace("\n", "\r\n")
422 .Replace("\r\r\n", "\r\n")
423 .Replace("<table width='96%'>", "<table width='100%' class='code'>")
424 .Replace("<pre>", "<pre class='code'>")
425 .Replace("[a]", "<span class='a'>")
426 .Replace("[/a]", "</span>")
427 .Replace("[link]", "<a ")
428 .Replace("[/link]", "</a>")
429 .Replace("[file]", "href='/Source/")
430 .Replace("[/file]", ".htm'>")
431 .Replace("&lt;!--", "<span class='com'>&lt;!--")
432 .Replace("--&gt;", "--&gt;</span>")
433 ;
434 }
435
436 private static string GetSourceCodeFromPath(string sourcePath, string source)
437 {
438 var code = "";
439
440 using (var sr = File.OpenText(sourcePath))
441 for (var s = sr.ReadLine(); s != null; s = sr.ReadLine())
442 if (!s.StartsWith("//@") && !s.StartsWith("''@"))
443 code += s + "\n";
444
445 return GetSourceCode(code, Path.GetExtension(sourcePath).ToLower(), source);
446 }
447
448 private static string GeneratePath(string[] path, string backPath, string fileName)
449 {
450 if (path.Length == 0)
451 return "";
452
453 var backLinks = "";
454 var parent = "";
455 var name = Path.GetFileNameWithoutExtension(fileName);
456
457 switch (path[0])
458 {
459 case "Doc":
460 backLinks += string.Format(
461 "<br><nobr>&nbsp;&nbsp;<small><a class='m' href='{0}Doc/index.htm'>Doc</a>",
462 backPath);
463
464 for (var i = 1; i < path.Length; i++)
465 {
466 parent = "";
467
468 for (var j = i + 1; j < path.Length; j++)
469 parent += "../";
470
471 backLinks += string.Format(".<a class='m' href='{0}index.htm'>{1}</a>", parent, path[i]);
472 }
473
474 if (name.ToLower() != "index")
475 {
476 backLinks += string.Format(".<a class='m' href='{0}{1}'>{2}</a>",
477 parent, Path.GetFileName(fileName), name);
478 }
479
480 backLinks += "<small></nobr></br>";
481
482 break;
483
484 case "Source":
485 backLinks += string.Format(
486 "<br><nobr>&nbsp;&nbsp;<small><a class='m' href='{0}Source/index.htm'>Source</a>",
487 backPath);
488
489 for (var i = 1; i < path.Length; i++)
490 {
491 parent = "";
492
493 for (var j = i + 1; j < path.Length; j++)
494 parent += "../";
495
496 backLinks += string.Format(".<a class='m' href='{0}index.htm'>{1}</a>", parent, path[i]);
497 }
498
499 if (name.ToLower() != "@@@")
500 {
501 backLinks += string.Format(".<a class='m' href='{0}{1}.htm'>{1}</a>",
502 parent, Path.GetFileName(fileName));
503 }
504
505 backLinks += "<small></nobr></br>";
506
507 break;
508 }
509
510 return backLinks;
511 }
512
513 class TableItem
514 {
515 public string Provider;
516 public string Feature;
517 public string Linq;
518 public string Implementation;
519 }
520
521 static string _providerName;
522
523 static TableItem GetTableItem(string line)
524 {
525 if (line.StartsWith("*"))
526 {
527 _providerName = line.Substring(1).Trim();
528 return null;
529 }
530
531 var ss = line.Replace("||", "$$$$$").Split('|');
532
533 if (ss.Length != 4)
534 throw new InvalidOperationException(line);
535
536 var impl = ss[3].Trim().Replace("$$$$$", "||");
537
538 if (impl.StartsWith("#"))
539 {
540 impl = impl.Substring(impl.IndexOf(' ')).Replace("\\n", "\n").Replace("\\t", "\t").Trim();
541 impl = GetSourceCode(impl, ".sql", "");
542 }
543
544 return new TableItem
545 {
546 Provider = _providerName,
547 Feature = ss[1].Trim().Replace("$$$$$", "||"),
548 Linq = ss[2].Trim().Replace("$$$$$", "||"),
549 Implementation = impl
550 };
551 }
552
553 static string GetTable(string sourcePath)
554 {
555 Console.WriteLine("table {0}", sourcePath);
556
557 var lines = File.ReadAllLines(sourcePath);
558 var items = (from l in lines where l.Trim().Length > 0 select GetTableItem(l)).Where(i => i != null).ToList();
559 var providers = (from i in items where i.Provider.Length > 0 group i by i.Provider into g select g.Key).ToList();
560 var forall = (from i in items where i.Provider.Length == 0 select i).ToList();
561
562 foreach (var p in providers)
563 {
564 items.AddRange(from a in forall select new TableItem
565 {
566 Provider = p,
567 Feature = a.Feature,
568 Linq = a.Linq,
569 Implementation = a.Implementation
570 });
571 }
572
573 foreach (var i in forall)
574 items.Remove(i);
575
576 var features = (
577 from i in items
578 group i by new { i.Feature, i.Linq } into g
579 orderby g.Key.Feature, g.Key.Linq
580 select new
581 {
582 g.Key.Feature,
583 g.Key.Linq,
584 Providers = new string[providers.Count()]
585 }
586 ).ToList();
587
588 foreach (var f in features)
589 {
590 for (var i = 0; i < providers.Count; i++)
591 {
592 f.Providers[i] = (
593 from it in items
594 where it.Provider == providers[i] && it.Feature == f.Feature && it.Linq == f.Linq
595 select it.Implementation
596 ).FirstOrDefault();
597 }
598 }
599
600 var s = "<table class='data bordered nowrappable'>\n<tr><th>&nbsp;</th><th>Linq</th>";
601
602 foreach (var p in providers)
603 s += "<th>" + p + "</th>";
604
605 s += "</tr>";
606
607 var byFeature = from f in features group f by f.Feature;
608
609 foreach (var f in byFeature)
610 {
611 bool first = true;
612
613 foreach (var l in f)
614 {
615 s += "<tr>";
616
617 if (first)
618 {
619 s += f.Count() == 1? "<td>": "<td rowspan=" + f.Count() + ">";
620 s += f.Key + "</td>";
621 first = false;
622 }
623
624 s += "<td>" + l.Linq + "</td>";
625
626 var n = 0;
627 string p = null;
628
629 for (var i = 0; i < l.Providers.Count(); i++)
630 {
631 if (l.Providers[i] == p)
632 n++;
633 else
634 {
635 if (n > 0)
636 {
637 s += n == 1? "<td": "<td colspan=" + n;
638 s += p == null ? " class=nosup>" : ">";
639 s += p ?? "X";
640 s += "</td>";
641 }
642
643 p = l.Providers[i];
644 n = 1;
645 }
646 }
647
648 if (n > 0)
649 {
650 s += n == 1? "<td": "<td colspan=" + n;
651 s += p == null ? " class=nosup>" : ">";
652 s += p ?? "X";
653 s += "</td>";
654 }
655
656 s += "</tr>\n";
657 }
658 }
659
660 return s + "</table>";
661 }
662 }
663 }