pkgtools/pkglint: update to 5.6.1
Changes since 5.6.0: * Fix output of relative paths in the diagnostics (thanks @wiz) * Fix parsing of ${VAR:ts---}; it is now a syntax error * Load more type definitions from mk/* instead of hard-coding them * Lots of refactoring to improve test coverage, fixing several small bugs as they were found
This commit is contained in:
parent
0507c0fcf0
commit
3505d7d933
48 changed files with 1073 additions and 628 deletions
|
@ -1,6 +1,6 @@
|
|||
# $NetBSD: Makefile,v 1.546 2018/08/12 16:31:56 rillig Exp $
|
||||
# $NetBSD: Makefile,v 1.547 2018/08/16 20:41:42 rillig Exp $
|
||||
|
||||
PKGNAME= pkglint-5.6.0
|
||||
PKGNAME= pkglint-5.6.1
|
||||
DISTFILES= # none
|
||||
CATEGORIES= pkgtools
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
)
|
||||
|
||||
func CheckfileAlternatives(filename string, plistFiles map[string]bool) {
|
||||
lines, err := readLines(filename, false)
|
||||
if err != nil {
|
||||
lines := Load(filename, NotEmpty|LogErrors)
|
||||
if lines == nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -5,23 +5,24 @@ import "gopkg.in/check.v1"
|
|||
func (s *Suite) Test_Alternatives_PLIST(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.Chdir("category/package")
|
||||
t.SetupFileLines("ALTERNATIVES",
|
||||
"sbin/sendmail @PREFIX@/sbin/sendmail.postfix@POSTFIXVER@",
|
||||
"sbin/sendmail @PREFIX@/sbin/sendmail.exim@EXIMVER@",
|
||||
"bin/echo bin/gnu-echo",
|
||||
"bin/editor bin/vim -e")
|
||||
|
||||
G.Pkg = NewPackage("")
|
||||
G.Pkg = NewPackage(".")
|
||||
G.Pkg.PlistFiles["bin/echo"] = true
|
||||
G.Pkg.PlistFiles["bin/vim"] = true
|
||||
G.Pkg.PlistFiles["sbin/sendmail.exim${EXIMVER}"] = true
|
||||
|
||||
CheckfileAlternatives(t.File("ALTERNATIVES"), G.Pkg.PlistFiles)
|
||||
CheckfileAlternatives("ALTERNATIVES", G.Pkg.PlistFiles)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"ERROR: ~/ALTERNATIVES:1: Alternative implementation \"@PREFIX@/sbin/sendmail.postfix@POSTFIXVER@\" must appear in the PLIST as \"sbin/sendmail.postfix${POSTFIXVER}\".",
|
||||
"NOTE: ~/ALTERNATIVES:1: @PREFIX@/ can be omitted from the file name.",
|
||||
"NOTE: ~/ALTERNATIVES:2: @PREFIX@/ can be omitted from the file name.",
|
||||
"ERROR: ~/ALTERNATIVES:3: Alternative wrapper \"bin/echo\" must not appear in the PLIST.",
|
||||
"ERROR: ~/ALTERNATIVES:3: Alternative implementation \"bin/gnu-echo\" must appear in the PLIST.")
|
||||
"ERROR: ALTERNATIVES:1: Alternative implementation \"@PREFIX@/sbin/sendmail.postfix@POSTFIXVER@\" must appear in the PLIST as \"sbin/sendmail.postfix${POSTFIXVER}\".",
|
||||
"NOTE: ALTERNATIVES:1: @PREFIX@/ can be omitted from the file name.",
|
||||
"NOTE: ALTERNATIVES:2: @PREFIX@/ can be omitted from the file name.",
|
||||
"ERROR: ALTERNATIVES:3: Alternative wrapper \"bin/echo\" must not appear in the PLIST.",
|
||||
"ERROR: ALTERNATIVES:3: Alternative implementation \"bin/gnu-echo\" must appear in the PLIST.")
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ func (s *Suite) Test_autofix_MkLines(c *check.C) {
|
|||
"line1 := value1",
|
||||
"line2 := value2",
|
||||
"line3 := value3")
|
||||
pkg := NewPackage("category/basename")
|
||||
pkg := NewPackage(t.File("category/basename"))
|
||||
G.Pkg = pkg
|
||||
mklines := pkg.loadPackageMakefile()
|
||||
G.Pkg = nil
|
||||
|
@ -259,7 +259,7 @@ func (s *Suite) Test_Autofix_show_source_code(c *check.C) {
|
|||
t.SetupCommandLine("--show-autofix", "--source")
|
||||
mklines := t.SetupFileMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"before \\",
|
||||
"# before \\",
|
||||
"The old song \\",
|
||||
"after")
|
||||
line := mklines.lines[1]
|
||||
|
@ -274,7 +274,7 @@ func (s *Suite) Test_Autofix_show_source_code(c *check.C) {
|
|||
t.CheckOutputLines(
|
||||
"WARN: ~/Makefile:2--4: Using \"old\" is deprecated.",
|
||||
"AUTOFIX: ~/Makefile:3: Replacing \"old\" with \"new\".",
|
||||
">\tbefore \\",
|
||||
">\t# before \\",
|
||||
"-\tThe old song \\",
|
||||
"+\tThe new song \\",
|
||||
">\tafter")
|
||||
|
|
|
@ -41,7 +41,7 @@ func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
t.SetupVartypes()
|
||||
G.Pkg = NewPackage("x11/hs-X11")
|
||||
G.Pkg = NewPackage(t.File("x11/hs-X11"))
|
||||
G.Pkg.EffectivePkgbase = "X11"
|
||||
G.Pkg.EffectivePkgnameLine = t.NewMkLine("Makefile", 3, "DISTNAME=\tX11-1.0")
|
||||
mklines := t.NewMkLines("buildlink3.mk",
|
||||
|
|
|
@ -10,12 +10,11 @@ func CheckdirCategory(dir string) {
|
|||
defer trace.Call1(dir)()
|
||||
}
|
||||
|
||||
lines := LoadNonemptyLines(dir+"/Makefile", true)
|
||||
if lines == nil {
|
||||
mklines := LoadMk(dir+"/Makefile", NotEmpty|LogErrors)
|
||||
if mklines == nil {
|
||||
return
|
||||
}
|
||||
|
||||
mklines := NewMkLines(lines)
|
||||
mklines.Check()
|
||||
|
||||
exp := NewMkExpecter(mklines)
|
||||
|
@ -164,7 +163,7 @@ func CheckdirCategory(dir string) {
|
|||
exp.CurrentLine().Errorf("The file should end here.")
|
||||
}
|
||||
|
||||
SaveAutofixChanges(lines)
|
||||
mklines.SaveAutofixChanges()
|
||||
|
||||
if G.opts.Recursive {
|
||||
G.Todo = append(append([]string(nil), subdirs...), G.Todo...)
|
||||
|
|
|
@ -58,12 +58,23 @@ func (s *Suite) SetUpTest(c *check.C) {
|
|||
t.checkC = nil
|
||||
|
||||
G.opts.LogVerbose = true // To detect duplicate work being done
|
||||
t.EnableSilentTracing()
|
||||
|
||||
prevdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
c.Fatalf("Cannot get current working directory: %s", err)
|
||||
}
|
||||
t.prevdir = prevdir
|
||||
}
|
||||
|
||||
func (s *Suite) TearDownTest(c *check.C) {
|
||||
t := s.Tester
|
||||
t.checkC = nil // No longer usable; see https://github.com/go-check/check/issues/22
|
||||
|
||||
if err := os.Chdir(t.prevdir); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Cannot chdir back to previous dir: %s", err)
|
||||
}
|
||||
|
||||
G = Pkglint{} // unusable because of missing logOut and logErr
|
||||
textproc.Testing = false
|
||||
if out := t.Output(); out != "" {
|
||||
|
@ -71,6 +82,7 @@ func (s *Suite) TearDownTest(c *check.C) {
|
|||
c.TestName(), strings.Split(out, "\n"))
|
||||
}
|
||||
t.tmpdir = ""
|
||||
t.DisableTracing()
|
||||
}
|
||||
|
||||
var _ = check.Suite(new(Suite))
|
||||
|
@ -82,10 +94,12 @@ func Test(t *testing.T) { check.TestingT(t) }
|
|||
// all the test methods, which makes it difficult to find
|
||||
// a method by auto-completion.
|
||||
type Tester struct {
|
||||
stdout bytes.Buffer
|
||||
stderr bytes.Buffer
|
||||
tmpdir string
|
||||
checkC *check.C
|
||||
stdout bytes.Buffer
|
||||
stderr bytes.Buffer
|
||||
tmpdir string
|
||||
checkC *check.C // Only usable during the test method itself
|
||||
prevdir string // The current working directory before the test started
|
||||
relcwd string
|
||||
}
|
||||
|
||||
func (t *Tester) c() *check.C {
|
||||
|
@ -98,6 +112,11 @@ func (t *Tester) c() *check.C {
|
|||
// SetupCommandLine simulates a command line for the remainder of the test.
|
||||
// See Pkglint.ParseCommandLine.
|
||||
func (t *Tester) SetupCommandLine(args ...string) {
|
||||
|
||||
// Prevent tracing from being disabled; see EnableSilentTracing.
|
||||
prevTracing := trace.Tracing
|
||||
defer func() { trace.Tracing = prevTracing }()
|
||||
|
||||
exitcode := G.ParseCommandLine(append([]string{"pkglint"}, args...))
|
||||
if exitcode != nil && *exitcode != 0 {
|
||||
t.CheckOutputEmpty()
|
||||
|
@ -149,15 +168,14 @@ func (t *Tester) SetupTool(tool *Tool) {
|
|||
// The file is then read in, without considering line continuations.
|
||||
func (t *Tester) SetupFileLines(relativeFilename string, lines ...string) []Line {
|
||||
filename := t.CreateFileLines(relativeFilename, lines...)
|
||||
return LoadExistingLines(filename, false)
|
||||
return Load(filename, MustSucceed)
|
||||
}
|
||||
|
||||
// SetupFileLines creates a temporary file and writes the given lines to it.
|
||||
// The file is then read in, handling line continuations for Makefiles.
|
||||
func (t *Tester) SetupFileMkLines(relativeFilename string, lines ...string) *MkLines {
|
||||
filename := t.CreateFileLines(relativeFilename, lines...)
|
||||
plainLines := LoadExistingLines(filename, true)
|
||||
return NewMkLines(plainLines)
|
||||
return LoadMk(filename, MustSucceed)
|
||||
}
|
||||
|
||||
// SetupPkgsrc sets up a minimal but complete pkgsrc installation in the
|
||||
|
@ -222,21 +240,62 @@ func (t *Tester) CreateFileLines(relativeFilename string, lines ...string) (file
|
|||
|
||||
// File returns the absolute path to the given file in the
|
||||
// temporary directory. It doesn't check whether that file exists.
|
||||
// Calls to Tester.Chdir change the base directory for the relative file name.
|
||||
func (t *Tester) File(relativeFilename string) string {
|
||||
if t.tmpdir == "" {
|
||||
t.tmpdir = filepath.ToSlash(t.c().MkDir())
|
||||
}
|
||||
return t.tmpdir + "/" + relativeFilename
|
||||
if t.relcwd != "" {
|
||||
return cleanpath(relativeFilename)
|
||||
}
|
||||
return cleanpath(t.tmpdir + "/" + relativeFilename)
|
||||
}
|
||||
|
||||
// ExpectFatalError, when run in a defer statement, runs the action
|
||||
// if the current function panics with a pkglintFatal
|
||||
// (typically from line.Fatalf).
|
||||
func (t *Tester) ExpectFatalError(action func()) {
|
||||
// Chdir changes the current working directory to the given subdirectory
|
||||
// of the temporary directory, creating it if necessary.
|
||||
//
|
||||
// After this call, all files loaded from the temporary directory via
|
||||
// SetupFileLines or CreateFileLines or similar methods will use path names
|
||||
// relative to this directory.
|
||||
//
|
||||
// After the test, the previous working directory is restored, so that
|
||||
// the other tests are unaffected.
|
||||
//
|
||||
// As long as this method is not called in a test, the current working
|
||||
// directory is indeterminate.
|
||||
func (t *Tester) Chdir(relativeFilename string) {
|
||||
if t.relcwd != "" {
|
||||
// When multiple calls of Chdir are mixed with calls to CreateFileLines,
|
||||
// the resulting []Line and MkLines variables will use relative file names,
|
||||
// and these will point to different areas in the file system. This is
|
||||
// usually not indented and therefore prevented.
|
||||
t.checkC.Fatalf("Chdir must only be called once per test; already in %q.", t.relcwd)
|
||||
}
|
||||
|
||||
_ = os.MkdirAll(t.File(relativeFilename), 0700)
|
||||
if err := os.Chdir(t.File(relativeFilename)); err != nil {
|
||||
t.checkC.Fatalf("Cannot chdir: %s", err)
|
||||
}
|
||||
t.relcwd = relativeFilename
|
||||
}
|
||||
|
||||
// ExpectFatalError promises that in the remainder of the current function
|
||||
// call, a panic with a pkglintFatal will occur (typically from Line.Fatalf).
|
||||
//
|
||||
// Usage:
|
||||
// func() {
|
||||
// defer t.ExpectFatalError()
|
||||
//
|
||||
// // The code that causes the fatal error.
|
||||
// Load(t.File("nonexistent"), MustSucceed)
|
||||
// }()
|
||||
// t.CheckOutputLines(
|
||||
// "FATAL: ~/nonexistent: Does not exist.")
|
||||
func (t *Tester) ExpectFatalError() {
|
||||
r := recover()
|
||||
if _, ok := r.(pkglintFatal); ok {
|
||||
action()
|
||||
} else {
|
||||
if r == nil {
|
||||
panic("Expected a pkglint fatal error, but didn't get one.")
|
||||
} else if _, ok := r.(pkglintFatal); !ok {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
|
@ -344,12 +403,28 @@ func (t *Tester) EnableTracing() {
|
|||
trace.Tracing = true
|
||||
}
|
||||
|
||||
// EnableTracingToLog enables the tracing and writes the tracing output
|
||||
// to the test log that can be examined with Tester.Output.
|
||||
func (t *Tester) EnableTracingToLog() {
|
||||
G.logOut = NewSeparatorWriter(io.MultiWriter(os.Stdout, &t.stdout))
|
||||
trace.Out = &t.stdout
|
||||
trace.Tracing = true
|
||||
}
|
||||
|
||||
// EnableSilentTracing enables tracing mode, but discards any tracing output.
|
||||
// This can be used to improve code coverage without any side-effects,
|
||||
// since tracing output is quite large.
|
||||
func (t *Tester) EnableSilentTracing() {
|
||||
trace.Out = ioutil.Discard
|
||||
trace.Tracing = true
|
||||
}
|
||||
|
||||
// DisableTracing logs the output to the buffers again, ready to be
|
||||
// checked with CheckOutputLines.
|
||||
func (t *Tester) DisableTracing() {
|
||||
G.logOut = NewSeparatorWriter(&t.stdout)
|
||||
trace.Out = &t.stdout
|
||||
trace.Tracing = false
|
||||
trace.Out = nil
|
||||
}
|
||||
|
||||
// CheckFileLines loads the lines from the temporary file and checks that
|
||||
|
@ -368,10 +443,7 @@ func (t *Tester) CheckFileLines(relativeFileName string, lines ...string) {
|
|||
// for indentation, while the lines in the code use spaces exclusively,
|
||||
// in order to make the depth of the indentation clearly visible.
|
||||
func (t *Tester) CheckFileLinesDetab(relativeFileName string, lines ...string) {
|
||||
actualLines, err := readLines(t.File(relativeFileName), false)
|
||||
if !t.c().Check(err, check.IsNil) {
|
||||
return
|
||||
}
|
||||
actualLines := Load(t.File(relativeFileName), MustSucceed)
|
||||
|
||||
var detabbed []string
|
||||
for _, line := range actualLines {
|
||||
|
|
|
@ -68,7 +68,7 @@ func (ck *distinfoLinesChecker) checkLines(lines []Line) {
|
|||
ck.algorithms = append(ck.algorithms, alg)
|
||||
|
||||
ck.checkGlobalMismatch(line, filename, alg, hash)
|
||||
ck.checkUncommittedPatch(line, filename, hash)
|
||||
ck.checkUncommittedPatch(line, filename, alg, hash)
|
||||
}
|
||||
ck.onFilenameChange(NewLineEOF(ck.distinfoFilename), "")
|
||||
}
|
||||
|
@ -149,13 +149,15 @@ func (ck *distinfoLinesChecker) checkGlobalMismatch(line Line, fname, alg, hash
|
|||
}
|
||||
}
|
||||
|
||||
func (ck *distinfoLinesChecker) checkUncommittedPatch(line Line, patchName, sha1Hash string) {
|
||||
func (ck *distinfoLinesChecker) checkUncommittedPatch(line Line, patchName, alg, hash string) {
|
||||
if ck.isPatch == yes {
|
||||
patchFname := ck.patchdir + "/" + patchName
|
||||
if ck.distinfoIsCommitted && !isCommitted(G.Pkg.File(patchFname)) {
|
||||
line.Warnf("%s is registered in distinfo but not added to CVS.", patchFname)
|
||||
}
|
||||
ck.checkPatchSha1(line, patchFname, sha1Hash)
|
||||
if alg == "SHA1" {
|
||||
ck.checkPatchSha1(line, patchFname, hash)
|
||||
}
|
||||
ck.patches[patchName] = true
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +196,7 @@ func computePatchSha1Hex(patchFilename string) (string, error) {
|
|||
|
||||
func AutofixDistinfo(oldSha1, newSha1 string) {
|
||||
distinfoFilename := G.Pkg.File(G.Pkg.DistinfoFile)
|
||||
if lines, err := readLines(distinfoFilename, false); err == nil {
|
||||
if lines := Load(distinfoFilename, NotEmpty|LogErrors); lines != nil {
|
||||
for _, line := range lines {
|
||||
fix := line.Autofix()
|
||||
fix.Warnf("Silent-Magic-Diagnostic")
|
||||
|
|
|
@ -5,28 +5,33 @@ import "gopkg.in/check.v1"
|
|||
func (s *Suite) Test_ChecklinesDistinfo(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupFileLines("category/package/patches/patch-aa",
|
||||
"$"+"NetBSD$ line is ignored",
|
||||
t.Chdir("category/package")
|
||||
t.SetupFileLines("patches/patch-aa",
|
||||
RcsID+" line is ignored for computing the SHA1 hash",
|
||||
"patch contents")
|
||||
t.SetupFileLines("category/package/patches/patch-ab",
|
||||
t.SetupFileLines("patches/patch-ab",
|
||||
"patch contents")
|
||||
lines := t.SetupFileLines("category/package/distinfo",
|
||||
lines := t.SetupFileLines("distinfo",
|
||||
"should be the RCS ID",
|
||||
"should be empty",
|
||||
"MD5 (distfile.tar.gz) = 12345678901234567890123456789012",
|
||||
"SHA1 (distfile.tar.gz) = 1234567890123456789012345678901234567890",
|
||||
"SHA1 (patch-aa) = 6b98dd609f85a9eb9c4c1e4e7055a6aaa62b7cc7",
|
||||
"Size (patch-aa) = 104",
|
||||
"SHA1 (patch-ab) = 6b98dd609f85a9eb9c4c1e4e7055a6aaa62b7cc7",
|
||||
"Another invalid line",
|
||||
"SHA1 (patch-nonexistent) = 1234")
|
||||
G.Pkg = NewPackage("category/package")
|
||||
G.Pkg = NewPackage(".")
|
||||
|
||||
ChecklinesDistinfo(lines)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"ERROR: ~/category/package/distinfo:1: Expected \"$"+"NetBSD$\".",
|
||||
"NOTE: ~/category/package/distinfo:2: Empty line expected.",
|
||||
"ERROR: ~/category/package/distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.",
|
||||
"WARN: ~/category/package/distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".")
|
||||
"ERROR: distinfo:1: Expected \"$"+"NetBSD$\".",
|
||||
"NOTE: distinfo:2: Empty line expected.",
|
||||
"ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.",
|
||||
"ERROR: distinfo:7: Expected SHA1 hash for patch-aa, got SHA1, Size.",
|
||||
"ERROR: distinfo:8: Invalid line.",
|
||||
"WARN: distinfo:9: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) {
|
||||
|
@ -49,7 +54,8 @@ func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) {
|
|||
func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupFileLines("category/package/patches/patch-aa",
|
||||
t.Chdir("category/package")
|
||||
t.SetupFileLines("patches/patch-aa",
|
||||
RcsID,
|
||||
"",
|
||||
"--- oldfile",
|
||||
|
@ -57,45 +63,47 @@ func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) {
|
|||
"@@ -1,1 +1,1 @@",
|
||||
"-old",
|
||||
"+new")
|
||||
t.SetupFileLines("category/package/CVS/Entries",
|
||||
t.SetupFileLines("CVS/Entries",
|
||||
"/distinfo/...")
|
||||
lines := t.SetupFileLines("category/package/distinfo",
|
||||
lines := t.SetupFileLines("distinfo",
|
||||
RcsID,
|
||||
"",
|
||||
"SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0")
|
||||
G.Pkg = NewPackage("category/package")
|
||||
G.Pkg = NewPackage(".")
|
||||
|
||||
ChecklinesDistinfo(lines)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/category/package/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.")
|
||||
"WARN: distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_ChecklinesDistinfo_unrecorded_patches(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupFileLines("category/package/patches/CVS/Entries")
|
||||
t.SetupFileLines("category/package/patches/patch-aa")
|
||||
t.SetupFileLines("category/package/patches/patch-src-Makefile")
|
||||
lines := t.SetupFileLines("category/package/distinfo",
|
||||
t.Chdir("category/package")
|
||||
t.SetupFileLines("patches/CVS/Entries")
|
||||
t.SetupFileLines("patches/patch-aa")
|
||||
t.SetupFileLines("patches/patch-src-Makefile")
|
||||
lines := t.SetupFileLines("distinfo",
|
||||
RcsID,
|
||||
"",
|
||||
"SHA1 (distfile.tar.gz) = ...",
|
||||
"RMD160 (distfile.tar.gz) = ...",
|
||||
"SHA512 (distfile.tar.gz) = ...",
|
||||
"Size (distfile.tar.gz) = 1024 bytes")
|
||||
G.Pkg = NewPackage("category/package")
|
||||
G.Pkg = NewPackage(".")
|
||||
|
||||
ChecklinesDistinfo(lines)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"ERROR: ~/category/package/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".",
|
||||
"ERROR: ~/category/package/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".")
|
||||
"ERROR: distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".",
|
||||
"ERROR: distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.Chdir("category/package")
|
||||
t.CreateFileLines("patches/manual-libtool.m4")
|
||||
lines := t.SetupFileLines("distinfo",
|
||||
RcsID,
|
||||
|
@ -115,7 +123,7 @@ func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) {
|
|||
// When a distinfo file is checked in the context of a package,
|
||||
// the PATCHDIR is known, therefore the checks are active.
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".")
|
||||
"WARN: distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".")
|
||||
}
|
||||
|
||||
// PHP modules that are not PECL use the distinfo file from lang/php* but
|
||||
|
|
|
@ -6,29 +6,51 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// LoadNonemptyLines loads the given file.
|
||||
// If the file doesn't exist or is empty, an error is logged.
|
||||
//
|
||||
// See [LoadExistingLines].
|
||||
func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line {
|
||||
lines, err := readLines(fname, joinBackslashLines)
|
||||
type LoadOptions uint8
|
||||
|
||||
const (
|
||||
MustSucceed LoadOptions = 1 << iota // It's a fatal error if loading fails.
|
||||
NotEmpty // It is an error if the file is empty.
|
||||
Makefile // Lines ending in a backslash are continued in the next line.
|
||||
LogErrors //
|
||||
)
|
||||
|
||||
func Load(fileName string, options LoadOptions) []Line {
|
||||
rawBytes, err := ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
NewLineWhole(fname).Errorf("Cannot be read.")
|
||||
switch {
|
||||
case options&MustSucceed != 0:
|
||||
NewLineWhole(fileName).Fatalf("Cannot be read.")
|
||||
case options&LogErrors != 0:
|
||||
NewLineWhole(fileName).Errorf("Cannot be read.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
NewLineWhole(fname).Errorf("Must not be empty.")
|
||||
|
||||
rawText := string(rawBytes)
|
||||
if rawText == "" && options&NotEmpty != 0 {
|
||||
switch {
|
||||
case options&MustSucceed != 0:
|
||||
NewLineWhole(fileName).Fatalf("Must not be empty.")
|
||||
case options&LogErrors != 0:
|
||||
NewLineWhole(fileName).Errorf("Must not be empty.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return lines
|
||||
|
||||
if G.opts.Profiling {
|
||||
G.loaded.Add(path.Clean(fileName), 1)
|
||||
}
|
||||
|
||||
return convertToLogicalLines(fileName, rawText, options&Makefile != 0)
|
||||
}
|
||||
|
||||
func LoadExistingLines(fname string, joinBackslashLines bool) []Line {
|
||||
lines, err := readLines(fname, joinBackslashLines)
|
||||
if err != nil {
|
||||
NewLineWhole(fname).Fatalf("Cannot be read.")
|
||||
func LoadMk(fileName string, options LoadOptions) *MkLines {
|
||||
lines := Load(fileName, options|Makefile)
|
||||
if lines == nil {
|
||||
return nil
|
||||
}
|
||||
return lines
|
||||
return NewMkLines(lines)
|
||||
}
|
||||
|
||||
func nextLogicalLine(fname string, rawLines []*RawLine, pindex *int) Line {
|
||||
|
@ -106,18 +128,6 @@ func splitRawLine(textnl string) (leadingWhitespace, text, trailingWhitespace, c
|
|||
return
|
||||
}
|
||||
|
||||
func readLines(fname string, joinBackslashLines bool) ([]Line, error) {
|
||||
rawText, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if G.opts.Profiling {
|
||||
G.loaded.Add(path.Clean(fname), 1)
|
||||
}
|
||||
return convertToLogicalLines(fname, string(rawText), joinBackslashLines), nil
|
||||
}
|
||||
|
||||
func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []Line {
|
||||
var rawLines []*RawLine
|
||||
for lineno, rawLine := range strings.SplitAfter(rawText, "\n") {
|
||||
|
|
|
@ -150,3 +150,23 @@ func (s *Suite) Test_splitRawLine(c *check.C) {
|
|||
c.Check(trailingWhitespace, equals, " ")
|
||||
c.Check(continuation, equals, "\\")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_Load(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.CreateFileLines("empty")
|
||||
|
||||
func() {
|
||||
defer t.ExpectFatalError()
|
||||
Load(t.File("does-not-exist"), MustSucceed)
|
||||
}()
|
||||
|
||||
func() {
|
||||
defer t.ExpectFatalError()
|
||||
Load(t.File("empty"), MustSucceed|NotEmpty)
|
||||
}()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"FATAL: ~/does-not-exist: Cannot be read.",
|
||||
"FATAL: ~/empty: Must not be empty.")
|
||||
}
|
||||
|
|
|
@ -47,16 +47,7 @@ func (s *Suite) Test_checklineLicense(c *check.C) {
|
|||
func (s *Suite) Test_checkToplevelUnusedLicenses(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupFileLines("mk/bsd.pkg.mk", "# dummy")
|
||||
t.SetupFileLines("mk/fetch/sites.mk", "# dummy")
|
||||
t.SetupFileLines("mk/defaults/options.description", "option\tdescription")
|
||||
t.SetupFileLines("doc/TODO")
|
||||
t.SetupFileLines("mk/defaults/mk.conf")
|
||||
t.SetupFileLines("mk/tools/bsd.tools.mk",
|
||||
".include \"actual-tools.mk\"")
|
||||
t.SetupFileLines("mk/tools/actual-tools.mk")
|
||||
t.SetupFileLines("mk/tools/defaults.mk")
|
||||
t.SetupFileLines("mk/bsd.prefs.mk")
|
||||
t.SetupPkgsrc()
|
||||
t.SetupFileLines("mk/misc/category.mk")
|
||||
t.SetupFileLines("licenses/2-clause-bsd")
|
||||
t.SetupFileLines("licenses/gnu-gpl-v3")
|
||||
|
@ -90,3 +81,36 @@ func (s *Suite) Test_checkToplevelUnusedLicenses(c *check.C) {
|
|||
"WARN: ~/licenses/gnu-gpl-v3: This license seems to be unused.",
|
||||
"0 errors and 1 warning found.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_LicenseChecker_checkLicenseName__LICENSE_FILE(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupPkgsrc()
|
||||
t.SetupCommandLine("-Wno-space")
|
||||
t.SetupFileLines("category/package/DESCR",
|
||||
"Package description")
|
||||
t.SetupFileMkLines("category/package/Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
"CATEGORIES= chinese",
|
||||
"",
|
||||
"COMMENT= Useful tools",
|
||||
"LICENSE= my-license",
|
||||
"",
|
||||
"LICENSE_FILE= my-license",
|
||||
"NO_CHECKSUM= yes",
|
||||
"",
|
||||
".include \"../../mk/bsd.pkg.mk\"")
|
||||
t.SetupFileLines("category/package/PLIST",
|
||||
PlistRcsID,
|
||||
"bin/program")
|
||||
t.SetupFileLines("category/package/my-license",
|
||||
"An individual license file.")
|
||||
|
||||
G.Main("pkglint", t.File("category/package"))
|
||||
|
||||
// FIXME: It should be allowed to place a license file directly into
|
||||
// the package directory.
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/category/package/my-license: Unexpected file found.", "0 errors and 1 warning found.")
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ var (
|
|||
)
|
||||
|
||||
var dummyLine = NewLine("", 0, "", nil)
|
||||
var dummyMkLine = NewMkLine(dummyLine)
|
||||
|
||||
func shallBeLogged(msg string) bool {
|
||||
if len(G.opts.LogOnly) > 0 {
|
||||
|
@ -57,7 +58,7 @@ func logs(level *LogLevel, fname, lineno, format, msg string) bool {
|
|||
fname = cleanpath(fname)
|
||||
}
|
||||
if G.Testing && format != "Magic-Autofix-Format" && !hasSuffix(format, ".") && !hasSuffix(format, ": %s") && !hasSuffix(format, ". %s") {
|
||||
panic(fmt.Sprintf("Format %q must end in a period.", format))
|
||||
panic(fmt.Sprintf("Diagnostic format %q must end in a period.", format))
|
||||
}
|
||||
|
||||
if !G.opts.LogVerbose && loggedAlready(fname, lineno, msg) {
|
||||
|
|
|
@ -35,7 +35,7 @@ type mkLineShell struct {
|
|||
}
|
||||
type mkLineComment struct{}
|
||||
type mkLineEmpty struct{}
|
||||
type mkLineConditional struct {
|
||||
type mkLineDirective struct {
|
||||
indent string
|
||||
directive string
|
||||
args string
|
||||
|
@ -43,11 +43,11 @@ type mkLineConditional struct {
|
|||
elseLine MkLine // (filled in later)
|
||||
}
|
||||
type mkLineInclude struct {
|
||||
mustExist bool
|
||||
sys bool
|
||||
indent string
|
||||
includeFile string
|
||||
conditionVars string // (filled in later)
|
||||
mustExist bool
|
||||
sys bool
|
||||
indent string
|
||||
includeFile string
|
||||
conditionalVars string // (filled in later)
|
||||
}
|
||||
type mkLineDependency struct {
|
||||
targets string
|
||||
|
@ -115,8 +115,8 @@ func NewMkLine(line Line) *MkLineImpl {
|
|||
return &MkLineImpl{line, mkLineEmpty{}}
|
||||
}
|
||||
|
||||
if m, indent, directive, args, comment := matchMkCond(text); m {
|
||||
return &MkLineImpl{line, mkLineConditional{indent, directive, args, comment, nil}}
|
||||
if m, indent, directive, args, comment := matchMkDirective(text); m {
|
||||
return &MkLineImpl{line, mkLineDirective{indent, directive, args, comment, nil}}
|
||||
}
|
||||
|
||||
if m, indent, directive, includefile := MatchMkInclude(text); m {
|
||||
|
@ -179,9 +179,9 @@ func (mkline *MkLineImpl) IsEmpty() bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
// IsCond checks whether the line is a conditional (.if/.ifelse/.else/.if) or a loop (.for/.endfor).
|
||||
func (mkline *MkLineImpl) IsCond() bool {
|
||||
_, ok := mkline.data.(mkLineConditional)
|
||||
// IsDirective checks whether the line is a conditional (.if/.elif/.else/.if) or a loop (.for/.endfor).
|
||||
func (mkline *MkLineImpl) IsDirective() bool {
|
||||
_, ok := mkline.data.(mkLineDirective)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
@ -233,8 +233,8 @@ func (mkline *MkLineImpl) Value() string { return mkline.data.(mkLineAssign
|
|||
func (mkline *MkLineImpl) VarassignComment() string { return mkline.data.(mkLineAssign).comment }
|
||||
func (mkline *MkLineImpl) ShellCommand() string { return mkline.data.(mkLineShell).command }
|
||||
func (mkline *MkLineImpl) Indent() string {
|
||||
if mkline.IsCond() {
|
||||
return mkline.data.(mkLineConditional).indent
|
||||
if mkline.IsDirective() {
|
||||
return mkline.data.(mkLineDirective).indent
|
||||
} else {
|
||||
return mkline.data.(mkLineInclude).indent
|
||||
}
|
||||
|
@ -242,15 +242,17 @@ func (mkline *MkLineImpl) Indent() string {
|
|||
|
||||
// Directive returns one of "if", "ifdef", "ifndef", "else", "elif", "endif", "for", "endfor", "undef".
|
||||
//
|
||||
// See matchMkCond.
|
||||
func (mkline *MkLineImpl) Directive() string { return mkline.data.(mkLineConditional).directive }
|
||||
func (mkline *MkLineImpl) Args() string { return mkline.data.(mkLineConditional).args }
|
||||
// See matchMkDirective.
|
||||
func (mkline *MkLineImpl) Directive() string { return mkline.data.(mkLineDirective).directive }
|
||||
|
||||
// CondComment is the trailing end-of-line comment, typically at a deeply nested .endif or .endfor.
|
||||
func (mkline *MkLineImpl) CondComment() string { return mkline.data.(mkLineConditional).comment }
|
||||
func (mkline *MkLineImpl) HasElseBranch() bool { return mkline.data.(mkLineConditional).elseLine != nil }
|
||||
// Args returns the arguments from an .if, .ifdef, .ifndef, .elif, .for, .undef.
|
||||
func (mkline *MkLineImpl) Args() string { return mkline.data.(mkLineDirective).args }
|
||||
|
||||
// DirectiveComment is the trailing end-of-line comment, typically at a deeply nested .endif or .endfor.
|
||||
func (mkline *MkLineImpl) DirectiveComment() string { return mkline.data.(mkLineDirective).comment }
|
||||
func (mkline *MkLineImpl) HasElseBranch() bool { return mkline.data.(mkLineDirective).elseLine != nil }
|
||||
func (mkline *MkLineImpl) SetHasElseBranch(elseLine MkLine) {
|
||||
data := mkline.data.(mkLineConditional)
|
||||
data := mkline.data.(mkLineDirective)
|
||||
data.elseLine = elseLine
|
||||
mkline.data = data
|
||||
}
|
||||
|
@ -261,13 +263,13 @@ func (mkline *MkLineImpl) IncludeFile() string { return mkline.data.(mkLineInclu
|
|||
func (mkline *MkLineImpl) Targets() string { return mkline.data.(mkLineDependency).targets }
|
||||
func (mkline *MkLineImpl) Sources() string { return mkline.data.(mkLineDependency).sources }
|
||||
|
||||
// ConditionVars is a space-separated list of those variable names
|
||||
// ConditionalVars is a space-separated list of those variable names
|
||||
// on which the inclusion depends. It is initialized later,
|
||||
// step by step, when parsing other lines
|
||||
func (mkline *MkLineImpl) ConditionVars() string { return mkline.data.(mkLineInclude).conditionVars }
|
||||
func (mkline *MkLineImpl) SetConditionVars(varnames string) {
|
||||
func (mkline *MkLineImpl) ConditionalVars() string { return mkline.data.(mkLineInclude).conditionalVars }
|
||||
func (mkline *MkLineImpl) SetConditionalVars(varnames string) {
|
||||
include := mkline.data.(mkLineInclude)
|
||||
include.conditionVars = varnames
|
||||
include.conditionalVars = varnames
|
||||
mkline.data = include
|
||||
}
|
||||
|
||||
|
@ -406,7 +408,7 @@ func (mkline *MkLineImpl) ExplainRelativeDirs() {
|
|||
"main pkgsrc repository.")
|
||||
}
|
||||
|
||||
func matchMkCond(text string) (m bool, indent, directive, args, comment string) {
|
||||
func matchMkDirective(text string) (m bool, indent, directive, args, comment string) {
|
||||
i, n := 0, len(text)
|
||||
if i < n && text[i] == '.' {
|
||||
i++
|
||||
|
@ -552,13 +554,6 @@ func (mkline *MkLineImpl) VariableNeedsQuoting(varname string, vartype *Vartype,
|
|||
return nqNo
|
||||
}
|
||||
|
||||
// Assigning lists to lists does not require any quoting, though
|
||||
// there may be cases like "CONFIGURE_ARGS+= -libs ${LDFLAGS:Q}"
|
||||
// where quoting is necessary.
|
||||
if wantList && haveList && !vuc.IsWordPart {
|
||||
return nqDoesntMatter
|
||||
}
|
||||
|
||||
if wantList != haveList {
|
||||
if vuc.vartype != nil && vartype != nil {
|
||||
if vuc.vartype.basicType == BtFetchURL && vartype.basicType == BtHomepage {
|
||||
|
@ -602,7 +597,7 @@ func (mkline *MkLineImpl) VariableType(varname string) *Vartype {
|
|||
if trace.Tracing {
|
||||
trace.Stepf("Use of tool %+v", tool)
|
||||
}
|
||||
if tool.UsableAtLoadtime {
|
||||
if tool.UsableAtLoadTime {
|
||||
if G.Pkg == nil || G.Pkg.SeenBsdPrefsMk || G.Pkg.loadTimeTools[tool.Name] {
|
||||
perms |= aclpUseLoadtime
|
||||
}
|
||||
|
@ -650,8 +645,6 @@ func (mkline *MkLineImpl) VariableType(varname string) *Vartype {
|
|||
gtype = &Vartype{lkShell, BtLdFlag, allowRuntime, true}
|
||||
case hasSuffix(varbase, "_MK"):
|
||||
gtype = &Vartype{lkNone, BtUnknown, allowAll, true}
|
||||
case hasPrefix(varbase, "PLIST."):
|
||||
gtype = &Vartype{lkNone, BtYes, allowAll, true}
|
||||
}
|
||||
|
||||
if trace.Tracing {
|
||||
|
@ -753,8 +746,8 @@ type vucTime uint8
|
|||
const (
|
||||
vucTimeUnknown vucTime = iota
|
||||
|
||||
// When Makefiles are loaded, the operators := and != are evaluated,
|
||||
// as well as the conditionals .if, .elif and .for.
|
||||
// When Makefiles are loaded, the operators := and != evaluate their
|
||||
// right-hand side, as well as the directives .if, .elif and .for.
|
||||
// During loading, not all variables are available yet.
|
||||
// Variable values are still subject to change, especially lists.
|
||||
vucTimeParse
|
||||
|
@ -815,18 +808,18 @@ func (ind *Indentation) String() string {
|
|||
s := ""
|
||||
for _, level := range ind.levels[1:] {
|
||||
s += fmt.Sprintf(" %d", level.depth)
|
||||
if len(level.conditionVars) != 0 {
|
||||
s += " (" + strings.Join(level.conditionVars, " ") + ")"
|
||||
if len(level.conditionalVars) != 0 {
|
||||
s += " (" + strings.Join(level.conditionalVars, " ") + ")"
|
||||
}
|
||||
}
|
||||
return "[" + strings.TrimSpace(s) + "]"
|
||||
}
|
||||
|
||||
type indentationLevel struct {
|
||||
mkline MkLine // The line in which the indentation started; the .if/.for
|
||||
depth int // Number of space characters; always a multiple of 2
|
||||
condition string // The corresponding condition from the .if or .elif
|
||||
conditionVars []string // Variables on which the current path depends
|
||||
mkline MkLine // The line in which the indentation started; the .if/.for
|
||||
depth int // Number of space characters; always a multiple of 2
|
||||
condition string // The corresponding condition from the .if or latest .elif
|
||||
conditionalVars []string // Variables on which the current path depends
|
||||
|
||||
// Files whose existence has been checked in a related path.
|
||||
// The check counts for both the "if" and the "else" branch,
|
||||
|
@ -861,7 +854,7 @@ func (ind *Indentation) Push(mkline MkLine, indent int, condition string) {
|
|||
}
|
||||
|
||||
func (ind *Indentation) AddVar(varname string) {
|
||||
vars := &ind.top().conditionVars
|
||||
vars := &ind.top().conditionalVars
|
||||
for _, existingVarname := range *vars {
|
||||
if varname == existingVarname {
|
||||
return
|
||||
|
@ -873,7 +866,7 @@ func (ind *Indentation) AddVar(varname string) {
|
|||
|
||||
func (ind *Indentation) DependsOn(varname string) bool {
|
||||
for _, level := range ind.levels {
|
||||
for _, levelVarname := range level.conditionVars {
|
||||
for _, levelVarname := range level.conditionalVars {
|
||||
if varname == levelVarname {
|
||||
return true
|
||||
}
|
||||
|
@ -882,9 +875,11 @@ func (ind *Indentation) DependsOn(varname string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// IsConditional returns whether the current line depends on evaluating
|
||||
// any variable in an .if or .elif expression or from a .for loop.
|
||||
func (ind *Indentation) IsConditional() bool {
|
||||
for _, level := range ind.levels {
|
||||
for _, varname := range level.conditionVars {
|
||||
for _, varname := range level.conditionalVars {
|
||||
if !hasSuffix(varname, "_MK") {
|
||||
return true
|
||||
}
|
||||
|
@ -900,7 +895,7 @@ func (ind *Indentation) Varnames() string {
|
|||
sep := ""
|
||||
varnames := ""
|
||||
for _, level := range ind.levels {
|
||||
for _, levelVarname := range level.conditionVars {
|
||||
for _, levelVarname := range level.conditionalVars {
|
||||
if !hasSuffix(levelVarname, "_MK") {
|
||||
varnames += sep + levelVarname
|
||||
sep = ", "
|
||||
|
@ -910,7 +905,7 @@ func (ind *Indentation) Varnames() string {
|
|||
return varnames
|
||||
}
|
||||
|
||||
// Condition returns the condition for the innermost .if, .elif or .for.
|
||||
// Condition returns the condition of the innermost .if, .elif or .for.
|
||||
func (ind *Indentation) Condition() string {
|
||||
return ind.top().condition
|
||||
}
|
||||
|
@ -932,7 +927,7 @@ func (ind *Indentation) IsCheckedFile(filename string) bool {
|
|||
}
|
||||
|
||||
func (ind *Indentation) TrackBefore(mkline MkLine) {
|
||||
if !mkline.IsCond() {
|
||||
if !mkline.IsDirective() {
|
||||
return
|
||||
}
|
||||
if trace.Tracing {
|
||||
|
@ -949,7 +944,7 @@ func (ind *Indentation) TrackBefore(mkline MkLine) {
|
|||
}
|
||||
|
||||
func (ind *Indentation) TrackAfter(mkline MkLine) {
|
||||
if !mkline.IsCond() {
|
||||
if !mkline.IsDirective() {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -966,7 +961,7 @@ func (ind *Indentation) TrackAfter(mkline MkLine) {
|
|||
}
|
||||
|
||||
// Note: adding the used variables for arbitrary conditions
|
||||
// happens in MkLineChecker.CheckCond for performance reasons.
|
||||
// happens in MkLineChecker.checkDirectiveCond for performance reasons.
|
||||
|
||||
if contains(args, "exists") {
|
||||
cond := NewMkParser(mkline.Line, args, false).MkCond()
|
||||
|
@ -984,7 +979,7 @@ func (ind *Indentation) TrackAfter(mkline MkLine) {
|
|||
ind.top().depth += 2
|
||||
|
||||
case "elif":
|
||||
// Handled here instead of TrackAfter to allow the action to access the previous condition.
|
||||
// Handled here instead of TrackBefore to allow the action to access the previous condition.
|
||||
ind.top().condition = args
|
||||
|
||||
case "else":
|
||||
|
|
|
@ -123,12 +123,13 @@ func (s *Suite) Test_NewMkLine(c *check.C) {
|
|||
"\tshell command # shell comment",
|
||||
"# whole line comment",
|
||||
"",
|
||||
". if !empty(PKGNAME:M*-*) && ${RUBY_RAILS_SUPPORTED:[\\#]} == 1 # cond comment",
|
||||
". if !empty(PKGNAME:M*-*) && ${RUBY_RAILS_SUPPORTED:[\\#]} == 1 # directive comment",
|
||||
". include \"../../mk/bsd.prefs.mk\" # include comment",
|
||||
". include <subdir.mk> # sysinclude comment",
|
||||
"target1 target2: source1 source2",
|
||||
"target : source",
|
||||
"VARNAME+=value")
|
||||
"VARNAME+=value",
|
||||
"<<<<<<<<<<<<<<<<<")
|
||||
ln := mklines.mklines
|
||||
|
||||
c.Check(ln[0].IsVarassign(), equals, true)
|
||||
|
@ -146,11 +147,11 @@ func (s *Suite) Test_NewMkLine(c *check.C) {
|
|||
|
||||
c.Check(ln[3].IsEmpty(), equals, true)
|
||||
|
||||
c.Check(ln[4].IsCond(), equals, true)
|
||||
c.Check(ln[4].IsDirective(), equals, true)
|
||||
c.Check(ln[4].Indent(), equals, " ")
|
||||
c.Check(ln[4].Directive(), equals, "if")
|
||||
c.Check(ln[4].Args(), equals, "!empty(PKGNAME:M*-*) && ${RUBY_RAILS_SUPPORTED:[#]} == 1")
|
||||
c.Check(ln[4].CondComment(), equals, "cond comment")
|
||||
c.Check(ln[4].DirectiveComment(), equals, "directive comment")
|
||||
|
||||
c.Check(ln[5].IsInclude(), equals, true)
|
||||
c.Check(ln[5].Indent(), equals, " ")
|
||||
|
@ -171,6 +172,16 @@ func (s *Suite) Test_NewMkLine(c *check.C) {
|
|||
c.Check(ln[9].Varcanon(), equals, "VARNAME")
|
||||
c.Check(ln[9].Varparam(), equals, "")
|
||||
|
||||
// Merge conflicts are of neither type.
|
||||
c.Check(ln[10].IsVarassign(), equals, false)
|
||||
c.Check(ln[10].IsDirective(), equals, false)
|
||||
c.Check(ln[10].IsInclude(), equals, false)
|
||||
c.Check(ln[10].IsEmpty(), equals, false)
|
||||
c.Check(ln[10].IsComment(), equals, false)
|
||||
c.Check(ln[10].IsDependency(), equals, false)
|
||||
c.Check(ln[10].IsShellCommand(), equals, false)
|
||||
c.Check(ln[10].IsSysinclude(), equals, false)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: test.mk:9: Space before colon in dependency line.")
|
||||
}
|
||||
|
@ -207,6 +218,7 @@ func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) {
|
|||
"pkgbase := pkglint")
|
||||
}
|
||||
|
||||
// Guessing the variable type works for both plain and parameterized variable names.
|
||||
func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
|
@ -216,12 +228,12 @@ func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) {
|
|||
t1 := mkline.VariableType("FONT_DIRS")
|
||||
|
||||
c.Assert(t1, check.NotNil)
|
||||
c.Check(t1.String(), equals, "ShellList of Pathmask")
|
||||
c.Check(t1.String(), equals, "ShellList of Pathmask (guessed)")
|
||||
|
||||
t2 := mkline.VariableType("FONT_DIRS.ttf")
|
||||
|
||||
c.Assert(t2, check.NotNil)
|
||||
c.Check(t2.String(), equals, "ShellList of Pathmask")
|
||||
c.Check(t2.String(), equals, "ShellList of Pathmask (guessed)")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_VarUseContext_String(c *check.C) {
|
||||
|
@ -277,7 +289,7 @@ func (s *Suite) Test_MkLines_Check__extra(c *check.C) {
|
|||
|
||||
t.SetupCommandLine("-Wextra")
|
||||
t.SetupVartypes()
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
G.Mk = t.NewMkLines("options.mk",
|
||||
MkRcsID,
|
||||
".for word in ${PKG_FAIL_REASON}",
|
||||
|
@ -379,7 +391,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C)
|
|||
t.SetupVartypes()
|
||||
t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true})
|
||||
t.SetupTool(&Tool{Name: "sort", Varname: "SORT", Predefined: true})
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
G.Mk = t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};")
|
||||
|
@ -629,7 +641,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check
|
|||
|
||||
t.SetupCommandLine("-Wall")
|
||||
t.SetupVartypes()
|
||||
G.Pkgsrc.Tools.RegisterVarname("tar", "TAR", dummyLine)
|
||||
G.Pkgsrc.Tools.RegisterVarname("tar", "TAR", dummyMkLine)
|
||||
mklines := t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
|
@ -650,7 +662,7 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__backticks(c *check.C) {
|
|||
|
||||
t.SetupCommandLine("-Wall")
|
||||
t.SetupVartypes()
|
||||
G.Pkgsrc.Tools.RegisterVarname("cat", "CAT", dummyLine)
|
||||
G.Pkgsrc.Tools.RegisterVarname("cat", "CAT", dummyMkLine)
|
||||
mklines := t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
|
@ -698,6 +710,69 @@ func (s *Suite) Test_MkLine_variableNeedsQuoting__only_remove_known(c *check.C)
|
|||
"\t${ECHO} ${FOODIR:Q}")
|
||||
}
|
||||
|
||||
// TODO: COMPILER_RPATH_FLAG and LINKER_RPATH_FLAG have different types
|
||||
// defined in vardefs.go; examine why.
|
||||
func (s *Suite) Test_MkLine_variableNeedsQuoting__shellword_part(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Wall,no-space")
|
||||
t.SetupVartypes()
|
||||
|
||||
mklines := t.SetupFileMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
"SUBST_CLASSES+= class",
|
||||
"SUBST_STAGE.class= pre-configure",
|
||||
"SUBST_FILES.class= files",
|
||||
"SUBST_SED.class=-e s:@LINKER_RPATH_FLAG@:${LINKER_RPATH_FLAG}:g")
|
||||
|
||||
mklines.Check()
|
||||
|
||||
t.CheckOutputEmpty()
|
||||
}
|
||||
|
||||
// Tools, when used in a shell command, must not be quoted.
|
||||
func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_shell_command(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Wall,no-space")
|
||||
t.SetupVartypes()
|
||||
t.SetupTool(&Tool{Varname: "BASH"})
|
||||
|
||||
mklines := t.SetupFileMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
"CONFIG_SHELL= ${BASH}")
|
||||
|
||||
mklines.Check()
|
||||
|
||||
t.CheckOutputEmpty()
|
||||
}
|
||||
|
||||
// These examples from real pkgsrc end up in the final nqDontKnow case.
|
||||
func (s *Suite) Test_MkLine_variableNeedsQuoting__uncovered_cases(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Wall,no-space")
|
||||
t.SetupVartypes()
|
||||
|
||||
mklines := t.SetupFileMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
"GO_SRCPATH= ${HOMEPAGE:S,https://,,}",
|
||||
"LINKER_RPATH_FLAG:= ${LINKER_RPATH_FLAG:S/-rpath/& /}",
|
||||
"HOMEPAGE= http://godoc.org/${GO_SRCPATH}",
|
||||
"PATH:= ${PREFIX}/cross/bin:${PATH}",
|
||||
"NO_SRC_ON_FTP= ${RESTRICTED}")
|
||||
|
||||
mklines.Check()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/Makefile:4: The variable LINKER_RPATH_FLAG may not be set by any package.",
|
||||
"WARN: ~/Makefile:4: Please use ${LINKER_RPATH_FLAG:S/-rpath/& /:Q} instead of ${LINKER_RPATH_FLAG:S/-rpath/& /}.",
|
||||
"WARN: ~/Makefile:4: LINKER_RPATH_FLAG should not be evaluated at load time.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
|
@ -767,11 +842,31 @@ func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) {
|
|||
|
||||
// See PR 46570, Ctrl+F "3. In lang/perl5".
|
||||
func (s *Suite) Test_MkLine_VariableType(c *check.C) {
|
||||
mkline := NewMkLine(dummyLine)
|
||||
t := s.Init(c)
|
||||
|
||||
c.Check(mkline.VariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil)
|
||||
c.Check(mkline.VariableType("SOME_DIR").guessed, equals, true)
|
||||
c.Check(mkline.VariableType("SOMEDIR").guessed, equals, true)
|
||||
t.SetupVartypes()
|
||||
|
||||
checkType := func(varname string, vartype string) {
|
||||
actualType := dummyMkLine.VariableType(varname)
|
||||
if vartype == "" {
|
||||
c.Check(actualType, check.IsNil)
|
||||
} else {
|
||||
if c.Check(actualType, check.NotNil) {
|
||||
c.Check(actualType.String(), equals, vartype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR", "")
|
||||
checkType("SOME_DIR", "Pathname (guessed)")
|
||||
checkType("SOMEDIR", "Pathname (guessed)")
|
||||
checkType("SEARCHPATHS", "ShellList of Pathname (guessed)")
|
||||
checkType("APACHE_USER", "UserGroupName (guessed)")
|
||||
checkType("APACHE_GROUP", "UserGroupName (guessed)")
|
||||
checkType("MY_CMD_ENV", "ShellList of ShellWord (guessed)")
|
||||
checkType("MY_CMD_ARGS", "ShellList of ShellWord (guessed)")
|
||||
checkType("MY_CMD_CFLAGS", "ShellList of CFlag (guessed)")
|
||||
checkType("PLIST.abcde", "Yes")
|
||||
}
|
||||
|
||||
// PR 51696, security/py-pbkdf2/Makefile, r1.2
|
||||
|
@ -789,16 +884,16 @@ func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) {
|
|||
"WARN: Makefile:2: The # character starts a comment.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_MkLine_ConditionVars(c *check.C) {
|
||||
func (s *Suite) Test_MkLine_ConditionalVars(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
mkline := t.NewMkLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"")
|
||||
|
||||
c.Check(mkline.ConditionVars(), equals, "")
|
||||
c.Check(mkline.ConditionalVars(), equals, "")
|
||||
|
||||
mkline.SetConditionVars("OPSYS")
|
||||
mkline.SetConditionalVars("OPSYS")
|
||||
|
||||
c.Check(mkline.ConditionVars(), equals, "OPSYS")
|
||||
c.Check(mkline.ConditionalVars(), equals, "OPSYS")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_MkLine_ValueSplit(c *check.C) {
|
||||
|
@ -830,6 +925,33 @@ func (s *Suite) Test_MkLine_ValueSplit(c *check.C) {
|
|||
"${DESTDIR:S,/,\\:,:S,:,:,}/sbin")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_MkLine_ResolveVarsInRelativePath(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
checkResolve := func(before string, after string) {
|
||||
c.Check(dummyMkLine.ResolveVarsInRelativePath(before, false), equals, after)
|
||||
}
|
||||
|
||||
t.CreateFileLines("lang/lua53/Makefile")
|
||||
t.CreateFileLines("lang/php72/Makefile")
|
||||
t.CreateFileLines("emulators/suse100_base/Makefile")
|
||||
t.CreateFileLines("lang/python36/Makefile")
|
||||
|
||||
checkResolve("", "")
|
||||
checkResolve("${LUA_PKGSRCDIR}", "../../lang/lua53")
|
||||
checkResolve("${PHPPKGSRCDIR}", "../../lang/php72")
|
||||
checkResolve("${SUSE_DIR_PREFIX}", "suse100")
|
||||
checkResolve("${PYPKGSRCDIR}", "../../lang/python36")
|
||||
checkResolve("${PYPACKAGE}", "python36")
|
||||
checkResolve("${FILESDIR}", "${FILESDIR}")
|
||||
checkResolve("${PKGDIR}", "${PKGDIR}")
|
||||
|
||||
G.Pkg = NewPackage(t.File("category/package"))
|
||||
|
||||
checkResolve("${FILESDIR}", "files")
|
||||
checkResolve("${PKGDIR}", ".")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_MatchVarassign(c *check.C) {
|
||||
s.Init(c)
|
||||
|
||||
|
@ -918,3 +1040,31 @@ func (s *Suite) Test_Indentation(c *check.C) {
|
|||
c.Check(ind.IsConditional(), equals, false)
|
||||
c.Check(ind.String(), equals, "[]")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_Indentation_RememberUsedVariables(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
mkline := t.NewMkLine("Makefile", 123, ".if ${PKGREVISION} > 0")
|
||||
ind := NewIndentation()
|
||||
cond := NewMkParser(mkline.Line, mkline.Args(), false)
|
||||
|
||||
ind.RememberUsedVariables(cond.MkCond())
|
||||
|
||||
t.CheckOutputEmpty()
|
||||
c.Check(ind.Varnames(), equals, "PKGREVISION")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_MkLine_ExtractUsedVariables(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
mkline := t.NewMkLine("Makefile", 123, "")
|
||||
|
||||
nestedVarnames := mkline.ExtractUsedVariables("${VAR.${param}}")
|
||||
|
||||
// ExtractUsedVariables is very old code, should be more advanced.
|
||||
c.Check(nestedVarnames, check.IsNil)
|
||||
|
||||
plainVarnames := mkline.ExtractUsedVariables("${VAR}and${VAR2}")
|
||||
|
||||
c.Check(plainVarnames, deepEquals, []string{"VAR", "VAR2"})
|
||||
}
|
||||
|
|
|
@ -105,32 +105,17 @@ func (ck MkLineChecker) checkInclude() {
|
|||
}
|
||||
}
|
||||
|
||||
func (ck MkLineChecker) checkCond(forVars map[string]bool, indentation *Indentation) {
|
||||
func (ck MkLineChecker) checkDirective(forVars map[string]bool, ind *Indentation) {
|
||||
mkline := ck.MkLine
|
||||
|
||||
directive := mkline.Directive()
|
||||
args := mkline.Args()
|
||||
comment := mkline.CondComment()
|
||||
|
||||
expectedDepth := indentation.Depth(directive)
|
||||
expectedDepth := ind.Depth(directive)
|
||||
ck.checkDirectiveIndentation(expectedDepth)
|
||||
|
||||
if directive == "endfor" || directive == "endif" {
|
||||
if directive == "endif" && comment != "" {
|
||||
if condition := indentation.Condition(); !contains(condition, comment) {
|
||||
mkline.Warnf("Comment %q does not match condition %q.", comment, condition)
|
||||
}
|
||||
}
|
||||
|
||||
if directive == "endfor" && comment != "" {
|
||||
if condition := indentation.Condition(); !contains(condition, comment) {
|
||||
mkline.Warnf("Comment %q does not match loop %q.", comment, condition)
|
||||
}
|
||||
}
|
||||
|
||||
if indentation.Len() <= 1 {
|
||||
mkline.Errorf("Unmatched .%s.", directive)
|
||||
}
|
||||
ck.checkDirectiveEnd(ind)
|
||||
}
|
||||
|
||||
needsArgument := false
|
||||
|
@ -150,54 +135,81 @@ func (ck MkLineChecker) checkCond(forVars map[string]bool, indentation *Indentat
|
|||
}
|
||||
|
||||
} else if directive == "if" || directive == "elif" {
|
||||
ck.CheckCond()
|
||||
ck.checkDirectiveCond()
|
||||
|
||||
} else if directive == "ifdef" || directive == "ifndef" {
|
||||
mkline.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.",
|
||||
directive, ifelseStr(directive == "ifdef", "", "!"), args)
|
||||
|
||||
} else if directive == "for" {
|
||||
if m, vars, values := match2(args, `^(\S+(?:\s*\S+)*?)\s+in\s+(.*)$`); m {
|
||||
for _, forvar := range splitOnSpace(vars) {
|
||||
indentation.AddVar(forvar)
|
||||
if !G.Infrastructure && hasPrefix(forvar, "_") {
|
||||
mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", forvar)
|
||||
}
|
||||
ck.checkDirectiveFor(forVars, ind)
|
||||
|
||||
if matches(forvar, `^[_a-z][_a-z0-9]*$`) {
|
||||
// Fine.
|
||||
} else if matches(forvar, `[A-Z]`) {
|
||||
mkline.Warnf(".for variable names should not contain uppercase letters.")
|
||||
} else {
|
||||
mkline.Errorf("Invalid variable name %q.", forvar)
|
||||
}
|
||||
} else if directive == "undef" && args != "" {
|
||||
for _, varname := range splitOnSpace(args) {
|
||||
if forVars[varname] {
|
||||
mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forVars[forvar] = true
|
||||
func (ck MkLineChecker) checkDirectiveEnd(ind *Indentation) {
|
||||
mkline := ck.MkLine
|
||||
directive := mkline.Directive()
|
||||
comment := mkline.DirectiveComment()
|
||||
|
||||
if directive == "endif" && comment != "" {
|
||||
if condition := ind.Condition(); !contains(condition, comment) {
|
||||
mkline.Warnf("Comment %q does not match condition %q.", comment, condition)
|
||||
}
|
||||
}
|
||||
if directive == "endfor" && comment != "" {
|
||||
if condition := ind.Condition(); !contains(condition, comment) {
|
||||
mkline.Warnf("Comment %q does not match loop %q.", comment, condition)
|
||||
}
|
||||
}
|
||||
if ind.Len() <= 1 {
|
||||
mkline.Errorf("Unmatched .%s.", directive)
|
||||
}
|
||||
}
|
||||
|
||||
func (ck MkLineChecker) checkDirectiveFor(forVars map[string]bool, indentation *Indentation) {
|
||||
mkline := ck.MkLine
|
||||
args := mkline.Args()
|
||||
|
||||
if m, vars, values := match2(args, `^(\S+(?:\s*\S+)*?)\s+in\s+(.*)$`); m {
|
||||
for _, forvar := range splitOnSpace(vars) {
|
||||
indentation.AddVar(forvar)
|
||||
if !G.Infrastructure && hasPrefix(forvar, "_") {
|
||||
mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", forvar)
|
||||
}
|
||||
|
||||
// Check if any of the value's types is not guessed.
|
||||
guessed := true
|
||||
for _, value := range splitOnSpace(values) {
|
||||
if m, vname := match1(value, `^\$\{(.*)\}`); m {
|
||||
vartype := mkline.VariableType(vname)
|
||||
if vartype != nil && !vartype.guessed {
|
||||
guessed = false
|
||||
}
|
||||
}
|
||||
if matches(forvar, `^[_a-z][_a-z0-9]*$`) {
|
||||
// Fine.
|
||||
} else if matches(forvar, `[A-Z]`) {
|
||||
mkline.Warnf(".for variable names should not contain uppercase letters.")
|
||||
} else {
|
||||
mkline.Errorf("Invalid variable name %q.", forvar)
|
||||
}
|
||||
|
||||
forLoopType := &Vartype{lkSpace, BtUnknown, []ACLEntry{{"*", aclpAllRead}}, guessed}
|
||||
forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false}
|
||||
for _, forLoopVar := range mkline.ExtractUsedVariables(values) {
|
||||
ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext)
|
||||
forVars[forvar] = true
|
||||
}
|
||||
|
||||
// Check if any of the value's types is not guessed.
|
||||
guessed := true
|
||||
for _, value := range splitOnSpace(values) {
|
||||
if m, vname := match1(value, `^\$\{(.*)\}`); m {
|
||||
vartype := mkline.VariableType(vname)
|
||||
if vartype != nil && !vartype.guessed {
|
||||
guessed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if directive == "undef" && args != "" {
|
||||
for _, uvar := range splitOnSpace(args) {
|
||||
if forVars[uvar] {
|
||||
mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.")
|
||||
}
|
||||
forLoopType := &Vartype{lkSpace, BtUnknown, []ACLEntry{{"*", aclpAllRead}}, guessed}
|
||||
forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false}
|
||||
for _, forLoopVar := range mkline.ExtractUsedVariables(values) {
|
||||
ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -330,11 +342,14 @@ func (ck MkLineChecker) CheckVaruse(varuse *MkVarUse, vuc *VarUseContext) {
|
|||
|
||||
varname := varuse.varname
|
||||
vartype := mkline.VariableType(varname)
|
||||
if G.opts.WarnExtra &&
|
||||
(vartype == nil || vartype.guessed) &&
|
||||
!varIsUsed(varname) &&
|
||||
!(G.Mk != nil && G.Mk.forVars[varname]) &&
|
||||
!containsVarRef(varname) {
|
||||
switch {
|
||||
case !G.opts.WarnExtra:
|
||||
case vartype != nil && !vartype.guessed:
|
||||
// Well-known variables are probably defined by the infrastructure.
|
||||
case varIsUsed(varname):
|
||||
case G.Mk != nil && G.Mk.forVars[varname]:
|
||||
case containsVarRef(varname):
|
||||
default:
|
||||
mkline.Warnf("%s is used but not defined.", varname)
|
||||
}
|
||||
|
||||
|
@ -886,7 +901,7 @@ func (ck MkLineChecker) checkVarassignPlistComment(varname, value string) {
|
|||
contains(value, "@comment") && !matches(value, `="@comment "`) {
|
||||
ck.MkLine.Warnf("Please don't use @comment in %s.", varname)
|
||||
Explain(
|
||||
"If you are defining a PLIST conditional here, use one of the",
|
||||
"If you are defining a PLIST condition here, use one of the",
|
||||
"following patterns instead:",
|
||||
"",
|
||||
"1. The direct way, without intermediate variable",
|
||||
|
@ -941,18 +956,6 @@ func (ck MkLineChecker) CheckVartype(varname string, op MkOperator, value, comme
|
|||
case vartype.kindOfList == lkNone:
|
||||
ck.CheckVartypePrimitive(varname, vartype.basicType, op, value, comment, vartype.guessed)
|
||||
|
||||
if op == opUseMatch && matches(value, `^[\w-/]+$`) && !vartype.IsConsideredList() {
|
||||
mkline.Notef("%s should be compared using == instead of the :M or :N modifier without wildcards.", varname)
|
||||
Explain(
|
||||
"This variable has a single value, not a list of values. Therefore",
|
||||
"it feels strange to apply list operators like :M and :N onto it.",
|
||||
"A more direct approach is to use the == and != operators.",
|
||||
"",
|
||||
"An entirely different case is when the pattern contains wildcards",
|
||||
"like ^, *, $. In such a case, using the :M or :N modifiers is",
|
||||
"useful and preferred.")
|
||||
}
|
||||
|
||||
case value == "":
|
||||
break
|
||||
|
||||
|
@ -1030,7 +1033,7 @@ func (ck MkLineChecker) checkText(text string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ck MkLineChecker) CheckCond() {
|
||||
func (ck MkLineChecker) checkDirectiveCond() {
|
||||
mkline := ck.MkLine
|
||||
if trace.Tracing {
|
||||
defer trace.Call1(mkline.Args())()
|
||||
|
@ -1039,7 +1042,7 @@ func (ck MkLineChecker) CheckCond() {
|
|||
p := NewMkParser(mkline.Line, mkline.Args(), false)
|
||||
cond := p.MkCond()
|
||||
if !p.EOF() {
|
||||
mkline.Warnf("Invalid conditional %q.", mkline.Args())
|
||||
mkline.Warnf("Invalid condition, unrecognized part: %q.", p.Rest())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1060,9 +1063,25 @@ func (ck MkLineChecker) CheckCond() {
|
|||
"\t!empty(VARNAME:Mpattern)",
|
||||
"\t${VARNAME:Mpattern}")
|
||||
}
|
||||
for _, modifier := range varuse.modifiers {
|
||||
if modifier[0] == 'M' || modifier[0] == 'N' {
|
||||
|
||||
modifiers := varuse.modifiers
|
||||
for _, modifier := range modifiers {
|
||||
if modifier[0] == 'M' || (modifier[0] == 'N' && len(modifiers) == 1) {
|
||||
ck.CheckVartype(varname, opUseMatch, modifier[1:], "")
|
||||
|
||||
value := modifier[1:]
|
||||
vartype := mkline.VariableType(varname)
|
||||
if matches(value, `^[\w-/]+$`) && vartype != nil && !vartype.IsConsideredList() {
|
||||
mkline.Notef("%s should be compared using == instead of the :M or :N modifier without wildcards.", varname)
|
||||
Explain(
|
||||
"This variable has a single value, not a list of values. Therefore",
|
||||
"it feels strange to apply list operators like :M and :N onto it.",
|
||||
"A more direct approach is to use the == and != operators.",
|
||||
"",
|
||||
"An entirely different case is when the pattern contains wildcards",
|
||||
"like ^, *, $. In such a case, using the :M or :N modifiers is",
|
||||
"useful and preferred.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func (s *Suite) Test_MkLineChecker_CheckVartype(c *check.C) {
|
|||
func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
G.Pkg = NewPackage("graphics/gimp-fix-ca")
|
||||
G.Pkg = NewPackage(t.File("graphics/gimp-fix-ca"))
|
||||
t.SetupVartypes()
|
||||
mkline := t.NewMkLine("fname", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=")
|
||||
|
||||
|
@ -57,37 +57,37 @@ func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
|
|||
t.SetupCommandLine("-Wtypes")
|
||||
t.SetupVartypes()
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_COMPILER:Mmycc)")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_COMPILER:Mmycc)")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:1: The pattern \"mycc\" cannot match any of " +
|
||||
"{ ccache ccc clang distcc f2c gcc hp icc ido " +
|
||||
"mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.")
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".elif ${A} != ${B}")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".elif ${A} != ${B}")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputEmpty()
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone@example.org\"")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone@example.org\"")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:1: \"mailto:someone@example.org\" is not a valid URL.")
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputEmpty()
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.")
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:1: " +
|
||||
|
@ -100,7 +100,7 @@ func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
|
|||
"mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 " +
|
||||
"} instead.")
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:1: "+
|
||||
|
@ -113,7 +113,7 @@ func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
|
|||
"for the hardware architecture part of EMUL_PLATFORM.",
|
||||
"NOTE: fname:1: EMUL_PLATFORM should be compared using == instead of the :M or :N modifier without wildcards.")
|
||||
|
||||
MkLineChecker{t.NewMkLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}")}.CheckCond()
|
||||
MkLineChecker{t.NewMkLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}")}.checkDirectiveCond()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:98: "+
|
||||
|
|
|
@ -140,9 +140,9 @@ func (mklines *MkLines) Check() {
|
|||
G.Pkg.CheckInclude(mkline, mklines.indentation)
|
||||
}
|
||||
|
||||
case mkline.IsCond():
|
||||
ck.checkCond(mklines.forVars, mklines.indentation)
|
||||
substcontext.Conditional(mkline)
|
||||
case mkline.IsDirective():
|
||||
ck.checkDirective(mklines.forVars, mklines.indentation)
|
||||
substcontext.Directive(mkline)
|
||||
|
||||
case mkline.IsDependency():
|
||||
ck.checkDependencyRule(allowedTargets)
|
||||
|
@ -173,7 +173,7 @@ func (mklines *MkLines) Check() {
|
|||
}
|
||||
|
||||
// ForEach calls the action for each line, until the action returns false.
|
||||
// It keeps track of the indentation and all conditionals.
|
||||
// It keeps track of the indentation and all conditional variables.
|
||||
func (mklines *MkLines) ForEach(action func(mkline MkLine) bool, atEnd func(mkline MkLine)) {
|
||||
mklines.indentation = NewIndentation()
|
||||
|
||||
|
@ -256,7 +256,7 @@ func (mklines *MkLines) DetermineDefinedVariables() {
|
|||
}
|
||||
}
|
||||
|
||||
mklines.toolRegistry.ParseToolLine(mkline.Line)
|
||||
mklines.toolRegistry.ParseToolLine(mkline)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,6 +396,10 @@ func (mklines *MkLines) CheckRedundantVariables() {
|
|||
func(mkline MkLine) {})
|
||||
}
|
||||
|
||||
func (mklines *MkLines) SaveAutofixChanges() {
|
||||
SaveAutofixChanges(mklines.lines)
|
||||
}
|
||||
|
||||
// VaralignBlock checks that all variable assignments from a paragraph
|
||||
// use the same indentation depth for their values.
|
||||
// It also checks that the indentation uses tabs instead of spaces.
|
||||
|
@ -433,7 +437,7 @@ func (va *VaralignBlock) Check(mkline MkLine) {
|
|||
case mkline.IsComment():
|
||||
return
|
||||
|
||||
case mkline.IsCond():
|
||||
case mkline.IsDirective():
|
||||
return
|
||||
|
||||
case !mkline.IsVarassign():
|
||||
|
@ -613,7 +617,7 @@ func (va *VaralignBlock) realign(mkline MkLine, varnameOp, oldSpace string, cont
|
|||
"alignment at all.",
|
||||
"",
|
||||
"When the block contains something else than variable definitions",
|
||||
"and conditionals, it is not checked at all.")
|
||||
"and directives like .if or .for, it is not checked at all.")
|
||||
}
|
||||
fix.ReplaceAfter(varnameOp, oldSpace, newSpace)
|
||||
fix.Apply()
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"sort"
|
||||
)
|
||||
|
||||
func (s *Suite) Test_MkLines_Check__autofix_conditional_indentation(c *check.C) {
|
||||
func (s *Suite) Test_MkLines_Check__autofix_directive_indentation(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("--autofix", "-Wspace")
|
||||
|
@ -69,7 +69,7 @@ func (s *Suite) Test_MkLines_quoting_LDFLAGS_for_GNU_configure(c *check.C) {
|
|||
|
||||
t.SetupCommandLine("-Wall")
|
||||
t.SetupVartypes()
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
mklines := t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"GNU_CONFIGURE=\tyes",
|
||||
|
@ -443,7 +443,7 @@ func (s *Suite) Test_MkLines_Check__endif_comment(c *check.C) {
|
|||
".elif ${OPSYS} == FreeBSD",
|
||||
".endif # NetBSD") // Wrong, should be FreeBSD from the .elif.
|
||||
|
||||
// See MkLineChecker.checkCond
|
||||
// See MkLineChecker.checkDirective
|
||||
mklines.Check()
|
||||
|
||||
t.CheckOutputLines(""+
|
||||
|
|
|
@ -108,6 +108,7 @@ func (p *MkParser) VarUseModifiers(varname, closing string) []string {
|
|||
|
||||
var modifiers []string
|
||||
mayOmitColon := false
|
||||
loop:
|
||||
for repl.AdvanceStr(":") || mayOmitColon {
|
||||
mayOmitColon = false
|
||||
modifierMark := repl.Mark()
|
||||
|
@ -125,7 +126,7 @@ func (p *MkParser) VarUseModifiers(varname, closing string) []string {
|
|||
} else if len(rest) >= 1 && (rest[0] == closing[0] || rest[0] == ':') {
|
||||
} else if repl.AdvanceRegexp(`^\\\d+`) {
|
||||
} else {
|
||||
break
|
||||
break loop
|
||||
}
|
||||
modifiers = append(modifiers, repl.Since(modifierMark))
|
||||
continue
|
||||
|
|
|
@ -110,6 +110,10 @@ func (s *Suite) Test_MkParser_MkTokens(c *check.C) {
|
|||
check("${VAR:ts\\000012}", varuse("VAR", "ts\\000012")) // The separator character can be a long octal number.
|
||||
check("${VAR:ts\\124}", varuse("VAR", "ts\\124")) // Or even decimal.
|
||||
|
||||
checkRest("${VAR:ts---}", nil, "${VAR:ts---}") // The :ts modifier only takes single-character separators.
|
||||
|
||||
check("$<", varuseText("$<", "<")) // Same as ${.IMPSRC}
|
||||
|
||||
check("$(GNUSTEP_USER_ROOT)", varuseText("$(GNUSTEP_USER_ROOT)", "GNUSTEP_USER_ROOT"))
|
||||
t.CheckOutputLines(
|
||||
"WARN: Test_MkParser_MkTokens.mk:1: Please use curly braces {} instead of round parentheses () for GNUSTEP_USER_ROOT.")
|
||||
|
@ -222,6 +226,15 @@ func (s *Suite) Test_MkParser_MkCond(c *check.C) {
|
|||
checkRest("!empty(PKG_OPTIONS:Msndfile) || defined(PKG_OPTIONS:Msamplerate)",
|
||||
&mkCond{Not: &mkCond{Empty: varuse("PKG_OPTIONS", "Msndfile")}},
|
||||
" || defined(PKG_OPTIONS:Msamplerate)")
|
||||
checkRest("${LEFT} &&",
|
||||
&mkCond{Not: &mkCond{Empty: varuse("LEFT")}},
|
||||
" &&")
|
||||
checkRest("\"unfinished string literal",
|
||||
nil,
|
||||
"\"unfinished string literal")
|
||||
checkRest("${VAR} == \"unfinished string literal",
|
||||
nil, // Not even the ${VAR} gets through here, although that can be expected.
|
||||
"${VAR} == \"unfinished string literal")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_MkParser__varuse_parentheses_autofix(c *check.C) {
|
||||
|
|
|
@ -45,7 +45,7 @@ loop:
|
|||
}
|
||||
}
|
||||
|
||||
case mkline.IsCond():
|
||||
case mkline.IsDirective():
|
||||
// The conditionals are typically for OPSYS and MACHINE_ARCH.
|
||||
|
||||
case mkline.IsInclude():
|
||||
|
@ -74,7 +74,7 @@ loop:
|
|||
|
||||
for ; !exp.EOF(); exp.Advance() {
|
||||
mkline := exp.CurrentMkLine()
|
||||
if mkline.IsCond() && (mkline.Directive() == "if" || mkline.Directive() == "elif") {
|
||||
if mkline.IsDirective() && (mkline.Directive() == "if" || mkline.Directive() == "elif") {
|
||||
cond := NewMkParser(mkline.Line, mkline.Args(), false).MkCond()
|
||||
if cond == nil {
|
||||
continue
|
||||
|
|
|
@ -87,7 +87,7 @@ func (s *Suite) Test_ChecklinesOptionsMk__unexpected_line(c *check.C) {
|
|||
"WARN: ~/category/package/options.mk:7: Expected inclusion of \"../../mk/bsd.options.mk\".")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_ChecklinesOptionsMk__malformed_conditional(c *check.C) {
|
||||
func (s *Suite) Test_ChecklinesOptionsMk__malformed_condition(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Wno-space")
|
||||
|
@ -115,5 +115,5 @@ func (s *Suite) Test_ChecklinesOptionsMk__malformed_conditional(c *check.C) {
|
|||
ChecklinesOptionsMk(mklines)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/category/package/options.mk:9: Invalid conditional \"${OPSYS} == 'Darwin'\".")
|
||||
"WARN: ~/category/package/options.mk:9: Invalid condition, unrecognized part: \"${OPSYS} == 'Darwin'\".")
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ const rePkgname = `^([\w\-.+]+)-(\d[.0-9A-Z_a-z]*)$`
|
|||
|
||||
// Package contains data for the pkgsrc package that is currently checked.
|
||||
type Package struct {
|
||||
dir string // The directory of the package, for resolving files
|
||||
Pkgpath string // e.g. "category/pkgdir"
|
||||
Pkgdir string // PKGDIR from the package Makefile
|
||||
Filesdir string // FILESDIR from the package Makefile
|
||||
|
@ -30,7 +31,7 @@ type Package struct {
|
|||
|
||||
vars Scope
|
||||
bl3 map[string]Line // buildlink3.mk name => line; contains only buildlink3.mk files that are directly included.
|
||||
plistSubstCond map[string]bool // varname => true; list of all variables that are used as conditionals (@comment or nothing) in PLISTs.
|
||||
plistSubstCond map[string]bool // varname => true; all variables that are used as conditions (@comment or nothing) in PLISTs.
|
||||
included map[string]Line // fname => line
|
||||
seenMakefileCommon bool // Does the package have any .includes?
|
||||
loadTimeTools map[string]bool // true=ok, false=not ok, absent=not mentioned in USE_TOOLS.
|
||||
|
@ -40,12 +41,19 @@ type Package struct {
|
|||
IgnoreMissingPatches bool // In distinfo, don't warn about patches that cannot be found.
|
||||
}
|
||||
|
||||
func NewPackage(pkgpath string) *Package {
|
||||
func NewPackage(dir string) *Package {
|
||||
pkgpath := G.Pkgsrc.ToRel(dir)
|
||||
if strings.Count(pkgpath, "/") != 1 {
|
||||
NewLineWhole(dir).Errorf("Package directory %q must be two subdirectories below the pkgsrc root %q.", dir, G.Pkgsrc.File("."))
|
||||
}
|
||||
|
||||
pkg := &Package{
|
||||
dir: dir,
|
||||
Pkgpath: pkgpath,
|
||||
Pkgdir: ".",
|
||||
Filesdir: "files",
|
||||
Patchdir: "patches",
|
||||
DistinfoFile: "distinfo",
|
||||
PlistDirs: make(map[string]bool),
|
||||
PlistFiles: make(map[string]bool),
|
||||
vars: NewScope(),
|
||||
|
@ -65,7 +73,7 @@ func NewPackage(pkgpath string) *Package {
|
|||
// File returns the (possibly absolute) path to relativeFilename,
|
||||
// as resolved from the package's directory.
|
||||
func (pkg *Package) File(relativeFilename string) string {
|
||||
return G.Pkgsrc.File(pkg.Pkgpath + "/" + relativeFilename)
|
||||
return cleanpath(pkg.dir + "/" + relativeFilename)
|
||||
}
|
||||
|
||||
func (pkg *Package) varValue(varname string) (string, bool) {
|
||||
|
@ -151,21 +159,14 @@ func (pkg *Package) checklinesBuildlink3Inclusion(mklines *MkLines) {
|
|||
}
|
||||
}
|
||||
|
||||
// Given the package path relative to the pkgsrc top directory,
|
||||
// checks a complete pkgsrc package.
|
||||
//
|
||||
// Example:
|
||||
// checkdirPackage("category/pkgbase")
|
||||
func (pkglint *Pkglint) checkdirPackage(pkgpath string) {
|
||||
// checkdirPackage checks a complete pkgsrc package, including each
|
||||
// of the files individually, and also when seen in combination.
|
||||
func (pkglint *Pkglint) checkdirPackage(dir string) {
|
||||
if trace.Tracing {
|
||||
defer trace.Call1(pkgpath)()
|
||||
defer trace.Call1(dir)()
|
||||
}
|
||||
|
||||
if strings.Count(pkgpath, "/") != 1 {
|
||||
dummyLine.Fatalf("Internal pkglint error: Wrong pkgpath %q.", pkgpath)
|
||||
}
|
||||
|
||||
G.Pkg = NewPackage(pkgpath)
|
||||
G.Pkg = NewPackage(dir)
|
||||
defer func() { G.Pkg = nil }()
|
||||
pkg := G.Pkg
|
||||
|
||||
|
@ -195,8 +196,8 @@ func (pkglint *Pkglint) checkdirPackage(pkgpath string) {
|
|||
!matches(fname, `patch-`) &&
|
||||
!contains(fname, pkg.Pkgdir+"/") &&
|
||||
!contains(fname, pkg.Filesdir+"/") {
|
||||
if lines, err := readLines(fname, true); err == nil && lines != nil {
|
||||
NewMkLines(lines).DetermineUsedVariables()
|
||||
if mklines := LoadMk(fname, MustSucceed); mklines != nil {
|
||||
mklines.DetermineUsedVariables()
|
||||
}
|
||||
}
|
||||
if hasPrefix(path.Base(fname), "PLIST") {
|
||||
|
@ -301,11 +302,10 @@ func (pkg *Package) readMakefile(fname string, mainLines *MkLines, allLines *MkL
|
|||
defer trace.Call1(fname)()
|
||||
}
|
||||
|
||||
fileLines := LoadNonemptyLines(fname, true)
|
||||
if fileLines == nil {
|
||||
fileMklines := LoadMk(fname, NotEmpty|LogErrors)
|
||||
if fileMklines == nil {
|
||||
return false
|
||||
}
|
||||
fileMklines := NewMkLines(fileLines)
|
||||
|
||||
isMainMakefile := len(mainLines.mklines) == 0
|
||||
|
||||
|
@ -916,10 +916,10 @@ func (pkg *Package) checkLocallyModified(fname string) {
|
|||
}
|
||||
|
||||
func (pkg *Package) CheckInclude(mkline MkLine, indentation *Indentation) {
|
||||
conditionVars := mkline.ConditionVars()
|
||||
if conditionVars == "" {
|
||||
conditionVars = indentation.Varnames()
|
||||
mkline.SetConditionVars(conditionVars)
|
||||
conditionalVars := mkline.ConditionalVars()
|
||||
if conditionalVars == "" {
|
||||
conditionalVars = indentation.Varnames()
|
||||
mkline.SetConditionalVars(conditionalVars)
|
||||
}
|
||||
|
||||
if path.Dir(abspath(mkline.Filename)) == abspath(pkg.File(".")) {
|
||||
|
@ -929,27 +929,23 @@ func (pkg *Package) CheckInclude(mkline MkLine, indentation *Indentation) {
|
|||
pkg.conditionalIncludes[includefile] = mkline
|
||||
if other := pkg.unconditionalIncludes[includefile]; other != nil {
|
||||
mkline.Warnf("%q is included conditionally here (depending on %s) and unconditionally in %s.",
|
||||
cleanpath(includefile), mkline.ConditionVars(), other.ReferenceFrom(mkline.Line))
|
||||
cleanpath(includefile), mkline.ConditionalVars(), other.ReferenceFrom(mkline.Line))
|
||||
}
|
||||
} else {
|
||||
pkg.unconditionalIncludes[includefile] = mkline
|
||||
if other := pkg.conditionalIncludes[includefile]; other != nil {
|
||||
mkline.Warnf("%q is included unconditionally here and conditionally in %s (depending on %s).",
|
||||
cleanpath(includefile), other.ReferenceFrom(mkline.Line), other.ConditionVars())
|
||||
cleanpath(includefile), other.ReferenceFrom(mkline.Line), other.ConditionalVars())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (pkg *Package) loadPlistDirs(plistFilename string) {
|
||||
lines, err := readLines(plistFilename, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
lines := Load(plistFilename, MustSucceed)
|
||||
for _, line := range lines {
|
||||
text := line.Text
|
||||
pkg.PlistFiles[text] = true // XXX: ignores PLIST conditionals for now
|
||||
pkg.PlistFiles[text] = true // XXX: ignores PLIST conditions for now
|
||||
// Keep in sync with PlistChecker.collectFilesAndDirs
|
||||
if !contains(text, "$") && !contains(text, "@") {
|
||||
for dir := path.Dir(text); dir != "."; dir = path.Dir(dir) {
|
||||
|
|
|
@ -5,7 +5,7 @@ import "gopkg.in/check.v1"
|
|||
func (s *Suite) Test_Package_pkgnameFromDistname(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
pkg := NewPackage("dummy")
|
||||
pkg := NewPackage(t.File("category/package"))
|
||||
pkg.vars.Define("PKGNAME", t.NewMkLine("Makefile", 5, "PKGNAME=dummy"))
|
||||
|
||||
c.Check(pkg.pkgnameFromDistname("pkgname-1.0", "whatever"), equals, "pkgname-1.0")
|
||||
|
@ -25,7 +25,7 @@ func (s *Suite) Test_Package_CheckVarorder(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Worder")
|
||||
pkg := NewPackage("x11/9term")
|
||||
pkg := NewPackage(t.File("x11/9term"))
|
||||
|
||||
pkg.CheckVarorder(t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
|
@ -56,7 +56,7 @@ func (s *Suite) Test_Package_CheckVarorder__comments_do_not_crash(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Worder")
|
||||
pkg := NewPackage("x11/9term")
|
||||
pkg := NewPackage(t.File("x11/9term"))
|
||||
|
||||
pkg.CheckVarorder(t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
|
@ -79,7 +79,7 @@ func (s *Suite) Test_Package_CheckVarorder__comments_are_ignored(c *check.C) {
|
|||
|
||||
t.SetupCommandLine("-Worder")
|
||||
|
||||
pkg := NewPackage("x11/9term")
|
||||
pkg := NewPackage(t.File("x11/9term"))
|
||||
|
||||
pkg.CheckVarorder(t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
|
@ -95,12 +95,12 @@ func (s *Suite) Test_Package_CheckVarorder__comments_are_ignored(c *check.C) {
|
|||
t.CheckOutputEmpty()
|
||||
}
|
||||
|
||||
func (s *Suite) Test_Package_CheckVarorder__conditionals_skip(c *check.C) {
|
||||
func (s *Suite) Test_Package_CheckVarorder__skip_if_there_are_directives(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Worder")
|
||||
|
||||
pkg := NewPackage("x11/9term")
|
||||
pkg := NewPackage(t.File("category/package"))
|
||||
|
||||
pkg.CheckVarorder(t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
|
@ -113,8 +113,8 @@ func (s *Suite) Test_Package_CheckVarorder__conditionals_skip(c *check.C) {
|
|||
".endif",
|
||||
"LICENSE=\tgnu-gpl-v2"))
|
||||
|
||||
// No warning about the missing COMMENT since the conditional
|
||||
// skips the whole check.
|
||||
// No warning about the missing COMMENT since the directive
|
||||
// causes the whole check to be skipped.
|
||||
t.CheckOutputEmpty()
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ func (s *Suite) Test_Package_CheckVarorder_GitHub(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Worder")
|
||||
pkg := NewPackage("x11/9term")
|
||||
pkg := NewPackage(t.File("x11/9term"))
|
||||
|
||||
pkg.CheckVarorder(t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
|
@ -172,7 +172,7 @@ func (s *Suite) Test_Package_CheckVarorder__MASTER_SITES(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Worder")
|
||||
pkg := NewPackage("category/package")
|
||||
pkg := NewPackage(t.File("category/package"))
|
||||
|
||||
pkg.CheckVarorder(t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
|
@ -196,7 +196,7 @@ func (s *Suite) Test_Package_CheckVarorder__diagnostics(c *check.C) {
|
|||
|
||||
t.SetupCommandLine("-Worder")
|
||||
t.SetupVartypes()
|
||||
pkg := NewPackage("category/package")
|
||||
pkg := NewPackage(t.File("category/package"))
|
||||
|
||||
pkg.CheckVarorder(t.NewMkLines("Makefile",
|
||||
MkRcsID,
|
||||
|
@ -246,7 +246,7 @@ func (s *Suite) Test_Package_CheckVarorder__diagnostics(c *check.C) {
|
|||
func (s *Suite) Test_Package_getNbpart(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
pkg := NewPackage("category/pkgbase")
|
||||
pkg := NewPackage(t.File("category/pkgbase"))
|
||||
pkg.vars.Define("PKGREVISION", t.NewMkLine("Makefile", 1, "PKGREVISION=14"))
|
||||
|
||||
c.Check(pkg.getNbpart(), equals, "nb14")
|
||||
|
@ -260,7 +260,7 @@ func (s *Suite) Test_Package_getNbpart(c *check.C) {
|
|||
func (s *Suite) Test_Package_determineEffectivePkgVars__precedence(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
pkg := NewPackage("category/pkgbase")
|
||||
pkg := NewPackage(t.File("category/pkgbase"))
|
||||
pkgnameLine := t.NewMkLine("Makefile", 3, "PKGNAME=pkgname-1.0")
|
||||
distnameLine := t.NewMkLine("Makefile", 4, "DISTNAME=distname-1.0")
|
||||
pkgrevisionLine := t.NewMkLine("Makefile", 5, "PKGREVISION=13")
|
||||
|
@ -279,21 +279,19 @@ func (s *Suite) Test_Package_determineEffectivePkgVars__precedence(c *check.C) {
|
|||
func (s *Suite) Test_Package_checkPossibleDowngrade(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
t.CreateFileLines("doc/CHANGES-2018",
|
||||
"\tUpdated category/pkgbase to 1.8 [committer 2018-01-05]")
|
||||
G.Pkgsrc.loadDocChanges()
|
||||
|
||||
t.Chdir("category/pkgbase")
|
||||
G.Pkg = NewPackage(".")
|
||||
G.Pkg.EffectivePkgname = "package-1.0nb15"
|
||||
G.Pkg.EffectivePkgnameLine = t.NewMkLine("category/pkgbase/Makefile", 5, "PKGNAME=dummy")
|
||||
G.Pkgsrc.LastChange = map[string]*Change{
|
||||
"category/pkgbase": {
|
||||
Action: "Updated",
|
||||
Version: "1.8",
|
||||
Line: t.NewLine("doc/CHANGES", 116, "dummy"),
|
||||
},
|
||||
}
|
||||
G.Pkg.EffectivePkgnameLine = t.NewMkLine("Makefile", 5, "PKGNAME=dummy")
|
||||
|
||||
G.Pkg.checkPossibleDowngrade()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15.")
|
||||
"WARN: Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES-2018:1) to 1.0nb15.")
|
||||
|
||||
G.Pkgsrc.LastChange["category/pkgbase"].Version = "1.0nb22"
|
||||
|
||||
|
@ -305,31 +303,33 @@ func (s *Suite) Test_Package_checkPossibleDowngrade(c *check.C) {
|
|||
func (s *Suite) Test_checkdirPackage(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupFileLines("category/package/Makefile",
|
||||
t.Chdir("category/package")
|
||||
t.SetupFileLines("Makefile",
|
||||
MkRcsID)
|
||||
|
||||
G.checkdirPackage("category/package")
|
||||
G.checkdirPackage(".")
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/category/package/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
|
||||
"WARN: ~/category/package/distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
|
||||
"ERROR: ~/category/package/Makefile: Each package must define its LICENSE.",
|
||||
"WARN: ~/category/package/Makefile: No COMMENT given.")
|
||||
"WARN: Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
|
||||
"WARN: distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
|
||||
"ERROR: Makefile: Each package must define its LICENSE.",
|
||||
"WARN: Makefile: No COMMENT given.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_Pkglint_checkdirPackage__meta_package_without_license(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.CreateFileLines("category/package/Makefile",
|
||||
t.Chdir("category/package")
|
||||
t.CreateFileLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
"META_PACKAGE=\tyes")
|
||||
t.SetupVartypes()
|
||||
|
||||
G.checkdirPackage("category/package")
|
||||
G.checkdirPackage(".")
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/category/package/Makefile: No COMMENT given.") // No error about missing LICENSE.
|
||||
"WARN: Makefile: No COMMENT given.") // No error about missing LICENSE.
|
||||
}
|
||||
|
||||
func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) {
|
||||
|
@ -391,10 +391,9 @@ func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) {
|
|||
"PKGNAME=pkgname-1.67",
|
||||
"DISTNAME=distfile_1_67",
|
||||
".include \"../../category/package/Makefile\"")
|
||||
pkg := NewPackage("category/package")
|
||||
G.Pkg = pkg
|
||||
G.Pkg = NewPackage(t.File("category/package"))
|
||||
|
||||
pkg.loadPackageMakefile()
|
||||
G.Pkg.loadPackageMakefile()
|
||||
|
||||
// Including a package Makefile directly is an error (in the last line),
|
||||
// but that is checked later.
|
||||
|
@ -409,7 +408,13 @@ func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
t.SetupVartypes()
|
||||
t.CreateFileLines("category/package/Makefile",
|
||||
t.CreateFileLines("devel/zlib/buildlink3.mk", "")
|
||||
t.CreateFileLines("licenses/gnu-gpl-v2", "")
|
||||
t.CreateFileLines("mk/bsd.pkg.mk", "")
|
||||
t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "")
|
||||
|
||||
t.Chdir("category/package")
|
||||
t.CreateFileLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
"COMMENT\t=Description",
|
||||
|
@ -419,37 +424,29 @@ func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) {
|
|||
".include \"../../sysutils/coreutils/buildlink3.mk\"",
|
||||
".endif",
|
||||
".include \"../../mk/bsd.pkg.mk\"")
|
||||
t.CreateFileLines("category/package/options.mk",
|
||||
t.CreateFileLines("options.mk",
|
||||
MkRcsID,
|
||||
"",
|
||||
".if !empty(PKG_OPTIONS:Mzlib)",
|
||||
". include \"../../devel/zlib/buildlink3.mk\"",
|
||||
".endif",
|
||||
".include \"../../sysutils/coreutils/buildlink3.mk\"")
|
||||
t.CreateFileLines("category/package/PLIST",
|
||||
t.CreateFileLines("PLIST",
|
||||
PlistRcsID,
|
||||
"bin/program")
|
||||
t.CreateFileLines("category/package/distinfo",
|
||||
t.CreateFileLines("distinfo",
|
||||
RcsID)
|
||||
|
||||
t.CreateFileLines("devel/zlib/buildlink3.mk", "")
|
||||
t.CreateFileLines("licenses/gnu-gpl-v2", "")
|
||||
t.CreateFileLines("mk/bsd.pkg.mk", "")
|
||||
t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "")
|
||||
|
||||
pkg := NewPackage("category/package")
|
||||
G.Pkg = pkg
|
||||
|
||||
G.checkdirPackage("category/package")
|
||||
G.checkdirPackage(".")
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/category/package/Makefile:3: The canonical order of the variables is CATEGORIES, empty line, COMMENT, LICENSE.",
|
||||
"WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".",
|
||||
"WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is "+
|
||||
"WARN: Makefile:3: The canonical order of the variables is CATEGORIES, empty line, COMMENT, LICENSE.",
|
||||
"WARN: options.mk:3: Unknown option \"zlib\".",
|
||||
"WARN: options.mk:4: \"../../devel/zlib/buildlink3.mk\" is "+
|
||||
"included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.",
|
||||
"WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is "+
|
||||
"WARN: options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is "+
|
||||
"included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).",
|
||||
"WARN: ~/category/package/options.mk:3: Expected definition of PKG_OPTIONS_VAR.")
|
||||
"WARN: options.mk:3: Expected definition of PKG_OPTIONS_VAR.")
|
||||
}
|
||||
|
||||
// See https://github.com/rillig/pkglint/issues/1
|
||||
|
@ -465,7 +462,7 @@ func (s *Suite) Test_Package_includeWithoutExists(c *check.C) {
|
|||
"",
|
||||
".include \"../../mk/bsd.pkg.mk\"")
|
||||
|
||||
G.checkdirPackage("category/package")
|
||||
G.checkdirPackage(t.File("category/package"))
|
||||
|
||||
t.CheckOutputLines(
|
||||
"ERROR: ~/category/package/options.mk: Cannot be read.")
|
||||
|
@ -477,7 +474,8 @@ func (s *Suite) Test_Package_includeAfterExists(c *check.C) {
|
|||
|
||||
t.SetupVartypes()
|
||||
t.CreateFileLines("mk/bsd.pkg.mk")
|
||||
t.CreateFileLines("category/package/Makefile",
|
||||
t.Chdir("category/package")
|
||||
t.CreateFileLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
".if exists(options.mk)",
|
||||
|
@ -486,14 +484,14 @@ func (s *Suite) Test_Package_includeAfterExists(c *check.C) {
|
|||
"",
|
||||
".include \"../../mk/bsd.pkg.mk\"")
|
||||
|
||||
G.checkdirPackage("category/package")
|
||||
G.checkdirPackage(".")
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: ~/category/package/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
|
||||
"WARN: ~/category/package/distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
|
||||
"ERROR: ~/category/package/Makefile: Each package must define its LICENSE.",
|
||||
"WARN: ~/category/package/Makefile: No COMMENT given.",
|
||||
"ERROR: ~/category/package/Makefile:4: \"options.mk\" does not exist.")
|
||||
"WARN: Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
|
||||
"WARN: distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
|
||||
"ERROR: Makefile: Each package must define its LICENSE.",
|
||||
"WARN: Makefile: No COMMENT given.",
|
||||
"ERROR: Makefile:4: \"options.mk\" does not exist.")
|
||||
}
|
||||
|
||||
// See https://github.com/rillig/pkglint/issues/1
|
||||
|
@ -511,7 +509,7 @@ func (s *Suite) Test_Package_includeOtherAfterExists(c *check.C) {
|
|||
"",
|
||||
".include \"../../mk/bsd.pkg.mk\"")
|
||||
|
||||
G.checkdirPackage("category/package")
|
||||
G.checkdirPackage(t.File("category/package"))
|
||||
|
||||
t.CheckOutputLines(
|
||||
"ERROR: ~/category/package/another.mk: Cannot be read.")
|
||||
|
@ -547,7 +545,7 @@ func (s *Suite) Test_Package__redundant_master_sites(c *check.C) {
|
|||
|
||||
// See Package.checkfilePackageMakefile
|
||||
// See Scope.uncond
|
||||
G.checkdirPackage("math/R-date")
|
||||
G.checkdirPackage(t.File("math/R-date"))
|
||||
|
||||
t.CheckOutputLines(
|
||||
"NOTE: ~/math/R-date/Makefile:6: Definition of MASTER_SITES is redundant because of ../R/Makefile.extension:4.")
|
||||
|
|
|
@ -31,6 +31,14 @@ func (s *Suite) Test_Parser_Dependency(c *check.C) {
|
|||
}
|
||||
}
|
||||
|
||||
checkNil := func(pattern string) {
|
||||
parser := NewParser(dummyLine, pattern, false)
|
||||
dp := parser.Dependency()
|
||||
if c.Check(dp, check.IsNil) {
|
||||
c.Check(parser.Rest(), equals, pattern)
|
||||
}
|
||||
}
|
||||
|
||||
check := func(pattern string, expected DependencyPattern) {
|
||||
checkRest(pattern, expected, "")
|
||||
}
|
||||
|
@ -50,5 +58,7 @@ func (s *Suite) Test_Parser_Dependency(c *check.C) {
|
|||
check("ncurses-${NC_VERS}{,nb*}", DependencyPattern{"ncurses", "", "", "", "", "${NC_VERS}{,nb*}"})
|
||||
check("xulrunner10>=${MOZ_BRANCH}${MOZ_BRANCH_MINOR}", DependencyPattern{"xulrunner10", ">=", "${MOZ_BRANCH}${MOZ_BRANCH_MINOR}", "", "", ""})
|
||||
checkRest("gnome-control-center>=2.20.1{,nb*}", DependencyPattern{"gnome-control-center", ">=", "2.20.1", "", "", ""}, "{,nb*}")
|
||||
checkNil(">=2.20.1{,nb*}")
|
||||
checkNil("pkgbase<=")
|
||||
// "{ssh{,6}-[0-9]*,openssh-[0-9]*}" is not representable using the current data structure
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ func (s *Suite) Test_ChecklinesPatch__with_comment(c *check.C) {
|
|||
func (s *Suite) Test_ChecklinesPatch__without_empty_line__autofix(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.Chdir("category/package")
|
||||
patchLines := t.SetupFileLines("patch-WithoutEmptyLines",
|
||||
RcsID,
|
||||
"Text",
|
||||
|
@ -48,14 +49,14 @@ func (s *Suite) Test_ChecklinesPatch__without_empty_line__autofix(c *check.C) {
|
|||
"SHA1 (some patch) = 49abd735b7e706ea9ed6671628bb54e91f7f5ffb")
|
||||
|
||||
t.SetupCommandLine("-Wall", "--autofix")
|
||||
G.Pkg = &Package{DistinfoFile: "distinfo"}
|
||||
G.Pkg = NewPackage(".")
|
||||
|
||||
ChecklinesPatch(patchLines)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.",
|
||||
"AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.",
|
||||
"AUTOFIX: ~/distinfo:3: Replacing \"49abd735b7e706ea9ed6671628bb54e91f7f5ffb\" "+
|
||||
"AUTOFIX: patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.",
|
||||
"AUTOFIX: patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.",
|
||||
"AUTOFIX: distinfo:3: Replacing \"49abd735b7e706ea9ed6671628bb54e91f7f5ffb\" "+
|
||||
"with \"4938fc8c0b483dc2e33e741b0da883d199e78164\".")
|
||||
|
||||
t.CheckFileLines("patch-WithoutEmptyLines",
|
||||
|
|
|
@ -138,7 +138,10 @@ func (pkglint *Pkglint) Main(argv ...string) (exitcode int) {
|
|||
dummyLine.Fatalf("Cannot create profiling file: %s", err)
|
||||
}
|
||||
pprof.StartCPUProfile(f)
|
||||
defer pprof.StopCPUProfile()
|
||||
defer func() {
|
||||
pprof.StopCPUProfile()
|
||||
f.Close()
|
||||
}()
|
||||
|
||||
regex.Profiling = true
|
||||
pkglint.loghisto = histogram.New()
|
||||
|
@ -146,7 +149,7 @@ func (pkglint *Pkglint) Main(argv ...string) (exitcode int) {
|
|||
defer func() {
|
||||
pkglint.logOut.Write("")
|
||||
pkglint.loghisto.PrintStats("loghisto", pkglint.logOut.out, -1)
|
||||
regex.PrintStats()
|
||||
regex.PrintStats(pkglint.logOut.out)
|
||||
pkglint.loaded.PrintStats("loaded", pkglint.logOut.out, 50)
|
||||
}()
|
||||
}
|
||||
|
@ -168,7 +171,7 @@ func (pkglint *Pkglint) Main(argv ...string) (exitcode int) {
|
|||
}
|
||||
|
||||
pkglint.Pkgsrc = NewPkgsrc(firstArg + "/" + relTopdir)
|
||||
pkglint.Pkgsrc.Load()
|
||||
pkglint.Pkgsrc.LoadInfrastructure()
|
||||
|
||||
currentUser, err := user.Current()
|
||||
if err == nil {
|
||||
|
@ -296,13 +299,13 @@ func (pkglint *Pkglint) CheckDirent(fname string) {
|
|||
isDir := st.Mode().IsDir()
|
||||
isReg := st.Mode().IsRegular()
|
||||
|
||||
currentDir := ifelseStr(isReg, path.Dir(fname), fname)
|
||||
absCurrentDir := abspath(currentDir)
|
||||
dir := ifelseStr(isReg, path.Dir(fname), fname)
|
||||
absCurrentDir := abspath(dir)
|
||||
pkglint.Wip = !pkglint.opts.Import && matches(absCurrentDir, `/wip/|/wip$`)
|
||||
pkglint.Infrastructure = matches(absCurrentDir, `/mk/|/mk$`)
|
||||
pkgsrcdir := findPkgsrcTopdir(currentDir)
|
||||
pkgsrcdir := findPkgsrcTopdir(dir)
|
||||
if pkgsrcdir == "" {
|
||||
NewLineWhole(fname).Errorf("Cannot determine the pkgsrc root directory for %q.", cleanpath(currentDir))
|
||||
NewLineWhole(fname).Errorf("Cannot determine the pkgsrc root directory for %q.", cleanpath(dir))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -316,11 +319,11 @@ func (pkglint *Pkglint) CheckDirent(fname string) {
|
|||
|
||||
switch pkgsrcdir {
|
||||
case "../..":
|
||||
pkglint.checkdirPackage(pkglint.Pkgsrc.ToRel(currentDir))
|
||||
pkglint.checkdirPackage(dir)
|
||||
case "..":
|
||||
CheckdirCategory(currentDir)
|
||||
CheckdirCategory(dir)
|
||||
case ".":
|
||||
CheckdirToplevel(currentDir)
|
||||
CheckdirToplevel(dir)
|
||||
default:
|
||||
NewLineWhole(fname).Errorf("Cannot check directories outside a pkgsrc tree.")
|
||||
}
|
||||
|
@ -374,7 +377,7 @@ func CheckfileExtra(fname string) {
|
|||
defer trace.Call1(fname)()
|
||||
}
|
||||
|
||||
if lines := LoadNonemptyLines(fname, false); lines != nil {
|
||||
if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
|
||||
ChecklinesTrailingEmptyLines(lines)
|
||||
}
|
||||
}
|
||||
|
@ -458,13 +461,13 @@ func CheckfileMk(fname string) {
|
|||
defer trace.Call1(fname)()
|
||||
}
|
||||
|
||||
lines := LoadNonemptyLines(fname, true)
|
||||
if lines == nil {
|
||||
mklines := LoadMk(fname, NotEmpty|LogErrors)
|
||||
if mklines == nil {
|
||||
return
|
||||
}
|
||||
|
||||
NewMkLines(lines).Check()
|
||||
SaveAutofixChanges(lines)
|
||||
mklines.Check()
|
||||
mklines.SaveAutofixChanges()
|
||||
}
|
||||
|
||||
func (pkglint *Pkglint) Checkfile(fname string) {
|
||||
|
@ -514,21 +517,21 @@ func (pkglint *Pkglint) Checkfile(fname string) {
|
|||
|
||||
case basename == "buildlink3.mk":
|
||||
if pkglint.opts.CheckBuildlink3 {
|
||||
if lines := LoadNonemptyLines(fname, true); lines != nil {
|
||||
ChecklinesBuildlink3Mk(NewMkLines(lines))
|
||||
if mklines := LoadMk(fname, NotEmpty|LogErrors); mklines != nil {
|
||||
ChecklinesBuildlink3Mk(mklines)
|
||||
}
|
||||
}
|
||||
|
||||
case hasPrefix(basename, "DESCR"):
|
||||
if pkglint.opts.CheckDescr {
|
||||
if lines := LoadNonemptyLines(fname, false); lines != nil {
|
||||
if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
|
||||
ChecklinesDescr(lines)
|
||||
}
|
||||
}
|
||||
|
||||
case basename == "distinfo":
|
||||
if pkglint.opts.CheckDistinfo {
|
||||
if lines := LoadNonemptyLines(fname, false); lines != nil {
|
||||
if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
|
||||
ChecklinesDistinfo(lines)
|
||||
}
|
||||
}
|
||||
|
@ -540,21 +543,21 @@ func (pkglint *Pkglint) Checkfile(fname string) {
|
|||
|
||||
case hasPrefix(basename, "MESSAGE"):
|
||||
if pkglint.opts.CheckMessage {
|
||||
if lines := LoadNonemptyLines(fname, false); lines != nil {
|
||||
if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
|
||||
ChecklinesMessage(lines)
|
||||
}
|
||||
}
|
||||
|
||||
case basename == "options.mk":
|
||||
if pkglint.opts.CheckOptions {
|
||||
if lines := LoadNonemptyLines(fname, true); lines != nil {
|
||||
ChecklinesOptionsMk(NewMkLines(lines))
|
||||
if mklines := LoadMk(fname, NotEmpty|LogErrors); mklines != nil {
|
||||
ChecklinesOptionsMk(mklines)
|
||||
}
|
||||
}
|
||||
|
||||
case matches(basename, `^patch-[-A-Za-z0-9_.~+]*[A-Za-z0-9_]$`):
|
||||
if pkglint.opts.CheckPatches {
|
||||
if lines := LoadNonemptyLines(fname, false); lines != nil {
|
||||
if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
|
||||
ChecklinesPatch(lines)
|
||||
}
|
||||
}
|
||||
|
@ -574,7 +577,7 @@ func (pkglint *Pkglint) Checkfile(fname string) {
|
|||
|
||||
case hasPrefix(basename, "PLIST"):
|
||||
if pkglint.opts.CheckPlist {
|
||||
if lines := LoadNonemptyLines(fname, false); lines != nil {
|
||||
if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
|
||||
ChecklinesPlist(lines)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,7 +291,7 @@ func (s *Suite) Test_resolveVariableRefs__circular_reference(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
mkline := t.NewMkLine("fname", 1, "GCC_VERSION=${GCC_VERSION}")
|
||||
G.Pkg = NewPackage(".")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
G.Pkg.vars.Define("GCC_VERSION", mkline)
|
||||
|
||||
resolved := resolveVariableRefs("gcc-${GCC_VERSION}")
|
||||
|
@ -305,7 +305,7 @@ func (s *Suite) Test_resolveVariableRefs__multilevel(c *check.C) {
|
|||
mkline1 := t.NewMkLine("fname", 10, "_=${SECOND}")
|
||||
mkline2 := t.NewMkLine("fname", 11, "_=${THIRD}")
|
||||
mkline3 := t.NewMkLine("fname", 12, "_=got it")
|
||||
G.Pkg = NewPackage(".")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
defineVar(mkline1, "FIRST")
|
||||
defineVar(mkline2, "SECOND")
|
||||
defineVar(mkline3, "THIRD")
|
||||
|
@ -322,7 +322,7 @@ func (s *Suite) Test_resolveVariableRefs__special_chars(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
mkline := t.NewMkLine("fname", 10, "_=x11")
|
||||
G.Pkg = NewPackage("category/pkg")
|
||||
G.Pkg = NewPackage(t.File("category/pkg"))
|
||||
G.Pkg.vars.Define("GST_PLUGINS0.10_TYPE", mkline)
|
||||
|
||||
resolved := resolveVariableRefs("gst-plugins0.10-${GST_PLUGINS0.10_TYPE}/distinfo")
|
||||
|
@ -484,3 +484,52 @@ func (s *Suite) Test_Pkglint_Checkfile__alternatives(c *check.C) {
|
|||
"Looks fine.",
|
||||
"(Run \"pkglint -e\" to show explanations.)")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_Pkglint__profiling(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupPkgsrc()
|
||||
G.Main("pkglint", "--profiling", t.File("."))
|
||||
|
||||
// Pkglint always writes the profiling data into the current directory.
|
||||
// Luckily, this directory is usually writable.
|
||||
c.Check(fileExists("pkglint.pprof"), equals, true)
|
||||
|
||||
err := os.Remove("pkglint.pprof")
|
||||
c.Check(err, check.IsNil)
|
||||
|
||||
// Everything but the first few lines of output is not easily testable
|
||||
// or not interesting enough, since that info includes the exact timing
|
||||
// that the top time-consuming regular expressions took.
|
||||
firstOutput := strings.Split(t.Output(), "\n")[0]
|
||||
c.Check(firstOutput, equals, "ERROR: ~/Makefile: Cannot be read.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_Pkglint_Checkfile__in_current_working_directory(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupPkgsrc()
|
||||
t.SetupVartypes()
|
||||
t.CreateFileLines("licenses/mit")
|
||||
t.Chdir("category/package")
|
||||
t.CreateFileLines("log")
|
||||
t.CreateFileLines("Makefile",
|
||||
MkRcsID,
|
||||
"",
|
||||
"NO_CHECKSUM= yes",
|
||||
"COMMENT= Useful utilities",
|
||||
"LICENSE= mit",
|
||||
"",
|
||||
".include \"../../mk/bsd.pkg.mk\"")
|
||||
t.CreateFileLines("PLIST",
|
||||
PlistRcsID,
|
||||
"bin/program")
|
||||
t.CreateFileLines("DESCR",
|
||||
"Package description")
|
||||
|
||||
G.Main("pkglint")
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: log: Unexpected file found.",
|
||||
"0 errors and 1 warning found.")
|
||||
}
|
||||
|
|
|
@ -79,14 +79,14 @@ func NewPkgsrc(dir string) *Pkgsrc {
|
|||
return src
|
||||
}
|
||||
|
||||
// Load reads the pkgsrc infrastructure files to
|
||||
// LoadInfrastructure reads the pkgsrc infrastructure files to
|
||||
// extract information like the tools, packages to update,
|
||||
// user-defined variables.
|
||||
//
|
||||
// This work is not done in the constructor to keep the tests
|
||||
// simple, since setting up a realistic pkgsrc environment requires
|
||||
// a lot of files.
|
||||
func (src *Pkgsrc) Load() {
|
||||
func (src *Pkgsrc) LoadInfrastructure() {
|
||||
src.InitVartypes()
|
||||
src.loadMasterSites()
|
||||
src.loadPkgOptions()
|
||||
|
@ -148,9 +148,10 @@ func (src *Pkgsrc) loadTools() {
|
|||
toolFiles := []string{"defaults.mk"}
|
||||
{
|
||||
toc := G.Pkgsrc.File("mk/tools/bsd.tools.mk")
|
||||
lines := LoadExistingLines(toc, true)
|
||||
for _, line := range lines {
|
||||
if m, _, _, includefile := MatchMkInclude(line.Text); m {
|
||||
mklines := LoadMk(toc, MustSucceed|NotEmpty)
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsInclude() {
|
||||
includefile := mkline.IncludeFile()
|
||||
if !contains(includefile, "/") {
|
||||
toolFiles = append(toolFiles, includefile)
|
||||
}
|
||||
|
@ -162,41 +163,38 @@ func (src *Pkgsrc) loadTools() {
|
|||
}
|
||||
|
||||
reg := src.Tools
|
||||
reg.RegisterTool(&Tool{"echo", "ECHO", true, true, true}, dummyLine)
|
||||
reg.RegisterTool(&Tool{"echo -n", "ECHO_N", true, true, true}, dummyLine)
|
||||
reg.RegisterTool(&Tool{"false", "FALSE", true /*why?*/, true, false}, dummyLine)
|
||||
reg.RegisterTool(&Tool{"test", "TEST", true, true, true}, dummyLine)
|
||||
reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true}, dummyLine)
|
||||
reg.RegisterTool(&Tool{"echo", "ECHO", true, true, true}, dummyMkLine)
|
||||
reg.RegisterTool(&Tool{"echo -n", "ECHO_N", true, true, true}, dummyMkLine)
|
||||
reg.RegisterTool(&Tool{"false", "FALSE", true /*why?*/, true, false}, dummyMkLine)
|
||||
reg.RegisterTool(&Tool{"test", "TEST", true, true, true}, dummyMkLine)
|
||||
reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true}, dummyMkLine)
|
||||
|
||||
for _, basename := range toolFiles {
|
||||
lines := G.Pkgsrc.LoadExistingLines("mk/tools/"+basename, true)
|
||||
for _, line := range lines {
|
||||
reg.ParseToolLine(line)
|
||||
mklines := G.Pkgsrc.LoadMk("mk/tools/"+basename, MustSucceed|NotEmpty)
|
||||
for _, mkline := range mklines.mklines {
|
||||
reg.ParseToolLine(mkline)
|
||||
}
|
||||
}
|
||||
|
||||
for _, relativeName := range [...]string{"mk/bsd.prefs.mk", "mk/bsd.pkg.mk"} {
|
||||
condDepth := 0
|
||||
dirDepth := 0
|
||||
|
||||
lines := G.Pkgsrc.LoadExistingLines(relativeName, true)
|
||||
for _, line := range lines {
|
||||
text := line.Text
|
||||
if hasPrefix(text, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
if m, _, varname, _, _, _, value, _, _ := MatchVarassign(text); m {
|
||||
mklines := G.Pkgsrc.LoadMk(relativeName, MustSucceed|NotEmpty)
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsVarassign() {
|
||||
varname := mkline.Varname()
|
||||
value := mkline.Value()
|
||||
if varname == "USE_TOOLS" {
|
||||
if trace.Tracing {
|
||||
trace.Stepf("[condDepth=%d] %s", condDepth, value)
|
||||
trace.Stepf("[dirDepth=%d] %s", dirDepth, value)
|
||||
}
|
||||
if condDepth == 0 || condDepth == 1 && relativeName == "mk/bsd.prefs.mk" {
|
||||
if dirDepth == 0 || dirDepth == 1 && relativeName == "mk/bsd.prefs.mk" {
|
||||
for _, toolname := range splitOnSpace(value) {
|
||||
if !containsVarRef(toolname) {
|
||||
tool := reg.Register(toolname, line)
|
||||
tool := reg.Register(toolname, mkline)
|
||||
tool.Predefined = true
|
||||
if relativeName == "mk/bsd.prefs.mk" {
|
||||
tool.UsableAtLoadtime = true
|
||||
tool.UsableAtLoadTime = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,12 +206,12 @@ func (src *Pkgsrc) loadTools() {
|
|||
}
|
||||
}
|
||||
|
||||
} else if m, _, cond, _, _ := matchMkCond(text); m {
|
||||
switch cond {
|
||||
} else if mkline.IsDirective() {
|
||||
switch mkline.Directive() {
|
||||
case "if", "ifdef", "ifndef", "for":
|
||||
condDepth++
|
||||
dirDepth++
|
||||
case "endif", "endfor":
|
||||
condDepth--
|
||||
dirDepth--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,11 +222,6 @@ func (src *Pkgsrc) loadTools() {
|
|||
}
|
||||
}
|
||||
|
||||
func (src *Pkgsrc) loadSuggestedUpdatesFile(fname string) []SuggestedUpdate {
|
||||
lines := LoadExistingLines(fname, false)
|
||||
return src.parseSuggestedUpdates(lines)
|
||||
}
|
||||
|
||||
func (src *Pkgsrc) parseSuggestedUpdates(lines []Line) []SuggestedUpdate {
|
||||
var updates []SuggestedUpdate
|
||||
state := 0
|
||||
|
@ -261,14 +254,11 @@ func (src *Pkgsrc) parseSuggestedUpdates(lines []Line) []SuggestedUpdate {
|
|||
}
|
||||
|
||||
func (src *Pkgsrc) loadSuggestedUpdates() {
|
||||
src.suggestedUpdates = src.loadSuggestedUpdatesFile(G.Pkgsrc.File("doc/TODO"))
|
||||
if wipFilename := G.Pkgsrc.File("wip/TODO"); fileExists(wipFilename) {
|
||||
src.suggestedWipUpdates = src.loadSuggestedUpdatesFile(wipFilename)
|
||||
}
|
||||
src.suggestedUpdates = src.parseSuggestedUpdates(Load(G.Pkgsrc.File("doc/TODO"), MustSucceed))
|
||||
src.suggestedWipUpdates = src.parseSuggestedUpdates(Load(G.Pkgsrc.File("wip/TODO"), NotEmpty))
|
||||
}
|
||||
|
||||
func (src *Pkgsrc) loadDocChangesFromFile(fname string) []*Change {
|
||||
lines := LoadExistingLines(fname, false)
|
||||
|
||||
parseChange := func(line Line) *Change {
|
||||
text := line.Text
|
||||
|
@ -306,6 +296,7 @@ func (src *Pkgsrc) loadDocChangesFromFile(fname string) []*Change {
|
|||
year = yyyy
|
||||
}
|
||||
|
||||
lines := Load(fname, MustSucceed|NotEmpty)
|
||||
var changes []*Change
|
||||
for _, line := range lines {
|
||||
if change := parseChange(line); change != nil {
|
||||
|
@ -371,8 +362,7 @@ func (src *Pkgsrc) loadDocChanges() {
|
|||
}
|
||||
|
||||
func (src *Pkgsrc) loadUserDefinedVars() {
|
||||
lines := G.Pkgsrc.LoadExistingLines("mk/defaults/mk.conf", true)
|
||||
mklines := NewMkLines(lines)
|
||||
mklines := G.Pkgsrc.LoadMk("mk/defaults/mk.conf", MustSucceed|NotEmpty)
|
||||
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsVarassign() {
|
||||
|
@ -542,9 +532,14 @@ func (src *Pkgsrc) initDeprecatedVars() {
|
|||
}
|
||||
}
|
||||
|
||||
// LoadExistingLines loads the file relative to the pkgsrc top directory.
|
||||
func (src *Pkgsrc) LoadExistingLines(fileName string, joinBackslashLines bool) []Line {
|
||||
return LoadExistingLines(src.File(fileName), joinBackslashLines)
|
||||
// Load loads the file relative to the pkgsrc top directory.
|
||||
func (src *Pkgsrc) Load(fileName string, options LoadOptions) []Line {
|
||||
return Load(src.File(fileName), options)
|
||||
}
|
||||
|
||||
// LoadMk loads the Makefile relative to the pkgsrc top directory.
|
||||
func (src *Pkgsrc) LoadMk(fileName string, options LoadOptions) *MkLines {
|
||||
return LoadMk(src.File(fileName), options)
|
||||
}
|
||||
|
||||
// File resolves a file name relative to the pkgsrc top directory.
|
||||
|
@ -572,14 +567,15 @@ func (src *Pkgsrc) IsBuildDef(varname string) bool {
|
|||
}
|
||||
|
||||
func (src *Pkgsrc) loadMasterSites() {
|
||||
lines := src.LoadExistingLines("mk/fetch/sites.mk", true)
|
||||
mklines := src.LoadMk("mk/fetch/sites.mk", MustSucceed|NotEmpty)
|
||||
|
||||
nameToUrl := src.MasterSiteVarToURL
|
||||
urlToName := src.MasterSiteURLToVar
|
||||
for _, line := range lines {
|
||||
if m, commented, varname, _, _, _, urls, _, _ := MatchVarassign(line.Text); m {
|
||||
if !commented && hasPrefix(varname, "MASTER_SITE_") && varname != "MASTER_SITE_BACKUP" {
|
||||
for _, url := range splitOnSpace(urls) {
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsVarassign() {
|
||||
varname := mkline.Varname()
|
||||
if hasPrefix(varname, "MASTER_SITE_") && varname != "MASTER_SITE_BACKUP" {
|
||||
for _, url := range splitOnSpace(mkline.Value()) {
|
||||
if matches(url, `^(?:http://|https://|ftp://)`) {
|
||||
if nameToUrl[varname] == "" {
|
||||
nameToUrl[varname] = url
|
||||
|
@ -600,7 +596,7 @@ func (src *Pkgsrc) loadMasterSites() {
|
|||
}
|
||||
|
||||
func (src *Pkgsrc) loadPkgOptions() {
|
||||
lines := src.LoadExistingLines("mk/defaults/options.description", false)
|
||||
lines := src.Load("mk/defaults/options.description", MustSucceed)
|
||||
|
||||
for _, line := range lines {
|
||||
if m, optname, optdescr := match2(line.Text, `^([-0-9a-z_+]+)(?:\s+(.*))?$`); m {
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gopkg.in/check.v1"
|
||||
"netbsd.org/pkglint/trace"
|
||||
)
|
||||
import "gopkg.in/check.v1"
|
||||
|
||||
// Ensures that pkglint can handle MASTER_SITES definitions with and
|
||||
// without line continuations.
|
||||
|
@ -99,25 +96,26 @@ func (s *Suite) Test_Pkgsrc_loadTools(c *check.C) {
|
|||
|
||||
G.Pkgsrc.loadTools()
|
||||
|
||||
trace.Tracing = true
|
||||
t.EnableTracingToLog()
|
||||
G.Pkgsrc.Tools.Trace()
|
||||
t.DisableTracing()
|
||||
|
||||
t.CheckOutputLines(
|
||||
"TRACE: + (*ToolRegistry).Trace()",
|
||||
"TRACE: 1 tool &{Name:bzcat Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:bzip2 Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:chown Varname:CHOWN MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:echo Varname:ECHO MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
|
||||
"TRACE: 1 tool &{Name:echo -n Varname:ECHO_N MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
|
||||
"TRACE: 1 tool &{Name:false Varname:FALSE MustUseVarForm:true Predefined:true UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:gawk Varname:AWK MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:m4 Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
|
||||
"TRACE: 1 tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
|
||||
"TRACE: 1 tool &{Name:strip Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
|
||||
"TRACE: 1 tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
|
||||
"TRACE: 1 tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
|
||||
"TRACE: 1 tool &{Name:bzcat Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:bzip2 Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:chown Varname:CHOWN MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:echo Varname:ECHO MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
|
||||
"TRACE: 1 tool &{Name:echo -n Varname:ECHO_N MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
|
||||
"TRACE: 1 tool &{Name:false Varname:FALSE MustUseVarForm:true Predefined:true UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:gawk Varname:AWK MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:m4 Varname: MustUseVarForm:false Predefined:true UsableAtLoadTime:true}",
|
||||
"TRACE: 1 tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadTime:true}",
|
||||
"TRACE: 1 tool &{Name:strip Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
|
||||
"TRACE: 1 tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
|
||||
"TRACE: 1 tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
|
||||
"TRACE: - (*ToolRegistry).Trace()")
|
||||
}
|
||||
|
||||
|
|
|
@ -45,9 +45,9 @@ type PlistChecker struct {
|
|||
}
|
||||
|
||||
type PlistLine struct {
|
||||
line Line
|
||||
conditional string // e.g. PLIST.docs
|
||||
text string // Like line.text, without the conditional
|
||||
line Line
|
||||
condition string // e.g. PLIST.docs
|
||||
text string // Like line.text, without the condition
|
||||
}
|
||||
|
||||
func (ck *PlistChecker) Check(plainLines []Line) {
|
||||
|
@ -55,8 +55,8 @@ func (ck *PlistChecker) Check(plainLines []Line) {
|
|||
ck.collectFilesAndDirs(plines)
|
||||
|
||||
if fname := plines[0].line.Filename; path.Base(fname) == "PLIST.common_end" {
|
||||
commonLines, err := readLines(strings.TrimSuffix(fname, "_end"), false)
|
||||
if err == nil {
|
||||
commonLines := Load(strings.TrimSuffix(fname, "_end"), NotEmpty)
|
||||
if commonLines != nil {
|
||||
ck.collectFilesAndDirs(ck.NewLines(commonLines))
|
||||
}
|
||||
}
|
||||
|
@ -81,13 +81,13 @@ func (ck *PlistChecker) Check(plainLines []Line) {
|
|||
func (ck *PlistChecker) NewLines(lines []Line) []*PlistLine {
|
||||
plines := make([]*PlistLine, len(lines))
|
||||
for i, line := range lines {
|
||||
conditional, text := "", line.Text
|
||||
condition, text := "", line.Text
|
||||
if hasPrefix(text, "${PLIST.") {
|
||||
if m, cond, rest := match2(text, `^(?:\$\{(PLIST\.[\w-.]+)\})+(.*)`); m {
|
||||
conditional, text = cond, rest
|
||||
condition, text = cond, rest
|
||||
}
|
||||
}
|
||||
plines[i] = &PlistLine{line, conditional, text}
|
||||
plines[i] = &PlistLine{line, condition, text}
|
||||
}
|
||||
return plines
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func (ck *PlistChecker) collectFilesAndDirs(plines []*PlistLine) {
|
|||
first == '$',
|
||||
'A' <= first && first <= 'Z',
|
||||
'0' <= first && first <= '9':
|
||||
if prev := ck.allFiles[text]; prev == nil || pline.conditional < prev.conditional {
|
||||
if prev := ck.allFiles[text]; prev == nil || pline.condition < prev.condition {
|
||||
ck.allFiles[text] = pline
|
||||
}
|
||||
for dir := path.Dir(text); dir != "."; dir = path.Dir(dir) {
|
||||
|
@ -224,7 +224,7 @@ func (ck *PlistChecker) checkDuplicate(pline *PlistLine) {
|
|||
}
|
||||
|
||||
prev := ck.allFiles[text]
|
||||
if prev == pline || prev.conditional != "" {
|
||||
if prev == pline || prev.condition != "" {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -518,7 +518,7 @@ func (s *plistLineSorter) Sort() {
|
|||
mi := s.middle[i]
|
||||
mj := s.middle[j]
|
||||
less := mi.text < mj.text || (mi.text == mj.text &&
|
||||
mi.conditional < mj.conditional)
|
||||
mi.condition < mj.condition)
|
||||
if (i < j) != less {
|
||||
s.changed = true
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ func (s *Suite) Test_ChecklinesPlist(c *check.C) {
|
|||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Wall")
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
lines := t.NewLines("PLIST",
|
||||
"bin/i386/6c",
|
||||
"bin/program",
|
||||
|
@ -76,10 +76,10 @@ func (s *Suite) Test_ChecklinesPlist__commonEnd(c *check.C) {
|
|||
t.CheckOutputEmpty()
|
||||
}
|
||||
|
||||
func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) {
|
||||
func (s *Suite) Test_ChecklinesPlist__condition(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
G.Pkg.plistSubstCond["PLIST.bincmds"] = true
|
||||
lines := t.NewLines("PLIST",
|
||||
PlistRcsID,
|
||||
|
@ -101,7 +101,7 @@ func (s *Suite) Test_ChecklinesPlist__sorting(c *check.C) {
|
|||
"sbin/i386/6c",
|
||||
"sbin/program",
|
||||
"bin/otherprogram",
|
||||
"${PLIST.conditional}bin/cat")
|
||||
"${PLIST.condition}bin/cat")
|
||||
|
||||
ChecklinesPlist(lines)
|
||||
|
||||
|
@ -129,7 +129,7 @@ func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
|
|||
"man/man1/program.1",
|
||||
"${PLIST.two}bin/program2",
|
||||
"lib/before.la",
|
||||
"${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", // Double conditional, see graphics/graphviz
|
||||
"${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", // Double condition, see graphics/graphviz
|
||||
"lib/after.la",
|
||||
"@exec echo \"after lib/after.la\"")
|
||||
ck := &PlistChecker{nil, nil, "", Once{}}
|
||||
|
@ -155,7 +155,7 @@ func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
|
|||
"C",
|
||||
"CCC",
|
||||
"b",
|
||||
"${PLIST.one}bin/program", // Conditionals are ignored while sorting
|
||||
"${PLIST.one}bin/program", // Conditional lines are ignored during sorting
|
||||
"${PLIST.two}bin/program2",
|
||||
"ddd",
|
||||
"lib/after.la",
|
||||
|
@ -169,7 +169,7 @@ func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
|
|||
func (s *Suite) Test_PlistChecker_checkpathMan_gz(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
lines := t.NewLines("PLIST",
|
||||
PlistRcsID,
|
||||
"man/man3/strerror.3.gz")
|
||||
|
@ -211,7 +211,7 @@ func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
|
|||
|
||||
t.SetupCommandLine("-Wall")
|
||||
|
||||
fname := t.CreateFileLines("PLIST",
|
||||
lines := t.SetupFileLines("PLIST",
|
||||
PlistRcsID,
|
||||
"lib/libvirt/connection-driver/libvirt_driver_storage.la",
|
||||
"${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la",
|
||||
|
@ -232,7 +232,7 @@ func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
|
|||
"@pkgdir etc/libvirt/qemu/networks/autostart",
|
||||
"@pkgdir etc/logrotate.d",
|
||||
"@pkgdir etc/sasl2")
|
||||
lines := LoadExistingLines(fname, false)
|
||||
|
||||
ChecklinesPlist(lines)
|
||||
|
||||
t.CheckOutputLines(
|
||||
|
@ -245,12 +245,9 @@ func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
|
|||
t.SetupCommandLine("-Wall", "--autofix")
|
||||
ChecklinesPlist(lines)
|
||||
|
||||
fixedLines := LoadExistingLines(fname, false)
|
||||
|
||||
t.CheckOutputLines(
|
||||
"AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".",
|
||||
"AUTOFIX: ~/PLIST:2: Sorting the whole file.")
|
||||
c.Check(len(lines), equals, len(fixedLines))
|
||||
t.CheckFileLines("PLIST",
|
||||
PlistRcsID,
|
||||
"${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la",
|
||||
|
@ -274,9 +271,9 @@ func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
|
|||
"@pkgdir etc/sasl2")
|
||||
}
|
||||
|
||||
// When the same entry appears both with and without a conditional,
|
||||
// the one with the conditional can be removed.
|
||||
// When the same entry appears with several different conditionals,
|
||||
// When the same entry appears both with and without a condition,
|
||||
// the one with the condition can be removed.
|
||||
// When the same entry appears with several different conditions,
|
||||
// all of them must stay.
|
||||
func (s *Suite) Test_PlistChecker__remove_same_entries(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
|
|
@ -6,8 +6,8 @@ package regex
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"netbsd.org/pkglint/histogram"
|
||||
"os"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
@ -19,16 +19,13 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
res map[Pattern]*regexp.Regexp
|
||||
rematch *histogram.Histogram
|
||||
renomatch *histogram.Histogram
|
||||
retime *histogram.Histogram
|
||||
res = make(map[Pattern]*regexp.Regexp)
|
||||
rematch = histogram.New()
|
||||
renomatch = histogram.New()
|
||||
retime = histogram.New()
|
||||
)
|
||||
|
||||
func Compile(re Pattern) *regexp.Regexp {
|
||||
if res == nil {
|
||||
res = make(map[Pattern]*regexp.Regexp)
|
||||
}
|
||||
cre := res[re]
|
||||
if cre == nil {
|
||||
cre = regexp.MustCompile(string(re))
|
||||
|
@ -50,12 +47,6 @@ func Match(s string, re Pattern) []string {
|
|||
delay := immediatelyBefore.UnixNano() - before.UnixNano()
|
||||
timeTaken := after.UnixNano() - immediatelyBefore.UnixNano() - delay
|
||||
|
||||
if retime == nil {
|
||||
retime = histogram.New()
|
||||
rematch = histogram.New()
|
||||
renomatch = histogram.New()
|
||||
}
|
||||
|
||||
retime.Add(string(re), int(timeTaken))
|
||||
if m != nil {
|
||||
rematch.Add(string(re), 1)
|
||||
|
@ -124,11 +115,11 @@ func ReplaceFirst(s string, re Pattern, replacement string) ([]string, string) {
|
|||
return nil, s
|
||||
}
|
||||
|
||||
func PrintStats() {
|
||||
func PrintStats(out io.Writer) {
|
||||
if Profiling {
|
||||
rematch.PrintStats("rematch", os.Stdout, 10)
|
||||
renomatch.PrintStats("renomatch", os.Stdout, 10)
|
||||
retime.PrintStats("retime", os.Stdout, 10)
|
||||
rematch.PrintStats("rematch", out, 10)
|
||||
renomatch.PrintStats("renomatch", out, 10)
|
||||
retime.PrintStats("retime", out, 10)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
|
|||
|
||||
t.CheckOutputEmpty()
|
||||
|
||||
checkShellCommandLine("${RUN} echo $${variable+set}")
|
||||
checkShellCommandLine("${RUN} set +x; echo $${variable+set}")
|
||||
|
||||
t.CheckOutputEmpty()
|
||||
|
||||
|
@ -234,7 +234,7 @@ func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
|
|||
"WARN: fname:1: The shell command \"cp\" should not be hidden.",
|
||||
"WARN: fname:1: Unknown shell command \"cp\".")
|
||||
|
||||
G.Pkg = NewPackage("category/pkgbase")
|
||||
G.Pkg = NewPackage(t.File("category/pkgbase"))
|
||||
G.Pkg.PlistDirs["share/pkgbase"] = true
|
||||
|
||||
// A directory that is found in the PLIST.
|
||||
|
|
|
@ -32,3 +32,10 @@ func (s *Suite) Test_ShAtom_String(c *check.C) {
|
|||
func (s *Suite) Test_ShQuoting_String(c *check.C) {
|
||||
c.Check(shqDquotBacktSquot.String(), equals, "dbs")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_ShToken_String(c *check.C) {
|
||||
tokenizer := NewShTokenizer(dummyLine, "${ECHO} \"hello, world\"", false)
|
||||
|
||||
c.Check(tokenizer.ShToken().String(), equals, "ShToken([varuse(\"ECHO\")])")
|
||||
c.Check(tokenizer.ShToken().String(), equals, "ShToken([ShAtom(word, \"\\\"\", d) ShAtom(word, \"hello, world\", d) \"\\\"\"])")
|
||||
}
|
||||
|
|
|
@ -134,13 +134,13 @@ func (ctx *SubstContext) Varassign(mkline MkLine) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ctx *SubstContext) Conditional(mkline MkLine) {
|
||||
func (ctx *SubstContext) Directive(mkline MkLine) {
|
||||
if ctx.id == "" || !G.opts.WarnExtra {
|
||||
return
|
||||
}
|
||||
|
||||
if trace.Tracing {
|
||||
trace.Stepf("+ SubstContext.Conditional %#v %v#", ctx.curr, ctx.inAllBranches)
|
||||
trace.Stepf("+ SubstContext.Directive %#v %v#", ctx.curr, ctx.inAllBranches)
|
||||
}
|
||||
dir := mkline.Directive()
|
||||
if dir == "if" {
|
||||
|
@ -159,7 +159,7 @@ func (ctx *SubstContext) Conditional(mkline MkLine) {
|
|||
ctx.curr.Or(ctx.inAllBranches)
|
||||
}
|
||||
if trace.Tracing {
|
||||
trace.Stepf("- SubstContext.Conditional %#v %v#", ctx.curr, ctx.inAllBranches)
|
||||
trace.Stepf("- SubstContext.Directive %#v %v#", ctx.curr, ctx.inAllBranches)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ func (s *Suite) Test_SubstContext__no_class(c *check.C) {
|
|||
"WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_SubstContext__conditionals(c *check.C) {
|
||||
func (s *Suite) Test_SubstContext__directives(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Wextra")
|
||||
|
@ -119,7 +119,7 @@ func (s *Suite) Test_SubstContext__conditionals(c *check.C) {
|
|||
"WARN: Makefile:18: All but the first \"SUBST_SED.os\" lines should use the \"+=\" operator.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_SubstContext__one_conditional_missing_transformation(c *check.C) {
|
||||
func (s *Suite) Test_SubstContext__missing_transformation_in_one_branch(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
t.SetupCommandLine("-Wextra")
|
||||
|
@ -254,7 +254,7 @@ func simulateSubstLines(t *Tester, texts ...string) {
|
|||
case text == "":
|
||||
ctx.Finish(line)
|
||||
case hasPrefix(text, "."):
|
||||
ctx.Conditional(line)
|
||||
ctx.Directive(line)
|
||||
default:
|
||||
ctx.Varassign(line)
|
||||
}
|
||||
|
|
|
@ -6,13 +6,17 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// Tool is one of the many standard shell utilities that are typically
|
||||
// provided by the operating system, or, if missing, are installed via
|
||||
// pkgsrc.
|
||||
//
|
||||
// See `mk/tools/`.
|
||||
type Tool struct {
|
||||
Name string // e.g. "sed", "gzip"
|
||||
Varname string // e.g. "SED", "GZIP_CMD"
|
||||
MustUseVarForm bool // True for `echo`, because of many differing implementations.
|
||||
Predefined bool // This tool is used by the pkgsrc infrastructure, therefore the package does not need to add it to `USE_TOOLS` explicitly.
|
||||
UsableAtLoadtime bool // May be used after including `bsd.prefs.mk`.
|
||||
UsableAtLoadTime bool // May be used after including `bsd.prefs.mk`.
|
||||
}
|
||||
|
||||
type ToolRegistry struct {
|
||||
|
@ -28,9 +32,9 @@ func NewToolRegistry() ToolRegistry {
|
|||
// The tool may then be used by this name (e.g. "awk"),
|
||||
// but not by a corresponding variable (e.g. ${AWK}).
|
||||
// The toolname may include the scope (:pkgsrc, :run, etc.).
|
||||
func (tr *ToolRegistry) Register(toolname string, line Line) *Tool {
|
||||
func (tr *ToolRegistry) Register(toolname string, mkline MkLine) *Tool {
|
||||
name := strings.SplitN(toolname, ":", 2)[0]
|
||||
tr.validateToolName(name, line)
|
||||
tr.validateToolName(name, mkline)
|
||||
|
||||
tool := tr.byName[name]
|
||||
if tool == nil {
|
||||
|
@ -40,15 +44,15 @@ func (tr *ToolRegistry) Register(toolname string, line Line) *Tool {
|
|||
return tool
|
||||
}
|
||||
|
||||
func (tr *ToolRegistry) RegisterVarname(toolname, varname string, line Line) *Tool {
|
||||
tool := tr.Register(toolname, line)
|
||||
func (tr *ToolRegistry) RegisterVarname(toolname, varname string, mkline MkLine) *Tool {
|
||||
tool := tr.Register(toolname, mkline)
|
||||
tool.Varname = varname
|
||||
tr.byVarname[varname] = tool
|
||||
return tool
|
||||
}
|
||||
|
||||
func (tr *ToolRegistry) RegisterTool(tool *Tool, line Line) {
|
||||
tr.validateToolName(tool.Name, line)
|
||||
func (tr *ToolRegistry) RegisterTool(tool *Tool, mkline MkLine) {
|
||||
tr.validateToolName(tool.Name, mkline)
|
||||
|
||||
if tool.Name != "" && tr.byName[tool.Name] == nil {
|
||||
tr.byName[tool.Name] = tool
|
||||
|
@ -90,24 +94,23 @@ func (tr *ToolRegistry) Trace() {
|
|||
|
||||
// ParseToolLine parses a tool definition from the pkgsrc infrastructure,
|
||||
// e.g. in mk/tools/replace.mk.
|
||||
func (tr *ToolRegistry) ParseToolLine(line Line) {
|
||||
if m, commented, varname, _, _, _, value, _, _ := MatchVarassign(line.Text); m {
|
||||
if commented {
|
||||
return
|
||||
}
|
||||
func (tr *ToolRegistry) ParseToolLine(mkline MkLine) {
|
||||
if mkline.IsVarassign() {
|
||||
varname := mkline.Varname()
|
||||
value := mkline.Value()
|
||||
if varname == "TOOLS_CREATE" && (value == "[" || matches(value, `^?[-\w.]+$`)) {
|
||||
tr.Register(value, line)
|
||||
tr.Register(value, mkline)
|
||||
|
||||
} else if m, toolname := match1(varname, `^_TOOLS_VARNAME\.([-\w.]+|\[)$`); m {
|
||||
tr.RegisterVarname(toolname, value, line)
|
||||
tr.RegisterVarname(toolname, value, mkline)
|
||||
|
||||
} else if m, toolname := match1(varname, `^(?:TOOLS_PATH|_TOOLS_DEPMETHOD)\.([-\w.]+|\[)$`); m {
|
||||
tr.Register(toolname, line)
|
||||
} else if m, toolname = match1(varname, `^(?:TOOLS_PATH|_TOOLS_DEPMETHOD)\.([-\w.]+|\[)$`); m {
|
||||
tr.Register(toolname, mkline)
|
||||
|
||||
} else if m, toolname := match1(varname, `^_TOOLS\.(.*)`); m {
|
||||
tr.Register(toolname, line)
|
||||
} else if m, toolname = match1(varname, `^_TOOLS\.(.*)`); m {
|
||||
tr.Register(toolname, mkline)
|
||||
for _, tool := range splitOnSpace(value) {
|
||||
tr.Register(tool, line)
|
||||
tr.Register(tool, mkline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +130,8 @@ func (tr *ToolRegistry) ForEach(action func(tool *Tool)) {
|
|||
}
|
||||
}
|
||||
|
||||
func (tr *ToolRegistry) validateToolName(toolName string, line Line) {
|
||||
func (tr *ToolRegistry) validateToolName(toolName string, mkline MkLine) {
|
||||
if toolName != "echo -n" && !matches(toolName, `^([-a-z0-9.]+|\[)$`) {
|
||||
line.Errorf("Invalid tool name %q", toolName)
|
||||
mkline.Errorf("Invalid tool name %q.", toolName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,3 +17,16 @@ func (s *Suite) Test_ToolRegistry_ParseToolLine(c *check.C) {
|
|||
// No error about "Unknown tool \"NetBSD\"."
|
||||
t.CheckOutputEmpty()
|
||||
}
|
||||
|
||||
func (s *Suite) Test_ToolRegistry_validateToolName__invalid(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
reg := NewToolRegistry()
|
||||
|
||||
reg.Register("tool_name", dummyMkLine)
|
||||
|
||||
// Currently, the underscore is not used in any tool name.
|
||||
// If there should ever be such a case, just use a different character.
|
||||
t.CheckOutputLines(
|
||||
"ERROR: Invalid tool name \"tool_name\".")
|
||||
}
|
||||
|
|
|
@ -18,18 +18,18 @@ func CheckdirToplevel(dir string) {
|
|||
ctx := &Toplevel{dir, "", nil}
|
||||
fname := dir + "/Makefile"
|
||||
|
||||
lines := LoadNonemptyLines(fname, true)
|
||||
if lines == nil {
|
||||
mklines := LoadMk(fname, NotEmpty|LogErrors)
|
||||
if mklines == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
if m, commentedOut, indentation, subdir, comment := match4(line.Text, `^(#?)SUBDIR\s*\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m {
|
||||
ctx.checkSubdir(line, commentedOut == "#", indentation, subdir, comment)
|
||||
for _, mkline := range mklines.mklines {
|
||||
if (mkline.IsVarassign() || mkline.IsCommentedVarassign()) && mkline.Varname() == "SUBDIR" {
|
||||
ctx.checkSubdir(mkline)
|
||||
}
|
||||
}
|
||||
|
||||
NewMkLines(lines).Check()
|
||||
mklines.Check()
|
||||
|
||||
if G.opts.Recursive {
|
||||
if G.opts.CheckGlobal {
|
||||
|
@ -40,13 +40,15 @@ func CheckdirToplevel(dir string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subdir, comment string) {
|
||||
if commentedOut && comment == "" {
|
||||
line.Warnf("%q commented out without giving a reason.", subdir)
|
||||
func (ctx *Toplevel) checkSubdir(mkline MkLine) {
|
||||
subdir := mkline.Value()
|
||||
|
||||
if mkline.IsCommentedVarassign() && (mkline.VarassignComment() == "#" || mkline.VarassignComment() == "") {
|
||||
mkline.Warnf("%q commented out without giving a reason.", subdir)
|
||||
}
|
||||
|
||||
if indentation != "\t" {
|
||||
line.Warnf("Indentation should be a single tab character.")
|
||||
if !hasSuffix(mkline.ValueAlign(), "=\t") {
|
||||
mkline.Warnf("Indentation should be a single tab character.")
|
||||
}
|
||||
|
||||
if contains(subdir, "$") || !fileExists(ctx.dir+"/"+subdir+"/Makefile") {
|
||||
|
@ -58,15 +60,15 @@ func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subd
|
|||
case subdir > prev:
|
||||
// Correctly ordered
|
||||
case subdir == prev:
|
||||
line.Errorf("Each subdir must only appear once.")
|
||||
mkline.Errorf("Each subdir must only appear once.")
|
||||
case subdir == "archivers" && prev == "x11":
|
||||
// This exception is documented in the top-level Makefile.
|
||||
default:
|
||||
line.Warnf("%s should come before %s.", subdir, prev)
|
||||
mkline.Warnf("%s should come before %s.", subdir, prev)
|
||||
}
|
||||
ctx.previousSubdir = subdir
|
||||
|
||||
if !commentedOut {
|
||||
if !mkline.IsCommentedVarassign() {
|
||||
ctx.subdirs = append(ctx.subdirs, ctx.dir+"/"+subdir)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,8 +169,8 @@ func loadCvsEntries(fname string) []Line {
|
|||
return G.CvsEntriesLines
|
||||
}
|
||||
|
||||
lines, err := readLines(dir+"/CVS/Entries", false)
|
||||
if err != nil {
|
||||
lines := Load(dir+"/CVS/Entries", 0)
|
||||
if lines == nil {
|
||||
return nil
|
||||
}
|
||||
G.CvsEntriesDir = dir
|
||||
|
@ -301,7 +301,7 @@ func dirglob(dirname string) []string {
|
|||
var fnames []string
|
||||
for _, fi := range fis {
|
||||
if !(isIgnoredFilename(fi.Name())) {
|
||||
fnames = append(fnames, dirname+"/"+fi.Name())
|
||||
fnames = append(fnames, cleanpath(dirname+"/"+fi.Name()))
|
||||
}
|
||||
}
|
||||
return fnames
|
||||
|
@ -585,7 +585,7 @@ func naturalLess(str1, str2 string) bool {
|
|||
// but that's deep in the infrastructure and only affects the "nb13" extension.)
|
||||
type RedundantScope struct {
|
||||
vars map[string]*redundantScopeVarinfo
|
||||
condLevel int
|
||||
dirLevel int
|
||||
OnIgnore func(old, new MkLine)
|
||||
OnOverwrite func(old, new MkLine)
|
||||
}
|
||||
|
@ -602,7 +602,7 @@ func (s *RedundantScope) Handle(mkline MkLine) {
|
|||
switch {
|
||||
case mkline.IsVarassign():
|
||||
varname := mkline.Varname()
|
||||
if s.condLevel != 0 {
|
||||
if s.dirLevel != 0 {
|
||||
s.vars[varname] = nil
|
||||
break
|
||||
}
|
||||
|
@ -645,12 +645,12 @@ func (s *RedundantScope) Handle(mkline MkLine) {
|
|||
}
|
||||
}
|
||||
|
||||
case mkline.IsCond():
|
||||
case mkline.IsDirective():
|
||||
switch mkline.Directive() {
|
||||
case "for", "if", "ifdef", "ifndef":
|
||||
s.condLevel++
|
||||
s.dirLevel++
|
||||
case "endfor", "endif":
|
||||
s.condLevel--
|
||||
s.dirLevel--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,11 +86,13 @@ func (s *Suite) Test_isEmptyDir_and_getSubdirs(c *check.C) {
|
|||
|
||||
if absent := t.File("nonexistent"); true {
|
||||
c.Check(isEmptyDir(absent), equals, true) // Counts as empty.
|
||||
defer t.ExpectFatalError(func() {
|
||||
c.Check(t.Output(), check.Matches, `FATAL: (.+): Cannot be read: open (.+): (.+)\n`)
|
||||
})
|
||||
getSubdirs(absent) // Panics with a pkglintFatal.
|
||||
c.FailNow()
|
||||
|
||||
func() {
|
||||
defer t.ExpectFatalError()
|
||||
getSubdirs(absent) // Panics with a pkglintFatal.
|
||||
}()
|
||||
// The last group from the error message is localized, therefore the matching.
|
||||
c.Check(t.Output(), check.Matches, `FATAL: ~/nonexistent: Cannot be read: open ~/nonexistent: (.+)\n`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,41 +71,18 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
acl(varname, kindOfList, checker, "buildlink3.mk, builtin.mk:; *: use-loadtime, use")
|
||||
}
|
||||
|
||||
jvms := enum(func() string {
|
||||
lines, _ := readLines(src.File("mk/java-vm.mk"), true)
|
||||
mklines := NewMkLines(lines)
|
||||
jvms := make(map[string]bool)
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsVarassign() && mkline.Varcanon() == "_PKG_JVMS.*" {
|
||||
words, _ := splitIntoMkWords(mkline.Line, mkline.Value())
|
||||
for _, word := range words {
|
||||
if !contains(word, "$") {
|
||||
jvms[word] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(jvms) == 0 {
|
||||
return "openjdk8 oracle-jdk8 openjdk7 sun-jdk7 sun-jdk6 jdk16 jdk15 kaffe"
|
||||
}
|
||||
joined := keysJoined(jvms)
|
||||
if trace.Tracing {
|
||||
trace.Stepf("JVMs from mk/java-vm.mk: %s", joined)
|
||||
}
|
||||
return joined
|
||||
}())
|
||||
|
||||
languages := enum(
|
||||
func() string {
|
||||
lines, _ := readLines(src.File("mk/compiler.mk"), true)
|
||||
mklines := NewMkLines(lines)
|
||||
mklines := LoadMk(src.File("mk/compiler.mk"), NotEmpty)
|
||||
languages := make(map[string]bool)
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsCond() && mkline.Directive() == "for" {
|
||||
words := splitOnSpace(mkline.Args())
|
||||
if len(words) > 2 && words[0] == "_version_" {
|
||||
for _, word := range words[2:] {
|
||||
languages[word] = true
|
||||
if mklines != nil {
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsDirective() && mkline.Directive() == "for" {
|
||||
words := splitOnSpace(mkline.Args())
|
||||
if len(words) > 2 && words[0] == "_version_" {
|
||||
for _, word := range words[2:] {
|
||||
languages[word] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,17 +98,68 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
return joined
|
||||
}())
|
||||
|
||||
enumFrom := func(fileName, varname, defval string) *BasicType {
|
||||
lines, _ := readLines(src.File(fileName), true)
|
||||
mklines := NewMkLines(lines)
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsVarassign() && mkline.Varname() == varname {
|
||||
return enum(mkline.Value())
|
||||
enumFrom := func(fileName string, defval string, varcanons ...string) *BasicType {
|
||||
mklines := LoadMk(src.File(fileName), NotEmpty)
|
||||
values := make(map[string]bool)
|
||||
|
||||
if mklines != nil {
|
||||
for _, mkline := range mklines.mklines {
|
||||
if mkline.IsVarassign() {
|
||||
varcanon := mkline.Varcanon()
|
||||
for _, vc := range varcanons {
|
||||
if vc == varcanon {
|
||||
words, _ := splitIntoMkWords(mkline.Line, mkline.Value())
|
||||
for _, word := range words {
|
||||
if !contains(word, "$") {
|
||||
values[word] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(values) != 0 {
|
||||
joined := keysJoined(values)
|
||||
if trace.Tracing {
|
||||
trace.Stepf("Enum from %s in: %s", strings.Join(varcanons, " "), fileName, joined)
|
||||
}
|
||||
return enum(joined)
|
||||
}
|
||||
|
||||
if trace.Tracing {
|
||||
trace.Stepf("Enum from default value: %s", defval)
|
||||
}
|
||||
return enum(defval)
|
||||
}
|
||||
|
||||
compilers := enumFrom(
|
||||
"mk/compiler.mk",
|
||||
"ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc",
|
||||
"_COMPILERS",
|
||||
"_PSEUDO_COMPILERS")
|
||||
|
||||
emacsVersions := enumFrom(
|
||||
"editors/emacs/modules.mk",
|
||||
"emacs25 emacs21 emacs21nox emacs20 xemacs215 xemacs215nox xemacs214 xemacs214nox",
|
||||
"_EMACS_VERSIONS_ALL")
|
||||
|
||||
mysqlVersions := enumFrom(
|
||||
"mk/mysql.buildlink3.mk",
|
||||
"57 56 55 51 MARIADB55",
|
||||
"MYSQL_VERSIONS_ACCEPTED")
|
||||
|
||||
pgsqlVersions := enumFrom(
|
||||
"mk/pgsql.buildlink3.mk",
|
||||
"10 96 95 94 93",
|
||||
"PGSQL_VERSIONS_ACCEPTED")
|
||||
|
||||
jvms := enumFrom(
|
||||
"mk/java-vm.mk",
|
||||
"openjdk8 oracle-jdk8 openjdk7 sun-jdk7 sun-jdk6 jdk16 jdk15 kaffe",
|
||||
"_PKG_JVMS.*")
|
||||
|
||||
// Last synced with mk/defaults/mk.conf revision 1.269
|
||||
usr("USE_CWRAPPERS", lkNone, enum("yes no auto"))
|
||||
usr("ALLOW_VULNERABLE_PACKAGES", lkNone, BtYes)
|
||||
|
@ -153,7 +181,7 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
usr("PKG_DEVELOPER", lkNone, BtYesNo)
|
||||
usr("USE_ABI_DEPENDS", lkNone, BtYesNo)
|
||||
usr("PKG_REGISTER_SHELLS", lkNone, enum("YES NO"))
|
||||
usr("PKGSRC_COMPILER", lkShell, enum("ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc"))
|
||||
usr("PKGSRC_COMPILER", lkShell, compilers)
|
||||
usr("PKGSRC_KEEP_BIN_PKGS", lkNone, BtYesNo)
|
||||
usr("PKGSRC_MESSAGE_RECIPIENTS", lkShell, BtMailAddress)
|
||||
usr("PKGSRC_SHOW_BUILD_DEFS", lkNone, BtYesNo)
|
||||
|
@ -599,10 +627,10 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
sys("EMACS_PKGNAME_PREFIX", lkNone, BtIdentifier) // Or the empty string.
|
||||
sys("EMACS_TYPE", lkNone, enum("emacs xemacs"))
|
||||
acl("EMACS_USE_LEIM", lkNone, BtYes, "")
|
||||
acl("EMACS_VERSIONS_ACCEPTED", lkShell, enumFrom("editors/emacs/modules.mk", "_EMACS_VERSIONS_ALL", "emacs25 emacs21 emacs21nox emacs20 xemacs215 xemacs215nox xemacs214 xemacs214nox"), "Makefile: set")
|
||||
acl("EMACS_VERSIONS_ACCEPTED", lkShell, emacsVersions, "Makefile: set")
|
||||
sys("EMACS_VERSION_MAJOR", lkNone, BtInteger)
|
||||
sys("EMACS_VERSION_MINOR", lkNone, BtInteger)
|
||||
acl("EMACS_VERSION_REQD", lkShell, enum("emacs25 emacs25nox emacs21 emacs21nox emacs20 xemacs215 xemacs214"), "Makefile: set, append")
|
||||
acl("EMACS_VERSION_REQD", lkShell, emacsVersions, "Makefile: set, append")
|
||||
sys("EMULDIR", lkNone, BtPathname)
|
||||
sys("EMULSUBDIR", lkNone, BtPathname)
|
||||
sys("OPSYS_EMULDIR", lkNone, BtPathname)
|
||||
|
@ -796,11 +824,11 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
acl("MESSAGE_SUBST", lkShell, BtShellWord, "Makefile, Makefile.common, options.mk: append")
|
||||
pkg("META_PACKAGE", lkNone, BtYes)
|
||||
sys("MISSING_FEATURES", lkShell, BtIdentifier)
|
||||
acl("MYSQL_VERSIONS_ACCEPTED", lkShell, enumFrom("mk/mysql.buildlink3.mk", "MYSQL_VERSIONS_ACCEPTED", "57 56 55 51 MARIADB55"), "Makefile: set")
|
||||
acl("MYSQL_VERSIONS_ACCEPTED", lkShell, mysqlVersions, "Makefile: set")
|
||||
usr("MYSQL_VERSION_DEFAULT", lkNone, BtVersion)
|
||||
sys("NM", lkNone, BtShellCommand)
|
||||
sys("NONBINMODE", lkNone, BtFileMode)
|
||||
pkg("NOT_FOR_COMPILER", lkShell, enum("ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc"))
|
||||
pkg("NOT_FOR_COMPILER", lkShell, compilers)
|
||||
pkglist("NOT_FOR_BULK_PLATFORM", lkSpace, BtMachinePlatformPattern)
|
||||
pkglist("NOT_FOR_PLATFORM", lkSpace, BtMachinePlatformPattern)
|
||||
pkg("NOT_FOR_UNPRIVILEGED", lkNone, BtYesNo)
|
||||
|
@ -817,7 +845,7 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
acl("NO_PKGTOOLS_REQD_CHECK", lkNone, BtYes, "Makefile: set")
|
||||
acl("NO_SRC_ON_CDROM", lkNone, BtRestricted, "Makefile, Makefile.common: set")
|
||||
acl("NO_SRC_ON_FTP", lkNone, BtRestricted, "Makefile, Makefile.common: set")
|
||||
pkglist("ONLY_FOR_COMPILER", lkShell, enum("ccc clang gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc"))
|
||||
pkglist("ONLY_FOR_COMPILER", lkShell, compilers)
|
||||
pkglist("ONLY_FOR_PLATFORM", lkSpace, BtMachinePlatformPattern)
|
||||
pkg("ONLY_FOR_UNPRIVILEGED", lkNone, BtYesNo)
|
||||
sys("OPSYS", lkNone, BtIdentifier)
|
||||
|
@ -844,7 +872,7 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
pkg("PERL5_REQD", lkShell, BtVersion)
|
||||
pkg("PERL5_USE_PACKLIST", lkNone, BtYesNo)
|
||||
sys("PGSQL_PREFIX", lkNone, BtPathname)
|
||||
acl("PGSQL_VERSIONS_ACCEPTED", lkShell, enumFrom("mk/pgsql.buildlink3.mk", "PGSQL_VERSIONS_ACCEPTED", "10 96 95 94 93"), "")
|
||||
acl("PGSQL_VERSIONS_ACCEPTED", lkShell, pgsqlVersions, "")
|
||||
usr("PGSQL_VERSION_DEFAULT", lkNone, BtVersion)
|
||||
sys("PG_LIB_EXT", lkNone, enum("dylib so"))
|
||||
sys("PGSQL_TYPE", lkNone, enum("postgresql81-client postgresql80-client"))
|
||||
|
@ -924,7 +952,7 @@ func (src *Pkgsrc) InitVartypes() {
|
|||
acl("PKG_USERS", lkShell, BtShellWord, "Makefile: set, append")
|
||||
pkg("PKG_USERS_VARS", lkShell, BtVariableName)
|
||||
acl("PKG_USE_KERBEROS", lkNone, BtYes, "Makefile, Makefile.common: set")
|
||||
// PLIST.* has special handling code
|
||||
pkg("PLIST.*", lkNone, BtYes)
|
||||
pkglist("PLIST_VARS", lkShell, BtIdentifier)
|
||||
pkglist("PLIST_SRC", lkShell, BtRelativePkgPath)
|
||||
pkglist("PLIST_SUBST", lkShell, BtShellWord)
|
||||
|
|
|
@ -8,14 +8,39 @@ func (s *Suite) Test_InitVartypes__enumFrom(c *check.C) {
|
|||
t.SetupFileMkLines("editors/emacs/modules.mk",
|
||||
MkRcsID,
|
||||
"",
|
||||
"_EMACS_VERSIONS_ALL=\temacs31",
|
||||
"_EMACS_VERSIONS_ALL=\tignored")
|
||||
"_EMACS_VERSIONS_ALL= emacs31",
|
||||
"_EMACS_VERSIONS_ALL+= emacs29")
|
||||
t.SetupFileMkLines("mk/java-vm.mk",
|
||||
MkRcsID,
|
||||
"",
|
||||
"_PKG_JVMS.8= openjdk8 oracle-jdk8",
|
||||
"_PKG_JVMS.7= ${_PKG_JVMS.8} openjdk7 sun-jdk7",
|
||||
"_PKG_JVMS.6= ${_PKG_JVMS.7} sun-jdk6 jdk16")
|
||||
t.SetupFileMkLines("mk/compiler.mk",
|
||||
MkRcsID,
|
||||
"",
|
||||
"_COMPILERS= gcc ido mipspro-ucode \\",
|
||||
" sunpro",
|
||||
"_PSEUDO_COMPILERS= ccache distcc f2c g95",
|
||||
"",
|
||||
".for _version_ in gnu++14 c++14 gnu++11 c++11 gnu++0x c++0x gnu++03 c++03",
|
||||
". if !empty(USE_LANGUAGES:M${_version_})",
|
||||
"USE_LANGUAGES+= c++",
|
||||
". endif",
|
||||
".endfor")
|
||||
mklines := t.SetupFileMkLines("Makefile",
|
||||
MkRcsID,
|
||||
"")
|
||||
|
||||
t.SetupVartypes()
|
||||
vartype := mklines.mklines[1].VariableType("EMACS_VERSIONS_ACCEPTED")
|
||||
|
||||
c.Check(vartype.String(), equals, "ShellList of enum: emacs31 ")
|
||||
checkEnumValues := func(varname, values string) {
|
||||
vartype := mklines.mklines[1].VariableType(varname).String()
|
||||
c.Check(vartype, equals, values)
|
||||
}
|
||||
|
||||
checkEnumValues("EMACS_VERSIONS_ACCEPTED", "ShellList of enum: emacs29 emacs31 ")
|
||||
checkEnumValues("PKG_JVM", "enum: jdk16 openjdk7 openjdk8 oracle-jdk8 sun-jdk6 sun-jdk7 ")
|
||||
checkEnumValues("USE_LANGUAGES", "ShellList of enum: ada c c++ c++03 c++0x c++11 c++14 c99 fortran fortran77 gnu++03 gnu++0x gnu++11 gnu++14 java obj-c++ objc ")
|
||||
checkEnumValues("PKGSRC_COMPILER", "ShellList of enum: ccache distcc f2c g95 gcc ido mipspro-ucode sunpro ")
|
||||
}
|
||||
|
|
|
@ -122,16 +122,21 @@ func (vt *Vartype) MayBeAppendedTo() bool {
|
|||
}
|
||||
|
||||
func (vt *Vartype) String() string {
|
||||
listPrefix := ""
|
||||
switch vt.kindOfList {
|
||||
case lkNone:
|
||||
return vt.basicType.name
|
||||
listPrefix = ""
|
||||
case lkSpace:
|
||||
return "SpaceList of " + vt.basicType.name
|
||||
listPrefix = "SpaceList of "
|
||||
case lkShell:
|
||||
return "ShellList of " + vt.basicType.name
|
||||
listPrefix = "ShellList of "
|
||||
default:
|
||||
panic("Unknown list type")
|
||||
}
|
||||
|
||||
guessedSuffix := ifelseStr(vt.guessed, " (guessed)", "")
|
||||
|
||||
return listPrefix + vt.basicType.name + guessedSuffix
|
||||
}
|
||||
|
||||
func (vt *Vartype) IsShell() bool {
|
||||
|
|
|
@ -39,7 +39,7 @@ const (
|
|||
opAssignEval // :=
|
||||
opAssignAppend // +=
|
||||
opAssignDefault // ?=
|
||||
opUseCompare // A variable is compared to a value, e.g. in a conditional.
|
||||
opUseCompare // A variable is compared to a value, e.g. in a condition.
|
||||
opUseMatch // A variable is matched using the :M or :N modifier.
|
||||
)
|
||||
|
||||
|
@ -1085,7 +1085,7 @@ func (cv *VartypeCheck) WrksrcSubdirectory() {
|
|||
func (cv *VartypeCheck) Yes() {
|
||||
switch cv.Op {
|
||||
case opUseMatch:
|
||||
cv.Line.Warnf("%s should only be used in a \".if defined(...)\" conditional.", cv.Varname)
|
||||
cv.Line.Warnf("%s should only be used in a \".if defined(...)\" condition.", cv.Varname)
|
||||
Explain(
|
||||
"This variable can have only two values: defined or undefined.",
|
||||
"When it is defined, it means \"yes\", even when its value is",
|
||||
|
|
|
@ -78,7 +78,7 @@ func (s *Suite) Test_VartypeCheck_CFlag(c *check.C) {
|
|||
func (s *Suite) Test_VartypeCheck_Comment(c *check.C) {
|
||||
t := s.Init(c)
|
||||
|
||||
G.Pkg = NewPackage("category/converter")
|
||||
G.Pkg = NewPackage(t.File("category/converter"))
|
||||
G.Pkg.EffectivePkgbase = "converter"
|
||||
|
||||
runVartypeChecks(t, "COMMENT", opAssign, (*VartypeCheck).Comment,
|
||||
|
@ -168,13 +168,13 @@ func (s *Suite) Test_VartypeCheck_DependencyWithPath(c *check.C) {
|
|||
|
||||
t.CreateFileLines("x11/alacarte/Makefile")
|
||||
t.CreateFileLines("category/package/Makefile")
|
||||
G.Pkg = NewPackage("category/package")
|
||||
G.Pkg = NewPackage(t.File("category/package"))
|
||||
|
||||
// Since this test involves relative paths, the filename of the line must be realistic.
|
||||
// Therefore this custom implementation of runVartypeChecks.
|
||||
runChecks := func(values ...string) {
|
||||
for i, value := range values {
|
||||
mkline := t.NewMkLine(t.File("category/package/fname.mk"), i+1, "DEPENDS+=\t"+value)
|
||||
mkline := t.NewMkLine(G.Pkg.File("fname.mk"), i+1, "DEPENDS+=\t"+value)
|
||||
mkline.Tokenize(mkline.Value())
|
||||
valueNovar := mkline.WithoutMakeVariables(mkline.Value())
|
||||
vc := &VartypeCheck{mkline, mkline.Line, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
|
||||
|
@ -272,6 +272,8 @@ func (s *Suite) Test_VartypeCheck_Enum__use_match(c *check.C) {
|
|||
".if !empty(MACHINE_ARCH:Mi386) || ${MACHINE_ARCH} == i386",
|
||||
".endif",
|
||||
".if !empty(PKGSRC_COMPILER:Mclang) || ${PKGSRC_COMPILER} == clang",
|
||||
".endif",
|
||||
".if ${MACHINE_ARCH:Ni386:Nx86_64:Nsparc64}",
|
||||
".endif")
|
||||
|
||||
mklines.Check()
|
||||
|
@ -661,9 +663,9 @@ func (s *Suite) Test_VartypeCheck_Yes(c *check.C) {
|
|||
"${YESVAR}")
|
||||
|
||||
t.CheckOutputLines(
|
||||
"WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
|
||||
"WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
|
||||
"WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.")
|
||||
"WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" condition.",
|
||||
"WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" condition.",
|
||||
"WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" condition.")
|
||||
}
|
||||
|
||||
func (s *Suite) Test_VartypeCheck_YesNo(c *check.C) {
|
||||
|
|
Loading…
Reference in a new issue