#!/usr/bin/env bash # The helper of a share: laid here by the fabric node that serves this directory at https://files.playground.balcony.codes, and laid again by it # whenever that address moves. Run it from anywhere; it reads nothing but where it lies. # # fab-share.bash url ... the address a file or directory beneath this share is served at # fab-share.bash list [] every file beneath a directory of the share, with its address # fab-share.bash where this share's directory and its address # # Files and directories whose names begin with a dot are not served. set -euo pipefail shopt -s inherit_errexit share_url='https://files.playground.balcony.codes' die() { printf 'fab-share: %s\n' "$*" >&2 exit 1 } # The share is the directory this script lies in, however it was called. with_share() { local share_dir share_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" "$@" } # A path, absolute or relative to where the call was made, as the share serves it: its part beneath the share. with_held() { local given="$1" path held shift path="$(realpath -m -- "$given")" case "$path/" in "$share_dir"/*) ;; *) die "$given is not beneath $share_dir" ;; esac held="${path#"$share_dir"}" "$@" } do_url() { printf '%s%s\n' "$share_url" "$(do_encoded "${held:-/}")"; } # A path as a URL carries it: every byte but the unreserved ones and the slash percent-encoded. do_encoded() { local LC_ALL=C text="$1" out="" char i for ((i = 0; i < ${#text}; i++)); do char="${text:i:1}" case "$char" in [A-Za-z0-9._~/-]) out+="$char" ;; *) printf -v char '%%%02X' "'$char" && out+="$char" ;; esac done printf '%s' "$out" } do_listed() { printf '%s\t%s\n' "$held" "$(do_url)"; } goal__url() { (($#)) || die "url ..." local one for one in "$@"; do with_held "$one" do_url; done } goal__list() { local dir file dir="$(realpath -m -- "${1:-$share_dir}")" while IFS= read -r -d '' file; do with_held "$file" do_listed done < <(find "$dir" -mindepth 1 -name '.*' -prune -o -type f -print0 | sort -z) } goal__where() { printf '%s\t%s/\n' "$share_dir" "$share_url"; } goal() { local verb="${1:-}" declare -F "goal__$verb" >/dev/null || die "a verb: url ..., list [], where" shift "goal__$verb" "$@" } with_share goal "$@"