|
|
@ -5,18 +5,6 @@ |
|
|
|
# https://github.com/carlesfe/bashblog/contributors |
|
|
|
# Check out README.md for more details |
|
|
|
|
|
|
|
# Some shell settings for robustness by default. These help eliminate |
|
|
|
# unexpected snags and security vulnerabilities in case someone forgets to |
|
|
|
# quote a variable somewhere. They do require a few coding adaptations. |
|
|
|
|
|
|
|
IFS=$'\n' # Globally, we do word splitting only on newline (which also |
|
|
|
# makes "$*" expand with newline separator instead of space). |
|
|
|
|
|
|
|
set -f # Disable globbing (pathname expansion). It can be re-enabled |
|
|
|
# locally using 'set +f'; it's handy to do this in a subshell, |
|
|
|
# for example in $(command substitution), as the globbing will |
|
|
|
# be local to the subshell. |
|
|
|
|
|
|
|
# Global variables |
|
|
|
# It is recommended to perform a 'rebuild' after changing any of this in the code |
|
|
|
|
|
|
@ -269,14 +257,6 @@ get_html_file_content() { |
|
|
|
}" |
|
|
|
} |
|
|
|
|
|
|
|
# Invoke the editor specified by the $EDITOR environment variable. Use a |
|
|
|
# function for this as we need to locally word-split $EDITOR on spaces |
|
|
|
# (in case it contains arguments, like EDITOR='joe -nobackups). |
|
|
|
invoke_editor() { |
|
|
|
local IFS=$' \t\n' |
|
|
|
$EDITOR "$1" |
|
|
|
} |
|
|
|
|
|
|
|
# Edit an existing, published .html file while keeping its original timestamp |
|
|
|
# Please note that this function does not automatically republish anything, as |
|
|
|
# it is usually called from 'main'. |
|
|
@ -296,8 +276,7 @@ edit() { |
|
|
|
touch_timestamp=$(LC_ALL=C date -r "${1%%.*}.html" +"$date_format_timestamp") |
|
|
|
tags_before=$(tags_in_post "${1%%.*}.html") |
|
|
|
if [[ $2 == full ]]; then |
|
|
|
invoke_editor "$1" |
|
|
|
touch -t "$touch_timestamp" "$1" |
|
|
|
$EDITOR "$1" |
|
|
|
filename=$1 |
|
|
|
else |
|
|
|
if [[ ${1##*.} == md ]]; then |
|
|
@ -307,8 +286,7 @@ edit() { |
|
|
|
exit |
|
|
|
fi |
|
|
|
# editing markdown file |
|
|
|
invoke_editor "$1" |
|
|
|
touch -t "$touch_timestamp" "$1" |
|
|
|
$EDITOR "$1" |
|
|
|
TMPFILE=$(markdown "$1") |
|
|
|
filename=${1%%.*}.html |
|
|
|
else |
|
|
@ -318,29 +296,27 @@ edit() { |
|
|
|
get_post_title "$1" > "$TMPFILE" |
|
|
|
# Post text with plaintext tags |
|
|
|
get_html_file_content 'text' 'text' <"$1" | sed "/^<p>$template_tags_line_header/s|<a href='$prefix_tags\([^']*\).html'>\\1</a>|\\1|g" >> "$TMPFILE" |
|
|
|
invoke_editor "$TMPFILE" |
|
|
|
$EDITOR "$TMPFILE" |
|
|
|
filename=$1 |
|
|
|
fi |
|
|
|
rm "$filename" |
|
|
|
if [[ $2 == keep ]]; then |
|
|
|
old_filename='' |
|
|
|
parse_file "$TMPFILE" "$edit_timestamp" "$filename" |
|
|
|
else |
|
|
|
old_filename=$filename # save old filename to exclude it from $relevant_posts |
|
|
|
parse_file "$TMPFILE" "$edit_timestamp" # this command sets $filename as the html processed file |
|
|
|
[[ ${1##*.} == md ]] && mv "$1" "${filename%%.*}.md" 2>/dev/null |
|
|
|
fi |
|
|
|
rm "$TMPFILE" |
|
|
|
touch -t "$touch_timestamp" "$filename" |
|
|
|
fi |
|
|
|
touch -t "$touch_timestamp" "$filename" |
|
|
|
touch -t "$touch_timestamp" "$1" |
|
|
|
chmod 644 "$filename" |
|
|
|
echo "Posted $filename" |
|
|
|
tags_after=$(tags_in_post "$filename") |
|
|
|
relevant_tags=$(sort -u <<< "$tags_before"$'\n'"$tags_after") |
|
|
|
if [[ -n $relevant_tags ]]; then |
|
|
|
relevant_posts=$(posts_with_tags $relevant_tags)$'\n'$filename |
|
|
|
[[ -n $old_filename ]] && relevant_posts=$(grep -vFx "$old_filename" <<<"$relevant_posts") |
|
|
|
rebuild_tags $relevant_posts --tags $relevant_tags |
|
|
|
relevant_tags=$(echo "$tags_before $tags_after" | tr ',' ' ' | tr ' ' '\n' | sort -u | tr '\n' ' ') |
|
|
|
if [[ ! -z $relevant_tags ]]; then |
|
|
|
relevant_posts="$(posts_with_tags $relevant_tags) $filename" |
|
|
|
rebuild_tags "$relevant_posts" "$relevant_tags" |
|
|
|
fi |
|
|
|
} |
|
|
|
|
|
|
@ -512,11 +488,10 @@ create_html_page() { |
|
|
|
parse_file() { |
|
|
|
# Read for the title and check that the filename is ok |
|
|
|
title="" |
|
|
|
while read -r line; do |
|
|
|
while IFS='' read -r line; do |
|
|
|
if [[ -z $title ]]; then |
|
|
|
# remove extra <p> and </p> added by markdown |
|
|
|
title=${line#<p>} |
|
|
|
title=${title%</p>} |
|
|
|
title=$(echo "$line" | sed 's/<\/*p>//g') |
|
|
|
if [[ -n $3 ]]; then |
|
|
|
filename=$3 |
|
|
|
else |
|
|
@ -538,6 +513,7 @@ parse_file() { |
|
|
|
elif [[ $line == "<p>$template_tags_line_header"* ]]; then |
|
|
|
tags=$(echo "$line" | cut -d ":" -f 2- | sed -e 's/<\/p>//g' -e 's/^ *//' -e 's/ *$//' -e 's/, /,/g') |
|
|
|
IFS=, read -r -a array <<< "$tags" |
|
|
|
|
|
|
|
echo -n "<p>$template_tags_line_header " >> "$content" |
|
|
|
for item in "${array[@]}"; do |
|
|
|
echo -n "<a href='$prefix_tags$item.html'>$item</a>, " |
|
|
@ -602,7 +578,7 @@ EOF |
|
|
|
filename="" |
|
|
|
while [[ $post_status != "p" && $post_status != "P" ]]; do |
|
|
|
[[ -n $filename ]] && rm "$filename" # Delete the generated html file, if any |
|
|
|
invoke_editor "$TMPFILE" |
|
|
|
$EDITOR "$TMPFILE" |
|
|
|
if [[ $fmt == md ]]; then |
|
|
|
html_from_md=$(markdown "$TMPFILE") |
|
|
|
parse_file "$html_from_md" |
|
|
@ -644,8 +620,8 @@ EOF |
|
|
|
echo "Posted $filename" |
|
|
|
relevant_tags=$(tags_in_post $filename) |
|
|
|
if [[ -n $relevant_tags ]]; then |
|
|
|
relevant_posts=$(posts_with_tags $relevant_tags)$'\n'$filename |
|
|
|
rebuild_tags $relevant_posts --tags $relevant_tags |
|
|
|
relevant_posts="$(posts_with_tags $relevant_tags) $filename" |
|
|
|
rebuild_tags "$relevant_posts" "$relevant_tags" |
|
|
|
fi |
|
|
|
} |
|
|
|
|
|
|
@ -660,7 +636,7 @@ all_posts() { |
|
|
|
{ |
|
|
|
echo "<h3>$template_archive_title</h3>" |
|
|
|
prev_month="" |
|
|
|
for i in $(set +f; ls -t ./*.html); do |
|
|
|
while IFS='' read -r i; do |
|
|
|
is_boilerplate_file "$i" && continue |
|
|
|
echo -n "." 1>&3 |
|
|
|
# Month headers |
|
|
@ -677,7 +653,7 @@ all_posts() { |
|
|
|
# Date |
|
|
|
date=$(LC_ALL=$date_locale date -r "$i" +"$date_format") |
|
|
|
echo " $date</li>" |
|
|
|
done |
|
|
|
done < <(ls -t ./*.html) |
|
|
|
echo "" 1>&3 |
|
|
|
echo "</ul>" |
|
|
|
echo "<div id=\"all_posts\"><a href=\"./$index_file\">$template_archive_index_page</a></div>" |
|
|
@ -700,7 +676,7 @@ all_tags() { |
|
|
|
{ |
|
|
|
echo "<h3>$template_tags_title</h3>" |
|
|
|
echo "<ul>" |
|
|
|
for i in $(set +f; printf '%s\n' $prefix_tags*.html); do |
|
|
|
for i in $prefix_tags*.html; do |
|
|
|
[[ -f "$i" ]] || break |
|
|
|
echo -n "." 1>&3 |
|
|
|
nposts=$(grep -c "<\!-- text begin -->" "$i") |
|
|
@ -737,8 +713,7 @@ rebuild_index() { |
|
|
|
# Create the content file |
|
|
|
{ |
|
|
|
n=0 |
|
|
|
for i in $(set +f; ls -t ./*.html) # sort by date, newest first |
|
|
|
do |
|
|
|
while IFS='' read -r i; do |
|
|
|
is_boilerplate_file "$i" && continue; |
|
|
|
if ((n >= number_of_index_articles)); then break; fi |
|
|
|
if [[ -n $cut_do ]]; then |
|
|
@ -748,7 +723,7 @@ rebuild_index() { |
|
|
|
fi |
|
|
|
echo -n "." 1>&3 |
|
|
|
n=$(( n + 1 )) |
|
|
|
done |
|
|
|
done < <(ls -t ./*.html) # sort by date, newest first |
|
|
|
|
|
|
|
feed=$blog_feed |
|
|
|
if [[ -n $global_feedburner ]]; then feed=$global_feedburner; fi |
|
|
@ -765,22 +740,14 @@ rebuild_index() { |
|
|
|
|
|
|
|
# Finds all tags referenced in one post. |
|
|
|
# Accepts either filename as first argument, or post content at stdin |
|
|
|
# Prints tags to stdout, one per line. |
|
|
|
# (Since we're doing global IFS word splitting on newline only, |
|
|
|
# something like 'for tag in $(tags_in_post $i)' will work.) |
|
|
|
# Prints one line with space-separated tags to stdout |
|
|
|
tags_in_post() { |
|
|
|
local newline=$'\n' |
|
|
|
sed -n "/^<p>$template_tags_line_header/ { |
|
|
|
s/^<p>$template_tags_line_header[[:blank:]]*// |
|
|
|
s/[[:blank:]]*<[^>]*>[[:blank:]]*//g |
|
|
|
s/[[:blank:]]*,[[:blank:]]*/\\$newline/g |
|
|
|
p |
|
|
|
}" "$1" |
|
|
|
sed -n "/^<p>$template_tags_line_header/{s/^<p>$template_tags_line_header//;s/<[^>]*>//g;s/[ ,]\+/ /g;p;}" "$1" | tr ', ' ' ' |
|
|
|
} |
|
|
|
|
|
|
|
# Finds all posts referenced in a number of tags. |
|
|
|
# Arguments are tags. |
|
|
|
# Prints file names to stdout, one per line. |
|
|
|
# Arguments are tags |
|
|
|
# Prints one line with space-separated tags to stdout |
|
|
|
posts_with_tags() { |
|
|
|
(($# < 1)) && return |
|
|
|
set -- "${@/#/$prefix_tags}" |
|
|
@ -791,40 +758,38 @@ posts_with_tags() { |
|
|
|
# Rebuilds tag_*.html files |
|
|
|
# if no arguments given, rebuilds all of them |
|
|
|
# if arguments given, they should have this format: |
|
|
|
# FILE1 [FILE2 [...]] --tags TAG1 [TAG2 [...]] |
|
|
|
# "FILE1 [FILE2 [...]]" "TAG1 [TAG2 [...]]" |
|
|
|
# where FILEn are files with posts which should be used for rebuilding tags, |
|
|
|
# and TAGn are names of tags which should be rebuilt. |
|
|
|
# example: |
|
|
|
# rebuild_tags one_post.html another_article.html --tags example-tag another-tag |
|
|
|
# rebuild_tags "one_post.html another_article.html" "example-tag another-tag" |
|
|
|
# mind the quotes! |
|
|
|
rebuild_tags() { |
|
|
|
if (($# < 1)); then |
|
|
|
if (($# < 2)); then |
|
|
|
# will process all files and tags |
|
|
|
files=( $(set +f; ls -t ./*.html) ) |
|
|
|
files=$(ls -t ./*.html) |
|
|
|
all_tags=yes |
|
|
|
else |
|
|
|
# will process only given files and tags |
|
|
|
for ((i=1; i<=$#; i++)); do |
|
|
|
[[ ${!i} == --tags ]] && break |
|
|
|
done |
|
|
|
files=( $(ls -t $(sort -u <<< "${*:1:$((i-1))}")) ) |
|
|
|
tags=( "${@:$((i+1)):$#}" ) |
|
|
|
all_tags='' |
|
|
|
files=$(printf '%s\n' $1 | sort -u) |
|
|
|
files=$(ls -t $files) |
|
|
|
tags=$2 |
|
|
|
fi |
|
|
|
echo -n "Rebuilding tag pages " |
|
|
|
n=0 |
|
|
|
if [[ -n $all_tags ]]; then |
|
|
|
( set +f; rm -f ./"$prefix_tags"*.html ) |
|
|
|
rm ./"$prefix_tags"*.html &> /dev/null |
|
|
|
else |
|
|
|
for i in "${tags[@]}"; do |
|
|
|
rm -f "./$prefix_tags$i.html" |
|
|
|
for i in $tags; do |
|
|
|
rm "./$prefix_tags$i.html" &> /dev/null |
|
|
|
done |
|
|
|
fi |
|
|
|
# First we will process all files and create temporal tag files |
|
|
|
# with just the content of the posts |
|
|
|
tmpfile=tmp.$RANDOM |
|
|
|
while [[ -f $tmpfile ]]; do tmpfile=tmp.$RANDOM; done |
|
|
|
for i in "${files[@]}"; do |
|
|
|
is_boilerplate_file "$i" && continue |
|
|
|
while IFS='' read -r i; do |
|
|
|
is_boilerplate_file "$i" && continue; |
|
|
|
echo -n "." |
|
|
|
if [[ -n $cut_do ]]; then |
|
|
|
get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"<p class=\\\"readmore\\\"><a href=\\\"$i\\\">$template_read_more</a></p>\" ; next } 1" |
|
|
@ -832,20 +797,19 @@ rebuild_tags() { |
|
|
|
get_html_file_content 'entry' 'entry' <"$i" |
|
|
|
fi >"$tmpfile" |
|
|
|
for tag in $(tags_in_post "$i"); do |
|
|
|
# if either all tags or array tags[] contains $tag... |
|
|
|
if [[ -n $all_tags || $'\n'"${tags[*]}"$'\n' == *$'\n'"$tag"$'\n'* ]]; then |
|
|
|
if [[ -n $all_tags || " $tags " == *" $tag "* ]]; then |
|
|
|
cat "$tmpfile" >> "$prefix_tags$tag".tmp.html |
|
|
|
fi |
|
|
|
done |
|
|
|
done |
|
|
|
done <<< "$files" |
|
|
|
rm "$tmpfile" |
|
|
|
# Now generate the tag files with headers, footers, etc |
|
|
|
for i in $(set +f; ls -t ./"$prefix_tags"*.tmp.html 2>/dev/null); do |
|
|
|
while IFS='' read -r i; do |
|
|
|
tagname=${i#./"$prefix_tags"} |
|
|
|
tagname=${tagname%.tmp.html} |
|
|
|
create_html_page "$i" "$prefix_tags$tagname.html" yes "$global_title — $template_tag_title \"$tagname\"" "$global_author" |
|
|
|
rm "$i" |
|
|
|
done |
|
|
|
done < <(ls -t ./"$prefix_tags"*.tmp.html 2>/dev/null) |
|
|
|
echo |
|
|
|
} |
|
|
|
|
|
|
@ -869,12 +833,11 @@ get_post_author() { |
|
|
|
list_tags() { |
|
|
|
if [[ $2 == -n ]]; then do_sort=1; else do_sort=0; fi |
|
|
|
|
|
|
|
if ! (set +f; set -- $prefix_tags*.html; [[ -e $1 ]]); then |
|
|
|
echo "No posts yet. Use 'bb.sh post' to create one" |
|
|
|
return |
|
|
|
fi |
|
|
|
ls ./$prefix_tags*.html &> /dev/null |
|
|
|
(($? != 0)) && echo "No posts yet. Use 'bb.sh post' to create one" && return |
|
|
|
|
|
|
|
for i in $(set +f; printf '%s\n' $prefix_tags*.html); do |
|
|
|
lines="" |
|
|
|
for i in $prefix_tags*.html; do |
|
|
|
[[ -f "$i" ]] || break |
|
|
|
nposts=$(grep -c "<\!-- text begin -->" "$i") |
|
|
|
tagname=${i#"$prefix_tags"} |
|
|
@ -893,19 +856,17 @@ list_tags() { |
|
|
|
|
|
|
|
# Displays a list of the posts |
|
|
|
list_posts() { |
|
|
|
if ! (set +f; set -- *.html; [[ -e $1 ]]); then |
|
|
|
echo "No posts yet. Use 'bb.sh post' to create one" |
|
|
|
return |
|
|
|
fi |
|
|
|
ls ./*.html &> /dev/null |
|
|
|
(($? != 0)) && echo "No posts yet. Use 'bb.sh post' to create one" && return |
|
|
|
|
|
|
|
lines="" |
|
|
|
n=1 |
|
|
|
for i in $(set +f; ls -t ./*.html); do |
|
|
|
while IFS='' read -r i; do |
|
|
|
is_boilerplate_file "$i" && continue |
|
|
|
line="$n # $(get_post_title "$i") # $(LC_ALL=$date_locale date -r "$i" +"$date_format")" |
|
|
|
lines+=$line\\n |
|
|
|
n=$(( n + 1 )) |
|
|
|
done |
|
|
|
done < <(ls -t ./*.html) |
|
|
|
|
|
|
|
echo -e "$lines" | column -t -s "#" |
|
|
|
} |
|
|
@ -928,7 +889,7 @@ make_rss() { |
|
|
|
echo "<atom:link href=\"$global_url/$blog_feed\" rel=\"self\" type=\"application/rss+xml\" />" |
|
|
|
|
|
|
|
n=0 |
|
|
|
for i in $(set +f; ls -t ./*.html); do |
|
|
|
while IFS='' read -r i; do |
|
|
|
is_boilerplate_file "$i" && continue |
|
|
|
((n >= number_of_feed_articles)) && break # max 10 items |
|
|
|
echo -n "." 1>&3 |
|
|
@ -942,7 +903,7 @@ make_rss() { |
|
|
|
echo "<pubDate>$(LC_ALL=C date -r "$i" +"$date_format_full")</pubDate></item>" |
|
|
|
|
|
|
|
n=$(( n + 1 )) |
|
|
|
done |
|
|
|
done < <(ls -t ./*.html) |
|
|
|
|
|
|
|
echo '</channel></rss>' |
|
|
|
} 3>&1 >"$rssfile" |
|
|
@ -1041,7 +1002,7 @@ create_css() { |
|
|
|
rebuild_all_entries() { |
|
|
|
echo -n "Rebuilding all entries " |
|
|
|
|
|
|
|
for i in $(set +f; printf '%s\n' *.html); do |
|
|
|
for i in ./*.html; do |
|
|
|
is_boilerplate_file "$i" && continue; |
|
|
|
contentfile=.tmp.$RANDOM |
|
|
|
while [[ -f $contentfile ]]; do contentfile=.tmp.$RANDOM; done |
|
|
@ -1097,7 +1058,7 @@ reset() { |
|
|
|
echo "Are you sure you want to delete all blog entries? Please write \"Yes, I am!\" " |
|
|
|
read -r line |
|
|
|
if [[ $line == "Yes, I am!" ]]; then |
|
|
|
(set +f; rm -f .*.html ./*.html ./*.css ./*.rss) |
|
|
|
rm .*.html ./*.html ./*.css ./*.rss &> /dev/null |
|
|
|
echo |
|
|
|
echo "Deleted all posts, stylesheets and feeds." |
|
|
|
echo "Kept your old '.backup.tar.gz' just in case, please delete it manually if needed." |
|
|
@ -1169,9 +1130,9 @@ do_main() { |
|
|
|
fi |
|
|
|
|
|
|
|
# Test for existing html files |
|
|
|
if (set +f; set -- *.html; [[ -e $1 ]]); then |
|
|
|
if ls ./*.html &> /dev/null; then |
|
|
|
# We're going to back up just in case |
|
|
|
(set +f; tar -c -z -f ".backup.tar.gz" -- *.html) && |
|
|
|
tar -c -z -f ".backup.tar.gz" -- *.html && |
|
|
|
chmod 600 ".backup.tar.gz" |
|
|
|
elif [[ $1 == rebuild ]]; then |
|
|
|
echo "Can't find any html files, nothing to rebuild" |
|
|
|