File: [cvs.NetBSD.org] / pkgsrc / pkgtools / pkglint / files / Attic / plist_test.go (download)
Revision 1.48, Sun Mar 22 17:43:15 2020 UTC (4 years ago) by rillig
Branch: MAIN
CVS Tags: pkgsrc-2020Q1-base, pkgsrc-2020Q1 Changes since 1.47: +72 -15
lines
pkgtools/pkglint: update to 19.4.13
Changes since 19.4.12:
Files that are mentioned redundantly in PLIST files generate an error.
Missing DESCR files generate an error.
Hard-coded /usr/pkg in patches generates an error.
|
package pkglint
import "gopkg.in/check.v1"
func (s *Suite) Test_CheckLinesPlist(c *check.C) {
t := s.Init(c)
pkg := NewPackage(t.File("category/pkgbase"))
lines := t.NewLines("PLIST",
"bin/i386/6c",
"bin/program",
"etc/my.cnf",
"etc/rc.d/service",
"@exec ${MKDIR} include/pkgbase",
"info/dir",
"lib/c.so",
"lib/libc.so.6",
"lib/libc.la",
"${PLIST.man}man/cat3/strcpy.4",
"man/man1/imake.${IMAKE_MANNEWSUFFIX}",
"${PLIST.obsolete}@unexec rmdir /tmp",
"sbin/clockctl",
"share/icons/gnome/delete-icon",
"share/icons/hicolor/icon1.png",
"share/icons/hicolor/icon2.png", // No additional error for hicolor-icon-theme.
"share/tzinfo",
"share/tzinfo",
"/absolute")
CheckLinesPlist(pkg, lines)
t.CheckOutputLines(
"ERROR: PLIST:1: Expected \"@comment $"+"NetBSD$\".",
"WARN: PLIST:1: The bin/ directory should not have subdirectories.",
"ERROR: PLIST:3: Configuration files must not be registered in the PLIST.",
"ERROR: PLIST:4: RCD_SCRIPTS must not be registered in the PLIST.",
"ERROR: PLIST:6: \"info/dir\" must not be listed. Use install-info to add/remove an entry.",
"WARN: PLIST:8: Redundant library found. The libtool library is in line 9.",
"WARN: PLIST:9: \"lib/libc.la\" should be sorted before \"lib/libc.so.6\".",
"WARN: PLIST:9: Packages that install libtool libraries should define USE_LIBTOOL.",
"WARN: PLIST:10: Preformatted manual page without unformatted one.",
"WARN: PLIST:10: Preformatted manual pages should end in \".0\".",
"WARN: PLIST:11: IMAKE_MANNEWSUFFIX is not meant to appear in PLISTs.",
"WARN: PLIST:12: Please remove this line. It is no longer necessary.",
"ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".",
"WARN: PLIST:14: Packages that install icon theme files should set ICON_THEMES.",
"ERROR: PLIST:15: Packages that install hicolor icons "+
"must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.",
"ERROR: PLIST:18: Duplicate filename \"share/tzinfo\", already appeared in line 17.",
"ERROR: PLIST:19: Invalid line type: /absolute")
}
func (s *Suite) Test_CheckLinesPlist__single_file_no_comment(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
"bin/program")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: PLIST:1: Expected \"" + PlistCvsID + "\".")
}
// When a PLIST contains multiple libtool libraries, USE_LIBTOOL needs only
// be defined once in the package Makefile. Therefore, a single warning is enough.
func (s *Suite) Test_CheckLinesPlist__multiple_libtool_libraries(c *check.C) {
t := s.Init(c)
pkg := NewPackage(t.File("category/pkgbase"))
lines := t.NewLines("PLIST",
PlistCvsID,
"lib/libc.la",
"lib/libm.la")
CheckLinesPlist(pkg, lines)
t.CheckOutputLines(
"WARN: PLIST:2: Packages that install libtool libraries should define USE_LIBTOOL.")
}
func (s *Suite) Test_CheckLinesPlist__empty(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID)
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: PLIST:1: PLIST files must not be empty.")
}
func (s *Suite) Test_CheckLinesPlist__common_end(c *check.C) {
t := s.Init(c)
t.CreateFileLines("PLIST.common",
PlistCvsID,
"bin/common")
lines := t.SetUpFileLines("PLIST.common_end",
PlistCvsID,
"sbin/common_end")
CheckLinesPlist(nil, lines)
t.CheckOutputEmpty()
}
func (s *Suite) Test_CheckLinesPlist__common_end_without_common(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST.common_end",
PlistCvsID,
"sbin/common_end")
CheckLinesPlist(nil, lines)
t.CheckOutputEmpty()
}
func (s *Suite) Test_CheckLinesPlist__condition(c *check.C) {
t := s.Init(c)
pkg := NewPackage(t.File("category/pkgbase"))
lines := t.NewLines("PLIST",
PlistCvsID,
"${PLIST.bincmds}bin/subdir/command")
CheckLinesPlist(pkg, lines)
t.CheckOutputLines(
"WARN: PLIST:2: The bin/ directory should not have subdirectories.")
}
func (s *Suite) Test_CheckLinesPlist__sorting(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"@comment Do not remove",
"sbin/i386/6c",
"sbin/program",
"bin/otherprogram",
"${PLIST.condition}bin/cat")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: PLIST:5: \"bin/otherprogram\" should be sorted before \"sbin/program\".",
"WARN: PLIST:6: \"bin/cat\" should be sorted before \"bin/otherprogram\".")
}
func (s *Suite) Test_CheckLinesPlist__sort_common(c *check.C) {
t := s.Init(c)
// TODO: Examine what happens if there is a PLIST.common to be sorted.
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"lib/libvirt/connection-driver/libvirt_driver_storage.la",
"${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la",
"${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la",
"lib/libvirt/lock-driver/lockd.la",
"${PKGMANDIR}/man1/sh.1",
"share/augeas/lenses/virtlockd.aug",
"share/doc/pkgname-1.0/html/32favicon.png",
"share/doc/pkgname-1.0/html/404.html",
"share/doc/pkgname-1.0/html/acl.html",
"share/doc/pkgname-1.0/html/aclpolkit.html",
"share/doc/pkgname-1.0/html/windows.html",
"share/examples/libvirt/libvirt.conf",
"share/locale/zh_CN/LC_MESSAGES/libvirt.mo",
"share/locale/zh_TW/LC_MESSAGES/libvirt.mo",
"share/locale/zu/LC_MESSAGES/libvirt.mo",
"@pkgdir share/examples/libvirt/nwfilter",
// Directives may contain arbitrary horizontal whitespace.
"@pkgdir etc/libvirt/qemu/networks/autostart",
"@pkgdir etc/logrotate.d",
"@pkgdir etc/sasl2")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: ~/PLIST:3: \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\" "+
"should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_storage.la\".",
"WARN: ~/PLIST:4: \"lib/libvirt/connection-driver/libvirt_driver_libxl.la\" "+
"should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".",
"NOTE: ~/PLIST:6: PLIST files should use \"man/\" instead of \"${PKGMANDIR}\".")
t.SetUpCommandLine("-Wall", "--autofix")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".",
"AUTOFIX: ~/PLIST:2: Sorting the whole file.")
t.CheckFileLines("PLIST",
PlistCvsID,
"${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la",
"${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la",
"lib/libvirt/connection-driver/libvirt_driver_storage.la",
"lib/libvirt/lock-driver/lockd.la",
"man/man1/sh.1",
"share/augeas/lenses/virtlockd.aug",
"share/doc/pkgname-1.0/html/32favicon.png",
"share/doc/pkgname-1.0/html/404.html",
"share/doc/pkgname-1.0/html/acl.html",
"share/doc/pkgname-1.0/html/aclpolkit.html",
"share/doc/pkgname-1.0/html/windows.html",
"share/examples/libvirt/libvirt.conf",
"share/locale/zh_CN/LC_MESSAGES/libvirt.mo",
"share/locale/zh_TW/LC_MESSAGES/libvirt.mo",
"share/locale/zu/LC_MESSAGES/libvirt.mo",
"@pkgdir share/examples/libvirt/nwfilter",
"@pkgdir etc/libvirt/qemu/networks/autostart",
"@pkgdir etc/logrotate.d",
"@pkgdir etc/sasl2")
}
// When the same entry appears both with and without a condition,
// the one with the condition can be removed.
// When the same entry appears with several different conditions,
// all of them must stay.
func (s *Suite) Test_PlistChecker__remove_same_entries(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"${PLIST.option1}bin/true",
"bin/true",
"${PLIST.option1}bin/true",
"bin/true",
"${PLIST.option3}bin/false",
"${PLIST.option2}bin/false",
"bin/true")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: ~/PLIST:2: Duplicate filename \"bin/true\", already appeared in line 3.",
"ERROR: ~/PLIST:4: Duplicate filename \"bin/true\", already appeared in line 3.",
"ERROR: ~/PLIST:5: Duplicate filename \"bin/true\", already appeared in line 3.",
"WARN: ~/PLIST:6: \"bin/false\" should be sorted before \"bin/true\".",
"ERROR: ~/PLIST:8: Duplicate filename \"bin/true\", already appeared in line 3.")
t.SetUpCommandLine("-Wall", "--autofix")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"AUTOFIX: ~/PLIST:2: Deleting this line.",
"AUTOFIX: ~/PLIST:4: Deleting this line.",
"AUTOFIX: ~/PLIST:5: Deleting this line.",
"AUTOFIX: ~/PLIST:8: Deleting this line.",
"AUTOFIX: ~/PLIST:2: Sorting the whole file.")
t.CheckFileLines("PLIST",
PlistCvsID,
"${PLIST.option2}bin/false",
"${PLIST.option3}bin/false",
"bin/true")
}
// When pkglint is run with the --only option, only the matched
// diagnostics must be autofixed. Up to 2018-03-12, the PLIST was
// sorted even if it didn't match the --only pattern.
func (s *Suite) Test_PlistChecker__autofix_with_only(c *check.C) {
t := s.Init(c)
t.SetUpCommandLine("-Wall", "--autofix", "--only", "matches nothing")
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"sbin/program",
"bin/program")
CheckLinesPlist(nil, lines)
t.CheckOutputEmpty()
t.CheckFileLines("PLIST",
PlistCvsID,
"sbin/program",
"bin/program")
}
func (s *Suite) Test_PlistChecker__exec_MKDIR(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"bin/program",
"@exec ${MKDIR} %D/share/mk/subdir")
CheckLinesPlist(nil, lines)
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker__empty_line(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"",
"bin/program")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: ~/PLIST:2: PLISTs should not contain empty lines.")
t.SetUpCommandLine("-Wall", "--autofix")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"AUTOFIX: ~/PLIST:2: Deleting this line.")
t.CheckFileLines("PLIST",
PlistCvsID,
"bin/program")
}
func (s *Suite) Test_PlistChecker__invalid_line_type(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"---invalid",
"+++invalid",
"<<<<<<<< merge conflict",
"======== merge conflict",
">>>>>>>> merge conflict")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: ~/PLIST:2: Invalid line type: ---invalid",
"ERROR: ~/PLIST:3: Invalid line type: +++invalid",
"ERROR: ~/PLIST:4: Invalid line type: <<<<<<<< merge conflict",
"ERROR: ~/PLIST:5: Invalid line type: ======== merge conflict",
"ERROR: ~/PLIST:6: Invalid line type: >>>>>>>> merge conflict")
}
func (s *Suite) Test_PlistChecker__doc(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"doc/html/index.html")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: ~/PLIST:2: Documentation must be installed under share/doc, not doc.")
}
func (s *Suite) Test_PlistChecker__PKGLOCALEDIR(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package")
t.CreateFileLines("category/package/PLIST",
PlistCvsID,
"${PKGLOCALEDIR}/file")
t.FinishSetUp()
G.Check(t.File("category/package"))
t.CheckOutputLines(
"WARN: ~/category/package/PLIST:2: PLIST contains ${PKGLOCALEDIR}, " +
"but USE_PKGLOCALEDIR is not set in the package Makefile.")
}
func (s *Suite) Test_PlistChecker__PKGLOCALEDIR_with_USE_PKGLOCALEDIR(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package",
"USE_PKGLOCALEDIR=\tyes")
t.CreateFileLines("category/package/PLIST",
PlistCvsID,
"${PKGLOCALEDIR}/file")
t.FinishSetUp()
G.Check(t.File("category/package"))
}
func (s *Suite) Test_PlistChecker__PKGLOCALEDIR_without_package(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"${PKGLOCALEDIR}/file")
CheckLinesPlist(nil, lines)
// When a PLIST file is checked on its own, outside of checking a
// package, there can be no warning that USE_PKGLOCALEDIR is missing
// in the package.
t.CheckOutputEmpty()
}
func (s *Suite) Test_NewPlistChecker(c *check.C) {
t := s.Init(c)
pkg := NewPackage(t.File("category/package"))
ck := NewPlistChecker(pkg)
t.CheckEquals(ck.pkg, pkg)
t.Check(ck.allDirs, check.NotNil)
t.Check(ck.allFiles, check.NotNil)
}
func (s *Suite) Test_PlistChecker_Load__common_end(c *check.C) {
t := s.Init(c)
t.Chdir(".")
t.CreateFileLines("PLIST",
PlistCvsID,
"bin/plist")
t.CreateFileLines("PLIST.common",
PlistCvsID,
"bin/plist_common")
t.CreateFileLines("PLIST.common_end",
PlistCvsID,
"bin/plist_common_end")
ck := NewPlistChecker(nil)
plistLines := ck.Load(Load(t.File("PLIST.common_end"), MustSucceed))
// The corresponding PLIST.common is loaded if possible.
// Its lines are not appended to plistLines since they
// are checked separately.
t.Check(plistLines, check.HasLen, 2)
// But the files and directories from PLIST.common are registered,
// to check for duplicates and to make these lists available to
// the package being checked, for cross-validation.
t.Check(ck.allFiles["bin/plist"], check.IsNil)
t.CheckEquals(
ck.allFiles["bin/plist_common"].String(),
"PLIST.common:2: bin/plist_common")
t.CheckEquals(
ck.allFiles["bin/plist_common_end"].String(),
"PLIST.common_end:2: bin/plist_common_end")
}
func (s *Suite) Test_PlistChecker_Check(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
"bin/subdir/program")
ck := NewPlistChecker(nil)
ck.Check(lines)
t.CheckOutputLines(
"WARN: PLIST:1: The bin/ directory should not have subdirectories.")
}
func (s *Suite) Test_PlistChecker_newLines(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
"bin/program",
"${PLIST.cond}bin/conditional",
"${PLIST.abs}${PLIST.abs2}/bin/conditional-absolute",
"${PLIST.mod:Q}invalid")
plistLines := (*PlistChecker)(nil).newLines(lines)
// The invalid condition in line 4 is silently skipped when the
// lines are parsed. The actual check happens later.
t.Check(plistLines, check.HasLen, 4)
t.CheckEquals(plistLines[0].text, "bin/program")
t.CheckEquals(plistLines[1].text, "bin/conditional")
t.CheckEquals(plistLines[2].text, "/bin/conditional-absolute")
t.CheckEquals(plistLines[3].text, "${PLIST.mod:Q}invalid")
t.Check(plistLines[0].conditions, check.HasLen, 0)
t.CheckDeepEquals(plistLines[1].conditions, []string{"PLIST.cond"})
t.CheckDeepEquals(plistLines[2].conditions, []string{"PLIST.abs", "PLIST.abs2"})
t.Check(plistLines[3].conditions, check.HasLen, 0)
}
func (s *Suite) Test_PlistChecker_collectFilesAndDirs(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"bin/program",
"man/man1/program.1",
"/absolute",
"${PLIST.cond}/absolute",
"@exec ${MKDIR} %D//absolute")
ck := NewPlistChecker(nil)
plistLines := ck.newLines(lines)
ck.collectFilesAndDirs(plistLines)
t.CheckDeepEquals(keys(ck.allDirs),
[]string{"bin", "man", "man/man1"})
t.CheckDeepEquals(keys(ck.allFiles),
[]string{"bin/program", "man/man1/program.1"})
}
func (s *Suite) Test_PlistChecker_collectPath(c *check.C) {
t := s.Init(c)
line := t.NewLine("PLIST", 1, "a/b/c/program")
ck := NewPlistChecker(nil)
ck.collectPath("a/b/c/program", &PlistLine{line, nil, line.Text})
t.CheckDeepEquals(keys(ck.allDirs),
[]string{"a", "a/b", "a/b/c"})
t.CheckDeepEquals(keys(ck.allFiles),
[]string{"a/b/c/program"})
}
func (s *Suite) Test_PlistChecker_collectDirective(c *check.C) {
t := s.Init(c)
test := func(directive string, dirs ...string) {
line := t.NewLine("PLIST", 1, directive)
ck := NewPlistChecker(nil)
ck.collectDirective(&PlistLine{line, nil, line.Text})
t.CheckDeepEquals(keys(ck.allDirs), dirs)
t.Check(keys(ck.allFiles), check.HasLen, 0)
}
test("@exec ${MKDIR} %D/a/b/c",
"a", "a/b", "a/b/c")
test("@exec echo hello",
nil...)
test("@exec ${MKDIR} %D//absolute",
nil...)
test("@exec ${MKDIR} %D/a/../../../breakout",
"a", "a/..", "a/../..", "a/../../..", "a/../../../breakout")
}
func (s *Suite) Test_PlistChecker_checkLine(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"bin/program",
"${PLIST.var}bin/conditional-program",
"${PLIST.linux}${PLIST.arm}bin/arm-linux-only",
"${PLIST.linux}${PLIST.arm-64}@exec echo 'This is Linux/arm64'",
"${PLIST.ocaml-opt}share/ocaml",
"${PLIST.ocaml-opt}@exec echo 'This is OCaml'",
"${PLIST.ocaml-opt}@exec echo 'This is OCaml'",
"${PYSITELIB:S,lib,share}/modifiers don't work in PLISTs",
"${PLIST.empty}",
"",
"$prefix/bin",
// This line does not count as a PLIST condition since it has
// a :Q modifier, which does not work in PLISTs. Therefore the
// ${PLIST.man:Q} is considered part of the filename.
"${PLIST.man:Q}man/cat3/strlcpy.3",
"<<<<<<<<< merge conflict")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: PLIST:3: \"bin/conditional-program\" should be sorted before \"bin/program\".",
"WARN: PLIST:4: \"bin/arm-linux-only\" should be sorted before \"bin/conditional-program\".",
"WARN: PLIST:10: PLISTs should not contain empty lines.",
"WARN: PLIST:11: PLISTs should not contain empty lines.",
"ERROR: PLIST:14: Invalid line type: <<<<<<<<< merge conflict")
}
func (s *Suite) Test_PlistChecker_checkPath__PKGMANDIR(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"${PKGMANDIR}/man1/sh.1")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"NOTE: PLIST:2: PLIST files should use \"man/\" instead of \"${PKGMANDIR}\".")
}
func (s *Suite) Test_PlistChecker_checkPathMisc__python_egg(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"${PYSITELIB}/gdspy-${PKGVERSION}-py${PYVERSSUFFIX}.egg-info/PKG-INFO")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.")
}
func (s *Suite) Test_PlistChecker_checkPathMisc__unwanted_entries(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"share/perllocal.pod",
"share/pkgbase/CVS/Entries",
"share/pkgbase/Makefile.orig",
"../breakout",
"t/../../breakout",
"t/../../breakout/${VAR}",
"t/./non-canonical",
"t///non-canonical",
"t///non-canonical/${VAR}",
"t///non-canonical${VAR}",
"t/non-canonical/",
"t/ok/${VAR}")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: ~/PLIST:2: The perllocal.pod file should not be in the PLIST.",
"WARN: ~/PLIST:3: CVS files should not be in the PLIST.",
"WARN: ~/PLIST:4: .orig files should not be in the PLIST.",
"ERROR: ~/PLIST:5: Invalid line type: ../breakout",
"ERROR: ~/PLIST:6: Paths in PLIST files must not contain \"..\".",
"ERROR: ~/PLIST:7: Paths in PLIST files must not contain \"..\".",
"ERROR: ~/PLIST:8: Paths in PLIST files must be canonical (t/non-canonical).",
"ERROR: ~/PLIST:9: Paths in PLIST files must be canonical (t/non-canonical).",
"ERROR: ~/PLIST:10: Paths in PLIST files must be canonical (t/non-canonical/${VAR}).",
"ERROR: ~/PLIST:11: Paths in PLIST files must be canonical (t/non-canonical${VAR}).",
"ERROR: ~/PLIST:12: Paths in PLIST files must be canonical (t/non-canonical).")
}
func (s *Suite) Test_PlistChecker_checkPathNonAscii(c *check.C) {
t := s.Init(c)
t.SetUpCommandLine("-Wall", "--explain")
lines := t.NewLines("PLIST",
PlistCvsID,
"dir1/fr\xFCher", // German, "back then", encoded in ISO 8859-1
// Subsequent non-ASCII filenames do not generate further messages
// since these filenames typically appear in groups, and issuing
// too many warnings quickly gets boring.
"dir1/\u00C4thernetz", // German
// This ASCII-only pathname enables the check again.
"dir2/aaa",
"dir2/\u0633\u0644\u0627\u0645", // Arabic: salaam
"dir2/\uC548\uB148", // Korean: annyeong
// This ASCII-only pathname enables the check again.
"dir3/ascii-only",
// Any comment suppresses the check for the next contiguous
// sequence of non-ASCII filenames.
"@comment The next file is non-ASCII on purpose.",
"dir3/\U0001F603", // Smiling face with open mouth
// This ASCII-only pathname enables the check again.
"sbin/iconv",
"sbin/\U0001F603", // Smiling face with open mouth
// Directives other than comments do not allow non-ASCII.
"unicode/00FC/reset",
"@exec true",
"unicode/00FC/\u00FC", // u-umlaut
)
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: PLIST:2: Non-ASCII filename \"dir1/fr<0xFC>her\".",
"",
"\tThe great majority of filenames installed by pkgsrc packages are",
"\tASCII-only. Filenames containing non-ASCII characters can cause",
"\tvarious problems since their name may already be different when",
"\tanother character encoding is set in the locale.",
"",
"\tTo mark a filename as intentionally non-ASCII, insert a PLIST",
"\t@comment with a convincing reason directly above this line. That",
"\tcomment will allow this line and the lines directly below it to",
"\tcontain non-ASCII filenames.",
"",
"WARN: PLIST:5: Non-ASCII filename \"dir2/<U+0633><U+0644><U+0627><U+0645>\".",
"WARN: PLIST:11: Non-ASCII filename \"sbin/<U+1F603>\".",
"WARN: PLIST:14: Non-ASCII filename \"unicode/00FC/<U+00FC>\".")
}
func (s *Suite) Test_PlistChecker_checkSorted(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"bin/program2",
"bin/program1")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: PLIST:3: \"bin/program1\" should be " +
"sorted before \"bin/program2\".")
}
func (s *Suite) Test_PlistChecker_checkDuplicate(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"bin/program",
"bin/program")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: PLIST:3: Duplicate filename \"bin/program\", " +
"already appeared in line 2.")
}
func (s *Suite) Test_PlistChecker_checkDuplicate__OPSYS(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package")
t.Chdir("category/package")
t.CreateFileLines("PLIST",
PlistCvsID,
"bin/common",
"bin/common_end",
"${PLIST.cond}bin/conditional",
"bin/plist")
t.CreateFileLines("PLIST.Linux",
PlistCvsID,
"bin/common",
"bin/common_end",
"${PLIST.cond}bin/conditional",
"bin/os-specific",
"bin/plist")
t.CreateFileLines("PLIST.NetBSD",
PlistCvsID,
"bin/common",
"bin/common_end",
"${PLIST.cond}bin/conditional",
"bin/os-specific",
"bin/plist")
t.CreateFileLines("PLIST.common",
PlistCvsID,
"bin/common",
"${PLIST.cond}bin/conditional")
t.CreateFileLines("PLIST.common_end",
PlistCvsID,
"bin/common_end",
"${PLIST.cond}bin/conditional")
t.FinishSetUp()
// TODO: Use the same order as in PLIST_SRC_DFLT, see mk/plist/plist.mk.
// PLIST.common
// PLIST.${OPSYS}
// PLIST.${MACHINE_ARCH:C/i[3-6]86/i386/g}
// PLIST.${OPSYS}-${MACHINE_ARCH:C/i[3-6]86/i386/g}
// ${defined(EMUL_PLATFORM):?PLIST.${EMUL_PLATFORM}:}
// PLIST
// PLIST.common_end
//
G.Check(".")
// For example, bin/program is duplicate, but not bin/os-specific.
t.CheckOutputLines(
"ERROR: PLIST.Linux:2: Path bin/common is already listed in PLIST:2.",
"ERROR: PLIST.Linux:3: Path bin/common_end is already listed in PLIST:3.",
"ERROR: PLIST.Linux:4: Path bin/conditional is already listed in PLIST:4.",
"ERROR: PLIST.Linux:6: Path bin/plist is already listed in PLIST:5.",
"ERROR: PLIST.NetBSD:2: Path bin/common is already listed in PLIST:2.",
"ERROR: PLIST.NetBSD:3: Path bin/common_end is already listed in PLIST:3.",
"ERROR: PLIST.NetBSD:4: Path bin/conditional is already listed in PLIST:4.",
"ERROR: PLIST.NetBSD:6: Path bin/plist is already listed in PLIST:5.",
"ERROR: PLIST.common:2: Path bin/common is already listed in PLIST:2.",
"ERROR: PLIST.Linux:2: Path bin/common is already listed in PLIST.common:2.",
"ERROR: PLIST.NetBSD:2: Path bin/common is already listed in PLIST.common:2.",
"ERROR: PLIST.common:3: Path bin/conditional is already listed in PLIST:4.",
"ERROR: PLIST.Linux:4: Path bin/conditional is already listed in PLIST.common:3.",
"ERROR: PLIST.NetBSD:4: Path bin/conditional is already listed in PLIST.common:3.",
"ERROR: PLIST.common_end:2: Path bin/common_end is already listed in PLIST:3.",
"ERROR: PLIST.Linux:3: Path bin/common_end is already listed in PLIST.common_end:2.",
"ERROR: PLIST.NetBSD:3: Path bin/common_end is already listed in PLIST.common_end:2.",
"ERROR: PLIST.common_end:3: Path bin/conditional is already listed in PLIST:4.",
"ERROR: PLIST.Linux:4: Path bin/conditional is already listed in PLIST.common_end:3.",
"ERROR: PLIST.NetBSD:4: Path bin/conditional is already listed in PLIST.common_end:3.",
"ERROR: PLIST.common_end:3: Path bin/conditional is already listed in PLIST.common:3.")
}
func (s *Suite) Test_PlistChecker_checkPathBin(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"bin",
"bin/subdir/program")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: PLIST:3: The bin/ directory should not have subdirectories.")
}
func (s *Suite) Test_PlistChecker_checkPathEtc(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"etc/config")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: PLIST:2: Configuration files must not be registered in the PLIST.")
}
func (s *Suite) Test_PlistChecker_checkPathInfo(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package")
t.Chdir("category/package")
t.CreateFileLines("PLIST",
PlistCvsID,
"info/gmake.1.info")
t.FinishSetUp()
G.Check(".")
t.CheckOutputLines(
"WARN: PLIST:2: Packages that install info files should set INFO_FILES in the Makefile.")
}
func (s *Suite) Test_PlistChecker_checkPathInfo__with_package(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package",
"INFO_FILES=\tyes")
t.Chdir("category/package")
t.CreateFileLines("PLIST",
PlistCvsID,
"info/gmake.1.info")
t.FinishSetUp()
G.Check(".")
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker_checkPathInfo__without_package(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"info/gmake.1.info")
CheckLinesPlist(nil, lines)
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker_checkPathLib(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"lib/charset.alias",
"lib/liberty-1.0.a",
"lib/liberty-1.0.archive",
"lib/liberty-1.0.la",
"lib/locale/de_DE/liberty.mo",
"lib/package/liberty-1.0.so")
pkg := NewPackage(t.File("category/package"))
pkg.EffectivePkgbase = "package"
CheckLinesPlist(pkg, lines)
t.CheckOutputLines(
"ERROR: ~/PLIST:2: Only the libiconv package may install lib/charset.alias.",
"WARN: ~/PLIST:3: Redundant library found. The libtool library is in line 5.",
"WARN: ~/PLIST:5: Packages that install libtool libraries should define USE_LIBTOOL.",
"ERROR: ~/PLIST:6: \"lib/locale\" must not be listed. "+
"Use ${PKGLOCALEDIR}/locale and set USE_PKGLOCALEDIR instead.")
}
func (s *Suite) Test_PlistChecker_checkPathLib__libiconv(c *check.C) {
t := s.Init(c)
t.SetUpPackage("converters/libiconv")
t.Chdir("converters/libiconv")
t.CreateFileLines("PLIST",
PlistCvsID,
"lib/charset.alias")
t.FinishSetUp()
G.Check(".")
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker_checkPathLib__libtool(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package",
"USE_LIBTOOL=\tyes")
t.Chdir("category/package")
t.CreateFileLines("PLIST",
PlistCvsID,
"lib/libname.la")
t.FinishSetUp()
G.Check(".")
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker_checkPathMan(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"man/cat1/formatted.0",
"man/man1/formatted.1",
"man/man1/program.8",
"man/manx/program.x")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: ~/PLIST:4: Mismatch between the section (1) and extension (8) of the manual page.",
"WARN: ~/PLIST:5: Unknown section \"x\" for manual page.")
}
func (s *Suite) Test_PlistChecker_checkPathMan__gz(c *check.C) {
t := s.Init(c)
pkg := NewPackage(t.File("category/package"))
t.Chdir("category/package")
doTest := func(bool) {
lines := t.NewLines("PLIST",
PlistCvsID,
"man/man3/strerror.3.gz")
CheckLinesPlist(pkg, lines)
}
t.ExpectDiagnosticsAutofix(
doTest,
"NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.",
"AUTOFIX: PLIST:2: Replacing \".gz\" with \"\".")
}
func (s *Suite) Test_PlistChecker_checkPathShare(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"share/doc/html/package/index.html",
"share/doc/package/index.html",
"share/icons/hicolor/icon-theme.cache",
"share/icons/open_24x24.svg",
"share/info/program.1.info",
"share/man/man1/program.1")
pkg := NewPackage(t.File("category/package"))
pkg.EffectivePkgbase = "package"
CheckLinesPlist(pkg, lines)
t.CheckOutputLines(
"WARN: ~/PLIST:2: Use of \"share/doc/html\" is deprecated. Use \"share/doc/${PKGBASE}\" instead.",
"ERROR: ~/PLIST:4: Packages that install hicolor icons must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.",
"ERROR: ~/PLIST:4: The file icon-theme.cache must not appear in any PLIST file.",
"WARN: ~/PLIST:4: Packages that install icon theme files should set ICON_THEMES.",
"WARN: ~/PLIST:6: Info pages should be installed into info/, not share/info/.",
"WARN: ~/PLIST:7: Man pages should be installed into man/, not share/man/.")
}
func (s *Suite) Test_PlistChecker_checkPathShareIcons__using_gnome_icon_theme(c *check.C) {
t := s.Init(c)
t.CreateFileBuildlink3("graphics/gnome-icon-theme/buildlink3.mk")
t.SetUpPackage("graphics/gnome-icon-theme-extras",
"ICON_THEMES=\tyes",
".include \"../../graphics/gnome-icon-theme/buildlink3.mk\"")
t.CreateFileLines("graphics/gnome-icon-theme-extras/PLIST",
PlistCvsID,
"share/icons/gnome/16x16/devices/media-optical-cd-audio.png",
"share/icons/gnome/16x16/devices/media-optical-dvd.png")
t.FinishSetUp()
t.Chdir(".")
// This variant is typically run interactively.
G.Check("graphics/gnome-icon-theme-extras")
t.CheckOutputEmpty()
// Note the leading "./".
// This variant is typical for recursive runs of pkglint.
G.Check("./graphics/gnome-icon-theme-extras")
// Up to March 2019, a bug in Relpath produced different behavior
// depending on the leading dot.
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker_checkPathShareIcons__gnome_icon_theme_itself(c *check.C) {
t := s.Init(c)
t.CreateFileBuildlink3("graphics/gnome-icon-theme/buildlink3.mk",
"ICON_THEMES=\tyes")
t.SetUpPackage("graphics/gnome-icon-theme",
".include \"../../graphics/gnome-icon-theme/buildlink3.mk\"")
t.CreateFileLines("graphics/gnome-icon-theme/PLIST",
PlistCvsID,
"share/icons/gnome/16x16/devices/media-optical-cd-audio.png",
"share/icons/gnome/16x16/devices/media-optical-dvd.png")
t.FinishSetUp()
t.Chdir(".")
G.Check("graphics/gnome-icon-theme")
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker_checkPathShareIcons(c *check.C) {
t := s.Init(c)
t.SetUpPackage("graphics/hicolor-icon-theme")
t.CreateFileLines("graphics/hicolor-icon-theme/PLIST",
PlistCvsID,
"share/icons/hicolor/icon-theme.cache",
"share/icons/hicolor/open.svg")
t.SetUpPackage("graphics/other")
t.Copy("graphics/hicolor-icon-theme/PLIST", "graphics/other/PLIST")
t.Chdir(".")
t.FinishSetUp()
G.Check("graphics/hicolor-icon-theme")
G.Check("graphics/other")
t.CheckOutputLines(
"WARN: graphics/hicolor-icon-theme/PLIST:2: "+
"Packages that install icon theme files should set ICON_THEMES.",
"ERROR: graphics/other/PLIST:2: Packages that install hicolor icons "+
"must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.",
"ERROR: graphics/other/PLIST:2: The file icon-theme.cache must not appear in any PLIST file.",
"WARN: graphics/other/PLIST:2: "+
"Packages that install icon theme files should set ICON_THEMES.")
}
func (s *Suite) Test_PlistChecker_checkPathShareIcons__hicolor_ok(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package",
".include \"../../graphics/hicolor-icon-theme/buildlink3.mk\"")
t.CreateFileLines("category/package/PLIST",
PlistCvsID,
"share/icons/hicolor/open.svg")
t.CreateFileLines("graphics/hicolor-icon-theme/buildlink3.mk",
MkCvsID,
"ICON_THEMES=\tyes")
t.FinishSetUp()
G.Check(t.File("category/package"))
t.CheckOutputEmpty()
}
func (s *Suite) Test_PlistChecker_checkPathCond(c *check.C) {
t := s.Init(c)
pkg := t.SetUpPackage("category/package",
"PLIST_VARS+=\tmk-undefined mk-yes both",
"PLIST.mk-yes=\tyes",
"PLIST.both=\tyes")
t.CreateFileLines("category/package/PLIST",
PlistCvsID,
"${PLIST.both}${PLIST.plist}bin/program")
t.FinishSetUp()
G.Check(pkg)
t.CheckOutputLines(
"WARN: ~/category/package/Makefile:20: "+
"\"mk-undefined\" is added to PLIST_VARS, "+
"but PLIST.mk-undefined is not defined in this file.",
"WARN: ~/category/package/PLIST:2: "+
"Condition \"plist\" should be added to PLIST_VARS "+
"in the package Makefile.")
}
func (s *Suite) Test_PlistChecker_checkCond(c *check.C) {
t := s.Init(c)
pkg := t.SetUpPackage("category/package",
"PLIST_VARS+=\tboth mk-yes",
"PLIST.mk-yes=\tyes",
"PLIST.both=\tyes")
t.CreateFileLines("category/package/PLIST",
PlistCvsID,
"${PLIST.both}${PLIST.plist}bin/program",
"${PLIST.both}${PLIST.plist}bin/program2")
t.FinishSetUp()
G.Check(pkg)
t.CheckOutputLines(
"WARN: ~/category/package/PLIST:2: " +
"Condition \"plist\" should be added to PLIST_VARS " +
"in the package Makefile.")
}
// Because of the unresolvable variable in the package Makefile,
// pkglint cannot be absolutely sure about the possible PLIST
// conditions. Therefore all such warnings are suppressed.
//
// As of January 2020, this case typically occurs when PLIST_VARS
// is defined based on PKG_SUPPORTED_OPTIONS. Expanding that variable
// typically contains ${_o_} and ${_opt_}.
//
// See audio/cmus for an example package.
func (s *Suite) Test_PlistChecker_checkCond__unresolvable_variable(c *check.C) {
t := s.Init(c)
pkg := t.SetUpPackage("category/package",
"PLIST_VARS+=\tmk-only ${UNRESOLVABLE}",
"PLIST.mk-only=\tyes")
t.CreateFileLines("category/package/PLIST",
PlistCvsID,
"${PLIST.plist}bin/program")
t.FinishSetUp()
G.Check(pkg)
t.CheckOutputLines(
"WARN: ~/category/package/Makefile:20: " +
"UNRESOLVABLE is used but not defined.")
}
func (s *Suite) Test_PlistChecker_checkCond__hacks_mk(c *check.C) {
t := s.Init(c)
t.SetUpPackage("category/package",
"PLIST_VARS+=\tmk", // To get past the mkline == nil condition.
"PLIST.mk=\tyes")
t.Chdir("category/package")
t.CreateFileLines("hacks.mk",
MkCvsID,
"PLIST_VARS+=\thack",
"PLIST.hack=\tyes")
t.CreateFileLines("PLIST",
PlistCvsID,
"${PLIST.hack}${PLIST.plist}bin/program")
t.FinishSetUp()
G.Check(".")
// Since hacks.mk is included implicitly into the package Makefile,
// the condition that is defined there may be used in the PLIST.
t.CheckOutputLines(
"WARN: PLIST:2: Condition \"plist\" should be added to PLIST_VARS " +
"in the package Makefile.")
}
func (s *Suite) Test_PlistChecker_checkOmf__autofix(c *check.C) {
t := s.Init(c)
t.CreateFileLines("mk/omf-scrollkeeper.mk",
MkCvsID)
t.SetUpPackage("category/package",
".include \"../../mk/omf-scrollkeeper.mk\"")
t.Chdir("category/package")
t.FinishSetUp()
t.ExpectDiagnosticsAutofix(
func(bool) { G.checkdirPackage(".") },
"ERROR: Makefile:20: Only packages that have .omf files in "+
"their PLIST may include omf-scrollkeeper.mk.",
"AUTOFIX: Makefile:20: Deleting this line.")
}
func (s *Suite) Test_PlistChecker_checkOmf__rationale(c *check.C) {
t := s.Init(c)
t.CreateFileLines("mk/omf-scrollkeeper.mk",
MkCvsID)
t.SetUpPackage("category/package",
".include \"../../mk/omf-scrollkeeper.mk\" # needs to stay")
t.Chdir("category/package")
t.FinishSetUp()
t.ExpectDiagnosticsAutofix(
func(bool) { G.checkdirPackage(".") },
"ERROR: Makefile:20: Only packages that have .omf files in "+
"their PLIST may include omf-scrollkeeper.mk.")
}
func (s *Suite) Test_PlistChecker_checkOmf__ok(c *check.C) {
t := s.Init(c)
t.CreateFileLines("mk/omf-scrollkeeper.mk",
MkCvsID)
t.SetUpPackage("category/package",
".include \"../../mk/omf-scrollkeeper.mk\" # needs to stay")
t.Chdir("category/package")
t.CreateFileLines("PLIST",
PlistCvsID,
"bin/program",
"share/omf/documentation.omf")
t.FinishSetUp()
t.ExpectDiagnosticsAutofix(
func(bool) { G.checkdirPackage(".") },
nil...)
}
func (s *Suite) Test_PlistLine_HasPath(c *check.C) {
t := s.Init(c)
test := func(text string, hasPath bool) {
t.CheckEquals((&PlistLine{text: text}).HasPath(), hasPath)
}
test("abc", true)
test("9plan", true)
test("bin/program", true)
test("", false)
test("@", false)
test(":", false)
test("/absolute", false)
test("-rf", false)
test("\\", false)
test("bin/$<", true)
test("bin/${VAR}", true)
}
func (s *Suite) Test_PlistLine_HasPlainPath(c *check.C) {
t := s.Init(c)
test := func(text string, hasPlainPath bool) {
t.CheckEquals((&PlistLine{text: text}).HasPlainPath(), hasPlainPath)
}
test("abc", true)
test("9plan", true)
test("bin/program", true)
test("", false)
test("@", false)
test(":", false)
test("/absolute", false)
test("-rf", false)
test("\\", false)
test("bin/$<", false)
test("bin/${VAR}", false)
}
func (s *Suite) Test_PlistLine_Path(c *check.C) {
t := s.Init(c)
t.CheckEquals(
(&PlistLine{text: "relative"}).Path(),
NewRelPathString("relative"))
t.ExpectAssert(
func() { (&PlistLine{text: "/absolute"}).Path() })
}
func (s *Suite) Test_PlistLine_CheckTrailingWhitespace(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"bin/space ",
"bin/space-tab \t",
"bin/tab\t")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"ERROR: ~/PLIST:2: Pkgsrc does not support filenames ending in whitespace.",
"WARN: ~/PLIST:3: Non-ASCII filename \"bin/space-tab \\t\".",
"ERROR: ~/PLIST:3: Pkgsrc does not support filenames ending in whitespace.",
"ERROR: ~/PLIST:4: Pkgsrc does not support filenames ending in whitespace.")
}
func (s *Suite) Test_PlistLine_CheckDirective(c *check.C) {
t := s.Init(c)
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"@unexec rmdir %D/bin",
"@unexec rmdir %D/bin || true",
"@unexec rmdir %D/bin || ${TRUE}",
"@unexec echo 'uninstalling'",
"@exec ldconfig",
"@exec ldconfig || /usr/bin/true",
"@comment This is a comment",
"@dirrm %D/bin",
"@imake-man 1 2 3 4",
"@imake-man 1 2 ${IMAKE_MANNEWSUFFIX}",
"@imake-man 1 2 3",
"@unknown")
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"WARN: ~/PLIST:2: Please remove this line. It is no longer necessary.",
"ERROR: ~/PLIST:6: The ldconfig command must be used with \"||/usr/bin/true\".",
"WARN: ~/PLIST:9: @dirrm is obsolete. Please remove this line.",
"WARN: ~/PLIST:10: Invalid number of arguments for imake-man, should be 3.",
"WARN: ~/PLIST:11: IMAKE_MANNEWSUFFIX is not meant to appear in PLISTs.",
"WARN: ~/PLIST:13: Unknown PLIST directive \"@unknown\".")
}
func (s *Suite) Test_plistLineSorter__unsortable(c *check.C) {
t := s.Init(c)
t.SetUpCommandLine("-Wall", "--show-autofix")
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"bin/program${OPSYS}",
"@exec true",
"bin/program1")
t.EnableTracingToLog()
CheckLinesPlist(nil, lines)
t.CheckOutputLines(
"TRACE: + CheckLinesPlist(\"~/PLIST\")",
"TRACE: 1 + (*Lines).CheckCvsID(\"@comment \", \"@comment \")",
"TRACE: 1 - (*Lines).CheckCvsID(\"@comment \", \"@comment \")",
"TRACE: 1 ~/PLIST:2: bin/program${OPSYS}: This line prevents pkglint from sorting the PLIST automatically.",
"TRACE: 1 + SaveAutofixChanges()",
"TRACE: 1 - SaveAutofixChanges()",
"TRACE: - CheckLinesPlist(\"~/PLIST\")")
}
func (s *Suite) Test_NewPlistLineSorter__only_comments(c *check.C) {
t := s.Init(c)
lines := t.NewLines("PLIST",
PlistCvsID,
"@comment intentionally left empty")
CheckLinesPlist(nil, lines)
t.CheckOutputEmpty()
}
func (s *Suite) Test_plistLineSorter_Sort(c *check.C) {
t := s.Init(c)
t.SetUpCommandLine("--autofix")
lines := t.SetUpFileLines("PLIST",
PlistCvsID,
"@comment Do not remove",
"A",
"b",
"CCC",
"lib/${UNKNOWN}.la",
"C",
"ddd",
"@exec echo \"after ddd\"", // Makes the PLIST unsortable
"sbin/program",
"${PLIST.one}bin/program",
"man/man1/program.1",
"${PLIST.two}bin/program2",
"lib/before.la",
"${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", // Double condition, see graphics/graphviz
"lib/after.la",
"@exec echo \"after lib/after.la\"")
ck := PlistChecker{nil, nil, nil, "", Once{}, false}
plines := ck.newLines(lines)
sorter1 := NewPlistLineSorter(plines)
t.CheckEquals(sorter1.unsortable, lines.Lines[5])
cleanedLines := append(append(lines.Lines[0:5], lines.Lines[6:8]...), lines.Lines[9:]...) // Remove ${UNKNOWN} and @exec
sorter2 := NewPlistLineSorter((&PlistChecker{nil, nil, nil, "", Once{}, false}).
newLines(NewLines(lines.Filename, cleanedLines)))
c.Check(sorter2.unsortable, check.IsNil)
sorter2.Sort()
t.CheckOutputLines(
"AUTOFIX: ~/PLIST:3: Sorting the whole file.")
t.CheckFileLines("PLIST",
PlistCvsID,
"@comment Do not remove", // The header ends here
"A",
"C",
"CCC",
"b",
"${PLIST.one}bin/program", // Conditional lines are ignored during sorting
"${PLIST.two}bin/program2",
"ddd",
"lib/after.la",
"lib/before.la",
"${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so",
"man/man1/program.1",
"sbin/program",
"@exec echo \"after lib/after.la\"") // The footer starts here
}
func (s *Suite) Test_NewPlistRank(c *check.C) {
t := s.Init(c)
t.SetUpVartypes()
t.CheckDeepEquals(NewPlistRank("PLIST"), &PlistRank{0, "", "", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.common"), &PlistRank{1, "", "", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.common_end"), &PlistRank{2, "", "", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.NetBSD"), &PlistRank{3, "NetBSD", "", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.NetBSD-opt"), &PlistRank{3, "NetBSD", "", "opt"})
t.CheckDeepEquals(NewPlistRank("PLIST.x86_64"), &PlistRank{3, "", "x86_64", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.NetBSD-x86_64"), &PlistRank{3, "NetBSD", "x86_64", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.linux-x86_64"), &PlistRank{3, "linux", "x86_64", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.solaris-sparc"), &PlistRank{3, "solaris", "sparc", ""})
t.CheckDeepEquals(NewPlistRank("PLIST.other"), &PlistRank{3, "", "", "other"})
// To list all current PLIST filenames:
// cd $pkgsrcdir && find . -name 'PLIST*' -printf '%f\n' | sort | uniq -c | sort -nr
}
func (s *Suite) Test_PlistRank_MoreGeneric(c *check.C) {
t := s.Init(c)
t.SetUpVartypes()
plain := NewPlistRank("PLIST")
common := NewPlistRank("PLIST.common")
commonEnd := NewPlistRank("PLIST.common_end")
netbsd := NewPlistRank("PLIST.NetBSD")
netbsdRest := NewPlistRank("PLIST.NetBSD-rest")
x86 := NewPlistRank("PLIST.x86_64")
netbsdX86 := NewPlistRank("PLIST.NetBSD-x86_64")
linuxX86 := NewPlistRank("PLIST.Linux-x86_64")
emulLinuxX86 := NewPlistRank("PLIST.linux-x86_64")
var rel relation
rel.add(plain, common)
rel.add(common, commonEnd)
rel.add(commonEnd, netbsd)
rel.add(commonEnd, x86)
rel.add(commonEnd, linuxX86)
rel.add(netbsd, netbsdX86)
rel.add(netbsd, netbsdRest)
rel.add(x86, netbsdX86)
rel.add(x86, linuxX86)
rel.add(x86, emulLinuxX86)
rel.reflexive = false
rel.transitive = true
rel.antisymmetric = true
rel.onError = func(s string) { c.Error(s) }
rel.check(func(a, b interface{}) bool { return a.(*PlistRank).MoreGeneric(b.(*PlistRank)) })
}
func (s *Suite) Test_NewPlistLines(c *check.C) {
lines := NewPlistLines()
c.Check(lines.all, check.NotNil)
}
func (s *Suite) Test_PlistLines_Add(c *check.C) {
t := s.Init(c)
t.SetUpFileLines("PLIST",
PlistCvsID,
"bin/program")
t.SetUpFileLines("PLIST.common",
PlistCvsID,
"bin/program")
plistLines := NewPlistChecker(nil).Load(Load(t.File("PLIST"), MustSucceed))
plistCommonLines := NewPlistChecker(nil).Load(Load(t.File("PLIST.common"), MustSucceed))
lines := NewPlistLines()
for _, line := range plistLines {
if line.HasPath() {
lines.Add(line, NewPlistRank(line.Basename))
}
}
for _, line := range plistCommonLines {
if line.HasPath() {
lines.Add(line, NewPlistRank(line.Basename))
}
}
t.CheckOutputLines(
// TODO: Wrong order. The diagnostics should be in the same order
// as in mk/plist/plist.mk.
"ERROR: ~/PLIST.common:2: Path bin/program is already listed in PLIST:2.")
}