Html.pm 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. package Gsg::Html;
  2. use strict;
  3. use warnings;
  4. use Log::Log4perl qw(:easy);
  5. use lib "/usr/local/lib";
  6. use Shellex::Shellex qw(shellex findBin);
  7. use Gsg::Gather qw(get_file_tree get_diff_stat);
  8. use Gsg::MdParse qw (render_readme);
  9. use Exporter qw(import);
  10. our @EXPORT_OK = qw(
  11. write_file append_file write_root_index clean_web_root
  12. write_project_content
  13. );
  14. # These subs might belong in shellex
  15. # Add logger for write opts TODO
  16. sub write_file($$) {
  17. my $content = shift;
  18. my $path = shift;
  19. open(my $fh, ">", $path) or die "Couldnt open $path\n";
  20. print $fh "$content";
  21. close $fh;
  22. }
  23. sub append_file($$) {
  24. my $content = shift;
  25. my $path = shift;
  26. open(my $fh, ">>", $path) or die "Couldnt open $path\n";
  27. print $fh "$content";
  28. close $fh;
  29. }
  30. sub write_root_index($$$$) {
  31. my $index = shift;
  32. my $project_dirs_ref = shift;
  33. my $web_projects_dir_path = shift;
  34. my $logger = shift;
  35. write_file("", $index);
  36. append_file("<html><body><b>Git Projects</b><br><head><META NAME=\"ROBOTS\" CONTENT=\"NOINDEX, NOFOLLOW\"></head>\n",$index);
  37. append_file("<small><i>Statically generated web root for browsing this git server</i></small><br>\n",$index);
  38. my $date_cmd = findBin("date",$logger);
  39. my $current_time = `$date_cmd`;
  40. chomp $current_time;
  41. append_file("<small><i>Generated at $current_time</i></small><br><hr/>\n",$index);
  42. my $mkdirCmd = findBin("mkdir",$logger);
  43. foreach my $project ( @$project_dirs_ref ) {
  44. my $indexPath = $project . "index.html";
  45. append_file("<table><div id=\"cotent\"><table id=\"index\"><tbody>\n",$index);
  46. append_file("<tr><td><a href=\"projects/$indexPath\">$project</a></td>\n",$index);
  47. shellex("$mkdirCmd -p $web_projects_dir_path$project",$logger);
  48. }
  49. append_file("</tr></tbody></table></div></body></html>\n",$index);
  50. $logger->info("Wrote root index at $index");
  51. }
  52. sub check_for_html($) {
  53. # Expects line from gen_line_nums or gen_diff_colors
  54. # Will change < and > chars to &lt; or &gt;
  55. # This adds tons of overhead, but should work better
  56. # than <xmp> and will solve the rendering problems
  57. my $line = shift;
  58. my $new_line;
  59. open my $fh, '>>', \$new_line or die "Can't open variable: $!";
  60. foreach my $char ( split("",$line) ) {
  61. if ( ! defined $char || $char eq "" ) {
  62. print "Empty char\n";
  63. next;
  64. }
  65. if ( $char eq "<" ) {
  66. print $fh "&lt;";
  67. } elsif ( $char eq ">" ) {
  68. print $fh "&gt;";
  69. } else {
  70. print $fh "$char";
  71. }
  72. }
  73. close $fh;
  74. return $new_line;
  75. }
  76. sub gen_line_nums($$$) {
  77. my $raw_file = shift;
  78. my $filename = shift;
  79. my $logger = shift;
  80. my $html_file;
  81. # Might be a better way to do this? TODO
  82. open my $fh, '>>', \$html_file or die "Can't open variable: $!";
  83. print $fh "<!DOCTYPE html><html><b>$filename</b><hr/><div id=\"content\"><pre id=\"blob\">";
  84. my $line_counter = 1;
  85. foreach my $line ( split("\n", $raw_file) ) {
  86. if ( $line ne "" ) {
  87. $line = check_for_html($line);
  88. }
  89. print $fh "<a href=\"\#l$line_counter\" class=\"line\" id=\"l$line_counter\">$line_counter</a>\t$line<br>";
  90. $line_counter++;
  91. }
  92. print $fh "</pre></div><html>";
  93. close $fh;
  94. $logger->info("Generated line numbers for $filename");
  95. return $html_file;
  96. }
  97. sub gen_raw_html($$$) {
  98. my $raw_file = shift;
  99. my $filename = shift;
  100. my $logger = shift;
  101. my $html_file;
  102. # Might be a better way to do this? TODO
  103. open my $fh, '>>', \$html_file or die "Can't open variable: $!";
  104. print $fh "<!DOCTYPE html><html><div id=\"content\"><pre id=\"blob\">";
  105. foreach my $line ( split("\n", $raw_file) ) {
  106. if ($line ne "") {
  107. $line = check_for_html($line);
  108. }
  109. print $fh "$line<br>";
  110. }
  111. print $fh "</pre></div><html>";
  112. close $fh;
  113. $logger->info("Generated HTML file for $filename");
  114. return $html_file;
  115. }
  116. sub gen_diff_colors($$$) {
  117. my $raw_diff = shift;
  118. my $id = shift;
  119. my $logger = shift;
  120. my $html_diff;
  121. open my $fh, '>>', \$html_diff or die "Can't open variable: $!";
  122. #print $fh "<!DOCTYPE html><html><div id=\"content\"><pre id=\"blob\">";
  123. print $fh "<!DOCTYPE html><html><b>$id</b><hr/><div id=\"content\"><pre>";
  124. my $line_counter = 1;
  125. foreach my $line ( split("\n", $raw_diff) ) {
  126. if ( $line ne "" ) {
  127. $line = check_for_html($line);
  128. }
  129. if ( $line =~ m/^\+/ ) {
  130. print $fh "<font color=\"green\">$line</font><br>";
  131. } elsif ( $line =~ m/^\-/ ) {
  132. print $fh "<font color=\"red\">$line</font><br>";
  133. } elsif ( $line =~ m/^@@/ ) {
  134. print $fh "<font color=\"blue\">$line</font><br>";
  135. } elsif ( $line =~ m/^diff/ ) {
  136. print $fh "<font color=\"purple\">$line</font><br>";
  137. } elsif ( $line =~ m/^commit/ ) {
  138. print $fh "<font color=\"purple\"><b>$line</b></font><br>";
  139. } else {
  140. print $fh "$line<br>";
  141. }
  142. $line_counter++;
  143. }
  144. print $fh "</pre></div></html>";
  145. close $fh;
  146. $logger->info("Generated colored diff for $id");
  147. return $html_diff;
  148. }
  149. # Main sub for generating project page
  150. # Might make more sense to split into more subs?
  151. sub write_project_content($$$$$) {
  152. my $project_dirs_ref = shift;
  153. my $trimmed_project_dirs_ref = shift;
  154. my $web_projects_dir = shift;
  155. my $clone_path = shift;
  156. my $logger = shift;
  157. # Make these array's easier to work with in a hash
  158. # Key is path to actual git dir, val is path to associated web dir
  159. my %projects_map;
  160. @projects_map{@$project_dirs_ref} = @$trimmed_project_dirs_ref;
  161. $logger->info("Assembling data structures of git info");
  162. # Write files part of project index
  163. foreach my $project_path ( keys %projects_map ) {
  164. my $spec_web_dir = $web_projects_dir . $projects_map{$project_path};
  165. my $project_index = $spec_web_dir . "index.html";
  166. write_file("",$project_index);
  167. append_file("<html><a href=\"../../index.html\"><b>Return to index</a></b><br>",$project_index);
  168. my $uniq_clone_path = "Disabled";
  169. if ( $clone_path ne "Disabled" ) {
  170. $uniq_clone_path = $clone_path . $projects_map{$project_path};
  171. }
  172. append_file("<b><pre>Clone:<font color=\"green\"> git clone $uniq_clone_path</font></pre></b><hr/>",$project_index);
  173. # Get all project data structures/info
  174. my ( $file_tree_ref, $file_content_ref, $commits_ref, $commit_ids_ref ) = get_file_tree($project_path,$logger);
  175. # Handle README
  176. if ( grep /^README.md$/, keys %$file_content_ref ) {
  177. $logger->info("$projects_map{$project_path} contains a README");
  178. my $readme_html = render_readme(${$file_content_ref}{'README.md'},$logger);
  179. append_file("$readme_html",$project_index);
  180. }
  181. append_file("<b>Files for $projects_map{$project_path}</b><br>",$project_index);
  182. append_file("<hr/>",$project_index);
  183. ## Write files ##
  184. append_file("<table><div id=\"cotent\"><table id=\"index\"><thead><tr><td><b>File</b></td><td><b>Commit</b></td><td><b>Raw</b></td></tr></thead><tbody>",$project_index);
  185. foreach my $filename ( sort keys %$file_content_ref ) {
  186. my $browserCompat = $filename . ".html";
  187. my $browserCompatRaw = $filename . "_raw" . ".html";
  188. # Rewrite dir paths so we can save on disk without producing actual dir structure
  189. if ( $filename =~ m/\// ) {
  190. my $copy = $filename;
  191. $copy =~ s/\//_/g;
  192. $browserCompat = $copy . ".html";
  193. $browserCompatRaw = $copy . "_raw" . ".html";
  194. }
  195. append_file("<tr><td><a href=\"$browserCompat\">$filename</a></td><td>${$file_tree_ref}{$filename}</td><td><a href=\"$browserCompatRaw\">raw</a></td>",$project_index);
  196. my $html_file = gen_line_nums(${$file_content_ref}{$filename},$filename,$logger);
  197. write_file("$html_file",$spec_web_dir . $browserCompat);
  198. my $raw_html_file = gen_raw_html(${$file_content_ref}{$filename},$filename,$logger);
  199. write_file("$raw_html_file",$spec_web_dir . $browserCompatRaw);
  200. }
  201. append_file("</tr></tbody></table></div></body>",$project_index);
  202. append_file("<br>", $project_index);
  203. append_file("<html><b>Logs for $projects_map{$project_path}</b><br>",$project_index);
  204. append_file("<table><div id=\"cotent\"><table id=\"index\"><tbody>",$project_index);
  205. append_file("<hr/>",$project_index);
  206. # iterate over array to keep ordering
  207. foreach my $commit_id ( @$commit_ids_ref ) {
  208. my $filename = $commit_id . ".html";
  209. append_file("<tr><td><a href=\"$filename\">$filename</a></td>",$project_index);
  210. my $html_diff = gen_diff_colors(${$commits_ref}{$commit_id},$commit_id,$logger);
  211. write_file($html_diff,$spec_web_dir . $filename);
  212. }
  213. append_file("</tr></tbody></table></div></body>",$project_index);
  214. append_file("</html>",$project_index);
  215. }
  216. $logger->info("Done writing files");
  217. }
  218. # Not used currently, need to do more trimming/etc
  219. # TODO
  220. # Work around is rm -rf the webroot manually and then just rerun gsg
  221. sub clean_web_root($$$) {
  222. my $web_projects_dir_path = shift;
  223. my $git_projects_ref = shift;
  224. my $logger = shift;
  225. my $lsCmd = findBin("ls",$logger);
  226. my $rmCmd = findBin("rm",$logger);
  227. foreach my $dir ( split("\n", shellex("$lsCmd -d $web_projects_dir_path/*/",$logger)) ) {
  228. if ( ! grep( /^$dir$/, @$git_projects_ref ) ) {
  229. $logger->info("Found $dir in webroot but not in git root, removing...");
  230. my $rmdir = $web_projects_dir_path . $dir;
  231. $logger->info("Would remove $rmdir");
  232. # Does this need to be safer? TODO
  233. #shellex("$rmCmd $rmdir/*",$logger);
  234. #shellex("$rmCmd -d $rmdir",$logger);
  235. }
  236. }
  237. }
  238. 1;