Skip to content

Commit 63ca84c

Browse files
committed
Add markdown template processing to embed includes
1 parent 2784eef commit 63ca84c

File tree

3 files changed

+162
-6
lines changed

3 files changed

+162
-6
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env bash
2+
3+
# Processes a template_markdown_file markdown file, replacing placeholders like "<!-- include:intro.md -->" with the contents of the specified markdown files. The files to include needs to be in the "includes" subdirectory.
4+
5+
# Fail on any error ("-e" = exit on first error, "-o pipefail" exist on errors within piped commands)
6+
set -o errexit -o pipefail
7+
8+
## Get this "scripts" directory if not already set
9+
# Even if $BASH_SOURCE is made for Bourne-like shells it is also supported by others and therefore here the preferred solution.
10+
# CDPATH reduces the scope of the cd command to potentially prevent unintended directory changes.
11+
# This way non-standard tools like readlink aren't needed.
12+
MARKDOWN_SCRIPTS_DIR=${MARKDOWN_SCRIPTS_DIR:-$( CDPATH=. cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P )} # Repository directory containing the shell scripts
13+
#echo "embedMarkdownIncludes: MARKDOWN_SCRIPTS_DIR=${MARKDOWN_SCRIPTS_DIR}" >&2
14+
15+
template_markdown_file="$1"
16+
include_directory="includes"
17+
18+
awk -v include_directory="${include_directory}" '
19+
# Check if the filename is safe
20+
function is_safe(path) {
21+
if (substr(path, 1, 1) == "/") return 0
22+
if (path ~ /\.\./) return 0
23+
return 1
24+
}
25+
26+
function include_file(path, fullpath, line) {
27+
fullpath = include_directory "/" path
28+
29+
if (!is_safe(path)) {
30+
print "ERROR: illegal include path: " path > "/dev/stderr"
31+
exit 1
32+
}
33+
34+
if ((getline test < fullpath) < 0) {
35+
print "ERROR: missing file " fullpath > "/dev/stderr"
36+
exit 1
37+
}
38+
close(fullpath)
39+
40+
while ((getline line < fullpath) > 0) {
41+
print line
42+
}
43+
close(fullpath)
44+
}
45+
46+
{
47+
# Look for the include marker using index+substr (portable)
48+
if ($0 ~ /<!-- include:/) {
49+
start = index($0, "include:") + 8
50+
end = index($0, "-->")
51+
fname = substr($0, start, end - start)
52+
gsub(/^[ \t]+|[ \t]+$/, "", fname) # trim spaces
53+
54+
include_file(fname)
55+
} else {
56+
print
57+
}
58+
}
59+
' "${template_markdown_file}"
60+
61+
#echo "embedMarkdownIncludes: $(date +'%Y-%m-%dT%H:%M:%S%z') Successfully finished." >&2
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#!/usr/bin/env bash
2+
3+
# Tests template processing for markdown by embedding includes.
4+
5+
# Requires embedMarkdownIncludes.sh
6+
7+
# Fail on any error ("-e" = exit on first error, "-o pipefail" exist on errors within piped commands)
8+
set -o errexit -o pipefail
9+
10+
## Get this "scripts" directory if not already set
11+
# Even if $BASH_SOURCE is made for Bourne-like shells it is also supported by others and therefore here the preferred solution.
12+
# CDPATH reduces the scope of the cd command to potentially prevent unintended directory changes.
13+
# This way non-standard tools like readlink aren't needed.
14+
SCRIPTS_DIR=${SCRIPTS_DIR:-$( CDPATH=. cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P )} # Repository directory containing the shell scripts
15+
echo "testEmbedMarkdownIncludes: SCRIPTS_DIR=${SCRIPTS_DIR}" >&2
16+
17+
tearDown() {
18+
# echo "testEmbedMarkdownIncludes: Tear down tests...."
19+
rm -rf "${temporaryTestDirectory}"
20+
}
21+
22+
successful() {
23+
local COLOR_SUCCESSFUL="\033[0;32m" # green
24+
local COLOR_DEFAULT='\033[0m'
25+
26+
echo -e "testEmbedMarkdownIncludes: ${COLOR_SUCCESSFUL}Tests finished successfully.${COLOR_DEFAULT}"
27+
28+
tearDown
29+
exit 0
30+
}
31+
32+
fail() {
33+
local COLOR_ERROR='\033[0;31m' # red
34+
local COLOR_DEFAULT='\033[0m'
35+
36+
local errorMessage="${1}"
37+
38+
echo -e "testEmbedMarkdownIncludes: ${COLOR_ERROR}${errorMessage}${COLOR_DEFAULT}"
39+
tearDown
40+
exit 1
41+
}
42+
43+
echo "testEmbedMarkdownIncludes: Starting tests...."
44+
45+
# Create testing resources
46+
temporaryTestDirectory=$(mktemp -d 2>/dev/null || mktemp -d -t 'temporaryTestDirectory')
47+
48+
testMarkdownTemplate="${temporaryTestDirectory}/testMarkdownTemplate.md"
49+
echo "<!-- include:testInclude.md -->" > "${testMarkdownTemplate}"
50+
51+
# Setup test files
52+
mkdir -p "${temporaryTestDirectory}/includes"
53+
54+
# ------------------------------------------------------------
55+
# Test case --
56+
# ------------------------------------------------------------
57+
echo "testEmbedMarkdownIncludes: 1.) An existing include file is correctly embedded."
58+
59+
# - Setup
60+
testIncludeFile="includes/testInclude.md"
61+
expected_test_include_content="This is the included content for the test."
62+
echo "${expected_test_include_content}" > "${temporaryTestDirectory}/${testIncludeFile}"
63+
64+
# - Execute script under test
65+
embeddedContent=$(cd "${temporaryTestDirectory}"; "${SCRIPTS_DIR}/embedMarkdownIncludes.sh" "${testMarkdownTemplate}" )
66+
67+
# - Verify results
68+
if [ "${embeddedContent}" != "${expected_test_include_content}" ]; then
69+
fail "1.) Test failed: Expected embedded content to be '${expected_test_include_content}', but got '${embeddedContent}'."
70+
fi
71+
72+
# ------------------------------------------------------------
73+
# Test case --
74+
# ------------------------------------------------------------
75+
echo "testEmbedMarkdownIncludes: 2.) A missing include file results in an error."
76+
77+
# - Setup
78+
testMarkdownTemplateMissingInclude="testMarkdownTemplateMissingInclude.md"
79+
echo "<!-- include:nonExistentFile.md -->" > "${temporaryTestDirectory}/${testMarkdownTemplateMissingInclude}"
80+
81+
# - Execute script under test
82+
set +o errexit
83+
errorOutput=$(cd "${temporaryTestDirectory}"; { "${SCRIPTS_DIR}/embedMarkdownIncludes.sh" "${testMarkdownTemplateMissingInclude}" 2>&1 1>/dev/null; } )
84+
exitCode=$?
85+
set -o errexit
86+
87+
# - Verify results
88+
if [ ${exitCode} -eq 0 ]; then
89+
fail "2.) Test failed: Expected an error due to missing include file, but the script succeeded."
90+
fi
91+
if [[ "${errorOutput}" != *"ERROR: missing file"* ]]; then
92+
fail "2.) Test failed: Expected error message to contain 'ERROR: missing file', but got '${errorOutput}'."
93+
fi
94+
95+
successful

scripts/runTests.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ SCRIPTS_DIR=${SCRIPTS_DIR:-$( CDPATH=. cd -- "$(dirname -- "${BASH_SOURCE[0]}")"
1818
echo "runTests: SCRIPTS_DIR=${SCRIPTS_DIR}" >&2
1919

2020
# Run all report scripts
21-
for test_script_file in "${SCRIPTS_DIR}"/test*.sh; do
22-
test_script_filename=$(basename -- "${test_script_file}");
21+
find "${SCRIPTS_DIR}" -type f -name 'test*.sh' | while read -r test_script_file; do
22+
test_script_filename=$(basename -- "${test_script_file}")
2323
test_script_filename="${test_script_filename%.*}" # Remove file extension
2424

25-
echo "${LOG_GROUP_START}Run ${test_script_filename}";
26-
echo "runTests: $(date +'%Y-%m-%dT%H:%M:%S%z') Starting ${test_script_filename}...";
25+
echo "${LOG_GROUP_START}Run ${test_script_filename}"
26+
echo "runTests: $(date +'%Y-%m-%dT%H:%M:%S%z') Starting ${test_script_filename}..."
2727

2828
source "${test_script_file}"
2929

30-
echo "runTests: $(date +'%Y-%m-%dT%H:%M:%S%z') Finished ${test_script_filename}";
31-
echo "${LOG_GROUP_END}";
30+
echo "runTests: $(date +'%Y-%m-%dT%H:%M:%S%z') Finished ${test_script_filename}"
31+
echo "${LOG_GROUP_END}"
3232
done

0 commit comments

Comments
 (0)