pkgtools/pkglint: update to 20.2.6 Changes since 20.2.5: Some selected absolute paths, such as /etc/passwd, /etc/shadow and /etc/hosts are allowed in patch files. Other files in /etc should still use PKG_SYSCONFDIR, to keep the package portable between platforms and also in unprivileged mode. (Fixes PR pkg/55524.) Absolute pathnames are also allowed in C-style end-of-line comments (fixes PR pkg/55516) and in continuations of C-style block comments (fixes PR pkg/55524). The explanation for make's :ts modifier has been adjusted to the 2020 bmake update. The modifier :ts\040 is now interpreted as octal, as opposed to decimal.diff -r1.666 -r1.667 pkgsrc/pkgtools/pkglint/Makefile
(rillig)
@@ -1,16 +1,16 @@ | @@ -1,16 +1,16 @@ | |||
1 | # $NetBSD: Makefile,v 1.666 2020/07/31 22:39:36 rillig Exp $ | 1 | # $NetBSD: Makefile,v 1.667 2020/08/02 13:27:17 rillig Exp $ | |
2 | 2 | |||
3 | PKGNAME= pkglint-20.2.5 | 3 | PKGNAME= pkglint-20.2.6 | |
4 | CATEGORIES= pkgtools | 4 | CATEGORIES= pkgtools | |
5 | DISTNAME= tools | 5 | DISTNAME= tools | |
6 | MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/} | 6 | MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/} | |
7 | GITHUB_PROJECT= tools | 7 | GITHUB_PROJECT= tools | |
8 | GITHUB_TAG= 92d8274bd7b8a4c65f24bafe401a029e58392704 | 8 | GITHUB_TAG= 92d8274bd7b8a4c65f24bafe401a029e58392704 | |
9 | 9 | |||
10 | MAINTAINER= rillig@NetBSD.org | 10 | MAINTAINER= rillig@NetBSD.org | |
11 | HOMEPAGE= https://github.com/rillig/pkglint | 11 | HOMEPAGE= https://github.com/rillig/pkglint | |
12 | COMMENT= Verifier for NetBSD packages | 12 | COMMENT= Verifier for NetBSD packages | |
13 | LICENSE= 2-clause-bsd | 13 | LICENSE= 2-clause-bsd | |
14 | CONFLICTS+= pkglint4-[0-9]* | 14 | CONFLICTS+= pkglint4-[0-9]* | |
15 | 15 | |||
16 | USE_TOOLS+= pax | 16 | USE_TOOLS+= pax |
@@ -357,40 +357,40 @@ func (p *MkLexer) varUseModifier(varname | @@ -357,40 +357,40 @@ func (p *MkLexer) varUseModifier(varname | |||
357 | } | 357 | } | |
358 | 358 | |||
359 | return "" | 359 | return "" | |
360 | } | 360 | } | |
361 | 361 | |||
362 | // varUseModifierTs parses the :ts modifier. | 362 | // varUseModifierTs parses the :ts modifier. | |
363 | // | 363 | // | |
364 | // The API of this method is tricky. | 364 | // The API of this method is tricky. | |
365 | // It is only extracted from varUseModifier to make the latter smaller. | 365 | // It is only extracted from varUseModifier to make the latter smaller. | |
366 | func (p *MkLexer) varUseModifierTs( | 366 | func (p *MkLexer) varUseModifierTs( | |
367 | mod string, closing byte, lexer *textproc.Lexer, varname string, | 367 | mod string, closing byte, lexer *textproc.Lexer, varname string, | |
368 | mark textproc.LexerMark) MkVarUseModifier { | 368 | mark textproc.LexerMark) MkVarUseModifier { | |
369 | 369 | |||
370 | // See devel/bmake/files/var.c:/case 't' | 370 | // See devel/bmake/files/var.c:/^ApplyModifier_ToSep/ | |
371 | sep := mod[2:] + p.varUseText(closing) | 371 | sep := mod[2:] + p.varUseText(closing) | |
372 | switch { | 372 | switch { | |
373 | case sep == "": | 373 | case sep == "": | |
374 | lexer.SkipString(":") | 374 | lexer.SkipString(":") | |
375 | case len(sep) == 1: | 375 | case len(sep) == 1: | |
376 | break | 376 | break | |
377 | case matches(sep, `^\\\d+`): | 377 | case matches(sep, `^\\\d+`): | |
378 | break | 378 | break | |
379 | default: | 379 | default: | |
380 | p.Warnf("Invalid separator %q for :ts modifier of %q.", sep, varname) | 380 | p.Warnf("Invalid separator %q for :ts modifier of %q.", sep, varname) | |
381 | p.Explain( | 381 | p.Explain( | |
382 | "The separator for the :ts modifier must be either a single character", | 382 | "The separator for the :ts modifier must be either a single character", | |
383 | "or an escape sequence like \\t or \\n or an octal or decimal escape", | 383 | "or an escape sequence like \\t or \\n or an octal or hexadecimal escape", | |
384 | "sequence; see the bmake man page for further details.") | 384 | "sequence; see the bmake man page for further details.") | |
385 | } | 385 | } | |
386 | return MkVarUseModifier(lexer.Since(mark)) | 386 | return MkVarUseModifier(lexer.Since(mark)) | |
387 | } | 387 | } | |
388 | 388 | |||
389 | // varUseModifierMatch parses an :M or :N pattern. | 389 | // varUseModifierMatch parses an :M or :N pattern. | |
390 | // | 390 | // | |
391 | // See devel/bmake/files/var.c:/^ApplyModifiers/, case 'M'. | 391 | // See devel/bmake/files/var.c:/^ApplyModifiers/, case 'M'. | |
392 | func (p *MkLexer) varUseModifierMatch(closing byte) MkVarUseModifier { | 392 | func (p *MkLexer) varUseModifierMatch(closing byte) MkVarUseModifier { | |
393 | lexer := p.lexer | 393 | lexer := p.lexer | |
394 | mark := lexer.Mark() | 394 | mark := lexer.Mark() | |
395 | lexer.Skip(1) | 395 | lexer.Skip(1) | |
396 | opening := byte(condInt(closing == '}', '{', '(')) | 396 | opening := byte(condInt(closing == '}', '{', '(')) |
@@ -631,28 +631,28 @@ func (s *Suite) Test_MkLexer_varUseModif | @@ -631,28 +631,28 @@ func (s *Suite) Test_MkLexer_varUseModif | |||
631 | 631 | |||
632 | t.SetUpCommandLine("-Wall", "--explain") | 632 | t.SetUpCommandLine("-Wall", "--explain") | |
633 | line := t.NewLine("filename.mk", 123, "${VAR:tsabc}") | 633 | line := t.NewLine("filename.mk", 123, "${VAR:tsabc}") | |
634 | p := NewMkLexer("tsabc}", line) | 634 | p := NewMkLexer("tsabc}", line) | |
635 | 635 | |||
636 | modifier := p.varUseModifier("VAR", '}') | 636 | modifier := p.varUseModifier("VAR", '}') | |
637 | 637 | |||
638 | t.CheckEquals(modifier, MkVarUseModifier("tsabc")) | 638 | t.CheckEquals(modifier, MkVarUseModifier("tsabc")) | |
639 | t.CheckEquals(p.Rest(), "}") | 639 | t.CheckEquals(p.Rest(), "}") | |
640 | t.CheckOutputLines( | 640 | t.CheckOutputLines( | |
641 | "WARN: filename.mk:123: Invalid separator \"abc\" for :ts modifier of \"VAR\".", | 641 | "WARN: filename.mk:123: Invalid separator \"abc\" for :ts modifier of \"VAR\".", | |
642 | "", | 642 | "", | |
643 | "\tThe separator for the :ts modifier must be either a single character", | 643 | "\tThe separator for the :ts modifier must be either a single character", | |
644 | "\tor an escape sequence like \\t or \\n or an octal or decimal escape", | 644 | "\tor an escape sequence like \\t or \\n or an octal or hexadecimal", | |
645 | "\tsequence; see the bmake man page for further details.", | 645 | "\tescape sequence; see the bmake man page for further details.", | |
646 | "") | 646 | "") | |
647 | } | 647 | } | |
648 | 648 | |||
649 | func (s *Suite) Test_MkLexer_varUseModifier__invalid_ts_modifier_without_warning(c *check.C) { | 649 | func (s *Suite) Test_MkLexer_varUseModifier__invalid_ts_modifier_without_warning(c *check.C) { | |
650 | t := s.Init(c) | 650 | t := s.Init(c) | |
651 | 651 | |||
652 | p := NewMkLexer("tsabc}", nil) | 652 | p := NewMkLexer("tsabc}", nil) | |
653 | 653 | |||
654 | modifier := p.varUseModifier("VAR", '}') | 654 | modifier := p.varUseModifier("VAR", '}') | |
655 | 655 | |||
656 | t.CheckEquals(modifier, MkVarUseModifier("tsabc")) | 656 | t.CheckEquals(modifier, MkVarUseModifier("tsabc")) | |
657 | t.CheckEquals(p.Rest(), "}") | 657 | t.CheckEquals(p.Rest(), "}") | |
658 | } | 658 | } |
@@ -286,43 +286,58 @@ func (ck *PatchChecker) checkAddedAbsPat | @@ -286,43 +286,58 @@ func (ck *PatchChecker) checkAddedAbsPat | |||
286 | line := ck.llex.PreviousLine() | 286 | line := ck.llex.PreviousLine() | |
287 | 287 | |||
288 | // Remove the #define from C and C++ macros. | 288 | // Remove the #define from C and C++ macros. | |
289 | before = replaceAll(before, `^[ \t]*#[ \t]*define[ \t]*\w+[ \t]*(.+)[ \t]*$`, "$1") | 289 | before = replaceAll(before, `^[ \t]*#[ \t]*define[ \t]*\w+[ \t]*(.+)[ \t]*$`, "$1") | |
290 | 290 | |||
291 | // Remove the "set(VAR" from CMakeLists.txt. | 291 | // Remove the "set(VAR" from CMakeLists.txt. | |
292 | before = replaceAll(before, `^[ \t]*set\(\w+[ \t]*`, "") | 292 | before = replaceAll(before, `^[ \t]*set\(\w+[ \t]*`, "") | |
293 | 293 | |||
294 | // Ignore comments in shell programs. | 294 | // Ignore comments in shell programs. | |
295 | if hasPrefix(trimHspace(before), "#") { | 295 | if hasPrefix(trimHspace(before), "#") { | |
296 | return | 296 | return | |
297 | } | 297 | } | |
298 | 298 | |||
299 | // Ignore paths inside C-style comments. | 299 | // Ignore paths inside C-style block comments. | |
300 | if contains(before, "/*") && contains(after, "*/") { | 300 | if contains(before, "/*") && contains(after, "*/") { | |
301 | return | 301 | return | |
302 | } | 302 | } | |
303 | 303 | |||
304 | // Ignore paths inside multiline C-style block comments. | |||
305 | if hasPrefix(trimHspace(before), "*") { | |||
306 | return | |||
307 | } | |||
308 | ||||
309 | // Ignore paths inside C-style end-of-line comments. | |||
310 | if contains(before, "//") { | |||
311 | return | |||
312 | } | |||
313 | ||||
304 | // Ignore composed C string literals such as PREFIX "/etc". | 314 | // Ignore composed C string literals such as PREFIX "/etc". | |
305 | if matches(before, `\w+[ \t]*"$`) { | 315 | if matches(before, `\w+[ \t]*"$`) { | |
306 | return | 316 | return | |
307 | } | 317 | } | |
308 | 318 | |||
309 | // Ignore shell literals such as $PREFIX/etc. | 319 | // Ignore shell literals such as $PREFIX/etc. | |
310 | // But keep compiler options like -I/usr/pkg even though they look | 320 | // But keep compiler options like -I/usr/pkg even though they look | |
311 | // like a relative pathname. | 321 | // like a relative pathname. | |
312 | if matches(before, `\w$`) && !matches(before, `(^|[ \t])-(I|L|R|rpath|Wl,-R)$`) { | 322 | if matches(before, `\w$`) && !matches(before, `(^|[ \t])-(I|L|R|rpath|Wl,-R)$`) { | |
313 | return | 323 | return | |
314 | } | 324 | } | |
315 | 325 | |||
326 | // Allow well-known pathnames that belong to the base system. | |||
327 | if matches(after, `hosts|passwd|shadow`) { | |||
328 | return | |||
329 | } | |||
330 | ||||
316 | switch dir { | 331 | switch dir { | |
317 | case "/usr/pkg": | 332 | case "/usr/pkg": | |
318 | 333 | |||
319 | line.Errorf("Patches must not hard-code the pkgsrc PREFIX.") | 334 | line.Errorf("Patches must not hard-code the pkgsrc PREFIX.") | |
320 | line.Explain( | 335 | line.Explain( | |
321 | "Not every pkgsrc installation uses /usr/pkg as its PREFIX.", | 336 | "Not every pkgsrc installation uses /usr/pkg as its PREFIX.", | |
322 | "To keep the PREFIX configurable, the patch files should contain", | 337 | "To keep the PREFIX configurable, the patch files should contain", | |
323 | "the placeholder @PREFIX@ instead.", | 338 | "the placeholder @PREFIX@ instead.", | |
324 | "", | 339 | "", | |
325 | "In the pre-configure stage, this placeholder should then be", | 340 | "In the pre-configure stage, this placeholder should then be", | |
326 | "replaced with the actual configuration directory", | 341 | "replaced with the actual configuration directory", | |
327 | "using a SUBST block containing SUBST_VARS.dirs=PREFIX.", | 342 | "using a SUBST block containing SUBST_VARS.dirs=PREFIX.", | |
328 | "See mk/subst.mk for details.") | 343 | "See mk/subst.mk for details.") |
@@ -965,48 +965,70 @@ func (s *Suite) Test_PatchChecker_checkA | @@ -965,48 +965,70 @@ func (s *Suite) Test_PatchChecker_checkA | |||
965 | // There should be an additional warning for using COMPILER_RPATH_FLAG. | 965 | // There should be an additional warning for using COMPILER_RPATH_FLAG. | |
966 | test( | 966 | test( | |
967 | "LDFLAGS+= -rpath/usr/pkg/lib", | 967 | "LDFLAGS+= -rpath/usr/pkg/lib", | |
968 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc PREFIX.") | 968 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc PREFIX.") | |
969 | 969 | |||
970 | // Makefile with flags for the linker. | 970 | // Makefile with flags for the linker. | |
971 | // There should be an additional warning for using COMPILER_RPATH_FLAG. | 971 | // There should be an additional warning for using COMPILER_RPATH_FLAG. | |
972 | test( | 972 | test( | |
973 | "LDFLAGS+= -Wl,-R/usr/pkg/lib", | 973 | "LDFLAGS+= -Wl,-R/usr/pkg/lib", | |
974 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc PREFIX.") | 974 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc PREFIX.") | |
975 | 975 | |||
976 | // The dot before the "/etc" makes it a relative pathname. | 976 | // The dot before the "/etc" makes it a relative pathname. | |
977 | test( | 977 | test( | |
978 | "cp ./etc/hostname /tmp") | 978 | "cp ./etc/hostname /tmp", | |
979 | nil...) | |||
979 | 980 | |||
980 | // +> +# from /etc/inittab (SYSV systems) | 981 | // +> +# from /etc/inittab (SYSV systems) | |
981 | // +ERROR: devel/tet3/patches/patch-ac:51: Patches must not hard-code the pkgsrc PKG_SYSCONFDIR. | 982 | // +ERROR: devel/tet3/patches/patch-ac:51: Patches must not hard-code the pkgsrc PKG_SYSCONFDIR. | |
982 | 983 | |||
983 | test( | 984 | test( | |
984 | "# SysV /etc/install, /usr/sbin/install") | 985 | "# SysV /etc/install, /usr/sbin/install", | |
986 | nil...) | |||
985 | 987 | |||
986 | // C or C++ program, macro definition. | 988 | // C or C++ program, macro definition. | |
987 | // This is an absolute path since the PID_FILE is the macro name, | 989 | // This is an absolute path since the PID_FILE is the macro name, | |
988 | // and not part of the macro body containing the path. | 990 | // and not part of the macro body containing the path. | |
989 | test( | 991 | test( | |
990 | "#define PID_FILE \"/var/run/daemon.pid\"", | 992 | "#define PID_FILE \"/var/run/daemon.pid\"", | |
991 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc VARBASE.") | 993 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc VARBASE.") | |
992 | 994 | |||
993 | // This is a relative path because of the PREFIX before it. | 995 | // This is a relative path because of the PREFIX before it. | |
994 | test( | 996 | test( | |
995 | "#define PID_FILE PREFIX \"/etc/conf\"", | 997 | "#define PID_FILE PREFIX \"/etc/conf\"", | |
996 | nil...) | 998 | nil...) | |
997 | 999 | |||
1000 | // In C-style block comments, absolute pathnames are ok, | |||
1001 | // even though they could still be confusing. | |||
1002 | test( | |||
1003 | "#define L 150 /* Length of a line in /etc/some/file */", | |||
1004 | nil...) | |||
1005 | ||||
1006 | // In multiline C-style block comment, absolute pathnames are ok, | |||
1007 | // even though they could still be confusing. | |||
1008 | test( | |||
1009 | " * Length of a line in /etc/some/file", | |||
1010 | nil...) | |||
1011 | ||||
1012 | // In C-style end-of-line comments, absolute pathnames are ok, | |||
1013 | // // even though they could still be confusing. | |||
1014 | test( | |||
1015 | "#define L 150 // Length of a line in /etc/some/file", | |||
1016 | nil...) | |||
1017 | ||||
1018 | // Allow /etc/passwd, /etc/shadow, /etc/hosts and their variants. | |||
1019 | // These belong to the base system, not to pkgsrc. | |||
998 | test( | 1020 | test( | |
999 | "#define L 150 /* Length of a line in /etc/passwd */", | 1021 | "#define PATH_SHADOW \"/etc/master.passwd\"", | |
1000 | nil...) | 1022 | nil...) | |
1001 | 1023 | |||
1002 | test( | 1024 | test( | |
1003 | "#define PID_FILE \"/var/run/daemon.pid\" /* comment */", | 1025 | "#define PID_FILE \"/var/run/daemon.pid\" /* comment */", | |
1004 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc VARBASE.") | 1026 | "ERROR: patch-file:8: Patches must not hard-code the pkgsrc VARBASE.") | |
1005 | 1027 | |||
1006 | // This is a rather theoretical case. | 1028 | // This is a rather theoretical case. | |
1007 | // Don't worry if pkglint doesn't complain about the absolute path here. | 1029 | // Don't worry if pkglint doesn't complain about the absolute path here. | |
1008 | test( | 1030 | test( | |
1009 | "#define PID_FILE /* */ \"/var/run/daemon.pid\" /* */", | 1031 | "#define PID_FILE /* */ \"/var/run/daemon.pid\" /* */", | |
1010 | nil...) | 1032 | nil...) | |
1011 | 1033 | |||
1012 | // The absolute path occurs in a comment that is only opened but not closed. | 1034 | // The absolute path occurs in a comment that is only opened but not closed. |