Refactored the code into separate packages. No functional changes.

This commit is contained in:
rillig 2017-01-29 14:27:48 +00:00
parent c635062088
commit 5bbfc26161
50 changed files with 1318 additions and 902 deletions

View file

@ -1,7 +1,9 @@
package main
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/pkgver"
"netbsd.org/pkglint/textproc"
"netbsd.org/pkglint/trace"
"strings"
)
@ -13,7 +15,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
mklines.Check()
exp := NewExpecter(mklines.lines)
exp := textproc.NewExpecter(mklines.lines)
for exp.AdvanceIfPrefix("#") {
line := exp.PreviousLine()
@ -23,7 +25,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
}
}
exp.ExpectEmptyLine()
exp.ExpectEmptyLine(G.opts.WarnSpace)
if exp.AdvanceIfMatches(`^BUILDLINK_DEPMETHOD\.(\S+)\?=.*$`) {
exp.PreviousLine().Warnf("This line belongs inside the .ifdef block.")
@ -32,7 +34,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
}
pkgbaseLine, pkgbase := exp.CurrentLine(), ""
var abiLine, apiLine Line
var abiLine, apiLine line.Line
var abi, api *DependencyPattern
// First paragraph: Introduction of the package identifier
@ -40,7 +42,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
exp.CurrentLine().Warnf("Expected a BUILDLINK_TREE line.")
return
}
pkgbase = exp.m[1]
pkgbase = exp.Group(1)
if containsVarRef(pkgbase) {
warned := false
for _, pair := range [...]struct{ varuse, simple string }{
@ -70,19 +72,19 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
}
}
exp.ExpectEmptyLine()
exp.ExpectEmptyLine(G.opts.WarnSpace)
// Second paragraph: multiple inclusion protection and introduction
// of the uppercase package identifier.
if !exp.AdvanceIfMatches(`^\.if !defined\((\S+)_BUILDLINK3_MK\)$`) {
return
}
pkgupperLine, pkgupper := exp.PreviousLine(), exp.m[1]
pkgupperLine, pkgupper := exp.PreviousLine(), exp.Group(1)
if !exp.ExpectText(pkgupper + "_BUILDLINK3_MK:=") {
return
}
exp.ExpectEmptyLine()
exp.ExpectEmptyLine(G.opts.WarnSpace)
// See pkgtools/createbuildlink/files/createbuildlink, keyword PKGUPPER
ucPkgbase := strings.ToUpper(strings.Replace(pkgbase, "-", "_", -1))
@ -93,7 +95,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
if G.Pkg != nil {
if mkbase := G.Pkg.EffectivePkgbase; mkbase != "" && mkbase != pkgbase {
pkgbaseLine.Errorf("Package name mismatch between %q in this file and %q from %s.",
pkgbase, mkbase, G.Pkg.EffectivePkgnameLine.Line.ReferenceFrom(pkgbaseLine))
pkgbase, mkbase, G.Pkg.EffectivePkgnameLine.ReferenceFrom(pkgbaseLine))
}
}
@ -106,7 +108,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
}
line := exp.CurrentLine()
mkline := mklines.mklines[exp.index]
mkline := mklines.mklines[exp.Index()]
if mkline.IsVarassign() {
exp.Advance()
@ -185,7 +187,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
if apiLine == nil {
exp.CurrentLine().Warnf("Definition of BUILDLINK_API_DEPENDS is missing.")
}
exp.ExpectEmptyLine()
exp.ExpectEmptyLine(G.opts.WarnSpace)
// Fourth paragraph: Cleanup, corresponding to the first paragraph.
if !exp.ExpectText("BUILDLINK_TREE+=\t-" + pkgbase) {

View file

@ -5,6 +5,7 @@ import (
)
func (s *Suite) Test_ChecklinesBuildlink3Mk(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -27,17 +28,18 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk(c *check.C) {
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, ""+
"ERROR: buildlink3.mk:12: \"/x11/Xbae\" does not exist.\n"+
"ERROR: buildlink3.mk:12: There is no package in \"x11/Xbae\".\n"+
"ERROR: buildlink3.mk:14: \"/mk/motif.buildlink3.mk\" does not exist.\n"+
"ERROR: buildlink3.mk:2: This comment indicates unfinished work (url2pkg).\n")
s.CheckOutputLines(
"ERROR: buildlink3.mk:12: \"/x11/Xbae\" does not exist.",
"ERROR: buildlink3.mk:12: There is no package in \"x11/Xbae\".",
"ERROR: buildlink3.mk:14: \"/mk/motif.buildlink3.mk\" does not exist.",
"ERROR: buildlink3.mk:2: This comment indicates unfinished work (url2pkg).")
}
// Before version 5.3, pkglint wrongly warned here.
// The mk/haskell.mk file takes care of constructing the correct PKGNAME,
// but pkglint had not looked at that file.
func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
G.Pkg = NewPackage("x11/hs-X11")
G.Pkg.EffectivePkgbase = "X11"
@ -59,10 +61,12 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch(c *check.C) {
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, "ERROR: buildlink3.mk:3: Package name mismatch between \"hs-X11\" in this file and \"X11\" from Makefile:3.\n")
s.CheckOutputLines(
"ERROR: buildlink3.mk:3: Package name mismatch between \"hs-X11\" in this file and \"X11\" from Makefile:3.")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_multiple_inclusion(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -78,12 +82,13 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_multiple_inclusion(c *
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, ""+
"ERROR: buildlink3.mk:5: Package name mismatch between multiple-inclusion guard \"PKGBASE2\" (expected \"PKGBASE1\") and package name \"pkgbase1\" (from line 3).\n"+
"WARN: buildlink3.mk:9: Definition of BUILDLINK_API_DEPENDS is missing.\n")
s.CheckOutputLines(
"ERROR: buildlink3.mk:5: Package name mismatch between multiple-inclusion guard \"PKGBASE2\" (expected \"PKGBASE1\") and package name \"pkgbase1\" (from line 3).",
"WARN: buildlink3.mk:9: Definition of BUILDLINK_API_DEPENDS is missing.")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_abi_api(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -102,10 +107,12 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_abi_api(c *check.C) {
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, "WARN: buildlink3.mk:9: Package name mismatch between ABI \"hs-X12\" and API \"hs-X11\" (from line 8).\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:9: Package name mismatch between ABI \"hs-X12\" and API \"hs-X11\" (from line 8).")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_abi_api_versions(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -124,11 +131,12 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_abi_api_versions(c *check.C) {
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, ""+
"WARN: buildlink3.mk:9: ABI version \"1.6.0\" should be at least API version \"1.6.1\" (see line 8).\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:9: ABI version \"1.6.0\" should be at least API version \"1.6.1\" (see line 8).")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_beginning(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -146,10 +154,12 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_beginning(c *ch
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, "WARN: buildlink3.mk:3: Expected a BUILDLINK_TREE line.\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:3: Expected a BUILDLINK_TREE line.")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_end(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -171,12 +181,13 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_end(c *check.C)
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, ""+
"WARN: buildlink3.mk:3: This line belongs inside the .ifdef block.\n"+
"WARN: buildlink3.mk:15: This line should contain the following text: BUILDLINK_TREE+=\t-hs-X11\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:3: This line belongs inside the .ifdef block.",
"WARN: buildlink3.mk:15: This line should contain the following text: BUILDLINK_TREE+=\t-hs-X11")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_multiple_inclusion_wrong(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -188,12 +199,13 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_multiple_inclusion_wrong(c *check.C)
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, ""+
"WARN: buildlink3.mk:6: UNRELATED_BUILDLINK3_MK is defined but not used. Spelling mistake?\n"+
"WARN: buildlink3.mk:6: This line should contain the following text: HS_X11_BUILDLINK3_MK:=\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:6: UNRELATED_BUILDLINK3_MK is defined but not used. Spelling mistake?",
"WARN: buildlink3.mk:6: This line should contain the following text: HS_X11_BUILDLINK3_MK:=")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_missing_endif(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -205,10 +217,12 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_missing_endif(c *check.C) {
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, "WARN: buildlink3.mk:EOF: Expected .endif\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:EOF: Expected .endif")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_unknown_dependency_patterns(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -228,12 +242,13 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_unknown_dependency_patterns(c *check
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, ""+
"WARN: buildlink3.mk:9: Unknown dependency pattern \"hs-X11!=1.6.1\".\n"+
"WARN: buildlink3.mk:10: Unknown dependency pattern \"hs-X11!=1.6.1.2nb2\".\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:9: Unknown dependency pattern \"hs-X11!=1.6.1\".",
"WARN: buildlink3.mk:10: Unknown dependency pattern \"hs-X11!=1.6.1.2nb2\".")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_variable(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -252,10 +267,12 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_variable(c *check.C) {
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, "WARN: buildlink3.mk:3: Please use \"py\" instead of \"${PYPKGPREFIX}\" (also in other variables in this file).\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:3: Please use \"py\" instead of \"${PYPKGPREFIX}\" (also in other variables in this file).")
}
func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_unknown_variable(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("buildlink3.mk",
mkrcsid,
@ -274,7 +291,7 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_unknown_variable(c *che
ChecklinesBuildlink3Mk(mklines)
c.Check(s.Output(), equals, ""+
"WARN: buildlink3.mk:3: Please replace \"${LICENSE}\" with a simple string (also in other variables in this file).\n"+
"WARN: buildlink3.mk:13: This line should contain the following text: BUILDLINK_TREE+=\t-${LICENSE}-wxWidgets\n")
s.CheckOutputLines(
"WARN: buildlink3.mk:3: Please replace \"${LICENSE}\" with a simple string (also in other variables in this file).",
"WARN: buildlink3.mk:13: This line should contain the following text: BUILDLINK_TREE+=\t-${LICENSE}-wxWidgets")
}

View file

@ -1,6 +1,8 @@
package main
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/textproc"
"netbsd.org/pkglint/trace"
"sort"
)
@ -18,21 +20,21 @@ func CheckdirCategory() {
mklines := NewMkLines(lines)
mklines.Check()
exp := NewExpecter(lines)
exp := textproc.NewExpecter(lines)
for exp.AdvanceIfPrefix("#") {
}
exp.ExpectEmptyLine()
exp.ExpectEmptyLine(G.opts.WarnSpace)
if exp.AdvanceIfMatches(`^COMMENT=\t*(.*)`) {
MkLineChecker{mklines.mklines[exp.index-1]}.CheckValidCharactersInValue(`[- '(),/0-9A-Za-z]`)
MkLineChecker{mklines.mklines[exp.Index()-1]}.CheckValidCharactersInValue(`[- '(),/0-9A-Za-z]`)
} else {
exp.CurrentLine().Errorf("COMMENT= line expected.")
}
exp.ExpectEmptyLine()
exp.ExpectEmptyLine(G.opts.WarnSpace)
type subdir struct {
name string
line Line
line line.Line
active bool
}
@ -96,7 +98,7 @@ func CheckdirCategory() {
var subdirs []string
var line Line
var line line.Line
mActive := false
for !(mAtend && fAtend) {
@ -153,10 +155,10 @@ func CheckdirCategory() {
// the pkgsrc-wip category Makefile defines its own targets for
// generating indexes and READMEs. Just skip them.
if G.Wip {
exp.index = len(exp.lines) - 2
exp.SkipToFooter()
}
exp.ExpectEmptyLine()
exp.ExpectEmptyLine(G.opts.WarnSpace)
exp.ExpectText(".include \"../mk/misc/category.mk\"")
if !exp.EOF() {
exp.CurrentLine().Errorf("The file should end here.")

View file

@ -51,5 +51,6 @@ func (s *Suite) Test_CheckdirCategory_invalid_comment(c *check.C) {
CheckdirCategory()
c.Check(s.Output(), equals, "WARN: ~/archivers/Makefile:2: COMMENT contains invalid characters (U+005C U+0024 U+0024 U+0024 U+0024 U+0022).\n")
s.CheckOutputLines(
"WARN: ~/archivers/Makefile:2: COMMENT contains invalid characters (U+005C U+0024 U+0024 U+0024 U+0024 U+0022).")
}

View file

@ -11,6 +11,7 @@ import (
"testing"
check "gopkg.in/check.v1"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/textproc"
"netbsd.org/pkglint/trace"
)
@ -61,6 +62,18 @@ func (s *Suite) Output() string {
return output
}
func (s *Suite) CheckOutputEmpty() {
s.c().Check(s.Output(), equals, "")
}
func (s *Suite) CheckOutputLines(expectedLines ...string) {
expectedOutput := ""
for _, expectedLine := range expectedLines {
expectedOutput += expectedLine + "\n"
}
s.c().Check(s.Output(), equals, expectedOutput)
}
// Arguments are either (lineno, orignl) or (lineno, orignl, textnl).
func (s *Suite) NewRawLines(args ...interface{}) []*RawLine {
rawlines := make([]*RawLine, len(args)/2)
@ -81,8 +94,8 @@ func (s *Suite) NewRawLines(args ...interface{}) []*RawLine {
return rawlines[:j]
}
func (s *Suite) NewLines(fname string, texts ...string) []Line {
result := make([]Line, len(texts))
func (s *Suite) NewLines(fname string, texts ...string) []line.Line {
result := make([]line.Line, len(texts))
for i, text := range texts {
textnl := text + "\n"
result[i] = NewLine(fname, i+1, text, s.NewRawLines(i+1, textnl))

View file

@ -5,11 +5,12 @@ import (
"crypto/sha1"
"fmt"
"io/ioutil"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/trace"
"strings"
)
func ChecklinesDistinfo(lines []Line) {
func ChecklinesDistinfo(lines []line.Line) {
if trace.Tracing {
defer trace.Call1(lines[0].Filename())()
}
@ -46,13 +47,13 @@ type distinfoLinesChecker struct {
distinfoIsCommitted bool
patches map[string]bool // "patch-aa" => true
currentFirstLine Line
currentFirstLine line.Line
currentFilename string
isPatch bool
algorithms []string
}
func (ck *distinfoLinesChecker) checkLines(lines []Line) {
func (ck *distinfoLinesChecker) checkLines(lines []line.Line) {
LineChecker{lines[0]}.CheckRcsid(``, "")
if 1 < len(lines) && lines[1].Text() != "" {
lines[1].Notef("Empty line expected.")
@ -79,7 +80,7 @@ func (ck *distinfoLinesChecker) checkLines(lines []Line) {
ck.onFilenameChange(NewLineEOF(ck.distinfoFilename), "")
}
func (ck *distinfoLinesChecker) onFilenameChange(line Line, nextFname string) {
func (ck *distinfoLinesChecker) onFilenameChange(line line.Line, nextFname string) {
currentFname := ck.currentFilename
if currentFname != "" {
algorithms := strings.Join(ck.algorithms, ", ")
@ -106,7 +107,7 @@ func (ck *distinfoLinesChecker) onFilenameChange(line Line, nextFname string) {
ck.algorithms = nil
}
func (ck *distinfoLinesChecker) checkPatchSha1(line Line, patchFname, distinfoSha1Hex string) {
func (ck *distinfoLinesChecker) checkPatchSha1(line line.Line, patchFname, distinfoSha1Hex string) {
patchBytes, err := ioutil.ReadFile(G.CurrentDir + "/" + patchFname)
if err != nil {
line.Errorf("%s does not exist.", patchFname)
@ -146,7 +147,7 @@ func (ck *distinfoLinesChecker) checkUnrecordedPatches() {
}
// Inter-package check for differing distfile checksums.
func (ck *distinfoLinesChecker) checkGlobalMismatch(line Line, fname, alg, hash string) {
func (ck *distinfoLinesChecker) checkGlobalMismatch(line line.Line, fname, alg, hash string) {
if G.Hash != nil && !hasPrefix(fname, "patch-") { // Intentionally checking the filename instead of ck.isPatch
key := alg + ":" + fname
otherHash := G.Hash[key]
@ -161,7 +162,7 @@ func (ck *distinfoLinesChecker) checkGlobalMismatch(line Line, fname, alg, hash
}
}
func (ck *distinfoLinesChecker) checkUncommittedPatch(line Line, patchName, sha1Hash string) {
func (ck *distinfoLinesChecker) checkUncommittedPatch(line line.Line, patchName, sha1Hash string) {
if ck.isPatch {
patchFname := ck.patchdir + "/" + patchName
if ck.distinfoIsCommitted && !isCommitted(G.CurrentDir+"/"+patchFname) {

View file

@ -22,14 +22,15 @@ func (s *Suite) Test_ChecklinesDistinfo(c *check.C) {
"SHA1 (patch-ab) = 6b98dd609f85a9eb9c4c1e4e7055a6aaa62b7cc7",
"SHA1 (patch-nonexistent) = 1234"))
c.Check(s.Output(), equals, ""+
"ERROR: distinfo:1: Expected \"$"+"NetBSD$\".\n"+
"NOTE: distinfo:2: Empty line expected.\n"+
"ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.\n"+
"WARN: distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".\n")
s.CheckOutputLines(
"ERROR: distinfo:1: Expected \"$"+"NetBSD$\".",
"NOTE: distinfo:2: Empty line expected.",
"ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.",
"WARN: distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".")
}
func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) {
s.Init(c)
otherLine := NewLine("other/distinfo", 7, "dummy", nil)
G.Hash = make(map[string]*Hash)
G.Hash["SHA512:pkgname-1.0.tar.gz"] = &Hash{"asdfasdf", otherLine}
@ -39,9 +40,9 @@ func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) {
"",
"SHA512 (pkgname-1.0.tar.gz) = 12341234"))
c.Check(s.Output(), equals, ""+
"ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from asdfasdf in other/distinfo:7.\n"+
"ERROR: distinfo:EOF: Expected SHA1, RMD160, SHA512, Size checksums for \"pkgname-1.0.tar.gz\", got SHA512.\n")
s.CheckOutputLines(
"ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from asdfasdf in other/distinfo:7.",
"ERROR: distinfo:EOF: Expected SHA1, RMD160, SHA512, Size checksums for \"pkgname-1.0.tar.gz\", got SHA512.")
}
func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) {
@ -63,8 +64,8 @@ func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) {
"",
"SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0"))
c.Check(s.Output(), equals, ""+
"WARN: ~/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.\n")
s.CheckOutputLines(
"WARN: ~/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.")
}
func (s *Suite) Test_ChecklinesDistinfo_unrecorded_patches(c *check.C) {
@ -82,9 +83,9 @@ func (s *Suite) Test_ChecklinesDistinfo_unrecorded_patches(c *check.C) {
"SHA512 (distfile.tar.gz) = ...",
"Size (distfile.tar.gz) = 1024 bytes"))
c.Check(s.Output(), equals, ""+
"ERROR: ~/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".\n"+
"ERROR: ~/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".\n")
s.CheckOutputLines(
"ERROR: ~/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".",
"ERROR: ~/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".")
}
func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) {
@ -97,6 +98,6 @@ func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) {
"",
"SHA1 (patch-aa) = ..."))
c.Check(s.Output(), equals, ""+
"WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".\n")
s.CheckOutputLines(
"WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".")
}

View file

@ -2,11 +2,12 @@ package main
import (
"io/ioutil"
"netbsd.org/pkglint/line"
"os"
"strings"
)
func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line {
func LoadNonemptyLines(fname string, joinBackslashLines bool) []line.Line {
lines, err := readLines(fname, joinBackslashLines)
if err != nil {
NewLineWhole(fname).Errorf("Cannot be read.")
@ -19,7 +20,7 @@ func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line {
return lines
}
func LoadExistingLines(fname string, joinBackslashLines bool) []Line {
func LoadExistingLines(fname string, joinBackslashLines bool) []line.Line {
lines, err := readLines(fname, joinBackslashLines)
if err != nil {
NewLineWhole(fname).Fatalf("Cannot be read.")
@ -30,7 +31,7 @@ func LoadExistingLines(fname string, joinBackslashLines bool) []Line {
return lines
}
func getLogicalLine(fname string, rawLines []*RawLine, pindex *int) Line {
func getLogicalLine(fname string, rawLines []*RawLine, pindex *int) line.Line {
{ // Handle the common case efficiently
index := *pindex
rawLine := rawLines[index]
@ -101,7 +102,7 @@ func splitRawLine(textnl string) (leadingWhitespace, text, trailingWhitespace, c
return
}
func readLines(fname string, joinBackslashLines bool) ([]Line, error) {
func readLines(fname string, joinBackslashLines bool) ([]line.Line, error) {
rawText, err := ioutil.ReadFile(fname)
if err != nil {
return nil, err
@ -110,7 +111,7 @@ func readLines(fname string, joinBackslashLines bool) ([]Line, error) {
return convertToLogicalLines(fname, string(rawText), joinBackslashLines), nil
}
func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []Line {
func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []line.Line {
var rawLines []*RawLine
for lineno, rawLine := range strings.SplitAfter(rawText, "\n") {
if rawLine != "" {
@ -118,7 +119,7 @@ func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool
}
}
var loglines []Line
var loglines []line.Line
if joinBackslashLines {
for lineno := 0; lineno < len(rawLines); {
loglines = append(loglines, getLogicalLine(fname, rawLines, &lineno))
@ -138,7 +139,7 @@ func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool
return loglines
}
func SaveAutofixChanges(lines []Line) (autofixed bool) {
func SaveAutofixChanges(lines []line.Line) (autofixed bool) {
if !G.opts.Autofix {
for _, line := range lines {
if line.IsChanged() {

View file

@ -72,9 +72,9 @@ func (s *Suite) Test_show_autofix(c *check.C) {
c.Check(lines[1].(*LineImpl).raw[0].textnl, equals, "XXXXX\n")
c.Check(s.LoadTmpFile("Makefile"), equals, "line1\nline2\nline3\n")
c.Check(s.Output(), equals, ""+
"WARN: ~/Makefile:2: Something's wrong here.\n"+
"AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".\n")
s.CheckOutputLines(
"WARN: ~/Makefile:2: Something's wrong here.",
"AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".")
}
func (s *Suite) Test_autofix(c *check.C) {
@ -92,7 +92,7 @@ func (s *Suite) Test_autofix(c *check.C) {
SaveAutofixChanges(lines)
c.Check(s.LoadTmpFile("Makefile"), equals, "line1\nXXXXX\nline3\n")
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".\n"+
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".",
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
}

View file

@ -2,6 +2,7 @@ package main
import (
"io/ioutil"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"path"
@ -20,7 +21,7 @@ type GlobalData struct {
suggestedUpdates []SuggestedUpdate //
suggestedWipUpdates []SuggestedUpdate //
LastChange map[string]*Change //
UserDefinedVars map[string]*MkLine // varname => line
UserDefinedVars map[string]MkLine // varname => line
Deprecated map[string]string //
vartypes map[string]*Vartype // varcanon => type
latest map[string]string // "lang/php[0-9]*" => "lang/php70"
@ -28,7 +29,7 @@ type GlobalData struct {
// Change is a change entry from the `doc/CHANGES-*` files.
type Change struct {
Line Line
Line line.Line
Action string
Pkgpath string
Version string
@ -38,7 +39,7 @@ type Change struct {
// SuggestedUpdate is from the `doc/TODO` file.
type SuggestedUpdate struct {
Line Line
Line line.Line
Pkgname string
Version string
Comment string
@ -253,7 +254,7 @@ func loadSuggestedUpdates(fname string) []SuggestedUpdate {
return parselinesSuggestedUpdates(lines)
}
func parselinesSuggestedUpdates(lines []Line) []SuggestedUpdate {
func parselinesSuggestedUpdates(lines []line.Line) []SuggestedUpdate {
var updates []SuggestedUpdate
state := 0
for _, line := range lines {
@ -294,7 +295,7 @@ func (gd *GlobalData) loadSuggestedUpdates() {
func (gd *GlobalData) loadDocChangesFromFile(fname string) []*Change {
lines := LoadExistingLines(fname, false)
parseChange := func(line Line) *Change {
parseChange := func(line line.Line) *Change {
text := line.Text()
if !hasPrefix(text, "\t") {
return nil
@ -374,7 +375,7 @@ func (gd *GlobalData) loadUserDefinedVars() {
lines := LoadExistingLines(G.globalData.Pkgsrcdir+"/mk/defaults/mk.conf", true)
mklines := NewMkLines(lines)
gd.UserDefinedVars = make(map[string]*MkLine)
gd.UserDefinedVars = make(map[string]MkLine)
for _, mkline := range mklines.mklines {
if mkline.IsVarassign() {
gd.UserDefinedVars[mkline.Varname()] = mkline
@ -603,7 +604,7 @@ func (tr *ToolRegistry) Trace() {
}
}
func (tr *ToolRegistry) ParseToolLine(line Line) {
func (tr *ToolRegistry) ParseToolLine(line line.Line) {
if m, varname, _, _, _, value, _, _ := MatchVarassign(line.Text()); m {
if varname == "TOOLS_CREATE" && (value == "[" || matches(value, `^?[-\w.]+$`)) {
tr.Register(value)

View file

@ -100,12 +100,14 @@ func (s *Suite) Test_GlobalData_loadDocChangesFromFile(c *check.C) {
}
func (s *Suite) Test_GlobalData_deprecated(c *check.C) {
s.Init(c)
G.globalData.loadDeprecatedVars()
line := NewLine("Makefile", 5, "USE_PERL5=\tyes", nil)
MkLineChecker{NewMkLine(line)}.checkVarassign()
c.Check(s.Output(), equals, "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.\n")
s.CheckOutputLines(
"WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.")
}
// https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html

View file

@ -3,6 +3,7 @@ package main
import (
"io"
"netbsd.org/pkglint/histogram"
"netbsd.org/pkglint/line"
)
type GlobalVars struct {
@ -19,7 +20,7 @@ type GlobalVars struct {
Testing bool // Is pkglint in self-testing mode (only during development)?
CurrentUsername string // For checking against OWNER and MAINTAINER
CvsEntriesDir string // Cached to avoid I/O
CvsEntriesLines []Line
CvsEntriesLines []line.Line
Hash map[string]*Hash // Maps "alg:fname" => hash (inter-package check).
UsedLicenses map[string]bool // Maps "license name" => true (inter-package check).
@ -81,7 +82,7 @@ type CmdOpts struct {
type Hash struct {
hash string
line Line
line line.Line
}
var G GlobalVars

View file

@ -24,7 +24,7 @@ func checkToplevelUnusedLicenses() {
}
type LicenseChecker struct {
MkLine *MkLine
MkLine MkLine
}
func (lc *LicenseChecker) Check(value string, op MkOperator) {
@ -47,7 +47,7 @@ func (lc *LicenseChecker) checkLicenseName(license string) {
var licenseFile string
if G.Pkg != nil {
if licenseFileValue, ok := G.Pkg.varValue("LICENSE_FILE"); ok {
licenseFile = G.CurrentDir + "/" + lc.MkLine.resolveVarsInRelativePath(licenseFileValue, false)
licenseFile = G.CurrentDir + "/" + lc.MkLine.ResolveVarsInRelativePath(licenseFileValue, false)
}
}
if licenseFile == "" {

View file

@ -14,29 +14,32 @@ func (s *Suite) Test_checklineLicense(c *check.C) {
licenseChecker := &LicenseChecker{mkline}
licenseChecker.Check("gpl-v2", opAssign)
c.Check(s.Output(), equals, "WARN: Makefile:7: License file ~/licenses/gpl-v2 does not exist.\n")
s.CheckOutputLines(
"WARN: Makefile:7: License file ~/licenses/gpl-v2 does not exist.")
licenseChecker.Check("no-profit shareware", opAssign)
c.Check(s.Output(), equals, "ERROR: Makefile:7: Parse error for license condition \"no-profit shareware\".\n")
s.CheckOutputLines(
"ERROR: Makefile:7: Parse error for license condition \"no-profit shareware\".")
licenseChecker.Check("no-profit AND shareware", opAssign)
c.Check(s.Output(), equals, ""+
"WARN: Makefile:7: License file ~/licenses/no-profit does not exist.\n"+
"ERROR: Makefile:7: License \"no-profit\" must not be used.\n"+
"WARN: Makefile:7: License file ~/licenses/shareware does not exist.\n"+
"ERROR: Makefile:7: License \"shareware\" must not be used.\n")
s.CheckOutputLines(
"WARN: Makefile:7: License file ~/licenses/no-profit does not exist.",
"ERROR: Makefile:7: License \"no-profit\" must not be used.",
"WARN: Makefile:7: License file ~/licenses/shareware does not exist.",
"ERROR: Makefile:7: License \"shareware\" must not be used.")
licenseChecker.Check("gnu-gpl-v2", opAssign)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
licenseChecker.Check("gnu-gpl-v2 AND gnu-gpl-v2 OR gnu-gpl-v2", opAssign)
c.Check(s.Output(), equals, "ERROR: Makefile:7: AND and OR operators in license conditions can only be combined using parentheses.\n")
s.CheckOutputLines(
"ERROR: Makefile:7: AND and OR operators in license conditions can only be combined using parentheses.")
licenseChecker.Check("(gnu-gpl-v2 OR gnu-gpl-v2) AND gnu-gpl-v2", opAssign)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}

View file

@ -16,6 +16,7 @@ package main
import (
"fmt"
"io"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"path"
"strconv"
@ -32,28 +33,6 @@ func (rline *RawLine) String() string {
return strconv.Itoa(rline.Lineno) + ":" + rline.textnl
}
type Line interface {
fmt.Stringer
Filename() string
Linenos() string
Text() string
IsMultiline() bool
IsChanged() bool
Fatalf(fmt string, args ...interface{})
Errorf(fmt string, args ...interface{})
Warnf(fmt string, args ...interface{})
Notef(fmt string, args ...interface{})
ReferenceFrom(Line) string
AutofixReplace(from, to string) bool
AutofixReplaceRegexp(from regex.RegexPattern, to string) bool
AutofixInsertBefore(text string) bool
AutofixDelete() bool
AutofixMark(reason string)
}
type LineImpl struct {
fname string
firstLine int32 // Zero means not applicable, -1 means EOF
@ -66,22 +45,22 @@ type LineImpl struct {
autofixMessage string
}
func NewLine(fname string, lineno int, text string, rawLines []*RawLine) Line {
func NewLine(fname string, lineno int, text string, rawLines []*RawLine) line.Line {
return NewLineMulti(fname, lineno, lineno, text, rawLines)
}
// NewLineMulti is for logical Makefile lines that end with backslash.
func NewLineMulti(fname string, firstLine, lastLine int, text string, rawLines []*RawLine) Line {
func NewLineMulti(fname string, firstLine, lastLine int, text string, rawLines []*RawLine) line.Line {
return &LineImpl{fname, int32(firstLine), int32(lastLine), text, rawLines, false, nil, nil, ""}
}
// NewLineEOF creates a dummy line for logging, with the "line number" EOF.
func NewLineEOF(fname string) Line {
func NewLineEOF(fname string) line.Line {
return NewLineMulti(fname, -1, 0, "", nil)
}
// NewLineWhole creates a dummy line for logging messages that affect a file as a whole.
func NewLineWhole(fname string) Line {
func NewLineWhole(fname string) line.Line {
return NewLine(fname, 0, "", nil)
}
@ -120,7 +99,7 @@ func (line *LineImpl) Linenos() string {
}
}
func (line *LineImpl) ReferenceFrom(other Line) string {
func (line *LineImpl) ReferenceFrom(other line.Line) string {
if line.fname != other.Filename() {
return cleanpath(relpath(path.Dir(other.Filename()), line.fname)) + ":" + line.Linenos()
}
@ -260,3 +239,7 @@ func (line *LineImpl) AutofixMark(reason string) {
line.logAutofix()
line.changed = true
}
func init() {
line.NewLineEOF = NewLineEOF
}

View file

@ -0,0 +1,30 @@
package line
import (
"fmt"
"netbsd.org/pkglint/regex"
)
type Line interface {
fmt.Stringer
Filename() string
Linenos() string
Text() string
IsMultiline() bool
IsChanged() bool
Fatalf(fmt string, args ...interface{})
Errorf(fmt string, args ...interface{})
Warnf(fmt string, args ...interface{})
Notef(fmt string, args ...interface{})
ReferenceFrom(Line) string
AutofixReplace(from, to string) bool
AutofixReplaceRegexp(from regex.RegexPattern, to string) bool
AutofixInsertBefore(text string) bool
AutofixDelete() bool
AutofixMark(reason string)
}
var NewLineEOF func(filename string) Line

View file

@ -66,14 +66,14 @@ func (s *Suite) Test_Line_show_autofix_AutofixReplace(c *check.C) {
line.Warnf("Using \"old\" is deprecated.")
}
c.Check(s.Output(), equals, ""+
"\n"+
"> before\n"+
"- The old song\n"+
"+ The new song\n"+
"> after\n"+
"WARN: Makefile:27--29: Using \"old\" is deprecated.\n"+
"AUTOFIX: Makefile:27--29: Replacing \"old\" with \"new\".\n")
s.CheckOutputLines(
"",
"> before",
"- The old song",
"+ The new song",
"> after",
"WARN: Makefile:27--29: Using \"old\" is deprecated.",
"AUTOFIX: Makefile:27--29: Replacing \"old\" with \"new\".")
}
func (s *Suite) Test_Line_show_autofix_AutofixInsertBefore(c *check.C) {
@ -85,12 +85,12 @@ func (s *Suite) Test_Line_show_autofix_AutofixInsertBefore(c *check.C) {
line.Warnf("Dummy")
}
c.Check(s.Output(), equals, ""+
"\n"+
"+ inserted\n"+
"> original\n"+
"WARN: Makefile:30: Dummy\n"+
"AUTOFIX: Makefile:30: Inserting a line \"inserted\" before this line.\n")
s.CheckOutputLines(
"",
"+ inserted",
"> original",
"WARN: Makefile:30: Dummy",
"AUTOFIX: Makefile:30: Inserting a line \"inserted\" before this line.")
}
func (s *Suite) Test_Line_show_autofix_AutofixDelete(c *check.C) {
@ -102,9 +102,9 @@ func (s *Suite) Test_Line_show_autofix_AutofixDelete(c *check.C) {
line.Warnf("Dummy")
}
c.Check(s.Output(), equals, ""+
"\n"+
"- to be deleted\n"+
"WARN: Makefile:30: Dummy\n"+
"AUTOFIX: Makefile:30: Deleting this line.\n")
s.CheckOutputLines(
"",
"- to be deleted",
"WARN: Makefile:30: Dummy",
"AUTOFIX: Makefile:30: Deleting this line.")
}

View file

@ -2,12 +2,13 @@ package main
import (
"fmt"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
)
type LineChecker struct {
Line Line
Line line.Line
}
func (ck LineChecker) CheckAbsolutePathname(text string) {

View file

@ -3,23 +3,28 @@ package main
import "gopkg.in/check.v1"
func (s *Suite) Test_LineChecker_CheckAbsolutePathname(c *check.C) {
s.Init(c)
ck := LineChecker{NewLine("Makefile", 1, "# dummy", nil)}
ck.CheckAbsolutePathname("bindir=/bin")
ck.CheckAbsolutePathname("bindir=/../lib")
c.Check(s.Output(), equals, "WARN: Makefile:1: Found absolute pathname: /bin\n")
s.CheckOutputLines(
"WARN: Makefile:1: Found absolute pathname: /bin")
}
func (s *Suite) Test_LineChecker_CheckTrailingWhitespace(c *check.C) {
s.Init(c)
ck := LineChecker{NewLine("Makefile", 32, "The line must go on ", nil)}
ck.CheckTrailingWhitespace()
c.Check(s.Output(), equals, "NOTE: Makefile:32: Trailing white-space.\n")
s.CheckOutputLines(
"NOTE: Makefile:32: Trailing white-space.")
}
func (s *Suite) Test_LineChecker_CheckRcsid(c *check.C) {
s.Init(c)
lines := s.NewLines("fname",
"$"+"NetBSD: dummy $",
"$"+"NetBSD$",
@ -31,8 +36,8 @@ func (s *Suite) Test_LineChecker_CheckRcsid(c *check.C) {
LineChecker{line}.CheckRcsid(``, "")
}
c.Check(s.Output(), equals, ""+
"ERROR: fname:3: Expected \"$"+"NetBSD$\".\n"+
"ERROR: fname:4: Expected \"$"+"NetBSD$\".\n"+
"ERROR: fname:5: Expected \"$"+"NetBSD$\".\n")
s.CheckOutputLines(
"ERROR: fname:3: Expected \"$"+"NetBSD$\".",
"ERROR: fname:4: Expected \"$"+"NetBSD$\".",
"ERROR: fname:5: Expected \"$"+"NetBSD$\".")
}

View file

@ -4,13 +4,59 @@ package main
import (
"fmt"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"strings"
)
type MkLine struct {
Line
type MkLine interface {
line.Line
IsVarassign() bool
Varname() string
Varcanon() string
Varparam() string
Op() MkOperator
ValueAlign() string
Value() string
VarassignComment() string
IsShellcmd() bool
Shellcmd() string
IsComment() bool
IsEmpty() bool
IsCond() bool
Indent() string
Directive() string
Args() string
IsInclude() bool
IsSysinclude() bool
// Indent() works here, too.
MustExist() bool
Includefile() string
ConditionVars() string
SetConditionVars(varnames string) // Initialized lazily
IsDependency() bool
Targets() string
Sources() string
VariableType(varname string) *Vartype
ResolveVarsInRelativePath(relpath string, adjustDepth bool) string
ExtractUsedVariables(value string) []string
WithoutMakeVariables(value string) string
VariableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) NeedsQuoting
DetermineUsedVariables() []string
ExplainRelativeDirs()
}
type MkLineImpl struct {
line.Line
data interface{} // One of the following mkLine* types
}
type mkLineAssign struct {
@ -44,8 +90,8 @@ type mkLineDependency struct {
sources string
}
func NewMkLine(line Line) (mkline *MkLine) {
mkline = &MkLine{Line: line}
func NewMkLine(line line.Line) (mkline *MkLineImpl) {
mkline = &MkLineImpl{Line: line}
text := line.Text()
@ -141,51 +187,58 @@ func NewMkLine(line Line) (mkline *MkLine) {
return mkline
}
func (mkline *MkLine) String() string {
return fmt.Sprintf("%s:%s", mkline.Line.Filename(), mkline.Line.Linenos())
func (mkline *MkLineImpl) String() string {
return fmt.Sprintf("%s:%s", mkline.Filename(), mkline.Linenos())
}
func (mkline *MkLine) IsVarassign() bool { _, ok := mkline.data.(mkLineAssign); return ok }
func (mkline *MkLine) IsShellcmd() bool { _, ok := mkline.data.(mkLineShell); return ok }
func (mkline *MkLine) IsComment() bool { _, ok := mkline.data.(mkLineComment); return ok }
func (mkline *MkLine) IsEmpty() bool { _, ok := mkline.data.(mkLineEmpty); return ok }
func (mkline *MkLine) IsCond() bool { _, ok := mkline.data.(mkLineConditional); return ok }
func (mkline *MkLine) IsInclude() bool {
func (mkline *MkLineImpl) IsVarassign() bool { _, ok := mkline.data.(mkLineAssign); return ok }
func (mkline *MkLineImpl) IsShellcmd() bool { _, ok := mkline.data.(mkLineShell); return ok }
func (mkline *MkLineImpl) IsComment() bool { _, ok := mkline.data.(mkLineComment); return ok }
func (mkline *MkLineImpl) IsEmpty() bool { _, ok := mkline.data.(mkLineEmpty); return ok }
func (mkline *MkLineImpl) IsCond() bool { _, ok := mkline.data.(mkLineConditional); return ok }
func (mkline *MkLineImpl) IsInclude() bool {
incl, ok := mkline.data.(mkLineInclude)
return ok && !incl.sys
}
func (mkline *MkLine) IsSysinclude() bool {
func (mkline *MkLineImpl) IsSysinclude() bool {
incl, ok := mkline.data.(mkLineInclude)
return ok && incl.sys
}
func (mkline *MkLine) IsDependency() bool { _, ok := mkline.data.(mkLineDependency); return ok }
func (mkline *MkLine) Varname() string { return mkline.data.(mkLineAssign).varname }
func (mkline *MkLine) Varcanon() string { return mkline.data.(mkLineAssign).varcanon }
func (mkline *MkLine) Varparam() string { return mkline.data.(mkLineAssign).varparam }
func (mkline *MkLine) Op() MkOperator { return mkline.data.(mkLineAssign).op }
func (mkline *MkLine) ValueAlign() string { return mkline.data.(mkLineAssign).valueAlign }
func (mkline *MkLine) Value() string { return mkline.data.(mkLineAssign).value }
func (mkline *MkLine) VarassignComment() string { return mkline.data.(mkLineAssign).comment }
func (mkline *MkLine) Shellcmd() string { return mkline.data.(mkLineShell).command }
func (mkline *MkLine) Indent() string {
func (mkline *MkLineImpl) IsDependency() bool { _, ok := mkline.data.(mkLineDependency); return ok }
func (mkline *MkLineImpl) Varname() string { return mkline.data.(mkLineAssign).varname }
func (mkline *MkLineImpl) Varcanon() string { return mkline.data.(mkLineAssign).varcanon }
func (mkline *MkLineImpl) Varparam() string { return mkline.data.(mkLineAssign).varparam }
func (mkline *MkLineImpl) Op() MkOperator { return mkline.data.(mkLineAssign).op }
func (mkline *MkLineImpl) ValueAlign() string { return mkline.data.(mkLineAssign).valueAlign }
func (mkline *MkLineImpl) Value() string { return mkline.data.(mkLineAssign).value }
func (mkline *MkLineImpl) VarassignComment() string { return mkline.data.(mkLineAssign).comment }
func (mkline *MkLineImpl) Shellcmd() string { return mkline.data.(mkLineShell).command }
func (mkline *MkLineImpl) Indent() string {
if mkline.IsCond() {
return mkline.data.(mkLineConditional).indent
} else {
return mkline.data.(mkLineInclude).indent
}
}
func (mkline *MkLine) Directive() string { return mkline.data.(mkLineConditional).directive }
func (mkline *MkLine) Args() string { return mkline.data.(mkLineConditional).args }
func (mkline *MkLine) MustExist() bool { return mkline.data.(mkLineInclude).mustexist }
func (mkline *MkLine) Includefile() string { return mkline.data.(mkLineInclude).includeFile }
func (mkline *MkLine) Targets() string { return mkline.data.(mkLineDependency).targets }
func (mkline *MkLine) Sources() string { return mkline.data.(mkLineDependency).sources }
func (mkline *MkLineImpl) Directive() string { return mkline.data.(mkLineConditional).directive }
func (mkline *MkLineImpl) Args() string { return mkline.data.(mkLineConditional).args }
func (mkline *MkLineImpl) MustExist() bool { return mkline.data.(mkLineInclude).mustexist }
func (mkline *MkLineImpl) Includefile() string { return mkline.data.(mkLineInclude).includeFile }
func (mkline *MkLineImpl) Targets() string { return mkline.data.(mkLineDependency).targets }
func (mkline *MkLineImpl) Sources() string { return mkline.data.(mkLineDependency).sources }
func (mkline *MkLine) Tokenize(s string) []*MkToken {
func (mkline *MkLineImpl) ConditionVars() string { return mkline.data.(mkLineInclude).conditionVars }
func (mkline *MkLineImpl) SetConditionVars(varnames string) {
include := mkline.data.(mkLineInclude)
include.conditionVars = varnames
mkline.data = include
}
func (mkline *MkLineImpl) Tokenize(s string) []*MkToken {
if trace.Tracing {
defer trace.Call(mkline, s)()
}
p := NewMkParser(mkline.Line, s, true)
p := NewMkParser(mkline, s, true)
tokens := p.MkTokens()
if p.Rest() != "" {
mkline.Warnf("Pkglint parse error in MkLine.Tokenize at %q.", p.Rest())
@ -193,7 +246,7 @@ func (mkline *MkLine) Tokenize(s string) []*MkToken {
return tokens
}
func (mkline *MkLine) withoutMakeVariables(value string) string {
func (mkline *MkLineImpl) WithoutMakeVariables(value string) string {
valueNovar := value
for {
var m []string
@ -204,7 +257,7 @@ func (mkline *MkLine) withoutMakeVariables(value string) string {
}
}
func (mkline *MkLine) resolveVarsInRelativePath(relpath string, adjustDepth bool) string {
func (mkline *MkLineImpl) ResolveVarsInRelativePath(relpath string, adjustDepth bool) string {
tmp := relpath
tmp = strings.Replace(tmp, "${PKGSRCDIR}", G.CurPkgsrcdir, -1)
tmp = strings.Replace(tmp, "${.CURDIR}", ".", -1)
@ -242,23 +295,18 @@ func (mkline *MkLine) resolveVarsInRelativePath(relpath string, adjustDepth bool
return tmp
}
func (mkline *MkLine) rememberUsedVariables(cond *Tree) {
if G.Mk == nil {
return
}
indentation := &G.Mk.indentation
func (ind *Indentation) RememberUsedVariables(cond *Tree) {
arg0varname := func(node *Tree) {
varname := node.args[0].(string)
indentation.AddVar(varname)
ind.AddVar(varname)
}
arg0varuse := func(node *Tree) {
varuse := node.args[0].(MkVarUse)
indentation.AddVar(varuse.varname)
ind.AddVar(varuse.varname)
}
arg2varuse := func(node *Tree) {
varuse := node.args[2].(MkVarUse)
indentation.AddVar(varuse.varname)
ind.AddVar(varuse.varname)
}
cond.Visit("defined", arg0varname)
cond.Visit("empty", arg0varuse)
@ -268,7 +316,7 @@ func (mkline *MkLine) rememberUsedVariables(cond *Tree) {
cond.Visit("compareVarVar", arg2varuse)
}
func (mkline *MkLine) explainRelativeDirs() {
func (mkline *MkLineImpl) ExplainRelativeDirs() {
Explain(
"Directories in the form \"../../category/package\" make it easier to",
"move a package around in pkgsrc, for example from pkgsrc-wip to the",
@ -334,7 +382,7 @@ func (nq NeedsQuoting) String() string {
return [...]string{"no", "yes", "doesn't matter", "don't know"}[nq]
}
func (mkline *MkLine) variableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting NeedsQuoting) {
func (mkline *MkLineImpl) VariableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting NeedsQuoting) {
if trace.Tracing {
defer trace.Call(varname, vartype, vuc, "=>", &needsQuoting)()
}
@ -443,7 +491,7 @@ func (mkline *MkLine) variableNeedsQuoting(varname string, vartype *Vartype, vuc
// Returns the type of the variable (maybe guessed based on the variable name),
// or nil if the type cannot even be guessed.
func (mkline *MkLine) getVariableType(varname string) *Vartype {
func (mkline *MkLineImpl) VariableType(varname string) *Vartype {
if trace.Tracing {
defer trace.Call1(varname)()
}
@ -522,7 +570,7 @@ func (mkline *MkLine) getVariableType(varname string) *Vartype {
}
// TODO: merge with determineUsedVariables
func (mkline *MkLine) extractUsedVariables(text string) []string {
func (mkline *MkLineImpl) ExtractUsedVariables(text string) []string {
re := regex.Compile(`^(?:[^\$]+|\$[\$*<>?@]|\$\{([.0-9A-Z_a-z]+)(?::(?:[^\${}]|\$[^{])+)?\})`)
rest := text
var result []string
@ -544,8 +592,8 @@ func (mkline *MkLine) extractUsedVariables(text string) []string {
return result
}
func (mkline *MkLine) determineUsedVariables() (varnames []string) {
rest := mkline.Line.Text()
func (mkline *MkLineImpl) DetermineUsedVariables() (varnames []string) {
rest := mkline.Text()
if strings.HasPrefix(rest, "#") {
return

View file

@ -75,10 +75,10 @@ func (s *Suite) Test_VaralignBlock_Check__reduce_indentation(c *check.C) {
}
varalign.Finish()
c.Check(s.Output(), equals, ""+
"NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.\n"+
"NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.\n"+
"NOTE: file.mk:3: This variable value should be aligned to column 9.\n")
s.CheckOutputLines(
"NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.",
"NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.",
"NOTE: file.mk:3: This variable value should be aligned to column 9.")
}
func (s *Suite) Test_VaralignBlock_Check_longest_line_no_space(c *check.C) {
@ -96,11 +96,11 @@ func (s *Suite) Test_VaralignBlock_Check_longest_line_no_space(c *check.C) {
}
varalign.Finish()
c.Check(s.Output(), equals, ""+
"NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
"NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
"NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
"NOTE: file.mk:4: This variable value should be aligned to column 33.\n")
s.CheckOutputLines(
"NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
"NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
"NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
"NOTE: file.mk:4: This variable value should be aligned to column 33.")
}
func (s *Suite) Test_VaralignBlock_Check_only_spaces(c *check.C) {
@ -118,11 +118,11 @@ func (s *Suite) Test_VaralignBlock_Check_only_spaces(c *check.C) {
}
varalign.Finish()
c.Check(s.Output(), equals, ""+
"NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
"NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
"NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
"NOTE: file.mk:4: This variable value should be aligned with tabs, not spaces, to column 33.\n")
s.CheckOutputLines(
"NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
"NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
"NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
"NOTE: file.mk:4: This variable value should be aligned with tabs, not spaces, to column 33.")
}
func (s *Suite) Test_NewMkLine(c *check.C) {
@ -180,7 +180,8 @@ func (s *Suite) Test_NewMkLine(c *check.C) {
c.Check(ln[9].Varcanon(), equals, "VARNAME")
c.Check(ln[9].Varparam(), equals, "")
c.Check(s.Output(), equals, "WARN: test.mk:9: Space before colon in dependency line.\n")
s.CheckOutputLines(
"WARN: test.mk:9: Space before colon in dependency line.")
}
func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) {
@ -195,19 +196,19 @@ func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) {
CheckfileMk(fname)
c.Check(s.Output(), equals, ""+
"WARN: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".\n"+
"WARN: ~/Makefile:4: Unnecessary space after variable name \"VARNAME+\".\n")
s.CheckOutputLines(
"WARN: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".",
"WARN: ~/Makefile:4: Unnecessary space after variable name \"VARNAME+\".")
s.UseCommandLine("-Wspace", "--autofix")
CheckfileMk(fname)
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".\n"+
"AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".\n"+
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n"+
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".",
"AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".",
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.",
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
c.Check(s.LoadTmpFile("Makefile"), equals, ""+
mkrcsid+"\n"+
"VARNAME+=\t${VARNAME}\n"+
@ -216,16 +217,16 @@ func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) {
"pkgbase := pkglint\n")
}
func (s *Suite) Test_MkLine_getVariableType_varparam(c *check.C) {
func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) {
mkline := NewMkLine(NewLine("fname", 1, "# dummy", nil))
G.globalData.InitVartypes()
t1 := mkline.getVariableType("FONT_DIRS")
t1 := mkline.VariableType("FONT_DIRS")
c.Assert(t1, check.NotNil)
c.Check(t1.String(), equals, "ShellList of Pathmask")
t2 := mkline.getVariableType("FONT_DIRS.ttf")
t2 := mkline.VariableType("FONT_DIRS.ttf")
c.Assert(t2, check.NotNil)
c.Check(t2.String(), equals, "ShellList of Pathmask")
@ -234,7 +235,7 @@ func (s *Suite) Test_MkLine_getVariableType_varparam(c *check.C) {
func (s *Suite) Test_VarUseContext_String(c *check.C) {
G.globalData.InitVartypes()
mkline := NewMkLine(NewLine("fname", 1, "# dummy", nil))
vartype := mkline.getVariableType("PKGNAME")
vartype := mkline.VariableType("PKGNAME")
vuc := &VarUseContext{vartype, vucTimeUnknown, vucQuotBackt, false}
c.Check(vuc.String(), equals, "(PkgName time:unknown quoting:backt wordpart:false)")
@ -244,6 +245,7 @@ func (s *Suite) Test_VarUseContext_String(c *check.C) {
// it is escaped by a backslash. In shell commands, on the other hand, it
// is interpreted literally.
func (s *Suite) Test_NewMkLine_numbersign(c *check.C) {
s.Init(c)
mklineVarassignEscaped := NewMkLine(NewLine("fname", 1, "SED_CMD=\t's,\\#,hash,g'", nil))
c.Check(mklineVarassignEscaped.Varname(), equals, "SED_CMD")
@ -257,18 +259,21 @@ func (s *Suite) Test_NewMkLine_numbersign(c *check.C) {
mklineCommandUnescaped := NewMkLine(NewLine("fname", 1, "\t# $ sha1 patches/patch-ac", nil))
c.Check(mklineCommandUnescaped.Shellcmd(), equals, "# $ sha1 patches/patch-ac")
c.Check(s.Output(), equals, "") // No warning about parsing the lonely dollar sign.
s.CheckOutputEmpty() // No warning about parsing the lonely dollar sign.
mklineVarassignUnescaped := NewMkLine(NewLine("fname", 1, "SED_CMD=\t's,#,hash,'", nil))
c.Check(mklineVarassignUnescaped.Value(), equals, "'s,")
c.Check(s.Output(), equals, "WARN: fname:1: The # character starts a comment.\n")
s.CheckOutputLines(
"WARN: fname:1: The # character starts a comment.")
}
func (s *Suite) Test_NewMkLine_leading_space(c *check.C) {
s.Init(c)
_ = NewMkLine(NewLine("rubyversion.mk", 427, " _RUBYVER=\t2.15", nil))
c.Check(s.Output(), equals, "WARN: rubyversion.mk:427: Makefile lines should not start with space characters.\n")
s.CheckOutputLines(
"WARN: rubyversion.mk:427: Makefile lines should not start with space characters.")
}
func (s *Suite) Test_MkLines_Check__extra(c *check.C) {
@ -290,13 +295,13 @@ func (s *Suite) Test_MkLines_Check__extra(c *check.C) {
G.Mk.Check()
c.Check(s.Output(), equals, ""+
"WARN: options.mk:3: The values for PYTHON_VERSIONS_ACCEPTED should be in decreasing order.\n"+
"NOTE: options.mk:4: Please .include \"../../meta-pkgs/kde3/kde3.mk\" instead of this line.\n"+
"NOTE: options.mk:5: Please use \"# empty\", \"# none\" or \"yes\" instead of \"# defined\".\n"+
"WARN: options.mk:7: Please include \"../../mk/bsd.prefs.mk\" before using \"?=\".\n"+
"WARN: options.mk:10: Building the package should take place entirely inside ${WRKSRC}, not \"${WRKSRC}/..\".\n"+
"NOTE: options.mk:10: You can use \"../build\" instead of \"${WRKSRC}/../build\".\n")
s.CheckOutputLines(
"WARN: options.mk:3: The values for PYTHON_VERSIONS_ACCEPTED should be in decreasing order.",
"NOTE: options.mk:4: Please .include \"../../meta-pkgs/kde3/kde3.mk\" instead of this line.",
"NOTE: options.mk:5: Please use \"# empty\", \"# none\" or \"yes\" instead of \"# defined\".",
"WARN: options.mk:7: Please include \"../../mk/bsd.prefs.mk\" before using \"?=\".",
"WARN: options.mk:10: Building the package should take place entirely inside ${WRKSRC}, not \"${WRKSRC}/..\".",
"NOTE: options.mk:10: You can use \"../build\" instead of \"${WRKSRC}/../build\".")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__unknown_rhs(c *check.C) {
@ -304,7 +309,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__unknown_rhs(c *check.C) {
G.globalData.InitVartypes()
vuc := &VarUseContext{G.globalData.vartypes["PKGNAME"], vucTimeParse, vucQuotUnknown, false}
nq := mkline.variableNeedsQuoting("UNKNOWN", nil, vuc)
nq := mkline.VariableNeedsQuoting("UNKNOWN", nil, vuc)
c.Check(nq, equals, nqDontKnow)
}
@ -317,13 +322,13 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__append_URL_to_list_of_URLs(c *
mkline := NewMkLine(NewLine("Makefile", 95, "MASTER_SITES=\t${HOMEPAGE}", nil))
vuc := &VarUseContext{G.globalData.vartypes["MASTER_SITES"], vucTimeRun, vucQuotPlain, false}
nq := mkline.variableNeedsQuoting("HOMEPAGE", G.globalData.vartypes["HOMEPAGE"], vuc)
nq := mkline.VariableNeedsQuoting("HOMEPAGE", G.globalData.vartypes["HOMEPAGE"], vuc)
c.Check(nq, equals, nqNo)
MkLineChecker{mkline}.checkVarassign()
c.Check(s.Output(), equals, "") // Up to pkglint 5.3.6, it warned about a missing :Q here, which was wrong.
s.CheckOutputEmpty() // Up to pkglint 5.3.6, it warned about a missing :Q here, which was wrong.
}
// Assigning lists to lists is ok.
@ -336,7 +341,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__append_list_to_list(c *check.C
MkLineChecker{mkline}.checkVarassign()
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__eval_shell(c *check.C) {
@ -347,9 +352,9 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__eval_shell(c *check.C) {
MkLineChecker{mkline}.checkVarassign()
c.Check(s.Output(), equals, ""+
"WARN: builtin.mk:3: PKG_ADMIN should not be evaluated at load time.\n"+
"NOTE: builtin.mk:3: The :Q operator isn't necessary for ${BUILTIN_PKG.Xfixes} here.\n")
s.CheckOutputLines(
"WARN: builtin.mk:3: PKG_ADMIN should not be evaluated at load time.",
"NOTE: builtin.mk:3: The :Q operator isn't necessary for ${BUILTIN_PKG.Xfixes} here.")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_single_quotes(c *check.C) {
@ -360,7 +365,8 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_single_quotes(c *ch
MkLineChecker{mkline}.checkVarassign()
c.Check(s.Output(), equals, "WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} and make sure the variable appears outside of any quoting characters.\n")
s.CheckOutputLines(
"WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} and make sure the variable appears outside of any quoting characters.")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C) {
@ -374,11 +380,11 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C)
mkrcsid,
"GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};")
G.Mk.determineDefinedVariables()
G.Mk.DetermineDefinedVariables()
MkLineChecker{G.Mk.mklines[1]}.Check()
c.Check(s.Output(), equals, ""+
"WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.\n")
s.CheckOutputLines(
"WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__word_as_part_of_word(c *check.C) {
@ -391,7 +397,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__word_as_part_of_word(c *check.
MkLineChecker{G.Mk.mklines[1]}.Check()
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
// As an argument to ${ECHO}, the :Q modifier should be used, but pkglint
@ -414,9 +420,9 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_as_command_argument(c
MkLineChecker{G.Mk.mklines[1]}.Check()
MkLineChecker{G.Mk.mklines[2]}.Check()
c.Check(s.Output(), equals, ""+
"WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
"WARN: Makefile:3: The exitcode of the left-hand-side command of the pipe operator is ignored.\n")
s.CheckOutputLines(
"WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.",
"WARN: Makefile:3: The exitcode of the left-hand-side command of the pipe operator is ignored.")
}
// Based on mail/mailfront/Makefile.
@ -430,7 +436,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__URL_as_part_of_word_in_list(c
MkLineChecker{G.Mk.mklines[1]}.Check()
c.Check(s.Output(), equals, "") // Don't suggest to use ${HOMEPAGE:Q}.
s.CheckOutputEmpty() // Don't suggest to use ${HOMEPAGE:Q}.
}
// Pkglint currently does not parse $$(subshell) commands very well. As
@ -452,7 +458,8 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_subshell(c *check.C
MkLineChecker{G.Mk.mklines[1]}.Check()
MkLineChecker{G.Mk.mklines[2]}.Check()
c.Check(s.Output(), equals, "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.\n") // Don't suggest to use ${AWK:Q}.
s.CheckOutputLines(
"WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.") // Don't suggest to use ${AWK:Q}.
}
// LDFLAGS (and even more so CPPFLAGS and CFLAGS) may contain special
@ -470,7 +477,8 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__LDFLAGS_in_single_quotes(c *ch
MkLineChecker{G.Mk.mklines[1]}.Check()
MkLineChecker{G.Mk.mklines[2]}.Check()
c.Check(s.Output(), equals, "WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.\n")
s.CheckOutputLines(
"WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.")
}
func (s *Suite) Test_MkLines_Check__MASTER_SITE_in_HOMEPAGE(c *check.C) {
@ -487,11 +495,11 @@ func (s *Suite) Test_MkLines_Check__MASTER_SITE_in_HOMEPAGE(c *check.C) {
G.Mk.Check()
c.Check(s.Output(), equals, ""+
"WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/philsquared/Catch/ directly.\n"+
"WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/ directly.\n"+
"WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.\n"+
"WARN: devel/catch/Makefile:5: HOMEPAGE should not be defined in terms of MASTER_SITEs.\n")
s.CheckOutputLines(
"WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/philsquared/Catch/ directly.",
"WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/ directly.",
"WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.",
"WARN: devel/catch/Makefile:5: HOMEPAGE should not be defined in terms of MASTER_SITEs.")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_quotes_in_subshell_in_shellwords(c *check.C) {
@ -506,7 +514,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_quotes_in_subshell_in_
MkLineChecker{G.Mk.mklines[1]}.Check()
c.Check(s.Output(), equals, "") // Don't suggest ${ECHO:Q} here.
s.CheckOutputEmpty() // Don't suggest ${ECHO:Q} here.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__LDADD_in_BUILDLINK_TRANSFORM(c *check.C) {
@ -519,7 +527,8 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__LDADD_in_BUILDLINK_TRANSFORM(c
MkLineChecker{G.Mk.mklines[0]}.Check()
// Note: The :M* modifier is not necessary, since this is not a GNU Configure package.
c.Check(s.Output(), equals, "WARN: x11/qt5-qtbase/Makefile.common:1: Please use ${BUILDLINK_LDADD.dl:Q} instead of ${BUILDLINK_LDADD.dl:M*}.\n")
s.CheckOutputLines(
"WARN: x11/qt5-qtbase/Makefile.common:1: Please use ${BUILDLINK_LDADD.dl:Q} instead of ${BUILDLINK_LDADD.dl:M*}.")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_message(c *check.C) {
@ -531,7 +540,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_message(c *check.C)
MkLineChecker{G.Mk.mklines[0]}.Check()
c.Check(s.Output(), equals, "") // Don't suggest ${REPLACE_PERL:Q}.
s.CheckOutputEmpty() // Don't suggest ${REPLACE_PERL:Q}.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__guessed_list_variable_in_quotes(c *check.C) {
@ -545,7 +554,8 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__guessed_list_variable_in_quote
G.Mk.Check()
c.Check(s.Output(), equals, "WARN: audio/jack-rack/Makefile:3: The list variable LADSPA_PLUGIN_PATH should not be embedded in a word.\n")
s.CheckOutputLines(
"WARN: audio/jack-rack/Makefile:3: The list variable LADSPA_PLUGIN_PATH should not be embedded in a word.")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__list_in_list(c *check.C) {
@ -558,7 +568,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__list_in_list(c *check.C) {
G.Mk.Check()
c.Check(s.Output(), equals, "") // Don't warn about missing :Q modifiers.
s.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__PKGNAME_and_URL_list_in_URL_list(c *check.C) {
@ -572,7 +582,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__PKGNAME_and_URL_list_in_URL_li
MkLineChecker{G.Mk.mklines[1]}.checkVarassignVaruse()
c.Check(s.Output(), equals, "") // Don't warn about missing :Q modifiers.
s.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check.C) {
@ -591,7 +601,8 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check
// The TOOLS_* variables only contain the path to the tool,
// without any additional arguments that might be necessary.
c.Check(s.Output(), equals, "NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.\n")
s.CheckOutputLines(
"NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.")
}
func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) {
@ -605,7 +616,8 @@ func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) {
G.Mk.Check()
c.Check(s.Output(), equals, "WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".\n")
s.CheckOutputLines(
"WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".")
}
func (s *Suite) Test_MkLines_Check__VERSION_as_wordpart_in_MASTER_SITES(c *check.C) {
@ -632,9 +644,9 @@ func (s *Suite) Test_MkLines_Check__shell_command_as_wordpart_in_ENV_list(c *che
mklines.Check()
c.Check(s.Output(), equals, ""+
"WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.\n"+
"WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.\n")
s.CheckOutputLines(
"WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.",
"WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.")
}
func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) {
@ -648,20 +660,22 @@ func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".\n") // No parse errors.
s.CheckOutputLines(
"WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".") // No parse errors.
}
// See PR 46570, Ctrl+F "3. In lang/perl5".
func (s *Suite) Test_MkLine_getVariableType(c *check.C) {
func (s *Suite) Test_MkLine_VariableType(c *check.C) {
mkline := NewMkLine(dummyLine)
c.Check(mkline.getVariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil)
c.Check(mkline.getVariableType("SOME_DIR").guessed, equals, true)
c.Check(mkline.getVariableType("SOMEDIR").guessed, equals, true)
c.Check(mkline.VariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil)
c.Check(mkline.VariableType("SOME_DIR").guessed, equals, true)
c.Check(mkline.VariableType("SOMEDIR").guessed, equals, true)
}
// PR 51696, security/py-pbkdf2/Makefile, r1.2
func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("Makefile",
mkrcsid,
@ -669,10 +683,23 @@ func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "WARN: Makefile:2: The # character starts a comment.\n")
s.CheckOutputLines(
"WARN: Makefile:2: The # character starts a comment.")
}
func (s *Suite) Test_MkLine_ConditionVars(c *check.C) {
s.Init(c)
var mkline MkLine = NewMkLine(NewLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"", nil))
c.Check(mkline.ConditionVars(), equals, "")
mkline.SetConditionVars("OPSYS")
c.Check(mkline.ConditionVars(), equals, "OPSYS")
}
func (s *Suite) Test_MatchVarassign(c *check.C) {
s.Init(c)
checkVarassign := func(text string, ck check.Checker, varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string) {
type va struct {
varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string

View file

@ -11,14 +11,14 @@ import (
)
type MkLineChecker struct {
MkLine *MkLine
MkLine MkLine
}
func (ck MkLineChecker) Check() {
mkline := ck.MkLine
LineChecker{mkline.Line}.CheckTrailingWhitespace()
LineChecker{mkline.Line}.CheckValidCharacters(`[\t -~]`)
LineChecker{mkline}.CheckTrailingWhitespace()
LineChecker{mkline}.CheckValidCharacters(`[\t -~]`)
switch {
case mkline.IsVarassign():
@ -30,8 +30,8 @@ func (ck MkLineChecker) Check() {
NewShellLine(mkline).CheckShellCommandLine(shellcmd)
case mkline.IsComment():
if hasPrefix(mkline.Line.Text(), "# url2pkg-marker") {
mkline.Line.Errorf("This comment indicates unfinished work (url2pkg).")
if hasPrefix(mkline.Text(), "# url2pkg-marker") {
mkline.Errorf("This comment indicates unfinished work (url2pkg).")
}
case mkline.IsInclude():
@ -58,7 +58,7 @@ func (ck MkLineChecker) checkInclude() {
switch {
case hasSuffix(includefile, "/Makefile"):
mkline.Line.Errorf("Other Makefiles must not be included directly.")
mkline.Errorf("Other Makefiles must not be included directly.")
Explain(
"If you want to include portions of another Makefile, extract",
"the common parts and put them into a Makefile.common. After",
@ -66,7 +66,7 @@ func (ck MkLineChecker) checkInclude() {
"Makefile.common.")
case includefile == "../../mk/bsd.prefs.mk":
if path.Base(mkline.Line.Filename()) == "buildlink3.mk" {
if path.Base(mkline.Filename()) == "buildlink3.mk" {
mkline.Notef("For efficiency reasons, please include bsd.fast.prefs.mk instead of bsd.prefs.mk.")
}
if G.Pkg != nil {
@ -88,7 +88,7 @@ func (ck MkLineChecker) checkInclude() {
mkline.Warnf("Please write \"USE_TOOLS+= intltool\" instead of this line.")
case hasSuffix(includefile, "/builtin.mk"):
mkline.Line.Errorf("%s must not be included directly. Include \"%s/buildlink3.mk\" instead.", includefile, path.Dir(includefile))
mkline.Errorf("%s must not be included directly. Include \"%s/buildlink3.mk\" instead.", includefile, path.Dir(includefile))
}
}
@ -135,7 +135,7 @@ func (ck MkLineChecker) checkCond(forVars map[string]bool) {
ck.CheckCond()
} else if directive == "ifdef" || directive == "ifndef" {
mkline.Line.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.",
mkline.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.",
directive, ifelseStr(directive == "ifdef", "", "!"), args)
} else if directive == "for" {
@ -160,7 +160,7 @@ func (ck MkLineChecker) checkCond(forVars map[string]bool) {
guessed := true
for _, value := range splitOnSpace(values) {
if m, vname := match1(value, `^\$\{(.*)\}`); m {
vartype := mkline.getVariableType(vname)
vartype := mkline.VariableType(vname)
if vartype != nil && !vartype.guessed {
guessed = false
}
@ -169,7 +169,7 @@ func (ck MkLineChecker) checkCond(forVars map[string]bool) {
forLoopType := &Vartype{lkSpace, BtUnknown, []AclEntry{{"*", aclpAllRead}}, guessed}
forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false}
for _, forLoopVar := range mkline.extractUsedVariables(values) {
for _, forLoopVar := range mkline.ExtractUsedVariables(values) {
ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext)
}
}
@ -239,7 +239,7 @@ func (ck MkLineChecker) checkVarassignDefPermissions() {
mkline := ck.MkLine
varname := mkline.Varname()
op := mkline.Op()
vartype := mkline.getVariableType(varname)
vartype := mkline.VariableType(varname)
if vartype == nil {
if trace.Tracing {
trace.Step1("No type definition found for %q.", varname)
@ -247,7 +247,7 @@ func (ck MkLineChecker) checkVarassignDefPermissions() {
return
}
perms := vartype.EffectivePermissions(mkline.Line.Filename())
perms := vartype.EffectivePermissions(mkline.Filename())
var needed AclPermissions
switch op {
case opAssign, opAssignShell, opAssignEval:
@ -270,16 +270,16 @@ func (ck MkLineChecker) checkVarassignDefPermissions() {
alternativeFiles := vartype.AllowedFiles(needed)
switch {
case alternativeActions != 0 && alternativeFiles != "":
mkline.Line.Warnf("The variable %s may not be %s (only %s) in this file; it would be ok in %s.",
mkline.Warnf("The variable %s may not be %s (only %s) in this file; it would be ok in %s.",
varname, needed.HumanString(), alternativeActions.HumanString(), alternativeFiles)
case alternativeFiles != "":
mkline.Line.Warnf("The variable %s may not be %s in this file; it would be ok in %s.",
mkline.Warnf("The variable %s may not be %s in this file; it would be ok in %s.",
varname, needed.HumanString(), alternativeFiles)
case alternativeActions != 0:
mkline.Line.Warnf("The variable %s may not be %s (only %s) in this file.",
mkline.Warnf("The variable %s may not be %s (only %s) in this file.",
varname, needed.HumanString(), alternativeActions.HumanString())
default:
mkline.Line.Warnf("The variable %s may not be %s by any package.",
mkline.Warnf("The variable %s may not be %s by any package.",
varname, needed.HumanString())
}
Explain(
@ -301,7 +301,7 @@ func (ck MkLineChecker) CheckVaruse(varuse *MkVarUse, vuc *VarUseContext) {
}
varname := varuse.varname
vartype := mkline.getVariableType(varname)
vartype := mkline.VariableType(varname)
if G.opts.WarnExtra &&
(vartype == nil || vartype.guessed) &&
!varIsUsed(varname) &&
@ -316,7 +316,7 @@ func (ck MkLineChecker) CheckVaruse(varuse *MkVarUse, vuc *VarUseContext) {
ck.WarnVaruseLocalbase()
}
needsQuoting := mkline.variableNeedsQuoting(varname, vartype, vuc)
needsQuoting := mkline.VariableNeedsQuoting(varname, vartype, vuc)
if vuc.quoting == vucQuotFor {
ck.checkVaruseFor(varname, vartype, needsQuoting)
@ -708,7 +708,7 @@ func (ck MkLineChecker) checkVarassignVaruse() {
time = vucTimeParse
}
vartype := mkline.getVariableType(mkline.Varname())
vartype := mkline.VariableType(mkline.Varname())
if op == opAssignShell {
vartype = shellcommandsContextType
}
@ -725,7 +725,7 @@ func (ck MkLineChecker) checkVarassignVaruseMk(vartype *Vartype, time vucTime) {
defer trace.Call(vartype, time)()
}
mkline := ck.MkLine
tokens := NewMkParser(mkline.Line, mkline.Value(), false).MkTokens()
tokens := NewMkParser(mkline, mkline.Value(), false).MkTokens()
for i, token := range tokens {
if token.Varuse != nil {
spaceLeft := i-1 < 0 || matches(tokens[i-1].Text, `\s$`)
@ -753,7 +753,7 @@ func (ck MkLineChecker) checkVarassignVaruseShell(vartype *Vartype, time vucTime
}
mkline := ck.MkLine
atoms := NewShTokenizer(mkline.Line, mkline.Value(), false).ShAtoms()
atoms := NewShTokenizer(mkline, mkline.Value(), false).ShAtoms()
for i, atom := range atoms {
if atom.Type == shtVaruse {
isWordPart := isWordPart(atoms, i)
@ -811,7 +811,7 @@ func (ck MkLineChecker) checkVarassignSpecific() {
if m, revvarname := match1(value, `\$\{(PKGNAME|PKGVERSION)[:\}]`); m {
if varname == "DIST_SUBDIR" || varname == "WRKSRC" {
mkline.Line.Warnf("%s should not be used in %s, as it includes the PKGREVISION. Please use %s_NOREV instead.", revvarname, varname, revvarname)
mkline.Warnf("%s should not be used in %s, as it includes the PKGREVISION. Please use %s_NOREV instead.", revvarname, varname, revvarname)
}
}
@ -884,7 +884,7 @@ func (ck MkLineChecker) CheckVartype(varname string, op MkOperator, value, comme
}
mkline := ck.MkLine
vartype := mkline.getVariableType(varname)
vartype := mkline.VariableType(varname)
if op == opAssignAppend {
if vartype != nil && !vartype.MayBeAppendedTo() {
@ -915,7 +915,7 @@ func (ck MkLineChecker) CheckVartype(varname string, op MkOperator, value, comme
}
case vartype.kindOfList == lkShell:
words, _ := splitIntoMkWords(mkline.Line, value)
words, _ := splitIntoMkWords(mkline, value)
for _, word := range words {
ck.CheckVartypePrimitive(varname, vartype.basicType, op, word, comment, vartype.guessed)
}
@ -930,8 +930,8 @@ func (ck MkLineChecker) CheckVartypePrimitive(varname string, checker *BasicType
}
mkline := ck.MkLine
valueNoVar := mkline.withoutMakeVariables(value)
ctx := &VartypeCheck{mkline, mkline.Line, varname, op, value, valueNoVar, comment, guessed}
valueNoVar := mkline.WithoutMakeVariables(value)
ctx := &VartypeCheck{mkline, mkline, varname, op, value, valueNoVar, comment, guessed}
checker.checker(ctx)
}
@ -989,7 +989,7 @@ func (ck MkLineChecker) CheckCond() {
defer trace.Call1(mkline.Args())()
}
p := NewMkParser(mkline.Line, mkline.Args(), false)
p := NewMkParser(mkline, mkline.Args(), false)
cond := p.MkCond()
if !p.EOF() {
mkline.Warnf("Invalid conditional %q.", mkline.Args())
@ -1033,7 +1033,9 @@ func (ck MkLineChecker) CheckCond() {
}
})
mkline.rememberUsedVariables(cond)
if G.Mk != nil {
G.Mk.indentation.RememberUsedVariables(cond)
}
}
func (ck MkLineChecker) checkCompareVarStr(varname, op, value string) {
@ -1067,7 +1069,7 @@ func (ck MkLineChecker) CheckRelativePkgdir(pkgdir string) {
mkline := ck.MkLine
ck.CheckRelativePath(pkgdir, true)
pkgdir = mkline.resolveVarsInRelativePath(pkgdir, false)
pkgdir = mkline.ResolveVarsInRelativePath(pkgdir, false)
if m, otherpkgpath := match1(pkgdir, `^(?:\./)?\.\./\.\./([^/]+/[^/]+)$`); m {
if !fileExists(G.globalData.Pkgsrcdir + "/" + otherpkgpath + "/Makefile") {
@ -1093,7 +1095,7 @@ func (ck MkLineChecker) CheckRelativePath(path string, mustExist bool) {
mkline.Errorf("A main pkgsrc package must not depend on a pkgsrc-wip package.")
}
resolvedPath := mkline.resolveVarsInRelativePath(path, true)
resolvedPath := mkline.ResolveVarsInRelativePath(path, true)
if containsVarRef(resolvedPath) {
return
}

View file

@ -12,7 +12,7 @@ func (s *Suite) Test_MkLineChecker_CheckVartype__simple_type(c *check.C) {
c.Assert(vartype1, check.NotNil)
c.Check(vartype1.guessed, equals, false)
vartype := mkline.getVariableType("COMMENT")
vartype := mkline.VariableType("COMMENT")
c.Assert(vartype, check.NotNil)
c.Check(vartype.basicType.name, equals, "Comment")
@ -34,13 +34,14 @@ func (s *Suite) Test_MkLineChecker_CheckVartype(c *check.C) {
// Pkglint once interpreted all lists as consisting of shell tokens,
// splitting this URL at the ampersands.
func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
s.Init(c)
G.Pkg = NewPackage("graphics/gimp-fix-ca")
G.globalData.InitVartypes()
mkline := NewMkLine(NewLine("fname", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=", nil))
MkLineChecker{mkline}.checkVarassign()
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
@ -60,36 +61,42 @@ func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
MkLineChecker{NewMkLine(NewLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone@example.org\"", nil))}.CheckCond()
c.Check(s.Output(), equals, "WARN: fname:1: \"mailto:someone@example.org\" is not a valid URL.\n")
s.CheckOutputLines(
"WARN: fname:1: \"mailto:someone@example.org\" is not a valid URL.")
MkLineChecker{NewMkLine(NewLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])", nil))}.CheckCond()
c.Check(s.Output(), equals, "WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".\n")
s.CheckOutputLines(
"WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
MkLineChecker{NewMkLine(NewLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])", nil))}.CheckCond()
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
MkLineChecker{NewMkLine(NewLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})", nil))}.CheckCond()
c.Check(s.Output(), equals, "WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.\n")
s.CheckOutputLines(
"WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.")
MkLineChecker{NewMkLine(NewLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"", nil))}.CheckCond()
c.Check(s.Output(), equals, "WARN: fname: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.\n")
s.CheckOutputLines(
"WARN: fname: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.")
MkLineChecker{NewMkLine(NewLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}", nil))}.CheckCond()
c.Check(s.Output(), equals, "WARN: fname: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.\n")
s.CheckOutputLines(
"WARN: fname: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.")
MkLineChecker{NewMkLine(NewLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}", nil))}.CheckCond()
c.Check(s.Output(), equals, ""+
"WARN: fname:98: 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.\n"+
"WARN: fname:98: 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.\n")
s.CheckOutputLines(
"WARN: fname:98: 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: fname:98: 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.")
}
func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
G.Mk = s.NewMkLines("Makefile",
@ -98,7 +105,8 @@ func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) {
MkLineChecker{G.Mk.mklines[1]}.checkVarassign()
c.Check(s.Output(), equals, "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?\n")
s.CheckOutputLines(
"WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?")
}
func (s *Suite) Test_MkLineChecker_checkVarassignDefPermissions(c *check.C) {
@ -109,7 +117,8 @@ func (s *Suite) Test_MkLineChecker_checkVarassignDefPermissions(c *check.C) {
MkLineChecker{mkline}.checkVarassignDefPermissions()
c.Check(s.Output(), equals, "WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.\n")
s.CheckOutputLines(
"WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.")
}
func (s *Suite) Test_MkLineChecker_CheckVarusePermissions(c *check.C) {
@ -121,18 +130,18 @@ func (s *Suite) Test_MkLineChecker_CheckVarusePermissions(c *check.C) {
"COMMENT=\t${GAMES_USER}",
"COMMENT:=\t${PKGBASE}",
"PYPKGPREFIX=${PKGBASE}")
G.globalData.UserDefinedVars = map[string]*MkLine{
G.globalData.UserDefinedVars = map[string]MkLine{
"GAMES_USER": mklines.mklines[0],
}
mklines.Check()
c.Check(s.Output(), equals, ""+
"WARN: options.mk:2: The user-defined variable GAMES_USER is used but not added to BUILD_DEFS.\n"+
"WARN: options.mk:3: PKGBASE should not be evaluated at load time.\n"+
"WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.\n"+
"WARN: options.mk:4: PKGBASE should not be evaluated indirectly at load time.\n"+
"NOTE: options.mk:4: This variable value should be aligned to column 17.\n")
s.CheckOutputLines(
"WARN: options.mk:2: The user-defined variable GAMES_USER is used but not added to BUILD_DEFS.",
"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) {
@ -145,37 +154,41 @@ func (s *Suite) Test_MkLineChecker_CheckVarusePermissions__load_time(c *check.C)
mklines.Check()
c.Check(s.Output(), equals, "") // Don't warn that ".CURDIR should not be evaluated at load time."
s.CheckOutputEmpty() // Don't warn that ".CURDIR should not be evaluated at load time."
}
func (s *Suite) Test_MkLineChecker_WarnVaruseLocalbase(c *check.C) {
s.Init(c)
mkline := NewMkLine(NewLine("options.mk", 56, "PKGNAME=${LOCALBASE}", nil))
MkLineChecker{mkline}.WarnVaruseLocalbase()
c.Check(s.Output(), equals, "WARN: options.mk:56: The LOCALBASE variable should not be used by packages.\n")
s.CheckOutputLines(
"WARN: options.mk:56: The LOCALBASE variable should not be used by packages.")
}
func (s *Suite) Test_MkLineChecker_CheckRelativePkgdir(c *check.C) {
s.Init(c)
mkline := NewMkLine(NewLine("Makefile", 46, "# dummy", nil))
MkLineChecker{mkline}.CheckRelativePkgdir("../pkgbase")
c.Check(s.Output(), equals, ""+
"ERROR: Makefile:46: \"../pkgbase\" does not exist.\n"+
"WARN: Makefile:46: \"../pkgbase\" is not a valid relative package directory.\n")
s.CheckOutputLines(
"ERROR: Makefile:46: \"../pkgbase\" does not exist.",
"WARN: Makefile:46: \"../pkgbase\" is not a valid relative package directory.")
}
// PR pkg/46570, item 2
func (s *Suite) Test_MkLineChecker__unclosed_varuse(c *check.C) {
s.Init(c)
mkline := NewMkLine(NewLine("Makefile", 93, "EGDIRS=${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d", nil))
MkLineChecker{mkline}.checkVarassign()
c.Check(s.Output(), equals, ""+
"WARN: Makefile:93: Pkglint parse error in MkLine.Tokenize at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".\n"+
"WARN: Makefile:93: Pkglint parse error in ShTokenizer.ShAtom at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\" (quoting=plain)\n"+
"WARN: Makefile:93: EGDIRS is defined but not used. Spelling mistake?\n")
s.CheckOutputLines(
"WARN: Makefile:93: Pkglint parse error in MkLine.Tokenize at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".",
"WARN: Makefile:93: Pkglint parse error in ShTokenizer.ShAtom at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\" (quoting=plain)",
"WARN: Makefile:93: EGDIRS is defined but not used. Spelling mistake?")
}
func (s *Suite) Test_MkLineChecker__Varuse_Modifier_L(c *check.C) {
@ -187,7 +200,7 @@ func (s *Suite) Test_MkLineChecker__Varuse_Modifier_L(c *check.C) {
MkLineChecker{G.Mk.mklines[0]}.Check()
c.Check(s.Output(), equals, "") // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
s.CheckOutputEmpty() // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
}
func (s *Suite) Test_MkLineChecker_CheckCond__comparison_with_shell_command(c *check.C) {
@ -202,7 +215,8 @@ func (s *Suite) Test_MkLineChecker_CheckCond__comparison_with_shell_command(c *c
G.Mk.Check()
// Don't warn about unknown shell command "cc".
c.Check(s.Output(), equals, "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.\n")
s.CheckOutputLines(
"WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.")
}
func (s *Suite) Test_MkLine_CheckCond_comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) {
@ -216,7 +230,8 @@ func (s *Suite) Test_MkLine_CheckCond_comparing_PKGSRC_COMPILER_with_eqeq(c *che
G.Mk.Check()
c.Check(s.Output(), equals, "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.\n")
s.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) {
@ -228,20 +243,21 @@ func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS_with_backticks(c *check.
"CFLAGS+=\t`pkg-config pidgin --cflags`")
mkline := G.Mk.mklines[1]
words, rest := splitIntoMkWords(mkline.Line, mkline.Value())
words, rest := splitIntoMkWords(mkline, 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`", "")
c.Check(s.Output(), equals, "") // No warning about "`pkg-config" being an unknown CFlag.
s.CheckOutputEmpty() // No warning about "`pkg-config" being an unknown CFlag.
}
// 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) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("Makefile",
mkrcsid,
@ -249,7 +265,7 @@ func (s *Suite) Test_MkLineChecker_CheckVartype_CFLAGS(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, ""+
"WARN: Makefile:2: Unknown compiler flag \"-bs\".\n"+
"WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.\n")
s.CheckOutputLines(
"WARN: Makefile:2: Unknown compiler flag \"-bs\".",
"WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.")
}

View file

@ -1,6 +1,7 @@
package main
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/trace"
"path"
"strings"
@ -8,22 +9,22 @@ import (
// MkLines contains data for the Makefile (or *.mk) that is currently checked.
type MkLines struct {
mklines []*MkLine
lines []Line
forVars map[string]bool // The variables currently used in .for loops
target string // Current make(1) target
vardef map[string]*MkLine // varname => line; for all variables that are defined in the current file
varuse map[string]*MkLine // varname => line; for all variables that are used in the current file
buildDefs map[string]bool // Variables that are registered in BUILD_DEFS, to ensure that all user-defined variables are added to it.
plistVars map[string]bool // Variables that are registered in PLIST_VARS, to ensure that all user-defined variables are added to it.
tools map[string]bool // Set of tools that are declared to be used.
toolRegistry ToolRegistry // Tools defined in file scope.
mklines []MkLine
lines []line.Line
forVars map[string]bool // The variables currently used in .for loops
target string // Current make(1) target
vardef map[string]MkLine // varname => line; for all variables that are defined in the current file
varuse map[string]MkLine // varname => line; for all variables that are used in the current file
buildDefs map[string]bool // Variables that are registered in BUILD_DEFS, to ensure that all user-defined variables are added to it.
plistVars map[string]bool // Variables that are registered in PLIST_VARS, to ensure that all user-defined variables are added to it.
tools map[string]bool // Set of tools that are declared to be used.
toolRegistry ToolRegistry // Tools defined in file scope.
SeenBsdPrefsMk bool
indentation Indentation // Indentation depth of preprocessing directives
}
func NewMkLines(lines []Line) *MkLines {
mklines := make([]*MkLine, len(lines))
func NewMkLines(lines []line.Line) *MkLines {
mklines := make([]MkLine, len(lines))
for i, line := range lines {
mklines[i] = NewMkLine(line)
}
@ -39,8 +40,8 @@ func NewMkLines(lines []Line) *MkLines {
lines,
make(map[string]bool),
"",
make(map[string]*MkLine),
make(map[string]*MkLine),
make(map[string]MkLine),
make(map[string]MkLine),
make(map[string]bool),
make(map[string]bool),
tools,
@ -49,7 +50,7 @@ func NewMkLines(lines []Line) *MkLines {
Indentation{}}
}
func (mklines *MkLines) DefineVar(mkline *MkLine, varname string) {
func (mklines *MkLines) DefineVar(mkline MkLine, varname string) {
if mklines.vardef[varname] == nil {
mklines.vardef[varname] = mkline
}
@ -59,7 +60,7 @@ func (mklines *MkLines) DefineVar(mkline *MkLine, varname string) {
}
}
func (mklines *MkLines) UseVar(mkline *MkLine, varname string) {
func (mklines *MkLines) UseVar(mkline MkLine, varname string) {
varcanon := varnameCanon(varname)
mklines.varuse[varname] = mkline
mklines.varuse[varcanon] = mkline
@ -96,7 +97,7 @@ func (mklines *MkLines) Check() {
// In the first pass, all additions to BUILD_DEFS and USE_TOOLS
// are collected to make the order of the definitions irrelevant.
mklines.DetermineUsedVariables()
mklines.determineDefinedVariables()
mklines.DetermineDefinedVariables()
// In the second pass, the actual checks are done.
@ -150,7 +151,7 @@ func (mklines *MkLines) Check() {
SaveAutofixChanges(mklines.lines)
}
func (mklines *MkLines) determineDefinedVariables() {
func (mklines *MkLines) DetermineDefinedVariables() {
if trace.Tracing {
defer trace.Call0()()
}
@ -210,13 +211,13 @@ func (mklines *MkLines) determineDefinedVariables() {
}
}
mklines.toolRegistry.ParseToolLine(mkline.Line)
mklines.toolRegistry.ParseToolLine(mkline)
}
}
func (mklines *MkLines) DetermineUsedVariables() {
for _, mkline := range mklines.mklines {
varnames := mkline.determineUsedVariables()
varnames := mkline.DetermineUsedVariables()
for _, varname := range varnames {
mklines.UseVar(mkline, varname)
}
@ -234,7 +235,7 @@ func (mklines *MkLines) setSeenBsdPrefsMk() {
type VaralignBlock struct {
info []struct {
mkline *MkLine
mkline MkLine
prefix string
align string
}
@ -245,8 +246,8 @@ type VaralignBlock struct {
maxTabWidth int
}
func (va *VaralignBlock) Check(mkline *MkLine) {
if !G.opts.WarnSpace || mkline.Line.IsMultiline() || mkline.IsComment() || mkline.IsCond() {
func (va *VaralignBlock) Check(mkline MkLine) {
if !G.opts.WarnSpace || mkline.IsMultiline() || mkline.IsComment() || mkline.IsCond() {
return
}
if mkline.IsEmpty() {
@ -263,7 +264,7 @@ func (va *VaralignBlock) Check(mkline *MkLine) {
align := valueAlign[len(prefix):]
va.info = append(va.info, struct {
mkline *MkLine
mkline MkLine
prefix string
align string
}{mkline, prefix, align})
@ -291,7 +292,7 @@ func (va *VaralignBlock) Check(mkline *MkLine) {
func (va *VaralignBlock) Finish() {
if !va.skip {
for _, info := range va.info {
if !info.mkline.Line.IsMultiline() {
if !info.mkline.IsMultiline() {
va.fixalign(info.mkline, info.prefix, info.align)
}
}
@ -299,7 +300,7 @@ func (va *VaralignBlock) Finish() {
*va = VaralignBlock{}
}
func (va *VaralignBlock) fixalign(mkline *MkLine, prefix, oldalign string) {
func (va *VaralignBlock) fixalign(mkline MkLine, prefix, oldalign string) {
if mkline.Value() == "" && mkline.VarassignComment() == "" {
return
}

View file

@ -21,12 +21,12 @@ func (s *Suite) Test_MkLines_Check__autofix_conditional_indentation(c *check.C)
mklines.Check()
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/fname.mk:3: Replacing \".\" with \". \".\n"+
"AUTOFIX: ~/fname.mk:4: Replacing \".\" with \". \".\n"+
"AUTOFIX: ~/fname.mk:5: Replacing \".\" with \". \".\n"+
"AUTOFIX: ~/fname.mk:6: Replacing \".\" with \". \".\n"+
"AUTOFIX: ~/fname.mk: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/fname.mk:3: Replacing \".\" with \". \".",
"AUTOFIX: ~/fname.mk:4: Replacing \".\" with \". \".",
"AUTOFIX: ~/fname.mk:5: Replacing \".\" with \". \".",
"AUTOFIX: ~/fname.mk:6: Replacing \".\" with \". \".",
"AUTOFIX: ~/fname.mk: Has been auto-fixed. Please re-run pkglint.")
c.Check(s.LoadTmpFile("fname.mk"), equals, ""+
"# $"+"NetBSD$\n"+
".if defined(A)\n"+
@ -38,6 +38,7 @@ func (s *Suite) Test_MkLines_Check__autofix_conditional_indentation(c *check.C)
}
func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) {
s.Init(c)
mklines := s.NewMkLines("Makefile",
mkrcsid,
"",
@ -46,17 +47,19 @@ func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "WARN: Makefile:3: Unusual target \"echo\".\n")
s.CheckOutputLines(
"WARN: Makefile:3: Unusual target \"echo\".")
}
func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) {
s.Init(c)
mkline := NewMkLine(NewLine("Makefile", 2, ".include \"../../other/package/Makefile\"", nil))
MkLineChecker{mkline}.checkInclude()
c.Check(s.Output(), equals, ""+
"ERROR: Makefile:2: \"/other/package/Makefile\" does not exist.\n"+
"ERROR: Makefile:2: Other Makefiles must not be included directly.\n")
s.CheckOutputLines(
"ERROR: Makefile:2: \"/other/package/Makefile\" does not exist.",
"ERROR: Makefile:2: Other Makefiles must not be included directly.")
}
func (s *Suite) Test_MkLines_quoting_LDFLAGS_for_GNU_configure(c *check.C) {
@ -71,9 +74,9 @@ func (s *Suite) Test_MkLines_quoting_LDFLAGS_for_GNU_configure(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, ""+
"WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.\n"+
"WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.\n")
s.CheckOutputLines(
"WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.",
"WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.")
}
func (s *Suite) Test_MkLines__variable_alignment_advanced(c *check.C) {
@ -105,28 +108,28 @@ func (s *Suite) Test_MkLines__variable_alignment_advanced(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, ""+
"NOTE: ~/Makefile:6: This variable value should be aligned with tabs, not spaces, to column 9.\n"+
"NOTE: ~/Makefile:7: This variable value should be aligned with tabs, not spaces, to column 9.\n"+
"NOTE: ~/Makefile:12: This variable value should be aligned to column 17.\n"+
"NOTE: ~/Makefile:15: This variable value should be aligned with tabs, not spaces, to column 17.\n"+
"NOTE: ~/Makefile:16: This variable value should be aligned with tabs, not spaces, to column 17.\n"+
"NOTE: ~/Makefile:17: This variable value should be aligned with tabs, not spaces, to column 17.\n"+
"NOTE: ~/Makefile:18: This variable value should be aligned with tabs, not spaces, to column 17.\n")
s.CheckOutputLines(
"NOTE: ~/Makefile:6: This variable value should be aligned with tabs, not spaces, to column 9.",
"NOTE: ~/Makefile:7: This variable value should be aligned with tabs, not spaces, to column 9.",
"NOTE: ~/Makefile:12: This variable value should be aligned to column 17.",
"NOTE: ~/Makefile:15: This variable value should be aligned with tabs, not spaces, to column 17.",
"NOTE: ~/Makefile:16: This variable value should be aligned with tabs, not spaces, to column 17.",
"NOTE: ~/Makefile:17: This variable value should be aligned with tabs, not spaces, to column 17.",
"NOTE: ~/Makefile:18: This variable value should be aligned with tabs, not spaces, to column 17.")
s.UseCommandLine("-Wspace", "--autofix")
mklines.Check()
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/Makefile:6: Replacing \"VAR= \" with \"VAR=\\t\".\n"+
"AUTOFIX: ~/Makefile:7: Replacing \"VAR= \" with \"VAR=\\t\".\n"+
"AUTOFIX: ~/Makefile:12: Replacing \"BLOCK=\\t\" with \"BLOCK=\\t\\t\".\n"+
"AUTOFIX: ~/Makefile:15: Replacing \"GRP_A= \" with \"GRP_A=\\t\\t\".\n"+
"AUTOFIX: ~/Makefile:16: Replacing \"GRP_AA= \" with \"GRP_AA=\\t\\t\".\n"+
"AUTOFIX: ~/Makefile:17: Replacing \"GRP_AAA= \" with \"GRP_AAA=\\t\".\n"+
"AUTOFIX: ~/Makefile:18: Replacing \"GRP_AAAA= \" with \"GRP_AAAA=\\t\".\n"+
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/Makefile:6: Replacing \"VAR= \" with \"VAR=\\t\".",
"AUTOFIX: ~/Makefile:7: Replacing \"VAR= \" with \"VAR=\\t\".",
"AUTOFIX: ~/Makefile:12: Replacing \"BLOCK=\\t\" with \"BLOCK=\\t\\t\".",
"AUTOFIX: ~/Makefile:15: Replacing \"GRP_A= \" with \"GRP_A=\\t\\t\".",
"AUTOFIX: ~/Makefile:16: Replacing \"GRP_AA= \" with \"GRP_AA=\\t\\t\".",
"AUTOFIX: ~/Makefile:17: Replacing \"GRP_AAA= \" with \"GRP_AAA=\\t\".",
"AUTOFIX: ~/Makefile:18: Replacing \"GRP_AAAA= \" with \"GRP_AAAA=\\t\".",
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
c.Check(s.LoadTmpFile("Makefile"), equals, ""+
"# $"+"NetBSD$\n"+
"\n"+
@ -162,7 +165,8 @@ func (s *Suite) Test_MkLines__variable_alignment_space_and_tab(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "NOTE: Makefile:3: Variable values should be aligned with tabs, not spaces.\n")
s.CheckOutputLines(
"NOTE: Makefile:3: Variable values should be aligned with tabs, not spaces.")
}
func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) {
@ -181,10 +185,10 @@ func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, ""+
"WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.\n"+
"WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.\n"+
"WARN: audio/squeezeboxserver/Makefile:4: The exitcode of the left-hand-side command of the pipe operator is ignored.\n")
s.CheckOutputLines(
"WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.",
"WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.",
"WARN: audio/squeezeboxserver/Makefile:4: The exitcode of the left-hand-side command of the pipe operator is ignored.")
}
func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) {
@ -213,17 +217,17 @@ func (s *Suite) Test_MkLines__varuse_sh_modifier(c *check.C) {
"qore-version=\tqore --short-version | ${SED} -e s/-.*//",
"PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"")
vars2 := mklines.mklines[1].determineUsedVariables()
vars2 := mklines.mklines[1].DetermineUsedVariables()
c.Check(vars2, deepEquals, []string{"SED"})
vars3 := mklines.mklines[2].determineUsedVariables()
vars3 := mklines.mklines[2].DetermineUsedVariables()
c.Check(vars3, deepEquals, []string{"qore-version"})
mklines.Check()
c.Check(s.Output(), equals, "") // No warnings about defined but not used or vice versa
s.CheckOutputEmpty() // No warnings about defined but not used or vice versa
}
func (s *Suite) Test_MkLines__varuse_parameterized(c *check.C) {
@ -237,7 +241,7 @@ func (s *Suite) Test_MkLines__varuse_parameterized(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "") // No warnings about defined but not used or vice versa
s.CheckOutputEmpty() // No warnings about defined but not used or vice versa
}
func (s *Suite) Test_MkLines__loop_modifier(c *check.C) {
@ -260,6 +264,7 @@ func (s *Suite) Test_MkLines__loop_modifier(c *check.C) {
// PR 46570
func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
mklines := s.NewMkLines("Makefile",
mkrcsid,
@ -270,7 +275,8 @@ func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.\n")
s.CheckOutputLines(
"NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.")
}
// PR 46570, item "15. net/uucp/Makefile has a make loop"
@ -288,8 +294,8 @@ func (s *Suite) Test_MkLines__indirect_variables(c *check.C) {
mklines.Check()
// No warning about UUCP_${var} being used but not defined.
c.Check(s.Output(), equals, ""+
"WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".\n")
s.CheckOutputLines(
"WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".")
}
func (s *Suite) Test_MkLines_Check__list_variable_as_part_of_word(c *check.C) {
@ -301,9 +307,9 @@ func (s *Suite) Test_MkLines_Check__list_variable_as_part_of_word(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, ""+
"WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".\n"+
"WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.\n")
s.CheckOutputLines(
"WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".",
"WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.")
}
func (s *Suite) Test_MkLines_Check__absolute_pathname_depending_on_OPSYS(c *check.C) {
@ -321,10 +327,10 @@ func (s *Suite) Test_MkLines_Check__absolute_pathname_depending_on_OPSYS(c *chec
// No warning about an unknown shell command in line 3,
// since that line depends on OPSYS.
c.Check(s.Output(), equals, ""+
"WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.\n"+
"WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.\n"+
"WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".\n")
s.CheckOutputLines(
"WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.",
"WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.",
"WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".")
}
func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) {
@ -336,24 +342,24 @@ func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) {
"# used by sysutils/mc",
).checkForUsedComment("sysutils/mc")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
s.NewMkLines("Makefile.common").checkForUsedComment("category/package")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
s.NewMkLines("Makefile.common",
mkrcsid,
).checkForUsedComment("category/package")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
s.NewMkLines("Makefile.common",
mkrcsid,
"",
).checkForUsedComment("category/package")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
s.NewMkLines("Makefile.common",
mkrcsid,
@ -361,9 +367,9 @@ func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) {
"VARNAME=\tvalue",
).checkForUsedComment("category/package")
c.Check(s.Output(), equals, ""+
"WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.\n"+
"AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line.\n")
s.CheckOutputLines(
"WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.",
"AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line.")
s.NewMkLines("Makefile.common",
mkrcsid,
@ -371,9 +377,9 @@ func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) {
"#",
).checkForUsedComment("category/package")
c.Check(s.Output(), equals, ""+
"WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.\n"+
"AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.\n")
s.CheckOutputLines(
"WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.",
"AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.")
}
func (s *Suite) Test_MkLines_DetermineUsedVariables__simple(c *check.C) {
@ -413,7 +419,8 @@ func (s *Suite) Test_MkLines_PrivateTool_Undefined(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "WARN: fname:3: Unknown shell command \"md5sum\".\n")
s.CheckOutputLines(
"WARN: fname:3: Unknown shell command \"md5sum\".")
}
func (s *Suite) Test_MkLines_PrivateTool_Defined(c *check.C) {
@ -428,7 +435,7 @@ func (s *Suite) Test_MkLines_PrivateTool_Defined(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_MkLines_Check_indentation(c *check.C) {

View file

@ -1,6 +1,7 @@
package main
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"strings"
@ -10,7 +11,7 @@ type MkParser struct {
*Parser
}
func NewMkParser(line Line, text string, emitWarnings bool) *MkParser {
func NewMkParser(line line.Line, text string, emitWarnings bool) *MkParser {
return &MkParser{NewParser(line, text, emitWarnings)}
}

View file

@ -5,6 +5,7 @@ import (
)
func (s *Suite) Test_MkParser_MkTokens(c *check.C) {
s.Init(c)
checkRest := func(input string, expectedTokens []*MkToken, expectedRest string) {
p := NewMkParser(dummyLine, input, true)
actualTokens := p.MkTokens()
@ -106,15 +107,17 @@ func (s *Suite) Test_MkParser_MkTokens(c *check.C) {
check("${VAR:ts\\124}", varuse("VAR", "ts\\124")) // Or even decimal.
check("$(GNUSTEP_USER_ROOT)", varuseText("$(GNUSTEP_USER_ROOT)", "GNUSTEP_USER_ROOT"))
c.Check(s.Output(), equals, "WARN: Please use curly braces {} instead of round parentheses () for GNUSTEP_USER_ROOT.\n")
s.CheckOutputLines(
"WARN: Please use curly braces {} instead of round parentheses () for GNUSTEP_USER_ROOT.")
checkRest("${VAR)", nil, "${VAR)") // Opening brace, closing parenthesis
checkRest("$(VAR}", nil, "$(VAR}") // Opening parenthesis, closing brace
c.Check(s.Output(), equals, "") // Warnings are only printed for balanced expressions.
s.CheckOutputEmpty() // Warnings are only printed for balanced expressions.
check("${PLIST_SUBST_VARS:@var@${var}=${${var}:Q}@}", varuse("PLIST_SUBST_VARS", "@var@${var}=${${var}:Q}@"))
check("${PLIST_SUBST_VARS:@var@${var}=${${var}:Q}}", varuse("PLIST_SUBST_VARS", "@var@${var}=${${var}:Q}")) // Missing @ at the end
c.Check(s.Output(), equals, "WARN: Modifier ${PLIST_SUBST_VARS:@var@...@} is missing the final \"@\".\n")
s.CheckOutputLines(
"WARN: Modifier ${PLIST_SUBST_VARS:@var@...@} is missing the final \"@\".")
checkRest("hello, ${W:L:tl}orld", []*MkToken{
literal("hello, "),
@ -221,11 +224,11 @@ func (s *Suite) Test_MkParser__varuse_parentheses_autofix(c *check.C) {
mklines.Check()
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/Makefile:2: Replacing \"$(P1)\" with \"${P1}\".\n"+
"AUTOFIX: ~/Makefile:2: Replacing \"$(P2)\" with \"${P2}\".\n"+
"AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".\n"+
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/Makefile:2: Replacing \"$(P1)\" with \"${P1}\".",
"AUTOFIX: ~/Makefile:2: Replacing \"$(P2)\" with \"${P2}\".",
"AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".",
"AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
c.Check(s.LoadTmpFile("Makefile"), equals, ""+
mkrcsid+"\n"+
"COMMENT=${P1} ${P2}) ${P3:Q} ${BRACES}\n")

View file

@ -2,11 +2,12 @@ package main
import (
"fmt"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/trace"
"strconv"
)
func parseShellProgram(line Line, program string) (list *MkShList, err error) {
func parseShellProgram(line line.Line, program string) (list *MkShList, err error) {
if trace.Tracing {
defer trace.Call(program)()
}

View file

@ -2,6 +2,7 @@ package main
import (
"fmt"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/pkgver"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
@ -15,39 +16,39 @@ const rePkgname = `^([\w\-.+]+)-(\d(?:\w|\.\d)*)$`
// Package contains data for the pkgsrc package that is currently checked.
type Package struct {
Pkgpath string // e.g. "category/pkgdir"
Pkgdir string // PKGDIR from the package Makefile
Filesdir string // FILESDIR from the package Makefile
Patchdir string // PATCHDIR from the package Makefile
DistinfoFile string // DISTINFO_FILE from the package Makefile
EffectivePkgname string // PKGNAME or DISTNAME from the package Makefile, including nb13
EffectivePkgbase string // The effective PKGNAME without the version
EffectivePkgversion string // The version part of the effective PKGNAME, excluding nb13
EffectivePkgnameLine *MkLine // The origin of the three effective_* values
SeenBsdPrefsMk bool // Has bsd.prefs.mk already been included?
Pkgpath string // e.g. "category/pkgdir"
Pkgdir string // PKGDIR from the package Makefile
Filesdir string // FILESDIR from the package Makefile
Patchdir string // PATCHDIR from the package Makefile
DistinfoFile string // DISTINFO_FILE from the package Makefile
EffectivePkgname string // PKGNAME or DISTNAME from the package Makefile, including nb13
EffectivePkgbase string // The effective PKGNAME without the version
EffectivePkgversion string // The version part of the effective PKGNAME, excluding nb13
EffectivePkgnameLine MkLine // The origin of the three effective_* values
SeenBsdPrefsMk bool // Has bsd.prefs.mk already been included?
vardef map[string]*MkLine // (varname, varcanon) => line
varuse map[string]*MkLine // (varname, varcanon) => line
bl3 map[string]Line // buildlink3.mk name => line; contains only buildlink3.mk files that are directly included.
plistSubstCond map[string]bool // varname => true; list of all variables that are used as conditionals (@comment or nothing) in PLISTs.
included map[string]Line // fname => line
seenMakefileCommon bool // Does the package have any .includes?
loadTimeTools map[string]bool // true=ok, false=not ok, absent=not mentioned in USE_TOOLS.
conditionalIncludes map[string]*MkLine
unconditionalIncludes map[string]*MkLine
vardef map[string]MkLine // (varname, varcanon) => line
varuse map[string]MkLine // (varname, varcanon) => line
bl3 map[string]line.Line // buildlink3.mk name => line; contains only buildlink3.mk files that are directly included.
plistSubstCond map[string]bool // varname => true; list of all variables that are used as conditionals (@comment or nothing) in PLISTs.
included map[string]line.Line // fname => line
seenMakefileCommon bool // Does the package have any .includes?
loadTimeTools map[string]bool // true=ok, false=not ok, absent=not mentioned in USE_TOOLS.
conditionalIncludes map[string]MkLine
unconditionalIncludes map[string]MkLine
}
func NewPackage(pkgpath string) *Package {
pkg := &Package{
Pkgpath: pkgpath,
vardef: make(map[string]*MkLine),
varuse: make(map[string]*MkLine),
bl3: make(map[string]Line),
vardef: make(map[string]MkLine),
varuse: make(map[string]MkLine),
bl3: make(map[string]line.Line),
plistSubstCond: make(map[string]bool),
included: make(map[string]Line),
included: make(map[string]line.Line),
loadTimeTools: make(map[string]bool),
conditionalIncludes: make(map[string]*MkLine),
unconditionalIncludes: make(map[string]*MkLine),
conditionalIncludes: make(map[string]MkLine),
unconditionalIncludes: make(map[string]MkLine),
}
for varname, line := range G.globalData.UserDefinedVars {
pkg.vardef[varname] = line
@ -55,7 +56,7 @@ func NewPackage(pkgpath string) *Package {
return pkg
}
func (pkg *Package) defineVar(mkline *MkLine, varname string) {
func (pkg *Package) defineVar(mkline MkLine, varname string) {
if pkg.vardef[varname] == nil {
pkg.vardef[varname] = mkline
}
@ -110,7 +111,7 @@ func (pkg *Package) checkPossibleDowngrade() {
if change.Action == "Updated" {
changeVersion := regex.Compile(`nb\d+$`).ReplaceAllString(change.Version, "")
if pkgver.Compare(pkgversion, changeVersion) < 0 {
mkline.Warnf("The package is being downgraded from %s (see %s) to %s", change.Version, change.Line.ReferenceFrom(mkline.Line), pkgversion)
mkline.Warnf("The package is being downgraded from %s (see %s) to %s", change.Version, change.Line.ReferenceFrom(mkline), pkgversion)
Explain(
"The files in doc/CHANGES-*, in which all version changes are",
"recorded, have a higher version number than what the package says.",
@ -126,7 +127,7 @@ func (pkg *Package) checklinesBuildlink3Inclusion(mklines *MkLines) {
}
// Collect all the included buildlink3.mk files from the file.
includedFiles := make(map[string]*MkLine)
includedFiles := make(map[string]MkLine)
for _, mkline := range mklines.mklines {
if mkline.IsInclude() {
file := mkline.Includefile()
@ -276,22 +277,21 @@ func (pkg *Package) readMakefile(fname string, mainLines *MkLines, allLines *MkL
isMainMakefile := len(mainLines.mklines) == 0
for _, mkline := range fileMklines.mklines {
line := mkline.Line
if isMainMakefile {
mainLines.mklines = append(mainLines.mklines, mkline)
mainLines.lines = append(mainLines.lines, line)
mainLines.lines = append(mainLines.lines, mkline)
}
allLines.mklines = append(allLines.mklines, mkline)
allLines.lines = append(allLines.lines, line)
allLines.lines = append(allLines.lines, mkline)
var includeFile, incDir, incBase string
if mkline.IsInclude() {
inc := mkline.Includefile()
includeFile = resolveVariableRefs(mkline.resolveVarsInRelativePath(inc, true))
includeFile = resolveVariableRefs(mkline.ResolveVarsInRelativePath(inc, true))
if containsVarRef(includeFile) {
if !contains(fname, "/mk/") {
line.Notef("Skipping include file %q. This may result in false warnings.", includeFile)
mkline.Notef("Skipping include file %q. This may result in false warnings.", includeFile)
}
includeFile = ""
}
@ -301,7 +301,7 @@ func (pkg *Package) readMakefile(fname string, mainLines *MkLines, allLines *MkL
if includeFile != "" {
if path.Base(fname) != "buildlink3.mk" {
if m, bl3File := match1(includeFile, `^\.\./\.\./(.*)/buildlink3\.mk$`); m {
G.Pkg.bl3[bl3File] = line
G.Pkg.bl3[bl3File] = mkline
if trace.Tracing {
trace.Step1("Buildlink3 file in package: %q", bl3File)
}
@ -310,11 +310,11 @@ func (pkg *Package) readMakefile(fname string, mainLines *MkLines, allLines *MkL
}
if includeFile != "" && G.Pkg.included[includeFile] == nil {
G.Pkg.included[includeFile] = line
G.Pkg.included[includeFile] = mkline
if matches(includeFile, `^\.\./[^./][^/]*/[^/]+`) {
mkline.Warnf("References to other packages should look like \"../../category/package\", not \"../package\".")
mkline.explainRelativeDirs()
mkline.ExplainRelativeDirs()
}
if path.Base(fname) == "Makefile" && !hasPrefix(incDir, "../../mk/") && incBase != "buildlink3.mk" && incBase != "builtin.mk" && incBase != "options.mk" {
@ -336,7 +336,7 @@ func (pkg *Package) readMakefile(fname string, mainLines *MkLines, allLines *MkL
if dirname != G.CurrentDir { // Prevent unnecessary syscalls
dirname = G.CurrentDir
if !fileExists(dirname + "/" + includeFile) {
line.Errorf("Cannot read %q.", dirname+"/"+includeFile)
mkline.Errorf("Cannot read %q.", dirname+"/"+includeFile)
return false
}
}
@ -396,7 +396,7 @@ func (pkg *Package) checkfilePackageMakefile(fname string, mklines *MkLines) {
}
if perlLine, noconfLine := vardef["REPLACE_PERL"], vardef["NO_CONFIGURE"]; perlLine != nil && noconfLine != nil {
perlLine.Warnf("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.ReferenceFrom(perlLine.Line))
perlLine.Warnf("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.ReferenceFrom(perlLine))
}
if vardef["LICENSE"] == nil && vardef["META_PACKAGE"] == nil {
@ -411,7 +411,7 @@ func (pkg *Package) checkfilePackageMakefile(fname string, mklines *MkLines) {
} else if !matches(useLine.Value(), `(?:^|\s+)(?:c|c99|objc)(?:\s+|$)`) {
gnuLine.Warnf("GNU_CONFIGURE almost always needs a C compiler, but \"c\" is not added to USE_LANGUAGES in %s.",
useLine.Line.ReferenceFrom(gnuLine.Line))
useLine.ReferenceFrom(gnuLine))
}
}
@ -423,8 +423,8 @@ func (pkg *Package) checkfilePackageMakefile(fname string, mklines *MkLines) {
}
if imake, x11 := vardef["USE_IMAKE"], vardef["USE_X11"]; imake != nil && x11 != nil {
if !hasSuffix(x11.Line.Filename(), "/mk/x11.buildlink3.mk") {
imake.Line.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.Line.ReferenceFrom(imake.Line))
if !hasSuffix(x11.Filename(), "/mk/x11.buildlink3.mk") {
imake.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.ReferenceFrom(imake))
}
}
@ -542,7 +542,7 @@ func (pkg *Package) expandVariableWithDefault(varname, defaultValue string) stri
}
value := mkline.Value()
value = mkline.resolveVarsInRelativePath(value, true)
value = mkline.ResolveVarsInRelativePath(value, true)
if containsVarRef(value) {
value = resolveVariableRefs(value)
}
@ -856,10 +856,11 @@ func (pkg *Package) checkLocallyModified(fname string) {
}
}
func (pkg *Package) CheckInclude(mkline *MkLine, indentation *Indentation) {
if includeLine := mkline.data.(mkLineInclude); includeLine.conditionVars == "" {
includeLine.conditionVars = indentation.Varnames()
mkline.data = includeLine
func (pkg *Package) CheckInclude(mkline MkLine, indentation *Indentation) {
conditionVars := mkline.ConditionVars()
if conditionVars == "" {
conditionVars = indentation.Varnames()
mkline.SetConditionVars(conditionVars)
}
if path.Dir(abspath(mkline.Filename())) == abspath(G.CurrentDir) {
@ -868,16 +869,14 @@ func (pkg *Package) CheckInclude(mkline *MkLine, indentation *Indentation) {
if indentation.IsConditional() {
pkg.conditionalIncludes[includefile] = mkline
if other := pkg.unconditionalIncludes[includefile]; other != nil {
dependingOn := mkline.data.(mkLineInclude).conditionVars
mkline.Warnf("%q is included conditionally here (depending on %s) and unconditionally in %s.",
cleanpath(includefile), dependingOn, other.ReferenceFrom(mkline.Line))
cleanpath(includefile), mkline.ConditionVars(), other.ReferenceFrom(mkline))
}
} else {
pkg.unconditionalIncludes[includefile] = mkline
if other := pkg.conditionalIncludes[includefile]; other != nil {
dependingOn := other.data.(mkLineInclude).conditionVars
mkline.Warnf("%q is included unconditionally here and conditionally in %s (depending on %s).",
cleanpath(includefile), other.ReferenceFrom(mkline.Line), dependingOn)
cleanpath(includefile), other.ReferenceFrom(mkline), other.ConditionVars())
}
}
}

View file

@ -5,6 +5,7 @@ import (
)
func (s *Suite) Test_Package_pkgnameFromDistname(c *check.C) {
s.Init(c)
pkg := NewPackage("dummy")
pkg.vardef["PKGNAME"] = NewMkLine(NewLine("Makefile", 5, "PKGNAME=dummy", nil))
@ -18,7 +19,7 @@ func (s *Suite) Test_Package_pkgnameFromDistname(c *check.C) {
c.Check(pkg.pkgnameFromDistname("${DISTNAME:C/beta/.0./}", "fspanel-0.8beta1"), equals, "${DISTNAME:C/beta/.0./}")
c.Check(pkg.pkgnameFromDistname("${DISTNAME:S/-0$/.0/1}", "aspell-af-0.50-0"), equals, "aspell-af-0.50.0")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder(c *check.C) {
@ -32,7 +33,7 @@ func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder(c *check.C) {
"DISTNAME=9term",
"CATEGORIES=x11"))
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
pkg.ChecklinesPackageMakefileVarorder(s.NewMkLines("Makefile",
mkrcsid,
@ -42,9 +43,9 @@ func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder(c *check.C) {
"",
".include \"../../mk/bsd.pkg.mk\""))
c.Check(s.Output(), equals, ""+
"WARN: Makefile:6: The canonical position for the required variable COMMENT is here.\n"+
"WARN: Makefile:6: The canonical position for the required variable LICENSE is here.\n")
s.CheckOutputLines(
"WARN: Makefile:6: The canonical position for the required variable COMMENT is here.",
"WARN: Makefile:6: The canonical position for the required variable LICENSE is here.")
}
// https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html
@ -61,7 +62,7 @@ func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder__MASTER_SITES(c *
"MASTER_SITES=\thttp://example.org/",
"MASTER_SITES+=\thttp://mirror.example.org/"))
c.Check(s.Output(), equals, "") // No warning that "MASTER_SITES appears too late"
s.CheckOutputEmpty() // No warning that "MASTER_SITES appears too late"
}
func (s *Suite) Test_Package_getNbpart(c *check.C) {
@ -93,6 +94,7 @@ func (s *Suite) Test_Package_determineEffectivePkgVars__precedence(c *check.C) {
}
func (s *Suite) Test_Package_checkPossibleDowngrade(c *check.C) {
s.Init(c)
G.Pkg = NewPackage("category/pkgbase")
G.CurPkgsrcdir = "../.."
G.Pkg.EffectivePkgname = "package-1.0nb15"
@ -107,13 +109,14 @@ func (s *Suite) Test_Package_checkPossibleDowngrade(c *check.C) {
G.Pkg.checkPossibleDowngrade()
c.Check(s.Output(), equals, "WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15\n")
s.CheckOutputLines(
"WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15")
G.globalData.LastChange["category/pkgbase"].Version = "1.0nb22"
G.Pkg.checkPossibleDowngrade()
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_checkdirPackage(c *check.C) {
@ -124,11 +127,11 @@ func (s *Suite) Test_checkdirPackage(c *check.C) {
checkdirPackage(s.tmpdir)
c.Check(s.Output(), equals, ""+
"WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?\n"+
"WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".\n"+
"ERROR: ~/Makefile: Each package must define its LICENSE.\n"+
"WARN: ~/Makefile: No COMMENT given.\n")
s.CheckOutputLines(
"WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?",
"WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".",
"ERROR: ~/Makefile: Each package must define its LICENSE.",
"WARN: ~/Makefile: No COMMENT given.")
}
func (s *Suite) Test_checkdirPackage__meta_package_without_license(c *check.C) {
@ -142,7 +145,8 @@ func (s *Suite) Test_checkdirPackage__meta_package_without_license(c *check.C) {
checkdirPackage(s.TmpDir())
c.Check(s.Output(), equals, "WARN: ~/Makefile: No COMMENT given.\n") // No error about missing LICENSE.
s.CheckOutputLines(
"WARN: ~/Makefile: No COMMENT given.") // No error about missing LICENSE.
}
func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) {
@ -201,11 +205,11 @@ func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) {
(&Pkglint{}).Main("pkglint", "-q", "-Wperm", s.tmpdir+"/category/pkgbase")
c.Check(s.Output(), equals, ""+
"WARN: ~/category/pkgbase/Makefile:8: To use the tool \"FALSE\" at load time, bsd.prefs.mk has to be included before.\n"+
"WARN: ~/category/pkgbase/Makefile:9: To use the tool \"NICE\" at load time, bsd.prefs.mk has to be included before.\n"+
"WARN: ~/category/pkgbase/Makefile:10: To use the tool \"TRUE\" at load time, bsd.prefs.mk has to be included before.\n"+
"WARN: ~/category/pkgbase/Makefile:16: To use the tool \"NICE\" at load time, it has to be added to USE_TOOLS before including bsd.prefs.mk.\n")
s.CheckOutputLines(
"WARN: ~/category/pkgbase/Makefile:8: To use the tool \"FALSE\" at load time, bsd.prefs.mk has to be included before.",
"WARN: ~/category/pkgbase/Makefile:9: To use the tool \"NICE\" at load time, bsd.prefs.mk has to be included before.",
"WARN: ~/category/pkgbase/Makefile:10: To use the tool \"TRUE\" at load time, bsd.prefs.mk has to be included before.",
"WARN: ~/category/pkgbase/Makefile:16: To use the tool \"NICE\" at load time, it has to be added to USE_TOOLS before including bsd.prefs.mk.")
}
func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) {
@ -223,7 +227,7 @@ func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) {
pkg.loadPackageMakefile(makefile)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) {
@ -265,8 +269,8 @@ func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) {
checkdirPackage("category/package")
c.Check(s.Output(), equals, ""+
"WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".\n"+
"WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.\n"+
"WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).\n")
s.CheckOutputLines(
"WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".",
"WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.",
"WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).")
}

View file

@ -1,17 +1,18 @@
package main
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/textproc"
"strings"
)
type Parser struct {
Line Line
Line line.Line
repl *textproc.PrefixReplacer
EmitWarnings bool
}
func NewParser(line Line, s string, emitWarnings bool) *Parser {
func NewParser(line line.Line, s string, emitWarnings bool) *Parser {
return &Parser{line, textproc.NewPrefixReplacer(s), emitWarnings}
}

View file

@ -3,22 +3,24 @@ package main
// Checks for patch files.
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/textproc"
"netbsd.org/pkglint/trace"
"path"
"strings"
)
func ChecklinesPatch(lines []Line) {
func ChecklinesPatch(lines []line.Line) {
if trace.Tracing {
defer trace.Call1(lines[0].Filename())()
}
(&PatchChecker{lines, NewExpecter(lines), false, false}).Check()
(&PatchChecker{lines, textproc.NewExpecter(lines), false, false}).Check()
}
type PatchChecker struct {
lines []Line
exp *Expecter
lines []line.Line
exp *textproc.Expecter
seenDocumentation bool
previousLineEmpty bool
}
@ -37,7 +39,7 @@ func (ck *PatchChecker) Check() {
if (LineChecker{ck.lines[0]}).CheckRcsid(``, "") {
ck.exp.Advance()
}
ck.previousLineEmpty = ck.exp.ExpectEmptyLine()
ck.previousLineEmpty = ck.exp.ExpectEmptyLine(G.opts.WarnSpace)
patchedFiles := 0
for !ck.exp.EOF() {
@ -45,7 +47,7 @@ func (ck *PatchChecker) Check() {
if ck.exp.AdvanceIfMatches(rePatchUniFileDel) {
if ck.exp.AdvanceIfMatches(rePatchUniFileAdd) {
ck.checkBeginDiff(line, patchedFiles)
ck.checkUnifiedDiff(ck.exp.m[1])
ck.checkUnifiedDiff(ck.exp.Group(1))
patchedFiles++
continue
}
@ -54,7 +56,7 @@ func (ck *PatchChecker) Check() {
}
if ck.exp.AdvanceIfMatches(rePatchUniFileAdd) {
patchedFile := ck.exp.m[1]
patchedFile := ck.exp.Group(1)
if ck.exp.AdvanceIfMatches(rePatchUniFileDel) {
ck.checkBeginDiff(line, patchedFiles)
ck.exp.PreviousLine().Warnf("Unified diff headers should be first ---, then +++.")
@ -107,8 +109,8 @@ func (ck *PatchChecker) checkUnifiedDiff(patchedFile string) {
hasHunks := false
for ck.exp.AdvanceIfMatches(rePatchUniHunk) {
hasHunks = true
linesToDel := toInt(ck.exp.m[2], 1)
linesToAdd := toInt(ck.exp.m[4], 1)
linesToDel := toInt(ck.exp.Group(2), 1)
linesToAdd := toInt(ck.exp.Group(4), 1)
if trace.Tracing {
trace.Stepf("hunk -%d +%d", linesToDel, linesToAdd)
}
@ -154,7 +156,7 @@ func (ck *PatchChecker) checkUnifiedDiff(patchedFile string) {
}
}
func (ck *PatchChecker) checkBeginDiff(line Line, patchedFiles int) {
func (ck *PatchChecker) checkBeginDiff(line line.Line, patchedFiles int) {
if trace.Tracing {
defer trace.Call0()()
}
@ -283,7 +285,7 @@ func (ft FileType) String() string {
}
// This is used to select the proper subroutine for detecting absolute pathnames.
func guessFileType(line Line, fname string) (fileType FileType) {
func guessFileType(line line.Line, fname string) (fileType FileType) {
if trace.Tracing {
defer trace.Call(fname, "=>", &fileType)()
}
@ -316,7 +318,7 @@ func guessFileType(line Line, fname string) (fileType FileType) {
return ftUnknown
}
func checkwordAbsolutePathname(line Line, word string) {
func checkwordAbsolutePathname(line line.Line, word string) {
if trace.Tracing {
defer trace.Call1(word)()
}
@ -345,7 +347,7 @@ func checkwordAbsolutePathname(line Line, word string) {
}
// Looks for strings like "/dev/cd0" appearing in source code
func checklineSourceAbsolutePathname(line Line, text string) {
func checklineSourceAbsolutePathname(line line.Line, text string) {
if !strings.ContainsAny(text, "\"'") {
return
}
@ -367,7 +369,7 @@ func checklineSourceAbsolutePathname(line Line, text string) {
}
}
func checklineOtherAbsolutePathname(line Line, text string) {
func checklineOtherAbsolutePathname(line line.Line, text string) {
if trace.Tracing {
defer trace.Call1(text)()
}

View file

@ -24,7 +24,7 @@ func (s *Suite) Test_ChecklinesPatch__with_comment(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ChecklinesPatch__without_empty_line(c *check.C) {
@ -44,10 +44,10 @@ func (s *Suite) Test_ChecklinesPatch__without_empty_line(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.\n"+
"AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.\n"+
"AUTOFIX: ~/patch-WithoutEmptyLines: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.",
"AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.",
"AUTOFIX: ~/patch-WithoutEmptyLines: Has been auto-fixed. Please re-run pkglint.")
fixed, err := ioutil.ReadFile(fname)
c.Assert(err, check.IsNil)
@ -81,7 +81,8 @@ func (s *Suite) Test_ChecklinesPatch__without_comment(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "ERROR: patch-WithoutComment:3: Each patch must be documented.\n")
s.CheckOutputLines(
"ERROR: patch-WithoutComment:3: Each patch must be documented.")
}
func (s *Suite) Test_ChecklinesPatch__git_without_comment(c *check.C) {
@ -100,15 +101,17 @@ func (s *Suite) Test_ChecklinesPatch__git_without_comment(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "ERROR: patch-aa:5: Each patch must be documented.\n")
s.CheckOutputLines(
"ERROR: patch-aa:5: Each patch must be documented.")
}
func (s *Suite) Test_checklineOtherAbsolutePathname(c *check.C) {
s.Init(c)
line := NewLine("patch-ag", 1, "+$install -s -c ./bin/rosegarden ${DESTDIR}$BINDIR", nil)
checklineOtherAbsolutePathname(line, line.Text())
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ChecklinesPatch__error_code(c *check.C) {
@ -129,7 +132,7 @@ func (s *Suite) Test_ChecklinesPatch__error_code(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ChecklinesPatch__wrong_header_order(c *check.C) {
@ -151,7 +154,8 @@ func (s *Suite) Test_ChecklinesPatch__wrong_header_order(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "WARN: patch-WrongOrder:7: Unified diff headers should be first ---, then +++.\n")
s.CheckOutputLines(
"WARN: patch-WrongOrder:7: Unified diff headers should be first ---, then +++.")
}
func (s *Suite) Test_ChecklinesPatch__context_diff(c *check.C) {
@ -166,12 +170,13 @@ func (s *Suite) Test_ChecklinesPatch__context_diff(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, ""+
"ERROR: patch-ctx:4: Each patch must be documented.\n"+
"WARN: patch-ctx:4: Please use unified diffs (diff -u) for patches.\n")
s.CheckOutputLines(
"ERROR: patch-ctx:4: Each patch must be documented.",
"WARN: patch-ctx:4: Please use unified diffs (diff -u) for patches.")
}
func (s *Suite) Test_ChecklinesPatch__no_patch(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
"",
@ -180,10 +185,12 @@ func (s *Suite) Test_ChecklinesPatch__no_patch(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "ERROR: patch-aa: Contains no patch.\n")
s.CheckOutputLines(
"ERROR: patch-aa: Contains no patch.")
}
func (s *Suite) Test_ChecklinesPatch__two_patched_files(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
"",
@ -200,12 +207,13 @@ func (s *Suite) Test_ChecklinesPatch__two_patched_files(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, ""+
"ERROR: patch-aa:3: Each patch must be documented.\n"+
"WARN: patch-aa: Contains patches for 2 files, should be only one.\n")
s.CheckOutputLines(
"ERROR: patch-aa:3: Each patch must be documented.",
"WARN: patch-aa: Contains patches for 2 files, should be only one.")
}
func (s *Suite) Test_ChecklinesPatch__documentation_that_looks_like_patch_lines(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
"",
@ -217,10 +225,12 @@ func (s *Suite) Test_ChecklinesPatch__documentation_that_looks_like_patch_lines(
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "ERROR: patch-aa: Contains no patch.\n")
s.CheckOutputLines(
"ERROR: patch-aa: Contains no patch.")
}
func (s *Suite) Test_ChecklinesPatch__only_unified_header_but_no_content(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-unified",
"$"+"NetBSD$",
"",
@ -231,10 +241,12 @@ func (s *Suite) Test_ChecklinesPatch__only_unified_header_but_no_content(c *chec
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "ERROR: patch-unified:EOF: No patch hunks for \"file\".\n")
s.CheckOutputLines(
"ERROR: patch-unified:EOF: No patch hunks for \"file\".")
}
func (s *Suite) Test_ChecklinesPatch__only_context_header_but_no_content(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-context",
"$"+"NetBSD$",
"",
@ -247,10 +259,12 @@ func (s *Suite) Test_ChecklinesPatch__only_context_header_but_no_content(c *chec
// Context diffs are deprecated, therefore it is not worth
// adding extra code for checking them thoroughly.
c.Check(s.Output(), equals, "WARN: patch-context:5: Please use unified diffs (diff -u) for patches.\n")
s.CheckOutputLines(
"WARN: patch-context:5: Please use unified diffs (diff -u) for patches.")
}
func (s *Suite) Test_ChecklinesPatch__Makefile_with_absolute_pathnames(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-unified",
"$"+"NetBSD$",
"",
@ -270,22 +284,23 @@ func (s *Suite) Test_ChecklinesPatch__Makefile_with_absolute_pathnames(c *check.
ChecklinesPatch(lines)
c.Check(s.Output(), equals, ""+
"WARN: patch-unified:10: Found absolute pathname: /bin/cp\n"+
"WARN: patch-unified:13: Found absolute pathname: /bin/cp\n")
s.CheckOutputLines(
"WARN: patch-unified:10: Found absolute pathname: /bin/cp",
"WARN: patch-unified:13: Found absolute pathname: /bin/cp")
G.opts.WarnExtra = true
ChecklinesPatch(lines)
c.Check(s.Output(), equals, ""+
"WARN: patch-unified:8: Found absolute pathname: /bin/cp\n"+
"WARN: patch-unified:10: Found absolute pathname: /bin/cp\n"+
"WARN: patch-unified:13: Found absolute pathname: /bin/cp\n"+
"WARN: patch-unified:15: Found absolute pathname: /bin/cp\n")
s.CheckOutputLines(
"WARN: patch-unified:8: Found absolute pathname: /bin/cp",
"WARN: patch-unified:10: Found absolute pathname: /bin/cp",
"WARN: patch-unified:13: Found absolute pathname: /bin/cp",
"WARN: patch-unified:15: Found absolute pathname: /bin/cp")
}
func (s *Suite) Test_ChecklinesPatch__no_newline_with_text_following(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
"",
@ -302,10 +317,12 @@ func (s *Suite) Test_ChecklinesPatch__no_newline_with_text_following(c *check.C)
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "WARN: patch-aa:12: Empty line or end of file expected.\n")
s.CheckOutputLines(
"WARN: patch-aa:12: Empty line or end of file expected.")
}
func (s *Suite) Test_ChecklinesPatch__no_newline(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
"",
@ -321,10 +338,11 @@ func (s *Suite) Test_ChecklinesPatch__no_newline(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ChecklinesPatch__empty_lines_left_out_at_eof(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
"",
@ -342,12 +360,13 @@ func (s *Suite) Test_ChecklinesPatch__empty_lines_left_out_at_eof(c *check.C) {
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
// In some context lines, the leading space character is missing.
// Since this is no problem for patch(1), pkglint also doesn't complain.
func (s *Suite) Test_ChecklinesPatch__context_lines_with_tab_instead_of_space(c *check.C) {
s.Init(c)
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
"",
@ -363,5 +382,5 @@ func (s *Suite) Test_ChecklinesPatch__context_lines_with_tab_instead_of_space(c
ChecklinesPatch(lines)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}

View file

@ -5,6 +5,7 @@ import (
"io"
"netbsd.org/pkglint/getopt"
"netbsd.org/pkglint/histogram"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"os"
@ -272,7 +273,7 @@ func CheckfileExtra(fname string) {
}
}
func ChecklinesDescr(lines []Line) {
func ChecklinesDescr(lines []line.Line) {
if trace.Tracing {
defer trace.Call1(lines[0].Filename())()
}
@ -300,7 +301,7 @@ func ChecklinesDescr(lines []Line) {
SaveAutofixChanges(lines)
}
func ChecklinesMessage(lines []Line) {
func ChecklinesMessage(lines []line.Line) {
if trace.Tracing {
defer trace.Call1(lines[0].Filename())()
}
@ -486,7 +487,7 @@ func Checkfile(fname string) {
}
}
func ChecklinesTrailingEmptyLines(lines []Line) {
func ChecklinesTrailingEmptyLines(lines []line.Line) {
max := len(lines)
last := max
for last > 1 && lines[last-1].Text() == "" {

View file

@ -47,7 +47,8 @@ func (s *Suite) Test_Pkglint_CheckDirent__outside(c *check.C) {
new(Pkglint).CheckDirent(s.tmpdir)
c.Check(s.Output(), equals, "ERROR: ~: Cannot determine the pkgsrc root directory for \"~\".\n")
s.CheckOutputLines(
"ERROR: ~: Cannot determine the pkgsrc root directory for \"~\".")
}
func (s *Suite) Test_Pkglint_CheckDirent(c *check.C) {
@ -61,19 +62,23 @@ func (s *Suite) Test_Pkglint_CheckDirent(c *check.C) {
pkglint.CheckDirent(s.tmpdir)
c.Check(s.Output(), equals, "ERROR: ~/Makefile: Must not be empty.\n")
s.CheckOutputLines(
"ERROR: ~/Makefile: Must not be empty.")
pkglint.CheckDirent(s.tmpdir + "/category")
c.Check(s.Output(), equals, "ERROR: ~/category/Makefile: Must not be empty.\n")
s.CheckOutputLines(
"ERROR: ~/category/Makefile: Must not be empty.")
pkglint.CheckDirent(s.tmpdir + "/category/package")
c.Check(s.Output(), equals, "ERROR: ~/category/package/Makefile: Must not be empty.\n")
s.CheckOutputLines(
"ERROR: ~/category/package/Makefile: Must not be empty.")
pkglint.CheckDirent(s.tmpdir + "/category/package/nonexistent")
c.Check(s.Output(), equals, "ERROR: ~/category/package/nonexistent: No such file or directory.\n")
s.CheckOutputLines(
"ERROR: ~/category/package/nonexistent: No such file or directory.")
}
func (s *Suite) Test_resolveVariableRefs__circular_reference(c *check.C) {
@ -111,6 +116,7 @@ func (s *Suite) Test_resolveVariableRefs__special_chars(c *check.C) {
}
func (s *Suite) Test_ChecklinesDescr(c *check.C) {
s.Init(c)
lines := s.NewLines("DESCR",
strings.Repeat("X", 90),
"", "", "", "", "", "", "", "", "10",
@ -120,22 +126,25 @@ func (s *Suite) Test_ChecklinesDescr(c *check.C) {
ChecklinesDescr(lines)
c.Check(s.Output(), equals, ""+
"WARN: DESCR:1: Line too long (should be no more than 80 characters).\n"+
"NOTE: DESCR:11: Variables are not expanded in the DESCR file.\n"+
"WARN: DESCR:25: File too long (should be no more than 24 lines).\n")
s.CheckOutputLines(
"WARN: DESCR:1: Line too long (should be no more than 80 characters).",
"NOTE: DESCR:11: Variables are not expanded in the DESCR file.",
"WARN: DESCR:25: File too long (should be no more than 24 lines).")
}
func (s *Suite) Test_ChecklinesMessage__short(c *check.C) {
s.Init(c)
lines := s.NewLines("MESSAGE",
"one line")
ChecklinesMessage(lines)
c.Check(s.Output(), equals, "WARN: MESSAGE:1: File too short.\n")
s.CheckOutputLines(
"WARN: MESSAGE:1: File too short.")
}
func (s *Suite) Test_ChecklinesMessage__malformed(c *check.C) {
s.Init(c)
lines := s.NewLines("MESSAGE",
"1",
"2",
@ -145,10 +154,10 @@ func (s *Suite) Test_ChecklinesMessage__malformed(c *check.C) {
ChecklinesMessage(lines)
c.Check(s.Output(), equals, ""+
"WARN: MESSAGE:1: Expected a line of exactly 75 \"=\" characters.\n"+
"ERROR: MESSAGE:2: Expected \"$"+"NetBSD$\".\n"+
"WARN: MESSAGE:5: Expected a line of exactly 75 \"=\" characters.\n")
s.CheckOutputLines(
"WARN: MESSAGE:1: Expected a line of exactly 75 \"=\" characters.",
"ERROR: MESSAGE:2: Expected \"$"+"NetBSD$\".",
"WARN: MESSAGE:5: Expected a line of exactly 75 \"=\" characters.")
}
func (s *Suite) Test_GlobalData_Latest(c *check.C) {
@ -158,7 +167,8 @@ func (s *Suite) Test_GlobalData_Latest(c *check.C) {
latest1 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
c.Check(latest1, equals, "")
c.Check(s.Output(), equals, "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".\n")
s.CheckOutputLines(
"ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".")
s.CreateTmpFile("lang/Makefile", "")
G.globalData.latest = nil
@ -166,7 +176,8 @@ func (s *Suite) Test_GlobalData_Latest(c *check.C) {
latest2 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
c.Check(latest2, equals, "")
c.Check(s.Output(), equals, "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".\n")
s.CheckOutputLines(
"ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".")
s.CreateTmpFile("lang/python27/Makefile", "")
G.globalData.latest = nil
@ -174,7 +185,7 @@ func (s *Suite) Test_GlobalData_Latest(c *check.C) {
latest3 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
c.Check(latest3, equals, "../../lang/python27")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
s.CreateTmpFile("lang/python35/Makefile", "")
G.globalData.latest = nil
@ -182,5 +193,5 @@ func (s *Suite) Test_GlobalData_Latest(c *check.C) {
latest4 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
c.Check(latest4, equals, "../../lang/python35")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}

View file

@ -1,6 +1,7 @@
package main
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"path"
@ -8,7 +9,7 @@ import (
"strings"
)
func ChecklinesPlist(lines []Line) {
func ChecklinesPlist(lines []line.Line) {
if trace.Tracing {
defer trace.Call1(lines[0].Filename())()
}
@ -43,12 +44,12 @@ type PlistChecker struct {
}
type PlistLine struct {
line Line
line line.Line
conditional string // e.g. PLIST.docs
text string // Like line.text, without the conditional
}
func (ck *PlistChecker) Check(plainLines []Line) {
func (ck *PlistChecker) Check(plainLines []line.Line) {
plines := ck.NewLines(plainLines)
ck.collectFilesAndDirs(plines)
@ -76,7 +77,7 @@ func (ck *PlistChecker) Check(plainLines []Line) {
}
}
func (ck *PlistChecker) NewLines(lines []Line) []*PlistLine {
func (ck *PlistChecker) NewLines(lines []line.Line) []*PlistLine {
plines := make([]*PlistLine, len(lines))
for i, line := range lines {
conditional, text := "", line.Text()
@ -471,14 +472,14 @@ func (pline *PlistLine) warnImakeMannewsuffix() {
type plistLineSorter struct {
first *PlistLine
plines []*PlistLine
lines []Line
after map[*PlistLine][]Line
lines []line.Line
after map[*PlistLine][]line.Line
swapped bool
autofixed bool
}
func NewPlistLineSorter(plines []*PlistLine) *plistLineSorter {
s := &plistLineSorter{first: plines[0], after: make(map[*PlistLine][]Line)}
s := &plistLineSorter{first: plines[0], after: make(map[*PlistLine][]line.Line)}
prev := plines[0]
for _, pline := range plines[1:] {
if hasPrefix(pline.text, "@") || contains(pline.text, "$") {
@ -513,7 +514,7 @@ func (s *plistLineSorter) Sort() {
firstLine := s.first.line
firstLine.AutofixMark("Sorting the whole file.")
lines := []Line{firstLine}
lines := []line.Line{firstLine}
lines = append(lines, s.after[s.first]...)
for _, pline := range s.plines {
lines = append(lines, pline.line)

View file

@ -28,32 +28,34 @@ func (s *Suite) Test_ChecklinesPlist(c *check.C) {
ChecklinesPlist(lines)
c.Check(s.Output(), equals, ""+
"ERROR: PLIST:1: Expected \"@comment $"+"NetBSD$\".\n"+
"WARN: PLIST:1: The bin/ directory should not have subdirectories.\n"+
"WARN: PLIST:2: Manual page missing for bin/program.\n"+
"ERROR: PLIST:3: Configuration files must not be registered in the PLIST. Please use the CONF_FILES framework, which is described in mk/pkginstall/bsd.pkginstall.mk.\n"+
"ERROR: PLIST:4: RCD_SCRIPTS must not be registered in the PLIST. Please use the RCD_SCRIPTS framework.\n"+
"ERROR: PLIST:6: \"info/dir\" must not be listed. Use install-info to add/remove an entry.\n"+
"WARN: PLIST:7: Library filename \"c.so\" should start with \"lib\".\n"+
"WARN: PLIST:8: Redundant library found. The libtool library is in line 9.\n"+
"WARN: PLIST:9: \"lib/libc.la\" should be sorted before \"lib/libc.so.6\".\n"+
"WARN: PLIST:10: Preformatted manual page without unformatted one.\n"+
"WARN: PLIST:10: Preformatted manual pages should end in \".0\".\n"+
"WARN: PLIST:11: IMAKE_MANNEWSUFFIX is not meant to appear in PLISTs.\n"+
"WARN: PLIST:12: Please remove this line. It is no longer necessary.\n"+
"WARN: PLIST:13: Manual page missing for sbin/clockctl.\n"+
"ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".\n"+
"ERROR: PLIST:16: Duplicate filename \"share/tzinfo\", already appeared in line 15.\n")
s.CheckOutputLines(
"ERROR: PLIST:1: Expected \"@comment $"+"NetBSD$\".",
"WARN: PLIST:1: The bin/ directory should not have subdirectories.",
"WARN: PLIST:2: Manual page missing for bin/program.",
"ERROR: PLIST:3: Configuration files must not be registered in the PLIST. Please use the CONF_FILES framework, which is described in mk/pkginstall/bsd.pkginstall.mk.",
"ERROR: PLIST:4: RCD_SCRIPTS must not be registered in the PLIST. Please use the RCD_SCRIPTS framework.",
"ERROR: PLIST:6: \"info/dir\" must not be listed. Use install-info to add/remove an entry.",
"WARN: PLIST:7: Library filename \"c.so\" should start with \"lib\".",
"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: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.",
"WARN: PLIST:13: Manual page missing for sbin/clockctl.",
"ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".",
"ERROR: PLIST:16: Duplicate filename \"share/tzinfo\", already appeared in line 15.")
}
func (s *Suite) Test_ChecklinesPlist__empty(c *check.C) {
s.Init(c)
lines := s.NewLines("PLIST",
"@comment $"+"NetBSD$")
ChecklinesPlist(lines)
c.Check(s.Output(), equals, "WARN: PLIST:1: PLIST files shouldn't be empty.\n")
s.CheckOutputLines(
"WARN: PLIST:1: PLIST files shouldn't be empty.")
}
func (s *Suite) Test_ChecklinesPlist__commonEnd(c *check.C) {
@ -67,10 +69,11 @@ func (s *Suite) Test_ChecklinesPlist__commonEnd(c *check.C) {
ChecklinesPlist(LoadExistingLines(fname, false))
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) {
s.Init(c)
G.Pkg = NewPackage("category/pkgbase")
G.Pkg.plistSubstCond["PLIST.bincmds"] = true
lines := s.NewLines("PLIST",
@ -79,7 +82,8 @@ func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) {
ChecklinesPlist(lines)
c.Check(s.Output(), equals, "WARN: PLIST:2: The bin/ directory should not have subdirectories.\n")
s.CheckOutputLines(
"WARN: PLIST:2: The bin/ directory should not have subdirectories.")
}
func (s *Suite) Test_ChecklinesPlist__sorting(c *check.C) {
@ -95,9 +99,9 @@ func (s *Suite) Test_ChecklinesPlist__sorting(c *check.C) {
ChecklinesPlist(lines)
c.Check(s.Output(), equals, ""+
"WARN: PLIST:5: \"bin/otherprogram\" should be sorted before \"sbin/program\".\n"+
"WARN: PLIST:6: \"bin/cat\" should be sorted before \"bin/otherprogram\".\n")
s.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_PlistLineSorter_Sort(c *check.C) {
@ -126,9 +130,9 @@ func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
NewPlistLineSorter(plines).Sort()
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/PLIST:1: Sorting the whole file.\n"+
"AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/PLIST:1: Sorting the whole file.",
"AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.")
c.Check(s.LoadTmpFile("PLIST"), equals, ""+
"@comment $"+"NetBSD$\n"+
"@comment Do not remove\n"+
@ -160,37 +164,44 @@ func (s *Suite) Test_PlistChecker_checkpathShare_Desktop(c *check.C) {
"@comment $"+"NetBSD$",
"share/applications/pkgbase.desktop"))
c.Check(s.Output(), equals, "WARN: PLIST:2: Packages that install a .desktop entry should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".\n")
s.CheckOutputLines(
"WARN: PLIST:2: Packages that install a .desktop entry should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".")
}
func (s *Suite) Test_PlistChecker_checkpathMan_gz(c *check.C) {
s.Init(c)
G.Pkg = NewPackage("category/pkgbase")
ChecklinesPlist(s.NewLines("PLIST",
"@comment $"+"NetBSD$",
"man/man3/strerror.3.gz"))
c.Check(s.Output(), equals, "NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.\n")
s.CheckOutputLines(
"NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.")
}
func (s *Suite) TestPlistChecker_checkpath__PKGMANDIR(c *check.C) {
s.Init(c)
lines := s.NewLines("PLIST",
"@comment $"+"NetBSD$",
"${PKGMANDIR}/man1/sh.1")
ChecklinesPlist(lines)
c.Check(s.Output(), equals, "NOTE: PLIST:2: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".\n")
s.CheckOutputLines(
"NOTE: PLIST:2: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".")
}
func (s *Suite) TestPlistChecker_checkpath__python_egg(c *check.C) {
s.Init(c)
lines := s.NewLines("PLIST",
"@comment $"+"NetBSD$",
"${PYSITELIB}/gdspy-${PKGVERSION}-py${PYVERSSUFFIX}.egg-info/PKG-INFO")
ChecklinesPlist(lines)
c.Check(s.Output(), equals, "WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.\n")
s.CheckOutputLines(
"WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.")
}
func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
@ -221,20 +232,20 @@ func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
lines := LoadExistingLines(fname, false)
ChecklinesPlist(lines)
c.Check(s.Output(), equals, ""+
"WARN: ~/PLIST:3: \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_storage.la\".\n"+
"WARN: ~/PLIST:4: \"lib/libvirt/connection-driver/libvirt_driver_libxl.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".\n"+
"NOTE: ~/PLIST:6: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".\n")
s.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 mention \"man/\" instead of \"${PKGMANDIR}\".")
s.UseCommandLine("-Wall", "--autofix")
ChecklinesPlist(lines)
fixedLines := LoadExistingLines(fname, false)
c.Check(s.Output(), equals, ""+
"AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".\n"+
"AUTOFIX: ~/PLIST:1: Sorting the whole file.\n"+
"AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.\n")
s.CheckOutputLines(
"AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".",
"AUTOFIX: ~/PLIST:1: Sorting the whole file.",
"AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.")
c.Check(len(lines), equals, len(fixedLines))
c.Check(s.LoadTmpFile("PLIST"), equals, ""+
"@comment $"+"NetBSD$\n"+

View file

@ -3,6 +3,7 @@ package main
// Parsing and checking shell commands embedded in Makefiles
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/textproc"
"netbsd.org/pkglint/trace"
"path"
@ -17,12 +18,11 @@ const (
)
type ShellLine struct {
line Line
mkline *MkLine
mkline MkLine
}
func NewShellLine(mkline *MkLine) *ShellLine {
return &ShellLine{mkline.Line, mkline}
func NewShellLine(mkline MkLine) *ShellLine {
return &ShellLine{mkline}
}
var shellcommandsContextType = &Vartype{lkNone, BtShellCommands, []AclEntry{{"*", aclpAllRuntime}}, false}
@ -37,7 +37,7 @@ func (shline *ShellLine) CheckWord(token string, checkQuoting bool) {
return
}
line := shline.line
var line line.Line = shline.mkline
p := NewMkParser(line, token, false)
if varuse := p.VarUse(); varuse != nil && p.EOF() {
@ -184,7 +184,7 @@ func (shline *ShellLine) checkVaruseToken(parser *MkParser, quoting ShQuoting) b
varname := varuse.varname
if varname == "@" {
shline.line.Warnf("Please use \"${.TARGET}\" instead of \"$@\".")
shline.mkline.Warnf("Please use \"${.TARGET}\" instead of \"$@\".")
Explain(
"The variable $@ can easily be confused with the shell variable of",
"the same name, which has a completely different meaning.")
@ -200,7 +200,7 @@ func (shline *ShellLine) checkVaruseToken(parser *MkParser, quoting ShQuoting) b
case (quoting == shqSquot || quoting == shqDquot) && matches(varname, `^(?:.*DIR|.*FILE|.*PATH|.*_VAR|PREFIX|.*BASE|PKGNAME)$`):
// This is ok if we don't allow these variables to have embedded [\$\\\"\'\`].
case quoting == shqDquot && varuse.IsQ():
shline.line.Warnf("Please don't use the :Q operator in double quotes.")
shline.mkline.Warnf("Please don't use the :Q operator in double quotes.")
Explain(
"Either remove the :Q or the double quotes. In most cases, it is",
"more appropriate to remove the double quotes.")
@ -224,7 +224,7 @@ func (shline *ShellLine) unescapeBackticks(shellword string, repl *textproc.Pref
defer trace.Call(shellword, quoting, "=>", trace.Ref(&unescaped))()
}
line := shline.line
var line line.Line = shline.mkline
for !repl.EOF() {
switch {
case repl.AdvanceStr("`"):
@ -276,7 +276,7 @@ func (shline *ShellLine) CheckShellCommandLine(shelltext string) {
defer trace.Call1(shelltext)()
}
line := shline.line
var line line.Line = shline.mkline
if contains(shelltext, "${SED}") && contains(shelltext, "${MV}") {
line.Notef("Please use the SUBST framework instead of ${SED} and ${MV}.")
@ -325,13 +325,14 @@ func (shline *ShellLine) CheckShellCommand(shellcmd string, pSetE *bool) {
defer trace.Call()()
}
program, err := parseShellProgram(shline.line, shellcmd)
var line line.Line = shline.mkline
program, err := parseShellProgram(line, shellcmd)
if err != nil && contains(shellcmd, "$$(") { // Hack until the shell parser can handle subshells.
shline.line.Warnf("Invoking subshells via $(...) is not portable enough.")
line.Warnf("Invoking subshells via $(...) is not portable enough.")
return
}
if err != nil {
shline.line.Warnf("Pkglint ShellLine.CheckShellCommand: %s", err)
line.Warnf("Pkglint ShellLine.CheckShellCommand: %s", err)
return
}
@ -352,7 +353,7 @@ func (shline *ShellLine) CheckShellCommand(shellcmd string, pSetE *bool) {
}
if cmd, ok := node.(*MkShPipeline); ok {
spc.checkPipeExitcode(shline.line, cmd)
spc.checkPipeExitcode(line, cmd)
}
if word, ok := node.(*ShToken); ok {
@ -365,7 +366,7 @@ func (shline *ShellLine) CheckShellCommands(shellcmds string) {
setE := true
shline.CheckShellCommand(shellcmds, &setE)
if !hasSuffix(shellcmds, ";") {
shline.line.Warnf("This shell command list should end with a semicolon.")
shline.mkline.Warnf("This shell command list should end with a semicolon.")
}
}
@ -385,7 +386,7 @@ func (shline *ShellLine) checkHiddenAndSuppress(hiddenAndSuppress, rest string)
// Shell comments may be hidden, since they cannot have side effects.
default:
tokens, _ := splitIntoShellTokens(shline.line, rest)
tokens, _ := splitIntoShellTokens(shline.mkline, rest)
if len(tokens) > 0 {
cmd := tokens[0]
switch cmd {
@ -398,7 +399,7 @@ func (shline *ShellLine) checkHiddenAndSuppress(hiddenAndSuppress, rest string)
"${WARNING_CAT}", "${WARNING_MSG}":
break
default:
shline.line.Warnf("The shell command %q should not be hidden.", cmd)
shline.mkline.Warnf("The shell command %q should not be hidden.", cmd)
Explain(
"Hidden shell commands do not appear on the terminal or in the log",
"file when they are executed. When they fail, the error message",
@ -412,7 +413,7 @@ func (shline *ShellLine) checkHiddenAndSuppress(hiddenAndSuppress, rest string)
}
if contains(hiddenAndSuppress, "-") {
shline.line.Warnf("Using a leading \"-\" to suppress errors is deprecated.")
shline.mkline.Warnf("Using a leading \"-\" to suppress errors is deprecated.")
Explain(
"If you really want to ignore any errors from this command, append",
"\"|| ${TRUE}\" to the command.")
@ -461,7 +462,7 @@ func (scc *SimpleCommandChecker) checkCommandStart() {
case scc.handleComment():
default:
if G.opts.WarnExtra && !(G.Mk != nil && G.Mk.indentation.DependsOn("OPSYS")) {
scc.shline.line.Warnf("Unknown shell command %q.", shellword)
scc.shline.mkline.Warnf("Unknown shell command %q.", shellword)
Explain(
"If you want your package to be portable to all platforms that pkgsrc",
"supports, you should only use shell commands that are covered by the",
@ -485,11 +486,11 @@ func (scc *SimpleCommandChecker) handleTool() bool {
}
if !localTool && !G.Mk.tools[shellword] && !G.Mk.tools["g"+shellword] {
scc.shline.line.Warnf("The %q tool is used but not added to USE_TOOLS.", shellword)
scc.shline.mkline.Warnf("The %q tool is used but not added to USE_TOOLS.", shellword)
}
if tool.MustUseVarForm {
scc.shline.line.Warnf("Please use \"${%s}\" instead of %q.", tool.Varname, shellword)
scc.shline.mkline.Warnf("Please use \"${%s}\" instead of %q.", tool.Varname, shellword)
}
scc.shline.checkCommandUse(shellword)
@ -504,7 +505,7 @@ func (scc *SimpleCommandChecker) handleForbiddenCommand() bool {
shellword := scc.strcmd.Name
switch path.Base(shellword) {
case "ktrace", "mktexlsr", "strace", "texconfig", "truss":
scc.shline.line.Errorf("%q must not be used in Makefiles.", shellword)
scc.shline.mkline.Errorf("%q must not be used in Makefiles.", shellword)
Explain(
"This command must appear in INSTALL scripts, not in the package",
"Makefile, so that the package also works if it is installed as a binary",
@ -524,13 +525,13 @@ func (scc *SimpleCommandChecker) handleCommandVariable() bool {
if tool := G.globalData.Tools.byVarname[varname]; tool != nil {
if !G.Mk.tools[tool.Name] {
scc.shline.line.Warnf("The %q tool is used but not added to USE_TOOLS.", tool.Name)
scc.shline.mkline.Warnf("The %q tool is used but not added to USE_TOOLS.", tool.Name)
}
scc.shline.checkCommandUse(shellword)
return true
}
if vartype := scc.shline.mkline.getVariableType(varname); vartype != nil && vartype.basicType.name == "ShellCommand" {
if vartype := scc.shline.mkline.VariableType(varname); vartype != nil && vartype.basicType.name == "ShellCommand" {
scc.shline.checkCommandUse(shellword)
return true
}
@ -559,13 +560,13 @@ func (scc *SimpleCommandChecker) handleComment() bool {
}
semicolon := contains(shellword, ";")
multiline := scc.shline.line.IsMultiline()
multiline := scc.shline.mkline.IsMultiline()
if semicolon {
scc.shline.line.Warnf("A shell comment should not contain semicolons.")
scc.shline.mkline.Warnf("A shell comment should not contain semicolons.")
}
if multiline {
scc.shline.line.Warnf("A shell comment does not stop at the end of line.")
scc.shline.mkline.Warnf("A shell comment does not stop at the end of line.")
}
if semicolon || multiline {
@ -595,10 +596,10 @@ func (scc *SimpleCommandChecker) checkAbsolutePathnames() {
isSubst := false
for _, arg := range scc.strcmd.Args {
if !isSubst {
LineChecker{scc.shline.line}.CheckAbsolutePathname(arg)
LineChecker{scc.shline.mkline}.CheckAbsolutePathname(arg)
}
if false && isSubst && !matches(arg, `"^[\"\'].*[\"\']$`) {
scc.shline.line.Warnf("Substitution commands like %q should always be quoted.", arg)
scc.shline.mkline.Warnf("Substitution commands like %q should always be quoted.", arg)
Explain(
"Usually these substitution commands contain characters like '*' or",
"other shell metacharacters that might lead to lookup of matching",
@ -628,7 +629,7 @@ func (scc *SimpleCommandChecker) checkAutoMkdirs() {
for _, arg := range scc.strcmd.Args {
if !contains(arg, "$$") && !matches(arg, `\$\{[_.]*[a-z]`) {
if m, dirname := match1(arg, `^(?:\$\{DESTDIR\})?\$\{PREFIX(?:|:Q)\}/(.*)`); m {
scc.shline.line.Notef("You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= %s\" instead of %q.", dirname, cmdname)
scc.shline.mkline.Notef("You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= %s\" instead of %q.", dirname, cmdname)
Explain(
"Many packages include a list of all needed directories in their",
"PLIST file. In such a case, you can just set AUTO_MKDIRS=yes and",
@ -662,7 +663,7 @@ func (scc *SimpleCommandChecker) checkInstallMulti() {
break
default:
if prevdir != "" {
scc.shline.line.Warnf("The INSTALL_*_DIR commands can only handle one directory at a time.")
scc.shline.mkline.Warnf("The INSTALL_*_DIR commands can only handle one directory at a time.")
Explain(
"Many implementations of install(1) can handle more, but pkgsrc aims",
"at maximum portability.")
@ -680,7 +681,7 @@ func (scc *SimpleCommandChecker) checkPaxPe() {
}
if scc.strcmd.Name == "${PAX}" && scc.strcmd.HasOption("-pe") {
scc.shline.line.Warnf("Please use the -pp option to pax(1) instead of -pe.")
scc.shline.mkline.Warnf("Please use the -pp option to pax(1) instead of -pe.")
Explain(
"The -pe option tells pax to preserve the ownership of the files, which",
"means that the installed files will belong to the user that has built",
@ -694,7 +695,7 @@ func (scc *SimpleCommandChecker) checkEchoN() {
}
if scc.strcmd.Name == "${ECHO}" && scc.strcmd.HasOption("-n") {
scc.shline.line.Warnf("Please use ${ECHO_N} instead of \"echo -n\".")
scc.shline.mkline.Warnf("Please use ${ECHO_N} instead of \"echo -n\".")
}
}
@ -720,7 +721,7 @@ func (spc *ShellProgramChecker) checkConditionalCd(list *MkShList) {
checkConditionalCd := func(cmd *MkShSimpleCommand) {
if NewStrCommand(cmd).Name == "cd" {
spc.shline.line.Errorf("The Solaris /bin/sh cannot handle \"cd\" inside conditionals.")
spc.shline.mkline.Errorf("The Solaris /bin/sh cannot handle \"cd\" inside conditionals.")
Explain(
"When the Solaris shell is in \"set -e\" mode and \"cd\" fails, the",
"shell will exit, no matter if it is protected by an \"if\" or the",
@ -762,7 +763,7 @@ func (spc *ShellProgramChecker) checkWord(word *ShToken, checkQuoting bool) {
spc.shline.CheckWord(word.MkText, checkQuoting)
}
func (scc *ShellProgramChecker) checkPipeExitcode(line Line, pipeline *MkShPipeline) {
func (scc *ShellProgramChecker) checkPipeExitcode(line line.Line, pipeline *MkShPipeline) {
if trace.Tracing {
defer trace.Call()()
}
@ -786,7 +787,7 @@ func (scc *ShellProgramChecker) checkSetE(list *MkShList, eflag *bool) {
// Disabled until the shell parser can recognize "command || exit 1" reliably.
if false && G.opts.WarnExtra && !*eflag && "the current token" == ";" {
*eflag = true
scc.shline.line.Warnf("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", "previous token")
scc.shline.mkline.Warnf("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", "previous token")
Explain(
"Normally, when a shell command fails (returns non-zero), the",
"remaining commands are still executed. For example, the following",
@ -813,7 +814,7 @@ func (shline *ShellLine) checkCommandUse(shellcmd string) {
return
}
line := shline.line
var line line.Line = shline.mkline
switch shellcmd {
case "${INSTALL}",
"${INSTALL_DATA}", "${INSTALL_DATA_DIR}",
@ -848,7 +849,7 @@ func (shline *ShellLine) checkCommandUse(shellcmd string) {
}
// Example: "word1 word2;;;" => "word1", "word2", ";;", ";"
func splitIntoShellTokens(line Line, text string) (tokens []string, rest string) {
func splitIntoShellTokens(line line.Line, text string) (tokens []string, rest string) {
if trace.Tracing {
defer trace.Call(line, text)()
}
@ -880,7 +881,7 @@ func splitIntoShellTokens(line Line, text string) (tokens []string, rest string)
// Example: "word1 word2;;;" => "word1", "word2;;;"
// Compare devel/bmake/files/str.c, function brk_string.
func splitIntoMkWords(line Line, text string) (words []string, rest string) {
func splitIntoMkWords(line line.Line, text string) (words []string, rest string) {
if trace.Tracing {
defer trace.Call(line, text)()
}

View file

@ -6,12 +6,14 @@ import (
)
func (s *Suite) Test_splitIntoShellTokens__line_continuation(c *check.C) {
s.Init(c)
words, rest := splitIntoShellTokens(dummyLine, "if true; then \\")
c.Check(words, check.DeepEquals, []string{"if", "true", ";", "then"})
c.Check(rest, equals, "\\")
c.Check(s.Output(), equals, "WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)\n")
s.CheckOutputLines(
"WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)")
}
func (s *Suite) Test_splitIntoShellTokens__dollar_slash(c *check.C) {
@ -111,14 +113,14 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
shline.CheckShellCommandLine("@# Comment")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
shline.CheckShellCommandLine("uname=`uname`; echo $$uname; echo")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Unknown shell command \"uname\".\n"+
"WARN: fname:1: Unknown shell command \"echo\".\n"+
"WARN: fname:1: Unknown shell command \"echo\".\n")
s.CheckOutputLines(
"WARN: fname:1: Unknown shell command \"uname\".",
"WARN: fname:1: Unknown shell command \"echo\".",
"WARN: fname:1: Unknown shell command \"echo\".")
s.RegisterTool(&Tool{Name: "echo", Predefined: true})
G.Mk = s.NewMkLines("fname",
@ -127,58 +129,59 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
shline.CheckShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain
c.Check(s.Output(), equals, ""+
"WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
s.CheckOutputLines(
"WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
"NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.")
shline.CheckShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Please don't use the :Q operator in double quotes.\n"+
"WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.\n"+
"WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.\n")
s.CheckOutputLines(
"WARN: fname:1: Please don't use the :Q operator in double quotes.",
"WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.",
"WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.")
shline.CheckShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot
c.Check(s.Output(), equals, ""+
"WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n"+
"WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.\n")
s.CheckOutputLines(
"WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.",
"WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.")
shline.CheckShellCommandLine("echo target=$@ exitcode=$$? '$$' \"\\$$\"")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n"+
"WARN: fname:1: The $? shell variable is often not available in \"set -e\" mode.\n")
s.CheckOutputLines(
"WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".",
"WARN: fname:1: The $? shell variable is often not available in \"set -e\" mode.")
shline.CheckShellCommandLine("echo $$@")
c.Check(s.Output(), equals, "WARN: fname:1: The $@ shell variable should only be used in double quotes.\n")
s.CheckOutputLines(
"WARN: fname:1: The $@ shell variable should only be used in double quotes.")
shline.CheckShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$"
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)\n"+
"WARN: fname:1: Pkglint ShellLine.CheckShellCommand: parse error at [\"]\n")
s.CheckOutputLines(
"WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)",
"WARN: fname:1: Pkglint ShellLine.CheckShellCommand: parse error at [\"]")
shline.CheckShellCommandLine("echo \"\\n\"")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
shline.CheckShellCommandLine("${RUN} for f in *.c; do echo $${f%.c}; done")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
shline.CheckShellCommandLine("${RUN} echo $${variable+set}")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
// Based on mail/thunderbird/Makefile, rev. 1.159
shline.CheckShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
"WARN: fname:1: Unknown shell command \"unzip\".\n"+
"WARN: fname:1: Unknown shell command \"awk\".\n")
s.CheckOutputLines(
"WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.",
"WARN: fname:1: Unknown shell command \"unzip\".",
"WARN: fname:1: Unknown shell command \"awk\".")
// From mail/thunderbird/Makefile, rev. 1.159
shline.CheckShellCommandLine("" +
@ -189,14 +192,14 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
" ${UNZIP_CMD} -aqo $$e; " +
"done")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?\n"+
"WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
"WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n"+
"WARN: fname:1: Unknown shell command \"awk\".\n"+
"WARN: fname:1: Unknown shell command \"${MKDIR}\".\n"+
"WARN: fname:1: MKDIR is used but not defined. Spelling mistake?\n"+
"WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n")
s.CheckOutputLines(
"WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?",
"WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.",
"WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?",
"WARN: fname:1: Unknown shell command \"awk\".",
"WARN: fname:1: Unknown shell command \"${MKDIR}\".",
"WARN: fname:1: MKDIR is used but not defined. Spelling mistake?",
"WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?")
// From x11/wxGTK28/Makefile
shline.CheckShellCommandLine("" +
@ -206,27 +209,27 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
" ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; " +
"done")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"WARN: fname:1: Unknown shell command \"[\".\n"+
"WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".\n")
s.CheckOutputLines(
"WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
"WARN: fname:1: Unknown shell command \"[\".",
"WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".")
shline.CheckShellCommandLine("@cp from to")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: The shell command \"cp\" should not be hidden.\n"+
"WARN: fname:1: Unknown shell command \"cp\".\n")
s.CheckOutputLines(
"WARN: fname:1: The shell command \"cp\" should not be hidden.",
"WARN: fname:1: Unknown shell command \"cp\".")
shline.CheckShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase")
c.Check(s.Output(), equals, ""+
"NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"WARN: fname:1: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
s.CheckOutputLines(
"NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of \"${INSTALL_DATA_DIR}\".",
"WARN: fname:1: The INSTALL_*_DIR commands can only handle one directory at a time.")
// See PR 46570, item "1. It does not"
shline.CheckShellCommandLine("for x in 1 2 3; do echo \"$$x\" || exit 1; done")
c.Check(s.Output(), equals, "") // No warning about missing error checking.
s.CheckOutputEmpty() // No warning about missing error checking.
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__nofix(c *check.C) {
@ -240,8 +243,8 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine__nofix(c *check.C) {
shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
s.CheckOutputLines(
"NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__show_autofix(c *check.C) {
@ -255,9 +258,9 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine__show_autofix(c *check.C) {
shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.\n"+
"AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".\n")
s.CheckOutputLines(
"NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.",
"AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__autofix(c *check.C) {
@ -271,8 +274,8 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine__autofix(c *check.C) {
shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
c.Check(s.Output(), equals, ""+
"AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".\n")
s.CheckOutputLines(
"AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__implementation(c *check.C) {
@ -293,7 +296,8 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine__implementation(c *check.C)
shline.CheckWord(text, false)
c.Check(s.Output(), equals, "WARN: fname:1: Unknown shell command \"echo\".\n")
s.CheckOutputLines(
"WARN: fname:1: Unknown shell command \"echo\".")
shline.CheckShellCommandLine(text)
@ -302,6 +306,7 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine__implementation(c *check.C)
}
func (s *Suite) Test_ShellLine_CheckShelltext__dollar_without_variable(c *check.C) {
s.Init(c)
G.globalData.InitVartypes()
G.Mk = s.NewMkLines("fname",
"# dummy")
@ -311,7 +316,7 @@ func (s *Suite) Test_ShellLine_CheckShelltext__dollar_without_variable(c *check.
shline.CheckShellCommandLine("pax -rwpp -s /.*~$$//g . ${DESTDIR}${PREFIX}")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ShellLine_CheckWord(c *check.C) {
@ -322,47 +327,50 @@ func (s *Suite) Test_ShellLine_CheckWord(c *check.C) {
shline.CheckWord("${${list}}", false)
c.Check(s.Output(), equals, "") // No warning for variables that are completely indirect.
s.CheckOutputEmpty() // No warning for variables that are completely indirect.
shline.CheckWord("${SED_FILE.${id}}", false)
c.Check(s.Output(), equals, "") // No warning for variables that are partly indirect.
s.CheckOutputEmpty() // No warning for variables that are partly indirect.
shline.CheckWord("\"$@\"", false)
c.Check(s.Output(), equals, "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n")
s.CheckOutputLines(
"WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".")
shline.CheckWord("${COMMENT:Q}", true)
c.Check(s.Output(), equals, "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n")
s.CheckOutputLines(
"WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.")
shline.CheckWord("\"${DISTINFO_FILE:Q}\"", true)
c.Check(s.Output(), equals, ""+
"WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.\n")
s.CheckOutputLines(
"WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
"NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.")
shline.CheckWord("embed${DISTINFO_FILE:Q}ded", true)
c.Check(s.Output(), equals, ""+
"WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.\n")
s.CheckOutputLines(
"WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
"NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.")
shline.CheckWord("s,\\.,,", true)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
shline.CheckWord("\"s,\\.,,\"", true)
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ShellLine_CheckWord__dollar_without_variable(c *check.C) {
s.Init(c)
shline := NewShellLine(NewMkLine(NewLine("fname", 1, "# dummy", nil)))
shline.CheckWord("/.*~$$//g", false) // Typical argument to pax(1).
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__echo(c *check.C) {
@ -375,37 +383,41 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine__echo(c *check.C) {
MkLineChecker{mkline}.checkText("echo \"hello, world\"")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
NewShellLine(mkline).CheckShellCommandLine("echo \"hello, world\"")
c.Check(s.Output(), equals, ""+
"WARN: fname:3: Please use \"${ECHO}\" instead of \"echo\".\n")
s.CheckOutputLines(
"WARN: fname:3: Please use \"${ECHO}\" instead of \"echo\".")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__shell_variables(c *check.C) {
s.Init(c)
text := "\tfor f in *.pl; do ${SED} s,@PREFIX@,${PREFIX}, < $f > $f.tmp && ${MV} $f.tmp $f; done"
shline := NewShellLine(NewMkLine(NewLine("Makefile", 3, text, nil)))
shline.CheckShellCommandLine(text)
c.Check(s.Output(), equals, ""+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"NOTE: Makefile:3: Please use the SUBST framework instead of ${SED} and ${MV}.\n")
s.CheckOutputLines(
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
"NOTE: Makefile:3: Please use the SUBST framework instead of ${SED} and ${MV}.")
shline.CheckShellCommandLine("install -c manpage.1 ${PREFIX}/man/man1/manpage.1")
c.Check(s.Output(), equals, "WARN: Makefile:3: Please use ${PKGMANDIR} instead of \"man\".\n")
s.CheckOutputLines(
"WARN: Makefile:3: Please use ${PKGMANDIR} instead of \"man\".")
shline.CheckShellCommandLine("cp init-script ${PREFIX}/etc/rc.d/service")
c.Check(s.Output(), equals, "WARN: Makefile:3: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.\n")
s.CheckOutputLines(
"WARN: Makefile:3: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.")
}
func (s *Suite) Test_ShellLine_checkCommandUse(c *check.C) {
s.Init(c)
G.Mk = s.NewMkLines("fname",
"# dummy")
G.Mk.target = "do-install"
@ -414,11 +426,13 @@ func (s *Suite) Test_ShellLine_checkCommandUse(c *check.C) {
shline.checkCommandUse("sed")
c.Check(s.Output(), equals, "WARN: fname:1: The shell command \"sed\" should not be used in the install phase.\n")
s.CheckOutputLines(
"WARN: fname:1: The shell command \"sed\" should not be used in the install phase.")
shline.checkCommandUse("cp")
c.Check(s.Output(), equals, "WARN: fname:1: ${CP} should not be used to install files.\n")
s.CheckOutputLines(
"WARN: fname:1: ${CP} should not be used to install files.")
}
func (s *Suite) Test_splitIntoMkWords(c *check.C) {
@ -441,53 +455,59 @@ func (s *Suite) Test_splitIntoMkWords(c *check.C) {
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__sed_and_mv(c *check.C) {
s.Init(c)
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' fname > fname.tmp; ${MV} fname.tmp fname", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, "NOTE: Makefile:85: Please use the SUBST framework instead of ${SED} and ${MV}.\n")
s.CheckOutputLines(
"NOTE: Makefile:85: Please use the SUBST framework instead of ${SED} and ${MV}.")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__subshell(c *check.C) {
s.Init(c)
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} uname=$$(uname)", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, "WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.\n")
s.CheckOutputLines(
"WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_dir(c *check.C) {
s.Init(c)
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
s.CheckOutputLines(
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".",
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".",
"WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.")
shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/share/examples/gdchart")
// No warning about multiple directories, since 0755 is an option, not an argument.
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/examples/gdchart\" instead of \"${INSTALL_DATA_DIR}\".\n")
s.CheckOutputLines(
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/examples/gdchart\" instead of \"${INSTALL_DATA_DIR}\".")
shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/dir1 ${PREFIX}/dir2")
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
s.CheckOutputLines(
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".",
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".",
"WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_option_d(c *check.C) {
s.Init(c)
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".\n"+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".\n")
s.CheckOutputLines(
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".",
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".")
}
func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) {
@ -501,7 +521,8 @@ func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C)
NewMkLines(lines).Check()
c.Check(s.Output(), equals, "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.\n")
s.CheckOutputLines(
"WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.")
}
func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) {

View file

@ -1,13 +1,16 @@
package main
import "netbsd.org/pkglint/textproc"
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/textproc"
)
type ShTokenizer struct {
parser *Parser
mkp *MkParser
}
func NewShTokenizer(line Line, text string, emitWarnings bool) *ShTokenizer {
func NewShTokenizer(line line.Line, text string, emitWarnings bool) *ShTokenizer {
p := NewParser(line, text, emitWarnings)
mkp := &MkParser{p}
return &ShTokenizer{p, mkp}

View file

@ -5,6 +5,7 @@ import (
)
func (s *Suite) Test_ShTokenizer_ShAtom(c *check.C) {
s.Init(c)
checkRest := func(s string, expected ...*ShAtom) string {
p := NewShTokenizer(dummyLine, s, false)
q := shqPlain
@ -17,7 +18,7 @@ func (s *Suite) Test_ShTokenizer_ShAtom(c *check.C) {
check := func(str string, expected ...*ShAtom) {
rest := checkRest(str, expected...)
c.Check(rest, equals, "")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
token := func(typ ShAtomType, text string, quoting ShQuoting) *ShAtom {
@ -356,13 +357,14 @@ func (s *Suite) Test_Shtokenizer_ShAtom__quoting(c *check.C) {
}
func (s *Suite) Test_ShTokenizer_ShToken(c *check.C) {
s.Init(c)
check := func(str string, expected ...*ShToken) {
p := NewShTokenizer(dummyLine, str, false)
for _, exp := range expected {
c.Check(p.ShToken(), deepEquals, exp)
}
c.Check(p.Rest(), equals, "")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
check("",

View file

@ -12,7 +12,7 @@ type SubstContext struct {
filterCmd string
}
func (ctx *SubstContext) Varassign(mkline *MkLine) {
func (ctx *SubstContext) Varassign(mkline MkLine) {
if !G.opts.WarnExtra {
return
}
@ -85,7 +85,7 @@ func (ctx *SubstContext) IsComplete() bool {
(len(ctx.sed) != 0 || len(ctx.vars) != 0 || ctx.filterCmd != "")
}
func (ctx *SubstContext) Finish(mkline *MkLine) {
func (ctx *SubstContext) Finish(mkline MkLine) {
if ctx.id == "" || !G.opts.WarnExtra {
return
}
@ -116,14 +116,14 @@ func (ctx *SubstContext) varname(varbase string) string {
}
}
func (ctx *SubstContext) dup(mkline *MkLine, pstr *string, varname, value string) {
func (ctx *SubstContext) dup(mkline MkLine, pstr *string, varname, value string) {
if *pstr != "" {
mkline.Warnf("Duplicate definition of %q.", varname)
}
*pstr = value
}
func (ctx *SubstContext) duplist(mkline *MkLine, plist *[]string, varname string, op MkOperator, value string) {
func (ctx *SubstContext) duplist(mkline MkLine, plist *[]string, varname string, op MkOperator, value string) {
if len(*plist) > 0 && op != opAssignAppend {
mkline.Warnf("All but the first %q lines should use the \"+=\" operator.", varname)
}

View file

@ -5,6 +5,7 @@ import (
)
func (s *Suite) Test_SubstContext__incomplete(c *check.C) {
s.Init(c)
G.opts.WarnExtra = true
ctx := new(SubstContext)
@ -26,10 +27,12 @@ func (s *Suite) Test_SubstContext__incomplete(c *check.C) {
ctx.Finish(newSubstLine(14, ""))
c.Check(s.Output(), equals, "WARN: Makefile:14: Incomplete SUBST block: SUBST_STAGE.interp missing.\n")
s.CheckOutputLines(
"WARN: Makefile:14: Incomplete SUBST block: SUBST_STAGE.interp missing.")
}
func (s *Suite) Test_SubstContext__complete(c *check.C) {
s.Init(c)
G.opts.WarnExtra = true
ctx := new(SubstContext)
@ -46,10 +49,11 @@ func (s *Suite) Test_SubstContext__complete(c *check.C) {
ctx.Finish(newSubstLine(15, ""))
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_SubstContext__OPSYSVARS(c *check.C) {
s.Init(c)
G.opts.WarnExtra = true
ctx := new(SubstContext)
@ -63,7 +67,7 @@ func (s *Suite) Test_SubstContext__OPSYSVARS(c *check.C) {
ctx.Finish(newSubstLine(15, ""))
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_SubstContext__no_class(c *check.C) {
@ -76,11 +80,11 @@ func (s *Suite) Test_SubstContext__no_class(c *check.C) {
ctx.Varassign(newSubstLine(12, "SUBST_SED.repl+=-e s,from,to,g"))
ctx.Finish(newSubstLine(13, ""))
c.Check(s.Output(), equals, ""+
"WARN: Makefile:11: SUBST_CLASSES should come before the definition of \"SUBST_FILES.repl\".\n"+
"WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.\n")
s.CheckOutputLines(
"WARN: Makefile:11: SUBST_CLASSES should come before the definition of \"SUBST_FILES.repl\".",
"WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.")
}
func newSubstLine(lineno int, text string) *MkLine {
func newSubstLine(lineno int, text string) MkLine {
return NewMkLine(NewLine("Makefile", lineno, text, nil))
}

View file

@ -0,0 +1,112 @@
package textproc
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"strings"
)
// Expecter records the state when checking a list of lines from top to bottom.
type Expecter struct {
lines []line.Line
index int
m []string
}
func NewExpecter(lines []line.Line) *Expecter {
return &Expecter{lines, 0, nil}
}
func (exp *Expecter) CurrentLine() line.Line {
if exp.index < len(exp.lines) {
return exp.lines[exp.index]
}
return line.NewLineEOF(exp.lines[0].Filename())
}
func (exp *Expecter) PreviousLine() line.Line {
return exp.lines[exp.index-1]
}
func (exp *Expecter) Index() int {
return exp.index
}
func (exp *Expecter) EOF() bool {
return !(exp.index < len(exp.lines))
}
func (exp *Expecter) Group(index int) string {
return exp.m[index]
}
func (exp *Expecter) Advance() bool {
exp.index++
exp.m = nil
return true
}
func (exp *Expecter) StepBack() {
exp.index--
}
func (exp *Expecter) AdvanceIfMatches(re regex.RegexPattern) bool {
if trace.Tracing {
defer trace.Call(exp.CurrentLine().Text(), re)()
}
if !exp.EOF() {
if m := regex.Match(exp.lines[exp.index].Text(), re); m != nil {
exp.index++
exp.m = m
return true
}
}
return false
}
func (exp *Expecter) AdvanceIfPrefix(prefix string) bool {
if trace.Tracing {
defer trace.Call2(exp.CurrentLine().Text(), prefix)()
}
return !exp.EOF() && strings.HasPrefix(exp.lines[exp.index].Text(), prefix) && exp.Advance()
}
func (exp *Expecter) AdvanceIfEquals(text string) bool {
if trace.Tracing {
defer trace.Call2(exp.CurrentLine().Text(), text)()
}
return !exp.EOF() && exp.lines[exp.index].Text() == text && exp.Advance()
}
func (exp *Expecter) ExpectEmptyLine(warnSpace bool) bool {
if exp.AdvanceIfEquals("") {
return true
}
if warnSpace {
if !exp.CurrentLine().AutofixInsertBefore("") {
exp.CurrentLine().Notef("Empty line expected.")
}
}
return false
}
func (exp *Expecter) ExpectText(text string) bool {
if !exp.EOF() && exp.lines[exp.index].Text() == text {
exp.index++
exp.m = nil
return true
}
exp.CurrentLine().Warnf("This line should contain the following text: %s", text)
return false
}
func (exp *Expecter) SkipToFooter() {
exp.index = len(exp.lines) - 2
}

View file

@ -1,6 +1,9 @@
package main
import "netbsd.org/pkglint/trace"
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/trace"
)
type Toplevel struct {
previousSubdir string
@ -37,7 +40,7 @@ func CheckdirToplevel() {
}
}
func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subdir, comment string) {
func (ctx *Toplevel) checkSubdir(line line.Line, commentedOut bool, indentation, subdir, comment string) {
if commentedOut && comment == "" {
line.Warnf("%q commented out without giving a reason.", subdir)
}

View file

@ -25,9 +25,9 @@ func (s *Suite) Test_CheckdirToplevel(c *check.C) {
G.CurrentDir = s.tmpdir
CheckdirToplevel()
c.Check(s.Output(), equals, ""+
"WARN: ~/Makefile:3: Indentation should be a single tab character.\n"+
"ERROR: ~/Makefile:6: Each subdir must only appear once.\n"+
"WARN: ~/Makefile:7: \"ignoreme\" commented out without giving a reason.\n"+
"WARN: ~/Makefile:9: bbb should come before ccc\n")
s.CheckOutputLines(
"WARN: ~/Makefile:3: Indentation should be a single tab character.",
"ERROR: ~/Makefile:6: Each subdir must only appear once.",
"WARN: ~/Makefile:7: \"ignoreme\" commented out without giving a reason.",
"WARN: ~/Makefile:9: bbb should come before ccc")
}

View file

@ -3,6 +3,7 @@ package main
import (
"fmt"
"io/ioutil"
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"os"
@ -133,7 +134,7 @@ func isLocallyModified(fname string) bool {
return false
}
func loadCvsEntries(fname string) []Line {
func loadCvsEntries(fname string) []line.Line {
dir := path.Dir(fname)
if dir == G.CvsEntriesDir {
return G.CvsEntriesLines
@ -184,7 +185,7 @@ func varnameParam(varname string) string {
return ""
}
func defineVar(mkline *MkLine, varname string) {
func defineVar(mkline MkLine, varname string) {
if G.Mk != nil {
G.Mk.DefineVar(mkline, varname)
}

View file

@ -135,7 +135,7 @@ func (gd *GlobalData) InitVartypes() {
usr("LOCALPATCHES", lkNone, BtPathname)
// The remaining variables from mk/defaults/mk.conf follow the
// naming conventions from MkLine.getVariableType, furthermore
// naming conventions from MkLine.VariableType, furthermore
// they may be redefined by packages. Therefore they cannot be
// defined as user-defined.
if false {

View file

@ -1,6 +1,7 @@
package main
import (
"netbsd.org/pkglint/line"
"netbsd.org/pkglint/regex"
"netbsd.org/pkglint/trace"
"path"
@ -9,8 +10,8 @@ import (
)
type VartypeCheck struct {
MkLine *MkLine
Line Line
MkLine MkLine
Line line.Line
Varname string
Op MkOperator
Value string
@ -23,7 +24,7 @@ type VartypeCheck struct {
// fields except the value. This is typically used when checking parts
// of composite types.
func NewVartypeCheckValue(vc *VartypeCheck, value string) *VartypeCheck {
valueNoVar := vc.MkLine.withoutMakeVariables(value)
valueNoVar := vc.MkLine.WithoutMakeVariables(value)
copy := *vc
copy.Value = value
@ -209,7 +210,7 @@ func (cv *VartypeCheck) Comment() {
}
func (cv *VartypeCheck) ConfFiles() {
words, _ := splitIntoMkWords(cv.MkLine.Line, cv.Value)
words, _ := splitIntoMkWords(cv.MkLine, cv.Value)
if len(words)%2 != 0 {
cv.Line.Warnf("Values for %s should always be pairs of paths.", cv.Varname)
}
@ -318,7 +319,7 @@ func (cv *VartypeCheck) DependencyWithPath() {
if matches(value, `:\.\./[^/]+$`) {
line.Warnf("Dependencies should have the form \"../../category/package\".")
cv.MkLine.explainRelativeDirs()
cv.MkLine.ExplainRelativeDirs()
return
}

View file

@ -7,27 +7,33 @@ import (
)
func (s *Suite) Test_VartypeCheck_AwkCommand(c *check.C) {
s.Init(c)
runVartypeChecks("PLIST_AWK", opAssignAppend, (*VartypeCheck).AwkCommand,
"{print $0}",
"{print $$0}")
c.Check(s.Output(), equals, "WARN: fname:1: $0 is ambiguous. Use ${0} if you mean a Makefile variable or $$0 if you mean a shell variable.\n")
s.CheckOutputLines(
"WARN: fname:1: $0 is ambiguous. Use ${0} if you mean a Makefile variable or $$0 if you mean a shell variable.")
}
func (s *Suite) Test_VartypeCheck_BasicRegularExpression(c *check.C) {
s.Init(c)
runVartypeChecks("REPLACE_FILES.pl", opAssign, (*VartypeCheck).BasicRegularExpression,
".*\\.pl$",
".*\\.pl$$")
c.Check(s.Output(), equals, "WARN: fname:1: Pkglint parse error in MkLine.Tokenize at \"$\".\n")
s.CheckOutputLines(
"WARN: fname:1: Pkglint parse error in MkLine.Tokenize at \"$\".")
}
func (s *Suite) Test_VartypeCheck_BuildlinkDepmethod(c *check.C) {
s.Init(c)
runVartypeChecks("BUILDLINK_DEPMETHOD.libc", opAssignDefault, (*VartypeCheck).BuildlinkDepmethod,
"full",
"unknown")
c.Check(s.Output(), equals, "WARN: fname:2: Invalid dependency method \"unknown\". Valid methods are \"build\" or \"full\".\n")
s.CheckOutputLines(
"WARN: fname:2: Invalid dependency method \"unknown\". Valid methods are \"build\" or \"full\".")
}
func (s *Suite) Test_VartypeCheck_Category(c *check.C) {
@ -43,12 +49,13 @@ func (s *Suite) Test_VartypeCheck_Category(c *check.C) {
"filesyscategory",
"wip")
c.Check(s.Output(), equals, ""+
"ERROR: fname:2: Invalid category \"arabic\".\n"+
"ERROR: fname:4: Invalid category \"wip\".\n")
s.CheckOutputLines(
"ERROR: fname:2: Invalid category \"arabic\".",
"ERROR: fname:4: Invalid category \"wip\".")
}
func (s *Suite) Test_VartypeCheck_CFlag(c *check.C) {
s.Init(c)
runVartypeChecks("CFLAGS", opAssignAppend, (*VartypeCheck).CFlag,
"-Wall",
"/W3",
@ -57,13 +64,14 @@ func (s *Suite) Test_VartypeCheck_CFlag(c *check.C) {
"-XX:+PrintClassHistogramAfterFullGC",
"`pkg-config pidgin --cflags`")
c.Check(s.Output(), equals, ""+
"WARN: fname:2: Compiler flag \"/W3\" should start with a hyphen.\n"+
"WARN: fname:3: Compiler flag \"target:sparc64\" should start with a hyphen.\n"+
"WARN: fname:5: Unknown compiler flag \"-XX:+PrintClassHistogramAfterFullGC\".\n")
s.CheckOutputLines(
"WARN: fname:2: Compiler flag \"/W3\" should start with a hyphen.",
"WARN: fname:3: Compiler flag \"target:sparc64\" should start with a hyphen.",
"WARN: fname:5: Unknown compiler flag \"-XX:+PrintClassHistogramAfterFullGC\".")
}
func (s *Suite) Test_VartypeCheck_Comment(c *check.C) {
s.Init(c)
runVartypeChecks("COMMENT", opAssign, (*VartypeCheck).Comment,
"Versatile Programming Language",
"TODO: Short description of the package",
@ -72,17 +80,18 @@ func (s *Suite) Test_VartypeCheck_Comment(c *check.C) {
"\"Quoting the comment is wrong\"",
"'Quoting the comment is wrong'")
c.Check(s.Output(), equals, ""+
"ERROR: fname:2: COMMENT must be set.\n"+
"WARN: fname:3: COMMENT should not begin with \"A\".\n"+
"WARN: fname:3: COMMENT should not end with a period.\n"+
"WARN: fname:4: COMMENT should start with a capital letter.\n"+
"WARN: fname:4: COMMENT should not be longer than 70 characters.\n"+
"WARN: fname:5: COMMENT should not be enclosed in quotes.\n"+
"WARN: fname:6: COMMENT should not be enclosed in quotes.\n")
s.CheckOutputLines(
"ERROR: fname:2: COMMENT must be set.",
"WARN: fname:3: COMMENT should not begin with \"A\".",
"WARN: fname:3: COMMENT should not end with a period.",
"WARN: fname:4: COMMENT should start with a capital letter.",
"WARN: fname:4: COMMENT should not be longer than 70 characters.",
"WARN: fname:5: COMMENT should not be enclosed in quotes.",
"WARN: fname:6: COMMENT should not be enclosed in quotes.")
}
func (s *Suite) Test_VartypeCheck_ConfFiles(c *check.C) {
s.Init(c)
runVartypeChecks("CONF_FILES", opAssignAppend, (*VartypeCheck).ConfFiles,
"single/file",
"share/etc/config ${PKG_SYSCONFDIR}/etc/config",
@ -90,11 +99,11 @@ func (s *Suite) Test_VartypeCheck_ConfFiles(c *check.C) {
"share/etc/config ${PREFIX}/etc/config share/etc/config2 ${VARBASE}/config2",
"share/etc/bootrc /etc/bootrc")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Values for CONF_FILES should always be pairs of paths.\n"+
"WARN: fname:3: Values for CONF_FILES should always be pairs of paths.\n"+
"WARN: fname:5: Found absolute pathname: /etc/bootrc\n"+
"WARN: fname:5: The destination file \"/etc/bootrc\" should start with a variable reference.\n")
s.CheckOutputLines(
"WARN: fname:1: Values for CONF_FILES should always be pairs of paths.",
"WARN: fname:3: Values for CONF_FILES should always be pairs of paths.",
"WARN: fname:5: Found absolute pathname: /etc/bootrc",
"WARN: fname:5: The destination file \"/etc/bootrc\" should start with a variable reference.")
}
func (s *Suite) Test_VartypeCheck_Dependency(c *check.C) {
@ -173,36 +182,42 @@ func (s *Suite) Test_VartypeCheck_DependencyWithPath(c *check.C) {
}
func (s *Suite) Test_VartypeCheck_DistSuffix(c *check.C) {
s.Init(c)
runVartypeChecks("EXTRACT_SUFX", opAssign, (*VartypeCheck).DistSuffix,
".tar.gz",
".tar.bz2")
c.Check(s.Output(), equals, "NOTE: fname:1: EXTRACT_SUFX is \".tar.gz\" by default, so this definition may be redundant.\n")
s.CheckOutputLines(
"NOTE: fname:1: EXTRACT_SUFX is \".tar.gz\" by default, so this definition may be redundant.")
}
func (s *Suite) Test_VartypeCheck_EmulPlatform(c *check.C) {
s.Init(c)
runVartypeChecks("EMUL_PLATFORM", opAssign, (*VartypeCheck).EmulPlatform,
"linux-i386",
"nextbsd-8087",
"${LINUX}")
c.Check(s.Output(), equals, ""+
"WARN: fname:2: \"nextbsd\" is not valid for the operating system part of EMUL_PLATFORM. Use one of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd netbsd openbsd osf1 solaris sunos } instead.\n"+
"WARN: fname:2: \"8087\" 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.\n"+
"WARN: fname:3: \"${LINUX}\" is not a valid emulation platform.\n")
s.CheckOutputLines(
"WARN: fname:2: \"nextbsd\" is not valid for the operating system part of EMUL_PLATFORM. Use one of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd netbsd openbsd osf1 solaris sunos } instead.",
"WARN: fname:2: \"8087\" 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.",
"WARN: fname:3: \"${LINUX}\" is not a valid emulation platform.")
}
func (s *Suite) Test_VartypeCheck_Enum(c *check.C) {
s.Init(c)
runVartypeMatchChecks("JDK", enum("jdk1 jdk2 jdk4").checker,
"*",
"jdk*",
"sun-jdk*",
"${JDKNAME}")
c.Check(s.Output(), equals, "WARN: fname:3: The pattern \"sun-jdk*\" cannot match any of { jdk1 jdk2 jdk4 } for JDK.\n")
s.CheckOutputLines(
"WARN: fname:3: The pattern \"sun-jdk*\" cannot match any of { jdk1 jdk2 jdk4 } for JDK.")
}
func (s *Suite) Test_VartypeCheck_FetchURL(c *check.C) {
s.Init(c)
s.RegisterMasterSite("MASTER_SITE_GNU", "http://ftp.gnu.org/pub/gnu/")
s.RegisterMasterSite("MASTER_SITE_GITHUB", "https://github.com/")
@ -212,90 +227,101 @@ func (s *Suite) Test_VartypeCheck_FetchURL(c *check.C) {
"${MASTER_SITE_GNU:=bison}",
"${MASTER_SITE_INVALID:=subdir/}")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Please use ${MASTER_SITE_GITHUB:=example/} instead of \"https://github.com/example/project/\" and run \""+confMake+" help topic=github\" for further tips.\n"+
"WARN: fname:2: Please use ${MASTER_SITE_GNU:=bison} instead of \"http://ftp.gnu.org/pub/gnu/bison\".\n"+
"ERROR: fname:3: The subdirectory in MASTER_SITE_GNU must end with a slash.\n"+
"ERROR: fname:4: The site MASTER_SITE_INVALID does not exist.\n")
s.CheckOutputLines(
"WARN: fname:1: Please use ${MASTER_SITE_GITHUB:=example/} instead of \"https://github.com/example/project/\" and run \""+confMake+" help topic=github\" for further tips.",
"WARN: fname:2: Please use ${MASTER_SITE_GNU:=bison} instead of \"http://ftp.gnu.org/pub/gnu/bison\".",
"ERROR: fname:3: The subdirectory in MASTER_SITE_GNU must end with a slash.",
"ERROR: fname:4: The site MASTER_SITE_INVALID does not exist.")
// PR 46570, keyword gimp-fix-ca
runVartypeChecks("MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
"https://example.org/download.cgi?fname=fname&sha1=12341234")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
runVartypeChecks("MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
"http://example.org/distfiles/",
"http://example.org/download?fname=distfile;version=1.0",
"http://example.org/download?fname=<distfile>;version=<version>")
c.Check(s.Output(), equals, "WARN: fname:3: \"http://example.org/download?fname=<distfile>;version=<version>\" is not a valid URL.\n")
s.CheckOutputLines(
"WARN: fname:3: \"http://example.org/download?fname=<distfile>;version=<version>\" is not a valid URL.")
}
func (s *Suite) Test_VartypeCheck_Filename(c *check.C) {
s.Init(c)
runVartypeChecks("FNAME", opAssign, (*VartypeCheck).Filename,
"Filename with spaces.docx",
"OS/2-manual.txt")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: \"Filename with spaces.docx\" is not a valid filename.\n"+
"WARN: fname:2: A filename should not contain a slash.\n")
s.CheckOutputLines(
"WARN: fname:1: \"Filename with spaces.docx\" is not a valid filename.",
"WARN: fname:2: A filename should not contain a slash.")
}
func (s *Suite) Test_VartypeCheck_LdFlag(c *check.C) {
s.Init(c)
runVartypeChecks("LDFLAGS", opAssignAppend, (*VartypeCheck).LdFlag,
"-lc",
"-L/usr/lib64",
"`pkg-config pidgin --ldflags`",
"-unknown")
c.Check(s.Output(), equals, "WARN: fname:4: Unknown linker flag \"-unknown\".\n")
s.CheckOutputLines(
"WARN: fname:4: Unknown linker flag \"-unknown\".")
}
func (s *Suite) Test_VartypeCheck_License(c *check.C) {
s.Init(c)
runVartypeChecks("LICENSE", opAssign, (*VartypeCheck).License,
"gnu-gpl-v2",
"AND mit")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: License file /licenses/gnu-gpl-v2 does not exist.\n"+
"ERROR: fname:2: Parse error for license condition \"AND mit\".\n")
s.CheckOutputLines(
"WARN: fname:1: License file /licenses/gnu-gpl-v2 does not exist.",
"ERROR: fname:2: Parse error for license condition \"AND mit\".")
runVartypeChecks("LICENSE", opAssignAppend, (*VartypeCheck).License,
"gnu-gpl-v2",
"AND mit")
c.Check(s.Output(), equals, ""+
"ERROR: fname:1: Parse error for appended license condition \"gnu-gpl-v2\".\n"+
"WARN: fname:2: License file /licenses/mit does not exist.\n")
s.CheckOutputLines(
"ERROR: fname:1: Parse error for appended license condition \"gnu-gpl-v2\".",
"WARN: fname:2: License file /licenses/mit does not exist.")
}
func (s *Suite) Test_VartypeCheck_MachineGnuPlatform(c *check.C) {
s.Init(c)
runVartypeMatchChecks("MACHINE_GNU_PLATFORM", (*VartypeCheck).MachineGnuPlatform,
"x86_64-pc-cygwin",
"Cygwin-*-amd64")
c.Check(s.Output(), equals, ""+
"WARN: fname:2: The pattern \"Cygwin\" cannot match any of { aarch64 aarch64_be alpha amd64 arc arm armeb armv4 armv4eb armv6 armv6eb armv7 armv7eb cobalt convex dreamcast hpcmips hpcsh hppa hppa64 i386 i486 ia64 m5407 m68010 m68k m88k mips mips64 mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh shle sparc sparc64 vax x86_64 } for the hardware architecture part of MACHINE_GNU_PLATFORM.\n"+
"WARN: fname:2: The pattern \"amd64\" cannot match any of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd netbsd openbsd osf1 solaris sunos } for the operating system part of MACHINE_GNU_PLATFORM.\n")
s.CheckOutputLines(
"WARN: fname:2: The pattern \"Cygwin\" cannot match any of { aarch64 aarch64_be alpha amd64 arc arm armeb armv4 armv4eb armv6 armv6eb armv7 armv7eb cobalt convex dreamcast hpcmips hpcsh hppa hppa64 i386 i486 ia64 m5407 m68010 m68k m88k mips mips64 mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh shle sparc sparc64 vax x86_64 } for the hardware architecture part of MACHINE_GNU_PLATFORM.",
"WARN: fname:2: The pattern \"amd64\" cannot match any of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd netbsd openbsd osf1 solaris sunos } for the operating system part of MACHINE_GNU_PLATFORM.")
}
func (s *Suite) Test_VartypeCheck_MailAddress(c *check.C) {
s.Init(c)
runVartypeChecks("MAINTAINER", opAssign, (*VartypeCheck).MailAddress,
"pkgsrc-users@netbsd.org")
c.Check(s.Output(), equals, "WARN: fname:1: Please write \"NetBSD.org\" instead of \"netbsd.org\".\n")
s.CheckOutputLines(
"WARN: fname:1: Please write \"NetBSD.org\" instead of \"netbsd.org\".")
}
func (s *Suite) Test_VartypeCheck_Message(c *check.C) {
s.Init(c)
runVartypeChecks("SUBST_MESSAGE.id", opAssign, (*VartypeCheck).Message,
"\"Correct paths\"",
"Correct paths")
c.Check(s.Output(), equals, "WARN: fname:1: SUBST_MESSAGE.id should not be quoted.\n")
s.CheckOutputLines(
"WARN: fname:1: SUBST_MESSAGE.id should not be quoted.")
}
func (s *Suite) Test_VartypeCheck_Option(c *check.C) {
s.Init(c)
G.globalData.PkgOptions = map[string]string{
"documented": "Option description",
"undocumented": "",
@ -306,50 +332,58 @@ func (s *Suite) Test_VartypeCheck_Option(c *check.C) {
"undocumented",
"unknown")
c.Check(s.Output(), equals, "WARN: fname:3: Unknown option \"unknown\".\n")
s.CheckOutputLines(
"WARN: fname:3: Unknown option \"unknown\".")
}
func (s *Suite) Test_VartypeCheck_Pathlist(c *check.C) {
s.Init(c)
runVartypeChecks("PATH", opAssign, (*VartypeCheck).Pathlist,
"/usr/bin:/usr/sbin:.:${LOCALBASE}/bin")
c.Check(s.Output(), equals, "WARN: fname:1: All components of PATH (in this case \".\") should be absolute paths.\n")
s.CheckOutputLines(
"WARN: fname:1: All components of PATH (in this case \".\") should be absolute paths.")
}
func (s *Suite) Test_VartypeCheck_Perms(c *check.C) {
s.Init(c)
runVartypeChecks("CONF_FILES_PERMS", opAssignAppend, (*VartypeCheck).Perms,
"root",
"${ROOT_USER}",
"ROOT_USER",
"${REAL_ROOT_USER}")
c.Check(s.Output(), equals, "ERROR: fname:2: ROOT_USER must not be used in permission definitions. Use REAL_ROOT_USER instead.\n")
s.CheckOutputLines(
"ERROR: fname:2: ROOT_USER must not be used in permission definitions. Use REAL_ROOT_USER instead.")
}
func (s *Suite) Test_VartypeCheck_PkgOptionsVar(c *check.C) {
s.Init(c)
runVartypeChecks("PKG_OPTIONS_VAR.screen", opAssign, (*VartypeCheck).PkgOptionsVar,
"PKG_OPTIONS.${PKGBASE}",
"PKG_OPTIONS.anypkgbase")
c.Check(s.Output(), equals, ""+
"ERROR: fname:1: PKGBASE must not be used in PKG_OPTIONS_VAR.\n")
s.CheckOutputLines(
"ERROR: fname:1: PKGBASE must not be used in PKG_OPTIONS_VAR.")
}
func (s *Suite) Test_VartypeCheck_PkgRevision(c *check.C) {
s.Init(c)
runVartypeChecks("PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
"3a")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: PKGREVISION must be a positive integer number.\n"+
"ERROR: fname:1: PKGREVISION only makes sense directly in the package Makefile.\n")
s.CheckOutputLines(
"WARN: fname:1: PKGREVISION must be a positive integer number.",
"ERROR: fname:1: PKGREVISION only makes sense directly in the package Makefile.")
runVartypeChecksFname("Makefile", "PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
"3")
c.Check(s.Output(), equals, "")
s.CheckOutputEmpty()
}
func (s *Suite) Test_VartypeCheck_MachinePlatformPattern(c *check.C) {
s.Init(c)
runVartypeMatchChecks("ONLY_FOR_PLATFORM", (*VartypeCheck).MachinePlatformPattern,
"linux-i386",
"nextbsd-5.0-8087",
@ -359,74 +393,85 @@ func (s *Suite) Test_VartypeCheck_MachinePlatformPattern(c *check.C) {
"FreeBSD-*",
"${LINUX}")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: \"linux-i386\" is not a valid platform pattern.\n"+
"WARN: fname:2: The pattern \"nextbsd\" 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 ONLY_FOR_PLATFORM.\n"+
"WARN: fname:2: The pattern \"8087\" 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 ONLY_FOR_PLATFORM.\n"+
"WARN: fname:3: The pattern \"netbsd\" 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 ONLY_FOR_PLATFORM.\n"+
"WARN: fname:3: The pattern \"l*\" 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 ONLY_FOR_PLATFORM.\n"+
"WARN: fname:5: \"FreeBSD*\" is not a valid platform pattern.\n")
s.CheckOutputLines(
"WARN: fname:1: \"linux-i386\" is not a valid platform pattern.",
"WARN: fname:2: The pattern \"nextbsd\" 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 ONLY_FOR_PLATFORM.",
"WARN: fname:2: The pattern \"8087\" 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 ONLY_FOR_PLATFORM.",
"WARN: fname:3: The pattern \"netbsd\" 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 ONLY_FOR_PLATFORM.",
"WARN: fname:3: The pattern \"l*\" 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 ONLY_FOR_PLATFORM.",
"WARN: fname:5: \"FreeBSD*\" is not a valid platform pattern.")
}
func (s *Suite) Test_VartypeCheck_PythonDependency(c *check.C) {
s.Init(c)
runVartypeChecks("PYTHON_VERSIONED_DEPENDENCIES", opAssign, (*VartypeCheck).PythonDependency,
"cairo",
"${PYDEP}",
"cairo,X")
c.Check(s.Output(), equals, ""+
"WARN: fname:2: Python dependencies should not contain variables.\n"+
"WARN: fname:3: Invalid Python dependency \"cairo,X\".\n")
s.CheckOutputLines(
"WARN: fname:2: Python dependencies should not contain variables.",
"WARN: fname:3: Invalid Python dependency \"cairo,X\".")
}
func (s *Suite) Test_VartypeCheck_Restricted(c *check.C) {
s.Init(c)
runVartypeChecks("NO_BIN_ON_CDROM", opAssign, (*VartypeCheck).Restricted,
"May only be distributed free of charge")
c.Check(s.Output(), equals, "WARN: fname:1: The only valid value for NO_BIN_ON_CDROM is ${RESTRICTED}.\n")
s.CheckOutputLines(
"WARN: fname:1: The only valid value for NO_BIN_ON_CDROM is ${RESTRICTED}.")
}
func (s *Suite) Test_VartypeCheck_SedCommands(c *check.C) {
s.Init(c)
runVartypeChecks("SUBST_SED.dummy", opAssign, (*VartypeCheck).SedCommands,
"s,@COMPILER@,gcc,g",
"-e s,a,b, -e a,b,c,",
"-e \"s,#,comment ,\"",
"-e \"s,\\#,comment ,\"")
c.Check(s.Output(), equals, ""+
"NOTE: fname:1: Please always use \"-e\" in sed commands, even if there is only one substitution.\n"+
"NOTE: fname:2: Each sed command should appear in an assignment of its own.\n"+
"WARN: fname:3: The # character starts a comment.\n")
s.CheckOutputLines(
"NOTE: fname:1: Please always use \"-e\" in sed commands, even if there is only one substitution.",
"NOTE: fname:2: Each sed command should appear in an assignment of its own.",
"WARN: fname:3: The # character starts a comment.")
}
func (s *Suite) Test_VartypeCheck_ShellCommands(c *check.C) {
s.Init(c)
runVartypeChecks("GENERATE_PLIST", opAssign, (*VartypeCheck).ShellCommands,
"echo bin/program",
"echo bin/program;")
c.Check(s.Output(), equals, "WARN: fname:1: This shell command list should end with a semicolon.\n")
s.CheckOutputLines(
"WARN: fname:1: This shell command list should end with a semicolon.")
}
func (s *Suite) Test_VartypeCheck_Stage(c *check.C) {
s.Init(c)
runVartypeChecks("SUBST_STAGE.dummy", opAssign, (*VartypeCheck).Stage,
"post-patch",
"post-modern",
"pre-test")
c.Check(s.Output(), equals, "WARN: fname:2: Invalid stage name \"post-modern\". Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.\n")
s.CheckOutputLines(
"WARN: fname:2: Invalid stage name \"post-modern\". Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.")
}
func (s *Suite) Test_VartypeCheck_VariableName(c *check.C) {
s.Init(c)
runVartypeChecks("BUILD_DEFS", opAssign, (*VartypeCheck).VariableName,
"VARBASE",
"VarBase",
"PKG_OPTIONS_VAR.pkgbase",
"${INDIRECT}")
c.Check(s.Output(), equals, "WARN: fname:2: \"VarBase\" is not a valid variable name.\n")
s.CheckOutputLines(
"WARN: fname:2: \"VarBase\" is not a valid variable name.")
}
func (s *Suite) Test_VartypeCheck_Version(c *check.C) {
s.Init(c)
runVartypeChecks("PERL5_REQD", opAssignAppend, (*VartypeCheck).Version,
"0",
"1.2.3.4.5.6",
@ -434,51 +479,55 @@ func (s *Suite) Test_VartypeCheck_Version(c *check.C) {
"4.1-SNAPSHOT",
"4pre7")
c.Check(s.Output(), equals, "WARN: fname:4: Invalid version number \"4.1-SNAPSHOT\".\n")
s.CheckOutputLines(
"WARN: fname:4: Invalid version number \"4.1-SNAPSHOT\".")
}
func (s *Suite) Test_VartypeCheck_Yes(c *check.C) {
s.Init(c)
runVartypeChecks("APACHE_MODULE", opAssign, (*VartypeCheck).Yes,
"yes",
"no",
"${YESVAR}")
c.Check(s.Output(), equals, ""+
"WARN: fname:2: APACHE_MODULE should be set to YES or yes.\n"+
"WARN: fname:3: APACHE_MODULE should be set to YES or yes.\n")
s.CheckOutputLines(
"WARN: fname:2: APACHE_MODULE should be set to YES or yes.",
"WARN: fname:3: APACHE_MODULE should be set to YES or yes.")
runVartypeMatchChecks("PKG_DEVELOPER", (*VartypeCheck).Yes,
"yes",
"no",
"${YESVAR}")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.\n"+
"WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.\n"+
"WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.\n")
s.CheckOutputLines(
"WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
"WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
"WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.")
}
func (s *Suite) Test_VartypeCheck_YesNo(c *check.C) {
s.Init(c)
runVartypeChecks("GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNo,
"yes",
"no",
"ja",
"${YESVAR}")
c.Check(s.Output(), equals, ""+
"WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.\n"+
"WARN: fname:4: GNU_CONFIGURE should be set to YES, yes, NO, or no.\n")
s.CheckOutputLines(
"WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.",
"WARN: fname:4: GNU_CONFIGURE should be set to YES, yes, NO, or no.")
}
func (s *Suite) Test_VartypeCheck_YesNoIndirectly(c *check.C) {
s.Init(c)
runVartypeChecks("GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNoIndirectly,
"yes",
"no",
"ja",
"${YESVAR}")
c.Check(s.Output(), equals, ""+
"WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.\n")
s.CheckOutputLines(
"WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.")
}
func runVartypeChecks(varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
@ -487,8 +536,8 @@ func runVartypeChecks(varname string, op MkOperator, checker func(*VartypeCheck)
}
for i, value := range values {
mkline := NewMkLine(NewLine("fname", i+1, varname+op.String()+value, nil))
valueNovar := mkline.withoutMakeVariables(mkline.Value())
vc := &VartypeCheck{mkline, mkline.Line, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
valueNovar := mkline.WithoutMakeVariables(mkline.Value())
vc := &VartypeCheck{mkline, mkline, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
checker(vc)
}
}
@ -497,8 +546,8 @@ func runVartypeMatchChecks(varname string, checker func(*VartypeCheck), values .
for i, value := range values {
text := fmt.Sprintf(".if ${%s:M%s} == \"\"", varname, value)
mkline := NewMkLine(NewLine("fname", i+1, text, nil))
valueNovar := mkline.withoutMakeVariables(value)
vc := &VartypeCheck{mkline, mkline.Line, varname, opUseMatch, value, valueNovar, "", false}
valueNovar := mkline.WithoutMakeVariables(value)
vc := &VartypeCheck{mkline, mkline, varname, opUseMatch, value, valueNovar, "", false}
checker(vc)
}
}
@ -506,8 +555,8 @@ func runVartypeMatchChecks(varname string, checker func(*VartypeCheck), values .
func runVartypeChecksFname(fname, varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
for i, value := range values {
mkline := NewMkLine(NewLine(fname, i+1, varname+op.String()+value, nil))
valueNovar := mkline.withoutMakeVariables(value)
vc := &VartypeCheck{mkline, mkline.Line, varname, op, value, valueNovar, "", false}
valueNovar := mkline.WithoutMakeVariables(value)
vc := &VartypeCheck{mkline, mkline, varname, op, value, valueNovar, "", false}
checker(vc)
}
}