mirror of
https://github.com/oSoWoSo/DistroHopper.git
synced 2026-06-14 17:36:40 +00:00
425 lines
11 KiB
Bash
Executable file
425 lines
11 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#shellcheck disable=SC2089
|
|
#
|
|
# Make website from .md files
|
|
#
|
|
# Author: zenobit <zen@duck.com>
|
|
# Date: February 14, 2026
|
|
# License: MIT
|
|
#
|
|
|
|
count=$(find ./ -name '*.md' | wc -l)
|
|
|
|
# Functions for colored bordered messages (gum) or ANSI colored messages
|
|
if command -v gum -v >/dev/null; then
|
|
_r() {
|
|
gum style --border rounded --border-foreground "#e50203" --padding "0 1" "${@}"
|
|
}
|
|
|
|
_re() {
|
|
gum style --border rounded --border-foreground "#e50203" --padding "0 1" "${@}"
|
|
exit 1
|
|
}
|
|
|
|
_g() {
|
|
gum style --border rounded --border-foreground "#14a113" --padding "0 1" "$@"
|
|
}
|
|
|
|
_b() {
|
|
gum style --border rounded --border-foreground "#004EFB" --padding "0 1" "$@"
|
|
}
|
|
|
|
_y() {
|
|
gum style --border rounded --border-foreground "#fdde13" --padding "0 1" "$@"
|
|
}
|
|
|
|
ask() {
|
|
gum confirm "$@"
|
|
}
|
|
|
|
_header() {
|
|
local text green red yellow
|
|
text="${1}"
|
|
red=$(gum style --border rounded --border-foreground "#e50203" --padding "0 1" "$text")
|
|
yellow=$(gum style --border rounded --border-foreground "#fdde13" --padding "0 1" "$red")
|
|
green=$(gum style --border rounded --border-foreground "#14a113" --padding "0 1" "$yellow")
|
|
echo "$green"
|
|
}
|
|
|
|
_footer() {
|
|
local text green red yellow
|
|
text="${1}"
|
|
green=$(gum style --border rounded --border-foreground "#14a113" --padding "0 1" "$text")
|
|
yellow=$(gum style --border rounded --border-foreground "#fdde13" --padding "0 1" "$green")
|
|
red=$(gum style --border rounded --border-foreground "#e50203" --padding "0 1" "$yellow")
|
|
echo "$red"
|
|
}
|
|
else
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
#CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
_g() {
|
|
echo -e "${GREEN}${1}${NC}"
|
|
}
|
|
|
|
_r() {
|
|
echo -e "${RED}${1}${NC}"
|
|
}
|
|
|
|
_re() {
|
|
echo -e "${RED}${1}${NC}" >&2
|
|
exit 1
|
|
}
|
|
|
|
_b() {
|
|
echo -e "${BLUE}${1}${NC}"
|
|
}
|
|
|
|
_y() {
|
|
echo -e "${YELLOW}${1}${NC}"
|
|
}
|
|
|
|
ask() {
|
|
_y "Press Enter to continue
|
|
anything else for Quit..."
|
|
echo "$1"
|
|
read -n 1 -s key
|
|
if [[ ! $key == '' ]]; then
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
_header() {
|
|
echo -e "\n${RED}${1}${NC}\n"
|
|
}
|
|
|
|
_footer() {
|
|
echo -e "\n${RED}${1}${NC}\n"
|
|
}
|
|
fi
|
|
export -f _r _re _g _b _y
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Optional override: set FORGE_URL to your Gitea/Forgejo base URL to skip
|
|
# auto-detection, e.g. in .env or before calling the script:
|
|
# export FORGE_URL="https://git.example.com"
|
|
# ---------------------------------------------------------------------------
|
|
[ -f .env ] && source .env
|
|
|
|
# Try to detect a Gitea/Forgejo instance by probing /api/v1/meta
|
|
# Returns 0 (true) if confirmed, 1 if not
|
|
_is_gitea() {
|
|
local base_url="$1"
|
|
local response
|
|
response=$(curl -sf --max-time 5 "${base_url}/api/v1/meta" 2>/dev/null)
|
|
# Gitea/Forgejo meta endpoint returns JSON with a "version" field
|
|
[[ "$response" =~ \"version\" ]] && return 0
|
|
return 1
|
|
}
|
|
|
|
# Detect repository URL and platform from git remote origin
|
|
_detect_repo() {
|
|
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
|
_r "Not a git repository — repo buttons will be disabled"
|
|
REPO_URL="" REPO_PLATFORM="" REPO_ZIP_URL="" REPO_RELEASE_URL=""
|
|
return
|
|
fi
|
|
|
|
# Always use the main remote repository
|
|
local raw
|
|
raw=$(git remote get-url "$(git remote | head -n 1)" 2>/dev/null)
|
|
|
|
if [ -z "$raw" ]; then
|
|
_r "No git remote found — repo buttons will be disabled"
|
|
REPO_URL="" REPO_PLATFORM="" REPO_ZIP_URL="" REPO_RELEASE_URL=""
|
|
return
|
|
fi
|
|
|
|
# Normalize SSH → HTTPS
|
|
local https_url
|
|
if [[ "$raw" =~ ^git@ ]]; then
|
|
https_url=$(echo "$raw" | sed 's|git@\(.*\):\(.*\)\.git|https://\1/\2|; s|git@\(.*\):\(.*\)|https://\1/\2|')
|
|
else
|
|
https_url="${raw%.git}"
|
|
fi
|
|
|
|
# Extract base URL (scheme + host) and slug (user/repo)
|
|
local base_url slug
|
|
base_url=$(echo "$https_url" | grep -oP 'https?://[^/]+')
|
|
slug=$(echo "$https_url" | sed "s|${base_url}/||")
|
|
|
|
# Detect platform — known hosts first, then Gitea/Forgejo probe
|
|
if [[ "$https_url" =~ github\.com ]]; then
|
|
REPO_PLATFORM="github"
|
|
REPO_URL="$https_url"
|
|
REPO_ZIP_URL="${https_url}/archive/refs/heads/main.zip"
|
|
REPO_RELEASE_URL="${https_url}/releases/latest"
|
|
|
|
elif [[ "$https_url" =~ gitlab\.com ]]; then
|
|
REPO_PLATFORM="gitlab"
|
|
REPO_URL="$https_url"
|
|
# GitLab: project path needed for archive URL
|
|
local proj_path
|
|
proj_path=$(echo "$https_url" | sed 's|https://gitlab\.com/||')
|
|
REPO_ZIP_URL="https://gitlab.com/${proj_path}/-/archive/main/${proj_path##*/}-main.zip"
|
|
REPO_RELEASE_URL="${https_url}/-/releases"
|
|
|
|
else
|
|
# Gitea/Forgejo: use FORGE_URL override or auto-detect via API probe
|
|
local forge_base="${FORGE_URL:-}"
|
|
|
|
if [ -n "$forge_base" ]; then
|
|
_b "FORGE_URL override: $forge_base"
|
|
REPO_PLATFORM="gitea"
|
|
elif _is_gitea "$base_url"; then
|
|
_g "Gitea/Forgejo detected at: $base_url"
|
|
forge_base="$base_url"
|
|
REPO_PLATFORM="gitea"
|
|
else
|
|
_y "Unknown platform — only source link will be shown"
|
|
REPO_PLATFORM="other"
|
|
REPO_URL="$https_url"
|
|
REPO_ZIP_URL=""
|
|
REPO_RELEASE_URL=""
|
|
_check_release
|
|
return
|
|
fi
|
|
|
|
REPO_URL="$https_url"
|
|
REPO_ZIP_URL="${forge_base}/${slug}/archive/main.zip"
|
|
REPO_RELEASE_URL="${https_url}/releases/latest"
|
|
fi
|
|
|
|
_g "Repo detected [$REPO_PLATFORM]: $REPO_URL"
|
|
# Check if any release exists via API
|
|
_check_release
|
|
}
|
|
|
|
# Query platform API to detect if at least one release exists
|
|
_check_release() {
|
|
REPO_HAS_RELEASE=0
|
|
|
|
[ -z "$REPO_URL" ] && return
|
|
|
|
local base_url slug http_code body
|
|
base_url=$(echo "$REPO_URL" | grep -oP 'https?://[^/]+')
|
|
slug=$(echo "$REPO_URL" | sed "s|${base_url}/||")
|
|
|
|
case "$REPO_PLATFORM" in
|
|
github)
|
|
http_code=$(curl -sf -o /dev/null -w "%{http_code}" \
|
|
-H "Accept: application/vnd.github+json" \
|
|
"https://api.github.com/repos/${slug}/releases/latest" 2>/dev/null)
|
|
# 200 = release exists, 404 = no releases
|
|
[ "$http_code" = "200" ] && REPO_HAS_RELEASE=1
|
|
;;
|
|
gitlab)
|
|
local encoded_slug
|
|
encoded_slug=$(echo "$slug" | sed 's|/|%2F|g')
|
|
body=$(curl -sf \
|
|
"https://gitlab.com/api/v4/projects/${encoded_slug}/releases?per_page=1" 2>/dev/null)
|
|
[ -n "$body" ] && [ "$body" != "[]" ] && REPO_HAS_RELEASE=1
|
|
;;
|
|
gitea)
|
|
# Gitea/Forgejo: GET /api/v1/repos/{owner}/{repo}/releases?limit=1
|
|
body=$(curl -sf --max-time 5 \
|
|
"${base_url}/api/v1/repos/${slug}/releases?limit=1" 2>/dev/null)
|
|
[ -n "$body" ] && [ "$body" != "[]" ] && [ "$body" != "null" ] && REPO_HAS_RELEASE=1
|
|
;;
|
|
*)
|
|
REPO_HAS_RELEASE=0
|
|
;;
|
|
esac
|
|
|
|
if [ "$REPO_HAS_RELEASE" = "1" ]; then
|
|
_g "Release found"
|
|
else
|
|
_y "No release found — release button will be shown as strikethrough"
|
|
fi
|
|
}
|
|
|
|
add_validation() {
|
|
echo '
|
|
<p>
|
|
<a href="https://jigsaw.w3.org/css-validator/check/referer">
|
|
<img style="border:0;width:88px;height:31px"
|
|
src="https://jigsaw.w3.org/css-validator/images/vcss-blue"
|
|
alt="Ověřit CSS!" />
|
|
</a>
|
|
</p>
|
|
' >> "$output"
|
|
}
|
|
|
|
# Build nav snippet for a given page with active class
|
|
# Injects: oSoWoSo | Home | [Download Release] [Download ZIP] [Source] | other pages...
|
|
_build_nav() {
|
|
local current="$1"
|
|
local nav_file="$2"
|
|
|
|
echo '<nav><ul>' > "$nav_file"
|
|
|
|
# oSoWoSo button — always first
|
|
echo ' <li><a href="https://osowoso.org">oSoWoSo</a></li>' >> "$nav_file"
|
|
|
|
# Home button
|
|
local home_active=""
|
|
[ "$current" = "index" ] && home_active=' class="active"'
|
|
echo " <li><a href=\"index.html\"${home_active}>Home</a></li>" >> "$nav_file"
|
|
|
|
# Repo buttons (only when URLs are available)
|
|
if [ -n "$REPO_RELEASE_URL" ]; then
|
|
if [ "${REPO_HAS_RELEASE:-0}" = "1" ]; then
|
|
echo " <li><a href=\"${REPO_RELEASE_URL}\">⏬ release</a></li>" >> "$nav_file"
|
|
else
|
|
echo " <li><a class=\"no-release\" href=\"${REPO_RELEASE_URL}\">⏬ release</a></li>" >> "$nav_file"
|
|
fi
|
|
fi
|
|
if [ -n "$REPO_ZIP_URL" ]; then
|
|
echo " <li><a href=\"${REPO_ZIP_URL}\">📦repo zip</a></li>" >> "$nav_file"
|
|
fi
|
|
if [ -n "$REPO_URL" ]; then
|
|
echo " <li><a href=\"${REPO_URL}\">🔗git</a></li>" >> "$nav_file"
|
|
fi
|
|
|
|
echo " <li>⏭️</a></li>" >> "$nav_file"
|
|
|
|
# Other .md pages
|
|
for md in *.md; do
|
|
[ -f "$md" ] || continue
|
|
[ "$md" = "README.md" ] && continue
|
|
local name=$(echo "${md%.md}" | sed 's/_/ /g')
|
|
local active=""
|
|
[ "$name" = "$current" ] && active=' class="active"'
|
|
echo " <li><a href=\"${name}.html\"${active}>${name}</a></li>" >> "$nav_file"
|
|
done
|
|
|
|
echo '</ul></nav>' >> "$nav_file"
|
|
}
|
|
|
|
# Target: build
|
|
target_build() { ## Builds the website, optional: title argument
|
|
_detect_repo
|
|
|
|
if [ -z "$1" ]; then
|
|
_r "No website title provided
|
|
using generated one!"
|
|
title=$(basename "$(pwd)" | sed 's/_/ /g')
|
|
else
|
|
title="$1"
|
|
fi
|
|
_g "Creating: $title"
|
|
if [ -f docs/CNAME ]; then
|
|
cp docs/CNAME src/
|
|
fi
|
|
rm -rf docs && mkdir -p docs
|
|
cp -r src/* docs/
|
|
rm -f docs/toggle.html docs/toc.html docs/svg-color.html
|
|
|
|
if [ "$count" = 1 ]; then
|
|
for file in *.md; do
|
|
[ -f "$file" ] || continue
|
|
local nav_file="docs/_nav.html"
|
|
_build_nav "index" "$nav_file"
|
|
echo "Processing: $file → index.html"
|
|
# single file
|
|
pandoc "$file" -f gfm -s \
|
|
--css=style.css \
|
|
--toc \
|
|
--toc-depth=3 \
|
|
--include-before-body=src/toggle.html \
|
|
--include-before-body=src/toc.html \
|
|
--include-before-body="$nav_file" \
|
|
--include-after-body=src/svg-color.html \
|
|
--metadata title="$title" \
|
|
-o docs/index.html
|
|
rm -f "$nav_file"
|
|
done
|
|
|
|
elif [ "$count" -gt 1 ]; then
|
|
for file in *.md; do
|
|
[ -f "$file" ] || continue
|
|
|
|
if [ "$file" = "README.md" ]; then
|
|
output="docs/index.html"
|
|
meta_title="$title"
|
|
current="index"
|
|
else
|
|
output="docs/${file%.md}.html"
|
|
meta_title=$(echo "${file%.md}" | sed 's/_/ /g')
|
|
current="${file%.md}"
|
|
fi
|
|
|
|
local nav_file="docs/_nav_${current}.html"
|
|
_build_nav "$current" "$nav_file"
|
|
|
|
echo "Processing: $file → $output"
|
|
# multi file
|
|
pandoc "$file" -f gfm -s \
|
|
--css=style.css \
|
|
--toc \
|
|
--toc-depth=3 \
|
|
--include-before-body=src/toggle.html \
|
|
--include-before-body=src/toc.html \
|
|
--include-before-body="$nav_file" \
|
|
--include-after-body=src/svg-color.html \
|
|
--metadata title="$meta_title" \
|
|
-o "$output"
|
|
rm -f "$nav_file"
|
|
done
|
|
else
|
|
_re "ERROR: No .md files found!"
|
|
fi
|
|
_g "Finished"
|
|
}
|
|
|
|
# Target: help
|
|
target_help() { ## Show this help message
|
|
_b 'OSOWOSO Website Build System'
|
|
echo ""
|
|
echo "Usage: $0 [target]"
|
|
echo ""
|
|
echo "Available targets:"
|
|
echo ""
|
|
awk 'BEGIN {FS = "## "} /^target_[a-zA-Z_-]+\(\).*## / {
|
|
sub(/target_/, "", $1)
|
|
sub(/\(\) \{/, "", $1)
|
|
gsub(/^[ \t]+/, "", $1)
|
|
printf " \033[36m%-15s\033[0m %s\n", $1, $2
|
|
}' "$0" | sort || _re 'ERROR: No functions found!
|
|
Create function you want use for arguments and help as:
|
|
target_"Name of argument aka function"() { ## Your usage message here.'
|
|
echo ""
|
|
}
|
|
|
|
# Target: serve
|
|
target_serve() { ## Serve site locally out of docs folder
|
|
if [ ! -f docs/index.html ]; then
|
|
_r "Site not built!"
|
|
ask 'Build first?' && target_build "$@" || _re "Exiting"
|
|
fi
|
|
|
|
_g 'Press Ctrl+C to stop'
|
|
python3 -m http.server -d docs 8000
|
|
}
|
|
|
|
# Main script logic
|
|
main() {
|
|
local target="${1:-help}"
|
|
target="${target#target_}"
|
|
local func_name="target_${target//-/_}"
|
|
|
|
if declare -f "$func_name" > /dev/null; then
|
|
shift
|
|
"$func_name" "$@"
|
|
else
|
|
#shellcheck disable=SC2016,2086
|
|
_re 'Unknown target: $target. Run '$0 help' for available targets.'
|
|
fi
|
|
}
|
|
|
|
# Run main with all arguments
|
|
main "$@"
|