commit 352607712f6b3ba93178459f295ed7cff71ee561
parent d489cce019a7f2d9a73709aa80542969c12e9dc9
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 25 Aug 2025 15:24:48 +0200
Move the build system shells to the scripts subdirectory
Update the scripts accordingly to reflect this update
Diffstat:
15 files changed, 532 insertions(+), 533 deletions(-)
diff --git a/Makefile b/Makefile
@@ -24,11 +24,11 @@ default: build
build clean distclean lint install: hooks index
@$(MAKE) -f.hooks -f.index -fMakefile $@__ \
- HTML="$$($(SHELL) ./list.sh html | tr '\n' ' ')" \
- SH="$$( $(SHELL) ./list.sh shell | tr '\n' ' ')"
+ HTML="$$($(SHELL) ./scripts/list.sh html | tr '\n' ' ')" \
+ SH="$$( $(SHELL) ./scripts/list.sh shell | tr '\n' ' ')"
hooks index:
- $(SHELL) $@.sh > .$@
+ $(SHELL) scripts/$@.sh > .$@
build__: $(HTML)
@@ -41,12 +41,12 @@ distclean__: clean__
install__: $(HTML) $(SIG)
@rsync --mkpath -avzrR --delete-after --progress \
- meso.css $(HTML) $$($(SHELL) ./list.sh subdir) $(PREFIX)
+ meso.css $(HTML) $$($(SHELL) ./scripts/list.sh subdir) $(PREFIX)
################################################################################
# Generate content
################################################################################
-$(HTML): generate_header.sh menu.tsv
+$(HTML): scripts/generate_header.sh menu.tsv
.sh.md:
@cd -- "$$(dirname "$<")"; \
@@ -55,7 +55,7 @@ $(HTML): generate_header.sh menu.tsv
.md.html:
@echo "Building $@"
@{ \
- $(SHELL) generate_header.sh $${PWD}/$@; \
+ $(SHELL) scripts/generate_header.sh $${PWD}/$@; \
$(MD2HTML) $<; \
cat footer.html; \
} > $@
@@ -69,15 +69,14 @@ $(HTML): generate_header.sh menu.tsv
.sh.shlint:
@echo "Linting $<"
- @# Scripts are executed in their local directory, with the
- @# exception of hooks, which are executed relative to the section
- @# directory.
+ @# Scripts are executed relative to their section directory.
+ @# Scripts belonging to the compilation system are executed
+ @# relative to the working directory.
@i="$<"; \
- if echo "$${i#*/}" | grep -qe '^hooks/'; then \
+ if [ "$${i%%/*}" != "scripts" ]; then \
cd -- "$${i%%/*}"; \
- else \
- cd -- "$$(dirname "$<")"; \
+ i="$${i#*/}"; \
fi; \
- shellcheck -o all -x "$${i#*/}"
+ shellcheck -o all -x "$${i}"
lint__: $(LINT)
diff --git a/generate_header.sh b/generate_header.sh
@@ -1,256 +0,0 @@
-#!/bin/sh
-
-# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-set -e
-
-. "./meso-web.sh"
-
-########################################################################
-# Helper functions
-########################################################################
-# Print the absolute dir of the input file
-absdir() # file
-{
- cd -- "$(dirname "$1")" && pwd
- cd "${OLDPWD}"
-}
-
-# List the indexed content in TSV format. Each line contains the index
-# label, followed by the indexed content, and possibly an indicator of
-# the language used.
-#
-# The input data is the content of an index.tsv file, submitted on
-# standard input.
-indexed_content()
-(
- strip_dummy | while read -r _line; do
- _langs="$(echo "${_line}" | cut -d' ' -f3)"
-
- if [ -z "${_langs}" ]; then
- # There is no lang field defined: print the line as it
- printf '%s\n' "${_line}"
-
- else
- # The lang field is defined. Duplicate the line as many times as
- # there are languages listed. Define the content URI by replacing
- # the @LANG@ string with the language value.
- echo "${_langs}" \
- | sed 's/:/\n/g' \
- | while read -r _translation; do
- echo "${_line}" \
- | sed -e "s/\t[^\t]\{1,\}$/\t${_translation}/g" \
- -e "s/@LANG@/${_translation}/g"
- done
- fi
- done
-)
-
-# Print relative path from input file to worktree
-relpath_to_worktree() # file
-(
- # Build directory from worktree to path
- _dir="$(absdir "$1")"
- _dir="$(printf '%s\n' "${_dir}" | sed "s;^${worktree}[/]\{0,\};;g")"
-
- # Ensure that the directory if a subpath of the worktree
- if ! [ -d "${_dir}" ]; then
- return 1
- fi
-
- echo "${_dir}" | sed 's/\//\n/g' | while read -r _i; do
- printf "../"
- done
-)
-
-print_head()
-{
- printf '<!DOCTYPE html>\n'
- printf '<html lang="%s">\n' "${lang}"
- printf '<head>\n'
- printf ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n'
- printf ' <meta name="viewport" content="width=device-width, initial-scale=1">\n'
- printf ' <title>|M|S> %s</title>\n' "${label}"
- printf ' <link rel="stylesheet" title="default" href="%smeso.css">\n' "${root}"
- printf '</head>\n'
- printf '<body>\n'
-}
-
-# Print top-level menu
-print_menu1()
-(
- printf '<div id="menu">\n'
-
- _separator=""
- strip_dummy < "${worktree}/menu.tsv" | while read -r _i; do
-
- # Retrieve the menu label and its associated directory
- _label="$(echo "${_i}" | cut -d' ' -f1)"
- _directory="$(echo "${_i}" | cut -d' ' -f2)"
-
- echo "${_separator}" && _separator='  | '
-
- if [ "${_directory}" = "${section}" ]; then
- printf ' %s\n' "${_label}"
-
- else
- # Get the default page of the section, i.e., the first entry in
- # its index. The menu is a link to it.
- _uri="$(indexed_content < "${worktree}/${_directory}/index.tsv" \
- | head -1 | cut -d' ' -f2)"
-
- printf ' <a href="%s%s/%s">%s</a>\n' \
- "${root}" "${_directory}" "${_uri}" "${_label}"
- fi
- done
-
- printf '</div>\n<hr>\n'
-)
-
-# Print the list of translation choices
-# Available langs are submitted on standard input
-print_translations() # uri_template (i.e. URI generic to the lang)
-(
- _uri_template="$1"
-
- printf ' <span style="float: right;">\n'
-
- _separator=""
- while read -r _lang; do
-
- _translation="$(echo "${_uri_template}" | sed "s/@LANG@/${_lang}/g")"
-
- echo "${_separator}" && _separator='  / '
-
- if [ "${content}" = "${_translation}" ]; then
- printf ' <span class="cur">%s</span>\n' "${_lang}"
- else
- printf ' <a href="%s%s/%s">%s</a>\n' \
- "${root}" "${section}" "${_translation}" "${_lang}"
- fi
- done
-
- printf ' </span>\n'
-)
-
-# Print second-level menu
-print_menu2()
-(
-
- printf '<div id="sub-menu">\n'
-
- _separator=""
- strip_dummy < "${worktree}/${section}/index.tsv" | while read -r _i; do
-
- _label="$(echo "${_i}" | cut -d' ' -f1)"
- _uri_template="$(echo "${_i}" | cut -d' ' -f2)"
- _langs="$(echo "${_i}" | cut -d' ' -f3)"
- _lang_default="$(echo "${_langs}" | cut -d ':' -f1)"
-
- _uri="$(echo "${_uri_template}" | sed "s/@LANG@/${lang}/g")"
-
- echo "${_separator}" && _separator='  . '
-
- if [ "${_uri}" = "${content}" ]; then
- # This is the current web page
- printf ' <span class="cur">%s</span>\n' "${_label}"
-
- # Print links to translations if available
- if [ -n "${_langs}" ]; then
- echo "${_langs}" \
- | sed 's/:/\n/g' \
- | print_translations "${_uri_template}"
- fi
-
- elif echo "${_uri}" | grep -qe "^http[s]\{0,1\}://"; then
- # The entry links to an http[s] URL
- printf ' <a href="%s">%s</a>\n' "${_uri}" "${_label}"
-
- else
- # The entry links to a local web page for the section
- _uri="$(echo "${_uri_template}" | sed "s/@LANG@/${_lang_default}/g")"
- printf ' <a href="%s%s/%s">%s</a>\n' \
- "${root}" "${section}" "${_uri}" "${_label}"
- fi
- done
-
- printf '</div>\n'
-)
-
-########################################################################
-# The script
-########################################################################
-if [ "$#" -lt 1 ]; then
- >&2 printf 'usage: %s file\n' "${0##*/}"
- exit 1
-fi
-
-# Define the absolute path of the working directory, i.e. the root
-# directory of the site, and enter it.
-worktree="$(absdir "$0")"
-cd "${worktree}"
-
-# Define the section directory where the input file is located, i.e., the
-# subdirectory in the working directory.
-section="$(absdir "$1")"
-section="$(printf '%s\n' "${section}" | sed "s;^${worktree}[/]\{0,\};;g")"
-section="${section%%/*}"
-
-if [ -z "${section}" ]; then
- >&2 printf \
- '%s: unable to extract the section directory from file %s\n' \
- "${0##*/}" "$1"
- exit 1
-fi
-
-# Find the menu entry corresponding to the section directory
-entry="$(strip_dummy < "${worktree}/menu.tsv" \
- | sed -n "/\t${section}/p")"
-
-if [ -z "${entry}" ]; then
- >&2 printf \
-'%s: the %s directory of the %s file is not a valid menu entry '\
-'(see menu.tsv)\n' "${0##*/}" "${section}" "$1"
- exit 1
-fi
-
-label="$(echo "${entry}" | cut -d' ' -f1)"
-
-if ! [ -e "${section}/index.tsv" ]; then
- >&2 printf \
- '%s: unable to find the index.tsv file in the directory %s\n' \
- "${0##*/}" "${section}"
- exit 1
-fi
-
-# Define whether the entry corresponds to a subsection index, i.e.,
-# whether it is the file to be displayed when entering the subsection.
-content="$(basename "$1")"
-subentry="$(indexed_content < "${worktree}/${section}/index.tsv" \
- | sed -n "/\t${content}/p")"
-
-if [ -n "${subentry}" ]; then
- lang="$(echo "${subentry}" | cut -d' ' -f3 | cut -d':' -f1)"
-fi
-
-lang="${lang:-en}"
-root="$(relpath_to_worktree "$1")"
-
-print_head
-print_menu1
-print_menu2
-
-printf '<div id="content">\n'
diff --git a/hooks.sh b/hooks.sh
@@ -1,111 +0,0 @@
-#!/bin/sh
-
-# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-. "./meso-web.sh"
-
-set -e
-
-
-# Print on standard output the Makefile targets used to automate hook
-# management
-
-shtml="$(sh ./list.sh shtml)"
-hook="$(sh ./list.sh hook)"
-
-sections | while read -r i; do
- shtml_section="$(printf '%s\n' "${shtml}" \
- | sed -n "/^${i}\//p" | tr '\n' ' ')"
- hook_section="$(printf '%s\n' "${hook}" \
- | sed -n "/^${i}\//p" | tr '\n' ' ' \
- | sed -e 's/\.sh[[:space:]]/.hook /g')"
-
- # Define Makefile target that makes section hooks prerequisites for
- # the HTML content of the section.
- #
- # It is the files generated by each of the hooks that are
- # prerequisites for the HTML files, not the scripts of the hooks
- # themselves, because even if the scripts have not changed, their
- # output may have been updated, which can impact the HTML content
- # generated at build time.
- printf '%s: %s\n' "${shtml_section}" "${hook_section}"
-done
-
-printf '%s\n' "${hook}" | while read -r i; do
- # Divide the path into two parts:
- # - the top-level directory, i.e. the section
- # - the shell script to be executed from the section directory
- section="${i%%/*}"
- hook="${i##"${section}"/}"
-
- # The hook is the first one in the current section: it has the highest
- # priority and therefore has no prerequisites.
- if [ "${section}" != "${prev_section}" ]; then
- dep=""
- fi
-
- # Define a name for the hook used as a prefix for Makefile targets in
- # order to automate its execution and the management of the file it
- # generates. To ensure that this name is unique, and thus avoid
- # conflicts between different hooks, it is constructed from the names
- # of the section and file corresponding to the hook.
- file="$(basename "${hook}")"
- prefix="${section}-${file%%.*}"
-
- # The hook name begins with 'xx-', meaning that it does not depend on
- # any other hook in the section.
- if echo "${file}" | grep -qe '^xx-.*'; then
- dep=""
- fi
-
- # Set the file in which the names of the files generated by the hook
- # are stored as resources for the website, i.e., the files that must
- # be deployed with the website.
- tgt="${i%%.*}.hook"
-
- # Define the Makefile target that automate the hook executation. Its
- # pre-requisites are the hook script and the output of the # previous
- # hook in the section, i.e. with an higher priority. So that
- # execution priority is ensured.
- #
- # Finally, make this target a prerequisite for building the website
- # in order to enforce its execution during the build call.
- printf '%s: %s %s\n' "${tgt}" "${i}" "${dep}"
- printf " @( cd -- %s && \$(SHELL) %s ) > \$@\n" \
- "${section}" "${hook}"
-
- # Set the target for cleaning files generated by executing the hook.
- # Run it on "distclean" and not on "clean", as their generation can be
- # costly while effectively being files generated to "distribute" the
- # website.
- printf '%s-clean:\n' "${prefix}"
- printf ' if [ -f %s ]; then cat %s | xargs rm -f; fi\n' \
- "${tgt}" "${tgt}"
- printf ' rm -f %s\n' "${tgt}"
- printf 'distclean__: %s-clean\n' "${prefix}"
-
- # Set the target that installs website resources generated by the hook
- printf '%s-install: %s\n' "${prefix}" "${tgt}"
- printf " @rsync --mkpath -avzrR --files-from=%s ./ \$(PREFIX)\n" \
- "${tgt}"
- printf 'install__: %s-install\n' "${prefix}"
-
- # Ensure that the target of the hook is a prerequisite for the next
- # hook in the section, so that the execution order follows their
- # priority as defined by their file name.
- dep="${tgt}"
- prev_section="${section}"
-done
diff --git a/index.sh b/index.sh
@@ -1,33 +0,0 @@
-#!/bin/sh
-#
-# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-. "./meso-web.sh"
-
-set -e
-
-# Print to standard output the Makefile targets that make the section
-# index file a prerequisite for the section's HTML content.
-
-html="$(sh ./list.sh html)"
-
-sections | while read -r i; do
- html_section="$(printf '%s\n' "${html}" \
- | sed -n "/^${i}\//p" \
- | tr '\n' ' ')"
-
- printf '%s: %s/index.tsv\n' "${html_section}" "${i}"
-done
diff --git a/list.sh b/list.sh
@@ -1,114 +0,0 @@
-#!/bin/sh
-
-# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-. "./meso-web.sh"
-
-set -e
-
-if [ "$#" -lt 1 ]; then
- >&2 printf 'usage: %s <html|hook|shell|sig>\n' "${0##*/}"
- exit 1
-fi
-
-########################################################################
-# Helper functions
-########################################################################
-# List of HTML files to generate from Markdown files or shell scripts
-# stored in each section
-html()
-{
- _find_args="$(\
- printf '%s\n' "${sections}" \
- | sed -e 's/^/! -path /' \
- | tr '\n' ' ')"
-
- eval "exec find ${search_dirs} ${_find_args} -type d -prune -o \
- \( \
- -name \"*.md\" \
- -o -name \"*.sh\" \
- \) -exec sh -c 'printf \"%s.html\n\" \"\${1%.*}\"' -- {} \; \
- | sort"
-}
-
-# List of shell scripts that dynamically generate HTML content
-shtml()
-{
- _find_args="$(\
- printf '%s\n' "${sections}" \
- | sed -e 's/^/! -path /' \
- | tr '\n' ' ')"
-
- eval "exec find ${search_dirs} ${_find_args} -type d -prune -o \
- -name \"*.sh\" -print \
- | sort"
-}
-
-# List of hooks, i.e. shell scripts to be run by section
-hook()
-{
- _find_args="$(\
- printf '%s\n' "${sections}" \
- | sed -e 's/^/-path "/;s/$/\/hooks\/*" -o/' \
- | tr '\n' ' ' \
- | sed 's/ -o $//')"
-
- eval "find ${search_dirs} \
- \( \( ${_find_args} \) -type f -name \"*.sh\" \) \
- | sort"
-}
-
-# List the shell scripts relevant to the compilation system, i.e. the
-# shell script at the root of the working tree and those in each section
-# used to generate HTML pages.
-shell()
-{
- _find_args="$(\
- printf '%s\n' "${sections}" \
- | sed -e 's/^\(.\{0,\}\)$/! -path \1 ! -path \1\/hooks/' \
- | tr '\n' ' ')"
-
- eval "exec find . ${search_dirs} \
- ! -path . ${_find_args} -type d -prune -o -name \"*.sh\" -print \
- | sort"
-}
-
-# List the relevent section subdirectories which are:
-# - downloads
-# - images
-# - thumbs
-subdir()
-{
- downloads="-path \1/downloads"
- images="-path \1/images -o -path \1/thumbs"
-
- _find_args="$(\
- printf '%s\n' "${sections}" \
- | sed "s;^\(.\{0,\}\)$;${downloads} -o ${images} -o;" \
- | tr '\n' ' ' \
- | sed 's/ -o $//')"
-
- eval "exec find ${search_dirs} ${_find_args} -type d | sort"
-}
-
-########################################################################
-# Script
-########################################################################
-# List of sections to be dealt with
-sections="$(sections)"
-search_dirs="$(printf '%s\n' "${sections}" | tr '\n' ' ')"
-
-"$@"
diff --git a/schiff/hooks/01-generate-man.sh b/schiff/hooks/01-generate-man.sh
@@ -32,8 +32,8 @@ man2html() # output_filename
{
{
cd ..
- sh ./generate_header.sh "${OLDPWD##*/}/$1"
- sh ./convert_man.sh
+ sh ./scripts/generate_header.sh "${OLDPWD##*/}/$1"
+ sh ./scripts/convert_man.sh
cat ./footer.html
cd "${OLDPWD}"
} > "$1"
diff --git a/schiff/schiff-downloads.sh b/schiff/schiff-downloads.sh
@@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. "./config.sh.in"
-. "../meso-web.sh"
+. "../scripts/meso-web.sh"
set -e
diff --git a/convert_man.sh b/scripts/convert_man.sh
diff --git a/scripts/generate_header.sh b/scripts/generate_header.sh
@@ -0,0 +1,256 @@
+#!/bin/sh
+
+# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+set -e
+
+. "./scripts/meso-web.sh"
+
+########################################################################
+# Helper functions
+########################################################################
+# Print the absolute dir of the input file
+absdir() # file
+{
+ cd -- "$(dirname "$1")" && pwd
+ cd "${OLDPWD}"
+}
+
+# List the indexed content in TSV format. Each line contains the index
+# label, followed by the indexed content, and possibly an indicator of
+# the language used.
+#
+# The input data is the content of an index.tsv file, submitted on
+# standard input.
+indexed_content()
+(
+ strip_dummy | while read -r _line; do
+ _langs="$(echo "${_line}" | cut -d' ' -f3)"
+
+ if [ -z "${_langs}" ]; then
+ # There is no lang field defined: print the line as it
+ printf '%s\n' "${_line}"
+
+ else
+ # The lang field is defined. Duplicate the line as many times as
+ # there are languages listed. Define the content URI by replacing
+ # the @LANG@ string with the language value.
+ echo "${_langs}" \
+ | sed 's/:/\n/g' \
+ | while read -r _translation; do
+ echo "${_line}" \
+ | sed -e "s/\t[^\t]\{1,\}$/\t${_translation}/g" \
+ -e "s/@LANG@/${_translation}/g"
+ done
+ fi
+ done
+)
+
+# Print relative path from input file to worktree
+relpath_to_worktree() # file
+(
+ # Build directory from worktree to path
+ _dir="$(absdir "$1")"
+ _dir="$(printf '%s\n' "${_dir}" | sed "s;^${worktree}[/]\{0,\};;g")"
+
+ # Ensure that the directory if a subpath of the worktree
+ if ! [ -d "${_dir}" ]; then
+ return 1
+ fi
+
+ echo "${_dir}" | sed 's/\//\n/g' | while read -r _i; do
+ printf "../"
+ done
+)
+
+print_head()
+{
+ printf '<!DOCTYPE html>\n'
+ printf '<html lang="%s">\n' "${lang}"
+ printf '<head>\n'
+ printf ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n'
+ printf ' <meta name="viewport" content="width=device-width, initial-scale=1">\n'
+ printf ' <title>|M|S> %s</title>\n' "${label}"
+ printf ' <link rel="stylesheet" title="default" href="%smeso.css">\n' "${root}"
+ printf '</head>\n'
+ printf '<body>\n'
+}
+
+# Print top-level menu
+print_menu1()
+(
+ printf '<div id="menu">\n'
+
+ _separator=""
+ strip_dummy < "${worktree}/menu.tsv" | while read -r _i; do
+
+ # Retrieve the menu label and its associated directory
+ _label="$(echo "${_i}" | cut -d' ' -f1)"
+ _directory="$(echo "${_i}" | cut -d' ' -f2)"
+
+ echo "${_separator}" && _separator='  | '
+
+ if [ "${_directory}" = "${section}" ]; then
+ printf ' %s\n' "${_label}"
+
+ else
+ # Get the default page of the section, i.e., the first entry in
+ # its index. The menu is a link to it.
+ _uri="$(indexed_content < "${worktree}/${_directory}/index.tsv" \
+ | head -1 | cut -d' ' -f2)"
+
+ printf ' <a href="%s%s/%s">%s</a>\n' \
+ "${root}" "${_directory}" "${_uri}" "${_label}"
+ fi
+ done
+
+ printf '</div>\n<hr>\n'
+)
+
+# Print the list of translation choices
+# Available langs are submitted on standard input
+print_translations() # uri_template (i.e. URI generic to the lang)
+(
+ _uri_template="$1"
+
+ printf ' <span style="float: right;">\n'
+
+ _separator=""
+ while read -r _lang; do
+
+ _translation="$(echo "${_uri_template}" | sed "s/@LANG@/${_lang}/g")"
+
+ echo "${_separator}" && _separator='  / '
+
+ if [ "${content}" = "${_translation}" ]; then
+ printf ' <span class="cur">%s</span>\n' "${_lang}"
+ else
+ printf ' <a href="%s%s/%s">%s</a>\n' \
+ "${root}" "${section}" "${_translation}" "${_lang}"
+ fi
+ done
+
+ printf ' </span>\n'
+)
+
+# Print second-level menu
+print_menu2()
+(
+
+ printf '<div id="sub-menu">\n'
+
+ _separator=""
+ strip_dummy < "${worktree}/${section}/index.tsv" | while read -r _i; do
+
+ _label="$(echo "${_i}" | cut -d' ' -f1)"
+ _uri_template="$(echo "${_i}" | cut -d' ' -f2)"
+ _langs="$(echo "${_i}" | cut -d' ' -f3)"
+ _lang_default="$(echo "${_langs}" | cut -d ':' -f1)"
+
+ _uri="$(echo "${_uri_template}" | sed "s/@LANG@/${lang}/g")"
+
+ echo "${_separator}" && _separator='  . '
+
+ if [ "${_uri}" = "${content}" ]; then
+ # This is the current web page
+ printf ' <span class="cur">%s</span>\n' "${_label}"
+
+ # Print links to translations if available
+ if [ -n "${_langs}" ]; then
+ echo "${_langs}" \
+ | sed 's/:/\n/g' \
+ | print_translations "${_uri_template}"
+ fi
+
+ elif echo "${_uri}" | grep -qe "^http[s]\{0,1\}://"; then
+ # The entry links to an http[s] URL
+ printf ' <a href="%s">%s</a>\n' "${_uri}" "${_label}"
+
+ else
+ # The entry links to a local web page for the section
+ _uri="$(echo "${_uri_template}" | sed "s/@LANG@/${_lang_default}/g")"
+ printf ' <a href="%s%s/%s">%s</a>\n' \
+ "${root}" "${section}" "${_uri}" "${_label}"
+ fi
+ done
+
+ printf '</div>\n'
+)
+
+########################################################################
+# The script
+########################################################################
+if [ "$#" -lt 1 ]; then
+ >&2 printf 'usage: %s file\n' "${0##*/}"
+ exit 1
+fi
+
+# Define the absolute path of the working directory, i.e. the root
+# directory of the site, and enter it.
+worktree="$(absdir "${0%%/*}")"
+cd "${worktree}"
+
+# Define the section directory where the input file is located, i.e., the
+# subdirectory in the working directory.
+section="$(absdir "$1")"
+section="$(printf '%s\n' "${section}" | sed "s;^${worktree}[/]\{0,\};;g")"
+section="${section%%/*}"
+
+if [ -z "${section}" ]; then
+ >&2 printf \
+ '%s: unable to extract the section directory from file %s\n' \
+ "${0##*/}" "$1"
+ exit 1
+fi
+
+# Find the menu entry corresponding to the section directory
+entry="$(strip_dummy < "${worktree}/menu.tsv" \
+ | sed -n "/\t${section}/p")"
+
+if [ -z "${entry}" ]; then
+ >&2 printf \
+'%s: the %s directory of the %s file is not a valid menu entry '\
+'(see menu.tsv)\n' "${0##*/}" "${section}" "$1"
+ exit 1
+fi
+
+label="$(echo "${entry}" | cut -d' ' -f1)"
+
+if ! [ -e "${section}/index.tsv" ]; then
+ >&2 printf \
+ '%s: unable to find the index.tsv file in the directory %s\n' \
+ "${0##*/}" "${section}"
+ exit 1
+fi
+
+# Define whether the entry corresponds to a subsection index, i.e.,
+# whether it is the file to be displayed when entering the subsection.
+content="$(basename "$1")"
+subentry="$(indexed_content < "${worktree}/${section}/index.tsv" \
+ | sed -n "/\t${content}/p")"
+
+if [ -n "${subentry}" ]; then
+ lang="$(echo "${subentry}" | cut -d' ' -f3 | cut -d':' -f1)"
+fi
+
+lang="${lang:-en}"
+root="$(relpath_to_worktree "$1")"
+
+print_head
+print_menu1
+print_menu2
+
+printf '<div id="content">\n'
diff --git a/scripts/hooks.sh b/scripts/hooks.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "scripts/meso-web.sh"
+
+set -e
+
+
+# Print on standard output the Makefile targets used to automate hook
+# management
+
+shtml="$(sh ./scripts/list.sh shtml)"
+hook="$(sh ./scripts/list.sh hook)"
+
+sections | while read -r i; do
+ shtml_section="$(printf '%s\n' "${shtml}" \
+ | sed -n "/^${i}\//p" | tr '\n' ' ')"
+ hook_section="$(printf '%s\n' "${hook}" \
+ | sed -n "/^${i}\//p" | tr '\n' ' ' \
+ | sed -e 's/\.sh[[:space:]]/.hook /g')"
+
+ # Define Makefile target that makes section hooks prerequisites for
+ # the HTML content of the section.
+ #
+ # It is the files generated by each of the hooks that are
+ # prerequisites for the HTML files, not the scripts of the hooks
+ # themselves, because even if the scripts have not changed, their
+ # output may have been updated, which can impact the HTML content
+ # generated at build time.
+ printf '%s: %s\n' "${shtml_section}" "${hook_section}"
+done
+
+printf '%s\n' "${hook}" | while read -r i; do
+ # Divide the path into two parts:
+ # - the top-level directory, i.e. the section
+ # - the shell script to be executed from the section directory
+ section="${i%%/*}"
+ hook="${i##"${section}"/}"
+
+ # The hook is the first one in the current section: it has the highest
+ # priority and therefore has no prerequisites.
+ if [ "${section}" != "${prev_section}" ]; then
+ dep=""
+ fi
+
+ # Define a name for the hook used as a prefix for Makefile targets in
+ # order to automate its execution and the management of the file it
+ # generates. To ensure that this name is unique, and thus avoid
+ # conflicts between different hooks, it is constructed from the names
+ # of the section and file corresponding to the hook.
+ file="$(basename "${hook}")"
+ prefix="${section}-${file%%.*}"
+
+ # The hook name begins with 'xx-', meaning that it does not depend on
+ # any other hook in the section.
+ if echo "${file}" | grep -qe '^xx-.*'; then
+ dep=""
+ fi
+
+ # Set the file in which the names of the files generated by the hook
+ # are stored as resources for the website, i.e., the files that must
+ # be deployed with the website.
+ tgt="${i%%.*}.hook"
+
+ # Define the Makefile target that automate the hook executation. Its
+ # pre-requisites are the hook script and the output of the # previous
+ # hook in the section, i.e. with an higher priority. So that
+ # execution priority is ensured.
+ #
+ # Finally, make this target a prerequisite for building the website
+ # in order to enforce its execution during the build call.
+ printf '%s: %s %s\n' "${tgt}" "${i}" "${dep}"
+ printf " @( cd -- %s && \$(SHELL) %s ) > \$@\n" \
+ "${section}" "${hook}"
+
+ # Set the target for cleaning files generated by executing the hook.
+ # Run it on "distclean" and not on "clean", as their generation can be
+ # costly while effectively being files generated to "distribute" the
+ # website.
+ printf '%s-clean:\n' "${prefix}"
+ printf ' if [ -f %s ]; then cat %s | xargs rm -f; fi\n' \
+ "${tgt}" "${tgt}"
+ printf ' rm -f %s\n' "${tgt}"
+ printf 'distclean__: %s-clean\n' "${prefix}"
+
+ # Set the target that installs website resources generated by the hook
+ printf '%s-install: %s\n' "${prefix}" "${tgt}"
+ printf " @rsync --mkpath -avzrR --files-from=%s ./ \$(PREFIX)\n" \
+ "${tgt}"
+ printf 'install__: %s-install\n' "${prefix}"
+
+ # Ensure that the target of the hook is a prerequisite for the next
+ # hook in the section, so that the execution order follows their
+ # priority as defined by their file name.
+ dep="${tgt}"
+ prev_section="${section}"
+done
diff --git a/scripts/index.sh b/scripts/index.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "./scripts/meso-web.sh"
+
+set -e
+
+# Print to standard output the Makefile targets that make the section
+# index file a prerequisite for the section's HTML content.
+
+html="$(sh ./scripts/list.sh html)"
+
+sections | while read -r i; do
+ html_section="$(printf '%s\n' "${html}" \
+ | sed -n "/^${i}\//p" \
+ | tr '\n' ' ')"
+
+ printf '%s: %s/index.tsv\n' "${html_section}" "${i}"
+done
diff --git a/scripts/list.sh b/scripts/list.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+
+# Copyright (C) 2017-2025 |Méso|Star> (contact@meso-star.com)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "./scripts/meso-web.sh"
+
+set -e
+
+if [ "$#" -lt 1 ]; then
+ >&2 printf 'usage: %s <html|hook|shell|sig>\n' "${0##*/}"
+ exit 1
+fi
+
+########################################################################
+# Helper functions
+########################################################################
+# List of HTML files to generate from Markdown files or shell scripts
+# stored in each section
+html()
+{
+ _find_args="$(\
+ printf '%s\n' "${sections}" \
+ | sed -e 's/^/! -path /' \
+ | tr '\n' ' ')"
+
+ eval "exec find ${search_dirs} ${_find_args} -type d -prune -o \
+ \( \
+ -name \"*.md\" \
+ -o -name \"*.sh\" \
+ \) -exec sh -c 'printf \"%s.html\n\" \"\${1%.*}\"' -- {} \; \
+ | sort"
+}
+
+# List of shell scripts that dynamically generate HTML content
+shtml()
+{
+ _find_args="$(\
+ printf '%s\n' "${sections}" \
+ | sed -e 's/^/! -path /' \
+ | tr '\n' ' ')"
+
+ eval "exec find ${search_dirs} ${_find_args} -type d -prune -o \
+ -name \"*.sh\" -print \
+ | sort"
+}
+
+# List of hooks, i.e. shell scripts to be run by section
+hook()
+{
+ _find_args="$(\
+ printf '%s\n' "${sections}" \
+ | sed -e 's/^/-path "/;s/$/\/hooks\/*" -o/' \
+ | tr '\n' ' ' \
+ | sed 's/ -o $//')"
+
+ eval "find ${search_dirs} \
+ \( \( ${_find_args} \) -type f -name \"*.sh\" \) \
+ | sort"
+}
+
+# List the shell scripts relevant to the compilation system, i.e. the
+# shell script at the root of the working tree and those in each section
+# used to generate HTML pages.
+shell()
+{
+ _find_args="$(\
+ printf '%s\n' "${sections}" \
+ | sed -e 's/^\(.\{0,\}\)$/! -path \1 ! -path \1\/hooks/' \
+ | tr '\n' ' ')"
+
+ eval "exec find scripts ${search_dirs} \
+ ! -path scripts ${_find_args} -type d -prune -o -name \"*.sh\" -print \
+ | sort"
+}
+
+# List the relevent section subdirectories which are:
+# - downloads
+# - images
+# - thumbs
+subdir()
+{
+ downloads="-path \1/downloads"
+ images="-path \1/images -o -path \1/thumbs"
+
+ _find_args="$(\
+ printf '%s\n' "${sections}" \
+ | sed "s;^\(.\{0,\}\)$;${downloads} -o ${images} -o;" \
+ | tr '\n' ' ' \
+ | sed 's/ -o $//')"
+
+ eval "exec find ${search_dirs} ${_find_args} -type d | sort"
+}
+
+########################################################################
+# Script
+########################################################################
+# List of sections to be dealt with
+sections="$(sections)"
+search_dirs="$(printf '%s\n' "${sections}" | tr '\n' ' ')"
+
+"$@"
diff --git a/meso-web.sh b/scripts/meso-web.sh
diff --git a/solstice/hooks/01-generate-man.sh b/solstice/hooks/01-generate-man.sh
@@ -32,8 +32,8 @@ man2html() # output_filename
{
{
cd ..
- sh ./generate_header.sh "${OLDPWD##*/}/$1"
- sh ./convert_man.sh
+ sh ./scripts/generate_header.sh "${OLDPWD##*/}/$1"
+ sh ./scripts/convert_man.sh
cat ./footer.html
cd "${OLDPWD}"
} > "$1"
diff --git a/solstice/solstice-downloads.sh b/solstice/solstice-downloads.sh
@@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. "./config.sh.in"
-. "../meso-web.sh"
+. "../scripts/meso-web.sh"
set -e