Backend dieser Webseite oder ich bin faul, mag kein JavaScript und lerne gerade Perl

Erst einmal guten Tag, freut mich, dass du meinen Blog gefunden hast. Ehrlich gesagt ist das noch mehr Baustelle, aber eventuell findet sich hier schon etwas Interessantes. Genauer gesagt möchte ich in diesem Post etwas genauer auf die erwähnte Baustelle eingehen.

Ich habe mir ein paar Blogging Platformen oder überhaupt Plattformen zur Erstellung von Webseiten angeschaut, doch entweder waren diese mir zu langsam, benötigten JavaScript, damit sie überhaupt funktionierten oder haben mich beim Installieren wegen ihren Abhängigkeiten abgeschreckt. Außerdem habe ich sehr genaue Vorstellungen, wie das Ergebnis von dem, was ich schreibe aussehen soll. Dementsprechend wäre es die beste Lösung, wenn ich alles von Hand in Html schreibe. Genau das mache ich jetzt auch. Bis auf dass ich nicht jedes Mal den Htmlboilerplatecode schreibe, dafür habe ich mir ein Script geschrieben, dass mir aus einem einfachen Text in einer Datei mit ein paar Tags meine Webseite baut. Effektiv sieht dieser Blogpost so aus:

 1[title]
 2Backend dieser Webseite oder ich bin faul, mag kein JavaScript und lerne gerade Perl
 3[date]
 42016-12-19T02:00
 5[content]
 6<p>Erst einmal guten Tag, freut mich, dass du meinen Blog gefunden hast. Ehrlich 
 7gesagt ist das noch mehr Baustelle, aber eventuell findet sich hier schon etwas 
 8Interessantes. Genauer gesagt möchte ich in diesem Post etwas genauer auf die 
 9erwähnte Baustelle eingehen.</p>
10<p>Ich habe mir ein paar Blogging Platformen oder überhaupt Plattformen zur 
11Erstellung von Webseiten angeschaut, doch entweder waren diese mir zu langsam, 
12benötigten JavaScript, damit sie überhaupt funktionierten oder haben mich beim 
13Installieren wegen ihren Abhängigkeiten abgeschreckt. Außerdem habe ich sehr 
14genaue Vorstellungen, wie das Ergebnis von dem, was ich schreibe aussehen soll. 
15Dementsprechend wäre es die beste Lösung, wenn ich alles von Hand in Html 
16schreibe. Genau das mache ich jetzt auch. Bis auf dass ich nicht jedes Mal den 
17Htmlboilerplatecode schreibe, dafür habe ich mir ein Script geschrieben, dass 
18mir aus einem einfachen Text in einer Datei mit ein paar Tags meine Webseite 
19baut. Effektiv sieht dieser Blogpost so aus:</p>
20
21[code]
22website-backend/blogpost
23
24<p>Die Tags sind dabei relativ selbsterklärend.</p>
25<ul>
26<li>[title] ist der Titel, damit der auch in alle passenden Tags eingebaut 
27werden kann und in die Überschrift kommt</li>
28<li>[date] ist das Datum in ISO8601</li>
29<li>[content] ist effektiv Html, das ohne weitere Bearbeitung, bis auf ersetzen 
30von Umlauten, ß, etc in die resultierende Datei kopiert wird.</li>
31<li>[code] ist die Außnahme von dieser Regel, wenn dieser Tag auftaucht, wird 
32die Codedatei, die in der nächsten Zeile angegeben ist, in den Post 
33kopiert.</li>
34</ul>
35
36<p>Das Perlskript, dass das alles macht ist folgendes:</p>
37
38[code]
39website-backend/webcc
40
41<p>Sehen wir mal davon ab, dass ich an diesem Skript Perl gelernt habe und ich 
42mir keine Mühe gebe, sauberen Code zu schreiben. Ich hatte auf jeden Fall sehr 
43viel Spaß daran und flexibler geht es kaum.</p>
44
45<p>Um die ganze Webseite mit den gesamten Abhängigkeiten und so weiter zu 
46kompilieren, habe ich noch ein zweites Skript, dass ich bloß ausführen muss und 
47dann die Ordner für Nginx an die richtige Stelle kopieren. Das achtet auch 
48darauf, dass alles in der richtigen Reihenfolge erstellt wird (z.B. zuerst der 
49Code mit vim gehighlightet wird) und erstellt auch die nach Datum oder Titel 
50sortierten Listen.</p>
51<p>Hier das Skript:</p>
52
53[code]
54website-backend/webmake
55
56<p>So, ich versuche jetzt mal, ob das auch funktioniert und mache mich dann mal 
57an den CSS Part. Schönen Abend noch!</p>

Die Tags sind dabei relativ selbsterklärend.

Das Perlskript, dass das alles macht ist folgendes:

  1#!/usr/bin/perl -CSD
  2use warnings;
  3use strict;
  4use v5.22;
  5
  6use File::Path qw(make_path);
  7use DateTime::Format::ISO8601;
  8use POSIX qw(strftime);
  9use HTML::Entities;
 10
 11my $FH;
 12
 13# default definitions
 14my $domain = "nekodev";
 15my $date_html = '';
 16my $date_str = '';
 17my $title = '';
 18my $outputFile;
 19
 20# mapping from domains (to navigation current page, output dir, etc)
 21my %id_cur_page = (
 22    'nekodev' => '',
 23    'blog.nekodev' => '',
 24    'code.nekodev' => ''
 25);
 26
 27my %output_dir = (
 28    'nekodev' => '../nekodev',
 29    'blog.nekodev' => '../blog.nekodev',
 30    'code.nekodev' => '../code.nekodev',
 31
 32    'code-tmp' => '../code-tmp',
 33    '' => '../tmp',
 34    'tmpdir' => '../tmp'
 35);
 36
 37
 38
 39# parse file name
 40my $argvSize = 0+@ARGV;
 41if ($argvSize > 0) {
 42    warn 'Processing: '.$ARGV[0]."\n";
 43
 44    die "too many arguments" if $argvSize > 1;
 45
 46    my ($basename,$fileext) = $ARGV[0] =~ /(.*)\.(.*)/;
 47
 48    print ' type: '.$fileext."\n";
 49    $domain = "nekodev" if $fileext eq "web";
 50    $domain = "blog.nekodev" if $fileext eq "blog";
 51    $domain = "code.nekodev" if $fileext eq "code";
 52
 53    # open output file
 54    $outputFile = $output_dir{$domain}.'/'.$basename.'.html';
 55
 56    warn $outputFile, "\n";
 57
 58    make_path($outputFile =~ /(.*)\//);
 59    open($FH, '>', $outputFile) or die "cannot open file $outputFile: $!";
 60    select $FH;
 61}
 62
 63
 64# parse file parameters
 65$id_cur_page{$domain} = 'id="cur-navpage"';
 66
 67while (<<>>) {
 68    chomp;
 69    my $currentTag = $_;
 70    $currentTag eq '[title]' and chomp($title = <<>>);
 71
 72    if ($currentTag eq '[date]') {
 73        chomp($date_str = <<>>);
 74        my $date = DateTime::Format::ISO8601->parse_datetime( $date_str );
 75
 76        # make sure we have the right format
 77        $date_str = $date->iso8601;
 78
 79        # format nice <time> tag with locale dependent text
 80        $date->set_locale('de-DE');
 81        #my $localeDate_str = $date->strftime('%c');
 82        my $localeDate_str = $date->strftime('%A, %d. %B %Y, %H:%M');
 83        $date_html = "<time datetime=$date_str>$localeDate_str</time>";
 84    }
 85
 86    last if $currentTag eq "[content]";
 87}
 88
 89
 90# write content
 91print<<EOF;
 92<html>
 93 <head>
 94  <meta charset="utf-8"/>
 95  <title>$title - $domain</title>
 96  <link title="dark" rel="stylesheet" type="text/css" href="colors-dark.css"/>
 97  <link title="light" rel="alternate stylesheet" type="text/css" href="colors-light.css"/>
 98  <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
 99  <meta name="viewport" content="width=device-width, initial-scale=1">
100 </head>
101 <body>
102  <nav id="navbar">
103   <ul>
104    <li $id_cur_page{'nekodev'} tabindex="1">
105     <a href="http://nekodev.net/index.html">Home</a>
106     <ul>
107      <li tabindex="2"><a href="http://nekodev.net/projects.html">Projects</a></li>
108      <li tabindex="3"><a href="http://nekodev.net/about.html">About</a></li>
109     </ul>
110    <li $id_cur_page{'blog.nekodev'} tabindex="4">
111     <a href="http://blog.nekodev.net">Blog</a>
112     <ul>
113      <li tabindex="5"><a href="http://blog.nekodev.net/alpha_index.html">Nach Titel</a></li>
114      <li tabindex="6"><a href="http://blog.nekodev.net/date_index.html">Nach Datum</a></li>
115     </ul>
116    </li>
117    </li>
118    <li $id_cur_page{'code.nekodev'} tabindex="7">
119     <a href="http://code.nekodev.net">Code</a>
120     <ul>
121      <li tabindex="8"><a href="test.html">Test</a></li>
122     </ul>
123    </li>
124   </ul>
125  </nav>
126  <h1>$title</h1>
127  $date_html
128EOF
129
130while (<<>>)
131{
132    # insert code when referenced by code tag
133    if ($_ eq "[code]\n")
134    {
135        chomp ( my $codefile = <<>> );
136        open my $codefh, "<", $output_dir{'code-tmp'}.'/'.$codefile.'.code' or die "cant find code file $codefile: $!";
137        while ( <$codefh> ne "[content]\n" ) {};
138        print while <$codefh>;
139    }
140
141    my $encoded =  encode_entities($_, '^\n\x20-\x25\x27-\x7e');
142    print $encoded if defined $encoded;
143}
144
145print<<EOF;
146 </body>
147</html>
148EOF
149
150close $FH if defined $FH;
151
152
153# build blog index
154if ($domain eq 'blog.nekodev' and defined $outputFile) {
155    open my $blogIndexFile, '>>', $output_dir{'tmpdir'}.'/blog_index';
156    $outputFile =~ s/$output_dir{'blog.nekodev'}\///;
157    print {$blogIndexFile} <<EOF;
158$outputFile
159$title
160$date_str
161EOF
162}

Sehen wir mal davon ab, dass ich an diesem Skript Perl gelernt habe und ich mir keine Mühe gebe, sauberen Code zu schreiben. Ich hatte auf jeden Fall sehr viel Spaß daran und flexibler geht es kaum.

Um die ganze Webseite mit den gesamten Abhängigkeiten und so weiter zu kompilieren, habe ich noch ein zweites Skript, dass ich bloß ausführen muss und dann die Ordner für Nginx an die richtige Stelle kopieren. Das achtet auch darauf, dass alles in der richtigen Reihenfolge erstellt wird (z.B. zuerst der Code mit vim gehighlightet wird) und erstellt auch die nach Datum oder Titel sortierten Listen. Hier das Skript:

  1#!/usr/bin/perl -CSD
  2use warnings;
  3use strict;
  4use v5.22;
  5
  6use File::Path qw(make_path remove_tree);
  7use DateTime;
  8use DateTime::Format::ISO8601;
  9use File::pushd;
 10use Text::VimColor;
 11
 12my %output_dir = (
 13        'nekodev' => '../nekodev',
 14        'blog.nekodev' => '../blog.nekodev',
 15    'code.nekodev' => '../code.nekodev',
 16        '' => '../tmp',
 17    'tmpdir' => '../tmp'
 18);
 19
 20my %src_dirs = (
 21    'code-tmp' => 'code-tmp',
 22    'blog' => 'blog',
 23    'web' => 'web'
 24);
 25
 26
 27my $blog_index = $output_dir{'tmpdir'}.'/blog_index';
 28
 29sub make {
 30    foreach(@_) {
 31        system($^X, '-CSD', "../webcc", $_) if (-f $_);
 32        #`perl -d webcc $_` if (-f $_);
 33        if (-d $_) {
 34            print "Processing directory $_\n";
 35
 36            my $dirGlob = $_.'/*';
 37            make(glob $dirGlob);
 38        }
 39    }
 40}
 41
 42sub make_code_highlight {
 43
 44    foreach(@_) {
 45        if (-f $_) {
 46            #$highlighter->syntax_mark_file($_);
 47            # need to overwrite vim options, as nvim doesn't provide -X flag
 48            my @vim_opts = [qw( -RZ -i NONE -u NONE -N -n ), "+set nomodeline"];
 49            my @extra_vim_opts = ['+setg number', '+set printoptions=number:y'];
 50            my $highlighter = Text::VimColor->new(
 51                file => $_,
 52                all_syntax_groups => 1,
 53                vim_command => 'nvim',
 54                vim_options => @vim_opts,
 55                extra_vim_options => @extra_vim_opts
 56            );
 57
 58            my $modDate = DateTime->from_epoch( epoch => (stat $_)[9])->iso8601();
 59            my $outFileName = $_ =~ s/^code\//code-tmp\//r;
 60            $outFileName .= ".code";
 61            my ($dir,$saneFileName) = $_ =~ /(.*)\/(.*)/;
 62            make_path($dir);
 63            print "outputting file $outFileName\n";
 64
 65            open my $out_file, '>', $outFileName or die "Can't open out file $outFileName: $!";
 66            print {$out_file} "[title]\n$saneFileName\n[date]\n$modDate\n[content]\n<pre>\n";
 67
 68            $saneFileName =~ s/\./_/g;
 69            my $lineNr = 1;
 70            foreach(split /^/, $highlighter->html) {
 71                my $lineId = 'L'.$lineNr.$saneFileName;
 72                print {$out_file} "<span id=\"$lineId\" class=\"synLineNr\">$lineNr </span>".$_;
 73                $lineNr++;
 74            }
 75            print {$out_file} "</pre>\n";
 76            close $out_file;
 77        }
 78
 79        if (-d $_) {
 80            print "Processing directory $_\n";
 81            my $dirGlob = $_.'/*';
 82            make_code_highlight(glob $dirGlob);
 83        }
 84    }
 85}
 86
 87
 88# setup tmpdirs
 89{
 90    my $dir = pushd($src_dirs{'blog'});
 91    remove_tree($output_dir{'tmpdir'});
 92    make_path($output_dir{'tmpdir'});
 93}
 94
 95make_code_highlight('code');
 96
 97foreach(values %src_dirs)
 98{
 99    my $dir = pushd($_);
100    make(glob '*');
101}
102
103
104#make(@ARGV);
105
106# build blog.nekodex index.html
107{
108my $dir = pushd('tmp');
109my %post2title;
110my %post2date;
111
112open (my $FH, '<', $blog_index) or die "can't open blog_index file, no blog post or serious error: $!";
113while( my $post = <$FH> ) {
114    chomp $post;
115
116
117    chomp( my $title = <$FH>);
118    chomp( my $date = <$FH>);
119
120    if( $date ne '' and $title ne '' )
121    {
122        $post2title{$post} = $title;
123        $post2date{$post} = $date;
124    }
125}
126close $FH;
127
128# traverse by date
129my $date_index = <<EOF;
130[title]
131Blogposts nach Datum sortiert
132[content]
133EOF
134
135my $lastMonth;
136foreach my $post (sort { $post2date{$a} cmp $post2date{$b} } keys %post2date) {
137    my $date_str = $post2date{$post};
138    my $date = DateTime::Format::ISO8601->parse_datetime( $date_str );
139        # format with locale dependent text
140        $date->set_locale('de-DE');
141        my $localeDate_str = $date->strftime('%A, %d. %B %Y, %H:%M');
142
143    my $curMonth = $date->strftime('%B %Y');
144    if (defined $lastMonth) {
145        if ($curMonth ne $lastMonth) {
146            $date_index .= "</ul><li><time datetime=<time datetime=$date_str>$curMonth</time></li><ul>\n";
147            $lastMonth = $curMonth;
148        }
149    } else {
150        $date_index .= "<ul><li><time datetime=<time datetime=$date_str>$curMonth</time></li><ul>\n";
151        $lastMonth = $curMonth;
152    }
153
154    my $pattern = $output_dir{'blog.nekodev'}."\/";
155    my $linkPath = $post;
156    $linkPath =~ s/$pattern//;
157    $date_index .= "<li><a href=\"$linkPath\">$post2title{$post} | <time datetime=$date_str>$localeDate_str</time></a></li>\n";
158}
159$date_index .= "</ul></ul>\n";
160
161# We're in tmpdir
162my $tmp_blog_index = 'date_index.blog';
163
164open (my $date_index_fh, '>', $tmp_blog_index) or die "can't open date_index file: $!";
165print {$date_index_fh} $date_index;
166close $date_index_fh;
167
168system($^X, '-CSD', "../webcc", $tmp_blog_index);
169
170
171# build alphabeticat index of posts
172my $alphaIndex =<<EOF;
173[title]
174Blogposts alphabetisch sortiert
175[content]
176<ul>
177EOF
178
179foreach my $post (sort { $post2title{$a} cmp $post2title{$b} } keys %post2title) {
180    my $pattern = $output_dir{'blog.nekodev'}."\/";
181    my $linkPath = $post;
182    $linkPath =~ s/$pattern//;
183    $alphaIndex .= "<li><a href=\"$linkPath\">$post2title{$post}</li>\n";
184}
185$alphaIndex .= "</ul>\n";
186
187
188# We're in tmpdir
189my $tmp_alpha_index = 'alpha_index.blog';
190
191open (my $alpha_index_fh, '>', $tmp_alpha_index) or die "can't open alpha_index file: $!";
192print {$alpha_index_fh} $alphaIndex;
193close $alpha_index_fh;
194
195system($^X, '-CSD', "../webcc", $tmp_alpha_index);
196}

So, ich versuche jetzt mal, ob das auch funktioniert und mache mich dann mal an den CSS Part. Schönen Abend noch!

Impressum