Commit some images on Saturday, 24th of January, Anno Domini MMIX, at the hour of...
[git/dscho.git] / upload.sh
blob38924e0741ed7ce2dd93594905da755313eb6fb4
1 #!/bin/sh
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 "source.txt" exists, it is
12 # automatically renamed using the current timestamp.
14 # TODO: have a configurable maximum number of entries per page, and links
15 # to older pages
17 # make sure we're in the correct working directory
18 cd "$(dirname "$0")"
20 GITWEBURL="$(git config gitweb.url)"
21 test -z "$GITWEBURL" && {
22 echo "Please set gitweb.url in the Git config first!" >&2
23 exit 1
26 URLPREFIX="$(dirname "$GITWEBURL")"/
27 REMOTEREPOSITORY="$(basename "$GITWEBURL")"
28 BRANCH=blog
29 URL="$REMOTEREPOSITORY?a=blob_plain;hb=$BRANCH;f="
30 ORIGURL=$URL
31 NEW=new
32 OUTPUT=index.html
33 RSS=blog.rss
34 TEST=test.html
35 TITLE="Dscho's blog"
36 THIS=$0
38 LC_ALL=C
39 export LC_ALL
41 move_new_entry_back () {
42 test -f source-$now.txt &&
43 mv source-$now.txt $NEW &&
44 git rm --cached -f source-$now.txt
47 die () {
48 move_new_entry_back
49 echo "$*" >&2
50 exit 1
53 nth () {
54 # add illogical suffix
55 case "$1" in
56 *1?|*[04-9]) echo "$1th";;
57 *1) echo "$1st";;
58 *2) echo "$1nd";;
59 *3) echo "$1rd";;
60 esac
63 make_chinese_hour () {
64 case $1 in
65 23|00) echo Rat;;
66 01|02) echo Buffalo;;
67 03|04) echo Tiger;;
68 05|06) echo Rabbit;;
69 07|08) echo Dragon;;
70 09|10) echo Snake;;
71 11|12) echo Horse;;
72 13|14) echo Goat;;
73 15|16) echo Monkey;;
74 17|18) echo Rooster;;
75 19|20) echo Dog;;
76 21|22) echo Pig;;
77 esac
80 digit_to_roman () {
81 case $1 in
82 1) echo $2;;
83 2) echo $2$2;;
84 3) echo $2$2$2;;
85 4) echo $2$3;;
86 5) echo $3;;
87 6) echo $3$2;;
88 7) echo $3$2$2;;
89 8) echo $3$2$2$2;;
90 9) echo $2$4;;
91 esac
94 make_roman_number () {
95 case $1 in
96 '') ;;
97 ?) digit_to_roman $1 I V X;;
98 ??) echo $(digit_to_roman ${1%?} X L C)$(make_roman_number ${1#?});;
99 ???) echo $(digit_to_roman ${1%??} C D M)$(make_roman_number ${1#?});;
100 ????) echo $(digit_to_roman ${1%???} M)$(make_roman_number ${1#?});;
101 esac
104 make_date () {
105 printf "%s, %s of %s, Anno Domini %s, at the hour of the %s\n" \
106 $(date +%A -d @$1) \
107 $(nth $(date +%e -d @$1)) \
108 $(date +%B -d @$1) \
109 $(make_roman_number $(date +%Y -d @$1)) \
110 $(make_chinese_hour $(date +%H -d @$1))
113 # make an argument for sed, to replace $1..$1 by <$2>..</$2>
114 markup_substitution () {
115 case "$1" in
116 ?) echo "s/$1\\([^$1]*\\)$1/<$2>\\\\1<\/$2>/g";;
118 tmp="[^${1%?}]*"
119 tmp2="\\|${1%?}[^${1#?}]$tmp"
120 tmp3="\\($tmp\\($tmp2\\($tmp2\\($tmp2\\)\\)\\)\\)"
121 echo "s/$1$tmp3$1/<$2>\\\\1<\/$2>/g"
123 esac
126 # transform markup in stdin to HTML
127 markup () {
128 image_pattern="\\[\\[Image:\([^]]*\)"
129 image_pattern2="$image_pattern\(\\|[^\]]*\)\?\]\]"
130 case "$*" in
131 *invert-bash*) bash_bg=white; bash_fg=black;;
132 *) bash_bg=black; bash_fg=white;;
133 esac
134 sed -e 's!^$!</p><p>!' \
135 -e "$(markup_substitution "''" i)" \
136 -e "$(markup_substitution "_" u)" \
137 -e 's!IMHO!in my humble opinion!g' \
138 -e 's!BTW!By the way,!g' \
139 -e 's!repo.or.cz!<a href=http://&>&</a>!g' \
140 -e 's!:-)!\&#x263a;!g' \
141 -e "s!$image_pattern2!<center><img src=$URL\1></center>!g" \
142 -e "s!\\[\\[SVG:\\([^]]*\\)\]\]!$THIS handle &!e" \
143 -e 's!<bash>!<table\
144 border=1 bgcolor='$bash_bg'>\
145 <tr><td bgcolor=lightblue colspan=3>\
146 \&nbsp;\
147 </td></tr>\
148 <tr><td>\
149 <table cellspacing=5 border=0\
150 style="color:'$bash_fg';">\
151 <tr><td>\
152 <pre>!' \
153 -e 's!</bash>! </pre>\
154 </td></tr>\
155 </table>\
156 </td></tr>\
157 </table>!' \
161 # output lines containing <timestamp> <filename> <title>
162 get_blog_entries () {
163 for file in $(ls -r source-*.txt)
165 basename=${file%.txt}
166 timestamp=${basename#source-}
167 title="$(sed 1q < $file | markup)"
168 echo "$timestamp $file $title"
169 done
172 # make HTML page
173 make_html () {
174 body_style="width:800px"
175 body_style="$body_style;background-image:url(${URL}paper.jpg)"
176 body_style="$body_style;background-repeat:repeat-y"
177 body_style="$body_style;background-attachment:scroll"
178 body_style="$body_style;padding:0px;"
179 text_style="width:610px"
180 text_style="$text_style;margin-left:120px"
181 text_style="$text_style;margin-top:50px"
182 text_style="$text_style;align:left"
183 text_style="$text_style;vertical-align:top;"
184 cat << EOF
185 <html>
186 <head>
187 <title>$TITLE</title>
188 <meta http-equiv="Content-Type"
189 content="text/html; charset=UTF-8"/>
190 </head>
191 <body style="$body_style">
192 <div style="$text_style">
193 <h1>$TITLE</h1>
195 indent='\t\t\t'
197 # make toc
198 toc_width=400px
199 toc_style="position:absolute;top:50px;left:810px;width=$toc_width"
201 echo "<div style=\"$toc_style\">"
202 echo "<table width=$toc_width bgcolor=#e0e0e0 border=1>"
203 echo "<tr><th>Table of contents:</th></tr>"
204 echo "<tr><td>"
205 echo '<p><ol>'
206 get_blog_entries |
207 while read timestamp filename title
209 date="$(date +"%d %b %Y" -d @$timestamp)"
210 echo "<li><a href=#$timestamp>$date $title</a>"
211 done
212 echo '</ol></p>'
213 echo '</td></tr></table>'
215 # RSS feed
216 rss_style="background-color:orange;text-decoration:none"
217 rss_style="$rss_style;color:white;font-family:sans-serif;"
218 echo '<br>'
219 echo '<div style="text-align:right;">'
220 echo "<a href=\"$ORIGURL$RSS\""
221 echo ' title="Subscribe to my RSS feed"'
222 echo ' class="rss" rel="nofollow"'
223 echo " style=\"$rss_style\">RSS</a>"
224 echo '</div>'
226 # Links
227 test -f links.html && {
228 echo "<br>"
229 echo "<table width=$toc_width bgcolor=#e0e0e0 border=1>"
230 echo "<tr><th>Links:</th></tr>"
231 echo "<tr><td>"
232 cat links.html
233 echo "</td></tr></table>"
236 # Google AdSense
237 test -z "$DRYRUN" && test -f google.adsense && {
238 echo "<br>"
239 echo "<table width=$toc_width bgcolor=#e0e0e0 border=1>"
240 echo "<tr><th>Google Ads:</th></tr>"
241 echo "<tr><td align=center>"
242 cat google.adsense
243 echo "</td></tr></table>"
246 echo '</div>'
247 } | sed -s "s/^/$indent/"
250 # timestamps will not need padding to sort correctly, for some time...
251 get_blog_entries |
252 while read timestamp filename title
254 echo "<h6>$(make_date $timestamp)</h6>"
255 echo "<a name=$timestamp>"
256 echo "<h2>$title</h2>"
257 echo ""
258 echo "<p>"
259 sed 1d < $filename | markup
260 echo "</p>"
261 done |
262 sed -e "s/^./$indent&/" \
263 -e "/<pre>/,/<\/pre>/s/^$indent//"
265 cat << EOF
266 </div>
267 </body>
268 </html>
272 generate_rss () {
273 echo '<?xml version="1.0" encoding="utf-8"?>'
274 echo '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">'
275 echo '<channel>'
276 echo "<title>Dscho's blog</title>"
277 echo "<link>$URLPREFIX${URL}index.html</link>"
278 self="$URLPREFIX$ORIGURL$RSS"
279 selfattribs='rel="self" type="application/rss+xml"'
280 echo "<atom:link href=\"$self\" $selfattribs/>"
281 echo '<description>A few stories told by Dscho</description>'
282 echo "<lastBuildDate>$(date --rfc-2822)</lastBuildDate>"
283 echo '<language>en-us</language>'
285 get_blog_entries |
286 while read timestamp filename title
288 echo '<item>'
289 echo "<title>$title</title>"
290 echo "<link>$URLPREFIX${URL}index.html#$timestamp</link>"
291 echo "<guid>$URLPREFIX${URL}index.html#$timestamp</guid>"
292 echo "<pubDate>$(date --rfc-2822 -d @$timestamp)</pubDate>"
293 description="$(cat < $filename | markup invert-bash)"
294 echo "<description><![CDATA[$description]]></description>"
295 echo "</item>"
296 done
298 echo '</channel>'
299 echo '</rss>'
302 # never, ever have spaces in the file names
303 commit_new_images () {
304 generate_rss > $RSS &&
305 git add $RSS ||
306 die "Could not generate $RSS"
308 images=
309 for image in $(cat source-* |
310 tr ' ]|' '\n' |
311 sed -n 's/.*\[\[\(Image\|SVG\)://p' |
312 sort |
313 uniq)
315 git add $image || die "Could not git add image $image"
316 images="$images $image"
317 done
319 git update-index --refresh &&
320 git diff-files --quiet -- $images &&
321 git diff --cached --quiet HEAD -- $images ||
322 git commit -s -m "Commit some images on $(make_date $now)" $images
325 handle_svg_file () {
326 # for some reason, Firefox adds scrollbars, so nudge the width a bit
327 width=$(sed -ne 's/.* width="\([^"]*\).*/\1/p' -e '/<metadata/q' < "$1")
328 test -z "$width" || width=" width=$(($width+5))"
329 REV=$(git rev-list -1 HEAD -- $1)
330 test -z "$REV" || URL="$REMOTEREPOSITORY?a=blob_plain;hb=$REV;f="
331 cat << EOF
332 <center>
333 <table border=0>
334 <tr>
335 <td align=center>
336 <embed type="image/svg+xml"
337 src="$URL$1"$width />
338 </td>
339 </tr>
340 <tr>
341 <td align=center>
342 <a href=$URL$1>$1</a>
343 </td>
344 </tr>
345 </table>
346 </center>
352 # parse command line option
353 case "$1" in
354 *dry*) DRYRUN=1; shift;;
355 *show*) firefox "$(pwd)"/$TEST; exit;;
356 *remote*) firefox $URLPREFIX$URL$OUTPUT; exit;;
357 handle)
358 case "$2" in
359 "[[SVG:"*) file=${2#??SVG:}; file=${file%??}; handle_svg_file "$file";;
360 esac
361 exit
363 esac
365 test "$#" = 0 ||
366 die "Usage: $0 [--dry-run]"
368 # make sure we're on the correct branch
369 test refs/heads/$BRANCH = $(git symbolic-ref HEAD) ||
370 die "Not on branch $BRANCH"
372 # make sure there are no uncommitted changes
373 git update-index --refresh &&
374 git diff-files --quiet ||
375 die "Have unstaged changes!"
377 # rename the new blog entry if it exists
378 now=$(date +%s)
379 test ! -f $NEW || {
380 mv -i $NEW source-$now.txt &&
381 git add source-$now.txt
382 } ||
383 die "Could not rename source.txt"
385 # commit the images that are referenced and not yet committed
386 test ! -z "$DRYRUN" ||
387 commit_new_images ||
388 die "Could not commit new images"
390 # to find the images reliably, we have to use the commit name, not the branch
391 # we use the latest commit touching an image file.
392 IMAGEFILES="$(git ls-files |
393 grep -v '\.\(rss\|html\|gitignore\|in\|sh\|txt\|adsense\)$')"
394 REV=$(git rev-list -1 HEAD -- $IMAGEFILES)
395 test -z "$REV" && REV=$BRANCH
396 URL="$REMOTEREPOSITORY?a=blob_plain;hb=$REV;f="
398 if test ! -z "$DRYRUN"
399 then
400 # Output to test.html and have local links into the current directory
401 OUTPUT=$TEST
402 URL=
405 make_html > $OUTPUT || die "Could not write $OUTPUT"
407 test ! -z "$DRYRUN" && {
408 move_new_entry_back
409 exit
412 git add $OUTPUT &&
413 git commit -s -m "Update $(make_date $now)" &&
414 git push origin +$BRANCH