diff options
author | rillig <rillig@pkgsrc.org> | 2019-11-01 19:56:52 +0000 |
---|---|---|
committer | rillig <rillig@pkgsrc.org> | 2019-11-01 19:56:52 +0000 |
commit | 1780979c3ee38c9797427d7dfa96fed153e37349 (patch) | |
tree | 1a2095a273bb1874a64c21385c0ee256592f89f9 /pkgtools | |
parent | 032a3d5a8a86713c153ade17bf7173829d4d0f20 (diff) | |
download | pkgsrc-1780979c3ee38c9797427d7dfa96fed153e37349.tar.gz |
pkgtools/pkglint: update to 19.3.4
Changes since 19.3.3:
In cases where the conditions for including buildlink3.mk files differ
between the package itself and its own buildlink3.mk file, explain how
to determine PKG_OPTIONS for dependencies.
Don't issue wrong warnings in options.mk files when the options are
handled in a .for loop.
Diffstat (limited to 'pkgtools')
-rw-r--r-- | pkgtools/pkglint/Makefile | 4 | ||||
-rw-r--r-- | pkgtools/pkglint/files/category.go | 2 | ||||
-rw-r--r-- | pkgtools/pkglint/files/category_test.go | 4 | ||||
-rw-r--r-- | pkgtools/pkglint/files/check_test.go | 3 | ||||
-rw-r--r-- | pkgtools/pkglint/files/mklinechecker.go | 11 | ||||
-rw-r--r-- | pkgtools/pkglint/files/mktypes.go | 8 | ||||
-rw-r--r-- | pkgtools/pkglint/files/mktypes_test.go | 41 | ||||
-rwxr-xr-x | pkgtools/pkglint/files/options.go | 80 | ||||
-rwxr-xr-x | pkgtools/pkglint/files/options_test.go | 98 | ||||
-rw-r--r-- | pkgtools/pkglint/files/package.go | 24 | ||||
-rw-r--r-- | pkgtools/pkglint/files/package_test.go | 105 | ||||
-rw-r--r-- | pkgtools/pkglint/files/pkglint.go | 27 | ||||
-rw-r--r-- | pkgtools/pkglint/files/toplevel.go | 2 | ||||
-rw-r--r-- | pkgtools/pkglint/files/util.go | 31 | ||||
-rw-r--r-- | pkgtools/pkglint/files/vardefs.go | 46 |
15 files changed, 388 insertions, 98 deletions
diff --git a/pkgtools/pkglint/Makefile b/pkgtools/pkglint/Makefile index e6a7c80c24a..f34bbdb4784 100644 --- a/pkgtools/pkglint/Makefile +++ b/pkgtools/pkglint/Makefile @@ -1,6 +1,6 @@ -# $NetBSD: Makefile,v 1.603 2019/10/26 11:43:36 rillig Exp $ +# $NetBSD: Makefile,v 1.604 2019/11/01 19:56:52 rillig Exp $ -PKGNAME= pkglint-19.3.3 +PKGNAME= pkglint-19.3.4 CATEGORIES= pkgtools DISTNAME= tools MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/} diff --git a/pkgtools/pkglint/files/category.go b/pkgtools/pkglint/files/category.go index f068419edc5..5d1a66d5cf5 100644 --- a/pkgtools/pkglint/files/category.go +++ b/pkgtools/pkglint/files/category.go @@ -161,6 +161,6 @@ func CheckdirCategory(dir string) { recurseInto = append(recurseInto, joinPath(dir, msub.name)) } } - G.Todo = append(recurseInto, G.Todo...) + G.Todo.PushFront(recurseInto...) } } diff --git a/pkgtools/pkglint/files/category_test.go b/pkgtools/pkglint/files/category_test.go index e279d41fee0..6d6a8a10499 100644 --- a/pkgtools/pkglint/files/category_test.go +++ b/pkgtools/pkglint/files/category_test.go @@ -208,12 +208,12 @@ func (s *Suite) Test_CheckdirCategory__recursive(c *check.C) { // It is only removed in Pkglint.Main, therefore it stays there even // after the call to CheckdirCategory. This is a bit unrealistic, // but close enough for this test. - t.CheckDeepEquals(G.Todo, []string{"."}) + t.CheckDeepEquals(G.Todo.entries, []string{"."}) CheckdirCategory(".") t.CheckOutputEmpty() - t.CheckDeepEquals(G.Todo, []string{"./package", "."}) + t.CheckDeepEquals(G.Todo.entries, []string{"./package", "."}) } // Ensures that a directory in the file system can be added at the very diff --git a/pkgtools/pkglint/files/check_test.go b/pkgtools/pkglint/files/check_test.go index 1dabb5237d2..289b86d8110 100644 --- a/pkgtools/pkglint/files/check_test.go +++ b/pkgtools/pkglint/files/check_test.go @@ -69,6 +69,7 @@ func (s *Suite) SetUpTest(c *check.C) { t.c = c t.SetUpCommandLine("-Wall") // To catch duplicate warnings + G.Todo.Pop() // The "." was inserted by default. t.seenSetUpCommandLine = false // This default call doesn't count. // To improve code coverage and ensure that trace.Result works @@ -693,6 +694,8 @@ func (t *Tester) FinishSetUp() { // // Arguments that name existing files or directories in the temporary test // directory are transformed to their actual paths. +// +// Does not work in combination with SetUpOption. func (t *Tester) Main(args ...string) int { if t.seenFinish && !t.seenMain { t.Errorf("Calling t.FinishSetup() before t.Main() is redundant " + diff --git a/pkgtools/pkglint/files/mklinechecker.go b/pkgtools/pkglint/files/mklinechecker.go index 3446a0ea5fd..df63a57fa7c 100644 --- a/pkgtools/pkglint/files/mklinechecker.go +++ b/pkgtools/pkglint/files/mklinechecker.go @@ -437,16 +437,9 @@ func (ck MkLineChecker) checkVarassignLeftRationale() { return } - needsRationale := func(mkline *MkLine) bool { - if !mkline.IsVarassignMaybeCommented() { - return false - } - vartype := G.Pkgsrc.VariableType(ck.MkLines, mkline.Varname()) - return vartype != nil && vartype.NeedsRationale() - } - mkline := ck.MkLine - if !needsRationale(mkline) { + vartype := G.Pkgsrc.VariableType(ck.MkLines, mkline.Varname()) + if vartype == nil || !vartype.NeedsRationale() { return } diff --git a/pkgtools/pkglint/files/mktypes.go b/pkgtools/pkglint/files/mktypes.go index 8212d3ff34e..e1bb9d30b8a 100644 --- a/pkgtools/pkglint/files/mktypes.go +++ b/pkgtools/pkglint/files/mktypes.go @@ -89,13 +89,15 @@ func (m MkVarUseModifier) Subst(str string) (string, bool) { // MatchMatch tries to match the modifier to a :M or a :N pattern matching. // Examples: -// :Mpattern => true, true, "pattern" -// :Npattern => true, false, "pattern" +// :Mpattern => true, true, "pattern", true +// :M* => true, true, "*", false +// :M${VAR} => true, true, "${VAR}", false +// :Npattern => true, false, "pattern", true // :X => false func (m MkVarUseModifier) MatchMatch() (ok bool, positive bool, pattern string, exact bool) { if hasPrefix(m.Text, "M") || hasPrefix(m.Text, "N") { // See devel/bmake/files/str.c:^Str_Match - exact := !strings.ContainsAny(m.Text[1:], "*?[\\") + exact := !strings.ContainsAny(m.Text[1:], "*?[\\$") return true, m.Text[0] == 'M', m.Text[1:], exact } return false, false, "", false diff --git a/pkgtools/pkglint/files/mktypes_test.go b/pkgtools/pkglint/files/mktypes_test.go index 6c18f15907a..fd89c22f40b 100644 --- a/pkgtools/pkglint/files/mktypes_test.go +++ b/pkgtools/pkglint/files/mktypes_test.go @@ -39,6 +39,16 @@ func (MkTokenBuilder) VarUse(varname string, modifiers ...string) *MkVarUse { return &MkVarUse{varname, mods} } +// AddCommand adds a command directly to a list of commands, +// creating all the intermediate nodes for the syntactic representation. +// As soon as that representation is replaced with a semantic representation, +// this method should no longer be necessary. +func (list *MkShList) AddCommand(command *MkShCommand) *MkShList { + pipeline := NewMkShPipeline(false, []*MkShCommand{command}) + andOr := NewMkShAndOr(pipeline) + return list.AddAndOr(andOr) +} + func (s *Suite) Test_MkVarUse_Mod(c *check.C) { t := s.Init(c) @@ -53,14 +63,29 @@ func (s *Suite) Test_MkVarUse_Mod(c *check.C) { test("${PATH:ts::Q}", ":ts::Q") } -// AddCommand adds a command directly to a list of commands, -// creating all the intermediate nodes for the syntactic representation. -// As soon as that representation is replaced with a semantic representation, -// this method should no longer be necessary. -func (list *MkShList) AddCommand(command *MkShCommand) *MkShList { - pipeline := NewMkShPipeline(false, []*MkShCommand{command}) - andOr := NewMkShAndOr(pipeline) - return list.AddAndOr(andOr) +func (s *Suite) Test_MkVarUseModifier_MatchMatch(c *check.C) { + t := s.Init(c) + + testFail := func(modifier string) { + mod := MkVarUseModifier{modifier} + ok, _, _, _ := mod.MatchMatch() + t.CheckEquals(ok, false) + } + test := func(modifier string, positive bool, pattern string, exact bool) { + mod := MkVarUseModifier{modifier} + actualOk, actualPositive, actualPattern, actualExact := mod.MatchMatch() + t.CheckDeepEquals( + []interface{}{actualOk, actualPositive, actualPattern, actualExact}, + []interface{}{true, positive, pattern, exact}) + } + + testFail("") + testFail("X") + + test("Mpattern", true, "pattern", true) + test("M*", true, "*", false) + test("M${VAR}", true, "${VAR}", false) + test("Npattern", false, "pattern", true) } func (s *Suite) Test_MkVarUseModifier_ChangesWords(c *check.C) { diff --git a/pkgtools/pkglint/files/options.go b/pkgtools/pkglint/files/options.go index ea238b348f7..2100fadcbc0 100755 --- a/pkgtools/pkglint/files/options.go +++ b/pkgtools/pkglint/files/options.go @@ -1,7 +1,5 @@ package pkglint -import "path" - func CheckLinesOptionsMk(mklines *MkLines) { ck := OptionsLinesChecker{ mklines, @@ -42,10 +40,13 @@ func (ck *OptionsLinesChecker) Check() { mlex.Skip() } - for !mlex.EOF() { - ck.handleLowerLine(mlex.CurrentMkLine()) - mlex.Skip() - } + i := 0 + mklines.ForEach(func(mkline *MkLine) { + if i >= mlex.index { + ck.handleLowerLine(mkline) + } + i++ + }) ck.checkOptionsMismatch() @@ -81,7 +82,10 @@ func (ck *OptionsLinesChecker) handleUpperLine(mkline *MkLine) bool { case mkline.IsVarassign(): switch mkline.Varcanon() { - case "PKG_SUPPORTED_OPTIONS", "PKG_OPTIONS_GROUP.*", "PKG_OPTIONS_SET.*": + case "PKG_SUPPORTED_OPTIONS", + "PKG_SUPPORTED_OPTIONS.*", + "PKG_OPTIONS_GROUP.*", + "PKG_OPTIONS_SET.*": for _, option := range mkline.ValueFields(mkline.Value()) { if !containsVarRef(option) { ck.declaredOptions[option] = mkline @@ -113,48 +117,64 @@ func (ck *OptionsLinesChecker) handleUpperLine(mkline *MkLine) bool { } func (ck *OptionsLinesChecker) handleLowerLine(mkline *MkLine) { - if mkline.IsDirective() { - directive := mkline.Directive() - if directive == "if" || directive == "elif" { - cond := mkline.Cond() - if cond != nil { - ck.handleLowerCondition(mkline, cond) - } - } + if !mkline.IsDirective() { + return + } + + directive := mkline.Directive() + if directive != "if" && directive != "elif" { + return + } + + cond := mkline.Cond() + if cond == nil { + return } + + ck.handleLowerCondition(mkline, cond) } func (ck *OptionsLinesChecker) handleLowerCondition(mkline *MkLine, cond *MkCond) { - recordUsedOption := func(varuse *MkVarUse) { - if varuse.varname != "PKG_OPTIONS" || len(varuse.modifiers) != 1 { + recordOption := func(option string) { + if containsVarRef(option) { return } - m, positive, pattern, exact := varuse.modifiers[0].MatchMatch() - if !m || !positive || containsVarRef(pattern) { + ck.handledOptions[option] = mkline + ck.optionsInDeclarationOrder = append(ck.optionsInDeclarationOrder, option) + } + + recordVarUse := func(varuse *MkVarUse) { + if varuse.varname != "PKG_OPTIONS" || len(varuse.modifiers) != 1 { return } - if exact { - option := pattern - ck.handledOptions[option] = mkline - ck.optionsInDeclarationOrder = append(ck.optionsInDeclarationOrder, option) + m, positive, pattern, exact := varuse.modifiers[0].MatchMatch() + if !m || !positive { return } - for declaredOption := range ck.declaredOptions { - matched, err := path.Match(pattern, declaredOption) - if err == nil && matched { - ck.handledOptions[declaredOption] = mkline - ck.optionsInDeclarationOrder = append(ck.optionsInDeclarationOrder, declaredOption) + if optionVarUse := ToVarUse(pattern); optionVarUse != nil { + for _, option := range ck.mklines.ExpandLoopVar(optionVarUse.varname) { + recordOption(option) + } + + } else if exact { + recordOption(pattern) + + } else { + for declaredOption := range ck.declaredOptions { + if pathMatches(pattern, declaredOption) { + recordOption(declaredOption) + } } } } cond.Walk(&MkCondCallback{ - Empty: recordUsedOption, - Var: recordUsedOption}) + Empty: recordVarUse, + Var: recordVarUse}) if cond.Empty != nil && cond.Empty.varname == "PKG_OPTIONS" && mkline.HasElseBranch() { mkline.Notef("The positive branch of the .if/.else should be the one where the option is set.") diff --git a/pkgtools/pkglint/files/options_test.go b/pkgtools/pkglint/files/options_test.go index 77dba48ce9d..61986f2af9d 100755 --- a/pkgtools/pkglint/files/options_test.go +++ b/pkgtools/pkglint/files/options_test.go @@ -387,3 +387,101 @@ func (s *Suite) Test_CheckLinesOptionsMk__combined_option_handling_coverage(c *c t.CheckOutputLines( "WARN: options.mk:4: Option \"opt-variant\" should be handled below in an .if block.") } + +func (s *Suite) Test_CheckLinesOptionsMk__options_in_for_loop(c *check.C) { + t := s.Init(c) + + t.SetUpOption("idea", "") + t.SetUpOption("md2", "") + t.SetUpOption("md5", "") + t.SetUpOption("other", "") + t.CreateFileLines("mk/bsd.options.mk") + t.SetUpPackage("category/package", + ".include \"options.mk\"") + t.CreateFileLines("category/package/options.mk", + MkCvsID, + "", + "PKG_OPTIONS_VAR=\tPKG_OPTIONS.package", + "PKG_SUPPORTED_OPTIONS=\tidea md2 md5 other", + "", + ".include \"../../mk/bsd.options.mk\"", + "", + ".for alg in idea md2 md5", + ". if ${PKG_OPTIONS:M${alg}}", + ". endif", + ".endfor") + t.FinishSetUp() + t.Chdir("category/package") + + G.Check(".") + + t.CheckOutputLines( + "WARN: options.mk:4: Option \"other\" should be handled below in an .if block.") +} + +func (s *Suite) Test_CheckLinesOptionsMk__indirect(c *check.C) { + t := s.Init(c) + + t.SetUpOption("generic", "") + t.SetUpOption("netbsd", "") + t.SetUpOption("os", "") + t.CreateFileLines("mk/bsd.options.mk") + t.SetUpPackage("category/package", + ".include \"options.mk\"") + t.CreateFileLines("category/package/options.mk", + MkCvsID, + "", + "PKG_OPTIONS_VAR=\tPKG_OPTIONS.package", + "PKG_SUPPORTED_OPTIONS=\tgeneric", + "PKG_SUGGESTED_OPTIONS=\tgeneric", + "", + "PKG_SUPPORTED_OPTIONS.FreeBSD=\tos", + "PKG_SUGGESTED_OPTIONS.FreeBSD=\tos", + "", + "PKG_SUPPORTED_OPTIONS.NetBSD+=\tnetbsd os", + "PKG_SUGGESTED_OPTIONS.NetBSD+=\tnetbsd os", + "", + ".include \"../../mk/bsd.options.mk\"", + "", + "PLIST_VARS+=\tgeneric netbsd os", + "", + ".for option in ${PLIST_VARS}", + ". if ${PKG_OPTIONS:M${option}}", + "CONFIGURE_ARGS+=\t--enable-${option:S/-/_/}", + "PLIST.${option}=\tyes", + ". endif", + ".endfor") + t.FinishSetUp() + t.Chdir("category/package") + + G.Check(".") + + t.CheckOutputEmpty() +} + +// An unrealistic scenario, but necessary for code coverage. +func (s *Suite) Test_CheckLinesOptionsMk__partly_indirect(c *check.C) { + t := s.Init(c) + + t.CreateFileLines("mk/bsd.options.mk") + t.SetUpPackage("category/package", + ".include \"options.mk\"") + t.CreateFileLines("category/package/options.mk", + MkCvsID, + "", + "PKG_OPTIONS_VAR=\tPKG_OPTIONS.package", + "PKG_SUPPORTED_OPTIONS=\tgeneric-${OPSYS}", + "", + ".include \"../../mk/bsd.options.mk\"", + "", + ".for option in generic-${OPSYS}", + ". if ${PKG_OPTIONS:M${option}}", + ". endif", + ".endfor") + t.FinishSetUp() + t.Chdir("category/package") + + G.Check(".") + + t.CheckOutputEmpty() +} diff --git a/pkgtools/pkglint/files/package.go b/pkgtools/pkglint/files/package.go index 5f1e75dc7c3..bdfd012dc4e 100644 --- a/pkgtools/pkglint/files/package.go +++ b/pkgtools/pkglint/files/package.go @@ -1272,6 +1272,18 @@ func (pkg *Package) checkIncludeConditionally(mkline *MkLine, indentation *Inden key := pkg.Rel(mkline.IncludedFileFull()) + explainPkgOptions := func(uncond *MkLine, cond *MkLine) { + if uncond.Basename == "buildlink3.mk" && containsStr(cond.ConditionalVars(), "PKG_OPTIONS") { + mkline.Explain( + "When including a dependent file, the conditions in the", + "buildlink3.mk file should be the same as in options.mk", + "or the Makefile.", + "", + "To find out the PKG_OPTIONS of this package at build time,", + "have a look at mk/pkg-build-options.mk.") + } + } + if indentation.IsConditional() { if other := pkg.unconditionalIncludes[key]; other != nil { if !pkg.Once.FirstTimeSlice("checkIncludeConditionally", mkline.Location.String(), other.Location.String()) { @@ -1282,6 +1294,8 @@ func (pkg *Package) checkIncludeConditionally(mkline *MkLine, indentation *Inden "%q is included conditionally here (depending on %s) "+ "and unconditionally in %s.", cleanpath(mkline.IncludedFile()), strings.Join(mkline.ConditionalVars(), ", "), mkline.RefTo(other)) + + explainPkgOptions(other, mkline) } } else { @@ -1295,15 +1309,7 @@ func (pkg *Package) checkIncludeConditionally(mkline *MkLine, indentation *Inden "and conditionally in %s (depending on %s).", cleanpath(mkline.IncludedFile()), mkline.RefTo(other), strings.Join(other.ConditionalVars(), ", ")) - if mkline.Basename == "buildlink3.mk" && containsStr(other.ConditionalVars(), "PKG_OPTIONS") { - mkline.Explain( - "When including a dependent file, the conditions in the", - "buildlink3.mk file should be the same as in options.mk", - "or the Makefile.", - "", - "To find out the PKG_OPTIONS of this package at build time,", - "have a look at mk/pkg-build-options.mk.") - } + explainPkgOptions(mkline, other) } } diff --git a/pkgtools/pkglint/files/package_test.go b/pkgtools/pkglint/files/package_test.go index 7873af65b1b..b6a8fd6091e 100644 --- a/pkgtools/pkglint/files/package_test.go +++ b/pkgtools/pkglint/files/package_test.go @@ -1288,6 +1288,111 @@ func (s *Suite) Test_Package_checkIncludeConditionally__conditional_and_uncondit "WARN: options.mk:3: Expected definition of PKG_OPTIONS_VAR.") } +func (s *Suite) Test_Package_checkIncludeConditionally__explain_PKG_OPTIONS_in_Makefile(c *check.C) { + t := s.Init(c) + + t.SetUpCommandLine("-Wall", "--explain") + t.SetUpOption("zlib", "use zlib compression") + + t.CreateFileLines("mk/bsd.options.mk", + MkCvsID) + t.CreateFileLines("devel/zlib/buildlink3.mk", + MkCvsID) + t.SetUpPackage("category/package", + "PKG_OPTIONS_VAR=\tPKG_OPTIONS.package", + "PKG_SUPPORTED_OPTIONS=\tzlib", + "", + ".include \"../../mk/bsd.options.mk\"", + "", + ".if ${PKG_OPTIONS:Mzlib}", + ".include \"../../devel/zlib/buildlink3.mk\"", + ".endif") + t.CreateFileDummyBuildlink3("category/package/buildlink3.mk", + ".include \"../../devel/zlib/buildlink3.mk\"") + t.Chdir("category/package") + t.FinishSetUp() + + G.checkdirPackage(".") + + t.CheckOutputLines( + "WARN: Makefile:26: "+ + "\"../../devel/zlib/buildlink3.mk\" is included conditionally here "+ + "(depending on PKG_OPTIONS) and unconditionally in buildlink3.mk:12.", + "", + "\tWhen including a dependent file, the conditions in the buildlink3.mk", + "\tfile should be the same as in options.mk or the Makefile.", + "", + "\tTo find out the PKG_OPTIONS of this package at build time, have a", + "\tlook at mk/pkg-build-options.mk.", + "") +} + +func (s *Suite) Test_Package_checkIncludeConditionally__no_explanation(c *check.C) { + t := s.Init(c) + + t.SetUpCommandLine("-Wall", "--explain") + t.CreateFileLines("devel/zlib/buildlink3.mk", + MkCvsID) + t.SetUpPackage("category/package", + ".if ${OPSYS} == Linux", + ".include \"../../devel/zlib/buildlink3.mk\"", + ".endif") + t.CreateFileDummyBuildlink3("category/package/buildlink3.mk", + ".include \"../../devel/zlib/buildlink3.mk\"") + t.Chdir("category/package") + t.FinishSetUp() + + G.checkdirPackage(".") + + t.CheckOutputLines( + "WARN: Makefile:21: " + + "\"../../devel/zlib/buildlink3.mk\" is included conditionally here " + + "(depending on OPSYS) and unconditionally in buildlink3.mk:12.") +} + +func (s *Suite) Test_Package_checkIncludeConditionally__explain_PKG_OPTIONS_in_options_mk(c *check.C) { + t := s.Init(c) + + t.SetUpCommandLine("-Wall", "--explain") + t.SetUpOption("zlib", "use zlib compression") + + t.CreateFileLines("mk/bsd.options.mk", + MkCvsID) + t.CreateFileLines("devel/zlib/buildlink3.mk", + MkCvsID) + t.SetUpPackage("category/package", + ".include \"options.mk\"") + t.CreateFileLines("category/package/options.mk", + MkCvsID, + "", + "PKG_OPTIONS_VAR=\tPKG_OPTIONS.package", + "PKG_SUPPORTED_OPTIONS=\tzlib", + "", + ".include \"../../mk/bsd.options.mk\"", + "", + ".if ${PKG_OPTIONS:Mzlib}", + ".include \"../../devel/zlib/buildlink3.mk\"", + ".endif") + t.CreateFileDummyBuildlink3("category/package/buildlink3.mk", + ".include \"../../devel/zlib/buildlink3.mk\"") + t.Chdir("category/package") + t.FinishSetUp() + + G.checkdirPackage(".") + + t.CheckOutputLines( + "WARN: buildlink3.mk:12: "+ + "\"../../devel/zlib/buildlink3.mk\" is included unconditionally here "+ + "and conditionally in options.mk:9 (depending on PKG_OPTIONS).", + "", + "\tWhen including a dependent file, the conditions in the buildlink3.mk", + "\tfile should be the same as in options.mk or the Makefile.", + "", + "\tTo find out the PKG_OPTIONS of this package at build time, have a", + "\tlook at mk/pkg-build-options.mk.", + "") +} + func (s *Suite) Test_Package_checkIncludeConditionally__unconditionally_first(c *check.C) { t := s.Init(c) diff --git a/pkgtools/pkglint/files/pkglint.go b/pkgtools/pkglint/files/pkglint.go index 252d476137b..05efef29622 100644 --- a/pkgtools/pkglint/files/pkglint.go +++ b/pkgtools/pkglint/files/pkglint.go @@ -26,12 +26,12 @@ type Pkglint struct { Pkgsrc Pkgsrc // Global data, mostly extracted from mk/*. Pkg *Package // The package that is currently checked, or nil. - Todo []string // The files or directories that still need to be checked. - Wip bool // Is the currently checked file or package from pkgsrc-wip? - Infrastructure bool // Is the currently checked file from the pkgsrc infrastructure? - Testing bool // Is pkglint in self-testing mode (only during development)? - Experimental bool // For experimental features, only enabled individually in tests - Username string // For checking against OWNER and MAINTAINER + Todo StringQueue // The files or directories that still need to be checked. + Wip bool // Is the currently checked file or package from pkgsrc-wip? + Infrastructure bool // Is the currently checked file from the pkgsrc infrastructure? + Testing bool // Is pkglint in self-testing mode (only during development)? + Experimental bool // For experimental features, only enabled individually in tests + Username string // For checking against OWNER and MAINTAINER cvsEntriesDir string // Cached to avoid I/O cvsEntries map[string]CvsEntry @@ -190,10 +190,8 @@ func (pkglint *Pkglint) Main(stdout io.Writer, stderr io.Writer, args []string) pkglint.prepareMainLoop() - for len(pkglint.Todo) > 0 { - item := pkglint.Todo[0] - pkglint.Todo = pkglint.Todo[1:] - pkglint.Check(item) + for !pkglint.Todo.Empty() { + pkglint.Check(pkglint.Todo.Pop()) } pkglint.Pkgsrc.checkToplevelUnusedLicenses() @@ -258,7 +256,7 @@ func (pkglint *Pkglint) setUpProfiling() func() { } func (pkglint *Pkglint) prepareMainLoop() { - firstDir := pkglint.Todo[0] + firstDir := pkglint.Todo.Front() if fileExists(firstDir) { firstDir = path.Dir(firstDir) } @@ -333,12 +331,11 @@ func (pkglint *Pkglint) ParseCommandLine(args []string) int { return 0 } - pkglint.Todo = nil for _, arg := range pkglint.Opts.args { - pkglint.Todo = append(pkglint.Todo, filepath.ToSlash(arg)) + pkglint.Todo.Push(filepath.ToSlash(arg)) } - if len(pkglint.Todo) == 0 { - pkglint.Todo = []string{"."} + if pkglint.Todo.Empty() { + pkglint.Todo.Push(".") } return -1 diff --git a/pkgtools/pkglint/files/toplevel.go b/pkgtools/pkglint/files/toplevel.go index 71af8aa6c87..a11d1dff856 100644 --- a/pkgtools/pkglint/files/toplevel.go +++ b/pkgtools/pkglint/files/toplevel.go @@ -31,7 +31,7 @@ func CheckdirToplevel(dir string) { if G.Opts.CheckGlobal { G.InterPackage.Enable() } - G.Todo = append(append([]string(nil), ctx.subdirs...), G.Todo...) + G.Todo.PushFront(ctx.subdirs...) } } diff --git a/pkgtools/pkglint/files/util.go b/pkgtools/pkglint/files/util.go index b2634f7b6fb..70594ac6751 100644 --- a/pkgtools/pkglint/files/util.go +++ b/pkgtools/pkglint/files/util.go @@ -1384,3 +1384,34 @@ func shquote(s string) string { } return "'" + strings.Replace(s, "'", "'\\''", -1) + "'" } + +func pathMatches(pattern, s string) bool { + matched, err := path.Match(pattern, s) + return err == nil && matched +} + +type StringQueue struct { + entries []string +} + +func (q *StringQueue) PushFront(entries ...string) { + q.entries = append(append([]string(nil), entries...), q.entries...) +} + +func (q *StringQueue) Push(entries ...string) { + q.entries = append(q.entries, entries...) +} + +func (q *StringQueue) Empty() bool { + return len(q.entries) == 0 +} + +func (q *StringQueue) Front() string { + return q.entries[0] +} + +func (q *StringQueue) Pop() string { + front := q.entries[0] + q.entries = q.entries[1:] + return front +} diff --git a/pkgtools/pkglint/files/vardefs.go b/pkgtools/pkglint/files/vardefs.go index 4e1aa236d28..4c98824323e 100644 --- a/pkgtools/pkglint/files/vardefs.go +++ b/pkgtools/pkglint/files/vardefs.go @@ -156,6 +156,17 @@ func (reg *VarTypeRegistry) pkglistrat(varname string, basicType *BasicType) { "Makefile, Makefile.*, *.mk: default, set, append, use") } +// A package-defined load-time list may be used or defined or appended to in +// all Makefiles except buildlink3.mk and builtin.mk. Simple assignment +// (instead of appending) is also allowed. If this leads to an unconditional +// assignment overriding a previous value, the redundancy check will catch it. +func (reg *VarTypeRegistry) pkgloadlist(varname string, basicType *BasicType) { + reg.acllist(varname, basicType, + List|PackageSettable, + "buildlink3.mk, builtin.mk: none", + "Makefile, Makefile.*, *.mk: default, set, append, use, use-loadtime") +} + // pkgappend declares a variable that may use the += operator, // even though it is not a list where each item can be interpreted // on its own. @@ -328,7 +339,7 @@ func (reg *VarTypeRegistry) compilerLanguages(src *Pkgsrc) *BasicType { VarUse: func(varuse *MkVarUse) { if varuse.varname == "USE_LANGUAGES" && len(varuse.modifiers) == 1 { ok, _, pattern, exact := varuse.modifiers[0].MatchMatch() - if ok && exact && !containsVarRef(pattern) { + if ok && exact { languages[intern(pattern)] = true } } @@ -1409,28 +1420,27 @@ func (reg *VarTypeRegistry) Init(src *Pkgsrc) { // define them in the Makefile or Makefile.common. reg.sysloadlist("PKG_OPTIONS", BtOption) reg.usrlist("PKG_OPTIONS.*", BtOption) - opt := reg.pkg - optlist := reg.pkglist - optlist("PKG_LEGACY_OPTIONS", BtOption) - optlist("PKG_OPTIONS_DEPRECATED_WARNINGS", BtShellWord) - optlist("PKG_OPTIONS_GROUP.*", BtOption) - optlist("PKG_OPTIONS_LEGACY_OPTS", BtUnknown) - optlist("PKG_OPTIONS_LEGACY_VARS", BtUnknown) - optlist("PKG_OPTIONS_NONEMPTY_SETS", BtIdentifier) - optlist("PKG_OPTIONS_OPTIONAL_GROUPS", BtIdentifier) - optlist("PKG_OPTIONS_REQUIRED_GROUPS", BtIdentifier) - optlist("PKG_OPTIONS_SET.*", BtOption) - opt("PKG_OPTIONS_VAR", BtPkgOptionsVar) - reg.pkglist("PKG_SKIP_REASON", BtShellWord) - optlist("PKG_SUGGESTED_OPTIONS", BtOption) - optlist("PKG_SUGGESTED_OPTIONS.*", BtOption) - optlist("PKG_SUPPORTED_OPTIONS", BtOption) + reg.pkgloadlist("PKG_LEGACY_OPTIONS", BtOption) + reg.pkgloadlist("PKG_OPTIONS_DEPRECATED_WARNINGS", BtShellWord) + reg.pkgloadlist("PKG_OPTIONS_GROUP.*", BtOption) + reg.pkgloadlist("PKG_OPTIONS_LEGACY_OPTS", BtUnknown) + reg.pkgloadlist("PKG_OPTIONS_LEGACY_VARS", BtUnknown) + reg.pkgloadlist("PKG_OPTIONS_NONEMPTY_SETS", BtIdentifier) + reg.pkgloadlist("PKG_OPTIONS_OPTIONAL_GROUPS", BtIdentifier) + reg.pkgloadlist("PKG_OPTIONS_REQUIRED_GROUPS", BtIdentifier) + reg.pkgloadlist("PKG_OPTIONS_SET.*", BtOption) + reg.pkgload("PKG_OPTIONS_VAR", BtPkgOptionsVar) + reg.pkgloadlist("PKG_SUGGESTED_OPTIONS", BtOption) + reg.pkgloadlist("PKG_SUGGESTED_OPTIONS.*", BtOption) + reg.pkgloadlist("PKG_SUPPORTED_OPTIONS", BtOption) + reg.pkgloadlist("PKG_SUPPORTED_OPTIONS.*", BtOption) // end PKG_OPTIONS section reg.pkg("PKG_PRESERVE", BtYes) reg.pkg("PKG_SHELL", BtPathname) reg.pkg("PKG_SHELL.*", BtPathname) reg.sys("PKG_SHLIBTOOL", BtPathname) + reg.pkglist("PKG_SKIP_REASON", BtShellWord) // The special exception for buildlink3.mk is only here because // of textproc/xmlcatmgr. reg.acl("PKG_SYSCONFDIR*", BtPathname, @@ -1447,7 +1457,7 @@ func (reg *VarTypeRegistry) Init(src *Pkgsrc) { reg.pkglist("PKG_USERS_VARS", BtVariableName) reg.pkg("PKG_USE_KERBEROS", BtYes) reg.pkgload("PLIST.*", BtYes) - reg.pkglist("PLIST_VARS", BtIdentifier) + reg.pkgloadlist("PLIST_VARS", BtIdentifier) reg.pkglist("PLIST_SRC", BtRelativePkgPath) reg.pkglist("PLIST_SUBST", BtShellWord) reg.pkg("PLIST_TYPE", enum("dynamic static")) |