summaryrefslogtreecommitdiff
path: root/pkgtools/pkglint
diff options
context:
space:
mode:
authorrillig <rillig@pkgsrc.org>2017-01-01 15:15:47 +0000
committerrillig <rillig@pkgsrc.org>2017-01-01 15:15:47 +0000
commitebab391e418b3f90bae1e17f5906d6221d08e571 (patch)
tree64a1241dafec2bf309a66f45501b6a582ad017f2 /pkgtools/pkglint
parentea9063dc3c6e546486252c0acc97c4bc8f0126d6 (diff)
downloadpkgsrc-ebab391e418b3f90bae1e17f5906d6221d08e571.tar.gz
Cleaned up and refactored code.
The getopt and pkgver code have been extracted to separate packages to make them reusable. Several other functions have been moved to make the structure easier to understand: * dir.go and main.go have been moved to pkglint.go * utility functions from pkglint.go have been moved to mkline.go Now pkglint.go contains only high-level code.
Diffstat (limited to 'pkgtools/pkglint')
-rw-r--r--pkgtools/pkglint/Makefile19
-rw-r--r--pkgtools/pkglint/files/buildlink3.go3
-rw-r--r--pkgtools/pkglint/files/category_test.go2
-rw-r--r--pkgtools/pkglint/files/dir.go49
-rw-r--r--pkgtools/pkglint/files/dir_test.go39
-rw-r--r--pkgtools/pkglint/files/files.go16
-rw-r--r--pkgtools/pkglint/files/getopt/getopt.go (renamed from pkgtools/pkglint/files/getopt.go)12
-rw-r--r--pkgtools/pkglint/files/getopt/getopt_test.go (renamed from pkgtools/pkglint/files/getopt_test.go)40
-rw-r--r--pkgtools/pkglint/files/globaldata.go2
-rw-r--r--pkgtools/pkglint/files/licenses.go2
-rw-r--r--pkgtools/pkglint/files/line.go4
-rw-r--r--pkgtools/pkglint/files/main.go174
-rw-r--r--pkgtools/pkglint/files/main_test.go40
-rw-r--r--pkgtools/pkglint/files/mkline.go144
-rw-r--r--pkgtools/pkglint/files/mkline_test.go53
-rw-r--r--pkgtools/pkglint/files/mklines.go2
-rw-r--r--pkgtools/pkglint/files/mkshparser_test.go4
-rw-r--r--pkgtools/pkglint/files/package.go36
-rw-r--r--pkgtools/pkglint/files/parser.go9
-rw-r--r--pkgtools/pkglint/files/patches.go2
-rw-r--r--pkgtools/pkglint/files/patches_test.go4
-rw-r--r--pkgtools/pkglint/files/pkglint.go368
-rw-r--r--pkgtools/pkglint/files/pkglint_test.go104
-rw-r--r--pkgtools/pkglint/files/pkgver/vercmp.go (renamed from pkgtools/pkglint/files/vercmp.go)16
-rw-r--r--pkgtools/pkglint/files/pkgver/vercmp_test.go (renamed from pkgtools/pkglint/files/vercmp_test.go)24
-rw-r--r--pkgtools/pkglint/files/plist.go2
-rw-r--r--pkgtools/pkglint/files/shell_test.go2
-rw-r--r--pkgtools/pkglint/files/shtokenizer_test.go4
-rw-r--r--pkgtools/pkglint/files/toplevel_test.go2
-rw-r--r--pkgtools/pkglint/files/util.go9
-rw-r--r--pkgtools/pkglint/files/vartype.go6
-rw-r--r--pkgtools/pkglint/files/vartypecheck.go2
32 files changed, 606 insertions, 589 deletions
diff --git a/pkgtools/pkglint/Makefile b/pkgtools/pkglint/Makefile
index 68ad8fd680d..c3f5134e732 100644
--- a/pkgtools/pkglint/Makefile
+++ b/pkgtools/pkglint/Makefile
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.505 2017/01/01 14:47:45 rillig Exp $
+# $NetBSD: Makefile,v 1.506 2017/01/01 15:15:47 rillig Exp $
PKGNAME= pkglint-5.4.14
DISTFILES= # none
@@ -10,7 +10,6 @@ COMMENT= Verifier for NetBSD packages
LICENSE= 2-clause-bsd
CONFLICTS+= pkglint4-[0-9]*
-WRKSRC= ${WRKDIR}/netbsd.org/pkglint
NO_CHECKSUM= yes
USE_LANGUAGES= c
USE_TOOLS+= pax
@@ -19,35 +18,37 @@ GO_SRCPATH= netbsd.org/pkglint
SUBST_CLASSES+= pkglint
SUBST_STAGE.pkglint= post-configure
-SUBST_FILES.pkglint+= main.go package_test.go
+SUBST_FILES.pkglint+= pkglint.go package_test.go
SUBST_SED.pkglint+= -e s\|@VERSION@\|${PKGNAME:S/pkglint-//}\|g
SUBST_SED.pkglint+= -e s\|@BMAKE@\|${MAKE:Q}\|g
do-extract:
- ${RUN} mkdir -p ${WRKDIR}/pkglint/plist-clash
- ${RUN} cd ${FILESDIR} && ${PAX} -rw *.go *.y */*.go pkglint.[01] ${WRKDIR}/pkglint
+ ${RUN} cd ${FILESDIR} && ${PAX} -rw . ${WRKDIR}/pkglint
pre-build:
${RUN} env GOPATH=${WRKDIR}:${BUILDLINK_DIR}/gopkg go generate ${GO_BUILD_PATTERN}
+pre-install:
+ ${RUN} rm -rf ${WRKDIR}/pkg
+
do-install: do-install-man
.include "../../mk/bsd.prefs.mk"
do-install-man: .PHONY
-.if !empty(MANINSTALL:Mcatinstall)
-. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss])
+.if ${MANINSTALL:Mcatinstall}
+. if ${CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss]}
${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/pkglint.1
. else
${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1
. endif
.endif
-.if !empty(MANINSTALL:Mmaninstall)
+.if ${MANINSTALL:Mmaninstall}
${INSTALL_MAN} ${WRKSRC}/pkglint.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1
.endif
.include "../../lang/go/go-package.mk"
.if !empty(PKGSRC_RUN_TEST:M[yY][eE][sS])
-.include "../../devel/go-check/buildlink3.mk"
+. include "../../devel/go-check/buildlink3.mk"
.endif
.include "../../mk/bsd.pkg.mk"
diff --git a/pkgtools/pkglint/files/buildlink3.go b/pkgtools/pkglint/files/buildlink3.go
index 1f6d6034fde..1105c696053 100644
--- a/pkgtools/pkglint/files/buildlink3.go
+++ b/pkgtools/pkglint/files/buildlink3.go
@@ -1,6 +1,7 @@
package main
import (
+ "netbsd.org/pkglint/pkgver"
"strings"
)
@@ -139,7 +140,7 @@ func ChecklinesBuildlink3Mk(mklines *MkLines) {
if doCheck {
if abi != nil && abi.lower != "" && !containsVarRef(abi.lower) {
if api != nil && api.lower != "" && !containsVarRef(api.lower) {
- if pkgverCmp(abi.lower, api.lower) < 0 {
+ if pkgver.Compare(abi.lower, api.lower) < 0 {
abiLine.Warnf("ABI version %q should be at least API version %q (see %s).",
abi.lower, api.lower, apiLine.ReferenceFrom(abiLine))
}
diff --git a/pkgtools/pkglint/files/category_test.go b/pkgtools/pkglint/files/category_test.go
index 42ab4d853d9..ee5bd700d21 100644
--- a/pkgtools/pkglint/files/category_test.go
+++ b/pkgtools/pkglint/files/category_test.go
@@ -11,7 +11,7 @@ func (s *Suite) Test_CheckdirCategory_totally_broken(c *check.C) {
"# $\n"+
"SUBDIR+=pkg1\n"+
"SUBDIR+=\u0020aaaaa\n"+
- "SUBDIR-=unknown #doesn’t work\n"+
+ "SUBDIR-=unknown #doesn\u2019t work\n"+
"\n"+
".include \"../mk/category.mk\"\n")
diff --git a/pkgtools/pkglint/files/dir.go b/pkgtools/pkglint/files/dir.go
deleted file mode 100644
index 1c5df0070b8..00000000000
--- a/pkgtools/pkglint/files/dir.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package main
-
-import (
- "os"
- "path"
-)
-
-func CheckDirent(fname string) {
- if G.opts.Debug {
- defer tracecall1(fname)()
- }
-
- st, err := os.Lstat(fname)
- if err != nil || !st.Mode().IsDir() && !st.Mode().IsRegular() {
- NewLineWhole(fname).Errorf("No such file or directory.")
- return
- }
- isDir := st.Mode().IsDir()
- isReg := st.Mode().IsRegular()
-
- G.CurrentDir = ifelseStr(isReg, path.Dir(fname), fname)
- absCurrentDir := abspath(G.CurrentDir)
- G.Wip = !G.opts.Import && matches(absCurrentDir, `/wip/|/wip$`)
- G.Infrastructure = matches(absCurrentDir, `/mk/|/mk$`)
- G.CurPkgsrcdir = findPkgsrcTopdir(G.CurrentDir)
- if G.CurPkgsrcdir == "" {
- NewLineWhole(fname).Errorf("Cannot determine the pkgsrc root directory for %q.", G.CurrentDir)
- return
- }
-
- switch {
- case isDir && isEmptyDir(fname):
- return
- case isReg:
- Checkfile(fname)
- return
- }
-
- switch G.CurPkgsrcdir {
- case "../..":
- checkdirPackage(relpath(G.globalData.Pkgsrcdir, G.CurrentDir))
- case "..":
- CheckdirCategory()
- case ".":
- CheckdirToplevel()
- default:
- NewLineWhole(fname).Errorf("Cannot check directories outside a pkgsrc tree.")
- }
-}
diff --git a/pkgtools/pkglint/files/dir_test.go b/pkgtools/pkglint/files/dir_test.go
deleted file mode 100644
index aa99c046f01..00000000000
--- a/pkgtools/pkglint/files/dir_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package main
-
-import (
- check "gopkg.in/check.v1"
-)
-
-func (s *Suite) Test_CheckDirent_outside(c *check.C) {
- s.Init(c)
- s.CreateTmpFile("empty", "")
-
- CheckDirent(s.tmpdir)
-
- c.Check(s.Output(), equals, "ERROR: ~: Cannot determine the pkgsrc root directory for \"~\".\n")
-}
-
-func (s *Suite) Test_CheckDirent(c *check.C) {
- s.Init(c)
- s.CreateTmpFile("mk/bsd.pkg.mk", "")
- s.CreateTmpFile("category/package/Makefile", "")
- s.CreateTmpFile("category/Makefile", "")
- s.CreateTmpFile("Makefile", "")
- G.globalData.Pkgsrcdir = s.tmpdir
-
- CheckDirent(s.tmpdir)
-
- c.Check(s.Output(), equals, "ERROR: ~/Makefile: Must not be empty.\n")
-
- CheckDirent(s.tmpdir + "/category")
-
- c.Check(s.Output(), equals, "ERROR: ~/category/Makefile: Must not be empty.\n")
-
- CheckDirent(s.tmpdir + "/category/package")
-
- c.Check(s.Output(), equals, "ERROR: ~/category/package/Makefile: Must not be empty.\n")
-
- CheckDirent(s.tmpdir + "/category/package/nonexistent")
-
- c.Check(s.Output(), equals, "ERROR: ~/category/package/nonexistent: No such file or directory.\n")
-}
diff --git a/pkgtools/pkglint/files/files.go b/pkgtools/pkglint/files/files.go
index 5ec188017b3..cfdf4339b33 100644
--- a/pkgtools/pkglint/files/files.go
+++ b/pkgtools/pkglint/files/files.go
@@ -6,8 +6,8 @@ import (
"strings"
)
-func LoadNonemptyLines(fname string, joinContinuationLines bool) []*Line {
- lines, err := readLines(fname, joinContinuationLines)
+func LoadNonemptyLines(fname string, joinBackslashLines bool) []*Line {
+ lines, err := readLines(fname, joinBackslashLines)
if err != nil {
NewLineWhole(fname).Errorf("Cannot be read.")
return nil
@@ -19,8 +19,8 @@ func LoadNonemptyLines(fname string, joinContinuationLines bool) []*Line {
return lines
}
-func LoadExistingLines(fname string, foldBackslashLines bool) []*Line {
- lines, err := readLines(fname, foldBackslashLines)
+func LoadExistingLines(fname string, joinBackslashLines bool) []*Line {
+ lines, err := readLines(fname, joinBackslashLines)
if err != nil {
NewLineWhole(fname).Fatalf("Cannot be read.")
}
@@ -101,16 +101,16 @@ func splitRawLine(textnl string) (leadingWhitespace, text, trailingWhitespace, c
return
}
-func readLines(fname string, joinContinuationLines bool) ([]*Line, error) {
+func readLines(fname string, joinBackslashLines bool) ([]*Line, error) {
rawText, err := ioutil.ReadFile(fname)
if err != nil {
return nil, err
}
- return convertToLogicalLines(fname, string(rawText), joinContinuationLines), nil
+ return convertToLogicalLines(fname, string(rawText), joinBackslashLines), nil
}
-func convertToLogicalLines(fname string, rawText string, joinContinuationLines bool) []*Line {
+func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []*Line {
var rawLines []*RawLine
for lineno, rawLine := range strings.SplitAfter(rawText, "\n") {
if rawLine != "" {
@@ -119,7 +119,7 @@ func convertToLogicalLines(fname string, rawText string, joinContinuationLines b
}
var loglines []*Line
- if joinContinuationLines {
+ if joinBackslashLines {
for lineno := 0; lineno < len(rawLines); {
loglines = append(loglines, getLogicalLine(fname, rawLines, &lineno))
}
diff --git a/pkgtools/pkglint/files/getopt.go b/pkgtools/pkglint/files/getopt/getopt.go
index 3b1db07acf1..b1deb30bd29 100644
--- a/pkgtools/pkglint/files/getopt.go
+++ b/pkgtools/pkglint/files/getopt/getopt.go
@@ -1,4 +1,4 @@
-package main
+package getopt
// Self-written getopt to support multi-argument options.
@@ -39,10 +39,10 @@ func (o *Options) Parse(args []string) (remainingArgs []string, err error) {
case arg == "--":
remainingArgs = append(remainingArgs, args[i+1:]...)
return
- case hasPrefix(arg, "--"):
+ case strings.HasPrefix(arg, "--"):
skip, err = o.parseLongOption(args, i, arg[2:])
i += skip
- case hasPrefix(arg, "-"):
+ case strings.HasPrefix(arg, "-"):
skip, err = o.parseShortOptions(args, i, arg[1:])
i += skip
default:
@@ -165,7 +165,11 @@ func (o *Options) Help(out io.Writer, generalUsage string) {
io.WriteString(wr, " all\t all of the following\n")
io.WriteString(wr, " none\t none of the following\n")
for _, flag := range flagGroup.flags {
- fmt.Fprintf(wr, " %s\t %s (%v)\n", flag.name, flag.help, ifelseStr(*flag.value, "enabled", "disabled"))
+ state := "disabled"
+ if *flag.value {
+ state = "enabled"
+ }
+ fmt.Fprintf(wr, " %s\t %s (%v)\n", flag.name, flag.help, state)
}
wr.Flush()
}
diff --git a/pkgtools/pkglint/files/getopt_test.go b/pkgtools/pkglint/files/getopt/getopt_test.go
index ec91f87d209..338fd3974ec 100644
--- a/pkgtools/pkglint/files/getopt_test.go
+++ b/pkgtools/pkglint/files/getopt/getopt_test.go
@@ -1,9 +1,17 @@
-package main
+package getopt
import (
check "gopkg.in/check.v1"
+ "testing"
)
+type Suite struct {
+}
+
+var _ = check.Suite(new(Suite))
+
+func Test(t *testing.T) { check.TestingT(t) }
+
func (s *Suite) Test_Options_Parse_short(c *check.C) {
opts := NewOptions()
var help bool
@@ -13,7 +21,7 @@ func (s *Suite) Test_Options_Parse_short(c *check.C) {
c.Assert(err, check.IsNil)
c.Check(args, check.IsNil)
- c.Check(help, equals, true)
+ c.Check(help, check.Equals, true)
}
func (s *Suite) Test_Options_Parse_unknown_short(c *check.C) {
@@ -21,7 +29,7 @@ func (s *Suite) Test_Options_Parse_unknown_short(c *check.C) {
_, err := opts.Parse([]string{"progname", "-z"})
- c.Check(err.Error(), equals, "progname: unknown option: -z")
+ c.Check(err.Error(), check.Equals, "progname: unknown option: -z")
}
func (s *Suite) Test_Options_Parse_unknown_long(c *check.C) {
@@ -29,7 +37,7 @@ func (s *Suite) Test_Options_Parse_unknown_long(c *check.C) {
_, err := opts.Parse([]string{"progname", "--unknown-long"})
- c.Check(err.Error(), equals, "progname: unknown option: --unknown-long")
+ c.Check(err.Error(), check.Equals, "progname: unknown option: --unknown-long")
}
func (s *Suite) Test_Options_Parse_unknown_flag_in_group(c *check.C) {
@@ -38,15 +46,15 @@ func (s *Suite) Test_Options_Parse_unknown_flag_in_group(c *check.C) {
_, err := opts.Parse([]string{"progname", "-Wall", "-Werror"})
- c.Check(err.Error(), equals, "progname: unknown option: -Werror")
+ c.Check(err.Error(), check.Equals, "progname: unknown option: -Werror")
_, err = opts.Parse([]string{"progname", "--warnings=all", "--warnings=no-error"})
- c.Check(err.Error(), equals, "progname: unknown option: --warnings=no-error")
+ c.Check(err.Error(), check.Equals, "progname: unknown option: --warnings=no-error")
_, err = opts.Parse([]string{"progname", "-W"})
- c.Check(err.Error(), equals, "progname: option requires an argument: -W")
+ c.Check(err.Error(), check.Equals, "progname: option requires an argument: -W")
}
func (s *Suite) Test_Options_Parse_abbreviated_long(c *check.C) {
@@ -57,22 +65,22 @@ func (s *Suite) Test_Options_Parse_abbreviated_long(c *check.C) {
_, err := opts.Parse([]string{"progname", "--lo"})
- c.Check(err.Error(), equals, "progname: ambiguous option: --lo could mean --long or --longer")
+ c.Check(err.Error(), check.Equals, "progname: ambiguous option: --lo could mean --long or --longer")
args, err := opts.Parse([]string{"progname", "--long"})
c.Assert(err, check.IsNil)
c.Check(args, check.IsNil)
- c.Check(longFlag, equals, true)
- c.Check(longerFlag, equals, false)
+ c.Check(longFlag, check.Equals, true)
+ c.Check(longerFlag, check.Equals, false)
longFlag = false
args, err = opts.Parse([]string{"progname", "--longe"})
c.Assert(err, check.IsNil)
c.Check(args, check.IsNil)
- c.Check(longFlag, equals, false)
- c.Check(longerFlag, equals, true)
+ c.Check(longFlag, check.Equals, false)
+ c.Check(longerFlag, check.Equals, true)
}
func (s *Suite) Test_Options_Parse_mixed_args_and_options(c *check.C) {
@@ -85,8 +93,8 @@ func (s *Suite) Test_Options_Parse_mixed_args_and_options(c *check.C) {
c.Assert(err, check.IsNil)
c.Check(args, check.DeepEquals, []string{"arg1", "arg2"})
- c.Check(aflag, equals, true)
- c.Check(bflag, equals, true)
+ c.Check(aflag, check.Equals, true)
+ c.Check(bflag, check.Equals, true)
aflag = false
bflag = false
@@ -94,6 +102,6 @@ func (s *Suite) Test_Options_Parse_mixed_args_and_options(c *check.C) {
c.Assert(err, check.IsNil)
c.Check(args, check.DeepEquals, []string{"arg1", "-b", "arg2"})
- c.Check(aflag, equals, true)
- c.Check(bflag, equals, false)
+ c.Check(aflag, check.Equals, true)
+ c.Check(bflag, check.Equals, false)
}
diff --git a/pkgtools/pkglint/files/globaldata.go b/pkgtools/pkglint/files/globaldata.go
index c91076cb854..f82a3c935ab 100644
--- a/pkgtools/pkglint/files/globaldata.go
+++ b/pkgtools/pkglint/files/globaldata.go
@@ -230,7 +230,7 @@ func (gd *GlobalData) loadTools() {
// Some user-defined variables do not influence the binary
// package at all and therefore do not have to be added to
- // BUILD_DEFS; therefore they are marked as “already added”.
+ // BUILD_DEFS; therefore they are marked as "already added".
systemBuildDefs["DISTDIR"] = true
systemBuildDefs["FETCH_CMD"] = true
systemBuildDefs["FETCH_OUTPUT_ARGS"] = true
diff --git a/pkgtools/pkglint/files/licenses.go b/pkgtools/pkglint/files/licenses.go
index 0deff0939b9..5051560ad99 100644
--- a/pkgtools/pkglint/files/licenses.go
+++ b/pkgtools/pkglint/files/licenses.go
@@ -119,7 +119,7 @@ func (lc *LicenseChecker) checkNode(cond *LicenseCondition) {
var licenseFile string
if G.Pkg != nil {
if licenseFileValue, ok := G.Pkg.varValue("LICENSE_FILE"); ok {
- licenseFile = G.CurrentDir + "/" + resolveVarsInRelativePath(licenseFileValue, false)
+ licenseFile = G.CurrentDir + "/" + lc.MkLine.resolveVarsInRelativePath(licenseFileValue, false)
}
}
if licenseFile == "" {
diff --git a/pkgtools/pkglint/files/line.go b/pkgtools/pkglint/files/line.go
index 9e85bafa31c..29ace63f733 100644
--- a/pkgtools/pkglint/files/line.go
+++ b/pkgtools/pkglint/files/line.go
@@ -10,7 +10,7 @@ package main
// do not.
//
// Some methods allow modification of the raw lines contained in the
-// logical line, but leave the “text” field untouched. These methods are
+// logical line, but leave the Text field untouched. These methods are
// used in the --autofix mode.
import (
@@ -52,7 +52,7 @@ func NewLineMulti(fname string, firstLine, lastLine int, text string, rawLines [
return &Line{fname, int32(firstLine), int32(lastLine), text, rawLines, false, nil, nil, ""}
}
-// NewLineEOF creates a dummy line for logging, with the “line number” EOF.
+// NewLineEOF creates a dummy line for logging, with the "line number" EOF.
func NewLineEOF(fname string) *Line {
return NewLineMulti(fname, -1, 0, "", nil)
}
diff --git a/pkgtools/pkglint/files/main.go b/pkgtools/pkglint/files/main.go
deleted file mode 100644
index 05c1a5ab992..00000000000
--- a/pkgtools/pkglint/files/main.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "os"
- "os/user"
- "path/filepath"
- "runtime/pprof"
-)
-
-const confMake = "@BMAKE@"
-const confVersion = "@VERSION@"
-
-func main() {
- G.logOut, G.logErr, G.debugOut = os.Stdout, os.Stderr, os.Stdout
- os.Exit(new(Pkglint).Main(os.Args...))
-}
-
-type Pkglint struct{}
-
-func (pkglint *Pkglint) Main(args ...string) (exitcode int) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(pkglintFatal); ok {
- exitcode = 1
- } else {
- panic(r)
- }
- }
- }()
-
- if exitcode := pkglint.ParseCommandLine(args); exitcode != nil {
- return *exitcode
- }
-
- if G.opts.PrintVersion {
- fmt.Fprintf(G.logOut, "%s\n", confVersion)
- return 0
- }
-
- if G.opts.Profiling {
- f, err := os.Create("pkglint.pprof")
- if err != nil {
- dummyLine.Fatalf("Cannot create profiling file: %s", err)
- }
- pprof.StartCPUProfile(f)
- defer pprof.StopCPUProfile()
-
- G.rematch = NewHistogram()
- G.renomatch = NewHistogram()
- G.retime = NewHistogram()
- G.loghisto = NewHistogram()
- }
-
- for _, arg := range G.opts.args {
- G.Todo = append(G.Todo, filepath.ToSlash(arg))
- }
- if len(G.Todo) == 0 {
- G.Todo = []string{"."}
- }
-
- G.globalData.Initialize()
-
- currentUser, err := user.Current()
- if err == nil {
- // On Windows, this is `Computername\Username`.
- G.CurrentUsername = regcomp(`^.*\\`).ReplaceAllString(currentUser.Username, "")
- }
-
- for len(G.Todo) != 0 {
- item := G.Todo[0]
- G.Todo = G.Todo[1:]
- CheckDirent(item)
- }
-
- checkToplevelUnusedLicenses()
- pkglint.PrintSummary()
- if G.opts.Profiling {
- G.loghisto.PrintStats("loghisto", G.logOut, 0)
- G.rematch.PrintStats("rematch", G.logOut, 10)
- G.renomatch.PrintStats("renomatch", G.logOut, 10)
- G.retime.PrintStats("retime", G.logOut, 10)
- }
- if G.errors != 0 {
- return 1
- }
- return 0
-}
-
-func (pkglint *Pkglint) ParseCommandLine(args []string) *int {
- gopts := &G.opts
- opts := NewOptions()
-
- check := opts.AddFlagGroup('C', "check", "check,...", "enable or disable specific checks")
- opts.AddFlagVar('d', "debug", &gopts.Debug, false, "log verbose call traces for debugging")
- opts.AddFlagVar('e', "explain", &gopts.Explain, false, "explain the diagnostics or give further help")
- opts.AddFlagVar('f', "show-autofix", &gopts.PrintAutofix, false, "show what pkglint can fix automatically")
- opts.AddFlagVar('F', "autofix", &gopts.Autofix, false, "try to automatically fix some errors (experimental)")
- opts.AddFlagVar('g', "gcc-output-format", &gopts.GccOutput, false, "mimic the gcc output format")
- opts.AddFlagVar('h', "help", &gopts.PrintHelp, false, "print a detailed usage message")
- opts.AddFlagVar('I', "dumpmakefile", &gopts.DumpMakefile, false, "dump the Makefile after parsing")
- opts.AddFlagVar('i', "import", &gopts.Import, false, "prepare the import of a wip package")
- opts.AddFlagVar('m', "log-verbose", &gopts.LogVerbose, false, "allow the same log message more than once")
- opts.AddFlagVar('p', "profiling", &gopts.Profiling, false, "profile the executing program")
- opts.AddFlagVar('q', "quiet", &gopts.Quiet, false, "don't print a summary line when finishing")
- opts.AddFlagVar('r', "recursive", &gopts.Recursive, false, "check subdirectories, too")
- opts.AddFlagVar('s', "source", &gopts.PrintSource, false, "show the source lines together with diagnostics")
- opts.AddFlagVar('V', "version", &gopts.PrintVersion, false, "print the version number of pkglint")
- warn := opts.AddFlagGroup('W', "warning", "warning,...", "enable or disable groups of warnings")
-
- check.AddFlagVar("ALTERNATIVES", &gopts.CheckAlternatives, true, "check ALTERNATIVES files")
- check.AddFlagVar("bl3", &gopts.CheckBuildlink3, true, "check buildlink3.mk files")
- check.AddFlagVar("DESCR", &gopts.CheckDescr, true, "check DESCR file")
- check.AddFlagVar("distinfo", &gopts.CheckDistinfo, true, "check distinfo file")
- check.AddFlagVar("extra", &gopts.CheckExtra, false, "check various additional files")
- check.AddFlagVar("global", &gopts.CheckGlobal, false, "inter-package checks")
- check.AddFlagVar("INSTALL", &gopts.CheckInstall, true, "check INSTALL and DEINSTALL scripts")
- check.AddFlagVar("Makefile", &gopts.CheckMakefile, true, "check Makefiles")
- check.AddFlagVar("MESSAGE", &gopts.CheckMessage, true, "check MESSAGE file")
- check.AddFlagVar("mk", &gopts.CheckMk, true, "check other .mk files")
- check.AddFlagVar("patches", &gopts.CheckPatches, true, "check patches")
- check.AddFlagVar("PLIST", &gopts.CheckPlist, true, "check PLIST files")
-
- warn.AddFlagVar("absname", &gopts.WarnAbsname, true, "warn about use of absolute file names")
- warn.AddFlagVar("directcmd", &gopts.WarnDirectcmd, true, "warn about use of direct command names instead of Make variables")
- warn.AddFlagVar("extra", &gopts.WarnExtra, false, "enable some extra warnings")
- warn.AddFlagVar("order", &gopts.WarnOrder, false, "warn if Makefile entries are unordered")
- warn.AddFlagVar("perm", &gopts.WarnPerm, false, "warn about unforeseen variable definition and use")
- warn.AddFlagVar("plist-depr", &gopts.WarnPlistDepr, false, "warn about deprecated paths in PLISTs")
- warn.AddFlagVar("plist-sort", &gopts.WarnPlistSort, false, "warn about unsorted entries in PLISTs")
- warn.AddFlagVar("quoting", &gopts.WarnQuoting, false, "warn about quoting issues")
- warn.AddFlagVar("space", &gopts.WarnSpace, false, "warn about inconsistent use of white-space")
- warn.AddFlagVar("style", &gopts.WarnStyle, false, "warn about stylistic issues")
- warn.AddFlagVar("types", &gopts.WarnTypes, true, "do some simple type checking in Makefiles")
-
- remainingArgs, err := opts.Parse(args)
- if err != nil {
- fmt.Fprintf(G.logErr, "%s\n\n", err)
- opts.Help(G.logErr, "pkglint [options] dir...")
- exitcode := 1
- return &exitcode
- }
- gopts.args = remainingArgs
-
- if gopts.PrintHelp {
- opts.Help(G.logOut, "pkglint [options] dir...")
- exitcode := 0
- return &exitcode
- }
-
- return nil
-}
-
-func (pkglint *Pkglint) PrintSummary() {
- if !G.opts.Quiet {
- if G.errors != 0 || G.warnings != 0 {
- fmt.Fprintf(G.logOut, "%d %s and %d %s found.\n",
- G.errors, ifelseStr(G.errors == 1, "error", "errors"),
- G.warnings, ifelseStr(G.warnings == 1, "warning", "warnings"))
- } else {
- io.WriteString(G.logOut, "looks fine.\n")
- }
- if G.explanationsAvailable && !G.opts.Explain {
- fmt.Fprint(G.logOut, "(Run \"pkglint -e\" to show explanations.)\n")
- }
- if G.autofixAvailable && !G.opts.PrintAutofix && !G.opts.Autofix {
- fmt.Fprint(G.logOut, "(Run \"pkglint -fs\" to show what can be fixed automatically.)\n")
- }
- if G.autofixAvailable && !G.opts.Autofix {
- fmt.Fprint(G.logOut, "(Run \"pkglint -F\" to automatically fix some issues.)\n")
- }
- }
-}
diff --git a/pkgtools/pkglint/files/main_test.go b/pkgtools/pkglint/files/main_test.go
deleted file mode 100644
index 48b7408fca2..00000000000
--- a/pkgtools/pkglint/files/main_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package main
-
-import (
- "os"
-
- check "gopkg.in/check.v1"
-)
-
-func (s *Suite) Test_Pkglint_Main_help(c *check.C) {
- exitcode := new(Pkglint).Main("pkglint", "-h")
-
- c.Check(exitcode, equals, 0)
- c.Check(s.Output(), check.Matches, `^\Qusage: pkglint [options] dir...\E\n(?s).+`)
-}
-
-func (s *Suite) Test_Pkglint_Main_version(c *check.C) {
- exitcode := new(Pkglint).Main("pkglint", "--version")
-
- c.Check(exitcode, equals, 0)
- c.Check(s.Output(), equals, confVersion+"\n")
-}
-
-func (s *Suite) Test_Pkglint_Main_no_args(c *check.C) {
- exitcode := new(Pkglint).Main("pkglint")
-
- c.Check(exitcode, equals, 1)
- c.Check(s.Stderr(), equals, "FATAL: \".\" is not inside a pkgsrc tree.\n")
-}
-
-// go test -c -covermode count
-// pkgsrcdir=...
-// env PKGLINT_TESTCMDLINE="$pkgsrcdir -r" ./pkglint.test -test.coverprofile pkglint.cov -check.f TestRunPkglint
-// go tool cover -html=pkglint.cov -o coverage.html
-func (s *Suite) Test_Pkglint_coverage(c *check.C) {
- cmdline := os.Getenv("PKGLINT_TESTCMDLINE")
- if cmdline != "" {
- G.logOut, G.logErr, G.debugOut = os.Stdout, os.Stderr, os.Stdout
- new(Pkglint).Main(append([]string{"pkglint"}, splitOnSpace(cmdline)...)...)
- }
-}
diff --git a/pkgtools/pkglint/files/mkline.go b/pkgtools/pkglint/files/mkline.go
index 6e46ffcabea..a0e0d84a612 100644
--- a/pkgtools/pkglint/files/mkline.go
+++ b/pkgtools/pkglint/files/mkline.go
@@ -216,7 +216,7 @@ func (mkline *MkLine) checkInclude() {
includefile := mkline.Includefile()
mustExist := mkline.MustExist()
if G.opts.Debug {
- traceStep1("includefile=%s", includefile)
+ traceStep2("includingFile=%s includefile=%s", mkline.Fname, includefile)
}
mkline.CheckRelativePath(includefile, mustExist)
@@ -1106,6 +1106,44 @@ func (mkline *MkLine) withoutMakeVariables(value string) string {
}
}
+func (mkline *MkLine) resolveVarsInRelativePath(relpath string, adjustDepth bool) string {
+ tmp := relpath
+ tmp = strings.Replace(tmp, "${PKGSRCDIR}", G.CurPkgsrcdir, -1)
+ tmp = strings.Replace(tmp, "${.CURDIR}", ".", -1)
+ tmp = strings.Replace(tmp, "${.PARSEDIR}", ".", -1)
+ if contains(tmp, "${LUA_PKGSRCDIR}") {
+ tmp = strings.Replace(tmp, "${LUA_PKGSRCDIR}", G.globalData.Latest("lang", `^lua[0-9]+$`, "../../lang/$0"), -1)
+ }
+ if contains(tmp, "${PHPPKGSRCDIR}") {
+ tmp = strings.Replace(tmp, "${PHPPKGSRCDIR}", G.globalData.Latest("lang", `^php[0-9]+$`, "../../lang/$0"), -1)
+ }
+ if contains(tmp, "${SUSE_DIR_PREFIX}") {
+ suseDirPrefix := G.globalData.Latest("emulators", `^(suse[0-9]+)_base`, "$1")
+ tmp = strings.Replace(tmp, "${SUSE_DIR_PREFIX}", suseDirPrefix, -1)
+ }
+ if contains(tmp, "${PYPKGSRCDIR}") {
+ tmp = strings.Replace(tmp, "${PYPKGSRCDIR}", G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0"), -1)
+ }
+ if contains(tmp, "${PYPACKAGE}") {
+ tmp = strings.Replace(tmp, "${PYPACKAGE}", G.globalData.Latest("lang", `^python[0-9]+$`, "$0"), -1)
+ }
+ if G.Pkg != nil {
+ tmp = strings.Replace(tmp, "${FILESDIR}", G.Pkg.Filesdir, -1)
+ tmp = strings.Replace(tmp, "${PKGDIR}", G.Pkg.Pkgdir, -1)
+ }
+
+ if adjustDepth {
+ if m, pkgpath := match1(tmp, `^\.\./\.\./([^.].*)$`); m {
+ tmp = G.CurPkgsrcdir + "/" + pkgpath
+ }
+ }
+
+ if G.opts.Debug {
+ traceStep2("resolveVarsInRelativePath: %q => %q", relpath, tmp)
+ }
+ return tmp
+}
+
func (mkline *MkLine) checkText(text string) {
if G.opts.Debug {
defer tracecall1(text)()
@@ -1262,8 +1300,12 @@ func (mkline *MkLine) explainRelativeDirs() {
}
func (mkline *MkLine) CheckRelativePkgdir(pkgdir string) {
+ if G.opts.Debug {
+ defer tracecall1(pkgdir)()
+ }
+
mkline.CheckRelativePath(pkgdir, true)
- pkgdir = resolveVarsInRelativePath(pkgdir, false)
+ pkgdir = mkline.resolveVarsInRelativePath(pkgdir, false)
if m, otherpkgpath := match1(pkgdir, `^(?:\./)?\.\./\.\./([^/]+/[^/]+)$`); m {
if !fileExists(G.globalData.Pkgsrcdir + "/" + otherpkgpath + "/Makefile") {
@@ -1280,11 +1322,15 @@ func (mkline *MkLine) CheckRelativePkgdir(pkgdir string) {
}
func (mkline *MkLine) CheckRelativePath(path string, mustExist bool) {
+ if G.opts.Debug {
+ defer tracecall(path, mustExist)()
+ }
+
if !G.Wip && contains(path, "/wip/") {
mkline.Line.Errorf("A main pkgsrc package must not depend on a pkgsrc-wip package.")
}
- resolvedPath := resolveVarsInRelativePath(path, true)
+ resolvedPath := mkline.resolveVarsInRelativePath(path, true)
if containsVarRef(resolvedPath) {
return
}
@@ -1621,7 +1667,7 @@ func (mkline *MkLine) determineUsedVariables() (varnames []string) {
// VarUseContext defines the context in which a variable is defined
// or used. Whether that is allowed depends on:
//
-// * The variable’s data type, as defined in vardefs.go.
+// * The variable's data type, as defined in vardefs.go.
// * When used on the right-hand side of an assigment, the variable can
// represent a list of words, a single word or even only part of a
// word. This distinction decides upon the correct use of the :Q
@@ -1629,7 +1675,7 @@ func (mkline *MkLine) determineUsedVariables() (varnames []string) {
// * When used in preprocessing statements like .if or .for, the other
// operands of that statement should fit to the variable and are
// checked against the variable type. For example, comparing OPSYS to
-// x86_64 doesn’t make sense.
+// x86_64 doesn't make sense.
type VarUseContext struct {
vartype *Vartype
time vucTime
@@ -1649,7 +1695,7 @@ const (
vucTimeParse
// All files have been read, all variables can be referenced.
- // Variable values don’t change anymore.
+ // Variable values don't change anymore.
vucTimeRun
)
@@ -1756,6 +1802,92 @@ func (ind *Indentation) Varnames() string {
return varnames
}
+func MatchVarassign(text string) (m bool, varname, spaceAfterVarname, op, valueAlign, value, spaceAfterValue, comment string) {
+ i, n := 0, len(text)
+
+ for i < n && text[i] == ' ' {
+ i++
+ }
+
+ varnameStart := i
+ for ; i < n; i++ {
+ b := text[i]
+ switch {
+ case 'A' <= b && b <= 'Z',
+ 'a' <= b && b <= 'z',
+ b == '_',
+ '0' <= b && b <= '9',
+ '$' <= b && b <= '.' && (b == '$' || b == '*' || b == '+' || b == '-' || b == '.'),
+ b == '[',
+ b == '{', b == '}':
+ continue
+ }
+ break
+ }
+ varnameEnd := i
+
+ if varnameEnd == varnameStart {
+ return
+ }
+
+ for i < n && (text[i] == ' ' || text[i] == '\t') {
+ i++
+ }
+
+ opStart := i
+ if i < n {
+ if b := text[i]; b == '!' || b == '+' || b == ':' || b == '?' {
+ i++
+ }
+ }
+ if i < n && text[i] == '=' {
+ i++
+ } else {
+ return
+ }
+ opEnd := i
+
+ if text[varnameEnd-1] == '+' && varnameEnd == opStart && text[opStart] == '=' {
+ varnameEnd--
+ opStart--
+ }
+
+ for i < n && (text[i] == ' ' || text[i] == '\t') {
+ i++
+ }
+
+ valueStart := i
+ valuebuf := make([]byte, n-valueStart)
+ j := 0
+ for ; i < n; i++ {
+ b := text[i]
+ if b == '#' && (i == valueStart || text[i-1] != '\\') {
+ break
+ } else if b != '\\' || i+1 >= n || text[i+1] != '#' {
+ valuebuf[j] = b
+ j++
+ }
+ }
+
+ commentStart := i
+ for text[i-1] == ' ' || text[i-1] == '\t' {
+ i--
+ }
+ valueEnd := i
+
+ commentEnd := n
+
+ m = true
+ varname = text[varnameStart:varnameEnd]
+ spaceAfterVarname = text[varnameEnd:opStart]
+ op = text[opStart:opEnd]
+ valueAlign = text[0:valueStart]
+ value = strings.TrimSpace(string(valuebuf[:j]))
+ spaceAfterValue = text[valueEnd:commentStart]
+ comment = text[commentStart:commentEnd]
+ return
+}
+
func MatchMkInclude(text string) (m bool, indentation, directive, filename string) {
return match3(text, `^\.(\s*)(s?include)\s+\"([^\"]+)\"\s*(?:#.*)?$`)
}
diff --git a/pkgtools/pkglint/files/mkline_test.go b/pkgtools/pkglint/files/mkline_test.go
index 40b0b11540c..a2a66eee717 100644
--- a/pkgtools/pkglint/files/mkline_test.go
+++ b/pkgtools/pkglint/files/mkline_test.go
@@ -414,7 +414,7 @@ func (s *Suite) Test_MkLine_CheckVarusePermissions__load_time(c *check.C) {
mklines.Check()
- c.Check(s.Output(), equals, "") // Don’t warn that “.CURDIR should not be evaluated at load time.”
+ c.Check(s.Output(), equals, "") // Don't warn that ".CURDIR should not be evaluated at load time."
}
func (s *Suite) Test_MkLine_WarnVaruseLocalbase(c *check.C) {
@@ -606,7 +606,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__URL_as_part_of_word_in_list(c
G.Mk.mklines[1].Check()
- c.Check(s.Output(), equals, "") // Don’t suggest to use ${HOMEPAGE:Q}.
+ c.Check(s.Output(), equals, "") // Don't suggest to use ${HOMEPAGE:Q}.
}
// Pkglint currently does not parse $$(subshell) commands very well. As
@@ -628,7 +628,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_subshell(c *check.C
G.Mk.mklines[1].Check()
G.Mk.mklines[2].Check()
- c.Check(s.Output(), equals, "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.\n") // Don’t suggest to use ${AWK:Q}.
+ c.Check(s.Output(), equals, "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.\n") // Don't suggest to use ${AWK:Q}.
}
// LDFLAGS (and even more so CPPFLAGS and CFLAGS) may contain special
@@ -682,7 +682,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_quotes_in_subshell_in_
G.Mk.mklines[1].Check()
- c.Check(s.Output(), equals, "") // Don’t suggest ${ECHO:Q} here.
+ c.Check(s.Output(), equals, "") // Don't suggest ${ECHO:Q} here.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting__LDADD_in_BUILDLINK_TRANSFORM(c *check.C) {
@@ -707,7 +707,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting_command_in_message(c *check.C)
G.Mk.mklines[0].Check()
- c.Check(s.Output(), equals, "") // Don’t suggest ${REPLACE_PERL:Q}.
+ c.Check(s.Output(), equals, "") // Don't suggest ${REPLACE_PERL:Q}.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting_guessed_list_variable_in_quotes(c *check.C) {
@@ -734,7 +734,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting_list_in_list(c *check.C) {
G.Mk.Check()
- c.Check(s.Output(), equals, "") // Don’t warn about missing :Q operators.
+ c.Check(s.Output(), equals, "") // Don't warn about missing :Q modifiers.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting_PKGNAME_and_URL_list_in_URL_list(c *check.C) {
@@ -748,7 +748,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting_PKGNAME_and_URL_list_in_URL_lis
G.Mk.mklines[1].checkVarassignVaruse()
- c.Check(s.Output(), equals, "") // Don’t warn about missing :Q operators.
+ c.Check(s.Output(), equals, "") // Don't warn about missing :Q modifiers.
}
func (s *Suite) Test_MkLine_variableNeedsQuoting_tool_in_CONFIGURE_ENV(c *check.C) {
@@ -779,7 +779,7 @@ func (s *Suite) Test_MkLine_Varuse_Modifier_L(c *check.C) {
G.Mk.mklines[0].Check()
- c.Check(s.Output(), equals, "") // Don’t warn that ${XKBBASE}/xkbcomp is used but not defined.
+ c.Check(s.Output(), equals, "") // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
}
func (s *Suite) Test_MkLine_CheckCond_comparison_with_shell_command(c *check.C) {
@@ -793,7 +793,7 @@ func (s *Suite) Test_MkLine_CheckCond_comparison_with_shell_command(c *check.C)
G.Mk.Check()
- // Don’t warn about unknown shell command "cc".
+ // Don't warn about unknown shell command "cc".
c.Check(s.Output(), equals, "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.\n")
}
@@ -924,6 +924,41 @@ func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) {
c.Check(s.Output(), equals, "WARN: Makefile:2: The # character starts a comment.\n")
}
+func (s *Suite) Test_MatchVarassign(c *check.C) {
+ checkVarassign := func(text string, ck check.Checker, varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string) {
+ type va struct {
+ varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string
+ }
+ expected := va{varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment}
+ am, avarname, aspaceAfterVarname, aop, aalign, avalue, aspaceAfterValue, acomment := MatchVarassign(text)
+ if !am {
+ c.Errorf("Text %q doesn't match variable assignment", text)
+ return
+ }
+ actual := va{avarname, aspaceAfterVarname, aop, aalign, avalue, aspaceAfterValue, acomment}
+ c.Check(actual, ck, expected)
+ }
+ checkNotVarassign := func(text string) {
+ m, _, _, _, _, _, _, _ := MatchVarassign(text)
+ if m {
+ c.Errorf("Text %q matches variable assignment, but shouldn't.", text)
+ }
+ }
+
+ checkVarassign("C++=c11", equals, "C+", "", "+=", "C++=", "c11", "", "")
+ checkVarassign("V=v", equals, "V", "", "=", "V=", "v", "", "")
+ checkVarassign("VAR=#comment", equals, "VAR", "", "=", "VAR=", "", "", "#comment")
+ checkVarassign("VAR=\\#comment", equals, "VAR", "", "=", "VAR=", "#comment", "", "")
+ checkVarassign("VAR=\\\\\\##comment", equals, "VAR", "", "=", "VAR=", "\\\\#", "", "#comment")
+ checkVarassign("VAR=\\", equals, "VAR", "", "=", "VAR=", "\\", "", "")
+ checkVarassign("VAR += value", equals, "VAR", " ", "+=", "VAR += ", "value", "", "")
+ checkVarassign(" VAR=value", equals, "VAR", "", "=", " VAR=", "value", "", "")
+ checkVarassign("VAR=value #comment", equals, "VAR", "", "=", "VAR=", "value", " ", "#comment")
+ checkNotVarassign("\tVAR=value")
+ checkNotVarassign("?=value")
+ checkNotVarassign("<=value")
+}
+
func (s *Suite) Test_Indentation(c *check.C) {
ind := &Indentation{}
diff --git a/pkgtools/pkglint/files/mklines.go b/pkgtools/pkglint/files/mklines.go
index be5c3499935..3d5714656f5 100644
--- a/pkgtools/pkglint/files/mklines.go
+++ b/pkgtools/pkglint/files/mklines.go
@@ -310,7 +310,7 @@ func (va *VaralignBlock) fixalign(mkline *MkLine, prefix, oldalign string) {
return
}
- // Don’t warn about procedure parameters
+ // Don't warn about procedure parameters
if mkline.Op() == opAssignEval && matches(mkline.Varname(), `^[a-z]`) {
return
}
diff --git a/pkgtools/pkglint/files/mkshparser_test.go b/pkgtools/pkglint/files/mkshparser_test.go
index f1682b17190..0e12065a552 100644
--- a/pkgtools/pkglint/files/mkshparser_test.go
+++ b/pkgtools/pkglint/files/mkshparser_test.go
@@ -263,7 +263,7 @@ func (s *ShSuite) Test_ShellParser_for_clause(c *check.C) {
b.Words("in", "esac"),
b.List().AddCommand(b.SimpleCommand("echo", "$var")).AddSemicolon())))
- // No semicolon necessary between the two “done”.
+ // No semicolon necessary between the two "done".
s.test("for i in 1; do for j in 1; do echo $$i$$j; done done",
b.List().AddCommand(b.For(
"i",
@@ -323,7 +323,7 @@ func (s *ShSuite) Test_ShellParser_if_clause(c *check.C) {
b.List().AddCommand(b.SimpleCommand("echo", "yes")).AddSemicolon(),
b.List().AddCommand(b.SimpleCommand("echo", "no")).AddSemicolon())))
- // No semicolon necessary between the two “fi”.
+ // No semicolon necessary between the two "fi".
s.test("if cond1; then if cond2; then action; fi fi",
b.List().AddCommand(b.If(
b.List().AddCommand(b.SimpleCommand("cond1")).AddSemicolon(),
diff --git a/pkgtools/pkglint/files/package.go b/pkgtools/pkglint/files/package.go
index a953564d030..f8ff29ac886 100644
--- a/pkgtools/pkglint/files/package.go
+++ b/pkgtools/pkglint/files/package.go
@@ -2,12 +2,15 @@ package main
import (
"fmt"
+ "netbsd.org/pkglint/pkgver"
"path"
"regexp"
"strconv"
"strings"
)
+const rePkgname = `^([\w\-.+]+)-(\d(?:\w|\.\d)*)$`
+
// Package contains data for the pkgsrc package that is currently checked.
type Package struct {
Pkgpath string // e.g. "category/pkgdir"
@@ -104,7 +107,7 @@ func (pkg *Package) checkPossibleDowngrade() {
if change.Action == "Updated" {
changeVersion := regcomp(`nb\d+$`).ReplaceAllString(change.Version, "")
- if pkgverCmp(pkgversion, changeVersion) < 0 {
+ if pkgver.Compare(pkgversion, changeVersion) < 0 {
mkline.Line.Warnf("The package is being downgraded from %s (see %s) to %s", change.Version, change.Line.ReferenceFrom(mkline.Line), pkgversion)
Explain(
"The files in doc/CHANGES-*, in which all version changes are",
@@ -233,10 +236,10 @@ func (pkg *Package) loadPackageMakefile(fname string) *MkLines {
allLines.DetermineUsedVariables()
- pkg.Pkgdir = expandVariableWithDefault("PKGDIR", ".")
- pkg.DistinfoFile = expandVariableWithDefault("DISTINFO_FILE", "distinfo")
- pkg.Filesdir = expandVariableWithDefault("FILESDIR", "files")
- pkg.Patchdir = expandVariableWithDefault("PATCHDIR", "patches")
+ pkg.Pkgdir = pkg.expandVariableWithDefault("PKGDIR", ".")
+ pkg.DistinfoFile = pkg.expandVariableWithDefault("DISTINFO_FILE", "distinfo")
+ pkg.Filesdir = pkg.expandVariableWithDefault("FILESDIR", "files")
+ pkg.Patchdir = pkg.expandVariableWithDefault("PATCHDIR", "patches")
if varIsDefined("PHPEXT_MK") {
if !varIsDefined("USE_PHP_EXT_PATCHES") {
@@ -283,7 +286,7 @@ func (pkg *Package) readMakefile(fname string, mainLines *MkLines, allLines *MkL
var includeFile, incDir, incBase string
if mkline.IsInclude() {
inc := mkline.Includefile()
- includeFile = resolveVariableRefs(resolveVarsInRelativePath(inc, true))
+ includeFile = resolveVariableRefs(mkline.resolveVarsInRelativePath(inc, true))
if containsVarRef(includeFile) {
if !contains(fname, "/mk/") {
line.Notef("Skipping include file %q. This may result in false warnings.", includeFile)
@@ -326,7 +329,7 @@ func (pkg *Package) readMakefile(fname string, mainLines *MkLines, allLines *MkL
// Only look in the directory relative to the
// current file and in the current working directory.
- // Pkglint doesn’t have an include dir list, like make(1) does.
+ // Pkglint doesn't have an include dir list, like make(1) does.
if !fileExists(dirname + "/" + includeFile) {
if dirname != G.CurrentDir { // Prevent unnecessary syscalls
dirname = G.CurrentDir
@@ -530,6 +533,23 @@ func (pkg *Package) pkgnameFromDistname(pkgname, distname string) string {
return result
}
+func (pkg *Package) expandVariableWithDefault(varname, defaultValue string) string {
+ mkline := G.Pkg.vardef[varname]
+ if mkline == nil {
+ return defaultValue
+ }
+
+ value := mkline.Value()
+ value = mkline.resolveVarsInRelativePath(value, true)
+ if containsVarRef(value) {
+ value = resolveVariableRefs(value)
+ }
+ if G.opts.Debug {
+ traceStep2("Expanded %q to %q", varname, value)
+ }
+ return value
+}
+
func (pkg *Package) checkUpdate() {
if pkg.EffectivePkgbase != "" {
for _, sugg := range G.globalData.GetSuggestedPackageUpdates() {
@@ -543,7 +563,7 @@ func (pkg *Package) checkUpdate() {
}
pkgnameLine := pkg.EffectivePkgnameLine
- cmp := pkgverCmp(pkg.EffectivePkgversion, suggver)
+ cmp := pkgver.Compare(pkg.EffectivePkgversion, suggver)
switch {
case cmp < 0:
pkgnameLine.Warnf("This package should be updated to %s%s.", sugg.Version, comment)
diff --git a/pkgtools/pkglint/files/parser.go b/pkgtools/pkglint/files/parser.go
index ea417eae392..b02689923de 100644
--- a/pkgtools/pkglint/files/parser.go
+++ b/pkgtools/pkglint/files/parser.go
@@ -48,6 +48,15 @@ func (p *Parser) PkgbasePattern() (pkgbase string) {
}
}
+type DependencyPattern struct {
+ pkgbase string // "freeciv-client", "{gcc48,gcc48-libs}", "${EMACS_REQD}"
+ lowerOp string // ">=", ">"
+ lower string // "2.5.0", "${PYVER}"
+ upperOp string // "<", "<="
+ upper string // "3.0", "${PYVER}"
+ wildcard string // "[0-9]*", "1.5.*", "${PYVER}"
+}
+
func (p *Parser) Dependency() *DependencyPattern {
repl := p.repl
diff --git a/pkgtools/pkglint/files/patches.go b/pkgtools/pkglint/files/patches.go
index 2087b5b0780..4debf06e5cd 100644
--- a/pkgtools/pkglint/files/patches.go
+++ b/pkgtools/pkglint/files/patches.go
@@ -288,7 +288,7 @@ func guessFileType(line *Line, fname string) (fileType FileType) {
}
basename := path.Base(fname)
- basename = strings.TrimSuffix(basename, ".in") // doesn’t influence the content type
+ basename = strings.TrimSuffix(basename, ".in") // doesn't influence the content type
ext := strings.ToLower(strings.TrimLeft(path.Ext(basename), "."))
switch {
diff --git a/pkgtools/pkglint/files/patches_test.go b/pkgtools/pkglint/files/patches_test.go
index d57fc1fa289..c45bd39b497 100644
--- a/pkgtools/pkglint/files/patches_test.go
+++ b/pkgtools/pkglint/files/patches_test.go
@@ -117,7 +117,7 @@ func (s *Suite) Test_ChecklinesPatch__error_code(c *check.C) {
lines := s.NewLines("patch-ErrorCode",
"$"+"NetBSD$",
"",
- "*** Error code 1", // Looks like a context diff, but isn’t.
+ "*** Error code 1", // Looks like a context diff, but isn't.
"",
"--- file.orig",
"+++ file",
@@ -346,7 +346,7 @@ func (s *Suite) Test_ChecklinesPatch__empty_lines_left_out_at_eof(c *check.C) {
}
// In some context lines, the leading space character is missing.
-// Since this is no problem for patch(1), pkglint also doesn’t complain.
+// Since this is no problem for patch(1), pkglint also doesn't complain.
func (s *Suite) Test_ChecklinesPatch__context_lines_with_tab_instead_of_space(c *check.C) {
lines := s.NewLines("patch-aa",
"$"+"NetBSD$",
diff --git a/pkgtools/pkglint/files/pkglint.go b/pkgtools/pkglint/files/pkglint.go
index 0d9d94cff29..2589fe45e9c 100644
--- a/pkgtools/pkglint/files/pkglint.go
+++ b/pkgtools/pkglint/files/pkglint.go
@@ -1,14 +1,224 @@
package main
import (
+ "fmt"
+ "io"
+ "netbsd.org/pkglint/getopt"
"os"
+ "os/user"
"path"
+ "path/filepath"
+ "runtime/pprof"
"strings"
)
-const (
- rePkgname = `^([\w\-.+]+)-(\d(?:\w|\.\d)*)$`
-)
+const confMake = "@BMAKE@"
+const confVersion = "@VERSION@"
+
+func main() {
+ G.logOut, G.logErr, G.debugOut = os.Stdout, os.Stderr, os.Stdout
+ os.Exit(new(Pkglint).Main(os.Args...))
+}
+
+type Pkglint struct{}
+
+func (pkglint *Pkglint) Main(args ...string) (exitcode int) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(pkglintFatal); ok {
+ exitcode = 1
+ } else {
+ panic(r)
+ }
+ }
+ }()
+
+ if exitcode := pkglint.ParseCommandLine(args); exitcode != nil {
+ return *exitcode
+ }
+
+ if G.opts.Profiling {
+ f, err := os.Create("pkglint.pprof")
+ if err != nil {
+ dummyLine.Fatalf("Cannot create profiling file: %s", err)
+ }
+ pprof.StartCPUProfile(f)
+ defer pprof.StopCPUProfile()
+
+ G.rematch = NewHistogram()
+ G.renomatch = NewHistogram()
+ G.retime = NewHistogram()
+ G.loghisto = NewHistogram()
+ }
+
+ for _, arg := range G.opts.args {
+ G.Todo = append(G.Todo, filepath.ToSlash(arg))
+ }
+ if len(G.Todo) == 0 {
+ G.Todo = []string{"."}
+ }
+
+ G.globalData.Initialize()
+
+ currentUser, err := user.Current()
+ if err == nil {
+ // On Windows, this is `Computername\Username`.
+ G.CurrentUsername = regcomp(`^.*\\`).ReplaceAllString(currentUser.Username, "")
+ }
+
+ for len(G.Todo) != 0 {
+ item := G.Todo[0]
+ G.Todo = G.Todo[1:]
+ pkglint.CheckDirent(item)
+ }
+
+ checkToplevelUnusedLicenses()
+ pkglint.PrintSummary()
+ if G.opts.Profiling {
+ G.loghisto.PrintStats("loghisto", G.logOut, 0)
+ G.rematch.PrintStats("rematch", G.logOut, 10)
+ G.renomatch.PrintStats("renomatch", G.logOut, 10)
+ G.retime.PrintStats("retime", G.logOut, 10)
+ }
+ if G.errors != 0 {
+ return 1
+ }
+ return 0
+}
+
+func (pkglint *Pkglint) ParseCommandLine(args []string) *int {
+ gopts := &G.opts
+ opts := getopt.NewOptions()
+
+ check := opts.AddFlagGroup('C', "check", "check,...", "enable or disable specific checks")
+ opts.AddFlagVar('d', "debug", &gopts.Debug, false, "log verbose call traces for debugging")
+ opts.AddFlagVar('e', "explain", &gopts.Explain, false, "explain the diagnostics or give further help")
+ opts.AddFlagVar('f', "show-autofix", &gopts.PrintAutofix, false, "show what pkglint can fix automatically")
+ opts.AddFlagVar('F', "autofix", &gopts.Autofix, false, "try to automatically fix some errors (experimental)")
+ opts.AddFlagVar('g', "gcc-output-format", &gopts.GccOutput, false, "mimic the gcc output format")
+ opts.AddFlagVar('h', "help", &gopts.PrintHelp, false, "print a detailed usage message")
+ opts.AddFlagVar('I', "dumpmakefile", &gopts.DumpMakefile, false, "dump the Makefile after parsing")
+ opts.AddFlagVar('i', "import", &gopts.Import, false, "prepare the import of a wip package")
+ opts.AddFlagVar('m', "log-verbose", &gopts.LogVerbose, false, "allow the same log message more than once")
+ opts.AddFlagVar('p', "profiling", &gopts.Profiling, false, "profile the executing program")
+ opts.AddFlagVar('q', "quiet", &gopts.Quiet, false, "don't print a summary line when finishing")
+ opts.AddFlagVar('r', "recursive", &gopts.Recursive, false, "check subdirectories, too")
+ opts.AddFlagVar('s', "source", &gopts.PrintSource, false, "show the source lines together with diagnostics")
+ opts.AddFlagVar('V', "version", &gopts.PrintVersion, false, "print the version number of pkglint")
+ warn := opts.AddFlagGroup('W', "warning", "warning,...", "enable or disable groups of warnings")
+
+ check.AddFlagVar("ALTERNATIVES", &gopts.CheckAlternatives, true, "check ALTERNATIVES files")
+ check.AddFlagVar("bl3", &gopts.CheckBuildlink3, true, "check buildlink3.mk files")
+ check.AddFlagVar("DESCR", &gopts.CheckDescr, true, "check DESCR file")
+ check.AddFlagVar("distinfo", &gopts.CheckDistinfo, true, "check distinfo file")
+ check.AddFlagVar("extra", &gopts.CheckExtra, false, "check various additional files")
+ check.AddFlagVar("global", &gopts.CheckGlobal, false, "inter-package checks")
+ check.AddFlagVar("INSTALL", &gopts.CheckInstall, true, "check INSTALL and DEINSTALL scripts")
+ check.AddFlagVar("Makefile", &gopts.CheckMakefile, true, "check Makefiles")
+ check.AddFlagVar("MESSAGE", &gopts.CheckMessage, true, "check MESSAGE file")
+ check.AddFlagVar("mk", &gopts.CheckMk, true, "check other .mk files")
+ check.AddFlagVar("patches", &gopts.CheckPatches, true, "check patches")
+ check.AddFlagVar("PLIST", &gopts.CheckPlist, true, "check PLIST files")
+
+ warn.AddFlagVar("absname", &gopts.WarnAbsname, true, "warn about use of absolute file names")
+ warn.AddFlagVar("directcmd", &gopts.WarnDirectcmd, true, "warn about use of direct command names instead of Make variables")
+ warn.AddFlagVar("extra", &gopts.WarnExtra, false, "enable some extra warnings")
+ warn.AddFlagVar("order", &gopts.WarnOrder, false, "warn if Makefile entries are unordered")
+ warn.AddFlagVar("perm", &gopts.WarnPerm, false, "warn about unforeseen variable definition and use")
+ warn.AddFlagVar("plist-depr", &gopts.WarnPlistDepr, false, "warn about deprecated paths in PLISTs")
+ warn.AddFlagVar("plist-sort", &gopts.WarnPlistSort, false, "warn about unsorted entries in PLISTs")
+ warn.AddFlagVar("quoting", &gopts.WarnQuoting, false, "warn about quoting issues")
+ warn.AddFlagVar("space", &gopts.WarnSpace, false, "warn about inconsistent use of white-space")
+ warn.AddFlagVar("style", &gopts.WarnStyle, false, "warn about stylistic issues")
+ warn.AddFlagVar("types", &gopts.WarnTypes, true, "do some simple type checking in Makefiles")
+
+ remainingArgs, err := opts.Parse(args)
+ if err != nil {
+ fmt.Fprintf(G.logErr, "%s\n\n", err)
+ opts.Help(G.logErr, "pkglint [options] dir...")
+ exitcode := 1
+ return &exitcode
+ }
+ gopts.args = remainingArgs
+
+ if gopts.PrintHelp {
+ opts.Help(G.logOut, "pkglint [options] dir...")
+ exitcode := 0
+ return &exitcode
+ }
+
+ if G.opts.PrintVersion {
+ fmt.Fprintf(G.logOut, "%s\n", confVersion)
+ exitcode := 0
+ return &exitcode
+ }
+
+ return nil
+}
+
+func (pkglint *Pkglint) PrintSummary() {
+ if !G.opts.Quiet {
+ if G.errors != 0 || G.warnings != 0 {
+ fmt.Fprintf(G.logOut, "%d %s and %d %s found.\n",
+ G.errors, ifelseStr(G.errors == 1, "error", "errors"),
+ G.warnings, ifelseStr(G.warnings == 1, "warning", "warnings"))
+ } else {
+ io.WriteString(G.logOut, "looks fine.\n")
+ }
+ if G.explanationsAvailable && !G.opts.Explain {
+ fmt.Fprint(G.logOut, "(Run \"pkglint -e\" to show explanations.)\n")
+ }
+ if G.autofixAvailable && !G.opts.PrintAutofix && !G.opts.Autofix {
+ fmt.Fprint(G.logOut, "(Run \"pkglint -fs\" to show what can be fixed automatically.)\n")
+ }
+ if G.autofixAvailable && !G.opts.Autofix {
+ fmt.Fprint(G.logOut, "(Run \"pkglint -F\" to automatically fix some issues.)\n")
+ }
+ }
+}
+
+func (pkglint *Pkglint) CheckDirent(fname string) {
+ if G.opts.Debug {
+ defer tracecall1(fname)()
+ }
+
+ st, err := os.Lstat(fname)
+ if err != nil || !st.Mode().IsDir() && !st.Mode().IsRegular() {
+ NewLineWhole(fname).Errorf("No such file or directory.")
+ return
+ }
+ isDir := st.Mode().IsDir()
+ isReg := st.Mode().IsRegular()
+
+ G.CurrentDir = ifelseStr(isReg, path.Dir(fname), fname)
+ absCurrentDir := abspath(G.CurrentDir)
+ G.Wip = !G.opts.Import && matches(absCurrentDir, `/wip/|/wip$`)
+ G.Infrastructure = matches(absCurrentDir, `/mk/|/mk$`)
+ G.CurPkgsrcdir = findPkgsrcTopdir(G.CurrentDir)
+ if G.CurPkgsrcdir == "" {
+ NewLineWhole(fname).Errorf("Cannot determine the pkgsrc root directory for %q.", G.CurrentDir)
+ return
+ }
+
+ switch {
+ case isDir && isEmptyDir(fname):
+ return
+ case isReg:
+ Checkfile(fname)
+ return
+ }
+
+ switch G.CurPkgsrcdir {
+ case "../..":
+ checkdirPackage(relpath(G.globalData.Pkgsrcdir, G.CurrentDir))
+ case "..":
+ CheckdirCategory()
+ case ".":
+ CheckdirToplevel()
+ default:
+ NewLineWhole(fname).Errorf("Cannot check directories outside a pkgsrc tree.")
+ }
+}
// Returns the pkgsrc top-level directory, relative to the given file or directory.
func findPkgsrcTopdir(fname string) string {
@@ -53,23 +263,6 @@ func resolveVariableRefs(text string) string {
}
}
-func expandVariableWithDefault(varname, defaultValue string) string {
- mkline := G.Pkg.vardef[varname]
- if mkline == nil {
- return defaultValue
- }
-
- value := mkline.Value()
- value = resolveVarsInRelativePath(value, true)
- if containsVarRef(value) {
- value = resolveVariableRefs(value)
- }
- if G.opts.Debug {
- traceStep2("Expanded %q to %q", varname, value)
- }
- return value
-}
-
func CheckfileExtra(fname string) {
if G.opts.Debug {
defer tracecall1(fname)()
@@ -277,7 +470,7 @@ func Checkfile(fname string) {
// Ok
case hasPrefix(basename, "CHANGES-"):
- // This only checks the file, but doesn’t register the changes globally.
+ // This only checks the file, but doesn't register the changes globally.
G.globalData.loadDocChangesFromFile(fname)
case matches(fname, `(?:^|/)files/[^/]*$`):
@@ -304,136 +497,3 @@ func ChecklinesTrailingEmptyLines(lines []*Line) {
lines[last].Notef("Trailing empty lines.")
}
}
-
-func MatchVarassign(text string) (m bool, varname, spaceAfterVarname, op, valueAlign, value, spaceAfterValue, comment string) {
- i, n := 0, len(text)
-
- for i < n && text[i] == ' ' {
- i++
- }
-
- varnameStart := i
- for ; i < n; i++ {
- b := text[i]
- switch {
- case 'A' <= b && b <= 'Z',
- 'a' <= b && b <= 'z',
- b == '_',
- '0' <= b && b <= '9',
- '$' <= b && b <= '.' && (b == '$' || b == '*' || b == '+' || b == '-' || b == '.'),
- b == '[',
- b == '{', b == '}':
- continue
- }
- break
- }
- varnameEnd := i
-
- if varnameEnd == varnameStart {
- return
- }
-
- for i < n && (text[i] == ' ' || text[i] == '\t') {
- i++
- }
-
- opStart := i
- if i < n {
- if b := text[i]; b == '!' || b == '+' || b == ':' || b == '?' {
- i++
- }
- }
- if i < n && text[i] == '=' {
- i++
- } else {
- return
- }
- opEnd := i
-
- if text[varnameEnd-1] == '+' && varnameEnd == opStart && text[opStart] == '=' {
- varnameEnd--
- opStart--
- }
-
- for i < n && (text[i] == ' ' || text[i] == '\t') {
- i++
- }
-
- valueStart := i
- valuebuf := make([]byte, n-valueStart)
- j := 0
- for ; i < n; i++ {
- b := text[i]
- if b == '#' && (i == valueStart || text[i-1] != '\\') {
- break
- } else if b != '\\' || i+1 >= n || text[i+1] != '#' {
- valuebuf[j] = b
- j++
- }
- }
-
- commentStart := i
- for text[i-1] == ' ' || text[i-1] == '\t' {
- i--
- }
- valueEnd := i
-
- commentEnd := n
-
- m = true
- varname = text[varnameStart:varnameEnd]
- spaceAfterVarname = text[varnameEnd:opStart]
- op = text[opStart:opEnd]
- valueAlign = text[0:valueStart]
- value = strings.TrimSpace(string(valuebuf[:j]))
- spaceAfterValue = text[valueEnd:commentStart]
- comment = text[commentStart:commentEnd]
- return
-}
-
-type DependencyPattern struct {
- pkgbase string // "freeciv-client", "{gcc48,gcc48-libs}", "${EMACS_REQD}"
- lowerOp string // ">=", ">"
- lower string // "2.5.0", "${PYVER}"
- upperOp string // "<", "<="
- upper string // "3.0", "${PYVER}"
- wildcard string // "[0-9]*", "1.5.*", "${PYVER}"
-}
-
-func resolveVarsInRelativePath(relpath string, adjustDepth bool) string {
- tmp := relpath
- tmp = strings.Replace(tmp, "${PKGSRCDIR}", G.CurPkgsrcdir, -1)
- tmp = strings.Replace(tmp, "${.CURDIR}", ".", -1)
- tmp = strings.Replace(tmp, "${.PARSEDIR}", ".", -1)
- if contains(tmp, "${LUA_PKGSRCDIR}") {
- tmp = strings.Replace(tmp, "${LUA_PKGSRCDIR}", G.globalData.Latest("lang", `^lua[0-9]+$`, "../../lang/$0"), -1)
- }
- if contains(tmp, "${PHPPKGSRCDIR}") {
- tmp = strings.Replace(tmp, "${PHPPKGSRCDIR}", G.globalData.Latest("lang", `^php[0-9]+$`, "../../lang/$0"), -1)
- }
- if contains(tmp, "${SUSE_DIR_PREFIX}") {
- suseDirPrefix := G.globalData.Latest("emulators", `^(suse[0-9]+)_base`, "$1")
- tmp = strings.Replace(tmp, "${SUSE_DIR_PREFIX}", suseDirPrefix, -1)
- }
- if contains(tmp, "${PYPKGSRCDIR}") {
- tmp = strings.Replace(tmp, "${PYPKGSRCDIR}", G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0"), -1)
- }
- if contains(tmp, "${PYPACKAGE}") {
- tmp = strings.Replace(tmp, "${PYPACKAGE}", G.globalData.Latest("lang", `^python[0-9]+$`, "$0"), -1)
- }
- if G.Pkg != nil {
- tmp = strings.Replace(tmp, "${FILESDIR}", G.Pkg.Filesdir, -1)
- tmp = strings.Replace(tmp, "${PKGDIR}", G.Pkg.Pkgdir, -1)
- }
-
- if adjustDepth {
- if m, pkgpath := match1(tmp, `^\.\./\.\./([^.].*)$`); m {
- tmp = G.CurPkgsrcdir + "/" + pkgpath
- }
- }
-
- if G.opts.Debug {
- traceStep2("resolveVarsInRelativePath: %q => %q", relpath, tmp)
- }
- return tmp
-}
diff --git a/pkgtools/pkglint/files/pkglint_test.go b/pkgtools/pkglint/files/pkglint_test.go
index 486a96178f8..e0e709b9f5c 100644
--- a/pkgtools/pkglint/files/pkglint_test.go
+++ b/pkgtools/pkglint/files/pkglint_test.go
@@ -4,8 +4,77 @@ import (
"strings"
check "gopkg.in/check.v1"
+ "os"
)
+func (s *Suite) Test_Pkglint_Main_help(c *check.C) {
+ exitcode := new(Pkglint).Main("pkglint", "-h")
+
+ c.Check(exitcode, equals, 0)
+ c.Check(s.Output(), check.Matches, `^\Qusage: pkglint [options] dir...\E\n(?s).+`)
+}
+
+func (s *Suite) Test_Pkglint_Main_version(c *check.C) {
+ exitcode := new(Pkglint).Main("pkglint", "--version")
+
+ c.Check(exitcode, equals, 0)
+ c.Check(s.Output(), equals, confVersion+"\n")
+}
+
+func (s *Suite) Test_Pkglint_Main_no_args(c *check.C) {
+ exitcode := new(Pkglint).Main("pkglint")
+
+ c.Check(exitcode, equals, 1)
+ c.Check(s.Stderr(), equals, "FATAL: \".\" is not inside a pkgsrc tree.\n")
+}
+
+// go test -c -covermode count
+// pkgsrcdir=...
+// env PKGLINT_TESTCMDLINE="$pkgsrcdir -r" ./pkglint.test -test.coverprofile pkglint.cov -check.f TestRunPkglint
+// go tool cover -html=pkglint.cov -o coverage.html
+func (s *Suite) Test_Pkglint_coverage(c *check.C) {
+ cmdline := os.Getenv("PKGLINT_TESTCMDLINE")
+ if cmdline != "" {
+ G.logOut, G.logErr, G.debugOut = os.Stdout, os.Stderr, os.Stdout
+ new(Pkglint).Main(append([]string{"pkglint"}, splitOnSpace(cmdline)...)...)
+ }
+}
+
+func (s *Suite) Test_Pkglint_CheckDirent__outside(c *check.C) {
+ s.Init(c)
+ s.CreateTmpFile("empty", "")
+
+ new(Pkglint).CheckDirent(s.tmpdir)
+
+ c.Check(s.Output(), equals, "ERROR: ~: Cannot determine the pkgsrc root directory for \"~\".\n")
+}
+
+func (s *Suite) Test_Pkglint_CheckDirent(c *check.C) {
+ s.Init(c)
+ s.CreateTmpFile("mk/bsd.pkg.mk", "")
+ s.CreateTmpFile("category/package/Makefile", "")
+ s.CreateTmpFile("category/Makefile", "")
+ s.CreateTmpFile("Makefile", "")
+ G.globalData.Pkgsrcdir = s.tmpdir
+ pkglint := new(Pkglint)
+
+ pkglint.CheckDirent(s.tmpdir)
+
+ c.Check(s.Output(), equals, "ERROR: ~/Makefile: Must not be empty.\n")
+
+ pkglint.CheckDirent(s.tmpdir + "/category")
+
+ c.Check(s.Output(), equals, "ERROR: ~/category/Makefile: Must not be empty.\n")
+
+ pkglint.CheckDirent(s.tmpdir + "/category/package")
+
+ c.Check(s.Output(), equals, "ERROR: ~/category/package/Makefile: Must not be empty.\n")
+
+ pkglint.CheckDirent(s.tmpdir + "/category/package/nonexistent")
+
+ c.Check(s.Output(), equals, "ERROR: ~/category/package/nonexistent: No such file or directory.\n")
+}
+
func (s *Suite) Test_resolveVariableRefs__circular_reference(c *check.C) {
mkline := NewMkLine(NewLine("fname", 1, "GCC_VERSION=${GCC_VERSION}", nil))
G.Pkg = NewPackage(".")
@@ -40,41 +109,6 @@ func (s *Suite) Test_resolveVariableRefs__special_chars(c *check.C) {
c.Check(resolved, equals, "gst-plugins0.10-x11/distinfo")
}
-func (s *Suite) Test_MatchVarassign(c *check.C) {
- checkVarassign := func(text string, ck check.Checker, varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string) {
- type va struct {
- varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string
- }
- expected := va{varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment}
- am, avarname, aspaceAfterVarname, aop, aalign, avalue, aspaceAfterValue, acomment := MatchVarassign(text)
- if !am {
- c.Errorf("Text %q doesn’t match variable assignment", text)
- return
- }
- actual := va{avarname, aspaceAfterVarname, aop, aalign, avalue, aspaceAfterValue, acomment}
- c.Check(actual, ck, expected)
- }
- checkNotVarassign := func(text string) {
- m, _, _, _, _, _, _, _ := MatchVarassign(text)
- if m {
- c.Errorf("Text %q matches variable assignment, but shouldn’t.", text)
- }
- }
-
- checkVarassign("C++=c11", equals, "C+", "", "+=", "C++=", "c11", "", "")
- checkVarassign("V=v", equals, "V", "", "=", "V=", "v", "", "")
- checkVarassign("VAR=#comment", equals, "VAR", "", "=", "VAR=", "", "", "#comment")
- checkVarassign("VAR=\\#comment", equals, "VAR", "", "=", "VAR=", "#comment", "", "")
- checkVarassign("VAR=\\\\\\##comment", equals, "VAR", "", "=", "VAR=", "\\\\#", "", "#comment")
- checkVarassign("VAR=\\", equals, "VAR", "", "=", "VAR=", "\\", "", "")
- checkVarassign("VAR += value", equals, "VAR", " ", "+=", "VAR += ", "value", "", "")
- checkVarassign(" VAR=value", equals, "VAR", "", "=", " VAR=", "value", "", "")
- checkVarassign("VAR=value #comment", equals, "VAR", "", "=", "VAR=", "value", " ", "#comment")
- checkNotVarassign("\tVAR=value")
- checkNotVarassign("?=value")
- checkNotVarassign("<=value")
-}
-
func (s *Suite) Test_ChecklinesDescr(c *check.C) {
lines := s.NewLines("DESCR",
strings.Repeat("X", 90),
diff --git a/pkgtools/pkglint/files/vercmp.go b/pkgtools/pkglint/files/pkgver/vercmp.go
index fd43fa8626d..52ad6cdb8b2 100644
--- a/pkgtools/pkglint/files/vercmp.go
+++ b/pkgtools/pkglint/files/pkgver/vercmp.go
@@ -1,4 +1,4 @@
-package main
+package pkgver
// See pkgtools/pkg_install/files/lib/dewey.c
@@ -22,7 +22,7 @@ func icmp(a, b int) int {
return 0
}
-func pkgverCmp(left, right string) int {
+func Compare(left, right string) int {
lv := newVersion(left)
rv := newVersion(right)
@@ -57,22 +57,22 @@ func newVersion(vstr string) *version {
case rest[0] == '_' || rest[0] == '.':
v.Add(0)
rest = rest[1:]
- case hasPrefix(rest, "alpha"):
+ case strings.HasPrefix(rest, "alpha"):
v.Add(-3)
rest = rest[5:]
- case hasPrefix(rest, "beta"):
+ case strings.HasPrefix(rest, "beta"):
v.Add(-2)
rest = rest[4:]
- case hasPrefix(rest, "pre"):
+ case strings.HasPrefix(rest, "pre"):
v.Add(-1)
rest = rest[3:]
- case hasPrefix(rest, "rc"):
+ case strings.HasPrefix(rest, "rc"):
v.Add(-1)
rest = rest[2:]
- case hasPrefix(rest, "pl"):
+ case strings.HasPrefix(rest, "pl"):
v.Add(0)
rest = rest[2:]
- case hasPrefix(rest, "nb"):
+ case strings.HasPrefix(rest, "nb"):
i := 2
n := 0
for i < len(rest) && isdigit(rest[i]) {
diff --git a/pkgtools/pkglint/files/vercmp_test.go b/pkgtools/pkglint/files/pkgver/vercmp_test.go
index 512fa7ef958..e44a88c15d5 100644
--- a/pkgtools/pkglint/files/vercmp_test.go
+++ b/pkgtools/pkglint/files/pkgver/vercmp_test.go
@@ -1,9 +1,17 @@
-package main
+package pkgver
import (
check "gopkg.in/check.v1"
+ "testing"
)
+type Suite struct{}
+
+func Test(t *testing.T) {
+ check.Suite(&Suite{})
+ check.TestingT(t)
+}
+
func (s *Suite) Test_newVersion(c *check.C) {
c.Check(newVersion("5.0"), check.DeepEquals, &version{[]int{5, 0, 0}, 0})
c.Check(newVersion("5.0nb5"), check.DeepEquals, &version{[]int{5, 0, 0}, 5})
@@ -13,9 +21,9 @@ func (s *Suite) Test_newVersion(c *check.C) {
c.Check(newVersion("20151110"), check.DeepEquals, &version{[]int{20151110}, 0})
c.Check(newVersion("0"), check.DeepEquals, &version{[]int{0}, 0})
c.Check(newVersion("nb1"), check.DeepEquals, &version{nil, 1})
- c.Check(newVersion("1.0.1a"), deepEquals, &version{[]int{1, 0, 0, 0, 1, 1}, 0})
- c.Check(newVersion("1.0.1z"), deepEquals, &version{[]int{1, 0, 0, 0, 1, 26}, 0})
- c.Check(newVersion("0pre20160620"), deepEquals, &version{[]int{0, -1, 20160620}, 0})
+ c.Check(newVersion("1.0.1a"), check.DeepEquals, &version{[]int{1, 0, 0, 0, 1, 1}, 0})
+ c.Check(newVersion("1.0.1z"), check.DeepEquals, &version{[]int{1, 0, 0, 0, 1, 26}, 0})
+ c.Check(newVersion("0pre20160620"), check.DeepEquals, &version{[]int{0, -1, 20160620}, 0})
}
func (s *Suite) Test_pkgverCmp(c *check.C) {
@@ -46,15 +54,15 @@ func (s *Suite) Test_pkgverCmp(c *check.C) {
for _, iversion := range iversions {
for j, jversions := range versions {
for _, jversion := range jversions {
- actual := pkgverCmp(iversion, jversion)
+ actual := Compare(iversion, jversion)
if i < j && !(actual < 0) {
- c.Check([]interface{}{i, iversion, j, jversion, "<0"}, deepEquals, []interface{}{i, iversion, j, jversion, actual})
+ c.Check([]interface{}{i, iversion, j, jversion, "<0"}, check.DeepEquals, []interface{}{i, iversion, j, jversion, actual})
}
if i == j && !(actual == 0) {
- c.Check([]interface{}{i, iversion, j, jversion, "==0"}, deepEquals, []interface{}{i, iversion, j, jversion, actual})
+ c.Check([]interface{}{i, iversion, j, jversion, "==0"}, check.DeepEquals, []interface{}{i, iversion, j, jversion, actual})
}
if i > j && !(actual > 0) {
- c.Check([]interface{}{i, iversion, j, jversion, ">0"}, deepEquals, []interface{}{i, iversion, j, jversion, actual})
+ c.Check([]interface{}{i, iversion, j, jversion, ">0"}, check.DeepEquals, []interface{}{i, iversion, j, jversion, actual})
}
}
}
diff --git a/pkgtools/pkglint/files/plist.go b/pkgtools/pkglint/files/plist.go
index bfe56c34663..36207dded12 100644
--- a/pkgtools/pkglint/files/plist.go
+++ b/pkgtools/pkglint/files/plist.go
@@ -512,7 +512,7 @@ func (s *plistLineSorter) Sort() {
firstLine := s.first.line
firstLine.RememberAutofix("Sorting the whole file.")
firstLine.logAutofix()
- firstLine.changed = true // Otherwise the changes won’t be saved
+ firstLine.changed = true // Otherwise the changes won't be saved
lines := []*Line{firstLine}
lines = append(lines, s.after[s.first]...)
for _, pline := range s.plines {
diff --git a/pkgtools/pkglint/files/shell_test.go b/pkgtools/pkglint/files/shell_test.go
index 0079fab8fa4..163edbba0ce 100644
--- a/pkgtools/pkglint/files/shell_test.go
+++ b/pkgtools/pkglint/files/shell_test.go
@@ -426,7 +426,7 @@ func (s *Suite) Test_ShellLine_checkCommandUse(c *check.C) {
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
+ 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, "")
diff --git a/pkgtools/pkglint/files/shtokenizer_test.go b/pkgtools/pkglint/files/shtokenizer_test.go
index 1f7d35ce6d1..fae2c3f51f8 100644
--- a/pkgtools/pkglint/files/shtokenizer_test.go
+++ b/pkgtools/pkglint/files/shtokenizer_test.go
@@ -291,7 +291,7 @@ func (s *Suite) Test_ShTokenizer_ShAtom(c *check.C) {
token(shtWord, "echo", shqDquotBackt),
token(shtSpace, " ", shqDquotBackt),
token(shtWord, "\"", shqDquotBacktDquot),
- token(shtWord, "\\`echo foo\\`", shqDquotBacktDquot), // One token, since it doesn’t influence parsing.
+ token(shtWord, "\\`echo foo\\`", shqDquotBacktDquot), // One token, since it doesn't influence parsing.
token(shtWord, "\"", shqDquotBackt),
token(shtWord, "`", shqDquot),
token(shtWord, "\"", shqPlain))
@@ -435,7 +435,7 @@ func (s *Suite) Test_ShTokenizer_ShToken(c *check.C) {
NewShAtomVaruse("${PATH:Q}", shqPlain, "PATH", "Q")),
NewShToken("true", NewShAtom(shtWord, "true", shqPlain)))
- if false { // Don’t know how to tokenize this correctly.
+ if false { // Don't know how to tokenize this correctly.
check("id=$$(${AWK} '{print}' < ${WRKSRC}/idfile)",
NewShToken("id=$$(${AWK} '{print}' < ${WRKSRC}/idfile)",
NewShAtom(shtWord, "id=", shqPlain),
diff --git a/pkgtools/pkglint/files/toplevel_test.go b/pkgtools/pkglint/files/toplevel_test.go
index 5f810b781dd..d9422c75889 100644
--- a/pkgtools/pkglint/files/toplevel_test.go
+++ b/pkgtools/pkglint/files/toplevel_test.go
@@ -14,7 +14,7 @@ func (s *Suite) Test_CheckdirToplevel(c *check.C) {
"SUBDIR+=\tccc\n"+
"SUBDIR+=\tccc\n"+
"#SUBDIR+=\tignoreme\n"+
- "SUBDIR+=\tnonexisting\n"+ // This just doesn’t happen in practice.
+ "SUBDIR+=\tnonexisting\n"+ // This doesn't happen in practice, therefore no warning.
"SUBDIR+=\tbbb\n")
s.CreateTmpFile("archivers/Makefile", "")
s.CreateTmpFile("bbb/Makefile", "")
diff --git a/pkgtools/pkglint/files/util.go b/pkgtools/pkglint/files/util.go
index d62f612310b..88d42801a9c 100644
--- a/pkgtools/pkglint/files/util.go
+++ b/pkgtools/pkglint/files/util.go
@@ -28,6 +28,13 @@ func ifelseStr(cond bool, a, b string) string {
return b
}
+func imax(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
+
func mustMatch(s string, re RegexPattern) []string {
if m := match(s, re); m != nil {
return m
@@ -420,7 +427,7 @@ func (r Ref) String() string {
return fmt.Sprintf("%v", ref)
}
-// Emulates make(1)’s :S substitution operator.
+// Emulates make(1)'s :S substitution operator.
func mkopSubst(s string, left bool, from string, right bool, to string, flags string) string {
if G.opts.Debug {
defer tracecall(s, left, from, right, to, flags)()
diff --git a/pkgtools/pkglint/files/vartype.go b/pkgtools/pkglint/files/vartype.go
index d5ef2dbb8a9..1c773bffd85 100644
--- a/pkgtools/pkglint/files/vartype.go
+++ b/pkgtools/pkglint/files/vartype.go
@@ -101,7 +101,7 @@ func (vt *Vartype) AllowedFiles(perms AclPermissions) string {
}
// Returns whether the type is considered a shell list.
-// This distinction between “real lists” and “considered a list” makes
+// This distinction between "real lists" and "considered a list" makes
// the implementation of checklineMkVartype easier.
func (vt *Vartype) IsConsideredList() bool {
switch vt.kindOfList {
@@ -147,8 +147,8 @@ func (vt *Vartype) IsShell() bool {
return false
}
-// The basic vartype consists only of characters that don’t
-// need escaping in most contexts, like A-Za-z0-9-_.
+// IsBasicSafe returns whether the basic vartype consists only of
+// characters that don't need escaping in most contexts, like A-Za-z0-9-_.
func (vt *Vartype) IsBasicSafe() bool {
switch vt.basicType {
case BtBuildlinkDepmethod,
diff --git a/pkgtools/pkglint/files/vartypecheck.go b/pkgtools/pkglint/files/vartypecheck.go
index f3ffa9b0af3..3e55a64d0d0 100644
--- a/pkgtools/pkglint/files/vartypecheck.go
+++ b/pkgtools/pkglint/files/vartypecheck.go
@@ -591,7 +591,7 @@ func (cv *VartypeCheck) Option() {
}
if m, optname := match1(value, `^-?([a-z][-0-9a-z+]*)$`); m {
- if _, found := G.globalData.PkgOptions[optname]; !found { // There’s a difference between empty and absent here.
+ if _, found := G.globalData.PkgOptions[optname]; !found { // There's a difference between empty and absent here.
line.Warnf("Unknown option \"%s\".", optname)
Explain(
"This option is not documented in the mk/defaults/options.description",