package Gsg::Html; use strict; use warnings; use Log::Log4perl qw(:easy); use lib "/usr/local/lib"; use Shellex::Shellex qw(shellex findBin); use Gsg::Gather qw(get_file_tree get_diff_stat); use Gsg::MdParse qw (render_readme); use Exporter qw(import); our @EXPORT_OK = qw( write_file append_file write_root_index clean_web_root write_project_content ); # These subs might belong in shellex # Add logger for write opts TODO sub write_file($$) { my $content = shift; my $path = shift; open(my $fh, ">", $path) or die "Couldnt open $path\n"; print $fh "$content"; close $fh; } sub append_file($$) { my $content = shift; my $path = shift; open(my $fh, ">>", $path) or die "Couldnt open $path\n"; print $fh "$content"; close $fh; } sub write_root_index($$$$) { my $index = shift; my $project_dirs_ref = shift; my $web_projects_dir_path = shift; my $logger = shift; write_file("", $index); append_file("Git Projects
\n",$index); append_file("Statically generated web root for browsing this git server
\n",$index); my $date_cmd = findBin("date",$logger); my $current_time = `$date_cmd`; chomp $current_time; append_file("Generated at $current_time

\n",$index); my $mkdirCmd = findBin("mkdir",$logger); foreach my $project ( @$project_dirs_ref ) { my $indexPath = $project . "index.html"; append_file("
\n",$index); append_file("\n",$index); shellex("$mkdirCmd -p $web_projects_dir_path$project",$logger); } append_file("
$project
\n",$index); $logger->info("Wrote root index at $index"); } sub check_for_html($) { # Expects line from gen_line_nums or gen_diff_colors # Will change < and > chars to < or > # This adds tons of overhead, but should work better # than and will solve the rendering problems my $line = shift; my $new_line; open my $fh, '>>', \$new_line or die "Can't open variable: $!"; foreach my $char ( split("",$line) ) { if ( ! defined $char || $char eq "" ) { print "Empty char\n"; next; } if ( $char eq "<" ) { print $fh "&lt;"; } elsif ( $char eq ">" ) { print $fh "&gt;"; } else { print $fh "$char"; } } close $fh; return $new_line; } sub gen_line_nums($$$) { my $raw_file = shift; my $filename = shift; my $logger = shift; my $html_file; # Might be a better way to do this? TODO open my $fh, '>>', \$html_file or die "Can't open variable: $!"; print $fh "<!DOCTYPE html><html><b>$filename</b><hr/><div id=\"content\"><pre id=\"blob\">"; my $line_counter = 1; foreach my $line ( split("\n", $raw_file) ) { if ( $line ne "" ) { $line = check_for_html($line); } print $fh "<a href=\"\#l$line_counter\" class=\"line\" id=\"l$line_counter\">$line_counter</a>\t$line<br>"; $line_counter++; } print $fh "</pre></div><html>"; close $fh; $logger->info("Generated line numbers for $filename"); return $html_file; } sub gen_diff_colors($$$) { my $raw_diff = shift; my $id = shift; my $logger = shift; my $html_diff; open my $fh, '>>', \$html_diff or die "Can't open variable: $!"; #print $fh "<!DOCTYPE html><html><div id=\"content\"><pre id=\"blob\">"; print $fh "<!DOCTYPE html><html><b>$id</b><hr/><div id=\"content\"><pre>"; my $line_counter = 1; foreach my $line ( split("\n", $raw_diff) ) { if ( $line ne "" ) { $line = check_for_html($line); } if ( $line =~ m/^\+/ ) { print $fh "<font color=\"green\">$line</font><br>"; } elsif ( $line =~ m/^\-/ ) { print $fh "<font color=\"red\">$line</font><br>"; } elsif ( $line =~ m/^@@/ ) { print $fh "<font color=\"blue\">$line</font><br>"; } elsif ( $line =~ m/^diff/ ) { print $fh "<font color=\"purple\">$line</font><br>"; } elsif ( $line =~ m/^commit/ ) { print $fh "<font color=\"purple\"><b>$line</b></font><br>"; } else { print $fh "$line<br>"; } $line_counter++; } print $fh "</pre></div></html>"; close $fh; $logger->info("Generated colored diff for $id"); return $html_diff; } # Main sub for generating project page # Might make more sense to split into more subs? sub write_project_content($$$$$) { my $project_dirs_ref = shift; my $trimmed_project_dirs_ref = shift; my $web_projects_dir = shift; my $clone_path = shift; my $logger = shift; # Make these array's easier to work with in a hash # Key is path to actual git dir, val is path to associated web dir my %projects_map; @projects_map{@$project_dirs_ref} = @$trimmed_project_dirs_ref; $logger->info("Assembling data structures of git info"); # Write files part of project index foreach my $project_path ( keys %projects_map ) { my $spec_web_dir = $web_projects_dir . $projects_map{$project_path}; my $project_index = $spec_web_dir . "index.html"; write_file("",$project_index); append_file("<html><a href=\"../../index.html\"><b>Return to index</a></b><br>",$project_index); my $uniq_clone_path = "Disabled"; if ( $clone_path ne "Disabled" ) { $uniq_clone_path = $clone_path . $projects_map{$project_path}; } append_file("<b><pre>Clone:<font color=\"green\"> git clone $uniq_clone_path</font></pre></b><hr/>",$project_index); # Get all project data structures/info my ( $file_tree_ref, $file_content_ref, $commits_ref, $commit_ids_ref ) = get_file_tree($project_path,$logger); # Handle README if ( grep /^README.md$/, keys %$file_content_ref ) { $logger->info("$projects_map{$project_path} contains a README"); my $readme_html = render_readme(${$file_content_ref}{'README.md'},$logger); append_file("$readme_html",$project_index); } append_file("<b>Files for $projects_map{$project_path}</b><br>",$project_index); append_file("<hr/>",$project_index); ## Write files ## append_file("<table><div id=\"cotent\"><table id=\"index\"><thead><tr><td><b>File</b></td><td><b>Commit</b></td></tr></thead><tbody>",$project_index); foreach my $filename ( sort keys %$file_content_ref ) { my $browserCompat = $filename . ".html"; # Rewrite dir paths so we can save on disk without producing actual dir structure if ( $filename =~ m/\// ) { my $copy = $filename; $copy =~ s/\//_/g; $browserCompat = $copy . ".html"; } append_file("<tr><td><a href=\"$browserCompat\">$filename</a></td><td>${$file_tree_ref}{$filename}</td>",$project_index); my $html_file = gen_line_nums(${$file_content_ref}{$filename},$filename,$logger); write_file("$html_file",$spec_web_dir . $browserCompat); } append_file("</tr></tbody></table></div></body>",$project_index); append_file("<br>", $project_index); append_file("<html><b>Logs for $projects_map{$project_path}</b><br>",$project_index); append_file("<table><div id=\"cotent\"><table id=\"index\"><tbody>",$project_index); append_file("<hr/>",$project_index); # iterate over array to keep ordering foreach my $commit_id ( @$commit_ids_ref ) { my $filename = $commit_id . ".html"; append_file("<tr><td><a href=\"$filename\">$filename</a></td>",$project_index); my $html_diff = gen_diff_colors(${$commits_ref}{$commit_id},$commit_id,$logger); write_file($html_diff,$spec_web_dir . $filename); } append_file("</tr></tbody></table></div></body>",$project_index); append_file("</html>",$project_index); } $logger->info("Done writing files"); } # Not used currently, need to do more trimming/etc # TODO # Work around is rm -rf the webroot manually and then just rerun gsg sub clean_web_root($$$) { my $web_projects_dir_path = shift; my $git_projects_ref = shift; my $logger = shift; my $lsCmd = findBin("ls",$logger); my $rmCmd = findBin("rm",$logger); foreach my $dir ( split("\n", shellex("$lsCmd -d $web_projects_dir_path/*/",$logger)) ) { if ( ! grep( /^$dir$/, @$git_projects_ref ) ) { $logger->info("Found $dir in webroot but not in git root, removing..."); my $rmdir = $web_projects_dir_path . $dir; $logger->info("Would remove $rmdir"); # Does this need to be safer? TODO #shellex("$rmCmd $rmdir/*",$logger); #shellex("$rmCmd -d $rmdir",$logger); } } } 1;