diff --git a/.gitea/workflows/deploy-website.yml b/.gitea/workflows/deploy-website.yml new file mode 100644 index 0000000..469eba2 --- /dev/null +++ b/.gitea/workflows/deploy-website.yml @@ -0,0 +1,42 @@ +name: Deploy Website + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + deploy-website: + runs-on: local + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Ensure deploy tools are available + run: | + if ! command -v ssh >/dev/null 2>&1 || ! command -v rsync >/dev/null 2>&1 || ! command -v ssh-keyscan >/dev/null 2>&1; then + sudo apt-get update + sudo apt-get install -y openssh-client rsync + fi + + - name: Build website + run: | + sh kewt.sh --from site --to out + + - name: Setup SSH + run: | + mkdir -p ~/.ssh + printf '%s\n' "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + + REMOTE_HOST_VAL="${{ secrets.REMOTE_HOST }}" + REMOTE_ADDR=$(printf '%s\n' "$REMOTE_HOST_VAL" | awk -F@ '{print $NF}') + + ssh-keyscan -H "$REMOTE_ADDR" >> ~/.ssh/known_hosts + + - name: Deploy website + run: | + rsync -az --delete \ + -e "ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no" \ + out/ "${{ secrets.REMOTE_HOST }}:/var/www/kewt.krzak.org/" diff --git a/.gitea/workflows/lint.yml b/.gitea/workflows/lint.yml deleted file mode 100644 index 755ffe0..0000000 --- a/.gitea/workflows/lint.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Lint - -on: - push: - branches: [main, master] - paths: - - '**.sh' - pull_request: - paths: - - '**.sh' - -jobs: - shellcheck: - runs-on: local - steps: - - uses: actions/checkout@v4 - - name: Install Shellcheck - run: sudo apt-get update && sudo apt-get install -y shellcheck - - name: Run Shellcheck - run: shellcheck -s sh kewt.sh markdown.sh tools/build-standalone.sh || true diff --git a/kewt.sh b/kewt.sh index 13c511b..54bab81 100755 --- a/kewt.sh +++ b/kewt.sh @@ -5,15 +5,30 @@ die() { exit 1 } +make_temp_dir() { + _temp_base="${TMPDIR:-/tmp}/kewt_run.$$" + _temp_try=0 + while [ "$_temp_try" -lt 1000 ]; do + _temp_path="${_temp_base}.${_temp_try}" + if (umask 077 && mkdir "$_temp_path") 2>/dev/null; then + printf '%s\n' "$_temp_path" + return 0 + fi + _temp_try=$((_temp_try + 1)) + done + return 1 +} + script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd) awk_dir="$script_dir/awk" -KEWT_TMPDIR=$(mktemp -d "/tmp/kewt_run.XXXXXX") +KEWT_TMPDIR=$(make_temp_dir) || die "Could not create temporary directory." trap 'rm -rf "$KEWT_TMPDIR"' EXIT trap 'exit 0' HUP INT TERM . "$script_dir/lib/config.sh" . "$script_dir/lib/metadata.sh" +. "$script_dir/lib/manifest.sh" . "$script_dir/lib/commands.sh" . "$script_dir/lib/generator.sh" . "$script_dir/lib/builder.sh" diff --git a/lib/builder.sh b/lib/builder.sh index 755c568..16236ba 100644 --- a/lib/builder.sh +++ b/lib/builder.sh @@ -1,3 +1,5 @@ +#!/bin/sh + needs_rebuild() { src_file="$1" out_file="$2" @@ -30,6 +32,8 @@ write_content_warning_outputs() { build_site() { echo "Building site from '$src' to '$out'..." +build_markdown_manifest + eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while read -r dir; do rel_dir="${dir#"$src"}" rel_dir="${rel_dir#/}" @@ -64,9 +68,8 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while is_posts_dir="true" fi if [ "$single_file_index" = "true" ] && [ "$is_posts_dir" = "false" ] && [ "$has_list" = "false" ]; then - md_count=$(find "$dir" ! -name "$(basename "$dir")" -prune -name "*.md" | wc -l) - if [ "$md_count" -eq 1 ]; then - md_file=$(find "$dir" ! -name "$(basename "$dir")" -prune -name "*.md") + if load_manifest_dir_entry "$rel_dir" && [ "$dir_md_count" -eq 1 ]; then + md_file="$src/$dir_first_md" is_home="false"; [ "$dir" = "$src" ] && is_home="true" target_url=$(directory_index_url "$rel_dir") if needs_rebuild "$md_file" "$out_dir/index.html"; then @@ -117,11 +120,12 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while dir_url="$(encode_url_path "$name")/index.html" echo "${name}|- [${name}/](${dir_url})" >> "$temp_entries" elif [ "${entry%.md}" != "$entry" ]; then + entry_rel_path="${entry#"$src"/}" + load_manifest_entry "$entry_rel_path" || continue label="${name%.md}" - set_post_metadata "$entry" "" - [ "$fm_draft" = "true" ] && continue + [ "$manifest_draft" = "true" ] && continue - post_h="$post_heading" + post_h="$manifest_title" is_post_entry="false" if is_posts_directory_rel "$rel_dir"; then @@ -130,23 +134,23 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while if [ -n "$post_h" ]; then if [ "$is_post_entry" = "true" ]; then - if [ -n "$post_time" ]; then - label="$post_h - $post_date $post_time" + if [ -n "$manifest_post_time" ]; then + label="$post_h - $manifest_post_date $manifest_post_time" else - label="$post_h - $post_date" + label="$post_h - $manifest_post_date" fi else label="$post_h" fi elif [ "$is_post_entry" = "true" ]; then - if [ -n "$post_time" ]; then - label="$post_date $post_time" + if [ -n "$manifest_post_time" ]; then + label="$manifest_post_date $manifest_post_time" else - label="$post_date" + label="$manifest_post_date" fi fi if [ "$is_post_entry" = "true" ]; then - sort_key="${post_date} ${post_time}" + sort_key="${manifest_post_date} ${manifest_post_time}" else sort_key="$name" fi @@ -196,7 +200,8 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while num_items=$(wc -l < "$temp_list") if [ "$is_posts_dir" = "true" ] && [ -n "$posts_per_page" ] && [ "$posts_per_page" -gt 0 ] && [ "$num_items" -gt "$posts_per_page" ]; then num_pages=$(( (num_items + posts_per_page - 1) / posts_per_page )) - for p in $(seq 1 $num_pages); do + p=1 + while [ "$p" -le "$num_pages" ]; do chunk_list="$KEWT_TMPDIR/chunk.md" start_line=$(( (p - 1) * posts_per_page + 1 )) tail -n +$start_line "$temp_list" | head -n "$posts_per_page" > "$chunk_list" @@ -255,6 +260,7 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while render_markdown "$temp_index_p" "$is_home" "$target_url_p" > "$out_file" rm -f "$temp_index_p" "$chunk_list" + p=$((p + 1)) done else if [ "$has_custom_index" = "true" ]; then @@ -352,23 +358,21 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type f -print" | sort | while fi if [ "$single_file_index" = "true" ] && [ "${file%.md}" != "$file" ] && [ "$is_preserved" -eq 0 ] && [ ! -f "$(dirname "$file")/index.md" ] && [ "$is_posts_dir_2" = "false" ]; then - md_count=$(find "$(dirname "$file")" ! -name "$(basename "$(dirname "$file")")" -prune -name "*.md" | wc -l) - [ "$md_count" -eq 1 ] && continue + load_manifest_dir_entry "$dir_rel" && [ "$dir_md_count" -eq 1 ] && continue fi if [ "${file%.md}" != "$file" ] && [ "$is_preserved" -eq 0 ]; then - # Skip draft files - parse_frontmatter "$file" - if [ "$fm_draft" = "true" ]; then - continue - fi + load_manifest_entry "$rel_path" || continue + [ "$manifest_draft" = "true" ] && continue is_home="false"; [ "$file" = "$src/index.md" ] && is_home="true" out_file="$out/${rel_path%.md}.html" if needs_rebuild "$file" "$out_file"; then - if [ -n "$fm_content_warning" ]; then + fm_title="$manifest_title" + fm_content_warning="$manifest_content_warning" + if [ -n "$manifest_content_warning" ]; then content_out_file="$out/${rel_path%.md}-content.html" content_rel_url="/$(encode_url_path "${rel_path%.md}")-content.html" - orig_rel_url=$(markdown_file_url "$rel_path") + orig_rel_url="$manifest_url" write_content_warning_outputs "$file" "$content_out_file" "$content_rel_url" "$orig_rel_url" "$out_file" "$is_home" else render_markdown "$file" "$is_home" > "$out_file" @@ -433,44 +437,32 @@ if [ "$generate_feed" = "true" ] && [ -n "$base_url" ]; then temp_feed_files="$KEWT_TMPDIR/feed_files_$$.txt" : > "$temp_feed_files" - find "$src" -type f -name '*.md' -path "*${posts_dir:-__no_posts__}*" -print | while IFS= read -r post_file; do - post_basename=$(basename "$post_file" .md) - parse_frontmatter "$post_file" - [ "$fm_draft" = "true" ] && continue - set_post_datetime "$fm_date" "$post_basename" - echo "${post_date} ${post_time}|${post_file}" >> "$temp_feed_files" - done + while IFS= read -r manifest_rel_path; do + case "$manifest_rel_path" in + *"${posts_dir:-__no_posts__}"*) ;; + *) continue ;; + esac + load_manifest_entry "$manifest_rel_path" || continue + [ "$manifest_draft" = "true" ] && continue + printf '%s %s|%s\n' "$manifest_post_date" "$manifest_post_time" "$manifest_rel_path" >> "$temp_feed_files" + done < "$manifest_all_list" - LC_ALL=C sort -r "$temp_feed_files" | cut -d'|' -f2- | while IFS= read -r post_file; do - post_basename=$(basename "$post_file" .md) - parse_frontmatter "$post_file" - [ "$fm_draft" = "true" ] && continue - set_post_metadata "$post_file" "Post" + LC_ALL=C sort -r "$temp_feed_files" | cut -d'|' -f2- | while IFS= read -r post_rel_path; do + load_manifest_entry "$post_rel_path" || continue + [ "$manifest_draft" = "true" ] && continue + + post_date="$manifest_post_date" + post_time="$manifest_post_time" + post_heading="$manifest_title" + post_slug="$manifest_post_slug" if [ -z "$post_heading" ] && [ -n "$post_slug" ] && ! echo "$post_slug" | grep -q '^[0-9]\+$'; then post_heading=$(echo "$post_slug" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)}1') fi feed_post_title="$post_heading - $post_date $post_time" - rel_path="${post_file#"$src"}" - rel_path="${rel_path#/}" - post_url="$base_url_feed$(markdown_file_url "$rel_path")" + post_url="$base_url_feed$manifest_url" - if date -u -d "$post_date $post_time" '+%a, %d %b %Y %H:%M:%S +0000' >/dev/null 2>&1; then - pub_date=$(date -u -d "$post_date $post_time" '+%a, %d %b %Y %H:%M:%S +0000') - else - pub_year=$(echo "$post_date" | cut -d- -f1) - pub_month=$(echo "$post_date" | cut -d- -f2) - pub_day=$(echo "$post_date" | cut -d- -f3) - # zero-padded - pub_day=$(printf '%02d' "${pub_day#0}") - case "$pub_month" in - 01) pub_mon="Jan" ;; 02) pub_mon="Feb" ;; 03) pub_mon="Mar" ;; - 04) pub_mon="Apr" ;; 05) pub_mon="May" ;; 06) pub_mon="Jun" ;; - 07) pub_mon="Jul" ;; 08) pub_mon="Aug" ;; 09) pub_mon="Sep" ;; - 10) pub_mon="Oct" ;; 11) pub_mon="Nov" ;; 12) pub_mon="Dec" ;; - esac - pub_date="Mon, ${pub_day} ${pub_mon} ${pub_year} ${post_time}:00 +0000" - fi + pub_date=$(format_rfc2822_utc "$post_date" "$post_time") { printf ' \n' @@ -494,25 +486,25 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then temp_tags="$KEWT_TMPDIR/tags_$$.txt" : > "$temp_tags" - eval "find \"$src\" \( $IGNORE_ARGS -o $HIDE_ARGS -o $PRESERVE_ARGS \) -prune -o -name \"*.md\" -print" | sort | while IFS= read -r md_file; do - is_index="false" - [ "$(basename "$md_file")" = "index.md" ] && is_index="true" + while IFS= read -r rel_path; do + load_manifest_entry "$rel_path" || continue - rel_path="${md_file#"$src"}" - rel_path="${rel_path#/}" - if [ "$is_index" = "true" ]; then + if [ "$manifest_is_index" = "true" ]; then if [ "$rel_path" = "index.md" ]; then md_url="/index.html" else md_url=$(directory_index_url "${rel_path%/index.md}") fi else - md_url=$(markdown_file_url "$rel_path") + md_url="$manifest_url" if [ "$single_file_index" = "true" ]; then - dir_of_file="$(dirname "$md_file")" - rel_dir_of_file="${dir_of_file#"$src"}" - rel_dir_of_file="${rel_dir_of_file#/}" + rel_dir_of_file="$manifest_dir_rel" [ -z "$rel_dir_of_file" ] && rel_dir_of_file="." + if [ "$rel_dir_of_file" = "." ]; then + dir_of_file="$src" + else + dir_of_file="$src/$rel_dir_of_file" + fi is_posts_dir_search="false" if [ -n "$posts_dir" ] && { [ "$rel_dir_of_file" = "$posts_dir" ] || [ "./$rel_dir_of_file" = "$posts_dir" ]; }; then @@ -520,8 +512,7 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then fi if [ "$is_posts_dir_search" = "false" ] && [ ! -f "$dir_of_file/index.md" ]; then - md_count_search=$(find "$dir_of_file" ! -name "$(basename "$dir_of_file")" -prune -name "*.md" | wc -l) - if [ "$md_count_search" -eq 1 ]; then + if load_manifest_dir_entry "$rel_dir_of_file" && [ "$dir_md_count" -eq 1 ]; then if [ "$rel_dir_of_file" = "." ]; then md_url="/index.html" else @@ -532,38 +523,12 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then fi fi - parse_frontmatter "$md_file" - [ "$fm_draft" = "true" ] && continue - - markdown_title_from_loaded_file "$md_file" "$title - Page" - md_heading="$markdown_title" + [ "$manifest_draft" = "true" ] && continue + md_heading="$manifest_title" if [ "$generate_search" = "true" ]; then - if [ -z "$fm_content_warning" ] || [ "$include_cw_pages_in_search" = "true" ]; then - md_content=$(awk '{ - if (NR == 1 && $0 == "---") { in_fm = 1; next } - if (in_fm && $0 == "---") { in_fm = 0; next } - if (in_fm) next - if ($0 ~ /^```/) { in_code = !in_code; next } - if (in_code) next - print - }' "$md_file" | sed \ - -e 's/^#\{1,6\} //' \ - -e 's/\*\*\([^*]*\)\*\*/\1/g' \ - -e 's/\*\([^*]*\)\*/\1/g' \ - -e 's/__\([^_]*\)__/\1/g' \ - -e 's/_\([^_]*\)_/\1/g' \ - -e 's/`\([^`]*\)`/\1/g' \ - -e 's/\[\([^]]*\)](\([^)]*\))/\1/g' \ - -e 's/!\[\([^]]*\)](\([^)]*\))//g' \ - -e 's/^[[:space:]]*[-*+] //' \ - -e 's/^[[:space:]]*[0-9]\{1,\}\. //' \ - -e 's/^>[[:space:]]*//' \ - -e 's/<[^>]*>//g' \ - -e '/^[[:space:]]*$/d' \ - -e 's/|//g' \ - -e 's/^[[:space:]]*---[[:space:]]*$//' \ - | tr '\n' ' ' | sed -e 's/ */ /g' -e 's/\\/\\\\/g' -e 's/"/\\"/g' | head -c 500) + if [ -z "$manifest_content_warning" ] || [ "$include_cw_pages_in_search" = "true" ]; then + md_content="$manifest_search_content" if [ "$first_search_item" = "false" ]; then printf ',\n' >> "$out/search.json" fi @@ -572,17 +537,17 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then fi fi - if [ "$generate_tags" = "true" ] && [ -n "$fm_tags" ]; then + if [ "$generate_tags" = "true" ] && [ -n "$manifest_tags" ]; then old_ifs=$IFS IFS=',' - for tag in $fm_tags; do + for tag in $manifest_tags; do tag=$(echo "$tag" | sed 's/^[ \t]*//;s/[ \t]*$//') [ -z "$tag" ] && continue printf '%s|%s|%s\n' "$tag" "$md_url" "$md_heading" >> "$temp_tags" done IFS=$old_ifs fi - done + done < "$manifest_visible_list" if [ "$generate_search" = "true" ]; then printf '\n]\n' >> "$out/search.json" @@ -614,7 +579,7 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then cut -d'|' -f1 "$temp_tags" | sort -u | while IFS= read -r tag; do tag_slug=$(echo "$tag" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g') - echo "- [$tag](/$(echo $tags_dir | sed 's|^\/||; s|\/$||')/$tag_slug.html)" >> "$tags_index_md" + echo "- [$tag](/$(echo "$tags_dir" | sed 's|^\/||; s|\/$||')/$tag_slug.html)" >> "$tags_index_md" tag_page_md="$KEWT_TMPDIR/tag_page_$$.md" echo "# Tag: $tag" > "$tag_page_md" diff --git a/lib/commands.sh b/lib/commands.sh index 5218348..4f5948b 100644 --- a/lib/commands.sh +++ b/lib/commands.sh @@ -1,3 +1,5 @@ +#!/bin/sh + usage() { invoked_as=$(basename "${KEWT_INVOKED_AS:-$0}") cat <' SEARCH_FORM_HEADER='
' SEARCH_FORM_NAV='
' diff --git a/lib/manifest.sh b/lib/manifest.sh new file mode 100644 index 0000000..d6f3a28 --- /dev/null +++ b/lib/manifest.sh @@ -0,0 +1,166 @@ +#!/bin/sh + +shell_quote() { + printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")" +} + +manifest_meta_path() { + printf '%s/manifest/meta/%s.meta\n' "$KEWT_TMPDIR" "$1" +} + +manifest_dir_meta_path() { + printf '%s/manifest/dir-meta/%s.meta\n' "$KEWT_TMPDIR" "$1" +} + +write_manifest_dir_meta() { + _dir_meta_rel="$1" + _dir_meta_count="$2" + _dir_meta_first="$3" + _dir_meta_has_index="$4" + _dir_meta_path=$(manifest_dir_meta_path "$_dir_meta_rel") + mkdir -p "$(dirname "$_dir_meta_path")" + { + printf 'dir_manifest_rel=%s\n' "$(shell_quote "$_dir_meta_rel")" + printf 'dir_md_count=%s\n' "$(shell_quote "$_dir_meta_count")" + printf 'dir_first_md=%s\n' "$(shell_quote "$_dir_meta_first")" + printf 'dir_has_index=%s\n' "$(shell_quote "$_dir_meta_has_index")" + } > "$_dir_meta_path" +} + +load_manifest_dir_entry() { + _dir_manifest_rel="$1" + _dir_manifest_meta_path=$(manifest_dir_meta_path "$_dir_manifest_rel") + [ -f "$_dir_manifest_meta_path" ] || return 1 + # shellcheck disable=SC1090 + . "$_dir_manifest_meta_path" +} + +load_manifest_entry() { + _manifest_rel_path="$1" + _manifest_meta_path=$(manifest_meta_path "$_manifest_rel_path") + [ -f "$_manifest_meta_path" ] || return 1 + # shellcheck disable=SC1090 + . "$_manifest_meta_path" +} + +extract_search_content() { + _search_file="$1" + awk '{ + if (NR == 1 && $0 == "---") { in_fm = 1; next } + if (in_fm && $0 == "---") { in_fm = 0; next } + if (in_fm) next + if ($0 ~ /^```/) { in_code = !in_code; next } + if (in_code) next + print + }' "$_search_file" | sed \ + -e 's/^#\{1,6\} //' \ + -e 's/\*\*\([^*]*\)\*\*/\1/g' \ + -e 's/\*\([^*]*\)\*/\1/g' \ + -e 's/__\([^_]*\)__/\1/g' \ + -e 's/_\([^_]*\)_/\1/g' \ + -e 's/`\([^`]*\)`/\1/g' \ + -e 's/\[\([^]]*\)](\([^)]*\))/\1/g' \ + -e 's/!\[\([^]]*\)](\([^)]*\))//g' \ + -e 's/^[[:space:]]*[-*+] //' \ + -e 's/^[[:space:]]*[0-9]\{1,\}\. //' \ + -e 's/^>[[:space:]]*//' \ + -e 's/<[^>]*>//g' \ + -e '/^[[:space:]]*$/d' \ + -e 's/|//g' \ + -e 's/^[[:space:]]*---[[:space:]]*$//' | + tr '\n' ' ' | + sed -e 's/ */ /g' -e 's/\\/\\\\/g' -e 's/"/\\"/g' | + awk '{ print substr($0, 1, 500) }' +} + +build_markdown_manifest() { + manifest_root="$KEWT_TMPDIR/manifest" + manifest_meta_root="$manifest_root/meta" + manifest_dir_meta_root="$manifest_root/dir-meta" + manifest_all_list="$manifest_root/all.lst" + manifest_visible_list="$manifest_root/visible.lst" + + rm -rf "$manifest_root" + mkdir -p "$manifest_meta_root" + mkdir -p "$manifest_dir_meta_root" + : > "$manifest_all_list" + : > "$manifest_visible_list" + + eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -name \"*.md\" -print" | sort | while IFS= read -r manifest_file; do + manifest_rel_path="${manifest_file#"$src"/}" + manifest_dir_rel=$(dirname "$manifest_rel_path") + manifest_filename=$(basename "$manifest_rel_path") + manifest_is_index="false" + [ "$manifest_filename" = "index.md" ] && manifest_is_index="true" + + parse_frontmatter "$manifest_file" + markdown_title_from_loaded_file "$manifest_file" "$title - Page" + manifest_title="$markdown_title" + set_post_datetime "$fm_date" "$(basename "$manifest_file" .md)" + + manifest_post_date="$post_date" + manifest_post_time="$post_time" + manifest_post_slug=$(basename "$manifest_file" .md | sed \ + -e 's/^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}[:\-][0-9]\{2\}//' \ + -e 's/^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}//' \ + -e 's/^[_\-]//') + + if [ "$manifest_is_index" = "true" ]; then + if [ "$manifest_rel_path" = "index.md" ]; then + manifest_url="/index.html" + else + manifest_url=$(directory_index_url "${manifest_rel_path%/index.md}") + fi + else + manifest_url=$(markdown_file_url "$manifest_rel_path") + fi + + manifest_search_content="" + if [ "$generate_search" = "true" ]; then + manifest_search_content=$(extract_search_content "$manifest_file") + fi + + manifest_meta_file=$(manifest_meta_path "$manifest_rel_path") + mkdir -p "$(dirname "$manifest_meta_file")" + { + printf 'manifest_rel_path=%s\n' "$(shell_quote "$manifest_rel_path")" + printf 'manifest_dir_rel=%s\n' "$(shell_quote "$manifest_dir_rel")" + printf 'manifest_filename=%s\n' "$(shell_quote "$manifest_filename")" + printf 'manifest_is_index=%s\n' "$(shell_quote "$manifest_is_index")" + printf 'manifest_title=%s\n' "$(shell_quote "$manifest_title")" + printf 'manifest_date=%s\n' "$(shell_quote "$fm_date")" + printf 'manifest_draft=%s\n' "$(shell_quote "$fm_draft")" + printf 'manifest_description=%s\n' "$(shell_quote "$fm_description")" + printf 'manifest_content_warning=%s\n' "$(shell_quote "$fm_content_warning")" + printf 'manifest_tags=%s\n' "$(shell_quote "$fm_tags")" + printf 'manifest_url=%s\n' "$(shell_quote "$manifest_url")" + printf 'manifest_search_content=%s\n' "$(shell_quote "$manifest_search_content")" + printf 'manifest_post_date=%s\n' "$(shell_quote "$manifest_post_date")" + printf 'manifest_post_time=%s\n' "$(shell_quote "$manifest_post_time")" + printf 'manifest_post_slug=%s\n' "$(shell_quote "$manifest_post_slug")" + } > "$manifest_meta_file" + + if load_manifest_dir_entry "$manifest_dir_rel"; then + : + else + dir_md_count=0 + dir_first_md="" + dir_has_index="false" + fi + + dir_md_count=$((dir_md_count + 1)) + if [ -z "$dir_first_md" ]; then + dir_first_md="$manifest_rel_path" + fi + if [ "$manifest_filename" = "index.md" ]; then + dir_has_index="true" + fi + write_manifest_dir_meta "$manifest_dir_rel" "$dir_md_count" "$dir_first_md" "$dir_has_index" + + printf '%s\n' "$manifest_rel_path" >> "$manifest_all_list" + done + + eval "find \"$src\" \( $IGNORE_ARGS -o $HIDE_ARGS -o $PRESERVE_ARGS \) -prune -o -name \"*.md\" -print" | sort | while IFS= read -r visible_file; do + printf '%s\n' "${visible_file#"$src"/}" >> "$manifest_visible_list" + done +} diff --git a/lib/metadata.sh b/lib/metadata.sh index d83c94c..a178927 100644 --- a/lib/metadata.sh +++ b/lib/metadata.sh @@ -1,3 +1,5 @@ +#!/bin/sh + parse_frontmatter() { _fm_file="$1" _fm_out="$KEWT_TMPDIR/fm_vals.txt" diff --git a/lib/runtime.sh b/lib/runtime.sh index 0f7c43d..aeaa0f1 100644 --- a/lib/runtime.sh +++ b/lib/runtime.sh @@ -1,3 +1,5 @@ +#!/bin/sh + trim_whitespace() { printf '%s' "$1" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//' } @@ -26,6 +28,43 @@ directory_index_url() { fi } +format_rfc2822_utc() { + _rfc_date="$1" + _rfc_time="${2:-00:00}" + [ -n "$_rfc_time" ] || _rfc_time="00:00" + awk -v d="$_rfc_date" -v t="$_rfc_time" ' + function weekday(y, m, day, k, j, h) { + if (m < 3) { + m += 12 + y-- + } + k = y % 100 + j = int(y / 100) + h = (day + int((13 * (m + 1)) / 5) + k + int(k / 4) + int(j / 4) + 5 * j) % 7 + return (h + 6) % 7 + } + BEGIN { + split(d, da, "-") + split(t, ti, ":") + year = da[1] + 0 + month = da[2] + 0 + day = da[3] + 0 + hour = (ti[1] == "" ? 0 : ti[1]) + 0 + minute = (ti[2] == "" ? 0 : ti[2]) + 0 + + months[1] = "Jan"; months[2] = "Feb"; months[3] = "Mar"; months[4] = "Apr" + months[5] = "May"; months[6] = "Jun"; months[7] = "Jul"; months[8] = "Aug" + months[9] = "Sep"; months[10] = "Oct"; months[11] = "Nov"; months[12] = "Dec" + + days[0] = "Sun"; days[1] = "Mon"; days[2] = "Tue"; days[3] = "Wed" + days[4] = "Thu"; days[5] = "Fri"; days[6] = "Sat" + + printf "%s, %02d %s %04d %02d:%02d:00 +0000\n", + days[weekday(year, month, day)], day, months[month], year, hour, minute + } + ' +} + append_find_rule() { _expr="$1" _rule="$2" @@ -72,7 +111,7 @@ append_nested_marker_rules() { find "$_root" -name "$_marker" > "$_tmp_file" while IFS= read -r marker_path; do - marker_dir="${marker_path%/$marker}" + marker_dir="${marker_path%/"$marker"}" if [ "$marker_dir" != "$_root" ] && [ "$marker_dir" != "." ]; then _expr=$(append_find_rule "$_expr" "-path '$marker_dir'") _expr=$(append_find_rule "$_expr" "-path '$marker_dir/*'") @@ -130,7 +169,7 @@ refresh_build_context() { asset_version="" if [ "$versioning" = "true" ]; then - asset_version="?v=$(date +%s)" + asset_version="?v=$(date '+%Y%m%d%H%M%S')" fi resolve_template_path diff --git a/markdown.sh b/markdown.sh index 425ecfd..6adb61d 100755 --- a/markdown.sh +++ b/markdown.sh @@ -15,7 +15,8 @@ sed_inplace() { fi } -temp_file=$(mktemp "${KEWT_TMPDIR:-/tmp}/markdown.XXXXXX") +temp_parent="${KEWT_TMPDIR:-${TMPDIR:-/tmp}}" +temp_file="${temp_parent}/markdown.$$.md" cat "$@" > "$temp_file" trap 'rm -f "$temp_file" "$temp_file.tmp" "$temp_file.fm"' EXIT INT TERM