summaryrefslogtreecommitdiff
path: root/pkgtools
diff options
context:
space:
mode:
authorrillig <rillig@pkgsrc.org>2018-01-07 01:13:21 +0000
committerrillig <rillig@pkgsrc.org>2018-01-07 01:13:21 +0000
commitfbca3a69df272d990963956d39a18bcdcc645cde (patch)
treef4db99898e2794dd199a87f57e5896a3f5994c8c /pkgtools
parent8055a406e392c1db7d426a0ff41e70e073f47a70 (diff)
downloadpkgsrc-fbca3a69df272d990963956d39a18bcdcc645cde.tar.gz
Updated pkglint to 5.4.25.
Changes since 5.4.24: * More specific warning for "exitcode with pipe shell commands" * Don't warn that the echo in "echo | sed" could fail * Allow packages to define custom make targets * Don't warn about a misplaced LICENSE when a package doesn't define it * Skip .git directories * Reduce number of hicolor-icon-theme error messages in PLIST files * Remove MKCRYPTO, USE_CRYPTO, CRYPTO variable definitions
Diffstat (limited to 'pkgtools')
-rw-r--r--pkgtools/pkglint/Makefile4
-rw-r--r--pkgtools/pkglint/files/globaldata.go14
-rw-r--r--pkgtools/pkglint/files/mkline_test.go6
-rw-r--r--pkgtools/pkglint/files/mklinechecker.go14
-rw-r--r--pkgtools/pkglint/files/mklines_test.go32
-rw-r--r--pkgtools/pkglint/files/package.go22
-rw-r--r--pkgtools/pkglint/files/package_test.go29
-rw-r--r--pkgtools/pkglint/files/pkglint.go2
-rw-r--r--pkgtools/pkglint/files/plist.go15
-rw-r--r--pkgtools/pkglint/files/plist_test.go9
-rw-r--r--pkgtools/pkglint/files/shell.go53
-rw-r--r--pkgtools/pkglint/files/shell_test.go37
-rw-r--r--pkgtools/pkglint/files/shtypes.go8
-rw-r--r--pkgtools/pkglint/files/util.go29
14 files changed, 232 insertions, 42 deletions
diff --git a/pkgtools/pkglint/Makefile b/pkgtools/pkglint/Makefile
index d0c3799fa35..a9589d003a6 100644
--- a/pkgtools/pkglint/Makefile
+++ b/pkgtools/pkglint/Makefile
@@ -1,6 +1,6 @@
-# $NetBSD: Makefile,v 1.521 2018/01/02 08:13:15 maya Exp $
+# $NetBSD: Makefile,v 1.522 2018/01/07 01:13:21 rillig Exp $
-PKGNAME= pkglint-5.4.24
+PKGNAME= pkglint-5.4.25
DISTFILES= # none
CATEGORIES= pkgtools
diff --git a/pkgtools/pkglint/files/globaldata.go b/pkgtools/pkglint/files/globaldata.go
index 66cc758af78..9af8b61a1b5 100644
--- a/pkgtools/pkglint/files/globaldata.go
+++ b/pkgtools/pkglint/files/globaldata.go
@@ -587,6 +587,20 @@ func (tr *ToolRegistry) RegisterTool(tool *Tool) {
}
}
+func (tr *ToolRegistry) FindByCommand(cmd *ShToken) *Tool {
+ if tool := tr.byName[cmd.MkText]; tool != nil {
+ return tool
+ }
+ if len(cmd.Atoms) == 1 {
+ if varuse := cmd.Atoms[0].VarUse(); varuse != nil {
+ if tool := tr.byVarname[varuse.varname]; tool != nil {
+ return tool
+ }
+ }
+ }
+ return nil
+}
+
func (tr *ToolRegistry) Trace() {
if trace.Tracing {
defer trace.Call0()()
diff --git a/pkgtools/pkglint/files/mkline_test.go b/pkgtools/pkglint/files/mkline_test.go
index 9b84891b0e7..5327d4b170e 100644
--- a/pkgtools/pkglint/files/mkline_test.go
+++ b/pkgtools/pkglint/files/mkline_test.go
@@ -383,7 +383,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C)
MkLineChecker{G.Mk.mklines[1]}.Check()
s.CheckOutputLines(
- "WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.")
+ "WARN: Makefile:2: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__word_as_part_of_word(c *check.C) {
@@ -420,8 +420,8 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_as_command_argument(c
MkLineChecker{G.Mk.mklines[2]}.Check()
s.CheckOutputLines(
- "WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.",
- "WARN: Makefile:3: The exitcode of the left-hand-side command of the pipe operator is ignored.")
+ "WARN: Makefile:2: The exitcode of the command at the left of the | operator is ignored.",
+ "WARN: Makefile:3: The exitcode of the command at the left of the | operator is ignored.")
}
// Based on mail/mailfront/Makefile.
diff --git a/pkgtools/pkglint/files/mklinechecker.go b/pkgtools/pkglint/files/mklinechecker.go
index bf69746a456..f268d8f0aa5 100644
--- a/pkgtools/pkglint/files/mklinechecker.go
+++ b/pkgtools/pkglint/files/mklinechecker.go
@@ -218,12 +218,20 @@ func (ck MkLineChecker) checkDependencyRule(allowedTargets map[string]bool) {
} else if target == ".ORDER" {
// TODO: Check for spelling mistakes.
+ } else if hasPrefix(target, "${.CURDIR}/") {
+ // OK, this is intentional
+
} else if !allowedTargets[target] {
mkline.Warnf("Unusual target %q.", target)
Explain(
- "If you want to define your own targets, you can \"declare\"",
- "them by inserting a \".PHONY: my-target\" line before this line. This",
- "will tell make(1) to not interpret this target's name as a filename.")
+ "If you want to define your own target, declare it like this:",
+ "",
+ "\t.PHONY: my-target",
+ "",
+ "In the rare case that you actually want a file-based make(1)",
+ "target, write it like this:",
+ "",
+ "\t${.CURDIR}/my-filename:")
}
}
}
diff --git a/pkgtools/pkglint/files/mklines_test.go b/pkgtools/pkglint/files/mklines_test.go
index 767d5e9eebf..6f46a0e8483 100644
--- a/pkgtools/pkglint/files/mklines_test.go
+++ b/pkgtools/pkglint/files/mklines_test.go
@@ -1,7 +1,7 @@
package main
import (
- check "gopkg.in/check.v1"
+ "gopkg.in/check.v1"
)
const mkrcsid = "# $" + "NetBSD$"
@@ -188,7 +188,7 @@ func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) {
s.CheckOutputLines(
"WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.",
"WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.",
- "WARN: audio/squeezeboxserver/Makefile:4: The exitcode of the left-hand-side command of the pipe operator is ignored.")
+ "WARN: audio/squeezeboxserver/Makefile:4: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
}
func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) {
@@ -479,3 +479,31 @@ func (s *Suite) Test_MkLines_Check_indentation(c *check.C) {
"ERROR: options.mk:15: Unmatched .endif.\n"+
"NOTE: options.mk:15: This directive should be indented by 0 spaces.\n")
}
+
+// Demonstrates how to define your own make(1) targets.
+func (s *Suite) Test_MkLines_wip_category_Makefile(c *check.C) {
+ s.Init(c)
+ s.UseCommandLine("-Wall")
+ G.globalData.InitVartypes()
+ s.RegisterTool(&Tool{Name: "rm", Varname: "RM", Predefined: true})
+ mklines := s.NewMkLines("Makefile",
+ mkrcsid,
+ "",
+ "COMMENT=\tWIP pkgsrc packages",
+ "",
+ "SUBDIR+=\taaa",
+ "SUBDIR+=\tzzz",
+ "",
+ "${.CURDIR}/PKGDB:",
+ "\t${RM} -f ${.CURDIR}/PKGDB",
+ "",
+ "${.CURDIR}/INDEX:",
+ "\t${RM} -f ${.CURDIR}/INDEX",
+ "",
+ ".include \"../../mk/misc/category.mk\"")
+
+ mklines.Check()
+
+ c.Check(s.Output(), equals, ""+
+ "ERROR: Makefile:14: \"/mk/misc/category.mk\" does not exist.\n")
+}
diff --git a/pkgtools/pkglint/files/package.go b/pkgtools/pkglint/files/package.go
index ca52bdd224b..609f9d0fac5 100644
--- a/pkgtools/pkglint/files/package.go
+++ b/pkgtools/pkglint/files/package.go
@@ -35,6 +35,7 @@ type Package struct {
loadTimeTools map[string]bool // true=ok, false=not ok, absent=not mentioned in USE_TOOLS.
conditionalIncludes map[string]MkLine
unconditionalIncludes map[string]MkLine
+ once Once
}
func NewPackage(pkgpath string) *Package {
@@ -398,7 +399,7 @@ func (pkg *Package) checkfilePackageMakefile(fname string, mklines *MkLines) {
perlLine.Warnf("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.ReferenceFrom(perlLine.Line))
}
- if vardef["LICENSE"] == nil && vardef["META_PACKAGE"] == nil {
+ if vardef["LICENSE"] == nil && vardef["META_PACKAGE"] == nil && pkg.once.FirstTime("LICENSE") {
NewLineWhole(fname).Errorf("Each package must define its LICENSE.")
}
@@ -756,16 +757,19 @@ func (pkg *Package) ChecklinesPackageMakefileVarorder(mklines *MkLines) {
default:
for varindex < len(vars) {
+ varname := vars[varindex].varname
if vars[varindex].count == once && !maySkipSection {
- line.Warnf("The canonical position for the required variable %s is here.", vars[varindex].varname)
- Explain(
- "In simple package Makefiles, some common variables should be",
- "arranged in a specific order.",
- "",
- "See doc/Makefile-example or the pkgsrc guide, section",
- "\"Package components\", subsection \"Makefile\" for more information.")
+ if varname != "LICENSE" || pkg.once.FirstTime("LICENSE") {
+ line.Warnf("The canonical position for the required variable %s is here.", varname)
+ Explain(
+ "In simple package Makefiles, some common variables should be",
+ "arranged in a specific order.",
+ "",
+ "See doc/Makefile-example or the pkgsrc guide, section",
+ "\"Package components\", subsection \"Makefile\" for more information.")
+ }
}
- below[vars[varindex].varname] = belowWhat
+ below[varname] = belowWhat
varindex++
}
nextSection = true
diff --git a/pkgtools/pkglint/files/package_test.go b/pkgtools/pkglint/files/package_test.go
index 0cfce3b221b..0dce87c0aa7 100644
--- a/pkgtools/pkglint/files/package_test.go
+++ b/pkgtools/pkglint/files/package_test.go
@@ -48,6 +48,35 @@ func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder(c *check.C) {
"WARN: Makefile:6: The canonical position for the required variable LICENSE is here.")
}
+func (s *Suite) Test_Package_varorder_license(c *check.C) {
+ s.Init(c)
+ s.UseCommandLine("-Worder")
+
+ s.CreateTmpFileLines("mk/bsd.pkg.mk", "# dummy")
+ s.CreateTmpFileLines("x11/Makefile", mkrcsid)
+ s.CreateTmpFileLines("x11/9term/PLIST", "@comment $"+"NetBSD$", "bin/9term")
+ s.CreateTmpFileLines("x11/9term/distinfo", "$"+"NetBSD$")
+ s.CreateTmpFileLines("x11/9term/Makefile",
+ mkrcsid,
+ "",
+ "DISTNAME=9term-1.0",
+ "CATEGORIES=x11",
+ "",
+ "COMMENT=Terminal",
+ "",
+ ".include \"../../mk/bsd.pkg.mk\"")
+
+ G.globalData.InitVartypes()
+ G.globalData.Pkgsrcdir = s.TmpDir()
+ G.CurrentDir = s.TmpDir()
+
+ (&Pkglint{}).CheckDirent(s.TmpDir() + "/x11/9term")
+
+ // Since the error is grave enough, the warning about the correct position is suppressed.
+ s.CheckOutputLines(
+ "ERROR: ~/x11/9term/Makefile: Each package must define its LICENSE.")
+}
+
// https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html
func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder__MASTER_SITES(c *check.C) {
s.Init(c)
diff --git a/pkgtools/pkglint/files/pkglint.go b/pkgtools/pkglint/files/pkglint.go
index 17f083c5b51..614ed54638c 100644
--- a/pkgtools/pkglint/files/pkglint.go
+++ b/pkgtools/pkglint/files/pkglint.go
@@ -384,7 +384,7 @@ func Checkfile(fname string) {
switch {
case st.Mode().IsDir():
switch {
- case basename == "files" || basename == "patches" || basename == "CVS":
+ case basename == "files" || basename == "patches" || isIgnoredFilename(basename):
// Ok
case matches(fname, `(?:^|/)files/[^/]*$`):
// Ok
diff --git a/pkgtools/pkglint/files/plist.go b/pkgtools/pkglint/files/plist.go
index 6c7dc9f3a3b..cd18537e397 100644
--- a/pkgtools/pkglint/files/plist.go
+++ b/pkgtools/pkglint/files/plist.go
@@ -33,15 +33,15 @@ func ChecklinesPlist(lines []Line) {
make(map[string]*PlistLine),
make(map[string]*PlistLine),
"",
- false}
+ Once{}}
ck.Check(lines)
}
type PlistChecker struct {
- allFiles map[string]*PlistLine
- allDirs map[string]*PlistLine
- lastFname string
- warnedAboutIconThemes bool
+ allFiles map[string]*PlistLine
+ allDirs map[string]*PlistLine
+ lastFname string
+ once Once
}
type PlistLine struct {
@@ -365,7 +365,7 @@ func (ck *PlistChecker) checkpathShare(pline *PlistLine) {
case hasPrefix(text, "share/icons/") && G.Pkg != nil:
if hasPrefix(text, "share/icons/hicolor/") && G.Pkg.Pkgpath != "graphics/hicolor-icon-theme" {
f := "../../graphics/hicolor-icon-theme/buildlink3.mk"
- if G.Pkg.included[f] == nil {
+ if G.Pkg.included[f] == nil && ck.once.FirstTime("hicolor-icon-theme") {
line.Errorf("Packages that install hicolor icons must include %q in the Makefile.", f)
}
}
@@ -380,9 +380,8 @@ func (ck *PlistChecker) checkpathShare(pline *PlistLine) {
}
}
- if !ck.warnedAboutIconThemes && contains(text[12:], "/") && G.Pkg.vardef["ICON_THEMES"] == nil {
+ if contains(text[12:], "/") && G.Pkg.vardef["ICON_THEMES"] == nil && ck.once.FirstTime("ICON_THEMES") {
line.Warnf("Packages that install icon theme files should set ICON_THEMES.")
- ck.warnedAboutIconThemes = true
}
case hasPrefix(text, "share/doc/html/"):
diff --git a/pkgtools/pkglint/files/plist_test.go b/pkgtools/pkglint/files/plist_test.go
index c4c674f1381..09dcd634c4e 100644
--- a/pkgtools/pkglint/files/plist_test.go
+++ b/pkgtools/pkglint/files/plist_test.go
@@ -23,6 +23,8 @@ func (s *Suite) Test_ChecklinesPlist(c *check.C) {
"${PLIST.obsolete}@unexec rmdir /tmp",
"sbin/clockctl",
"share/icons/gnome/delete-icon",
+ "share/icons/hicolor/icon1.png",
+ "share/icons/hicolor/icon2.png", // No additional warning
"share/tzinfo",
"share/tzinfo")
@@ -45,7 +47,8 @@ func (s *Suite) Test_ChecklinesPlist(c *check.C) {
"WARN: PLIST:13: Manual page missing for sbin/clockctl.",
"ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".",
"WARN: PLIST:14: Packages that install icon theme files should set ICON_THEMES.",
- "ERROR: PLIST:16: Duplicate filename \"share/tzinfo\", already appeared in line 15.")
+ "ERROR: PLIST:15: Packages that install hicolor icons must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.",
+ "ERROR: PLIST:18: Duplicate filename \"share/tzinfo\", already appeared in line 17.")
}
func (s *Suite) Test_ChecklinesPlist__empty(c *check.C) {
@@ -127,7 +130,7 @@ func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
"${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", // Double conditional, see graphics/graphviz
"lib/after.la",
"@exec echo \"after lib/after.la\"")
- ck := &PlistChecker{nil, nil, "", false}
+ ck := &PlistChecker{nil, nil, "", Once{}}
plines := ck.NewLines(lines)
sorter1 := NewPlistLineSorter(plines)
@@ -135,7 +138,7 @@ func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
cleanedLines := append(append(lines[0:5], lines[6:8]...), lines[9:]...) // Remove ${UNKNOWN} and @exec
- sorter2 := NewPlistLineSorter((&PlistChecker{nil, nil, "", false}).NewLines(cleanedLines))
+ sorter2 := NewPlistLineSorter((&PlistChecker{nil, nil, "", Once{}}).NewLines(cleanedLines))
c.Check(sorter2.unsortable, check.IsNil)
diff --git a/pkgtools/pkglint/files/shell.go b/pkgtools/pkglint/files/shell.go
index e45be3c6d1a..ac6b1450930 100644
--- a/pkgtools/pkglint/files/shell.go
+++ b/pkgtools/pkglint/files/shell.go
@@ -767,14 +767,53 @@ func (scc *ShellProgramChecker) checkPipeExitcode(line Line, pipeline *MkShPipel
defer trace.Call()()
}
+ oneOf := func(s string, others ...string) bool {
+ for _, other := range others {
+ if s == other {
+ return true
+ }
+ }
+ return false
+ }
+
+ canFail := func() (bool, string) {
+ for _, cmd := range pipeline.Cmds[:len(pipeline.Cmds)-1] {
+ simple := cmd.Simple
+ if simple == nil {
+ return true, ""
+ }
+ if len(simple.Redirections) != 0 {
+ return true, simple.Name.MkText
+ }
+ tool := G.globalData.Tools.FindByCommand(simple.Name)
+ switch {
+ case tool == nil:
+ return true, simple.Name.MkText
+ case oneOf(tool.Name, "echo", "printf"):
+ case oneOf(tool.Name, "sed", "gsed", "grep", "ggrep") && len(simple.Args) == 1:
+ break
+ default:
+ return true, simple.Name.MkText
+ }
+ }
+ return false, ""
+ }
+
if G.opts.WarnExtra && len(pipeline.Cmds) > 1 {
- line.Warnf("The exitcode of the left-hand-side command of the pipe operator is ignored.")
- Explain(
- "In a shell command like \"cat *.txt | grep keyword\", if the command",
- "on the left side of the \"|\" fails, this failure is ignored.",
- "",
- "If you need to detect the failure of the left-hand-side command, use",
- "temporary files to save the output of the command.")
+ if canFail, cmd := canFail(); canFail {
+ if cmd != "" {
+ line.Warnf("The exitcode of %q at the left of the | operator is ignored.", cmd)
+ } else {
+ line.Warnf("The exitcode of the command at the left of the | operator is ignored.")
+ }
+ Explain(
+ "In a shell command like \"cat *.txt | grep keyword\", if the command",
+ "on the left side of the \"|\" fails, this failure is ignored.",
+ "",
+ "If you need to detect the failure of the left-hand-side command, use",
+ "temporary files to save the output of the command. A good place to",
+ "create those files is in ${WRKDIR}.")
+ }
}
}
diff --git a/pkgtools/pkglint/files/shell_test.go b/pkgtools/pkglint/files/shell_test.go
index dd57e43dcee..09d10cf947e 100644
--- a/pkgtools/pkglint/files/shell_test.go
+++ b/pkgtools/pkglint/files/shell_test.go
@@ -179,7 +179,7 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
shline.CheckShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")
s.CheckOutputLines(
- "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.",
+ "WARN: fname:1: The exitcode of \"unzip\" at the left of the | operator is ignored.",
"WARN: fname:1: Unknown shell command \"unzip\".",
"WARN: fname:1: Unknown shell command \"awk\".")
@@ -194,7 +194,7 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
s.CheckOutputLines(
"WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?",
- "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.",
+ "WARN: fname:1: The exitcode of \"${UNZIP_CMD}\" at the left of the | operator is ignored.",
"WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?",
"WARN: fname:1: Unknown shell command \"awk\".",
"WARN: fname:1: Unknown shell command \"${MKDIR}\".",
@@ -263,6 +263,39 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine__show_autofix(c *check.C) {
"AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".")
}
+// Simple commands like echo(1) or printf(1) are assumed to never fail.
+func (s *Suite) Test_ShellLine_CheckShellCommandLine__exitcode(c *check.C) {
+ s.Init(c)
+ s.UseCommandLine("-Wall")
+ G.globalData.InitVartypes()
+ s.RegisterTool(&Tool{Name: "cat", Predefined: true})
+ s.RegisterTool(&Tool{Name: "echo", Predefined: true})
+ s.RegisterTool(&Tool{Name: "printf", Predefined: true})
+ s.RegisterTool(&Tool{Name: "sed", Predefined: true})
+ s.RegisterTool(&Tool{Name: "right-side", Predefined: true})
+ G.Mk = s.NewMkLines("Makefile",
+ "\t echo | right-side",
+ "\t sed s,s,s, | right-side",
+ "\t printf | sed s,s,s, | right-side ",
+ "\t cat | right-side",
+ "\t cat | echo | right-side",
+ "\t echo | cat | right-side",
+ "\t sed s,s,s, filename | right-side",
+ "\t sed s,s,s < input | right-side")
+
+ for _, mkline := range G.Mk.mklines {
+ shline := NewShellLine(mkline)
+ shline.CheckShellCommandLine(mkline.Shellcmd())
+ }
+
+ s.CheckOutputLines(
+ "WARN: Makefile:4: The exitcode of \"cat\" at the left of the | operator is ignored.",
+ "WARN: Makefile:5: The exitcode of \"cat\" at the left of the | operator is ignored.",
+ "WARN: Makefile:6: The exitcode of \"cat\" at the left of the | operator is ignored.",
+ "WARN: Makefile:7: The exitcode of \"sed\" at the left of the | operator is ignored.",
+ "WARN: Makefile:8: The exitcode of \"sed\" at the left of the | operator is ignored.")
+}
+
func (s *Suite) Test_ShellLine_CheckShellCommandLine__autofix(c *check.C) {
s.Init(c)
s.UseCommandLine("-Wall", "--autofix")
diff --git a/pkgtools/pkglint/files/shtypes.go b/pkgtools/pkglint/files/shtypes.go
index 1c37844b8cf..084fc6b67ac 100644
--- a/pkgtools/pkglint/files/shtypes.go
+++ b/pkgtools/pkglint/files/shtypes.go
@@ -55,6 +55,14 @@ func (token *ShAtom) String() string {
return fmt.Sprintf("ShAtom(%v, %q, %s)", token.Type, token.MkText, token.Quoting)
}
+// Returns nil for plain shell tokens.
+func (atom *ShAtom) VarUse() *MkVarUse {
+ if atom.Type == shtVaruse {
+ return atom.Data.(*MkVarUse)
+ }
+ return nil
+}
+
// ShQuoting describes the context in which a string appears
// and how it must be unescaped to get its literal value.
type ShQuoting uint8
diff --git a/pkgtools/pkglint/files/util.go b/pkgtools/pkglint/files/util.go
index 7961efd69dd..aaf8f19bfae 100644
--- a/pkgtools/pkglint/files/util.go
+++ b/pkgtools/pkglint/files/util.go
@@ -68,7 +68,7 @@ func isEmptyDir(fname string) bool {
}
for _, dirent := range dirents {
name := dirent.Name()
- if name == "." || name == ".." || name == "CVS" {
+ if isIgnoredFilename(name) {
continue
}
if dirent.IsDir() && isEmptyDir(fname+"/"+name) {
@@ -88,13 +88,21 @@ func getSubdirs(fname string) []string {
var subdirs []string
for _, dirent := range dirents {
name := dirent.Name()
- if name != "." && name != ".." && name != "CVS" && dirent.IsDir() && !isEmptyDir(fname+"/"+name) {
+ if dirent.IsDir() && !isIgnoredFilename(name) && !isEmptyDir(fname+"/"+name) {
subdirs = append(subdirs, name)
}
}
return subdirs
}
+func isIgnoredFilename(fileName string) bool {
+ switch fileName {
+ case ".", "..", "CVS", ".svn", ".git", ".hg":
+ return true
+ }
+ return false
+}
+
// Checks whether a file is already committed to the CVS repository.
func isCommitted(fname string) bool {
lines := loadCvsEntries(fname)
@@ -333,3 +341,20 @@ func hasAlnumPrefix(s string) bool {
b := s[0]
return '0' <= b && b <= '9' || 'A' <= b && b <= 'Z' || b == '_' || 'a' <= b && b <= 'z'
}
+
+// Once remembers with which arguments its FirstTime method has been called
+// and only returns true on each first call.
+type Once struct {
+ seen map[string]bool
+}
+
+func (o *Once) FirstTime(what string) bool {
+ if o.seen == nil {
+ o.seen = make(map[string]bool)
+ }
+ if _, ok := o.seen[what]; ok {
+ return false
+ }
+ o.seen[what] = true
+ return true
+}