3 # This is a simple script that will produce my blog on repo.or.cz
5 # The idea is to have source-<timestamp>.txt files as input, having the
6 # stories, and this script turning them into nice HTML, committing
7 # everything, and then pushing it to my repository.
9 # The blog will then be served using gitweb.
11 # To make it easier on me, if a file "new" exists, it is automatically
12 # renamed using the current timestamp.
14 # make sure we're in the correct working directory
17 GITWEBURL
="$(git config gitweb.url)"
18 test -z "$GITWEBURL" && {
19 echo "Please set gitweb.url in the Git config first!" >&2
24 value
=$
(git config blog.
$1)
25 test -z "$value" && value
=$2
29 BACKGROUNDIMG
=$
(get_config background paper.jpg
)
30 TITLE
=$
(get_config title
"Dscho's blog")
31 MAXENTRIES
=$
(get_config maxPostsPerPage
10)
32 BRANCH
=$
(get_config branch blog
)
34 URLPREFIX
="$(dirname "$GITWEBURL")"/
35 REMOTEREPOSITORY
="$(basename "$GITWEBURL")"
36 URL
="$REMOTEREPOSITORY?a=blob_plain;hb=$BRANCH;f="
47 move_new_entry_back
() {
48 test -f source-
$now.txt
&&
49 mv source-
$now.txt
$NEW &&
50 git
rm --cached -f source-
$now.txt
60 # add illogical suffix
62 *1?|
*[04-9]) echo "$1th";;
69 make_chinese_hour
() {
100 make_roman_number
() {
103 ?
) digit_to_roman
$1 I V X
;;
104 ??
) echo $
(digit_to_roman
${1%?} X L C
)$
(make_roman_number
${1#?});;
105 ???
) echo $
(digit_to_roman
${1%??} C D M
)$
(make_roman_number
${1#?});;
106 ????
) echo $
(digit_to_roman
${1%???} M
)$
(make_roman_number
${1#?});;
111 printf "%s, %s of %s, Anno Domini %s, at the hour of the %s\n" \
113 $
(nth $
(date +%e
-d @
$1)) \
115 $
(make_roman_number $
(date +%Y
-d @
$1)) \
116 $
(make_chinese_hour $
(date +%H
-d @
$1))
119 # make an argument for sed, to replace $1..$1 by <$2>..</$2>
120 markup_substitution
() {
122 ?
) echo "s/$1\\([^$1]*\\)$1/<$2>\\\\1<\/$2>/g";;
125 tmp2
="\\|${1%?}[^${1#?}]$tmp"
126 tmp3
="\\($tmp\\($tmp2\\($tmp2\\($tmp2\\)\\)\\)\\)"
127 echo "s/$1$tmp3$1/<$2>\\\\1<\/$2>/g"
132 # transform markup in stdin to HTML
134 image_pattern
="\\[\\[Image:\([^]]*\)"
135 image_pattern2
="$image_pattern\(\\|[^\]]*\)\?\]\]"
137 *invert-bash
*) bash_bg
=white
; bash_fg
=black
;;
138 *) bash_bg
=black
; bash_fg
=white
;;
140 sed -e 's!^$!</p><p>!' \
141 -e "$(markup_substitution "''" i)" \
142 -e "$(markup_substitution "_
" u)" \
143 -e 's!IMHO!in my humble opinion!g' \
144 -e 's!BTW!By the way,!g' \
145 -e 's!repo.or.cz!<a href=http://&>&</a>!g' \
146 -e 's!:-)!\☺!g' \
147 -e "s!$image_pattern2!<center><img src=$URL\1></center>!g" \
148 -e "s!\\[\\[SVG:\\([^]]*\\)\]\]!$THIS handle &!e" \
150 border=1 bgcolor='$bash_bg'>\
151 <tr><td bgcolor=lightblue colspan=3>\
155 <table cellspacing=5 border=0\
156 style="color:'$bash_fg';">\
159 -e 's!</bash>! </pre>\
167 # output lines containing <timestamp> <filename> <title>
168 get_blog_entries
() {
169 for file in $
(ls -r source-
*.txt
)
171 basename=${file%.txt}
172 timestamp
=${basename#source-}
173 title
="$(sed 1q < $file | markup)"
174 echo "$timestamp $file $title"
178 get_last_removed_entry
() {
179 git log
--pretty=format
: --name-only --diff-filter=D HEAD |
183 source-
*.txt
) file=$line;;
184 '') test -z "$file" ||
{
194 body_style
="width:800px"
195 body_style
="$body_style;background-image:url($URL$BACKGROUNDIMG)"
196 body_style
="$body_style;background-repeat:repeat-y"
197 body_style
="$body_style;background-attachment:scroll"
198 body_style
="$body_style;padding:0px;"
199 text_style
="width:610px"
200 text_style
="$text_style;margin-left:120px"
201 text_style
="$text_style;margin-top:50px"
202 text_style
="$text_style;align:left"
203 text_style
="$text_style;vertical-align:top;"
207 <title>$TITLE</title>
208 <meta http-equiv="Content-Type"
209 content="text/html; charset=UTF-8"/>
211 <body style="$body_style">
212 <div style="$text_style">
219 toc_style
="position:absolute;top:50px;left:810px;width=$toc_width"
221 echo "<div style=\"$toc_style\">"
222 echo "<table width=$toc_width bgcolor=#e0e0e0 border=1>"
223 echo "<tr><th>Table of contents:</th></tr>"
227 while read timestamp filename title
229 date="$(date +"%d
%b
%Y
" -d @$timestamp)"
230 echo "<li><a href=#$timestamp>$date $title</a>"
234 last_removed_entry
=$
(get_last_removed_entry
)
235 test -z "$last_removed_entry" ||
{
236 commit
=$
(git log
--pretty=format
:%H
--diff-filter=AM \
237 -- $last_removed_entry |
239 previous
="$REMOTEREPOSITORY?a=blob_plain;hb=$commit"
240 echo "<a href=$previous;f=index.html>Older posts</a>"
242 echo '</td></tr></table>'
245 rss_style
="background-color:orange;text-decoration:none"
246 rss_style
="$rss_style;color:white;font-family:sans-serif;"
248 echo '<div style="text-align:right;">'
249 echo "<a href=\"$ORIGURL$RSS\""
250 echo ' title="Subscribe to my RSS feed"'
251 echo ' class="rss" rel="nofollow"'
252 echo " style=\"$rss_style\">RSS</a>"
256 test -f links.html
&& {
258 echo "<table width=$toc_width bgcolor=#e0e0e0 border=1>"
259 echo "<tr><th>Links:</th></tr>"
262 echo "</td></tr></table>"
266 test -z "$DRYRUN" && test -f google.adsense
&& {
268 echo "<table width=$toc_width bgcolor=#e0e0e0 border=1>"
269 echo "<tr><th>Google Ads:</th></tr>"
270 echo "<tr><td align=center>"
272 echo "</td></tr></table>"
276 } |
sed -s "s/^/$indent/"
279 # timestamps will not need padding to sort correctly, for some time...
281 while read timestamp filename title
283 echo "<h6>$(make_date $timestamp)</h6>"
284 echo "<a name=$timestamp>"
285 echo "<h2>$title</h2>"
288 sed 1d
< $filename | markup
291 sed -e "s/^./$indent&/" \
292 -e "/<pre>/,/<\/pre>/s/^$indent//"
302 echo '<?xml version="1.0" encoding="utf-8"?>'
303 echo '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">'
305 echo "<title>Dscho's blog</title>"
306 echo "<link>$URLPREFIX${URL}index.html</link>"
307 self
="$URLPREFIX$ORIGURL$RSS"
308 selfattribs
='rel="self" type="application/rss+xml"'
309 echo "<atom:link href=\"$self\" $selfattribs/>"
310 echo '<description>A few stories told by Dscho</description>'
311 echo "<lastBuildDate>$(date --rfc-2822)</lastBuildDate>"
312 echo '<language>en-us</language>'
315 while read timestamp filename title
318 echo "<title>$title</title>"
319 echo "<link>$URLPREFIX${URL}index.html#$timestamp</link>"
320 echo "<guid>$URLPREFIX${URL}index.html#$timestamp</guid>"
321 echo "<pubDate>$(date --rfc-2822 -d @$timestamp)</pubDate>"
322 description
="$(cat < $filename | markup invert-bash)"
323 echo "<description><![CDATA[$description]]></description>"
333 grep -v '\.\(rss\|html\|gitignore\|in\|sh\|txt\|adsense\)$'
336 remove_old_entries
() {
337 count
=$
(ls source-
*.txt |
wc -l)
338 test $MAXENTRIES -ge $count && return
340 for file in source-
*.txt
342 test $MAXENTRIES -lt $count ||
break
343 git
rm $file > /dev
/null ||
return 1
348 # remove no-longer referenced images
349 image_files
=$
(get_image_files
)
350 referenced_files
="$(cat source-*.txt |
352 sed -ne 's/\[\[\(Image\|SVG\)://p') $BACKGROUNDIMG"
353 for file in $
(echo $image_files $referenced_files $referenced_files |
354 tr ' ' '\n' |
sort |
uniq -u)
356 git
rm $file > /dev
/null ||
return 1
361 # never, ever have spaces in the file names
362 commit_new_images
() {
363 files
="$(remove_old_entries) $RSS" ||
364 die
"Could not remove old entries"
367 generate_rss
> $RSS &&
369 die
"Could not generate $RSS"
371 for image
in $
(cat source-
* |
373 sed -n 's/.*\[\[\(Image\|SVG\)://p' |
377 git add
$image || die
"Could not git add image $image"
378 files
="$files $image"
381 git update-index
--refresh &&
382 git diff-files
--quiet -- $files &&
383 git
diff --cached --quiet HEAD
-- $files ||
384 git commit
-s -m "Commit some images on $(make_date $now)" $files
388 # for some reason, Firefox adds scrollbars, so nudge the width a bit
389 width
=$
(sed -ne 's/.* width="\([^"]*\).*/\1/p' -e '/<metadata/q' < "$1")
390 test -z "$width" || width
=" width=$(($width+5))"
394 REV
=$
(git rev-list
-1 HEAD
-- $1)
396 URL
="$REMOTEREPOSITORY?a=blob_plain;hb=$REV;f="
403 <embed type="image/svg+xml"
404 src="$URL$1"$width />
409 <a href=$URL$1>$1</a>
419 # parse command line option
421 *dry
*) DRYRUN
=1; export DRYRUN
; shift;;
422 *show
*) firefox
"$(pwd)"/$TEST; exit;;
423 *remote
*) firefox
$URLPREFIX$URL$OUTPUT; exit;;
426 "[[SVG:"*) file=${2#??SVG:}; file=${file%??}; handle_svg_file
"$file";;
433 die
"Usage: $0 [--dry-run]"
435 # make sure we're on the correct branch
436 test refs
/heads
/$BRANCH = $
(git symbolic-ref HEAD
) ||
437 die
"Not on branch $BRANCH"
439 # make sure there are no uncommitted changes
440 git update-index
--refresh &&
441 git diff-files
--quiet ||
442 die
"Have unstaged changes!"
444 # rename the new blog entry if it exists
447 mv -i $NEW source-
$now.txt
&&
448 git add source-
$now.txt
450 die
"Could not rename source.txt"
452 # commit the images that are referenced and not yet committed
453 test ! -z "$DRYRUN" ||
455 die
"Could not commit new images"
457 # to find the images reliably, we have to use the commit name, not the branch
458 # we use the latest commit touching an image file.
459 IMAGEFILES
="$(get_image_files)"
460 REV
=$
(git rev-list
-1 HEAD
-- $IMAGEFILES)
461 test -z "$REV" && REV
=$BRANCH
462 URL
="$REMOTEREPOSITORY?a=blob_plain;hb=$REV;f="
464 if test ! -z "$DRYRUN"
466 # Output to test.html and have local links into the current directory
471 make_html
> $OUTPUT || die
"Could not write $OUTPUT"
473 test ! -z "$DRYRUN" && {
479 git commit
-s -m "Update $(make_date $now)" &&
480 git push origin
+$BRANCH