Changes since 5.6.5: - Removed plist-clash since it had crashed unconditionally whenever it was called. This means that in the last 3 years, nobody can have used it in the originally intended way. - Fixed interactions between the --source, --explain, --show-autofix, --autofix and --only options. - Fixed "defined but not used" and "used but not defined" for variables from the pkgsrc infrastructure. - Lots of small fixes and improvements found by the large pkglint code review (12% done).
842 lines
27 KiB
Go
842 lines
27 KiB
Go
package main
|
|
|
|
import "gopkg.in/check.v1"
|
|
|
|
func (s *Suite) Test_MkLineChecker_Check__url2pkg(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
|
|
mkline := t.NewMkLine("fileName.mk", 1, "# url2pkg-marker")
|
|
|
|
MkLineChecker{mkline}.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"ERROR: fileName.mk:1: This comment indicates unfinished work (url2pkg).")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_Check__buildlink3_include_prefs(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
|
|
t.CreateFileLines("mk/bsd.prefs.mk")
|
|
mklines := t.SetupFileMkLines("category/package/buildlink3.mk",
|
|
".include \"../../mk/bsd.prefs.mk\"")
|
|
// If the buildlink3.mk file is not actually created, resolving the
|
|
// relative path fails since that depends on the actual file system,
|
|
// not on syntactical paths; see os.Stat in CheckRelativePath.
|
|
|
|
MkLineChecker{mklines.mklines[0]}.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"NOTE: ~/category/package/buildlink3.mk:1: For efficiency reasons, please include bsd.fast.prefs.mk instead of bsd.prefs.mk.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkInclude(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
|
|
t.CreateFileLines("pkgtools/x11-links/buildlink3.mk")
|
|
t.CreateFileLines("graphics/jpeg/buildlink3.mk")
|
|
t.CreateFileLines("devel/intltool/buildlink3.mk")
|
|
t.CreateFileLines("devel/intltool/builtin.mk")
|
|
mklines := t.SetupFileMkLines("category/package/fileName.mk",
|
|
MkRcsID,
|
|
"",
|
|
".include \"../../pkgtools/x11-links/buildlink3.mk\"",
|
|
".include \"../../graphics/jpeg/buildlink3.mk\"",
|
|
".include \"../../devel/intltool/buildlink3.mk\"",
|
|
".include \"../../devel/intltool/builtin.mk\"")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"ERROR: ~/category/package/fileName.mk:3: ../../pkgtools/x11-links/buildlink3.mk must not be included directly. "+
|
|
"Include \"../../mk/x11.buildlink3.mk\" instead.",
|
|
"ERROR: ~/category/package/fileName.mk:4: ../../graphics/jpeg/buildlink3.mk must not be included directly. "+
|
|
"Include \"../../mk/jpeg.buildlink3.mk\" instead.",
|
|
"WARN: ~/category/package/fileName.mk:5: Please write \"USE_TOOLS+= intltool\" instead of this line.",
|
|
"ERROR: ~/category/package/fileName.mk:6: ../../devel/intltool/builtin.mk must not be included directly. "+
|
|
"Include \"../../devel/intltool/buildlink3.mk\" instead.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline := t.NewMkLine(t.File("Makefile"), 2, ".include \"../../other/package/Makefile\"")
|
|
|
|
MkLineChecker{mkline}.checkInclude()
|
|
|
|
t.CheckOutputLines(
|
|
"ERROR: ~/Makefile:2: \"other/package/Makefile\" does not exist.",
|
|
"ERROR: ~/Makefile:2: Other Makefiles must not be included directly.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkDirective(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
|
|
mklines := t.NewMkLines("category/package/fileName.mk",
|
|
MkRcsID,
|
|
"",
|
|
".for",
|
|
".endfor",
|
|
"",
|
|
".if",
|
|
".else don't",
|
|
".endif invalid-arg",
|
|
"",
|
|
".ifdef FNAME_MK",
|
|
".endif",
|
|
".ifndef FNAME_MK",
|
|
".endif",
|
|
"",
|
|
".for var in a b c",
|
|
".endfor",
|
|
".undef var",
|
|
"",
|
|
".for VAR in a b c",
|
|
".endfor",
|
|
"",
|
|
".for $ in a b c",
|
|
".endfor")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"ERROR: category/package/fileName.mk:3: \".for\" requires arguments.",
|
|
"ERROR: category/package/fileName.mk:6: \".if\" requires arguments.",
|
|
"ERROR: category/package/fileName.mk:7: \".else\" does not take arguments. If you meant \"else if\", use \".elif\".",
|
|
"ERROR: category/package/fileName.mk:8: \".endif\" does not take arguments.",
|
|
"WARN: category/package/fileName.mk:10: The \".ifdef\" directive is deprecated. Please use \".if defined(FNAME_MK)\" instead.",
|
|
"WARN: category/package/fileName.mk:12: The \".ifndef\" directive is deprecated. Please use \".if !defined(FNAME_MK)\" instead.",
|
|
"NOTE: category/package/fileName.mk:17: Using \".undef\" after a \".for\" loop is unnecessary.",
|
|
"WARN: category/package/fileName.mk:19: .for variable names should not contain uppercase letters.",
|
|
"ERROR: category/package/fileName.mk:22: Invalid variable name \"$\".")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkDependencyRule(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
|
|
mklines := t.NewMkLines("category/package/fileName.mk",
|
|
MkRcsID,
|
|
"",
|
|
".PHONY: target-1",
|
|
"target-2: .PHONY",
|
|
".ORDER: target-1 target-2",
|
|
"target-1:",
|
|
"target-2:",
|
|
"target-3:")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: category/package/fileName.mk:8: Unusual target \"target-3\".")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVartype__simple_type(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("-Wtypes")
|
|
t.SetupVartypes()
|
|
|
|
vartype1 := G.Pkgsrc.vartypes["COMMENT"]
|
|
c.Assert(vartype1, check.NotNil)
|
|
c.Check(vartype1.guessed, equals, false)
|
|
|
|
vartype := G.Pkgsrc.VariableType("COMMENT")
|
|
|
|
c.Assert(vartype, check.NotNil)
|
|
c.Check(vartype.basicType.name, equals, "Comment")
|
|
c.Check(vartype.guessed, equals, false)
|
|
c.Check(vartype.kindOfList, equals, lkNone)
|
|
|
|
MkLineChecker{dummyMkLine}.CheckVartype("COMMENT", opAssign, "A nice package", "")
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: COMMENT should not begin with \"A\".")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVartype(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mkline := t.NewMkLine("fileName", 1, "DISTNAME=gcc-${GCC_VERSION}")
|
|
|
|
MkLineChecker{mkline}.CheckVartype("DISTNAME", opAssign, "gcc-${GCC_VERSION}", "")
|
|
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVartype__skip(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("-Wno-types")
|
|
t.SetupVartypes()
|
|
mkline := t.NewMkLine("fileName", 1, "DISTNAME=invalid:::distname")
|
|
|
|
MkLineChecker{mkline}.Check()
|
|
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVartype__append_to_non_list(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mklines := t.NewMkLines("fileName.mk",
|
|
MkRcsID,
|
|
"DISTNAME+=\tsuffix",
|
|
"COMMENT=\tComment for",
|
|
"COMMENT+=\tthe package")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: fileName.mk:2: The variable DISTNAME may not be appended to (only set, given a default value) in this file.",
|
|
"WARN: fileName.mk:2: The \"+=\" operator should only be used with lists, not with DISTNAME.")
|
|
}
|
|
|
|
// Pkglint once interpreted all lists as consisting of shell tokens,
|
|
// splitting this URL at the ampersand.
|
|
func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
G.Pkg = NewPackage(t.File("graphics/gimp-fix-ca"))
|
|
t.SetupVartypes()
|
|
mkline := t.NewMkLine("fileName", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=")
|
|
|
|
MkLineChecker{mkline}.checkVarassign()
|
|
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("-Wtypes")
|
|
t.SetupVartypes()
|
|
|
|
testCond := func(cond string, output ...string) {
|
|
MkLineChecker{t.NewMkLine("fileName", 1, cond)}.checkDirectiveCond()
|
|
if len(output) > 0 {
|
|
t.CheckOutputLines(output...)
|
|
} else {
|
|
t.CheckOutputEmpty()
|
|
}
|
|
}
|
|
|
|
testCond(".if !empty(PKGSRC_COMPILER:Mmycc)",
|
|
"WARN: fileName:1: The pattern \"mycc\" cannot match any of "+
|
|
"{ ccache ccc clang distcc f2c gcc hp icc ido "+
|
|
"mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.")
|
|
|
|
testCond(".elif ${A} != ${B}")
|
|
|
|
testCond(".if ${HOMEPAGE} == \"mailto:someone@example.org\"",
|
|
"WARN: fileName:1: \"mailto:someone@example.org\" is not a valid URL.")
|
|
|
|
testCond(".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])",
|
|
"WARN: fileName:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
|
|
|
|
testCond(".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")
|
|
|
|
testCond(".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})",
|
|
"WARN: fileName:1: The empty() function takes a variable name as parameter, not a variable expression.")
|
|
|
|
testCond(".if ${EMUL_PLATFORM} == \"linux-x386\"",
|
|
"WARN: fileName:1: "+
|
|
"\"x386\" is not valid for the hardware architecture part of EMUL_PLATFORM. "+
|
|
"Use one of "+
|
|
"{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex "+
|
|
"dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb "+
|
|
"earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 "+
|
|
"i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 "+
|
|
"mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
|
|
"} instead.")
|
|
|
|
testCond(".if ${EMUL_PLATFORM:Mlinux-x386}",
|
|
"WARN: fileName:1: "+
|
|
"The pattern \"x386\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 "+
|
|
"arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb "+
|
|
"earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf "+
|
|
"earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k "+
|
|
"mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 "+
|
|
"rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } "+
|
|
"for the hardware architecture part of EMUL_PLATFORM.",
|
|
"NOTE: fileName:1: EMUL_PLATFORM should be compared using == instead of the :M or :N modifier without wildcards.")
|
|
|
|
testCond(".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}",
|
|
"WARN: fileName:1: "+
|
|
"The pattern \"UnknownOS\" cannot match any of "+
|
|
"{ AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku "+
|
|
"IRIX Interix Linux Minix MirBSD NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare "+
|
|
"} for the operating system part of MACHINE_PLATFORM.",
|
|
"WARN: fileName:1: "+
|
|
"The pattern \"x86\" cannot match any of "+
|
|
"{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm "+
|
|
"earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb "+
|
|
"earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 "+
|
|
"m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax "+
|
|
"powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
|
|
"} for MACHINE_ARCH.",
|
|
"NOTE: fileName:1: MACHINE_ARCH should be compared using == instead of the :M or :N modifier without wildcards.")
|
|
|
|
testCond(".if ${MASTER_SITES:Mftp://*} == \"ftp://netbsd.org/\"")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
|
|
G.Mk = t.NewMkLines("Makefile",
|
|
MkRcsID,
|
|
"ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8
|
|
|
|
MkLineChecker{G.Mk.mklines[1]}.checkVarassign()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: Makefile:2: ac_cv_libpari_libs is defined but not used.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkVarassignPermissions(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("-Wall,no-space")
|
|
t.SetupVartypes()
|
|
mklines := t.NewMkLines("options.mk",
|
|
MkRcsID,
|
|
"PKG_DEVELOPER?= yes",
|
|
"BUILD_DEFS?= VARBASE")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.",
|
|
"WARN: options.mk:2: Please include \"../../mk/bsd.prefs.mk\" before using \"?=\".",
|
|
"WARN: options.mk:3: The variable BUILD_DEFS may not be given a default value (only appended to) in this file.")
|
|
}
|
|
|
|
// Don't check the permissions for infrastructure files since they have their own rules.
|
|
func (s *Suite) Test_MkLineChecker_checkVarassignPermissions__infrastructure(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
t.CreateFileLines("mk/infra.mk",
|
|
MkRcsID,
|
|
"",
|
|
"PKG_DEVELOPER?=\tyes")
|
|
t.CreateFileLines("mk/bsd.pkg.mk")
|
|
|
|
G.CheckDirent(t.File("mk/infra.mk"))
|
|
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkVarusePermissions(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mklines := t.NewMkLines("options.mk",
|
|
MkRcsID,
|
|
"COMMENT=\t${GAMES_USER}",
|
|
"COMMENT:=\t${PKGBASE}",
|
|
"PYPKGPREFIX=${PKGBASE}")
|
|
G.Pkgsrc.UserDefinedVars.Define("GAMES_USER", mklines.mklines[0])
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: options.mk:3: PKGBASE should not be evaluated at load time.",
|
|
"WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.",
|
|
"WARN: options.mk:4: PKGBASE should not be evaluated indirectly at load time.",
|
|
"NOTE: options.mk:4: This variable value should be aligned to column 17.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkVarusePermissions__load_time(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mklines := t.NewMkLines("options.mk",
|
|
MkRcsID,
|
|
"WRKSRC:=${.CURDIR}",
|
|
".if ${PKG_SYSCONFDIR.gdm} != \"etc\"",
|
|
".endif")
|
|
|
|
mklines.Check()
|
|
|
|
// Evaluating PKG_SYSCONFDIR.* at load time is probably ok, though
|
|
// pkglint cannot prove anything here.
|
|
//
|
|
// Evaluating .CURDIR at load time is ok since it is defined from
|
|
// the beginning.
|
|
t.CheckOutputLines(
|
|
"NOTE: options.mk:2: This variable value should be aligned to column 17.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkVarusePermissions__load_time_guessed(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
t.SetupTool("install", "", AtRunTime)
|
|
mklines := t.NewMkLines("install-docfiles.mk",
|
|
MkRcsID,
|
|
"DOCFILES=\ta b c",
|
|
"do-install:",
|
|
".for f in ${DOCFILES}",
|
|
"\tinstall -c ${WRKSRC}/${f} ${DESTDIR}${PREFIX}/${f}",
|
|
".endfor")
|
|
|
|
mklines.Check()
|
|
|
|
// No warning for using DOCFILES at compile-time. Since the variable
|
|
// name is not one of the predefined names from vardefs.go, the
|
|
// variable's type is guessed based on the name (see
|
|
// Pkgsrc.VariableType).
|
|
//
|
|
// These guessed variables are typically defined and used only in
|
|
// a single file, and in this context, mistakes are usually found
|
|
// quickly.
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkVarusePermissions__PKGREVISION(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mklines := t.NewMkLines("any.mk",
|
|
MkRcsID,
|
|
// PKGREVISION may only be set in Makefile, not used at load time; see vardefs.go.
|
|
".if defined(PKGREVISION)",
|
|
".endif")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: any.mk:2: PKGREVISION should not be evaluated at load time.",
|
|
"WARN: any.mk:2: PKGREVISION may not be used in any file; it is a write-only variable.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker__warn_varuse_LOCALBASE(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mkline := t.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}")
|
|
|
|
MkLineChecker{mkline}.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: options.mk:56: Please use PREFIX instead of LOCALBASE.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckRelativePkgdir(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mklines := t.SetupFileMkLines("Makefile",
|
|
"# dummy")
|
|
|
|
MkLineChecker{mklines.mklines[0]}.CheckRelativePkgdir("../pkgbase")
|
|
|
|
t.CheckOutputLines(
|
|
"ERROR: ~/Makefile:1: \"../pkgbase\" does not exist.",
|
|
"WARN: ~/Makefile:1: \"../pkgbase\" is not a valid relative package directory.")
|
|
}
|
|
|
|
// PR pkg/46570, item 2
|
|
func (s *Suite) Test_MkLineChecker__unclosed_varuse(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mklines := t.NewMkLines("Makefile",
|
|
MkRcsID,
|
|
"EGDIRS=\t${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: Makefile:2: Unclosed Make variable starting at \"${EGDIR/apparmor.d $...\".",
|
|
"WARN: Makefile:2: EGDIRS is defined but not used.",
|
|
"WARN: Makefile:2: Pkglint parse error in MkLine.Tokenize at "+
|
|
"\"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker__Varuse_Modifier_L(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
G.Mk = t.NewMkLines("x11/xkeyboard-config/Makefile",
|
|
"FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}")
|
|
|
|
MkLineChecker{G.Mk.mklines[0]}.Check()
|
|
|
|
// Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkDirectiveCond__comparison_with_shell_command(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
G.Mk = t.NewMkLines("security/openssl/Makefile",
|
|
MkRcsID,
|
|
".if ${PKGSRC_COMPILER} == \"gcc\" && ${CC} == \"cc\"",
|
|
".endif")
|
|
|
|
G.Mk.Check()
|
|
|
|
// Don't warn about unknown shell command "cc".
|
|
t.CheckOutputLines(
|
|
"WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkDirectiveCond__comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
G.Mk = t.NewMkLines("audio/pulseaudio/Makefile",
|
|
MkRcsID,
|
|
".if ${OPSYS} == \"Darwin\" && ${PKGSRC_COMPILER} == \"clang\"",
|
|
".endif")
|
|
|
|
G.Mk.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS_with_backticks(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile",
|
|
MkRcsID,
|
|
"CFLAGS+=\t`pkg-config pidgin --cflags`")
|
|
mkline := G.Mk.mklines[1]
|
|
|
|
words, rest := splitIntoMkWords(mkline.Line, mkline.Value())
|
|
|
|
c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"})
|
|
c.Check(rest, equals, "")
|
|
|
|
MkLineChecker{G.Mk.mklines[1]}.CheckVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "")
|
|
|
|
// No warning about "`pkg-config" being an unknown CFlag.
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
// See PR 46570, Ctrl+F "4. Shell quoting".
|
|
// Pkglint is correct, since the shell sees this definition for
|
|
// CPPFLAGS as three words, not one word.
|
|
func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mklines := t.NewMkLines("Makefile",
|
|
MkRcsID,
|
|
"CPPFLAGS.SunOS+=\t-DPIPECOMMAND=\\\"/usr/sbin/sendmail -bs %s\\\"")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: Makefile:2: Unknown compiler flag \"-bs\".",
|
|
"WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.")
|
|
}
|
|
|
|
// Up to 2018-01-28, pkglint applied the autofix also to the continuation
|
|
// lines, which is incorrect. It replaced the dot in "4.*" with spaces.
|
|
func (s *Suite) Test_MkLineChecker_checkDirectiveIndentation__autofix(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("-Wall", "--autofix")
|
|
t.SetupVartypes()
|
|
mklines := t.SetupFileMkLines("options.mk",
|
|
MkRcsID,
|
|
".if ${PKGNAME} == pkgname",
|
|
".if \\",
|
|
" ${PLATFORM:MNetBSD-4.*}",
|
|
".endif",
|
|
".endif")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"AUTOFIX: ~/options.mk:3: Replacing \".\" with \". \".",
|
|
"AUTOFIX: ~/options.mk:5: Replacing \".\" with \". \".")
|
|
|
|
t.CheckFileLines("options.mk",
|
|
MkRcsID,
|
|
".if ${PKGNAME} == pkgname",
|
|
". if \\",
|
|
" ${PLATFORM:MNetBSD-4.*}",
|
|
". endif",
|
|
".endif")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruseShellword(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
mklines := t.SetupFileMkLines("options.mk",
|
|
MkRcsID,
|
|
"GOPATH=\t${WRKDIR}",
|
|
"do-build:",
|
|
"\tcd ${WRKSRC} && GOPATH=${GOPATH} PATH=${PATH} :")
|
|
|
|
mklines.Check()
|
|
|
|
// For WRKSRC and GOPATH, no quoting is necessary since pkgsrc directories by
|
|
// definition don't contain special characters. Therefore they don't need the
|
|
// :Q, not even when used as part of a shell word.
|
|
|
|
// For PATH, the quoting is necessary because it may contain directories outside
|
|
// of pkgsrc, and these may contain special characters.
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: ~/options.mk:4: The variable PATH should be quoted as part of a shell word.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruseShellword__mstar(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("-Wall,no-space")
|
|
t.SetupVartypes()
|
|
mklines := t.SetupFileMkLines("options.mk",
|
|
MkRcsID,
|
|
"CONFIGURE_ARGS+= ${CFLAGS:Q}",
|
|
"CONFIGURE_ARGS+= ${CFLAGS:M*:Q}",
|
|
"CONFIGURE_ARGS+= ${ADA_FLAGS:Q}",
|
|
"CONFIGURE_ARGS+= ${ADA_FLAGS:M*:Q}",
|
|
"CONFIGURE_ENV+= ${CFLAGS:Q}",
|
|
"CONFIGURE_ENV+= ${CFLAGS:M*:Q}",
|
|
"CONFIGURE_ENV+= ${ADA_FLAGS:Q}",
|
|
"CONFIGURE_ENV+= ${ADA_FLAGS:M*:Q}")
|
|
|
|
mklines.Check()
|
|
|
|
// FIXME: There should be some notes and warnings about missing :M*;
|
|
// these are currently prevented by the PERL5 case in VariableNeedsQuoting.
|
|
t.CheckOutputLines(
|
|
"WARN: ~/options.mk:4: ADA_FLAGS is used but not defined.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruseShellword__mstar_not_needed(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("-Wall,no-space")
|
|
pkg := t.SetupPackage("category/package",
|
|
"MAKE_FLAGS+=\tCFLAGS=${CFLAGS:M*:Q}",
|
|
"MAKE_FLAGS+=\tLFLAGS=${LDFLAGS:M*:Q}")
|
|
G.Pkgsrc.LoadInfrastructure()
|
|
// FIXME: It is too easy to forget this important call.
|
|
|
|
// This package is guaranteed to not use GNU_CONFIGURE.
|
|
// Since the :M* hack is only needed for GNU_CONFIGURE, it is not necessary here.
|
|
G.CheckDirent(pkg)
|
|
|
|
// FIXME: Duplicate diagnostics.
|
|
t.CheckOutputLines(
|
|
"NOTE: ~/category/package/Makefile:20: The :M* modifier is not needed here.",
|
|
"NOTE: ~/category/package/Makefile:20: The :M* modifier is not needed here.",
|
|
"NOTE: ~/category/package/Makefile:21: The :M* modifier is not needed here.",
|
|
"NOTE: ~/category/package/Makefile:21: The :M* modifier is not needed here.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruseShellword__q_not_needed(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
pkg := t.SetupPackage("category/package",
|
|
"MASTER_SITES=\t${HOMEPAGE:Q}")
|
|
G.Pkgsrc.LoadInfrastructure()
|
|
|
|
G.CheckDirent(pkg)
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: ~/category/package/Makefile:5: The :Q operator should not be used for ${HOMEPAGE} here.")
|
|
}
|
|
|
|
// The ${VARNAME:=suffix} expression should only be used with lists.
|
|
// It typically appears in MASTER_SITE definitions.
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruse__eq_nonlist(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/")
|
|
mklines := t.SetupFileMkLines("options.mk",
|
|
MkRcsID,
|
|
"WRKSRC=\t\t${WRKDIR:=/subdir}",
|
|
"MASTER_SITES=\t${MASTER_SITE_GITHUB:=organization/}")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: ~/options.mk:2: The :from=to modifier should only be used with lists, not with WRKDIR.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruse__for(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupVartypes()
|
|
t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/")
|
|
mklines := t.SetupFileMkLines("options.mk",
|
|
MkRcsID,
|
|
".for var in a b c",
|
|
"\t: ${var}",
|
|
".endfor")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputEmpty()
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruse__defined_in_infrastructure(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupPkgsrc()
|
|
t.SetupVartypes()
|
|
t.CreateFileLines("mk/deeply/nested/infra.mk",
|
|
MkRcsID,
|
|
"INFRA_VAR?=\tvalue")
|
|
G.Pkgsrc.LoadInfrastructure()
|
|
mklines := t.SetupFileMkLines("category/package/module.mk",
|
|
MkRcsID,
|
|
"do-fetch:",
|
|
"\t: ${INFRA_VAR} ${UNDEFINED}")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: ~/category/package/module.mk:3: UNDEFINED is used but not defined.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruse__build_defs(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
// XXX: This paragraph should not be necessary since VARBASE and X11_TYPE
|
|
// are also defined in vardefs.go.
|
|
t.SetupPkgsrc()
|
|
t.CreateFileLines("mk/defaults/mk.conf",
|
|
"VARBASE?= /usr/pkg/var")
|
|
G.Pkgsrc.LoadInfrastructure()
|
|
|
|
t.SetupCommandLine("-Wall,no-space")
|
|
t.SetupVartypes()
|
|
mklines := t.SetupFileMkLines("options.mk",
|
|
MkRcsID,
|
|
"COMMENT= ${VARBASE} ${X11_TYPE}",
|
|
"BUILD_DEFS+= X11_TYPE")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: ~/options.mk:2: The user-defined variable VARBASE is used but not added to BUILD_DEFS.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckVaruse__complicated_range(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupCommandLine("--show-autofix", "--source")
|
|
t.SetupVartypes()
|
|
mkline := t.NewMkLine("mk/compiler/gcc.mk", 150,
|
|
"CC:=\t${CC:C/^/_asdf_/1:M_asdf_*:S/^_asdf_//}")
|
|
|
|
MkLineChecker{mkline}.Check()
|
|
|
|
// FIXME: The check is called two times, even though it only produces a single NOTE.
|
|
t.CheckOutputLines(
|
|
"NOTE: mk/compiler/gcc.mk:150: The modifier \":C/^/_asdf_/1:M_asdf_*:S/^_asdf_//\" can be written as \":[1]\".",
|
|
"AUTOFIX: mk/compiler/gcc.mk:150: Replacing \":C/^/_asdf_/1:M_asdf_*:S/^_asdf_//\" with \":[1]\".",
|
|
"-\tCC:=\t${CC:C/^/_asdf_/1:M_asdf_*:S/^_asdf_//}",
|
|
"+\tCC:=\t${CC:[1]}")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkVarassignSpecific(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupPkgsrc()
|
|
G.Pkgsrc.LoadInfrastructure()
|
|
|
|
t.SetupCommandLine("-Wall,no-space")
|
|
t.SetupVartypes()
|
|
mklines := t.SetupFileMkLines("module.mk",
|
|
MkRcsID,
|
|
"EGDIR= ${PREFIX}/etc/rc.d",
|
|
"_TOOLS_VARNAME.sed= SED",
|
|
"DIST_SUBDIR= ${PKGNAME}",
|
|
"WRKSRC= ${PKGNAME}",
|
|
"SITES_distfile.tar.gz= ${MASTER_SITE_GITHUB:=user/}",
|
|
// TODO: The first of the below assignments should be flagged as redundant by RedundantScope;
|
|
// that check is currently only implemented for package Makefiles, not for other files.
|
|
"PYTHON_VERSIONS_ACCEPTED= -13",
|
|
"PYTHON_VERSIONS_ACCEPTED= 27 36")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: ~/module.mk:2: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.",
|
|
"WARN: ~/module.mk:3: _TOOLS_VARNAME.sed is defined but not used.",
|
|
"WARN: ~/module.mk:3: Variable names starting with an underscore (_TOOLS_VARNAME.sed) are reserved for internal pkgsrc use.",
|
|
"WARN: ~/module.mk:4: PKGNAME should not be used in DIST_SUBDIR, as it includes the PKGREVISION. Please use PKGNAME_NOREV instead.",
|
|
"WARN: ~/module.mk:5: PKGNAME should not be used in WRKSRC, as it includes the PKGREVISION. Please use PKGNAME_NOREV instead.",
|
|
"WARN: ~/module.mk:6: SITES_distfile.tar.gz is defined but not used.",
|
|
"WARN: ~/module.mk:6: SITES_* is deprecated. Please use SITES.* instead.",
|
|
"WARN: ~/module.mk:7: The variable PYTHON_VERSIONS_ACCEPTED may not be set "+
|
|
"(only given a default value, appended to) in this file; it would be ok in Makefile, Makefile.common, options.mk.",
|
|
"WARN: ~/module.mk:7: Invalid version number \"-13\".",
|
|
"ERROR: ~/module.mk:7: All values for PYTHON_VERSIONS_ACCEPTED must be positive integers.",
|
|
"WARN: ~/module.mk:8: The variable PYTHON_VERSIONS_ACCEPTED may not be set "+
|
|
"(only given a default value, appended to) in this file; it would be ok in Makefile, Makefile.common, options.mk.",
|
|
"WARN: ~/module.mk:8: The values for PYTHON_VERSIONS_ACCEPTED should be in decreasing order.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_checkText(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupPkgsrc()
|
|
G.Pkgsrc.LoadInfrastructure()
|
|
|
|
t.SetupCommandLine("-Wall,no-space")
|
|
mklines := t.SetupFileMkLines("module.mk",
|
|
MkRcsID,
|
|
"CFLAGS+= -Wl,--rpath,${PREFIX}/lib",
|
|
"PKG_FAIL_REASON+= \"Group ${GAMEGRP} doesn't exist.\"")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: ~/module.mk:2: Please use ${COMPILER_RPATH_FLAG} instead of \"-Wl,--rpath,\".",
|
|
"WARN: ~/module.mk:3: Use of \"GAMEGRP\" is deprecated. Use GAMES_GROUP instead.")
|
|
}
|
|
|
|
func (s *Suite) Test_MkLineChecker_CheckRelativePath(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetupPkgsrc()
|
|
G.Pkgsrc.LoadInfrastructure()
|
|
t.CreateFileLines("wip/package/Makefile")
|
|
t.CreateFileLines("wip/package/module.mk")
|
|
mklines := t.SetupFileMkLines("category/package/module.mk",
|
|
MkRcsID,
|
|
"DEPENDS+= wip-package-[0-9]*:../../wip/package",
|
|
".include \"../../wip/package/module.mk\"",
|
|
"",
|
|
"DEPENDS+= unresolvable-[0-9]*:../../lang/${LATEST_PYTHON}",
|
|
".include \"../../lang/${LATEST_PYTHON}/module.mk\"",
|
|
"",
|
|
".include \"module.mk\"",
|
|
".include \"../../category/../category/package/module.mk\"", // Oops
|
|
".include \"../../mk/bsd.prefs.mk\"",
|
|
".include \"../package/module.mk\"")
|
|
|
|
mklines.Check()
|
|
|
|
t.CheckOutputLines(
|
|
"ERROR: ~/category/package/module.mk:2: A main pkgsrc package must not depend on a pkgsrc-wip package.",
|
|
"ERROR: ~/category/package/module.mk:3: A main pkgsrc package must not depend on a pkgsrc-wip package.",
|
|
"WARN: ~/category/package/module.mk:5: LATEST_PYTHON is used but not defined.",
|
|
"WARN: ~/category/package/module.mk:11: Invalid relative path \"../package/module.mk\".")
|
|
}
|