mk/subst.mk: allow identity substitutions in SUBST_NOOP_OK=no mode There are several cases where patterns like s|man|${PKGMANDIR}| appear in SUBST_SED. Up to now, these had been categorized as no-ops and required extra code to make the package build when SUBST_NOOP_OK was set to "no". This was against the original intention of SUBST_NOOP_OK, which was to find outdated substitution patterns that do not occur in SUBST_FILES anymore, most often because the packages have been updated since. The identity substitutions do appear in the files, they just don't change them. Typical cases are for PKGMANDIR, DEVOSSAUDIO, PREFIX, and these variables may well be different in another pkgsrc setup. These patterns are therefore excluded from the SUBST_NOOP_OK check.diff -r1.84 -r1.85 pkgsrc/mk/subst.mk
(rillig)
@@ -1,39 +1,51 @@ | @@ -1,39 +1,51 @@ | |||
1 | # $NetBSD: subst.mk,v 1.84 2020/04/23 19:32:53 rillig Exp $ | 1 | # $NetBSD: subst.mk,v 1.85 2020/04/29 18:33:56 rillig Exp $ | |
2 | # | 2 | # | |
3 | # The subst framework replaces text in one or more files in the WRKSRC | 3 | # The subst framework replaces text in one or more files in the WRKSRC | |
4 | # directory. Packages can define several ``classes'' of replacements. | 4 | # directory. Packages can define several ``classes'' of replacements. | |
5 | # Each such class defines: | 5 | # Each such class defines: | |
6 | # | 6 | # | |
7 | # - in which stage of the build process the replacement happens | 7 | # - in which stage of the build process the replacement happens | |
8 | # - which files are affected by the replacement | 8 | # - which files are affected by the replacement | |
9 | # - which text or pattern is replaced by which replacement text | 9 | # - which text or pattern is replaced by which replacement text | |
10 | # | 10 | # | |
11 | # A typical example is: | 11 | # A typical example is: | |
12 | # | 12 | # | |
13 | # SUBST_CLASSES+= prefix | 13 | # SUBST_CLASSES+= prefix | |
14 | # SUBST_STAGE.prefix= pre-configure | 14 | # SUBST_STAGE.prefix= pre-configure | |
15 | # SUBST_FILES.prefix= ./configure doc/*.html | 15 | # SUBST_FILES.prefix= ./configure doc/*.html | |
16 | # SUBST_SED.prefix= -e 's,/usr/local,${PREFIX},g' | 16 | # SUBST_SED.prefix= -e 's,/usr/local,${PREFIX},g' | |
17 | # | 17 | # | |
18 | # User-settable variables: | 18 | # User-settable variables: | |
19 | # | 19 | # | |
20 | # SUBST_SHOW_DIFF | 20 | # SUBST_SHOW_DIFF | |
21 | # Whether to log each changed file as a unified diff, for all | 21 | # Whether to log each changed file as a unified diff, for all | |
22 | # SUBST classes. Defaults to "no". | 22 | # SUBST classes. Defaults to "no". | |
23 | # | 23 | # | |
24 | # SUBST_NOOP_OK | 24 | # SUBST_NOOP_OK | |
25 | # Whether it is ok to have filename patterns in SUBST_FILES that | 25 | # Whether it is ok to list files in SUBST_FILES that don't contain | |
26 | # don't have any effect. | 26 | # any of the patterns from SUBST_SED or SUBST_VARS. Such a | |
27 | # situation often arises when a package is updated to a newer | |||
28 | # version, and the build instructions of the package have been | |||
29 | # made more portable or flexible. | |||
30 | # | |||
31 | # This setting only affects the filename patterns in SUBST_FILES. | |||
32 | # It does not (yet) affect the regular expressions in SUBST_SED. | |||
33 | # | |||
34 | # From the viewpoint of sed(1), a pattern like s|man|man| may look | |||
35 | # redundant but it really isn't, because the second "man" probably | |||
36 | # comes from ${PKGMANDIR}, which may be configured to a different | |||
37 | # directory. Patterns like these are therefore allowed, even if | |||
38 | # they are no-ops in the current configuration. | |||
27 | # | 39 | # | |
28 | # For backwards compatibility this defaults to "yes", but it | 40 | # For backwards compatibility this defaults to "yes", but it | |
29 | # should rather be set to "no". | 41 | # should rather be set to "no". | |
30 | # | 42 | # | |
31 | # Package-settable variables: | 43 | # Package-settable variables: | |
32 | # | 44 | # | |
33 | # SUBST_CLASSES | 45 | # SUBST_CLASSES | |
34 | # A list of class names. When adding new classes to this list, be | 46 | # A list of class names. When adding new classes to this list, be | |
35 | # sure to append them (+=) instead of overriding them (=). | 47 | # sure to append them (+=) instead of overriding them (=). | |
36 | # | 48 | # | |
37 | # SUBST_STAGE.<class> | 49 | # SUBST_STAGE.<class> | |
38 | # "stage" at which we do the text replacement. Should be one of | 50 | # "stage" at which we do the text replacement. Should be one of | |
39 | # {pre,do,post}-{extract,configure,build,install}. | 51 | # {pre,do,post}-{extract,configure,build,install}. | |
@@ -84,27 +96,27 @@ | @@ -84,27 +96,27 @@ | |||
84 | # Whether to fail when a SUBST_FILES pattern has no effect. | 96 | # Whether to fail when a SUBST_FILES pattern has no effect. | |
85 | # In most cases, "yes" is appropriate, to catch typos and outdated | 97 | # In most cases, "yes" is appropriate, to catch typos and outdated | |
86 | # definitions. | 98 | # definitions. | |
87 | # | 99 | # | |
88 | # Default: no (up to 2019Q4), yes (starting with 2020Q1) | 100 | # Default: no (up to 2019Q4), yes (starting with 2020Q1) | |
89 | # | 101 | # | |
90 | # See also: | 102 | # See also: | |
91 | # PLIST_SUBST | 103 | # PLIST_SUBST | |
92 | # | 104 | # | |
93 | # Keywords: subst | 105 | # Keywords: subst | |
94 | # | 106 | # | |
95 | 107 | |||
96 | SUBST_SHOW_DIFF?= no | 108 | SUBST_SHOW_DIFF?= no | |
97 | SUBST_NOOP_OK?= yes # only for backwards compatiblity | 109 | SUBST_NOOP_OK?= yes # only for backwards compatibility | |
98 | 110 | |||
99 | _VARGROUPS+= subst | 111 | _VARGROUPS+= subst | |
100 | _USER_VARS.subst= SUBST_SHOW_DIFF SUBST_NOOP_OK | 112 | _USER_VARS.subst= SUBST_SHOW_DIFF SUBST_NOOP_OK | |
101 | _PKG_VARS.subst= SUBST_CLASSES | 113 | _PKG_VARS.subst= SUBST_CLASSES | |
102 | .for c in ${SUBST_CLASSES} | 114 | .for c in ${SUBST_CLASSES} | |
103 | . for pv in SUBST_STAGE SUBST_MESSAGE SUBST_FILES SUBST_SED SUBST_VARS \ | 115 | . for pv in SUBST_STAGE SUBST_MESSAGE SUBST_FILES SUBST_SED SUBST_VARS \ | |
104 | SUBST_FILTER_CMD SUBST_SKIP_TEXT_CHECK SUBST_NOOP_OK | 116 | SUBST_FILTER_CMD SUBST_SKIP_TEXT_CHECK SUBST_NOOP_OK | |
105 | _PKG_VARS.subst+= ${pv}.${c} | 117 | _PKG_VARS.subst+= ${pv}.${c} | |
106 | . endfor | 118 | . endfor | |
107 | .endfor | 119 | .endfor | |
108 | _DEF_VARS.subst= ECHO_SUBST_MSG | 120 | _DEF_VARS.subst= ECHO_SUBST_MSG | |
109 | _USE_VARS.subst= WRKDIR WRKSRC | 121 | _USE_VARS.subst= WRKDIR WRKSRC | |
110 | _IGN_VARS.subst= _SUBST_IS_TEXT_FILE_CMD | 122 | _IGN_VARS.subst= _SUBST_IS_TEXT_FILE_CMD | |
@@ -173,37 +185,44 @@ ${_SUBST_COOKIE.${class}}: | @@ -173,37 +185,44 @@ ${_SUBST_COOKIE.${class}}: | |||
173 | case $$file in ([!A-Za-z0-9/]*) file="./$$file";; esac; \ | 185 | case $$file in ([!A-Za-z0-9/]*) file="./$$file";; esac; \ | |
174 | tmpfile="$$file.subst.sav"; \ | 186 | tmpfile="$$file.subst.sav"; \ | |
175 | [ -d "$$file" ] && continue; \ | 187 | [ -d "$$file" ] && continue; \ | |
176 | [ -f "$$file" ] || { \ | 188 | [ -f "$$file" ] || { \ | |
177 | ${_SUBST_WARN.${class}} "Ignoring non-existent file \"$$file\"."; \ | 189 | ${_SUBST_WARN.${class}} "Ignoring non-existent file \"$$file\"."; \ | |
178 | continue; \ | 190 | continue; \ | |
179 | }; \ | 191 | }; \ | |
180 | ${_SUBST_IS_TEXT_FILE_CMD.${class}} || { \ | 192 | ${_SUBST_IS_TEXT_FILE_CMD.${class}} || { \ | |
181 | ${_SUBST_WARN.${class}} "Ignoring non-text file \"$$file\"."; \ | 193 | ${_SUBST_WARN.${class}} "Ignoring non-text file \"$$file\"."; \ | |
182 | continue; \ | 194 | continue; \ | |
183 | }; \ | 195 | }; \ | |
184 | ${SUBST_FILTER_CMD.${class}} < "$$file" > "$$tmpfile"; \ | 196 | ${SUBST_FILTER_CMD.${class}} < "$$file" > "$$tmpfile"; \ | |
185 | ${CMP} -s "$$tmpfile" "$$file" && { \ | 197 | ${CMP} -s "$$tmpfile" "$$file" && { \ | |
198 | [ ${"${SUBST_FILTER_CMD.${class}}" == "LC_ALL=C ${SED} ${SUBST_SED.${class}}":?true:false} ] \ | |||
199 | && ${AWK} -f ${PKGSRCDIR}/mk/scripts/subst-identity.awk -- ${SUBST_SED.${class}} \ | |||
200 | && found=`LC_ALL=C ${SED} -n ${SUBST_SED.${class}:C,^['"]?s.*,&p,} "$$file"` \ | |||
201 | && [ "x$$found" != "x" ] && { \ | |||
202 | changed=yes; \ | |||
203 | continue; \ | |||
204 | }; \ | |||
186 | ${_SUBST_WARN.${class}} "Nothing changed in \"$$file\"."; \ | 205 | ${_SUBST_WARN.${class}} "Nothing changed in \"$$file\"."; \ | |
187 | ${RM} -f "$$tmpfile"; \ | 206 | ${RM} -f "$$tmpfile"; \ | |
188 | continue; \ | 207 | continue; \ | |
189 | }; \ | 208 | }; \ | |
190 | [ -x "$$file" ] && ${CHMOD} +x "$$tmpfile"; \ | 209 | [ -x "$$file" ] && ${CHMOD} +x "$$tmpfile"; \ | |
191 | changed=yes; \ | 210 | changed=yes; \ | |
192 | ${_SUBST_KEEP.${class}}; \ | 211 | ${_SUBST_KEEP.${class}}; \ | |
193 | ${MV} -f "$$tmpfile" "$$file"; \ | 212 | ${MV} -f "$$tmpfile" "$$file"; \ | |
194 | ${ECHO} "$$file" >> ${.TARGET}.tmp; \ | 213 | ${ECHO} "$$file" >> ${.TARGET}.tmp; \ | |
195 | done; \ | 214 | done; \ | |
196 | \ | 215 | \ | |
197 | [ "$$changed,${SUBST_NOOP_OK.${class}:tl}" = no,no ] && { \ | 216 | [ "$$changed,${SUBST_NOOP_OK.${class}:tl}" = no,no ] && { \ | |
198 | noop_count="$$noop_count+"; \ | 217 | noop_count="$$noop_count+"; \ | |
199 | noop_patterns="$$noop_patterns$$noop_sep$$pattern"; \ | 218 | noop_patterns="$$noop_patterns$$noop_sep$$pattern"; \ | |
200 | noop_sep=" "; \ | 219 | noop_sep=" "; \ | |
201 | }; \ | 220 | }; \ | |
202 | done; \ | 221 | done; \ | |
203 | \ | 222 | \ | |
204 | case $$noop_count in \ | 223 | case $$noop_count in \ | |
205 | ('') ;; \ | 224 | ('') ;; \ | |
206 | (+) ${FAIL_MSG} "[subst.mk:${class}] The filename pattern \"$$noop_patterns\" has no effect.";; \ | 225 | (+) ${FAIL_MSG} "[subst.mk:${class}] The filename pattern \"$$noop_patterns\" has no effect.";; \ | |
207 | (*) ${FAIL_MSG} "[subst.mk:${class}] The filename patterns \"$$noop_patterns\" have no effect."; \ | 226 | (*) ${FAIL_MSG} "[subst.mk:${class}] The filename patterns \"$$noop_patterns\" have no effect."; \ | |
208 | esac; \ | 227 | esac; \ | |
209 | ${TOUCH} ${TOUCH_FLAGS} ${.TARGET}.tmp; \ | 228 | ${TOUCH} ${TOUCH_FLAGS} ${.TARGET}.tmp; \ |
#! /usr/bin/awk -f
# $NetBSD: subst-identity.awk,v 1.1 2020/04/29 18:33:57 rillig Exp $
#
# Tests whether a sed(1) command line consists of only identity substitutions
# like s,id,id,.
#
# See SUBST_NOOP_OK and regress/infra-unittests/subst.sh.
#
function is_safe_char(ch) {
return ch ~ /[\t -~]/ && ch !~ /[$&*.\[\\\]^]/;
}
function is_identity_subst(s, len, i, sep, pat) {
len = length(s);
if (len < 6 || substr(s, 1, 1) != "s")
return 0;
sep = substr(s, 2, 1);
i = 3;
while (i < len && substr(s, i, 1) != sep && is_safe_char(substr(s, i, 1)))
i++;
pat = substr(s, 3, i - 3);
return (s == "s" sep pat sep pat sep ||
s == "s" sep pat sep pat sep "g");
}
function main( i) {
for (i = 1; i + 1 < ARGC; i += 2)
if (ARGV[i] != "-e" || !is_identity_subst(ARGV[i + 1]))
return 0;
return i == ARGC && ARGC > 1;
}
BEGIN {
exit(main() ? 0 : 1);
}
@@ -1,29 +1,30 @@ | @@ -1,29 +1,30 @@ | |||
1 | #! /bin/sh | 1 | #! /bin/sh | |
2 | # $NetBSD: subst.sh,v 1.25 2020/04/26 12:46:33 rillig Exp $ | 2 | # $NetBSD: subst.sh,v 1.26 2020/04/29 18:33:56 rillig Exp $ | |
3 | # | 3 | # | |
4 | # Tests for mk/subst.mk. | 4 | # Tests for mk/subst.mk. | |
5 | # | 5 | # | |
6 | 6 | |||
7 | set -eu | 7 | set -eu | |
8 | 8 | |||
9 | . "./test.subr" | 9 | . "./test.subr" | |
10 | 10 | |||
11 | test_case_set_up() { | 11 | test_case_set_up() { | |
12 | rm -rf "$tmpdir"/.??* "$tmpdir"/* | 12 | rm -rf "$tmpdir"/.??* "$tmpdir"/* | |
13 | 13 | |||
14 | create_file "prepare-subst.mk" <<EOF | 14 | create_file "prepare-subst.mk" <<EOF | |
15 | 15 | |||
16 | # The tools that are used by subst.mk | 16 | # The tools that are used by subst.mk | |
17 | AWK= awk | |||
17 | CHMOD= chmod | 18 | CHMOD= chmod | |
18 | CMP= cmp | 19 | CMP= cmp | |
19 | DIFF= diff | 20 | DIFF= diff | |
20 | ECHO= echo | 21 | ECHO= echo | |
21 | MKDIR= mkdir -p | 22 | MKDIR= mkdir -p | |
22 | MV= mv | 23 | MV= mv | |
23 | RM= rm | 24 | RM= rm | |
24 | RMDIR= rmdir | 25 | RMDIR= rmdir | |
25 | SED= sed | 26 | SED= sed | |
26 | TEST= test | 27 | TEST= test | |
27 | TOUCH= touch | 28 | TOUCH= touch | |
28 | TOUCH_FLAGS= # none | 29 | TOUCH_FLAGS= # none | |
29 | TR= tr | 30 | TR= tr | |
@@ -1121,13 +1122,210 @@ if test_case_begin "unreadable file"; th | @@ -1121,13 +1122,210 @@ if test_case_begin "unreadable file"; th | |||
1121 | && exitcode=0 || exitcode=$? | 1122 | && exitcode=0 || exitcode=$? | |
1122 | 1123 | |||
1123 | assert_that "out" --file-is-lines \ | 1124 | assert_that "out" --file-is-lines \ | |
1124 | '=> Substituting "id" in unreadable-file' \ | 1125 | '=> Substituting "id" in unreadable-file' \ | |
1125 | 'sh: cannot open unreadable-file: permission denied' \ | 1126 | 'sh: cannot open unreadable-file: permission denied' \ | |
1126 | 'sh: cannot open unreadable-file: permission denied' \ | 1127 | 'sh: cannot open unreadable-file: permission denied' \ | |
1127 | '*** Error code 1' \ | 1128 | '*** Error code 1' \ | |
1128 | '' \ | 1129 | '' \ | |
1129 | 'Stop.' \ | 1130 | 'Stop.' \ | |
1130 | "$make: stopped in $PWD" | 1131 | "$make: stopped in $PWD" | |
1131 | 1132 | |||
1132 | test_case_end | 1133 | test_case_end | |
1133 | fi | 1134 | fi | |
1135 | ||||
1136 | ||||
1137 | if test_case_begin "identity substitution implementation"; then | |||
1138 | ||||
1139 | assert_identity() { | |||
1140 | ai_expected="$1"; shift | |||
1141 | awk -f "$pkgsrcdir/mk/scripts/subst-identity.awk" -- "$@" \ | |||
1142 | && ai_actual="yes" || ai_actual="no" | |||
1143 | ||||
1144 | [ "$ai_actual" = "$ai_expected" ] \ | |||
1145 | || assert_fail "expected '%s', got '%s' for %s\n" "$ai_expected" "$ai_actual" "$*" | |||
1146 | } | |||
1147 | ||||
1148 | # If there is no SUBST_SED at all, this is not the situation | |||
1149 | # that is targeted by this test for identity substitution. | |||
1150 | assert_identity "no" # no substitutions at all | |||
1151 | ||||
1152 | # Even though this is an identity substitution, it is missing | |||
1153 | # the -e option and thus does not follow the usual format. | |||
1154 | # Therefore it is considered just a normal substitution. | |||
1155 | assert_identity "no" 's,from,from,' | |||
1156 | ||||
1157 | # The following are typical identity substitutions. | |||
1158 | # It does not matter whether the g modifier is there or not. | |||
1159 | # Unknown modifiers are not allowed though. | |||
1160 | assert_identity "yes" -e 's,from,from,' | |||
1161 | assert_identity "yes" -e 's;from;from;' | |||
1162 | assert_identity "yes" -e 's,from,from,g' | |||
1163 | assert_identity "no" -e 's,from,from,gunknown' | |||
1164 | ||||
1165 | # The identity substitution may include characters other than | |||
1166 | # A-Za-z0-9, but no characters that have a special meaning in | |||
1167 | # basic regular expressions. | |||
1168 | assert_identity "yes" -e 's,/dev/audio,/dev/audio,' | |||
1169 | assert_identity "yes" -e 's!/dev/audio!/dev/audio!' | |||
1170 | ||||
1171 | # There may be several identity substitutions in the same | |||
1172 | # SUBST_SED. As long as all these substitutions are identity | |||
1173 | # substitutions, they may be skipped. As soon as there is one | |||
1174 | # other substitution, the whole SUBST_SED is treated as usual. | |||
1175 | assert_identity "yes" -e 's;from;from;' -e 's!second!second!' | |||
1176 | assert_identity "no" -e 's,changing,x,' -e 's,id,id,' | |||
1177 | assert_identity "no" -e 's,id,id,' -e 's,changing,x,' | |||
1178 | ||||
1179 | # A demonstration of all ASCII characters that may appear in an | |||
1180 | # identity substitution. | |||
1181 | # | |||
1182 | # The # and $ are excluded since they are interpreted specially | |||
1183 | # in Makefiles and would thus be confusing to the human reader. | |||
1184 | # | |||
1185 | # The characters *.?[\]^ have a special meaning in the pattern of the | |||
1186 | # substitution. | |||
1187 | # The & has a special meaning in the replacement of the | |||
1188 | # substitution. | |||
1189 | specials='!"%'\''()+,-/:;<=>@_`{|}~' | |||
1190 | assert_identity "yes" -e "sX${specials}X${specials}X" | |||
1191 | ||||
1192 | test_case_end | |||
1193 | fi | |||
1194 | ||||
1195 | ||||
1196 | if test_case_begin "identity substitution, found in file"; then | |||
1197 | ||||
1198 | # There are many situations in which a fixed text is replaced | |||
1199 | # with a dynamic value that may or may not be equal to the | |||
1200 | # original text. | |||
1201 | # | |||
1202 | # Typical examples are s|man|${PKGMANDIR}|, s|/usr/pkg|${PREFIX}|, | |||
1203 | # s|/dev/audio|${DEVOSSAUDIO}|. | |||
1204 | # | |||
1205 | # It is not an error if these substitutions result in a no-op, | |||
1206 | # provided that the text is actually found in the file. | |||
1207 | # | |||
1208 | # Alternatives for this special exception would be: | |||
1209 | # | |||
1210 | # 1. Mark these blocks as SUBST_NOOP_OK. This would not detect | |||
1211 | # outdated definitions. Since this detection is the main goal | |||
1212 | # of SUBST_NOOP_OK, this is out of the question. | |||
1213 | # | |||
1214 | # 2. Surround these blocks with a condition like ".if ${VAR} != | |||
1215 | # fixed-value ... .endif". This pattern only works if VAR is | |||
1216 | # definitely assigned, which often requires a corresponding | |||
1217 | # .include line, leading to code bloat. It would also mean that | |||
1218 | # variables defined in bsd.pkg.mk could not be used in SUBST | |||
1219 | # blocks like these. | |||
1220 | ||||
1221 | create_file_lines "testcase.mk" \ | |||
1222 | 'SUBST_CLASSES+= id' \ | |||
1223 | 'SUBST_FILES.id= file' \ | |||
1224 | 'SUBST_SED.id= -e s,before,before,' \ | |||
1225 | 'SUBST_NOOP_OK.id= no' \ | |||
1226 | '' \ | |||
1227 | '.include "prepare-subst.mk"' \ | |||
1228 | '.include "mk/subst.mk"' | |||
1229 | create_file_lines "file" \ | |||
1230 | 'before' | |||
1231 | ||||
1232 | run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \ | |||
1233 | && exitcode=0 || exitcode=$? | |||
1234 | ||||
1235 | assert_that "out" --file-is-lines \ | |||
1236 | '=> Substituting "id" in file' | |||
1237 | ||||
1238 | test_case_end | |||
1239 | fi | |||
1240 | ||||
1241 | ||||
1242 | if test_case_begin "identity substitution, not found in file"; then | |||
1243 | ||||
1244 | create_file_lines "testcase.mk" \ | |||
1245 | 'SUBST_CLASSES+= id' \ | |||
1246 | 'SUBST_FILES.id= file' \ | |||
1247 | 'SUBST_SED.id= s,before,before,' \ | |||
1248 | 'SUBST_NOOP_OK.id= no' \ | |||
1249 | '' \ | |||
1250 | '.include "prepare-subst.mk"' \ | |||
1251 | '.include "mk/subst.mk"' | |||
1252 | create_file_lines "file" \ | |||
1253 | 'other' | |||
1254 | ||||
1255 | run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \ | |||
1256 | && exitcode=0 || exitcode=$? | |||
1257 | ||||
1258 | assert_that "out" --file-is-lines \ | |||
1259 | '=> Substituting "id" in file' \ | |||
1260 | 'warning: [subst.mk:id] Nothing changed in "file".' \ | |||
1261 | 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \ | |||
1262 | '*** Error code 1' \ | |||
1263 | '' \ | |||
1264 | 'Stop.' \ | |||
1265 | "$make: stopped in $PWD" | |||
1266 | ||||
1267 | test_case_end | |||
1268 | fi | |||
1269 | ||||
1270 | ||||
1271 | if test_case_begin "identity + effective substitution"; then | |||
1272 | ||||
1273 | create_file_lines "testcase.mk" \ | |||
1274 | 'SUBST_CLASSES+= id' \ | |||
1275 | 'SUBST_FILES.id= file' \ | |||
1276 | 'SUBST_SED.id= -e s,no-op,no-op,g' \ | |||
1277 | 'SUBST_SED.id+= -e s,from,to,' \ | |||
1278 | 'SUBST_NOOP_OK.id= no' \ | |||
1279 | '' \ | |||
1280 | '.include "prepare-subst.mk"' \ | |||
1281 | '.include "mk/subst.mk"' | |||
1282 | create_file_lines "file" \ | |||
1283 | 'from' | |||
1284 | ||||
1285 | run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \ | |||
1286 | && exitcode=0 || exitcode=$? | |||
1287 | ||||
1288 | assert_that "out" --file-is-lines \ | |||
1289 | '=> Substituting "id" in file' | |||
1290 | assert_that "file" --file-is-lines \ | |||
1291 | 'to' | |||
1292 | ||||
1293 | test_case_end | |||
1294 | fi | |||
1295 | ||||
1296 | ||||
1297 | if test_case_begin "identity + no-op substitution"; then | |||
1298 | ||||
1299 | # If there were only an identity substitution, it wouldn't be an | |||
1300 | # error. But since there is a regular substitution as well, | |||
1301 | # that substitution is an unexpected no-op and is therefore | |||
1302 | # flagged as an error. | |||
1303 | ||||
1304 | create_file_lines "testcase.mk" \ | |||
1305 | 'SUBST_CLASSES+= id' \ | |||
1306 | 'SUBST_FILES.id= file' \ | |||
1307 | 'SUBST_SED.id= -e s,no-op,no-op,g' \ | |||
1308 | 'SUBST_SED.id+= -e s,from,to,' \ | |||
1309 | 'SUBST_NOOP_OK.id= no' \ | |||
1310 | '' \ | |||
1311 | '.include "prepare-subst.mk"' \ | |||
1312 | '.include "mk/subst.mk"' | |||
1313 | create_file_lines "file" \ | |||
1314 | 'other' | |||
1315 | ||||
1316 | run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \ | |||
1317 | && exitcode=0 || exitcode=$? | |||
1318 | ||||
1319 | assert_that "out" --file-is-lines \ | |||
1320 | '=> Substituting "id" in file' \ | |||
1321 | 'warning: [subst.mk:id] Nothing changed in "file".' \ | |||
1322 | 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \ | |||
1323 | '*** Error code 1' \ | |||
1324 | '' \ | |||
1325 | 'Stop.' \ | |||
1326 | "$make: stopped in $PWD" | |||
1327 | assert_that "file" --file-is-lines \ | |||
1328 | 'other' | |||
1329 | ||||
1330 | test_case_end | |||
1331 | fi |
@@ -1,15 +1,15 @@ | @@ -1,15 +1,15 @@ | |||
1 | #! /bin/sh | 1 | #! /bin/sh | |
2 | # $NetBSD: test.subr,v 1.10 2020/04/26 12:46:33 rillig Exp $ | 2 | # $NetBSD: test.subr,v 1.11 2020/04/29 18:33:56 rillig Exp $ | |
3 | # | 3 | # | |
4 | # This file defines utilities for testing Makefile fragments and shell | 4 | # This file defines utilities for testing Makefile fragments and shell | |
5 | # programs from the pkgsrc infrastructure. While testing one part of the | 5 | # programs from the pkgsrc infrastructure. While testing one part of the | |
6 | # infrastructure, other parts can be mocked away. | 6 | # infrastructure, other parts can be mocked away. | |
7 | # | 7 | # | |
8 | # A test case is defined by the following functions: | 8 | # A test case is defined by the following functions: | |
9 | # | 9 | # | |
10 | # test_case_begin | 10 | # test_case_begin | |
11 | # test_case_set_up | 11 | # test_case_set_up | |
12 | # test_case_tear_down | 12 | # test_case_tear_down | |
13 | # test_case_end | 13 | # test_case_end | |
14 | # | 14 | # | |
15 | # These functions form the structure for a test. To define a test, use the | 15 | # These functions form the structure for a test. To define a test, use the | |
@@ -236,27 +236,27 @@ create_file() { | @@ -236,27 +236,27 @@ create_file() { | |||
236 | create_file_lines() { | 236 | create_file_lines() { | |
237 | mkdir -p "$(dirname "$tmpdir/$1")" | 237 | mkdir -p "$(dirname "$tmpdir/$1")" | |
238 | _cfl_filename="$1"; shift | 238 | _cfl_filename="$1"; shift | |
239 | printf '%s\n' "$@" > "$tmpdir/$_cfl_filename" | 239 | printf '%s\n' "$@" > "$tmpdir/$_cfl_filename" | |
240 | } | 240 | } | |
241 | 241 | |||
242 | create_pkgsrc_file() { | 242 | create_pkgsrc_file() { | |
243 | mkdir -p "$(dirname "$mocked_pkgsrcdir/$1")" | 243 | mkdir -p "$(dirname "$mocked_pkgsrcdir/$1")" | |
244 | cat > "$mocked_pkgsrcdir/$1" | 244 | cat > "$mocked_pkgsrcdir/$1" | |
245 | } | 245 | } | |
246 | 246 | |||
247 | run_bmake() { | 247 | run_bmake() { | |
248 | cat <<EOF > "$tmpdir/test.subr.main.mk" | 248 | cat <<EOF > "$tmpdir/test.subr.main.mk" | |
249 | PKGSRCDIR= $relative_pkgsrcdir | 249 | PKGSRCDIR= $pkgsrcdir | |
250 | .PATH: $mocked_pkgsrcdir | 250 | .PATH: $mocked_pkgsrcdir | |
251 | .PATH: $pkgsrcdir | 251 | .PATH: $pkgsrcdir | |
252 | .include "$1" | 252 | .include "$1" | |
253 | EOF | 253 | EOF | |
254 | shift | 254 | shift | |
255 | 255 | |||
256 | "$make" -f "$tmpdir/test.subr.main.mk" "$@" | 256 | "$make" -f "$tmpdir/test.subr.main.mk" "$@" | |
257 | } | 257 | } | |
258 | 258 | |||
259 | assert_succeeded=0 | 259 | assert_succeeded=0 | |
260 | assert_failed=0 | 260 | assert_failed=0 | |
261 | assert_fail_sep='' | 261 | assert_fail_sep='' | |
262 | 262 |