2022-11-05 11:53:26 -04:00
#!/bin/bash
# Checks if provided file (filename to be provided as first argument) conforms to XEP-0001.
# See https://github.com/xsf/xeps/issues/1235
#
# Expected to be executed from the directory that holds all xep XML files.
# Requires one argument: the file name of the xep to be validated, eg:
#
# $ tools/validate-xep0001-conformance.sh xep-0010.xml
#
# exit status will be non-zero upon validation failure.
#
2022-11-06 04:40:02 -05:00
# requires: bash, xmllint, sort (supporting the '-V' argument)
2022-11-05 11:53:26 -04:00
2022-11-06 03:29:18 -05:00
set -euo pipefail
2022-11-05 11:53:26 -04:00
2022-11-06 03:45:33 -05:00
validation_result = 0
2022-11-05 11:53:26 -04:00
# 1. Check DTD conformance against xep.dtd
2022-11-06 03:45:33 -05:00
xep_dtd = "xep.dtd"
if xmllint --noout --dtdvalid " $xep_dtd " " $1 "
2022-11-05 11:53:26 -04:00
then
echo "[PASS] DTD conformance against xep.dtd"
else
echo "[FAIL] DTD conformance against xep.dtd"
2022-11-06 03:45:33 -05:00
validation_result = 1;
2022-11-05 11:53:26 -04:00
fi
2022-11-06 03:45:33 -05:00
file_name = $( basename -- " $1 " )
2022-11-06 14:08:15 -05:00
# The test for exit code equalling 10 detects when the XPATH evaluation yields no results. In that case, the execution
# should not fail immediately, but use an empty value instead (which will likely cause a validation failure further down).
header_number = $( xmllint --xpath '/xep/header/number/text()' --nowarning --dtdvalid " $xep_dtd " " $1 " ) || test $? = 10
header_status = $( xmllint --xpath '/xep/header/status/text()' --nowarning --dtdvalid " $xep_dtd " " $1 " ) || test $? = 10
header_type = $( xmllint --xpath '/xep/header/type/text()' --nowarning --dtdvalid " $xep_dtd " " $1 " ) || test $? = 10
header_approver = $( xmllint --xpath '/xep/header/approver/text()' --nowarning --dtdvalid " $xep_dtd " " $1 " ) || test $? = 10
header_revisions = $( xmllint --xpath '/xep/header/revision/version/text()' --nowarning --dtdvalid " $xep_dtd " " $1 " ) || test $? = 10
processing_instructions = $( xmllint --xpath '/processing-instruction("xml-stylesheet")' --nowarning --dtdvalid " $xep_dtd " " $1 " ) || test $? = 10
2022-11-05 11:53:26 -04:00
2022-11-06 03:45:33 -05:00
if echo " $file_name " | grep -Eq " ^xep-[0-9]{4}.xml $"
2022-11-05 11:53:26 -04:00
then
2022-11-06 03:45:33 -05:00
echo " [INFO] The filename (' $file_name ') matches 'xep-[0-9]{4}.xml'. "
2022-11-05 11:53:26 -04:00
# 2. If the filename matches xep-[0-9]{4}.xml, check:
# 2.1 that the number in the filename equals /xep/header/number (XPath)
2022-11-06 03:45:33 -05:00
if [ " $file_name " = " xep- $header_number .xml " ]
2022-11-05 11:53:26 -04:00
then
2022-11-06 03:45:33 -05:00
echo " [PASS] The number in the filename (' $file_name ') equals XPATH value /xep/header/number/text() (' $header_number '). "
2022-11-05 11:53:26 -04:00
else
2022-11-06 03:45:33 -05:00
echo " [FAIL] The number in the filename (' $file_name ') does not equals XPATH value /xep/header/number/text() (' $header_number ') (but should). "
2022-11-06 04:14:54 -05:00
validation_result = 1
2022-11-05 11:53:26 -04:00
fi
else
2022-11-06 03:45:33 -05:00
echo " [INFO] The filename (' $file_name ') does not match 'xep-[0-9]{4}.xml'. "
2022-11-05 11:53:26 -04:00
# 3. If the filename does not match xep-[0-9]{4}.xml, check:
# 3.1 That the /xep/header/status/text() (XPath) is ProtoXEP
2022-11-06 03:45:33 -05:00
if [ " $header_status " = "ProtoXEP" ]
2022-11-05 11:53:26 -04:00
then
2022-11-06 03:45:33 -05:00
echo " [PASS] XPATH value /xep/header/status/text() (' $header_status ') equals 'ProtoXEP'. "
2022-11-05 11:53:26 -04:00
else
2022-11-06 03:45:33 -05:00
echo " [FAIL] XPATH value /xep/header/status/text() (' $header_status ') does not equal 'ProtoXEP' (but should). "
2022-11-06 04:14:54 -05:00
validation_result = 1
2022-11-05 11:53:26 -04:00
fi
2022-12-20 13:31:09 -05:00
# 3.2 That the /xep/header/number/text() (XPath) is literally XXXX or xxxx
if [ " $header_number " = "XXXX" ] || [ " $header_number " = "xxxx" ]
2022-11-05 11:53:26 -04:00
then
2022-12-20 13:31:09 -05:00
echo " [PASS] XPATH value /xep/header/number/text() (' $header_status ') equals 'XXXX' (case insensitive). "
2022-11-05 11:53:26 -04:00
else
2022-11-06 05:11:13 -05:00
echo " [FAIL] XPATH value /xep/header/number/text() (' $header_status ') does not equal 'XXXX' (but should). "
2022-11-06 04:14:54 -05:00
validation_result = 1
2022-11-05 11:53:26 -04:00
fi
# 3.3 That the name does not start with xep-[0-9]
2022-11-06 03:45:33 -05:00
if echo " $file_name " | grep -Eq " ^xep-[0-9].* $"
2022-11-05 11:53:26 -04:00
then
2022-11-06 03:45:33 -05:00
echo " [FAIL] The filename (' $file_name ') starts with 'xep-[0-9]' (but should not). "
2022-11-06 04:14:54 -05:00
validation_result = 1
2022-11-05 11:53:26 -04:00
else
2022-11-06 03:45:33 -05:00
echo " [PASS] The filename (' $file_name ') does not start with 'xep-[0-9]'. "
2022-11-05 11:53:26 -04:00
fi
fi
# 4. Check that /xep/header/status/text() (XPath) is a defined status (see tools/xeplib.py for an enum)
2022-11-06 03:45:33 -05:00
case $header_status in
2022-11-05 11:53:26 -04:00
ProtoXEP | Experimental | Proposed | Draft | Active | Final | Retracted | Obsolete | Deferred | Rejected | Deprecated )
2022-11-06 03:45:33 -05:00
echo " [PASS] XPATH value /xep/header/status/text() (' $header_status ') equals a defined status. "
2022-11-05 11:53:26 -04:00
; ;
*)
2022-11-06 03:45:33 -05:00
echo " [FAIL] XPATH value /xep/header/status/text() (' $header_status ') does not equals a defined status (but should). "
2022-11-06 04:14:54 -05:00
validation_result = 1
2022-11-05 11:53:26 -04:00
; ;
esac
# 5. Check that /xep/header/type/text() (XPath) is defined in XEP-0001
# If the XEP number is less than 400, also accept some legacy values. To find which, see which you encounter in the XEP numbers below 400 :-).
2022-11-06 05:11:13 -05:00
# FIXME: lots of duplications here. Find a better solution.
case $file_name in
2022-11-06 14:31:58 -05:00
'xep-0001.xml' | 'xep-0002.xml' | 'xep-0019.xml' | 'xep-0053.xml' | 'xep-0143.xml' | 'xep-0182.xml' | 'xep-0345.xml' | 'xep-0381.xml' | 'xep-0429.xml' | 'xep-0458.xml' )
2022-11-06 05:11:13 -05:00
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' | 'Procedural' )
echo " [PASS] XPATH value /xep/header/type/text() (' $header_type ') equals a defined type. "
; ;
*)
echo " [FAIL] XPATH value /xep/header/type/text() (' $header_type ') does not equals a defined type (but should). "
validation_result = 1
; ;
esac
; ;
'xep-0006.xml' | 'xep-0010.xml' | 'xep-0069.xml' | 'xep-0139.xml' )
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' | 'SIG Formation' )
echo " [PASS] XPATH value /xep/header/type/text() (' $header_type ') equals a defined type. "
; ;
*)
echo " [FAIL] XPATH value /xep/header/type/text() (' $header_type ') does not equals a defined type (but should). "
validation_result = 1
; ;
esac
; ;
'xep-0007.xml' )
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' | 'SIG Proposal' )
echo " [PASS] XPATH value /xep/header/type/text() (' $header_type ') equals a defined type. "
; ;
*)
echo " [FAIL] XPATH value /xep/header/type/text() (' $header_type ') does not equals a defined type (but should). "
validation_result = 1
; ;
esac
; ;
* )
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' )
echo " [PASS] XPATH value /xep/header/type/text() (' $header_type ') equals a defined type. "
; ;
*)
echo " [FAIL] XPATH value /xep/header/type/text() (' $header_type ') does not equals a defined type (but should). "
validation_result = 1
; ;
esac
; ;
esac
2022-11-05 11:53:26 -04:00
# 6. Check that /xep/header/approver/text() (XPath) is either Board or Council
2022-11-06 03:45:33 -05:00
case $header_approver in
2022-11-05 11:53:26 -04:00
Board | Council )
2022-11-06 03:45:33 -05:00
echo " [PASS] XPATH value /xep/header/approver/text() (' $header_approver ') equals either 'Board' or 'Council'. "
2022-11-05 11:53:26 -04:00
; ;
*)
2022-11-06 03:45:33 -05:00
echo " [FAIL] XPATH value /xep/header/approver/text() (' $header_approver ') does not equals 'Board' or 'Council' (but should). "
2022-11-06 04:14:54 -05:00
validation_result = 1
2022-11-05 11:53:26 -04:00
; ;
esac
# 7. Check that the version numbers in the revision blocks are descending (from top to bottom in the document)
2022-11-06 04:40:02 -05:00
expected_revision_order = $( echo " $header_revisions " | tr " " "\n" | sort -Vr)
if [ " $expected_revision_order " = " $header_revisions " ]
then
echo "[PASS] Version numbers in the revision blocks are descending."
else
echo "[FAIL] Version numbers in the revision blocks are not ordered (descending from top to bottom in the document) (but should be)."
echo " Order found : $( echo $header_revisions ) " # funky $() nesting to remove newlines.
echo " Expected was: $( echo $expected_revision_order ) "
validation_result = 1
fi
2022-11-05 11:53:26 -04:00
# 8. If the approver (see above) is Board, enforce that /xep/header/type is not Standards Track.
2022-11-06 03:45:33 -05:00
if [ " $header_approver " = "Board" ]
2022-11-05 11:53:26 -04:00
then
2022-11-06 03:45:33 -05:00
if [ " $header_type " = "Standards Track" ]
2022-11-05 11:53:26 -04:00
then
2022-11-06 03:45:33 -05:00
echo " [FAIL] XPATH value /xep/header/approver/text() (' $header_approver ') is 'Board' but XPATH value /xep/header/type/text() is 'Standards Track' (it should not be). "
2022-11-06 04:14:54 -05:00
validation_result = 1
2022-11-05 11:53:26 -04:00
else
2022-11-06 03:45:33 -05:00
echo " [PASS] XPATH value /xep/header/approver/text() (' $header_approver ') is 'Board' and XPATH value /xep/header/type/text() is not 'Standards Track'. "
2022-11-05 11:53:26 -04:00
fi
fi
# 9. Check that it uses the xep.xsl XML stylesheet.
2022-11-06 04:14:54 -05:00
if echo " $processing_instructions " | grep -Eq "href=['\"]xep.xsl['\"]"
then
echo "[PASS] xep.xsl XML stylesheet is used."
else
echo "[FAIL] xep.xsl XML stylesheet is not used (but should be)."
validation_result = 1
fi
2022-11-05 11:53:26 -04:00
2022-11-06 13:20:34 -05:00
# 10. Check that it includes the correct legal notice (by checking for the entity reference)
if grep -q "&LEGALNOTICE;" " $1 "
then
echo "[PASS] entity reference for the legal notice has been detected."
else
echo "[FAIL] entity reference for the legal notice has not been detected (but it should have been)."
validation_result = 1
fi
2022-11-05 11:53:26 -04:00
echo ""
2022-11-06 03:45:33 -05:00
if [ $validation_result = 0 ]
2022-11-05 11:53:26 -04:00
then
2022-11-06 13:20:34 -05:00
echo "No issues found."
2022-11-05 11:53:26 -04:00
else
echo "Issues found!"
fi
2022-11-06 03:45:33 -05:00
exit $validation_result