289 lines
8.5 KiB
Bash
Executable File
289 lines
8.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
if [[ -a ".env" ]]; then
|
|
export $(cat .env | sed 's/^#.*//g' | xargs)
|
|
fi
|
|
|
|
help() {
|
|
echo
|
|
echo "task <command> [options]"
|
|
echo
|
|
echo "commands:"
|
|
echo
|
|
|
|
local -a rows
|
|
local max_cmd=7 max_opt=6 max_desc=11
|
|
|
|
rows+=("Command|Option|Description")
|
|
rows+=("install-vuepress||Install build dependencies.")
|
|
rows+=("update-vuepres||Update build dependencies.")
|
|
rows+=("dev-vuepress||Start vuepress development server.")
|
|
rows+=("build-vuepress||Create vuepress build.")
|
|
rows+=("serve-vuepress||Serve vuepress build.")
|
|
rows+=("download-icons||Download module icons from Odoo assets.")
|
|
rows+=("update-module-versions|[file]|Check and update frontmatter versions list.")
|
|
rows+=("get-frontmatter-field|<file> <field>|Read a single frontmatter field value.")
|
|
rows+=("set-frontmatter-field|<file> <versions>|Write versions list to frontmatter.")
|
|
rows+=("lint||Lint code with prettier.")
|
|
|
|
for row in "${rows[@]}"; do
|
|
IFS='|' read -r cmd opt desc <<< "$row"
|
|
(( ${#cmd} > max_cmd )) && max_cmd=${#cmd}
|
|
(( ${#opt} > max_opt )) && max_opt=${#opt}
|
|
(( ${#desc} > max_desc )) && max_desc=${#desc}
|
|
done
|
|
|
|
printf '| %-*s | %-*s | %-*s |\n' \
|
|
"$max_cmd" "Command" \
|
|
"$max_opt" "Option" \
|
|
"$max_desc" "Description"
|
|
|
|
printf '|-%*s-|-%*s-|-%*s-|\n' \
|
|
"$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
|
|
"$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
|
|
"$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"
|
|
|
|
for row in "${rows[@]:1}"; do
|
|
IFS='|' read -r cmd opt desc <<< "$row"
|
|
printf '| %-*s | %-*s | %-*s |\n' \
|
|
"$max_cmd" "$cmd" \
|
|
"$max_opt" "$opt" \
|
|
"$max_desc" "$desc"
|
|
done
|
|
}
|
|
|
|
if [ -d "$HOME/taskfile.build/bin" ]; then
|
|
for file in "$HOME/taskfile.build/bin/"*; do
|
|
if [ -f "$file" ]; then
|
|
source "$file"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
get-frontmatter-field() {
|
|
local FILE="$1"
|
|
local FIELD="$2"
|
|
awk '
|
|
BEGIN { in_fm=0; found=0 }
|
|
/^---$/ {
|
|
if (in_fm == 0) { in_fm=1; next }
|
|
else { exit }
|
|
}
|
|
in_fm && /^'"$FIELD"':[ \t]*/ {
|
|
sub(/^'"$FIELD"':[ \t]*/, "")
|
|
# Strip surrounding quotes if present
|
|
gsub(/^'"'"'|'"'"'$/, "")
|
|
gsub(/^"|"$/, "")
|
|
print
|
|
found=1
|
|
}
|
|
' "$FILE"
|
|
}
|
|
|
|
set-frontmatter-field() {
|
|
local FILE="$1"
|
|
shift
|
|
local VERSIONS=("$@")
|
|
|
|
# Build the replacement block: "versions:\n - 'x.y'\n - ..."
|
|
local NEW_BLOCK="versions:"
|
|
for V in "${VERSIONS[@]}"; do
|
|
NEW_BLOCK="${NEW_BLOCK}\n - '${V}'"
|
|
done
|
|
|
|
# Use awk to replace the existing versions block inside the frontmatter.
|
|
# The versions block may span multiple lines (the key line + list items).
|
|
# Skips any lines that are part of a YAML block sequence (optional indent + "- ").
|
|
awk -v new_block="$NEW_BLOCK" '
|
|
BEGIN { in_fm=0; in_versions=0; fm_done=0 }
|
|
/^---$/ {
|
|
if (in_fm == 0) { in_fm=1; print; next }
|
|
else { fm_done=1; in_fm=0 }
|
|
}
|
|
# Once frontmatter is closed, print everything verbatim
|
|
fm_done { print; next }
|
|
in_fm {
|
|
if (/^versions:/) {
|
|
# Print replacement block and enter versions-skip mode
|
|
printf "%s\n", new_block
|
|
in_versions=1
|
|
next
|
|
}
|
|
if (in_versions) {
|
|
# Skip continuation list items (lines starting with optional whitespace + "- ")
|
|
if (/^[ \t]*- /) { next }
|
|
else { in_versions=0 }
|
|
}
|
|
print
|
|
}
|
|
!in_fm { print }
|
|
' "$FILE" > "${FILE}.tmp" && mv "${FILE}.tmp" "$FILE"
|
|
}
|
|
|
|
update-module-versions() {
|
|
local TARGET_FILE="${1:-}" # Optional: single file path to process
|
|
local VERSIONS=("14.0" "15.0" "16.0" "17.0" "18.0" "19.0")
|
|
local PROGRESS_FILE="tmp/update-module-versions.progress"
|
|
|
|
# Collect files to process
|
|
local FILES=()
|
|
if [[ -n "$TARGET_FILE" ]]; then
|
|
if [[ ! -f "$TARGET_FILE" ]]; then
|
|
echo "Error: File '$TARGET_FILE' not found."
|
|
exit 1
|
|
fi
|
|
FILES=("$TARGET_FILE")
|
|
else
|
|
while IFS= read -r -d '' f; do
|
|
FILES+=("$f")
|
|
done < <(find . -maxdepth 1 -name "*.md" -type f -print0)
|
|
fi
|
|
|
|
local TOTAL_FILES=${#FILES[@]}
|
|
local FILE_COUNT=0
|
|
local RESUME_COUNT=0
|
|
|
|
if [[ -z "$TARGET_FILE" ]]; then
|
|
mkdir -p tmp
|
|
if [[ -f "$PROGRESS_FILE" ]]; then
|
|
RESUME_COUNT=$(cat "$PROGRESS_FILE" 2>/dev/null || echo 0)
|
|
if ! [[ "$RESUME_COUNT" =~ ^[0-9]+$ ]]; then
|
|
RESUME_COUNT=0
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$TARGET_FILE" && "$RESUME_COUNT" -gt 0 ]]; then
|
|
echo "Resuming from file $RESUME_COUNT/$TOTAL_FILES"
|
|
fi
|
|
|
|
for FILE in "${FILES[@]}"; do
|
|
FILE_COUNT=$((FILE_COUNT + 1))
|
|
|
|
if [[ -z "$TARGET_FILE" && "$FILE_COUNT" -le "$RESUME_COUNT" ]]; then
|
|
continue
|
|
fi
|
|
|
|
echo "Processing file '$FILE' ($FILE_COUNT/$TOTAL_FILES)"
|
|
|
|
local SKIP_FILE=0
|
|
|
|
# Only process files that have a versions: key in their frontmatter
|
|
if ! awk '/^---$/{c++;next} c==1 && /^versions:/{found=1} c==2{exit} END{exit !found}' "$FILE"; then
|
|
echo " Skipping: no 'versions' key in frontmatter."
|
|
SKIP_FILE=1
|
|
fi
|
|
|
|
if [[ "$SKIP_FILE" -eq 0 ]]; then
|
|
# Read required frontmatter fields
|
|
local FORGE
|
|
FORGE=$(get-frontmatter-field "$FILE" "forge")
|
|
local REPO
|
|
REPO=$(get-frontmatter-field "$FILE" "repo")
|
|
local NAME
|
|
NAME=$(get-frontmatter-field "$FILE" "name")
|
|
|
|
if [[ -z "$FORGE" || -z "$REPO" || -z "$NAME" ]]; then
|
|
echo " Skipping: missing forge/repo/name in frontmatter."
|
|
SKIP_FILE=1
|
|
fi
|
|
fi
|
|
|
|
if [[ "$SKIP_FILE" -eq 0 ]]; then
|
|
# Test each version and collect available ones
|
|
local AVAILABLE_VERSIONS=()
|
|
for VERSION in "${VERSIONS[@]}"; do
|
|
local URL
|
|
if [[ "${FORGE}" == "github.com" ]]; then
|
|
URL="https://raw.githubusercontent.com/${REPO}/${VERSION}/${NAME}/__manifest__.py"
|
|
else
|
|
URL="https://${FORGE}/${REPO}/tree/${VERSION}/${NAME}"
|
|
fi
|
|
local HTTP_STATUS
|
|
HTTP_STATUS=$(curl -o /dev/null -s -w "%{http_code}" --max-time 10 "$URL" || echo "ERR")
|
|
if [[ "$HTTP_STATUS" == "200" ]]; then
|
|
echo " ✓ $VERSION available ($URL)"
|
|
AVAILABLE_VERSIONS+=("$VERSION")
|
|
else
|
|
echo " ✗ $VERSION not found (HTTP $HTTP_STATUS)"
|
|
fi
|
|
done
|
|
|
|
if [[ ${#AVAILABLE_VERSIONS[@]} -eq 0 ]]; then
|
|
echo " No available versions found. Frontmatter unchanged."
|
|
SKIP_FILE=1
|
|
fi
|
|
fi
|
|
|
|
if [[ "$SKIP_FILE" -eq 0 ]]; then
|
|
# Reverse so that the latest version appears first in the list
|
|
local REVERSED=()
|
|
for (( i=${#AVAILABLE_VERSIONS[@]}-1; i>=0; i-- )); do
|
|
REVERSED+=("${AVAILABLE_VERSIONS[$i]}")
|
|
done
|
|
|
|
echo " Updating versions: ${REVERSED[*]}"
|
|
set-frontmatter-field "$FILE" "${REVERSED[@]}"
|
|
fi
|
|
|
|
if [[ -z "$TARGET_FILE" ]]; then
|
|
echo "$FILE_COUNT" > "$PROGRESS_FILE"
|
|
fi
|
|
done
|
|
|
|
if [[ -z "$TARGET_FILE" && -f "$PROGRESS_FILE" ]]; then
|
|
rm -f "$PROGRESS_FILE"
|
|
fi
|
|
}
|
|
|
|
install-vuepress() {
|
|
pnpm install
|
|
}
|
|
|
|
update() {
|
|
pnpm install -D @vuepress/bundler-vite@next
|
|
pnpm install -D @vuepress/client@next
|
|
pnpm install -D @vuepress/plugin-docsearch@next
|
|
pnpm install -D @vuepress/plugin-search@next
|
|
pnpm install -D @vuepress/plugin-shiki@next
|
|
pnpm install -D @vuepress/theme-default@next
|
|
pnpm install -D @vuepress/utils@next
|
|
pnpm install -D vuepress@next
|
|
}
|
|
|
|
dev-vuepress() {
|
|
open-url "http://localhost:8080/"
|
|
pnpm run dev
|
|
}
|
|
|
|
build-vuepress() {
|
|
pnpm run build
|
|
}
|
|
|
|
serve-vuepress() {
|
|
cd ./src/.vuepress/dist
|
|
npx serve
|
|
}
|
|
|
|
download-icons() {
|
|
pnpm run download-icons
|
|
}
|
|
|
|
lint() {
|
|
pnpm exec prettier . --write
|
|
}
|
|
|
|
if declare -f "$1" > /dev/null; then
|
|
"$1" "${@:2}"
|
|
else
|
|
case "$1" in
|
|
*)
|
|
echo "Unknown command: $1"
|
|
help
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|