diff options
-rw-r--r-- | pkgtools/pkglint/files/check_test.go | 13 | ||||
-rw-r--r-- | pkgtools/pkglint/files/files.go | 5 | ||||
-rw-r--r-- | pkgtools/pkglint/files/globaldata.go | 4 | ||||
-rw-r--r-- | pkgtools/pkglint/files/globaldata_test.go | 28 | ||||
-rw-r--r-- | pkgtools/pkglint/files/line_test.go | 9 | ||||
-rw-r--r-- | pkgtools/pkglint/files/makefiles.go | 4 | ||||
-rw-r--r-- | pkgtools/pkglint/files/mkline.go | 4 | ||||
-rw-r--r-- | pkgtools/pkglint/files/mkline_test.go | 9 | ||||
-rw-r--r-- | pkgtools/pkglint/files/shell.go | 25 | ||||
-rw-r--r-- | pkgtools/pkglint/files/shell_test.go | 91 | ||||
-rw-r--r-- | pkgtools/pkglint/files/vartypecheck.go | 10 |
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) } } |