summaryrefslogtreecommitdiff
path: root/pkgtools
diff options
context:
space:
mode:
authorrillig <rillig@pkgsrc.org>2018-04-28 23:32:52 +0000
committerrillig <rillig@pkgsrc.org>2018-04-28 23:32:52 +0000
commita80885a34fef3ccb290e22d0b411a223a87b5db4 (patch)
tree975818a4523081a5f94d2783a827d8436c7416ed /pkgtools
parent39b0ef9b23a4ed8b3193691ca8b2e7c1b9cfc5ac (diff)
downloadpkgsrc-a80885a34fef3ccb290e22d0b411a223a87b5db4.tar.gz
Update pkglint to 5.5.9
Changes since 5.5.8: * Improved support for the "strip" tool, which has a special definition and is not directly connected to the STRIP variable. * Miscellaneous code cleanup and new tests.
Diffstat (limited to 'pkgtools')
-rw-r--r--pkgtools/pkglint/Makefile5
-rw-r--r--pkgtools/pkglint/files/autofix.go2
-rw-r--r--pkgtools/pkglint/files/licenses_test.go49
-rw-r--r--pkgtools/pkglint/files/mkline_test.go4
-rw-r--r--pkgtools/pkglint/files/mklines.go3
-rw-r--r--pkgtools/pkglint/files/mktypes.go7
-rw-r--r--pkgtools/pkglint/files/pkglint.go6
-rw-r--r--pkgtools/pkglint/files/pkgsrc.go28
-rw-r--r--pkgtools/pkglint/files/pkgsrc_test.go25
-rw-r--r--pkgtools/pkglint/files/shell_test.go26
-rw-r--r--pkgtools/pkglint/files/shtypes.go21
-rw-r--r--pkgtools/pkglint/files/shtypes_test.go15
-rw-r--r--pkgtools/pkglint/files/tools.go44
-rw-r--r--pkgtools/pkglint/files/tools_test.go20
-rw-r--r--pkgtools/pkglint/files/util.go2
-rw-r--r--pkgtools/pkglint/files/util_test.go7
-rw-r--r--pkgtools/pkglint/files/vardefs.go1
-rw-r--r--pkgtools/pkglint/files/vartype.go1
-rw-r--r--pkgtools/pkglint/files/vartypecheck.go5
-rw-r--r--pkgtools/pkglint/files/vartypecheck_test.go24
20 files changed, 237 insertions, 58 deletions
diff --git a/pkgtools/pkglint/Makefile b/pkgtools/pkglint/Makefile
index 49d8612fbf4..767e68ac1eb 100644
--- a/pkgtools/pkglint/Makefile
+++ b/pkgtools/pkglint/Makefile
@@ -1,6 +1,6 @@
-# $NetBSD: Makefile,v 1.535 2018/04/06 21:04:22 rillig Exp $
+# $NetBSD: Makefile,v 1.536 2018/04/28 23:32:52 rillig Exp $
-PKGNAME= pkglint-5.5.8
+PKGNAME= pkglint-5.5.9
DISTFILES= # none
CATEGORIES= pkgtools
@@ -11,7 +11,6 @@ LICENSE= 2-clause-bsd
CONFLICTS+= pkglint4-[0-9]*
NO_CHECKSUM= yes
-USE_LANGUAGES= c
USE_TOOLS+= pax
AUTO_MKDIRS= yes
GO_SRCPATH= netbsd.org/pkglint
diff --git a/pkgtools/pkglint/files/autofix.go b/pkgtools/pkglint/files/autofix.go
index 944c7206071..d7cca2a7e7b 100644
--- a/pkgtools/pkglint/files/autofix.go
+++ b/pkgtools/pkglint/files/autofix.go
@@ -42,8 +42,10 @@ func NewAutofix(line Line) *Autofix {
// because of the --only option.
//
// The fixer function must always call Describef.
+//
// If printAutofix or autofix is true, the fix should be done in
// memory as far as possible (e.g. changes to the text of the line).
+//
// If autofix is true, the fix should be done permanently
// (e.g. direct changes to the file system).
func (fix *Autofix) Custom(fixer func(printAutofix, autofix bool)) {
diff --git a/pkgtools/pkglint/files/licenses_test.go b/pkgtools/pkglint/files/licenses_test.go
index 5ae52eb1fcd..2f5b543e3df 100644
--- a/pkgtools/pkglint/files/licenses_test.go
+++ b/pkgtools/pkglint/files/licenses_test.go
@@ -1,7 +1,7 @@
package main
import (
- check "gopkg.in/check.v1"
+ "gopkg.in/check.v1"
)
func (s *Suite) Test_checklineLicense(c *check.C) {
@@ -44,3 +44,50 @@ func (s *Suite) Test_checklineLicense(c *check.C) {
t.CheckOutputEmpty()
}
+
+func (s *Suite) Test_checkToplevelUnusedLicenses(c *check.C) {
+ t := s.Init(c)
+
+ t.SetupFileLines("mk/bsd.pkg.mk", "# dummy")
+ t.SetupFileLines("mk/fetch/sites.mk", "# dummy")
+ t.SetupFileLines("mk/defaults/options.description", "option\tdescription")
+ t.SetupFileLines("doc/TODO")
+ t.SetupFileLines("mk/defaults/mk.conf")
+ t.SetupFileLines("mk/tools/bsd.tools.mk",
+ ".include \"actual-tools.mk\"")
+ t.SetupFileLines("mk/tools/actual-tools.mk")
+ t.SetupFileLines("mk/tools/defaults.mk")
+ t.SetupFileLines("mk/bsd.prefs.mk")
+ t.SetupFileLines("mk/misc/category.mk")
+ t.SetupFileLines("licenses/2-clause-bsd")
+ t.SetupFileLines("licenses/gnu-gpl-v3")
+
+ t.SetupFileLines("Makefile",
+ MkRcsID,
+ "SUBDIR+=\tcategory")
+
+ t.SetupFileLines("category/Makefile",
+ MkRcsID,
+ "COMMENT=\tExample category",
+ "",
+ "SUBDIR+=\tpackage",
+ "",
+ ".include \"../mk/misc/category.mk\"")
+
+ t.SetupFileLines("category/package/Makefile",
+ MkRcsID,
+ "CATEGORIES=\tcategory",
+ "",
+ "COMMENT=Example package",
+ "LICENSE=\t2-clause-bsd",
+ "NO_CHECKSUM=\tyes")
+ t.SetupFileLines("category/package/PLIST",
+ PlistRcsID,
+ "bin/program")
+
+ G.Main("pkglint", "-r", "-Cglobal", t.TmpDir())
+
+ t.CheckOutputLines(
+ "WARN: ~/licenses/gnu-gpl-v3: This license seems to be unused.",
+ "0 errors and 1 warning found.")
+}
diff --git a/pkgtools/pkglint/files/mkline_test.go b/pkgtools/pkglint/files/mkline_test.go
index 7abbc129cdf..02dfb4554e0 100644
--- a/pkgtools/pkglint/files/mkline_test.go
+++ b/pkgtools/pkglint/files/mkline_test.go
@@ -627,7 +627,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check
t.SetupCommandLine("-Wall")
t.SetupVartypes()
- G.Pkgsrc.Tools.RegisterVarname("tar", "TAR")
+ G.Pkgsrc.Tools.RegisterVarname("tar", "TAR", dummyLine)
mklines := t.NewMkLines("Makefile",
MkRcsID,
"",
@@ -648,7 +648,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__backticks(c *check.C) {
t.SetupCommandLine("-Wall")
t.SetupVartypes()
- G.Pkgsrc.Tools.RegisterVarname("cat", "CAT")
+ G.Pkgsrc.Tools.RegisterVarname("cat", "CAT", dummyLine)
mklines := t.NewMkLines("Makefile",
MkRcsID,
"",
diff --git a/pkgtools/pkglint/files/mklines.go b/pkgtools/pkglint/files/mklines.go
index b958fc520cb..df1b0c2b152 100644
--- a/pkgtools/pkglint/files/mklines.go
+++ b/pkgtools/pkglint/files/mklines.go
@@ -19,6 +19,7 @@ type MkLines struct {
toolRegistry ToolRegistry // Tools defined in file scope.
SeenBsdPrefsMk bool
indentation Indentation // Indentation depth of preprocessing directives
+ // XXX: Why both tools and toolRegistry?
}
func NewMkLines(lines []Line) *MkLines {
@@ -289,7 +290,7 @@ type VaralignBlock struct {
type varalignBlockInfo struct {
mkline MkLine
varnameOp string // Variable name + assignment operator
- varnameOpWidth int // Screen width of varnameOp + space
+ varnameOpWidth int // Screen width of varnameOp
space string // Whitespace between varnameOp and the variable value
totalWidth int // Screen width of varnameOp + space
continuation bool // A continuation line with no value in the first line.
diff --git a/pkgtools/pkglint/files/mktypes.go b/pkgtools/pkglint/files/mktypes.go
index 186bb6b3119..66cd72c3f97 100644
--- a/pkgtools/pkglint/files/mktypes.go
+++ b/pkgtools/pkglint/files/mktypes.go
@@ -11,10 +11,15 @@ type MkToken struct {
// MkVarUse represents a reference to a Make variable, with optional modifiers.
//
+// For nested variable expressions, the variable name can contain references
+// to other variables. For example, ${TOOLS.${t}} is a MkVarUse with varname
+// "TOOLS.${t}" and no modifiers.
+//
// Example: ${PKGNAME}
+//
// Example: ${PKGNAME:S/from/to/}
type MkVarUse struct {
- varname string
+ varname string // E.g. "PKGNAME", or "${BUILD_DEFS}"
modifiers []string // E.g. "Q", "S/from/to/"
}
diff --git a/pkgtools/pkglint/files/pkglint.go b/pkgtools/pkglint/files/pkglint.go
index 7fb0f2d1ae0..d2a9c8878a1 100644
--- a/pkgtools/pkglint/files/pkglint.go
+++ b/pkgtools/pkglint/files/pkglint.go
@@ -119,8 +119,8 @@ func main() {
}
// Main runs the main program with the given arguments.
-// args[0] is the program name.
-func (pkglint *Pkglint) Main(args ...string) (exitcode int) {
+// argv[0] is the program name.
+func (pkglint *Pkglint) Main(argv ...string) (exitcode int) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(pkglintFatal); ok {
@@ -131,7 +131,7 @@ func (pkglint *Pkglint) Main(args ...string) (exitcode int) {
}
}()
- if exitcode := pkglint.ParseCommandLine(args); exitcode != nil {
+ if exitcode := pkglint.ParseCommandLine(argv); exitcode != nil {
return *exitcode
}
diff --git a/pkgtools/pkglint/files/pkgsrc.go b/pkgtools/pkglint/files/pkgsrc.go
index f8f9aaa3114..ccd963ceccf 100644
--- a/pkgtools/pkglint/files/pkgsrc.go
+++ b/pkgtools/pkglint/files/pkgsrc.go
@@ -14,7 +14,6 @@ import (
type Pkgsrc = *PkgsrcImpl
type PkgsrcImpl struct {
-
// The top directory (PKGSRCDIR), either absolute or relative to
// the current working directory.
topdir string
@@ -145,7 +144,8 @@ func (src *PkgsrcImpl) Latest(category string, re regex.Pattern, repl string) st
func (src *PkgsrcImpl) loadTools() {
toolFiles := []string{"defaults.mk"}
{
- lines := G.Pkgsrc.LoadExistingLines("mk/tools/bsd.tools.mk", true)
+ toc := G.Pkgsrc.File("mk/tools/bsd.tools.mk")
+ lines := LoadExistingLines(toc, true)
for _, line := range lines {
if m, _, _, includefile := MatchMkInclude(line.Text); m {
if !contains(includefile, "/") {
@@ -154,16 +154,16 @@ func (src *PkgsrcImpl) loadTools() {
}
}
if len(toolFiles) <= 1 {
- lines[0].Fatalf("Too few tool files.")
+ NewLine(toc, 0, "", nil).Fatalf("Too few tool files.")
}
}
reg := src.Tools
- reg.RegisterTool(&Tool{"echo", "ECHO", true, true, true})
- reg.RegisterTool(&Tool{"echo -n", "ECHO_N", true, true, true})
- reg.RegisterTool(&Tool{"false", "FALSE", true /*why?*/, true, false})
- reg.RegisterTool(&Tool{"test", "TEST", true, true, true})
- reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true})
+ reg.RegisterTool(&Tool{"echo", "ECHO", true, true, true}, dummyLine)
+ reg.RegisterTool(&Tool{"echo -n", "ECHO_N", true, true, true}, dummyLine)
+ reg.RegisterTool(&Tool{"false", "FALSE", true /*why?*/, true, false}, dummyLine)
+ reg.RegisterTool(&Tool{"test", "TEST", true, true, true}, dummyLine)
+ reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true}, dummyLine)
for _, basename := range toolFiles {
lines := G.Pkgsrc.LoadExistingLines("mk/tools/"+basename, true)
@@ -190,11 +190,10 @@ func (src *PkgsrcImpl) loadTools() {
if condDepth == 0 || condDepth == 1 && relativeName == "mk/bsd.prefs.mk" {
for _, toolname := range splitOnSpace(value) {
if !containsVarRef(toolname) {
- for _, tool := range [...]*Tool{reg.Register(toolname), reg.Register("TOOLS_" + toolname)} {
- tool.Predefined = true
- if relativeName == "mk/bsd.prefs.mk" {
- tool.UsableAtLoadtime = true
- }
+ tool := reg.Register(toolname, line)
+ tool.Predefined = true
+ if relativeName == "mk/bsd.prefs.mk" {
+ tool.UsableAtLoadtime = true
}
}
}
@@ -357,7 +356,6 @@ func (src *PkgsrcImpl) loadUserDefinedVars() {
func (src *PkgsrcImpl) initDeprecatedVars() {
src.Deprecated = map[string]string{
-
// December 2003
"FIX_RPATH": "It has been removed from pkgsrc in 2003.",
@@ -519,7 +517,7 @@ func (src *PkgsrcImpl) initDeprecatedVars() {
// LoadExistingLines loads the file relative to the pkgsrc top directory.
func (src *PkgsrcImpl) LoadExistingLines(fileName string, joinBackslashLines bool) []Line {
- return LoadExistingLines(src.topdir+"/"+fileName, joinBackslashLines)
+ return LoadExistingLines(src.File(fileName), joinBackslashLines)
}
// File resolves a file name relative to the pkgsrc top directory.
diff --git a/pkgtools/pkglint/files/pkgsrc_test.go b/pkgtools/pkglint/files/pkgsrc_test.go
index f2d78ccafc5..0ef60a8c539 100644
--- a/pkgtools/pkglint/files/pkgsrc_test.go
+++ b/pkgtools/pkglint/files/pkgsrc_test.go
@@ -66,7 +66,9 @@ func (s *Suite) Test_GlobalData_loadTools(c *check.C) {
t.SetupFileLines("mk/tools/bsd.tools.mk",
".include \"flex.mk\"",
- ".include \"gettext.mk\"")
+ ".include \"gettext.mk\"",
+ ".include \"strip.mk\"",
+ ".include \"replace.mk\"")
t.SetupFileLines("mk/tools/defaults.mk",
"_TOOLS_VARNAME.chown=CHOWN",
"_TOOLS_VARNAME.gawk=AWK",
@@ -77,8 +79,21 @@ func (s *Suite) Test_GlobalData_loadTools(c *check.C) {
t.SetupFileLines("mk/tools/gettext.mk",
"USE_TOOLS+=msgfmt",
"TOOLS_CREATE+=msgfmt")
+ t.SetupFileLines("mk/tools/strip.mk",
+ ".if defined(_INSTALL_UNSTRIPPED) || !defined(TOOLS_PLATFORM.strip)",
+ "TOOLS_NOOP+= strip",
+ ".else",
+ "TOOLS_CREATE+= strip",
+ "TOOLS_PATH.strip= ${TOOLS_PLATFORM.strip}",
+ ".endif",
+ "STRIP?= strip")
+ t.SetupFileLines("mk/tools/replace.mk",
+ "_TOOLS.bzip2=\tbzip2 bzcat",
+ "#TOOLS_CREATE+=commented out",
+ "_UNRELATED_VAR=\t# empty")
t.SetupFileLines("mk/bsd.prefs.mk",
- "USE_TOOLS+=\tpwd")
+ "USE_TOOLS+=\tpwd",
+ "USE_TOOLS+=\tm4:pkgsrc")
t.SetupFileLines("mk/bsd.pkg.mk",
"USE_TOOLS+=\tmv")
G.CurrentDir = t.TmpDir()
@@ -91,16 +106,18 @@ func (s *Suite) Test_GlobalData_loadTools(c *check.C) {
t.CheckOutputLines(
"TRACE: + (*ToolRegistry).Trace()",
- "TRACE: 1 tool &{Name:TOOLS_mv Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:false}",
- "TRACE: 1 tool &{Name:TOOLS_pwd Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
+ "TRACE: 1 tool &{Name:bzcat Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
+ "TRACE: 1 tool &{Name:bzip2 Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
"TRACE: 1 tool &{Name:chown Varname:CHOWN MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
"TRACE: 1 tool &{Name:echo Varname:ECHO MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
"TRACE: 1 tool &{Name:echo -n Varname:ECHO_N MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
"TRACE: 1 tool &{Name:false Varname:FALSE MustUseVarForm:true Predefined:true UsableAtLoadtime:false}",
"TRACE: 1 tool &{Name:gawk Varname:AWK MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
+ "TRACE: 1 tool &{Name:m4 Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
"TRACE: 1 tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
"TRACE: 1 tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadtime:false}",
"TRACE: 1 tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
+ "TRACE: 1 tool &{Name:strip Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
"TRACE: 1 tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
"TRACE: 1 tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
"TRACE: - (*ToolRegistry).Trace()")
diff --git a/pkgtools/pkglint/files/shell_test.go b/pkgtools/pkglint/files/shell_test.go
index 469d8f25014..1f52c329e75 100644
--- a/pkgtools/pkglint/files/shell_test.go
+++ b/pkgtools/pkglint/files/shell_test.go
@@ -254,6 +254,32 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
t.CheckOutputEmpty() // No warning about missing error checking.
}
+func (s *Suite) Test_ShellLine_CheckShellCommandLine_strip(c *check.C) {
+ t := s.Init(c)
+
+ t.SetupCommandLine("-Wall")
+
+ checkShellCommandLine := func(shellCommand string) {
+ G.Mk = t.NewMkLines("fname",
+ "\t"+shellCommand)
+ shline := NewShellLine(G.Mk.mklines[0])
+
+ shline.CheckShellCommandLine(shline.mkline.Shellcmd())
+ }
+
+ checkShellCommandLine("${STRIP} executable")
+
+ t.CheckOutputLines(
+ "WARN: fname:1: Unknown shell command \"${STRIP}\".",
+ "WARN: fname:1: STRIP is used but not defined. Spelling mistake?")
+
+ t.SetupVartypes()
+
+ checkShellCommandLine("${STRIP} executable")
+
+ t.CheckOutputEmpty()
+}
+
func (s *Suite) Test_ShellLine_CheckShellCommandLine__nofix(c *check.C) {
t := s.Init(c)
diff --git a/pkgtools/pkglint/files/shtypes.go b/pkgtools/pkglint/files/shtypes.go
index f474a9efe99..ce7abd3aff5 100644
--- a/pkgtools/pkglint/files/shtypes.go
+++ b/pkgtools/pkglint/files/shtypes.go
@@ -36,7 +36,6 @@ func (t ShAtomType) IsWord() bool {
return false
}
-// @Beta
type ShAtom struct {
Type ShAtomType
MkText string
@@ -44,21 +43,21 @@ type ShAtom struct {
Data interface{}
}
-func (token *ShAtom) String() string {
- if token.Type == shtWord && token.Quoting == shqPlain && token.Data == nil {
- return fmt.Sprintf("%q", token.MkText)
+func (atom *ShAtom) String() string {
+ if atom.Type == shtWord && atom.Quoting == shqPlain && atom.Data == nil {
+ return fmt.Sprintf("%q", atom.MkText)
}
- if token.Type == shtVaruse {
- varuse := token.Data.(*MkVarUse)
+ if atom.Type == shtVaruse {
+ varuse := atom.Data.(*MkVarUse)
return fmt.Sprintf("varuse(%q)", varuse.varname+varuse.Mod())
}
- return fmt.Sprintf("ShAtom(%v, %q, %s)", token.Type, token.MkText, token.Quoting)
+ return fmt.Sprintf("ShAtom(%v, %q, %s)", atom.Type, atom.MkText, atom.Quoting)
}
-// Returns nil for plain shell tokens.
-func (token *ShAtom) VarUse() *MkVarUse {
- if token.Type == shtVaruse {
- return token.Data.(*MkVarUse)
+// VarUse returns a read access to a Makefile variable, or nil for plain shell tokens.
+func (atom *ShAtom) VarUse() *MkVarUse {
+ if atom.Type == shtVaruse {
+ return atom.Data.(*MkVarUse)
}
return nil
}
diff --git a/pkgtools/pkglint/files/shtypes_test.go b/pkgtools/pkglint/files/shtypes_test.go
index 263f459abbb..a007e1dcdc7 100644
--- a/pkgtools/pkglint/files/shtypes_test.go
+++ b/pkgtools/pkglint/files/shtypes_test.go
@@ -12,10 +12,23 @@ func NewShAtomVaruse(text string, quoting ShQuoting, varname string, modifiers .
return &ShAtom{shtVaruse, text, quoting, NewMkVarUse(varname, modifiers...)}
}
-func (s *Suite) Test_ShAtom_String(c *check.C) {
+func (s *Suite) Test_ShAtomType_String(c *check.C) {
c.Check(shtComment.String(), equals, "comment")
}
+func (s *Suite) Test_ShAtom_String(c *check.C) {
+ tokenizer := NewShTokenizer(dummyLine, "${ECHO} \"hello, world\"", false)
+
+ atoms := tokenizer.ShAtoms()
+
+ c.Check(len(atoms), equals, 5)
+ c.Check(atoms[0].String(), equals, "varuse(\"ECHO\")")
+ c.Check(atoms[1].String(), equals, "ShAtom(space, \" \", plain)")
+ c.Check(atoms[2].String(), equals, "ShAtom(word, \"\\\"\", d)")
+ c.Check(atoms[3].String(), equals, "ShAtom(word, \"hello, world\", d)")
+ c.Check(atoms[4].String(), equals, "\"\\\"\"")
+}
+
func (s *Suite) Test_ShQuoting_String(c *check.C) {
c.Check(shqDquotBacktSquot.String(), equals, "dbs")
}
diff --git a/pkgtools/pkglint/files/tools.go b/pkgtools/pkglint/files/tools.go
index 08437fb9379..9efd0fa6c81 100644
--- a/pkgtools/pkglint/files/tools.go
+++ b/pkgtools/pkglint/files/tools.go
@@ -3,6 +3,7 @@ package main
import (
"netbsd.org/pkglint/trace"
"sort"
+ "strings"
)
// See `mk/tools/`.
@@ -23,23 +24,32 @@ func NewToolRegistry() ToolRegistry {
return ToolRegistry{make(map[string]*Tool), make(map[string]*Tool)}
}
-func (tr *ToolRegistry) Register(toolname string) *Tool {
- tool := tr.byName[toolname]
+// Register registers the tool by its name.
+// The tool may then be used by this name (e.g. "awk"),
+// but not by a corresponding variable (e.g. ${AWK}).
+// The toolname may include the scope (:pkgsrc, :run, etc.).
+func (tr *ToolRegistry) Register(toolname string, line Line) *Tool {
+ name := strings.SplitN(toolname, ":", 2)[0]
+ tr.validateToolName(name, line)
+
+ tool := tr.byName[name]
if tool == nil {
- tool = &Tool{Name: toolname}
- tr.byName[toolname] = tool
+ tool = &Tool{Name: name}
+ tr.byName[name] = tool
}
return tool
}
-func (tr *ToolRegistry) RegisterVarname(toolname, varname string) *Tool {
- tool := tr.Register(toolname)
+func (tr *ToolRegistry) RegisterVarname(toolname, varname string, line Line) *Tool {
+ tool := tr.Register(toolname, line)
tool.Varname = varname
tr.byVarname[varname] = tool
return tool
}
-func (tr *ToolRegistry) RegisterTool(tool *Tool) {
+func (tr *ToolRegistry) RegisterTool(tool *Tool, line Line) {
+ tr.validateToolName(tool.Name, line)
+
if tool.Name != "" && tr.byName[tool.Name] == nil {
tr.byName[tool.Name] = tool
}
@@ -78,24 +88,26 @@ func (tr *ToolRegistry) Trace() {
}
}
+// ParseToolLine parses a tool definition from the pkgsrc infrastructure,
+// e.g. in mk/tools/replace.mk.
func (tr *ToolRegistry) ParseToolLine(line Line) {
if m, commented, varname, _, _, _, value, _, _ := MatchVarassign(line.Text); m {
if commented {
return
}
if varname == "TOOLS_CREATE" && (value == "[" || matches(value, `^?[-\w.]+$`)) {
- tr.Register(value)
+ tr.Register(value, line)
} else if m, toolname := match1(varname, `^_TOOLS_VARNAME\.([-\w.]+|\[)$`); m {
- tr.RegisterVarname(toolname, value)
+ tr.RegisterVarname(toolname, value, line)
} else if m, toolname := match1(varname, `^(?:TOOLS_PATH|_TOOLS_DEPMETHOD)\.([-\w.]+|\[)$`); m {
- tr.Register(toolname)
+ tr.Register(toolname, line)
- } else if m, toolname := match1(varname, `_TOOLS\.(.*)`); m {
- tr.Register(toolname)
+ } else if m, toolname := match1(varname, `^_TOOLS\.(.*)`); m {
+ tr.Register(toolname, line)
for _, tool := range splitOnSpace(value) {
- tr.Register(tool)
+ tr.Register(tool, line)
}
}
}
@@ -114,3 +126,9 @@ func (tr *ToolRegistry) ForEach(action func(tool *Tool)) {
action(tool)
}
}
+
+func (tr *ToolRegistry) validateToolName(toolName string, line Line) {
+ if toolName != "echo -n" && !matches(toolName, `^([-a-z0-9.]+|\[)$`) {
+ line.Errorf("Invalid tool name %q", toolName)
+ }
+}
diff --git a/pkgtools/pkglint/files/tools_test.go b/pkgtools/pkglint/files/tools_test.go
new file mode 100644
index 00000000000..645f390222f
--- /dev/null
+++ b/pkgtools/pkglint/files/tools_test.go
@@ -0,0 +1,20 @@
+package main
+
+import "gopkg.in/check.v1"
+
+func (s *Suite) Test_ToolRegistry_ParseToolLine(c *check.C) {
+ t := s.Init(c)
+
+ t.SetupTool(&Tool{Name: "tool1", Predefined: true})
+ t.SetupVartypes()
+ t.SetupFileLines("Makefile",
+ MkRcsID,
+ "",
+ "USE_TOOLS.NetBSD+=\ttool1")
+
+ G.CurrentDir = t.TmpDir()
+ CheckdirToplevel()
+
+ // No error about "Unknown tool \"NetBSD\"."
+ t.CheckOutputEmpty()
+}
diff --git a/pkgtools/pkglint/files/util.go b/pkgtools/pkglint/files/util.go
index 5324e23a440..5771ff8d35a 100644
--- a/pkgtools/pkglint/files/util.go
+++ b/pkgtools/pkglint/files/util.go
@@ -243,7 +243,7 @@ func varIsUsed(varname string) bool {
}
func splitOnSpace(s string) []string {
- return regex.Compile(`\s+`).Split(s, -1)
+ return regex.Compile(`\S+`).FindAllString(s, -1)
}
func fileExists(fname string) bool {
diff --git a/pkgtools/pkglint/files/util_test.go b/pkgtools/pkglint/files/util_test.go
index 65afa3f2d40..91be65d52f2 100644
--- a/pkgtools/pkglint/files/util_test.go
+++ b/pkgtools/pkglint/files/util_test.go
@@ -164,3 +164,10 @@ func emptyToNil(slice []string) []string {
}
return slice
}
+
+func (s *Suite) Test_splitOnSpace(c *check.C) {
+ c.Check(splitOnSpace("aaaaa"), deepEquals, []string{"aaaaa"})
+ c.Check(splitOnSpace(" a b\tc\n"), deepEquals, []string{"a", "b", "c"})
+ c.Check(splitOnSpace(" "), check.IsNil)
+ c.Check(splitOnSpace(""), check.IsNil)
+}
diff --git a/pkgtools/pkglint/files/vardefs.go b/pkgtools/pkglint/files/vardefs.go
index e6988c04454..5a80a499cc6 100644
--- a/pkgtools/pkglint/files/vardefs.go
+++ b/pkgtools/pkglint/files/vardefs.go
@@ -938,6 +938,7 @@ func (src *PkgsrcImpl) InitVartypes() {
pkg("SMF_METHOD_SHELL", lkNone, BtShellCommand)
pkglist("SPECIAL_PERMS", lkShell, BtPerms)
sys("STEP_MSG", lkNone, BtShellCommand)
+ sys("STRIP", lkNone, BtShellCommand) // see mk/tools/strip.mk
acl("SUBDIR", lkShell, BtFilename, "Makefile: append; *:")
acl("SUBST_CLASSES", lkShell, BtIdentifier, "Makefile: set, append; *: append")
acl("SUBST_CLASSES.*", lkShell, BtIdentifier, "Makefile: set, append; *: append")
diff --git a/pkgtools/pkglint/files/vartype.go b/pkgtools/pkglint/files/vartype.go
index df33d3307c2..b36cafa2eef 100644
--- a/pkgtools/pkglint/files/vartype.go
+++ b/pkgtools/pkglint/files/vartype.go
@@ -173,6 +173,7 @@ func (vt *Vartype) IsBasicSafe() bool {
BtRelativePkgDir,
BtRelativePkgPath,
BtStage,
+ BtTool, // Sometimes contains a colon, but that should be ok.
BtUserGroupName,
BtVersion,
BtWrkdirSubdirectory,
diff --git a/pkgtools/pkglint/files/vartypecheck.go b/pkgtools/pkglint/files/vartypecheck.go
index f08b152d84a..cb6a0b98d04 100644
--- a/pkgtools/pkglint/files/vartypecheck.go
+++ b/pkgtools/pkglint/files/vartypecheck.go
@@ -940,18 +940,19 @@ func (cv *VartypeCheck) Stage() {
}
}
+// Tool checks for tool names like "awk", "m4:pkgsrc", "digest:bootstrap".
func (cv *VartypeCheck) Tool() {
if cv.Varname == "TOOLS_NOOP" && cv.Op == opAssignAppend {
// no warning for package-defined tool definitions
} else if m, toolname, tooldep := match2(cv.Value, `^([-\w]+|\[)(?::(\w+))?$`); m {
- if G.Pkgsrc.Tools.ByName(toolname) == nil && (G.Mk == nil || G.Mk.toolRegistry.byName[toolname] == nil) {
+ if G.Pkgsrc.Tools.ByName(toolname) == nil && (G.Mk == nil || G.Mk.toolRegistry.ByName(toolname) == nil) {
cv.Line.Errorf("Unknown tool %q.", toolname)
}
switch tooldep {
case "", "bootstrap", "build", "pkgsrc", "run":
default:
- cv.Line.Errorf("Unknown tool dependency %q. Use one of \"build\", \"pkgsrc\" or \"run\".", tooldep)
+ cv.Line.Errorf("Unknown tool dependency %q. Use one of \"bootstrap\", \"build\", \"pkgsrc\" or \"run\".", tooldep)
}
} else if cv.Op != opUseMatch {
cv.Line.Errorf("Invalid tool syntax: %q.", cv.Value)
diff --git a/pkgtools/pkglint/files/vartypecheck_test.go b/pkgtools/pkglint/files/vartypecheck_test.go
index a5c67076162..9953659e679 100644
--- a/pkgtools/pkglint/files/vartypecheck_test.go
+++ b/pkgtools/pkglint/files/vartypecheck_test.go
@@ -541,6 +541,30 @@ func (s *Suite) Test_VartypeCheck_Stage(c *check.C) {
"Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.")
}
+func (s *Suite) Test_VartypeCheck_Tool(c *check.C) {
+ t := s.Init(c)
+
+ t.SetupTool(&Tool{Name: "tool1", Predefined: true})
+ t.SetupTool(&Tool{Name: "tool2", Predefined: true})
+ t.SetupTool(&Tool{Name: "tool3", Predefined: true})
+
+ runVartypeChecks(t, "USE_TOOLS", opAssignAppend, (*VartypeCheck).Tool,
+ "tool3:run",
+ "tool2:unknown")
+
+ t.CheckOutputLines(
+ "ERROR: fname:2: Unknown tool dependency \"unknown\". " +
+ "Use one of \"bootstrap\", \"build\", \"pkgsrc\" or \"run\".")
+
+ runVartypeChecks(t, "USE_TOOLS.NetBSD", opAssignAppend, (*VartypeCheck).Tool,
+ "tool3:run",
+ "tool2:unknown")
+
+ t.CheckOutputLines(
+ "ERROR: fname:2: Unknown tool dependency \"unknown\". " +
+ "Use one of \"bootstrap\", \"build\", \"pkgsrc\" or \"run\".")
+}
+
func (s *Suite) Test_VartypeCheck_VariableName(c *check.C) {
t := s.Init(c)