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]
 2 Backend dieser Webseite oder ich bin faul, mag kein JavaScript und lerne gerade Perl
 3 [date]
 4 2016-12-19T02:00
 5 [content]
 6 <p>Erst einmal guten Tag, freut mich, dass du meinen Blog gefunden hast. Ehrlich 
 7 gesagt ist das noch mehr Baustelle, aber eventuell findet sich hier schon etwas 
 8 Interessantes. Genauer gesagt möchte ich in diesem Post etwas genauer auf die 
 9 erwähnte Baustelle eingehen.</p>
10 <p>Ich habe mir ein paar Blogging Platformen oder überhaupt Plattformen zur 
11 Erstellung von Webseiten angeschaut, doch entweder waren diese mir zu langsam, 
12 benötigten JavaScript, damit sie überhaupt funktionierten oder haben mich beim 
13 Installieren wegen ihren Abhängigkeiten abgeschreckt. Außerdem habe ich sehr 
14 genaue Vorstellungen, wie das Ergebnis von dem, was ich schreibe aussehen soll. 
15 Dementsprechend wäre es die beste Lösung, wenn ich alles von Hand in Html 
16 schreibe. Genau das mache ich jetzt auch. Bis auf dass ich nicht jedes Mal den 
17 Htmlboilerplatecode schreibe, dafür habe ich mir ein Script geschrieben, dass 
18 mir aus einem einfachen Text in einer Datei mit ein paar Tags meine Webseite 
19 baut. Effektiv sieht dieser Blogpost so aus:</p>
20 
21 [code]
22 website-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 
27 werden 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 
30 von Umlauten, ß, etc in die resultierende Datei kopiert wird.</li>
31 <li>[code] ist die Außnahme von dieser Regel, wenn dieser Tag auftaucht, wird 
32 die Codedatei, die in der nächsten Zeile angegeben ist, in den Post 
33 kopiert.</li>
34 </ul>
35 
36 <p>Das Perlskript, dass das alles macht ist folgendes:</p>
37 
38 [code]
39 website-backend/webcc
40 
41 <p>Sehen wir mal davon ab, dass ich an diesem Skript Perl gelernt habe und ich 
42 mir keine Mühe gebe, sauberen Code zu schreiben. Ich hatte auf jeden Fall sehr 
43 viel Spaß daran und flexibler geht es kaum.</p>
44 
45 <p>Um die ganze Webseite mit den gesamten Abhängigkeiten und so weiter zu 
46 kompilieren, habe ich noch ein zweites Skript, dass ich bloß ausführen muss und 
47 dann die Ordner für Nginx an die richtige Stelle kopieren. Das achtet auch 
48 darauf, dass alles in der richtigen Reihenfolge erstellt wird (z.B. zuerst der 
49 Code mit vim gehighlightet wird) und erstellt auch die nach Datum oder Titel 
50 sortierten Listen.</p>
51 <p>Hier das Skript:</p>
52 
53 [code]
54 website-backend/webmake
55 
56 <p>So, ich versuche jetzt mal, ob das auch funktioniert und mache mich dann mal 
57 an 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
  2 use warnings;
  3 use strict;
  4 use v5.22;
  5 
  6 use File::Path qw(make_path);
  7 use DateTime::Format::ISO8601;
  8 use POSIX qw(strftime);
  9 use HTML::Entities;
 10 
 11 my $FH;
 12 
 13 # default definitions
 14 my $domain = "nekodev";
 15 my $date_html = '';
 16 my $date_str = '';
 17 my $title = '';
 18 my $outputFile;
 19 
 20 # mapping from domains (to navigation current page, output dir, etc)
 21 my %id_cur_page = (
 22     'nekodev' => '',
 23     'blog.nekodev' => '',
 24     'code.nekodev' => ''
 25 );
 26 
 27 my %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
 40 my $argvSize = 0+@ARGV;
 41 if ($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 
 67 while (<<>>) {
 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
 91 print<<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
128 EOF
129 
130 while (<<>>)
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 
145 print<<EOF;
146  </body>
147 </html>
148 EOF
149 
150 close $FH if defined $FH;
151 
152 
153 # build blog index
154 if ($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
161 EOF
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
  2 use warnings;
  3 use strict;
  4 use v5.22;
  5 
  6 use File::Path qw(make_path remove_tree);
  7 use DateTime;
  8 use DateTime::Format::ISO8601;
  9 use File::pushd;
 10 use Text::VimColor;
 11 
 12 my %output_dir = (
 13         'nekodev' => '../nekodev',
 14         'blog.nekodev' => '../blog.nekodev',
 15     'code.nekodev' => '../code.nekodev',
 16         '' => '../tmp',
 17     'tmpdir' => '../tmp'
 18 );
 19 
 20 my %src_dirs = (
 21     'code-tmp' => 'code-tmp',
 22     'blog' => 'blog',
 23     'web' => 'web'
 24 );
 25 
 26 
 27 my $blog_index = $output_dir{'tmpdir'}.'/blog_index';
 28 
 29 sub 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 
 42 sub 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 
 95 make_code_highlight('code');
 96 
 97 foreach(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 {
108 my $dir = pushd('tmp');
109 my %post2title;
110 my %post2date;
111 
112 open (my $FH, '<', $blog_index) or die "can't open blog_index file, no blog post or serious error: $!";
113 while( 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 }
126 close $FH;
127 
128 # traverse by date
129 my $date_index = <<EOF;
130 [title]
131 Blogposts nach Datum sortiert
132 [content]
133 EOF
134 
135 my $lastMonth;
136 foreach 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
162 my $tmp_blog_index = 'date_index.blog';
163 
164 open (my $date_index_fh, '>', $tmp_blog_index) or die "can't open date_index file: $!";
165 print {$date_index_fh} $date_index;
166 close $date_index_fh;
167 
168 system($^X, '-CSD', "../webcc", $tmp_blog_index);
169 
170 
171 # build alphabeticat index of posts
172 my $alphaIndex =<<EOF;
173 [title]
174 Blogposts alphabetisch sortiert
175 [content]
176 <ul>
177 EOF
178 
179 foreach 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
189 my $tmp_alpha_index = 'alpha_index.blog';
190 
191 open (my $alpha_index_fh, '>', $tmp_alpha_index) or die "can't open alpha_index file: $!";
192 print {$alpha_index_fh} $alphaIndex;
193 close $alpha_index_fh;
194 
195 system($^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