Sun Dec 2 23:12:43 2018 UTC ()
pkgtools/pkglint: update to 5.6.8

Changes since 5.6.7:

In pkgsrc-wip, if the first line of a file contains an expanded CVS Id,
it is not an error but only a note that it should be an unexpanded CVS
Id. The autofix for this no longer inserts a new line but replaces the
existing line.

Several refactorings and small improvements to the existing diagnostics.


(rillig)
diff -r1.559 -r1.560 pkgsrc/pkgtools/pkglint/Makefile
diff -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/autofix.go
diff -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/pkgsrc.go
diff -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/buildlink3_test.go
diff -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/vartype.go
diff -r1.14 -r1.15 pkgsrc/pkgtools/pkglint/files/category_test.go
diff -r1.17 -r1.18 pkgsrc/pkgtools/pkglint/files/licenses.go
diff -r1.28 -r1.29 pkgsrc/pkgtools/pkglint/files/line.go
diff -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/lines.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/lines_test.go
diff -r1.41 -r1.42 pkgsrc/pkgtools/pkglint/files/mkline.go
diff -r1.41 -r1.42 pkgsrc/pkgtools/pkglint/files/pkglint.go
diff -r1.45 -r1.46 pkgsrc/pkgtools/pkglint/files/mkline_test.go
diff -r1.23 -r1.24 pkgsrc/pkgtools/pkglint/files/mklinechecker.go
diff -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
diff -r1.35 -r1.36 pkgsrc/pkgtools/pkglint/files/mklines.go
diff -r1.31 -r1.32 pkgsrc/pkgtools/pkglint/files/mklines_test.go
diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/mklines_varalign_test.go
diff -r1.39 -r1.40 pkgsrc/pkgtools/pkglint/files/package.go
diff -r1.33 -r1.34 pkgsrc/pkgtools/pkglint/files/package_test.go
diff -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/substcontext.go
diff -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/tools_test.go
diff -r1.50 -r1.51 pkgsrc/pkgtools/pkglint/files/vardefs.go
diff -r1.36 -r1.37 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go

cvs diff -r1.559 -r1.560 pkgsrc/pkgtools/pkglint/Makefile (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/Makefile 2018/12/02 01:57:48 1.559
+++ pkgsrc/pkgtools/pkglint/Makefile 2018/12/02 23:12:43 1.560
@@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
1# $NetBSD: Makefile,v 1.559 2018/12/02 01:57:48 rillig Exp $ 1# $NetBSD: Makefile,v 1.560 2018/12/02 23:12:43 rillig Exp $
2 2
3PKGNAME= pkglint-5.6.7 3PKGNAME= pkglint-5.6.8
4CATEGORIES= pkgtools 4CATEGORIES= pkgtools
5DISTNAME= tools 5DISTNAME= tools
6MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/} 6MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/}
7GITHUB_PROJECT= tools 7GITHUB_PROJECT= tools
8GITHUB_TAG= 92d8274bd7b8a4c65f24bafe401a029e58392704 8GITHUB_TAG= 92d8274bd7b8a4c65f24bafe401a029e58392704
9 9
10MAINTAINER= rillig@NetBSD.org 10MAINTAINER= rillig@NetBSD.org
11HOMEPAGE= https://github.com/rillig/pkglint 11HOMEPAGE= https://github.com/rillig/pkglint
12COMMENT= Verifier for NetBSD packages 12COMMENT= Verifier for NetBSD packages
13LICENSE= 2-clause-bsd 13LICENSE= 2-clause-bsd
14CONFLICTS+= pkglint4-[0-9]* 14CONFLICTS+= pkglint4-[0-9]*
15 15
16USE_TOOLS+= pax 16USE_TOOLS+= pax

cvs diff -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/Attic/autofix.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/autofix.go 2018/12/02 01:57:48 1.13
+++ pkgsrc/pkgtools/pkglint/files/Attic/autofix.go 2018/12/02 23:12:43 1.14
@@ -293,40 +293,43 @@ func (fix *Autofix) Apply() { @@ -293,40 +293,43 @@ func (fix *Autofix) Apply() {
293 G.Explain(fix.explanation...) 293 G.Explain(fix.explanation...)
294 } 294 }
295 if G.Logger.Opts.ShowSource { 295 if G.Logger.Opts.ShowSource {
296 if !G.Logger.Opts.Explain || !logDiagnostic || len(fix.explanation) == 0 { 296 if !G.Logger.Opts.Explain || !logDiagnostic || len(fix.explanation) == 0 {
297 G.out.Separate() 297 G.out.Separate()
298 } 298 }
299 } 299 }
300 } 300 }
301 301
302 reset() 302 reset()
303} 303}
304 304
305func (fix *Autofix) Realign(mkline MkLine, newWidth int) { 305func (fix *Autofix) Realign(mkline MkLine, newWidth int) {
 306
 307 // XXX: Check whether this method can be implemented as Custom fix.
 308 // This complicated code should not be in the Autofix type.
 309
306 fix.assertRealLine() 310 fix.assertRealLine()
307 G.Assertf(mkline.IsMultiline(), "Line must be a multiline.") 311 G.Assertf(mkline.IsMultiline(), "Line must be a multiline.")
308 G.Assertf(mkline.IsVarassign() || mkline.IsCommentedVarassign(), "Line must be a variable assignment.") 312 G.Assertf(mkline.IsVarassign() || mkline.IsCommentedVarassign(), "Line must be a variable assignment.")
309 313
310 if fix.skip() { 314 if fix.skip() {
311 return 315 return
312 } 316 }
313 317
314 normalized := true // Whether all indentation is tabs, followed by spaces. 318 normalized := true // Whether all indentation is tabs, followed by spaces.
315 oldWidth := 0 // The minimum required indentation in the original lines. 319 oldWidth := 0 // The minimum required indentation in the original lines.
316 320
317 { 321 {
318 // Parsing the continuation marker as variable value 322 // Parsing the continuation marker as variable value is cheating but works well.
319 // is cheating but works well. 
320 text := strings.TrimSuffix(mkline.raw[0].orignl, "\n") 323 text := strings.TrimSuffix(mkline.raw[0].orignl, "\n")
321 m, _, _, _, _, valueAlign, value, _, _ := MatchVarassign(text) 324 m, _, _, _, _, valueAlign, value, _, _ := MatchVarassign(text)
322 if m && value != "\\" { 325 if m && value != "\\" {
323 oldWidth = tabWidth(valueAlign) 326 oldWidth = tabWidth(valueAlign)
324 } 327 }
325 } 328 }
326 329
327 for _, rawLine := range fix.line.raw[1:] { 330 for _, rawLine := range fix.line.raw[1:] {
328 _, comment, space := match2(rawLine.textnl, `^(#?)([ \t]*)`) 331 _, comment, space := match2(rawLine.textnl, `^(#?)([ \t]*)`)
329 width := tabWidth(comment + space) 332 width := tabWidth(comment + space)
330 if (oldWidth == 0 || width < oldWidth) && width >= 8 && rawLine.textnl != "\n" { 333 if (oldWidth == 0 || width < oldWidth) && width >= 8 && rawLine.textnl != "\n" {
331 oldWidth = width 334 oldWidth = width
332 } 335 }

cvs diff -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc.go 2018/12/02 01:57:48 1.13
+++ pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc.go 2018/12/02 23:12:43 1.14
@@ -313,28 +313,28 @@ func (src *Pkgsrc) loadTools() { @@ -313,28 +313,28 @@ func (src *Pkgsrc) loadTools() {
313 } 313 }
314 314
315 for _, relativeName := range [...]string{"mk/bsd.prefs.mk", "mk/bsd.pkg.mk"} { 315 for _, relativeName := range [...]string{"mk/bsd.prefs.mk", "mk/bsd.pkg.mk"} {
316 316
317 mklines := G.Pkgsrc.LoadMk(relativeName, MustSucceed|NotEmpty) 317 mklines := G.Pkgsrc.LoadMk(relativeName, MustSucceed|NotEmpty)
318 mklines.ForEach(func(mkline MkLine) { 318 mklines.ForEach(func(mkline MkLine) {
319 if mkline.IsVarassign() { 319 if mkline.IsVarassign() {
320 varname := mkline.Varname() 320 varname := mkline.Varname()
321 switch varname { 321 switch varname {
322 case "USE_TOOLS": 322 case "USE_TOOLS":
323 tools.ParseToolLine(mkline, true, !mklines.indentation.IsConditional()) 323 tools.ParseToolLine(mkline, true, !mklines.indentation.IsConditional())
324 324
325 case "_BUILD_DEFS": 325 case "_BUILD_DEFS":
326 for _, bdvar := range mkline.ValueFields(mkline.Value()) { 326 for _, buildDefsVar := range mkline.Fields() {
327 src.AddBuildDefs(bdvar) 327 src.AddBuildDefs(buildDefsVar)
328 } 328 }
329 } 329 }
330 } 330 }
331 }) 331 })
332 } 332 }
333 333
334 if trace.Tracing { 334 if trace.Tracing {
335 tools.Trace() 335 tools.Trace()
336 } 336 }
337} 337}
338 338
339// loadUntypedVars scans all pkgsrc infrastructure files in mk/ 339// loadUntypedVars scans all pkgsrc infrastructure files in mk/
340// to find variable definitions that are not yet covered in 340// to find variable definitions that are not yet covered in

cvs diff -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/Attic/buildlink3_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/buildlink3_test.go 2018/12/02 01:57:48 1.21
+++ pkgsrc/pkgtools/pkglint/files/Attic/buildlink3_test.go 2018/12/02 23:12:43 1.22
@@ -1,46 +1,46 @@ @@ -1,46 +1,46 @@
1package main 1package main
2 2
3import "gopkg.in/check.v1" 3import "gopkg.in/check.v1"
4 4
5func (s *Suite) Test_ChecklinesBuildlink3Mk__unfinished_url2pkg(c *check.C) { 5func (s *Suite) Test_ChecklinesBuildlink3Mk__unfinished_url2pkg(c *check.C) {
6 t := s.Init(c) 6 t := s.Init(c)
7 7
8 t.SetupVartypes() 8 t.SetupVartypes()
9 t.CreateFileLines("x11/Xbae/Makefile") 9 t.CreateFileLines("x11/Xbae/Makefile")
10 t.CreateFileLines("mk/motif.buildlink3.mk") 10 t.CreateFileLines("mk/motif.buildlink3.mk")
11 mklines := t.SetupFileMkLines("buildlink3.mk", 11 mklines := t.SetupFileMkLines("category/package/buildlink3.mk",
12 MkRcsID, 12 MkRcsID,
13 "# XXX This file was created automatically using createbuildlink-@PKGVERSION@", 13 "# XXX This file was created automatically using createbuildlink-@PKGVERSION@",
14 "", 14 "",
15 "BUILDLINK_TREE+=\tXbae", 15 "BUILDLINK_TREE+=\tXbae",
16 "", 16 "",
17 "BUILDLINK_DEPMETHOD.Xbae?=\tfull", 17 "BUILDLINK_DEPMETHOD.Xbae?=\tfull",
18 ".if !defined(XBAE_BUILDLINK3_MK)", 18 ".if !defined(XBAE_BUILDLINK3_MK)",
19 "XBAE_BUILDLINK3_MK:=", 19 "XBAE_BUILDLINK3_MK:=",
20 "", 20 "",
21 "BUILDLINK_API_DEPENDS.Xbae+=\tXbae>=4.8.4", 21 "BUILDLINK_API_DEPENDS.Xbae+=\tXbae>=4.8.4",
22 "BUILDLINK_ABI_DEPENDS.Xbae+=\tXbae>=4.51.01nb2", 22 "BUILDLINK_ABI_DEPENDS.Xbae+=\tXbae>=4.51.01nb2",
23 "BUILDLINK_PKGSRCDIR.Xbae?=\t../../x11/Xbae", 23 "BUILDLINK_PKGSRCDIR.Xbae?=\t../../x11/Xbae",
24 "", 24 "",
25 ".include \"../../mk/motif.buildlink3.mk\"", 25 ".include \"../../mk/motif.buildlink3.mk\"",
26 ".endif # XBAE_BUILDLINK3_MK", 26 ".endif # XBAE_BUILDLINK3_MK",
27 "", 27 "",
28 "BUILDLINK_TREE+=\t-Xbae") 28 "BUILDLINK_TREE+=\t-Xbae")
29 29
30 ChecklinesBuildlink3Mk(mklines) 30 ChecklinesBuildlink3Mk(mklines)
31 31
32 t.CheckOutputLines( 32 t.CheckOutputLines(
33 "ERROR: ~/buildlink3.mk:2: This comment indicates unfinished work (url2pkg).") 33 "ERROR: ~/category/package/buildlink3.mk:2: This comment indicates unfinished work (url2pkg).")
34} 34}
35 35
36// Before version 5.3, pkglint wrongly warned here. 36// Before version 5.3, pkglint wrongly warned here.
37// The mk/haskell.mk file takes care of constructing the correct PKGNAME, 37// The mk/haskell.mk file takes care of constructing the correct PKGNAME,
38// but pkglint had not looked at that file. 38// but pkglint had not looked at that file.
39// 39//
40// Since then, pkglint also looks at files from mk/ when they are directly 40// Since then, pkglint also looks at files from mk/ when they are directly
41// included, and therefore finds the default definition for PKGNAME. 41// included, and therefore finds the default definition for PKGNAME.
42func (s *Suite) Test_ChecklinesBuildlink3Mk__name_mismatch_Haskell_incomplete(c *check.C) { 42func (s *Suite) Test_ChecklinesBuildlink3Mk__name_mismatch_Haskell_incomplete(c *check.C) {
43 t := s.Init(c) 43 t := s.Init(c)
44 44
45 t.SetupPackage("x11/hs-X11", 45 t.SetupPackage("x11/hs-X11",
46 "DISTNAME=\tX11-1.0") 46 "DISTNAME=\tX11-1.0")

cvs diff -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/Attic/vartype.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/vartype.go 2018/12/02 01:57:48 1.21
+++ pkgsrc/pkgtools/pkglint/files/Attic/vartype.go 2018/12/02 23:12:43 1.22
@@ -6,26 +6,27 @@ import ( @@ -6,26 +6,27 @@ import (
6) 6)
7 7
8// Vartype is a combination of a data type and a permission specification. 8// Vartype is a combination of a data type and a permission specification.
9// See vardefs.go for examples, and vartypecheck.go for the implementation. 9// See vardefs.go for examples, and vartypecheck.go for the implementation.
10type Vartype struct { 10type Vartype struct {
11 kindOfList KindOfList 11 kindOfList KindOfList
12 basicType *BasicType 12 basicType *BasicType
13 aclEntries []ACLEntry 13 aclEntries []ACLEntry
14 guessed bool 14 guessed bool
15} 15}
16 16
17type KindOfList uint8 17type KindOfList uint8
18 18
 19// TODO: Remove lkSpace. Since 2015 the .for variables are split on shell words, like everywhere else.
19const ( 20const (
20 lkNone KindOfList = iota // Plain data type 21 lkNone KindOfList = iota // Plain data type
21 lkSpace // List entries are separated by whitespace; used in .for loops. 22 lkSpace // List entries are separated by whitespace; used in .for loops.
22 lkShell // List entries are shell words; used in the :M, :S modifiers. 23 lkShell // List entries are shell words; used in the :M, :S modifiers.
23) 24)
24 25
25type ACLEntry struct { 26type ACLEntry struct {
26 glob string // Examples: "Makefile", "*.mk" 27 glob string // Examples: "Makefile", "*.mk"
27 permissions ACLPermissions 28 permissions ACLPermissions
28} 29}
29 30
30type ACLPermissions uint8 31type ACLPermissions uint8
31 32
@@ -193,26 +194,30 @@ type BasicType struct { @@ -193,26 +194,30 @@ type BasicType struct {
193 checker func(*VartypeCheck) 194 checker func(*VartypeCheck)
194} 195}
195 196
196func (bt *BasicType) IsEnum() bool { 197func (bt *BasicType) IsEnum() bool {
197 return hasPrefix(bt.name, "enum: ") 198 return hasPrefix(bt.name, "enum: ")
198} 199}
199func (bt *BasicType) HasEnum(value string) bool { 200func (bt *BasicType) HasEnum(value string) bool {
200 return !contains(value, " ") && contains(bt.name, " "+value+" ") 201 return !contains(value, " ") && contains(bt.name, " "+value+" ")
201} 202}
202func (bt *BasicType) AllowedEnums() string { 203func (bt *BasicType) AllowedEnums() string {
203 return bt.name[6 : len(bt.name)-1] 204 return bt.name[6 : len(bt.name)-1]
204} 205}
205 206
 207// TODO: Try to implement BasicType.PossibleChars()
 208// TODO: Try to implement BasicType.CanBeEmpty()
 209// TODO: Try to implement BasicType.PossibleWords() / PossibleValues()
 210
206var ( 211var (
207 BtAwkCommand = &BasicType{"AwkCommand", (*VartypeCheck).AwkCommand} 212 BtAwkCommand = &BasicType{"AwkCommand", (*VartypeCheck).AwkCommand}
208 BtBasicRegularExpression = &BasicType{"BasicRegularExpression", (*VartypeCheck).BasicRegularExpression} 213 BtBasicRegularExpression = &BasicType{"BasicRegularExpression", (*VartypeCheck).BasicRegularExpression}
209 BtBuildlinkDepmethod = &BasicType{"BuildlinkDepmethod", (*VartypeCheck).BuildlinkDepmethod} 214 BtBuildlinkDepmethod = &BasicType{"BuildlinkDepmethod", (*VartypeCheck).BuildlinkDepmethod}
210 BtCategory = &BasicType{"Category", (*VartypeCheck).Category} 215 BtCategory = &BasicType{"Category", (*VartypeCheck).Category}
211 BtCFlag = &BasicType{"CFlag", (*VartypeCheck).CFlag} 216 BtCFlag = &BasicType{"CFlag", (*VartypeCheck).CFlag}
212 BtComment = &BasicType{"Comment", (*VartypeCheck).Comment} 217 BtComment = &BasicType{"Comment", (*VartypeCheck).Comment}
213 BtConfFiles = &BasicType{"ConfFiles", (*VartypeCheck).ConfFiles} 218 BtConfFiles = &BasicType{"ConfFiles", (*VartypeCheck).ConfFiles}
214 BtDependency = &BasicType{"Dependency", (*VartypeCheck).Dependency} 219 BtDependency = &BasicType{"Dependency", (*VartypeCheck).Dependency}
215 BtDependencyWithPath = &BasicType{"DependencyWithPath", (*VartypeCheck).DependencyWithPath} 220 BtDependencyWithPath = &BasicType{"DependencyWithPath", (*VartypeCheck).DependencyWithPath}
216 BtDistSuffix = &BasicType{"DistSuffix", (*VartypeCheck).DistSuffix} 221 BtDistSuffix = &BasicType{"DistSuffix", (*VartypeCheck).DistSuffix}
217 BtEmulPlatform = &BasicType{"EmulPlatform", (*VartypeCheck).EmulPlatform} 222 BtEmulPlatform = &BasicType{"EmulPlatform", (*VartypeCheck).EmulPlatform}
218 BtFetchURL = &BasicType{"FetchURL", (*VartypeCheck).FetchURL} 223 BtFetchURL = &BasicType{"FetchURL", (*VartypeCheck).FetchURL}

cvs diff -r1.14 -r1.15 pkgsrc/pkgtools/pkglint/files/Attic/category_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/category_test.go 2018/11/07 20:58:22 1.14
+++ pkgsrc/pkgtools/pkglint/files/Attic/category_test.go 2018/12/02 23:12:43 1.15
@@ -13,27 +13,27 @@ func (s *Suite) Test_CheckdirCategory__t @@ -13,27 +13,27 @@ func (s *Suite) Test_CheckdirCategory__t
13 "SUBDIR-=unknown #doesn\u2019t work", 13 "SUBDIR-=unknown #doesn\u2019t work",
14 "", 14 "",
15 ".include \"../mk/category.mk\"") 15 ".include \"../mk/category.mk\"")
16 16
17 CheckdirCategory(t.File("archivers")) 17 CheckdirCategory(t.File("archivers"))
18 18
19 t.CheckOutputLines( 19 t.CheckOutputLines(
20 "ERROR: ~/archivers/Makefile:1: Expected \"# $"+"NetBSD$\".", 20 "ERROR: ~/archivers/Makefile:1: Expected \"# $"+"NetBSD$\".",
21 "WARN: ~/archivers/Makefile:4: Line contains invalid characters (U+2019).", 21 "WARN: ~/archivers/Makefile:4: Line contains invalid characters (U+2019).",
22 "WARN: ~/archivers/Makefile:4: SUBDIR- is defined but not used.", 22 "WARN: ~/archivers/Makefile:4: SUBDIR- is defined but not used.",
23 "NOTE: ~/archivers/Makefile:2: This variable value should be aligned to column 17.", 23 "NOTE: ~/archivers/Makefile:2: This variable value should be aligned to column 17.",
24 "NOTE: ~/archivers/Makefile:3: This variable value should be aligned with tabs, not spaces, to column 17.", 24 "NOTE: ~/archivers/Makefile:3: This variable value should be aligned with tabs, not spaces, to column 17.",
25 "NOTE: ~/archivers/Makefile:4: This variable value should be aligned to column 17.", 25 "NOTE: ~/archivers/Makefile:4: This variable value should be aligned to column 17.",
26 "ERROR: ~/archivers/Makefile:6: \"../mk/category.mk\" does not exist.", 26 "ERROR: ~/archivers/Makefile:6: Relative path \"../mk/category.mk\" does not exist.",
27 "NOTE: ~/archivers/Makefile:1: Empty line expected after this line.", 27 "NOTE: ~/archivers/Makefile:1: Empty line expected after this line.",
28 "ERROR: ~/archivers/Makefile:2: COMMENT= line expected.", 28 "ERROR: ~/archivers/Makefile:2: COMMENT= line expected.",
29 "NOTE: ~/archivers/Makefile:1: Empty line expected after this line.", // XXX: Duplicate. 29 "NOTE: ~/archivers/Makefile:1: Empty line expected after this line.", // XXX: Duplicate.
30 "WARN: ~/archivers/Makefile:3: \"aaaaa\" should come before \"pkg1\".", 30 "WARN: ~/archivers/Makefile:3: \"aaaaa\" should come before \"pkg1\".",
31 "ERROR: ~/archivers/Makefile:4: SUBDIR+= line or empty line expected.", 31 "ERROR: ~/archivers/Makefile:4: SUBDIR+= line or empty line expected.",
32 "ERROR: ~/archivers/Makefile:2: \"pkg1\" exists in the Makefile but not in the file system.", 32 "ERROR: ~/archivers/Makefile:2: \"pkg1\" exists in the Makefile but not in the file system.",
33 "ERROR: ~/archivers/Makefile:3: \"aaaaa\" exists in the Makefile but not in the file system.", 33 "ERROR: ~/archivers/Makefile:3: \"aaaaa\" exists in the Makefile but not in the file system.",
34 "NOTE: ~/archivers/Makefile:3: Empty line expected after this line.", 34 "NOTE: ~/archivers/Makefile:3: Empty line expected after this line.",
35 "WARN: ~/archivers/Makefile:4: This line should contain the following text: .include \"../mk/misc/category.mk\"", 35 "WARN: ~/archivers/Makefile:4: This line should contain the following text: .include \"../mk/misc/category.mk\"",
36 "ERROR: ~/archivers/Makefile:4: The file should end here.") 36 "ERROR: ~/archivers/Makefile:4: The file should end here.")
37} 37}
38 38
39func (s *Suite) Test_CheckdirCategory__invalid_comment(c *check.C) { 39func (s *Suite) Test_CheckdirCategory__invalid_comment(c *check.C) {

cvs diff -r1.17 -r1.18 pkgsrc/pkgtools/pkglint/files/Attic/licenses.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/licenses.go 2018/12/02 01:57:48 1.17
+++ pkgsrc/pkgtools/pkglint/files/Attic/licenses.go 2018/12/02 23:12:43 1.18
@@ -16,27 +16,27 @@ func (lc *LicenseChecker) Check(value st @@ -16,27 +16,27 @@ func (lc *LicenseChecker) Check(value st
16 } else { 16 } else {
17 lc.MkLine.Errorf("Parse error for appended license condition %q.", value) 17 lc.MkLine.Errorf("Parse error for appended license condition %q.", value)
18 } 18 }
19 return 19 return
20 } 20 }
21 21
22 cond.Walk(lc.checkNode) 22 cond.Walk(lc.checkNode)
23} 23}
24 24
25func (lc *LicenseChecker) checkName(license string) { 25func (lc *LicenseChecker) checkName(license string) {
26 licenseFile := "" 26 licenseFile := ""
27 if G.Pkg != nil { 27 if G.Pkg != nil {
28 if mkline := G.Pkg.vars.FirstDefinition("LICENSE_FILE"); mkline != nil { 28 if mkline := G.Pkg.vars.FirstDefinition("LICENSE_FILE"); mkline != nil {
29 licenseFile = G.Pkg.File(mkline.ResolveVarsInRelativePath(mkline.Value(), false)) 29 licenseFile = G.Pkg.File(mkline.ResolveVarsInRelativePath(mkline.Value()))
30 } 30 }
31 } 31 }
32 if licenseFile == "" { 32 if licenseFile == "" {
33 licenseFile = G.Pkgsrc.File("licenses/" + license) 33 licenseFile = G.Pkgsrc.File("licenses/" + license)
34 if G.Pkgsrc.UsedLicenses != nil { 34 if G.Pkgsrc.UsedLicenses != nil {
35 G.Pkgsrc.UsedLicenses[license] = true 35 G.Pkgsrc.UsedLicenses[license] = true
36 } 36 }
37 } 37 }
38 38
39 if !fileExists(licenseFile) { 39 if !fileExists(licenseFile) {
40 lc.MkLine.Warnf("License file %s does not exist.", cleanpath(licenseFile)) 40 lc.MkLine.Warnf("License file %s does not exist.", cleanpath(licenseFile))
41 } 41 }
42 42

cvs diff -r1.28 -r1.29 pkgsrc/pkgtools/pkglint/files/Attic/line.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/line.go 2018/12/02 01:57:48 1.28
+++ pkgsrc/pkgtools/pkglint/files/Attic/line.go 2018/12/02 23:12:43 1.29
@@ -25,26 +25,28 @@ type RawLine struct { @@ -25,26 +25,28 @@ type RawLine struct {
25 25
26 // XXX: Since only Autofix needs to distinguish between orignl and textnl, 26 // XXX: Since only Autofix needs to distinguish between orignl and textnl,
27 // one of these fields should probably be moved there. 27 // one of these fields should probably be moved there.
28} 28}
29 29
30func (rline *RawLine) String() string { return sprintf("%d:%s", rline.Lineno, rline.textnl) } 30func (rline *RawLine) String() string { return sprintf("%d:%s", rline.Lineno, rline.textnl) }
31 31
32// Line represents a line of text from a file. 32// Line represents a line of text from a file.
33// It aliases a pointer type to reduces the number of *Line occurrences in the code. 33// It aliases a pointer type to reduces the number of *Line occurrences in the code.
34// Using a type alias is more efficient than an interface type, I guess. 34// Using a type alias is more efficient than an interface type, I guess.
35type Line = *LineImpl 35type Line = *LineImpl
36 36
37type LineImpl struct { 37type LineImpl struct {
 38 // TODO: Consider storing pointers to the Filename and Basename instead of strings to save memory.
 39 // But first find out where and why pkglint needs so much memory (200 MB for a full recursive run over pkgsrc + wip).
38 Filename string // uses / as directory separator on all platforms 40 Filename string // uses / as directory separator on all platforms
39 Basename string // the last component of the Filename 41 Basename string // the last component of the Filename
40 firstLine int32 // zero means the whole file, -1 means EOF 42 firstLine int32 // zero means the whole file, -1 means EOF
41 lastLine int32 // usually the same as firstLine, may differ in Makefiles 43 lastLine int32 // usually the same as firstLine, may differ in Makefiles
42 // without the trailing newline character; 44 // without the trailing newline character;
43 // in Makefiles, also contains the text from the continuation lines 45 // in Makefiles, also contains the text from the continuation lines
44 Text string 46 Text string
45 raw []*RawLine // contains the original text including trailing newline 47 raw []*RawLine // contains the original text including trailing newline
46 autofix *Autofix // any changes that pkglint would like to apply to the line 48 autofix *Autofix // any changes that pkglint would like to apply to the line
47 Once 49 Once
48 50
49 // XXX: Filename and Basename could be replaced with a pointer to a Lines object. 51 // XXX: Filename and Basename could be replaced with a pointer to a Lines object.
50} 52}

cvs diff -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/Attic/lines.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/lines.go 2018/12/02 01:57:48 1.2
+++ pkgsrc/pkgtools/pkglint/files/Attic/lines.go 2018/12/02 23:12:43 1.3
@@ -35,41 +35,41 @@ func (ls *LinesImpl) SaveAutofixChanges( @@ -35,41 +35,41 @@ func (ls *LinesImpl) SaveAutofixChanges(
35 SaveAutofixChanges(ls) 35 SaveAutofixChanges(ls)
36} 36}
37 37
38func (ls *LinesImpl) CheckRcsID(index int, prefixRe regex.Pattern, suggestedPrefix string) bool { 38func (ls *LinesImpl) CheckRcsID(index int, prefixRe regex.Pattern, suggestedPrefix string) bool {
39 if trace.Tracing { 39 if trace.Tracing {
40 defer trace.Call(prefixRe, suggestedPrefix)() 40 defer trace.Call(prefixRe, suggestedPrefix)()
41 } 41 }
42 42
43 line := ls.Lines[index] 43 line := ls.Lines[index]
44 if m, expanded := match1(line.Text, `^`+prefixRe+`\$`+`NetBSD(:[^\$]+)?\$$`); m { 44 if m, expanded := match1(line.Text, `^`+prefixRe+`\$`+`NetBSD(:[^\$]+)?\$$`); m {
45 45
46 if G.Wip && expanded != "" { 46 if G.Wip && expanded != "" {
47 fix := line.Autofix() 47 fix := line.Autofix()
48 fix.Errorf("Expected exactly %q.", suggestedPrefix+"$"+"NetBSD$") 48 fix.Notef("Expected exactly %q.", suggestedPrefix+"$"+"NetBSD$")
49 fix.Explain( 49 fix.Explain(
50 "Several files in pkgsrc must contain the CVS Id, so that their", 50 "Several files in pkgsrc must contain the CVS Id, so that their",
51 "current version can be traced back later from a binary package.", 51 "current version can be traced back later from a binary package.",
52 "This is to ensure reproducible builds, for example for finding bugs.", 52 "This is to ensure reproducible builds, for example for finding bugs.",
53 "", 53 "",
54 "These CVS Ids are specific to the CVS version control system, and", 54 "These CVS Ids are specific to the CVS version control system, and",
55 "pkgsrc-wip uses Git instead. Therefore, having the expanded CVS Ids", 55 "pkgsrc-wip uses Git instead. Therefore, having the expanded CVS Ids",
56 "in those files represents the file from which they were originally", 56 "in those files represents the file from which they were originally",
57 "copied but not their current state. Because of that, these markers", 57 "copied but not their current state. Because of that, these markers",
58 "should be replaced with the plain, unexpanded string $"+"NetBSD$.", 58 "should be replaced with the plain, unexpanded string $"+"NetBSD$.",
59 "", 59 "",
60 "To preserve the history of the CVS Id, should that ever be needed,", 60 "To preserve the history of the CVS Id, should that ever be needed,",
61 "remove the leading $.") 61 "remove the leading $.")
62 fix.InsertBefore(suggestedPrefix + "$" + "NetBSD$") 62 fix.ReplaceRegex(`.*`, suggestedPrefix+"$"+"NetBSD$", 1)
63 fix.Apply() 63 fix.Apply()
64 } 64 }
65 65
66 return true 66 return true
67 } 67 }
68 68
69 fix := line.Autofix() 69 fix := line.Autofix()
70 fix.Errorf("Expected %q.", suggestedPrefix+"$"+"NetBSD$") 70 fix.Errorf("Expected %q.", suggestedPrefix+"$"+"NetBSD$")
71 fix.Explain( 71 fix.Explain(
72 "Most files in pkgsrc contain the CVS Id, so that their current", 72 "Most files in pkgsrc contain the CVS Id, so that their current",
73 "version can be traced back later from a binary package.", 73 "version can be traced back later from a binary package.",
74 "This is to ensure reproducible builds, for example for finding bugs.") 74 "This is to ensure reproducible builds, for example for finding bugs.")
75 fix.InsertBefore(suggestedPrefix + "$" + "NetBSD$") 75 fix.InsertBefore(suggestedPrefix + "$" + "NetBSD$")

cvs diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/Attic/lines_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/lines_test.go 2018/12/02 01:57:48 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/lines_test.go 2018/12/02 23:12:43 1.2
@@ -37,18 +37,28 @@ func (s *Suite) Test_Lines_CheckRcsID__w @@ -37,18 +37,28 @@ func (s *Suite) Test_Lines_CheckRcsID__w
37 "# $"+"NetBSD: dummy $") 37 "# $"+"NetBSD: dummy $")
38 t.CreateFileLines("wip/package/file2.mk", 38 t.CreateFileLines("wip/package/file2.mk",
39 "# $"+"NetBSD$") 39 "# $"+"NetBSD$")
40 t.CreateFileLines("wip/package/file3.mk", 40 t.CreateFileLines("wip/package/file3.mk",
41 "# $"+"Id: dummy $") 41 "# $"+"Id: dummy $")
42 t.CreateFileLines("wip/package/file4.mk", 42 t.CreateFileLines("wip/package/file4.mk",
43 "# $"+"Id$") 43 "# $"+"Id$")
44 t.CreateFileLines("wip/package/file5.mk", 44 t.CreateFileLines("wip/package/file5.mk",
45 "# $"+"FreeBSD$") 45 "# $"+"FreeBSD$")
46 46
47 G.CheckDirent(t.File("wip/package")) 47 G.CheckDirent(t.File("wip/package"))
48 48
49 t.CheckOutputLines( 49 t.CheckOutputLines(
50 "ERROR: ~/wip/package/file1.mk:1: Expected exactly \"# $"+"NetBSD$\".", 50 "NOTE: ~/wip/package/file1.mk:1: Expected exactly \"# $"+"NetBSD$\".",
51 "ERROR: ~/wip/package/file3.mk:1: Expected \"# $"+"NetBSD$\".", 51 "ERROR: ~/wip/package/file3.mk:1: Expected \"# $"+"NetBSD$\".",
52 "ERROR: ~/wip/package/file4.mk:1: Expected \"# $"+"NetBSD$\".", 52 "ERROR: ~/wip/package/file4.mk:1: Expected \"# $"+"NetBSD$\".",
53 "ERROR: ~/wip/package/file5.mk:1: Expected \"# $"+"NetBSD$\".") 53 "ERROR: ~/wip/package/file5.mk:1: Expected \"# $"+"NetBSD$\".")
 54
 55 G.Logger.Opts.Autofix = true
 56
 57 G.CheckDirent(t.File("wip/package"))
 58
 59 t.CheckOutputLines(
 60 "AUTOFIX: ~/wip/package/file1.mk:1: Replacing \"# $NetBSD: lines_test.go,v 1.2 2018/12/02 23:12:43 rillig Exp $\" with \"# $NetBSD: lines_test.go,v 1.2 2018/12/02 23:12:43 rillig Exp $\".",
 61 "AUTOFIX: ~/wip/package/file3.mk:1: Inserting a line \"# $NetBSD: lines_test.go,v 1.2 2018/12/02 23:12:43 rillig Exp $\" before this line.",
 62 "AUTOFIX: ~/wip/package/file4.mk:1: Inserting a line \"# $NetBSD: lines_test.go,v 1.2 2018/12/02 23:12:43 rillig Exp $\" before this line.",
 63 "AUTOFIX: ~/wip/package/file5.mk:1: Inserting a line \"# $NetBSD: lines_test.go,v 1.2 2018/12/02 23:12:43 rillig Exp $\" before this line.")
54} 64}

cvs diff -r1.41 -r1.42 pkgsrc/pkgtools/pkglint/files/Attic/mkline.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mkline.go 2018/12/02 01:57:48 1.41
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkline.go 2018/12/02 23:12:43 1.42
@@ -21,41 +21,43 @@ type MkLineImpl struct { @@ -21,41 +21,43 @@ type MkLineImpl struct {
21 data interface{} // One of the following mkLine* types 21 data interface{} // One of the following mkLine* types
22} 22}
23type mkLineAssign = *mkLineAssignImpl // See https://github.com/golang/go/issues/28045 23type mkLineAssign = *mkLineAssignImpl // See https://github.com/golang/go/issues/28045
24type mkLineAssignImpl struct { 24type mkLineAssignImpl struct {
25 commented bool // Whether the whole variable assignment is commented out 25 commented bool // Whether the whole variable assignment is commented out
26 varname string // e.g. "HOMEPAGE", "SUBST_SED.perl" 26 varname string // e.g. "HOMEPAGE", "SUBST_SED.perl"
27 varcanon string // e.g. "HOMEPAGE", "SUBST_SED.*" 27 varcanon string // e.g. "HOMEPAGE", "SUBST_SED.*"
28 varparam string // e.g. "", "perl" 28 varparam string // e.g. "", "perl"
29 op MkOperator // 29 op MkOperator //
30 valueAlign string // The text up to and including the assignment operator, e.g. VARNAME+=\t 30 valueAlign string // The text up to and including the assignment operator, e.g. VARNAME+=\t
31 value string // The trimmed value 31 value string // The trimmed value
32 valueMk []*MkToken // The value, sent through splitIntoMkWords 32 valueMk []*MkToken // The value, sent through splitIntoMkWords
33 valueMkRest string // nonempty in case of parse errors 33 valueMkRest string // nonempty in case of parse errors
 34 fields []string // The value, space-separated according to shell quoting rules
34 comment string 35 comment string
35} 36}
36type mkLineShell struct { 37type mkLineShell struct {
37 command string 38 command string
38} 39}
39type mkLineComment struct{} // See mkLineAssignImpl.commented for another type of comment line 40type mkLineComment struct{} // See mkLineAssignImpl.commented for another type of comment line
40type mkLineEmpty struct{} 41type mkLineEmpty struct{}
41type mkLineDirective = *mkLineDirectiveImpl // See https://github.com/golang/go/issues/28045 42type mkLineDirective = *mkLineDirectiveImpl // See https://github.com/golang/go/issues/28045
42type mkLineDirectiveImpl struct { 43type mkLineDirectiveImpl struct {
43 indent string // the space between the leading "." and the directive 44 indent string // the space between the leading "." and the directive
44 directive string // "if", "else", "for", etc. 45 directive string // "if", "else", "for", etc.
45 args string 46 args string
46 comment string // mainly interesting for .endif and .endfor 47 comment string // mainly interesting for .endif and .endfor
47 elseLine MkLine // for .if (filled in later) 48 elseLine MkLine // for .if (filled in later)
48 cond MkCond // for .if and .elif (filled in later as needed) 49 cond MkCond // for .if and .elif (filled in on first access)
 50 fields []string // the arguments for the .for loop (filled in on first access)
49} 51}
50type mkLineInclude = *mkLineIncludeImpl // See https://github.com/golang/go/issues/28045 52type mkLineInclude = *mkLineIncludeImpl // See https://github.com/golang/go/issues/28045
51type mkLineIncludeImpl struct { 53type mkLineIncludeImpl struct {
52 mustExist bool // for .sinclude, nonexistent files are ignored 54 mustExist bool // for .sinclude, nonexistent files are ignored
53 sys bool // whether the include uses <file.mk> (very rare) instead of "file.mk" 55 sys bool // whether the include uses <file.mk> (very rare) instead of "file.mk"
54 indent string // the space between the leading "." and the directive 56 indent string // the space between the leading "." and the directive
55 includedFile string // the text between the <brackets> or "quotes" 57 includedFile string // the text between the <brackets> or "quotes"
56 conditionalVars []string // variables on which this inclusion depends (filled in later, as needed) 58 conditionalVars []string // variables on which this inclusion depends (filled in later, as needed)
57} 59}
58type mkLineDependency struct { 60type mkLineDependency struct {
59 targets string 61 targets string
60 sources string 62 sources string
61} 63}
@@ -100,45 +102,46 @@ func NewMkLine(line Line) *MkLineImpl { @@ -100,45 +102,46 @@ func NewMkLine(line Line) *MkLineImpl {
100 "continues until the end of the line. To escape the #, write \\#.") 102 "continues until the end of the line. To escape the #, write \\#.")
101 } 103 }
102 104
103 return &MkLineImpl{line, &mkLineAssignImpl{ 105 return &MkLineImpl{line, &mkLineAssignImpl{
104 commented, 106 commented,
105 varname, 107 varname,
106 varnameCanon(varname), 108 varnameCanon(varname),
107 varnameParam(varname), 109 varnameParam(varname),
108 NewMkOperator(op), 110 NewMkOperator(op),
109 valueAlign, 111 valueAlign,
110 strings.Replace(value, "\\#", "#", -1), 112 strings.Replace(value, "\\#", "#", -1),
111 nil, 113 nil,
112 "", 114 "",
 115 nil,
113 comment}} 116 comment}}
114 } 117 }
115 118
116 if hasPrefix(text, "\t") { 119 if hasPrefix(text, "\t") {
117 shellcmd := text[1:] 120 shellcmd := text[1:]
118 return &MkLineImpl{line, mkLineShell{shellcmd}} 121 return &MkLineImpl{line, mkLineShell{shellcmd}}
119 } 122 }
120 123
121 trimmedText := trimHspace(text) 124 trimmedText := trimHspace(text)
122 if strings.HasPrefix(trimmedText, "#") { 125 if strings.HasPrefix(trimmedText, "#") {
123 return &MkLineImpl{line, mkLineComment{}} 126 return &MkLineImpl{line, mkLineComment{}}
124 } 127 }
125 128
126 if trimmedText == "" { 129 if trimmedText == "" {
127 return &MkLineImpl{line, mkLineEmpty{}} 130 return &MkLineImpl{line, mkLineEmpty{}}
128 } 131 }
129 132
130 if m, indent, directive, args, comment := matchMkDirective(text); m { 133 if m, indent, directive, args, comment := matchMkDirective(text); m {
131 return &MkLineImpl{line, &mkLineDirectiveImpl{indent, directive, args, comment, nil, nil}} 134 return &MkLineImpl{line, &mkLineDirectiveImpl{indent, directive, args, comment, nil, nil, nil}}
132 } 135 }
133 136
134 if m, indent, directive, includedFile := MatchMkInclude(text); m { 137 if m, indent, directive, includedFile := MatchMkInclude(text); m {
135 return &MkLineImpl{line, &mkLineIncludeImpl{directive == "include", false, indent, includedFile, nil}} 138 return &MkLineImpl{line, &mkLineIncludeImpl{directive == "include", false, indent, includedFile, nil}}
136 } 139 }
137 140
138 if m, indent, directive, includedFile := match3(text, `^\.([\t ]*)(s?include)[\t ]+<([^>]+)>[\t ]*(?:#.*)?$`); m { 141 if m, indent, directive, includedFile := match3(text, `^\.([\t ]*)(s?include)[\t ]+<([^>]+)>[\t ]*(?:#.*)?$`); m {
139 return &MkLineImpl{line, &mkLineIncludeImpl{directive == "include", true, indent, includedFile, nil}} 142 return &MkLineImpl{line, &mkLineIncludeImpl{directive == "include", true, indent, includedFile, nil}}
140 } 143 }
141 144
142 // XXX: Replace this regular expression with proper parsing. 145 // XXX: Replace this regular expression with proper parsing.
143 // There might be a ${VAR:M*.c} in these variables, which currently confuses the "parser". 146 // There might be a ${VAR:M*.c} in these variables, which currently confuses the "parser".
144 if m, targets, whitespace, sources := match3(text, `^([^\t :]+(?:[\t ]*[^\t :]+)*)([\t ]*):[\t ]*([^#]*?)(?:[\t ]*#.*)?$`); m { 147 if m, targets, whitespace, sources := match3(text, `^([^\t :]+(?:[\t ]*[^\t :]+)*)([\t ]*):[\t ]*([^#]*?)(?:[\t ]*#.*)?$`); m {
@@ -462,37 +465,72 @@ func (mkline *MkLineImpl) ValueTokens()  @@ -462,37 +465,72 @@ func (mkline *MkLineImpl) ValueTokens()
462 } 465 }
463 466
464 assign := mkline.data.(mkLineAssign) 467 assign := mkline.data.(mkLineAssign)
465 if assign.valueMk != nil || assign.valueMkRest != "" { 468 if assign.valueMk != nil || assign.valueMkRest != "" {
466 return assign.valueMk 469 return assign.valueMk
467 } 470 }
468 471
469 p := NewMkParser(mkline.Line, value, true) 472 p := NewMkParser(mkline.Line, value, true)
470 assign.valueMk = p.MkTokens() 473 assign.valueMk = p.MkTokens()
471 assign.valueMkRest = p.Rest() 474 assign.valueMkRest = p.Rest()
472 return assign.valueMk 475 return assign.valueMk
473} 476}
474 477
 478// Fields applies to variable assignments and .for loops.
 479// For variable assignments, it returns the right-hand side, properly split into words.
 480// For .for loops, it returns all arguments (including variable names), properly split into words.
 481func (mkline *MkLineImpl) Fields() []string {
 482 if mkline.IsVarassign() {
 483 value := mkline.Value()
 484 if value == "" {
 485 return nil
 486 }
 487
 488 assign := mkline.data.(mkLineAssign)
 489 if assign.fields != nil {
 490 return assign.fields
 491 }
 492
 493 assign.fields = mkline.ValueFields(value)
 494 return assign.fields
 495 }
 496
 497 // For .for loops.
 498 args := mkline.Args()
 499 if args == "" {
 500 return nil
 501 }
 502
 503 directive := mkline.data.(mkLineDirective)
 504 if directive.fields != nil {
 505 return directive.fields
 506 }
 507
 508 directive.fields = mkline.ValueFields(args)
 509 return directive.fields
 510
 511}
 512
475func (mkline *MkLineImpl) WithoutMakeVariables(value string) string { 513func (mkline *MkLineImpl) WithoutMakeVariables(value string) string {
476 valueNovar := "" 514 valueNovar := ""
477 for _, token := range NewMkParser(nil, value, false).MkTokens() { 515 for _, token := range NewMkParser(nil, value, false).MkTokens() {
478 if token.Varuse == nil { 516 if token.Varuse == nil {
479 valueNovar += token.Text 517 valueNovar += token.Text
480 } 518 }
481 } 519 }
482 return valueNovar 520 return valueNovar
483} 521}
484 522
485func (mkline *MkLineImpl) ResolveVarsInRelativePath(relativePath string, adjustDepth bool) string { 523func (mkline *MkLineImpl) ResolveVarsInRelativePath(relativePath string) string {
486 524
487 var basedir string 525 var basedir string
488 if G.Pkg != nil { 526 if G.Pkg != nil {
489 basedir = G.Pkg.File(".") 527 basedir = G.Pkg.File(".")
490 } else { 528 } else {
491 basedir = path.Dir(mkline.Filename) 529 basedir = path.Dir(mkline.Filename)
492 } 530 }
493 pkgsrcdir := relpath(basedir, G.Pkgsrc.File(".")) 531 pkgsrcdir := relpath(basedir, G.Pkgsrc.File("."))
494 532
495 if G.Testing { 533 if G.Testing {
496 // Relative pkgsrc paths usually only contain two or three levels. 534 // Relative pkgsrc paths usually only contain two or three levels.
497 // A possible reason for reaching this assertion is: 535 // A possible reason for reaching this assertion is:
498 // Tests that access the file system must create their lines 536 // Tests that access the file system must create their lines
@@ -516,33 +554,26 @@ func (mkline *MkLineImpl) ResolveVarsInR @@ -516,33 +554,26 @@ func (mkline *MkLineImpl) ResolveVarsInR
516 replaceLatest("${LUA_PKGSRCDIR}", "lang", `^lua[0-9]+$`, "../../lang/$0") 554 replaceLatest("${LUA_PKGSRCDIR}", "lang", `^lua[0-9]+$`, "../../lang/$0")
517 replaceLatest("${PHPPKGSRCDIR}", "lang", `^php[0-9]+$`, "../../lang/$0") 555 replaceLatest("${PHPPKGSRCDIR}", "lang", `^php[0-9]+$`, "../../lang/$0")
518 replaceLatest("${SUSE_DIR_PREFIX}", "emulators", `^(suse[0-9]+)_base$`, "$1") 556 replaceLatest("${SUSE_DIR_PREFIX}", "emulators", `^(suse[0-9]+)_base$`, "$1")
519 replaceLatest("${PYPKGSRCDIR}", "lang", `^python[0-9]+$`, "../../lang/$0") 557 replaceLatest("${PYPKGSRCDIR}", "lang", `^python[0-9]+$`, "../../lang/$0")
520 replaceLatest("${PYPACKAGE}", "lang", `^python[0-9]+$`, "$0") 558 replaceLatest("${PYPACKAGE}", "lang", `^python[0-9]+$`, "$0")
521 if G.Pkg != nil { 559 if G.Pkg != nil {
522 // XXX: Even if these variables are defined indirectly, 560 // XXX: Even if these variables are defined indirectly,
523 // pkglint should be able to resolve them properly. 561 // pkglint should be able to resolve them properly.
524 // There is already G.Pkg.Value, maybe that can be used here. 562 // There is already G.Pkg.Value, maybe that can be used here.
525 tmp = strings.Replace(tmp, "${FILESDIR}", G.Pkg.Filesdir, -1) 563 tmp = strings.Replace(tmp, "${FILESDIR}", G.Pkg.Filesdir, -1)
526 tmp = strings.Replace(tmp, "${PKGDIR}", G.Pkg.Pkgdir, -1) 564 tmp = strings.Replace(tmp, "${PKGDIR}", G.Pkg.Pkgdir, -1)
527 } 565 }
528 566
529 // TODO: What is this good for, and in which cases does it make a difference? 
530 if adjustDepth { 
531 if hasPrefix(tmp, "../../") && !hasPrefix(tmp[6:], ".") { 
532 tmp = pkgsrcdir + "/" + tmp[6:] 
533 } 
534 } 
535 
536 tmp = cleanpath(tmp) 567 tmp = cleanpath(tmp)
537 568
538 if trace.Tracing && relativePath != tmp { 569 if trace.Tracing && relativePath != tmp {
539 trace.Step2("resolveVarsInRelativePath: %q => %q", relativePath, tmp) 570 trace.Step2("resolveVarsInRelativePath: %q => %q", relativePath, tmp)
540 } 571 }
541 return tmp 572 return tmp
542} 573}
543 574
544func (mkline *MkLineImpl) ExplainRelativeDirs() { 575func (mkline *MkLineImpl) ExplainRelativeDirs() {
545 G.Explain( 576 G.Explain(
546 "Directories in the form \"../../category/package\" make it easier to", 577 "Directories in the form \"../../category/package\" make it easier to",
547 "move a package around in pkgsrc, for example from pkgsrc-wip to the", 578 "move a package around in pkgsrc, for example from pkgsrc-wip to the",
548 "main pkgsrc repository.") 579 "main pkgsrc repository.")

cvs diff -r1.41 -r1.42 pkgsrc/pkgtools/pkglint/files/Attic/pkglint.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/pkglint.go 2018/12/02 01:57:48 1.41
+++ pkgsrc/pkgtools/pkglint/files/Attic/pkglint.go 2018/12/02 23:12:43 1.42
@@ -349,27 +349,27 @@ func (pkglint *Pkglint) checkdirPackage( @@ -349,27 +349,27 @@ func (pkglint *Pkglint) checkdirPackage(
349 } 349 }
350 350
351 haveDistinfo := false 351 haveDistinfo := false
352 havePatches := false 352 havePatches := false
353 353
354 // Determine the used variables and PLIST directories before checking any of the Makefile fragments. 354 // Determine the used variables and PLIST directories before checking any of the Makefile fragments.
355 for _, filename := range files { 355 for _, filename := range files {
356 basename := path.Base(filename) 356 basename := path.Base(filename)
357 if (hasPrefix(basename, "Makefile.") || hasSuffix(filename, ".mk")) && 357 if (hasPrefix(basename, "Makefile.") || hasSuffix(filename, ".mk")) &&
358 !matches(filename, `patch-`) && 358 !matches(filename, `patch-`) &&
359 !contains(filename, pkg.Pkgdir+"/") && 359 !contains(filename, pkg.Pkgdir+"/") &&
360 !contains(filename, pkg.Filesdir+"/") { 360 !contains(filename, pkg.Filesdir+"/") {
361 if fragmentMklines := LoadMk(filename, MustSucceed); fragmentMklines != nil { 361 if fragmentMklines := LoadMk(filename, MustSucceed); fragmentMklines != nil {
362 fragmentMklines.DetermineUsedVariables() 362 fragmentMklines.collectUsedVariables()
363 } 363 }
364 } 364 }
365 if hasPrefix(basename, "PLIST") { 365 if hasPrefix(basename, "PLIST") {
366 pkg.loadPlistDirs(filename) 366 pkg.loadPlistDirs(filename)
367 } 367 }
368 } 368 }
369 369
370 for _, filename := range files { 370 for _, filename := range files {
371 if containsVarRef(filename) { 371 if containsVarRef(filename) {
372 if trace.Tracing { 372 if trace.Tracing {
373 trace.Stepf("Skipping file %q because the name contains an unresolved variable.", filename) 373 trace.Stepf("Skipping file %q because the name contains an unresolved variable.", filename)
374 } 374 }
375 continue 375 continue
@@ -412,26 +412,28 @@ func (pkglint *Pkglint) Assertf(cond boo @@ -412,26 +412,28 @@ func (pkglint *Pkglint) Assertf(cond boo
412} 412}
413 413
414// Returns the pkgsrc top-level directory, relative to the given file or directory. 414// Returns the pkgsrc top-level directory, relative to the given file or directory.
415func findPkgsrcTopdir(filename string) string { 415func findPkgsrcTopdir(filename string) string {
416 for _, dir := range [...]string{".", "..", "../..", "../../.."} { 416 for _, dir := range [...]string{".", "..", "../..", "../../.."} {
417 if fileExists(filename + "/" + dir + "/mk/bsd.pkg.mk") { 417 if fileExists(filename + "/" + dir + "/mk/bsd.pkg.mk") {
418 return dir 418 return dir
419 } 419 }
420 } 420 }
421 return "" 421 return ""
422} 422}
423 423
424func resolveVariableRefs(text string) (resolved string) { 424func resolveVariableRefs(text string) (resolved string) {
 425 // TODO: How does this fit into the Scope type, which is newer than this function?
 426
425 if !contains(text, "${") { 427 if !contains(text, "${") {
426 return text 428 return text
427 } 429 }
428 430
429 visited := make(map[string]bool) // To prevent endless loops 431 visited := make(map[string]bool) // To prevent endless loops
430 432
431 replacer := func(m string) string { 433 replacer := func(m string) string {
432 varname := m[2 : len(m)-1] 434 varname := m[2 : len(m)-1]
433 if !visited[varname] { 435 if !visited[varname] {
434 visited[varname] = true 436 visited[varname] = true
435 if G.Pkg != nil { 437 if G.Pkg != nil {
436 if value, ok := G.Pkg.vars.Value(varname); ok { 438 if value, ok := G.Pkg.vars.Value(varname); ok {
437 return value 439 return value

cvs diff -r1.45 -r1.46 pkgsrc/pkgtools/pkglint/files/Attic/mkline_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mkline_test.go 2018/12/02 01:57:48 1.45
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkline_test.go 2018/12/02 23:12:43 1.46
@@ -385,27 +385,27 @@ func (s *Suite) Test_MkLine_VariableNeed @@ -385,27 +385,27 @@ func (s *Suite) Test_MkLine_VariableNeed
385} 385}
386 386
387func (s *Suite) Test_MkLine_VariableNeedsQuoting__command_in_command(c *check.C) { 387func (s *Suite) Test_MkLine_VariableNeedsQuoting__command_in_command(c *check.C) {
388 t := s.Init(c) 388 t := s.Init(c)
389 389
390 t.SetupVartypes() 390 t.SetupVartypes()
391 t.SetupTool("find", "FIND", AtRunTime) 391 t.SetupTool("find", "FIND", AtRunTime)
392 t.SetupTool("sort", "SORT", AtRunTime) 392 t.SetupTool("sort", "SORT", AtRunTime)
393 G.Pkg = NewPackage(t.File("category/pkgbase")) 393 G.Pkg = NewPackage(t.File("category/pkgbase"))
394 G.Mk = t.NewMkLines("Makefile", 394 G.Mk = t.NewMkLines("Makefile",
395 MkRcsID, 395 MkRcsID,
396 "GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};") 396 "GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};")
397 397
398 G.Mk.DetermineDefinedVariables() 398 G.Mk.collectDefinedVariables()
399 MkLineChecker{G.Mk.mklines[1]}.Check() 399 MkLineChecker{G.Mk.mklines[1]}.Check()
400 400
401 t.CheckOutputLines( 401 t.CheckOutputLines(
402 "WARN: Makefile:2: The exitcode of \"${FIND}\" at the left of the | operator is ignored.") 402 "WARN: Makefile:2: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
403} 403}
404 404
405func (s *Suite) Test_MkLine_VariableNeedsQuoting__word_as_part_of_word(c *check.C) { 405func (s *Suite) Test_MkLine_VariableNeedsQuoting__word_as_part_of_word(c *check.C) {
406 t := s.Init(c) 406 t := s.Init(c)
407 407
408 t.SetupVartypes() 408 t.SetupVartypes()
409 G.Mk = t.NewMkLines("Makefile", 409 G.Mk = t.NewMkLines("Makefile",
410 MkRcsID, 410 MkRcsID,
411 "EGDIR=\t${EGDIR}/${MACHINE_GNU_PLATFORM}") 411 "EGDIR=\t${EGDIR}/${MACHINE_GNU_PLATFORM}")
@@ -906,27 +906,27 @@ func (s *Suite) Test_MkLine_ValueTokens_ @@ -906,27 +906,27 @@ func (s *Suite) Test_MkLine_ValueTokens_
906 906
907func (s *Suite) Test_MkLine_ResolveVarsInRelativePath(c *check.C) { 907func (s *Suite) Test_MkLine_ResolveVarsInRelativePath(c *check.C) {
908 t := s.Init(c) 908 t := s.Init(c)
909 909
910 t.CreateFileLines("lang/lua53/Makefile") 910 t.CreateFileLines("lang/lua53/Makefile")
911 t.CreateFileLines("lang/php72/Makefile") 911 t.CreateFileLines("lang/php72/Makefile")
912 t.CreateFileLines("emulators/suse100_base/Makefile") 912 t.CreateFileLines("emulators/suse100_base/Makefile")
913 t.CreateFileLines("lang/python36/Makefile") 913 t.CreateFileLines("lang/python36/Makefile")
914 mklines := t.SetupFileMkLines("Makefile", 914 mklines := t.SetupFileMkLines("Makefile",
915 MkRcsID) 915 MkRcsID)
916 mkline := mklines.mklines[0] 916 mkline := mklines.mklines[0]
917 917
918 checkResolve := func(before string, after string) { 918 checkResolve := func(before string, after string) {
919 c.Check(mkline.ResolveVarsInRelativePath(before, false), equals, after) 919 c.Check(mkline.ResolveVarsInRelativePath(before), equals, after)
920 } 920 }
921 921
922 checkResolve("", ".") 922 checkResolve("", ".")
923 checkResolve("${LUA_PKGSRCDIR}", "../../lang/lua53") 923 checkResolve("${LUA_PKGSRCDIR}", "../../lang/lua53")
924 checkResolve("${PHPPKGSRCDIR}", "../../lang/php72") 924 checkResolve("${PHPPKGSRCDIR}", "../../lang/php72")
925 checkResolve("${SUSE_DIR_PREFIX}", "suse100") 925 checkResolve("${SUSE_DIR_PREFIX}", "suse100")
926 checkResolve("${PYPKGSRCDIR}", "../../lang/python36") 926 checkResolve("${PYPKGSRCDIR}", "../../lang/python36")
927 checkResolve("${PYPACKAGE}", "python36") 927 checkResolve("${PYPACKAGE}", "python36")
928 checkResolve("${FILESDIR}", "${FILESDIR}") 928 checkResolve("${FILESDIR}", "${FILESDIR}")
929 checkResolve("${PKGDIR}", "${PKGDIR}") 929 checkResolve("${PKGDIR}", "${PKGDIR}")
930 930
931 G.Pkg = NewPackage(t.File("category/package")) 931 G.Pkg = NewPackage(t.File("category/package"))
932 932

cvs diff -r1.23 -r1.24 pkgsrc/pkgtools/pkglint/files/Attic/mklinechecker.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mklinechecker.go 2018/12/02 01:57:48 1.23
+++ pkgsrc/pkgtools/pkglint/files/Attic/mklinechecker.go 2018/12/02 23:12:43 1.24
@@ -152,27 +152,27 @@ func (ck MkLineChecker) checkDirective(f @@ -152,27 +152,27 @@ func (ck MkLineChecker) checkDirective(f
152 } 152 }
153 153
154 case directive == "if" || directive == "elif": 154 case directive == "if" || directive == "elif":
155 ck.checkDirectiveCond() 155 ck.checkDirectiveCond()
156 156
157 case directive == "ifdef" || directive == "ifndef": 157 case directive == "ifdef" || directive == "ifndef":
158 mkline.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.", 158 mkline.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.",
159 directive, ifelseStr(directive == "ifdef", "", "!"), args) 159 directive, ifelseStr(directive == "ifdef", "", "!"), args)
160 160
161 case directive == "for": 161 case directive == "for":
162 ck.checkDirectiveFor(forVars, ind) 162 ck.checkDirectiveFor(forVars, ind)
163 163
164 case directive == "undef": 164 case directive == "undef":
165 for _, varname := range fields(args) { 165 for _, varname := range mkline.Fields() {
166 if forVars[varname] { 166 if forVars[varname] {
167 mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.") 167 mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.")
168 } 168 }
169 } 169 }
170 } 170 }
171} 171}
172 172
173func (ck MkLineChecker) checkDirectiveEnd(ind *Indentation) { 173func (ck MkLineChecker) checkDirectiveEnd(ind *Indentation) {
174 mkline := ck.MkLine 174 mkline := ck.MkLine
175 directive := mkline.Directive() 175 directive := mkline.Directive()
176 comment := mkline.DirectiveComment() 176 comment := mkline.DirectiveComment()
177 177
178 if directive == "endif" && comment != "" { 178 if directive == "endif" && comment != "" {
@@ -193,28 +193,28 @@ func (ck MkLineChecker) checkDirectiveEn @@ -193,28 +193,28 @@ func (ck MkLineChecker) checkDirectiveEn
193func (ck MkLineChecker) checkDirectiveFor(forVars map[string]bool, indentation *Indentation) { 193func (ck MkLineChecker) checkDirectiveFor(forVars map[string]bool, indentation *Indentation) {
194 mkline := ck.MkLine 194 mkline := ck.MkLine
195 args := mkline.Args() 195 args := mkline.Args()
196 196
197 if m, vars, _ := match2(args, `^([^\t ]+(?:[\t ]*[^\t ]+)*?)[\t ]+in[\t ]+(.*)$`); m { 197 if m, vars, _ := match2(args, `^([^\t ]+(?:[\t ]*[^\t ]+)*?)[\t ]+in[\t ]+(.*)$`); m {
198 for _, forvar := range fields(vars) { 198 for _, forvar := range fields(vars) {
199 indentation.AddVar(forvar) 199 indentation.AddVar(forvar)
200 if !G.Infrastructure && hasPrefix(forvar, "_") { 200 if !G.Infrastructure && hasPrefix(forvar, "_") {
201 mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", forvar) 201 mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", forvar)
202 } 202 }
203 203
204 if matches(forvar, `^[_a-z][_a-z0-9]*$`) { 204 if matches(forvar, `^[_a-z][_a-z0-9]*$`) {
205 // Fine. 205 // Fine.
206 } else if strings.IndexFunc(forvar, func(r rune) bool { return 'A' <= r && r <= 'Z' }) != -1 { 206 } else if matches(forvar, `^[A-Z_a-z][0-9A-Z_a-z]*$`) {
207 mkline.Warnf(".for variable names should not contain uppercase letters.") 207 mkline.Warnf("The variable name %q in the .for loop should not contain uppercase letters.", forvar)
208 } else { 208 } else {
209 mkline.Errorf("Invalid variable name %q.", forvar) 209 mkline.Errorf("Invalid variable name %q.", forvar)
210 } 210 }
211 211
212 forVars[forvar] = true 212 forVars[forvar] = true
213 } 213 }
214 214
215 // XXX: The type BtUnknown is very unspecific here. For known variables 215 // XXX: The type BtUnknown is very unspecific here. For known variables
216 // or constant values this could probably be improved. 216 // or constant values this could probably be improved.
217 // 217 //
218 // The guessed flag could also be determined more correctly. As of November 2018, 218 // The guessed flag could also be determined more correctly. As of November 2018,
219 // running pkglint over the whole pkgsrc tree did not produce any different result 219 // running pkglint over the whole pkgsrc tree did not produce any different result
220 // whether guessed was true or false, so currently it is not worth investing 220 // whether guessed was true or false, so currently it is not worth investing
@@ -754,46 +754,46 @@ func (ck MkLineChecker) checkVaruseDepre @@ -754,46 +754,46 @@ func (ck MkLineChecker) checkVaruseDepre
754 return 754 return
755 } 755 }
756 756
757 varname := varuse.varname 757 varname := varuse.varname
758 instead := G.Pkgsrc.Deprecated[varname] 758 instead := G.Pkgsrc.Deprecated[varname]
759 if instead == "" { 759 if instead == "" {
760 instead = G.Pkgsrc.Deprecated[varnameCanon(varname)] 760 instead = G.Pkgsrc.Deprecated[varnameCanon(varname)]
761 } 761 }
762 if instead != "" { 762 if instead != "" {
763 ck.MkLine.Warnf("Use of %q is deprecated. %s", varname, instead) 763 ck.MkLine.Warnf("Use of %q is deprecated. %s", varname, instead)
764 } 764 }
765} 765}
766 766
767func (ck MkLineChecker) checkVarassignDecreasingVersions(varname, value string) { 767func (ck MkLineChecker) checkVarassignDecreasingVersions() {
768 if trace.Tracing { 768 if trace.Tracing {
769 defer trace.Call2(varname, value)() 769 defer trace.Call0()()
770 } 770 }
771 771
772 mkline := ck.MkLine 772 mkline := ck.MkLine
773 strVersions := fields(value) 773 strVersions := mkline.Fields()
774 intVersions := make([]int, len(strVersions)) 774 intVersions := make([]int, len(strVersions))
775 for i, strVersion := range strVersions { 775 for i, strVersion := range strVersions {
776 iver, err := strconv.Atoi(strVersion) 776 iver, err := strconv.Atoi(strVersion)
777 if err != nil || !(iver > 0) { 777 if err != nil || !(iver > 0) {
778 mkline.Errorf("All values for %s must be positive integers.", varname) 778 mkline.Errorf("All values for %s must be positive integers.", mkline.Varname())
779 return 779 return
780 } 780 }
781 intVersions[i] = iver 781 intVersions[i] = iver
782 } 782 }
783 783
784 for i, ver := range intVersions { 784 for i, ver := range intVersions {
785 if i > 0 && ver >= intVersions[i-1] { 785 if i > 0 && ver >= intVersions[i-1] {
786 mkline.Warnf("The values for %s should be in decreasing order.", varname) 786 mkline.Warnf("The values for %s should be in decreasing order.", mkline.Varname())
787 G.Explain( 787 G.Explain(
788 "If they aren't, it may be possible that needless versions of", 788 "If they aren't, it may be possible that needless versions of",
789 "packages are installed.") 789 "packages are installed.")
790 } 790 }
791 } 791 }
792} 792}
793 793
794func (ck MkLineChecker) checkVarassign() { 794func (ck MkLineChecker) checkVarassign() {
795 mkline := ck.MkLine 795 mkline := ck.MkLine
796 varname := mkline.Varname() 796 varname := mkline.Varname()
797 op := mkline.Op() 797 op := mkline.Op()
798 value := mkline.Value() 798 value := mkline.Value()
799 comment := mkline.VarassignComment() 799 comment := mkline.VarassignComment()
@@ -935,54 +935,54 @@ func (ck MkLineChecker) checkVarassignSp @@ -935,54 +935,54 @@ func (ck MkLineChecker) checkVarassignSp
935 mkline := ck.MkLine 935 mkline := ck.MkLine
936 varname := mkline.Varname() 936 varname := mkline.Varname()
937 value := mkline.Value() 937 value := mkline.Value()
938 938
939 if contains(value, "/etc/rc.d") && mkline.Varname() != "RPMIGNOREPATH" { 939 if contains(value, "/etc/rc.d") && mkline.Varname() != "RPMIGNOREPATH" {
940 mkline.Warnf("Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.") 940 mkline.Warnf("Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.")
941 } 941 }
942 942
943 if hasPrefix(varname, "_") && !G.Infrastructure { 943 if hasPrefix(varname, "_") && !G.Infrastructure {
944 mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", varname) 944 mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", varname)
945 } 945 }
946 946
947 if varname == "PYTHON_VERSIONS_ACCEPTED" { 947 if varname == "PYTHON_VERSIONS_ACCEPTED" {
948 ck.checkVarassignDecreasingVersions(varname, value) 948 ck.checkVarassignDecreasingVersions()
949 } 949 }
950 950
951 if mkline.VarassignComment() == "# defined" && !hasSuffix(varname, "_MK") && !hasSuffix(varname, "_COMMON") { 951 if mkline.VarassignComment() == "# defined" && !hasSuffix(varname, "_MK") && !hasSuffix(varname, "_COMMON") {
952 mkline.Notef("Please use \"# empty\", \"# none\" or \"# yes\" instead of \"# defined\".") 952 mkline.Notef("Please use \"# empty\", \"# none\" or \"# yes\" instead of \"# defined\".")
953 G.Explain( 953 G.Explain(
954 "The value #defined says something about the state of the variable,", 954 "The value #defined says something about the state of the variable,",
955 "but not what that _means_. In some cases a variable that is defined", 955 "but not what that _means_. In some cases a variable that is defined",
956 "means \"yes\", in other cases it is an empty list (which is also", 956 "means \"yes\", in other cases it is an empty list (which is also",
957 "only the state of the variable), whose meaning could be described", 957 "only the state of the variable), whose meaning could be described",
958 "with \"none\". It is this meaning that should be described.") 958 "with \"none\". It is this meaning that should be described.")
959 } 959 }
960 960
961 if varname == "DIST_SUBDIR" || varname == "WRKSRC" { 961 if varname == "DIST_SUBDIR" || varname == "WRKSRC" {
962 if m, revVarname := match1(value, `\$\{(PKGNAME|PKGVERSION)[:\}]`); m { 962 if m, revVarname := match1(value, `\$\{(PKGNAME|PKGVERSION)[:\}]`); m {
963 mkline.Warnf("%s should not be used in %s as it includes the PKGREVISION. "+ 963 mkline.Warnf("%s should not be used in %s as it includes the PKGREVISION. "+
964 "Please use %[1]s_NOREV instead.", revVarname, varname) 964 "Please use %[1]s_NOREV instead.", revVarname, varname)
965 } 965 }
966 } 966 }
967 967
968 if hasPrefix(varname, "SITES_") { 968 if hasPrefix(varname, "SITES_") {
969 mkline.Warnf("SITES_* is deprecated. Please use SITES.* instead.") 969 mkline.Warnf("SITES_* is deprecated. Please use SITES.* instead.")
970 // No autofix since it doesn't occur anymore. 970 // No autofix since it doesn't occur anymore.
971 } 971 }
972 972
973 if varname == "PKG_SKIP_REASON" && G.Mk.indentation.DependsOn("OPSYS") { 973 if varname == "PKG_SKIP_REASON" && G.Mk.indentation.DependsOn("OPSYS") {
974 mkline.Notef("Consider defining NOT_FOR_PLATFORM instead of " + 974 mkline.Notef("Consider setting NOT_FOR_PLATFORM instead of " +
975 "setting PKG_SKIP_REASON depending on ${OPSYS}.") 975 "PKG_SKIP_REASON depending on ${OPSYS}.")
976 } 976 }
977} 977}
978 978
979func (ck MkLineChecker) checkVarassignBsdPrefs() { 979func (ck MkLineChecker) checkVarassignBsdPrefs() {
980 mkline := ck.MkLine 980 mkline := ck.MkLine
981 981
982 switch mkline.Varcanon() { 982 switch mkline.Varcanon() {
983 case "BUILDLINK_PKGSRCDIR.*", 983 case "BUILDLINK_PKGSRCDIR.*",
984 "BUILDLINK_DEPMETHOD.*", 984 "BUILDLINK_DEPMETHOD.*",
985 "BUILDLINK_ABI_DEPENDS.*", 985 "BUILDLINK_ABI_DEPENDS.*",
986 "BUILDLINK_INCDIRS.*", 986 "BUILDLINK_INCDIRS.*",
987 "BUILDLINK_LIBDIRS.*": 987 "BUILDLINK_LIBDIRS.*":
988 return 988 return
@@ -1141,150 +1141,179 @@ func (ck MkLineChecker) checkTextDepreca @@ -1141,150 +1141,179 @@ func (ck MkLineChecker) checkTextDepreca
1141func (ck MkLineChecker) checkDirectiveCond() { 1141func (ck MkLineChecker) checkDirectiveCond() {
1142 mkline := ck.MkLine 1142 mkline := ck.MkLine
1143 if trace.Tracing { 1143 if trace.Tracing {
1144 defer trace.Call1(mkline.Args())() 1144 defer trace.Call1(mkline.Args())()
1145 } 1145 }
1146 1146
1147 p := NewMkParser(nil, mkline.Args(), false) // No emitWarnings here, see the code below. 1147 p := NewMkParser(nil, mkline.Args(), false) // No emitWarnings here, see the code below.
1148 cond := p.MkCond() 1148 cond := p.MkCond()
1149 if !p.EOF() { 1149 if !p.EOF() {
1150 mkline.Warnf("Invalid condition, unrecognized part: %q.", p.Rest()) 1150 mkline.Warnf("Invalid condition, unrecognized part: %q.", p.Rest())
1151 return 1151 return
1152 } 1152 }
1153 1153
1154 checkEmpty := func(varuse *MkVarUse) { 
1155 varname := varuse.varname 
1156 if matches(varname, `^\$.*:[MN]`) { 
1157 mkline.Warnf("The empty() function takes a variable name as parameter, not a variable expression.") 
1158 G.Explain( 
1159 "Instead of empty(${VARNAME:Mpattern}), you should write either", 
1160 "of the following:", 
1161 "", 
1162 "\tempty(VARNAME:Mpattern)", 
1163 "\t${VARNAME:Mpattern} == \"\"", 
1164 "", 
1165 "Instead of !empty(${VARNAME:Mpattern}), you should write either", 
1166 "of the following:", 
1167 "", 
1168 "\t!empty(VARNAME:Mpattern)", 
1169 "\t${VARNAME:Mpattern}") 
1170 } 
1171 
1172 modifiers := varuse.modifiers 
1173 for _, modifier := range modifiers { 
1174 if m, positive, pattern := modifier.MatchMatch(); m && (positive || len(modifiers) == 1) { 
1175 ck.checkVartype(varname, opUseMatch, pattern, "") 
1176 
1177 vartype := G.Pkgsrc.VariableType(varname) 
1178 if matches(pattern, `^[\w-/]+$`) && vartype != nil && !vartype.IsConsideredList() { 
1179 mkline.Notef("%s should be compared using == instead of the :M or :N modifier without wildcards.", varname) 
1180 G.Explain( 
1181 "This variable has a single value, not a list of values. Therefore", 
1182 "it feels strange to apply list operators like :M and :N onto it.", 
1183 "A more direct approach is to use the == and != operators.", 
1184 "", 
1185 "An entirely different case is when the pattern contains wildcards", 
1186 "like ^, *, $. In such a case, using the :M or :N modifiers is", 
1187 "useful and preferred.") 
1188 } 
1189 } 
1190 } 
1191 } 
1192 
1193 checkCompareVarStr := func(varuse *MkVarUse, op string, value string) { 1154 checkCompareVarStr := func(varuse *MkVarUse, op string, value string) {
1194 varname := varuse.varname 1155 varname := varuse.varname
1195 varmods := varuse.modifiers 1156 varmods := varuse.modifiers
1196 if len(varmods) == 0 { 1157 switch len(varmods) {
 1158 case 0:
1197 ck.checkCompareVarStr(varname, op, value) 1159 ck.checkCompareVarStr(varname, op, value)
1198 } else if len(varmods) == 1 { 1160
 1161 case 1:
1199 if m, _, _ := varmods[0].MatchMatch(); m && value != "" { 1162 if m, _, _ := varmods[0].MatchMatch(); m && value != "" {
1200 ck.checkVartype(varname, opUseMatch, value, "") 1163 ck.checkVartype(varname, opUseMatch, value, "")
1201 } 1164 }
 1165
 1166 default:
 1167 // This case covers ${VAR:Mfilter:O:u} or similar uses in conditions.
 1168 // To check these properly, pkglint first needs to know the most common modifiers and how they interact.
 1169 // As of November 2018, the modifiers are not modeled.
 1170 // The following tracing statement makes it easy to discover these cases,
 1171 // in order to decide whether checking them is worthwhile.
 1172 if trace.Tracing {
 1173 trace.Stepf("checkCompareVarStr ${%s%s} %s %s", varuse.varname, varuse.Mod(), op, value)
 1174 }
1202 } 1175 }
1203 } 1176 }
1204 1177
1205 checkVarUse := func(varuse *MkVarUse) { 1178 checkVarUse := func(varuse *MkVarUse) {
1206 var vartype *Vartype // TODO: Insert a better type guess here. 1179 var vartype *Vartype // TODO: Insert a better type guess here.
1207 vuc := VarUseContext{vartype, vucTimeParse, vucQuotPlain, false} 1180 vuc := VarUseContext{vartype, vucTimeParse, vucQuotPlain, false}
1208 ck.CheckVaruse(varuse, &vuc) 1181 ck.CheckVaruse(varuse, &vuc)
1209 } 1182 }
1210 1183
1211 cond.Walk(&MkCondCallback{ 1184 cond.Walk(&MkCondCallback{
1212 Empty: checkEmpty, 1185 Empty: ck.checkDirectiveCondEmpty,
1213 CompareVarStr: checkCompareVarStr, 1186 CompareVarStr: checkCompareVarStr,
1214 VarUse: checkVarUse}) 1187 VarUse: checkVarUse})
1215} 1188}
1216 1189
 1190// checkDirectiveCondEmpty checks a condition of the form empty(...) in an .if directive.
 1191func (ck MkLineChecker) checkDirectiveCondEmpty(varuse *MkVarUse) {
 1192 varname := varuse.varname
 1193 if matches(varname, `^\$.*:[MN]`) {
 1194 ck.MkLine.Warnf("The empty() function takes a variable name as parameter, not a variable expression.")
 1195 G.Explain(
 1196 "Instead of empty(${VARNAME:Mpattern}), you should write either",
 1197 "of the following:",
 1198 "",
 1199 "\tempty(VARNAME:Mpattern)",
 1200 "\t${VARNAME:Mpattern} == \"\"",
 1201 "",
 1202 "Instead of !empty(${VARNAME:Mpattern}), you should write either",
 1203 "of the following:",
 1204 "",
 1205 "\t!empty(VARNAME:Mpattern)",
 1206 "\t${VARNAME:Mpattern}")
 1207 }
 1208
 1209 modifiers := varuse.modifiers
 1210 for _, modifier := range modifiers {
 1211 if m, positive, pattern := modifier.MatchMatch(); m && (positive || len(modifiers) == 1) {
 1212 ck.checkVartype(varname, opUseMatch, pattern, "")
 1213
 1214 vartype := G.Pkgsrc.VariableType(varname)
 1215 if matches(pattern, `^[\w-/]+$`) && vartype != nil && !vartype.IsConsideredList() {
 1216 ck.MkLine.Notef("%s should be compared using %s instead of matching against %q.",
 1217 varname, ifelseStr(positive, "==", "!="), ":"+modifier.Text)
 1218 G.Explain(
 1219 "This variable has a single value, not a list of values.",
 1220 "Therefore it feels strange to apply list operators like :M and :N onto it.",
 1221 "A more direct approach is to use the == and != operators.",
 1222 "",
 1223 "An entirely different case is when the pattern contains wildcards like ^, *, $.",
 1224 "In such a case, using the :M or :N modifiers is useful and preferred.")
 1225 }
 1226 }
 1227 }
 1228
 1229}
 1230
1217func (ck MkLineChecker) checkCompareVarStr(varname, op, value string) { 1231func (ck MkLineChecker) checkCompareVarStr(varname, op, value string) {
1218 ck.checkVartype(varname, opUseCompare, value, "") 1232 ck.checkVartype(varname, opUseCompare, value, "")
1219 1233
1220 if varname == "PKGSRC_COMPILER" { 1234 if varname == "PKGSRC_COMPILER" {
1221 ck.MkLine.Warnf("Use ${PKGSRC_COMPILER:%s%s} instead of the %s operator.", ifelseStr(op == "==", "M", "N"), value, op) 1235 ck.MkLine.Warnf("Use ${PKGSRC_COMPILER:%s%s} instead of the %s operator.", ifelseStr(op == "==", "M", "N"), value, op)
1222 G.Explain( 1236 G.Explain(
1223 "The PKGSRC_COMPILER can be a list of chained compilers, e.g. \"ccache", 1237 "The PKGSRC_COMPILER can be a list of chained compilers, e.g. \"ccache",
1224 "distcc clang\". Therefore, comparing it using == or != leads to", 1238 "distcc clang\". Therefore, comparing it using == or != leads to",
1225 "wrong results in these cases.") 1239 "wrong results in these cases.")
1226 } 1240 }
1227} 1241}
1228 1242
 1243// CheckRelativePkgdir checks a reference from one pkgsrc package to another.
 1244// These references should always have the form ../../category/package.
 1245//
 1246// When used in DEPENDS or similar variables, these directories could theoretically
 1247// also be relative to the pkgsrc root, which would save a few keystrokes.
 1248// This, however, is not implemented in pkgsrc and suggestions regarding this topic
 1249// have not been made in the last two decades on the public mailing lists.
 1250// While being a bit redundant, the current scheme works well.
 1251//
 1252// When used in .include directives, the relative package directories must be written
 1253// with the leading ../.. anyway, so the benefit might not be too big at all.
1229func (ck MkLineChecker) CheckRelativePkgdir(pkgdir string) { 1254func (ck MkLineChecker) CheckRelativePkgdir(pkgdir string) {
1230 if trace.Tracing { 1255 if trace.Tracing {
1231 defer trace.Call1(pkgdir)() 1256 defer trace.Call1(pkgdir)()
1232 } 1257 }
1233 1258
1234 mkline := ck.MkLine 1259 mkline := ck.MkLine
1235 ck.CheckRelativePath(pkgdir, true) 1260 ck.CheckRelativePath(pkgdir, true)
1236 pkgdir = mkline.ResolveVarsInRelativePath(pkgdir, false) 1261 pkgdir = mkline.ResolveVarsInRelativePath(pkgdir)
1237 1262
 1263 // XXX: Is the leading "./" realistic?
1238 if m, otherpkgpath := match1(pkgdir, `^(?:\./)?\.\./\.\./([^/]+/[^/]+)$`); m { 1264 if m, otherpkgpath := match1(pkgdir, `^(?:\./)?\.\./\.\./([^/]+/[^/]+)$`); m {
1239 if !fileExists(G.Pkgsrc.File(otherpkgpath + "/Makefile")) { 1265 if !fileExists(G.Pkgsrc.File(otherpkgpath + "/Makefile")) {
1240 mkline.Errorf("There is no package in %q.", otherpkgpath) 1266 mkline.Errorf("There is no package in %q.", otherpkgpath)
1241 } 1267 }
1242 1268
1243 } else if !containsVarRef(pkgdir) { 1269 } else if !containsVarRef(pkgdir) {
1244 mkline.Warnf("%q is not a valid relative package directory.", pkgdir) 1270 mkline.Warnf("%q is not a valid relative package directory.", pkgdir)
1245 G.Explain( 1271 G.Explain(
1246 "A relative pathname always starts with \"../../\", followed", 1272 "A relative pathname always starts with \"../../\", followed",
1247 "by a category, a slash and a the directory name of the package.", 1273 "by a category, a slash and a the directory name of the package.",
1248 "For example, \"../../misc/screen\" is a valid relative pathname.") 1274 "For example, \"../../misc/screen\" is a valid relative pathname.")
1249 } 1275 }
1250} 1276}
1251 1277
 1278// CheckRelativePath checks a relative path that leads to the directory of another package
 1279// or to a subdirectory thereof or a file within there.
1252func (ck MkLineChecker) CheckRelativePath(relativePath string, mustExist bool) { 1280func (ck MkLineChecker) CheckRelativePath(relativePath string, mustExist bool) {
1253 if trace.Tracing { 1281 if trace.Tracing {
1254 defer trace.Call(relativePath, mustExist)() 1282 defer trace.Call(relativePath, mustExist)()
1255 } 1283 }
1256 1284
1257 mkline := ck.MkLine 1285 mkline := ck.MkLine
1258 if !G.Wip && contains(relativePath, "/wip/") { 1286 if !G.Wip && contains(relativePath, "/wip/") {
1259 mkline.Errorf("A main pkgsrc package must not depend on a pkgsrc-wip package.") 1287 mkline.Errorf("A main pkgsrc package must not depend on a pkgsrc-wip package.")
1260 } 1288 }
1261 1289
1262 resolvedPath := mkline.ResolveVarsInRelativePath(relativePath, true) 1290 resolvedPath := mkline.ResolveVarsInRelativePath(relativePath)
1263 if containsVarRef(resolvedPath) { 1291 if containsVarRef(resolvedPath) {
1264 return 1292 return
1265 } 1293 }
1266 1294
1267 abs := resolvedPath 1295 abs := resolvedPath
1268 if !hasPrefix(abs, "/") { 1296 if !hasPrefix(abs, "/") {
1269 abs = path.Dir(mkline.Filename) + "/" + abs 1297 abs = path.Dir(mkline.Filename) + "/" + abs
1270 } 1298 }
1271 if _, err := os.Stat(abs); err != nil { 1299 if _, err := os.Stat(abs); err != nil {
1272 if mustExist { 1300 if mustExist {
1273 mkline.Errorf("%q does not exist.", resolvedPath) 1301 mkline.Errorf("Relative path %q does not exist.", resolvedPath)
1274 } 1302 }
1275 return 1303 return
1276 } 1304 }
1277 1305
1278 switch { 1306 switch {
1279 case !hasPrefix(relativePath, "../"): 1307 case !hasPrefix(relativePath, "../"):
1280 break 1308 break
1281 case hasPrefix(relativePath, "../../mk/"): 1309 case hasPrefix(relativePath, "../../mk/"):
1282 // From a package to the infrastructure. 1310 // From a package to the infrastructure.
1283 case matches(relativePath, `^\.\./\.\./[^/]+/[^/]`): 1311 case matches(relativePath, `^\.\./\.\./[^/]+/[^/]`):
1284 // From a package to another package. 1312 // From a package to another package.
1285 case hasPrefix(relativePath, "../mk/") && relpath(path.Dir(mkline.Filename), G.Pkgsrc.File(".")) == "..": 1313 case hasPrefix(relativePath, "../mk/") && relpath(path.Dir(mkline.Filename), G.Pkgsrc.File(".")) == "..":
1286 // For category Makefiles. 1314 // For category Makefiles.
1287 default: 1315 default:
1288 mkline.Warnf("Invalid relative path %q.", relativePath) 1316 mkline.Warnf("Invalid relative path %q.", relativePath)
 1317 // TODO: Explain this warning.
1289 } 1318 }
1290} 1319}

cvs diff -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/Attic/mklinechecker_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mklinechecker_test.go 2018/12/02 01:57:48 1.19
+++ pkgsrc/pkgtools/pkglint/files/Attic/mklinechecker_test.go 2018/12/02 23:12:43 1.20
@@ -13,119 +13,164 @@ func (s *Suite) Test_MkLineChecker_Check @@ -13,119 +13,164 @@ func (s *Suite) Test_MkLineChecker_Check
13 13
14 t.CheckOutputLines( 14 t.CheckOutputLines(
15 "ERROR: filename.mk:1: This comment indicates unfinished work (url2pkg).") 15 "ERROR: filename.mk:1: This comment indicates unfinished work (url2pkg).")
16} 16}
17 17
18func (s *Suite) Test_MkLineChecker_Check__buildlink3_include_prefs(c *check.C) { 18func (s *Suite) Test_MkLineChecker_Check__buildlink3_include_prefs(c *check.C) {
19 t := s.Init(c) 19 t := s.Init(c)
20 20
21 t.SetupVartypes() 21 t.SetupVartypes()
22 22
23 t.CreateFileLines("mk/bsd.prefs.mk") 23 t.CreateFileLines("mk/bsd.prefs.mk")
24 mklines := t.SetupFileMkLines("category/package/buildlink3.mk", 24 mklines := t.SetupFileMkLines("category/package/buildlink3.mk",
25 ".include \"../../mk/bsd.prefs.mk\"") 25 ".include \"../../mk/bsd.prefs.mk\"")
26 // If the buildlink3.mk file is not actually created, resolving the 26 // If the buildlink3.mk file doesn't actually exist, resolving the
27 // relative path fails since that depends on the actual file system, 27 // relative path fails since that depends on the actual file system,
28 // not on syntactical paths; see os.Stat in CheckRelativePath. 28 // not on syntactical paths; see os.Stat in CheckRelativePath.
 29 //
 30 // TODO: Refactor relpath to be independent of a filesystem.
29 31
30 MkLineChecker{mklines.mklines[0]}.Check() 32 MkLineChecker{mklines.mklines[0]}.Check()
31 33
32 t.CheckOutputLines( 34 t.CheckOutputLines(
33 "NOTE: ~/category/package/buildlink3.mk:1: For efficiency reasons, please include bsd.fast.prefs.mk instead of bsd.prefs.mk.") 35 "NOTE: ~/category/package/buildlink3.mk:1: For efficiency reasons, " +
 36 "please include bsd.fast.prefs.mk instead of bsd.prefs.mk.")
34} 37}
35 38
36func (s *Suite) Test_MkLineChecker_checkInclude(c *check.C) { 39func (s *Suite) Test_MkLineChecker_checkInclude(c *check.C) {
37 t := s.Init(c) 40 t := s.Init(c)
38 41
39 t.SetupVartypes() 42 t.SetupVartypes()
40 43
41 t.CreateFileLines("pkgtools/x11-links/buildlink3.mk") 44 t.CreateFileLines("pkgtools/x11-links/buildlink3.mk")
42 t.CreateFileLines("graphics/jpeg/buildlink3.mk") 45 t.CreateFileLines("graphics/jpeg/buildlink3.mk")
43 t.CreateFileLines("devel/intltool/buildlink3.mk") 46 t.CreateFileLines("devel/intltool/buildlink3.mk")
44 t.CreateFileLines("devel/intltool/builtin.mk") 47 t.CreateFileLines("devel/intltool/builtin.mk")
45 mklines := t.SetupFileMkLines("category/package/filename.mk", 48 mklines := t.SetupFileMkLines("category/package/filename.mk",
46 MkRcsID, 49 MkRcsID,
47 "", 50 "",
48 ".include \"../../pkgtools/x11-links/buildlink3.mk\"", 51 ".include \"../../pkgtools/x11-links/buildlink3.mk\"",
49 ".include \"../../graphics/jpeg/buildlink3.mk\"", 52 ".include \"../../graphics/jpeg/buildlink3.mk\"",
50 ".include \"../../devel/intltool/buildlink3.mk\"", 53 ".include \"../../devel/intltool/buildlink3.mk\"",
51 ".include \"../../devel/intltool/builtin.mk\"") 54 ".include \"../../devel/intltool/builtin.mk\"")
52 55
53 mklines.Check() 56 mklines.Check()
54 57
55 t.CheckOutputLines( 58 t.CheckOutputLines(
56 "ERROR: ~/category/package/filename.mk:3: ../../pkgtools/x11-links/buildlink3.mk must not be included directly. "+ 59 "ERROR: ~/category/package/filename.mk:3: "+
 60 "../../pkgtools/x11-links/buildlink3.mk must not be included directly. "+
57 "Include \"../../mk/x11.buildlink3.mk\" instead.", 61 "Include \"../../mk/x11.buildlink3.mk\" instead.",
58 "ERROR: ~/category/package/filename.mk:4: ../../graphics/jpeg/buildlink3.mk must not be included directly. "+ 62 "ERROR: ~/category/package/filename.mk:4: "+
 63 "../../graphics/jpeg/buildlink3.mk must not be included directly. "+
59 "Include \"../../mk/jpeg.buildlink3.mk\" instead.", 64 "Include \"../../mk/jpeg.buildlink3.mk\" instead.",
60 "WARN: ~/category/package/filename.mk:5: Please write \"USE_TOOLS+= intltool\" instead of this line.", 65 "WARN: ~/category/package/filename.mk:5: "+
61 "ERROR: ~/category/package/filename.mk:6: ../../devel/intltool/builtin.mk must not be included directly. "+ 66 "Please write \"USE_TOOLS+= intltool\" instead of this line.",
 67 "ERROR: ~/category/package/filename.mk:6: "+
 68 "../../devel/intltool/builtin.mk must not be included directly. "+
62 "Include \"../../devel/intltool/buildlink3.mk\" instead.") 69 "Include \"../../devel/intltool/buildlink3.mk\" instead.")
63} 70}
64 71
65func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) { 72func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) {
66 t := s.Init(c) 73 t := s.Init(c)
67 74
68 mkline := t.NewMkLine(t.File("Makefile"), 2, ".include \"../../other/package/Makefile\"") 75 mkline := t.NewMkLine(t.File("Makefile"), 2, ".include \"../../other/package/Makefile\"")
69 76
70 MkLineChecker{mkline}.checkInclude() 77 MkLineChecker{mkline}.checkInclude()
71 78
72 t.CheckOutputLines( 79 t.CheckOutputLines(
73 "ERROR: ~/Makefile:2: \"other/package/Makefile\" does not exist.", 80 "ERROR: ~/Makefile:2: Relative path \"../../other/package/Makefile\" does not exist.",
74 "ERROR: ~/Makefile:2: Other Makefiles must not be included directly.") 81 "ERROR: ~/Makefile:2: Other Makefiles must not be included directly.")
75} 82}
76 83
 84func (s *Suite) Test_MkLineChecker_checkInclude__Makefile_exists(c *check.C) {
 85 t := s.Init(c)
 86
 87 t.CreateFileLines("other/existing/Makefile")
 88 t.SetupPackage("category/package",
 89 ".include \"../../other/existing/Makefile\"",
 90 ".include \"../../other/not-found/Makefile\"")
 91
 92 G.checkdirPackage(t.File("category/package"))
 93
 94 t.CheckOutputLines(
 95 "ERROR: ~/category/package/Makefile:20: Cannot read \"../../other/existing/Makefile\".")
 96}
 97
77func (s *Suite) Test_MkLineChecker_checkDirective(c *check.C) { 98func (s *Suite) Test_MkLineChecker_checkDirective(c *check.C) {
78 t := s.Init(c) 99 t := s.Init(c)
79 100
80 t.SetupVartypes() 101 t.SetupVartypes()
81 102
82 mklines := t.NewMkLines("category/package/filename.mk", 103 mklines := t.NewMkLines("category/package/filename.mk",
83 MkRcsID, 104 MkRcsID,
84 "", 105 "",
85 ".for", 106 ".for",
86 ".endfor", 107 ".endfor",
87 "", 108 "",
88 ".if", 109 ".if",
89 ".else don't", 110 ".else don't",
90 ".endif invalid-arg", 111 ".endif invalid-arg",
91 "", 112 "",
92 ".ifdef FNAME_MK", 113 ".ifdef FNAME_MK",
93 ".endif", 114 ".endif",
94 ".ifndef FNAME_MK", 115 ".ifndef FNAME_MK",
95 ".endif", 116 ".endif",
96 "", 117 "",
97 ".for var in a b c", 118 ".for var in a b c",
98 ".endfor", 119 ".endfor",
99 ".undef var", 120 ".undef var")
 121
 122 mklines.Check()
 123
 124 t.CheckOutputLines(
 125 "ERROR: category/package/filename.mk:3: \".for\" requires arguments.",
 126 "ERROR: category/package/filename.mk:6: \".if\" requires arguments.",
 127 "ERROR: category/package/filename.mk:7: \".else\" does not take arguments. "+
 128 "If you meant \"else if\", use \".elif\".",
 129 "ERROR: category/package/filename.mk:8: \".endif\" does not take arguments.",
 130 "WARN: category/package/filename.mk:10: The \".ifdef\" directive is deprecated. "+
 131 "Please use \".if defined(FNAME_MK)\" instead.",
 132 "WARN: category/package/filename.mk:12: The \".ifndef\" directive is deprecated. "+
 133 "Please use \".if !defined(FNAME_MK)\" instead.",
 134 "NOTE: category/package/filename.mk:17: Using \".undef\" after a \".for\" loop is unnecessary.")
 135}
 136
 137func (s *Suite) Test_MkLineChecker_checkDirective__for_loop_varname(c *check.C) {
 138 t := s.Init(c)
 139
 140 t.SetupVartypes()
 141
 142 mklines := t.NewMkLines("filename.mk",
 143 MkRcsID,
 144 "",
 145 ".for VAR in a b c", // Should be lowercase.
 146 ".endfor",
100 "", 147 "",
101 ".for VAR in a b c", 148 ".for _var_ in a b c", // Should be written without underscores.
102 ".endfor", 149 ".endfor",
103 "", 150 "",
104 ".for $ in a b c", 151 ".for .var. in a b c", // Should be written without dots.
 152 ".endfor",
 153 "",
 154 ".for ${VAR} in a b c", // The variable name really must be an identifier.
105 ".endfor") 155 ".endfor")
106 156
107 mklines.Check() 157 mklines.Check()
108 158
109 t.CheckOutputLines( 159 t.CheckOutputLines(
110 "ERROR: category/package/filename.mk:3: \".for\" requires arguments.", 160 "WARN: filename.mk:3: The variable name \"VAR\" in the .for loop should not contain uppercase letters.",
111 "ERROR: category/package/filename.mk:6: \".if\" requires arguments.", 161 "WARN: filename.mk:6: Variable names starting with an underscore (_var_) are reserved for internal pkgsrc use.",
112 "ERROR: category/package/filename.mk:7: \".else\" does not take arguments. If you meant \"else if\", use \".elif\".", 162 "ERROR: filename.mk:9: Invalid variable name \".var.\".",
113 "ERROR: category/package/filename.mk:8: \".endif\" does not take arguments.", 163 "ERROR: filename.mk:12: Invalid variable name \"${VAR}\".")
114 "WARN: category/package/filename.mk:10: The \".ifdef\" directive is deprecated. Please use \".if defined(FNAME_MK)\" instead.", 
115 "WARN: category/package/filename.mk:12: The \".ifndef\" directive is deprecated. Please use \".if !defined(FNAME_MK)\" instead.", 
116 "NOTE: category/package/filename.mk:17: Using \".undef\" after a \".for\" loop is unnecessary.", 
117 "WARN: category/package/filename.mk:19: .for variable names should not contain uppercase letters.", 
118 "ERROR: category/package/filename.mk:22: Invalid variable name \"$\".") 
119} 164}
120 165
121func (s *Suite) Test_MkLineChecker_checkDependencyRule(c *check.C) { 166func (s *Suite) Test_MkLineChecker_checkDependencyRule(c *check.C) {
122 t := s.Init(c) 167 t := s.Init(c)
123 168
124 t.SetupVartypes() 169 t.SetupVartypes()
125 170
126 mklines := t.NewMkLines("category/package/filename.mk", 171 mklines := t.NewMkLines("category/package/filename.mk",
127 MkRcsID, 172 MkRcsID,
128 "", 173 "",
129 ".PHONY: target-1", 174 ".PHONY: target-1",
130 "target-2: .PHONY", 175 "target-2: .PHONY",
131 ".ORDER: target-1 target-2", 176 ".ORDER: target-1 target-2",
@@ -135,55 +180,55 @@ func (s *Suite) Test_MkLineChecker_check @@ -135,55 +180,55 @@ func (s *Suite) Test_MkLineChecker_check
135 180
136 mklines.Check() 181 mklines.Check()
137 182
138 t.CheckOutputLines( 183 t.CheckOutputLines(
139 "WARN: category/package/filename.mk:8: Unusual target \"target-3\".") 184 "WARN: category/package/filename.mk:8: Unusual target \"target-3\".")
140} 185}
141 186
142func (s *Suite) Test_MkLineChecker_checkVartype__simple_type(c *check.C) { 187func (s *Suite) Test_MkLineChecker_checkVartype__simple_type(c *check.C) {
143 t := s.Init(c) 188 t := s.Init(c)
144 189
145 t.SetupCommandLine("-Wtypes") 190 t.SetupCommandLine("-Wtypes")
146 t.SetupVartypes() 191 t.SetupVartypes()
147 192
148 vartype1 := G.Pkgsrc.vartypes["COMMENT"] 193 // Since COMMENT is defined in vardefs.go its type is certain instead of guessed.
149 c.Assert(vartype1, check.NotNil) 
150 c.Check(vartype1.guessed, equals, false) 
151 
152 vartype := G.Pkgsrc.VariableType("COMMENT") 194 vartype := G.Pkgsrc.VariableType("COMMENT")
153 195
154 c.Assert(vartype, check.NotNil) 196 c.Assert(vartype, check.NotNil)
155 c.Check(vartype.basicType.name, equals, "Comment") 197 c.Check(vartype.basicType.name, equals, "Comment")
156 c.Check(vartype.guessed, equals, false) 198 c.Check(vartype.guessed, equals, false)
157 c.Check(vartype.kindOfList, equals, lkNone) 199 c.Check(vartype.kindOfList, equals, lkNone)
158 200
159 mkline := t.NewMkLine("Makefile", 123, "COMMENT=\tA nice package") 201 mkline := t.NewMkLine("Makefile", 123, "COMMENT=\tA nice package")
160 MkLineChecker{mkline}.checkVartype(mkline.Varname(), mkline.Op(), mkline.Value(), mkline.VarassignComment()) 202 MkLineChecker{mkline}.checkVartype(mkline.Varname(), mkline.Op(), mkline.Value(), mkline.VarassignComment())
161 203
162 t.CheckOutputLines( 204 t.CheckOutputLines(
163 "WARN: Makefile:123: COMMENT should not begin with \"A\".") 205 "WARN: Makefile:123: COMMENT should not begin with \"A\".")
164} 206}
165 207
166func (s *Suite) Test_MkLineChecker_checkVartype(c *check.C) { 208func (s *Suite) Test_MkLineChecker_checkVartype(c *check.C) {
167 t := s.Init(c) 209 t := s.Init(c)
168 210
169 t.SetupVartypes() 211 t.SetupVartypes()
170 mkline := t.NewMkLine("filename", 1, "DISTNAME=gcc-${GCC_VERSION}") 212 mkline := t.NewMkLine("filename", 1, "DISTNAME=gcc-${GCC_VERSION}")
171 213
172 MkLineChecker{mkline}.checkVartype("DISTNAME", opAssign, "gcc-${GCC_VERSION}", "") 214 MkLineChecker{mkline}.checkVartype("DISTNAME", opAssign, "gcc-${GCC_VERSION}", "")
173 215
174 t.CheckOutputEmpty() 216 t.CheckOutputEmpty()
175} 217}
176 218
 219// The command line option -Wno-types can be used to suppress the type checks.
 220// Suppressing it is rarely needed and comes from Feb 12 2005 when this feature was introduced.
 221// Since then the type system has matured and proven effective.
177func (s *Suite) Test_MkLineChecker_checkVartype__skip(c *check.C) { 222func (s *Suite) Test_MkLineChecker_checkVartype__skip(c *check.C) {
178 t := s.Init(c) 223 t := s.Init(c)
179 224
180 t.SetupCommandLine("-Wno-types") 225 t.SetupCommandLine("-Wno-types")
181 t.SetupVartypes() 226 t.SetupVartypes()
182 mkline := t.NewMkLine("filename", 1, "DISTNAME=invalid:::distname") 227 mkline := t.NewMkLine("filename", 1, "DISTNAME=invalid:::distname")
183 228
184 MkLineChecker{mkline}.Check() 229 MkLineChecker{mkline}.Check()
185 230
186 t.CheckOutputEmpty() 231 t.CheckOutputEmpty()
187} 232}
188 233
189func (s *Suite) Test_MkLineChecker_checkVartype__append_to_non_list(c *check.C) { 234func (s *Suite) Test_MkLineChecker_checkVartype__append_to_non_list(c *check.C) {
@@ -207,96 +252,84 @@ func (s *Suite) Test_MkLineChecker_check @@ -207,96 +252,84 @@ func (s *Suite) Test_MkLineChecker_check
207// splitting this URL at the ampersand. 252// splitting this URL at the ampersand.
208func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) { 253func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
209 t := s.Init(c) 254 t := s.Init(c)
210 255
211 G.Pkg = NewPackage(t.File("graphics/gimp-fix-ca")) 256 G.Pkg = NewPackage(t.File("graphics/gimp-fix-ca"))
212 t.SetupVartypes() 257 t.SetupVartypes()
213 mkline := t.NewMkLine("filename", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=") 258 mkline := t.NewMkLine("filename", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=")
214 259
215 MkLineChecker{mkline}.checkVarassign() 260 MkLineChecker{mkline}.checkVarassign()
216 261
217 t.CheckOutputEmpty() 262 t.CheckOutputEmpty()
218} 263}
219 264
220func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) { 265func (s *Suite) Test_MkLineChecker_checkDirectiveCond(c *check.C) {
221 t := s.Init(c) 266 t := s.Init(c)
222 267
223 t.SetupCommandLine("-Wtypes") 268 t.SetupCommandLine("-Wtypes")
224 t.SetupVartypes() 269 t.SetupVartypes()
225 270
226 testCond := func(cond string, output ...string) { 271 testCond := func(cond string, output ...string) {
227 MkLineChecker{t.NewMkLine("filename", 1, cond)}.checkDirectiveCond() 272 MkLineChecker{t.NewMkLine("filename", 1, cond)}.checkDirectiveCond()
228 if len(output) > 0 { 273 if len(output) > 0 {
229 t.CheckOutputLines(output...) 274 t.CheckOutputLines(output...)
230 } else { 275 } else {
231 t.CheckOutputEmpty() 276 t.CheckOutputEmpty()
232 } 277 }
233 } 278 }
234 279
235 testCond(".if !empty(PKGSRC_COMPILER:Mmycc)", 280 testCond(".if !empty(PKGSRC_COMPILER:Mmycc)",
236 "WARN: filename:1: The pattern \"mycc\" cannot match any of "+ 281 "WARN: filename:1: The pattern \"mycc\" cannot match any of "+
237 "{ ccache ccc clang distcc f2c gcc hp icc ido "+ 282 "{ ccache ccc clang distcc f2c gcc hp icc ido "+
238 "mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.") 283 "mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.")
239 284
240 testCond(".elif ${A} != ${B}") 285 testCond(".elif ${A} != ${B}")
241 286
242 testCond(".if ${HOMEPAGE} == \"mailto:someone@example.org\"", 287 testCond(".if ${HOMEPAGE} == \"mailto:someone@example.org\"",
243 "WARN: filename:1: \"mailto:someone@example.org\" is not a valid URL.") 288 "WARN: filename:1: \"mailto:someone@example.org\" is not a valid URL.")
244 289
245 testCond(".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])", 290 testCond(".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])",
246 "WARN: filename:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".") 291 "WARN: filename:1: PKGSRC_RUN_TEST should be matched "+
 292 "against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
247 293
248 testCond(".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])") 294 testCond(".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")
249 295
250 testCond(".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})", 296 testCond(".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})",
251 "WARN: filename:1: The empty() function takes a variable name as parameter, not a variable expression.") 297 "WARN: filename:1: The empty() function takes a variable name as parameter, "+
 298 "not a variable expression.")
252 299
253 testCond(".if ${EMUL_PLATFORM} == \"linux-x386\"", 300 testCond(".if ${PKGSRC_COMPILER} == \"msvc\"",
254 "WARN: filename:1: "+ 301 "WARN: filename:1: \"msvc\" is not valid for PKGSRC_COMPILER. "+
255 "\"x386\" is not valid for the hardware architecture part of EMUL_PLATFORM. "+ 302 "Use one of { ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc } instead.",
256 "Use one of "+ 303 "WARN: filename:1: Use ${PKGSRC_COMPILER:Mmsvc} instead of the == operator.")
257 "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex "+ 
258 "dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb "+ 
259 "earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 "+ 
260 "i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 "+ 
261 "mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+ 
262 "} instead.") 
263 304
264 testCond(".if ${EMUL_PLATFORM:Mlinux-x386}", 305 testCond(".if ${PKG_LIBTOOL:Mlibtool}",
265 "WARN: filename:1: "+ 306 "NOTE: filename:1: PKG_LIBTOOL should be compared using == instead of matching against \":Mlibtool\".")
266 "The pattern \"x386\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 "+ 
267 "arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb "+ 
268 "earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf "+ 
269 "earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k "+ 
270 "mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 "+ 
271 "rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } "+ 
272 "for the hardware architecture part of EMUL_PLATFORM.", 
273 "NOTE: filename:1: EMUL_PLATFORM should be compared using == instead of the :M or :N modifier without wildcards.") 
274 307
275 testCond(".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}", 308 testCond(".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}",
276 "WARN: filename:1: "+ 309 "WARN: filename:1: "+
277 "The pattern \"UnknownOS\" cannot match any of "+ 310 "The pattern \"UnknownOS\" cannot match any of "+
278 "{ AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku "+ 311 "{ AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku "+
279 "IRIX Interix Linux Minix MirBSD NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare "+ 312 "IRIX Interix Linux Minix MirBSD NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare "+
280 "} for the operating system part of MACHINE_PLATFORM.", 313 "} for the operating system part of MACHINE_PLATFORM.",
281 "WARN: filename:1: "+ 314 "WARN: filename:1: "+
282 "The pattern \"x86\" cannot match any of "+ 315 "The pattern \"x86\" cannot match any of "+
283 "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm "+ 316 "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm "+
284 "earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb "+ 317 "earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb "+
285 "earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 "+ 318 "earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 "+
286 "m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax "+ 319 "m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax "+
287 "powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+ 320 "powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
288 "} for MACHINE_ARCH.", 321 "} for MACHINE_ARCH.",
289 "NOTE: filename:1: MACHINE_ARCH should be compared using == instead of the :M or :N modifier without wildcards.") 322 "NOTE: filename:1: MACHINE_ARCH should be compared using == instead of matching against \":Mx86\".")
290 323
291 testCond(".if ${MASTER_SITES:Mftp://*} == \"ftp://netbsd.org/\"") 324 testCond(".if ${MASTER_SITES:Mftp://*} == \"ftp://netbsd.org/\"")
292} 325}
293 326
294func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) { 327func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) {
295 t := s.Init(c) 328 t := s.Init(c)
296 329
297 t.SetupVartypes() 330 t.SetupVartypes()
298 331
299 G.Mk = t.NewMkLines("Makefile", 332 G.Mk = t.NewMkLines("Makefile",
300 MkRcsID, 333 MkRcsID,
301 "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8 334 "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8
302 335
@@ -376,31 +409,30 @@ func (s *Suite) Test_MkLineChecker_check @@ -376,31 +409,30 @@ func (s *Suite) Test_MkLineChecker_check
376 409
377func (s *Suite) Test_MkLineChecker_checkVarusePermissions__load_time(c *check.C) { 410func (s *Suite) Test_MkLineChecker_checkVarusePermissions__load_time(c *check.C) {
378 t := s.Init(c) 411 t := s.Init(c)
379 412
380 t.SetupVartypes() 413 t.SetupVartypes()
381 mklines := t.NewMkLines("options.mk", 414 mklines := t.NewMkLines("options.mk",
382 MkRcsID, 415 MkRcsID,
383 "WRKSRC:=${.CURDIR}", 416 "WRKSRC:=${.CURDIR}",
384 ".if ${PKG_SYSCONFDIR.gdm} != \"etc\"", 417 ".if ${PKG_SYSCONFDIR.gdm} != \"etc\"",
385 ".endif") 418 ".endif")
386 419
387 mklines.Check() 420 mklines.Check()
388 421
389 // Evaluating PKG_SYSCONFDIR.* at load time is probably ok, though 422 // Evaluating PKG_SYSCONFDIR.* at load time is probably ok,
390 // pkglint cannot prove anything here. 423 // though pkglint cannot prove anything here.
391 // 424 //
392 // Evaluating .CURDIR at load time is ok since it is defined from 425 // Evaluating .CURDIR at load time is definitely ok since it is defined from the beginning.
393 // the beginning. 
394 t.CheckOutputLines( 426 t.CheckOutputLines(
395 "NOTE: options.mk:2: This variable value should be aligned to column 17.") 427 "NOTE: options.mk:2: This variable value should be aligned to column 17.")
396} 428}
397 429
398func (s *Suite) Test_MkLineChecker_checkVarusePermissions__load_time_guessed(c *check.C) { 430func (s *Suite) Test_MkLineChecker_checkVarusePermissions__load_time_guessed(c *check.C) {
399 t := s.Init(c) 431 t := s.Init(c)
400 432
401 t.SetupVartypes() 433 t.SetupVartypes()
402 t.SetupTool("install", "", AtRunTime) 434 t.SetupTool("install", "", AtRunTime)
403 mklines := t.NewMkLines("install-docfiles.mk", 435 mklines := t.NewMkLines("install-docfiles.mk",
404 MkRcsID, 436 MkRcsID,
405 "DOCFILES=\ta b c", 437 "DOCFILES=\ta b c",
406 "do-install:", 438 "do-install:",
@@ -428,97 +460,155 @@ func (s *Suite) Test_MkLineChecker_check @@ -428,97 +460,155 @@ func (s *Suite) Test_MkLineChecker_check
428 mklines := t.NewMkLines("any.mk", 460 mklines := t.NewMkLines("any.mk",
429 MkRcsID, 461 MkRcsID,
430 // PKGREVISION may only be set in Makefile, not used at load time; see vardefs.go. 462 // PKGREVISION may only be set in Makefile, not used at load time; see vardefs.go.
431 ".if defined(PKGREVISION)", 463 ".if defined(PKGREVISION)",
432 ".endif") 464 ".endif")
433 465
434 mklines.Check() 466 mklines.Check()
435 467
436 t.CheckOutputLines( 468 t.CheckOutputLines(
437 "WARN: any.mk:2: PKGREVISION should not be evaluated at load time.", 469 "WARN: any.mk:2: PKGREVISION should not be evaluated at load time.",
438 "WARN: any.mk:2: PKGREVISION may not be used in any file; it is a write-only variable.") 470 "WARN: any.mk:2: PKGREVISION may not be used in any file; it is a write-only variable.")
439} 471}
440 472
441func (s *Suite) Test_MkLineChecker__warn_varuse_LOCALBASE(c *check.C) { 473func (s *Suite) Test_MkLineChecker_Check__warn_varuse_LOCALBASE(c *check.C) {
442 t := s.Init(c) 474 t := s.Init(c)
443 475
444 t.SetupVartypes() 476 t.SetupVartypes()
445 mkline := t.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}") 477 mkline := t.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}")
446 478
447 MkLineChecker{mkline}.Check() 479 MkLineChecker{mkline}.Check()
448 480
449 t.CheckOutputLines( 481 t.CheckOutputLines(
450 "WARN: options.mk:56: Please use PREFIX instead of LOCALBASE.") 482 "WARN: options.mk:56: Please use PREFIX instead of LOCALBASE.")
451} 483}
452 484
453func (s *Suite) Test_MkLineChecker_CheckRelativePkgdir(c *check.C) { 485func (s *Suite) Test_MkLineChecker_CheckRelativePkgdir(c *check.C) {
454 t := s.Init(c) 486 t := s.Init(c)
455 487
456 mklines := t.SetupFileMkLines("Makefile", 488 t.CreateFileLines("other/package/Makefile")
 489 // Must be in the filesystem because of directory references.
 490 mklines := t.SetupFileMkLines("category/package/Makefile",
457 "# dummy") 491 "# dummy")
 492 ck := MkLineChecker{mklines.mklines[0]}
458 493
459 MkLineChecker{mklines.mklines[0]}.CheckRelativePkgdir("../pkgbase") 494 ck.CheckRelativePkgdir("../pkgbase")
460 495 ck.CheckRelativePkgdir("../../other/package")
461 t.CheckOutputLines( 496 ck.CheckRelativePkgdir("../../other/does-not-exist")
462 "ERROR: ~/Makefile:1: \"../pkgbase\" does not exist.", 497
463 "WARN: ~/Makefile:1: \"../pkgbase\" is not a valid relative package directory.") 498 // FIXME: The diagnostics for does-not-exist are redundant.
 499 t.CheckOutputLines(
 500 "ERROR: ~/category/package/Makefile:1: Relative path \"../pkgbase\" does not exist.",
 501 "WARN: ~/category/package/Makefile:1: \"../pkgbase\" is not a valid relative package directory.",
 502 "ERROR: ~/category/package/Makefile:1: Relative path \"../../other/does-not-exist\" does not exist.",
 503 "ERROR: ~/category/package/Makefile:1: There is no package in \"other/does-not-exist\".")
464} 504}
465 505
466// PR pkg/46570, item 2 506// PR pkg/46570, item 2
467func (s *Suite) Test_MkLineChecker__unclosed_varuse(c *check.C) { 507func (s *Suite) Test_MkLineChecker__unclosed_varuse(c *check.C) {
468 t := s.Init(c) 508 t := s.Init(c)
469 509
470 mklines := t.NewMkLines("Makefile", 510 mklines := t.NewMkLines("Makefile",
471 MkRcsID, 511 MkRcsID,
472 "EGDIRS=\t${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d") 512 "EGDIRS=\t${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d")
473 513
474 mklines.Check() 514 mklines.Check()
475 515
476 t.CheckOutputLines( 516 t.CheckOutputLines(
477 "WARN: Makefile:2: Unclosed Make variable starting at \"${EGDIR/apparmor.d $...\".", 517 "WARN: Makefile:2: Unclosed Make variable starting at \"${EGDIR/apparmor.d $...\".",
478 "WARN: Makefile:2: EGDIRS is defined but not used.", 518 "WARN: Makefile:2: EGDIRS is defined but not used.",
 519
 520 // XXX: This warning is redundant because of the "Unclosed" warning above.
479 "WARN: Makefile:2: Pkglint parse error in MkLine.Tokenize at "+ 521 "WARN: Makefile:2: Pkglint parse error in MkLine.Tokenize at "+
480 "\"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".") 522 "\"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".")
481} 523}
482 524
483func (s *Suite) Test_MkLineChecker__Varuse_Modifier_L(c *check.C) { 525func (s *Suite) Test_MkLineChecker_Check__varuse_modifier_L(c *check.C) {
484 t := s.Init(c) 526 t := s.Init(c)
485 527
486 t.SetupVartypes() 528 t.SetupVartypes()
487 G.Mk = t.NewMkLines("x11/xkeyboard-config/Makefile", 529 mklines := t.NewMkLines("x11/xkeyboard-config/Makefile",
488 "FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}") 530 "FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}",
 531 "FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:Q}")
489 532
490 MkLineChecker{G.Mk.mklines[0]}.Check() 533 MkLineChecker{mklines.mklines[0]}.Check()
 534 MkLineChecker{mklines.mklines[1]}.Check()
491 535
492 // Don't warn that ${XKBBASE}/xkbcomp is used but not defined. 536 // In line 1, don't warn that ${XKBBASE}/xkbcomp is used but not defined.
493 t.CheckOutputEmpty() 537 // This is because the :L modifier interprets everything before as an expression
 538 // instead of a variable name.
 539 //
 540 // In line 2 the :L modifier is missing, therefore ${XKBBASE}/xkbcomp is the
 541 // name of another variable, and that variable is not known. Only XKBBASE is known.
 542 //
 543 // FIXME: The below warnings are wrong because the MkParser does not recognize the
 544 // slash as part of a variable name. Because of that, parsing stops before the $.
 545 // The warning "Unclosed Make variable" wrongly assumes that any parse error from
 546 // a variable use is because of unclosed braces, which it isn't in this case.h
 547 t.CheckOutputLines(
 548 "WARN: x11/xkeyboard-config/Makefile:2: Unclosed Make variable starting at \"${${XKBBASE}/xkbcomp...\".",
 549 "WARN: x11/xkeyboard-config/Makefile:2: Unclosed Make variable starting at \"${${XKBBASE}/xkbcomp...\".")
494} 550}
495 551
496func (s *Suite) Test_MkLineChecker_checkDirectiveCond__comparison_with_shell_command(c *check.C) { 552func (s *Suite) Test_MkLineChecker_checkDirectiveCond__comparison_with_shell_command(c *check.C) {
497 t := s.Init(c) 553 t := s.Init(c)
498 554
499 t.SetupVartypes() 555 t.SetupVartypes()
500 G.Mk = t.NewMkLines("security/openssl/Makefile", 556 mklines := t.NewMkLines("security/openssl/Makefile",
501 MkRcsID, 557 MkRcsID,
502 ".if ${PKGSRC_COMPILER} == \"gcc\" && ${CC} == \"cc\"", 558 ".if ${PKGSRC_COMPILER} == \"gcc\" && ${CC} == \"cc\"",
503 ".endif") 559 ".endif")
504 560
505 G.Mk.Check() 561 mklines.Check()
506 562
507 // Don't warn about unknown shell command "cc". 563 // Don't warn about unknown shell command "cc".
508 t.CheckOutputLines( 564 t.CheckOutputLines(
509 "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.") 565 "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.")
510} 566}
511 567
 568func (s *Suite) Test_MkLineChecker_checkDirectiveCondEmpty(c *check.C) {
 569 t := s.Init(c)
 570
 571 t.SetupVartypes()
 572 mkline := t.NewMkLine("module.mk", 123, ".if ${PKGPATH} == \"category/package\"")
 573 ck := MkLineChecker{mkline}
 574
 575 // FIXME: checkDirectiveCondEmpty cannot know whether it is empty(...) or !empty(...).
 576 // It must know that to generate the proper diagnostics.
 577
 578 ck.checkDirectiveCondEmpty(NewMkVarUse("PKGPATH", "Mpattern"))
 579
 580 // When the pattern contains placeholders, it cannot be converted to == or !=.
 581 ck.checkDirectiveCondEmpty(NewMkVarUse("PKGPATH", "Mpa*n"))
 582
 583 ck.checkDirectiveCondEmpty(NewMkVarUse("PKGPATH", "tl", "Mpattern"))
 584
 585 ck.checkDirectiveCondEmpty(NewMkVarUse("PKGPATH", "Ncategory/package"))
 586
 587 // ${PKGPATH:None:Ntwo} is a short variant of ${PKGPATH} != "one" && ${PKGPATH} != "two",
 588 // therefore no note is logged in this case.
 589 ck.checkDirectiveCondEmpty(NewMkVarUse("PKGPATH", "None", "Ntwo"))
 590
 591 // Note: this combination doesn't make sense since the patterns "one" and "two" don't overlap.
 592 ck.checkDirectiveCondEmpty(NewMkVarUse("PKGPATH", "Mone", "Mtwo"))
 593
 594 t.CheckOutputLines(
 595 "NOTE: module.mk:123: PKGPATH should be compared using == instead of matching against \":Mpattern\".",
 596 "NOTE: module.mk:123: PKGPATH should be compared using == instead of matching against \":Mpattern\".",
 597 "NOTE: module.mk:123: PKGPATH should be compared using != instead of matching against \":Ncategory/package\".",
 598 "NOTE: module.mk:123: PKGPATH should be compared using == instead of matching against \":Mone\".",
 599 "NOTE: module.mk:123: PKGPATH should be compared using == instead of matching against \":Mtwo\".")
 600}
 601
512func (s *Suite) Test_MkLineChecker_checkDirectiveCond__comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) { 602func (s *Suite) Test_MkLineChecker_checkDirectiveCond__comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) {
513 t := s.Init(c) 603 t := s.Init(c)
514 604
515 t.SetupVartypes() 605 t.SetupVartypes()
516 G.Mk = t.NewMkLines("audio/pulseaudio/Makefile", 606 G.Mk = t.NewMkLines("audio/pulseaudio/Makefile",
517 MkRcsID, 607 MkRcsID,
518 ".if ${OPSYS} == \"Darwin\" && ${PKGSRC_COMPILER} == \"clang\"", 608 ".if ${OPSYS} == \"Darwin\" && ${PKGSRC_COMPILER} == \"clang\"",
519 ".endif") 609 ".endif")
520 610
521 G.Mk.Check() 611 G.Mk.Check()
522 612
523 t.CheckOutputLines( 613 t.CheckOutputLines(
524 "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.") 614 "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.")
@@ -528,27 +618,28 @@ func (s *Suite) Test_MkLineChecker_check @@ -528,27 +618,28 @@ func (s *Suite) Test_MkLineChecker_check
528 t := s.Init(c) 618 t := s.Init(c)
529 619
530 t.SetupVartypes() 620 t.SetupVartypes()
531 G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile", 621 G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile",
532 MkRcsID, 622 MkRcsID,
533 "CFLAGS+=\t`pkg-config pidgin --cflags`") 623 "CFLAGS+=\t`pkg-config pidgin --cflags`")
534 mkline := G.Mk.mklines[1] 624 mkline := G.Mk.mklines[1]
535 625
536 words, rest := splitIntoMkWords(mkline.Line, mkline.Value()) 626 words, rest := splitIntoMkWords(mkline.Line, mkline.Value())
537 627
538 c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"}) 628 c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"})
539 c.Check(rest, equals, "") 629 c.Check(rest, equals, "")
540 630
541 MkLineChecker{G.Mk.mklines[1]}.checkVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "") 631 ck := MkLineChecker{G.Mk.mklines[1]}
 632 ck.checkVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "")
542 633
543 // No warning about "`pkg-config" being an unknown CFlag. 634 // No warning about "`pkg-config" being an unknown CFlag.
544 t.CheckOutputEmpty() 635 t.CheckOutputEmpty()
545} 636}
546 637
547// See PR 46570, Ctrl+F "4. Shell quoting". 638// See PR 46570, Ctrl+F "4. Shell quoting".
548// Pkglint is correct, since the shell sees this definition for 639// Pkglint is correct, since the shell sees this definition for
549// CPPFLAGS as three words, not one word. 640// CPPFLAGS as three words, not one word.
550func (s *Suite) Test_MkLineChecker_checkVartype__CFLAGS(c *check.C) { 641func (s *Suite) Test_MkLineChecker_checkVartype__CFLAGS(c *check.C) {
551 t := s.Init(c) 642 t := s.Init(c)
552 643
553 t.SetupVartypes() 644 t.SetupVartypes()
554 mklines := t.NewMkLines("Makefile", 645 mklines := t.NewMkLines("Makefile",
@@ -730,26 +821,30 @@ func (s *Suite) Test_MkLineChecker_Check @@ -730,26 +821,30 @@ func (s *Suite) Test_MkLineChecker_Check
730 kindOfList: lkNone, 821 kindOfList: lkNone,
731 basicType: BtPathname, 822 basicType: BtPathname,
732 aclEntries: nil, 823 aclEntries: nil,
733 guessed: true, 824 guessed: true,
734 }, 825 },
735 time: vucTimeRun, 826 time: vucTimeRun,
736 quoting: vucQuotPlain, 827 quoting: vucQuotPlain,
737 IsWordPart: false, 828 IsWordPart: false,
738 }) 829 })
739 830
740 t.CheckOutputEmpty() 831 t.CheckOutputEmpty()
741} 832}
742 833
 834// Any variable that is defined in the pkgsrc infrastructure in mk/**/*.mk is
 835// considered defined, and no "used but not defined" warning is logged for it.
 836//
 837// See Pkgsrc.loadUntypedVars.
743func (s *Suite) Test_MkLineChecker_CheckVaruse__defined_in_infrastructure(c *check.C) { 838func (s *Suite) Test_MkLineChecker_CheckVaruse__defined_in_infrastructure(c *check.C) {
744 t := s.Init(c) 839 t := s.Init(c)
745 840
746 t.SetupPkgsrc() 841 t.SetupPkgsrc()
747 t.SetupVartypes() 842 t.SetupVartypes()
748 t.CreateFileLines("mk/deeply/nested/infra.mk", 843 t.CreateFileLines("mk/deeply/nested/infra.mk",
749 MkRcsID, 844 MkRcsID,
750 "INFRA_VAR?=\tvalue") 845 "INFRA_VAR?=\tvalue")
751 G.Pkgsrc.LoadInfrastructure() 846 G.Pkgsrc.LoadInfrastructure()
752 mklines := t.SetupFileMkLines("category/package/module.mk", 847 mklines := t.SetupFileMkLines("category/package/module.mk",
753 MkRcsID, 848 MkRcsID,
754 "do-fetch:", 849 "do-fetch:",
755 "\t: ${INFRA_VAR} ${UNDEFINED}") 850 "\t: ${INFRA_VAR} ${UNDEFINED}")
@@ -786,70 +881,72 @@ func (s *Suite) Test_MkLineChecker_Check @@ -786,70 +881,72 @@ func (s *Suite) Test_MkLineChecker_Check
786 881
787func (s *Suite) Test_MkLineChecker_CheckVaruse__complicated_range(c *check.C) { 882func (s *Suite) Test_MkLineChecker_CheckVaruse__complicated_range(c *check.C) {
788 t := s.Init(c) 883 t := s.Init(c)
789 884
790 t.SetupCommandLine("--show-autofix", "--source") 885 t.SetupCommandLine("--show-autofix", "--source")
791 t.SetupVartypes() 886 t.SetupVartypes()
792 mkline := t.NewMkLine("mk/compiler/gcc.mk", 150, 887 mkline := t.NewMkLine("mk/compiler/gcc.mk", 150,
793 "CC:=\t${CC:C/^/_asdf_/1:M_asdf_*:S/^_asdf_//}") 888 "CC:=\t${CC:C/^/_asdf_/1:M_asdf_*:S/^_asdf_//}")
794 889
795 MkLineChecker{mkline}.Check() 890 MkLineChecker{mkline}.Check()
796 891
797 // FIXME: The check is called two times, even though it only produces a single NOTE. 892 // FIXME: The check is called two times, even though it only produces a single NOTE.
798 t.CheckOutputLines( 893 t.CheckOutputLines(
799 "NOTE: mk/compiler/gcc.mk:150: The modifier \":C/^/_asdf_/1:M_asdf_*:S/^_asdf_//\" can be written as \":[1]\".", 894 "NOTE: mk/compiler/gcc.mk:150: "+
800 "AUTOFIX: mk/compiler/gcc.mk:150: Replacing \":C/^/_asdf_/1:M_asdf_*:S/^_asdf_//\" with \":[1]\".", 895 "The modifier \":C/^/_asdf_/1:M_asdf_*:S/^_asdf_//\" can be written as \":[1]\".",
 896 "AUTOFIX: mk/compiler/gcc.mk:150: "+
 897 "Replacing \":C/^/_asdf_/1:M_asdf_*:S/^_asdf_//\" with \":[1]\".",
801 "-\tCC:=\t${CC:C/^/_asdf_/1:M_asdf_*:S/^_asdf_//}", 898 "-\tCC:=\t${CC:C/^/_asdf_/1:M_asdf_*:S/^_asdf_//}",
802 "+\tCC:=\t${CC:[1]}") 899 "+\tCC:=\t${CC:[1]}")
803} 900}
804 901
805func (s *Suite) Test_MkLineChecker_CheckVaruse__deprecated_PKG_DEBUG(c *check.C) { 902func (s *Suite) Test_MkLineChecker_CheckVaruse__deprecated_PKG_DEBUG(c *check.C) {
806 t := s.Init(c) 903 t := s.Init(c)
807 904
808 t.SetupVartypes() 905 t.SetupVartypes()
809 G.Pkgsrc.initDeprecatedVars() 906 G.Pkgsrc.initDeprecatedVars()
810 907
811 mkline := t.NewMkLine("module.mk", 123, 908 mkline := t.NewMkLine("module.mk", 123,
812 "\t${_PKG_SILENT}${_PKG_DEBUG} :") 909 "\t${_PKG_SILENT}${_PKG_DEBUG} :")
813 910
814 MkLineChecker{mkline}.Check() 911 MkLineChecker{mkline}.Check()
815 912
816 t.CheckOutputLines( 913 t.CheckOutputLines(
817 "WARN: module.mk:123: Use of \"_PKG_SILENT\" is deprecated. Use RUN (with more error checking) instead.", 914 "WARN: module.mk:123: Use of \"_PKG_SILENT\" is deprecated. Use RUN (with more error checking) instead.",
818 "WARN: module.mk:123: Use of \"_PKG_DEBUG\" is deprecated. Use RUN (with more error checking) instead.") 915 "WARN: module.mk:123: Use of \"_PKG_DEBUG\" is deprecated. Use RUN (with more error checking) instead.")
819} 916}
820 917
821func (s *Suite) Test_MkLineChecker_checkVarassignSpecific(c *check.C) { 918func (s *Suite) Test_MkLineChecker_checkVarassignSpecific(c *check.C) {
822 t := s.Init(c) 919 t := s.Init(c)
823 920
824 t.SetupPkgsrc() 921 t.SetupPkgsrc()
825 G.Pkgsrc.LoadInfrastructure() 922 G.Pkgsrc.LoadInfrastructure()
826 
827 t.SetupCommandLine("-Wall,no-space") 923 t.SetupCommandLine("-Wall,no-space")
828 t.SetupVartypes() 924 t.SetupVartypes()
829 mklines := t.SetupFileMkLines("module.mk", 925 mklines := t.SetupFileMkLines("module.mk",
830 MkRcsID, 926 MkRcsID,
831 "EGDIR= ${PREFIX}/etc/rc.d", 927 "EGDIR= ${PREFIX}/etc/rc.d",
832 "_TOOLS_VARNAME.sed= SED", 928 "_TOOLS_VARNAME.sed= SED",
833 "DIST_SUBDIR= ${PKGNAME}", 929 "DIST_SUBDIR= ${PKGNAME}",
834 "WRKSRC= ${PKGNAME}", 930 "WRKSRC= ${PKGNAME}",
835 "SITES_distfile.tar.gz= ${MASTER_SITE_GITHUB:=user/}", 931 "SITES_distfile.tar.gz= ${MASTER_SITE_GITHUB:=user/}",
836 // TODO: The first of the below assignments should be flagged as redundant by RedundantScope; 932 // TODO: The first of the below assignments should be flagged as redundant by RedundantScope;
837 // that check is currently only implemented for package Makefiles, not for other files. 933 // that check is currently only implemented for package Makefiles, not for other files.
838 "PYTHON_VERSIONS_ACCEPTED= -13", 934 "PYTHON_VERSIONS_ACCEPTED= -13",
839 "PYTHON_VERSIONS_ACCEPTED= 27 36") 935 "PYTHON_VERSIONS_ACCEPTED= 27 36")
840 936
841 mklines.Check() 937 mklines.Check()
842 938
 939 // TODO: Split this test into several, one for each topic.
843 t.CheckOutputLines( 940 t.CheckOutputLines(
844 "WARN: ~/module.mk:2: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.", 941 "WARN: ~/module.mk:2: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.",
845 "WARN: ~/module.mk:3: _TOOLS_VARNAME.sed is defined but not used.", 942 "WARN: ~/module.mk:3: _TOOLS_VARNAME.sed is defined but not used.",
846 "WARN: ~/module.mk:3: Variable names starting with an underscore (_TOOLS_VARNAME.sed) are reserved for internal pkgsrc use.", 943 "WARN: ~/module.mk:3: Variable names starting with an underscore (_TOOLS_VARNAME.sed) are reserved for internal pkgsrc use.",
847 "WARN: ~/module.mk:4: PKGNAME should not be used in DIST_SUBDIR as it includes the PKGREVISION. Please use PKGNAME_NOREV instead.", 944 "WARN: ~/module.mk:4: PKGNAME should not be used in DIST_SUBDIR as it includes the PKGREVISION. Please use PKGNAME_NOREV instead.",
848 "WARN: ~/module.mk:5: PKGNAME should not be used in WRKSRC as it includes the PKGREVISION. Please use PKGNAME_NOREV instead.", 945 "WARN: ~/module.mk:5: PKGNAME should not be used in WRKSRC as it includes the PKGREVISION. Please use PKGNAME_NOREV instead.",
849 "WARN: ~/module.mk:6: SITES_distfile.tar.gz is defined but not used.", 946 "WARN: ~/module.mk:6: SITES_distfile.tar.gz is defined but not used.",
850 "WARN: ~/module.mk:6: SITES_* is deprecated. Please use SITES.* instead.", 947 "WARN: ~/module.mk:6: SITES_* is deprecated. Please use SITES.* instead.",
851 "WARN: ~/module.mk:7: The variable PYTHON_VERSIONS_ACCEPTED may not be set "+ 948 "WARN: ~/module.mk:7: The variable PYTHON_VERSIONS_ACCEPTED may not be set "+
852 "(only given a default value, appended to) in this file; it would be ok in Makefile, Makefile.common, options.mk.", 949 "(only given a default value, appended to) in this file; it would be ok in Makefile, Makefile.common, options.mk.",
853 "WARN: ~/module.mk:7: Invalid version number \"-13\".", 950 "WARN: ~/module.mk:7: Invalid version number \"-13\".",
854 "ERROR: ~/module.mk:7: All values for PYTHON_VERSIONS_ACCEPTED must be positive integers.", 951 "ERROR: ~/module.mk:7: All values for PYTHON_VERSIONS_ACCEPTED must be positive integers.",
855 "WARN: ~/module.mk:8: The variable PYTHON_VERSIONS_ACCEPTED may not be set "+ 952 "WARN: ~/module.mk:8: The variable PYTHON_VERSIONS_ACCEPTED may not be set "+
@@ -922,15 +1019,16 @@ func (s *Suite) Test_MkLineChecker_Check @@ -922,15 +1019,16 @@ func (s *Suite) Test_MkLineChecker_Check
922 ".include \"../../lang/${LATEST_PYTHON}/module.mk\"", 1019 ".include \"../../lang/${LATEST_PYTHON}/module.mk\"",
923 "", 1020 "",
924 ".include \"module.mk\"", 1021 ".include \"module.mk\"",
925 ".include \"../../category/../category/package/module.mk\"", // Oops 1022 ".include \"../../category/../category/package/module.mk\"", // Oops
926 ".include \"../../mk/bsd.prefs.mk\"", 1023 ".include \"../../mk/bsd.prefs.mk\"",
927 ".include \"../package/module.mk\"") 1024 ".include \"../package/module.mk\"")
928 1025
929 mklines.Check() 1026 mklines.Check()
930 1027
931 t.CheckOutputLines( 1028 t.CheckOutputLines(
932 "ERROR: ~/category/package/module.mk:2: A main pkgsrc package must not depend on a pkgsrc-wip package.", 1029 "ERROR: ~/category/package/module.mk:2: A main pkgsrc package must not depend on a pkgsrc-wip package.",
933 "ERROR: ~/category/package/module.mk:3: A main pkgsrc package must not depend on a pkgsrc-wip package.", 1030 "ERROR: ~/category/package/module.mk:3: A main pkgsrc package must not depend on a pkgsrc-wip package.",
934 "WARN: ~/category/package/module.mk:5: LATEST_PYTHON is used but not defined.", 1031 "WARN: ~/category/package/module.mk:5: LATEST_PYTHON is used but not defined.",
 1032 // TODO: This warning is unspecific, there is also a pkglint warning "should be ../../category/package".
935 "WARN: ~/category/package/module.mk:11: Invalid relative path \"../package/module.mk\".") 1033 "WARN: ~/category/package/module.mk:11: Invalid relative path \"../package/module.mk\".")
936} 1034}

cvs diff -r1.35 -r1.36 pkgsrc/pkgtools/pkglint/files/Attic/mklines.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mklines.go 2018/12/02 01:57:48 1.35
+++ pkgsrc/pkgtools/pkglint/files/Attic/mklines.go 2018/12/02 23:12:43 1.36
@@ -1,147 +1,165 @@ @@ -1,147 +1,165 @@
1package main 1package main
2 2
3import ( 3import (
4 "strings" 4 "strings"
5) 5)
6 6
7// MkLines contains data for the Makefile (or *.mk) that is currently checked. 7// MkLines contains data for the Makefile (or *.mk) that is currently checked.
8type MkLines = *MkLinesImpl 8type MkLines = *MkLinesImpl
9 9
10type MkLinesImpl struct { 10type MkLinesImpl struct {
11 mklines []MkLine 11 mklines []MkLine
12 lines Lines 12 lines Lines
13 forVars map[string]bool // The variables currently used in .for loops 13 target string // Current make(1) target; only available during checkAll
14 target string // Current make(1) target 14 vars Scope //
15 vars Scope 
16 buildDefs map[string]bool // Variables that are registered in BUILD_DEFS, to ensure that all user-defined variables are added to it. 15 buildDefs map[string]bool // Variables that are registered in BUILD_DEFS, to ensure that all user-defined variables are added to it.
17 plistVarAdded map[string]MkLine // Identifiers that are added to PLIST_VARS. 16 plistVarAdded map[string]MkLine // Identifiers that are added to PLIST_VARS.
18 plistVarSet map[string]MkLine // Identifiers for which PLIST.${id} is defined. 17 plistVarSet map[string]MkLine // Identifiers for which PLIST.${id} is defined.
19 plistVarSkip bool // True if any of the PLIST_VARS identifiers refers to a variable. 18 plistVarSkip bool // True if any of the PLIST_VARS identifiers refers to a variable.
20 Tools *Tools // Tools defined in file scope. 19 Tools *Tools // Tools defined in file scope.
21 indentation *Indentation // Indentation depth of preprocessing directives; only available during MkLines.ForEach. 20 indentation *Indentation // Indentation depth of preprocessing directives; only available during MkLines.ForEach.
 21 forVars map[string]bool // The variables currently used in .for loops; only available during MkLines.checkAll.
22 Once 22 Once
 23
 24 // TODO: Consider extracting plistVarAdded, plistVarSet, plistVarSkip into an own type.
 25 // TODO: Describe where each of the above fields is valid.
23} 26}
24 27
25func NewMkLines(lines Lines) MkLines { 28func NewMkLines(lines Lines) MkLines {
26 mklines := make([]MkLine, lines.Len()) 29 mklines := make([]MkLine, lines.Len())
27 for i, line := range lines.Lines { 30 for i, line := range lines.Lines {
28 mklines[i] = NewMkLine(line) 31 mklines[i] = NewMkLine(line)
29 } 32 }
30 33
31 tools := NewTools(lines.FileName) 34 tools := NewTools(lines.FileName)
32 tools.Fallback(G.Pkgsrc.Tools) 35 tools.Fallback(G.Pkgsrc.Tools)
33 36
34 return &MkLinesImpl{ 37 return &MkLinesImpl{
35 mklines, 38 mklines,
36 lines, 39 lines,
37 make(map[string]bool), 
38 "", 40 "",
39 NewScope(), 41 NewScope(),
40 make(map[string]bool), 42 make(map[string]bool),
41 make(map[string]MkLine), 43 make(map[string]MkLine),
42 make(map[string]MkLine), 44 make(map[string]MkLine),
43 false, 45 false,
44 tools, 46 tools,
45 nil, 47 nil,
 48 make(map[string]bool),
46 Once{}} 49 Once{}}
47} 50}
48 51
 52// TODO: Consider defining an interface MkLinesChecker (different name, though, since this one confuses even me)
 53// that checks a single topic, like:
 54//
 55// * PlistVars
 56// * ForLoops
 57// * MakeTargets
 58// * Tools
 59// * Indentation
 60// * LoadTimeVarUse
 61// * Subst
 62// * VarAlign
 63//
 64// These could be run in parallel to get the diagnostics strictly from top to bottom.
 65// Some of the checkers will probably depend on one another.
 66//
 67// The driving code for these checkers could look like:
 68//
 69// ck.Init
 70// ck.BeforeLine
 71// ck.Line
 72// ck.AfterLine
 73// ck.Finish
 74
 75// UseVar remembers that the given variable is used in the given line.
 76// This controls the "defined but not used" warning.
49func (mklines *MkLinesImpl) UseVar(mkline MkLine, varname string) { 77func (mklines *MkLinesImpl) UseVar(mkline MkLine, varname string) {
50 mklines.vars.Use(varname, mkline) 78 mklines.vars.Use(varname, mkline)
51 if G.Pkg != nil { 79 if G.Pkg != nil {
52 G.Pkg.vars.Use(varname, mkline) 80 G.Pkg.vars.Use(varname, mkline)
53 } 81 }
54} 82}
55 83
56func (mklines *MkLinesImpl) Check() { 84func (mklines *MkLinesImpl) Check() {
57 if trace.Tracing { 85 if trace.Tracing {
58 defer trace.Call1(mklines.lines.FileName)() 86 defer trace.Call1(mklines.lines.FileName)()
59 } 87 }
60 88
61 G.Mk = mklines 89 G.Mk = mklines
62 defer func() { G.Mk = nil }() 90 defer func() { G.Mk = nil }()
63 91
64 // In the first pass, all additions to BUILD_DEFS and USE_TOOLS 92 // In the first pass, all additions to BUILD_DEFS and USE_TOOLS
65 // are collected to make the order of the definitions irrelevant. 93 // are collected to make the order of the definitions irrelevant.
66 mklines.DetermineUsedVariables() 94 mklines.collectUsedVariables()
67 mklines.DetermineDefinedVariables() 95 mklines.collectDefinedVariables()
68 mklines.collectPlistVars() 96 mklines.collectPlistVars()
69 mklines.collectElse() 97 mklines.collectElse()
70 98
71 // In the second pass, the actual checks are done. 99 // In the second pass, the actual checks are done.
72 mklines.checkAll() 100 mklines.checkAll()
73 101
74 SaveAutofixChanges(mklines.lines) 102 SaveAutofixChanges(mklines.lines)
75} 103}
76 104
77func (mklines *MkLinesImpl) checkAll() { 105func (mklines *MkLinesImpl) checkAll() {
78 allowedTargets := func() map[string]bool { 106 allowedTargets := map[string]bool{
79 targets := make(map[string]bool) 107 "pre-fetch": true, "do-fetch": true, "post-fetch": true,
80 prefixes := [...]string{"pre", "do", "post"} 108 "pre-extract": true, "do-extract": true, "post-extract": true,
81 actions := [...]string{"fetch", "extract", "patch", "tools", "wrapper", "configure", "build", "test", "install", "package", "clean"} 109 "pre-patch": true, "do-patch": true, "post-patch": true,
82 for _, prefix := range prefixes { 110 "pre-tools": true, "do-tools": true, "post-tools": true,
83 for _, action := range actions { 111 "pre-wrapper": true, "do-wrapper": true, "post-wrapper": true,
84 targets[prefix+"-"+action] = true 112 "pre-configure": true, "do-configure": true, "post-configure": true,
85 } 113 "pre-build": true, "do-build": true, "post-build": true,
86 } 114 "pre-test": true, "do-test": true, "post-test": true,
87 return targets 115 "pre-install": true, "do-install": true, "post-install": true,
88 }() 116 "pre-package": true, "do-package": true, "post-package": true,
 117 "pre-clean": true, "do-clean": true, "post-clean": true}
 118 G.Assertf(len(allowedTargets) == 33, "Error in allowedTargets initialization")
89 119
90 mklines.lines.CheckRcsID(0, `#[\t ]+`, "# ") 120 mklines.lines.CheckRcsID(0, `#[\t ]+`, "# ")
91 121
92 substContext := NewSubstContext() 122 substContext := NewSubstContext()
93 var varalign VaralignBlock 123 var varalign VaralignBlock
94 isHacksMk := mklines.lines.BaseName == "hacks.mk" 124 isHacksMk := mklines.lines.BaseName == "hacks.mk"
95 125
96 lineAction := func(mkline MkLine) bool { 126 lineAction := func(mkline MkLine) bool {
97 if isHacksMk { 127 if isHacksMk {
 128 // Needs to be set here because it is reset in MkLines.ForEach.
98 mklines.Tools.SeenPrefs = true 129 mklines.Tools.SeenPrefs = true
99 } 130 }
100 131
101 ck := MkLineChecker{mkline} 132 ck := MkLineChecker{mkline}
102 ck.Check() 133 ck.Check()
103 varalign.Check(mkline) 134
 135 varalign.Process(mkline)
104 mklines.Tools.ParseToolLine(mkline, false, false) 136 mklines.Tools.ParseToolLine(mkline, false, false)
105 137
106 switch { 138 switch {
107 case mkline.IsEmpty(): 139 case mkline.IsEmpty():
108 substContext.Finish(mkline) 140 substContext.Finish(mkline)
109 141
110 case mkline.IsVarassign(): 142 case mkline.IsVarassign():
111 mklines.target = "" 143 mklines.target = ""
112 mkline.Tokenize(mkline.Value(), true) // Just for the side-effect of the warnings. 144 mkline.Tokenize(mkline.Value(), true) // Just for the side-effect of the warnings.
113 substContext.Varassign(mkline) 145 substContext.Varassign(mkline)
114 146
115 switch mkline.Varcanon() { 147 mklines.checkVarassignPlist(mkline)
116 case "PLIST_VARS": 
117 ids := mkline.ValueFields(resolveVariableRefs(mkline.Value())) 
118 for _, id := range ids { 
119 if !mklines.plistVarSkip && mklines.plistVarSet[id] == nil { 
120 mkline.Warnf("%q is added to PLIST_VARS, but PLIST.%s is not defined in this file.", id, id) 
121 } 
122 } 
123 
124 case "PLIST.*": 
125 id := mkline.Varparam() 
126 if !mklines.plistVarSkip && mklines.plistVarAdded[id] == nil { 
127 mkline.Warnf("PLIST.%s is defined, but %q is not added to PLIST_VARS in this file.", id, id) 
128 } 
129 } 
130 148
131 case mkline.IsInclude(): 149 case mkline.IsInclude():
132 mklines.target = "" 150 mklines.target = ""
133 if G.Pkg != nil { 151 if G.Pkg != nil {
134 G.Pkg.CheckInclude(mkline, mklines.indentation) 152 G.Pkg.checkIncludeConditionally(mkline, mklines.indentation)
135 } 153 }
136 154
137 case mkline.IsDirective(): 155 case mkline.IsDirective():
138 ck.checkDirective(mklines.forVars, mklines.indentation) 156 ck.checkDirective(mklines.forVars, mklines.indentation)
139 substContext.Directive(mkline) 157 substContext.Directive(mkline)
140 158
141 case mkline.IsDependency(): 159 case mkline.IsDependency():
142 ck.checkDependencyRule(allowedTargets) 160 ck.checkDependencyRule(allowedTargets)
143 mklines.target = mkline.Targets() 161 mklines.target = mkline.Targets()
144 162
145 case mkline.IsShellCommand(): 163 case mkline.IsShellCommand():
146 mkline.Tokenize(mkline.ShellCommand(), true) // Just for the side-effect of the warnings. 164 mkline.Tokenize(mkline.ShellCommand(), true) // Just for the side-effect of the warnings.
147 } 165 }
@@ -155,26 +173,43 @@ func (mklines *MkLinesImpl) checkAll() { @@ -155,26 +173,43 @@ func (mklines *MkLinesImpl) checkAll() {
155 173
156 // TODO: Extract this code so that it is clearly visible in the stack trace. 174 // TODO: Extract this code so that it is clearly visible in the stack trace.
157 if trace.Tracing { 175 if trace.Tracing {
158 trace.Stepf("Starting main checking loop") 176 trace.Stepf("Starting main checking loop")
159 } 177 }
160 mklines.ForEachEnd(lineAction, atEnd) 178 mklines.ForEachEnd(lineAction, atEnd)
161 179
162 substContext.Finish(NewMkLine(mklines.lines.EOFLine())) // TODO: mklines.EOFLine() 180 substContext.Finish(NewMkLine(mklines.lines.EOFLine())) // TODO: mklines.EOFLine()
163 varalign.Finish() 181 varalign.Finish()
164 182
165 ChecklinesTrailingEmptyLines(mklines.lines) 183 ChecklinesTrailingEmptyLines(mklines.lines)
166} 184}
167 185
 186func (mklines *MkLinesImpl) checkVarassignPlist(mkline MkLine) {
 187 switch mkline.Varcanon() {
 188 case "PLIST_VARS":
 189 for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value())) {
 190 if !mklines.plistVarSkip && mklines.plistVarSet[id] == nil {
 191 mkline.Warnf("%q is added to PLIST_VARS, but PLIST.%s is not defined in this file.", id, id)
 192 }
 193 }
 194
 195 case "PLIST.*":
 196 id := mkline.Varparam()
 197 if !mklines.plistVarSkip && mklines.plistVarAdded[id] == nil {
 198 mkline.Warnf("PLIST.%s is defined, but %q is not added to PLIST_VARS in this file.", id, id)
 199 }
 200 }
 201}
 202
168// ForEach calls the action for each line, until the action returns false. 203// ForEach calls the action for each line, until the action returns false.
169// It keeps track of the indentation (see MkLines.indentation) 204// It keeps track of the indentation (see MkLines.indentation)
170// and all conditional variables (see Indentation.IsConditional). 205// and all conditional variables (see Indentation.IsConditional).
171func (mklines *MkLinesImpl) ForEach(action func(mkline MkLine)) { 206func (mklines *MkLinesImpl) ForEach(action func(mkline MkLine)) {
172 mklines.ForEachEnd( 207 mklines.ForEachEnd(
173 func(mkline MkLine) bool { action(mkline); return true }, 208 func(mkline MkLine) bool { action(mkline); return true },
174 func(mkline MkLine) {}) 209 func(mkline MkLine) {})
175} 210}
176 211
177// ForEachEnd calls the action for each line, until the action returns false. 212// ForEachEnd calls the action for each line, until the action returns false.
178// It keeps track of the indentation and all conditional variables. 213// It keeps track of the indentation and all conditional variables.
179// At the end, atEnd is called with the last line as its argument. 214// At the end, atEnd is called with the last line as its argument.
180func (mklines *MkLinesImpl) ForEachEnd(action func(mkline MkLine) bool, atEnd func(lastMkline MkLine)) { 215func (mklines *MkLinesImpl) ForEachEnd(action func(mkline MkLine) bool, atEnd func(lastMkline MkLine)) {
@@ -189,133 +224,137 @@ func (mklines *MkLinesImpl) ForEachEnd(a @@ -189,133 +224,137 @@ func (mklines *MkLinesImpl) ForEachEnd(a
189 224
190 for _, mkline := range mklines.mklines { 225 for _, mkline := range mklines.mklines {
191 mklines.indentation.TrackBefore(mkline) 226 mklines.indentation.TrackBefore(mkline)
192 if !action(mkline) { 227 if !action(mkline) {
193 break 228 break
194 } 229 }
195 mklines.indentation.TrackAfter(mkline) 230 mklines.indentation.TrackAfter(mkline)
196 } 231 }
197 232
198 atEnd(mklines.mklines[len(mklines.mklines)-1]) 233 atEnd(mklines.mklines[len(mklines.mklines)-1])
199 mklines.indentation = nil 234 mklines.indentation = nil
200} 235}
201 236
202func (mklines *MkLinesImpl) DetermineDefinedVariables() { 237func (mklines *MkLinesImpl) collectDefinedVariables() {
203 if trace.Tracing { 238 if trace.Tracing {
204 defer trace.Call0()() 239 defer trace.Call0()()
205 } 240 }
206 241
207 for _, mkline := range mklines.mklines { 242 for _, mkline := range mklines.mklines {
208 mklines.Tools.ParseToolLine(mkline, false, true) 243 mklines.Tools.ParseToolLine(mkline, false, true)
209 244
210 if !mkline.IsVarassign() { 245 if !mkline.IsVarassign() {
211 continue 246 continue
212 } 247 }
213 248
214 defineVar(mkline, mkline.Varname()) 249 defineVar(mkline, mkline.Varname())
215 250
216 varcanon := mkline.Varcanon() 251 varcanon := mkline.Varcanon()
217 switch varcanon { 252 switch varcanon {
218 case 253 case
219 "BUILD_DEFS", 254 "BUILD_DEFS",
220 "PKG_GROUPS_VARS", 255 "PKG_GROUPS_VARS", // see mk/misc/unprivileged.mk
221 "PKG_USERS_VARS": 256 "PKG_USERS_VARS": // see mk/misc/unprivileged.mk
222 for _, varname := range fields(mkline.Value()) { 257 for _, varname := range mkline.Fields() {
223 mklines.buildDefs[varname] = true 258 mklines.buildDefs[varname] = true
224 if trace.Tracing { 259 if trace.Tracing {
225 trace.Step1("%q is added to BUILD_DEFS.", varname) 260 trace.Step1("%q is added to BUILD_DEFS.", varname)
226 } 261 }
227 } 262 }
228 263
229 case 264 case
230 "BUILTIN_FIND_FILES_VAR", 265 "BUILTIN_FIND_FILES_VAR",
231 "BUILTIN_FIND_HEADERS_VAR": 266 "BUILTIN_FIND_HEADERS_VAR":
232 for _, varname := range fields(mkline.Value()) { 267 for _, varname := range mkline.Fields() {
233 mklines.vars.Define(varname, mkline) 268 mklines.vars.Define(varname, mkline)
234 } 269 }
235 270
236 case "PLIST_VARS": 271 case "PLIST_VARS":
237 ids := mkline.ValueFields(resolveVariableRefs(mkline.Value())) 272 for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value())) {
238 for _, id := range ids { 
239 if trace.Tracing { 273 if trace.Tracing {
240 trace.Step1("PLIST.%s is added to PLIST_VARS.", id) 274 trace.Step1("PLIST.%s is added to PLIST_VARS.", id)
241 } 275 }
 276
242 if containsVarRef(id) { 277 if containsVarRef(id) {
243 mklines.UseVar(mkline, "PLIST.*") 278 mklines.UseVar(mkline, "PLIST.*")
244 mklines.plistVarSkip = true 279 mklines.plistVarSkip = true
245 } else { 280 } else {
246 mklines.UseVar(mkline, "PLIST."+id) 281 mklines.UseVar(mkline, "PLIST."+id)
247 } 282 }
248 } 283 }
249 284
250 case "SUBST_VARS.*": 285 case "SUBST_VARS.*":
251 for _, svar := range fields(mkline.Value()) { 286 for _, substVar := range mkline.Fields() {
252 mklines.UseVar(mkline, varnameCanon(svar)) 287 mklines.UseVar(mkline, varnameCanon(substVar))
253 if trace.Tracing { 288 if trace.Tracing {
254 trace.Step1("varuse %s", svar) 289 trace.Step1("varuse %s", substVar)
255 } 290 }
256 } 291 }
257 292
258 case "OPSYSVARS": 293 case "OPSYSVARS":
259 for _, osvar := range fields(mkline.Value()) { 294 for _, opsysVar := range mkline.Fields() {
260 mklines.UseVar(mkline, osvar+".*") 295 mklines.UseVar(mkline, opsysVar+".*")
261 defineVar(mkline, osvar) 296 defineVar(mkline, opsysVar)
262 } 297 }
263 } 298 }
264 } 299 }
265} 300}
266 301
267func (mklines *MkLinesImpl) collectPlistVars() { 302func (mklines *MkLinesImpl) collectPlistVars() {
 303 // TODO: The PLIST_VARS code above looks very similar.
268 for _, mkline := range mklines.mklines { 304 for _, mkline := range mklines.mklines {
269 if mkline.IsVarassign() { 305 if mkline.IsVarassign() {
270 switch mkline.Varcanon() { 306 switch mkline.Varcanon() {
271 case "PLIST_VARS": 307 case "PLIST_VARS":
272 ids := mkline.ValueFields(resolveVariableRefs(mkline.Value())) 308 for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value())) {
273 for _, id := range ids { 
274 if containsVarRef(id) { 309 if containsVarRef(id) {
275 mklines.plistVarSkip = true 310 mklines.plistVarSkip = true
276 } else { 311 } else {
277 mklines.plistVarAdded[id] = mkline 312 mklines.plistVarAdded[id] = mkline
278 } 313 }
279 } 314 }
280 case "PLIST.*": 315 case "PLIST.*":
281 id := mkline.Varparam() 316 id := mkline.Varparam()
282 if containsVarRef(id) { 317 if containsVarRef(id) {
283 mklines.plistVarSkip = true 318 mklines.plistVarSkip = true
284 } else { 319 } else {
285 mklines.plistVarSet[id] = mkline 320 mklines.plistVarSet[id] = mkline
286 } 321 }
287 } 322 }
288 } 323 }
289 } 324 }
290} 325}
291 326
292func (mklines *MkLinesImpl) collectElse() { 327func (mklines *MkLinesImpl) collectElse() {
293 // Make a dry-run over the lines, which sets data.elseLine (in mkline.go) as a side-effect. 328 // Make a dry-run over the lines, which sets data.elseLine (in mkline.go) as a side-effect.
294 mklines.ForEach(func(mkline MkLine) {}) 329 mklines.ForEach(func(mkline MkLine) {})
 330 // TODO: Check whether this ForEach is redundant because it is already run somewhere else.
295} 331}
296 332
297func (mklines *MkLinesImpl) DetermineUsedVariables() { 333func (mklines *MkLinesImpl) collectUsedVariables() {
298 for _, mkline := range mklines.mklines { 334 for _, mkline := range mklines.mklines {
299 for _, varname := range mkline.DetermineUsedVariables() { 335 for _, varname := range mkline.DetermineUsedVariables() {
300 mklines.UseVar(mkline, varname) 336 mklines.UseVar(mkline, varname)
301 } 337 }
302 } 338 }
303 339
304 mklines.determineDocumentedVariables() 340 mklines.collectDocumentedVariables()
305} 341}
306 342
307// Loosely based on mk/help/help.awk, revision 1.28 343// collectDocumentedVariables collects the variables that are mentioned in the human-readable
308func (mklines *MkLinesImpl) determineDocumentedVariables() { 344// documentation of the Makefile fragments from the pkgsrc infrastructure.
 345//
 346// Loosely based on mk/help/help.awk, revision 1.28, but much simpler.
 347func (mklines *MkLinesImpl) collectDocumentedVariables() {
309 scope := NewScope() 348 scope := NewScope()
310 commentLines := 0 349 commentLines := 0
311 relevant := true 350 relevant := true
312 351
313 finish := func() { 352 finish := func() {
314 if commentLines >= 3 && relevant { 353 if commentLines >= 3 && relevant {
315 for varname, mkline := range scope.used { 354 for varname, mkline := range scope.used {
316 mklines.vars.Use(varname, mkline) 355 mklines.vars.Use(varname, mkline)
317 } 356 }
318 } 357 }
319 358
320 scope = NewScope() 359 scope = NewScope()
321 commentLines = 0 360 commentLines = 0
@@ -347,42 +386,45 @@ func (mklines *MkLinesImpl) determineDoc @@ -347,42 +386,45 @@ func (mklines *MkLinesImpl) determineDoc
347 386
348 if 1 < len(words) && words[1] == "Copyright" { 387 if 1 < len(words) && words[1] == "Copyright" {
349 relevant = false 388 relevant = false
350 } 389 }
351 390
352 case mkline.IsEmpty(): 391 case mkline.IsEmpty():
353 finish() 392 finish()
354 } 393 }
355 } 394 }
356 395
357 finish() 396 finish()
358} 397}
359 398
360func (mklines *MkLinesImpl) CheckRedundantVariables() { 399func (mklines *MkLinesImpl) CheckRedundantAssignments() {
361 scope := NewRedundantScope() 400 scope := NewRedundantScope()
 401
362 isRelevant := func(old, new MkLine) bool { 402 isRelevant := func(old, new MkLine) bool {
363 if old.Basename != "Makefile" && new.Basename == "Makefile" { 403 if old.Basename != "Makefile" && new.Basename == "Makefile" {
364 return false 404 return false
365 } 405 }
366 if new.Op() == opAssignEval { 406 if new.Op() == opAssignEval {
367 return false 407 return false
368 } 408 }
369 return true 409 return true
370 } 410 }
 411
371 scope.OnIgnore = func(old, new MkLine) { 412 scope.OnIgnore = func(old, new MkLine) {
372 if isRelevant(old, new) && old.Value() == new.Value() { 413 if isRelevant(old, new) && old.Value() == new.Value() {
373 old.Notef("Definition of %s is redundant because of %s.", new.Varname(), old.RefTo(new)) 414 old.Notef("Definition of %s is redundant because of %s.", new.Varname(), old.RefTo(new))
374 } 415 }
375 } 416 }
 417
376 scope.OnOverwrite = func(old, new MkLine) { 418 scope.OnOverwrite = func(old, new MkLine) {
377 if isRelevant(old, new) { 419 if isRelevant(old, new) {
378 old.Warnf("Variable %s is overwritten in %s.", new.Varname(), old.RefTo(new)) 420 old.Warnf("Variable %s is overwritten in %s.", new.Varname(), old.RefTo(new))
379 G.Explain( 421 G.Explain(
380 "The variable definition in this line does not have an effect since", 422 "The variable definition in this line does not have an effect since",
381 "it is overwritten elsewhere. This typically happens because of a", 423 "it is overwritten elsewhere. This typically happens because of a",
382 "typo (writing = instead of +=) or because the line that overwrites", 424 "typo (writing = instead of +=) or because the line that overwrites",
383 "is in another file that is used by several packages.") 425 "is in another file that is used by several packages.")
384 } 426 }
385 } 427 }
386 428
387 mklines.ForEach(scope.Handle) 429 mklines.ForEach(scope.Handle)
388} 430}
@@ -438,74 +480,72 @@ type VaralignBlock struct { @@ -438,74 +480,72 @@ type VaralignBlock struct {
438 infos []*varalignBlockInfo 480 infos []*varalignBlockInfo
439 skip bool 481 skip bool
440} 482}
441 483
442type varalignBlockInfo struct { 484type varalignBlockInfo struct {
443 mkline MkLine 485 mkline MkLine
444 varnameOp string // Variable name + assignment operator 486 varnameOp string // Variable name + assignment operator
445 varnameOpWidth int // Screen width of varnameOp 487 varnameOpWidth int // Screen width of varnameOp
446 space string // Whitespace between varnameOp and the variable value 488 space string // Whitespace between varnameOp and the variable value
447 totalWidth int // Screen width of varnameOp + space 489 totalWidth int // Screen width of varnameOp + space
448 continuation bool // A continuation line with no value in the first line. 490 continuation bool // A continuation line with no value in the first line.
449} 491}
450 492
451func (va *VaralignBlock) Check(mkline MkLine) { 493func (va *VaralignBlock) Process(mkline MkLine) {
452 switch { 494 switch {
453 case !G.Opts.WarnSpace: 495 case !G.Opts.WarnSpace:
454 return 496 return
455 497
456 case mkline.IsEmpty(): 498 case mkline.IsEmpty():
457 va.Finish() 499 va.Finish()
458 return 500 return
459 501
460 case mkline.IsCommentedVarassign(): 502 case mkline.IsVarassign(), mkline.IsCommentedVarassign():
461 break 503 va.processVarassign(mkline)
462 504
463 case mkline.IsComment(): 505 case mkline.IsComment(), mkline.IsDirective():
464 return 506 return
465 507
466 case mkline.IsDirective(): 508 default:
467 return 
468 
469 case !mkline.IsVarassign(): 
470 trace.Stepf("Skipping") 509 trace.Stepf("Skipping")
471 va.skip = true 510 va.skip = true
472 return 511 return
473 } 512 }
 513}
474 514
 515func (va *VaralignBlock) processVarassign(mkline MkLine) {
475 switch { 516 switch {
476 case mkline.Op() == opAssignEval && matches(mkline.Varname(), `^[a-z]`): 517 case mkline.Op() == opAssignEval && matches(mkline.Varname(), `^[a-z]`):
477 // Arguments to procedures do not take part in block alignment. 518 // Arguments to procedures do not take part in block alignment.
478 // 519 //
479 // Example: 520 // Example:
480 // pkgpath := ${PKGPATH} 521 // pkgpath := ${PKGPATH}
481 return 522 return
482 523
483 case mkline.Value() == "" && mkline.VarassignComment() == "": 524 case mkline.Value() == "" && mkline.VarassignComment() == "":
484 // Multiple-inclusion guards usually appear in a block of 525 // Multiple-inclusion guards usually appear in a block of
485 // their own and therefore do not need alignment. 526 // their own and therefore do not need alignment.
486 // 527 //
487 // Example: 528 // Example:
488 // .if !defined(INCLUSION_GUARD_MK) 529 // .if !defined(INCLUSION_GUARD_MK)
489 // INCLUSION_GUARD_MK:= 530 // INCLUSION_GUARD_MK:=
490 // # ... 531 // # ...
491 // .endif 532 // .endif
492 return 533 return
493 } 534 }
494 535
495 continuation := false 536 continuation := false
496 if mkline.IsMultiline() { 537 if mkline.IsMultiline() {
497 // Interpreting the continuation marker as variable value 538 // Parsing the continuation marker as variable value is cheating but works well.
498 // is cheating but works well. 
499 text := strings.TrimSuffix(mkline.raw[0].orignl, "\n") 539 text := strings.TrimSuffix(mkline.raw[0].orignl, "\n")
500 m, _, _, _, _, _, value, _, _ := MatchVarassign(text) 540 m, _, _, _, _, _, value, _, _ := MatchVarassign(text)
501 continuation = m && value == "\\" 541 continuation = m && value == "\\"
502 } 542 }
503 543
504 valueAlign := mkline.ValueAlign() 544 valueAlign := mkline.ValueAlign()
505 varnameOp := strings.TrimRight(valueAlign, " \t") 545 varnameOp := strings.TrimRight(valueAlign, " \t")
506 space := valueAlign[len(varnameOp):] 546 space := valueAlign[len(varnameOp):]
507 547
508 width := tabWidth(valueAlign) 548 width := tabWidth(valueAlign)
509 va.infos = append(va.infos, &varalignBlockInfo{mkline, varnameOp, tabWidth(varnameOp), space, width, continuation}) 549 va.infos = append(va.infos, &varalignBlockInfo{mkline, varnameOp, tabWidth(varnameOp), space, width, continuation})
510} 550}
511 551
@@ -571,34 +611,34 @@ func (va *VaralignBlock) optimalWidth(in @@ -571,34 +611,34 @@ func (va *VaralignBlock) optimalWidth(in
571 } 611 }
572 612
573 if width := info.totalWidth; info.varnameOpWidth != outlier { 613 if width := info.totalWidth; info.varnameOpWidth != outlier {
574 if minTotalWidth == 0 || width < minTotalWidth { 614 if minTotalWidth == 0 || width < minTotalWidth {
575 minTotalWidth = width 615 minTotalWidth = width
576 } 616 }
577 maxTotalWidth = imax(maxTotalWidth, width) 617 maxTotalWidth = imax(maxTotalWidth, width)
578 } 618 }
579 } 619 }
580 620
581 if trace.Tracing { 621 if trace.Tracing {
582 trace.Stepf("Indentation including whitespace is between %d and %d.", 622 trace.Stepf("Indentation including whitespace is between %d and %d.",
583 minTotalWidth, maxTotalWidth) 623 minTotalWidth, maxTotalWidth)
584 trace.Stepf("Minimum required indentation is %d + 1.", 624 trace.Stepf("Minimum required indentation is %d + 1.", minVarnameOpWidth)
585 minVarnameOpWidth) 
586 if outlier != 0 { 625 if outlier != 0 {
587 trace.Stepf("The outlier is at indentation %d.", outlier) 626 trace.Stepf("The outlier is at indentation %d.", outlier)
588 } 627 }
589 } 628 }
590 629
591 if minTotalWidth > minVarnameOpWidth && minTotalWidth == maxTotalWidth && minTotalWidth%8 == 0 { 630 if minTotalWidth > minVarnameOpWidth && minTotalWidth == maxTotalWidth && minTotalWidth%8 == 0 {
 631 // The whole paragraph is already indented to the same width.
592 return minTotalWidth 632 return minTotalWidth
593 } 633 }
594 634
595 if minVarnameOpWidth == 0 { 635 if minVarnameOpWidth == 0 {
596 // Only continuation lines in this paragraph. 636 // Only continuation lines in this paragraph.
597 return 0 637 return 0
598 } 638 }
599 639
600 return (minVarnameOpWidth & -8) + 8 640 return (minVarnameOpWidth & -8) + 8
601} 641}
602 642
603func (va *VaralignBlock) realign(mkline MkLine, varnameOp, oldSpace string, continuation bool, newWidth int) { 643func (va *VaralignBlock) realign(mkline MkLine, varnameOp, oldSpace string, continuation bool, newWidth int) {
604 hasSpace := contains(oldSpace, " ") 644 hasSpace := contains(oldSpace, " ")
@@ -633,35 +673,37 @@ func (va *VaralignBlock) realignInitialL @@ -633,35 +673,37 @@ func (va *VaralignBlock) realignInitialL
633 switch { 673 switch {
634 case hasSpace && wrongColumn: 674 case hasSpace && wrongColumn:
635 fix.Notef("This variable value should be aligned with tabs, not spaces, to column %d.", newWidth+1) 675 fix.Notef("This variable value should be aligned with tabs, not spaces, to column %d.", newWidth+1)
636 case hasSpace && oldSpace != newSpace: 676 case hasSpace && oldSpace != newSpace:
637 fix.Notef("Variable values should be aligned with tabs, not spaces.") 677 fix.Notef("Variable values should be aligned with tabs, not spaces.")
638 case wrongColumn: 678 case wrongColumn:
639 fix.Notef("This variable value should be aligned to column %d.", newWidth+1) 679 fix.Notef("This variable value should be aligned to column %d.", newWidth+1)
640 default: 680 default:
641 return 681 return
642 } 682 }
643 683
644 if wrongColumn { 684 if wrongColumn {
645 fix.Explain( 685 fix.Explain(
646 "Normally, all variable values in a block should start at the same", 686 "Normally, all variable values in a block should start at the same column.",
647 "column. There are some exceptions to this rule:", 687 "This provides orientation, especially for sequences",
 688 "of variables that often appear in the same order.",
 689 "For these it suffices to look at the variable values only.",
 690 "",
 691 "There are some exceptions to this rule:",
648 "", 692 "",
649 "Definitions for long variable names may be indented with a single", 693 "Definitions for long variable names may be indented with a single space instead of tabs,",
650 "space instead of tabs, but only if they appear in a block that is", 694 "but only if they appear in a block that is otherwise indented using tabs.",
651 "otherwise indented using tabs.", 
652 "", 695 "",
653 "Variable definitions that span multiple lines are not checked for", 696 "Variable definitions that span multiple lines are not checked for alignment at all.",
654 "alignment at all.", 
655 "", 697 "",
656 "When the block contains something else than variable definitions", 698 "When the block contains something else than variable definitions",
657 "and directives like .if or .for, it is not checked at all.") 699 "and directives like .if or .for, it is not checked at all.")
658 } 700 }
659 701
660 fix.ReplaceAfter(varnameOp, oldSpace, newSpace) 702 fix.ReplaceAfter(varnameOp, oldSpace, newSpace)
661 fix.Apply() 703 fix.Apply()
662} 704}
663 705
664func (va *VaralignBlock) realignContinuationLines(mkline MkLine, newWidth int) { 706func (va *VaralignBlock) realignContinuationLines(mkline MkLine, newWidth int) {
665 indentation := strings.Repeat("\t", newWidth/8) + strings.Repeat(" ", newWidth%8) 707 indentation := strings.Repeat("\t", newWidth/8) + strings.Repeat(" ", newWidth%8)
666 fix := mkline.Autofix() 708 fix := mkline.Autofix()
667 fix.Notef("This line should be aligned with %q.", indentation) 709 fix.Notef("This line should be aligned with %q.", indentation)

cvs diff -r1.31 -r1.32 pkgsrc/pkgtools/pkglint/files/Attic/mklines_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mklines_test.go 2018/12/02 01:57:48 1.31
+++ pkgsrc/pkgtools/pkglint/files/Attic/mklines_test.go 2018/12/02 23:12:43 1.32
@@ -30,41 +30,38 @@ func (s *Suite) Test_MkLines_Check__auto @@ -30,41 +30,38 @@ func (s *Suite) Test_MkLines_Check__auto
30 t.CheckFileLines("filename.mk", 30 t.CheckFileLines("filename.mk",
31 "# $"+"NetBSD$", 31 "# $"+"NetBSD$",
32 ".if defined(A)", 32 ".if defined(A)",
33 ". for a in ${A}", 33 ". for a in ${A}",
34 ". if defined(C)", 34 ". if defined(C)",
35 ". endif", 35 ". endif",
36 ". endfor", 36 ". endfor",
37 ".endif") 37 ".endif")
38} 38}
39 39
40func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) { 40func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) {
41 t := s.Init(c) 41 t := s.Init(c)
42 42
 43 t.SetupVartypes()
 44 t.SetupTool("cc", "CC", AtRunTime)
43 mklines := t.NewMkLines("Makefile", 45 mklines := t.NewMkLines("Makefile",
44 MkRcsID, 46 MkRcsID,
45 "", 47 "",
46 "echo: echo.c", 48 "echo: echo.c",
47 "\tcc -o ${.TARGET} ${.IMPSRC}") 49 "\tcc -o ${.TARGET} ${.IMPSRC}")
48 50
49 mklines.Check() 51 mklines.Check()
50 52
51 // FIXME: .TARGET is always defined. 
52 // FIXME: .IMPSRC is always defined. 
53 t.CheckOutputLines( 53 t.CheckOutputLines(
54 "WARN: Makefile:3: Unusual target \"echo\".", 54 "WARN: Makefile:3: Unusual target \"echo\".")
55 "WARN: Makefile:4: Unknown shell command \"cc\".", 
56 "WARN: Makefile:4: .TARGET is used but not defined.", 
57 "WARN: Makefile:4: .IMPSRC is used but not defined.") 
58} 55}
59 56
60func (s *Suite) Test_MkLines__quoting_LDFLAGS_for_GNU_configure(c *check.C) { 57func (s *Suite) Test_MkLines__quoting_LDFLAGS_for_GNU_configure(c *check.C) {
61 t := s.Init(c) 58 t := s.Init(c)
62 59
63 t.SetupVartypes() 60 t.SetupVartypes()
64 G.Pkg = NewPackage(t.File("category/pkgbase")) 61 G.Pkg = NewPackage(t.File("category/pkgbase"))
65 mklines := t.NewMkLines("Makefile", 62 mklines := t.NewMkLines("Makefile",
66 MkRcsID, 63 MkRcsID,
67 "GNU_CONFIGURE=\tyes", 64 "GNU_CONFIGURE=\tyes",
68 "CONFIGURE_ENV+=\tX_LIBS=${X11_LDFLAGS:Q}") 65 "CONFIGURE_ENV+=\tX_LIBS=${X11_LDFLAGS:Q}")
69 66
70 mklines.Check() 67 mklines.Check()
@@ -74,74 +71,79 @@ func (s *Suite) Test_MkLines__quoting_LD @@ -74,74 +71,79 @@ func (s *Suite) Test_MkLines__quoting_LD
74 "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.") 71 "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.")
75} 72}
76 73
77func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) { 74func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) {
78 t := s.Init(c) 75 t := s.Init(c)
79 76
80 t.SetupVartypes() 77 t.SetupVartypes()
81 t.SetupTool("echo", "ECHO", AtRunTime) 78 t.SetupTool("echo", "ECHO", AtRunTime)
82 t.SetupTool("find", "FIND", AtRunTime) 79 t.SetupTool("find", "FIND", AtRunTime)
83 t.SetupTool("pax", "PAX", AtRunTime) 80 t.SetupTool("pax", "PAX", AtRunTime)
84 mklines := t.NewMkLines("Makefile", // From audio/squeezeboxserver 81 mklines := t.NewMkLines("Makefile", // From audio/squeezeboxserver
85 MkRcsID, 82 MkRcsID,
86 "", 83 "",
 84 "SBS_COPY=\tsource target",
 85 "",
87 ".for _list_ _dir_ in ${SBS_COPY}", 86 ".for _list_ _dir_ in ${SBS_COPY}",
88 "\tcd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2>/dev/null "+ 87 "\tcd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2>/dev/null "+
89 "| pax -rw -pm ${DESTDIR}${PREFIX}/${${_dir_}}", 88 "| pax -rw -pm ${DESTDIR}${PREFIX}/${${_dir_}}",
90 ".endfor") 89 ".endfor")
91 90
92 mklines.Check() 91 mklines.Check()
93 92
94 t.CheckOutputLines( 93 t.CheckOutputLines(
95 "WARN: Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.", 94 "WARN: Makefile:5: Variable names starting with an underscore (_list_) "+
96 "WARN: Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.", 95 "are reserved for internal pkgsrc use.",
97 "WARN: Makefile:3: SBS_COPY is used but not defined.", 96 "WARN: Makefile:5: Variable names starting with an underscore (_dir_) "+
98 "WARN: Makefile:4: The exitcode of \"${FIND}\" at the left of the | operator is ignored.") 97 "are reserved for internal pkgsrc use.",
 98 "WARN: Makefile:6: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
99} 99}
100 100
101func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) { 101func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) {
102 t := s.Init(c) 102 t := s.Init(c)
103 103
104 t.SetupVartypes() 104 t.SetupVartypes()
105 mklines := t.NewMkLines("databases/gdbm_compat/builtin.mk", 105 mklines := t.NewMkLines("databases/gdbm_compat/builtin.mk",
106 MkRcsID, 106 MkRcsID,
107 ".if ${USE_BUILTIN.gdbm} == \"no\"", 107 ".if ${USE_BUILTIN.gdbm} == \"no\"",
108 ".endif", 108 ".endif",
109 ".if ${USE_BUILTIN.gdbm:tu} == \"no\"", // Can never be true, since "no" is not uppercase. 109 ".if ${USE_BUILTIN.gdbm:tu} == \"no\"", // Can never be true, since "no" is not uppercase.
110 ".endif") 110 ".endif")
111 111
112 mklines.Check() 112 mklines.Check()
113 113
114 t.CheckOutputLines( 114 t.CheckOutputLines(
115 "WARN: databases/gdbm_compat/builtin.mk:2: " + 115 "WARN: databases/gdbm_compat/builtin.mk:2: " +
116 "USE_BUILTIN.gdbm should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not compared with \"no\".") 116 "USE_BUILTIN.gdbm should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", " +
 117 "not compared with \"no\".")
117} 118}
118 119
119func (s *Suite) Test_MkLines__varuse_sh_modifier(c *check.C) { 120func (s *Suite) Test_MkLines__varuse_sh_modifier(c *check.C) {
120 t := s.Init(c) 121 t := s.Init(c)
121 122
122 t.SetupVartypes() 123 t.SetupVartypes()
123 t.SetupTool("sed", "SED", AfterPrefsMk) 124 t.SetupTool("sed", "SED", AfterPrefsMk)
124 mklines := t.NewMkLines("lang/qore/module.mk", 125 mklines := t.NewMkLines("lang/qore/module.mk",
125 MkRcsID, 126 MkRcsID,
126 "qore-version=\tqore --short-version | ${SED} -e s/-.*//", 127 "qore-version=\tqore --short-version | ${SED} -e s/-.*//",
127 "PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"") 128 "PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"")
128 129
129 vars2 := mklines.mklines[1].DetermineUsedVariables() 130 vars2 := mklines.mklines[1].DetermineUsedVariables()
130 131
131 c.Check(vars2, deepEquals, []string{"SED"}) 132 c.Check(vars2, deepEquals, []string{"SED"})
132 133
133 vars3 := mklines.mklines[2].DetermineUsedVariables() 134 vars3 := mklines.mklines[2].DetermineUsedVariables()
134 135
 136 // qore-version, despite its unusual name, is a pretty normal Make variable.
135 c.Check(vars3, deepEquals, []string{"qore-version"}) 137 c.Check(vars3, deepEquals, []string{"qore-version"})
136 138
137 mklines.Check() 139 mklines.Check()
138 140
139 // No warnings about defined but not used or vice versa 141 // No warnings about defined but not used or vice versa
140 t.CheckOutputEmpty() 142 t.CheckOutputEmpty()
141} 143}
142 144
143// For parameterized variables, the "defined but not used" and 145// For parameterized variables, the "defined but not used" and
144// the "used but not defined" checks are loosened a bit. 146// the "used but not defined" checks are loosened a bit.
145// When VAR.param1 is defined or used, VAR.param2 is also regarded 147// When VAR.param1 is defined or used, VAR.param2 is also regarded
146// as defined or used since often in pkgsrc, parameterized variables 148// as defined or used since often in pkgsrc, parameterized variables
147// are not referred to by their exact names but by VAR.${param}. 149// are not referred to by their exact names but by VAR.${param}.
@@ -151,63 +153,79 @@ func (s *Suite) Test_MkLines__varuse_par @@ -151,63 +153,79 @@ func (s *Suite) Test_MkLines__varuse_par
151 t.SetupVartypes() 153 t.SetupVartypes()
152 mklines := t.NewMkLines("converters/wv2/Makefile", 154 mklines := t.NewMkLines("converters/wv2/Makefile",
153 MkRcsID, 155 MkRcsID,
154 "CONFIGURE_ARGS+=\t\t${CONFIGURE_ARGS.${ICONV_TYPE}-iconv}", 156 "CONFIGURE_ARGS+=\t\t${CONFIGURE_ARGS.${ICONV_TYPE}-iconv}",
155 "CONFIGURE_ARGS.gnu-iconv=\t--with-libiconv=${BUILDLINK_PREFIX.iconv}") 157 "CONFIGURE_ARGS.gnu-iconv=\t--with-libiconv=${BUILDLINK_PREFIX.iconv}")
156 158
157 mklines.Check() 159 mklines.Check()
158 160
159 // No warnings about CONFIGURE_ARGS.* being defined but not used or vice versa. 161 // No warnings about CONFIGURE_ARGS.* being defined but not used or vice versa.
160 t.CheckOutputLines( 162 t.CheckOutputLines(
161 "WARN: converters/wv2/Makefile:2: ICONV_TYPE is used but not defined.") 163 "WARN: converters/wv2/Makefile:2: ICONV_TYPE is used but not defined.")
162} 164}
163 165
164// Even very complicated shell commands are parsed correctly. 166// When an ODE runtime loop is used to expand variables to shell commands,
165// Since the variable is defined in this same Makefile, it is 167// pkglint only understands that there is a variable that is executed as
166// assumed to be a known shell command and therefore does not need 168// shell command.
167// USE_TOOLS or a similar declaration. 169//
 170// In this example, GCONF_SCHEMAS is a list of filenames, but pkglint doesn't know this
 171// because there is no built-in rule saying *_SCHEMAS are filenames.
 172// If the variable name had been GCONF_SCHEMA_FILES, pkglint would know.
 173//
 174// As of November 2018, pkglint sees GCONF_SCHEMAS as being the shell command.
 175// It doesn't expand the @s@ loop to see what really happens.
 176//
 177// If it did that, it could notice that GCONF_SCHEMAS expands to a single shell command,
 178// and in that command INSTALL_DATA is used as the command for the first time,
 179// and as a regular command line argument in all other times.
 180// This combination is strange enough to warrant a warning.
 181//
 182// The bug here is the missing semicolon just before the @}.
 183//
 184// Pkglint could offer to either add the missing semicolon.
 185// Or, if it knows what INSTALL_DATA does, it could simply say that INSTALL_DATA
 186// can handle multiple files in a single invocation.
168func (s *Suite) Test_MkLines__loop_modifier(c *check.C) { 187func (s *Suite) Test_MkLines__loop_modifier(c *check.C) {
169 t := s.Init(c) 188 t := s.Init(c)
170 189
171 t.SetupVartypes() 190 t.SetupVartypes()
172 mklines := t.NewMkLines("chat/xchat/Makefile", 191 mklines := t.NewMkLines("chat/xchat/Makefile",
173 MkRcsID, 192 MkRcsID,
174 "GCONF_SCHEMAS=\tapps_xchat_url_handler.schemas", 193 "GCONF_SCHEMAS=\tapps_xchat_url_handler.schemas",
175 "post-install:", 194 "post-install:",
176 "\t${GCONF_SCHEMAS:@.s.@"+ 195 "\t${GCONF_SCHEMAS:@s@"+
177 "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}") 196 "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${s} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}")
178 197
179 mklines.Check() 198 mklines.Check()
180 199
181 // Earlier versions of pkglint warned about a missing @ at the end. 200 // Earlier versions of pkglint warned about a missing @ at the end.
182 t.CheckOutputEmpty() 201 t.CheckOutputEmpty()
183} 202}
184 203
185// PR 46570 
186func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) { 204func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) {
187 t := s.Init(c) 205 t := s.Init(c)
188 206
189 t.SetupVartypes() 207 t.SetupVartypes()
190 mklines := t.NewMkLines("Makefile", 208 mklines := t.NewMkLines("Makefile",
191 MkRcsID, 209 MkRcsID,
192 "PKG_SKIP_REASON+=\t\"Fails everywhere\"", 210 "PKG_SKIP_REASON+=\t\"Fails everywhere\"",
193 ".if ${OPSYS} == \"Cygwin\"", 211 ".if ${OPSYS} == \"Cygwin\"",
194 "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"", 212 "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"",
195 ".endif") 213 ".endif")
196 214
197 mklines.Check() 215 mklines.Check()
198 216
199 t.CheckOutputLines( 217 t.CheckOutputLines(
200 "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.") 218 "NOTE: Makefile:4: Consider setting NOT_FOR_PLATFORM instead of PKG_SKIP_REASON depending on ${OPSYS}.")
201} 219}
202 220
203// PR 46570, item "15. net/uucp/Makefile has a make loop" 221// PR 46570, item "15. net/uucp/Makefile has a make loop"
204func (s *Suite) Test_MkLines__indirect_variables(c *check.C) { 222func (s *Suite) Test_MkLines__indirect_variables(c *check.C) {
205 t := s.Init(c) 223 t := s.Init(c)
206 224
207 t.SetupTool("echo", "ECHO", AfterPrefsMk) 225 t.SetupTool("echo", "ECHO", AfterPrefsMk)
208 mklines := t.NewMkLines("net/uucp/Makefile", 226 mklines := t.NewMkLines("net/uucp/Makefile",
209 MkRcsID, 227 MkRcsID,
210 "", 228 "",
211 "post-configure:", 229 "post-configure:",
212 ".for var in MAIL_PROGRAM CMDPATH", 230 ".for var in MAIL_PROGRAM CMDPATH",
213 "\t"+`${RUN} ${ECHO} "#define ${var} \""${UUCP_${var}}"\""`, 231 "\t"+`${RUN} ${ECHO} "#define ${var} \""${UUCP_${var}}"\""`,
@@ -301,27 +319,27 @@ func (s *Suite) Test_MkLines_CheckForUse @@ -301,27 +319,27 @@ func (s *Suite) Test_MkLines_CheckForUse
301 t.NewMkLines("Makefile.common", 319 t.NewMkLines("Makefile.common",
302 MkRcsID, 320 MkRcsID,
303 "#", 321 "#",
304 "#", 322 "#",
305 ).CheckForUsedComment("category/package") 323 ).CheckForUsedComment("category/package")
306 324
307 t.CheckOutputLines( 325 t.CheckOutputLines(
308 "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.", 326 "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.",
309 "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.") 327 "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.")
310 328
311 c.Check(G.autofixAvailable, equals, true) 329 c.Check(G.autofixAvailable, equals, true)
312} 330}
313 331
314func (s *Suite) Test_MkLines_DetermineDefinedVariables(c *check.C) { 332func (s *Suite) Test_MkLines_collectDefinedVariables(c *check.C) {
315 t := s.Init(c) 333 t := s.Init(c)
316 334
317 t.SetupCommandLine("-Wall,no-space") 335 t.SetupCommandLine("-Wall,no-space")
318 t.SetupPkgsrc() 336 t.SetupPkgsrc()
319 t.CreateFileLines("mk/tools/defaults.mk", 337 t.CreateFileLines("mk/tools/defaults.mk",
320 "USE_TOOLS+= autoconf autoconf213") 338 "USE_TOOLS+= autoconf autoconf213")
321 G.Pkgsrc.LoadInfrastructure() 339 G.Pkgsrc.LoadInfrastructure()
322 mklines := t.NewMkLines("determine-defined-variables.mk", 340 mklines := t.NewMkLines("determine-defined-variables.mk",
323 MkRcsID, 341 MkRcsID,
324 "", 342 "",
325 "USE_TOOLS+= autoconf213 autoconf", 343 "USE_TOOLS+= autoconf213 autoconf",
326 "USE_TOOLS:= ${USE_TOOLS:Ntbl}", 344 "USE_TOOLS:= ${USE_TOOLS:Ntbl}",
327 "", 345 "",
@@ -340,80 +358,80 @@ func (s *Suite) Test_MkLines_DetermineDe @@ -340,80 +358,80 @@ func (s *Suite) Test_MkLines_DetermineDe
340 358
341 mklines.Check() 359 mklines.Check()
342 360
343 // The tools autoreconf and autoheader213 are known at this point because of the USE_TOOLS line. 361 // The tools autoreconf and autoheader213 are known at this point because of the USE_TOOLS line.
344 // The SUV variable is used implicitly by the SUBST framework, therefore no warning. 362 // The SUV variable is used implicitly by the SUBST framework, therefore no warning.
345 // The OSV.NetBSD variable is used implicitly via the OSV variable, therefore no warning. 363 // The OSV.NetBSD variable is used implicitly via the OSV variable, therefore no warning.
346 t.CheckOutputLines( 364 t.CheckOutputLines(
347 // FIXME: the below warning is wrong; it's ok to have SUBST blocks in all files, maybe except buildlink3.mk. 365 // FIXME: the below warning is wrong; it's ok to have SUBST blocks in all files, maybe except buildlink3.mk.
348 "WARN: determine-defined-variables.mk:12: The variable SUBST_VARS.subst may not be set "+ 366 "WARN: determine-defined-variables.mk:12: The variable SUBST_VARS.subst may not be set "+
349 "(only given a default value, appended to) in this file; it would be ok in Makefile, Makefile.common, options.mk.", 367 "(only given a default value, appended to) in this file; it would be ok in Makefile, Makefile.common, options.mk.",
350 "WARN: determine-defined-variables.mk:16: Unknown shell command \"unknown-command\".") 368 "WARN: determine-defined-variables.mk:16: Unknown shell command \"unknown-command\".")
351} 369}
352 370
353func (s *Suite) Test_MkLines_DetermineDefinedVariables__BUILTIN_FIND_FILES_VAR(c *check.C) { 371func (s *Suite) Test_MkLines_collectDefinedVariables__BUILTIN_FIND_FILES_VAR(c *check.C) {
354 t := s.Init(c) 372 t := s.Init(c)
355 373
356 t.SetupCommandLine("-Wall,no-space") 374 t.SetupCommandLine("-Wall,no-space")
357 t.SetupPackage("category/package") 375 t.SetupPackage("category/package")
358 t.CreateFileLines("mk/buildlink3/bsd.builtin.mk", 376 t.CreateFileLines("mk/buildlink3/bsd.builtin.mk",
359 MkRcsID) 377 MkRcsID)
360 mklines := t.SetupFileMkLines("category/package/builtin.mk", 378 mklines := t.SetupFileMkLines("category/package/builtin.mk",
361 MkRcsID, 379 MkRcsID,
362 "", 380 "",
363 "BUILTIN_FIND_FILES_VAR:= H_XFT2", 381 "BUILTIN_FIND_FILES_VAR:= H_XFT2",
364 "BUILTIN_FIND_FILES.H_XFT2= ${X11BASE}/include/X11/Xft/Xft.h", 382 "BUILTIN_FIND_FILES.H_XFT2= ${X11BASE}/include/X11/Xft/Xft.h",
365 "", 383 "",
366 ".include \"../../mk/buildlink3/bsd.builtin.mk\"", 384 ".include \"../../mk/buildlink3/bsd.builtin.mk\"",
367 "", 385 "",
368 ".if ${H_XFT2:N__nonexistent__} && ${H_UNDEF:N__nonexistent__}", 386 ".if ${H_XFT2:N__nonexistent__} && ${H_UNDEF:N__nonexistent__}",
369 ".endif") 387 ".endif")
370 G.Pkgsrc.LoadInfrastructure() 388 G.Pkgsrc.LoadInfrastructure()
371 389
372 mklines.Check() 390 mklines.Check()
373 391
374 t.CheckOutputLines( 392 t.CheckOutputLines(
375 "WARN: ~/category/package/builtin.mk:8: H_UNDEF is used but not defined.") 393 "WARN: ~/category/package/builtin.mk:8: H_UNDEF is used but not defined.")
376} 394}
377 395
378func (s *Suite) Test_MkLines_DetermineUsedVariables__simple(c *check.C) { 396func (s *Suite) Test_MkLines_collectUsedVariables__simple(c *check.C) {
379 t := s.Init(c) 397 t := s.Init(c)
380 398
381 mklines := t.NewMkLines("filename", 399 mklines := t.NewMkLines("filename",
382 "\t${VAR}") 400 "\t${VAR}")
383 mkline := mklines.mklines[0] 401 mkline := mklines.mklines[0]
384 G.Mk = mklines 402 G.Mk = mklines
385 403
386 mklines.DetermineUsedVariables() 404 mklines.collectUsedVariables()
387 405
388 c.Check(len(mklines.vars.used), equals, 1) 406 c.Check(len(mklines.vars.used), equals, 1)
389 c.Check(mklines.vars.FirstUse("VAR"), equals, mkline) 407 c.Check(mklines.vars.FirstUse("VAR"), equals, mkline)
390} 408}
391 409
392func (s *Suite) Test_MkLines_DetermineUsedVariables__nested(c *check.C) { 410func (s *Suite) Test_MkLines_collectUsedVariables__nested(c *check.C) {
393 t := s.Init(c) 411 t := s.Init(c)
394 412
395 mklines := t.NewMkLines("filename.mk", 413 mklines := t.NewMkLines("filename.mk",
396 MkRcsID, 414 MkRcsID,
397 "", 415 "",
398 "LHS.${lparam}=\tRHS.${rparam}", 416 "LHS.${lparam}=\tRHS.${rparam}",
399 "", 417 "",
400 "target:", 418 "target:",
401 "\t${outer.${inner}}") 419 "\t${outer.${inner}}")
402 assignMkline := mklines.mklines[2] 420 assignMkline := mklines.mklines[2]
403 shellMkline := mklines.mklines[5] 421 shellMkline := mklines.mklines[5]
404 G.Mk = mklines 422 G.Mk = mklines
405 423
406 mklines.DetermineUsedVariables() 424 mklines.collectUsedVariables()
407 425
408 c.Check(len(mklines.vars.used), equals, 5) 426 c.Check(len(mklines.vars.used), equals, 5)
409 c.Check(mklines.vars.FirstUse("lparam"), equals, assignMkline) 427 c.Check(mklines.vars.FirstUse("lparam"), equals, assignMkline)
410 c.Check(mklines.vars.FirstUse("rparam"), equals, assignMkline) 428 c.Check(mklines.vars.FirstUse("rparam"), equals, assignMkline)
411 c.Check(mklines.vars.FirstUse("inner"), equals, shellMkline) 429 c.Check(mklines.vars.FirstUse("inner"), equals, shellMkline)
412 c.Check(mklines.vars.FirstUse("outer.*"), equals, shellMkline) 430 c.Check(mklines.vars.FirstUse("outer.*"), equals, shellMkline)
413 c.Check(mklines.vars.FirstUse("outer.${inner}"), equals, shellMkline) 431 c.Check(mklines.vars.FirstUse("outer.${inner}"), equals, shellMkline)
414} 432}
415 433
416func (s *Suite) Test_MkLines__private_tool_undefined(c *check.C) { 434func (s *Suite) Test_MkLines__private_tool_undefined(c *check.C) {
417 t := s.Init(c) 435 t := s.Init(c)
418 436
419 t.SetupVartypes() 437 t.SetupVartypes()
@@ -628,27 +646,27 @@ func (s *Suite) Test_MkLines__wip_catego @@ -628,27 +646,27 @@ func (s *Suite) Test_MkLines__wip_catego
628 "WARN: ~/wip/Makefile:14: Unusual target \"clean-tmpdir\".", 646 "WARN: ~/wip/Makefile:14: Unusual target \"clean-tmpdir\".",
629 "", 647 "",
630 "\tIf you want to define your own target, declare it like this:", 648 "\tIf you want to define your own target, declare it like this:",
631 "", 649 "",
632 "\t\t.PHONY: my-target", 650 "\t\t.PHONY: my-target",
633 "", 651 "",
634 "\tIn the rare case that you actually want a file-based make(1) target,", 652 "\tIn the rare case that you actually want a file-based make(1) target,",
635 "\twrite it like this:", 653 "\twrite it like this:",
636 "", 654 "",
637 "\t\t${.CURDIR}/my-file:", 655 "\t\t${.CURDIR}/my-file:",
638 "") 656 "")
639} 657}
640 658
641func (s *Suite) Test_MkLines_determineDocumentedVariables(c *check.C) { 659func (s *Suite) Test_MkLines_collectDocumentedVariables(c *check.C) {
642 t := s.Init(c) 660 t := s.Init(c)
643 661
644 t.SetupVartypes() 662 t.SetupVartypes()
645 t.SetupTool("rm", "RM", AtRunTime) 663 t.SetupTool("rm", "RM", AtRunTime)
646 mklines := t.NewMkLines("Makefile", 664 mklines := t.NewMkLines("Makefile",
647 MkRcsID, 665 MkRcsID,
648 "#", 666 "#",
649 "# Copyright 2000-2018", 667 "# Copyright 2000-2018",
650 "#", 668 "#",
651 "# This whole comment is ignored, until the next empty line.", 669 "# This whole comment is ignored, until the next empty line.",
652 "", 670 "",
653 "# User-settable variables:", 671 "# User-settable variables:",
654 "#", 672 "#",
@@ -660,27 +678,27 @@ func (s *Suite) Test_MkLines_determineDo @@ -660,27 +678,27 @@ func (s *Suite) Test_MkLines_determineDo
660 "# PKG_VERBOSE", 678 "# PKG_VERBOSE",
661 "#\tWhen this variable is defined, pkgsrc gets a bit more verbose", 679 "#\tWhen this variable is defined, pkgsrc gets a bit more verbose",
662 "#\t(i.e. \"-v\" option is passed to some commands ...", 680 "#\t(i.e. \"-v\" option is passed to some commands ...",
663 "", 681 "",
664 "# VARIABLE", 682 "# VARIABLE",
665 "#\tA paragraph of a single line is not enough to be recognized as \"relevant\".", 683 "#\tA paragraph of a single line is not enough to be recognized as \"relevant\".",
666 "", 684 "",
667 "# VARBASE1.<param1>", 685 "# VARBASE1.<param1>",
668 "# VARBASE2.*", 686 "# VARBASE2.*",
669 "# VARBASE3.${id}") 687 "# VARBASE3.${id}")
670 688
671 // The variables that appear in the documentation are marked as 689 // The variables that appear in the documentation are marked as
672 // used, to prevent the "defined but not used" warnings. 690 // used, to prevent the "defined but not used" warnings.
673 mklines.determineDocumentedVariables() 691 mklines.collectDocumentedVariables()
674 692
675 var varnames []string 693 var varnames []string
676 for varname, mkline := range mklines.vars.used { 694 for varname, mkline := range mklines.vars.used {
677 varnames = append(varnames, fmt.Sprintf("%s (line %s)", varname, mkline.Linenos())) 695 varnames = append(varnames, fmt.Sprintf("%s (line %s)", varname, mkline.Linenos()))
678 } 696 }
679 sort.Strings(varnames) 697 sort.Strings(varnames)
680 698
681 expected := []string{ 699 expected := []string{
682 "PKG_DEBUG_LEVEL (line 9)", 700 "PKG_DEBUG_LEVEL (line 9)",
683 "PKG_VERBOSE (line 14)", 701 "PKG_VERBOSE (line 14)",
684 "VARBASE1.* (line 21)", 702 "VARBASE1.* (line 21)",
685 "VARBASE2.* (line 22)", 703 "VARBASE2.* (line 22)",
686 "VARBASE3.${id} (line 23)", 704 "VARBASE3.${id} (line 23)",
@@ -715,143 +733,143 @@ func (s *Suite) Test_MkLines__unknown_op @@ -715,143 +733,143 @@ func (s *Suite) Test_MkLines__unknown_op
715 mklines := t.NewMkLines("options.mk", 733 mklines := t.NewMkLines("options.mk",
716 MkRcsID, 734 MkRcsID,
717 "#", 735 "#",
718 "PKG_OPTIONS_VAR=\tPKG_OPTIONS.pkgbase", 736 "PKG_OPTIONS_VAR=\tPKG_OPTIONS.pkgbase",
719 "PKG_SUPPORTED_OPTIONS=\tknown unknown", 737 "PKG_SUPPORTED_OPTIONS=\tknown unknown",
720 "PKG_SUGGESTED_OPTIONS=\tknown unknown") 738 "PKG_SUGGESTED_OPTIONS=\tknown unknown")
721 739
722 mklines.Check() 740 mklines.Check()
723 741
724 t.CheckOutputLines( 742 t.CheckOutputLines(
725 "WARN: options.mk:4: Unknown option \"unknown\".") 743 "WARN: options.mk:4: Unknown option \"unknown\".")
726} 744}
727 745
728func (s *Suite) Test_MkLines_CheckRedundantVariables(c *check.C) { 746func (s *Suite) Test_MkLines_CheckRedundantAssignments(c *check.C) {
729 t := s.Init(c) 747 t := s.Init(c)
730 included := t.NewMkLines("module.mk", 748 included := t.NewMkLines("module.mk",
731 "VAR=\tvalue ${OTHER}", 749 "VAR=\tvalue ${OTHER}",
732 "VAR?=\tvalue ${OTHER}", 750 "VAR?=\tvalue ${OTHER}",
733 "VAR=\tnew value") 751 "VAR=\tnew value")
734 makefile := t.NewMkLines("Makefile", 752 makefile := t.NewMkLines("Makefile",
735 "VAR=\tthe package may overwrite variables from other files") 753 "VAR=\tthe package may overwrite variables from other files")
736 allLines := append(append([]Line(nil), included.lines.Lines...), makefile.lines.Lines...) 754 allLines := append(append([]Line(nil), included.lines.Lines...), makefile.lines.Lines...)
737 mklines := NewMkLines(NewLines(included.lines.FileName, allLines)) 755 mklines := NewMkLines(NewLines(included.lines.FileName, allLines))
738 756
739 // XXX: The warnings from here are not in the same order as the other warnings. 757 // XXX: The warnings from here are not in the same order as the other warnings.
740 // XXX: There may be some warnings for the same file separated by warnings for other files. 758 // XXX: There may be some warnings for the same file separated by warnings for other files.
741 mklines.CheckRedundantVariables() 759 mklines.CheckRedundantAssignments()
742 760
743 t.CheckOutputLines( 761 t.CheckOutputLines(
744 "NOTE: module.mk:1: Definition of VAR is redundant because of line 2.", 762 "NOTE: module.mk:1: Definition of VAR is redundant because of line 2.",
745 "WARN: module.mk:1: Variable VAR is overwritten in line 3.") 763 "WARN: module.mk:1: Variable VAR is overwritten in line 3.")
746} 764}
747 765
748func (s *Suite) Test_MkLines_CheckRedundantVariables__different_value(c *check.C) { 766func (s *Suite) Test_MkLines_CheckRedundantAssignments__different_value(c *check.C) {
749 t := s.Init(c) 767 t := s.Init(c)
750 mklines := t.NewMkLines("module.mk", 768 mklines := t.NewMkLines("module.mk",
751 "VAR=\tvalue ${OTHER}", 769 "VAR=\tvalue ${OTHER}",
752 "VAR?=\tdifferent value") 770 "VAR?=\tdifferent value")
753 771
754 mklines.CheckRedundantVariables() 772 mklines.CheckRedundantAssignments()
755 773
756 t.CheckOutputEmpty() 774 t.CheckOutputEmpty()
757} 775}
758 776
759func (s *Suite) Test_MkLines_CheckRedundantVariables__overwrite_same_value(c *check.C) { 777func (s *Suite) Test_MkLines_CheckRedundantAssignments__overwrite_same_value(c *check.C) {
760 t := s.Init(c) 778 t := s.Init(c)
761 mklines := t.NewMkLines("module.mk", 779 mklines := t.NewMkLines("module.mk",
762 "VAR=\tvalue ${OTHER}", 780 "VAR=\tvalue ${OTHER}",
763 "VAR=\tvalue ${OTHER}") 781 "VAR=\tvalue ${OTHER}")
764 782
765 mklines.CheckRedundantVariables() 783 mklines.CheckRedundantAssignments()
766 784
767 t.CheckOutputLines( 785 t.CheckOutputLines(
768 "NOTE: module.mk:1: Definition of VAR is redundant because of line 2.") 786 "NOTE: module.mk:1: Definition of VAR is redundant because of line 2.")
769} 787}
770 788
771func (s *Suite) Test_MkLines_CheckRedundantVariables__procedure_call(c *check.C) { 789func (s *Suite) Test_MkLines_CheckRedundantAssignments__procedure_call(c *check.C) {
772 t := s.Init(c) 790 t := s.Init(c)
773 mklines := t.NewMkLines("mk/pthread.buildlink3.mk", 791 mklines := t.NewMkLines("mk/pthread.buildlink3.mk",
774 "CHECK_BUILTIN.pthread:=\tyes", 792 "CHECK_BUILTIN.pthread:=\tyes",
775 ".include \"../../mk/pthread.builtin.mk\"", 793 ".include \"../../mk/pthread.builtin.mk\"",
776 "CHECK_BUILTIN.pthread:=\tno") 794 "CHECK_BUILTIN.pthread:=\tno")
777 795
778 mklines.CheckRedundantVariables() 796 mklines.CheckRedundantAssignments()
779 797
780 t.CheckOutputEmpty() 798 t.CheckOutputEmpty()
781} 799}
782 800
783func (s *Suite) Test_MkLines_CheckRedundantVariables__shell_and_eval(c *check.C) { 801func (s *Suite) Test_MkLines_CheckRedundantAssignments__shell_and_eval(c *check.C) {
784 t := s.Init(c) 802 t := s.Init(c)
785 mklines := t.NewMkLines("module.mk", 803 mklines := t.NewMkLines("module.mk",
786 "VAR:=\tvalue ${OTHER}", 804 "VAR:=\tvalue ${OTHER}",
787 "VAR!=\tvalue ${OTHER}") 805 "VAR!=\tvalue ${OTHER}")
788 806
789 mklines.CheckRedundantVariables() 807 mklines.CheckRedundantAssignments()
790 808
791 // Combining := and != is too complicated to be analyzed by pkglint, 809 // Combining := and != is too complicated to be analyzed by pkglint,
792 // therefore no warning. 810 // therefore no warning.
793 t.CheckOutputEmpty() 811 t.CheckOutputEmpty()
794} 812}
795 813
796func (s *Suite) Test_MkLines_CheckRedundantVariables__shell_and_eval_literal(c *check.C) { 814func (s *Suite) Test_MkLines_CheckRedundantAssignments__shell_and_eval_literal(c *check.C) {
797 t := s.Init(c) 815 t := s.Init(c)
798 mklines := t.NewMkLines("module.mk", 816 mklines := t.NewMkLines("module.mk",
799 "VAR:=\tvalue", 817 "VAR:=\tvalue",
800 "VAR!=\tvalue") 818 "VAR!=\tvalue")
801 819
802 mklines.CheckRedundantVariables() 820 mklines.CheckRedundantAssignments()
803 821
804 // Even when := is used with a literal value (which is usually 822 // Even when := is used with a literal value (which is usually
805 // only done for procedure calls), the shell evaluation can have 823 // only done for procedure calls), the shell evaluation can have
806 // so many different side effects that pkglint cannot reliably 824 // so many different side effects that pkglint cannot reliably
807 // help in this situation. 825 // help in this situation.
808 t.CheckOutputEmpty() 826 t.CheckOutputEmpty()
809} 827}
810 828
811func (s *Suite) Test_MkLines_Check__PLIST_VARS(c *check.C) { 829func (s *Suite) Test_MkLines_Check__PLIST_VARS(c *check.C) {
812 t := s.Init(c) 830 t := s.Init(c)
813 831
814 t.SetupCommandLine("-Wno-space") 832 t.SetupCommandLine("-Wno-space")
815 t.SetupVartypes() 833 t.SetupVartypes()
816 t.SetupOption("both", "") 834 t.SetupOption("both", "")
817 t.SetupOption("only-added", "") 835 t.SetupOption("only-added", "")
818 t.SetupOption("only-defined", "") 836 t.SetupOption("only-defined", "")
 837 t.CreateFileLines("mk/bsd.options.mk")
819 838
820 mklines := t.SetupFileMkLines("options.mk", 839 mklines := t.SetupFileMkLines("category/package/options.mk",
821 MkRcsID, 840 MkRcsID,
822 "", 841 "",
823 "PKG_OPTIONS_VAR= PKG_OPTIONS.pkg", 842 "PKG_OPTIONS_VAR= PKG_OPTIONS.pkg",
824 "PKG_SUPPORTED_OPTIONS= both only-added only-defined", 843 "PKG_SUPPORTED_OPTIONS= both only-added only-defined",
825 "PKG_SUGGESTED_OPTIONS= # none", 844 "PKG_SUGGESTED_OPTIONS= # none",
826 "", 845 "",
827 ".include \"../../mk/bsd.options.mk\"", 846 ".include \"../../mk/bsd.options.mk\"",
828 "", 847 "",
829 "PLIST_VARS+= both only-added", 848 "PLIST_VARS+= both only-added",
830 "", 849 "",
831 ".if !empty(PKG_OPTIONS:Mboth)", 850 ".if !empty(PKG_OPTIONS:Mboth)",
832 "PLIST.both= yes", 851 "PLIST.both= yes",
833 ".endif", 852 ".endif",
834 "", 853 "",
835 ".if !empty(PKG_OPTIONS:Monly-defined)", 854 ".if !empty(PKG_OPTIONS:Monly-defined)",
836 "PLIST.only-defined= yes", 855 "PLIST.only-defined= yes",
837 ".endif") 856 ".endif")
838 857
839 mklines.Check() 858 mklines.Check()
840 859
841 t.CheckOutputLines( 860 t.CheckOutputLines(
842 "ERROR: ~/options.mk:7: \"mk/bsd.options.mk\" does not exist.", // Not relevant for this test. 861 "WARN: ~/category/package/options.mk:9: \"only-added\" is added to PLIST_VARS, but PLIST.only-added is not defined in this file.",
843 "WARN: ~/options.mk:9: \"only-added\" is added to PLIST_VARS, but PLIST.only-added is not defined in this file.", 862 "WARN: ~/category/package/options.mk:16: PLIST.only-defined is defined, but \"only-defined\" is not added to PLIST_VARS in this file.")
844 "WARN: ~/options.mk:16: PLIST.only-defined is defined, but \"only-defined\" is not added to PLIST_VARS in this file.") 
845} 863}
846 864
847func (s *Suite) Test_MkLines_Check__PLIST_VARS_indirect(c *check.C) { 865func (s *Suite) Test_MkLines_Check__PLIST_VARS_indirect(c *check.C) {
848 t := s.Init(c) 866 t := s.Init(c)
849 867
850 t.SetupCommandLine("-Wno-space") 868 t.SetupCommandLine("-Wno-space")
851 t.SetupVartypes() 869 t.SetupVartypes()
852 t.SetupOption("option1", "") 870 t.SetupOption("option1", "")
853 t.SetupOption("option2", "") 871 t.SetupOption("option2", "")
854 872
855 mklines := t.SetupFileMkLines("module.mk", 873 mklines := t.SetupFileMkLines("module.mk",
856 MkRcsID, 874 MkRcsID,
857 "", 875 "",
@@ -864,27 +882,27 @@ func (s *Suite) Test_MkLines_Check__PLIS @@ -864,27 +882,27 @@ func (s *Suite) Test_MkLines_Check__PLIS
864 ".if 0", 882 ".if 0",
865 "PLIST.option1= yes", 883 "PLIST.option1= yes",
866 ".endif", 884 ".endif",
867 "", 885 "",
868 ".if 1", 886 ".if 1",
869 "PLIST.option2= yes", 887 "PLIST.option2= yes",
870 ".endif") 888 ".endif")
871 889
872 mklines.Check() 890 mklines.Check()
873 891
874 t.CheckOutputEmpty() 892 t.CheckOutputEmpty()
875} 893}
876 894
877func (s *Suite) Test_MkLines_Check__if_else(c *check.C) { 895func (s *Suite) Test_MkLines_collectElse(c *check.C) {
878 t := s.Init(c) 896 t := s.Init(c)
879 897
880 t.SetupCommandLine("-Wno-space") 898 t.SetupCommandLine("-Wno-space")
881 t.SetupVartypes() 899 t.SetupVartypes()
882 900
883 mklines := t.NewMkLines("module.mk", 901 mklines := t.NewMkLines("module.mk",
884 MkRcsID, 902 MkRcsID,
885 "", 903 "",
886 ".if 0", 904 ".if 0",
887 ".endif", 905 ".endif",
888 "", 906 "",
889 ".if 0", 907 ".if 0",
890 ".else", 908 ".else",
@@ -1080,128 +1098,149 @@ func (s *Suite) Test_MkLines_ForEach__co @@ -1080,128 +1098,149 @@ func (s *Suite) Test_MkLines_ForEach__co
1080 c.Check(mklines.indentation.IsConditional(), equals, true) 1098 c.Check(mklines.indentation.IsConditional(), equals, true)
1081 seenDeveloper = true 1099 seenDeveloper = true
1082 case "USES_GETTEXT": 1100 case "USES_GETTEXT":
1083 c.Check(mklines.indentation.IsConditional(), equals, true) 1101 c.Check(mklines.indentation.IsConditional(), equals, true)
1084 seenUsesGettext = true 1102 seenUsesGettext = true
1085 } 1103 }
1086 } 1104 }
1087 }) 1105 })
1088 1106
1089 c.Check(seenDeveloper, equals, true) 1107 c.Check(seenDeveloper, equals, true)
1090 c.Check(seenUsesGettext, equals, true) 1108 c.Check(seenUsesGettext, equals, true)
1091} 1109}
1092 1110
1093func (s *Suite) Test_VaralignBlock_Check__autofix(c *check.C) { 1111// At 2018-12-02, pkglint had resolved ${MY_PLIST_VARS} into a single word,
 1112// whereas the correct behavior is to resolve it into two words.
 1113// It had produced warnings about mismatched PLIST_VARS IDs.
 1114func (s *Suite) Test_MkLines_checkVarassignPlist__indirect(c *check.C) {
 1115 t := s.Init(c)
 1116
 1117 t.SetupVartypes()
 1118 mklines := t.SetupFileMkLines("plist.mk",
 1119 MkRcsID,
 1120 "",
 1121 "MY_PLIST_VARS=\tvar1 var2",
 1122 "PLIST_VARS+=\t${MY_PLIST_VARS}",
 1123 "",
 1124 "PLIST.var1=\tyes",
 1125 "PLIST.var2=\tyes")
 1126
 1127 mklines.Check()
 1128
 1129 t.CheckOutputEmpty()
 1130}
 1131
 1132func (s *Suite) Test_VaralignBlock_Process__autofix(c *check.C) {
1094 t := s.Init(c) 1133 t := s.Init(c)
1095 1134
1096 t.SetupCommandLine("-Wspace", "--show-autofix") 1135 t.SetupCommandLine("-Wspace", "--show-autofix")
1097 1136
1098 mklines := t.NewMkLines("file.mk", 1137 mklines := t.NewMkLines("file.mk",
1099 "VAR= value", // Indentation 7, fixed to 8. 1138 "VAR= value", // Indentation 7, fixed to 8.
1100 "", // 1139 "", //
1101 "VAR= value", // Indentation 8, fixed to 8. 1140 "VAR= value", // Indentation 8, fixed to 8.
1102 "", // 1141 "", //
1103 "VAR= value", // Indentation 9, fixed to 8. 1142 "VAR= value", // Indentation 9, fixed to 8.
1104 "", // 1143 "", //
1105 "VAR= \tvalue", // Mixed indentation 8, fixed to 8. 1144 "VAR= \tvalue", // Mixed indentation 8, fixed to 8.
1106 "", // 1145 "", //
1107 "VAR= \tvalue", // Mixed indentation 8, fixed to 8. 1146 "VAR= \tvalue", // Mixed indentation 8, fixed to 8.
1108 "", // 1147 "", //
1109 "VAR= \tvalue", // Mixed indentation 16, fixed to 16. 1148 "VAR= \tvalue", // Mixed indentation 16, fixed to 16.
1110 "", // 1149 "", //
1111 "VAR=\tvalue") // Already aligned with tabs only, left unchanged. 1150 "VAR=\tvalue") // Already aligned with tabs only, left unchanged.
1112 1151
1113 var varalign VaralignBlock 1152 var varalign VaralignBlock
1114 for _, line := range mklines.mklines { 1153 for _, line := range mklines.mklines {
1115 varalign.Check(line) 1154 varalign.Process(line)
1116 } 1155 }
1117 varalign.Finish() 1156 varalign.Finish()
1118 1157
1119 t.CheckOutputLines( 1158 t.CheckOutputLines(
1120 "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 9.", 1159 "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 9.",
1121 "AUTOFIX: file.mk:1: Replacing \" \" with \"\\t\".", 1160 "AUTOFIX: file.mk:1: Replacing \" \" with \"\\t\".",
1122 "NOTE: file.mk:3: Variable values should be aligned with tabs, not spaces.", 1161 "NOTE: file.mk:3: Variable values should be aligned with tabs, not spaces.",
1123 "AUTOFIX: file.mk:3: Replacing \" \" with \"\\t\".", 1162 "AUTOFIX: file.mk:3: Replacing \" \" with \"\\t\".",
1124 "NOTE: file.mk:5: This variable value should be aligned with tabs, not spaces, to column 9.", 1163 "NOTE: file.mk:5: This variable value should be aligned with tabs, not spaces, to column 9.",
1125 "AUTOFIX: file.mk:5: Replacing \" \" with \"\\t\".", 1164 "AUTOFIX: file.mk:5: Replacing \" \" with \"\\t\".",
1126 "NOTE: file.mk:7: Variable values should be aligned with tabs, not spaces.", 1165 "NOTE: file.mk:7: Variable values should be aligned with tabs, not spaces.",
1127 "AUTOFIX: file.mk:7: Replacing \" \\t\" with \"\\t\".", 1166 "AUTOFIX: file.mk:7: Replacing \" \\t\" with \"\\t\".",
1128 "NOTE: file.mk:9: Variable values should be aligned with tabs, not spaces.", 1167 "NOTE: file.mk:9: Variable values should be aligned with tabs, not spaces.",
1129 "AUTOFIX: file.mk:9: Replacing \" \\t\" with \"\\t\".", 1168 "AUTOFIX: file.mk:9: Replacing \" \\t\" with \"\\t\".",
1130 "NOTE: file.mk:11: Variable values should be aligned with tabs, not spaces.", 1169 "NOTE: file.mk:11: Variable values should be aligned with tabs, not spaces.",
1131 "AUTOFIX: file.mk:11: Replacing \" \\t\" with \"\\t\\t\".") 1170 "AUTOFIX: file.mk:11: Replacing \" \\t\" with \"\\t\\t\".")
1132} 1171}
1133 1172
1134// When the lines of a paragraph are inconsistently aligned, 1173// When the lines of a paragraph are inconsistently aligned,
1135// they are realigned to the minimum required width. 1174// they are realigned to the minimum required width.
1136func (s *Suite) Test_VaralignBlock_Check__reduce_indentation(c *check.C) { 1175func (s *Suite) Test_VaralignBlock_Process__reduce_indentation(c *check.C) {
1137 t := s.Init(c) 1176 t := s.Init(c)
1138 1177
1139 mklines := t.NewMkLines("file.mk", 1178 mklines := t.NewMkLines("file.mk",
1140 "VAR= \tvalue", 1179 "VAR= \tvalue",
1141 "VAR= \tvalue", 1180 "VAR= \tvalue",
1142 "VAR=\t\t\t\tvalue", 1181 "VAR=\t\t\t\tvalue",
1143 "", 1182 "",
1144 "VAR=\t\t\tneedlessly", // Nothing to be fixed here, since it looks good. 1183 "VAR=\t\t\tneedlessly", // Nothing to be fixed here, since it looks good.
1145 "VAR=\t\t\tdeep", 1184 "VAR=\t\t\tdeep",
1146 "VAR=\t\t\tindentation") 1185 "VAR=\t\t\tindentation")
1147 1186
1148 var varalign VaralignBlock 1187 var varalign VaralignBlock
1149 for _, mkline := range mklines.mklines { 1188 for _, mkline := range mklines.mklines {
1150 varalign.Check(mkline) 1189 varalign.Process(mkline)
1151 } 1190 }
1152 varalign.Finish() 1191 varalign.Finish()
1153 1192
1154 t.CheckOutputLines( 1193 t.CheckOutputLines(
1155 "NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.", 1194 "NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.",
1156 "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.", 1195 "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.",
1157 "NOTE: file.mk:3: This variable value should be aligned to column 9.") 1196 "NOTE: file.mk:3: This variable value should be aligned to column 9.")
1158} 1197}
1159 1198
1160// For every variable assignment, there is at least one space or tab between the variable 1199// For every variable assignment, there is at least one space or tab between the variable
1161// name and the value. Even if it is the longest line, and even if the value would start 1200// name and the value. Even if it is the longest line, and even if the value would start
1162// exactly at a tab stop. 1201// exactly at a tab stop.
1163func (s *Suite) Test_VaralignBlock_Check__longest_line_no_space(c *check.C) { 1202func (s *Suite) Test_VaralignBlock_Process__longest_line_no_space(c *check.C) {
1164 t := s.Init(c) 1203 t := s.Init(c)
1165 1204
1166 t.SetupCommandLine("-Wspace") 1205 t.SetupCommandLine("-Wspace")
1167 mklines := t.NewMkLines("file.mk", 1206 mklines := t.NewMkLines("file.mk",
1168 "SUBST_CLASSES+= aaaaaaaa", 1207 "SUBST_CLASSES+= aaaaaaaa",
1169 "SUBST_STAGE.aaaaaaaa= pre-configure", 1208 "SUBST_STAGE.aaaaaaaa= pre-configure",
1170 "SUBST_FILES.aaaaaaaa= *.pl", 1209 "SUBST_FILES.aaaaaaaa= *.pl",
1171 "SUBST_FILTER_CMD.aaaaaa=cat") 1210 "SUBST_FILTER_CMD.aaaaaa=cat")
1172 1211
1173 var varalign VaralignBlock 1212 var varalign VaralignBlock
1174 for _, mkline := range mklines.mklines { 1213 for _, mkline := range mklines.mklines {
1175 varalign.Check(mkline) 1214 varalign.Process(mkline)
1176 } 1215 }
1177 varalign.Finish() 1216 varalign.Finish()
1178 1217
1179 t.CheckOutputLines( 1218 t.CheckOutputLines(
1180 "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.", 1219 "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
1181 "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.", 1220 "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
1182 "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.", 1221 "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
1183 "NOTE: file.mk:4: This variable value should be aligned to column 33.") 1222 "NOTE: file.mk:4: This variable value should be aligned to column 33.")
1184} 1223}
1185 1224
1186func (s *Suite) Test_VaralignBlock_Check__only_spaces(c *check.C) { 1225func (s *Suite) Test_VaralignBlock_Process__only_spaces(c *check.C) {
1187 t := s.Init(c) 1226 t := s.Init(c)
1188 1227
1189 t.SetupCommandLine("-Wspace") 1228 t.SetupCommandLine("-Wspace")
1190 mklines := t.NewMkLines("file.mk", 1229 mklines := t.NewMkLines("file.mk",
1191 "SUBST_CLASSES+= aaaaaaaa", 1230 "SUBST_CLASSES+= aaaaaaaa",
1192 "SUBST_STAGE.aaaaaaaa= pre-configure", 1231 "SUBST_STAGE.aaaaaaaa= pre-configure",
1193 "SUBST_FILES.aaaaaaaa= *.pl", 1232 "SUBST_FILES.aaaaaaaa= *.pl",
1194 "SUBST_FILTER_CMD.aaaaaaaa= cat") 1233 "SUBST_FILTER_CMD.aaaaaaaa= cat")
1195 1234
1196 var varalign VaralignBlock 1235 var varalign VaralignBlock
1197 for _, mkline := range mklines.mklines { 1236 for _, mkline := range mklines.mklines {
1198 varalign.Check(mkline) 1237 varalign.Process(mkline)
1199 } 1238 }
1200 varalign.Finish() 1239 varalign.Finish()
1201 1240
1202 t.CheckOutputLines( 1241 t.CheckOutputLines(
1203 "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.", 1242 "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
1204 "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.", 1243 "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
1205 "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.", 1244 "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
1206 "NOTE: file.mk:4: This variable value should be aligned with tabs, not spaces, to column 33.") 1245 "NOTE: file.mk:4: This variable value should be aligned with tabs, not spaces, to column 33.")
1207} 1246}

cvs diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/Attic/mklines_varalign_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mklines_varalign_test.go 2018/11/07 20:58:23 1.5
+++ pkgsrc/pkgtools/pkglint/files/Attic/mklines_varalign_test.go 2018/12/02 23:12:43 1.6
@@ -51,27 +51,27 @@ func (vt *VaralignTester) run(autofix bo @@ -51,27 +51,27 @@ func (vt *VaralignTester) run(autofix bo
51 cmdline := []string{"-Wall"} 51 cmdline := []string{"-Wall"}
52 if autofix { 52 if autofix {
53 cmdline = append(cmdline, "--autofix") 53 cmdline = append(cmdline, "--autofix")
54 } 54 }
55 if vt.source { 55 if vt.source {
56 cmdline = append(cmdline, "--source") 56 cmdline = append(cmdline, "--source")
57 } 57 }
58 t.SetupCommandLine(cmdline...) 58 t.SetupCommandLine(cmdline...)
59 59
60 mklines := t.SetupFileMkLines("Makefile", vt.input...) 60 mklines := t.SetupFileMkLines("Makefile", vt.input...)
61 61
62 var varalign VaralignBlock 62 var varalign VaralignBlock
63 for _, mkline := range mklines.mklines { 63 for _, mkline := range mklines.mklines {
64 varalign.Check(mkline) 64 varalign.Process(mkline)
65 } 65 }
66 varalign.Finish() 66 varalign.Finish()
67 67
68 if autofix { 68 if autofix {
69 if len(vt.autofixes) > 0 { 69 if len(vt.autofixes) > 0 {
70 t.CheckOutputLines(vt.autofixes...) 70 t.CheckOutputLines(vt.autofixes...)
71 } else { 71 } else {
72 t.CheckOutputEmpty() 72 t.CheckOutputEmpty()
73 } 73 }
74 74
75 SaveAutofixChanges(mklines.lines) 75 SaveAutofixChanges(mklines.lines)
76 t.CheckFileLinesDetab("Makefile", vt.fixed...) 76 t.CheckFileLinesDetab("Makefile", vt.fixed...)
77 } else { 77 } else {

cvs diff -r1.39 -r1.40 pkgsrc/pkgtools/pkglint/files/Attic/package.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/package.go 2018/12/02 01:57:48 1.39
+++ pkgsrc/pkgtools/pkglint/files/Attic/package.go 2018/12/02 23:12:43 1.40
@@ -150,28 +150,28 @@ func (pkg *Package) loadPackageMakefile( @@ -150,28 +150,28 @@ func (pkg *Package) loadPackageMakefile(
150 150
151 if G.Opts.DumpMakefile { 151 if G.Opts.DumpMakefile {
152 G.out.WriteLine("Whole Makefile (with all included files) follows:") 152 G.out.WriteLine("Whole Makefile (with all included files) follows:")
153 for _, line := range allLines.lines.Lines { 153 for _, line := range allLines.lines.Lines {
154 G.out.WriteLine(line.String()) 154 G.out.WriteLine(line.String())
155 } 155 }
156 } 156 }
157 157
158 if pkg.vars.Defined("USE_CMAKE") { 158 if pkg.vars.Defined("USE_CMAKE") {
159 mainLines.Tools.def("cmake", "", false, AtRunTime) 159 mainLines.Tools.def("cmake", "", false, AtRunTime)
160 mainLines.Tools.def("cpack", "", false, AtRunTime) 160 mainLines.Tools.def("cpack", "", false, AtRunTime)
161 } 161 }
162 162
163 allLines.DetermineUsedVariables() 163 allLines.collectUsedVariables()
164 allLines.CheckRedundantVariables() 164 allLines.CheckRedundantAssignments()
165 165
166 pkg.Pkgdir, _ = pkg.vars.Value("PKGDIR") 166 pkg.Pkgdir, _ = pkg.vars.Value("PKGDIR")
167 pkg.DistinfoFile, _ = pkg.vars.Value("DISTINFO_FILE") 167 pkg.DistinfoFile, _ = pkg.vars.Value("DISTINFO_FILE")
168 pkg.Filesdir, _ = pkg.vars.Value("FILESDIR") 168 pkg.Filesdir, _ = pkg.vars.Value("FILESDIR")
169 pkg.Patchdir, _ = pkg.vars.Value("PATCHDIR") 169 pkg.Patchdir, _ = pkg.vars.Value("PATCHDIR")
170 170
171 // See lang/php/ext.mk 171 // See lang/php/ext.mk
172 if varIsDefinedSimilar("PHPEXT_MK") { 172 if varIsDefinedSimilar("PHPEXT_MK") {
173 if !varIsDefinedSimilar("USE_PHP_EXT_PATCHES") { 173 if !varIsDefinedSimilar("USE_PHP_EXT_PATCHES") {
174 pkg.Patchdir = "patches" 174 pkg.Patchdir = "patches"
175 } 175 }
176 if varIsDefinedSimilar("PECL_VERSION") { 176 if varIsDefinedSimilar("PECL_VERSION") {
177 pkg.DistinfoFile = "distinfo" 177 pkg.DistinfoFile = "distinfo"
@@ -207,27 +207,27 @@ func (pkg *Package) readMakefile(filenam @@ -207,27 +207,27 @@ func (pkg *Package) readMakefile(filenam
207 isMainMakefile := len(mainLines.mklines) == 0 207 isMainMakefile := len(mainLines.mklines) == 0
208 208
209 result = true 209 result = true
210 lineAction := func(mkline MkLine) bool { 210 lineAction := func(mkline MkLine) bool {
211 if isMainMakefile { 211 if isMainMakefile {
212 mainLines.mklines = append(mainLines.mklines, mkline) 212 mainLines.mklines = append(mainLines.mklines, mkline)
213 mainLines.lines.Lines = append(mainLines.lines.Lines, mkline.Line) 213 mainLines.lines.Lines = append(mainLines.lines.Lines, mkline.Line)
214 } 214 }
215 allLines.mklines = append(allLines.mklines, mkline) 215 allLines.mklines = append(allLines.mklines, mkline)
216 allLines.lines.Lines = append(allLines.lines.Lines, mkline.Line) 216 allLines.lines.Lines = append(allLines.lines.Lines, mkline.Line)
217 217
218 var includedFile, incDir, incBase string 218 var includedFile, incDir, incBase string
219 if mkline.IsInclude() { 219 if mkline.IsInclude() {
220 includedFile = resolveVariableRefs(mkline.ResolveVarsInRelativePath(mkline.IncludedFile(), true)) 220 includedFile = resolveVariableRefs(mkline.ResolveVarsInRelativePath(mkline.IncludedFile()))
221 if containsVarRef(includedFile) { 221 if containsVarRef(includedFile) {
222 if !contains(filename, "/mk/") { 222 if !contains(filename, "/mk/") {
223 mkline.Notef("Skipping include file %q. This may result in false warnings.", includedFile) 223 mkline.Notef("Skipping include file %q. This may result in false warnings.", includedFile)
224 } 224 }
225 includedFile = "" 225 includedFile = ""
226 } 226 }
227 incDir, incBase = path.Split(includedFile) 227 incDir, incBase = path.Split(includedFile)
228 } 228 }
229 229
230 if includedFile != "" { 230 if includedFile != "" {
231 if mkline.Basename != "buildlink3.mk" { 231 if mkline.Basename != "buildlink3.mk" {
232 if m, bl3File := match1(includedFile, `^\.\./\.\./(.*)/buildlink3\.mk$`); m { 232 if m, bl3File := match1(includedFile, `^\.\./\.\./(.*)/buildlink3\.mk$`); m {
233 pkg.bl3[bl3File] = mkline.Line 233 pkg.bl3[bl3File] = mkline.Line
@@ -743,27 +743,27 @@ func (pkg *Package) checkLocallyModified @@ -743,27 +743,27 @@ func (pkg *Package) checkLocallyModified
743 NewLineWhole(filename).Warnf("Don't commit changes to this file without asking the OWNER, %s.", owner) 743 NewLineWhole(filename).Warnf("Don't commit changes to this file without asking the OWNER, %s.", owner)
744 G.Explain( 744 G.Explain(
745 seeGuide("Package components, Makefile", "components.Makefile")) 745 seeGuide("Package components, Makefile", "components.Makefile"))
746 } 746 }
747 if maintainer != "" { 747 if maintainer != "" {
748 NewLineWhole(filename).Notef("Please only commit changes that %s would approve.", maintainer) 748 NewLineWhole(filename).Notef("Please only commit changes that %s would approve.", maintainer)
749 G.Explain( 749 G.Explain(
750 "See the pkgsrc guide, section \"Package components\",", 750 "See the pkgsrc guide, section \"Package components\",",
751 "keyword \"maintainer\", for more information.") 751 "keyword \"maintainer\", for more information.")
752 } 752 }
753 } 753 }
754} 754}
755 755
756func (pkg *Package) CheckInclude(mkline MkLine, indentation *Indentation) { 756func (pkg *Package) checkIncludeConditionally(mkline MkLine, indentation *Indentation) {
757 conditionalVars := mkline.ConditionalVars() 757 conditionalVars := mkline.ConditionalVars()
758 if len(conditionalVars) == 0 { 758 if len(conditionalVars) == 0 {
759 conditionalVars = indentation.Varnames() 759 conditionalVars = indentation.Varnames()
760 mkline.SetConditionalVars(conditionalVars) 760 mkline.SetConditionalVars(conditionalVars)
761 } 761 }
762 762
763 if path.Dir(abspath(mkline.Filename)) == abspath(pkg.File(".")) { 763 if path.Dir(abspath(mkline.Filename)) == abspath(pkg.File(".")) {
764 includedFile := mkline.IncludedFile() 764 includedFile := mkline.IncludedFile()
765 765
766 if indentation.IsConditional() { 766 if indentation.IsConditional() {
767 pkg.conditionalIncludes[includedFile] = mkline 767 pkg.conditionalIncludes[includedFile] = mkline
768 if other := pkg.unconditionalIncludes[includedFile]; other != nil { 768 if other := pkg.unconditionalIncludes[includedFile]; other != nil {
769 mkline.Warnf("%q is included conditionally here (depending on %s) and unconditionally in %s.", 769 mkline.Warnf("%q is included conditionally here (depending on %s) and unconditionally in %s.",

cvs diff -r1.33 -r1.34 pkgsrc/pkgtools/pkglint/files/Attic/package_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/package_test.go 2018/12/02 01:57:48 1.33
+++ pkgsrc/pkgtools/pkglint/files/Attic/package_test.go 2018/12/02 23:12:43 1.34
@@ -521,27 +521,27 @@ func (s *Suite) Test_Package_loadPackage @@ -521,27 +521,27 @@ func (s *Suite) Test_Package_loadPackage
521 ".if !defined(PECL_VERSION)", 521 ".if !defined(PECL_VERSION)",
522 "DISTINFO_FILE= ${.CURDIR}/${PHPPKGSRCDIR}/distinfo", 522 "DISTINFO_FILE= ${.CURDIR}/${PHPPKGSRCDIR}/distinfo",
523 ".endif", 523 ".endif",
524 ".if defined(USE_PHP_EXT_PATCHES)", 524 ".if defined(USE_PHP_EXT_PATCHES)",
525 "PATCHDIR= ${.CURDIR}/${PHPPKGSRCDIR}/patches", 525 "PATCHDIR= ${.CURDIR}/${PHPPKGSRCDIR}/patches",
526 ".endif") 526 ".endif")
527 pkg := t.SetupPackage("category/package", 527 pkg := t.SetupPackage("category/package",
528 "PECL_VERSION=\t1.1.2", 528 "PECL_VERSION=\t1.1.2",
529 ".include \"../../lang/php/ext.mk\"") 529 ".include \"../../lang/php/ext.mk\"")
530 530
531 G.CheckDirent(pkg) 531 G.CheckDirent(pkg)
532} 532}
533 533
534func (s *Suite) Test_Package_CheckInclude__conditional_and_unconditional_include(c *check.C) { 534func (s *Suite) Test_Package_checkIncludeConditionally__conditional_and_unconditional_include(c *check.C) {
535 t := s.Init(c) 535 t := s.Init(c)
536 536
537 t.SetupVartypes() 537 t.SetupVartypes()
538 t.CreateFileLines("devel/zlib/buildlink3.mk", "") 538 t.CreateFileLines("devel/zlib/buildlink3.mk", "")
539 t.CreateFileLines("licenses/gnu-gpl-v2", "") 539 t.CreateFileLines("licenses/gnu-gpl-v2", "")
540 t.CreateFileLines("mk/bsd.pkg.mk", "") 540 t.CreateFileLines("mk/bsd.pkg.mk", "")
541 t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "") 541 t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "")
542 542
543 t.Chdir("category/package") 543 t.Chdir("category/package")
544 t.CreateFileLines("Makefile", 544 t.CreateFileLines("Makefile",
545 MkRcsID, 545 MkRcsID,
546 "", 546 "",
547 "COMMENT=\tDescription", 547 "COMMENT=\tDescription",
@@ -608,27 +608,27 @@ func (s *Suite) Test_Package__include_af @@ -608,27 +608,27 @@ func (s *Suite) Test_Package__include_af
608 ".if exists(options.mk)", 608 ".if exists(options.mk)",
609 ". include \"options.mk\"", 609 ". include \"options.mk\"",
610 ".endif", 610 ".endif",
611 "", 611 "",
612 ".include \"../../mk/bsd.pkg.mk\"") 612 ".include \"../../mk/bsd.pkg.mk\"")
613 613
614 G.checkdirPackage(".") 614 G.checkdirPackage(".")
615 615
616 t.CheckOutputLines( 616 t.CheckOutputLines(
617 "WARN: Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.", 617 "WARN: Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
618 "WARN: distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.", 618 "WARN: distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
619 "ERROR: Makefile: Each package must define its LICENSE.", 619 "ERROR: Makefile: Each package must define its LICENSE.",
620 "WARN: Makefile: No COMMENT given.", 620 "WARN: Makefile: No COMMENT given.",
621 "ERROR: Makefile:4: \"options.mk\" does not exist.") 621 "ERROR: Makefile:4: Relative path \"options.mk\" does not exist.")
622} 622}
623 623
624// See https://github.com/rillig/pkglint/issues/1 624// See https://github.com/rillig/pkglint/issues/1
625func (s *Suite) Test_Package_readMakefile__include_other_after_exists(c *check.C) { 625func (s *Suite) Test_Package_readMakefile__include_other_after_exists(c *check.C) {
626 t := s.Init(c) 626 t := s.Init(c)
627 627
628 t.SetupVartypes() 628 t.SetupVartypes()
629 t.CreateFileLines("mk/bsd.pkg.mk") 629 t.CreateFileLines("mk/bsd.pkg.mk")
630 t.CreateFileLines("category/package/Makefile", 630 t.CreateFileLines("category/package/Makefile",
631 MkRcsID, 631 MkRcsID,
632 "", 632 "",
633 ".if exists(options.mk)", 633 ".if exists(options.mk)",
634 ". include \"another.mk\"", 634 ". include \"another.mk\"",

cvs diff -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/Attic/substcontext.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/substcontext.go 2018/12/02 01:57:48 1.16
+++ pkgsrc/pkgtools/pkglint/files/Attic/substcontext.go 2018/12/02 23:12:43 1.17
@@ -147,27 +147,27 @@ func (ctx *SubstContext) Varassign(mklin @@ -147,27 +147,27 @@ func (ctx *SubstContext) Varassign(mklin
147 147
148 case "SUBST_FILES.*": 148 case "SUBST_FILES.*":
149 ctx.dupBool(mkline, &ctx.curr.seenFiles, varname, op, value) 149 ctx.dupBool(mkline, &ctx.curr.seenFiles, varname, op, value)
150 150
151 case "SUBST_SED.*": 151 case "SUBST_SED.*":
152 ctx.dupBool(mkline, &ctx.curr.seenSed, varname, op, value) 152 ctx.dupBool(mkline, &ctx.curr.seenSed, varname, op, value)
153 ctx.curr.seenTransform = true 153 ctx.curr.seenTransform = true
154 154
155 ctx.suggestSubstVars(mkline) 155 ctx.suggestSubstVars(mkline)
156 156
157 case "SUBST_VARS.*": 157 case "SUBST_VARS.*":
158 ctx.dupBool(mkline, &ctx.curr.seenVars, varname, op, value) 158 ctx.dupBool(mkline, &ctx.curr.seenVars, varname, op, value)
159 ctx.curr.seenTransform = true 159 ctx.curr.seenTransform = true
160 for _, substVar := range mkline.ValueFields(value) { 160 for _, substVar := range mkline.Fields() {
161 if ctx.vars == nil { 161 if ctx.vars == nil {
162 ctx.vars = make(map[string]bool) 162 ctx.vars = make(map[string]bool)
163 } 163 }
164 ctx.vars[substVar] = true 164 ctx.vars[substVar] = true
165 } 165 }
166 166
167 case "SUBST_FILTER_CMD.*": 167 case "SUBST_FILTER_CMD.*":
168 ctx.dupString(mkline, &ctx.filterCmd, varname, value) 168 ctx.dupString(mkline, &ctx.filterCmd, varname, value)
169 ctx.curr.seenTransform = true 169 ctx.curr.seenTransform = true
170 } 170 }
171} 171}
172 172
173func (ctx *SubstContext) Directive(mkline MkLine) { 173func (ctx *SubstContext) Directive(mkline MkLine) {

cvs diff -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/Attic/tools_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/tools_test.go 2018/12/02 01:57:48 1.8
+++ pkgsrc/pkgtools/pkglint/files/Attic/tools_test.go 2018/12/02 23:12:43 1.9
@@ -245,52 +245,52 @@ func (s *Suite) Test_Tools__builtin_mk(c @@ -245,52 +245,52 @@ func (s *Suite) Test_Tools__builtin_mk(c
245 "_TOOLS_VARNAME.load= LOAD", 245 "_TOOLS_VARNAME.load= LOAD",
246 "_TOOLS_VARNAME.run= RUN_CMD", 246 "_TOOLS_VARNAME.run= RUN_CMD",
247 "_TOOLS_VARNAME.nowhere= NOWHERE") 247 "_TOOLS_VARNAME.nowhere= NOWHERE")
248 t.CreateFileLines("mk/bsd.prefs.mk", 248 t.CreateFileLines("mk/bsd.prefs.mk",
249 "USE_TOOLS+= load") 249 "USE_TOOLS+= load")
250 t.CreateFileLines("mk/bsd.pkg.mk", 250 t.CreateFileLines("mk/bsd.pkg.mk",
251 "USE_TOOLS+= run") 251 "USE_TOOLS+= run")
252 t.CreateFileLines("mk/buildlink3/bsd.builtin.mk") 252 t.CreateFileLines("mk/buildlink3/bsd.builtin.mk")
253 G.Pkgsrc.LoadInfrastructure() 253 G.Pkgsrc.LoadInfrastructure()
254 254
255 // Tools that are defined by pkgsrc as load-time tools 255 // Tools that are defined by pkgsrc as load-time tools
256 // may be used in any file at load time. 256 // may be used in any file at load time.
257 257
258 mklines := t.SetupFileMkLines("builtin.mk", 258 mklines := t.SetupFileMkLines("category/package/builtin.mk",
259 MkRcsID, 259 MkRcsID,
260 "", 260 "",
261 "VAR!= ${ECHO} 'too early'", 261 "VAR!= ${ECHO} 'too early'",
262 "VAR!= ${LOAD} 'too early'", 262 "VAR!= ${LOAD} 'too early'",
263 "VAR!= ${RUN_CMD} 'never allowed'", 263 "VAR!= ${RUN_CMD} 'never allowed'",
264 "VAR!= ${NOWHERE} 'never allowed'", 264 "VAR!= ${NOWHERE} 'never allowed'",
265 "", 265 "",
266 ".include \"../../mk/buildlink3/bsd.builtin.mk\"", 266 ".include \"../../mk/buildlink3/bsd.builtin.mk\"",
267 "", 267 "",
268 "VAR!= ${ECHO} 'valid'", 268 "VAR!= ${ECHO} 'valid'",
269 "VAR!= ${LOAD} 'valid'", 269 "VAR!= ${LOAD} 'valid'",
270 "VAR!= ${RUN_CMD} 'never allowed'", 270 "VAR!= ${RUN_CMD} 'never allowed'",
271 "VAR!= ${NOWHERE} 'never allowed'", 271 "VAR!= ${NOWHERE} 'never allowed'",
272 "", 272 "",
273 "VAR!= ${VAR}") 273 "VAR!= ${VAR}")
274 274
275 mklines.Check() 275 mklines.Check()
276 276
277 t.CheckOutputLines( 277 t.CheckOutputLines(
278 "WARN: ~/builtin.mk:3: To use the tool ${ECHO} at load time, bsd.prefs.mk has to be included before.", 278 "WARN: ~/category/package/builtin.mk:3: To use the tool ${ECHO} at load time, bsd.prefs.mk has to be included before.",
279 "WARN: ~/builtin.mk:4: To use the tool ${LOAD} at load time, bsd.prefs.mk has to be included before.", 279 "WARN: ~/category/package/builtin.mk:4: To use the tool ${LOAD} at load time, bsd.prefs.mk has to be included before.",
280 "WARN: ~/builtin.mk:5: The tool ${RUN_CMD} cannot be used at load time.", 280 "WARN: ~/category/package/builtin.mk:5: The tool ${RUN_CMD} cannot be used at load time.",
281 "WARN: ~/builtin.mk:6: The tool ${NOWHERE} cannot be used at load time.", 281 "WARN: ~/category/package/builtin.mk:6: The tool ${NOWHERE} cannot be used at load time.",
282 "WARN: ~/builtin.mk:12: The tool ${RUN_CMD} cannot be used at load time.", 282 "WARN: ~/category/package/builtin.mk:12: The tool ${RUN_CMD} cannot be used at load time.",
283 "WARN: ~/builtin.mk:13: The tool ${NOWHERE} cannot be used at load time.") 283 "WARN: ~/category/package/builtin.mk:13: The tool ${NOWHERE} cannot be used at load time.")
284} 284}
285 285
286func (s *Suite) Test_Tools__implicit_definition_in_bsd_pkg_mk(c *check.C) { 286func (s *Suite) Test_Tools__implicit_definition_in_bsd_pkg_mk(c *check.C) {
287 t := s.Init(c) 287 t := s.Init(c)
288 288
289 t.SetupPkgsrc() 289 t.SetupPkgsrc()
290 t.SetupCommandLine("-Wall,no-space") 290 t.SetupCommandLine("-Wall,no-space")
291 t.CreateFileLines("mk/tools/defaults.mk", 291 t.CreateFileLines("mk/tools/defaults.mk",
292 MkRcsID) // None 292 MkRcsID) // None
293 t.CreateFileLines("mk/bsd.prefs.mk", 293 t.CreateFileLines("mk/bsd.prefs.mk",
294 "USE_TOOLS+= load") 294 "USE_TOOLS+= load")
295 t.CreateFileLines("mk/bsd.pkg.mk", 295 t.CreateFileLines("mk/bsd.pkg.mk",
296 "USE_TOOLS+= run") 296 "USE_TOOLS+= run")

cvs diff -r1.50 -r1.51 pkgsrc/pkgtools/pkglint/files/Attic/vardefs.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/vardefs.go 2018/12/02 01:57:48 1.50
+++ pkgsrc/pkgtools/pkglint/files/Attic/vardefs.go 2018/12/02 23:12:43 1.51
@@ -131,27 +131,27 @@ func (src *Pkgsrc) InitVartypes() { @@ -131,27 +131,27 @@ func (src *Pkgsrc) InitVartypes() {
131 if !contains(word, "$") { 131 if !contains(word, "$") {
132 values[word] = true 132 values[word] = true
133 } 133 }
134 } 134 }
135 } 135 }
136 } 136 }
137 } 137 }
138 } 138 }
139 } 139 }
140 140
141 if len(values) > 0 { 141 if len(values) > 0 {
142 joined := keysJoined(values) 142 joined := keysJoined(values)
143 if trace.Tracing { 143 if trace.Tracing {
144 trace.Stepf("Enum from %s in: %s", strings.Join(varcanons, " "), filename, joined) 144 trace.Stepf("Enum from %s in %s with values: %s", strings.Join(varcanons, " "), filename, joined)
145 } 145 }
146 return enum(joined) 146 return enum(joined)
147 } 147 }
148 148
149 if trace.Tracing { 149 if trace.Tracing {
150 trace.Stepf("Enum from default value: %s", defval) 150 trace.Stepf("Enum from default value: %s", defval)
151 } 151 }
152 return enum(defval) 152 return enum(defval)
153 } 153 }
154 154
155 // enumFromDirs reads the directories from category, takes all 155 // enumFromDirs reads the directories from category, takes all
156 // that have a single number in them and ranks them from earliest 156 // that have a single number in them and ranks them from earliest
157 // to latest. 157 // to latest.
@@ -477,26 +477,27 @@ func (src *Pkgsrc) InitVartypes() { @@ -477,26 +477,27 @@ func (src *Pkgsrc) InitVartypes() {
477 usrpkg("WCALC_HTMLDIR", lkNone, BtPathname) 477 usrpkg("WCALC_HTMLDIR", lkNone, BtPathname)
478 usrpkg("WCALC_HTMLPATH", lkNone, BtPathname) // URL path 478 usrpkg("WCALC_HTMLPATH", lkNone, BtPathname) // URL path
479 usrpkg("WCALC_CGIDIR", lkNone, BtPrefixPathname) 479 usrpkg("WCALC_CGIDIR", lkNone, BtPrefixPathname)
480 usrpkg("WCALC_CGIPATH", lkNone, BtPathname) // URL path 480 usrpkg("WCALC_CGIPATH", lkNone, BtPathname) // URL path
481 usrpkg("WDM_MANAGERS", lkShell, BtIdentifier) 481 usrpkg("WDM_MANAGERS", lkShell, BtIdentifier)
482 usrpkg("X10_PORT", lkNone, BtPathname) 482 usrpkg("X10_PORT", lkNone, BtPathname)
483 usrpkg("XAW_TYPE", lkNone, enum("standard 3d xpm neXtaw")) 483 usrpkg("XAW_TYPE", lkNone, enum("standard 3d xpm neXtaw"))
484 usrpkg("XLOCK_DEFAULT_MODE", lkNone, BtIdentifier) 484 usrpkg("XLOCK_DEFAULT_MODE", lkNone, BtIdentifier)
485 usrpkg("ZSH_STATIC", lkNone, BtYes) 485 usrpkg("ZSH_STATIC", lkNone, BtYes)
486 486
487 // some other variables, sorted alphabetically 487 // some other variables, sorted alphabetically
488 488
489 acl(".CURDIR", lkNone, BtPathname, "buildlink3.mk:; *: use, use-loadtime") 489 acl(".CURDIR", lkNone, BtPathname, "buildlink3.mk:; *: use, use-loadtime")
 490 acl(".IMPSRC", lkShell, BtPathname, "buildlink3.mk:; *: use, use-loadtime")
490 acl(".TARGET", lkNone, BtPathname, "buildlink3.mk:; *: use, use-loadtime") 491 acl(".TARGET", lkNone, BtPathname, "buildlink3.mk:; *: use, use-loadtime")
491 acl("@", lkNone, BtPathname, "buildlink3.mk:; *: use, use-loadtime") 492 acl("@", lkNone, BtPathname, "buildlink3.mk:; *: use, use-loadtime")
492 acl("ALL_ENV", lkShell, BtShellWord, "") 493 acl("ALL_ENV", lkShell, BtShellWord, "")
493 acl("ALTERNATIVES_FILE", lkNone, BtFileName, "") 494 acl("ALTERNATIVES_FILE", lkNone, BtFileName, "")
494 acl("ALTERNATIVES_SRC", lkShell, BtPathname, "") 495 acl("ALTERNATIVES_SRC", lkShell, BtPathname, "")
495 pkg("APACHE_MODULE", lkNone, BtYes) 496 pkg("APACHE_MODULE", lkNone, BtYes)
496 sys("AR", lkNone, BtShellCommand) 497 sys("AR", lkNone, BtShellCommand)
497 sys("AS", lkNone, BtShellCommand) 498 sys("AS", lkNone, BtShellCommand)
498 pkglist("AUTOCONF_REQD", lkShell, BtVersion) 499 pkglist("AUTOCONF_REQD", lkShell, BtVersion)
499 acl("AUTOMAKE_OVERRIDE", lkShell, BtPathmask, "") 500 acl("AUTOMAKE_OVERRIDE", lkShell, BtPathmask, "")
500 pkglist("AUTOMAKE_REQD", lkShell, BtVersion) 501 pkglist("AUTOMAKE_REQD", lkShell, BtVersion)
501 pkg("AUTO_MKDIRS", lkNone, BtYesNo) 502 pkg("AUTO_MKDIRS", lkNone, BtYesNo)
502 usr("BATCH", lkNone, BtYes) 503 usr("BATCH", lkNone, BtYes)

cvs diff -r1.36 -r1.37 pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck_test.go 2018/12/02 01:57:48 1.36
+++ pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck_test.go 2018/12/02 23:12:43 1.37
@@ -206,27 +206,27 @@ func (s *Suite) Test_VartypeCheck_Depend @@ -206,27 +206,27 @@ func (s *Suite) Test_VartypeCheck_Depend
206 "broken[0-9]*../../x11/alacarte", 206 "broken[0-9]*../../x11/alacarte",
207 "broken>=:../../x11/alacarte", 207 "broken>=:../../x11/alacarte",
208 "broken=0:../../x11/alacarte", 208 "broken=0:../../x11/alacarte",
209 "broken=:../../x11/alacarte", 209 "broken=:../../x11/alacarte",
210 "broken-:../../x11/alacarte", 210 "broken-:../../x11/alacarte",
211 "broken>:../../x11/alacarte", 211 "broken>:../../x11/alacarte",
212 "gtk2+>=2.16:../../x11/alacarte", 212 "gtk2+>=2.16:../../x11/alacarte",
213 "gettext-[0-9]*:../../devel/gettext", 213 "gettext-[0-9]*:../../devel/gettext",
214 "gmake-[0-9]*:../../devel/gmake") 214 "gmake-[0-9]*:../../devel/gmake")
215 215
216 vt.Output( 216 vt.Output(
217 "WARN: ~/category/package/filename.mk:1: Invalid dependency pattern with path \"Perl\".", 217 "WARN: ~/category/package/filename.mk:1: Invalid dependency pattern with path \"Perl\".",
218 "WARN: ~/category/package/filename.mk:2: Dependencies should have the form \"../../category/package\".", 218 "WARN: ~/category/package/filename.mk:2: Dependencies should have the form \"../../category/package\".",
219 "ERROR: ~/category/package/filename.mk:3: \"../../lang/perl5\" does not exist.", 219 "ERROR: ~/category/package/filename.mk:3: Relative path \"../../lang/perl5\" does not exist.",
220 "ERROR: ~/category/package/filename.mk:3: There is no package in \"lang/perl5\".", 220 "ERROR: ~/category/package/filename.mk:3: There is no package in \"lang/perl5\".",
221 "WARN: ~/category/package/filename.mk:3: Please use USE_TOOLS+=perl:run instead of this dependency.", 221 "WARN: ~/category/package/filename.mk:3: Please use USE_TOOLS+=perl:run instead of this dependency.",
222 "WARN: ~/category/package/filename.mk:4: Invalid dependency pattern \"broken0.12.1\".", 222 "WARN: ~/category/package/filename.mk:4: Invalid dependency pattern \"broken0.12.1\".",
223 "WARN: ~/category/package/filename.mk:5: Invalid dependency pattern \"broken[0-9]*\".", 223 "WARN: ~/category/package/filename.mk:5: Invalid dependency pattern \"broken[0-9]*\".",
224 "WARN: ~/category/package/filename.mk:6: Invalid dependency pattern with path \"broken[0-9]*../../x11/alacarte\".", 224 "WARN: ~/category/package/filename.mk:6: Invalid dependency pattern with path \"broken[0-9]*../../x11/alacarte\".",
225 "WARN: ~/category/package/filename.mk:7: Invalid dependency pattern \"broken>=\".", 225 "WARN: ~/category/package/filename.mk:7: Invalid dependency pattern \"broken>=\".",
226 "WARN: ~/category/package/filename.mk:8: Invalid dependency pattern \"broken=0\".", 226 "WARN: ~/category/package/filename.mk:8: Invalid dependency pattern \"broken=0\".",
227 "WARN: ~/category/package/filename.mk:9: Invalid dependency pattern \"broken=\".", 227 "WARN: ~/category/package/filename.mk:9: Invalid dependency pattern \"broken=\".",
228 "WARN: ~/category/package/filename.mk:10: Invalid dependency pattern \"broken-\".", 228 "WARN: ~/category/package/filename.mk:10: Invalid dependency pattern \"broken-\".",
229 "WARN: ~/category/package/filename.mk:11: Invalid dependency pattern \"broken>\".", 229 "WARN: ~/category/package/filename.mk:11: Invalid dependency pattern \"broken>\".",
230 "WARN: ~/category/package/filename.mk:13: Please use USE_TOOLS+=msgfmt instead of this dependency.", 230 "WARN: ~/category/package/filename.mk:13: Please use USE_TOOLS+=msgfmt instead of this dependency.",
231 "WARN: ~/category/package/filename.mk:14: Please use USE_TOOLS+=gmake instead of this dependency.") 231 "WARN: ~/category/package/filename.mk:14: Please use USE_TOOLS+=gmake instead of this dependency.")
232} 232}
@@ -295,27 +295,27 @@ func (s *Suite) Test_VartypeCheck_Enum__ @@ -295,27 +295,27 @@ func (s *Suite) Test_VartypeCheck_Enum__
295 mklines := t.NewMkLines("module.mk", 295 mklines := t.NewMkLines("module.mk",
296 MkRcsID, 296 MkRcsID,
297 "", 297 "",
298 ".if !empty(MACHINE_ARCH:Mi386) || ${MACHINE_ARCH} == i386", 298 ".if !empty(MACHINE_ARCH:Mi386) || ${MACHINE_ARCH} == i386",
299 ".endif", 299 ".endif",
300 ".if !empty(PKGSRC_COMPILER:Mclang) || ${PKGSRC_COMPILER} == clang", 300 ".if !empty(PKGSRC_COMPILER:Mclang) || ${PKGSRC_COMPILER} == clang",
301 ".endif", 301 ".endif",
302 ".if ${MACHINE_ARCH:Ni386:Nx86_64:Nsparc64}", 302 ".if ${MACHINE_ARCH:Ni386:Nx86_64:Nsparc64}",
303 ".endif") 303 ".endif")
304 304
305 mklines.Check() 305 mklines.Check()
306 306
307 t.CheckOutputLines( 307 t.CheckOutputLines(
308 "NOTE: module.mk:3: MACHINE_ARCH should be compared using == instead of the :M or :N modifier without wildcards.", 308 "NOTE: module.mk:3: MACHINE_ARCH should be compared using == instead of matching against \":Mi386\".",
309 "WARN: module.mk:5: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.") 309 "WARN: module.mk:5: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.")
310} 310}
311 311
312func (s *Suite) Test_VartypeCheck_FetchURL(c *check.C) { 312func (s *Suite) Test_VartypeCheck_FetchURL(c *check.C) {
313 t := s.Init(c) 313 t := s.Init(c)
314 vt := NewVartypeCheckTester(t, (*VartypeCheck).FetchURL) 314 vt := NewVartypeCheckTester(t, (*VartypeCheck).FetchURL)
315 315
316 t.SetupMasterSite("MASTER_SITE_GNU", "http://ftp.gnu.org/pub/gnu/") 316 t.SetupMasterSite("MASTER_SITE_GNU", "http://ftp.gnu.org/pub/gnu/")
317 t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/") 317 t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/")
318 318
319 vt.Varname("MASTER_SITES") 319 vt.Varname("MASTER_SITES")
320 vt.Values( 320 vt.Values(
321 "https://github.com/example/project/", 321 "https://github.com/example/project/",
@@ -514,27 +514,27 @@ func (s *Suite) Test_VartypeCheck_LdFlag @@ -514,27 +514,27 @@ func (s *Suite) Test_VartypeCheck_LdFlag
514 vt.Output( 514 vt.Output(
515 "WARN: filename:4: Unknown linker flag \"-unknown\".", 515 "WARN: filename:4: Unknown linker flag \"-unknown\".",
516 "WARN: filename:5: Linker flag \"no-hyphen\" should start with a hyphen.", 516 "WARN: filename:5: Linker flag \"no-hyphen\" should start with a hyphen.",
517 "WARN: filename:6: Please use \"${COMPILER_RPATH_FLAG}\" instead of \"-Wl,--rpath\".") 517 "WARN: filename:6: Please use \"${COMPILER_RPATH_FLAG}\" instead of \"-Wl,--rpath\".")
518} 518}
519 519
520func (s *Suite) Test_VartypeCheck_License(c *check.C) { 520func (s *Suite) Test_VartypeCheck_License(c *check.C) {
521 t := s.Init(c) 521 t := s.Init(c)
522 t.SetupPkgsrc() // Adds the gnu-gpl-v2 and 2-clause-bsd licenses 522 t.SetupPkgsrc() // Adds the gnu-gpl-v2 and 2-clause-bsd licenses
523 523
524 G.Mk = t.NewMkLines("perl5.mk", 524 G.Mk = t.NewMkLines("perl5.mk",
525 MkRcsID, 525 MkRcsID,
526 "PERL5_LICENSE= gnu-gpl-v2 OR artistic") 526 "PERL5_LICENSE= gnu-gpl-v2 OR artistic")
527 G.Mk.DetermineDefinedVariables() 527 G.Mk.collectDefinedVariables()
528 528
529 vt := NewVartypeCheckTester(t, (*VartypeCheck).License) 529 vt := NewVartypeCheckTester(t, (*VartypeCheck).License)
530 530
531 vt.Varname("LICENSE") 531 vt.Varname("LICENSE")
532 vt.Values( 532 vt.Values(
533 "gnu-gpl-v2", 533 "gnu-gpl-v2",
534 "AND mit", 534 "AND mit",
535 "${PERL5_LICENSE}", // Is properly resolved, see perl5.mk above. 535 "${PERL5_LICENSE}", // Is properly resolved, see perl5.mk above.
536 "${UNKNOWN_LICENSE}") 536 "${UNKNOWN_LICENSE}")
537 537
538 vt.Output( 538 vt.Output(
539 "ERROR: filename:2: Parse error for license condition \"AND mit\".", 539 "ERROR: filename:2: Parse error for license condition \"AND mit\".",
540 "WARN: filename:3: License file ~/licenses/artistic does not exist.", 540 "WARN: filename:3: License file ~/licenses/artistic does not exist.",
@@ -743,29 +743,29 @@ func (s *Suite) Test_VartypeCheck_PkgPat @@ -743,29 +743,29 @@ func (s *Suite) Test_VartypeCheck_PkgPat
743 vt := NewVartypeCheckTester(t, (*VartypeCheck).PkgPath) 743 vt := NewVartypeCheckTester(t, (*VartypeCheck).PkgPath)
744 744
745 t.CreateFileLines("category/other-package/Makefile") 745 t.CreateFileLines("category/other-package/Makefile")
746 t.Chdir("category/package") 746 t.Chdir("category/package")
747 747
748 vt.Varname("PKGPATH") 748 vt.Varname("PKGPATH")
749 vt.Values( 749 vt.Values(
750 "category/other-package", 750 "category/other-package",
751 "${OTHER_VAR}", 751 "${OTHER_VAR}",
752 "invalid", 752 "invalid",
753 "../../invalid/relative") 753 "../../invalid/relative")
754 754
755 vt.Output( 755 vt.Output(
756 "ERROR: filename:3: \"../../invalid\" does not exist.", 756 "ERROR: filename:3: Relative path \"../../invalid\" does not exist.",
757 "WARN: filename:3: \"../../invalid\" is not a valid relative package directory.", 757 "WARN: filename:3: \"../../invalid\" is not a valid relative package directory.",
758 "ERROR: filename:4: \"../../../../invalid/relative\" does not exist.", 758 "ERROR: filename:4: Relative path \"../../../../invalid/relative\" does not exist.",
759 "WARN: filename:4: \"../../../../invalid/relative\" is not a valid relative package directory.") 759 "WARN: filename:4: \"../../../../invalid/relative\" is not a valid relative package directory.")
760} 760}
761 761
762func (s *Suite) Test_VartypeCheck_PkgRevision(c *check.C) { 762func (s *Suite) Test_VartypeCheck_PkgRevision(c *check.C) {
763 vt := NewVartypeCheckTester(s.Init(c), (*VartypeCheck).PkgRevision) 763 vt := NewVartypeCheckTester(s.Init(c), (*VartypeCheck).PkgRevision)
764 764
765 vt.Varname("PKGREVISION") 765 vt.Varname("PKGREVISION")
766 vt.Values( 766 vt.Values(
767 "3a") 767 "3a")
768 768
769 vt.Output( 769 vt.Output(
770 "WARN: filename:1: PKGREVISION must be a positive integer number.", 770 "WARN: filename:1: PKGREVISION must be a positive integer number.",
771 "ERROR: filename:1: PKGREVISION only makes sense directly in the package Makefile.") 771 "ERROR: filename:1: PKGREVISION only makes sense directly in the package Makefile.")
@@ -852,29 +852,29 @@ func (s *Suite) Test_VartypeCheck_Relati @@ -852,29 +852,29 @@ func (s *Suite) Test_VartypeCheck_Relati
852 852
853 t.CreateFileLines("category/other-package/Makefile") 853 t.CreateFileLines("category/other-package/Makefile")
854 t.Chdir("category/package") 854 t.Chdir("category/package")
855 855
856 vt.Varname("DISTINFO_FILE") 856 vt.Varname("DISTINFO_FILE")
857 vt.Values( 857 vt.Values(
858 "category/other-package", 858 "category/other-package",
859 "../../category/other-package", 859 "../../category/other-package",
860 "${OTHER_VAR}", 860 "${OTHER_VAR}",
861 "invalid", 861 "invalid",
862 "../../invalid/relative") 862 "../../invalid/relative")
863 863
864 vt.Output( 864 vt.Output(
865 "ERROR: filename:1: \"category/other-package\" does not exist.", 865 "ERROR: filename:1: Relative path \"category/other-package\" does not exist.",
866 "ERROR: filename:4: \"invalid\" does not exist.", 866 "ERROR: filename:4: Relative path \"invalid\" does not exist.",
867 "ERROR: filename:5: \"../../invalid/relative\" does not exist.") 867 "ERROR: filename:5: Relative path \"../../invalid/relative\" does not exist.")
868} 868}
869 869
870func (s *Suite) Test_VartypeCheck_Restricted(c *check.C) { 870func (s *Suite) Test_VartypeCheck_Restricted(c *check.C) {
871 vt := NewVartypeCheckTester(s.Init(c), (*VartypeCheck).Restricted) 871 vt := NewVartypeCheckTester(s.Init(c), (*VartypeCheck).Restricted)
872 872
873 vt.Varname("NO_BIN_ON_CDROM") 873 vt.Varname("NO_BIN_ON_CDROM")
874 vt.Values( 874 vt.Values(
875 "May only be distributed free of charge") 875 "May only be distributed free of charge")
876 876
877 vt.Output( 877 vt.Output(
878 "WARN: filename:1: The only valid value for NO_BIN_ON_CDROM is ${RESTRICTED}.") 878 "WARN: filename:1: The only valid value for NO_BIN_ON_CDROM is ${RESTRICTED}.")
879} 879}
880 880