summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pkgtools/pkglint/files/check_test.go13
-rw-r--r--pkgtools/pkglint/files/files.go5
-rw-r--r--pkgtools/pkglint/files/globaldata.go4
-rw-r--r--pkgtools/pkglint/files/globaldata_test.go28
-rw-r--r--pkgtools/pkglint/files/line_test.go9
-rw-r--r--pkgtools/pkglint/files/makefiles.go4
-rw-r--r--pkgtools/pkglint/files/mkline.go4
-rw-r--r--pkgtools/pkglint/files/mkline_test.go9
-rw-r--r--pkgtools/pkglint/files/shell.go25
-rw-r--r--pkgtools/pkglint/files/shell_test.go91
-rw-r--r--pkgtools/pkglint/files/vartypecheck.go10
11 files changed, 131 insertions, 71 deletions
diff --git a/pkgtools/pkglint/files/check_test.go b/pkgtools/pkglint/files/check_test.go
index 104e2c4f6bf..74b8e51a44e 100644
--- a/pkgtools/pkglint/files/check_test.go
+++ b/pkgtools/pkglint/files/check_test.go
@@ -50,6 +50,19 @@ func (s *Suite) UseCommandLine(c *check.C, args ...string) {
}
}
+func (s *Suite) RegisterTool(toolname, varname string, varRequired bool) {
+ if G.globalData.tools == nil {
+ G.globalData.tools = make(map[string]bool)
+ G.globalData.vartools = make(map[string]string)
+ G.globalData.toolsVarRequired = make(map[string]bool)
+ }
+ G.globalData.tools[toolname] = true
+ G.globalData.vartools[toolname] = varname
+ if varRequired {
+ G.globalData.toolsVarRequired[toolname] = true
+ }
+}
+
func (s *Suite) CreateTmpFile(c *check.C, fname, content string) {
if s.tmpdir == "" {
s.tmpdir = filepath.ToSlash(c.MkDir())
diff --git a/pkgtools/pkglint/files/files.go b/pkgtools/pkglint/files/files.go
index 07c66862cc6..ef1cda33461 100644
--- a/pkgtools/pkglint/files/files.go
+++ b/pkgtools/pkglint/files/files.go
@@ -21,9 +21,12 @@ func LoadNonemptyLines(fname string, joinContinuationLines bool) []*Line {
func LoadExistingLines(fname string, foldBackslashLines bool) []*Line {
lines, err := readLines(fname, foldBackslashLines)
- if lines == nil || err != nil {
+ if err != nil {
fatalf(fname, noLines, "Cannot be read.")
}
+ if lines == nil {
+ fatalf(fname, noLines, "Must not be empty.")
+ }
return lines
}
diff --git a/pkgtools/pkglint/files/globaldata.go b/pkgtools/pkglint/files/globaldata.go
index 38c8f2bbffc..5d6ae10f4a3 100644
--- a/pkgtools/pkglint/files/globaldata.go
+++ b/pkgtools/pkglint/files/globaldata.go
@@ -116,8 +116,8 @@ func (gd *GlobalData) loadTools() {
lines := LoadExistingLines(fname, true)
for _, line := range lines {
if m, _, includefile := match2(line.text, reMkInclude); m {
- if m, toolfile := match1(includefile, `^(?:\$\{PKGSRCDIR\}/mk/tools/)?([^/]+)$`); m {
- toolFiles = append(toolFiles, toolfile)
+ if !contains(includefile, "/") {
+ toolFiles = append(toolFiles, includefile)
}
}
}
diff --git a/pkgtools/pkglint/files/globaldata_test.go b/pkgtools/pkglint/files/globaldata_test.go
index bc8cf695246..cc80a557cb4 100644
--- a/pkgtools/pkglint/files/globaldata_test.go
+++ b/pkgtools/pkglint/files/globaldata_test.go
@@ -29,3 +29,31 @@ func (s *Suite) TestParselinesSuggestedUpdates(c *check.C) {
{lines[5], "CSP", "0.34", ""},
{lines[6], "freeciv-client", "2.5.0", "(urgent)"}})
}
+
+func (s *Suite) TestGlobalData_LoadTools(c *check.C) {
+ s.UseCommandLine(c, "-Dtools")
+ s.CreateTmpFile(c, "mk/tools/bsd.tools.mk", ""+
+ ".include \"flex.mk\"\n"+
+ ".include \"gettext.mk\"\n")
+ s.CreateTmpFile(c, "mk/tools/defaults.mk", ""+
+ "_TOOLS_VARNAME.chown=CHOWN\n"+
+ "_TOOLS_VARNAME.mv=MV\n"+
+ "_TOOLS_VARNAME.gawk=AWK\n")
+ s.CreateTmpFile(c, "mk/tools/flex.mk", ""+
+ "# empty\n")
+ s.CreateTmpFile(c, "mk/tools/gettext.mk", ""+
+ "USE_TOOLS+=msgfmt\n"+
+ "TOOLS_CREATE+=msgfmt\n")
+ s.CreateTmpFile(c, "mk/bsd.pkg.mk", "# empty\n")
+ G.globalData.pkgsrcdir = s.tmpdir
+ G.currentDir = s.tmpdir
+ G.curPkgsrcdir = "."
+
+ G.globalData.loadTools()
+
+ c.Check(s.Output(), equals, ""+
+ "DEBUG: tools: [chown gawk msgfmt mv]\n"+
+ "DEBUG: vartools: [chown gawk mv]\n"+
+ "DEBUG: predefinedTools: []\n"+
+ "DEBUG: varnameToToolname: [AWK CHOWN MV]\n")
+}
diff --git a/pkgtools/pkglint/files/line_test.go b/pkgtools/pkglint/files/line_test.go
index e589b06cc09..afb5ddd69e2 100644
--- a/pkgtools/pkglint/files/line_test.go
+++ b/pkgtools/pkglint/files/line_test.go
@@ -49,3 +49,12 @@ func (s *Suite) TestLineModify(c *check.C) {
{0, "between middle and after\n"},
{0, "after\n"}})
}
+
+func (s *Suite) TestLine_CheckAbsolutePathname(c *check.C) {
+ line := NewLine("Makefile", "1", "# dummy", nil)
+
+ line.checkAbsolutePathname("bindir=/bin")
+ line.checkAbsolutePathname("bindir=/../lib")
+
+ c.Check(s.Output(), equals, "WARN: Makefile:1: Found absolute pathname: /bin\n")
+}
diff --git a/pkgtools/pkglint/files/makefiles.go b/pkgtools/pkglint/files/makefiles.go
index 854fbffb9bb..74d6e4b1924 100644
--- a/pkgtools/pkglint/files/makefiles.go
+++ b/pkgtools/pkglint/files/makefiles.go
@@ -335,7 +335,9 @@ func ChecklinesMk(lines []*Line) {
substcontext.Varassign(line, varname, op, value)
} else if hasPrefix(text, "\t") {
- checklineMkShellcmd(line, text[1:])
+ shellcmd := text[1:]
+ NewMkLine(line).checkText(shellcmd)
+ NewMkShellLine(line).checkShelltext(shellcmd)
} else if m, include, includefile := match2(text, reMkInclude); m {
_ = G.opts.DebugInclude && line.debugf("includefile=%s", includefile)
diff --git a/pkgtools/pkglint/files/mkline.go b/pkgtools/pkglint/files/mkline.go
index 0812fa1ab8f..f12eb5d02e3 100644
--- a/pkgtools/pkglint/files/mkline.go
+++ b/pkgtools/pkglint/files/mkline.go
@@ -68,7 +68,7 @@ func (ml *MkLine) checkVaruse(varname string, mod string, vuc *VarUseContext) {
if G.opts.WarnExtra &&
(vartype == nil || vartype.guessed == guGuessed) &&
!varIsUsed(varname) &&
- (G.mkContext == nil || !G.mkContext.forVars[varname]) {
+ !(G.mkContext != nil && G.mkContext.forVars[varname]) {
line.warnf("%s is used but not defined. Spelling mistake?", varname)
}
@@ -541,7 +541,7 @@ func (ml *MkLine) checkVartype(varname, op, value, comment string) {
for _, word := range words {
ml.checkVartypePrimitive(varname, vartype.checker, op, word, comment, true, vartype.guessed)
if vartype.kindOfList != lkSpace {
- checklineMkShellword(line, word, true)
+ NewMkShellLine(ml.line).checkShellword(word, true)
}
}
}
diff --git a/pkgtools/pkglint/files/mkline_test.go b/pkgtools/pkglint/files/mkline_test.go
index 1605e7537b6..011e4fd7f59 100644
--- a/pkgtools/pkglint/files/mkline_test.go
+++ b/pkgtools/pkglint/files/mkline_test.go
@@ -76,12 +76,3 @@ func (s *Suite) TestChecklineMkVaralign(c *check.C) {
"NOTE: file.mk:6: Autofix: replacing \"VAR= \\t\" with \"VAR=\\t\\t\".\n")
c.Check(tabLength("VAR= \t"), equals, 16)
}
-
-func (s *Suite) TestMkLine_CheckAbsolutePathname(c *check.C) {
- ml := NewMkLine(NewLine("Makefile", "1", "# dummy", nil))
-
- ml.checkAbsolutePathname("bindir=/bin")
- ml.checkAbsolutePathname("bindir=/../lib")
-
- c.Check(s.Output(), equals, "WARN: Makefile:1: Found absolute pathname: /bin\n")
-}
diff --git a/pkgtools/pkglint/files/shell.go b/pkgtools/pkglint/files/shell.go
index ea1e9ad0a44..9bd79eca233 100644
--- a/pkgtools/pkglint/files/shell.go
+++ b/pkgtools/pkglint/files/shell.go
@@ -8,17 +8,6 @@ import (
"unicode"
)
-func checklineMkShellword(line *Line, word string, checkQuoting bool) {
- NewMkShellLine(line).checklineMkShellword(word, checkQuoting)
-}
-func checklineMkShellcmdUse(line *Line, shellcmd string) {
- NewMkShellLine(line).checkCommandUse(shellcmd)
-}
-func checklineMkShellcmd(line *Line, shellcmd string) {
- NewMkLine(line).checkText(shellcmd)
- NewMkShellLine(line).checklineMkShelltext(shellcmd)
-}
-
const (
reMkShellvaruse = `(?:^|[^\$])\$\$\{?(\w+)\}?`
reVarnameDirect = `(?:[-*+.0-9A-Z_a-z{}\[]+)`
@@ -92,7 +81,7 @@ func NewMkShellLine(line *Line) *MkShellLine {
return &MkShellLine{line}
}
-func (msline *MkShellLine) checklineMkShellword(shellword string, checkQuoting bool) {
+func (msline *MkShellLine) checkShellword(shellword string, checkQuoting bool) {
defer tracecall("MkShellLine.checklineMkShellword", shellword, checkQuoting)()
if shellword == "" || hasPrefix(shellword, "#") {
@@ -180,7 +169,7 @@ outer:
line.errorf("Unfinished backquotes: rest=%q", rest)
endOfBackticks:
- msline.checklineMkShelltext(stripped)
+ msline.checkShelltext(stripped)
// Make(1) variables have the same syntax, no matter in which state we are currently.
case replacePrefix(&rest, &m, `^\$\{(`+reVarnameDirect+`|@)(:[^\{]+)?\}`),
@@ -360,7 +349,7 @@ type ShelltextContext struct {
shellword string
}
-func (msline *MkShellLine) checklineMkShelltext(shelltext string) {
+func (msline *MkShellLine) checkShelltext(shelltext string) {
defer tracecall("MkShellLine.checklineMkShelltext", shelltext)()
line := msline.line
@@ -403,7 +392,7 @@ func (msline *MkShellLine) checklineMkShelltext(shelltext string) {
state != scstForCont &&
state != scstSetCont &&
!(state == scstStart && matches(shellword, reShVarassign))
- msline.checklineMkShellword(shellword, quotingNecessary)
+ msline.checkShellword(shellword, quotingNecessary)
}
st := &ShelltextContext{line, state, shellword}
@@ -525,7 +514,7 @@ func (ctx *ShelltextContext) handleTool() bool {
ctx.line.warnf("Please use \"${%s}\" instead of %q.", G.globalData.vartools[shellword], shellword)
}
- checklineMkShellcmdUse(ctx.line, shellword)
+ NewMkShellLine(ctx.line).checkCommandUse(shellword)
return true
}
@@ -554,12 +543,12 @@ func (ctx *ShelltextContext) handleCommandVariable() bool {
if !G.mkContext.tools[toolname] {
ctx.line.warnf("The %q tool is used but not added to USE_TOOLS.", toolname)
}
- checklineMkShellcmdUse(ctx.line, shellword)
+ NewMkShellLine(ctx.line).checkCommandUse(shellword)
return true
}
if vartype := getVariableType(ctx.line, varname); vartype != nil && vartype.checker.name == "ShellCommand" {
- checklineMkShellcmdUse(ctx.line, shellword)
+ NewMkShellLine(ctx.line).checkCommandUse(shellword)
return true
}
diff --git a/pkgtools/pkglint/files/shell_test.go b/pkgtools/pkglint/files/shell_test.go
index 489136e59d0..1d417cebd33 100644
--- a/pkgtools/pkglint/files/shell_test.go
+++ b/pkgtools/pkglint/files/shell_test.go
@@ -23,11 +23,11 @@ func (s *Suite) TestChecklineMkShelltext(c *check.C) {
G.mkContext = newMkContext()
msline := NewMkShellLine(NewLine("fname", "1", "# dummy", nil))
- msline.checklineMkShelltext("@# Comment")
+ msline.checkShelltext("@# Comment")
c.Check(s.Output(), equals, "")
- msline.checklineMkShelltext("uname=`uname`; echo $$uname")
+ msline.checkShelltext("uname=`uname`; echo $$uname")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Unknown shell command \"uname\".\n"+
@@ -35,80 +35,105 @@ func (s *Suite) TestChecklineMkShelltext(c *check.C) {
"WARN: fname:1: Unknown shell command \"echo\".\n"+
"WARN: fname:1: Unquoted shell variable \"uname\".\n")
- // The following test case goes beyond the limits of the current shell parser.
-
- // foobar="`echo \"foo bar\"`"
- msline.checklineMkShelltext("foobar=\"`echo \\\"foo bar\\\"`\"")
-
- c.Check(s.Output(), equals, ""+
- "WARN: fname:1: Backslashes should be doubled inside backticks.\n"+
- "WARN: fname:1: Double quotes inside backticks inside double quotes are error prone.\n"+
- "WARN: fname:1: Backslashes should be doubled inside backticks.\n"+
- "WARN: fname:1: Double quotes inside backticks inside double quotes are error prone.\n"+
- "WARN: fname:1: Unknown shell command \"echo\".\n"+
- "ERROR: fname:1: Internal pkglint error: checklineMkShellword state=plain, rest=\"\\\\foo\", shellword=\"\\\\foo\"\n"+
- "ERROR: fname:1: Internal pkglint error: checklineMkShelltext state=continuation rest=\"\\\\\" shellword=\"echo \\\\foo bar\\\\\"\n")
-
G.globalData.tools = map[string]bool{"echo": true}
G.globalData.predefinedTools = map[string]bool{"echo": true}
G.mkContext = newMkContext()
G.globalData.InitVartypes()
- msline.checklineMkShelltext("echo ${PKGNAME:Q}") // vucQuotPlain
+ msline.checkShelltext("echo ${PKGNAME:Q}") // vucQuotPlain
c.Check(s.Output(), equals, ""+
"WARN: fname:1: PKGNAME may not be used in this file.\n"+
"NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
- msline.checklineMkShelltext("echo \"${CFLAGS:Q}\"") // vucQuotDquot
+ msline.checkShelltext("echo \"${CFLAGS:Q}\"") // vucQuotDquot
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Please don't use the :Q operator in double quotes.\n"+
"WARN: fname:1: CFLAGS may not be used in this file.\n"+
"WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.\n")
- msline.checklineMkShelltext("echo '${COMMENT:Q}'") // vucQuotSquot
+ msline.checkShelltext("echo '${COMMENT:Q}'") // vucQuotSquot
c.Check(s.Output(), equals, "WARN: fname:1: COMMENT may not be used in this file.\n")
- msline.checklineMkShelltext("echo $$@")
+ msline.checkShelltext("echo $$@")
c.Check(s.Output(), equals, "WARN: fname:1: The $@ shell variable should only be used in double quotes.\n")
- msline.checklineMkShelltext("echo \"$$\"") // As seen by make(1); the shell sees: echo $
+ msline.checkShelltext("echo \"$$\"") // As seen by make(1); the shell sees: echo $
c.Check(s.Output(), equals, "WARN: fname:1: Unquoted $ or strange shell variable found.\n")
- msline.checklineMkShelltext("echo \"\\n\"") // As seen by make(1); the shell sees: echo "\n"
+ msline.checkShelltext("echo \"\\n\"") // As seen by make(1); the shell sees: echo "\n"
c.Check(s.Output(), equals, "WARN: fname:1: Please use \"\\\\n\" instead of \"\\n\".\n")
}
+func (s *Suite) TestMkShellLine_CheckShelltext_InternalError1(c *check.C) {
+ s.UseCommandLine(c, "-Wall")
+ G.globalData.InitVartypes()
+ G.mkContext = newMkContext()
+ msline := NewMkShellLine(NewLine("fname", "1", "# dummy", nil))
+
+ // foobar="`echo \"foo bar\"`"
+ msline.checkShelltext("foobar=\"`echo \\\"foo bar\\\"`\"")
+
+ c.Check(s.Output(), equals, ""+
+ "WARN: fname:1: Backslashes should be doubled inside backticks.\n"+
+ "WARN: fname:1: Double quotes inside backticks inside double quotes are error prone.\n"+
+ "WARN: fname:1: Backslashes should be doubled inside backticks.\n"+
+ "WARN: fname:1: Double quotes inside backticks inside double quotes are error prone.\n"+
+ "WARN: fname:1: Unknown shell command \"echo\".\n"+
+ "ERROR: fname:1: Internal pkglint error: checklineMkShellword state=plain, rest=\"\\\\foo\", shellword=\"\\\\foo\"\n"+
+ "ERROR: fname:1: Internal pkglint error: checklineMkShelltext state=continuation rest=\"\\\\\" shellword=\"echo \\\\foo bar\\\\\"\n")
+}
+
+func (s *Suite) TestMkShellLine_CheckShelltext_InternalError2(c *check.C) {
+ G.globalData.InitVartypes()
+ msline := NewMkShellLine(NewLine("fname", "1", "# dummy", nil))
+ G.mkContext = newMkContext()
+ s.RegisterTool("pax", "PAX", false)
+ G.mkContext.tools["pax"] = true
+
+ msline.checkShelltext("pax -rwpp -s /.*~$$//g . ${DESTDIR}${PREFIX}")
+
+ c.Check(s.Output(), equals, "ERROR: fname:1: Internal pkglint error: checklineMkShellword state=plain, rest=\"$$//g\", shellword=\"/.*~$$//g\"\n")
+}
+
func (s *Suite) TestChecklineMkShellword(c *check.C) {
s.UseCommandLine(c, "-Wall")
G.globalData.InitVartypes()
- line := NewLine("fname", "1", "# dummy", nil)
+ msline := NewMkShellLine(NewLine("fname", "1", "# dummy", nil))
c.Check(matches("${list}", `^`+reVarnameDirect+`$`), equals, false)
- checklineMkShellword(line, "${${list}}", false)
+ msline.checkShellword("${${list}}", false)
c.Check(s.Output(), equals, "")
- checklineMkShellword(line, "\"$@\"", false)
+ msline.checkShellword("\"$@\"", false)
c.Check(s.Output(), equals, "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n")
}
+func (s *Suite) TestMkShellLine_CheckShellword_InternalError(c *check.C) {
+ msline := NewMkShellLine(NewLine("fname", "1", "# dummy", nil))
+
+ msline.checkShellword("/.*~$$//g", false)
+
+ c.Check(s.Output(), equals, "ERROR: fname:1: Internal pkglint error: checklineMkShellword state=plain, rest=\"$$//g\", shellword=\"/.*~$$//g\"\n")
+}
+
func (s *Suite) TestShelltextContext_CheckCommandStart(c *check.C) {
s.UseCommandLine(c, "-Wall")
- G.globalData.tools = map[string]bool{"echo": true}
- G.globalData.vartools = map[string]string{"echo": "ECHO"}
- G.globalData.toolsVarRequired = map[string]bool{"echo": true}
+ s.RegisterTool("echo", "ECHO", true)
G.mkContext = newMkContext()
line := NewLine("fname", "3", "# dummy", nil)
- checklineMkShellcmd(line, "echo \"hello, world\"")
+ shellcmd := "echo \"hello, world\""
+ NewMkLine(line).checkText(shellcmd)
+ NewMkShellLine(line).checkShelltext(shellcmd)
c.Check(s.Output(), equals, ""+
"WARN: fname:3: The \"echo\" tool is used but not added to USE_TOOLS.\n"+
@@ -117,17 +142,17 @@ func (s *Suite) TestShelltextContext_CheckCommandStart(c *check.C) {
func (s *Suite) TestMkShellLine_checklineMkShelltext(c *check.C) {
- shline := NewMkShellLine(NewLine("Makefile", "3", "# dummy", nil))
+ msline := NewMkShellLine(NewLine("Makefile", "3", "# dummy", nil))
- shline.checklineMkShelltext("for f in *.pl; do ${SED} s,@PREFIX@,${PREFIX}, < $f > $f.tmp && ${MV} $f.tmp $f; done")
+ msline.checkShelltext("for f in *.pl; do ${SED} s,@PREFIX@,${PREFIX}, < $f > $f.tmp && ${MV} $f.tmp $f; done")
c.Check(s.Output(), equals, "NOTE: Makefile:3: Please use the SUBST framework instead of ${SED} and ${MV}.\n")
- shline.checklineMkShelltext("install -c manpage.1 ${PREFIX}/man/man1/manpage.1")
+ msline.checkShelltext("install -c manpage.1 ${PREFIX}/man/man1/manpage.1")
c.Check(s.Output(), equals, "WARN: Makefile:3: Please use ${PKGMANDIR} instead of \"man\".\n")
- shline.checklineMkShelltext("cp init-script ${PREFIX}/etc/rc.d/service")
+ msline.checkShelltext("cp init-script ${PREFIX}/etc/rc.d/service")
c.Check(s.Output(), equals, "WARN: Makefile:3: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.\n")
}
diff --git a/pkgtools/pkglint/files/vartypecheck.go b/pkgtools/pkglint/files/vartypecheck.go
index 9b8d8078063..8179173e7e5 100644
--- a/pkgtools/pkglint/files/vartypecheck.go
+++ b/pkgtools/pkglint/files/vartypecheck.go
@@ -532,7 +532,7 @@ func (cv *VartypeCheck) SedCommands() {
for i := 0; i < nwords; i++ {
word := words[i]
- checklineMkShellword(cv.line, word, true)
+ NewMkShellLine(cv.line).checkShellword(word, true)
switch {
case word == "-e":
@@ -551,8 +551,8 @@ func (cv *VartypeCheck) SedCommands() {
"",
"This way, short sed commands cannot be hidden at the end of a line.")
}
- checklineMkShellword(line, words[i-1], true)
- checklineMkShellword(line, words[i], true)
+ NewMkShellLine(line).checkShellword(words[i-1], true)
+ NewMkShellLine(line).checkShellword(words[i], true)
NewMkLine(line).checkVartypePrimitive(cv.varname, CheckvarSedCommand, cv.op, words[i], cv.comment, cv.listContext, cv.guessed)
} else {
line.errorf("The -e option to sed requires an argument.")
@@ -573,12 +573,12 @@ func (cv *VartypeCheck) SedCommands() {
}
func (cv *VartypeCheck) ShellCommand() {
- NewMkShellLine(cv.line).checklineMkShelltext(cv.value)
+ NewMkShellLine(cv.line).checkShelltext(cv.value)
}
func (cv *VartypeCheck) ShellWord() {
if !cv.listContext {
- checklineMkShellword(cv.line, cv.value, true)
+ NewMkShellLine(cv.line).checkShellword(cv.value, true)
}
}