pkgsrc-Changes archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
CVS commit: pkgsrc/pkgtools/pkglint
Module Name: pkgsrc
Committed By: rillig
Date: Wed Apr 3 21:49:51 UTC 2019
Modified Files:
pkgsrc/pkgtools/pkglint: Makefile
pkgsrc/pkgtools/pkglint/files: autofix.go check_test.go licenses.go
licenses_test.go mkline.go mkline_test.go mklinechecker.go
mklinechecker_test.go mklines.go mklines_test.go mkparser.go
mkparser_test.go mktypes.go mktypes_test.go package.go
package_test.go pkglint.go pkglint_test.go pkgsrc.go pkgsrc_test.go
redundantscope.go shell.go shell_test.go testnames_test.go util.go
util_test.go var.go vardefs.go vardefs_test.go vartype_test.go
vartypecheck.go vartypecheck_test.go
Log Message:
pkgtools/pkglint: update to 5.7.4
Changes since 5.7.3:
* Warn about dependency patterns that are missing a version number,
such as ${PYPKGPREFIX}-sqlite3:../../databases/py-sqlite3.
* Suggest to replace the := assignment operator with the :sh modifier,
in some cases where the variable is not obviously used at load time.
To generate a diff of this commit:
cvs rdiff -u -r1.572 -r1.573 pkgsrc/pkgtools/pkglint/Makefile
cvs rdiff -u -r1.18 -r1.19 pkgsrc/pkgtools/pkglint/files/autofix.go
cvs rdiff -u -r1.36 -r1.37 pkgsrc/pkgtools/pkglint/files/check_test.go \
pkgsrc/pkgtools/pkglint/files/shell.go
cvs rdiff -u -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/licenses.go \
pkgsrc/pkgtools/pkglint/files/licenses_test.go \
pkgsrc/pkgtools/pkglint/files/pkgsrc.go
cvs rdiff -u -r1.49 -r1.50 pkgsrc/pkgtools/pkglint/files/mkline.go \
pkgsrc/pkgtools/pkglint/files/pkglint.go
cvs rdiff -u -r1.54 -r1.55 pkgsrc/pkgtools/pkglint/files/mkline_test.go
cvs rdiff -u -r1.32 -r1.33 pkgsrc/pkgtools/pkglint/files/mklinechecker.go
cvs rdiff -u -r1.28 -r1.29 \
pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
cvs rdiff -u -r1.44 -r1.45 pkgsrc/pkgtools/pkglint/files/mklines.go \
pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
cvs rdiff -u -r1.39 -r1.40 pkgsrc/pkgtools/pkglint/files/mklines_test.go
cvs rdiff -u -r1.25 -r1.26 pkgsrc/pkgtools/pkglint/files/mkparser.go \
pkgsrc/pkgtools/pkglint/files/mkparser_test.go \
pkgsrc/pkgtools/pkglint/files/util_test.go
cvs rdiff -u -r1.12 -r1.13 pkgsrc/pkgtools/pkglint/files/mktypes.go
cvs rdiff -u -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/mktypes_test.go
cvs rdiff -u -r1.48 -r1.49 pkgsrc/pkgtools/pkglint/files/package.go
cvs rdiff -u -r1.41 -r1.42 pkgsrc/pkgtools/pkglint/files/package_test.go
cvs rdiff -u -r1.35 -r1.36 pkgsrc/pkgtools/pkglint/files/pkglint_test.go
cvs rdiff -u -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go
cvs rdiff -u -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/redundantscope.go \
pkgsrc/pkgtools/pkglint/files/var.go
cvs rdiff -u -r1.42 -r1.43 pkgsrc/pkgtools/pkglint/files/shell_test.go
cvs rdiff -u -r1.3 -r1.4 pkgsrc/pkgtools/pkglint/files/testnames_test.go
cvs rdiff -u -r1.40 -r1.41 pkgsrc/pkgtools/pkglint/files/util.go
cvs rdiff -u -r1.57 -r1.58 pkgsrc/pkgtools/pkglint/files/vardefs.go
cvs rdiff -u -r1.11 -r1.12 pkgsrc/pkgtools/pkglint/files/vardefs_test.go
cvs rdiff -u -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/vartype_test.go
cvs rdiff -u -r1.52 -r1.53 pkgsrc/pkgtools/pkglint/files/vartypecheck.go
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: pkgsrc/pkgtools/pkglint/Makefile
diff -u pkgsrc/pkgtools/pkglint/Makefile:1.572 pkgsrc/pkgtools/pkglint/Makefile:1.573
--- pkgsrc/pkgtools/pkglint/Makefile:1.572 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/Makefile Wed Apr 3 21:49:51 2019
@@ -1,6 +1,6 @@
-# $NetBSD: Makefile,v 1.572 2019/03/24 13:58:38 rillig Exp $
+# $NetBSD: Makefile,v 1.573 2019/04/03 21:49:51 rillig Exp $
-PKGNAME= pkglint-5.7.3
+PKGNAME= pkglint-5.7.4
CATEGORIES= pkgtools
DISTNAME= tools
MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/}
Index: pkgsrc/pkgtools/pkglint/files/autofix.go
diff -u pkgsrc/pkgtools/pkglint/files/autofix.go:1.18 pkgsrc/pkgtools/pkglint/files/autofix.go:1.19
--- pkgsrc/pkgtools/pkglint/files/autofix.go:1.18 Sun Mar 10 19:01:50 2019
+++ pkgsrc/pkgtools/pkglint/files/autofix.go Wed Apr 3 21:49:51 2019
@@ -82,7 +82,7 @@ func (fix *Autofix) Explain(explanation
fix.explanation = explanation
}
-// ReplaceAfter replaces "from" with "to", a single time.
+// Replace replaces "from" with "to", a single time.
func (fix *Autofix) Replace(from string, to string) {
fix.ReplaceAfter("", from, to)
}
@@ -227,7 +227,9 @@ func (fix *Autofix) Delete() {
}
// Anyway has the effect of showing the diagnostic even when nothing can
-// be fixed automatically, but only if neither --show-autofix nor
+// be fixed automatically.
+//
+// As usual, the diagnostic is only shown if neither --show-autofix nor
// --autofix mode is given.
func (fix *Autofix) Anyway() {
fix.anyway = !G.Logger.IsAutofix()
Index: pkgsrc/pkgtools/pkglint/files/check_test.go
diff -u pkgsrc/pkgtools/pkglint/files/check_test.go:1.36 pkgsrc/pkgtools/pkglint/files/check_test.go:1.37
--- pkgsrc/pkgtools/pkglint/files/check_test.go:1.36 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/check_test.go Wed Apr 3 21:49:51 2019
@@ -162,7 +162,7 @@ func (t *Tester) SetUpCommandLine(args .
//
// See SetUpTool for registering tools like echo, awk, perl.
func (t *Tester) SetUpVartypes() {
- G.Pkgsrc.vartypes.Init(G.Pkgsrc)
+ G.Pkgsrc.vartypes.Init(&G.Pkgsrc)
}
func (t *Tester) SetUpMasterSite(varname string, urls ...string) {
@@ -531,22 +531,27 @@ func (t *Tester) Remove(relativeFileName
// include("including.mk",
// include("other.mk",
// "VAR= other"),
-// include("module.mk",
+// include("subdir/module.mk",
// "VAR= module",
-// include("version.mk",
+// include("subdir/version.mk",
// "VAR= version"),
-// include("env.mk",
+// include("subdir/env.mk",
// "VAR= env")))
//
// mklines := get("including.mk")
// module := get("module.mk")
+//
+// The filenames passed to the include function are all relative to the
+// same location, but that location is irrelevant in practice. The generated
+// .include lines take the relative paths into account. For example, when
+// subdir/module.mk includes subdir/version.mk, the include line is just:
+// .include "version.mk"
func (t *Tester) SetUpHierarchy() (
include func(filename string, args ...interface{}) MkLines,
get func(string) MkLines) {
files := map[string]MkLines{}
- // FIXME: Define where the filename is relative to: to the file, or to the current directory.
include = func(filename string, args ...interface{}) MkLines {
var lines []Line
lineno := 1
@@ -561,7 +566,7 @@ func (t *Tester) SetUpHierarchy() (
case string:
addLine(arg)
case MkLines:
- text := sprintf(".include %q", arg.lines.FileName)
+ text := sprintf(".include %q", relpath(path.Dir(filename), arg.lines.FileName))
addLine(text)
lines = append(lines, arg.lines.Lines...)
default:
@@ -570,9 +575,7 @@ func (t *Tester) SetUpHierarchy() (
}
mklines := NewMkLines(NewLines(filename, lines))
- // FIXME: This filename must be relative to the including file.
- G.Assertf(files[filename] == nil, "MkLines with name %q already exist.", filename)
- // FIXME: This filename must be relative to the base directory.
+ G.Assertf(files[filename] == nil, "MkLines with name %q already exists.", filename)
files[filename] = mklines
return mklines
}
@@ -585,6 +588,37 @@ func (t *Tester) SetUpHierarchy() (
return
}
+// Demonstrates that Tester.SetUpHierarchy uses relative paths for the
+// .include directives.
+func (s *Suite) Test_Tester_SetUpHierarchy(c *check.C) {
+ t := s.Init(c)
+
+ include, get := t.SetUpHierarchy()
+ include("including.mk",
+ include("other.mk",
+ "VAR= other"),
+ include("subdir/module.mk",
+ "VAR= module",
+ include("subdir/version.mk",
+ "VAR= version"),
+ include("subdir/env.mk",
+ "VAR= env")))
+
+ mklines := get("including.mk")
+
+ mklines.ForEach(func(mkline MkLine) { mkline.Notef("Text is: %s", mkline.Text) })
+
+ t.CheckOutputLines(
+ "NOTE: including.mk:1: Text is: .include \"other.mk\"",
+ "NOTE: other.mk:1: Text is: VAR= other",
+ "NOTE: including.mk:2: Text is: .include \"subdir/module.mk\"",
+ "NOTE: subdir/module.mk:1: Text is: VAR= module",
+ "NOTE: subdir/module.mk:2: Text is: .include \"version.mk\"",
+ "NOTE: subdir/version.mk:1: Text is: VAR= version",
+ "NOTE: subdir/module.mk:3: Text is: .include \"env.mk\"",
+ "NOTE: subdir/env.mk:1: Text is: VAR= env")
+}
+
// Check delegates a check to the check.Check function.
// Thereby, there is no need to distinguish between c.Check and t.Check
// in the test code.
@@ -691,8 +725,8 @@ func (t *Tester) NewMkLine(filename stri
return NewMkLine(t.NewLine(filename, lineno, text))
}
-func (t *Tester) NewShellLineChecker(filename string, lineno int, text string) *ShellLineChecker {
- return NewShellLineChecker(t.NewMkLine(filename, lineno, text))
+func (t *Tester) NewShellLineChecker(mklines MkLines, filename string, lineno int, text string) *ShellLineChecker {
+ return NewShellLineChecker(mklines, t.NewMkLine(filename, lineno, text))
}
// NewLines returns a list of simple lines that belong together.
Index: pkgsrc/pkgtools/pkglint/files/shell.go
diff -u pkgsrc/pkgtools/pkglint/files/shell.go:1.36 pkgsrc/pkgtools/pkglint/files/shell.go:1.37
--- pkgsrc/pkgtools/pkglint/files/shell.go:1.36 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/shell.go Wed Apr 3 21:49:51 2019
@@ -16,11 +16,12 @@ import (
// Or it is a variable assignment line from a Makefile with a left-hand
// side variable that is of some shell-like type; see Vartype.IsShell.
type ShellLineChecker struct {
- mkline MkLine
+ MkLines MkLines
+ mkline MkLine
}
-func NewShellLineChecker(mkline MkLine) *ShellLineChecker {
- return &ShellLineChecker{mkline}
+func NewShellLineChecker(mklines MkLines, mkline MkLine) *ShellLineChecker {
+ return &ShellLineChecker{mklines, mkline}
}
var shellCommandsType = &Vartype{lkNone, BtShellCommands, []ACLEntry{{"*", aclpAllRuntime}}, false}
@@ -41,7 +42,7 @@ func (ck *ShellLineChecker) CheckWord(to
// to the MkLineChecker. Examples for these are ${VAR:Mpattern} or $@.
p := NewMkParser(nil, token, false)
if varuse := p.VarUse(); varuse != nil && p.EOF() {
- MkLineChecker{ck.mkline}.CheckVaruse(varuse, shellWordVuc)
+ MkLineChecker{ck.MkLines, ck.mkline}.CheckVaruse(varuse, shellWordVuc)
return
}
@@ -184,7 +185,7 @@ func (ck *ShellLineChecker) checkVaruseT
}
vuc := VarUseContext{shellCommandsType, vucTimeUnknown, quoting.ToVarUseContext(), true}
- MkLineChecker{ck.mkline}.CheckVaruse(varuse, &vuc)
+ MkLineChecker{ck.MkLines, ck.mkline}.CheckVaruse(varuse, &vuc)
return true
}
@@ -375,7 +376,7 @@ func (ck *ShellLineChecker) checkHiddenA
case !contains(hiddenAndSuppress, "@"):
// Nothing is hidden at all.
- case hasPrefix(G.Mk.target, "show-") || hasSuffix(G.Mk.target, "-message"):
+ case hasPrefix(ck.MkLines.target, "show-") || hasSuffix(ck.MkLines.target, "-message"):
// In these targets, all commands may be hidden.
case hasPrefix(rest, "#"):
@@ -470,7 +471,7 @@ func (scc *SimpleCommandChecker) checkCo
case scc.handleComment():
break
default:
- if G.Opts.WarnExtra && !(G.Mk != nil && G.Mk.indentation.DependsOn("OPSYS")) {
+ if G.Opts.WarnExtra && !(scc.MkLines != nil && scc.MkLines.indentation.DependsOn("OPSYS")) {
scc.mkline.Warnf("Unknown shell command %q.", shellword)
G.Explain(
"To make the package portable to all platforms that pkgsrc supports,",
@@ -490,7 +491,7 @@ func (scc *SimpleCommandChecker) handleT
command := scc.strcmd.Name
- tool, usable := G.Tool(command, scc.time)
+ tool, usable := G.Tool(scc.MkLines, command, scc.time)
if tool != nil && !usable {
scc.mkline.Warnf("The %q tool is used but not added to USE_TOOLS.", command)
@@ -530,14 +531,14 @@ func (scc *SimpleCommandChecker) handleC
if varuse := parser.VarUse(); varuse != nil && parser.EOF() {
varname := varuse.varname
- if vartype := G.Pkgsrc.VariableType(varname); vartype != nil && vartype.basicType.name == "ShellCommand" {
+ if vartype := G.Pkgsrc.VariableType(scc.MkLines, varname); vartype != nil && vartype.basicType.name == "ShellCommand" {
scc.checkInstallCommand(shellword)
return true
}
// When the package author has explicitly defined a command
// variable, assume it to be valid.
- if G.Mk != nil && G.Mk.vars.DefinedSimilar(varname) {
+ if scc.MkLines != nil && scc.MkLines.vars.DefinedSimilar(varname) {
return true
}
if G.Pkg != nil && G.Pkg.vars.DefinedSimilar(varname) {
@@ -875,7 +876,7 @@ func (spc *ShellProgramChecker) canFail(
case "set":
}
- tool, _ := G.Tool(cmdName, RunTime)
+ tool, _ := G.Tool(spc.MkLines, cmdName, RunTime)
if tool == nil {
return true
}
@@ -939,7 +940,7 @@ func (ck *ShellLineChecker) checkInstall
defer trace.Call0()()
}
- if G.Mk == nil || !matches(G.Mk.target, `^(?:pre|do|post)-install$`) {
+ if ck.MkLines == nil || !matches(ck.MkLines.target, `^(?:pre|do|post)-install$`) {
return
}
@@ -1025,34 +1026,3 @@ func splitIntoShellTokens(line Line, tex
return
}
-
-// Example: "word1 word2;;;" => "word1", "word2;;;"
-// Compare devel/bmake/files/str.c, function brk_string.
-//
-// TODO: Move to mkline.go or mkparser.go.
-//
-// TODO: Document what this function should be used for.
-//
-// TODO: Compare with brk_string from devel/bmake, especially for backticks.
-func splitIntoMkWords(line Line, text string) (words []string, rest string) {
- if trace.Tracing {
- defer trace.Call(line, text)()
- }
-
- p := NewShTokenizer(line, text, false)
- atoms := p.ShAtoms()
- word := ""
- for _, atom := range atoms {
- if atom.Type == shtSpace && atom.Quoting == shqPlain {
- words = append(words, word)
- word = ""
- } else {
- word += atom.MkText
- }
- }
- if word != "" && atoms[len(atoms)-1].Quoting == shqPlain {
- words = append(words, word)
- word = ""
- }
- return words, word + p.parser.Rest()
-}
Index: pkgsrc/pkgtools/pkglint/files/licenses.go
diff -u pkgsrc/pkgtools/pkglint/files/licenses.go:1.21 pkgsrc/pkgtools/pkglint/files/licenses.go:1.22
--- pkgsrc/pkgtools/pkglint/files/licenses.go:1.21 Thu Feb 21 22:49:03 2019
+++ pkgsrc/pkgtools/pkglint/files/licenses.go Wed Apr 3 21:49:51 2019
@@ -3,11 +3,12 @@ package pkglint
import "netbsd.org/pkglint/licenses"
type LicenseChecker struct {
- MkLine MkLine
+ MkLines MkLines
+ MkLine MkLine
}
func (lc *LicenseChecker) Check(value string, op MkOperator) {
- expanded := resolveVariableRefs(value) // For ${PERL5_LICENSE}
+ expanded := resolveVariableRefs(lc.MkLines, value) // For ${PERL5_LICENSE}
cond := licenses.Parse(ifelseStr(op == opAssignAppend, "append-placeholder ", "") + expanded)
if cond == nil {
Index: pkgsrc/pkgtools/pkglint/files/licenses_test.go
diff -u pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.21 pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.22
--- pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.21 Sat Jan 26 16:31:33 2019
+++ pkgsrc/pkgtools/pkglint/files/licenses_test.go Wed Apr 3 21:49:51 2019
@@ -11,7 +11,7 @@ func (s *Suite) Test_LicenseChecker_Chec
"The licenses for most software are designed to take away ...")
mkline := t.NewMkLine("Makefile", 7, "LICENSE=dummy")
- licenseChecker := LicenseChecker{mkline}
+ licenseChecker := LicenseChecker{nil, mkline}
licenseChecker.Check("gpl-v2", opAssign)
t.CheckOutputLines(
Index: pkgsrc/pkgtools/pkglint/files/pkgsrc.go
diff -u pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.21 pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.22
--- pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.21 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/pkgsrc.go Wed Apr 3 21:49:51 2019
@@ -45,8 +45,8 @@ type Pkgsrc struct {
vartypes VarTypeRegistry
}
-func NewPkgsrc(dir string) *Pkgsrc {
- src := Pkgsrc{
+func NewPkgsrc(dir string) Pkgsrc {
+ return Pkgsrc{
dir,
make(map[string]bool),
NewTools(),
@@ -60,8 +60,6 @@ func NewPkgsrc(dir string) *Pkgsrc {
NewScope(),
make(map[string]string),
NewVarTypeRegistry()}
-
- return &src
}
func (src *Pkgsrc) loadDefaultBuildDefs() {
@@ -368,8 +366,6 @@ func (src *Pkgsrc) loadUntypedVars() {
handleMkFile := func(path string) {
mklines := LoadMk(path, 0)
if mklines != nil && len(mklines.mklines) > 0 {
- G.Assertf(G.Mk == nil, "asdf")
- G.Mk = mklines // FIXME: This is because defineVar uses G.Mk instead of the method receiver.
mklines.collectDefinedVariables()
mklines.collectUsedVariables()
for varname, mkline := range mklines.vars.firstDef {
@@ -378,7 +374,6 @@ func (src *Pkgsrc) loadUntypedVars() {
for varname, mkline := range mklines.vars.used {
define(varnameCanon(varname), mkline)
}
- G.Mk = nil
}
}
@@ -893,7 +888,7 @@ func (src *Pkgsrc) loadPkgOptions() {
// VariableType returns the type of the variable
// (possibly guessed based on the variable name),
// or nil if the type cannot even be guessed.
-func (src *Pkgsrc) VariableType(varname string) (vartype *Vartype) {
+func (src *Pkgsrc) VariableType(mklines MkLines, varname string) (vartype *Vartype) {
if trace.Tracing {
defer trace.Call(varname, trace.Result(&vartype))()
}
@@ -906,19 +901,19 @@ func (src *Pkgsrc) VariableType(varname
return vartype
}
- if tool := G.ToolByVarname(varname); tool != nil {
+ if tool := G.ToolByVarname(mklines, varname); tool != nil {
if trace.Tracing {
trace.Stepf("Use of tool %+v", tool)
}
perms := aclpUse
- if tool.Validity == AfterPrefsMk && G.Mk.Tools.SeenPrefs {
+ if tool.Validity == AfterPrefsMk && mklines.Tools.SeenPrefs {
perms |= aclpUseLoadtime
}
return &Vartype{lkNone, BtShellCommand, []ACLEntry{{"*", perms}}, false}
}
if m, toolVarname := match1(varname, `^TOOLS_(.*)`); m {
- if tool := G.ToolByVarname(toolVarname); tool != nil {
+ if tool := G.ToolByVarname(mklines, toolVarname); tool != nil {
return &Vartype{lkNone, BtPathname, []ACLEntry{{"*", aclpUse}}, false}
}
}
Index: pkgsrc/pkgtools/pkglint/files/mkline.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline.go:1.49 pkgsrc/pkgtools/pkglint/files/mkline.go:1.50
--- pkgsrc/pkgtools/pkglint/files/mkline.go:1.49 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mkline.go Wed Apr 3 21:49:51 2019
@@ -423,47 +423,55 @@ func (mkline *MkLineImpl) ValueSplit(val
var notSpace = textproc.Space.Inverse()
-// ValueFields splits the given value, taking care of variable references.
-// Example:
+// ValueFields splits the given value in the same way as the :M variable
+// modifier, taking care of variable references. Example:
//
-// ValueFields("${VAR:Udefault value} ${VAR2}two words")
+// ValueFields("${VAR:Udefault value} ${VAR2}two words;;; 'word three'")
// => "${VAR:Udefault value}"
// "${VAR2}two"
-// "words"
+// "words;;;"
+// "'word three'"
//
// Note that even though the first word contains a space, it is not split
-// at that point since the space is inside a variable use.
+// at that point since the space is inside a variable use. Shell tokens
+// such as semicolons are also treated as normal characters. Only double
+// and single quotes are interpreted.
+//
+// Compare devel/bmake/files/str.c, function brk_string.
+//
+// TODO: Compare with brk_string from devel/bmake, especially for backticks.
func (mkline *MkLineImpl) ValueFields(value string) []string {
- tokens := mkline.Tokenize(value, false)
- var split []string
- cont := false
-
- out := func(s string) {
- if cont {
- split[len(split)-1] += s
- } else {
- split = append(split, s)
- }
+ if trace.Tracing {
+ defer trace.Call(mkline, value)()
+ }
+
+ p := NewShTokenizer(mkline.Line, value, false)
+ atoms := p.ShAtoms()
+
+ if len(atoms) > 0 && atoms[0].Type == shtSpace {
+ atoms = atoms[1:]
}
- for _, token := range tokens {
- if token.Varuse != nil {
- out(token.Text)
- cont = true
+ word := ""
+ var words []string
+ for _, atom := range atoms {
+ if atom.Type == shtSpace && atom.Quoting == shqPlain {
+ words = append(words, word)
+ word = ""
} else {
- lexer := textproc.NewLexer(token.Text)
- for !lexer.EOF() {
- for lexer.NextBytesSet(textproc.Space) != "" {
- cont = false
- }
- if word := lexer.NextBytesSet(notSpace); word != "" {
- out(word)
- cont = true
- }
- }
+ word += atom.MkText
}
}
- return split
+ if word != "" && atoms[len(atoms)-1].Quoting == shqPlain {
+ words = append(words, word)
+ word = ""
+ }
+
+ // TODO: Handle parse errors
+ rest := word + p.parser.Rest()
+ _ = rest
+
+ return words
}
func (mkline *MkLineImpl) ValueTokens() ([]*MkToken, string) {
@@ -748,6 +756,12 @@ func splitMkLine(text string) (main stri
mainWithSpaces := main
main = rtrimHspace(main)
spaceBeforeComment = mainWithSpaces[len(main):]
+ } else {
+ restWithoutSpace := strings.TrimRightFunc(rest, func(r rune) bool { return isHspace(byte(r)) })
+ if len(restWithoutSpace) < len(rest) {
+ spaceBeforeComment = rest[len(restWithoutSpace):]
+ rest = restWithoutSpace
+ }
}
return
@@ -797,9 +811,9 @@ func matchMkDirective(text string) (m bo
// This decision depends on many factors, such as whether the type of the context is
// a list of things, whether the variable is a list, whether it can contain only
// safe characters, and so on.
-func (mkline *MkLineImpl) VariableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting YesNoUnknown) {
+func (mkline *MkLineImpl) VariableNeedsQuoting(mklines MkLines, varuse *MkVarUse, vartype *Vartype, vuc *VarUseContext) (needsQuoting YesNoUnknown) {
if trace.Tracing {
- defer trace.Call(varname, vartype, vuc, trace.Result(&needsQuoting))()
+ defer trace.Call(varuse, vartype, vuc, trace.Result(&needsQuoting))()
}
// TODO: Systematically test this function, each and every case, from top to bottom.
@@ -845,7 +859,7 @@ func (mkline *MkLineImpl) VariableNeedsQ
// Pkglint assumes that the tool definitions don't include very
// special characters, so they can safely be used inside any quotes.
- if tool := G.ToolByVarname(varname); tool != nil {
+ if tool := G.ToolByVarname(mklines, varuse.varname); tool != nil {
switch vuc.quoting {
case VucQuotPlain:
if !vuc.IsWordPart {
@@ -879,6 +893,14 @@ func (mkline *MkLineImpl) VariableNeedsQ
if vucVartype.basicType == BtHomepage && vartype.basicType == BtFetchURL {
return no // Just for HOMEPAGE=${MASTER_SITE_*:=subdir/}.
}
+
+ // .for dir in ${PATH:C,:, ,g}
+ for _, modifier := range varuse.modifiers {
+ if modifier.ChangesWords() {
+ return unknown
+ }
+ }
+
return yes
}
@@ -889,42 +911,35 @@ func (mkline *MkLineImpl) VariableNeedsQ
}
if trace.Tracing {
- trace.Step1("Don't know whether :Q is needed for %q", varname)
+ trace.Step1("Don't know whether :Q is needed for %q", varuse.varname)
}
return unknown
}
-func (mkline *MkLineImpl) DetermineUsedVariables() []string {
- // TODO: It would be good to have these variables as MkVarUse objects
- // including the context in which they are used.
-
- var varnames []string
+// ForEachUsed calls the action for each variable that is used in the line.
+func (mkline *MkLineImpl) ForEachUsed(action func(varUse *MkVarUse, time vucTime)) {
- add := func(varname string) {
- varnames = append(varnames, varname)
- }
+ var searchIn func(text string, time vucTime) // mutually recursive with searchInVarUse
- var searchIn func(text string) // mutually recursive with searchInVarUse
-
- searchInVarUse := func(varuse *MkVarUse) {
+ searchInVarUse := func(varuse *MkVarUse, time vucTime) {
varname := varuse.varname
if !varuse.IsExpression() {
- add(varname)
+ action(varuse, time)
}
- searchIn(varname)
+ searchIn(varname, time)
for _, mod := range varuse.modifiers {
- searchIn(mod.Text)
+ searchIn(mod.Text, time)
}
}
- searchIn = func(text string) {
+ searchIn = func(text string, time vucTime) {
if !contains(text, "$") {
return
}
for _, token := range NewMkParser(nil, text, false).MkTokens() {
if token.Varuse != nil {
- searchInVarUse(token.Varuse)
+ searchInVarUse(token.Varuse, time)
}
}
}
@@ -932,27 +947,28 @@ func (mkline *MkLineImpl) DetermineUsedV
switch {
case mkline.IsVarassign():
- searchIn(mkline.Varname())
- searchIn(mkline.Value())
+ searchIn(mkline.Varname(), vucTimeParse)
+ searchIn(mkline.Value(), mkline.Op().Time())
case mkline.IsDirective() && mkline.Directive() == "for":
- searchIn(mkline.Args())
+ searchIn(mkline.Args(), vucTimeParse)
case mkline.IsDirective() && mkline.Cond() != nil:
- mkline.Cond().Walk(&MkCondCallback{VarUse: searchInVarUse})
+ mkline.Cond().Walk(&MkCondCallback{
+ VarUse: func(varuse *MkVarUse) {
+ searchInVarUse(varuse, vucTimeParse)
+ }})
case mkline.IsShellCommand():
- searchIn(mkline.ShellCommand())
+ searchIn(mkline.ShellCommand(), vucTimeRun)
case mkline.IsDependency():
- searchIn(mkline.Targets())
- searchIn(mkline.Sources())
+ searchIn(mkline.Targets(), vucTimeParse)
+ searchIn(mkline.Sources(), vucTimeParse)
case mkline.IsInclude():
- searchIn(mkline.IncludedFile())
+ searchIn(mkline.IncludedFile(), vucTimeParse)
}
-
- return varnames
}
func (mkline *MkLineImpl) UnquoteShell(str string) string {
@@ -1028,6 +1044,15 @@ func (op MkOperator) String() string {
return [...]string{"=", "!=", ":=", "+=", "?=", "use", "use-loadtime", "use-match"}[op]
}
+// Time returns the time at which the right-hand side of the assignment is
+// evaluated.
+func (op MkOperator) Time() vucTime {
+ if op == opAssignShell || op == opAssignEval {
+ return vucTimeParse
+ }
+ return vucTimeRun
+}
+
// VarUseContext defines the context in which a variable is defined
// or used. Whether that is allowed depends on:
//
Index: pkgsrc/pkgtools/pkglint/files/pkglint.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint.go:1.49 pkgsrc/pkgtools/pkglint/files/pkglint.go:1.50
--- pkgsrc/pkgtools/pkglint/files/pkglint.go:1.49 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/pkglint.go Wed Apr 3 21:49:51 2019
@@ -22,9 +22,8 @@ const confVersion = "@VERSION@"
// Pkglint is a container for all global variables of this Go package.
type Pkglint struct {
Opts CmdOpts // Command line options.
- Pkgsrc *Pkgsrc // Global data, mostly extracted from mk/*, never nil.
+ Pkgsrc Pkgsrc // Global data, mostly extracted from mk/*.
Pkg *Package // The package that is currently checked, or nil.
- Mk MkLines // The Makefile (or fragment) that is currently checked, or nil.
Todo []string // The files or directories that still need to be checked.
Wip bool // Is the currently checked file or package from pkgsrc-wip?
@@ -423,7 +422,7 @@ func findPkgsrcTopdir(dirname string) st
return ""
}
-func resolveVariableRefs(text string) (resolved string) {
+func resolveVariableRefs(mklines MkLines, text string) (resolved string) {
// TODO: How does this fit into the Scope type, which is newer than this function?
if !contains(text, "${") {
@@ -441,8 +440,8 @@ func resolveVariableRefs(text string) (r
return value
}
}
- if G.Mk != nil {
- if value, ok := G.Mk.vars.LastValueFound(varname); ok {
+ if mklines != nil {
+ if value, ok := mklines.vars.LastValueFound(varname); ok {
return value
}
}
@@ -487,7 +486,7 @@ func CheckLinesDescr(lines Lines) {
if contains(line.Text, "${") {
for _, token := range NewMkParser(nil, line.Text, false).MkTokens() {
- if token.Varuse != nil && G.Pkgsrc.VariableType(token.Varuse.varname) != nil {
+ if token.Varuse != nil && G.Pkgsrc.VariableType(nil, token.Varuse.varname) != nil {
line.Notef("Variables are not expanded in the DESCR file.")
}
}
@@ -729,14 +728,14 @@ func CheckLinesTrailingEmptyLines(lines
// The command can be "sed" or "gsed" or "${SED}".
// If a tool is returned, usable tells whether that tool has been added
// to USE_TOOLS in the current scope (file or package).
-func (pkglint *Pkglint) Tool(command string, time ToolTime) (tool *Tool, usable bool) {
+func (pkglint *Pkglint) Tool(mklines MkLines, command string, time ToolTime) (tool *Tool, usable bool) {
varname := ""
p := NewMkParser(nil, command, false)
if varUse := p.VarUse(); varUse != nil && p.EOF() {
varname = varUse.varname
}
- tools := pkglint.tools()
+ tools := pkglint.tools(mklines)
if t := tools.ByName(command); t != nil {
if tools.Usable(t, time) {
@@ -762,13 +761,13 @@ func (pkglint *Pkglint) Tool(command str
// It is not guaranteed to be usable (added to USE_TOOLS), only defined;
// that must be checked by the calling code,
// see Tool.UsableAtLoadTime and Tool.UsableAtRunTime.
-func (pkglint *Pkglint) ToolByVarname(varname string) *Tool {
- return pkglint.tools().ByVarname(varname)
+func (pkglint *Pkglint) ToolByVarname(mklines MkLines, varname string) *Tool {
+ return pkglint.tools(mklines).ByVarname(varname)
}
-func (pkglint *Pkglint) tools() *Tools {
- if pkglint.Mk != nil {
- return pkglint.Mk.Tools
+func (pkglint *Pkglint) tools(mklines MkLines) *Tools {
+ if mklines != nil {
+ return mklines.Tools
} else {
return pkglint.Pkgsrc.Tools
}
Index: pkgsrc/pkgtools/pkglint/files/mkline_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.54 pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.55
--- pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.54 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mkline_test.go Wed Apr 3 21:49:51 2019
@@ -160,24 +160,30 @@ func (s *Suite) Test_NewMkLine__autofix_
"VARNAME +=\t${VARNAME}",
"VARNAME+ =\t${VARNAME+}",
"VARNAME+ +=\t${VARNAME+}",
+ "VARNAME+ ?=\t${VARNAME}",
"pkgbase := pkglint")
CheckFileMk(filename)
t.CheckOutputLines(
- "NOTE: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".")
+ "NOTE: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".",
+
+ // The assignment operators other than = and += cannot lead to ambiguities.
+ "NOTE: ~/Makefile:5: Unnecessary space after variable name \"VARNAME+\".")
t.SetUpCommandLine("-Wspace", "--autofix")
CheckFileMk(filename)
t.CheckOutputLines(
- "AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".")
+ "AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".",
+ "AUTOFIX: ~/Makefile:5: Replacing \"VARNAME+ ?=\" with \"VARNAME+?=\".")
t.CheckFileLines("Makefile",
MkRcsID+"",
"VARNAME+=\t${VARNAME}",
"VARNAME+ =\t${VARNAME+}",
"VARNAME+ +=\t${VARNAME+}",
+ "VARNAME+?=\t${VARNAME}",
"pkgbase := pkglint")
}
@@ -269,7 +275,7 @@ func (s *Suite) Test_VarUseContext_Strin
t := s.Init(c)
t.SetUpVartypes()
- vartype := G.Pkgsrc.VariableType("PKGNAME")
+ vartype := G.Pkgsrc.VariableType(nil, "PKGNAME")
vuc := VarUseContext{vartype, vucTimeUnknown, VucQuotBackt, false}
c.Check(vuc.String(), equals, "(Pkgname time:unknown quoting:backt wordpart:false)")
@@ -361,8 +367,8 @@ func (s *Suite) Test_MkLine_VariableNeed
mkline := t.NewMkLine("filename.mk", 1, "PKGNAME:= ${UNKNOWN}")
t.SetUpVartypes()
- vuc := VarUseContext{G.Pkgsrc.VariableType("PKGNAME"), vucTimeParse, VucQuotUnknown, false}
- nq := mkline.VariableNeedsQuoting("UNKNOWN", nil, &vuc)
+ vuc := VarUseContext{G.Pkgsrc.VariableType(nil, "PKGNAME"), vucTimeParse, VucQuotUnknown, false}
+ nq := mkline.VariableNeedsQuoting(nil, &MkVarUse{"UNKNOWN", nil}, nil, &vuc)
c.Check(nq, equals, unknown)
}
@@ -375,11 +381,11 @@ func (s *Suite) Test_MkLine_VariableNeed
mkline := t.NewMkLine("Makefile", 95, "MASTER_SITES=\t${HOMEPAGE}")
vuc := VarUseContext{G.Pkgsrc.vartypes.Canon("MASTER_SITES"), vucTimeRun, VucQuotPlain, false}
- nq := mkline.VariableNeedsQuoting("HOMEPAGE", G.Pkgsrc.vartypes.Canon("HOMEPAGE"), &vuc)
+ nq := mkline.VariableNeedsQuoting(nil, &MkVarUse{"HOMEPAGE", nil}, G.Pkgsrc.vartypes.Canon("HOMEPAGE"), &vuc)
c.Check(nq, equals, no)
- MkLineChecker{mkline}.checkVarassign()
+ MkLineChecker{nil, mkline}.checkVarassign()
t.CheckOutputEmpty() // Up to version 5.3.6, pkglint warned about a missing :Q here, which was wrong.
}
@@ -391,7 +397,7 @@ func (s *Suite) Test_MkLine_VariableNeed
t.SetUpMasterSite("MASTER_SITE_SOURCEFORGE", "http://downloads.sourceforge.net/sourceforge/")
mkline := t.NewMkLine("Makefile", 96, "MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=squirrel-sql/}")
- MkLineChecker{mkline}.checkVarassign()
+ MkLineChecker{nil, mkline}.checkVarassign()
// Assigning lists to lists is ok.
t.CheckOutputEmpty()
@@ -404,7 +410,7 @@ func (s *Suite) Test_MkLine_VariableNeed
mkline := t.NewMkLine("builtin.mk", 3,
"USE_BUILTIN.Xfixes!=\t${PKG_ADMIN} pmatch 'pkg-[0-9]*' ${BUILTIN_PKG.Xfixes:Q}")
- MkLineChecker{mkline}.checkVarassign()
+ MkLineChecker{nil, mkline}.checkVarassign()
t.CheckOutputLines(
"WARN: builtin.mk:3: PKG_ADMIN should not be used at load time in any file.",
@@ -418,7 +424,7 @@ func (s *Suite) Test_MkLine_VariableNeed
mkline := t.NewMkLine("Makefile", 3,
"SUBST_SED.hpath=\t-e 's|^\\(INSTALL[\t:]*=\\).*|\\1${INSTALL}|'")
- MkLineChecker{mkline}.checkVarassign()
+ MkLineChecker{nil, mkline}.checkVarassign()
t.CheckOutputLines(
"WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} " +
@@ -432,12 +438,12 @@ func (s *Suite) Test_MkLine_VariableNeed
t.SetUpTool("find", "FIND", AtRunTime)
t.SetUpTool("sort", "SORT", AtRunTime)
G.Pkg = NewPackage(t.File("category/pkgbase"))
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
MkRcsID,
"GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};")
- G.Mk.collectDefinedVariables()
- MkLineChecker{G.Mk.mklines[1]}.Check()
+ mklines.collectDefinedVariables()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
t.CheckOutputLines(
"WARN: Makefile:2: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
@@ -447,11 +453,11 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
MkRcsID,
"EGDIR=\t${EGDIR}/${MACHINE_GNU_PLATFORM}")
- MkLineChecker{G.Mk.mklines[1]}.Check()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
t.CheckOutputEmpty()
}
@@ -485,11 +491,11 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
MkRcsID,
"MASTER_SITES=${HOMEPAGE}archive/")
- MkLineChecker{G.Mk.mklines[1]}.Check()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
t.CheckOutputEmpty() // Don't suggest to use ${HOMEPAGE:Q}.
}
@@ -523,13 +529,13 @@ func (s *Suite) Test_MkLine_VariableNeed
t.SetUpVartypes()
t.SetUpTool("awk", "AWK", AtRunTime)
t.SetUpTool("echo", "ECHO", AtRunTime)
- G.Mk = t.NewMkLines("xpi.mk",
+ mklines := t.NewMkLines("xpi.mk",
MkRcsID,
"\t id=$$(${AWK} '{print}' < ${WRKSRC}/idfile) && echo \"$$id\"",
"\t id=`${AWK} '{print}' < ${WRKSRC}/idfile` && echo \"$$id\"")
- MkLineChecker{G.Mk.mklines[1]}.Check()
- MkLineChecker{G.Mk.mklines[2]}.Check()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
+ MkLineChecker{mklines, mklines.mklines[2]}.Check()
// Don't suggest to use ${AWK:Q}.
t.CheckOutputLines(
@@ -543,13 +549,13 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("x11/mlterm/Makefile",
+ mklines := t.NewMkLines("x11/mlterm/Makefile",
MkRcsID,
"SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& ${LDFLAGS:M*:Q}|g'",
"SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& '${LDFLAGS:M*:Q}'|g'")
- MkLineChecker{G.Mk.mklines[1]}.Check()
- MkLineChecker{G.Mk.mklines[2]}.Check()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
+ MkLineChecker{mklines, mklines.mklines[2]}.Check()
t.CheckOutputLines(
"WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.")
@@ -565,11 +571,11 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
MkRcsID,
"PKG_SUGGESTED_OPTIONS+=\t${PKG_DEFAULT_OPTIONS:Mcdecimal} ${PKG_OPTIONS.py-trytond:Mcdecimal}")
- MkLineChecker{G.Mk.mklines[1]}.Check()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
// No warning about a missing :Q modifier.
t.CheckOutputEmpty()
@@ -581,11 +587,11 @@ func (s *Suite) Test_MkLine_VariableNeed
t.SetUpTool("echo", "ECHO", AtRunTime)
t.SetUpTool("sh", "SH", AtRunTime)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("x11/labltk/Makefile",
+ mklines := t.NewMkLines("x11/labltk/Makefile",
MkRcsID,
"CONFIGURE_ARGS+=\t-tklibs \"`${SH} -c '${ECHO} $$TK_LD_FLAGS'`\"")
- MkLineChecker{G.Mk.mklines[1]}.Check()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
// Don't suggest ${ECHO:Q} here.
t.CheckOutputEmpty()
@@ -595,10 +601,10 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("x11/qt5-qtbase/Makefile.common",
+ mklines := t.NewMkLines("x11/qt5-qtbase/Makefile.common",
"BUILDLINK_TRANSFORM+=opt:-ldl:${BUILDLINK_LDADD.dl:M*}")
- MkLineChecker{G.Mk.mklines[0]}.Check()
+ MkLineChecker{mklines, mklines.mklines[0]}.Check()
// Note: The :M* modifier is not necessary, since this is not a GNU Configure package.
t.CheckOutputLines(
@@ -609,10 +615,10 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("benchmarks/iozone/Makefile",
+ mklines := t.NewMkLines("benchmarks/iozone/Makefile",
"SUBST_MESSAGE.crlf=\tStripping EOL CR in ${REPLACE_PERL}")
- MkLineChecker{G.Mk.mklines[0]}.Check()
+ MkLineChecker{mklines, mklines.mklines[0]}.Check()
// Don't suggest ${REPLACE_PERL:Q}.
t.CheckOutputEmpty()
@@ -622,12 +628,12 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("audio/jack-rack/Makefile",
+ mklines := t.NewMkLines("audio/jack-rack/Makefile",
MkRcsID,
"LADSPA_PLUGIN_PATH=\t${PREFIX}/lib/ladspa",
"CPPFLAGS+=\t\t-DLADSPA_PATH=\"\\\"${LADSPA_PLUGIN_PATH}\\\"\"")
- G.Mk.Check()
+ mklines.Check()
t.CheckOutputLines(
"WARN: audio/jack-rack/Makefile:3: The variable LADSPA_PLUGIN_PATH should be quoted as part of a shell word.")
@@ -637,11 +643,11 @@ func (s *Suite) Test_MkLine_VariableNeed
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("x11/eterm/Makefile",
+ mklines := t.NewMkLines("x11/eterm/Makefile",
MkRcsID,
"DISTFILES=\t${DEFAULT_DISTFILES} ${PIXMAP_FILES}")
- G.Mk.Check()
+ mklines.Check()
// Don't warn about missing :Q modifiers.
t.CheckOutputLines(
@@ -653,11 +659,11 @@ func (s *Suite) Test_MkLine_VariableNeed
t.SetUpMasterSite("MASTER_SITE_GNOME", "http://ftp.gnome.org/")
t.SetUpVartypes()
- G.Mk = t.NewMkLines("x11/gtk3/Makefile",
+ mklines := t.NewMkLines("x11/gtk3/Makefile",
MkRcsID,
"MASTER_SITES=\tftp://ftp.gtk.org/${PKGNAME}/ ${MASTER_SITE_GNOME:=subdir/}")
- MkLineChecker{G.Mk.mklines[1]}.checkVarassignRightVaruse()
+ MkLineChecker{mklines, mklines.mklines[1]}.checkVarassignRightVaruse()
t.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
}
@@ -672,7 +678,7 @@ func (s *Suite) Test_MkLine_VariableNeed
"",
"CONFIGURE_ENV+=\tSYS_TAR_COMMAND_PATH=${TOOLS_TAR:Q}")
- MkLineChecker{mklines.mklines[2]}.checkVarassignRightVaruse()
+ MkLineChecker{mklines, mklines.mklines[2]}.checkVarassignRightVaruse()
// The TOOLS_* variables only contain the path to the tool,
// without any additional arguments that might be necessary
@@ -693,8 +699,8 @@ func (s *Suite) Test_MkLine_VariableNeed
"COMPILE_CMD=\tcc `${CAT} ${WRKDIR}/compileflags`",
"COMMENT_CMD=\techo `echo ${COMMENT}`")
- MkLineChecker{mklines.mklines[2]}.checkVarassignRightVaruse()
- MkLineChecker{mklines.mklines[3]}.checkVarassignRightVaruse()
+ MkLineChecker{mklines, mklines.mklines[2]}.checkVarassignRightVaruse()
+ MkLineChecker{mklines, mklines.mklines[3]}.checkVarassignRightVaruse()
// Both CAT and WRKDIR are safe from quoting, therefore no warnings.
// But COMMENT may contain arbitrary characters and therefore must
@@ -807,12 +813,6 @@ func (s *Suite) Test_MkLine_VariableNeed
"\tIf these rules seem to be incorrect, please ask on the",
"\ttech-pkg%NetBSD.org@localhost mailing list.",
"",
- "WARN: ~/Makefile:4: Please use ${LINKER_RPATH_FLAG:S/-rpath/& /:Q} "+
- "instead of ${LINKER_RPATH_FLAG:S/-rpath/& /}.",
- "",
- "\tSee the pkgsrc guide, section \"Echoing a string exactly as-is\":",
- "\thttps://www.NetBSD.org/docs/pkgsrc/pkgsrc.html#echo-literal",
- "",
"WARN: ~/Makefile:4: LINKER_RPATH_FLAG should not be used at load time in any file.",
"",
"\tMany variables, especially lists of something, get their values",
@@ -893,7 +893,7 @@ func (s *Suite) Test_MkLine_VariableNeed
// Just for branch coverage.
trace.Tracing = false
- MkLineChecker{mklines.mklines[2]}.Check()
+ MkLineChecker{mklines, mklines.mklines[2]}.Check()
t.CheckOutputEmpty()
}
@@ -1021,8 +1021,8 @@ func (s *Suite) Test_MkLine_Fields__vara
test("word '${VAR}single ${VAR}' \"\t\"",
"word",
- "'${VAR}single", "${VAR}'", // FIXME: should be a single word.
- "\"", "\"") // FIXME: should be a single word.
+ "'${VAR}single ${VAR}'",
+ "\"\t\"")
}
func (s *Suite) Test_MkLine_Fields__for(c *check.C) {
@@ -1053,8 +1053,27 @@ func (s *Suite) Test_MkLine_Fields__for(
"i",
"in",
"word",
- "'${VAR}single", "${VAR}'", // FIXME: should be a single word.
- "\"", "\"") // FIXME: should be a single word.
+ "'${VAR}single ${VAR}'",
+ "\"\t\"")
+}
+
+func (s *Suite) Test_MkLine_Fields__semicolons(c *check.C) {
+ t := s.Init(c)
+
+ mkline := t.NewMkLine("filename.mk", 123, "VAR=\tword1 word2;;;")
+ words := mkline.Fields()
+
+ c.Check(words, deepEquals, []string{"word1", "word2;;;"})
+}
+
+func (s *Suite) Test_MkLine_Fields__varuse_with_embedded_space(c *check.C) {
+ t := s.Init(c)
+
+ mkline := t.NewMkLine("filename.mk", 123, "VAR=\t${VAR:S/ /_/g}")
+
+ words := mkline.Fields()
+
+ c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"})
}
func (s *Suite) Test_MkLine_ValueFields(c *check.C) {
@@ -1071,10 +1090,12 @@ func (s *Suite) Test_MkLine_ValueFields(
"two",
"${THREE:Uthree:Nsome \tspaces}")
- test("${VAR:Udefault value} ${VAR2}two words",
+ // The example from the ValueFields documentation.
+ test("${VAR:Udefault value} ${VAR2}two words;;; 'word three'",
"${VAR:Udefault value}",
"${VAR2}two",
- "words")
+ "words;;;",
+ "'word three'")
}
// Before 2018-11-26, this test panicked.
@@ -1093,6 +1114,31 @@ func (s *Suite) Test_MkLine_ValueFields_
"${WRKSRC}")
}
+func (s *Suite) Test_MkLine_ValueFields__compared_to_splitIntoShellTokens(c *check.C) {
+ t := s.Init(c)
+ url := "http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file="
+ mkline := t.NewMkLine("filename.mk", 123, "MASTER_SITES=\t"+url)
+
+ words, rest := splitIntoShellTokens(dummyLine, url) // Doesn't really make sense
+
+ c.Check(words, check.DeepEquals, []string{
+ "http://registry.gimp.org/file/fix-ca.c?action=download",
+ "&",
+ "id=9884",
+ "&",
+ "file="})
+ c.Check(rest, equals, "")
+
+ words = mkline.ValueFields(url)
+
+ c.Check(words, check.DeepEquals, []string{url})
+
+ words = mkline.ValueFields("a b \"c c c\" d;;d;; \"e\"''`` 'rest")
+
+ c.Check(words, check.DeepEquals, []string{"a", "b", "\"c c c\"", "d;;d;;", "\"e\"''``"})
+ // TODO: c.Check(rest, equals, "'rest")
+}
+
func (s *Suite) Test_MkLine_ValueTokens(c *check.C) {
t := s.Init(c)
@@ -1269,6 +1315,29 @@ func (s *Suite) Test_MatchVarassign(c *c
test("VAR=value #comment", false, "VAR", "", "=", "VAR=", "value", " ", "#comment")
test("NFILES=${FILES:[#]}", false, "NFILES", "", "=", "NFILES=", "${FILES:[#]}", "", "")
+ // To humans, the base variable name seems to be SITES_, being parameterized
+ // with distfile-1.0.tar.gz. For pkglint though, the base variable name is
+ // SITES_distfile-1.
+ test("SITES_distfile-1.0.tar.gz=https://example.org/",
+ false,
+ "SITES_distfile-1.0.tar.gz",
+ "",
+ "=",
+ "SITES_distfile-1.0.tar.gz=",
+ "https://example.org/",
+ "",
+ "")
+
+ test("SITES_${distfile}=https://example.org/",
+ false,
+ "SITES_${distfile}",
+ "",
+ "=",
+ "SITES_${distfile}=",
+ "https://example.org/",
+ "",
+ "")
+
testInvalid("\tVAR=value")
testInvalid("?=value")
testInvalid("<=value")
@@ -1474,7 +1543,7 @@ func (s *Suite) Test_Indentation_Varname
"(depending on OPSYS, OPSYS) and unconditionally in Makefile:20.")
}
-func (s *Suite) Test_MkLine_DetermineUsedVariables(c *check.C) {
+func (s *Suite) Test_MkLine_ForEachUsed(c *check.C) {
t := s.Init(c)
mklines := t.NewMkLines("Makefile",
@@ -1495,30 +1564,32 @@ func (s *Suite) Test_MkLine_DetermineUse
var varnames []string
for _, mkline := range mklines.mklines {
- varnames = append(varnames, mkline.DetermineUsedVariables()...)
+ mkline.ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ varnames = append(varnames, time.String()+" "+varUse.varname)
+ })
}
c.Check(varnames, deepEquals, []string{
- "VALUE",
- "OPSYS",
- "endianness",
+ "run VALUE",
+ "parse OPSYS",
+ "parse endianness",
// "Hello" is not a variable name, the :L modifier makes it an expression.
- "two",
- "TARGETS",
- "SOURCES",
- "OTHER_FILE",
-
- "VAR.${param}",
- "param",
- "VAR",
- "VAR2",
- "VAR",
- "pattern",
- "ROUND_PARENTHESES",
+ "parse two",
+ "parse TARGETS",
+ "parse SOURCES",
+ "parse OTHER_FILE",
+
+ "run VAR.${param}",
+ "run param",
+ "run VAR",
+ "run VAR2",
+ "run VAR",
+ "run pattern",
+ "run ROUND_PARENTHESES",
// Shell variables are ignored here.
- "<",
- "@",
- "x"})
+ "run <",
+ "run @",
+ "run x"})
}
func (s *Suite) Test_MkLine_UnquoteShell(c *check.C) {
@@ -1857,14 +1928,23 @@ func (s *Suite) Test_splitMkLine(c *chec
false,
"")
- // When a parse error occurs, the comment is not parsed and the main text
- // is not trimmed to the right, to keep as much original information as
- // possible.
+ // Even if there is a parse error in the main part,
+ // the comment is extracted.
+ test("text before ${UNCLOSED# comment",
+ "text before ",
+ tokens(text("text before ")),
+ "${UNCLOSED",
+ "",
+ true,
+ " comment")
+
+ // Even in case of parse errors, the space before the comment is parsed
+ // correctly.
test("text before ${UNCLOSED # comment",
"text before ",
tokens(text("text before ")),
- "${UNCLOSED ", // FIXME: put the space into spaceBeforeComment
- "", // FIXME: the space is missing here
+ "${UNCLOSED",
+ " ",
true,
" comment")
Index: pkgsrc/pkgtools/pkglint/files/mklinechecker.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.32 pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.33
--- pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.32 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker.go Wed Apr 3 21:49:51 2019
@@ -11,7 +11,8 @@ import (
// MkLineChecker provides checks for a single line from a Makefile fragment.
type MkLineChecker struct {
- MkLine MkLine
+ MkLines MkLines
+ MkLine MkLine
}
func (ck MkLineChecker) Check() {
@@ -60,7 +61,7 @@ func (ck MkLineChecker) checkShellComman
}
ck.checkText(shellCommand)
- NewShellLineChecker(mkline).CheckShellCommandLine(shellCommand)
+ NewShellLineChecker(ck.MkLines, mkline).CheckShellCommandLine(shellCommand)
}
func (ck MkLineChecker) checkInclude() {
@@ -70,7 +71,7 @@ func (ck MkLineChecker) checkInclude() {
mkline := ck.MkLine
if mkline.Indent() != "" {
- ck.checkDirectiveIndentation(G.Mk.indentation.Depth("include"))
+ ck.checkDirectiveIndentation(ck.MkLines.indentation.Depth("include"))
}
includedFile := mkline.IncludedFile()
@@ -223,14 +224,14 @@ func (ck MkLineChecker) checkDirectiveFo
// whether guessed was true or false.
forLoopType := Vartype{lkShell, btForLoop, []ACLEntry{{"*", aclpAllRead}}, false}
forLoopContext := VarUseContext{&forLoopType, vucTimeParse, VucQuotPlain, false}
- for _, itemsVar := range mkline.DetermineUsedVariables() {
- ck.CheckVaruse(&MkVarUse{itemsVar, nil}, &forLoopContext)
- }
+ mkline.ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ ck.CheckVaruse(varUse, &forLoopContext)
+ })
}
}
func (ck MkLineChecker) checkDirectiveIndentation(expectedDepth int) {
- if G.Mk == nil || !G.Opts.WarnSpace {
+ if ck.MkLines == nil || !G.Opts.WarnSpace {
return
}
mkline := ck.MkLine
@@ -298,7 +299,7 @@ func (ck MkLineChecker) checkVarassignLe
mkline := ck.MkLine
varname := mkline.Varname()
op := mkline.Op()
- vartype := G.Pkgsrc.VariableType(varname)
+ vartype := G.Pkgsrc.VariableType(ck.MkLines, varname)
if vartype == nil {
return
}
@@ -399,11 +400,19 @@ func (ck MkLineChecker) CheckVaruse(varu
}
varname := varuse.varname
- vartype := G.Pkgsrc.VariableType(varname)
- ck.checkVaruseUndefined(vartype, varname)
+ vartype := G.Pkgsrc.VariableType(ck.MkLines, varname)
+ ck.checkVaruseUndefined(vartype, varname)
ck.checkVaruseModifiers(varuse, vartype)
+ ck.checkVarUseVarname(varuse)
+ ck.checkVarusePermissions(varname, vartype, vuc)
+ ck.checkVarUseQuoting(varuse, vartype, vuc)
+ ck.checkVarUseBuildDefs(varname)
+ ck.checkVaruseDeprecated(varuse)
+ ck.checkTextVarUse(varname, vartype, vuc.time)
+}
+func (ck MkLineChecker) checkVarUseVarname(varuse *MkVarUse) {
if varuse.varname == "@" {
ck.MkLine.Warnf("Please use %q instead of %q.", "${.TARGET}", "$@")
G.Explain(
@@ -411,59 +420,60 @@ func (ck MkLineChecker) CheckVaruse(varu
"of the same name.")
}
- ck.checkVarusePermissions(varname, vartype, vuc)
-
- if varname == "LOCALBASE" && !G.Infrastructure {
+ if varuse.varname == "LOCALBASE" && !G.Infrastructure {
fix := ck.MkLine.Autofix()
fix.Warnf("Please use PREFIX instead of LOCALBASE.")
fix.ReplaceRegex(`\$\{LOCALBASE\b`, "${PREFIX", 1)
fix.Apply()
}
+}
- needsQuoting := mkline.VariableNeedsQuoting(varname, vartype, vuc)
-
- if G.Opts.WarnQuoting && vuc.quoting != VucQuotUnknown && needsQuoting != unknown {
- // FIXME: Why "Shellword" when there's no indication that this is actually a shell type?
- // It's for splitting the value into tokens, taking "double" and 'single' quotes into account.
- ck.CheckVaruseShellword(varname, vartype, vuc, varuse.Mod(), needsQuoting == yes)
+func (ck MkLineChecker) checkVarUseBuildDefs(varname string) {
+ if !(G.Pkgsrc.UserDefinedVars.Defined(varname) && !G.Pkgsrc.IsBuildDef(varname)) {
+ return
}
- if G.Pkgsrc.UserDefinedVars.Defined(varname) && !G.Pkgsrc.IsBuildDef(varname) {
- if !G.Mk.buildDefs[varname] && G.Mk.FirstTimeSlice("BUILD_DEFS", varname) {
- mkline.Warnf("The user-defined variable %s is used but not added to BUILD_DEFS.", varname)
- G.Explain(
- "When a pkgsrc package is built, many things can be configured by the",
- "pkgsrc user in the mk.conf file.",
- "All these configurations should be recorded in the binary package",
- "so the package can be reliably rebuilt.",
- "The BUILD_DEFS variable contains a list of all these",
- "user-settable variables, so please add your variable to it, too.")
- }
+ if !(!ck.MkLines.buildDefs[varname] && ck.MkLines.FirstTimeSlice("BUILD_DEFS", varname)) {
+ return
}
- ck.checkVaruseDeprecated(varuse)
-
- ck.checkTextVarUse(varname, vartype, vuc.time)
+ ck.MkLine.Warnf("The user-defined variable %s is used but not added to BUILD_DEFS.", varname)
+ ck.MkLine.Explain(
+ "When a pkgsrc package is built, many things can be configured by the",
+ "pkgsrc user in the mk.conf file.",
+ "All these configurations should be recorded in the binary package",
+ "so the package can be reliably rebuilt.",
+ "The BUILD_DEFS variable contains a list of all these",
+ "user-settable variables, so please add your variable to it, too.")
}
func (ck MkLineChecker) checkVaruseUndefined(vartype *Vartype, varname string) {
switch {
+
case !G.Opts.WarnExtra:
- break
+ return
+
case vartype != nil && !vartype.guessed:
// Well-known variables are probably defined by the infrastructure.
- case varIsDefinedSimilar(G.Pkg, G.Mk, varname):
- break
+ return
+
+ case ck.MkLines != nil && (ck.MkLines.vars.DefinedSimilar(varname) || ck.MkLines.forVars[varname]):
+ return
+
+ case G.Pkg != nil && G.Pkg.vars.DefinedSimilar(varname):
+ return
+
case containsVarRef(varname):
- break
+ return
+
case G.Pkgsrc.vartypes.DefinedCanon(varname):
- break
- case G.Mk == nil || !G.Mk.FirstTimeSlice("used but not defined: ", varname):
- break
+ return
- default:
- ck.MkLine.Warnf("%s is used but not defined.", varname)
+ case ck.MkLines == nil || !ck.MkLines.FirstTimeSlice("used but not defined: ", varname):
+ return
}
+
+ ck.MkLine.Warnf("%s is used but not defined.", varname)
}
func (ck MkLineChecker) checkVaruseModifiers(varuse *MkVarUse, vartype *Vartype) {
@@ -572,8 +582,8 @@ func (ck MkLineChecker) checkVarusePermi
// whether bsd.prefs.mk has been included. That file examines the
// tools that have been added to USE_TOOLS up to this point and
// makes their variables available for use at load time.
- if tool := G.ToolByVarname(varname); tool != nil {
- if !tool.UsableAtLoadTime(G.Mk.Tools.SeenPrefs) {
+ if tool := G.ToolByVarname(ck.MkLines, varname); tool != nil {
+ if !tool.UsableAtLoadTime(ck.MkLines.Tools.SeenPrefs) {
ck.warnVaruseToolLoadTime(varname, tool)
}
return
@@ -588,7 +598,7 @@ func (ck MkLineChecker) checkVarusePermi
return
}
- if G.Mk != nil && !G.Mk.FirstTimeSlice("checkVarusePermissions", varname) {
+ if ck.MkLines != nil && !ck.MkLines.FirstTimeSlice("checkVarusePermissions", varname) {
return
}
@@ -715,13 +725,21 @@ func (ck MkLineChecker) warnVaruseToolLo
"except in the package Makefile itself.")
}
-// CheckVaruseShellword checks whether a variable use of the form ${VAR}
+// checkVarUseWords checks whether a variable use of the form ${VAR}
// or ${VAR:modifiers} is allowed in a certain context.
-func (ck MkLineChecker) CheckVaruseShellword(varname string, vartype *Vartype, vuc *VarUseContext, mod string, needsQuoting bool) {
- if trace.Tracing {
- defer trace.Call(varname, vartype, vuc, mod, needsQuoting)()
+func (ck MkLineChecker) checkVarUseQuoting(varUse *MkVarUse, vartype *Vartype, vuc *VarUseContext) {
+ if !G.Opts.WarnQuoting || vuc.quoting == VucQuotUnknown {
+ return
}
+ needsQuoting := ck.MkLine.VariableNeedsQuoting(ck.MkLines, varUse, vartype, vuc)
+ if needsQuoting == unknown {
+ return
+ }
+
+ varname := varUse.varname
+ mod := varUse.Mod()
+
// In GNU configure scripts, a few variables need to be passed through
// the :M* operator before they reach the configure scripts. Otherwise
// the leading or trailing spaces will lead to strange caching errors
@@ -735,7 +753,7 @@ func (ck MkLineChecker) CheckVaruseShell
if mod == ":M*:Q" && !needMstar {
mkline.Notef("The :M* modifier is not needed here.")
- } else if needsQuoting {
+ } else if needsQuoting == yes {
modNoQ := strings.TrimSuffix(mod, ":Q")
modNoM := strings.TrimSuffix(modNoQ, ":M*")
correctMod := modNoM + ifelseStr(needMstar, ":M*:Q", ":Q")
@@ -774,6 +792,7 @@ func (ck MkLineChecker) CheckVaruseShell
fix.Explain(
seeGuide("Echoing a string exactly as-is", "echo-literal"))
fix.Replace("${"+varname+mod+"}", "${"+varname+correctMod+"}")
+ fix.Anyway()
fix.Apply()
} else {
mkline.Warnf("Please use ${%s%s} instead of ${%s%s} and make sure"+
@@ -807,7 +826,7 @@ func (ck MkLineChecker) CheckVaruseShell
}
}
- if hasSuffix(mod, ":Q") && !needsQuoting {
+ if hasSuffix(mod, ":Q") && needsQuoting != yes {
bad := "${" + varname + mod + "}"
good := "${" + varname + strings.TrimSuffix(mod, ":Q") + "}"
@@ -866,6 +885,7 @@ func (ck MkLineChecker) checkVarassignDe
func (ck MkLineChecker) checkVarassign() {
ck.checkVarassignLeft()
+ ck.checkVarassignOp()
ck.checkVarassignRight()
}
@@ -887,6 +907,57 @@ func (ck MkLineChecker) checkVarassignLe
vucTimeParse)
}
+func (ck MkLineChecker) checkVarassignOp() {
+ ck.checkVarassignOpShell()
+}
+
+func (ck MkLineChecker) checkVarassignOpShell() {
+ mkline := ck.MkLine
+
+ switch {
+ case mkline.Op() != opAssignShell:
+ return
+
+ case mkline.VarassignComment() != "":
+ return
+
+ case mkline.Basename == "builtin.mk":
+ // These are typically USE_BUILTIN.* and BUILTIN_VERSION.*.
+ // Authors of builtin.mk files usually know what they're doing.
+ return
+
+ case G.Pkg == nil || G.Pkg.vars.UsedAtLoadTime(mkline.Varname()):
+ return
+ }
+
+ mkline.Notef("Consider the :sh modifier instead of != for %q.", mkline.Value())
+ mkline.Explain(
+ "For variable assignments using the != operator, the shell command",
+ "is run every time the file is parsed.",
+ "In some cases this is too early, and the command may not yet be installed.",
+ "In other cases the command is executed more often than necessary.",
+ "Most commands don't need to be executed for \"make clean\", for example.",
+ "",
+ "The :sh modifier defers execution until the variable value is actually needed.",
+ "On the other hand, this means the command is executed each time the variable",
+ "is evaluated.",
+ "",
+ "Example:",
+ "",
+ "\tEARLY_YEAR!= date +%Y",
+ "",
+ "\tLATE_YEAR_CMD= date +%Y",
+ "\tLATE_YEAR= ${LATE_YEAR_CMD:sh}",
+ "",
+ "\t# or, in a single line:",
+ "\tLATE_YEAR= ${date +%Y:L:sh}",
+ "",
+ "To suppress this note, provide an explanation in a comment at the end",
+ "of the line, or force the variable to be evaluated at load time,",
+ "by using it at the right-hand side of the := operator, or in an .if",
+ "or .for directive.")
+}
+
// checkVarassignLeft checks everything to the right of the assignment operator.
func (ck MkLineChecker) checkVarassignRight() {
mkline := ck.MkLine
@@ -930,7 +1001,11 @@ func (ck MkLineChecker) checkVarassignLe
return
}
- if varIsUsedSimilar(G.Pkg, G.Mk, varname) {
+ if ck.MkLines != nil && ck.MkLines.vars.UsedSimilar(varname) {
+ return
+ }
+
+ if G.Pkg != nil && G.Pkg.vars.UsedSimilar(varname) {
return
}
@@ -944,7 +1019,7 @@ func (ck MkLineChecker) checkVarassignLe
return
}
- if G.Mk == nil || !G.Mk.FirstTimeSlice("defined but not used: ", varname) {
+ if ck.MkLines == nil || !ck.MkLines.FirstTimeSlice("defined but not used: ", varname) {
return
}
@@ -970,7 +1045,7 @@ func (ck MkLineChecker) checkVarassignRi
time = vucTimeParse
}
- vartype := G.Pkgsrc.VariableType(mkline.Varname())
+ vartype := G.Pkgsrc.VariableType(ck.MkLines, mkline.Varname())
if op == opAssignShell {
vartype = shellCommandsType
}
@@ -1069,7 +1144,7 @@ func (ck MkLineChecker) checkVarassignMi
// No autofix since it doesn't occur anymore.
}
- if varname == "PKG_SKIP_REASON" && G.Mk.indentation.DependsOn("OPSYS") {
+ if varname == "PKG_SKIP_REASON" && ck.MkLines.indentation.DependsOn("OPSYS") {
// TODO: Provide autofix for simple cases, like ".if ${OPSYS} == SunOS".
mkline.Notef("Consider setting NOT_FOR_PLATFORM instead of " +
"PKG_SKIP_REASON depending on ${OPSYS}.")
@@ -1091,8 +1166,8 @@ func (ck MkLineChecker) checkVarassignLe
if !G.Opts.WarnExtra ||
G.Infrastructure ||
mkline.Op() != opAssignDefault ||
- G.Mk.Tools.SeenPrefs ||
- !G.Mk.FirstTime("include bsd.prefs.mk before using ?=") {
+ ck.MkLines.Tools.SeenPrefs ||
+ !ck.MkLines.FirstTime("include bsd.prefs.mk before using ?=") {
return
}
@@ -1116,7 +1191,7 @@ func (ck MkLineChecker) checkVartype(var
}
mkline := ck.MkLine
- vartype := G.Pkgsrc.VariableType(varname)
+ vartype := G.Pkgsrc.VariableType(ck.MkLines, varname)
if op == opAssignAppend {
// XXX: MayBeAppendedTo also depends on the current file, see checkVarusePermissions.
@@ -1144,7 +1219,7 @@ func (ck MkLineChecker) checkVartype(var
break
default:
- words, _ := splitIntoMkWords(mkline.Line, value)
+ words := mkline.ValueFields(value)
for _, word := range words {
ck.CheckVartypeBasic(varname, vartype.basicType, op, word, comment, vartype.guessed)
}
@@ -1162,7 +1237,7 @@ func (ck MkLineChecker) CheckVartypeBasi
mkline := ck.MkLine
valueNoVar := mkline.WithoutMakeVariables(value)
- ctx := VartypeCheck{mkline, varname, op, value, valueNoVar, comment, guessed}
+ ctx := VartypeCheck{ck.MkLines, mkline, varname, op, value, valueNoVar, comment, guessed}
checker.checker(&ctx)
}
@@ -1286,7 +1361,7 @@ func (ck MkLineChecker) checkDirectiveCo
if m, positive, pattern := modifier.MatchMatch(); m && (positive || len(modifiers) == 1) {
ck.checkVartype(varname, opUseMatch, pattern, "")
- vartype := G.Pkgsrc.VariableType(varname)
+ vartype := G.Pkgsrc.VariableType(ck.MkLines, varname)
if matches(pattern, `^[\w-/]+$`) && vartype != nil && !vartype.IsConsideredList() {
ck.MkLine.Notef("%s should be compared using %s instead of matching against %q.",
varname, ifelseStr(positive, "==", "!="), ":"+modifier.Text)
@@ -1373,7 +1448,7 @@ func (ck MkLineChecker) CheckRelativePat
abs := path.Dir(mkline.Filename) + "/" + resolvedPath
if _, err := os.Stat(abs); err != nil {
- if mustExist && !(G.Mk != nil && G.Mk.indentation.IsCheckedFile(resolvedPath)) {
+ if mustExist && !(ck.MkLines != nil && ck.MkLines.indentation.IsCheckedFile(resolvedPath)) {
mkline.Errorf("Relative path %q does not exist.", resolvedPath)
}
return
Index: pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.28 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.29
--- pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.28 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go Wed Apr 3 21:49:51 2019
@@ -11,8 +11,9 @@ func (s *Suite) Test_MkLineChecker_check
mklines := t.NewMkLines("module.mk",
MkRcsID,
"_VARNAME=\tvalue")
+ // Only to prevent "defined but not used".
+ mklines.vars.Use("_VARNAME", mklines.mklines[1], vucTimeRun)
- mklines.vars.Use("_VARNAME", mklines.mklines[1])
mklines.Check()
t.CheckOutputLines(
@@ -305,6 +306,39 @@ func (s *Suite) Test_MkLineChecker_check
func (s *Suite) Test_MkLineChecker_checkDirectiveFor(c *check.C) {
t := s.Init(c)
+ t.SetUpVartypes()
+ mklines := t.NewMkLines("for.mk",
+ MkRcsID,
+ ".for dir in ${PATH:C,:, ,g}",
+ ".endfor",
+ "",
+ ".for dir in ${PATH}",
+ ".endfor",
+ "",
+ ".for dir in ${PATH:M*/bin}",
+ ".endfor")
+
+ mklines.Check()
+
+ t.CheckOutputLines(
+ // FIXME: PATH may actually be used at load time.
+ "WARN: for.mk:2: PATH should not be used at load time in any file.",
+
+ // No warning about :Q in line 2 since the :C modifier converts the
+ // colon-separated list into a space-separated list, as required by
+ // the .for loop.
+
+ // This warning is correct since PATH is separated by colons, not by spaces.
+ "WARN: for.mk:5: Please use ${PATH:Q} instead of ${PATH}.",
+
+ // This warning is also correct since the :M modifier doesn't change the
+ // word boundaries.
+ "WARN: for.mk:8: Please use ${PATH:M*/bin:Q} instead of ${PATH:M*/bin}.")
+}
+
+func (s *Suite) Test_MkLineChecker_checkDirectiveFor__infrastructure(c *check.C) {
+ t := s.Init(c)
+
t.SetUpPkgsrc()
t.CreateFileLines("mk/file.mk",
MkRcsID,
@@ -316,7 +350,8 @@ func (s *Suite) Test_MkLineChecker_check
G.Check(t.File("mk/file.mk"))
- // Pkglint doesn't care about trivial syntax errors, bmake will already catch these.
+ // Pkglint doesn't care about trivial syntax errors like the "=" instead
+ // of "in" above; bmake will already catch these.
t.CheckOutputEmpty()
}
@@ -347,7 +382,7 @@ func (s *Suite) Test_MkLineChecker_check
t.SetUpVartypes()
// Since COMMENT is defined in vardefs.go its type is certain instead of guessed.
- vartype := G.Pkgsrc.VariableType("COMMENT")
+ vartype := G.Pkgsrc.VariableType(nil, "COMMENT")
c.Assert(vartype, check.NotNil)
c.Check(vartype.basicType.name, equals, "Comment")
@@ -419,9 +454,8 @@ func (s *Suite) Test_MkLineChecker_check
test := func(cond string, output ...string) {
mklines := t.NewMkLines("filename.mk",
cond)
- G.Mk = mklines
mklines.ForEach(func(mkline MkLine) {
- MkLineChecker{mkline}.checkDirectiveCond()
+ MkLineChecker{mklines, mkline}.checkDirectiveCond()
})
t.CheckOutput(output)
}
@@ -499,8 +533,8 @@ func (s *Suite) Test_MkLineChecker_check
"TRACE: 1 2 + MkLineChecker.checkVarusePermissions(\"VAR\", (no-type time:parse quoting:plain wordpart:false))",
"TRACE: 1 2 3 No type definition found for \"VAR\".",
"TRACE: 1 2 - MkLineChecker.checkVarusePermissions(\"VAR\", (no-type time:parse quoting:plain wordpart:false))",
- "TRACE: 1 2 + (*MkLineImpl).VariableNeedsQuoting(\"VAR\", (*pkglint.Vartype)(nil), (no-type time:parse quoting:plain wordpart:false))",
- "TRACE: 1 2 - (*MkLineImpl).VariableNeedsQuoting(\"VAR\", (*pkglint.Vartype)(nil), (no-type time:parse quoting:plain wordpart:false), \"=>\", unknown)",
+ "TRACE: 1 2 + (*MkLineImpl).VariableNeedsQuoting(${VAR:Mpattern1:Mpattern2}, (*pkglint.Vartype)(nil), (no-type time:parse quoting:plain wordpart:false))",
+ "TRACE: 1 2 - (*MkLineImpl).VariableNeedsQuoting(${VAR:Mpattern1:Mpattern2}, (*pkglint.Vartype)(nil), (no-type time:parse quoting:plain wordpart:false), \"=>\", unknown)",
"TRACE: 1 - MkLineChecker.CheckVaruse(filename.mk:1, ${VAR:Mpattern1:Mpattern2}, (no-type time:parse quoting:plain wordpart:false))",
"TRACE: - MkLineChecker.checkDirectiveCond(\"${VAR:Mpattern1:Mpattern2} == comparison\")",
"TRACE: + (*MkParser).mkCondAtom(\"${VAR:Mpattern1:Mpattern2} == comparison\")",
@@ -620,6 +654,77 @@ func (s *Suite) Test_MkLineChecker_check
t.CheckOutputEmpty()
}
+func (s *Suite) Test_MkLineChecker_checkVarassignOpShell(c *check.C) {
+ t := s.Init(c)
+
+ t.SetUpTool("uname", "UNAME", AfterPrefsMk)
+ t.SetUpTool("echo", "", AtRunTime)
+ t.SetUpPkgsrc()
+ t.SetUpPackage("category/package",
+ ".include \"standalone.mk\"")
+ t.CreateFileLines("category/package/standalone.mk",
+ MkRcsID,
+ "",
+ ".include \"../../mk/bsd.prefs.mk\"",
+ "",
+ "OPSYS_NAME!=\t${UNAME}",
+ ".if ${OPSYS_NAME} == \"NetBSD\"",
+ ".endif",
+ "",
+ "OS_NAME!=\t${UNAME}",
+ "",
+ "MUST_BE_EARLY!=\techo 123 # must be evaluated early",
+ "",
+ "show-package-vars: .PHONY",
+ "\techo OS_NAME=${OS_NAME:Q}",
+ "\techo MUST_BE_EARLY=${MUST_BE_EARLY:Q}")
+
+ G.Check(t.File("category/package/standalone.mk"))
+
+ // There is no warning about any variable since no package is currently
+ // being checked, therefore pkglint cannot decide whether the variable
+ // is used a load time.
+ t.CheckOutputEmpty()
+
+ t.SetUpCommandLine("-Wall", "--explain")
+ G.Check(t.File("category/package"))
+
+ // There is no warning for OPSYS_NAME since that variable is used at
+ // load time. In such a case the command has to be executed anyway,
+ // and executing it exactly once is the best thing to do.
+ //
+ // There is no warning for MUST_BE_EARLY since the comment provides the
+ // reason that this command really has to be executed at load time.
+ t.CheckOutputLines(
+ "NOTE: ~/category/package/standalone.mk:9: Consider the :sh modifier instead of != for \"${UNAME}\".",
+ "",
+ "\tFor variable assignments using the != operator, the shell command is",
+ "\trun every time the file is parsed. In some cases this is too early,",
+ "\tand the command may not yet be installed. In other cases the command",
+ "\tis executed more often than necessary. Most commands don't need to",
+ "\tbe executed for \"make clean\", for example.",
+ "",
+ "\tThe :sh modifier defers execution until the variable value is",
+ "\tactually needed. On the other hand, this means the command is",
+ "\texecuted each time the variable is evaluated.",
+ "",
+ "\tExample:",
+ "",
+ "\t\tEARLY_YEAR!= date +%Y",
+ "",
+ "\t\tLATE_YEAR_CMD= date +%Y",
+ "\t\tLATE_YEAR= ${LATE_YEAR_CMD:sh}",
+ "",
+ "\t\t# or, in a single line:",
+ "\t\tLATE_YEAR= ${date +%Y:L:sh}",
+ "",
+ "\tTo suppress this note, provide an explanation in a comment at the",
+ "\tend of the line, or force the variable to be evaluated at load time,",
+ "\tby using it at the right-hand side of the := operator, or in an .if",
+ "\tor .for directive.",
+ "")
+}
+
func (s *Suite) Test_MkLineChecker_checkVarassignRightVaruse(c *check.C) {
t := s.Init(c)
@@ -1147,7 +1252,7 @@ func (s *Suite) Test_MkLineChecker_Check
"# dummy")
mklines.ForEach(func(mkline MkLine) {
- ck := MkLineChecker{mkline}
+ ck := MkLineChecker{mklines, mkline}
ck.CheckRelativePkgdir("../pkgbase")
ck.CheckRelativePkgdir("../../other/package")
@@ -1189,8 +1294,8 @@ func (s *Suite) Test_MkLineChecker_Check
"FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}",
"FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:Q}")
- MkLineChecker{mklines.mklines[0]}.Check()
- MkLineChecker{mklines.mklines[1]}.Check()
+ MkLineChecker{mklines, mklines.mklines[0]}.Check()
+ MkLineChecker{mklines, mklines.mklines[1]}.Check()
// In line 1, don't warn that ${XKBBASE}/xkbcomp is used but not defined.
// This is because the :L modifier interprets everything before as an expression
@@ -1255,7 +1360,7 @@ func (s *Suite) Test_MkLineChecker_check
t.SetUpVartypes()
mkline := t.NewMkLine("module.mk", 123, ".if ${PKGPATH} == \"category/package\"")
- ck := MkLineChecker{mkline}
+ ck := MkLineChecker{nil, mkline}
// FIXME: checkDirectiveCondEmpty cannot know whether it is empty(...) or !empty(...).
// It must know that to generate the proper diagnostics.
@@ -1305,17 +1410,16 @@ func (s *Suite) Test_MkLineChecker_check
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile",
+ mklines := t.NewMkLines("chat/pidgin-icb/Makefile",
MkRcsID,
"CFLAGS+=\t`pkg-config pidgin --cflags`")
- mkline := G.Mk.mklines[1]
+ mkline := mklines.mklines[1]
- words, rest := splitIntoMkWords(mkline.Line, mkline.Value())
+ words := mkline.Fields()
c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"})
- c.Check(rest, equals, "")
- ck := MkLineChecker{G.Mk.mklines[1]}
+ ck := MkLineChecker{mklines, mklines.mklines[1]}
ck.checkVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "")
// No warning about "`pkg-config" being an unknown CFlag.
@@ -1346,7 +1450,7 @@ func (s *Suite) Test_MkLineChecker_check
mkline := t.NewMkLine("filename.mk", 123, ".if 0")
// Calling this method is only useful in the context of a whole file.
- MkLineChecker{mkline}.checkDirectiveIndentation(4)
+ MkLineChecker{nil, mkline}.checkDirectiveIndentation(4)
t.CheckOutputEmpty()
}
@@ -1412,7 +1516,7 @@ func (s *Suite) Test_MkLineChecker_check
".endif")
}
-func (s *Suite) Test_MkLineChecker_CheckVaruseShellword(c *check.C) {
+func (s *Suite) Test_MkLineChecker_checkVarUseQuoting(c *check.C) {
t := s.Init(c)
t.SetUpVartypes()
@@ -1435,7 +1539,7 @@ func (s *Suite) Test_MkLineChecker_Check
"WARN: ~/options.mk:4: The variable PATH should be quoted as part of a shell word.")
}
-func (s *Suite) Test_MkLineChecker_CheckVaruseShellword__mstar(c *check.C) {
+func (s *Suite) Test_MkLineChecker_checkVarUseQuoting__mstar(c *check.C) {
t := s.Init(c)
t.SetUpCommandLine("-Wall,no-space")
@@ -1459,7 +1563,7 @@ func (s *Suite) Test_MkLineChecker_Check
"WARN: ~/options.mk:4: ADA_FLAGS is used but not defined.")
}
-func (s *Suite) Test_MkLineChecker_CheckVaruseShellword__mstar_not_needed(c *check.C) {
+func (s *Suite) Test_MkLineChecker_checkVarUseQuoting__mstar_not_needed(c *check.C) {
t := s.Init(c)
t.SetUpCommandLine("-Wall,no-space")
@@ -1481,7 +1585,7 @@ func (s *Suite) Test_MkLineChecker_Check
"NOTE: ~/category/package/Makefile:21: The :M* modifier is not needed here.")
}
-func (s *Suite) Test_MkLineChecker_CheckVaruseShellword__q_not_needed(c *check.C) {
+func (s *Suite) Test_MkLineChecker_checkVarUseQuoting__q_not_needed(c *check.C) {
t := s.Init(c)
pkg := t.SetUpPackage("category/package",
@@ -1543,7 +1647,7 @@ func (s *Suite) Test_MkLineChecker_Check
"CPPPATH.Linux=\t/usr/bin/cpp")
G.Pkgsrc.LoadInfrastructure()
- ck := MkLineChecker{t.NewMkLine("module.mk", 101, "COMMENT=\t${CPPPATH.SunOS}")}
+ ck := MkLineChecker{nil, t.NewMkLine("module.mk", 101, "COMMENT=\t${CPPPATH.SunOS}")}
ck.CheckVaruse(NewMkVarUse("CPPPATH.SunOS"), &VarUseContext{
vartype: &Vartype{
@@ -1678,7 +1782,7 @@ func (s *Suite) Test_MkLineChecker_check
mkline := t.NewMkLine("mk/compiler/gcc.mk", 150,
"CC:=\t${CC:C/^/_asdf_/1:M_asdf_*:S/^_asdf_//}")
- MkLineChecker{mkline}.Check()
+ MkLineChecker{nil, mkline}.Check()
// FIXME: The check is called two times, even though it only produces a single NOTE.
t.CheckOutputLines(
@@ -1717,7 +1821,7 @@ func (s *Suite) Test_MkLineChecker_Check
mkline := t.NewMkLine("module.mk", 123,
"\t${_PKG_SILENT}${_PKG_DEBUG} :")
- MkLineChecker{mkline}.Check()
+ MkLineChecker{nil, mkline}.Check()
t.CheckOutputLines(
"WARN: module.mk:123: Use of _PKG_SILENT and _PKG_DEBUG is deprecated. Use ${RUN} instead.")
Index: pkgsrc/pkgtools/pkglint/files/mklines.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines.go:1.44 pkgsrc/pkgtools/pkglint/files/mklines.go:1.45
--- pkgsrc/pkgtools/pkglint/files/mklines.go:1.44 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mklines.go Wed Apr 3 21:49:51 2019
@@ -74,10 +74,10 @@ func NewMkLines(lines Lines) MkLines {
// UseVar remembers that the given variable is used in the given line.
// This controls the "defined but not used" warning.
-func (mklines *MkLinesImpl) UseVar(mkline MkLine, varname string) {
- mklines.vars.Use(varname, mkline)
+func (mklines *MkLinesImpl) UseVar(mkline MkLine, varname string, time vucTime) {
+ mklines.vars.Use(varname, mkline, time)
if G.Pkg != nil {
- G.Pkg.vars.Use(varname, mkline)
+ G.Pkg.vars.Use(varname, mkline, time)
}
}
@@ -86,9 +86,6 @@ func (mklines *MkLinesImpl) Check() {
defer trace.Call1(mklines.lines.FileName)()
}
- G.Mk = mklines
- defer func() { G.Mk = nil }()
-
// In the first pass, all additions to BUILD_DEFS and USE_TOOLS
// are collected to make the order of the definitions irrelevant.
mklines.collectUsedVariables()
@@ -128,7 +125,7 @@ func (mklines *MkLinesImpl) checkAll() {
mklines.Tools.SeenPrefs = true
}
- ck := MkLineChecker{mkline}
+ ck := MkLineChecker{mklines, mkline}
ck.Check()
varalign.Process(mkline)
@@ -184,7 +181,7 @@ func (mklines *MkLinesImpl) checkAll() {
func (mklines *MkLinesImpl) checkVarassignPlist(mkline MkLine) {
switch mkline.Varcanon() {
case "PLIST_VARS":
- for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value())) {
+ for _, id := range mkline.ValueFields(resolveVariableRefs(mklines, mkline.Value())) {
if !mklines.plistVarSkip && mklines.plistVarSet[id] == nil {
mkline.Warnf("%q is added to PLIST_VARS, but PLIST.%s is not defined in this file.", id, id)
}
@@ -244,7 +241,7 @@ func (mklines *MkLinesImpl) collectDefin
continue
}
- defineVar(G.Pkg, mklines, mkline, mkline.Varname())
+ mklines.defineVar(G.Pkg, mkline, mkline.Varname())
varcanon := mkline.Varcanon()
switch varcanon {
@@ -267,22 +264,22 @@ func (mklines *MkLinesImpl) collectDefin
}
case "PLIST_VARS":
- for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value())) {
+ for _, id := range mkline.ValueFields(resolveVariableRefs(mklines, mkline.Value())) {
if trace.Tracing {
trace.Step1("PLIST.%s is added to PLIST_VARS.", id)
}
if containsVarRef(id) {
- mklines.UseVar(mkline, "PLIST.*")
+ mklines.UseVar(mkline, "PLIST.*", mkline.Op().Time())
mklines.plistVarSkip = true
} else {
- mklines.UseVar(mkline, "PLIST."+id)
+ mklines.UseVar(mkline, "PLIST."+id, mkline.Op().Time())
}
}
case "SUBST_VARS.*":
for _, substVar := range mkline.Fields() {
- mklines.UseVar(mkline, varnameCanon(substVar))
+ mklines.UseVar(mkline, varnameCanon(substVar), mkline.Op().Time())
if trace.Tracing {
trace.Step1("varuse %s", substVar)
}
@@ -290,20 +287,28 @@ func (mklines *MkLinesImpl) collectDefin
case "OPSYSVARS":
for _, opsysVar := range mkline.Fields() {
- mklines.UseVar(mkline, opsysVar+".*")
- defineVar(G.Pkg, mklines, mkline, opsysVar)
+ mklines.UseVar(mkline, opsysVar+".*", mkline.Op().Time())
+ mklines.defineVar(G.Pkg, mkline, opsysVar)
}
}
}
}
+// defineVar marks a variable as defined in both the current package and the current file.
+func (mklines *MkLinesImpl) defineVar(pkg *Package, mkline MkLine, varname string) {
+ mklines.vars.Define(varname, mkline)
+ if pkg != nil {
+ pkg.vars.Define(varname, mkline)
+ }
+}
+
func (mklines *MkLinesImpl) collectPlistVars() {
// TODO: The PLIST_VARS code above looks very similar.
for _, mkline := range mklines.mklines {
if mkline.IsVarassign() {
switch mkline.Varcanon() {
case "PLIST_VARS":
- for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value())) {
+ for _, id := range mkline.ValueFields(resolveVariableRefs(mklines, mkline.Value())) {
if containsVarRef(id) {
mklines.plistVarSkip = true
} else {
@@ -330,9 +335,9 @@ func (mklines *MkLinesImpl) collectElse(
func (mklines *MkLinesImpl) collectUsedVariables() {
for _, mkline := range mklines.mklines {
- for _, varname := range mkline.DetermineUsedVariables() {
- mklines.UseVar(mkline, varname)
- }
+ mkline.ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ mklines.UseVar(mkline, varUse.varname, time)
+ })
}
mklines.collectDocumentedVariables()
@@ -357,7 +362,7 @@ func (mklines *MkLinesImpl) collectDocum
if commentLines >= 3 && relevant {
for varname, mkline := range scope.used {
mklines.vars.Define(varname, mkline)
- mklines.vars.Use(varname, mkline)
+ mklines.vars.Use(varname, mkline, vucTimeRun)
}
}
@@ -393,7 +398,7 @@ func (mklines *MkLinesImpl) collectDocum
varcanon := varnameCanon(varname)
if varcanon == strings.ToUpper(varcanon) && matches(varcanon, `[A-Z]`) && parser.EOF() {
scope.Define(varcanon, mkline)
- scope.Use(varcanon, mkline)
+ scope.Use(varcanon, mkline, vucTimeRun)
}
if words[1] == "Copyright" {
Index: pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.44 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.45
--- pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.44 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go Wed Apr 3 21:49:51 2019
@@ -172,55 +172,114 @@ func (s *Suite) Test_VartypeCheck_ConfFi
"WARN: filename.mk:5: The destination file \"/etc/bootrc\" should start with a variable reference.")
}
+// See Test_MkParser_Dependency.
func (s *Suite) Test_VartypeCheck_Dependency(c *check.C) {
vt := NewVartypeCheckTester(s.Init(c), (*VartypeCheck).Dependency)
vt.Varname("CONFLICTS")
vt.Op(opAssignAppend)
+
+ // comparison operators
vt.Values(
- "Perl",
"perl5>=5.22",
+ "libkipi>=0.1.5<4.0",
+ "gtk2+>=2.16")
+ vt.OutputEmpty()
+
+ // pattern matching
+ vt.Values(
+ "perl-5*",
"perl5-*",
+ "perl-5.22",
"perl5-5.22.*",
- "perl5-[5.10-5.22]*",
- "py-docs",
+ "gtksourceview-sharp-2.0-[0-9]*")
+ vt.Output(
+ "WARN: filename.mk:11: Please use \"5.*\" instead of \"5*\" as the version pattern.",
+ "WARN: filename.mk:12: Please use \"perl5-[0-9]*\" instead of \"perl5-*\".",
+ "WARN: filename.mk:13: Please use \"5.22{,nb*}\" instead of \"5.22\" as the version pattern.",
+ "WARN: filename.mk:15: The version pattern \"2.0-[0-9]*\" should not contain a hyphen.")
+
+ // nb suffix
+ vt.Values(
"perl5-5.22.*{,nb*}",
- "libkipi>=0.1.5<4.0",
- "gtk2+>=2.16",
- "perl-5.22",
- "perl-5*",
- "gtksourceview-sharp-2.0-[0-9]*",
"perl-5.22{,nb*}",
"perl-5.22{,nb[0-9]*}",
"mbrola-301h{,nb[0-9]*}",
+ "ncurses-${NC_VERS}{,nb*}",
+ "gnome-control-center>=2.20.1{,nb*}",
+ "gnome-control-center>=2.20.1{,nb[0-9]*}")
+ vt.Output(
+ "WARN: filename.mk:26: Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.",
+ "WARN: filename.mk:27: Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.")
+
+ // alternative patterns, using braces or brackets
+ vt.Values(
"mpg123{,-esound,-nas}>=0.59.18",
"mysql*-{client,server}-[0-9]*",
- "postgresql8[0-35-9]-${module}-[0-9]*",
- "ncurses-${NC_VERS}{,nb*}",
"{ssh{,6}-[0-9]*,openssh-[0-9]*}",
- "gnome-control-center>=2.20.1{,nb*}",
- "gnome-control-center>=2.20.1{,nb[0-9]*}",
- "package-1.0|garbage",
+ "libao-[a-z]*-[0-9]*")
+ vt.OutputEmpty()
+
+ // variables
+ vt.Values(
+ "postgresql8[0-35-9]-${module}-[0-9]*",
"${_EMACS_CONFLICTS.${_EMACS_FLAVOR}}",
- "package>=1.0:../../category/package",
- "package-1.0>=1.0.3")
+ "${PYPKGPREFIX}-sqlite3",
+ "${PYPKGPREFIX}-sqlite3-${VERSION}",
+ "${PYPKGPREFIX}-sqlite3-${PYSQLITE_REQD}",
+ "${PYPKGPREFIX}-sqlite3>=${PYSQLITE_REQD}",
+ "${EMACS_PACKAGE}>=${EMACS_MAJOR}",
+
+ // The "*" is ambiguous. It could either continue the PKGBASE or
+ // start the version number.
+ "${PKGNAME_NOREV:S/jdk/jre/}*",
+
+ // The canonical form is "{,nb*}" instead of "{nb*,}".
+ // Plus, mentioning nb* is not necessary when using >=.
+ "dovecot>=${PKGVERSION_NOREV}{nb*,}",
+
+ "oxygen-icons>=${KF5VER}{,nb[0-9]*}",
+
+ // The following pattern should have "]*}" instead of "]}*".
+ "ja-vflib-lib-${VFLIB_VERSION}{,nb[0-9]}*",
+
+ // The following pattern uses both ">=" and "*", which doesn't make sense.
+ "${PYPKGPREFIX}-sphinx>=1.2.3nb1*",
+
+ "{${NETSCAPE_PREFERRED:C/:/,/g}}-[0-9]*")
vt.Output(
- "WARN: filename.mk:1: Invalid dependency pattern \"Perl\".",
- "WARN: filename.mk:3: Please use \"perl5-[0-9]*\" instead of \"perl5-*\".",
- "WARN: filename.mk:5: Only [0-9]* is allowed in the numeric part of a dependency.",
- "WARN: filename.mk:5: The version pattern \"[5.10-5.22]*\" should not contain a hyphen.",
- "WARN: filename.mk:6: Invalid dependency pattern \"py-docs\".",
- "WARN: filename.mk:10: Please use \"5.22{,nb*}\" instead of \"5.22\" as the version pattern.",
- "WARN: filename.mk:11: Please use \"5.*\" instead of \"5*\" as the version pattern.",
- "WARN: filename.mk:12: The version pattern \"2.0-[0-9]*\" should not contain a hyphen.",
- "WARN: filename.mk:21: Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.",
- "WARN: filename.mk:22: Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.",
- "WARN: filename.mk:23: Invalid dependency pattern \"package-1.0|garbage\".",
+ "WARN: filename.mk:43: Invalid dependency pattern \"${PYPKGPREFIX}-sqlite3\".",
+ // This pattern is invalid because the variable name doesn't contain "VER".
+ "WARN: filename.mk:45: Invalid dependency pattern \"${PYPKGPREFIX}-sqlite3-${PYSQLITE_REQD}\".",
+ "WARN: filename.mk:48: Invalid dependency pattern \"${PKGNAME_NOREV:S/jdk/jre/}*\".",
+ "WARN: filename.mk:49: Invalid dependency pattern \"dovecot>=${PKGVERSION_NOREV}{nb*,}\".",
+ "WARN: filename.mk:50: Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.",
+ "WARN: filename.mk:51: Invalid dependency pattern \"ja-vflib-lib-${VFLIB_VERSION}{,nb[0-9]}*\".",
+ "WARN: filename.mk:52: Invalid dependency pattern \"${PYPKGPREFIX}-sphinx>=1.2.3nb1*\".")
+
+ // invalid dependency patterns
+ vt.Values(
+ "Perl",
+ "py-docs",
+ "perl5-[5.10-5.22]*",
+ "package-1.0|garbage",
+ "package>=1.0:../../category/package",
+ "package-1.0>=1.0.3",
+ // This should be regarded as invalid since the [a-z0-9] might either
+ // continue the PKGBASE or start the version number.
+ "${RUBY_PKGPREFIX}-theme-[a-z0-9]*")
+ vt.Output(
+ "WARN: filename.mk:61: Invalid dependency pattern \"Perl\".",
+ "WARN: filename.mk:62: Invalid dependency pattern \"py-docs\".",
+ "WARN: filename.mk:63: Only [0-9]* is allowed in the numeric part of a dependency.",
+ "WARN: filename.mk:63: The version pattern \"[5.10-5.22]*\" should not contain a hyphen.",
+ "WARN: filename.mk:64: Invalid dependency pattern \"package-1.0|garbage\".",
// TODO: Mention that the path should be removed.
- "WARN: filename.mk:25: Invalid dependency pattern \"package>=1.0:../../category/package\".",
+ "WARN: filename.mk:65: Invalid dependency pattern \"package>=1.0:../../category/package\".",
// TODO: Mention that version numbers in a pkgbase must be appended directly, without hyphen.
- "WARN: filename.mk:26: Invalid dependency pattern \"package-1.0>=1.0.3\".")
+ "WARN: filename.mk:66: Invalid dependency pattern \"package-1.0>=1.0.3\".",
+ "WARN: filename.mk:67: Invalid dependency pattern \"${RUBY_PKGPREFIX}-theme-[a-z0-9]*\".")
}
func (s *Suite) Test_VartypeCheck_DependencyWithPath(c *check.C) {
@@ -228,6 +287,7 @@ func (s *Suite) Test_VartypeCheck_Depend
vt := NewVartypeCheckTester(t, (*VartypeCheck).DependencyWithPath)
t.CreateFileLines("category/package/Makefile")
+ t.CreateFileLines("databases/py-sqlite3/Makefile")
t.CreateFileLines("devel/gettext/Makefile")
t.CreateFileLines("devel/gmake/Makefile")
t.CreateFileLines("devel/py-module/Makefile")
@@ -241,35 +301,56 @@ func (s *Suite) Test_VartypeCheck_Depend
"Perl",
"perl5>=5.22:../perl5",
"perl5>=5.24:../../lang/perl5",
- "broken0.12.1:../../x11/alacarte",
- "broken[0-9]*:../../x11/alacarte",
- "broken[0-9]*../../x11/alacarte",
- "broken>=:../../x11/alacarte",
- "broken=0:../../x11/alacarte",
- "broken=:../../x11/alacarte",
- "broken-:../../x11/alacarte",
- "broken>:../../x11/alacarte",
"gtk2+>=2.16:../../x11/alacarte",
"gettext-[0-9]*:../../devel/gettext",
- "gmake-[0-9]*:../../devel/gmake",
- "${PYPKGPREFIX}-module>=0:../../devel/py-module")
+ "gmake-[0-9]*:../../devel/gmake")
vt.Output(
"WARN: ~/category/package/filename.mk:1: Invalid dependency pattern with path \"Perl\".",
- "WARN: ~/category/package/filename.mk:2: Dependencies should have the form \"../../category/package\".",
+ "WARN: ~/category/package/filename.mk:2: Dependency paths should have the form \"../../category/package\".",
+ "ERROR: ~/category/package/filename.mk:2: Relative path \"../perl5\" does not exist.",
+ "WARN: ~/category/package/filename.mk:2: \"../perl5\" is not a valid relative package directory.",
+ "WARN: ~/category/package/filename.mk:2: Please use USE_TOOLS+=perl:run instead of this dependency.",
"ERROR: ~/category/package/filename.mk:3: Relative path \"../../lang/perl5\" does not exist.",
"ERROR: ~/category/package/filename.mk:3: There is no package in \"lang/perl5\".",
"WARN: ~/category/package/filename.mk:3: Please use USE_TOOLS+=perl:run instead of this dependency.",
- "WARN: ~/category/package/filename.mk:4: Invalid dependency pattern \"broken0.12.1\".",
- "WARN: ~/category/package/filename.mk:5: Invalid dependency pattern \"broken[0-9]*\".",
- "WARN: ~/category/package/filename.mk:6: Invalid dependency pattern with path \"broken[0-9]*../../x11/alacarte\".",
- "WARN: ~/category/package/filename.mk:7: Invalid dependency pattern \"broken>=\".",
- "WARN: ~/category/package/filename.mk:8: Invalid dependency pattern \"broken=0\".",
- "WARN: ~/category/package/filename.mk:9: Invalid dependency pattern \"broken=\".",
- "WARN: ~/category/package/filename.mk:10: Invalid dependency pattern \"broken-\".",
- "WARN: ~/category/package/filename.mk:11: Invalid dependency pattern \"broken>\".",
- "WARN: ~/category/package/filename.mk:13: Please use USE_TOOLS+=msgfmt instead of this dependency.",
- "WARN: ~/category/package/filename.mk:14: Please use USE_TOOLS+=gmake instead of this dependency.")
+ "WARN: ~/category/package/filename.mk:5: Please use USE_TOOLS+=msgfmt instead of this dependency.",
+ "WARN: ~/category/package/filename.mk:6: Please use USE_TOOLS+=gmake instead of this dependency.")
+
+ vt.Values(
+ "broken0.12.1:../../x11/alacarte", // missing version
+ "broken[0-9]*:../../x11/alacarte", // missing version
+ "broken[0-9]*../../x11/alacarte", // missing colon
+ "broken>=:../../x11/alacarte", // incomplete comparison
+ "broken=0:../../x11/alacarte", // invalid comparison operator
+ "broken=:../../x11/alacarte", // incomplete comparison
+ "broken-:../../x11/alacarte", // incomplete pattern
+ "broken>:../../x11/alacarte") // incomplete comparison
+
+ vt.Output(
+ "WARN: ~/category/package/filename.mk:11: Invalid dependency pattern \"broken0.12.1\".",
+ "WARN: ~/category/package/filename.mk:12: Invalid dependency pattern \"broken[0-9]*\".",
+ "WARN: ~/category/package/filename.mk:13: Invalid dependency pattern with path \"broken[0-9]*../../x11/alacarte\".",
+ "WARN: ~/category/package/filename.mk:14: Invalid dependency pattern \"broken>=\".",
+ "WARN: ~/category/package/filename.mk:15: Invalid dependency pattern \"broken=0\".",
+ "WARN: ~/category/package/filename.mk:16: Invalid dependency pattern \"broken=\".",
+ "WARN: ~/category/package/filename.mk:17: Invalid dependency pattern \"broken-\".",
+ "WARN: ~/category/package/filename.mk:18: Invalid dependency pattern \"broken>\".")
+
+ vt.Values(
+ "${PYPKGPREFIX}-sqlite3:../../${MY_PKGPATH.py-sqlite3}",
+ "${PYPKGPREFIX}-sqlite3:../../databases/py-sqlite3",
+ "${DEPENDS.NetBSD}",
+ "${DEPENDENCY_PATTERN.py-sqlite3}:${DEPENDENCY_PATH.py-sqlite}",
+ "${PYPKGPREFIX}-module>=0:../../devel/py-module",
+ "${EMACS_PACKAGE}>=${EMACS_MAJOR}:${EMACS_PKGDIR}",
+ "{${NETSCAPE_PREFERRED:C/:/,/g}}-[0-9]*:../../www/${NETSCAPE_PREFERRED:C/:.*//}")
+
+ vt.Output(
+ "WARN: ~/category/package/filename.mk:21: "+
+ "Invalid dependency pattern \"${PYPKGPREFIX}-sqlite3\".",
+ "WARN: ~/category/package/filename.mk:22: "+
+ "Invalid dependency pattern \"${PYPKGPREFIX}-sqlite3\".")
}
func (s *Suite) Test_VartypeCheck_DistSuffix(c *check.C) {
@@ -397,7 +478,7 @@ func (s *Suite) Test_VartypeCheck_FetchU
vt.Values(
"https://example.org/download.cgi?filename=filename&sha1=12341234")
- t.CheckOutputEmpty()
+ vt.OutputEmpty()
vt.Values(
"http://example.org/distfiles/",
@@ -405,7 +486,7 @@ func (s *Suite) Test_VartypeCheck_FetchU
"http://example.org/download?filename=<distfile>;version=<version>")
vt.Output(
- "WARN: filename.mk:8: \"http://example.org/download?filename=<distfile>;version=<version>\" is not a valid URL.")
+ "WARN: filename.mk:23: \"http://example.org/download?filename=<distfile>;version=<version>\" is not a valid URL.")
}
func (s *Suite) Test_VartypeCheck_Filename(c *check.C) {
@@ -517,7 +598,7 @@ func (s *Suite) Test_VartypeCheck_Homepa
// doesn't define MASTER_SITES, that variable cannot be expanded, which means
// the warning cannot refer to its value.
vt.Output(
- "WARN: filename.mk:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.")
+ "WARN: filename.mk:11: HOMEPAGE should not be defined in terms of MASTER_SITEs.")
delete(G.Pkg.vars.firstDef, "MASTER_SITES")
delete(G.Pkg.vars.lastDef, "MASTER_SITES")
@@ -528,7 +609,7 @@ func (s *Suite) Test_VartypeCheck_Homepa
"${MASTER_SITES}")
vt.Output(
- "WARN: filename.mk:5: HOMEPAGE should not be defined in terms of MASTER_SITEs. " +
+ "WARN: filename.mk:21: HOMEPAGE should not be defined in terms of MASTER_SITEs. " +
"Use https://cdn.NetBSD.org/pub/pkgsrc/distfiles/ directly.")
delete(G.Pkg.vars.firstDef, "MASTER_SITES")
@@ -542,7 +623,7 @@ func (s *Suite) Test_VartypeCheck_Homepa
// When MASTER_SITES itself makes use of another variable, pkglint doesn't
// resolve that variable and just outputs the simple variant of this warning.
vt.Output(
- "WARN: filename.mk:6: HOMEPAGE should not be defined in terms of MASTER_SITEs.")
+ "WARN: filename.mk:31: HOMEPAGE should not be defined in terms of MASTER_SITEs.")
}
@@ -1424,7 +1505,7 @@ func (vt *VartypeCheckTester) Values(val
return varname + space + opStr + value
}
- test := func(mkline MkLine, value string) {
+ test := func(mklines MkLines, mkline MkLine, value string) {
varname := vt.varname
comment := ""
if mkline.IsVarassign() {
@@ -1437,21 +1518,19 @@ func (vt *VartypeCheckTester) Values(val
effectiveValue = mkline.Value()
}
- vartype := G.Pkgsrc.VariableType(varname)
+ vartype := G.Pkgsrc.VariableType(nil, varname)
// See MkLineChecker.checkVartype.
var lineValues []string
if vartype == nil || vartype.kindOfList == lkNone {
lineValues = []string{effectiveValue}
} else {
- var rest string
- lineValues, rest = splitIntoMkWords(mkline.Line, effectiveValue)
- vt.tester.Check(rest, equals, "")
+ lineValues = mkline.ValueFields(effectiveValue)
}
for _, lineValue := range lineValues {
valueNovar := mkline.WithoutMakeVariables(lineValue)
- vc := VartypeCheck{mkline, varname, vt.op, lineValue, valueNovar, comment, false}
+ vc := VartypeCheck{mklines, mkline, varname, vt.op, lineValue, valueNovar, comment, false}
vt.checker(&vc)
}
}
@@ -1463,7 +1542,7 @@ func (vt *VartypeCheckTester) Values(val
mklines := NewMkLines(NewLines(vt.filename, []Line{line}))
vt.lineno++
- mklines.ForEach(func(mkline MkLine) { test(mkline, value) })
+ mklines.ForEach(func(mkline MkLine) { test(mklines, mkline, value) })
}
}
@@ -1471,10 +1550,12 @@ func (vt *VartypeCheckTester) Values(val
// the same as the expectedLines.
func (vt *VartypeCheckTester) Output(expectedLines ...string) {
vt.tester.CheckOutputLines(expectedLines...)
+ vt.nextSection()
}
func (vt *VartypeCheckTester) OutputEmpty() {
vt.tester.CheckOutputEmpty()
+ vt.nextSection()
}
func (vt *VartypeCheckTester) nextSection() {
Index: pkgsrc/pkgtools/pkglint/files/mklines_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.39 pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.40
--- pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.39 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mklines_test.go Wed Apr 3 21:49:51 2019
@@ -95,11 +95,17 @@ func (s *Suite) Test_MkLines__varuse_sh_
"qore-version=\tqore --short-version | ${SED} -e s/-.*//",
"PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"")
- vars2 := mklines.mklines[1].DetermineUsedVariables()
+ var vars2 []string
+ mklines.mklines[1].ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ vars2 = append(vars2, varUse.varname)
+ })
c.Check(vars2, deepEquals, []string{"SED"})
- vars3 := mklines.mklines[2].DetermineUsedVariables()
+ var vars3 []string
+ mklines.mklines[2].ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ vars3 = append(vars3, varUse.varname)
+ })
// qore-version, despite its unusual name, is a pretty normal Make variable.
c.Check(vars3, deepEquals, []string{"qore-version"})
@@ -365,7 +371,6 @@ func (s *Suite) Test_MkLines_collectUsed
mklines := t.NewMkLines("filename.mk",
"\t${VAR}")
mkline := mklines.mklines[0]
- G.Mk = mklines
mklines.collectUsedVariables()
@@ -385,7 +390,6 @@ func (s *Suite) Test_MkLines_collectUsed
"\t${outer.${inner}}")
assignMkline := mklines.mklines[2]
shellMkline := mklines.mklines[5]
- G.Mk = mklines
mklines.collectUsedVariables()
@@ -876,14 +880,14 @@ func (s *Suite) Test_MkLines_Check__MAST
t.SetUpMasterSite("MASTER_SITE_GITHUB", "https://github.com/")
t.SetUpVartypes()
- G.Mk = t.NewMkLines("devel/catch/Makefile",
+ mklines := t.NewMkLines("devel/catch/Makefile",
MkRcsID,
"HOMEPAGE=\t${MASTER_SITE_GITHUB:=philsquared/Catch/}",
"HOMEPAGE=\t${MASTER_SITE_GITHUB}",
"HOMEPAGE=\t${MASTER_SITES}",
"HOMEPAGE=\t${MASTER_SITES}${GITHUB_PROJECT}")
- G.Mk.Check()
+ mklines.Check()
t.CheckOutputLines(
"WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. "+
@@ -931,7 +935,7 @@ func (s *Suite) Test_MkLines_Check__extr
t.SetUpCommandLine("-Wextra")
t.SetUpVartypes()
G.Pkg = NewPackage(t.File("category/pkgbase"))
- G.Mk = t.NewMkLines("options.mk",
+ mklines := t.NewMkLines("options.mk",
MkRcsID,
"",
".for word in ${PKG_FAIL_REASON}",
@@ -944,7 +948,7 @@ func (s *Suite) Test_MkLines_Check__extr
"CONDITIONAL=\"@comment\"",
"BUILD_DIRS=\t${WRKSRC}/../build")
- G.Mk.Check()
+ mklines.Check()
t.CheckOutputLines(
"NOTE: options.mk:5: Please use \"# empty\", \"# none\" or \"# yes\" instead of \"# defined\".",
Index: pkgsrc/pkgtools/pkglint/files/mkparser.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser.go:1.25 pkgsrc/pkgtools/pkglint/files/mkparser.go:1.26
--- pkgsrc/pkgtools/pkglint/files/mkparser.go:1.25 Sun Mar 10 19:01:50 2019
+++ pkgsrc/pkgtools/pkglint/files/mkparser.go Wed Apr 3 21:49:51 2019
@@ -603,7 +603,7 @@ func (p *MkParser) PkgbasePattern() stri
for {
if p.VarUse() != nil ||
lexer.SkipRegexp(G.res.Compile(`^[\w.*+,{}]+`)) ||
- lexer.SkipRegexp(G.res.Compile(`^\[[\d-]+\]`)) {
+ lexer.SkipRegexp(G.res.Compile(`^\[[\w-]+\]`)) {
continue
}
@@ -633,6 +633,7 @@ type DependencyPattern struct {
Wildcard string // "[0-9]*", "1.5.*", "${PYVER}"
}
+// Dependency parses a dependency pattern like "pkg>=1<2" or "pkg-[0-9]*".
func (p *MkParser) Dependency() *DependencyPattern {
lexer := p.lexer
Index: pkgsrc/pkgtools/pkglint/files/mkparser_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.25 pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.26
--- pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.25 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mkparser_test.go Wed Apr 3 21:49:51 2019
@@ -679,9 +679,8 @@ func (s *Suite) Test_MkParser_PkgbasePat
// as a version number.
testRest("pkgbase-${PKGNAME:C/^.*-//}-[0-9]*", "pkgbase", "-${PKGNAME:C/^.*-//}-[0-9]*")
- // Using the [a-z] pattern in the package base is not seen in the wild.
- // Therefore this rather strange parsing result is ok.
- testRest("pkgbase-[a-z]-1.0", "pkgbase-", "[a-z]-1.0")
+ // Using the [a-z] pattern in the package base is only rarely seen in the wild.
+ testRest("pkgbase-[a-z]*-1.0", "pkgbase-[a-z]*", "-1.0")
// This is a valid dependency pattern, but it's more complicated
// than the patterns pkglint can handle as of January 2019.
Index: pkgsrc/pkgtools/pkglint/files/util_test.go
diff -u pkgsrc/pkgtools/pkglint/files/util_test.go:1.25 pkgsrc/pkgtools/pkglint/files/util_test.go:1.26
--- pkgsrc/pkgtools/pkglint/files/util_test.go:1.25 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/util_test.go Wed Apr 3 21:49:51 2019
@@ -373,7 +373,8 @@ func (s *Suite) Test_Scope_Used(c *check
t := s.Init(c)
scope := NewScope()
- scope.Use("VAR.param", t.NewMkLine("file.mk", 1, "\techo ${VAR.param}"))
+ mkline := t.NewMkLine("file.mk", 1, "\techo ${VAR.param}")
+ scope.Use("VAR.param", mkline, vucTimeRun)
c.Check(scope.Used("VAR.param"), equals, true)
c.Check(scope.Used("VAR.other"), equals, false)
Index: pkgsrc/pkgtools/pkglint/files/mktypes.go
diff -u pkgsrc/pkgtools/pkglint/files/mktypes.go:1.12 pkgsrc/pkgtools/pkglint/files/mktypes.go:1.13
--- pkgsrc/pkgtools/pkglint/files/mktypes.go:1.12 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mktypes.go Wed Apr 3 21:49:51 2019
@@ -137,6 +137,39 @@ func (m MkVarUseModifier) MatchMatch() (
func (m MkVarUseModifier) IsToLower() bool { return m.Text == "tl" }
+// ChangesWords returns true if applying this modifier to a list variable
+// may change the number of words in the list, or their boundaries.
+func (m MkVarUseModifier) ChangesWords() bool {
+ text := m.Text
+
+ // See MkParser.VarUseModifiers for the meaning of these modifiers.
+ switch text[0] {
+
+ case 'E', 'H', 'M', 'N', 'O', 'R', 'T':
+ return false
+
+ case 'C', 'Q', 'S':
+ // For the :C and :S modifiers, a more detailed analysis could reveal
+ // cases that don't change the structure, such as :S,a,b,g or
+ // :C,[0-9A-Za-z_],.,g, but not :C,x,,g.
+ return true
+ }
+
+ switch text {
+
+ case "tl", "tu":
+ return false
+
+ case "sh", "tW", "tw":
+ return true
+ }
+
+ // If in doubt, be pessimistic. As of March 2019, the only code that
+ // actually uses this function doesn't issue a possibly wrong warning
+ // in such a case.
+ return true
+}
+
func (vu *MkVarUse) Mod() string {
var mod strings.Builder
for _, modifier := range vu.modifiers {
Index: pkgsrc/pkgtools/pkglint/files/mktypes_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mktypes_test.go:1.8 pkgsrc/pkgtools/pkglint/files/mktypes_test.go:1.9
--- pkgsrc/pkgtools/pkglint/files/mktypes_test.go:1.8 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/mktypes_test.go Wed Apr 3 21:49:51 2019
@@ -28,6 +28,46 @@ func (list *MkShList) AddCommand(command
return list.AddAndOr(andOr)
}
+func (s *Suite) Test_MkVarUseModifier_ChangesWords(c *check.C) {
+ t := s.Init(c)
+
+ test := func(modifier string, changes bool) {
+ mod := MkVarUseModifier{modifier}
+ t.Check(mod.ChangesWords(), equals, changes)
+ }
+
+ test("E", false)
+ test("R", false)
+ test("Mpattern", false)
+ test("Npattern", false)
+ test("S,from,to,", true)
+ test("C,from,to,", true)
+ test("tl", false)
+ test("tu", false)
+ test("sh", true)
+
+ test("unknown", true)
+}
+
+// Ensures that ChangesWords cannot be called with an empty string as modifier.
+func (s *Suite) Test_MkVarUseModifier_ChangesWords__empty(c *check.C) {
+ t := s.Init(c)
+
+ mkline := t.NewMkLine("filename.mk", 123, "\t${VAR:}")
+
+ n := 0
+ mkline.ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ n += 100
+ for _, mod := range varUse.modifiers {
+ mod.ChangesWords()
+ n++
+ }
+ })
+
+ t.CheckOutputEmpty()
+ t.Check(n, equals, 100)
+}
+
func (s *Suite) Test_MkVarUseModifier_MatchSubst(c *check.C) {
mod := MkVarUseModifier{"S/from/to/1g"}
Index: pkgsrc/pkgtools/pkglint/files/package.go
diff -u pkgsrc/pkgtools/pkglint/files/package.go:1.48 pkgsrc/pkgtools/pkglint/files/package.go:1.49
--- pkgsrc/pkgtools/pkglint/files/package.go:1.48 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/package.go Wed Apr 3 21:49:51 2019
@@ -94,7 +94,7 @@ func NewPackage(dir string) *Package {
// as resolved from the package's directory.
// Variables that are known in the package are resolved, e.g. ${PKGDIR}.
func (pkg *Package) File(relativeFileName string) string {
- return cleanpath(resolveVariableRefs(pkg.dir + "/" + relativeFileName))
+ return cleanpath(resolveVariableRefs(nil, pkg.dir+"/"+relativeFileName))
}
func (pkg *Package) checkPossibleDowngrade() {
@@ -288,11 +288,11 @@ func (pkg *Package) loadPackageMakefile(
pkg.Patchdir = pkg.vars.LastValue("PATCHDIR")
// See lang/php/ext.mk
- if varIsDefinedSimilar(pkg, nil, "PHPEXT_MK") {
- if !varIsDefinedSimilar(pkg, nil, "USE_PHP_EXT_PATCHES") {
+ if pkg.vars.DefinedSimilar("PHPEXT_MK") {
+ if !pkg.vars.DefinedSimilar("USE_PHP_EXT_PATCHES") {
pkg.Patchdir = "patches"
}
- if varIsDefinedSimilar(pkg, nil, "PECL_VERSION") {
+ if pkg.vars.DefinedSimilar("PECL_VERSION") {
pkg.DistinfoFile = "distinfo"
} else {
pkg.IgnoreMissingPatches = true
@@ -495,7 +495,7 @@ func (pkg *Package) findIncludedFile(mkl
// TODO: resolveVariableRefs uses G.Pkg implicitly. It should be made explicit.
// TODO: Try to combine resolveVariableRefs and ResolveVarsInRelativePath.
- includedFile = resolveVariableRefs(mkline.ResolveVarsInRelativePath(mkline.IncludedFile()))
+ includedFile = resolveVariableRefs(nil, mkline.ResolveVarsInRelativePath(mkline.IncludedFile()))
if containsVarRef(includedFile) {
if trace.Tracing && !contains(includingFilename, "/mk/") {
trace.Stepf("%s:%s: Skipping include file %q. This may result in false warnings.",
Index: pkgsrc/pkgtools/pkglint/files/package_test.go
diff -u pkgsrc/pkgtools/pkglint/files/package_test.go:1.41 pkgsrc/pkgtools/pkglint/files/package_test.go:1.42
--- pkgsrc/pkgtools/pkglint/files/package_test.go:1.41 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/package_test.go Wed Apr 3 21:49:51 2019
@@ -560,12 +560,20 @@ func (s *Suite) Test_Package__varuse_at_
G.Check(t.File("category/pkgbase"))
t.CheckOutputLines(
+ "NOTE: ~/category/pkgbase/Makefile:14: Consider the :sh modifier instead of != for \"echo false=${FALSE:Q}\".",
"WARN: ~/category/pkgbase/Makefile:14: To use the tool ${FALSE} at load time, bsd.prefs.mk has to be included before.",
- // TODO: "before including bsd.prefs.mk in line ###".
+ "NOTE: ~/category/pkgbase/Makefile:15: Consider the :sh modifier instead of != for \"echo nice=${NICE:Q}\".",
+
+ // TODO: replace "at load time" with "before including bsd.prefs.mk in line ###".
// TODO: ${NICE} could be used at load time if it were added to USE_TOOLS earlier.
"WARN: ~/category/pkgbase/Makefile:15: The tool ${NICE} cannot be used at load time.",
+
+ "NOTE: ~/category/pkgbase/Makefile:16: Consider the :sh modifier instead of != for \"echo true=${TRUE:Q}\".",
"WARN: ~/category/pkgbase/Makefile:16: To use the tool ${TRUE} at load time, bsd.prefs.mk has to be included before.",
- "WARN: ~/category/pkgbase/Makefile:25: The tool ${NICE} cannot be used at load time.")
+ "NOTE: ~/category/pkgbase/Makefile:24: Consider the :sh modifier instead of != for \"echo false=${FALSE:Q}\".",
+ "NOTE: ~/category/pkgbase/Makefile:25: Consider the :sh modifier instead of != for \"echo nice=${NICE:Q}\".",
+ "WARN: ~/category/pkgbase/Makefile:25: The tool ${NICE} cannot be used at load time.",
+ "NOTE: ~/category/pkgbase/Makefile:26: Consider the :sh modifier instead of != for \"echo true=${TRUE:Q}\".")
}
func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) {
Index: pkgsrc/pkgtools/pkglint/files/pkglint_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.35 pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.36
--- pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.35 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/pkglint_test.go Wed Apr 3 21:49:51 2019
@@ -425,7 +425,7 @@ func (s *Suite) Test_resolveVariableRefs
// TODO: It may be better to define MkLines.Resolve and Package.Resolve,
// to clearly state the scope of the involved variables.
- resolved := resolveVariableRefs("gcc-${GCC_VERSION}")
+ resolved := resolveVariableRefs(nil, "gcc-${GCC_VERSION}")
c.Check(resolved, equals, "gcc-${GCC_VERSION}")
}
@@ -437,14 +437,14 @@ func (s *Suite) Test_resolveVariableRefs
mkline2 := t.NewMkLine("filename.mk", 11, "SECOND=\t${THIRD}")
mkline3 := t.NewMkLine("filename.mk", 12, "THIRD=\tgot it")
G.Pkg = NewPackage(t.File("category/pkgbase"))
- defineVar(G.Pkg, nil, mkline1, "FIRST")
- defineVar(G.Pkg, nil, mkline2, "SECOND")
- defineVar(G.Pkg, nil, mkline3, "THIRD")
+ G.Pkg.vars.Define("FIRST", mkline1)
+ G.Pkg.vars.Define("SECOND", mkline2)
+ G.Pkg.vars.Define("THIRD", mkline3)
// TODO: Add a similar test in which some of the variables are defined
// conditionally or with differing values, just to see what pkglint does
// in such a case.
- resolved := resolveVariableRefs("you ${FIRST}")
+ resolved := resolveVariableRefs(nil, "you ${FIRST}")
c.Check(resolved, equals, "you got it")
}
@@ -459,7 +459,7 @@ func (s *Suite) Test_resolveVariableRefs
G.Pkg = NewPackage(t.File("category/pkg"))
G.Pkg.vars.Define("GST_PLUGINS0.10_TYPE", mkline)
- resolved := resolveVariableRefs("gst-plugins0.10-${GST_PLUGINS0.10_TYPE}/distinfo")
+ resolved := resolveVariableRefs(nil, "gst-plugins0.10-${GST_PLUGINS0.10_TYPE}/distinfo")
c.Check(resolved, equals, "gst-plugins0.10-x11/distinfo")
}
@@ -631,15 +631,15 @@ func (s *Suite) Test_Pkglint_Tool__prefe
t := s.Init(c)
mkline := t.NewMkLine("dummy.mk", 123, "DUMMY=\tvalue")
- G.Mk = t.NewMkLines("Makefile", MkRcsID)
+ mklines := t.NewMkLines("Makefile", MkRcsID)
global := G.Pkgsrc.Tools.Define("tool", "TOOL", mkline)
- local := G.Mk.Tools.Define("tool", "TOOL", mkline)
+ local := mklines.Tools.Define("tool", "TOOL", mkline)
global.Validity = Nowhere
local.Validity = AtRunTime
- loadTimeTool, loadTimeUsable := G.Tool("tool", LoadTime)
- runTimeTool, runTimeUsable := G.Tool("tool", RunTime)
+ loadTimeTool, loadTimeUsable := G.Tool(mklines, "tool", LoadTime)
+ runTimeTool, runTimeUsable := G.Tool(mklines, "tool", RunTime)
c.Check(loadTimeTool, equals, local)
c.Check(loadTimeUsable, equals, false)
@@ -650,11 +650,11 @@ func (s *Suite) Test_Pkglint_Tool__prefe
func (s *Suite) Test_Pkglint_Tool__lookup_by_name_fallback(c *check.C) {
t := s.Init(c)
- G.Mk = t.NewMkLines("Makefile", MkRcsID)
+ mklines := t.NewMkLines("Makefile", MkRcsID)
t.SetUpTool("tool", "", Nowhere)
- loadTimeTool, loadTimeUsable := G.Tool("tool", LoadTime)
- runTimeTool, runTimeUsable := G.Tool("tool", RunTime)
+ loadTimeTool, loadTimeUsable := G.Tool(mklines, "tool", LoadTime)
+ runTimeTool, runTimeUsable := G.Tool(mklines, "tool", RunTime)
// The tool is returned even though it may not be used at the moment.
// The calling code must explicitly check for usability.
@@ -670,15 +670,15 @@ func (s *Suite) Test_Pkglint_Tool__looku
t := s.Init(c)
mkline := t.NewMkLine("dummy.mk", 123, "DUMMY=\tvalue")
- G.Mk = t.NewMkLines("Makefile", MkRcsID)
+ mklines := t.NewMkLines("Makefile", MkRcsID)
global := G.Pkgsrc.Tools.Define("tool", "TOOL", mkline)
- local := G.Mk.Tools.Define("tool", "TOOL", mkline)
+ local := mklines.Tools.Define("tool", "TOOL", mkline)
global.Validity = Nowhere
local.Validity = AtRunTime
- loadTimeTool, loadTimeUsable := G.Tool("${TOOL}", LoadTime)
- runTimeTool, runTimeUsable := G.Tool("${TOOL}", RunTime)
+ loadTimeTool, loadTimeUsable := G.Tool(mklines, "${TOOL}", LoadTime)
+ runTimeTool, runTimeUsable := G.Tool(mklines, "${TOOL}", RunTime)
c.Check(loadTimeTool, equals, local)
c.Check(loadTimeUsable, equals, false)
@@ -690,11 +690,11 @@ func (s *Suite) Test_Pkglint_Tool__looku
func (s *Suite) Test_Pkglint_Tool__lookup_by_varname_fallback(c *check.C) {
t := s.Init(c)
- G.Mk = t.NewMkLines("Makefile", MkRcsID)
+ mklines := t.NewMkLines("Makefile", MkRcsID)
G.Pkgsrc.Tools.def("tool", "TOOL", false, Nowhere)
- loadTimeTool, loadTimeUsable := G.Tool("${TOOL}", LoadTime)
- runTimeTool, runTimeUsable := G.Tool("${TOOL}", RunTime)
+ loadTimeTool, loadTimeUsable := G.Tool(mklines, "${TOOL}", LoadTime)
+ runTimeTool, runTimeUsable := G.Tool(mklines, "${TOOL}", RunTime)
c.Check(loadTimeTool.String(), equals, "tool:TOOL::Nowhere")
c.Check(loadTimeUsable, equals, false)
@@ -706,11 +706,11 @@ func (s *Suite) Test_Pkglint_Tool__looku
func (s *Suite) Test_Pkglint_Tool__lookup_by_varname_fallback_runtime(c *check.C) {
t := s.Init(c)
- G.Mk = t.NewMkLines("Makefile", MkRcsID)
+ mklines := t.NewMkLines("Makefile", MkRcsID)
G.Pkgsrc.Tools.def("tool", "TOOL", false, AtRunTime)
- loadTimeTool, loadTimeUsable := G.Tool("${TOOL}", LoadTime)
- runTimeTool, runTimeUsable := G.Tool("${TOOL}", RunTime)
+ loadTimeTool, loadTimeUsable := G.Tool(mklines, "${TOOL}", LoadTime)
+ runTimeTool, runTimeUsable := G.Tool(mklines, "${TOOL}", RunTime)
c.Check(loadTimeTool.String(), equals, "tool:TOOL::AtRunTime")
c.Check(loadTimeUsable, equals, false)
@@ -722,23 +722,23 @@ func (s *Suite) Test_Pkglint_ToolByVarna
t := s.Init(c)
mkline := t.NewMkLine("dummy.mk", 123, "DUMMY=\tvalue")
- G.Mk = t.NewMkLines("Makefile", MkRcsID)
+ mklines := t.NewMkLines("Makefile", MkRcsID)
global := G.Pkgsrc.Tools.Define("tool", "TOOL", mkline)
- local := G.Mk.Tools.Define("tool", "TOOL", mkline)
+ local := mklines.Tools.Define("tool", "TOOL", mkline)
global.Validity = Nowhere
local.Validity = AtRunTime
- c.Check(G.ToolByVarname("TOOL"), equals, local)
+ c.Check(G.ToolByVarname(mklines, "TOOL"), equals, local)
}
func (s *Suite) Test_Pkglint_ToolByVarname(c *check.C) {
t := s.Init(c)
- G.Mk = t.NewMkLines("Makefile", MkRcsID)
+ mklines := t.NewMkLines("Makefile", MkRcsID)
G.Pkgsrc.Tools.def("tool", "TOOL", false, AtRunTime)
- c.Check(G.ToolByVarname("TOOL").String(), equals, "tool:TOOL::AtRunTime")
+ c.Check(G.ToolByVarname(mklines, "TOOL").String(), equals, "tool:TOOL::AtRunTime")
}
func (s *Suite) Test_Pkglint_checkReg__other(c *check.C) {
Index: pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.19 pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.20
--- pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.19 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go Wed Apr 3 21:49:51 2019
@@ -573,7 +573,7 @@ func (s *Suite) Test_Pkgsrc_VariableType
t.SetUpVartypes()
test := func(varname string, vartype string) {
- actualType := G.Pkgsrc.VariableType(varname)
+ actualType := G.Pkgsrc.VariableType(nil, varname)
if vartype == "" {
c.Check(actualType, check.IsNil)
} else {
@@ -602,12 +602,12 @@ func (s *Suite) Test_Pkgsrc_VariableType
t.SetUpVartypes()
- t1 := G.Pkgsrc.VariableType("FONT_DIRS")
+ t1 := G.Pkgsrc.VariableType(nil, "FONT_DIRS")
c.Assert(t1, check.NotNil)
c.Check(t1.String(), equals, "List of PathMask (guessed)")
- t2 := G.Pkgsrc.VariableType("FONT_DIRS.ttf")
+ t2 := G.Pkgsrc.VariableType(nil, "FONT_DIRS.ttf")
c.Assert(t2, check.NotNil)
c.Check(t2.String(), equals, "List of PathMask (guessed)")
@@ -638,15 +638,15 @@ func (s *Suite) Test_Pkgsrc_VariableType
G.Main("pkglint", "-Wall", pkg)
- if typ := G.Pkgsrc.VariableType("PKGSRC_MAKE_ENV"); c.Check(typ, check.NotNil) {
+ if typ := G.Pkgsrc.VariableType(nil, "PKGSRC_MAKE_ENV"); c.Check(typ, check.NotNil) {
c.Check(typ.String(), equals, "List of ShellWord (guessed)")
}
- if typ := G.Pkgsrc.VariableType("CPPPATH"); c.Check(typ, check.NotNil) {
+ if typ := G.Pkgsrc.VariableType(nil, "CPPPATH"); c.Check(typ, check.NotNil) {
c.Check(typ.String(), equals, "Pathlist (guessed)")
}
- if typ := G.Pkgsrc.VariableType("OSNAME.Other"); c.Check(typ, check.NotNil) {
+ if typ := G.Pkgsrc.VariableType(nil, "OSNAME.Other"); c.Check(typ, check.NotNil) {
c.Check(typ.String(), equals, "Unknown")
}
@@ -672,10 +672,15 @@ func (s *Suite) Test_Pkgsrc_guessVariabl
mklines.Check()
- // FIXME: The permissions in guessVariableType say allRuntime, which excludes
- // aclpUseLoadtime. Therefore there should be a warning about the VarUse in
- // the .if line.
- // The check in MkLineChecker.checkVarusePermissions is disabled for guessed types.
+ vartype := G.Pkgsrc.VariableType(mklines, "MY_CHECK_SKIP")
+ t.Check(vartype.guessed, equals, true)
+ t.Check(vartype.EffectivePermissions("filename.mk"), equals, aclpAllRuntime)
+
+ // The permissions for MY_CHECK_SKIP say aclpAllRuntime, which excludes
+ // aclpUseLoadtime. Therefore there should be a warning about the VarUse in
+ // the .if line. As of March 2019, pkglint skips the permissions check for
+ // guessed variables since that variable might have an entirely different
+ // meaning; see MkLineChecker.checkVarusePermissions.
//
// There is no warning for the += operator in line 3 since the variable type
// (although guessed) is a list of things, and lists may be appended to.
Index: pkgsrc/pkgtools/pkglint/files/redundantscope.go
diff -u pkgsrc/pkgtools/pkglint/files/redundantscope.go:1.2 pkgsrc/pkgtools/pkglint/files/redundantscope.go:1.3
--- pkgsrc/pkgtools/pkglint/files/redundantscope.go:1.2 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/redundantscope.go Wed Apr 3 21:49:51 2019
@@ -153,12 +153,13 @@ func (s *RedundantScope) handleVarassign
func (s *RedundantScope) handleVarUse(mkline MkLine) {
switch {
case mkline.IsVarassign():
- for _, varname := range mkline.DetermineUsedVariables() {
+ mkline.ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ varname := varUse.varname
info := s.get(varname)
info.vari.Read(mkline)
info.lastAction = 1
s.access(varname)
- }
+ })
case mkline.IsDirective():
// TODO: Handle varuse for conditions and loops.
Index: pkgsrc/pkgtools/pkglint/files/var.go
diff -u pkgsrc/pkgtools/pkglint/files/var.go:1.2 pkgsrc/pkgtools/pkglint/files/var.go:1.3
--- pkgsrc/pkgtools/pkglint/files/var.go:1.2 Sun Mar 10 19:01:50 2019
+++ pkgsrc/pkgtools/pkglint/files/var.go Wed Apr 3 21:49:51 2019
@@ -179,7 +179,9 @@ func (v *Var) Write(mkline MkLine, condi
}
v.conditionalVars.AddAll(conditionVarnames)
- v.refs.AddAll(mkline.DetermineUsedVariables())
+ mkline.ForEachUsed(func(varUse *MkVarUse, time vucTime) {
+ v.refs.Add(varUse.varname)
+ })
v.refs.AddAll(conditionVarnames)
v.update(mkline, &v.valueInfra)
Index: pkgsrc/pkgtools/pkglint/files/shell_test.go
diff -u pkgsrc/pkgtools/pkglint/files/shell_test.go:1.42 pkgsrc/pkgtools/pkglint/files/shell_test.go:1.43
--- pkgsrc/pkgtools/pkglint/files/shell_test.go:1.42 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/shell_test.go Wed Apr 3 21:49:51 2019
@@ -96,13 +96,6 @@ func (s *Suite) Test_splitIntoShellToken
c.Check(rest, equals, "")
}
-func (s *Suite) Test_splitIntoMkWords__semicolons(c *check.C) {
- words, rest := splitIntoMkWords(dummyLine, "word1 word2;;;")
-
- c.Check(words, deepEquals, []string{"word1", "word2;;;"})
- c.Check(rest, equals, "")
-}
-
func (s *Suite) Test_splitIntoShellTokens__varuse_with_embedded_space(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "${VAR:S/ /_/g}")
@@ -110,13 +103,6 @@ func (s *Suite) Test_splitIntoShellToken
c.Check(rest, equals, "")
}
-func (s *Suite) Test_splitIntoMkWords__varuse_with_embedded_space(c *check.C) {
- words, rest := splitIntoMkWords(dummyLine, "${VAR:S/ /_/g}")
-
- c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"})
- c.Check(rest, equals, "")
-}
-
func (s *Suite) Test_splitIntoShellTokens__redirect(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "echo 1>output 2>>append 3>|clobber 4>&5 6<input >>append")
@@ -154,11 +140,11 @@ func (s *Suite) Test_ShellLineChecker_Ch
t.SetUpTool("unzip", "UNZIP_CMD", AtRunTime)
test := func(shellCommand string, diagnostics ...string) {
- G.Mk = t.NewMkLines("filename.mk",
+ mklines := t.NewMkLines("filename.mk",
"\t"+shellCommand)
- ck := NewShellLineChecker(G.Mk.mklines[0])
+ ck := NewShellLineChecker(mklines, mklines.mklines[0])
- G.Mk.ForEach(func(mkline MkLine) {
+ mklines.ForEach(func(mkline MkLine) {
ck.CheckShellCommandLine(ck.mkline.ShellCommand())
})
@@ -276,11 +262,11 @@ func (s *Suite) Test_ShellLineChecker_Ch
t := s.Init(c)
test := func(shellCommand string) {
- G.Mk = t.NewMkLines("filename.mk",
+ mklines := t.NewMkLines("filename.mk",
"\t"+shellCommand)
- G.Mk.ForEach(func(mkline MkLine) {
- ck := NewShellLineChecker(mkline)
+ mklines.ForEach(func(mkline MkLine) {
+ ck := NewShellLineChecker(mklines, mkline)
ck.CheckShellCommandLine(mkline.ShellCommand())
})
}
@@ -303,9 +289,9 @@ func (s *Suite) Test_ShellLineChecker_Ch
t.SetUpVartypes()
t.SetUpTool("echo", "", AtRunTime)
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
"\techo ${PKGNAME:Q}")
- ck := NewShellLineChecker(G.Mk.mklines[0])
+ ck := NewShellLineChecker(mklines, mklines.mklines[0])
ck.CheckShellCommandLine("echo ${PKGNAME:Q}")
@@ -319,9 +305,9 @@ func (s *Suite) Test_ShellLineChecker_Ch
t.SetUpCommandLine("-Wall", "--show-autofix")
t.SetUpVartypes()
t.SetUpTool("echo", "", AtRunTime)
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
"\techo ${PKGNAME:Q}")
- ck := NewShellLineChecker(G.Mk.mklines[0])
+ ck := NewShellLineChecker(mklines, mklines.mklines[0])
ck.CheckShellCommandLine("echo ${PKGNAME:Q}")
@@ -336,9 +322,9 @@ func (s *Suite) Test_ShellLineChecker_Ch
t.SetUpCommandLine("-Wall", "--autofix")
t.SetUpVartypes()
t.SetUpTool("echo", "", AtRunTime)
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
"\techo ${PKGNAME:Q}")
- ck := NewShellLineChecker(G.Mk.mklines[0])
+ ck := NewShellLineChecker(mklines, mklines.mklines[0])
ck.CheckShellCommandLine("echo ${PKGNAME:Q}")
@@ -358,7 +344,7 @@ func (s *Suite) Test_ShellProgramChecker
t.SetUpTool("printf", "", AtRunTime)
t.SetUpTool("sed", "", AtRunTime)
t.SetUpTool("right-side", "", AtRunTime)
- G.Mk = t.NewMkLines("Makefile",
+ mklines := t.NewMkLines("Makefile",
"\t echo | right-side",
"\t sed s,s,s, | right-side",
"\t printf | sed s,s,s, | right-side ",
@@ -371,8 +357,8 @@ func (s *Suite) Test_ShellProgramChecker
"\t var=value | right-side",
"\t if :; then :; fi | right-side")
- for _, mkline := range G.Mk.mklines {
- ck := NewShellLineChecker(mkline)
+ for _, mkline := range mklines.mklines {
+ ck := NewShellLineChecker(mklines, mkline)
ck.CheckShellCommandLine(mkline.ShellCommand())
}
@@ -391,9 +377,9 @@ func (s *Suite) Test_ShellLineChecker_Ch
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("filename.mk",
+ mklines := t.NewMkLines("filename.mk",
"# dummy")
- ck := NewShellLineChecker(G.Mk.mklines[0])
+ ck := NewShellLineChecker(mklines, mklines.mklines[0])
// foobar="`echo \"foo bar\"`"
text := "foobar=\"`echo \\\"foo bar\\\"`\""
@@ -403,12 +389,12 @@ func (s *Suite) Test_ShellLineChecker_Ch
c.Check(tokens, deepEquals, []string{text})
c.Check(rest, equals, "")
- G.Mk.ForEach(func(mkline MkLine) { ck.CheckWord(text, false, RunTime) })
+ mklines.ForEach(func(mkline MkLine) { ck.CheckWord(text, false, RunTime) })
t.CheckOutputLines(
"WARN: filename.mk:1: Unknown shell command \"echo\".")
- G.Mk.ForEach(func(mkline MkLine) { ck.CheckShellCommandLine(text) })
+ mklines.ForEach(func(mkline MkLine) { ck.CheckShellCommandLine(text) })
// No parse errors
t.CheckOutputLines(
@@ -420,9 +406,9 @@ func (s *Suite) Test_ShellLineChecker_Ch
t.SetUpVartypes()
t.SetUpTool("pax", "", AtRunTime)
- G.Mk = t.NewMkLines("filename.mk",
+ mklines := t.NewMkLines("filename.mk",
"# dummy")
- ck := NewShellLineChecker(G.Mk.mklines[0])
+ ck := NewShellLineChecker(mklines, mklines.mklines[0])
ck.CheckShellCommandLine("pax -rwpp -s /.*~$$//g . ${DESTDIR}${PREFIX}")
@@ -435,13 +421,11 @@ func (s *Suite) Test_ShellLineChecker_Ch
t.SetUpVartypes()
test := func(shellWord string, checkQuoting bool) {
- ck := t.NewShellLineChecker("dummy.mk", 1, "\t echo "+shellWord)
-
// Provide a storage for the "used but not defined" warnings.
// See checkVaruseUndefined and checkVarassignLeftNotUsed.
- G.Mk = NewMkLines(NewLines("dummy.mk", nil))
- defer func() { G.Mk = nil }()
+ mklines := NewMkLines(NewLines("dummy.mk", nil))
+ ck := t.NewShellLineChecker(mklines, "dummy.mk", 1, "\t echo "+shellWord)
ck.CheckWord(shellWord, checkQuoting, RunTime)
}
@@ -506,7 +490,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
func (s *Suite) Test_ShellLineChecker_CheckWord__dollar_without_variable(c *check.C) {
t := s.Init(c)
- ck := t.NewShellLineChecker("filename.mk", 1, "# dummy")
+ ck := t.NewShellLineChecker(nil, "filename.mk", 1, "# dummy")
ck.CheckWord("/.*~$$//g", false, RunTime) // Typical argument to pax(1).
@@ -517,7 +501,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
t := s.Init(c)
t.SetUpTool("find", "FIND", AtRunTime)
- ck := t.NewShellLineChecker("filename.mk", 1, "\tfind . -exec rm -rf {} \\+")
+ ck := t.NewShellLineChecker(nil, "filename.mk", 1, "\tfind . -exec rm -rf {} \\+")
ck.CheckShellCommandLine(ck.mkline.ShellCommand())
@@ -528,7 +512,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
func (s *Suite) Test_ShellLineChecker_CheckWord__squot_dollar(c *check.C) {
t := s.Init(c)
- ck := t.NewShellLineChecker("filename.mk", 1, "\t'$")
+ ck := t.NewShellLineChecker(nil, "filename.mk", 1, "\t'$")
ck.CheckWord(ck.mkline.ShellCommand(), false, RunTime)
@@ -542,7 +526,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
func (s *Suite) Test_ShellLineChecker_CheckWord__dquot_dollar(c *check.C) {
t := s.Init(c)
- ck := t.NewShellLineChecker("filename.mk", 1, "\t\"$")
+ ck := t.NewShellLineChecker(nil, "filename.mk", 1, "\t\"$")
ck.CheckWord(ck.mkline.ShellCommand(), false, RunTime)
@@ -554,7 +538,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
func (s *Suite) Test_ShellLineChecker_CheckWord__dollar_subshell(c *check.C) {
t := s.Init(c)
- ck := t.NewShellLineChecker("filename.mk", 1, "\t$$(echo output)")
+ ck := t.NewShellLineChecker(nil, "filename.mk", 1, "\t$$(echo output)")
ck.CheckWord(ck.mkline.ShellCommand(), false, RunTime)
@@ -566,12 +550,12 @@ func (s *Suite) Test_ShellLineChecker_Ch
t := s.Init(c)
t.SetUpVartypes()
- G.Mk = t.NewMkLines("chat/ircII/Makefile",
+ mklines := t.NewMkLines("chat/ircII/Makefile",
MkRcsID,
"CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/man",
"CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/${PKGMANDIR}")
- G.Mk.Check()
+ mklines.Check()
t.CheckOutputLines(
"WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".",
@@ -608,7 +592,7 @@ func (s *Suite) Test_ShellLineChecker_un
// direct, forcing test is only to reach the code coverage.
atoms := []*ShAtom{
NewShAtom(shtText, "`", shqBackt)}
- NewShellLineChecker(mkline).
+ NewShellLineChecker(nil, mkline).
unescapeBackticks(&atoms, shqBackt)
t.CheckOutputLines(
@@ -674,15 +658,15 @@ func (s *Suite) Test_ShellLineChecker_Ch
echo := t.SetUpTool("echo", "ECHO", AtRunTime)
echo.MustUseVarForm = true
- G.Mk = t.NewMkLines("filename.mk",
+ mklines := t.NewMkLines("filename.mk",
"# dummy")
mkline := t.NewMkLine("filename.mk", 3, "# dummy")
- MkLineChecker{mkline}.checkText("echo \"hello, world\"")
+ MkLineChecker{mklines, mkline}.checkText("echo \"hello, world\"")
t.CheckOutputEmpty()
- NewShellLineChecker(mkline).CheckShellCommandLine("echo \"hello, world\"")
+ NewShellLineChecker(mklines, mkline).CheckShellCommandLine("echo \"hello, world\"")
t.CheckOutputLines(
"WARN: filename.mk:3: Please use \"${ECHO}\" instead of \"echo\".")
@@ -698,7 +682,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
t.SetUpTool("sed", "SED", AtRunTime)
text := "\tfor f in *.pl; do ${SED} s,@PREFIX@,${PREFIX}, < $f > $f.tmp && ${MV} $f.tmp $f; done"
- ck := t.NewShellLineChecker("Makefile", 3, text)
+ ck := t.NewShellLineChecker(nil, "Makefile", 3, text)
ck.mkline.Tokenize(ck.mkline.ShellCommand(), true)
ck.CheckShellCommandLine(text)
@@ -723,11 +707,11 @@ func (s *Suite) Test_ShellLineChecker_Ch
func (s *Suite) Test_ShellLineChecker_checkInstallCommand(c *check.C) {
t := s.Init(c)
- G.Mk = t.NewMkLines("filename.mk",
+ mklines := t.NewMkLines("filename.mk",
"# dummy")
- G.Mk.target = "do-install"
+ mklines.target = "do-install"
- ck := t.NewShellLineChecker("filename.mk", 1, "\tdummy")
+ ck := t.NewShellLineChecker(mklines, "filename.mk", 1, "\tdummy")
ck.checkInstallCommand("sed")
@@ -740,38 +724,13 @@ func (s *Suite) Test_ShellLineChecker_ch
"WARN: filename.mk:1: ${CP} should not be used to install files.")
}
-func (s *Suite) Test_splitIntoMkWords(c *check.C) {
- url := "http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file="
-
- words, rest := splitIntoShellTokens(dummyLine, url) // Doesn't really make sense
-
- c.Check(words, check.DeepEquals, []string{
- "http://registry.gimp.org/file/fix-ca.c?action=download",
- "&",
- "id=9884",
- "&",
- "file="})
- c.Check(rest, equals, "")
-
- words, rest = splitIntoMkWords(dummyLine, url)
-
- c.Check(words, check.DeepEquals, []string{
- "http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file="})
- c.Check(rest, equals, "")
-
- words, rest = splitIntoMkWords(dummyLine, "a b \"c c c\" d;;d;; \"e\"''`` 'rest")
-
- c.Check(words, check.DeepEquals, []string{"a", "b", "\"c c c\"", "d;;d;;", "\"e\"''``"})
- c.Check(rest, equals, "'rest")
-}
-
func (s *Suite) Test_ShellLineChecker_CheckShellCommandLine__sed_and_mv(c *check.C) {
t := s.Init(c)
t.SetUpVartypes()
t.SetUpTool("sed", "SED", AtRunTime)
t.SetUpTool("mv", "MV", AtRunTime)
- ck := t.NewShellLineChecker("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' filename > filename.tmp; ${MV} filename.tmp filename")
+ ck := t.NewShellLineChecker(nil, "Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' filename > filename.tmp; ${MV} filename.tmp filename")
ck.CheckShellCommandLine(ck.mkline.ShellCommand())
@@ -782,7 +741,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
func (s *Suite) Test_ShellLineChecker_CheckShellCommandLine__subshell(c *check.C) {
t := s.Init(c)
- ck := t.NewShellLineChecker("Makefile", 85, "\t${RUN} uname=$$(uname)")
+ ck := t.NewShellLineChecker(nil, "Makefile", 85, "\t${RUN} uname=$$(uname)")
ck.CheckShellCommandLine(ck.mkline.ShellCommand())
@@ -794,7 +753,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
t := s.Init(c)
t.SetUpVartypes()
- ck := t.NewShellLineChecker("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
+ ck := t.NewShellLineChecker(nil, "Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
ck.CheckShellCommandLine(ck.mkline.ShellCommand())
@@ -821,7 +780,7 @@ func (s *Suite) Test_ShellLineChecker_Ch
t := s.Init(c)
t.SetUpVartypes()
- ck := t.NewShellLineChecker("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
+ ck := t.NewShellLineChecker(nil, "Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
ck.CheckShellCommandLine(ck.mkline.ShellCommand())
@@ -852,7 +811,7 @@ func (s *Suite) Test_ShellLineChecker_ch
t.SetUpTool("grep", "GREP", AtRunTime)
test := func(lineno int, input string) {
- ck := t.NewShellLineChecker("module.mk", lineno, "\t"+input)
+ ck := t.NewShellLineChecker(nil, "module.mk", lineno, "\t"+input)
ck.checkWordQuoting(ck.mkline.ShellCommand(), true, RunTime)
}
@@ -889,7 +848,7 @@ func (s *Suite) Test_ShellLineChecker_un
t := s.Init(c)
test := func(lineno int, input string, expectedOutput string, expectedRest string) {
- ck := t.NewShellLineChecker("dummy.mk", lineno, "# dummy")
+ ck := t.NewShellLineChecker(nil, "dummy.mk", lineno, "# dummy")
tok := NewShTokenizer(nil, input, false)
atoms := tok.ShAtoms()
@@ -958,7 +917,7 @@ func (s *Suite) Test_ShellLineChecker_un
t.SetUpTool("echo", "", AtRunTime)
mkline := t.NewMkLine("dummy.mk", 13, "\t var=\"`echo \"\"`\"")
- MkLineChecker{mkline}.Check()
+ MkLineChecker{nil, mkline}.Check()
t.CheckOutputLines(
"WARN: dummy.mk:13: Double quotes inside backticks inside double quotes are error prone.")
@@ -1143,7 +1102,7 @@ func (s *Suite) Test_SimpleCommandChecke
mkline := t.NewMkLine("file.mk", 3, "\t# comment; continuation")
- MkLineChecker{mkline}.Check()
+ MkLineChecker{nil, mkline}.Check()
t.CheckOutputLines(
"WARN: file.mk:3: A shell comment should not contain semicolons.")
Index: pkgsrc/pkgtools/pkglint/files/testnames_test.go
diff -u pkgsrc/pkgtools/pkglint/files/testnames_test.go:1.3 pkgsrc/pkgtools/pkglint/files/testnames_test.go:1.4
--- pkgsrc/pkgtools/pkglint/files/testnames_test.go:1.3 Mon Dec 17 00:15:39 2018
+++ pkgsrc/pkgtools/pkglint/files/testnames_test.go Wed Apr 3 21:49:51 2019
@@ -14,6 +14,7 @@ func (s *Suite) Test__test_names(c *chec
ck.AllowPrefix("Varalign", "mklines_varalign.go")
ck.AllowPrefix("ShellParser", "mkshparser.go")
ck.AllowCamelCaseDescriptions(
+ "compared_to_splitIntoShellTokens",
"comparing_YesNo_variable_to_string",
"enumFrom",
"enumFromDirs",
Index: pkgsrc/pkgtools/pkglint/files/util.go
diff -u pkgsrc/pkgtools/pkglint/files/util.go:1.40 pkgsrc/pkgtools/pkglint/files/util.go:1.41
--- pkgsrc/pkgtools/pkglint/files/util.go:1.40 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/util.go Wed Apr 3 21:49:51 2019
@@ -290,30 +290,6 @@ func varnameParam(varname string) string
return ""
}
-// defineVar marks a variable as defined in both the current package and the current file.
-func defineVar(pkg *Package, mklines MkLines, mkline MkLine, varname string) {
- if mklines != nil {
- mklines.vars.Define(varname, mkline)
- }
- if pkg != nil {
- pkg.vars.Define(varname, mkline)
- }
-}
-
-// varIsDefinedSimilar tests whether the variable (or its canonicalized form)
-// is defined in the current package or in the current file.
-func varIsDefinedSimilar(pkg *Package, mklines MkLines, varname string) bool {
- return mklines != nil && (mklines.vars.DefinedSimilar(varname) || mklines.forVars[varname]) ||
- pkg != nil && pkg.vars.DefinedSimilar(varname)
-}
-
-// varIsUsedSimilar tests whether the variable (or its canonicalized form)
-// is used in the current package or in the current file.
-func varIsUsedSimilar(pkg *Package, mklines MkLines, varname string) bool {
- return mklines != nil && mklines.vars.UsedSimilar(varname) ||
- pkg != nil && pkg.vars.UsedSimilar(varname)
-}
-
func fileExists(filename string) bool {
st, err := os.Stat(filename)
return err == nil && st.Mode().IsRegular()
@@ -507,11 +483,12 @@ func (o *Once) check(key uint64) bool {
// TODO: Merge this code with Var, which defines essentially the
// same features.
type Scope struct {
- firstDef map[string]MkLine // TODO: Can this be removed?
- lastDef map[string]MkLine
- value map[string]string
- used map[string]MkLine
- fallback map[string]string
+ firstDef map[string]MkLine // TODO: Can this be removed?
+ lastDef map[string]MkLine
+ value map[string]string
+ used map[string]MkLine
+ usedAtLoadTime map[string]bool
+ fallback map[string]string
}
func NewScope() Scope {
@@ -520,6 +497,7 @@ func NewScope() Scope {
make(map[string]MkLine),
make(map[string]string),
make(map[string]MkLine),
+ make(map[string]bool),
make(map[string]string)}
}
@@ -565,21 +543,21 @@ func (s *Scope) Fallback(varname string,
}
// Use marks the variable and its canonicalized form as used.
-func (s *Scope) Use(varname string, line MkLine) {
- if s.used[varname] == nil {
- s.used[varname] = line
- if trace.Tracing {
- trace.Step2("Using %q in %s", varname, line.String())
+func (s *Scope) Use(varname string, line MkLine, time vucTime) {
+ use := func(name string) {
+ if s.used[name] == nil {
+ s.used[name] = line
+ if trace.Tracing {
+ trace.Step2("Using %q in %s", name, line.String())
+ }
}
- }
-
- varcanon := varnameCanon(varname)
- if varcanon != varname && s.used[varcanon] == nil {
- s.used[varcanon] = line
- if trace.Tracing {
- trace.Step2("Using %q in %s", varcanon, line.String())
+ if time == vucTimeParse {
+ s.usedAtLoadTime[name] = true
}
}
+
+ use(varname)
+ use(varnameCanon(varname))
}
// Defined tests whether the variable is defined.
@@ -624,6 +602,12 @@ func (s *Scope) UsedSimilar(varname stri
return s.used[varnameCanon(varname)] != nil
}
+// UsedAtLoadTime returns true if the variable is used at load time
+// somewhere.
+func (s *Scope) UsedAtLoadTime(varname string) bool {
+ return s.usedAtLoadTime[varname]
+}
+
// FirstDefinition returns the line in which the variable has been defined first.
//
// Having multiple definitions is typical in the branches of "if" statements.
Index: pkgsrc/pkgtools/pkglint/files/vardefs.go
diff -u pkgsrc/pkgtools/pkglint/files/vardefs.go:1.57 pkgsrc/pkgtools/pkglint/files/vardefs.go:1.58
--- pkgsrc/pkgtools/pkglint/files/vardefs.go:1.57 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/vardefs.go Wed Apr 3 21:49:51 2019
@@ -1007,7 +1007,7 @@ func (reg *VarTypeRegistry) Init(src *Pk
sys("FAM_TYPE", enum("fam gamin"))
pkglist("FETCH_BEFORE_ARGS", BtShellWord)
pkglist("FETCH_MESSAGE", BtShellWord)
- pkg("FILESDIR", BtRelativePkgPath)
+ pkgload("FILESDIR", BtRelativePkgPath)
pkglist("FILES_SUBST", BtShellWord)
syslist("FILES_SUBST_SED", BtShellWord)
pkglist("FIX_RPATH", BtVariableName)
@@ -1220,7 +1220,7 @@ func (reg *VarTypeRegistry) Init(src *Pk
pkglist("OWN_DIRS_PERMS", BtPerms)
sys("PAMBASE", BtPathname)
usr("PAM_DEFAULT", enum("linux-pam openpam solaris-pam"))
- pkg("PATCHDIR", BtRelativePkgPath)
+ pkgload("PATCHDIR", BtRelativePkgPath)
pkglist("PATCHFILES", BtFileName)
pkglist("PATCH_ARGS", BtShellWord)
pkglist("PATCH_DIST_ARGS", BtShellWord)
Index: pkgsrc/pkgtools/pkglint/files/vardefs_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vardefs_test.go:1.11 pkgsrc/pkgtools/pkglint/files/vardefs_test.go:1.12
--- pkgsrc/pkgtools/pkglint/files/vardefs_test.go:1.11 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/vardefs_test.go Wed Apr 3 21:49:51 2019
@@ -6,7 +6,7 @@ func (s *Suite) Test_VarTypeRegistry_Ini
t := s.Init(c)
src := NewPkgsrc(t.File("."))
- src.vartypes.Init(src)
+ src.vartypes.Init(&src)
c.Check(src.vartypes.Canon("BSD_MAKE_ENV").basicType.name, equals, "ShellWord")
c.Check(src.vartypes.Canon("USE_BUILTIN.*").basicType.name, equals, "YesNoIndirectly")
@@ -48,7 +48,7 @@ func (s *Suite) Test_VarTypeRegistry_Ini
t.SetUpVartypes()
test := func(varname, values string) {
- vartype := G.Pkgsrc.VariableType(varname).String()
+ vartype := G.Pkgsrc.VariableType(nil, varname).String()
c.Check(vartype, equals, values)
}
@@ -70,7 +70,7 @@ func (s *Suite) Test_VarTypeRegistry_Ini
t.SetUpVartypes()
test := func(varname, values string) {
- vartype := G.Pkgsrc.VariableType(varname).String()
+ vartype := G.Pkgsrc.VariableType(nil, varname).String()
c.Check(vartype, equals, values)
}
Index: pkgsrc/pkgtools/pkglint/files/vartype_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vartype_test.go:1.16 pkgsrc/pkgtools/pkglint/files/vartype_test.go:1.17
--- pkgsrc/pkgtools/pkglint/files/vartype_test.go:1.16 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/vartype_test.go Wed Apr 3 21:49:51 2019
@@ -156,8 +156,8 @@ func (s *Suite) Test_Vartype_IsConsidere
t.SetUpVartypes()
- c.Check(G.Pkgsrc.VariableType("COMMENT").IsConsideredList(), equals, false)
- c.Check(G.Pkgsrc.VariableType("DEPENDS").IsConsideredList(), equals, true)
- c.Check(G.Pkgsrc.VariableType("PKG_FAIL_REASON").IsConsideredList(), equals, true)
- c.Check(G.Pkgsrc.VariableType("CONF_FILES").IsConsideredList(), equals, true)
+ c.Check(G.Pkgsrc.VariableType(nil, "COMMENT").IsConsideredList(), equals, false)
+ c.Check(G.Pkgsrc.VariableType(nil, "DEPENDS").IsConsideredList(), equals, true)
+ c.Check(G.Pkgsrc.VariableType(nil, "PKG_FAIL_REASON").IsConsideredList(), equals, true)
+ c.Check(G.Pkgsrc.VariableType(nil, "CONF_FILES").IsConsideredList(), equals, true)
}
Index: pkgsrc/pkgtools/pkglint/files/vartypecheck.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.52 pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.53
--- pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.52 Sun Mar 24 13:58:38 2019
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck.go Wed Apr 3 21:49:51 2019
@@ -8,6 +8,8 @@ import (
// VartypeCheck groups together the various checks for variables of the different types.
type VartypeCheck struct {
+ MkLines MkLines
+
// Note: if "go vet" or "go test" complains about a "variable with invalid type", update to go1.11.4.
// See https://github.com/golang/go/issues/28972.
// That doesn't help though since pkglint contains these "more convoluted alias declarations"
@@ -274,7 +276,7 @@ func (cv *VartypeCheck) Comment() {
// When a package is installed, the example file is installed as usual
// and is then copied to its final location.
func (cv *VartypeCheck) ConfFiles() {
- words, _ := splitIntoMkWords(cv.MkLine.Line, cv.Value)
+ words := cv.MkLine.ValueFields(cv.Value)
if len(words)%2 != 0 {
cv.Warnf("Values for %s should always be pairs of paths.", cv.Varname)
}
@@ -298,7 +300,9 @@ func (cv *VartypeCheck) Dependency() {
parser := NewMkParser(nil, value, false)
deppat := parser.Dependency()
- if deppat != nil && deppat.Wildcard == "" && (parser.Rest() == "{,nb*}" || parser.Rest() == "{,nb[0-9]*}") {
+ rest := parser.Rest()
+
+ if deppat != nil && deppat.Wildcard == "" && (rest == "{,nb*}" || rest == "{,nb[0-9]*}") {
cv.Warnf("Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.")
G.Explain(
"The \"{,nb*}\" extension is only necessary for dependencies of the",
@@ -307,12 +311,12 @@ func (cv *VartypeCheck) Dependency() {
"For dependency patterns using the comparison operators,",
"this is not necessary.")
- } else if deppat == nil && contains(value, "{") {
+ } else if deppat == nil && contains(cv.ValueNoVar, "{") {
// Don't warn about complicated patterns like "{ssh{,6}>=0,openssh>=0}"
// that pkglint doesn't understand as of January 2019.
return
- } else if deppat == nil || !parser.EOF() {
+ } else if deppat == nil || rest != "" {
cv.Warnf("Invalid dependency pattern %q.", value)
G.Explain(
"Typical dependencies have the following forms:",
@@ -377,12 +381,27 @@ func (cv *VartypeCheck) Dependency() {
func (cv *VartypeCheck) DependencyWithPath() {
value := cv.Value
- if value != cv.ValueNoVar {
- return // It's probably not worth checking this.
+ valueNoVar := cv.ValueNoVar
+
+ if valueNoVar == "" || valueNoVar == ":" {
+ return
}
- if m, pattern, relpath, pkg := match3(value, `(.*):(\.\./\.\./[^/]+/([^/]+))$`); m {
- MkLineChecker{cv.MkLine}.CheckRelativePkgdir(relpath)
+ parts := cv.MkLine.ValueSplit(value, ":")
+ if len(parts) == 2 {
+ pattern := parts[0]
+ relpath := parts[1]
+ pathParts := cv.MkLine.ValueSplit(relpath, "/")
+ pkg := pathParts[len(pathParts)-1]
+
+ if matches(relpath, `^\.\./[^.]`) {
+ cv.Warnf("Dependency paths should have the form \"../../category/package\".")
+ cv.MkLine.ExplainRelativeDirs()
+ }
+
+ if !containsVarRef(relpath) {
+ MkLineChecker{cv.MkLines, cv.MkLine}.CheckRelativePkgdir(relpath)
+ }
switch pkg {
case "gettext":
@@ -394,12 +413,7 @@ func (cv *VartypeCheck) DependencyWithPa
}
cv.WithValue(pattern).Dependency()
- return
- }
- if matches(value, `:\.\./[^/]+$`) {
- cv.Warnf("Dependencies should have the form \"../../category/package\".")
- cv.MkLine.ExplainRelativeDirs()
return
}
@@ -660,7 +674,7 @@ func (cv *VartypeCheck) LdFlag() {
}
func (cv *VartypeCheck) License() {
- (&LicenseChecker{cv.MkLine}).Check(cv.Value, cv.Op)
+ (&LicenseChecker{cv.MkLines, cv.MkLine}).Check(cv.Value, cv.Op)
}
func (cv *VartypeCheck) MachineGnuPlatform() {
@@ -748,7 +762,7 @@ func (cv *VartypeCheck) Option() {
}
if m, optname := match1(value, `^-?([a-z][-0-9a-z+]*)$`); m {
- if G.Mk != nil && !G.Mk.FirstTimeSlice("option:", optname) {
+ if cv.MkLines != nil && !cv.MkLines.FirstTimeSlice("option:", optname) {
return
}
@@ -879,7 +893,7 @@ func (cv *VartypeCheck) PkgOptionsVar()
// Despite its name, it is more similar to RelativePkgDir than to RelativePkgPath.
func (cv *VartypeCheck) PkgPath() {
pkgsrcdir := cv.MkLine.PathToFile(G.Pkgsrc.File("."))
- MkLineChecker{cv.MkLine}.CheckRelativePkgdir(pkgsrcdir + "/" + cv.Value)
+ MkLineChecker{cv.MkLines, cv.MkLine}.CheckRelativePkgdir(pkgsrcdir + "/" + cv.Value)
}
func (cv *VartypeCheck) PkgRevision() {
@@ -964,7 +978,7 @@ func (cv *VartypeCheck) PythonDependency
// RelativePkgDir refers to a package directory, e.g. ../../category/pkgbase.
func (cv *VartypeCheck) RelativePkgDir() {
- MkLineChecker{cv.MkLine}.CheckRelativePkgdir(cv.Value)
+ MkLineChecker{cv.MkLines, cv.MkLine}.CheckRelativePkgdir(cv.Value)
}
// RelativePkgPath refers to a file or directory, e.g. ../../category/pkgbase,
@@ -972,7 +986,7 @@ func (cv *VartypeCheck) RelativePkgDir()
//
// See RelativePkgDir, which requires a directory, not a file.
func (cv *VartypeCheck) RelativePkgPath() {
- MkLineChecker{cv.MkLine}.CheckRelativePath(cv.Value, true)
+ MkLineChecker{cv.MkLines, cv.MkLine}.CheckRelativePath(cv.Value, true)
}
func (cv *VartypeCheck) Restricted() {
@@ -1045,16 +1059,16 @@ func (cv *VartypeCheck) ShellCommand() {
return
}
setE := true
- NewShellLineChecker(cv.MkLine).CheckShellCommand(cv.Value, &setE, RunTime)
+ NewShellLineChecker(cv.MkLines, cv.MkLine).CheckShellCommand(cv.Value, &setE, RunTime)
}
// ShellCommands checks for zero or more shell commands, each terminated with a semicolon.
func (cv *VartypeCheck) ShellCommands() {
- NewShellLineChecker(cv.MkLine).CheckShellCommands(cv.Value, RunTime)
+ NewShellLineChecker(cv.MkLines, cv.MkLine).CheckShellCommands(cv.Value, RunTime)
}
func (cv *VartypeCheck) ShellWord() {
- NewShellLineChecker(cv.MkLine).CheckWord(cv.Value, true, RunTime)
+ NewShellLineChecker(cv.MkLines, cv.MkLine).CheckWord(cv.Value, true, RunTime)
}
func (cv *VartypeCheck) Stage() {
@@ -1071,7 +1085,7 @@ func (cv *VartypeCheck) Tool() {
// no warning for package-defined tool definitions
} else if m, toolname, tooldep := match2(cv.Value, `^([-\w]+|\[)(?::(\w+))?$`); m {
- if tool, _ := G.Tool(toolname, RunTime); tool == nil {
+ if tool, _ := G.Tool(cv.MkLines, toolname, RunTime); tool == nil {
cv.Errorf("Unknown tool %q.", toolname)
}
Home |
Main Index |
Thread Index |
Old Index