pkgtools/pkglint: update to 5.5.5 Changes since 5.5.3: - Removed check for PERL5_PACKLIST, since it was not fixable by the package author. - Completely rewrote the check for ordering variables in simple package Makefiles. Now it reports the variables in the correct order instead of just saying "this above that" for a few variables. - Lots of code cleanup and documentation.diff -r1.528 -r1.529 pkgsrc/pkgtools/pkglint/Makefile
(rillig)
@@ -1,16 +1,16 @@ | @@ -1,16 +1,16 @@ | |||
1 | # $NetBSD: Makefile,v 1.528 2018/01/28 23:21:16 rillig Exp $ | 1 | # $NetBSD: Makefile,v 1.529 2018/02/19 12:40:38 rillig Exp $ | |
2 | 2 | |||
3 | PKGNAME= pkglint-5.5.3 | 3 | PKGNAME= pkglint-5.5.5 | |
4 | DISTFILES= # none | 4 | DISTFILES= # none | |
5 | CATEGORIES= pkgtools | 5 | CATEGORIES= pkgtools | |
6 | 6 | |||
7 | MAINTAINER= rillig@NetBSD.org | 7 | MAINTAINER= rillig@NetBSD.org | |
8 | HOMEPAGE= https://github.com/rillig/pkglint | 8 | HOMEPAGE= https://github.com/rillig/pkglint | |
9 | COMMENT= Verifier for NetBSD packages | 9 | COMMENT= Verifier for NetBSD packages | |
10 | LICENSE= 2-clause-bsd | 10 | LICENSE= 2-clause-bsd | |
11 | CONFLICTS+= pkglint4-[0-9]* | 11 | CONFLICTS+= pkglint4-[0-9]* | |
12 | 12 | |||
13 | NO_CHECKSUM= yes | 13 | NO_CHECKSUM= yes | |
14 | USE_LANGUAGES= c | 14 | USE_LANGUAGES= c | |
15 | USE_TOOLS+= pax | 15 | USE_TOOLS+= pax | |
16 | AUTO_MKDIRS= yes | 16 | AUTO_MKDIRS= yes |
@@ -150,27 +150,27 @@ func (fix *Autofix) Realign(mkline MkLin | @@ -150,27 +150,27 @@ func (fix *Autofix) Realign(mkline MkLin | |||
150 | } | 150 | } | |
151 | 151 | |||
152 | // InsertBefore prepends a line before the current line. | 152 | // InsertBefore prepends a line before the current line. | |
153 | // The newline is added internally. | 153 | // The newline is added internally. | |
154 | func (fix *Autofix) InsertBefore(text string) { | 154 | func (fix *Autofix) InsertBefore(text string) { | |
155 | if fix.skip() { | 155 | if fix.skip() { | |
156 | return | 156 | return | |
157 | } | 157 | } | |
158 | 158 | |||
159 | fix.linesBefore = append(fix.linesBefore, text+"\n") | 159 | fix.linesBefore = append(fix.linesBefore, text+"\n") | |
160 | fix.Describef(fix.lines[0].Lineno, "Inserting a line %q before this line.", text) | 160 | fix.Describef(fix.lines[0].Lineno, "Inserting a line %q before this line.", text) | |
161 | } | 161 | } | |
162 | 162 | |||
163 | // InsertBefore appends a line after the current line. | 163 | // InsertAfter appends a line after the current line. | |
164 | // The newline is added internally. | 164 | // The newline is added internally. | |
165 | func (fix *Autofix) InsertAfter(text string) { | 165 | func (fix *Autofix) InsertAfter(text string) { | |
166 | if fix.skip() { | 166 | if fix.skip() { | |
167 | return | 167 | return | |
168 | } | 168 | } | |
169 | 169 | |||
170 | fix.linesAfter = append(fix.linesAfter, text+"\n") | 170 | fix.linesAfter = append(fix.linesAfter, text+"\n") | |
171 | fix.Describef(fix.lines[len(fix.lines)-1].Lineno, "Inserting a line %q after this line.", text) | 171 | fix.Describef(fix.lines[len(fix.lines)-1].Lineno, "Inserting a line %q after this line.", text) | |
172 | } | 172 | } | |
173 | 173 | |||
174 | func (fix *Autofix) Delete() { | 174 | func (fix *Autofix) Delete() { | |
175 | if fix.skip() { | 175 | if fix.skip() { | |
176 | return | 176 | return | |
@@ -186,46 +186,47 @@ func (fix *Autofix) Delete() { | @@ -186,46 +186,47 @@ func (fix *Autofix) Delete() { | |||
186 | // for logging it later when Apply is called. | 186 | // for logging it later when Apply is called. | |
187 | // There may be multiple fixes in one pass. | 187 | // There may be multiple fixes in one pass. | |
188 | func (fix *Autofix) Describef(lineno int, format string, args ...interface{}) { | 188 | func (fix *Autofix) Describef(lineno int, format string, args ...interface{}) { | |
189 | fix.actions = append(fix.actions, autofixAction{fmt.Sprintf(format, args...), lineno}) | 189 | fix.actions = append(fix.actions, autofixAction{fmt.Sprintf(format, args...), lineno}) | |
190 | } | 190 | } | |
191 | 191 | |||
192 | // Notef remembers the note for logging it later when Apply is called. | 192 | // Notef remembers the note for logging it later when Apply is called. | |
193 | func (fix *Autofix) Notef(format string, args ...interface{}) { | 193 | func (fix *Autofix) Notef(format string, args ...interface{}) { | |
194 | fix.level = llNote | 194 | fix.level = llNote | |
195 | fix.diagFormat = format | 195 | fix.diagFormat = format | |
196 | fix.diagArgs = args | 196 | fix.diagArgs = args | |
197 | } | 197 | } | |
198 | 198 | |||
199 | // Notef remembers the warning for logging it later when Apply is called. | 199 | // Warnf remembers the warning for logging it later when Apply is called. | |
200 | func (fix *Autofix) Warnf(format string, args ...interface{}) { | 200 | func (fix *Autofix) Warnf(format string, args ...interface{}) { | |
201 | fix.level = llWarn | 201 | fix.level = llWarn | |
202 | fix.diagFormat = format | 202 | fix.diagFormat = format | |
203 | fix.diagArgs = args | 203 | fix.diagArgs = args | |
204 | } | 204 | } | |
205 | 205 | |||
206 | // Notef remembers the error for logging it later when Apply is called. | 206 | // Errorf remembers the error for logging it later when Apply is called. | |
207 | func (fix *Autofix) Errorf(format string, args ...interface{}) { | 207 | func (fix *Autofix) Errorf(format string, args ...interface{}) { | |
208 | fix.level = llError | 208 | fix.level = llError | |
209 | fix.diagFormat = format | 209 | fix.diagFormat = format | |
210 | fix.diagArgs = args | 210 | fix.diagArgs = args | |
211 | } | 211 | } | |
212 | 212 | |||
213 | // Explain remembers the explanation for logging it later when Apply is called. | 213 | // Explain remembers the explanation for logging it later when Apply is called. | |
214 | func (fix *Autofix) Explain(explanation ...string) { | 214 | func (fix *Autofix) Explain(explanation ...string) { | |
215 | fix.explanation = explanation | 215 | fix.explanation = explanation | |
216 | } | 216 | } | |
217 | 217 | |||
218 | // Depending on the pkglint mode, either: | 218 | // Apply does the actual work. | |
219 | // Depending on the pkglint mode, it either: | |||
219 | // | 220 | // | |
220 | // * logs the associated message (default) | 221 | // * logs the associated message (default) | |
221 | // * logs what would be fixed (--show-autofix) | 222 | // * logs what would be fixed (--show-autofix) | |
222 | // * records the fixes in the line (--autofix) | 223 | // * records the fixes in the line (--autofix) | |
223 | func (fix *Autofix) Apply() { | 224 | func (fix *Autofix) Apply() { | |
224 | line := fix.line | 225 | line := fix.line | |
225 | if line.firstLine < 1 { | 226 | if line.firstLine < 1 { | |
226 | return | 227 | return | |
227 | } | 228 | } | |
228 | 229 | |||
229 | if shallBeLogged(fix.diagFormat) { | 230 | if shallBeLogged(fix.diagFormat) { | |
230 | logDiagnostic := fix.level != nil && fix.diagFormat != "Silent-Magic-Diagnostic" && | 231 | logDiagnostic := fix.level != nil && fix.diagFormat != "Silent-Magic-Diagnostic" && | |
231 | !(G.opts.Autofix && !G.opts.PrintAutofix) && len(fix.actions) > 0 | 232 | !(G.opts.Autofix && !G.opts.PrintAutofix) && len(fix.actions) > 0 |
@@ -245,27 +245,27 @@ func (s *Suite) Test_Autofix_multiple_mo | @@ -245,27 +245,27 @@ func (s *Suite) Test_Autofix_multiple_mo | |||
245 | c.Check(line.autofix.lines[0].textnl, equals, "") | 245 | c.Check(line.autofix.lines[0].textnl, equals, "") | |
246 | c.Check(line.autofix.linesAfter, deepEquals, []string{ | 246 | c.Check(line.autofix.linesAfter, deepEquals, []string{ | |
247 | "between middle and after\n", | 247 | "between middle and after\n", | |
248 | "after\n"}) | 248 | "after\n"}) | |
249 | t.CheckOutputLines( | 249 | t.CheckOutputLines( | |
250 | "AUTOFIX: fname:1: Deleting this line.") | 250 | "AUTOFIX: fname:1: Deleting this line.") | |
251 | } | 251 | } | |
252 | 252 | |||
253 | func (s *Suite) Test_Autofix_show_source_code(c *check.C) { | 253 | func (s *Suite) Test_Autofix_show_source_code(c *check.C) { | |
254 | t := s.Init(c) | 254 | t := s.Init(c) | |
255 | 255 | |||
256 | t.SetupCommandLine("--show-autofix", "--source") | 256 | t.SetupCommandLine("--show-autofix", "--source") | |
257 | lines := t.SetupFileLinesContinuation("Makefile", | 257 | lines := t.SetupFileLinesContinuation("Makefile", | |
258 | MkRcsId, | 258 | MkRcsID, | |
259 | "before \\", | 259 | "before \\", | |
260 | "The old song \\", | 260 | "The old song \\", | |
261 | "after") | 261 | "after") | |
262 | line := lines[1] | 262 | line := lines[1] | |
263 | 263 | |||
264 | { | 264 | { | |
265 | fix := line.Autofix() | 265 | fix := line.Autofix() | |
266 | fix.Warnf("Using \"old\" is deprecated.") | 266 | fix.Warnf("Using \"old\" is deprecated.") | |
267 | fix.Replace("old", "new") | 267 | fix.Replace("old", "new") | |
268 | fix.Apply() | 268 | fix.Apply() | |
269 | } | 269 | } | |
270 | 270 | |||
271 | t.CheckOutputLines( | 271 | t.CheckOutputLines( |
@@ -1,21 +1,26 @@ | @@ -1,21 +1,26 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | // MkToken represents a contiguous string from a Makefile. | |||
4 | // It is either a literal string or a variable use. | |||
5 | // | |||
3 | // Example (3 tokens): /usr/share/${PKGNAME}/data | 6 | // Example (3 tokens): /usr/share/${PKGNAME}/data | |
4 | type MkToken struct { | 7 | type MkToken struct { | |
5 | Text string // Used for both literals and varuses. | 8 | Text string // Used for both literals and varuses. | |
6 | Varuse *MkVarUse | 9 | Varuse *MkVarUse | |
7 | } | 10 | } | |
8 | 11 | |||
12 | // MkVarUse represents a reference to a Make variable, with optional modifiers. | |||
13 | // | |||
9 | // Example: ${PKGNAME} | 14 | // Example: ${PKGNAME} | |
10 | // Example: ${PKGNAME:S/from/to/} | 15 | // Example: ${PKGNAME:S/from/to/} | |
11 | type MkVarUse struct { | 16 | type MkVarUse struct { | |
12 | varname string | 17 | varname string | |
13 | modifiers []string // E.g. "Q", "S/from/to/" | 18 | modifiers []string // E.g. "Q", "S/from/to/" | |
14 | } | 19 | } | |
15 | 20 | |||
16 | func (vu *MkVarUse) Mod() string { | 21 | func (vu *MkVarUse) Mod() string { | |
17 | mod := "" | 22 | mod := "" | |
18 | for _, modifier := range vu.modifiers { | 23 | for _, modifier := range vu.modifiers { | |
19 | mod += ":" + modifier | 24 | mod += ":" + modifier | |
20 | } | 25 | } | |
21 | return mod | 26 | return mod |
@@ -1,23 +1,23 @@ | @@ -1,23 +1,23 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import "gopkg.in/check.v1" | 3 | import "gopkg.in/check.v1" | |
4 | 4 | |||
5 | func (s *Suite) Test_ChecklinesBuildlink3Mk(c *check.C) { | 5 | func (s *Suite) Test_ChecklinesBuildlink3Mk(c *check.C) { | |
6 | t := s.Init(c) | 6 | t := s.Init(c) | |
7 | 7 | |||
8 | G.globalData.InitVartypes() | 8 | G.globalData.InitVartypes() | |
9 | mklines := t.NewMkLines("buildlink3.mk", | 9 | mklines := t.NewMkLines("buildlink3.mk", | |
10 | MkRcsId, | 10 | MkRcsID, | |
11 | "# XXX This file was created automatically using createbuildlink-@PKGVERSION@", | 11 | "# XXX This file was created automatically using createbuildlink-@PKGVERSION@", | |
12 | "", | 12 | "", | |
13 | "BUILDLINK_TREE+= Xbae", | 13 | "BUILDLINK_TREE+= Xbae", | |
14 | "", | 14 | "", | |
15 | "BUILDLINK_DEPMETHOD.Xbae?=\tfull", | 15 | "BUILDLINK_DEPMETHOD.Xbae?=\tfull", | |
16 | ".if !defined(XBAE_BUILDLINK3_MK)", | 16 | ".if !defined(XBAE_BUILDLINK3_MK)", | |
17 | "XBAE_BUILDLINK3_MK:=", | 17 | "XBAE_BUILDLINK3_MK:=", | |
18 | "", | 18 | "", | |
19 | "BUILDLINK_API_DEPENDS.Xbae+= Xbae>=4.8.4", | 19 | "BUILDLINK_API_DEPENDS.Xbae+= Xbae>=4.8.4", | |
20 | "BUILDLINK_ABI_DEPENDS.Xbae+= Xbae>=4.51.01nb2", | 20 | "BUILDLINK_ABI_DEPENDS.Xbae+= Xbae>=4.51.01nb2", | |
21 | "BUILDLINK_PKGSRCDIR.Xbae?= ../../x11/Xbae", | 21 | "BUILDLINK_PKGSRCDIR.Xbae?= ../../x11/Xbae", | |
22 | "", | 22 | "", | |
23 | ".include \"../../mk/motif.buildlink3.mk\"", | 23 | ".include \"../../mk/motif.buildlink3.mk\"", | |
@@ -35,149 +35,149 @@ func (s *Suite) Test_ChecklinesBuildlink | @@ -35,149 +35,149 @@ func (s *Suite) Test_ChecklinesBuildlink | |||
35 | } | 35 | } | |
36 | 36 | |||
37 | // Before version 5.3, pkglint wrongly warned here. | 37 | // Before version 5.3, pkglint wrongly warned here. | |
38 | // The mk/haskell.mk file takes care of constructing the correct PKGNAME, | 38 | // The mk/haskell.mk file takes care of constructing the correct PKGNAME, | |
39 | // but pkglint had not looked at that file. | 39 | // but pkglint had not looked at that file. | |
40 | func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch(c *check.C) { | 40 | func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch(c *check.C) { | |
41 | t := s.Init(c) | 41 | t := s.Init(c) | |
42 | 42 | |||
43 | G.globalData.InitVartypes() | 43 | G.globalData.InitVartypes() | |
44 | G.Pkg = NewPackage("x11/hs-X11") | 44 | G.Pkg = NewPackage("x11/hs-X11") | |
45 | G.Pkg.EffectivePkgbase = "X11" | 45 | G.Pkg.EffectivePkgbase = "X11" | |
46 | G.Pkg.EffectivePkgnameLine = t.NewMkLine("Makefile", 3, "DISTNAME=\tX11-1.0") | 46 | G.Pkg.EffectivePkgnameLine = t.NewMkLine("Makefile", 3, "DISTNAME=\tX11-1.0") | |
47 | mklines := t.NewMkLines("buildlink3.mk", | 47 | mklines := t.NewMkLines("buildlink3.mk", | |
48 | MkRcsId, | 48 | MkRcsID, | |
49 | "", | 49 | "", | |
50 | "BUILDLINK_TREE+=\ths-X11", | 50 | "BUILDLINK_TREE+=\ths-X11", | |
51 | "", | 51 | "", | |
52 | ".if !defined(HS_X11_BUILDLINK3_MK)", | 52 | ".if !defined(HS_X11_BUILDLINK3_MK)", | |
53 | "HS_X11_BUILDLINK3_MK:=", | 53 | "HS_X11_BUILDLINK3_MK:=", | |
54 | "", | 54 | "", | |
55 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | 55 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | |
56 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.1.2nb2", | 56 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.1.2nb2", | |
57 | "", | 57 | "", | |
58 | ".endif\t# HS_X11_BUILDLINK3_MK", | 58 | ".endif\t# HS_X11_BUILDLINK3_MK", | |
59 | "", | 59 | "", | |
60 | "BUILDLINK_TREE+=\t-hs-X11") | 60 | "BUILDLINK_TREE+=\t-hs-X11") | |
61 | 61 | |||
62 | ChecklinesBuildlink3Mk(mklines) | 62 | ChecklinesBuildlink3Mk(mklines) | |
63 | 63 | |||
64 | t.CheckOutputLines( | 64 | t.CheckOutputLines( | |
65 | "ERROR: buildlink3.mk:3: Package name mismatch between \"hs-X11\" in this file and \"X11\" from Makefile:3.") | 65 | "ERROR: buildlink3.mk:3: Package name mismatch between \"hs-X11\" in this file and \"X11\" from Makefile:3.") | |
66 | } | 66 | } | |
67 | 67 | |||
68 | func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_multiple_inclusion(c *check.C) { | 68 | func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_multiple_inclusion(c *check.C) { | |
69 | t := s.Init(c) | 69 | t := s.Init(c) | |
70 | 70 | |||
71 | G.globalData.InitVartypes() | 71 | G.globalData.InitVartypes() | |
72 | mklines := t.NewMkLines("buildlink3.mk", | 72 | mklines := t.NewMkLines("buildlink3.mk", | |
73 | MkRcsId, | 73 | MkRcsID, | |
74 | "", | 74 | "", | |
75 | "BUILDLINK_TREE+=\tpkgbase1", | 75 | "BUILDLINK_TREE+=\tpkgbase1", | |
76 | "", | 76 | "", | |
77 | ".if !defined(PKGBASE2_BUILDLINK3_MK)", | 77 | ".if !defined(PKGBASE2_BUILDLINK3_MK)", | |
78 | "PKGBASE2_BUILDLINK3_MK:=", | 78 | "PKGBASE2_BUILDLINK3_MK:=", | |
79 | "", | 79 | "", | |
80 | ".endif", | 80 | ".endif", | |
81 | "", | 81 | "", | |
82 | "BUILDLINK_TREE+=\t-pkgbase1") | 82 | "BUILDLINK_TREE+=\t-pkgbase1") | |
83 | 83 | |||
84 | ChecklinesBuildlink3Mk(mklines) | 84 | ChecklinesBuildlink3Mk(mklines) | |
85 | 85 | |||
86 | t.CheckOutputLines( | 86 | t.CheckOutputLines( | |
87 | "ERROR: buildlink3.mk:5: Package name mismatch between multiple-inclusion guard \"PKGBASE2\" (expected \"PKGBASE1\") and package name \"pkgbase1\" (from line 3).", | 87 | "ERROR: buildlink3.mk:5: Package name mismatch between multiple-inclusion guard \"PKGBASE2\" (expected \"PKGBASE1\") and package name \"pkgbase1\" (from line 3).", | |
88 | "WARN: buildlink3.mk:9: Definition of BUILDLINK_API_DEPENDS is missing.") | 88 | "WARN: buildlink3.mk:9: Definition of BUILDLINK_API_DEPENDS is missing.") | |
89 | } | 89 | } | |
90 | 90 | |||
91 | func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_abi_api(c *check.C) { | 91 | func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_abi_api(c *check.C) { | |
92 | t := s.Init(c) | 92 | t := s.Init(c) | |
93 | 93 | |||
94 | G.globalData.InitVartypes() | 94 | G.globalData.InitVartypes() | |
95 | mklines := t.NewMkLines("buildlink3.mk", | 95 | mklines := t.NewMkLines("buildlink3.mk", | |
96 | MkRcsId, | 96 | MkRcsID, | |
97 | "", | 97 | "", | |
98 | "BUILDLINK_TREE+=\ths-X11", | 98 | "BUILDLINK_TREE+=\ths-X11", | |
99 | "", | 99 | "", | |
100 | ".if !defined(HS_X11_BUILDLINK3_MK)", | 100 | ".if !defined(HS_X11_BUILDLINK3_MK)", | |
101 | "HS_X11_BUILDLINK3_MK:=", | 101 | "HS_X11_BUILDLINK3_MK:=", | |
102 | "", | 102 | "", | |
103 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | 103 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | |
104 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X12>=1.6.1.2nb2", | 104 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X12>=1.6.1.2nb2", | |
105 | "", | 105 | "", | |
106 | ".endif\t# HS_X11_BUILDLINK3_MK", | 106 | ".endif\t# HS_X11_BUILDLINK3_MK", | |
107 | "", | 107 | "", | |
108 | "BUILDLINK_TREE+=\t-hs-X11") | 108 | "BUILDLINK_TREE+=\t-hs-X11") | |
109 | 109 | |||
110 | ChecklinesBuildlink3Mk(mklines) | 110 | ChecklinesBuildlink3Mk(mklines) | |
111 | 111 | |||
112 | t.CheckOutputLines( | 112 | t.CheckOutputLines( | |
113 | "WARN: buildlink3.mk:9: Package name mismatch between ABI \"hs-X12\" and API \"hs-X11\" (from line 8).") | 113 | "WARN: buildlink3.mk:9: Package name mismatch between ABI \"hs-X12\" and API \"hs-X11\" (from line 8).") | |
114 | } | 114 | } | |
115 | 115 | |||
116 | func (s *Suite) Test_ChecklinesBuildlink3Mk_abi_api_versions(c *check.C) { | 116 | func (s *Suite) Test_ChecklinesBuildlink3Mk_abi_api_versions(c *check.C) { | |
117 | t := s.Init(c) | 117 | t := s.Init(c) | |
118 | 118 | |||
119 | G.globalData.InitVartypes() | 119 | G.globalData.InitVartypes() | |
120 | mklines := t.NewMkLines("buildlink3.mk", | 120 | mklines := t.NewMkLines("buildlink3.mk", | |
121 | MkRcsId, | 121 | MkRcsID, | |
122 | "", | 122 | "", | |
123 | "BUILDLINK_TREE+=\ths-X11", | 123 | "BUILDLINK_TREE+=\ths-X11", | |
124 | "", | 124 | "", | |
125 | ".if !defined(HS_X11_BUILDLINK3_MK)", | 125 | ".if !defined(HS_X11_BUILDLINK3_MK)", | |
126 | "HS_X11_BUILDLINK3_MK:=", | 126 | "HS_X11_BUILDLINK3_MK:=", | |
127 | "", | 127 | "", | |
128 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | 128 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | |
129 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.0", | 129 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.0", | |
130 | "", | 130 | "", | |
131 | ".endif\t# HS_X11_BUILDLINK3_MK", | 131 | ".endif\t# HS_X11_BUILDLINK3_MK", | |
132 | "", | 132 | "", | |
133 | "BUILDLINK_TREE+=\t-hs-X11") | 133 | "BUILDLINK_TREE+=\t-hs-X11") | |
134 | 134 | |||
135 | ChecklinesBuildlink3Mk(mklines) | 135 | ChecklinesBuildlink3Mk(mklines) | |
136 | 136 | |||
137 | t.CheckOutputLines( | 137 | t.CheckOutputLines( | |
138 | "WARN: buildlink3.mk:9: ABI version \"1.6.0\" should be at least API version \"1.6.1\" (see line 8).") | 138 | "WARN: buildlink3.mk:9: ABI version \"1.6.0\" should be at least API version \"1.6.1\" (see line 8).") | |
139 | } | 139 | } | |
140 | 140 | |||
141 | func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_beginning(c *check.C) { | 141 | func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_beginning(c *check.C) { | |
142 | t := s.Init(c) | 142 | t := s.Init(c) | |
143 | 143 | |||
144 | G.globalData.InitVartypes() | 144 | G.globalData.InitVartypes() | |
145 | mklines := t.NewMkLines("buildlink3.mk", | 145 | mklines := t.NewMkLines("buildlink3.mk", | |
146 | MkRcsId, | 146 | MkRcsID, | |
147 | "", | 147 | "", | |
148 | ".if !defined(HS_X11_BUILDLINK3_MK)", | 148 | ".if !defined(HS_X11_BUILDLINK3_MK)", | |
149 | "HS_X11_BUILDLINK3_MK:=", | 149 | "HS_X11_BUILDLINK3_MK:=", | |
150 | "", | 150 | "", | |
151 | "BUILDLINK_DEPMETHOD.hs-X11?=\tfull", | 151 | "BUILDLINK_DEPMETHOD.hs-X11?=\tfull", | |
152 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | 152 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | |
153 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.1.2nb2", | 153 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.1.2nb2", | |
154 | "", | 154 | "", | |
155 | ".endif\t# HS_X11_BUILDLINK3_MK", | 155 | ".endif\t# HS_X11_BUILDLINK3_MK", | |
156 | "", | 156 | "", | |
157 | "BUILDLINK_TREE+=\t-hs-X11") | 157 | "BUILDLINK_TREE+=\t-hs-X11") | |
158 | 158 | |||
159 | ChecklinesBuildlink3Mk(mklines) | 159 | ChecklinesBuildlink3Mk(mklines) | |
160 | 160 | |||
161 | t.CheckOutputLines( | 161 | t.CheckOutputLines( | |
162 | "WARN: buildlink3.mk:3: Expected a BUILDLINK_TREE line.") | 162 | "WARN: buildlink3.mk:3: Expected a BUILDLINK_TREE line.") | |
163 | } | 163 | } | |
164 | 164 | |||
165 | func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_end(c *check.C) { | 165 | func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_end(c *check.C) { | |
166 | t := s.Init(c) | 166 | t := s.Init(c) | |
167 | 167 | |||
168 | G.globalData.InitVartypes() | 168 | G.globalData.InitVartypes() | |
169 | mklines := t.NewMkLines("buildlink3.mk", | 169 | mklines := t.NewMkLines("buildlink3.mk", | |
170 | MkRcsId, | 170 | MkRcsID, | |
171 | "", | 171 | "", | |
172 | "BUILDLINK_DEPMETHOD.hs-X11?=\tfull", | 172 | "BUILDLINK_DEPMETHOD.hs-X11?=\tfull", | |
173 | "", | 173 | "", | |
174 | "BUILDLINK_TREE+=\ths-X11", | 174 | "BUILDLINK_TREE+=\ths-X11", | |
175 | "", | 175 | "", | |
176 | ".if !defined(HS_X11_BUILDLINK3_MK)", | 176 | ".if !defined(HS_X11_BUILDLINK3_MK)", | |
177 | "HS_X11_BUILDLINK3_MK:=", | 177 | "HS_X11_BUILDLINK3_MK:=", | |
178 | "", | 178 | "", | |
179 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | 179 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11>=1.6.1", | |
180 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.1.2nb2", | 180 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11>=1.6.1.2nb2", | |
181 | "", | 181 | "", | |
182 | ".endif\t# HS_X11_BUILDLINK3_MK", | 182 | ".endif\t# HS_X11_BUILDLINK3_MK", | |
183 | "", | 183 | "", | |
@@ -186,116 +186,116 @@ func (s *Suite) Test_ChecklinesBuildlink | @@ -186,116 +186,116 @@ func (s *Suite) Test_ChecklinesBuildlink | |||
186 | 186 | |||
187 | ChecklinesBuildlink3Mk(mklines) | 187 | ChecklinesBuildlink3Mk(mklines) | |
188 | 188 | |||
189 | t.CheckOutputLines( | 189 | t.CheckOutputLines( | |
190 | "WARN: buildlink3.mk:3: This line belongs inside the .ifdef block.", | 190 | "WARN: buildlink3.mk:3: This line belongs inside the .ifdef block.", | |
191 | "WARN: buildlink3.mk:15: This line should contain the following text: BUILDLINK_TREE+=\t-hs-X11") | 191 | "WARN: buildlink3.mk:15: This line should contain the following text: BUILDLINK_TREE+=\t-hs-X11") | |
192 | } | 192 | } | |
193 | 193 | |||
194 | func (s *Suite) Test_ChecklinesBuildlink3Mk_multiple_inclusion_wrong(c *check.C) { | 194 | func (s *Suite) Test_ChecklinesBuildlink3Mk_multiple_inclusion_wrong(c *check.C) { | |
195 | t := s.Init(c) | 195 | t := s.Init(c) | |
196 | 196 | |||
197 | G.globalData.InitVartypes() | 197 | G.globalData.InitVartypes() | |
198 | mklines := t.NewMkLines("buildlink3.mk", | 198 | mklines := t.NewMkLines("buildlink3.mk", | |
199 | MkRcsId, | 199 | MkRcsID, | |
200 | "", | 200 | "", | |
201 | "BUILDLINK_TREE+=\ths-X11", | 201 | "BUILDLINK_TREE+=\ths-X11", | |
202 | "", | 202 | "", | |
203 | ".if !defined(HS_X11_BUILDLINK3_MK)", | 203 | ".if !defined(HS_X11_BUILDLINK3_MK)", | |
204 | "UNRELATED_BUILDLINK3_MK:=") | 204 | "UNRELATED_BUILDLINK3_MK:=") | |
205 | 205 | |||
206 | ChecklinesBuildlink3Mk(mklines) | 206 | ChecklinesBuildlink3Mk(mklines) | |
207 | 207 | |||
208 | t.CheckOutputLines( | 208 | t.CheckOutputLines( | |
209 | "WARN: buildlink3.mk:6: UNRELATED_BUILDLINK3_MK is defined but not used. Spelling mistake?", | 209 | "WARN: buildlink3.mk:6: UNRELATED_BUILDLINK3_MK is defined but not used. Spelling mistake?", | |
210 | "WARN: buildlink3.mk:6: This line should contain the following text: HS_X11_BUILDLINK3_MK:=") | 210 | "WARN: buildlink3.mk:6: This line should contain the following text: HS_X11_BUILDLINK3_MK:=") | |
211 | } | 211 | } | |
212 | 212 | |||
213 | func (s *Suite) Test_ChecklinesBuildlink3Mk_missing_endif(c *check.C) { | 213 | func (s *Suite) Test_ChecklinesBuildlink3Mk_missing_endif(c *check.C) { | |
214 | t := s.Init(c) | 214 | t := s.Init(c) | |
215 | 215 | |||
216 | G.globalData.InitVartypes() | 216 | G.globalData.InitVartypes() | |
217 | mklines := t.NewMkLines("buildlink3.mk", | 217 | mklines := t.NewMkLines("buildlink3.mk", | |
218 | MkRcsId, | 218 | MkRcsID, | |
219 | "", | 219 | "", | |
220 | "BUILDLINK_TREE+=\tpkgbase1", | 220 | "BUILDLINK_TREE+=\tpkgbase1", | |
221 | "", | 221 | "", | |
222 | ".if !defined(PKGBASE1_BUILDLINK3_MK)", | 222 | ".if !defined(PKGBASE1_BUILDLINK3_MK)", | |
223 | "PKGBASE1_BUILDLINK3_MK:=") | 223 | "PKGBASE1_BUILDLINK3_MK:=") | |
224 | 224 | |||
225 | ChecklinesBuildlink3Mk(mklines) | 225 | ChecklinesBuildlink3Mk(mklines) | |
226 | 226 | |||
227 | t.CheckOutputLines( | 227 | t.CheckOutputLines( | |
228 | "WARN: buildlink3.mk:EOF: Expected .endif") | 228 | "WARN: buildlink3.mk:EOF: Expected .endif") | |
229 | } | 229 | } | |
230 | 230 | |||
231 | func (s *Suite) Test_ChecklinesBuildlink3Mk_unknown_dependency_patterns(c *check.C) { | 231 | func (s *Suite) Test_ChecklinesBuildlink3Mk_unknown_dependency_patterns(c *check.C) { | |
232 | t := s.Init(c) | 232 | t := s.Init(c) | |
233 | 233 | |||
234 | G.globalData.InitVartypes() | 234 | G.globalData.InitVartypes() | |
235 | mklines := t.NewMkLines("buildlink3.mk", | 235 | mklines := t.NewMkLines("buildlink3.mk", | |
236 | MkRcsId, | 236 | MkRcsID, | |
237 | "", | 237 | "", | |
238 | "BUILDLINK_TREE+= hs-X11", | 238 | "BUILDLINK_TREE+= hs-X11", | |
239 | "", | 239 | "", | |
240 | ".if !defined(HS_X11_BUILDLINK3_MK)", | 240 | ".if !defined(HS_X11_BUILDLINK3_MK)", | |
241 | "HS_X11_BUILDLINK3_MK:=", | 241 | "HS_X11_BUILDLINK3_MK:=", | |
242 | "", | 242 | "", | |
243 | "BUILDLINK_DEPMETHOD.hs-X11?=\tfull", | 243 | "BUILDLINK_DEPMETHOD.hs-X11?=\tfull", | |
244 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11!=1.6.1", | 244 | "BUILDLINK_API_DEPENDS.hs-X11+=\ths-X11!=1.6.1", | |
245 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11!=1.6.1.2nb2", | 245 | "BUILDLINK_ABI_DEPENDS.hs-X11+=\ths-X11!=1.6.1.2nb2", | |
246 | "", | 246 | "", | |
247 | ".endif\t# HS_X11_BUILDLINK3_MK", | 247 | ".endif\t# HS_X11_BUILDLINK3_MK", | |
248 | "", | 248 | "", | |
249 | "BUILDLINK_TREE+=\t-hs-X11") | 249 | "BUILDLINK_TREE+=\t-hs-X11") | |
250 | 250 | |||
251 | ChecklinesBuildlink3Mk(mklines) | 251 | ChecklinesBuildlink3Mk(mklines) | |
252 | 252 | |||
253 | t.CheckOutputLines( | 253 | t.CheckOutputLines( | |
254 | "WARN: buildlink3.mk:9: Unknown dependency pattern \"hs-X11!=1.6.1\".", | 254 | "WARN: buildlink3.mk:9: Unknown dependency pattern \"hs-X11!=1.6.1\".", | |
255 | "WARN: buildlink3.mk:10: Unknown dependency pattern \"hs-X11!=1.6.1.2nb2\".") | 255 | "WARN: buildlink3.mk:10: Unknown dependency pattern \"hs-X11!=1.6.1.2nb2\".") | |
256 | } | 256 | } | |
257 | 257 | |||
258 | func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_variable(c *check.C) { | 258 | func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_variable(c *check.C) { | |
259 | t := s.Init(c) | 259 | t := s.Init(c) | |
260 | 260 | |||
261 | G.globalData.InitVartypes() | 261 | G.globalData.InitVartypes() | |
262 | mklines := t.NewMkLines("buildlink3.mk", | 262 | mklines := t.NewMkLines("buildlink3.mk", | |
263 | MkRcsId, | 263 | MkRcsID, | |
264 | "", | 264 | "", | |
265 | "BUILDLINK_TREE+=\t${PYPKGPREFIX}-wxWidgets", | 265 | "BUILDLINK_TREE+=\t${PYPKGPREFIX}-wxWidgets", | |
266 | "", | 266 | "", | |
267 | ".if !defined(PY_WXWIDGETS_BUILDLINK3_MK)", | 267 | ".if !defined(PY_WXWIDGETS_BUILDLINK3_MK)", | |
268 | "PY_WXWIDGETS_BUILDLINK3_MK:=", | 268 | "PY_WXWIDGETS_BUILDLINK3_MK:=", | |
269 | "", | 269 | "", | |
270 | "BUILDLINK_API_DEPENDS.${PYPKGPREFIX}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.6.1.0", | 270 | "BUILDLINK_API_DEPENDS.${PYPKGPREFIX}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.6.1.0", | |
271 | "BUILDLINK_ABI_DEPENDS.${PYPKGPREFIX}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.8.10.1nb26", | 271 | "BUILDLINK_ABI_DEPENDS.${PYPKGPREFIX}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.8.10.1nb26", | |
272 | "", | 272 | "", | |
273 | ".endif", | 273 | ".endif", | |
274 | "", | 274 | "", | |
275 | "BUILDLINK_TREE+=\t-${PYPKGPREFIX}-wxWidgets") | 275 | "BUILDLINK_TREE+=\t-${PYPKGPREFIX}-wxWidgets") | |
276 | 276 | |||
277 | ChecklinesBuildlink3Mk(mklines) | 277 | ChecklinesBuildlink3Mk(mklines) | |
278 | 278 | |||
279 | t.CheckOutputLines( | 279 | t.CheckOutputLines( | |
280 | "WARN: buildlink3.mk:3: Please use \"py\" instead of \"${PYPKGPREFIX}\" (also in other variables in this file).") | 280 | "WARN: buildlink3.mk:3: Please use \"py\" instead of \"${PYPKGPREFIX}\" (also in other variables in this file).") | |
281 | } | 281 | } | |
282 | 282 | |||
283 | func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_unknown_variable(c *check.C) { | 283 | func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_unknown_variable(c *check.C) { | |
284 | t := s.Init(c) | 284 | t := s.Init(c) | |
285 | 285 | |||
286 | G.globalData.InitVartypes() | 286 | G.globalData.InitVartypes() | |
287 | mklines := t.NewMkLines("buildlink3.mk", | 287 | mklines := t.NewMkLines("buildlink3.mk", | |
288 | MkRcsId, | 288 | MkRcsID, | |
289 | "", | 289 | "", | |
290 | "BUILDLINK_TREE+=\t${LICENSE}-wxWidgets", | 290 | "BUILDLINK_TREE+=\t${LICENSE}-wxWidgets", | |
291 | "", | 291 | "", | |
292 | ".if !defined(LICENSE_BUILDLINK3_MK)", | 292 | ".if !defined(LICENSE_BUILDLINK3_MK)", | |
293 | "LICENSE_BUILDLINK3_MK:=", | 293 | "LICENSE_BUILDLINK3_MK:=", | |
294 | "", | 294 | "", | |
295 | "BUILDLINK_API_DEPENDS.${LICENSE}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.6.1.0", | 295 | "BUILDLINK_API_DEPENDS.${LICENSE}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.6.1.0", | |
296 | "BUILDLINK_ABI_DEPENDS.${LICENSE}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.8.10.1nb26", | 296 | "BUILDLINK_ABI_DEPENDS.${LICENSE}-wxWidgets+=\t${PYPKGPREFIX}-wxWidgets>=2.8.10.1nb26", | |
297 | "", | 297 | "", | |
298 | ".endif", | 298 | ".endif", | |
299 | "", | 299 | "", | |
300 | "BUILDLINK_TREE+=\t-${PYPKGPREFIX}-wxWidgets") | 300 | "BUILDLINK_TREE+=\t-${PYPKGPREFIX}-wxWidgets") | |
301 | 301 | |||
@@ -306,27 +306,27 @@ func (s *Suite) Test_ChecklinesBuildlink | @@ -306,27 +306,27 @@ func (s *Suite) Test_ChecklinesBuildlink | |||
306 | "WARN: buildlink3.mk:13: This line should contain the following text: BUILDLINK_TREE+=\t-${LICENSE}-wxWidgets") | 306 | "WARN: buildlink3.mk:13: This line should contain the following text: BUILDLINK_TREE+=\t-${LICENSE}-wxWidgets") | |
307 | } | 307 | } | |
308 | 308 | |||
309 | // Those .include lines that are not indented at all may stay as-is. | 309 | // Those .include lines that are not indented at all may stay as-is. | |
310 | // This special exception might have been for backwards-compatibility, | 310 | // This special exception might have been for backwards-compatibility, | |
311 | // but ideally should be handled like everywhere else. | 311 | // but ideally should be handled like everywhere else. | |
312 | // See MkLineChecker.checkInclude. | 312 | // See MkLineChecker.checkInclude. | |
313 | func (s *Suite) Test_ChecklinesBuildlink3Mk_indentation(c *check.C) { | 313 | func (s *Suite) Test_ChecklinesBuildlink3Mk_indentation(c *check.C) { | |
314 | t := s.Init(c) | 314 | t := s.Init(c) | |
315 | 315 | |||
316 | t.SetupCommandLine("-Wall") | 316 | t.SetupCommandLine("-Wall") | |
317 | G.globalData.InitVartypes() | 317 | G.globalData.InitVartypes() | |
318 | mklines := t.NewMkLines("buildlink3.mk", | 318 | mklines := t.NewMkLines("buildlink3.mk", | |
319 | MkRcsId, | 319 | MkRcsID, | |
320 | "", | 320 | "", | |
321 | ".if ${VAAPI_AVAILABLE} == \"yes\"", | 321 | ".if ${VAAPI_AVAILABLE} == \"yes\"", | |
322 | "", | 322 | "", | |
323 | "BUILDLINK_TREE+= libva", | 323 | "BUILDLINK_TREE+= libva", | |
324 | "", | 324 | "", | |
325 | ". if !defined(LIBVA_BUILDLINK3_MK)", | 325 | ". if !defined(LIBVA_BUILDLINK3_MK)", | |
326 | "LIBVA_BUILDLINK3_MK:=", | 326 | "LIBVA_BUILDLINK3_MK:=", | |
327 | "", | 327 | "", | |
328 | "BUILDLINK_API_DEPENDS.libva+= libva>=1.0.6", | 328 | "BUILDLINK_API_DEPENDS.libva+= libva>=1.0.6", | |
329 | "BUILDLINK_PKGSRCDIR.libva?= ../../multimedia/libva", | 329 | "BUILDLINK_PKGSRCDIR.libva?= ../../multimedia/libva", | |
330 | "", | 330 | "", | |
331 | ".include \"../../x11/libX11/buildlink3.mk\"", | 331 | ".include \"../../x11/libX11/buildlink3.mk\"", | |
332 | "", | 332 | "", |
@@ -28,27 +28,27 @@ func (s *Suite) Test_CheckdirCategory_to | @@ -28,27 +28,27 @@ func (s *Suite) Test_CheckdirCategory_to | |||
28 | "WARN: ~/archivers/Makefile:3: \"aaaaa\" should come before \"pkg1\".", | 28 | "WARN: ~/archivers/Makefile:3: \"aaaaa\" should come before \"pkg1\".", | |
29 | "ERROR: ~/archivers/Makefile:4: SUBDIR+= line or empty line expected.", | 29 | "ERROR: ~/archivers/Makefile:4: SUBDIR+= line or empty line expected.", | |
30 | "ERROR: ~/archivers/Makefile:2: \"pkg1\" exists in the Makefile, but not in the file system.", | 30 | "ERROR: ~/archivers/Makefile:2: \"pkg1\" exists in the Makefile, but not in the file system.", | |
31 | "ERROR: ~/archivers/Makefile:3: \"aaaaa\" exists in the Makefile, but not in the file system.", | 31 | "ERROR: ~/archivers/Makefile:3: \"aaaaa\" exists in the Makefile, but not in the file system.", | |
32 | "WARN: ~/archivers/Makefile:4: This line should contain the following text: .include \"../mk/misc/category.mk\"", | 32 | "WARN: ~/archivers/Makefile:4: This line should contain the following text: .include \"../mk/misc/category.mk\"", | |
33 | "ERROR: ~/archivers/Makefile:4: The file should end here.") | 33 | "ERROR: ~/archivers/Makefile:4: The file should end here.") | |
34 | } | 34 | } | |
35 | 35 | |||
36 | func (s *Suite) Test_CheckdirCategory_invalid_comment(c *check.C) { | 36 | func (s *Suite) Test_CheckdirCategory_invalid_comment(c *check.C) { | |
37 | t := s.Init(c) | 37 | t := s.Init(c) | |
38 | 38 | |||
39 | G.globalData.InitVartypes() | 39 | G.globalData.InitVartypes() | |
40 | t.SetupFileLines("archivers/Makefile", | 40 | t.SetupFileLines("archivers/Makefile", | |
41 | MkRcsId, | 41 | MkRcsID, | |
42 | "COMMENT=\t\\Make $$$$ fast\"", | 42 | "COMMENT=\t\\Make $$$$ fast\"", | |
43 | "", | 43 | "", | |
44 | "SUBDIR+=\tpackage", | 44 | "SUBDIR+=\tpackage", | |
45 | "", | 45 | "", | |
46 | ".include \"../mk/misc/category.mk\"") | 46 | ".include \"../mk/misc/category.mk\"") | |
47 | t.SetupFileLines("archivers/package/Makefile", | 47 | t.SetupFileLines("archivers/package/Makefile", | |
48 | "# dummy") | 48 | "# dummy") | |
49 | t.SetupFileLines("mk/misc/category.mk", | 49 | t.SetupFileLines("mk/misc/category.mk", | |
50 | "# dummy") | 50 | "# dummy") | |
51 | G.CurrentDir = t.TempFilename("archivers") | 51 | G.CurrentDir = t.TempFilename("archivers") | |
52 | G.CurPkgsrcdir = ".." | 52 | G.CurPkgsrcdir = ".." | |
53 | 53 | |||
54 | CheckdirCategory() | 54 | CheckdirCategory() |
@@ -8,36 +8,40 @@ import ( | @@ -8,36 +8,40 @@ import ( | |||
8 | "path" | 8 | "path" | |
9 | "path/filepath" | 9 | "path/filepath" | |
10 | "strings" | 10 | "strings" | |
11 | "testing" | 11 | "testing" | |
12 | 12 | |||
13 | "gopkg.in/check.v1" | 13 | "gopkg.in/check.v1" | |
14 | "netbsd.org/pkglint/textproc" | 14 | "netbsd.org/pkglint/textproc" | |
15 | "netbsd.org/pkglint/trace" | 15 | "netbsd.org/pkglint/trace" | |
16 | ) | 16 | ) | |
17 | 17 | |||
18 | var equals = check.Equals | 18 | var equals = check.Equals | |
19 | var deepEquals = check.DeepEquals | 19 | var deepEquals = check.DeepEquals | |
20 | 20 | |||
21 | const RcsId = "$" + "NetBSD$" | 21 | const RcsID = "$" + "NetBSD$" | |
22 | const MkRcsId = "# $" + "NetBSD$" | 22 | const MkRcsID = "# $" + "NetBSD$" | |
23 | const PlistRcsId = "@comment $" + "NetBSD$" | 23 | const PlistRcsID = "@comment $" + "NetBSD$" | |
24 | 24 | |||
25 | type Suite struct { | 25 | type Suite struct { | |
26 | Tester *Tester | 26 | Tester *Tester | |
27 | } | 27 | } | |
28 | 28 | |||
29 | // Init initializes the suite with the check.C instance for the actual | 29 | // Init initializes the suite with the check.C instance for the actual | |
30 | // test run. See https://github.com/go-check/check/issues/22 | 30 | // test run. | |
31 | // The returned tester can be used to easily setup the test environment | |||
32 | // and check the results using a high-level API. | |||
33 | // | |||
34 | // See https://github.com/go-check/check/issues/22 | |||
31 | func (s *Suite) Init(c *check.C) *Tester { | 35 | func (s *Suite) Init(c *check.C) *Tester { | |
32 | t := s.Tester // Has been initialized by SetUpTest | 36 | t := s.Tester // Has been initialized by SetUpTest | |
33 | if t.checkC != nil { | 37 | if t.checkC != nil { | |
34 | panic("Suite.Init must only be called once.") | 38 | panic("Suite.Init must only be called once.") | |
35 | } | 39 | } | |
36 | t.checkC = c | 40 | t.checkC = c | |
37 | return t | 41 | return t | |
38 | } | 42 | } | |
39 | 43 | |||
40 | func (s *Suite) SetUpTest(c *check.C) { | 44 | func (s *Suite) SetUpTest(c *check.C) { | |
41 | t := &Tester{checkC: c} | 45 | t := &Tester{checkC: c} | |
42 | s.Tester = t | 46 | s.Tester = t | |
43 | 47 | |||
@@ -266,38 +270,38 @@ func (t *Tester) CheckOutputEmpty() { | @@ -266,38 +270,38 @@ func (t *Tester) CheckOutputEmpty() { | |||
266 | t.CheckOutputLines( /* none */ ) | 270 | t.CheckOutputLines( /* none */ ) | |
267 | } | 271 | } | |
268 | 272 | |||
269 | // CheckOutputLines checks that the output up to now equals the given lines. | 273 | // CheckOutputLines checks that the output up to now equals the given lines. | |
270 | // After the comparison, the output buffers are cleared so that later | 274 | // After the comparison, the output buffers are cleared so that later | |
271 | // calls only check against the newly added output. | 275 | // calls only check against the newly added output. | |
272 | func (t *Tester) CheckOutputLines(expectedLines ...string) { | 276 | func (t *Tester) CheckOutputLines(expectedLines ...string) { | |
273 | output := t.Output() | 277 | output := t.Output() | |
274 | actualLines := strings.Split(output, "\n") | 278 | actualLines := strings.Split(output, "\n") | |
275 | actualLines = actualLines[:len(actualLines)-1] | 279 | actualLines = actualLines[:len(actualLines)-1] | |
276 | t.c().Check(emptyToNil(actualLines), deepEquals, emptyToNil(expectedLines)) | 280 | t.c().Check(emptyToNil(actualLines), deepEquals, emptyToNil(expectedLines)) | |
277 | } | 281 | } | |
278 | 282 | |||
279 | // BeginDebugToStdout redirects all logging output to stdout instead of | 283 | // EnableTracing redirects all logging output to stdout instead of | |
280 | // the buffer. This is useful when stepping through the code, especially | 284 | // the buffer. This is useful when stepping through the code, especially | |
281 | // in combination with SetupCommandLine("--debug"). | 285 | // in combination with SetupCommandLine("--debug"). | |
282 | func (t *Tester) BeginDebugToStdout() { | 286 | func (t *Tester) EnableTracing() { | |
283 | G.logOut = NewSeparatorWriter(os.Stdout) | 287 | G.logOut = NewSeparatorWriter(os.Stdout) | |
284 | trace.Out = os.Stdout | 288 | trace.Out = os.Stdout | |
285 | trace.Tracing = true | 289 | trace.Tracing = true | |
286 | } | 290 | } | |
287 | 291 | |||
288 | // EndDebugToStdout logs the output to the buffers again, ready to be | 292 | // DisableTracing logs the output to the buffers again, ready to be | |
289 | // checked with CheckOutputLines. | 293 | // checked with CheckOutputLines. | |
290 | func (t *Tester) EndDebugToStdout() { | 294 | func (t *Tester) DisableTracing() { | |
291 | G.logOut = NewSeparatorWriter(&t.stdout) | 295 | G.logOut = NewSeparatorWriter(&t.stdout) | |
292 | trace.Out = &t.stdout | 296 | trace.Out = &t.stdout | |
293 | trace.Tracing = false | 297 | trace.Tracing = false | |
294 | } | 298 | } | |
295 | 299 | |||
296 | // CheckFileLines loads the lines from the temporary file and checks that | 300 | // CheckFileLines loads the lines from the temporary file and checks that | |
297 | // they equal the given lines. | 301 | // they equal the given lines. | |
298 | func (t *Tester) CheckFileLines(relativeFileName string, lines ...string) { | 302 | func (t *Tester) CheckFileLines(relativeFileName string, lines ...string) { | |
299 | text := t.LoadTmpFile(relativeFileName) | 303 | text := t.LoadTmpFile(relativeFileName) | |
300 | actualLines := strings.Split(text, "\n") | 304 | actualLines := strings.Split(text, "\n") | |
301 | actualLines = actualLines[:len(actualLines)-1] | 305 | actualLines = actualLines[:len(actualLines)-1] | |
302 | t.c().Check(emptyToNil(actualLines), deepEquals, emptyToNil(lines)) | 306 | t.c().Check(emptyToNil(actualLines), deepEquals, emptyToNil(lines)) | |
303 | } | 307 | } |
@@ -1,25 +1,25 @@ | @@ -1,25 +1,25 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import ( | 3 | import ( | |
4 | "gopkg.in/check.v1" | 4 | "gopkg.in/check.v1" | |
5 | ) | 5 | ) | |
6 | 6 | |||
7 | func (s *Suite) Test_MkLines_Check__autofix_conditional_indentation(c *check.C) { | 7 | func (s *Suite) Test_MkLines_Check__autofix_conditional_indentation(c *check.C) { | |
8 | t := s.Init(c) | 8 | t := s.Init(c) | |
9 | 9 | |||
10 | t.SetupCommandLine("--autofix", "-Wspace") | 10 | t.SetupCommandLine("--autofix", "-Wspace") | |
11 | lines := t.SetupFileLines("fname.mk", | 11 | lines := t.SetupFileLines("fname.mk", | |
12 | MkRcsId, | 12 | MkRcsID, | |
13 | ".if defined(A)", | 13 | ".if defined(A)", | |
14 | ".for a in ${A}", | 14 | ".for a in ${A}", | |
15 | ".if defined(C)", | 15 | ".if defined(C)", | |
16 | ".endif", | 16 | ".endif", | |
17 | ".endfor", | 17 | ".endfor", | |
18 | ".endif") | 18 | ".endif") | |
19 | mklines := NewMkLines(lines) | 19 | mklines := NewMkLines(lines) | |
20 | 20 | |||
21 | mklines.Check() | 21 | mklines.Check() | |
22 | 22 | |||
23 | t.CheckOutputLines( | 23 | t.CheckOutputLines( | |
24 | "AUTOFIX: ~/fname.mk:3: Replacing \".\" with \". \".", | 24 | "AUTOFIX: ~/fname.mk:3: Replacing \".\" with \". \".", | |
25 | "AUTOFIX: ~/fname.mk:4: Replacing \".\" with \". \".", | 25 | "AUTOFIX: ~/fname.mk:4: Replacing \".\" with \". \".", | |
@@ -29,27 +29,27 @@ func (s *Suite) Test_MkLines_Check__auto | @@ -29,27 +29,27 @@ func (s *Suite) Test_MkLines_Check__auto | |||
29 | "# $"+"NetBSD$", | 29 | "# $"+"NetBSD$", | |
30 | ".if defined(A)", | 30 | ".if defined(A)", | |
31 | ". for a in ${A}", | 31 | ". for a in ${A}", | |
32 | ". if defined(C)", | 32 | ". if defined(C)", | |
33 | ". endif", | 33 | ". endif", | |
34 | ". endfor", | 34 | ". endfor", | |
35 | ".endif") | 35 | ".endif") | |
36 | } | 36 | } | |
37 | 37 | |||
38 | func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) { | 38 | func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) { | |
39 | t := s.Init(c) | 39 | t := s.Init(c) | |
40 | 40 | |||
41 | mklines := t.NewMkLines("Makefile", | 41 | mklines := t.NewMkLines("Makefile", | |
42 | MkRcsId, | 42 | MkRcsID, | |
43 | "", | 43 | "", | |
44 | "echo: echo.c", | 44 | "echo: echo.c", | |
45 | "\tcc -o ${.TARGET} ${.IMPSRC}") | 45 | "\tcc -o ${.TARGET} ${.IMPSRC}") | |
46 | 46 | |||
47 | mklines.Check() | 47 | mklines.Check() | |
48 | 48 | |||
49 | t.CheckOutputLines( | 49 | t.CheckOutputLines( | |
50 | "WARN: Makefile:3: Unusual target \"echo\".") | 50 | "WARN: Makefile:3: Unusual target \"echo\".") | |
51 | } | 51 | } | |
52 | 52 | |||
53 | func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) { | 53 | func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) { | |
54 | t := s.Init(c) | 54 | t := s.Init(c) | |
55 | 55 | |||
@@ -59,256 +59,256 @@ func (s *Suite) Test_MkLineChecker_check | @@ -59,256 +59,256 @@ func (s *Suite) Test_MkLineChecker_check | |||
59 | 59 | |||
60 | t.CheckOutputLines( | 60 | t.CheckOutputLines( | |
61 | "ERROR: Makefile:2: \"/other/package/Makefile\" does not exist.", | 61 | "ERROR: Makefile:2: \"/other/package/Makefile\" does not exist.", | |
62 | "ERROR: Makefile:2: Other Makefiles must not be included directly.") | 62 | "ERROR: Makefile:2: Other Makefiles must not be included directly.") | |
63 | } | 63 | } | |
64 | 64 | |||
65 | func (s *Suite) Test_MkLines_quoting_LDFLAGS_for_GNU_configure(c *check.C) { | 65 | func (s *Suite) Test_MkLines_quoting_LDFLAGS_for_GNU_configure(c *check.C) { | |
66 | t := s.Init(c) | 66 | t := s.Init(c) | |
67 | 67 | |||
68 | t.SetupCommandLine("-Wall") | 68 | t.SetupCommandLine("-Wall") | |
69 | G.globalData.InitVartypes() | 69 | G.globalData.InitVartypes() | |
70 | G.Pkg = NewPackage("category/pkgbase") | 70 | G.Pkg = NewPackage("category/pkgbase") | |
71 | mklines := t.NewMkLines("Makefile", | 71 | mklines := t.NewMkLines("Makefile", | |
72 | MkRcsId, | 72 | MkRcsID, | |
73 | "GNU_CONFIGURE=\tyes", | 73 | "GNU_CONFIGURE=\tyes", | |
74 | "CONFIGURE_ENV+=\tX_LIBS=${X11_LDFLAGS:Q}") | 74 | "CONFIGURE_ENV+=\tX_LIBS=${X11_LDFLAGS:Q}") | |
75 | 75 | |||
76 | mklines.Check() | 76 | mklines.Check() | |
77 | 77 | |||
78 | t.CheckOutputLines( | 78 | t.CheckOutputLines( | |
79 | "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.", | 79 | "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.", | |
80 | "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.") | 80 | "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.") | |
81 | } | 81 | } | |
82 | 82 | |||
83 | func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) { | 83 | func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) { | |
84 | t := s.Init(c) | 84 | t := s.Init(c) | |
85 | 85 | |||
86 | t.SetupCommandLine("-Wall") | 86 | t.SetupCommandLine("-Wall") | |
87 | t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true}) | 87 | t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true}) | |
88 | t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true}) | 88 | t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true}) | |
89 | t.SetupTool(&Tool{Name: "pax", Varname: "PAX", Predefined: true}) | 89 | t.SetupTool(&Tool{Name: "pax", Varname: "PAX", Predefined: true}) | |
90 | mklines := t.NewMkLines("Makefile", // From audio/squeezeboxserver | 90 | mklines := t.NewMkLines("Makefile", // From audio/squeezeboxserver | |
91 | MkRcsId, | 91 | MkRcsID, | |
92 | "", | 92 | "", | |
93 | ".for _list_ _dir_ in ${SBS_COPY}", | 93 | ".for _list_ _dir_ in ${SBS_COPY}", | |
94 | "\tcd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2>/dev/null "+ | 94 | "\tcd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2>/dev/null "+ | |
95 | "| pax -rw -pm ${DESTDIR}${PREFIX}/${${_dir_}}", | 95 | "| pax -rw -pm ${DESTDIR}${PREFIX}/${${_dir_}}", | |
96 | ".endfor") | 96 | ".endfor") | |
97 | 97 | |||
98 | mklines.Check() | 98 | mklines.Check() | |
99 | 99 | |||
100 | t.CheckOutputLines( | 100 | t.CheckOutputLines( | |
101 | "WARN: Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.", | 101 | "WARN: Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.", | |
102 | "WARN: Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.", | 102 | "WARN: Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.", | |
103 | "WARN: Makefile:4: The exitcode of \"${FIND}\" at the left of the | operator is ignored.") | 103 | "WARN: Makefile:4: The exitcode of \"${FIND}\" at the left of the | operator is ignored.") | |
104 | } | 104 | } | |
105 | 105 | |||
106 | func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) { | 106 | func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) { | |
107 | t := s.Init(c) | 107 | t := s.Init(c) | |
108 | 108 | |||
109 | t.SetupCommandLine("-Wall") | 109 | t.SetupCommandLine("-Wall") | |
110 | G.globalData.InitVartypes() | 110 | G.globalData.InitVartypes() | |
111 | mklines := t.NewMkLines("databases/gdbm_compat/builtin.mk", | 111 | mklines := t.NewMkLines("databases/gdbm_compat/builtin.mk", | |
112 | MkRcsId, | 112 | MkRcsID, | |
113 | ".if ${USE_BUILTIN.gdbm} == \"no\"", | 113 | ".if ${USE_BUILTIN.gdbm} == \"no\"", | |
114 | ".endif", | 114 | ".endif", | |
115 | ".if ${USE_BUILTIN.gdbm:tu} == \"no\"", // Can never be true, since "no" is not uppercase. | 115 | ".if ${USE_BUILTIN.gdbm:tu} == \"no\"", // Can never be true, since "no" is not uppercase. | |
116 | ".endif") | 116 | ".endif") | |
117 | 117 | |||
118 | mklines.Check() | 118 | mklines.Check() | |
119 | 119 | |||
120 | t.CheckOutputLines( | 120 | t.CheckOutputLines( | |
121 | "WARN: databases/gdbm_compat/builtin.mk:2: " + | 121 | "WARN: databases/gdbm_compat/builtin.mk:2: " + | |
122 | "USE_BUILTIN.gdbm should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not compared with \"no\".") | 122 | "USE_BUILTIN.gdbm should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not compared with \"no\".") | |
123 | } | 123 | } | |
124 | 124 | |||
125 | func (s *Suite) Test_MkLines__varuse_sh_modifier(c *check.C) { | 125 | func (s *Suite) Test_MkLines__varuse_sh_modifier(c *check.C) { | |
126 | t := s.Init(c) | 126 | t := s.Init(c) | |
127 | 127 | |||
128 | t.SetupCommandLine("-Wall") | 128 | t.SetupCommandLine("-Wall") | |
129 | G.globalData.InitVartypes() | 129 | G.globalData.InitVartypes() | |
130 | mklines := t.NewMkLines("lang/qore/module.mk", | 130 | mklines := t.NewMkLines("lang/qore/module.mk", | |
131 | MkRcsId, | 131 | MkRcsID, | |
132 | "qore-version=\tqore --short-version | ${SED} -e s/-.*//", | 132 | "qore-version=\tqore --short-version | ${SED} -e s/-.*//", | |
133 | "PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"") | 133 | "PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"") | |
134 | 134 | |||
135 | vars2 := mklines.mklines[1].DetermineUsedVariables() | 135 | vars2 := mklines.mklines[1].DetermineUsedVariables() | |
136 | 136 | |||
137 | c.Check(vars2, deepEquals, []string{"SED"}) | 137 | c.Check(vars2, deepEquals, []string{"SED"}) | |
138 | 138 | |||
139 | vars3 := mklines.mklines[2].DetermineUsedVariables() | 139 | vars3 := mklines.mklines[2].DetermineUsedVariables() | |
140 | 140 | |||
141 | c.Check(vars3, deepEquals, []string{"qore-version"}) | 141 | c.Check(vars3, deepEquals, []string{"qore-version"}) | |
142 | 142 | |||
143 | mklines.Check() | 143 | mklines.Check() | |
144 | 144 | |||
145 | // No warnings about defined but not used or vice versa | 145 | // No warnings about defined but not used or vice versa | |
146 | t.CheckOutputEmpty() | 146 | t.CheckOutputEmpty() | |
147 | } | 147 | } | |
148 | 148 | |||
149 | func (s *Suite) Test_MkLines__varuse_parameterized(c *check.C) { | 149 | func (s *Suite) Test_MkLines__varuse_parameterized(c *check.C) { | |
150 | t := s.Init(c) | 150 | t := s.Init(c) | |
151 | 151 | |||
152 | t.SetupCommandLine("-Wall") | 152 | t.SetupCommandLine("-Wall") | |
153 | G.globalData.InitVartypes() | 153 | G.globalData.InitVartypes() | |
154 | mklines := t.NewMkLines("converters/wv2/Makefile", | 154 | mklines := t.NewMkLines("converters/wv2/Makefile", | |
155 | MkRcsId, | 155 | MkRcsID, | |
156 | "CONFIGURE_ARGS+=\t\t${CONFIGURE_ARGS.${ICONV_TYPE}-iconv}", | 156 | "CONFIGURE_ARGS+=\t\t${CONFIGURE_ARGS.${ICONV_TYPE}-iconv}", | |
157 | "CONFIGURE_ARGS.gnu-iconv=\t--with-libiconv=${BUILDLINK_PREFIX.iconv}") | 157 | "CONFIGURE_ARGS.gnu-iconv=\t--with-libiconv=${BUILDLINK_PREFIX.iconv}") | |
158 | 158 | |||
159 | mklines.Check() | 159 | mklines.Check() | |
160 | 160 | |||
161 | // No warnings about defined but not used or vice versa | 161 | // No warnings about defined but not used or vice versa | |
162 | t.CheckOutputEmpty() | 162 | t.CheckOutputEmpty() | |
163 | } | 163 | } | |
164 | 164 | |||
165 | func (s *Suite) Test_MkLines__loop_modifier(c *check.C) { | 165 | func (s *Suite) Test_MkLines__loop_modifier(c *check.C) { | |
166 | t := s.Init(c) | 166 | t := s.Init(c) | |
167 | 167 | |||
168 | t.SetupCommandLine("-Wall") | 168 | t.SetupCommandLine("-Wall") | |
169 | G.globalData.InitVartypes() | 169 | G.globalData.InitVartypes() | |
170 | mklines := t.NewMkLines("chat/xchat/Makefile", | 170 | mklines := t.NewMkLines("chat/xchat/Makefile", | |
171 | MkRcsId, | 171 | MkRcsID, | |
172 | "GCONF_SCHEMAS=\tapps_xchat_url_handler.schemas", | 172 | "GCONF_SCHEMAS=\tapps_xchat_url_handler.schemas", | |
173 | "post-install:", | 173 | "post-install:", | |
174 | "\t${GCONF_SCHEMAS:@.s.@"+ | 174 | "\t${GCONF_SCHEMAS:@.s.@"+ | |
175 | "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}") | 175 | "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}") | |
176 | 176 | |||
177 | mklines.Check() | 177 | mklines.Check() | |
178 | 178 | |||
179 | t.CheckOutputLines( | 179 | t.CheckOutputLines( | |
180 | // No warning about missing @ at the end | 180 | // No warning about missing @ at the end | |
181 | "WARN: chat/xchat/Makefile:4: " + | 181 | "WARN: chat/xchat/Makefile:4: " + | |
182 | "Unknown shell command \"${GCONF_SCHEMAS:@.s.@" + | 182 | "Unknown shell command \"${GCONF_SCHEMAS:@.s.@" + | |
183 | "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}\".") | 183 | "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}\".") | |
184 | } | 184 | } | |
185 | 185 | |||
186 | // PR 46570 | 186 | // PR 46570 | |
187 | func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) { | 187 | func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) { | |
188 | t := s.Init(c) | 188 | t := s.Init(c) | |
189 | 189 | |||
190 | G.globalData.InitVartypes() | 190 | G.globalData.InitVartypes() | |
191 | mklines := t.NewMkLines("Makefile", | 191 | mklines := t.NewMkLines("Makefile", | |
192 | MkRcsId, | 192 | MkRcsID, | |
193 | "PKG_SKIP_REASON+=\t\"Fails everywhere\"", | 193 | "PKG_SKIP_REASON+=\t\"Fails everywhere\"", | |
194 | ".if ${OPSYS} == \"Cygwin\"", | 194 | ".if ${OPSYS} == \"Cygwin\"", | |
195 | "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"", | 195 | "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"", | |
196 | ".endif") | 196 | ".endif") | |
197 | 197 | |||
198 | mklines.Check() | 198 | mklines.Check() | |
199 | 199 | |||
200 | t.CheckOutputLines( | 200 | t.CheckOutputLines( | |
201 | "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.") | 201 | "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.") | |
202 | } | 202 | } | |
203 | 203 | |||
204 | // PR 46570, item "15. net/uucp/Makefile has a make loop" | 204 | // PR 46570, item "15. net/uucp/Makefile has a make loop" | |
205 | func (s *Suite) Test_MkLines__indirect_variables(c *check.C) { | 205 | func (s *Suite) Test_MkLines__indirect_variables(c *check.C) { | |
206 | t := s.Init(c) | 206 | t := s.Init(c) | |
207 | 207 | |||
208 | t.SetupCommandLine("-Wall") | 208 | t.SetupCommandLine("-Wall") | |
209 | mklines := t.NewMkLines("net/uucp/Makefile", | 209 | mklines := t.NewMkLines("net/uucp/Makefile", | |
210 | MkRcsId, | 210 | MkRcsID, | |
211 | "", | 211 | "", | |
212 | "post-configure:", | 212 | "post-configure:", | |
213 | ".for var in MAIL_PROGRAM CMDPATH", | 213 | ".for var in MAIL_PROGRAM CMDPATH", | |
214 | "\t"+`${RUN} ${ECHO} "#define ${var} \""${UUCP_${var}}"\"`, | 214 | "\t"+`${RUN} ${ECHO} "#define ${var} \""${UUCP_${var}}"\"`, | |
215 | ".endfor") | 215 | ".endfor") | |
216 | 216 | |||
217 | mklines.Check() | 217 | mklines.Check() | |
218 | 218 | |||
219 | // No warning about UUCP_${var} being used but not defined. | 219 | // No warning about UUCP_${var} being used but not defined. | |
220 | t.CheckOutputLines( | 220 | t.CheckOutputLines( | |
221 | "WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".") | 221 | "WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".") | |
222 | } | 222 | } | |
223 | 223 | |||
224 | func (s *Suite) Test_MkLines_Check__list_variable_as_part_of_word(c *check.C) { | 224 | func (s *Suite) Test_MkLines_Check__list_variable_as_part_of_word(c *check.C) { | |
225 | t := s.Init(c) | 225 | t := s.Init(c) | |
226 | 226 | |||
227 | t.SetupCommandLine("-Wall") | 227 | t.SetupCommandLine("-Wall") | |
228 | mklines := t.NewMkLines("converters/chef/Makefile", | 228 | mklines := t.NewMkLines("converters/chef/Makefile", | |
229 | MkRcsId, | 229 | MkRcsID, | |
230 | "\tcd ${WRKSRC} && tr '\\r' '\\n' < ${DISTDIR}/${DIST_SUBDIR}/${DISTFILES} > chef.l") | 230 | "\tcd ${WRKSRC} && tr '\\r' '\\n' < ${DISTDIR}/${DIST_SUBDIR}/${DISTFILES} > chef.l") | |
231 | 231 | |||
232 | mklines.Check() | 232 | mklines.Check() | |
233 | 233 | |||
234 | t.CheckOutputLines( | 234 | t.CheckOutputLines( | |
235 | "WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".", | 235 | "WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".", | |
236 | "WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.") | 236 | "WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.") | |
237 | } | 237 | } | |
238 | 238 | |||
239 | func (s *Suite) Test_MkLines_Check__absolute_pathname_depending_on_OPSYS(c *check.C) { | 239 | func (s *Suite) Test_MkLines_Check__absolute_pathname_depending_on_OPSYS(c *check.C) { | |
240 | t := s.Init(c) | 240 | t := s.Init(c) | |
241 | 241 | |||
242 | t.SetupCommandLine("-Wall") | 242 | t.SetupCommandLine("-Wall") | |
243 | G.globalData.InitVartypes() | 243 | G.globalData.InitVartypes() | |
244 | mklines := t.NewMkLines("games/heretic2-demo/Makefile", | 244 | mklines := t.NewMkLines("games/heretic2-demo/Makefile", | |
245 | MkRcsId, | 245 | MkRcsID, | |
246 | ".if ${OPSYS} == \"DragonFly\"", | 246 | ".if ${OPSYS} == \"DragonFly\"", | |
247 | "TOOLS_PLATFORM.gtar=\t/usr/bin/bsdtar", | 247 | "TOOLS_PLATFORM.gtar=\t/usr/bin/bsdtar", | |
248 | ".endif", | 248 | ".endif", | |
249 | "TOOLS_PLATFORM.gtar=\t/usr/bin/bsdtar") | 249 | "TOOLS_PLATFORM.gtar=\t/usr/bin/bsdtar") | |
250 | 250 | |||
251 | mklines.Check() | 251 | mklines.Check() | |
252 | 252 | |||
253 | // No warning about an unknown shell command in line 3, | 253 | // No warning about an unknown shell command in line 3, | |
254 | // since that line depends on OPSYS. | 254 | // since that line depends on OPSYS. | |
255 | t.CheckOutputLines( | 255 | t.CheckOutputLines( | |
256 | "WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.", | 256 | "WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.", | |
257 | "WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.", | 257 | "WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.", | |
258 | "WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".") | 258 | "WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".") | |
259 | } | 259 | } | |
260 | 260 | |||
261 | func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) { | 261 | func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) { | |
262 | t := s.Init(c) | 262 | t := s.Init(c) | |
263 | 263 | |||
264 | t.SetupCommandLine("--show-autofix") | 264 | t.SetupCommandLine("--show-autofix") | |
265 | t.NewMkLines("Makefile.common", | 265 | t.NewMkLines("Makefile.common", | |
266 | MkRcsId, | 266 | MkRcsID, | |
267 | "", | 267 | "", | |
268 | "# used by sysutils/mc", | 268 | "# used by sysutils/mc", | |
269 | ).checkForUsedComment("sysutils/mc") | 269 | ).checkForUsedComment("sysutils/mc") | |
270 | 270 | |||
271 | t.CheckOutputEmpty() | 271 | t.CheckOutputEmpty() | |
272 | 272 | |||
273 | t.NewMkLines("Makefile.common").checkForUsedComment("category/package") | 273 | t.NewMkLines("Makefile.common").checkForUsedComment("category/package") | |
274 | 274 | |||
275 | t.CheckOutputEmpty() | 275 | t.CheckOutputEmpty() | |
276 | 276 | |||
277 | t.NewMkLines("Makefile.common", | 277 | t.NewMkLines("Makefile.common", | |
278 | MkRcsId, | 278 | MkRcsID, | |
279 | ).checkForUsedComment("category/package") | 279 | ).checkForUsedComment("category/package") | |
280 | 280 | |||
281 | t.CheckOutputEmpty() | 281 | t.CheckOutputEmpty() | |
282 | 282 | |||
283 | t.NewMkLines("Makefile.common", | 283 | t.NewMkLines("Makefile.common", | |
284 | MkRcsId, | 284 | MkRcsID, | |
285 | "", | 285 | "", | |
286 | ).checkForUsedComment("category/package") | 286 | ).checkForUsedComment("category/package") | |
287 | 287 | |||
288 | t.CheckOutputEmpty() | 288 | t.CheckOutputEmpty() | |
289 | 289 | |||
290 | t.NewMkLines("Makefile.common", | 290 | t.NewMkLines("Makefile.common", | |
291 | MkRcsId, | 291 | MkRcsID, | |
292 | "", | 292 | "", | |
293 | "VARNAME=\tvalue", | 293 | "VARNAME=\tvalue", | |
294 | ).checkForUsedComment("category/package") | 294 | ).checkForUsedComment("category/package") | |
295 | 295 | |||
296 | t.CheckOutputLines( | 296 | t.CheckOutputLines( | |
297 | "WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.", | 297 | "WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.", | |
298 | "AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line.") | 298 | "AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line.") | |
299 | 299 | |||
300 | t.NewMkLines("Makefile.common", | 300 | t.NewMkLines("Makefile.common", | |
301 | MkRcsId, | 301 | MkRcsID, | |
302 | "#", | 302 | "#", | |
303 | "#", | 303 | "#", | |
304 | ).checkForUsedComment("category/package") | 304 | ).checkForUsedComment("category/package") | |
305 | 305 | |||
306 | t.CheckOutputLines( | 306 | t.CheckOutputLines( | |
307 | "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.", | 307 | "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.", | |
308 | "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.") | 308 | "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.") | |
309 | 309 | |||
310 | c.Check(G.autofixAvailable, equals, true) | 310 | c.Check(G.autofixAvailable, equals, true) | |
311 | } | 311 | } | |
312 | 312 | |||
313 | func (s *Suite) Test_MkLines_DetermineUsedVariables__simple(c *check.C) { | 313 | func (s *Suite) Test_MkLines_DetermineUsedVariables__simple(c *check.C) { | |
314 | t := s.Init(c) | 314 | t := s.Init(c) | |
@@ -336,58 +336,58 @@ func (s *Suite) Test_MkLines_DetermineUs | @@ -336,58 +336,58 @@ func (s *Suite) Test_MkLines_DetermineUs | |||
336 | 336 | |||
337 | c.Check(len(mklines.varuse), equals, 3) | 337 | c.Check(len(mklines.varuse), equals, 3) | |
338 | c.Check(mklines.varuse["inner"], equals, mkline) | 338 | c.Check(mklines.varuse["inner"], equals, mkline) | |
339 | c.Check(mklines.varuse["outer."], equals, mkline) | 339 | c.Check(mklines.varuse["outer."], equals, mkline) | |
340 | c.Check(mklines.varuse["outer.*"], equals, mkline) | 340 | c.Check(mklines.varuse["outer.*"], equals, mkline) | |
341 | } | 341 | } | |
342 | 342 | |||
343 | func (s *Suite) Test_MkLines_PrivateTool_Undefined(c *check.C) { | 343 | func (s *Suite) Test_MkLines_PrivateTool_Undefined(c *check.C) { | |
344 | t := s.Init(c) | 344 | t := s.Init(c) | |
345 | 345 | |||
346 | t.SetupCommandLine("-Wall") | 346 | t.SetupCommandLine("-Wall") | |
347 | G.globalData.InitVartypes() | 347 | G.globalData.InitVartypes() | |
348 | mklines := t.NewMkLines("fname", | 348 | mklines := t.NewMkLines("fname", | |
349 | MkRcsId, | 349 | MkRcsID, | |
350 | "", | 350 | "", | |
351 | "\tmd5sum filename") | 351 | "\tmd5sum filename") | |
352 | 352 | |||
353 | mklines.Check() | 353 | mklines.Check() | |
354 | 354 | |||
355 | t.CheckOutputLines( | 355 | t.CheckOutputLines( | |
356 | "WARN: fname:3: Unknown shell command \"md5sum\".") | 356 | "WARN: fname:3: Unknown shell command \"md5sum\".") | |
357 | } | 357 | } | |
358 | 358 | |||
359 | func (s *Suite) Test_MkLines_PrivateTool_Defined(c *check.C) { | 359 | func (s *Suite) Test_MkLines_PrivateTool_Defined(c *check.C) { | |
360 | t := s.Init(c) | 360 | t := s.Init(c) | |
361 | 361 | |||
362 | t.SetupCommandLine("-Wall") | 362 | t.SetupCommandLine("-Wall") | |
363 | G.globalData.InitVartypes() | 363 | G.globalData.InitVartypes() | |
364 | mklines := t.NewMkLines("fname", | 364 | mklines := t.NewMkLines("fname", | |
365 | MkRcsId, | 365 | MkRcsID, | |
366 | "TOOLS_CREATE+=\tmd5sum", | 366 | "TOOLS_CREATE+=\tmd5sum", | |
367 | "", | 367 | "", | |
368 | "\tmd5sum filename") | 368 | "\tmd5sum filename") | |
369 | 369 | |||
370 | mklines.Check() | 370 | mklines.Check() | |
371 | 371 | |||
372 | t.CheckOutputEmpty() | 372 | t.CheckOutputEmpty() | |
373 | } | 373 | } | |
374 | 374 | |||
375 | func (s *Suite) Test_MkLines_Check_indentation(c *check.C) { | 375 | func (s *Suite) Test_MkLines_Check_indentation(c *check.C) { | |
376 | t := s.Init(c) | 376 | t := s.Init(c) | |
377 | 377 | |||
378 | t.SetupCommandLine("-Wall") | 378 | t.SetupCommandLine("-Wall") | |
379 | mklines := t.NewMkLines("options.mk", | 379 | mklines := t.NewMkLines("options.mk", | |
380 | MkRcsId, | 380 | MkRcsID, | |
381 | ". if !defined(GUARD_MK)", | 381 | ". if !defined(GUARD_MK)", | |
382 | ". if ${OPSYS} == ${OPSYS}", | 382 | ". if ${OPSYS} == ${OPSYS}", | |
383 | ". for i in ${FILES}", | 383 | ". for i in ${FILES}", | |
384 | ". if !defined(GUARD2_MK)", | 384 | ". if !defined(GUARD2_MK)", | |
385 | ". else", | 385 | ". else", | |
386 | ". endif", | 386 | ". endif", | |
387 | ". endfor", | 387 | ". endfor", | |
388 | ". if ${COND1}", | 388 | ". if ${COND1}", | |
389 | ". elif ${COND2}", | 389 | ". elif ${COND2}", | |
390 | ". else ${COND3}", | 390 | ". else ${COND3}", | |
391 | ". endif", | 391 | ". endif", | |
392 | ". endif", | 392 | ". endif", | |
393 | ". endif", | 393 | ". endif", | |
@@ -413,27 +413,27 @@ func (s *Suite) Test_MkLines_Check_inden | @@ -413,27 +413,27 @@ func (s *Suite) Test_MkLines_Check_inden | |||
413 | "NOTE: options.mk:14: This directive should be indented by 0 spaces.", | 413 | "NOTE: options.mk:14: This directive should be indented by 0 spaces.", | |
414 | "ERROR: options.mk:15: Unmatched .endif.", | 414 | "ERROR: options.mk:15: Unmatched .endif.", | |
415 | "NOTE: options.mk:15: This directive should be indented by 0 spaces.") | 415 | "NOTE: options.mk:15: This directive should be indented by 0 spaces.") | |
416 | } | 416 | } | |
417 | 417 | |||
418 | // Demonstrates how to define your own make(1) targets. | 418 | // Demonstrates how to define your own make(1) targets. | |
419 | func (s *Suite) Test_MkLines_wip_category_Makefile(c *check.C) { | 419 | func (s *Suite) Test_MkLines_wip_category_Makefile(c *check.C) { | |
420 | t := s.Init(c) | 420 | t := s.Init(c) | |
421 | 421 | |||
422 | t.SetupCommandLine("-Wall") | 422 | t.SetupCommandLine("-Wall") | |
423 | G.globalData.InitVartypes() | 423 | G.globalData.InitVartypes() | |
424 | t.SetupTool(&Tool{Name: "rm", Varname: "RM", Predefined: true}) | 424 | t.SetupTool(&Tool{Name: "rm", Varname: "RM", Predefined: true}) | |
425 | mklines := t.NewMkLines("Makefile", | 425 | mklines := t.NewMkLines("Makefile", | |
426 | MkRcsId, | 426 | MkRcsID, | |
427 | "", | 427 | "", | |
428 | "COMMENT=\tWIP pkgsrc packages", | 428 | "COMMENT=\tWIP pkgsrc packages", | |
429 | "", | 429 | "", | |
430 | "SUBDIR+=\taaa", | 430 | "SUBDIR+=\taaa", | |
431 | "SUBDIR+=\tzzz", | 431 | "SUBDIR+=\tzzz", | |
432 | "", | 432 | "", | |
433 | "${.CURDIR}/PKGDB:", | 433 | "${.CURDIR}/PKGDB:", | |
434 | "\t${RM} -f ${.CURDIR}/PKGDB", | 434 | "\t${RM} -f ${.CURDIR}/PKGDB", | |
435 | "", | 435 | "", | |
436 | "${.CURDIR}/INDEX:", | 436 | "${.CURDIR}/INDEX:", | |
437 | "\t${RM} -f ${.CURDIR}/INDEX", | 437 | "\t${RM} -f ${.CURDIR}/INDEX", | |
438 | "", | 438 | "", | |
439 | ".include \"../../mk/misc/category.mk\"") | 439 | ".include \"../../mk/misc/category.mk\"") |
@@ -24,86 +24,86 @@ func (s *Suite) Test_ChecklinesDistinfo( | @@ -24,86 +24,86 @@ func (s *Suite) Test_ChecklinesDistinfo( | |||
24 | t.CheckOutputLines( | 24 | t.CheckOutputLines( | |
25 | "ERROR: distinfo:1: Expected \"$"+"NetBSD$\".", | 25 | "ERROR: distinfo:1: Expected \"$"+"NetBSD$\".", | |
26 | "NOTE: distinfo:2: Empty line expected.", | 26 | "NOTE: distinfo:2: Empty line expected.", | |
27 | "ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.", | 27 | "ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.", | |
28 | "WARN: distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".") | 28 | "WARN: distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".") | |
29 | } | 29 | } | |
30 | 30 | |||
31 | func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) { | 31 | func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) { | |
32 | t := s.Init(c) | 32 | t := s.Init(c) | |
33 | 33 | |||
34 | otherLine := t.NewLine("other/distinfo", 7, "dummy") | 34 | otherLine := t.NewLine("other/distinfo", 7, "dummy") | |
35 | G.Hash = map[string]*Hash{"SHA512:pkgname-1.0.tar.gz": {"Some-512-bit-hash", otherLine}} | 35 | G.Hash = map[string]*Hash{"SHA512:pkgname-1.0.tar.gz": {"Some-512-bit-hash", otherLine}} | |
36 | lines := t.NewLines("distinfo", | 36 | lines := t.NewLines("distinfo", | |
37 | RcsId, | 37 | RcsID, | |
38 | "", | 38 | "", | |
39 | "SHA512 (pkgname-1.0.tar.gz) = 12341234") | 39 | "SHA512 (pkgname-1.0.tar.gz) = 12341234") | |
40 | 40 | |||
41 | ChecklinesDistinfo(lines) | 41 | ChecklinesDistinfo(lines) | |
42 | 42 | |||
43 | t.CheckOutputLines( | 43 | t.CheckOutputLines( | |
44 | "ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from Some-512-bit-hash in other/distinfo:7.", | 44 | "ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from Some-512-bit-hash in other/distinfo:7.", | |
45 | "ERROR: distinfo:EOF: Expected SHA1, RMD160, SHA512, Size checksums for \"pkgname-1.0.tar.gz\", got SHA512.") | 45 | "ERROR: distinfo:EOF: Expected SHA1, RMD160, SHA512, Size checksums for \"pkgname-1.0.tar.gz\", got SHA512.") | |
46 | } | 46 | } | |
47 | 47 | |||
48 | func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) { | 48 | func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) { | |
49 | t := s.Init(c) | 49 | t := s.Init(c) | |
50 | 50 | |||
51 | t.SetupFileLines("patches/patch-aa", | 51 | t.SetupFileLines("patches/patch-aa", | |
52 | RcsId, | 52 | RcsID, | |
53 | "", | 53 | "", | |
54 | "--- oldfile", | 54 | "--- oldfile", | |
55 | "+++ newfile", | 55 | "+++ newfile", | |
56 | "@@ -1,1 +1,1 @@", | 56 | "@@ -1,1 +1,1 @@", | |
57 | "-old", | 57 | "-old", | |
58 | "+new") | 58 | "+new") | |
59 | t.SetupFileLines("CVS/Entries", | 59 | t.SetupFileLines("CVS/Entries", | |
60 | "/distinfo/...") | 60 | "/distinfo/...") | |
61 | lines := t.SetupFileLines("distinfo", | 61 | lines := t.SetupFileLines("distinfo", | |
62 | RcsId, | 62 | RcsID, | |
63 | "", | 63 | "", | |
64 | "SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0") | 64 | "SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0") | |
65 | G.CurrentDir = t.TmpDir() | 65 | G.CurrentDir = t.TmpDir() | |
66 | 66 | |||
67 | ChecklinesDistinfo(lines) | 67 | ChecklinesDistinfo(lines) | |
68 | 68 | |||
69 | t.CheckOutputLines( | 69 | t.CheckOutputLines( | |
70 | "WARN: ~/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.") | 70 | "WARN: ~/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.") | |
71 | } | 71 | } | |
72 | 72 | |||
73 | func (s *Suite) Test_ChecklinesDistinfo_unrecorded_patches(c *check.C) { | 73 | func (s *Suite) Test_ChecklinesDistinfo_unrecorded_patches(c *check.C) { | |
74 | t := s.Init(c) | 74 | t := s.Init(c) | |
75 | 75 | |||
76 | t.SetupFileLines("patches/CVS/Entries") | 76 | t.SetupFileLines("patches/CVS/Entries") | |
77 | t.SetupFileLines("patches/patch-aa") | 77 | t.SetupFileLines("patches/patch-aa") | |
78 | t.SetupFileLines("patches/patch-src-Makefile") | 78 | t.SetupFileLines("patches/patch-src-Makefile") | |
79 | lines := t.SetupFileLines("distinfo", | 79 | lines := t.SetupFileLines("distinfo", | |
80 | RcsId, | 80 | RcsID, | |
81 | "", | 81 | "", | |
82 | "SHA1 (distfile.tar.gz) = ...", | 82 | "SHA1 (distfile.tar.gz) = ...", | |
83 | "RMD160 (distfile.tar.gz) = ...", | 83 | "RMD160 (distfile.tar.gz) = ...", | |
84 | "SHA512 (distfile.tar.gz) = ...", | 84 | "SHA512 (distfile.tar.gz) = ...", | |
85 | "Size (distfile.tar.gz) = 1024 bytes") | 85 | "Size (distfile.tar.gz) = 1024 bytes") | |
86 | G.CurrentDir = t.TmpDir() | 86 | G.CurrentDir = t.TmpDir() | |
87 | 87 | |||
88 | ChecklinesDistinfo(lines) | 88 | ChecklinesDistinfo(lines) | |
89 | 89 | |||
90 | t.CheckOutputLines( | 90 | t.CheckOutputLines( | |
91 | "ERROR: ~/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".", | 91 | "ERROR: ~/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".", | |
92 | "ERROR: ~/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".") | 92 | "ERROR: ~/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".") | |
93 | } | 93 | } | |
94 | 94 | |||
95 | func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) { | 95 | func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) { | |
96 | t := s.Init(c) | 96 | t := s.Init(c) | |
97 | 97 | |||
98 | t.SetupFileLines("patches/manual-libtool.m4") | 98 | t.SetupFileLines("patches/manual-libtool.m4") | |
99 | lines := t.SetupFileLines("distinfo", | 99 | lines := t.SetupFileLines("distinfo", | |
100 | RcsId, | 100 | RcsID, | |
101 | "", | 101 | "", | |
102 | "SHA1 (patch-aa) = ...") | 102 | "SHA1 (patch-aa) = ...") | |
103 | G.CurrentDir = t.TmpDir() | 103 | G.CurrentDir = t.TmpDir() | |
104 | 104 | |||
105 | ChecklinesDistinfo(lines) | 105 | ChecklinesDistinfo(lines) | |
106 | 106 | |||
107 | t.CheckOutputLines( | 107 | t.CheckOutputLines( | |
108 | "WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".") | 108 | "WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".") | |
109 | } | 109 | } |
@@ -1,106 +1,106 @@ | @@ -1,106 +1,106 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import ( | 3 | import ( | |
4 | "path" | 4 | "path" | |
5 | "strings" | 5 | "strings" | |
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. | |
10 | type Vartype struct { | 10 | type 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 | |||
17 | type KindOfList uint8 | 17 | type KindOfList uint8 | |
18 | 18 | |||
19 | const ( | 19 | const ( | |
20 | lkNone KindOfList = iota // Plain data type | 20 | lkNone KindOfList = iota // Plain data type | |
21 | lkSpace // List entries are separated by whitespace; used in .for loops. | 21 | lkSpace // List entries are separated by whitespace; used in .for loops. | |
22 | lkShell // List entries are shell words; used in the :M, :S modifiers. | 22 | lkShell // List entries are shell words; used in the :M, :S modifiers. | |
23 | ) | 23 | ) | |
24 | 24 | |||
25 | type AclEntry struct { | 25 | type ACLEntry struct { | |
26 | glob string // Examples: "Makefile", "*.mk" | 26 | glob string // Examples: "Makefile", "*.mk" | |
27 | permissions AclPermissions | 27 | permissions ACLPermissions | |
28 | } | 28 | } | |
29 | 29 | |||
30 | type AclPermissions uint8 | 30 | type ACLPermissions uint8 | |
31 | 31 | |||
32 | const ( | 32 | const ( | |
33 | aclpSet AclPermissions = 1 << iota // VAR = value | 33 | aclpSet ACLPermissions = 1 << iota // VAR = value | |
34 | aclpSetDefault // VAR ?= value | 34 | aclpSetDefault // VAR ?= value | |
35 | aclpAppend // VAR += value | 35 | aclpAppend // VAR += value | |
36 | aclpUseLoadtime // OTHER := ${VAR}, OTHER != ${VAR} | 36 | aclpUseLoadtime // OTHER := ${VAR}, OTHER != ${VAR} | |
37 | aclpUse // OTHER = ${VAR} | 37 | aclpUse // OTHER = ${VAR} | |
38 | aclpUnknown | 38 | aclpUnknown | |
39 | aclpAll AclPermissions = aclpAppend | aclpSetDefault | aclpSet | aclpUseLoadtime | aclpUse | 39 | aclpAll = aclpAppend | aclpSetDefault | aclpSet | aclpUseLoadtime | aclpUse | |
40 | aclpAllRuntime AclPermissions = aclpAppend | aclpSetDefault | aclpSet | aclpUse | 40 | aclpAllRuntime = aclpAppend | aclpSetDefault | aclpSet | aclpUse | |
41 | aclpAllWrite AclPermissions = aclpSet | aclpSetDefault | aclpAppend | 41 | aclpAllWrite = aclpSet | aclpSetDefault | aclpAppend | |
42 | aclpAllRead AclPermissions = aclpUseLoadtime | aclpUse | 42 | aclpAllRead = aclpUseLoadtime | aclpUse | |
43 | ) | 43 | ) | |
44 | 44 | |||
45 | func (perms AclPermissions) Contains(subset AclPermissions) bool { | 45 | func (perms ACLPermissions) Contains(subset ACLPermissions) bool { | |
46 | return perms&subset == subset | 46 | return perms&subset == subset | |
47 | } | 47 | } | |
48 | 48 | |||
49 | func (perms AclPermissions) String() string { | 49 | func (perms ACLPermissions) String() string { | |
50 | if perms == 0 { | 50 | if perms == 0 { | |
51 | return "none" | 51 | return "none" | |
52 | } | 52 | } | |
53 | result := "" + | 53 | result := "" + | |
54 | ifelseStr(perms.Contains(aclpSet), "set, ", "") + | 54 | ifelseStr(perms.Contains(aclpSet), "set, ", "") + | |
55 | ifelseStr(perms.Contains(aclpSetDefault), "set-default, ", "") + | 55 | ifelseStr(perms.Contains(aclpSetDefault), "set-default, ", "") + | |
56 | ifelseStr(perms.Contains(aclpAppend), "append, ", "") + | 56 | ifelseStr(perms.Contains(aclpAppend), "append, ", "") + | |
57 | ifelseStr(perms.Contains(aclpUseLoadtime), "use-loadtime, ", "") + | 57 | ifelseStr(perms.Contains(aclpUseLoadtime), "use-loadtime, ", "") + | |
58 | ifelseStr(perms.Contains(aclpUse), "use, ", "") + | 58 | ifelseStr(perms.Contains(aclpUse), "use, ", "") + | |
59 | ifelseStr(perms.Contains(aclpUnknown), "unknown, ", "") | 59 | ifelseStr(perms.Contains(aclpUnknown), "unknown, ", "") | |
60 | return strings.TrimRight(result, ", ") | 60 | return strings.TrimRight(result, ", ") | |
61 | } | 61 | } | |
62 | 62 | |||
63 | func (perms AclPermissions) HumanString() string { | 63 | func (perms ACLPermissions) HumanString() string { | |
64 | result := "" + | 64 | result := "" + | |
65 | ifelseStr(perms.Contains(aclpSet), "set, ", "") + | 65 | ifelseStr(perms.Contains(aclpSet), "set, ", "") + | |
66 | ifelseStr(perms.Contains(aclpSetDefault), "given a default value, ", "") + | 66 | ifelseStr(perms.Contains(aclpSetDefault), "given a default value, ", "") + | |
67 | ifelseStr(perms.Contains(aclpAppend), "appended to, ", "") + | 67 | ifelseStr(perms.Contains(aclpAppend), "appended to, ", "") + | |
68 | ifelseStr(perms.Contains(aclpUseLoadtime), "used at load time, ", "") + | 68 | ifelseStr(perms.Contains(aclpUseLoadtime), "used at load time, ", "") + | |
69 | ifelseStr(perms.Contains(aclpUse), "used, ", "") | 69 | ifelseStr(perms.Contains(aclpUse), "used, ", "") | |
70 | return strings.TrimRight(result, ", ") | 70 | return strings.TrimRight(result, ", ") | |
71 | } | 71 | } | |
72 | 72 | |||
73 | func (vt *Vartype) EffectivePermissions(fname string) AclPermissions { | 73 | func (vt *Vartype) EffectivePermissions(fname string) ACLPermissions { | |
74 | for _, aclEntry := range vt.aclEntries { | 74 | for _, aclEntry := range vt.aclEntries { | |
75 | if m, _ := path.Match(aclEntry.glob, path.Base(fname)); m { | 75 | if m, _ := path.Match(aclEntry.glob, path.Base(fname)); m { | |
76 | return aclEntry.permissions | 76 | return aclEntry.permissions | |
77 | } | 77 | } | |
78 | } | 78 | } | |
79 | return aclpUnknown | 79 | return aclpUnknown | |
80 | } | 80 | } | |
81 | 81 | |||
82 | // Returns the union of all possible permissions. This can be used to | 82 | // Returns the union of all possible permissions. This can be used to | |
83 | // check whether a variable may be defined or used at all, or if it is | 83 | // check whether a variable may be defined or used at all, or if it is | |
84 | // read-only. | 84 | // read-only. | |
85 | func (vt *Vartype) Union() AclPermissions { | 85 | func (vt *Vartype) Union() ACLPermissions { | |
86 | var permissions AclPermissions | 86 | var permissions ACLPermissions | |
87 | for _, aclEntry := range vt.aclEntries { | 87 | for _, aclEntry := range vt.aclEntries { | |
88 | permissions |= aclEntry.permissions | 88 | permissions |= aclEntry.permissions | |
89 | } | 89 | } | |
90 | return permissions | 90 | return permissions | |
91 | } | 91 | } | |
92 | 92 | |||
93 | func (vt *Vartype) AllowedFiles(perms AclPermissions) string { | 93 | func (vt *Vartype) AllowedFiles(perms ACLPermissions) string { | |
94 | files := make([]string, 0, len(vt.aclEntries)) | 94 | files := make([]string, 0, len(vt.aclEntries)) | |
95 | for _, aclEntry := range vt.aclEntries { | 95 | for _, aclEntry := range vt.aclEntries { | |
96 | if aclEntry.permissions.Contains(perms) { | 96 | if aclEntry.permissions.Contains(perms) { | |
97 | files = append(files, aclEntry.glob) | 97 | files = append(files, aclEntry.glob) | |
98 | } | 98 | } | |
99 | } | 99 | } | |
100 | return strings.Join(files, ", ") | 100 | return strings.Join(files, ", ") | |
101 | } | 101 | } | |
102 | 102 | |||
103 | // Returns whether the type is considered a shell list. | 103 | // Returns whether the type is considered a shell list. | |
104 | // This distinction between "real lists" and "considered a list" makes | 104 | // This distinction between "real lists" and "considered a list" makes | |
105 | // the implementation of checklineMkVartype easier. | 105 | // the implementation of checklineMkVartype easier. | |
106 | func (vt *Vartype) IsConsideredList() bool { | 106 | func (vt *Vartype) IsConsideredList() bool { |
@@ -1,20 +1,24 @@ | @@ -1,20 +1,24 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import ( | 3 | import ( | |
4 | "io/ioutil" | 4 | "io/ioutil" | |
5 | "strings" | 5 | "strings" | |
6 | ) | 6 | ) | |
7 | 7 | |||
8 | // LoadNonemptyLines loads the given file. | |||
9 | // If the file doesn't exist or is empty, an error is logged. | |||
10 | // | |||
11 | // See [LoadExistingLines]. | |||
8 | func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line { | 12 | func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line { | |
9 | lines, err := readLines(fname, joinBackslashLines) | 13 | lines, err := readLines(fname, joinBackslashLines) | |
10 | if err != nil { | 14 | if err != nil { | |
11 | NewLineWhole(fname).Errorf("Cannot be read.") | 15 | NewLineWhole(fname).Errorf("Cannot be read.") | |
12 | return nil | 16 | return nil | |
13 | } | 17 | } | |
14 | if len(lines) == 0 { | 18 | if len(lines) == 0 { | |
15 | NewLineWhole(fname).Errorf("Must not be empty.") | 19 | NewLineWhole(fname).Errorf("Must not be empty.") | |
16 | return nil | 20 | return nil | |
17 | } | 21 | } | |
18 | return lines | 22 | return lines | |
19 | } | 23 | } | |
20 | 24 |
@@ -1,115 +1,115 @@ | @@ -1,115 +1,115 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import "gopkg.in/check.v1" | 3 | import "gopkg.in/check.v1" | |
4 | 4 | |||
5 | func (s *Suite) Test_ChecklinesPatch__with_comment(c *check.C) { | 5 | func (s *Suite) Test_ChecklinesPatch__with_comment(c *check.C) { | |
6 | t := s.Init(c) | 6 | t := s.Init(c) | |
7 | 7 | |||
8 | t.SetupCommandLine("-Wall") | 8 | t.SetupCommandLine("-Wall") | |
9 | lines := t.NewLines("patch-WithComment", | 9 | lines := t.NewLines("patch-WithComment", | |
10 | RcsId, | 10 | RcsID, | |
11 | "", | 11 | "", | |
12 | "Text", | 12 | "Text", | |
13 | "Text", | 13 | "Text", | |
14 | "", | 14 | "", | |
15 | "--- file.orig", | 15 | "--- file.orig", | |
16 | "+++ file", | 16 | "+++ file", | |
17 | "@@ -5,3 +5,3 @@", | 17 | "@@ -5,3 +5,3 @@", | |
18 | " context before", | 18 | " context before", | |
19 | "-old line", | 19 | "-old line", | |
20 | "+old line", | 20 | "+old line", | |
21 | " context after") | 21 | " context after") | |
22 | 22 | |||
23 | ChecklinesPatch(lines) | 23 | ChecklinesPatch(lines) | |
24 | 24 | |||
25 | t.CheckOutputEmpty() | 25 | t.CheckOutputEmpty() | |
26 | } | 26 | } | |
27 | 27 | |||
28 | func (s *Suite) Test_ChecklinesPatch__without_empty_line__autofix(c *check.C) { | 28 | func (s *Suite) Test_ChecklinesPatch__without_empty_line__autofix(c *check.C) { | |
29 | t := s.Init(c) | 29 | t := s.Init(c) | |
30 | 30 | |||
31 | patchLines := t.SetupFileLines("patch-WithoutEmptyLines", | 31 | patchLines := t.SetupFileLines("patch-WithoutEmptyLines", | |
32 | RcsId, | 32 | RcsID, | |
33 | "Text", | 33 | "Text", | |
34 | "--- file.orig", | 34 | "--- file.orig", | |
35 | "+++ file", | 35 | "+++ file", | |
36 | "@@ -5,3 +5,3 @@", | 36 | "@@ -5,3 +5,3 @@", | |
37 | " context before", | 37 | " context before", | |
38 | "-old line", | 38 | "-old line", | |
39 | "+old line", | 39 | "+old line", | |
40 | " context after") | 40 | " context after") | |
41 | t.SetupFileLines("distinfo", | 41 | t.SetupFileLines("distinfo", | |
42 | RcsId, | 42 | RcsID, | |
43 | "", | 43 | "", | |
44 | "SHA1 (some patch) = 87ffcaaa0b0677ec679fff612b44df1af05f04df") // Taken from breakpoint at AutofixDistinfo | 44 | "SHA1 (some patch) = 87ffcaaa0b0677ec679fff612b44df1af05f04df") // Taken from breakpoint at AutofixDistinfo | |
45 | 45 | |||
46 | t.SetupCommandLine("-Wall", "--autofix") | 46 | t.SetupCommandLine("-Wall", "--autofix") | |
47 | G.CurrentDir = t.TmpDir() | 47 | G.CurrentDir = t.TmpDir() | |
48 | G.Pkg = &Package{DistinfoFile: "distinfo"} | 48 | G.Pkg = &Package{DistinfoFile: "distinfo"} | |
49 | 49 | |||
50 | ChecklinesPatch(patchLines) | 50 | ChecklinesPatch(patchLines) | |
51 | 51 | |||
52 | t.CheckOutputLines( | 52 | t.CheckOutputLines( | |
53 | "AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.", | 53 | "AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.", | |
54 | "AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.", | 54 | "AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.", | |
55 | "AUTOFIX: ~/distinfo:3: Replacing \"87ffcaaa0b0677ec679fff612b44df1af05f04df\" "+ | 55 | "AUTOFIX: ~/distinfo:3: Replacing \"87ffcaaa0b0677ec679fff612b44df1af05f04df\" "+ | |
56 | "with \"a7c35294b3853da0acedf8a972cb266baa9582a3\".") | 56 | "with \"a7c35294b3853da0acedf8a972cb266baa9582a3\".") | |
57 | 57 | |||
58 | t.CheckFileLines("patch-WithoutEmptyLines", | 58 | t.CheckFileLines("patch-WithoutEmptyLines", | |
59 | RcsId, | 59 | RcsID, | |
60 | "", | 60 | "", | |
61 | "Text", | 61 | "Text", | |
62 | "", | 62 | "", | |
63 | "--- file.orig", | 63 | "--- file.orig", | |
64 | "+++ file", | 64 | "+++ file", | |
65 | "@@ -5,3 +5,3 @@", | 65 | "@@ -5,3 +5,3 @@", | |
66 | " context before", | 66 | " context before", | |
67 | "-old line", | 67 | "-old line", | |
68 | "+old line", | 68 | "+old line", | |
69 | " context after") | 69 | " context after") | |
70 | t.CheckFileLines("distinfo", | 70 | t.CheckFileLines("distinfo", | |
71 | RcsId, | 71 | RcsID, | |
72 | "", | 72 | "", | |
73 | "SHA1 (some patch) = a7c35294b3853da0acedf8a972cb266baa9582a3") | 73 | "SHA1 (some patch) = a7c35294b3853da0acedf8a972cb266baa9582a3") | |
74 | } | 74 | } | |
75 | 75 | |||
76 | func (s *Suite) Test_ChecklinesPatch__without_comment(c *check.C) { | 76 | func (s *Suite) Test_ChecklinesPatch__without_comment(c *check.C) { | |
77 | t := s.Init(c) | 77 | t := s.Init(c) | |
78 | 78 | |||
79 | t.SetupCommandLine("-Wall") | 79 | t.SetupCommandLine("-Wall") | |
80 | lines := t.NewLines("patch-WithoutComment", | 80 | lines := t.NewLines("patch-WithoutComment", | |
81 | RcsId, | 81 | RcsID, | |
82 | "", | 82 | "", | |
83 | "--- file.orig", | 83 | "--- file.orig", | |
84 | "+++ file", | 84 | "+++ file", | |
85 | "@@ -5,3 +5,3 @@", | 85 | "@@ -5,3 +5,3 @@", | |
86 | " context before", | 86 | " context before", | |
87 | "-old line", | 87 | "-old line", | |
88 | "+old line", | 88 | "+old line", | |
89 | " context after") | 89 | " context after") | |
90 | 90 | |||
91 | ChecklinesPatch(lines) | 91 | ChecklinesPatch(lines) | |
92 | 92 | |||
93 | t.CheckOutputLines( | 93 | t.CheckOutputLines( | |
94 | "ERROR: patch-WithoutComment:3: Each patch must be documented.") | 94 | "ERROR: patch-WithoutComment:3: Each patch must be documented.") | |
95 | } | 95 | } | |
96 | 96 | |||
97 | func (s *Suite) Test_ChecklinesPatch__git_without_comment(c *check.C) { | 97 | func (s *Suite) Test_ChecklinesPatch__git_without_comment(c *check.C) { | |
98 | t := s.Init(c) | 98 | t := s.Init(c) | |
99 | 99 | |||
100 | t.SetupCommandLine("-Wall") | 100 | t.SetupCommandLine("-Wall") | |
101 | lines := t.NewLines("patch-aa", | 101 | lines := t.NewLines("patch-aa", | |
102 | RcsId, | 102 | RcsID, | |
103 | "", | 103 | "", | |
104 | "diff --git a/aa b/aa", | 104 | "diff --git a/aa b/aa", | |
105 | "index 1234567..1234567 100644", | 105 | "index 1234567..1234567 100644", | |
106 | "--- a/aa", | 106 | "--- a/aa", | |
107 | "+++ b/aa", | 107 | "+++ b/aa", | |
108 | "@@ -1,1 +1,1 @@", | 108 | "@@ -1,1 +1,1 @@", | |
109 | "-old", | 109 | "-old", | |
110 | "+new") | 110 | "+new") | |
111 | 111 | |||
112 | ChecklinesPatch(lines) | 112 | ChecklinesPatch(lines) | |
113 | 113 | |||
114 | t.CheckOutputLines( | 114 | t.CheckOutputLines( | |
115 | "ERROR: patch-aa:5: Each patch must be documented.") | 115 | "ERROR: patch-aa:5: Each patch must be documented.") | |
@@ -120,183 +120,183 @@ func (s *Suite) Test_checklineOtherAbsol | @@ -120,183 +120,183 @@ func (s *Suite) Test_checklineOtherAbsol | |||
120 | 120 | |||
121 | line := t.NewLine("patch-ag", 1, "+$install -s -c ./bin/rosegarden ${DESTDIR}$BINDIR") | 121 | line := t.NewLine("patch-ag", 1, "+$install -s -c ./bin/rosegarden ${DESTDIR}$BINDIR") | |
122 | 122 | |||
123 | checklineOtherAbsolutePathname(line, line.Text) | 123 | checklineOtherAbsolutePathname(line, line.Text) | |
124 | 124 | |||
125 | t.CheckOutputEmpty() | 125 | t.CheckOutputEmpty() | |
126 | } | 126 | } | |
127 | 127 | |||
128 | func (s *Suite) Test_ChecklinesPatch__error_code(c *check.C) { | 128 | func (s *Suite) Test_ChecklinesPatch__error_code(c *check.C) { | |
129 | t := s.Init(c) | 129 | t := s.Init(c) | |
130 | 130 | |||
131 | t.SetupCommandLine("-Wall") | 131 | t.SetupCommandLine("-Wall") | |
132 | lines := t.NewLines("patch-ErrorCode", | 132 | lines := t.NewLines("patch-ErrorCode", | |
133 | RcsId, | 133 | RcsID, | |
134 | "", | 134 | "", | |
135 | "*** Error code 1", // Looks like a context diff, but isn't. | 135 | "*** Error code 1", // Looks like a context diff, but isn't. | |
136 | "", | 136 | "", | |
137 | "--- file.orig", | 137 | "--- file.orig", | |
138 | "+++ file", | 138 | "+++ file", | |
139 | "@@ -5,3 +5,3 @@", | 139 | "@@ -5,3 +5,3 @@", | |
140 | " context before", | 140 | " context before", | |
141 | "-old line", | 141 | "-old line", | |
142 | "+old line", | 142 | "+old line", | |
143 | " context after") | 143 | " context after") | |
144 | 144 | |||
145 | ChecklinesPatch(lines) | 145 | ChecklinesPatch(lines) | |
146 | 146 | |||
147 | t.CheckOutputEmpty() | 147 | t.CheckOutputEmpty() | |
148 | } | 148 | } | |
149 | 149 | |||
150 | func (s *Suite) Test_ChecklinesPatch__wrong_header_order(c *check.C) { | 150 | func (s *Suite) Test_ChecklinesPatch__wrong_header_order(c *check.C) { | |
151 | t := s.Init(c) | 151 | t := s.Init(c) | |
152 | 152 | |||
153 | t.SetupCommandLine("-Wall") | 153 | t.SetupCommandLine("-Wall") | |
154 | lines := t.NewLines("patch-WrongOrder", | 154 | lines := t.NewLines("patch-WrongOrder", | |
155 | RcsId, | 155 | RcsID, | |
156 | "", | 156 | "", | |
157 | "Text", | 157 | "Text", | |
158 | "Text", | 158 | "Text", | |
159 | "", | 159 | "", | |
160 | "+++ file", // Wrong | 160 | "+++ file", // Wrong | |
161 | "--- file.orig", // Wrong | 161 | "--- file.orig", // Wrong | |
162 | "@@ -5,3 +5,3 @@", | 162 | "@@ -5,3 +5,3 @@", | |
163 | " context before", | 163 | " context before", | |
164 | "-old line", | 164 | "-old line", | |
165 | "+old line", | 165 | "+old line", | |
166 | " context after") | 166 | " context after") | |
167 | 167 | |||
168 | ChecklinesPatch(lines) | 168 | ChecklinesPatch(lines) | |
169 | 169 | |||
170 | t.CheckOutputLines( | 170 | t.CheckOutputLines( | |
171 | "WARN: patch-WrongOrder:7: Unified diff headers should be first ---, then +++.") | 171 | "WARN: patch-WrongOrder:7: Unified diff headers should be first ---, then +++.") | |
172 | } | 172 | } | |
173 | 173 | |||
174 | func (s *Suite) Test_ChecklinesPatch__context_diff(c *check.C) { | 174 | func (s *Suite) Test_ChecklinesPatch__context_diff(c *check.C) { | |
175 | t := s.Init(c) | 175 | t := s.Init(c) | |
176 | 176 | |||
177 | t.SetupCommandLine("-Wall") | 177 | t.SetupCommandLine("-Wall") | |
178 | lines := t.NewLines("patch-ctx", | 178 | lines := t.NewLines("patch-ctx", | |
179 | RcsId, | 179 | RcsID, | |
180 | "", | 180 | "", | |
181 | "diff -cr history.c.orig history.c", | 181 | "diff -cr history.c.orig history.c", | |
182 | "*** history.c.orig", | 182 | "*** history.c.orig", | |
183 | "--- history.c") | 183 | "--- history.c") | |
184 | 184 | |||
185 | ChecklinesPatch(lines) | 185 | ChecklinesPatch(lines) | |
186 | 186 | |||
187 | t.CheckOutputLines( | 187 | t.CheckOutputLines( | |
188 | "ERROR: patch-ctx:4: Each patch must be documented.", | 188 | "ERROR: patch-ctx:4: Each patch must be documented.", | |
189 | "WARN: patch-ctx:4: Please use unified diffs (diff -u) for patches.") | 189 | "WARN: patch-ctx:4: Please use unified diffs (diff -u) for patches.") | |
190 | } | 190 | } | |
191 | 191 | |||
192 | func (s *Suite) Test_ChecklinesPatch__no_patch(c *check.C) { | 192 | func (s *Suite) Test_ChecklinesPatch__no_patch(c *check.C) { | |
193 | t := s.Init(c) | 193 | t := s.Init(c) | |
194 | 194 | |||
195 | lines := t.NewLines("patch-aa", | 195 | lines := t.NewLines("patch-aa", | |
196 | RcsId, | 196 | RcsID, | |
197 | "", | 197 | "", | |
198 | "-- oldfile", | 198 | "-- oldfile", | |
199 | "++ newfile") | 199 | "++ newfile") | |
200 | 200 | |||
201 | ChecklinesPatch(lines) | 201 | ChecklinesPatch(lines) | |
202 | 202 | |||
203 | t.CheckOutputLines( | 203 | t.CheckOutputLines( | |
204 | "ERROR: patch-aa: Contains no patch.") | 204 | "ERROR: patch-aa: Contains no patch.") | |
205 | } | 205 | } | |
206 | 206 | |||
207 | func (s *Suite) Test_ChecklinesPatch__two_patched_files(c *check.C) { | 207 | func (s *Suite) Test_ChecklinesPatch__two_patched_files(c *check.C) { | |
208 | t := s.Init(c) | 208 | t := s.Init(c) | |
209 | 209 | |||
210 | lines := t.NewLines("patch-aa", | 210 | lines := t.NewLines("patch-aa", | |
211 | RcsId, | 211 | RcsID, | |
212 | "", | 212 | "", | |
213 | "--- oldfile", | 213 | "--- oldfile", | |
214 | "+++ newfile", | 214 | "+++ newfile", | |
215 | "@@ -1 +1 @@", | 215 | "@@ -1 +1 @@", | |
216 | "-old", | 216 | "-old", | |
217 | "+new", | 217 | "+new", | |
218 | "--- oldfile2", | 218 | "--- oldfile2", | |
219 | "+++ newfile2", | 219 | "+++ newfile2", | |
220 | "@@ -1 +1 @@", | 220 | "@@ -1 +1 @@", | |
221 | "-old", | 221 | "-old", | |
222 | "+new") | 222 | "+new") | |
223 | 223 | |||
224 | ChecklinesPatch(lines) | 224 | ChecklinesPatch(lines) | |
225 | 225 | |||
226 | t.CheckOutputLines( | 226 | t.CheckOutputLines( | |
227 | "ERROR: patch-aa:3: Each patch must be documented.", | 227 | "ERROR: patch-aa:3: Each patch must be documented.", | |
228 | "WARN: patch-aa: Contains patches for 2 files, should be only one.") | 228 | "WARN: patch-aa: Contains patches for 2 files, should be only one.") | |
229 | } | 229 | } | |
230 | 230 | |||
231 | func (s *Suite) Test_ChecklinesPatch__documentation_that_looks_like_patch_lines(c *check.C) { | 231 | func (s *Suite) Test_ChecklinesPatch__documentation_that_looks_like_patch_lines(c *check.C) { | |
232 | t := s.Init(c) | 232 | t := s.Init(c) | |
233 | 233 | |||
234 | lines := t.NewLines("patch-aa", | 234 | lines := t.NewLines("patch-aa", | |
235 | RcsId, | 235 | RcsID, | |
236 | "", | 236 | "", | |
237 | "--- oldfile", | 237 | "--- oldfile", | |
238 | "", | 238 | "", | |
239 | "+++ newfile", | 239 | "+++ newfile", | |
240 | "", | 240 | "", | |
241 | "*** oldOrNewFile") | 241 | "*** oldOrNewFile") | |
242 | 242 | |||
243 | ChecklinesPatch(lines) | 243 | ChecklinesPatch(lines) | |
244 | 244 | |||
245 | t.CheckOutputLines( | 245 | t.CheckOutputLines( | |
246 | "ERROR: patch-aa: Contains no patch.") | 246 | "ERROR: patch-aa: Contains no patch.") | |
247 | } | 247 | } | |
248 | 248 | |||
249 | func (s *Suite) Test_ChecklinesPatch__only_unified_header_but_no_content(c *check.C) { | 249 | func (s *Suite) Test_ChecklinesPatch__only_unified_header_but_no_content(c *check.C) { | |
250 | t := s.Init(c) | 250 | t := s.Init(c) | |
251 | 251 | |||
252 | lines := t.NewLines("patch-unified", | 252 | lines := t.NewLines("patch-unified", | |
253 | RcsId, | 253 | RcsID, | |
254 | "", | 254 | "", | |
255 | "Documentation for the patch", | 255 | "Documentation for the patch", | |
256 | "", | 256 | "", | |
257 | "--- file.orig", | 257 | "--- file.orig", | |
258 | "+++ file") | 258 | "+++ file") | |
259 | 259 | |||
260 | ChecklinesPatch(lines) | 260 | ChecklinesPatch(lines) | |
261 | 261 | |||
262 | t.CheckOutputLines( | 262 | t.CheckOutputLines( | |
263 | "ERROR: patch-unified:EOF: No patch hunks for \"file\".") | 263 | "ERROR: patch-unified:EOF: No patch hunks for \"file\".") | |
264 | } | 264 | } | |
265 | 265 | |||
266 | func (s *Suite) Test_ChecklinesPatch__only_context_header_but_no_content(c *check.C) { | 266 | func (s *Suite) Test_ChecklinesPatch__only_context_header_but_no_content(c *check.C) { | |
267 | t := s.Init(c) | 267 | t := s.Init(c) | |
268 | 268 | |||
269 | lines := t.NewLines("patch-context", | 269 | lines := t.NewLines("patch-context", | |
270 | RcsId, | 270 | RcsID, | |
271 | "", | 271 | "", | |
272 | "Documentation for the patch", | 272 | "Documentation for the patch", | |
273 | "", | 273 | "", | |
274 | "*** file.orig", | 274 | "*** file.orig", | |
275 | "--- file") | 275 | "--- file") | |
276 | 276 | |||
277 | ChecklinesPatch(lines) | 277 | ChecklinesPatch(lines) | |
278 | 278 | |||
279 | // Context diffs are deprecated, therefore it is not worth | 279 | // Context diffs are deprecated, therefore it is not worth | |
280 | // adding extra code for checking them thoroughly. | 280 | // adding extra code for checking them thoroughly. | |
281 | t.CheckOutputLines( | 281 | t.CheckOutputLines( | |
282 | "WARN: patch-context:5: Please use unified diffs (diff -u) for patches.") | 282 | "WARN: patch-context:5: Please use unified diffs (diff -u) for patches.") | |
283 | } | 283 | } | |
284 | 284 | |||
285 | func (s *Suite) Test_ChecklinesPatch__Makefile_with_absolute_pathnames(c *check.C) { | 285 | func (s *Suite) Test_ChecklinesPatch__Makefile_with_absolute_pathnames(c *check.C) { | |
286 | t := s.Init(c) | 286 | t := s.Init(c) | |
287 | 287 | |||
288 | lines := t.NewLines("patch-unified", | 288 | lines := t.NewLines("patch-unified", | |
289 | RcsId, | 289 | RcsID, | |
290 | "", | 290 | "", | |
291 | "Documentation for the patch", | 291 | "Documentation for the patch", | |
292 | "", | 292 | "", | |
293 | "--- Makefile.orig", | 293 | "--- Makefile.orig", | |
294 | "+++ Makefile", | 294 | "+++ Makefile", | |
295 | "@@ -1,3 +1,7 @@", | 295 | "@@ -1,3 +1,7 @@", | |
296 | " \t/bin/cp context before", | 296 | " \t/bin/cp context before", | |
297 | "-\t/bin/cp deleted", | 297 | "-\t/bin/cp deleted", | |
298 | "+\t/bin/cp added", | 298 | "+\t/bin/cp added", | |
299 | "+#\t/bin/cp added comment", | 299 | "+#\t/bin/cp added comment", | |
300 | "+# added comment", | 300 | "+# added comment", | |
301 | "+\t${DESTDIR}/bin/cp added", | 301 | "+\t${DESTDIR}/bin/cp added", | |
302 | "+\t${prefix}/bin/cp added", | 302 | "+\t${prefix}/bin/cp added", | |
@@ -313,125 +313,125 @@ func (s *Suite) Test_ChecklinesPatch__Ma | @@ -313,125 +313,125 @@ func (s *Suite) Test_ChecklinesPatch__Ma | |||
313 | ChecklinesPatch(lines) | 313 | ChecklinesPatch(lines) | |
314 | 314 | |||
315 | t.CheckOutputLines( | 315 | t.CheckOutputLines( | |
316 | "WARN: patch-unified:8: Found absolute pathname: /bin/cp", | 316 | "WARN: patch-unified:8: Found absolute pathname: /bin/cp", | |
317 | "WARN: patch-unified:10: Found absolute pathname: /bin/cp", | 317 | "WARN: patch-unified:10: Found absolute pathname: /bin/cp", | |
318 | "WARN: patch-unified:13: Found absolute pathname: /bin/cp", | 318 | "WARN: patch-unified:13: Found absolute pathname: /bin/cp", | |
319 | "WARN: patch-unified:15: Found absolute pathname: /bin/cp") | 319 | "WARN: patch-unified:15: Found absolute pathname: /bin/cp") | |
320 | } | 320 | } | |
321 | 321 | |||
322 | func (s *Suite) Test_ChecklinesPatch__no_newline_with_text_following(c *check.C) { | 322 | func (s *Suite) Test_ChecklinesPatch__no_newline_with_text_following(c *check.C) { | |
323 | t := s.Init(c) | 323 | t := s.Init(c) | |
324 | 324 | |||
325 | lines := t.NewLines("patch-aa", | 325 | lines := t.NewLines("patch-aa", | |
326 | RcsId, | 326 | RcsID, | |
327 | "", | 327 | "", | |
328 | "comment", | 328 | "comment", | |
329 | "", | 329 | "", | |
330 | "--- oldfile", | 330 | "--- oldfile", | |
331 | "+++ newfile", | 331 | "+++ newfile", | |
332 | "@@ -1 +1 @@", | 332 | "@@ -1 +1 @@", | |
333 | "-old", | 333 | "-old", | |
334 | "\\ No newline at end of file", | 334 | "\\ No newline at end of file", | |
335 | "+new", | 335 | "+new", | |
336 | "\\ No newline at end of file", | 336 | "\\ No newline at end of file", | |
337 | "last line (a comment)") | 337 | "last line (a comment)") | |
338 | 338 | |||
339 | ChecklinesPatch(lines) | 339 | ChecklinesPatch(lines) | |
340 | 340 | |||
341 | t.CheckOutputLines( | 341 | t.CheckOutputLines( | |
342 | "WARN: patch-aa:12: Empty line or end of file expected.") | 342 | "WARN: patch-aa:12: Empty line or end of file expected.") | |
343 | } | 343 | } | |
344 | 344 | |||
345 | func (s *Suite) Test_ChecklinesPatch__no_newline(c *check.C) { | 345 | func (s *Suite) Test_ChecklinesPatch__no_newline(c *check.C) { | |
346 | t := s.Init(c) | 346 | t := s.Init(c) | |
347 | 347 | |||
348 | lines := t.NewLines("patch-aa", | 348 | lines := t.NewLines("patch-aa", | |
349 | RcsId, | 349 | RcsID, | |
350 | "", | 350 | "", | |
351 | "comment", | 351 | "comment", | |
352 | "", | 352 | "", | |
353 | "--- oldfile", | 353 | "--- oldfile", | |
354 | "+++ newfile", | 354 | "+++ newfile", | |
355 | "@@ -1 +1 @@", | 355 | "@@ -1 +1 @@", | |
356 | "-old", | 356 | "-old", | |
357 | "\\ No newline at end of file", | 357 | "\\ No newline at end of file", | |
358 | "+new", | 358 | "+new", | |
359 | "\\ No newline at end of file") | 359 | "\\ No newline at end of file") | |
360 | 360 | |||
361 | ChecklinesPatch(lines) | 361 | ChecklinesPatch(lines) | |
362 | 362 | |||
363 | t.CheckOutputEmpty() | 363 | t.CheckOutputEmpty() | |
364 | } | 364 | } | |
365 | 365 | |||
366 | func (s *Suite) Test_ChecklinesPatch__empty_lines_left_out_at_eof(c *check.C) { | 366 | func (s *Suite) Test_ChecklinesPatch__empty_lines_left_out_at_eof(c *check.C) { | |
367 | t := s.Init(c) | 367 | t := s.Init(c) | |
368 | 368 | |||
369 | lines := t.NewLines("patch-aa", | 369 | lines := t.NewLines("patch-aa", | |
370 | RcsId, | 370 | RcsID, | |
371 | "", | 371 | "", | |
372 | "comment", | 372 | "comment", | |
373 | "", | 373 | "", | |
374 | "--- oldfile", | 374 | "--- oldfile", | |
375 | "+++ newfile", | 375 | "+++ newfile", | |
376 | "@@ -1,7 +1,6 @@", | 376 | "@@ -1,7 +1,6 @@", | |
377 | " 1", | 377 | " 1", | |
378 | " 2", | 378 | " 2", | |
379 | " 3", | 379 | " 3", | |
380 | "-4", | 380 | "-4", | |
381 | " 5", | 381 | " 5", | |
382 | " 6") // Line 7 was empty, therefore omitted | 382 | " 6") // Line 7 was empty, therefore omitted | |
383 | 383 | |||
384 | ChecklinesPatch(lines) | 384 | ChecklinesPatch(lines) | |
385 | 385 | |||
386 | t.CheckOutputEmpty() | 386 | t.CheckOutputEmpty() | |
387 | } | 387 | } | |
388 | 388 | |||
389 | // In some context lines, the leading space character is missing. | 389 | // In some context lines, the leading space character is missing. | |
390 | // Since this is no problem for patch(1), pkglint also doesn't complain. | 390 | // Since this is no problem for patch(1), pkglint also doesn't complain. | |
391 | func (s *Suite) Test_ChecklinesPatch__context_lines_with_tab_instead_of_space(c *check.C) { | 391 | func (s *Suite) Test_ChecklinesPatch__context_lines_with_tab_instead_of_space(c *check.C) { | |
392 | t := s.Init(c) | 392 | t := s.Init(c) | |
393 | 393 | |||
394 | lines := t.NewLines("patch-aa", | 394 | lines := t.NewLines("patch-aa", | |
395 | RcsId, | 395 | RcsID, | |
396 | "", | 396 | "", | |
397 | "comment", | 397 | "comment", | |
398 | "", | 398 | "", | |
399 | "--- oldfile", | 399 | "--- oldfile", | |
400 | "+++ newfile", | 400 | "+++ newfile", | |
401 | "@@ -1,3 +1,3 @@", | 401 | "@@ -1,3 +1,3 @@", | |
402 | "\tcontext", | 402 | "\tcontext", | |
403 | "-old", | 403 | "-old", | |
404 | "+new", | 404 | "+new", | |
405 | "\tcontext") | 405 | "\tcontext") | |
406 | 406 | |||
407 | ChecklinesPatch(lines) | 407 | ChecklinesPatch(lines) | |
408 | 408 | |||
409 | t.CheckOutputEmpty() | 409 | t.CheckOutputEmpty() | |
410 | } | 410 | } | |
411 | 411 | |||
412 | // Must not panic. | 412 | // Must not panic. | |
413 | func (s *Suite) Test_ChecklinesPatch__autofix_empty_patch(c *check.C) { | 413 | func (s *Suite) Test_ChecklinesPatch__autofix_empty_patch(c *check.C) { | |
414 | t := s.Init(c) | 414 | t := s.Init(c) | |
415 | 415 | |||
416 | t.SetupCommandLine("-Wall", "--autofix") | 416 | t.SetupCommandLine("-Wall", "--autofix") | |
417 | lines := t.NewLines("patch-aa", | 417 | lines := t.NewLines("patch-aa", | |
418 | RcsId) | 418 | RcsID) | |
419 | 419 | |||
420 | ChecklinesPatch(lines) | 420 | ChecklinesPatch(lines) | |
421 | 421 | |||
422 | t.CheckOutputEmpty() | 422 | t.CheckOutputEmpty() | |
423 | } | 423 | } | |
424 | 424 | |||
425 | // Must not panic. | 425 | // Must not panic. | |
426 | func (s *Suite) Test_ChecklinesPatch__autofix_long_empty_patch(c *check.C) { | 426 | func (s *Suite) Test_ChecklinesPatch__autofix_long_empty_patch(c *check.C) { | |
427 | t := s.Init(c) | 427 | t := s.Init(c) | |
428 | 428 | |||
429 | t.SetupCommandLine("-Wall", "--autofix") | 429 | t.SetupCommandLine("-Wall", "--autofix") | |
430 | lines := t.NewLines("patch-aa", | 430 | lines := t.NewLines("patch-aa", | |
431 | RcsId, | 431 | RcsID, | |
432 | "") | 432 | "") | |
433 | 433 | |||
434 | ChecklinesPatch(lines) | 434 | ChecklinesPatch(lines) | |
435 | 435 | |||
436 | t.CheckOutputEmpty() | 436 | t.CheckOutputEmpty() | |
437 | } | 437 | } |
@@ -10,27 +10,27 @@ import ( | @@ -10,27 +10,27 @@ import ( | |||
10 | ) | 10 | ) | |
11 | 11 | |||
12 | // GlobalData contains data describing pkgsrc as a whole. | 12 | // GlobalData contains data describing pkgsrc as a whole. | |
13 | type GlobalData struct { | 13 | type GlobalData struct { | |
14 | Pkgsrcdir string // Relative to the current working directory. | 14 | Pkgsrcdir string // Relative to the current working directory. | |
15 | MasterSiteURLToVar map[string]string // "https://github.com/" => "MASTER_SITE_GITHUB" | 15 | MasterSiteURLToVar map[string]string // "https://github.com/" => "MASTER_SITE_GITHUB" | |
16 | MasterSiteVarToURL map[string]string // "MASTER_SITE_GITHUB" => "https://github.com/" | 16 | MasterSiteVarToURL map[string]string // "MASTER_SITE_GITHUB" => "https://github.com/" | |
17 | PkgOptions map[string]string // "x11" => "Provides X11 support" | 17 | PkgOptions map[string]string // "x11" => "Provides X11 support" | |
18 | Tools ToolRegistry // | 18 | Tools ToolRegistry // | |
19 | SystemBuildDefs map[string]bool // The set of user-defined variables that are added to BUILD_DEFS within the bsd.pkg.mk file. | 19 | SystemBuildDefs map[string]bool // The set of user-defined variables that are added to BUILD_DEFS within the bsd.pkg.mk file. | |
20 | suggestedUpdates []SuggestedUpdate // | 20 | suggestedUpdates []SuggestedUpdate // | |
21 | suggestedWipUpdates []SuggestedUpdate // | 21 | suggestedWipUpdates []SuggestedUpdate // | |
22 | LastChange map[string]*Change // | 22 | LastChange map[string]*Change // | |
23 | UserDefinedVars map[string]MkLine // varname => line | 23 | UserDefinedVars map[string]MkLine // varname => line; used for checking BUILD_DEFS | |
24 | Deprecated map[string]string // | 24 | Deprecated map[string]string // | |
25 | vartypes map[string]*Vartype // varcanon => type | 25 | vartypes map[string]*Vartype // varcanon => type | |
26 | latest map[string]string // "lang/php[0-9]*" => "lang/php70" | 26 | latest map[string]string // "lang/php[0-9]*" => "lang/php70" | |
27 | } | 27 | } | |
28 | 28 | |||
29 | // Change is a change entry from the `doc/CHANGES-*` files. | 29 | // Change is a change entry from the `doc/CHANGES-*` files. | |
30 | type Change struct { | 30 | type Change struct { | |
31 | Line Line | 31 | Line Line | |
32 | Action string | 32 | Action string | |
33 | Pkgpath string | 33 | Pkgpath string | |
34 | Version string | 34 | Version string | |
35 | Author string | 35 | Author string | |
36 | Date string | 36 | Date string | |
@@ -95,51 +95,51 @@ func (gd *GlobalData) Latest(category st | @@ -95,51 +95,51 @@ func (gd *GlobalData) Latest(category st | |||
95 | } | 95 | } | |
96 | if latest == "" { | 96 | if latest == "" { | |
97 | return error() | 97 | return error() | |
98 | } | 98 | } | |
99 | 99 | |||
100 | gd.latest[key] = latest | 100 | gd.latest[key] = latest | |
101 | return latest | 101 | return latest | |
102 | } | 102 | } | |
103 | 103 | |||
104 | func (gd *GlobalData) loadDistSites() { | 104 | func (gd *GlobalData) loadDistSites() { | |
105 | fname := gd.Pkgsrcdir + "/mk/fetch/sites.mk" | 105 | fname := gd.Pkgsrcdir + "/mk/fetch/sites.mk" | |
106 | lines := LoadExistingLines(fname, true) | 106 | lines := LoadExistingLines(fname, true) | |
107 | 107 | |||
108 | name2url := make(map[string]string) | 108 | nameToUrl := make(map[string]string) | |
109 | url2name := make(map[string]string) | 109 | urlToName := make(map[string]string) | |
110 | for _, line := range lines { | 110 | for _, line := range lines { | |
111 | if m, commented, varname, _, _, _, urls, _, _ := MatchVarassign(line.Text); m { | 111 | if m, commented, varname, _, _, _, urls, _, _ := MatchVarassign(line.Text); m { | |
112 | if !commented && hasPrefix(varname, "MASTER_SITE_") && varname != "MASTER_SITE_BACKUP" { | 112 | if !commented && hasPrefix(varname, "MASTER_SITE_") && varname != "MASTER_SITE_BACKUP" { | |
113 | for _, url := range splitOnSpace(urls) { | 113 | for _, url := range splitOnSpace(urls) { | |
114 | if matches(url, `^(?:http://|https://|ftp://)`) { | 114 | if matches(url, `^(?:http://|https://|ftp://)`) { | |
115 | if name2url[varname] == "" { | 115 | if nameToUrl[varname] == "" { | |
116 | name2url[varname] = url | 116 | nameToUrl[varname] = url | |
117 | } | 117 | } | |
118 | url2name[url] = varname | 118 | urlToName[url] = varname | |
119 | } | 119 | } | |
120 | } | 120 | } | |
121 | } | 121 | } | |
122 | } | 122 | } | |
123 | } | 123 | } | |
124 | 124 | |||
125 | // Explicitly allowed, although not defined in mk/fetch/sites.mk. | 125 | // Explicitly allowed, although not defined in mk/fetch/sites.mk. | |
126 | name2url["MASTER_SITE_LOCAL"] = "ftp://ftp.NetBSD.org/pub/pkgsrc/distfiles/LOCAL_PORTS/" | 126 | nameToUrl["MASTER_SITE_LOCAL"] = "ftp://ftp.NetBSD.org/pub/pkgsrc/distfiles/LOCAL_PORTS/" | |
127 | 127 | |||
128 | if trace.Tracing { | 128 | if trace.Tracing { | |
129 | trace.Stepf("Loaded %d MASTER_SITE_* URLs.", len(url2name)) | 129 | trace.Stepf("Loaded %d MASTER_SITE_* URLs.", len(urlToName)) | |
130 | } | 130 | } | |
131 | gd.MasterSiteURLToVar = url2name | 131 | gd.MasterSiteURLToVar = urlToName | |
132 | gd.MasterSiteVarToURL = name2url | 132 | gd.MasterSiteVarToURL = nameToUrl | |
133 | } | 133 | } | |
134 | 134 | |||
135 | func (gd *GlobalData) loadPkgOptions() { | 135 | func (gd *GlobalData) loadPkgOptions() { | |
136 | fname := gd.Pkgsrcdir + "/mk/defaults/options.description" | 136 | fname := gd.Pkgsrcdir + "/mk/defaults/options.description" | |
137 | lines := LoadExistingLines(fname, false) | 137 | lines := LoadExistingLines(fname, false) | |
138 | 138 | |||
139 | gd.PkgOptions = make(map[string]string) | 139 | gd.PkgOptions = make(map[string]string) | |
140 | for _, line := range lines { | 140 | for _, line := range lines { | |
141 | if m, optname, optdescr := match2(line.Text, `^([-0-9a-z_+]+)(?:\s+(.*))?$`); m { | 141 | if m, optname, optdescr := match2(line.Text, `^([-0-9a-z_+]+)(?:\s+(.*))?$`); m { | |
142 | gd.PkgOptions[optname] = optdescr | 142 | gd.PkgOptions[optname] = optdescr | |
143 | } else { | 143 | } else { | |
144 | line.Fatalf("Unknown line format.") | 144 | line.Fatalf("Unknown line format.") | |
145 | } | 145 | } | |
@@ -170,48 +170,48 @@ func (gd *GlobalData) loadTools() { | @@ -170,48 +170,48 @@ func (gd *GlobalData) loadTools() { | |||
170 | reg.RegisterTool(&Tool{"test", "TEST", true, true, true}) | 170 | reg.RegisterTool(&Tool{"test", "TEST", true, true, true}) | |
171 | reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true}) | 171 | reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true}) | |
172 | 172 | |||
173 | systemBuildDefs := make(map[string]bool) | 173 | systemBuildDefs := make(map[string]bool) | |
174 | 174 | |||
175 | for _, basename := range toolFiles { | 175 | for _, basename := range toolFiles { | |
176 | fname := G.globalData.Pkgsrcdir + "/mk/tools/" + basename | 176 | fname := G.globalData.Pkgsrcdir + "/mk/tools/" + basename | |
177 | lines := LoadExistingLines(fname, true) | 177 | lines := LoadExistingLines(fname, true) | |
178 | for _, line := range lines { | 178 | for _, line := range lines { | |
179 | reg.ParseToolLine(line) | 179 | reg.ParseToolLine(line) | |
180 | } | 180 | } | |
181 | } | 181 | } | |
182 | 182 | |||
183 | for _, basename := range [...]string{"bsd.prefs.mk", "bsd.pkg.mk"} { | 183 | for _, relativeName := range [...]string{"mk/bsd.prefs.mk", "mk/bsd.pkg.mk"} { | |
184 | fname := G.globalData.Pkgsrcdir + "/mk/" + basename | 184 | fname := G.globalData.Pkgsrcdir + "/" + relativeName | |
185 | condDepth := 0 | 185 | condDepth := 0 | |
186 | 186 | |||
187 | lines := LoadExistingLines(fname, true) | 187 | lines := LoadExistingLines(fname, true) | |
188 | for _, line := range lines { | 188 | for _, line := range lines { | |
189 | text := line.Text | 189 | text := line.Text | |
190 | if hasPrefix(text, "#") { | 190 | if hasPrefix(text, "#") { | |
191 | continue | 191 | continue | |
192 | } | 192 | } | |
193 | 193 | |||
194 | if m, _, varname, _, _, _, value, _, _ := MatchVarassign(text); m { | 194 | if m, _, varname, _, _, _, value, _, _ := MatchVarassign(text); m { | |
195 | if varname == "USE_TOOLS" { | 195 | if varname == "USE_TOOLS" { | |
196 | if trace.Tracing { | 196 | if trace.Tracing { | |
197 | trace.Stepf("[condDepth=%d] %s", condDepth, value) | 197 | trace.Stepf("[condDepth=%d] %s", condDepth, value) | |
198 | } | 198 | } | |
199 | if condDepth == 0 || condDepth == 1 && basename == "bsd.prefs.mk" { | 199 | if condDepth == 0 || condDepth == 1 && relativeName == "mk/bsd.prefs.mk" { | |
200 | for _, toolname := range splitOnSpace(value) { | 200 | for _, toolname := range splitOnSpace(value) { | |
201 | if !containsVarRef(toolname) { | 201 | if !containsVarRef(toolname) { | |
202 | for _, tool := range [...]*Tool{reg.Register(toolname), reg.Register("TOOLS_" + toolname)} { | 202 | for _, tool := range [...]*Tool{reg.Register(toolname), reg.Register("TOOLS_" + toolname)} { | |
203 | tool.Predefined = true | 203 | tool.Predefined = true | |
204 | if basename == "bsd.prefs.mk" { | 204 | if relativeName == "mk/bsd.prefs.mk" { | |
205 | tool.UsableAtLoadtime = true | 205 | tool.UsableAtLoadtime = true | |
206 | } | 206 | } | |
207 | } | 207 | } | |
208 | } | 208 | } | |
209 | } | 209 | } | |
210 | } | 210 | } | |
211 | 211 | |||
212 | } else if varname == "_BUILD_DEFS" { | 212 | } else if varname == "_BUILD_DEFS" { | |
213 | for _, bdvar := range splitOnSpace(value) { | 213 | for _, bdvar := range splitOnSpace(value) { | |
214 | systemBuildDefs[bdvar] = true | 214 | systemBuildDefs[bdvar] = true | |
215 | } | 215 | } | |
216 | } | 216 | } | |
217 | 217 |
@@ -427,27 +427,27 @@ func (pkg *Package) checkfilePackageMake | @@ -427,27 +427,27 @@ func (pkg *Package) checkfilePackageMake | |||
427 | 427 | |||
428 | if vardef["COMMENT"] == nil { | 428 | if vardef["COMMENT"] == nil { | |
429 | NewLineWhole(fname).Warnf("No COMMENT given.") | 429 | NewLineWhole(fname).Warnf("No COMMENT given.") | |
430 | } | 430 | } | |
431 | 431 | |||
432 | if imake, x11 := vardef["USE_IMAKE"], vardef["USE_X11"]; imake != nil && x11 != nil { | 432 | if imake, x11 := vardef["USE_IMAKE"], vardef["USE_X11"]; imake != nil && x11 != nil { | |
433 | if !hasSuffix(x11.Filename, "/mk/x11.buildlink3.mk") { | 433 | if !hasSuffix(x11.Filename, "/mk/x11.buildlink3.mk") { | |
434 | imake.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.ReferenceFrom(imake.Line)) | 434 | imake.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.ReferenceFrom(imake.Line)) | |
435 | } | 435 | } | |
436 | } | 436 | } | |
437 | 437 | |||
438 | pkg.checkUpdate() | 438 | pkg.checkUpdate() | |
439 | mklines.Check() | 439 | mklines.Check() | |
440 | pkg.ChecklinesPackageMakefileVarorder(mklines) | 440 | pkg.CheckVarorder(mklines) | |
441 | SaveAutofixChanges(mklines.lines) | 441 | SaveAutofixChanges(mklines.lines) | |
442 | } | 442 | } | |
443 | 443 | |||
444 | func (pkg *Package) getNbpart() string { | 444 | func (pkg *Package) getNbpart() string { | |
445 | line := pkg.vardef["PKGREVISION"] | 445 | line := pkg.vardef["PKGREVISION"] | |
446 | if line == nil { | 446 | if line == nil { | |
447 | return "" | 447 | return "" | |
448 | } | 448 | } | |
449 | pkgrevision := line.Value() | 449 | pkgrevision := line.Value() | |
450 | if rev, err := strconv.Atoi(pkgrevision); err == nil { | 450 | if rev, err := strconv.Atoi(pkgrevision); err == nil { | |
451 | return "nb" + strconv.Itoa(rev) | 451 | return "nb" + strconv.Itoa(rev) | |
452 | } | 452 | } | |
453 | return "" | 453 | return "" | |
@@ -578,224 +578,230 @@ func (pkg *Package) checkUpdate() { | @@ -578,224 +578,230 @@ func (pkg *Package) checkUpdate() { | |||
578 | pkgnameLine.Warnf("This package should be updated to %s%s.", sugg.Version, comment) | 578 | pkgnameLine.Warnf("This package should be updated to %s%s.", sugg.Version, comment) | |
579 | Explain( | 579 | Explain( | |
580 | "The wishlist for package updates in doc/TODO mentions that a newer", | 580 | "The wishlist for package updates in doc/TODO mentions that a newer", | |
581 | "version of this package is available.") | 581 | "version of this package is available.") | |
582 | case cmp > 0: | 582 | case cmp > 0: | |
583 | pkgnameLine.Notef("This package is newer than the update request to %s%s.", suggver, comment) | 583 | pkgnameLine.Notef("This package is newer than the update request to %s%s.", suggver, comment) | |
584 | default: | 584 | default: | |
585 | pkgnameLine.Notef("The update request to %s from doc/TODO%s has been done.", suggver, comment) | 585 | pkgnameLine.Notef("The update request to %s from doc/TODO%s has been done.", suggver, comment) | |
586 | } | 586 | } | |
587 | } | 587 | } | |
588 | } | 588 | } | |
589 | } | 589 | } | |
590 | 590 | |||
591 | func (pkg *Package) ChecklinesPackageMakefileVarorder(mklines *MkLines) { | 591 | // CheckVarorder checks that in simple package Makefiles, | |
592 | // the most common variables appear in a fixed order. | |||
593 | // The order itself is a little arbitrary but provides | |||
594 | // at least a bit of consistency. | |||
595 | func (pkg *Package) CheckVarorder(mklines *MkLines) { | |||
592 | if trace.Tracing { | 596 | if trace.Tracing { | |
593 | defer trace.Call0()() | 597 | defer trace.Call0()() | |
594 | } | 598 | } | |
595 | 599 | |||
596 | if !G.opts.WarnOrder || pkg.seenMakefileCommon { | 600 | if !G.opts.WarnOrder || pkg.seenMakefileCommon { | |
597 | return | 601 | return | |
598 | } | 602 | } | |
599 | 603 | |||
600 | type OccCount uint8 | 604 | type Repetition uint8 | |
601 | const ( | 605 | const ( | |
602 | once OccCount = iota | 606 | optional Repetition = iota | |
603 | optional | 607 | once | |
604 | many | 608 | many | |
605 | ) | 609 | ) | |
606 | type OccDef struct { | 610 | type Variable struct { | |
607 | varname string | 611 | varname string | |
608 | count OccCount | 612 | repetition Repetition | |
609 | } | 613 | } | |
610 | type OccGroup struct { | 614 | type Section struct { | |
611 | name string | 615 | repetition Repetition | |
612 | count OccCount | 616 | vars []Variable | |
613 | occ []OccDef | 617 | } | |
614 | } | 618 | variable := func(name string, repetition Repetition) Variable { return Variable{name, repetition} } | |
615 | 619 | section := func(repetition Repetition, vars ...Variable) Section { return Section{repetition, vars} } | ||
616 | var sections = []OccGroup{ | 620 | ||
617 | {"Initial comments", once, | 621 | var sections = []Section{ | |
618 | []OccDef{}, | 622 | section(once, | |
619 | }, | 623 | variable("GITHUB_PROJECT", optional), // either here or below MASTER_SITES | |
620 | {"Unsorted stuff, part 1", once, | 624 | variable("GITHUB_TAG", optional), | |
621 | []OccDef{ | 625 | variable("DISTNAME", optional), | |
622 | {"DISTNAME", optional}, | 626 | variable("PKGNAME", optional), | |
623 | {"PKGNAME", optional}, | 627 | variable("PKGREVISION", optional), | |
624 | {"PKGREVISION", optional}, | 628 | variable("CATEGORIES", once), | |
625 | {"CATEGORIES", once}, | 629 | variable("MASTER_SITES", many), | |
626 | {"MASTER_SITES", many}, | 630 | variable("GITHUB_PROJECT", optional), // either here or at the very top | |
627 | {"DIST_SUBDIR", optional}, | 631 | variable("GITHUB_TAG", optional), | |
628 | {"EXTRACT_SUFX", optional}, | 632 | variable("DIST_SUBDIR", optional), | |
629 | {"DISTFILES", many}, | 633 | variable("EXTRACT_SUFX", optional), | |
630 | {"SITES.*", many}, | 634 | variable("DISTFILES", many), | |
631 | }, | 635 | variable("SITES.*", many)), | |
632 | }, | 636 | section(optional, | |
633 | {"Distribution patches", optional, | 637 | variable("PATCH_SITES", optional), // or once? | |
634 | []OccDef{ | 638 | variable("PATCH_SITE_SUBDIR", optional), | |
635 | {"PATCH_SITES", optional}, // or once? | 639 | variable("PATCHFILES", optional), // or once? | |
636 | {"PATCH_SITE_SUBDIR", optional}, | 640 | variable("PATCH_DIST_ARGS", optional), | |
637 | {"PATCHFILES", optional}, // or once? | 641 | variable("PATCH_DIST_STRIP", optional), | |
638 | {"PATCH_DIST_ARGS", optional}, | 642 | variable("PATCH_DIST_CAT", optional)), | |
639 | {"PATCH_DIST_STRIP", optional}, | 643 | section(once, | |
640 | {"PATCH_DIST_CAT", optional}, | 644 | variable("MAINTAINER", optional), | |
641 | }, | 645 | variable("OWNER", optional), | |
642 | }, | 646 | variable("HOMEPAGE", optional), | |
643 | {"Unsorted stuff, part 2", once, | 647 | variable("COMMENT", once), | |
644 | []OccDef{ | 648 | variable("LICENSE", once)), | |
645 | {"MAINTAINER", optional}, | 649 | section(optional, | |
646 | {"OWNER", optional}, | 650 | variable("LICENSE_FILE", optional), | |
647 | {"HOMEPAGE", optional}, | 651 | variable("RESTRICTED", optional), | |
648 | {"COMMENT", once}, | 652 | variable("NO_BIN_ON_CDROM", optional), | |
649 | {"LICENSE", once}, | 653 | variable("NO_BIN_ON_FTP", optional), | |
650 | }, | 654 | variable("NO_SRC_ON_CDROM", optional), | |
651 | }, | 655 | variable("NO_SRC_ON_FTP", optional)), | |
652 | {"Legal issues", optional, | 656 | section(optional, | |
653 | []OccDef{ | 657 | variable("BROKEN_EXCEPT_ON_PLATFORM", many), | |
654 | {"LICENSE_FILE", optional}, | 658 | variable("BROKEN_ON_PLATFORM", many), | |
655 | {"RESTRICTED", optional}, | 659 | variable("NOT_FOR_PLATFORM", many), | |
656 | {"NO_BIN_ON_CDROM", optional}, | 660 | variable("ONLY_FOR_PLATFORM", many), | |
657 | {"NO_BIN_ON_FTP", optional}, | 661 | variable("NOT_FOR_COMPILER", many), | |
658 | {"NO_SRC_ON_CDROM", optional}, | 662 | variable("ONLY_FOR_COMPILER", many), | |
659 | {"NO_SRC_ON_FTP", optional}, | 663 | variable("NOT_FOR_UNPRIVILEGED", optional), | |
660 | }, | 664 | variable("ONLY_FOR_UNPRIVILEGED", optional)), | |
661 | }, | 665 | section(optional, | |
662 | {"Technical restrictions", optional, | 666 | variable("BUILD_DEPENDS", many), | |
663 | []OccDef{ | 667 | variable("TOOL_DEPENDS", many), | |
664 | {"BROKEN_EXCEPT_ON_PLATFORM", many}, | 668 | variable("DEPENDS", many)), | |
665 | {"BROKEN_ON_PLATFORM", many}, | 669 | } | |
666 | {"NOT_FOR_PLATFORM", many}, | 670 | ||
667 | {"ONLY_FOR_PLATFORM", many}, | 671 | firstRelevant := -1 | |
668 | {"NOT_FOR_COMPILER", many}, | 672 | lastRelevant := -1 | |
669 | {"ONLY_FOR_COMPILER", many}, | 673 | skip := func() bool { | |
670 | {"NOT_FOR_UNPRIVILEGED", optional}, | 674 | relevantVars := make(map[string]bool) | |
671 | {"ONLY_FOR_UNPRIVILEGED", optional}, | 675 | for _, section := range sections { | |
672 | }, | 676 | for _, variable := range section.vars { | |
673 | }, | 677 | relevantVars[variable.varname] = true | |
674 | {"Dependencies", optional, | 678 | } | |
675 | []OccDef{ | |||
676 | {"BUILD_DEPENDS", many}, | |||
677 | {"TOOL_DEPENDS", many}, | |||
678 | {"DEPENDS", many}, | |||
679 | }, | |||
680 | }, | |||
681 | } | |||
682 | ||||
683 | lineno := 0 | |||
684 | sectindex := -1 | |||
685 | varindex := 0 | |||
686 | nextSection := true | |||
687 | var vars []OccDef | |||
688 | below := make(map[string]string) | |||
689 | var belowWhat string | |||
690 | ||||
691 | // If the current section is optional but contains non-optional | |||
692 | // fields, the complete section may be skipped as long as there | |||
693 | // has not been a non-optional variable. | |||
694 | maySkipSection := false | |||
695 | ||||
696 | // In each iteration, one of the following becomes true: | |||
697 | // - new lineno > old lineno | |||
698 | // - new sectindex > old sectindex | |||
699 | // - new sectindex == old sectindex && new varindex > old varindex | |||
700 | // - new nextSection == true && old nextSection == false | |||
701 | for lineno < len(mklines.lines) { | |||
702 | mkline := mklines.mklines[lineno] | |||
703 | line := mklines.lines[lineno] | |||
704 | text := line.Text | |||
705 | ||||
706 | if trace.Tracing { | |||
707 | trace.Stepf("[varorder] section %d variable %d vars %v", sectindex, varindex, vars) | |||
708 | } | 679 | } | |
709 | 680 | |||
710 | if nextSection { | 681 | firstIrrelevant := -1 | |
711 | nextSection = false | 682 | for i, mkline := range mklines.mklines { | |
712 | sectindex++ | 683 | switch { | |
713 | if !(sectindex < len(sections)) { | 684 | case mkline.IsVarassign(), mkline.IsCommentedVarassign(): | |
685 | varcanon := mkline.Varcanon() | |||
686 | if relevantVars[varcanon] { | |||
687 | if firstRelevant == -1 { | |||
688 | firstRelevant = i | |||
689 | } | |||
690 | if firstIrrelevant != -1 { | |||
691 | if trace.Tracing { | |||
692 | trace.Stepf("Skipping varorder because of line %s.", | |||
693 | mklines.mklines[firstIrrelevant].Linenos()) | |||
694 | } | |||
695 | return true | |||
696 | } | |||
697 | lastRelevant = i | |||
698 | } else { | |||
699 | if firstIrrelevant == -1 { | |||
700 | firstIrrelevant = i | |||
701 | } | |||
702 | } | |||
703 | ||||
704 | case mkline.IsComment(), mkline.IsEmpty(): | |||
714 | break | 705 | break | |
706 | ||||
707 | default: | |||
708 | if firstIrrelevant == -1 { | |||
709 | firstIrrelevant = i | |||
710 | } | |||
715 | } | 711 | } | |
716 | vars = sections[sectindex].occ | |||
717 | maySkipSection = sections[sectindex].count == optional | |||
718 | varindex = 0 | |||
719 | } | 712 | } | |
720 | 713 | |||
721 | switch { | 714 | interesting := mklines.mklines[firstRelevant : lastRelevant+1] | |
722 | case hasPrefix(text, "#"): | |||
723 | lineno++ | |||
724 | 715 | |||
725 | case mkline.IsVarassign(): | 716 | varcanon := func() string { | |
726 | varcanon := mkline.Varcanon() | 717 | for len(interesting) != 0 && interesting[0].IsComment() { | |
718 | interesting = interesting[1:] | |||
719 | } | |||
720 | if len(interesting) != 0 && (interesting[0].IsVarassign() || interesting[0].IsCommentedVarassign()) { | |||
721 | return interesting[0].Varcanon() | |||
722 | } | |||
723 | return "" | |||
724 | } | |||
727 | 725 | |||
728 | if belowText, exists := below[varcanon]; exists { | 726 | for _, section := range sections { | |
729 | if belowText != "" { | 727 | for _, variable := range section.vars { | |
730 | line.Warnf("%s appears too late. Please put it below %s.", varcanon, belowText) | 728 | switch variable.repetition { | |
731 | } else { | 729 | case optional: | |
732 | line.Warnf("%s appears too late. It should be the very first definition.", varcanon) | 730 | if varcanon() == variable.varname { | |
731 | interesting = interesting[1:] | |||
732 | } | |||
733 | case once: | |||
734 | if varcanon() == variable.varname { | |||
735 | interesting = interesting[1:] | |||
736 | } else if section.repetition == once { | |||
737 | if variable.varname != "LICENSE" { | |||
738 | if trace.Tracing { | |||
739 | trace.Stepf("Wrong varorder because %s is missing.", variable.varname) | |||
740 | } | |||
741 | return false | |||
742 | } | |||
743 | } | |||
744 | case many: | |||
745 | for varcanon() == variable.varname { | |||
746 | interesting = interesting[1:] | |||
747 | } | |||
733 | } | 748 | } | |
734 | lineno++ | |||
735 | continue | |||
736 | } | 749 | } | |
737 | 750 | |||
738 | for varindex < len(vars) && varcanon != vars[varindex].varname && (vars[varindex].count != once || maySkipSection) { | 751 | for len(interesting) != 0 && (interesting[0].IsEmpty() || interesting[0].IsComment()) { | |
739 | if vars[varindex].count == once { | 752 | interesting = interesting[1:] | |
740 | maySkipSection = false | |||
741 | } | |||
742 | below[vars[varindex].varname] = belowWhat | |||
743 | varindex++ | |||
744 | } | 753 | } | |
745 | switch { | 754 | } | |
746 | case !(varindex < len(vars)): | |||
747 | if sections[sectindex].count != optional { | |||
748 | line.Warnf("Empty line expected.") | |||
749 | } | |||
750 | nextSection = true | |||
751 | 755 | |||
752 | case varcanon != vars[varindex].varname: | 756 | return len(interesting) == 0 | |
753 | line.Warnf("Expected %s, but found %s.", vars[varindex].varname, varcanon) | 757 | } | |
754 | lineno++ | |||
755 | 758 | |||
756 | default: | 759 | if skip() { | |
757 | if vars[varindex].count != many { | 760 | return | |
758 | below[vars[varindex].varname] = belowWhat | 761 | } | |
759 | varindex++ | |||
760 | } | |||
761 | lineno++ | |||
762 | } | |||
763 | belowWhat = varcanon | |||
764 | 762 | |||
765 | default: | 763 | var canonical []string | |
766 | for varindex < len(vars) { | 764 | for _, section := range sections { | |
767 | varname := vars[varindex].varname | 765 | for _, variable := range section.vars { | |
768 | if vars[varindex].count == once && !maySkipSection { | 766 | found := false | |
769 | if varname != "LICENSE" || pkg.once.FirstTime("LICENSE") { | 767 | for _, mkline := range mklines.mklines[firstRelevant : lastRelevant+1] { | |
770 | line.Warnf("The canonical position for the required variable %s is here.", varname) | 768 | if mkline.IsVarassign() || mkline.IsCommentedVarassign() { | |
771 | Explain( | 769 | if mkline.Varcanon() == variable.varname { | |
772 | "In simple package Makefiles, some common variables should be", | 770 | canonical = append(canonical, mkline.Varname()) | |
773 | "arranged in a specific order.", | 771 | found = true | |
774 | "", | |||
775 | "See doc/Makefile-example or the pkgsrc guide, section", | |||
776 | "\"Package components\", subsection \"Makefile\" for more information.") | |||
777 | } | 772 | } | |
778 | } | 773 | } | |
779 | below[varname] = belowWhat | |||
780 | varindex++ | |||
781 | } | 774 | } | |
782 | nextSection = true | 775 | if !found && section.repetition == once && variable.repetition == once { | |
783 | if text == "" { | 776 | canonical = append(canonical, variable.varname) | |
784 | belowWhat = "the previous empty line" | |||
785 | lineno++ | |||
786 | } | 777 | } | |
787 | } | 778 | } | |
779 | if len(canonical) != 0 && canonical[len(canonical)-1] != "empty line" { | |||
780 | canonical = append(canonical, "empty line") | |||
781 | } | |||
782 | } | |||
783 | if len(canonical) != 0 && canonical[len(canonical)-1] == "empty line" { | |||
784 | canonical = canonical[:len(canonical)-1] | |||
788 | } | 785 | } | |
786 | ||||
787 | mkline := mklines.mklines[firstRelevant] | |||
788 | mkline.Warnf("The canonical order of the variables is %s.", strings.Join(canonical, ", ")) | |||
789 | Explain( | |||
790 | "In simple package Makefiles, some common variables should be", | |||
791 | "arranged in a specific order.", | |||
792 | "", | |||
793 | "See doc/Makefile-example or the pkgsrc guide, section", | |||
794 | "\"Package components\", subsection \"Makefile\" for more information.") | |||
789 | } | 795 | } | |
790 | 796 | |||
791 | func (mklines *MkLines) checkForUsedComment(relativeName string) { | 797 | func (mklines *MkLines) checkForUsedComment(relativeName string) { | |
792 | lines := mklines.lines | 798 | lines := mklines.lines | |
793 | if len(lines) < 3 { | 799 | if len(lines) < 3 { | |
794 | return | 800 | return | |
795 | } | 801 | } | |
796 | 802 | |||
797 | expected := "# used by " + relativeName | 803 | expected := "# used by " + relativeName | |
798 | for _, line := range lines { | 804 | for _, line := range lines { | |
799 | if line.Text == expected { | 805 | if line.Text == expected { | |
800 | return | 806 | return | |
801 | } | 807 | } |
@@ -114,27 +114,27 @@ func (s *Suite) Test_GlobalData_deprecat | @@ -114,27 +114,27 @@ func (s *Suite) Test_GlobalData_deprecat | |||
114 | t.CheckOutputLines( | 114 | t.CheckOutputLines( | |
115 | "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.") | 115 | "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.") | |
116 | } | 116 | } | |
117 | 117 | |||
118 | // Ensures that pkglint can handle MASTER_SITES definitions with and | 118 | // Ensures that pkglint can handle MASTER_SITES definitions with and | |
119 | // without line continuations. | 119 | // without line continuations. | |
120 | // | 120 | // | |
121 | // See https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html. | 121 | // See https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html. | |
122 | func (s *Suite) Test_GlobalData_loadDistSites(c *check.C) { | 122 | func (s *Suite) Test_GlobalData_loadDistSites(c *check.C) { | |
123 | t := s.Init(c) | 123 | t := s.Init(c) | |
124 | 124 | |||
125 | G.globalData.Pkgsrcdir = t.TmpDir() | 125 | G.globalData.Pkgsrcdir = t.TmpDir() | |
126 | t.CreateFileLines("mk/fetch/sites.mk", | 126 | t.CreateFileLines("mk/fetch/sites.mk", | |
127 | MkRcsId, | 127 | MkRcsID, | |
128 | "", | 128 | "", | |
129 | "MASTER_SITE_A+= https://example.org/distfiles/", | 129 | "MASTER_SITE_A+= https://example.org/distfiles/", | |
130 | "MASTER_SITE_B+= https://b.example.org/distfiles/ \\", | 130 | "MASTER_SITE_B+= https://b.example.org/distfiles/ \\", | |
131 | " https://b2.example.org/distfiles/", | 131 | " https://b2.example.org/distfiles/", | |
132 | "MASTER_SITE_A+= https://a.example.org/distfiles/") | 132 | "MASTER_SITE_A+= https://a.example.org/distfiles/") | |
133 | 133 | |||
134 | G.globalData.loadDistSites() | 134 | G.globalData.loadDistSites() | |
135 | 135 | |||
136 | c.Check(G.globalData.MasterSiteURLToVar["https://example.org/distfiles/"], equals, "MASTER_SITE_A") | 136 | c.Check(G.globalData.MasterSiteURLToVar["https://example.org/distfiles/"], equals, "MASTER_SITE_A") | |
137 | c.Check(G.globalData.MasterSiteURLToVar["https://b.example.org/distfiles/"], equals, "MASTER_SITE_B") | 137 | c.Check(G.globalData.MasterSiteURLToVar["https://b.example.org/distfiles/"], equals, "MASTER_SITE_B") | |
138 | c.Check(G.globalData.MasterSiteURLToVar["https://b2.example.org/distfiles/"], equals, "MASTER_SITE_B") | 138 | c.Check(G.globalData.MasterSiteURLToVar["https://b2.example.org/distfiles/"], equals, "MASTER_SITE_B") | |
139 | c.Check(G.globalData.MasterSiteURLToVar["https://a.example.org/distfiles/"], equals, "MASTER_SITE_A") | 139 | c.Check(G.globalData.MasterSiteURLToVar["https://a.example.org/distfiles/"], equals, "MASTER_SITE_A") | |
140 | c.Check(G.globalData.MasterSiteVarToURL["MASTER_SITE_A"], equals, "https://example.org/distfiles/") | 140 | c.Check(G.globalData.MasterSiteVarToURL["MASTER_SITE_A"], equals, "https://example.org/distfiles/") |
@@ -193,34 +193,53 @@ func (mkline *MkLineImpl) IsCond() bool | @@ -193,34 +193,53 @@ func (mkline *MkLineImpl) IsCond() bool | |||
193 | func (mkline *MkLineImpl) IsInclude() bool { | 193 | func (mkline *MkLineImpl) IsInclude() bool { | |
194 | incl, ok := mkline.data.(mkLineInclude) | 194 | incl, ok := mkline.data.(mkLineInclude) | |
195 | return ok && !incl.sys | 195 | return ok && !incl.sys | |
196 | } | 196 | } | |
197 | func (mkline *MkLineImpl) IsSysinclude() bool { | 197 | func (mkline *MkLineImpl) IsSysinclude() bool { | |
198 | incl, ok := mkline.data.(mkLineInclude) | 198 | incl, ok := mkline.data.(mkLineInclude) | |
199 | return ok && incl.sys | 199 | return ok && incl.sys | |
200 | } | 200 | } | |
201 | func (mkline *MkLineImpl) IsDependency() bool { | 201 | func (mkline *MkLineImpl) IsDependency() bool { | |
202 | _, ok := mkline.data.(mkLineDependency) | 202 | _, ok := mkline.data.(mkLineDependency) | |
203 | return ok | 203 | return ok | |
204 | } | 204 | } | |
205 | 205 | |||
206 | func (mkline *MkLineImpl) Varname() string { return mkline.data.(mkLineAssign).varname } | 206 | // Varname applies to variable assignments and returns the variable name, exactly as given in the Makefile. | |
207 | func (mkline *MkLineImpl) Varname() string { return mkline.data.(mkLineAssign).varname } | |||
208 | ||||
209 | // Varcanon applies to variable assignments and returns the canonicalized variable name for parameterized variables. | |||
210 | // Examples: | |||
211 | // HOMEPAGE => HOMEPAGE | |||
212 | // SUBST_SED.anything => SUBST_SED.* | |||
207 | func (mkline *MkLineImpl) Varcanon() string { return mkline.data.(mkLineAssign).varcanon } | 213 | func (mkline *MkLineImpl) Varcanon() string { return mkline.data.(mkLineAssign).varcanon } | |
214 | ||||
215 | // Varparam applies to variable assignments and returns the parameter for parameterized variables. | |||
216 | // Examples: | |||
217 | // HOMEPAGE => "" | |||
218 | // SUBST_SED.anything => anything | |||
208 | func (mkline *MkLineImpl) Varparam() string { return mkline.data.(mkLineAssign).varparam } | 219 | func (mkline *MkLineImpl) Varparam() string { return mkline.data.(mkLineAssign).varparam } | |
209 | func (mkline *MkLineImpl) Op() MkOperator { return mkline.data.(mkLineAssign).op } | 220 | ||
221 | // Op applies to variable assignments and returns the assignment operator. | |||
222 | func (mkline *MkLineImpl) Op() MkOperator { return mkline.data.(mkLineAssign).op } | |||
210 | 223 | |||
211 | // For a variable assignment, the text up to and including the assignment operator, e.g. VARNAME+=\t | 224 | // For a variable assignment, the text up to and including the assignment operator, e.g. VARNAME+=\t | |
212 | func (mkline *MkLineImpl) ValueAlign() string { return mkline.data.(mkLineAssign).valueAlign } | 225 | func (mkline *MkLineImpl) ValueAlign() string { return mkline.data.(mkLineAssign).valueAlign } | |
213 | func (mkline *MkLineImpl) Value() string { return mkline.data.(mkLineAssign).value } | 226 | func (mkline *MkLineImpl) Value() string { return mkline.data.(mkLineAssign).value } | |
227 | ||||
228 | // VarassignComment applies to variable assignments and returns the comment. | |||
229 | // Example: | |||
230 | // VAR=value # comment | |||
231 | // In the above line, the comment is "# comment". | |||
232 | // The leading "#" is included so that pkglint can distinguish between no comment at all and an empty comment. | |||
214 | func (mkline *MkLineImpl) VarassignComment() string { return mkline.data.(mkLineAssign).comment } | 233 | func (mkline *MkLineImpl) VarassignComment() string { return mkline.data.(mkLineAssign).comment } | |
215 | func (mkline *MkLineImpl) Shellcmd() string { return mkline.data.(mkLineShell).command } | 234 | func (mkline *MkLineImpl) Shellcmd() string { return mkline.data.(mkLineShell).command } | |
216 | func (mkline *MkLineImpl) Indent() string { | 235 | func (mkline *MkLineImpl) Indent() string { | |
217 | if mkline.IsCond() { | 236 | if mkline.IsCond() { | |
218 | return mkline.data.(mkLineConditional).indent | 237 | return mkline.data.(mkLineConditional).indent | |
219 | } else { | 238 | } else { | |
220 | return mkline.data.(mkLineInclude).indent | 239 | return mkline.data.(mkLineInclude).indent | |
221 | } | 240 | } | |
222 | } | 241 | } | |
223 | func (mkline *MkLineImpl) Directive() string { return mkline.data.(mkLineConditional).directive } | 242 | func (mkline *MkLineImpl) Directive() string { return mkline.data.(mkLineConditional).directive } | |
224 | func (mkline *MkLineImpl) Args() string { return mkline.data.(mkLineConditional).args } | 243 | func (mkline *MkLineImpl) Args() string { return mkline.data.(mkLineConditional).args } | |
225 | func (mkline *MkLineImpl) MustExist() bool { return mkline.data.(mkLineInclude).mustexist } | 244 | func (mkline *MkLineImpl) MustExist() bool { return mkline.data.(mkLineInclude).mustexist } | |
226 | func (mkline *MkLineImpl) Includefile() string { return mkline.data.(mkLineInclude).includeFile } | 245 | func (mkline *MkLineImpl) Includefile() string { return mkline.data.(mkLineInclude).includeFile } | |
@@ -402,40 +421,40 @@ func (mkline *MkLineImpl) VariableNeedsQ | @@ -402,40 +421,40 @@ func (mkline *MkLineImpl) VariableNeedsQ | |||
402 | } | 421 | } | |
403 | if vartype.kindOfList == lkShell && !vuc.IsWordPart { | 422 | if vartype.kindOfList == lkShell && !vuc.IsWordPart { | |
404 | return nqNo | 423 | return nqNo | |
405 | } | 424 | } | |
406 | } | 425 | } | |
407 | 426 | |||
408 | // In .for loops, the :Q operator is always misplaced, since | 427 | // In .for loops, the :Q operator is always misplaced, since | |
409 | // the items are broken up at white-space, not as shell words | 428 | // the items are broken up at white-space, not as shell words | |
410 | // like in all other parts of make(1). | 429 | // like in all other parts of make(1). | |
411 | if vuc.quoting == vucQuotFor { | 430 | if vuc.quoting == vucQuotFor { | |
412 | return nqNo | 431 | return nqNo | |
413 | } | 432 | } | |
414 | 433 | |||
415 | // Determine whether the context expects a list of shell words or not. | |||
416 | wantList := vuc.vartype.IsConsideredList() | |||
417 | haveList := vartype.IsConsideredList() | |||
418 | if trace.Tracing { | |||
419 | trace.Stepf("wantList=%v, haveList=%v", wantList, haveList) | |||
420 | } | |||
421 | ||||
422 | // A shell word may appear as part of a shell word, for example COMPILER_RPATH_FLAG. | 434 | // A shell word may appear as part of a shell word, for example COMPILER_RPATH_FLAG. | |
423 | if vuc.IsWordPart && vuc.quoting == vucQuotPlain { | 435 | if vuc.IsWordPart && vuc.quoting == vucQuotPlain { | |
424 | if vartype.kindOfList == lkNone && vartype.basicType == BtShellWord { | 436 | if vartype.kindOfList == lkNone && vartype.basicType == BtShellWord { | |
425 | return nqNo | 437 | return nqNo | |
426 | } | 438 | } | |
427 | } | 439 | } | |
428 | 440 | |||
441 | // Determine whether the context expects a list of shell words or not. | |||
442 | wantList := vuc.vartype.IsConsideredList() | |||
443 | haveList := vartype.IsConsideredList() | |||
444 | if trace.Tracing { | |||
445 | trace.Stepf("wantList=%v, haveList=%v", wantList, haveList) | |||
446 | } | |||
447 | ||||
429 | // Both of these can be correct, depending on the situation: | 448 | // Both of these can be correct, depending on the situation: | |
430 | // 1. echo ${PERL5:Q} | 449 | // 1. echo ${PERL5:Q} | |
431 | // 2. xargs ${PERL5} | 450 | // 2. xargs ${PERL5} | |
432 | if !vuc.IsWordPart && vuc.quoting == vucQuotPlain { | 451 | if !vuc.IsWordPart && vuc.quoting == vucQuotPlain { | |
433 | if wantList && haveList { | 452 | if wantList && haveList { | |
434 | return nqDontKnow | 453 | return nqDontKnow | |
435 | } | 454 | } | |
436 | } | 455 | } | |
437 | 456 | |||
438 | // Assuming the tool definitions don't include very special characters, | 457 | // Assuming the tool definitions don't include very special characters, | |
439 | // so they can safely be used inside any quotes. | 458 | // so they can safely be used inside any quotes. | |
440 | if G.globalData.Tools.byVarname[varname] != nil { | 459 | if G.globalData.Tools.byVarname[varname] != nil { | |
441 | switch vuc.quoting { | 460 | switch vuc.quoting { | |
@@ -508,35 +527,35 @@ func (mkline *MkLineImpl) VariableType(v | @@ -508,35 +527,35 @@ func (mkline *MkLineImpl) VariableType(v | |||
508 | return vartype | 527 | return vartype | |
509 | } | 528 | } | |
510 | 529 | |||
511 | if tool := G.globalData.Tools.byVarname[varname]; tool != nil { | 530 | if tool := G.globalData.Tools.byVarname[varname]; tool != nil { | |
512 | perms := aclpUse | 531 | perms := aclpUse | |
513 | if trace.Tracing { | 532 | if trace.Tracing { | |
514 | trace.Stepf("Use of tool %+v", tool) | 533 | trace.Stepf("Use of tool %+v", tool) | |
515 | } | 534 | } | |
516 | if tool.UsableAtLoadtime { | 535 | if tool.UsableAtLoadtime { | |
517 | if G.Pkg == nil || G.Pkg.SeenBsdPrefsMk || G.Pkg.loadTimeTools[tool.Name] { | 536 | if G.Pkg == nil || G.Pkg.SeenBsdPrefsMk || G.Pkg.loadTimeTools[tool.Name] { | |
518 | perms |= aclpUseLoadtime | 537 | perms |= aclpUseLoadtime | |
519 | } | 538 | } | |
520 | } | 539 | } | |
521 | return &Vartype{lkNone, BtShellCommand, []AclEntry{{"*", perms}}, false} | 540 | return &Vartype{lkNone, BtShellCommand, []ACLEntry{{"*", perms}}, false} | |
522 | } | 541 | } | |
523 | 542 | |||
524 | if m, toolvarname := match1(varname, `^TOOLS_(.*)`); m && G.globalData.Tools.byVarname[toolvarname] != nil { | 543 | if m, toolvarname := match1(varname, `^TOOLS_(.*)`); m && G.globalData.Tools.byVarname[toolvarname] != nil { | |
525 | return &Vartype{lkNone, BtPathname, []AclEntry{{"*", aclpUse}}, false} | 544 | return &Vartype{lkNone, BtPathname, []ACLEntry{{"*", aclpUse}}, false} | |
526 | } | 545 | } | |
527 | 546 | |||
528 | allowAll := []AclEntry{{"*", aclpAll}} | 547 | allowAll := []ACLEntry{{"*", aclpAll}} | |
529 | allowRuntime := []AclEntry{{"*", aclpAllRuntime}} | 548 | allowRuntime := []ACLEntry{{"*", aclpAllRuntime}} | |
530 | 549 | |||
531 | // Guess the datatype of the variable based on naming conventions. | 550 | // Guess the datatype of the variable based on naming conventions. | |
532 | varbase := varnameBase(varname) | 551 | varbase := varnameBase(varname) | |
533 | var gtype *Vartype | 552 | var gtype *Vartype | |
534 | switch { | 553 | switch { | |
535 | case hasSuffix(varbase, "DIRS"): | 554 | case hasSuffix(varbase, "DIRS"): | |
536 | gtype = &Vartype{lkShell, BtPathmask, allowRuntime, true} | 555 | gtype = &Vartype{lkShell, BtPathmask, allowRuntime, true} | |
537 | case hasSuffix(varbase, "DIR") && !hasSuffix(varbase, "DESTDIR"), hasSuffix(varname, "_HOME"): | 556 | case hasSuffix(varbase, "DIR") && !hasSuffix(varbase, "DESTDIR"), hasSuffix(varname, "_HOME"): | |
538 | gtype = &Vartype{lkNone, BtPathname, allowRuntime, true} | 557 | gtype = &Vartype{lkNone, BtPathname, allowRuntime, true} | |
539 | case hasSuffix(varbase, "FILES"): | 558 | case hasSuffix(varbase, "FILES"): | |
540 | gtype = &Vartype{lkShell, BtPathmask, allowRuntime, true} | 559 | gtype = &Vartype{lkShell, BtPathmask, allowRuntime, true} | |
541 | case hasSuffix(varbase, "FILE"): | 560 | case hasSuffix(varbase, "FILE"): | |
542 | gtype = &Vartype{lkNone, BtPathname, allowRuntime, true} | 561 | gtype = &Vartype{lkNone, BtPathname, allowRuntime, true} | |
@@ -625,27 +644,26 @@ func (mkline *MkLineImpl) DetermineUsedV | @@ -625,27 +644,26 @@ func (mkline *MkLineImpl) DetermineUsedV | |||
625 | if min == -1 || (p4 != -1 && p4 < min) { | 644 | if min == -1 || (p4 != -1 && p4 < min) { | |
626 | min = p4 | 645 | min = p4 | |
627 | } | 646 | } | |
628 | rest = rest[min:] | 647 | rest = rest[min:] | |
629 | 648 | |||
630 | m := regex.Compile(`(?:\$\{|\$\(|defined\(|empty\()([*+\-.0-9A-Z_a-z]+)[:})]`).FindStringSubmatchIndex(rest) | 649 | m := regex.Compile(`(?:\$\{|\$\(|defined\(|empty\()([*+\-.0-9A-Z_a-z]+)[:})]`).FindStringSubmatchIndex(rest) | |
631 | if m == nil { | 650 | if m == nil { | |
632 | return | 651 | return | |
633 | } | 652 | } | |
634 | varname := rest[m[2]:m[3]] | 653 | varname := rest[m[2]:m[3]] | |
635 | varnames = append(varnames, varname) | 654 | varnames = append(varnames, varname) | |
636 | rest = rest[:m[0]] + rest[m[1]:] | 655 | rest = rest[:m[0]] + rest[m[1]:] | |
637 | } | 656 | } | |
638 | return | |||
639 | } | 657 | } | |
640 | 658 | |||
641 | // VarUseContext defines the context in which a variable is defined | 659 | // VarUseContext defines the context in which a variable is defined | |
642 | // or used. Whether that is allowed depends on: | 660 | // or used. Whether that is allowed depends on: | |
643 | // | 661 | // | |
644 | // * The variable's data type, as defined in vardefs.go. | 662 | // * The variable's data type, as defined in vardefs.go. | |
645 | // | 663 | // | |
646 | // * When used on the right-hand side of an assigment, the variable can | 664 | // * When used on the right-hand side of an assigment, the variable can | |
647 | // represent a list of words, a single word or even only part of a | 665 | // represent a list of words, a single word or even only part of a | |
648 | // word. This distinction decides upon the correct use of the :Q | 666 | // word. This distinction decides upon the correct use of the :Q | |
649 | // operator. | 667 | // operator. | |
650 | // | 668 | // | |
651 | // * When used in preprocessing statements like .if or .for, the other | 669 | // * When used in preprocessing statements like .if or .for, the other |
@@ -169,47 +169,47 @@ func (s *Suite) Test_NewMkLine(c *check. | @@ -169,47 +169,47 @@ func (s *Suite) Test_NewMkLine(c *check. | |||
169 | c.Check(ln[9].Varname(), equals, "VARNAME") | 169 | c.Check(ln[9].Varname(), equals, "VARNAME") | |
170 | c.Check(ln[9].Varcanon(), equals, "VARNAME") | 170 | c.Check(ln[9].Varcanon(), equals, "VARNAME") | |
171 | c.Check(ln[9].Varparam(), equals, "") | 171 | c.Check(ln[9].Varparam(), equals, "") | |
172 | 172 | |||
173 | t.CheckOutputLines( | 173 | t.CheckOutputLines( | |
174 | "WARN: test.mk:9: Space before colon in dependency line.") | 174 | "WARN: test.mk:9: Space before colon in dependency line.") | |
175 | } | 175 | } | |
176 | 176 | |||
177 | func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) { | 177 | func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) { | |
178 | t := s.Init(c) | 178 | t := s.Init(c) | |
179 | 179 | |||
180 | t.SetupCommandLine("-Wspace") | 180 | t.SetupCommandLine("-Wspace") | |
181 | fname := t.CreateFileLines("Makefile", | 181 | fname := t.CreateFileLines("Makefile", | |
182 | MkRcsId, | 182 | MkRcsID, | |
183 | "VARNAME +=\t${VARNAME}", | 183 | "VARNAME +=\t${VARNAME}", | |
184 | "VARNAME+ =\t${VARNAME+}", | 184 | "VARNAME+ =\t${VARNAME+}", | |
185 | "VARNAME+ +=\t${VARNAME+}", | 185 | "VARNAME+ +=\t${VARNAME+}", | |
186 | "pkgbase := pkglint") | 186 | "pkgbase := pkglint") | |
187 | 187 | |||
188 | CheckfileMk(fname) | 188 | CheckfileMk(fname) | |
189 | 189 | |||
190 | t.CheckOutputLines( | 190 | t.CheckOutputLines( | |
191 | "WARN: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".", | 191 | "WARN: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".", | |
192 | "WARN: ~/Makefile:4: Unnecessary space after variable name \"VARNAME+\".") | 192 | "WARN: ~/Makefile:4: Unnecessary space after variable name \"VARNAME+\".") | |
193 | 193 | |||
194 | t.SetupCommandLine("-Wspace", "--autofix") | 194 | t.SetupCommandLine("-Wspace", "--autofix") | |
195 | 195 | |||
196 | CheckfileMk(fname) | 196 | CheckfileMk(fname) | |
197 | 197 | |||
198 | t.CheckOutputLines( | 198 | t.CheckOutputLines( | |
199 | "AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".", | 199 | "AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".", | |
200 | "AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".") | 200 | "AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".") | |
201 | t.CheckFileLines("Makefile", | 201 | t.CheckFileLines("Makefile", | |
202 | MkRcsId+"", | 202 | MkRcsID+"", | |
203 | "VARNAME+=\t${VARNAME}", | 203 | "VARNAME+=\t${VARNAME}", | |
204 | "VARNAME+ =\t${VARNAME+}", | 204 | "VARNAME+ =\t${VARNAME+}", | |
205 | "VARNAME++=\t${VARNAME+}", | 205 | "VARNAME++=\t${VARNAME+}", | |
206 | "pkgbase := pkglint") | 206 | "pkgbase := pkglint") | |
207 | } | 207 | } | |
208 | 208 | |||
209 | func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) { | 209 | func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) { | |
210 | t := s.Init(c) | 210 | t := s.Init(c) | |
211 | 211 | |||
212 | mkline := t.NewMkLine("fname", 1, "# dummy") | 212 | mkline := t.NewMkLine("fname", 1, "# dummy") | |
213 | G.globalData.InitVartypes() | 213 | G.globalData.InitVartypes() | |
214 | 214 | |||
215 | t1 := mkline.VariableType("FONT_DIRS") | 215 | t1 := mkline.VariableType("FONT_DIRS") | |
@@ -268,27 +268,27 @@ func (s *Suite) Test_NewMkLine_leading_s | @@ -268,27 +268,27 @@ func (s *Suite) Test_NewMkLine_leading_s | |||
268 | _ = t.NewMkLine("rubyversion.mk", 427, " _RUBYVER=\t2.15") | 268 | _ = t.NewMkLine("rubyversion.mk", 427, " _RUBYVER=\t2.15") | |
269 | 269 | |||
270 | t.CheckOutputLines( | 270 | t.CheckOutputLines( | |
271 | "WARN: rubyversion.mk:427: Makefile lines should not start with space characters.") | 271 | "WARN: rubyversion.mk:427: Makefile lines should not start with space characters.") | |
272 | } | 272 | } | |
273 | 273 | |||
274 | func (s *Suite) Test_MkLines_Check__extra(c *check.C) { | 274 | func (s *Suite) Test_MkLines_Check__extra(c *check.C) { | |
275 | t := s.Init(c) | 275 | t := s.Init(c) | |
276 | 276 | |||
277 | t.SetupCommandLine("-Wextra") | 277 | t.SetupCommandLine("-Wextra") | |
278 | G.globalData.InitVartypes() | 278 | G.globalData.InitVartypes() | |
279 | G.Pkg = NewPackage("category/pkgbase") | 279 | G.Pkg = NewPackage("category/pkgbase") | |
280 | G.Mk = t.NewMkLines("options.mk", | 280 | G.Mk = t.NewMkLines("options.mk", | |
281 | MkRcsId, | 281 | MkRcsID, | |
282 | ".for word in ${PKG_FAIL_REASON}", | 282 | ".for word in ${PKG_FAIL_REASON}", | |
283 | "PYTHON_VERSIONS_ACCEPTED=\t27 35 30", | 283 | "PYTHON_VERSIONS_ACCEPTED=\t27 35 30", | |
284 | "CONFIGURE_ARGS+=\t--sharedir=${PREFIX}/share/kde", | 284 | "CONFIGURE_ARGS+=\t--sharedir=${PREFIX}/share/kde", | |
285 | "COMMENT=\t# defined", | 285 | "COMMENT=\t# defined", | |
286 | ".endfor", | 286 | ".endfor", | |
287 | "GAMES_USER?=pkggames", | 287 | "GAMES_USER?=pkggames", | |
288 | "PLIST_SUBST+= CONDITIONAL=${CONDITIONAL}", | 288 | "PLIST_SUBST+= CONDITIONAL=${CONDITIONAL}", | |
289 | "CONDITIONAL=\"@comment\"", | 289 | "CONDITIONAL=\"@comment\"", | |
290 | "BUILD_DIRS=\t${WRKSRC}/../build") | 290 | "BUILD_DIRS=\t${WRKSRC}/../build") | |
291 | 291 | |||
292 | G.Mk.Check() | 292 | G.Mk.Check() | |
293 | 293 | |||
294 | t.CheckOutputLines( | 294 | t.CheckOutputLines( | |
@@ -369,187 +369,187 @@ func (s *Suite) Test_MkLine_variableNeed | @@ -369,187 +369,187 @@ func (s *Suite) Test_MkLine_variableNeed | |||
369 | t.CheckOutputLines( | 369 | t.CheckOutputLines( | |
370 | "WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} and make sure the variable appears outside of any quoting characters.") | 370 | "WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} and make sure the variable appears outside of any quoting characters.") | |
371 | } | 371 | } | |
372 | 372 | |||
373 | func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C) { | 373 | func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C) { | |
374 | t := s.Init(c) | 374 | t := s.Init(c) | |
375 | 375 | |||
376 | t.SetupCommandLine("-Wall") | 376 | t.SetupCommandLine("-Wall") | |
377 | G.globalData.InitVartypes() | 377 | G.globalData.InitVartypes() | |
378 | t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true}) | 378 | t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true}) | |
379 | t.SetupTool(&Tool{Name: "sort", Varname: "SORT", Predefined: true}) | 379 | t.SetupTool(&Tool{Name: "sort", Varname: "SORT", Predefined: true}) | |
380 | G.Pkg = NewPackage("category/pkgbase") | 380 | G.Pkg = NewPackage("category/pkgbase") | |
381 | G.Mk = t.NewMkLines("Makefile", | 381 | G.Mk = t.NewMkLines("Makefile", | |
382 | MkRcsId, | 382 | MkRcsID, | |
383 | "GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};") | 383 | "GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};") | |
384 | 384 | |||
385 | G.Mk.DetermineDefinedVariables() | 385 | G.Mk.DetermineDefinedVariables() | |
386 | MkLineChecker{G.Mk.mklines[1]}.Check() | 386 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
387 | 387 | |||
388 | t.CheckOutputLines( | 388 | t.CheckOutputLines( | |
389 | "WARN: Makefile:2: The exitcode of \"${FIND}\" at the left of the | operator is ignored.") | 389 | "WARN: Makefile:2: The exitcode of \"${FIND}\" at the left of the | operator is ignored.") | |
390 | } | 390 | } | |
391 | 391 | |||
392 | func (s *Suite) Test_MkLine_variableNeedsQuoting__word_as_part_of_word(c *check.C) { | 392 | func (s *Suite) Test_MkLine_variableNeedsQuoting__word_as_part_of_word(c *check.C) { | |
393 | t := s.Init(c) | 393 | t := s.Init(c) | |
394 | 394 | |||
395 | t.SetupCommandLine("-Wall") | 395 | t.SetupCommandLine("-Wall") | |
396 | G.globalData.InitVartypes() | 396 | G.globalData.InitVartypes() | |
397 | G.Mk = t.NewMkLines("Makefile", | 397 | G.Mk = t.NewMkLines("Makefile", | |
398 | MkRcsId, | 398 | MkRcsID, | |
399 | "EGDIR=\t${EGDIR}/${MACHINE_GNU_PLATFORM}") | 399 | "EGDIR=\t${EGDIR}/${MACHINE_GNU_PLATFORM}") | |
400 | 400 | |||
401 | MkLineChecker{G.Mk.mklines[1]}.Check() | 401 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
402 | 402 | |||
403 | t.CheckOutputEmpty() | 403 | t.CheckOutputEmpty() | |
404 | } | 404 | } | |
405 | 405 | |||
406 | // As an argument to ${ECHO}, the :Q modifier should be used, but pkglint | 406 | // As an argument to ${ECHO}, the :Q modifier should be used, but pkglint | |
407 | // currently does not know all shell commands and how they handle their | 407 | // currently does not know all shell commands and how they handle their | |
408 | // arguments. As an argument to xargs(1), the :Q modifier would be misplaced, | 408 | // arguments. As an argument to xargs(1), the :Q modifier would be misplaced, | |
409 | // therefore no warning is issued in both these cases. | 409 | // therefore no warning is issued in both these cases. | |
410 | // | 410 | // | |
411 | // Based on graphics/circos/Makefile. | 411 | // Based on graphics/circos/Makefile. | |
412 | func (s *Suite) Test_MkLine_variableNeedsQuoting__command_as_command_argument(c *check.C) { | 412 | func (s *Suite) Test_MkLine_variableNeedsQuoting__command_as_command_argument(c *check.C) { | |
413 | t := s.Init(c) | 413 | t := s.Init(c) | |
414 | 414 | |||
415 | t.SetupCommandLine("-Wall") | 415 | t.SetupCommandLine("-Wall") | |
416 | t.SetupTool(&Tool{Name: "perl", Varname: "PERL5", Predefined: true}) | 416 | t.SetupTool(&Tool{Name: "perl", Varname: "PERL5", Predefined: true}) | |
417 | t.SetupTool(&Tool{Name: "bash", Varname: "BASH", Predefined: true}) | 417 | t.SetupTool(&Tool{Name: "bash", Varname: "BASH", Predefined: true}) | |
418 | G.globalData.InitVartypes() | 418 | G.globalData.InitVartypes() | |
419 | G.Mk = t.NewMkLines("Makefile", | 419 | G.Mk = t.NewMkLines("Makefile", | |
420 | MkRcsId, | 420 | MkRcsID, | |
421 | "\t${RUN} cd ${WRKSRC} && ( ${ECHO} ${PERL5:Q} ; ${ECHO} ) | ${BASH} ./install", | 421 | "\t${RUN} cd ${WRKSRC} && ( ${ECHO} ${PERL5:Q} ; ${ECHO} ) | ${BASH} ./install", | |
422 | "\t${RUN} cd ${WRKSRC} && ( ${ECHO} ${PERL5} ; ${ECHO} ) | ${BASH} ./install") | 422 | "\t${RUN} cd ${WRKSRC} && ( ${ECHO} ${PERL5} ; ${ECHO} ) | ${BASH} ./install") | |
423 | 423 | |||
424 | MkLineChecker{G.Mk.mklines[1]}.Check() | 424 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
425 | MkLineChecker{G.Mk.mklines[2]}.Check() | 425 | MkLineChecker{G.Mk.mklines[2]}.Check() | |
426 | 426 | |||
427 | t.CheckOutputLines( | 427 | t.CheckOutputLines( | |
428 | "WARN: Makefile:2: The exitcode of the command at the left of the | operator is ignored.", | 428 | "WARN: Makefile:2: The exitcode of the command at the left of the | operator is ignored.", | |
429 | "WARN: Makefile:3: The exitcode of the command at the left of the | operator is ignored.") | 429 | "WARN: Makefile:3: The exitcode of the command at the left of the | operator is ignored.") | |
430 | } | 430 | } | |
431 | 431 | |||
432 | // Based on mail/mailfront/Makefile. | 432 | // Based on mail/mailfront/Makefile. | |
433 | func (s *Suite) Test_MkLine_variableNeedsQuoting__URL_as_part_of_word_in_list(c *check.C) { | 433 | func (s *Suite) Test_MkLine_variableNeedsQuoting__URL_as_part_of_word_in_list(c *check.C) { | |
434 | t := s.Init(c) | 434 | t := s.Init(c) | |
435 | 435 | |||
436 | t.SetupCommandLine("-Wall") | 436 | t.SetupCommandLine("-Wall") | |
437 | G.globalData.InitVartypes() | 437 | G.globalData.InitVartypes() | |
438 | G.Mk = t.NewMkLines("Makefile", | 438 | G.Mk = t.NewMkLines("Makefile", | |
439 | MkRcsId, | 439 | MkRcsID, | |
440 | "MASTER_SITES=${HOMEPAGE}archive/") | 440 | "MASTER_SITES=${HOMEPAGE}archive/") | |
441 | 441 | |||
442 | MkLineChecker{G.Mk.mklines[1]}.Check() | 442 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
443 | 443 | |||
444 | t.CheckOutputEmpty() // Don't suggest to use ${HOMEPAGE:Q}. | 444 | t.CheckOutputEmpty() // Don't suggest to use ${HOMEPAGE:Q}. | |
445 | } | 445 | } | |
446 | 446 | |||
447 | // Pkglint currently does not parse $$(subshell) commands very well. As | 447 | // Pkglint currently does not parse $$(subshell) commands very well. As | |
448 | // a side effect, it sometimes issues wrong warnings about the :Q | 448 | // a side effect, it sometimes issues wrong warnings about the :Q | |
449 | // modifier. | 449 | // modifier. | |
450 | // | 450 | // | |
451 | // Based on www/firefox31/xpi.mk. | 451 | // Based on www/firefox31/xpi.mk. | |
452 | func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_subshell(c *check.C) { | 452 | func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_subshell(c *check.C) { | |
453 | t := s.Init(c) | 453 | t := s.Init(c) | |
454 | 454 | |||
455 | t.SetupCommandLine("-Wall") | 455 | t.SetupCommandLine("-Wall") | |
456 | G.globalData.InitVartypes() | 456 | G.globalData.InitVartypes() | |
457 | t.SetupTool(&Tool{Name: "awk", Varname: "AWK", Predefined: true}) | 457 | t.SetupTool(&Tool{Name: "awk", Varname: "AWK", Predefined: true}) | |
458 | t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true}) | 458 | t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true}) | |
459 | G.Mk = t.NewMkLines("xpi.mk", | 459 | G.Mk = t.NewMkLines("xpi.mk", | |
460 | MkRcsId, | 460 | MkRcsID, | |
461 | "\t id=$$(${AWK} '{print}' < ${WRKSRC}/idfile) && echo \"$$id\"", | 461 | "\t id=$$(${AWK} '{print}' < ${WRKSRC}/idfile) && echo \"$$id\"", | |
462 | "\t id=`${AWK} '{print}' < ${WRKSRC}/idfile` && echo \"$$id\"") | 462 | "\t id=`${AWK} '{print}' < ${WRKSRC}/idfile` && echo \"$$id\"") | |
463 | 463 | |||
464 | MkLineChecker{G.Mk.mklines[1]}.Check() | 464 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
465 | MkLineChecker{G.Mk.mklines[2]}.Check() | 465 | MkLineChecker{G.Mk.mklines[2]}.Check() | |
466 | 466 | |||
467 | // Don't suggest to use ${AWK:Q}. | 467 | // Don't suggest to use ${AWK:Q}. | |
468 | t.CheckOutputLines( | 468 | t.CheckOutputLines( | |
469 | "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.") | 469 | "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.") | |
470 | } | 470 | } | |
471 | 471 | |||
472 | // LDFLAGS (and even more so CPPFLAGS and CFLAGS) may contain special | 472 | // LDFLAGS (and even more so CPPFLAGS and CFLAGS) may contain special | |
473 | // shell characters like quotes or backslashes. Therefore, quoting them | 473 | // shell characters like quotes or backslashes. Therefore, quoting them | |
474 | // correctly is more tricky than with other variables. | 474 | // correctly is more tricky than with other variables. | |
475 | func (s *Suite) Test_MkLine_variableNeedsQuoting__LDFLAGS_in_single_quotes(c *check.C) { | 475 | func (s *Suite) Test_MkLine_variableNeedsQuoting__LDFLAGS_in_single_quotes(c *check.C) { | |
476 | t := s.Init(c) | 476 | t := s.Init(c) | |
477 | 477 | |||
478 | t.SetupCommandLine("-Wall") | 478 | t.SetupCommandLine("-Wall") | |
479 | G.globalData.InitVartypes() | 479 | G.globalData.InitVartypes() | |
480 | G.Mk = t.NewMkLines("x11/mlterm/Makefile", | 480 | G.Mk = t.NewMkLines("x11/mlterm/Makefile", | |
481 | MkRcsId, | 481 | MkRcsID, | |
482 | "SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& ${LDFLAGS:M*:Q}|g'", | 482 | "SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& ${LDFLAGS:M*:Q}|g'", | |
483 | "SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& '${LDFLAGS:M*:Q}'|g'") | 483 | "SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& '${LDFLAGS:M*:Q}'|g'") | |
484 | 484 | |||
485 | MkLineChecker{G.Mk.mklines[1]}.Check() | 485 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
486 | MkLineChecker{G.Mk.mklines[2]}.Check() | 486 | MkLineChecker{G.Mk.mklines[2]}.Check() | |
487 | 487 | |||
488 | t.CheckOutputLines( | 488 | t.CheckOutputLines( | |
489 | "WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.") | 489 | "WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.") | |
490 | } | 490 | } | |
491 | 491 | |||
492 | // No quoting is necessary here. | 492 | // No quoting is necessary here. | |
493 | // PKG_OPTIONS are declared as "lkShell" although they are processed | 493 | // PKG_OPTIONS are declared as "lkShell" although they are processed | |
494 | // using make's .for loop, which splits them at whitespace and usually | 494 | // using make's .for loop, which splits them at whitespace and usually | |
495 | // requires the variable to be declared as "lkSpace". | 495 | // requires the variable to be declared as "lkSpace". | |
496 | // In this case it doesn't matter though since each option is an identifier, | 496 | // In this case it doesn't matter though since each option is an identifier, | |
497 | // and these do not pose any quoting or escaping problems. | 497 | // and these do not pose any quoting or escaping problems. | |
498 | func (s *Suite) Test_MkLine_variableNeedsQuoting__package_options(c *check.C) { | 498 | func (s *Suite) Test_MkLine_variableNeedsQuoting__package_options(c *check.C) { | |
499 | t := s.Init(c) | 499 | t := s.Init(c) | |
500 | 500 | |||
501 | t.SetupCommandLine("-Wall") | 501 | t.SetupCommandLine("-Wall") | |
502 | G.globalData.InitVartypes() | 502 | G.globalData.InitVartypes() | |
503 | G.Mk = t.NewMkLines("Makefile", | 503 | G.Mk = t.NewMkLines("Makefile", | |
504 | MkRcsId, | 504 | MkRcsID, | |
505 | "PKG_SUGGESTED_OPTIONS+=\t${PKG_DEFAULT_OPTIONS:Mcdecimal} ${PKG_OPTIONS.py-trytond:Mcdecimal}") | 505 | "PKG_SUGGESTED_OPTIONS+=\t${PKG_DEFAULT_OPTIONS:Mcdecimal} ${PKG_OPTIONS.py-trytond:Mcdecimal}") | |
506 | 506 | |||
507 | MkLineChecker{G.Mk.mklines[1]}.Check() | 507 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
508 | 508 | |||
509 | t.CheckOutputEmpty() | 509 | t.CheckOutputEmpty() | |
510 | } | 510 | } | |
511 | 511 | |||
512 | func (s *Suite) Test_MkLines_Check__MASTER_SITE_in_HOMEPAGE(c *check.C) { | 512 | func (s *Suite) Test_MkLines_Check__MASTER_SITE_in_HOMEPAGE(c *check.C) { | |
513 | t := s.Init(c) | 513 | t := s.Init(c) | |
514 | 514 | |||
515 | t.SetupCommandLine("-Wall") | 515 | t.SetupCommandLine("-Wall") | |
516 | t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/") | 516 | t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/") | |
517 | G.globalData.InitVartypes() | 517 | G.globalData.InitVartypes() | |
518 | G.Mk = t.NewMkLines("devel/catch/Makefile", | 518 | G.Mk = t.NewMkLines("devel/catch/Makefile", | |
519 | MkRcsId, | 519 | MkRcsID, | |
520 | "HOMEPAGE=\t${MASTER_SITE_GITHUB:=philsquared/Catch/}", | 520 | "HOMEPAGE=\t${MASTER_SITE_GITHUB:=philsquared/Catch/}", | |
521 | "HOMEPAGE=\t${MASTER_SITE_GITHUB}", | 521 | "HOMEPAGE=\t${MASTER_SITE_GITHUB}", | |
522 | "HOMEPAGE=\t${MASTER_SITES}", | 522 | "HOMEPAGE=\t${MASTER_SITES}", | |
523 | "HOMEPAGE=\t${MASTER_SITES}${GITHUB_PROJECT}") | 523 | "HOMEPAGE=\t${MASTER_SITES}${GITHUB_PROJECT}") | |
524 | 524 | |||
525 | G.Mk.Check() | 525 | G.Mk.Check() | |
526 | 526 | |||
527 | t.CheckOutputLines( | 527 | t.CheckOutputLines( | |
528 | "WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/philsquared/Catch/ directly.", | 528 | "WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/philsquared/Catch/ directly.", | |
529 | "WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/ directly.", | 529 | "WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/ directly.", | |
530 | "WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.", | 530 | "WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.", | |
531 | "WARN: devel/catch/Makefile:5: HOMEPAGE should not be defined in terms of MASTER_SITEs.") | 531 | "WARN: devel/catch/Makefile:5: HOMEPAGE should not be defined in terms of MASTER_SITEs.") | |
532 | } | 532 | } | |
533 | 533 | |||
534 | func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_quotes_in_subshell_in_shellwords(c *check.C) { | 534 | func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_quotes_in_subshell_in_shellwords(c *check.C) { | |
535 | t := s.Init(c) | 535 | t := s.Init(c) | |
536 | 536 | |||
537 | t.SetupCommandLine("-Wall") | 537 | t.SetupCommandLine("-Wall") | |
538 | t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true}) | 538 | t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true}) | |
539 | t.SetupTool(&Tool{Name: "sh", Varname: "SH", Predefined: true}) | 539 | t.SetupTool(&Tool{Name: "sh", Varname: "SH", Predefined: true}) | |
540 | G.globalData.InitVartypes() | 540 | G.globalData.InitVartypes() | |
541 | G.Mk = t.NewMkLines("x11/labltk/Makefile", | 541 | G.Mk = t.NewMkLines("x11/labltk/Makefile", | |
542 | MkRcsId, | 542 | MkRcsID, | |
543 | "CONFIGURE_ARGS+=\t-tklibs \"`${SH} -c '${ECHO} $$TK_LD_FLAGS'`\"") | 543 | "CONFIGURE_ARGS+=\t-tklibs \"`${SH} -c '${ECHO} $$TK_LD_FLAGS'`\"") | |
544 | 544 | |||
545 | MkLineChecker{G.Mk.mklines[1]}.Check() | 545 | MkLineChecker{G.Mk.mklines[1]}.Check() | |
546 | 546 | |||
547 | // Don't suggest ${ECHO:Q} here. | 547 | // Don't suggest ${ECHO:Q} here. | |
548 | t.CheckOutputEmpty() | 548 | t.CheckOutputEmpty() | |
549 | } | 549 | } | |
550 | 550 | |||
551 | func (s *Suite) Test_MkLine_variableNeedsQuoting__LDADD_in_BUILDLINK_TRANSFORM(c *check.C) { | 551 | func (s *Suite) Test_MkLine_variableNeedsQuoting__LDADD_in_BUILDLINK_TRANSFORM(c *check.C) { | |
552 | t := s.Init(c) | 552 | t := s.Init(c) | |
553 | 553 | |||
554 | t.SetupCommandLine("-Wall") | 554 | t.SetupCommandLine("-Wall") | |
555 | G.globalData.InitVartypes() | 555 | G.globalData.InitVartypes() | |
@@ -573,200 +573,225 @@ func (s *Suite) Test_MkLine_variableNeed | @@ -573,200 +573,225 @@ func (s *Suite) Test_MkLine_variableNeed | |||
573 | 573 | |||
574 | MkLineChecker{G.Mk.mklines[0]}.Check() | 574 | MkLineChecker{G.Mk.mklines[0]}.Check() | |
575 | 575 | |||
576 | // Don't suggest ${REPLACE_PERL:Q}. | 576 | // Don't suggest ${REPLACE_PERL:Q}. | |
577 | t.CheckOutputEmpty() | 577 | t.CheckOutputEmpty() | |
578 | } | 578 | } | |
579 | 579 | |||
580 | func (s *Suite) Test_MkLine_variableNeedsQuoting__guessed_list_variable_in_quotes(c *check.C) { | 580 | func (s *Suite) Test_MkLine_variableNeedsQuoting__guessed_list_variable_in_quotes(c *check.C) { | |
581 | t := s.Init(c) | 581 | t := s.Init(c) | |
582 | 582 | |||
583 | t.SetupCommandLine("-Wall") | 583 | t.SetupCommandLine("-Wall") | |
584 | G.globalData.InitVartypes() | 584 | G.globalData.InitVartypes() | |
585 | G.Mk = t.NewMkLines("audio/jack-rack/Makefile", | 585 | G.Mk = t.NewMkLines("audio/jack-rack/Makefile", | |
586 | MkRcsId, | 586 | MkRcsID, | |
587 | "LADSPA_PLUGIN_PATH?=\t${PREFIX}/lib/ladspa", | 587 | "LADSPA_PLUGIN_PATH?=\t${PREFIX}/lib/ladspa", | |
588 | "CPPFLAGS+=\t\t-DLADSPA_PATH=\"\\\"${LADSPA_PLUGIN_PATH}\\\"\"") | 588 | "CPPFLAGS+=\t\t-DLADSPA_PATH=\"\\\"${LADSPA_PLUGIN_PATH}\\\"\"") | |
589 | 589 | |||
590 | G.Mk.Check() | 590 | G.Mk.Check() | |
591 | 591 | |||
592 | t.CheckOutputLines( | 592 | t.CheckOutputLines( | |
593 | "WARN: audio/jack-rack/Makefile:3: The list variable LADSPA_PLUGIN_PATH should not be embedded in a word.") | 593 | "WARN: audio/jack-rack/Makefile:3: The variable LADSPA_PLUGIN_PATH should be quoted as part of a shell word.") | |
594 | } | 594 | } | |
595 | 595 | |||
596 | func (s *Suite) Test_MkLine_variableNeedsQuoting__list_in_list(c *check.C) { | 596 | func (s *Suite) Test_MkLine_variableNeedsQuoting__list_in_list(c *check.C) { | |
597 | t := s.Init(c) | 597 | t := s.Init(c) | |
598 | 598 | |||
599 | t.SetupCommandLine("-Wall") | 599 | t.SetupCommandLine("-Wall") | |
600 | G.globalData.InitVartypes() | 600 | G.globalData.InitVartypes() | |
601 | G.Mk = t.NewMkLines("x11/eterm/Makefile", | 601 | G.Mk = t.NewMkLines("x11/eterm/Makefile", | |
602 | MkRcsId, | 602 | MkRcsID, | |
603 | "DISTFILES=\t${DEFAULT_DISTFILES} ${PIXMAP_FILES}") | 603 | "DISTFILES=\t${DEFAULT_DISTFILES} ${PIXMAP_FILES}") | |
604 | 604 | |||
605 | G.Mk.Check() | 605 | G.Mk.Check() | |
606 | 606 | |||
607 | t.CheckOutputEmpty() // Don't warn about missing :Q modifiers. | 607 | t.CheckOutputEmpty() // Don't warn about missing :Q modifiers. | |
608 | } | 608 | } | |
609 | 609 | |||
610 | func (s *Suite) Test_MkLine_variableNeedsQuoting__PKGNAME_and_URL_list_in_URL_list(c *check.C) { | 610 | func (s *Suite) Test_MkLine_variableNeedsQuoting__PKGNAME_and_URL_list_in_URL_list(c *check.C) { | |
611 | t := s.Init(c) | 611 | t := s.Init(c) | |
612 | 612 | |||
613 | t.SetupCommandLine("-Wall") | 613 | t.SetupCommandLine("-Wall") | |
614 | t.SetupMasterSite("MASTER_SITE_GNOME", "http://ftp.gnome.org/") | 614 | t.SetupMasterSite("MASTER_SITE_GNOME", "http://ftp.gnome.org/") | |
615 | G.globalData.InitVartypes() | 615 | G.globalData.InitVartypes() | |
616 | G.Mk = t.NewMkLines("x11/gtk3/Makefile", | 616 | G.Mk = t.NewMkLines("x11/gtk3/Makefile", | |
617 | MkRcsId, | 617 | MkRcsID, | |
618 | "MASTER_SITES=\tftp://ftp.gtk.org/${PKGNAME}/ ${MASTER_SITE_GNOME:=subdir/}") | 618 | "MASTER_SITES=\tftp://ftp.gtk.org/${PKGNAME}/ ${MASTER_SITE_GNOME:=subdir/}") | |
619 | 619 | |||
620 | MkLineChecker{G.Mk.mklines[1]}.checkVarassignVaruse() | 620 | MkLineChecker{G.Mk.mklines[1]}.checkVarassignVaruse() | |
621 | 621 | |||
622 | t.CheckOutputEmpty() // Don't warn about missing :Q modifiers. | 622 | t.CheckOutputEmpty() // Don't warn about missing :Q modifiers. | |
623 | } | 623 | } | |
624 | 624 | |||
625 | func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check.C) { | 625 | func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check.C) { | |
626 | t := s.Init(c) | 626 | t := s.Init(c) | |
627 | 627 | |||
628 | t.SetupCommandLine("-Wall") | 628 | t.SetupCommandLine("-Wall") | |
629 | G.globalData.InitVartypes() | 629 | G.globalData.InitVartypes() | |
630 | G.globalData.Tools = NewToolRegistry() | 630 | G.globalData.Tools = NewToolRegistry() | |
631 | G.globalData.Tools.RegisterVarname("tar", "TAR") | 631 | G.globalData.Tools.RegisterVarname("tar", "TAR") | |
632 | mklines := t.NewMkLines("Makefile", | 632 | mklines := t.NewMkLines("Makefile", | |
633 | MkRcsId, | 633 | MkRcsID, | |
634 | "", | 634 | "", | |
635 | "CONFIGURE_ENV+=\tSYS_TAR_COMMAND_PATH=${TOOLS_TAR:Q}") | 635 | "CONFIGURE_ENV+=\tSYS_TAR_COMMAND_PATH=${TOOLS_TAR:Q}") | |
636 | 636 | |||
637 | MkLineChecker{mklines.mklines[2]}.checkVarassignVaruse() | 637 | MkLineChecker{mklines.mklines[2]}.checkVarassignVaruse() | |
638 | 638 | |||
639 | // The TOOLS_* variables only contain the path to the tool, | 639 | // The TOOLS_* variables only contain the path to the tool, | |
640 | // without any additional arguments that might be necessary | 640 | // without any additional arguments that might be necessary | |
641 | // for invoking the tool properly (e.g. touch -t). | 641 | // for invoking the tool properly (e.g. touch -t). | |
642 | // Therefore, no quoting is necessary. | 642 | // Therefore, no quoting is necessary. | |
643 | t.CheckOutputLines( | 643 | t.CheckOutputLines( | |
644 | "NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.") | 644 | "NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.") | |
645 | } | 645 | } | |
646 | 646 | |||
647 | func (s *Suite) Test_MkLine_variableNeedsQuoting__backticks(c *check.C) { | |||
648 | t := s.Init(c) | |||
649 | ||||
650 | t.SetupCommandLine("-Wall") | |||
651 | G.globalData.InitVartypes() | |||
652 | G.globalData.Tools = NewToolRegistry() | |||
653 | G.globalData.Tools.RegisterVarname("cat", "CAT") | |||
654 | mklines := t.NewMkLines("Makefile", | |||
655 | MkRcsID, | |||
656 | "", | |||
657 | "COMPILE_CMD=\tcc `${CAT} ${WRKDIR}/compileflags`", | |||
658 | "COMMENT_CMD=\techo `echo ${COMMENT}`") | |||
659 | ||||
660 | MkLineChecker{mklines.mklines[2]}.checkVarassignVaruse() | |||
661 | MkLineChecker{mklines.mklines[3]}.checkVarassignVaruse() | |||
662 | ||||
663 | // Both CAT and WRKDIR are safe from quoting, therefore no warnings. | |||
664 | // But COMMENT may contain arbitrary characters and therefore must | |||
665 | // only appear completely unquoted. There is no practical way of | |||
666 | // using it inside backticks, and luckily there is no need for it. | |||
667 | t.CheckOutputLines( | |||
668 | "WARN: Makefile:4: COMMENT may not be used in any file; it is a write-only variable.", | |||
669 | "WARN: Makefile:4: The variable COMMENT should be quoted as part of a shell word.") | |||
670 | } | |||
671 | ||||
647 | // For some well-known directory variables like WRKDIR, PREFIX, LOCALBASE, | 672 | // For some well-known directory variables like WRKDIR, PREFIX, LOCALBASE, | |
648 | // the :Q modifier can be safely removed since pkgsrc will never support | 673 | // the :Q modifier can be safely removed since pkgsrc will never support | |
649 | // having special characters in these directory names. | 674 | // having special characters in these directory names. | |
650 | // For guessed variable types be cautious and don't autofix them. | 675 | // For guessed variable types be cautious and don't autofix them. | |
651 | func (s *Suite) Test_MkLine_variableNeedsQuoting__only_remove_known(c *check.C) { | 676 | func (s *Suite) Test_MkLine_variableNeedsQuoting__only_remove_known(c *check.C) { | |
652 | t := s.Init(c) | 677 | t := s.Init(c) | |
653 | 678 | |||
654 | t.SetupCommandLine("-Wall", "--autofix") | 679 | t.SetupCommandLine("-Wall", "--autofix") | |
655 | G.globalData.InitVartypes() | 680 | G.globalData.InitVartypes() | |
656 | 681 | |||
657 | lines := t.SetupFileLinesContinuation("Makefile", | 682 | lines := t.SetupFileLinesContinuation("Makefile", | |
658 | MkRcsId, | 683 | MkRcsID, | |
659 | "", | 684 | "", | |
660 | "demo: .PHONY", | 685 | "demo: .PHONY", | |
661 | "\t${ECHO} ${WRKSRC:Q}", | 686 | "\t${ECHO} ${WRKSRC:Q}", | |
662 | "\t${ECHO} ${FOODIR:Q}") | 687 | "\t${ECHO} ${FOODIR:Q}") | |
663 | mklines := NewMkLines(lines) | 688 | mklines := NewMkLines(lines) | |
664 | 689 | |||
665 | mklines.Check() | 690 | mklines.Check() | |
666 | 691 | |||
667 | t.CheckOutputLines( | 692 | t.CheckOutputLines( | |
668 | "AUTOFIX: ~/Makefile:4: Replacing \"${WRKSRC:Q}\" with \"${WRKSRC}\".") | 693 | "AUTOFIX: ~/Makefile:4: Replacing \"${WRKSRC:Q}\" with \"${WRKSRC}\".") | |
669 | t.CheckFileLines("Makefile", | 694 | t.CheckFileLines("Makefile", | |
670 | MkRcsId, | 695 | MkRcsID, | |
671 | "", | 696 | "", | |
672 | "demo: .PHONY", | 697 | "demo: .PHONY", | |
673 | "\t${ECHO} ${WRKSRC}", | 698 | "\t${ECHO} ${WRKSRC}", | |
674 | "\t${ECHO} ${FOODIR:Q}") | 699 | "\t${ECHO} ${FOODIR:Q}") | |
675 | } | 700 | } | |
676 | 701 | |||
677 | func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) { | 702 | func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) { | |
678 | t := s.Init(c) | 703 | t := s.Init(c) | |
679 | 704 | |||
680 | t.SetupCommandLine("-Wall") | 705 | t.SetupCommandLine("-Wall") | |
681 | G.globalData.InitVartypes() | 706 | G.globalData.InitVartypes() | |
682 | G.Mk = t.NewMkLines("chat/ircII/Makefile", | 707 | G.Mk = t.NewMkLines("chat/ircII/Makefile", | |
683 | MkRcsId, | 708 | MkRcsID, | |
684 | "CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/man", | 709 | "CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/man", | |
685 | "CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/${PKGMANDIR}") | 710 | "CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/${PKGMANDIR}") | |
686 | 711 | |||
687 | G.Mk.Check() | 712 | G.Mk.Check() | |
688 | 713 | |||
689 | t.CheckOutputLines( | 714 | t.CheckOutputLines( | |
690 | "WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".", | 715 | "WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".", | |
691 | "NOTE: chat/ircII/Makefile:2: This variable value should be aligned to column 25.", | 716 | "NOTE: chat/ircII/Makefile:2: This variable value should be aligned to column 25.", | |
692 | "NOTE: chat/ircII/Makefile:3: This variable value should be aligned to column 25.") | 717 | "NOTE: chat/ircII/Makefile:3: This variable value should be aligned to column 25.") | |
693 | } | 718 | } | |
694 | 719 | |||
695 | func (s *Suite) Test_MkLines_Check__VERSION_as_wordpart_in_MASTER_SITES(c *check.C) { | 720 | func (s *Suite) Test_MkLines_Check__VERSION_as_wordpart_in_MASTER_SITES(c *check.C) { | |
696 | t := s.Init(c) | 721 | t := s.Init(c) | |
697 | 722 | |||
698 | t.SetupCommandLine("-Wall") | 723 | t.SetupCommandLine("-Wall") | |
699 | G.globalData.InitVartypes() | 724 | G.globalData.InitVartypes() | |
700 | mklines := t.NewMkLines("geography/viking/Makefile", | 725 | mklines := t.NewMkLines("geography/viking/Makefile", | |
701 | MkRcsId, | 726 | MkRcsID, | |
702 | "MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=viking/}${VERSION}/") | 727 | "MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=viking/}${VERSION}/") | |
703 | 728 | |||
704 | mklines.Check() | 729 | mklines.Check() | |
705 | 730 | |||
706 | t.CheckOutputLines( | 731 | t.CheckOutputLines( | |
707 | "WARN: geography/viking/Makefile:2: " + | 732 | "WARN: geography/viking/Makefile:2: " + | |
708 | "The list variable MASTER_SITE_SOURCEFORGE should not be embedded in a word.") | 733 | "The list variable MASTER_SITE_SOURCEFORGE should not be embedded in a word.") | |
709 | } | 734 | } | |
710 | 735 | |||
711 | func (s *Suite) Test_MkLines_Check__shell_command_as_wordpart_in_ENV_list(c *check.C) { | 736 | func (s *Suite) Test_MkLines_Check__shell_command_as_wordpart_in_ENV_list(c *check.C) { | |
712 | t := s.Init(c) | 737 | t := s.Init(c) | |
713 | 738 | |||
714 | t.SetupCommandLine("-Wall") | 739 | t.SetupCommandLine("-Wall") | |
715 | G.globalData.InitVartypes() | 740 | G.globalData.InitVartypes() | |
716 | mklines := t.NewMkLines("x11/lablgtk1/Makefile", | 741 | mklines := t.NewMkLines("x11/lablgtk1/Makefile", | |
717 | MkRcsId, | 742 | MkRcsID, | |
718 | "CONFIGURE_ENV+=\tCC=${CC}") | 743 | "CONFIGURE_ENV+=\tCC=${CC}") | |
719 | 744 | |||
720 | mklines.Check() | 745 | mklines.Check() | |
721 | 746 | |||
722 | t.CheckOutputLines( | 747 | t.CheckOutputLines( | |
723 | "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.", | 748 | "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.", | |
724 | "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.") | 749 | "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.") | |
725 | } | 750 | } | |
726 | 751 | |||
727 | func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) { | 752 | func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) { | |
728 | t := s.Init(c) | 753 | t := s.Init(c) | |
729 | 754 | |||
730 | t.SetupCommandLine("-Wall") | 755 | t.SetupCommandLine("-Wall") | |
731 | G.globalData.InitVartypes() | 756 | G.globalData.InitVartypes() | |
732 | mklines := t.NewMkLines("x11/motif/Makefile", | 757 | mklines := t.NewMkLines("x11/motif/Makefile", | |
733 | MkRcsId, | 758 | MkRcsID, | |
734 | "post-patch:", | 759 | "post-patch:", | |
735 | "\tfiles=`${GREP} -l \".fB$${name}.fP(3)\" *.3`") | 760 | "\tfiles=`${GREP} -l \".fB$${name}.fP(3)\" *.3`") | |
736 | 761 | |||
737 | mklines.Check() | 762 | mklines.Check() | |
738 | 763 | |||
739 | // Just ensure that there are no parse errors. | 764 | // Just ensure that there are no parse errors. | |
740 | t.CheckOutputLines( | 765 | t.CheckOutputLines( | |
741 | "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".") | 766 | "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".") | |
742 | } | 767 | } | |
743 | 768 | |||
744 | // See PR 46570, Ctrl+F "3. In lang/perl5". | 769 | // See PR 46570, Ctrl+F "3. In lang/perl5". | |
745 | func (s *Suite) Test_MkLine_VariableType(c *check.C) { | 770 | func (s *Suite) Test_MkLine_VariableType(c *check.C) { | |
746 | mkline := NewMkLine(dummyLine) | 771 | mkline := NewMkLine(dummyLine) | |
747 | 772 | |||
748 | c.Check(mkline.VariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil) | 773 | c.Check(mkline.VariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil) | |
749 | c.Check(mkline.VariableType("SOME_DIR").guessed, equals, true) | 774 | c.Check(mkline.VariableType("SOME_DIR").guessed, equals, true) | |
750 | c.Check(mkline.VariableType("SOMEDIR").guessed, equals, true) | 775 | c.Check(mkline.VariableType("SOMEDIR").guessed, equals, true) | |
751 | } | 776 | } | |
752 | 777 | |||
753 | // PR 51696, security/py-pbkdf2/Makefile, r1.2 | 778 | // PR 51696, security/py-pbkdf2/Makefile, r1.2 | |
754 | func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) { | 779 | func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) { | |
755 | t := s.Init(c) | 780 | t := s.Init(c) | |
756 | 781 | |||
757 | G.globalData.InitVartypes() | 782 | G.globalData.InitVartypes() | |
758 | mklines := t.NewMkLines("Makefile", | 783 | mklines := t.NewMkLines("Makefile", | |
759 | MkRcsId, | 784 | MkRcsID, | |
760 | "COMMENT=\tPKCS#5 v2.0 PBKDF2 Module") | 785 | "COMMENT=\tPKCS#5 v2.0 PBKDF2 Module") | |
761 | 786 | |||
762 | mklines.Check() | 787 | mklines.Check() | |
763 | 788 | |||
764 | t.CheckOutputLines( | 789 | t.CheckOutputLines( | |
765 | "WARN: Makefile:2: The # character starts a comment.") | 790 | "WARN: Makefile:2: The # character starts a comment.") | |
766 | } | 791 | } | |
767 | 792 | |||
768 | func (s *Suite) Test_MkLine_ConditionVars(c *check.C) { | 793 | func (s *Suite) Test_MkLine_ConditionVars(c *check.C) { | |
769 | t := s.Init(c) | 794 | t := s.Init(c) | |
770 | 795 | |||
771 | mkline := t.NewMkLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"") | 796 | mkline := t.NewMkLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"") | |
772 | 797 |
@@ -156,27 +156,27 @@ func (ck MkLineChecker) checkCond(forVar | @@ -156,27 +156,27 @@ func (ck MkLineChecker) checkCond(forVar | |||
156 | } | 156 | } | |
157 | 157 | |||
158 | // Check if any of the value's types is not guessed. | 158 | // Check if any of the value's types is not guessed. | |
159 | guessed := true | 159 | guessed := true | |
160 | for _, value := range splitOnSpace(values) { | 160 | for _, value := range splitOnSpace(values) { | |
161 | if m, vname := match1(value, `^\$\{(.*)\}`); m { | 161 | if m, vname := match1(value, `^\$\{(.*)\}`); m { | |
162 | vartype := mkline.VariableType(vname) | 162 | vartype := mkline.VariableType(vname) | |
163 | if vartype != nil && !vartype.guessed { | 163 | if vartype != nil && !vartype.guessed { | |
164 | guessed = false | 164 | guessed = false | |
165 | } | 165 | } | |
166 | } | 166 | } | |
167 | } | 167 | } | |
168 | 168 | |||
169 | forLoopType := &Vartype{lkSpace, BtUnknown, []AclEntry{{"*", aclpAllRead}}, guessed} | 169 | forLoopType := &Vartype{lkSpace, BtUnknown, []ACLEntry{{"*", aclpAllRead}}, guessed} | |
170 | forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false} | 170 | forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false} | |
171 | for _, forLoopVar := range mkline.ExtractUsedVariables(values) { | 171 | for _, forLoopVar := range mkline.ExtractUsedVariables(values) { | |
172 | ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext) | 172 | ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext) | |
173 | } | 173 | } | |
174 | } | 174 | } | |
175 | 175 | |||
176 | } else if directive == "undef" && args != "" { | 176 | } else if directive == "undef" && args != "" { | |
177 | for _, uvar := range splitOnSpace(args) { | 177 | for _, uvar := range splitOnSpace(args) { | |
178 | if forVars[uvar] { | 178 | if forVars[uvar] { | |
179 | mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.") | 179 | mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.") | |
180 | } | 180 | } | |
181 | } | 181 | } | |
182 | } | 182 | } | |
@@ -246,27 +246,27 @@ func (ck MkLineChecker) checkVarassignDe | @@ -246,27 +246,27 @@ func (ck MkLineChecker) checkVarassignDe | |||
246 | 246 | |||
247 | mkline := ck.MkLine | 247 | mkline := ck.MkLine | |
248 | varname := mkline.Varname() | 248 | varname := mkline.Varname() | |
249 | op := mkline.Op() | 249 | op := mkline.Op() | |
250 | vartype := mkline.VariableType(varname) | 250 | vartype := mkline.VariableType(varname) | |
251 | if vartype == nil { | 251 | if vartype == nil { | |
252 | if trace.Tracing { | 252 | if trace.Tracing { | |
253 | trace.Step1("No type definition found for %q.", varname) | 253 | trace.Step1("No type definition found for %q.", varname) | |
254 | } | 254 | } | |
255 | return | 255 | return | |
256 | } | 256 | } | |
257 | 257 | |||
258 | perms := vartype.EffectivePermissions(mkline.Filename) | 258 | perms := vartype.EffectivePermissions(mkline.Filename) | |
259 | var needed AclPermissions | 259 | var needed ACLPermissions | |
260 | switch op { | 260 | switch op { | |
261 | case opAssign, opAssignShell, opAssignEval: | 261 | case opAssign, opAssignShell, opAssignEval: | |
262 | needed = aclpSet | 262 | needed = aclpSet | |
263 | case opAssignDefault: | 263 | case opAssignDefault: | |
264 | needed = aclpSetDefault | 264 | needed = aclpSetDefault | |
265 | case opAssignAppend: | 265 | case opAssignAppend: | |
266 | needed = aclpAppend | 266 | needed = aclpAppend | |
267 | } | 267 | } | |
268 | 268 | |||
269 | switch { | 269 | switch { | |
270 | case perms.Contains(needed): | 270 | case perms.Contains(needed): | |
271 | break | 271 | break | |
272 | case perms == aclpUnknown: | 272 | case perms == aclpUnknown: | |
@@ -492,69 +492,78 @@ func (ck MkLineChecker) checkVaruseFor(v | @@ -492,69 +492,78 @@ func (ck MkLineChecker) checkVaruseFor(v | |||
492 | if false && // Too many false positives | 492 | if false && // Too many false positives | |
493 | vartype != nil && | 493 | vartype != nil && | |
494 | vartype.kindOfList != lkSpace && | 494 | vartype.kindOfList != lkSpace && | |
495 | needsQuoting != nqDoesntMatter { | 495 | needsQuoting != nqDoesntMatter { | |
496 | ck.MkLine.Warnf("The variable %s should not be used in .for loops.", varname) | 496 | ck.MkLine.Warnf("The variable %s should not be used in .for loops.", varname) | |
497 | Explain( | 497 | Explain( | |
498 | "The .for loop splits its argument at sequences of white-space, as", | 498 | "The .for loop splits its argument at sequences of white-space, as", | |
499 | "opposed to all other places in make(1), which act like the shell.", | 499 | "opposed to all other places in make(1), which act like the shell.", | |
500 | "Therefore only variables that are split at whitespace or don't", | 500 | "Therefore only variables that are split at whitespace or don't", | |
501 | "contain any special characters should be used here.") | 501 | "contain any special characters should be used here.") | |
502 | } | 502 | } | |
503 | } | 503 | } | |
504 | 504 | |||
505 | // CheckVaruseShellword checks whether a variable use of the form ${VAR} | |||
506 | // or ${VAR:Modifier} is allowed in a certain context. | |||
505 | func (ck MkLineChecker) CheckVaruseShellword(varname string, vartype *Vartype, vuc *VarUseContext, mod string, needsQuoting NeedsQuoting) { | 507 | func (ck MkLineChecker) CheckVaruseShellword(varname string, vartype *Vartype, vuc *VarUseContext, mod string, needsQuoting NeedsQuoting) { | |
506 | if trace.Tracing { | 508 | if trace.Tracing { | |
507 | defer trace.Call(varname, vartype, vuc, mod, needsQuoting)() | 509 | defer trace.Call(varname, vartype, vuc, mod, needsQuoting)() | |
508 | } | 510 | } | |
509 | 511 | |||
510 | // In GNU configure scripts, a few variables need to be | 512 | // In GNU configure scripts, a few variables need to be | |
511 | // passed through the :M* operator before they reach the | 513 | // passed through the :M* operator before they reach the | |
512 | // configure scripts. | 514 | // configure scripts. | |
513 | // | 515 | // | |
514 | // When doing checks outside a package, the :M* operator is needed for safety. | 516 | // When doing checks outside a package, the :M* operator is needed for safety. | |
515 | needMstar := matches(varname, `^(?:.*_)?(?:CFLAGS||CPPFLAGS|CXXFLAGS|FFLAGS|LDFLAGS|LIBS)$`) && | 517 | needMstar := matches(varname, `^(?:.*_)?(?:CFLAGS||CPPFLAGS|CXXFLAGS|FFLAGS|LDFLAGS|LIBS)$`) && | |
516 | (G.Pkg == nil || G.Pkg.vardef["GNU_CONFIGURE"] != nil) | 518 | (G.Pkg == nil || G.Pkg.vardef["GNU_CONFIGURE"] != nil) | |
517 | 519 | |||
518 | strippedMod := mod | 520 | strippedMod := mod | |
519 | if m, stripped := match1(mod, `(.*?)(?::M\*)?(?::Q)?$`); m { | 521 | if m, stripped := match1(mod, `(.*?)(?::M\*)?(?::Q)?$`); m { | |
520 | strippedMod = stripped | 522 | strippedMod = stripped | |
521 | } | 523 | } | |
522 | 524 | |||
523 | mkline := ck.MkLine | 525 | mkline := ck.MkLine | |
524 | if mod == ":M*:Q" && !needMstar { | 526 | if mod == ":M*:Q" && !needMstar { | |
525 | mkline.Notef("The :M* modifier is not needed here.") | 527 | mkline.Notef("The :M* modifier is not needed here.") | |
526 | 528 | |||
527 | } else if needsQuoting == nqYes { | 529 | } else if needsQuoting == nqYes { | |
528 | correctMod := strippedMod + ifelseStr(needMstar, ":M*:Q", ":Q") | 530 | correctMod := strippedMod + ifelseStr(needMstar, ":M*:Q", ":Q") | |
529 | if correctMod == mod+":Q" && vuc.IsWordPart && !vartype.IsShell() { | 531 | if correctMod == mod+":Q" && vuc.IsWordPart && !vartype.IsShell() { | |
530 | mkline.Warnf("The list variable %s should not be embedded in a word.", varname) | 532 | if vartype.IsConsideredList() { | |
531 | Explain( | 533 | mkline.Warnf("The list variable %s should not be embedded in a word.", varname) | |
532 | "When a list variable has multiple elements, this expression expands", | 534 | Explain( | |
533 | "to something unexpected:", | 535 | "When a list variable has multiple elements, this expression expands", | |
534 | "", | 536 | "to something unexpected:", | |
535 | "Example: ${MASTER_SITE_SOURCEFORGE}directory/ expands to", | 537 | "", | |
536 | "", | 538 | "Example: ${MASTER_SITE_SOURCEFORGE}directory/ expands to", | |
537 | "\thttps://mirror1.sf.net/ https://mirror2.sf.net/directory/", | 539 | "", | |
538 | "", | 540 | "\thttps://mirror1.sf.net/ https://mirror2.sf.net/directory/", | |
539 | "The first URL is missing the directory. To fix this, write", | 541 | "", | |
540 | "\t${MASTER_SITE_SOURCEFORGE:=directory/}.", | 542 | "The first URL is missing the directory. To fix this, write", | |
541 | "", | 543 | "\t${MASTER_SITE_SOURCEFORGE:=directory/}.", | |
542 | "Example: -l${LIBS} expands to", | 544 | "", | |
543 | "", | 545 | "Example: -l${LIBS} expands to", | |
544 | "\t-llib1 lib2", | 546 | "", | |
545 | "", | 547 | "\t-llib1 lib2", | |
546 | "The second library is missing the -l. To fix this, write", | 548 | "", | |
547 | "${LIBS:@lib@-l${lib}@}.") | 549 | "The second library is missing the -l. To fix this, write", | |
550 | "${LIBS:@lib@-l${lib}@}.") | |||
551 | } else { | |||
552 | mkline.Warnf("The variable %s should be quoted as part of a shell word.", varname) | |||
553 | Explain( | |||
554 | "This variable can contain spaces or other special characters.", | |||
555 | "Therefore it should be quoted by replacing ${VAR} with ${VAR:Q}.") | |||
556 | } | |||
548 | 557 | |||
549 | } else if mod != correctMod { | 558 | } else if mod != correctMod { | |
550 | if vuc.quoting == vucQuotPlain { | 559 | if vuc.quoting == vucQuotPlain { | |
551 | fix := mkline.Line.Autofix() | 560 | fix := mkline.Line.Autofix() | |
552 | fix.Warnf("Please use ${%s%s} instead of ${%s%s}.", varname, correctMod, varname, mod) | 561 | fix.Warnf("Please use ${%s%s} instead of ${%s%s}.", varname, correctMod, varname, mod) | |
553 | fix.Replace("${"+varname+mod+"}", "${"+varname+correctMod+"}") | 562 | fix.Replace("${"+varname+mod+"}", "${"+varname+correctMod+"}") | |
554 | fix.Apply() | 563 | fix.Apply() | |
555 | } else { | 564 | } else { | |
556 | mkline.Warnf("Please use ${%s%s} instead of ${%s%s} and make sure"+ | 565 | mkline.Warnf("Please use ${%s%s} instead of ${%s%s} and make sure"+ | |
557 | " the variable appears outside of any quoting characters.", varname, correctMod, varname, mod) | 566 | " the variable appears outside of any quoting characters.", varname, correctMod, varname, mod) | |
558 | } | 567 | } | |
559 | Explain( | 568 | Explain( | |
560 | "See the pkgsrc guide, section \"quoting guideline\", for details.") | 569 | "See the pkgsrc guide, section \"quoting guideline\", for details.") | |
@@ -773,37 +782,26 @@ func (ck MkLineChecker) checkVarassignVa | @@ -773,37 +782,26 @@ func (ck MkLineChecker) checkVarassignVa | |||
773 | func (ck MkLineChecker) checkVarassignSpecific() { | 782 | func (ck MkLineChecker) checkVarassignSpecific() { | |
774 | mkline := ck.MkLine | 783 | mkline := ck.MkLine | |
775 | varname := mkline.Varname() | 784 | varname := mkline.Varname() | |
776 | value := mkline.Value() | 785 | value := mkline.Value() | |
777 | 786 | |||
778 | if contains(value, "/etc/rc.d") { | 787 | if contains(value, "/etc/rc.d") { | |
779 | mkline.Warnf("Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.") | 788 | mkline.Warnf("Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.") | |
780 | } | 789 | } | |
781 | 790 | |||
782 | if hasPrefix(varname, "_") && !G.Infrastructure { | 791 | if hasPrefix(varname, "_") && !G.Infrastructure { | |
783 | mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", varname) | 792 | mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", varname) | |
784 | } | 793 | } | |
785 | 794 | |||
786 | if varname == "PERL5_PACKLIST" && G.Pkg != nil { | |||
787 | if m, p5pkgname := match1(G.Pkg.EffectivePkgbase, `^p5-(.*)`); m { | |||
788 | guess := "auto/" + strings.Replace(p5pkgname, "-", "/", -1) + "/.packlist" | |||
789 | ||||
790 | ucvalue, ucguess := strings.ToUpper(value), strings.ToUpper(guess) | |||
791 | if ucvalue != ucguess && ucvalue != "${PERL5_SITEARCH}/"+ucguess { | |||
792 | mkline.Warnf("Unusual value for PERL5_PACKLIST -- %q expected.", guess) | |||
793 | } | |||
794 | } | |||
795 | } | |||
796 | ||||
797 | if varname == "PYTHON_VERSIONS_ACCEPTED" { | 795 | if varname == "PYTHON_VERSIONS_ACCEPTED" { | |
798 | ck.checkVarassignPythonVersions(varname, value) | 796 | ck.checkVarassignPythonVersions(varname, value) | |
799 | } | 797 | } | |
800 | 798 | |||
801 | if mkline.VarassignComment() == "# defined" && !hasSuffix(varname, "_MK") && !hasSuffix(varname, "_COMMON") { | 799 | if mkline.VarassignComment() == "# defined" && !hasSuffix(varname, "_MK") && !hasSuffix(varname, "_COMMON") { | |
802 | mkline.Notef("Please use \"# empty\", \"# none\" or \"yes\" instead of \"# defined\".") | 800 | mkline.Notef("Please use \"# empty\", \"# none\" or \"yes\" instead of \"# defined\".") | |
803 | Explain( | 801 | Explain( | |
804 | "The value #defined says something about the state of the variable,", | 802 | "The value #defined says something about the state of the variable,", | |
805 | "but not what that _means_. In some cases a variable that is defined", | 803 | "but not what that _means_. In some cases a variable that is defined", | |
806 | "means \"yes\", in other cases it is an empty list (which is also", | 804 | "means \"yes\", in other cases it is an empty list (which is also", | |
807 | "only the state of the variable), whose meaning could be described", | 805 | "only the state of the variable), whose meaning could be described", | |
808 | "with \"none\". It is this meaning that should be described.") | 806 | "with \"none\". It is this meaning that should be described.") | |
809 | } | 807 | } |
@@ -213,27 +213,27 @@ func (s *Suite) Test_MkParser_MkCond(c * | @@ -213,27 +213,27 @@ func (s *Suite) Test_MkParser_MkCond(c * | |||
213 | 213 | |||
214 | // Errors | 214 | // Errors | |
215 | checkRest("!empty(PKG_OPTIONS:Msndfile) || defined(PKG_OPTIONS:Msamplerate)", | 215 | checkRest("!empty(PKG_OPTIONS:Msndfile) || defined(PKG_OPTIONS:Msamplerate)", | |
216 | NewTree("not", NewTree("empty", varuse("PKG_OPTIONS", "Msndfile"))), | 216 | NewTree("not", NewTree("empty", varuse("PKG_OPTIONS", "Msndfile"))), | |
217 | " || defined(PKG_OPTIONS:Msamplerate)") | 217 | " || defined(PKG_OPTIONS:Msamplerate)") | |
218 | } | 218 | } | |
219 | 219 | |||
220 | func (s *Suite) Test_MkParser__varuse_parentheses_autofix(c *check.C) { | 220 | func (s *Suite) Test_MkParser__varuse_parentheses_autofix(c *check.C) { | |
221 | t := s.Init(c) | 221 | t := s.Init(c) | |
222 | 222 | |||
223 | t.SetupCommandLine("--autofix") | 223 | t.SetupCommandLine("--autofix") | |
224 | G.globalData.InitVartypes() | 224 | G.globalData.InitVartypes() | |
225 | lines := t.SetupFileLines("Makefile", | 225 | lines := t.SetupFileLines("Makefile", | |
226 | MkRcsId, | 226 | MkRcsID, | |
227 | "COMMENT=$(P1) $(P2)) $(P3:Q) ${BRACES}") | 227 | "COMMENT=$(P1) $(P2)) $(P3:Q) ${BRACES}") | |
228 | mklines := NewMkLines(lines) | 228 | mklines := NewMkLines(lines) | |
229 | 229 | |||
230 | mklines.Check() | 230 | mklines.Check() | |
231 | 231 | |||
232 | t.CheckOutputLines( | 232 | t.CheckOutputLines( | |
233 | "AUTOFIX: ~/Makefile:2: Replacing \"$(P1)\" with \"${P1}\".", | 233 | "AUTOFIX: ~/Makefile:2: Replacing \"$(P1)\" with \"${P1}\".", | |
234 | "AUTOFIX: ~/Makefile:2: Replacing \"$(P2)\" with \"${P2}\".", | 234 | "AUTOFIX: ~/Makefile:2: Replacing \"$(P2)\" with \"${P2}\".", | |
235 | "AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".") | 235 | "AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".") | |
236 | t.CheckFileLines("Makefile", | 236 | t.CheckFileLines("Makefile", | |
237 | MkRcsId, | 237 | MkRcsID, | |
238 | "COMMENT=${P1} ${P2}) ${P3:Q} ${BRACES}") | 238 | "COMMENT=${P1} ${P2}) ${P3:Q} ${BRACES}") | |
239 | } | 239 | } |
@@ -25,27 +25,27 @@ func CheckdirToplevel() { | @@ -25,27 +25,27 @@ func CheckdirToplevel() { | |||
25 | for _, line := range lines { | 25 | for _, line := range lines { | |
26 | if m, commentedOut, indentation, subdir, comment := match4(line.Text, `^(#?)SUBDIR\s*\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m { | 26 | if m, commentedOut, indentation, subdir, comment := match4(line.Text, `^(#?)SUBDIR\s*\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m { | |
27 | ctx.checkSubdir(line, commentedOut == "#", indentation, subdir, comment) | 27 | ctx.checkSubdir(line, commentedOut == "#", indentation, subdir, comment) | |
28 | } | 28 | } | |
29 | } | 29 | } | |
30 | 30 | |||
31 | NewMkLines(lines).Check() | 31 | NewMkLines(lines).Check() | |
32 | 32 | |||
33 | if G.opts.Recursive { | 33 | if G.opts.Recursive { | |
34 | if G.opts.CheckGlobal { | 34 | if G.opts.CheckGlobal { | |
35 | G.UsedLicenses = make(map[string]bool) | 35 | G.UsedLicenses = make(map[string]bool) | |
36 | G.Hash = make(map[string]*Hash) | 36 | G.Hash = make(map[string]*Hash) | |
37 | } | 37 | } | |
38 | G.Todo = append(G.Todo, ctx.subdirs...) | 38 | G.Todo = append(append([]string(nil), ctx.subdirs...), G.Todo...) | |
39 | } | 39 | } | |
40 | } | 40 | } | |
41 | 41 | |||
42 | func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subdir, comment string) { | 42 | func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subdir, comment string) { | |
43 | if commentedOut && comment == "" { | 43 | if commentedOut && comment == "" { | |
44 | line.Warnf("%q commented out without giving a reason.", subdir) | 44 | line.Warnf("%q commented out without giving a reason.", subdir) | |
45 | } | 45 | } | |
46 | 46 | |||
47 | if indentation != "\t" { | 47 | if indentation != "\t" { | |
48 | line.Warnf("Indentation should be a single tab character.") | 48 | line.Warnf("Indentation should be a single tab character.") | |
49 | } | 49 | } | |
50 | 50 | |||
51 | if contains(subdir, "$") || !fileExists(G.CurrentDir+"/"+subdir+"/Makefile") { | 51 | if contains(subdir, "$") || !fileExists(G.CurrentDir+"/"+subdir+"/Makefile") { |
@@ -1,22 +1,22 @@ | @@ -1,22 +1,22 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import "gopkg.in/check.v1" | 3 | import "gopkg.in/check.v1" | |
4 | 4 | |||
5 | func (s *Suite) Test_CheckdirToplevel(c *check.C) { | 5 | func (s *Suite) Test_CheckdirToplevel(c *check.C) { | |
6 | t := s.Init(c) | 6 | t := s.Init(c) | |
7 | 7 | |||
8 | t.SetupFileLines("Makefile", | 8 | t.SetupFileLines("Makefile", | |
9 | MkRcsId, | 9 | MkRcsID, | |
10 | "", | 10 | "", | |
11 | "SUBDIR+= x11", | 11 | "SUBDIR+= x11", | |
12 | "SUBDIR+=\tarchivers", | 12 | "SUBDIR+=\tarchivers", | |
13 | "SUBDIR+=\tccc", | 13 | "SUBDIR+=\tccc", | |
14 | "SUBDIR+=\tccc", | 14 | "SUBDIR+=\tccc", | |
15 | "#SUBDIR+=\tignoreme", | 15 | "#SUBDIR+=\tignoreme", | |
16 | "SUBDIR+=\tnonexisting", // This doesn't happen in practice, therefore no warning. | 16 | "SUBDIR+=\tnonexisting", // This doesn't happen in practice, therefore no warning. | |
17 | "SUBDIR+=\tbbb") | 17 | "SUBDIR+=\tbbb") | |
18 | t.SetupFileLines("archivers/Makefile") | 18 | t.SetupFileLines("archivers/Makefile") | |
19 | t.SetupFileLines("bbb/Makefile") | 19 | t.SetupFileLines("bbb/Makefile") | |
20 | t.SetupFileLines("ccc/Makefile") | 20 | t.SetupFileLines("ccc/Makefile") | |
21 | t.SetupFileLines("x11/Makefile") | 21 | t.SetupFileLines("x11/Makefile") | |
22 | G.globalData.InitVartypes() | 22 | G.globalData.InitVartypes() |
@@ -126,27 +126,27 @@ func (s *Suite) Test_MkLineChecker_Check | @@ -126,27 +126,27 @@ func (s *Suite) Test_MkLineChecker_Check | |||
126 | "earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb "+ | 126 | "earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb "+ | |
127 | "earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 "+ | 127 | "earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 "+ | |
128 | "m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax "+ | 128 | "m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax "+ | |
129 | "powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+ | 129 | "powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+ | |
130 | "} for MACHINE_ARCH.") | 130 | "} for MACHINE_ARCH.") | |
131 | } | 131 | } | |
132 | 132 | |||
133 | func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) { | 133 | func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) { | |
134 | t := s.Init(c) | 134 | t := s.Init(c) | |
135 | 135 | |||
136 | G.globalData.InitVartypes() | 136 | G.globalData.InitVartypes() | |
137 | 137 | |||
138 | G.Mk = t.NewMkLines("Makefile", | 138 | G.Mk = t.NewMkLines("Makefile", | |
139 | MkRcsId, | 139 | MkRcsID, | |
140 | "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8 | 140 | "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8 | |
141 | 141 | |||
142 | MkLineChecker{G.Mk.mklines[1]}.checkVarassign() | 142 | MkLineChecker{G.Mk.mklines[1]}.checkVarassign() | |
143 | 143 | |||
144 | t.CheckOutputLines( | 144 | t.CheckOutputLines( | |
145 | "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?") | 145 | "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?") | |
146 | } | 146 | } | |
147 | 147 | |||
148 | func (s *Suite) Test_MkLineChecker_checkVarassignDefPermissions(c *check.C) { | 148 | func (s *Suite) Test_MkLineChecker_checkVarassignDefPermissions(c *check.C) { | |
149 | t := s.Init(c) | 149 | t := s.Init(c) | |
150 | 150 | |||
151 | t.SetupCommandLine("-Wall") | 151 | t.SetupCommandLine("-Wall") | |
152 | G.globalData.InitVartypes() | 152 | G.globalData.InitVartypes() | |
@@ -154,51 +154,51 @@ func (s *Suite) Test_MkLineChecker_check | @@ -154,51 +154,51 @@ func (s *Suite) Test_MkLineChecker_check | |||
154 | 154 | |||
155 | MkLineChecker{mkline}.checkVarassignDefPermissions() | 155 | MkLineChecker{mkline}.checkVarassignDefPermissions() | |
156 | 156 | |||
157 | t.CheckOutputLines( | 157 | t.CheckOutputLines( | |
158 | "WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.") | 158 | "WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.") | |
159 | } | 159 | } | |
160 | 160 | |||
161 | func (s *Suite) Test_MkLineChecker_CheckVarusePermissions(c *check.C) { | 161 | func (s *Suite) Test_MkLineChecker_CheckVarusePermissions(c *check.C) { | |
162 | t := s.Init(c) | 162 | t := s.Init(c) | |
163 | 163 | |||
164 | t.SetupCommandLine("-Wall") | 164 | t.SetupCommandLine("-Wall") | |
165 | G.globalData.InitVartypes() | 165 | G.globalData.InitVartypes() | |
166 | mklines := t.NewMkLines("options.mk", | 166 | mklines := t.NewMkLines("options.mk", | |
167 | MkRcsId, | 167 | MkRcsID, | |
168 | "COMMENT=\t${GAMES_USER}", | 168 | "COMMENT=\t${GAMES_USER}", | |
169 | "COMMENT:=\t${PKGBASE}", | 169 | "COMMENT:=\t${PKGBASE}", | |
170 | "PYPKGPREFIX=${PKGBASE}") | 170 | "PYPKGPREFIX=${PKGBASE}") | |
171 | G.globalData.UserDefinedVars = map[string]MkLine{ | 171 | G.globalData.UserDefinedVars = map[string]MkLine{ | |
172 | "GAMES_USER": mklines.mklines[0], | 172 | "GAMES_USER": mklines.mklines[0], | |
173 | } | 173 | } | |
174 | 174 | |||
175 | mklines.Check() | 175 | mklines.Check() | |
176 | 176 | |||
177 | t.CheckOutputLines( | 177 | t.CheckOutputLines( | |
178 | "WARN: options.mk:2: The user-defined variable GAMES_USER is used but not added to BUILD_DEFS.", | 178 | "WARN: options.mk:2: The user-defined variable GAMES_USER is used but not added to BUILD_DEFS.", | |
179 | "WARN: options.mk:3: PKGBASE should not be evaluated at load time.", | 179 | "WARN: options.mk:3: PKGBASE should not be evaluated at load time.", | |
180 | "WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.", | 180 | "WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.", | |
181 | "WARN: options.mk:4: PKGBASE should not be evaluated indirectly at load time.", | 181 | "WARN: options.mk:4: PKGBASE should not be evaluated indirectly at load time.", | |
182 | "NOTE: options.mk:4: This variable value should be aligned to column 17.") | 182 | "NOTE: options.mk:4: This variable value should be aligned to column 17.") | |
183 | } | 183 | } | |
184 | 184 | |||
185 | func (s *Suite) Test_MkLineChecker_CheckVarusePermissions__load_time(c *check.C) { | 185 | func (s *Suite) Test_MkLineChecker_CheckVarusePermissions__load_time(c *check.C) { | |
186 | t := s.Init(c) | 186 | t := s.Init(c) | |
187 | 187 | |||
188 | t.SetupCommandLine("-Wall") | 188 | t.SetupCommandLine("-Wall") | |
189 | G.globalData.InitVartypes() | 189 | G.globalData.InitVartypes() | |
190 | mklines := t.NewMkLines("options.mk", | 190 | mklines := t.NewMkLines("options.mk", | |
191 | MkRcsId, | 191 | MkRcsID, | |
192 | "WRKSRC:=${.CURDIR}") | 192 | "WRKSRC:=${.CURDIR}") | |
193 | 193 | |||
194 | mklines.Check() | 194 | mklines.Check() | |
195 | 195 | |||
196 | // Don't warn that ".CURDIR should not be evaluated at load time." | 196 | // Don't warn that ".CURDIR should not be evaluated at load time." | |
197 | t.CheckOutputLines( | 197 | t.CheckOutputLines( | |
198 | "NOTE: options.mk:2: This variable value should be aligned to column 17.") | 198 | "NOTE: options.mk:2: This variable value should be aligned to column 17.") | |
199 | } | 199 | } | |
200 | 200 | |||
201 | func (s *Suite) Test_MkLineChecker_WarnVaruseLocalbase(c *check.C) { | 201 | func (s *Suite) Test_MkLineChecker_WarnVaruseLocalbase(c *check.C) { | |
202 | t := s.Init(c) | 202 | t := s.Init(c) | |
203 | 203 | |||
204 | mkline := t.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}") | 204 | mkline := t.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}") | |
@@ -247,109 +247,134 @@ func (s *Suite) Test_MkLineChecker__Varu | @@ -247,109 +247,134 @@ func (s *Suite) Test_MkLineChecker__Varu | |||
247 | 247 | |||
248 | MkLineChecker{G.Mk.mklines[0]}.Check() | 248 | MkLineChecker{G.Mk.mklines[0]}.Check() | |
249 | 249 | |||
250 | // Don't warn that ${XKBBASE}/xkbcomp is used but not defined. | 250 | // Don't warn that ${XKBBASE}/xkbcomp is used but not defined. | |
251 | t.CheckOutputEmpty() | 251 | t.CheckOutputEmpty() | |
252 | } | 252 | } | |
253 | 253 | |||
254 | func (s *Suite) Test_MkLineChecker_CheckCond__comparison_with_shell_command(c *check.C) { | 254 | func (s *Suite) Test_MkLineChecker_CheckCond__comparison_with_shell_command(c *check.C) { | |
255 | t := s.Init(c) | 255 | t := s.Init(c) | |
256 | 256 | |||
257 | t.SetupCommandLine("-Wall") | 257 | t.SetupCommandLine("-Wall") | |
258 | G.globalData.InitVartypes() | 258 | G.globalData.InitVartypes() | |
259 | G.Mk = t.NewMkLines("security/openssl/Makefile", | 259 | G.Mk = t.NewMkLines("security/openssl/Makefile", | |
260 | MkRcsId, | 260 | MkRcsID, | |
261 | ".if ${PKGSRC_COMPILER} == \"gcc\" && ${CC} == \"cc\"", | 261 | ".if ${PKGSRC_COMPILER} == \"gcc\" && ${CC} == \"cc\"", | |
262 | ".endif") | 262 | ".endif") | |
263 | 263 | |||
264 | G.Mk.Check() | 264 | G.Mk.Check() | |
265 | 265 | |||
266 | // Don't warn about unknown shell command "cc". | 266 | // Don't warn about unknown shell command "cc". | |
267 | t.CheckOutputLines( | 267 | t.CheckOutputLines( | |
268 | "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.") | 268 | "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.") | |
269 | } | 269 | } | |
270 | 270 | |||
271 | func (s *Suite) Test_MkLine_CheckCond_comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) { | 271 | func (s *Suite) Test_MkLine_CheckCond_comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) { | |
272 | t := s.Init(c) | 272 | t := s.Init(c) | |
273 | 273 | |||
274 | t.SetupCommandLine("-Wall") | 274 | t.SetupCommandLine("-Wall") | |
275 | G.globalData.InitVartypes() | 275 | G.globalData.InitVartypes() | |
276 | G.Mk = t.NewMkLines("audio/pulseaudio/Makefile", | 276 | G.Mk = t.NewMkLines("audio/pulseaudio/Makefile", | |
277 | MkRcsId, | 277 | MkRcsID, | |
278 | ".if ${OPSYS} == \"Darwin\" && ${PKGSRC_COMPILER} == \"clang\"", | 278 | ".if ${OPSYS} == \"Darwin\" && ${PKGSRC_COMPILER} == \"clang\"", | |
279 | ".endif") | 279 | ".endif") | |
280 | 280 | |||
281 | G.Mk.Check() | 281 | G.Mk.Check() | |
282 | 282 | |||
283 | t.CheckOutputLines( | 283 | t.CheckOutputLines( | |
284 | "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.") | 284 | "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.") | |
285 | } | 285 | } | |
286 | 286 | |||
287 | func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS_with_backticks(c *check.C) { | 287 | func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS_with_backticks(c *check.C) { | |
288 | t := s.Init(c) | 288 | t := s.Init(c) | |
289 | 289 | |||
290 | t.SetupCommandLine("-Wall") | 290 | t.SetupCommandLine("-Wall") | |
291 | G.globalData.InitVartypes() | 291 | G.globalData.InitVartypes() | |
292 | G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile", | 292 | G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile", | |
293 | MkRcsId, | 293 | MkRcsID, | |
294 | "CFLAGS+=\t`pkg-config pidgin --cflags`") | 294 | "CFLAGS+=\t`pkg-config pidgin --cflags`") | |
295 | mkline := G.Mk.mklines[1] | 295 | mkline := G.Mk.mklines[1] | |
296 | 296 | |||
297 | words, rest := splitIntoMkWords(mkline.Line, mkline.Value()) | 297 | words, rest := splitIntoMkWords(mkline.Line, mkline.Value()) | |
298 | 298 | |||
299 | c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"}) | 299 | c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"}) | |
300 | c.Check(rest, equals, "") | 300 | c.Check(rest, equals, "") | |
301 | 301 | |||
302 | MkLineChecker{G.Mk.mklines[1]}.CheckVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "") | 302 | MkLineChecker{G.Mk.mklines[1]}.CheckVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "") | |
303 | 303 | |||
304 | // No warning about "`pkg-config" being an unknown CFlag. | 304 | // No warning about "`pkg-config" being an unknown CFlag. | |
305 | t.CheckOutputEmpty() | 305 | t.CheckOutputEmpty() | |
306 | } | 306 | } | |
307 | 307 | |||
308 | // See PR 46570, Ctrl+F "4. Shell quoting". | 308 | // See PR 46570, Ctrl+F "4. Shell quoting". | |
309 | // Pkglint is correct, since the shell sees this definition for | 309 | // Pkglint is correct, since the shell sees this definition for | |
310 | // CPPFLAGS as three words, not one word. | 310 | // CPPFLAGS as three words, not one word. | |
311 | func (s *Suite) Test_MkLineChecker_CheckVartype_CFLAGS(c *check.C) { | 311 | func (s *Suite) Test_MkLineChecker_CheckVartype_CFLAGS(c *check.C) { | |
312 | t := s.Init(c) | 312 | t := s.Init(c) | |
313 | 313 | |||
314 | G.globalData.InitVartypes() | 314 | G.globalData.InitVartypes() | |
315 | mklines := t.NewMkLines("Makefile", | 315 | mklines := t.NewMkLines("Makefile", | |
316 | MkRcsId, | 316 | MkRcsID, | |
317 | "CPPFLAGS.SunOS+=\t-DPIPECOMMAND=\\\"/usr/sbin/sendmail -bs %s\\\"") | 317 | "CPPFLAGS.SunOS+=\t-DPIPECOMMAND=\\\"/usr/sbin/sendmail -bs %s\\\"") | |
318 | 318 | |||
319 | mklines.Check() | 319 | mklines.Check() | |
320 | 320 | |||
321 | t.CheckOutputLines( | 321 | t.CheckOutputLines( | |
322 | "WARN: Makefile:2: Unknown compiler flag \"-bs\".", | 322 | "WARN: Makefile:2: Unknown compiler flag \"-bs\".", | |
323 | "WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.") | 323 | "WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.") | |
324 | } | 324 | } | |
325 | 325 | |||
326 | // Up to 2018-01-28, pkglint applied the autofix also to the continuation | 326 | // Up to 2018-01-28, pkglint applied the autofix also to the continuation | |
327 | // lines, which is incorrect. It replaced the dot in "4.*" with spaces. | 327 | // lines, which is incorrect. It replaced the dot in "4.*" with spaces. | |
328 | func (s *Suite) Test_MkLineChecker_checkDirectiveIndentation_autofix(c *check.C) { | 328 | func (s *Suite) Test_MkLineChecker_checkDirectiveIndentation_autofix(c *check.C) { | |
329 | t := s.Init(c) | 329 | t := s.Init(c) | |
330 | 330 | |||
331 | t.SetupCommandLine("-Wall", "--autofix") | 331 | t.SetupCommandLine("-Wall", "--autofix") | |
332 | G.globalData.InitVartypes() | 332 | G.globalData.InitVartypes() | |
333 | lines := t.SetupFileLinesContinuation("options.mk", | 333 | lines := t.SetupFileLinesContinuation("options.mk", | |
334 | MkRcsId, | 334 | MkRcsID, | |
335 | ".if ${PKGNAME} == pkgname", | 335 | ".if ${PKGNAME} == pkgname", | |
336 | ".if \\", | 336 | ".if \\", | |
337 | " ${PLATFORM:MNetBSD-4.*}", | 337 | " ${PLATFORM:MNetBSD-4.*}", | |
338 | ".endif", | 338 | ".endif", | |
339 | ".endif") | 339 | ".endif") | |
340 | mklines := NewMkLines(lines) | 340 | mklines := NewMkLines(lines) | |
341 | 341 | |||
342 | mklines.Check() | 342 | mklines.Check() | |
343 | 343 | |||
344 | t.CheckOutputLines( | 344 | t.CheckOutputLines( | |
345 | "AUTOFIX: ~/options.mk:3: Replacing \".\" with \". \".", | 345 | "AUTOFIX: ~/options.mk:3: Replacing \".\" with \". \".", | |
346 | "AUTOFIX: ~/options.mk:5: Replacing \".\" with \". \".") | 346 | "AUTOFIX: ~/options.mk:5: Replacing \".\" with \". \".") | |
347 | 347 | |||
348 | t.CheckFileLines("options.mk", | 348 | t.CheckFileLines("options.mk", | |
349 | MkRcsId, | 349 | MkRcsID, | |
350 | ".if ${PKGNAME} == pkgname", | 350 | ".if ${PKGNAME} == pkgname", | |
351 | ". if \\", | 351 | ". if \\", | |
352 | " ${PLATFORM:MNetBSD-4.*}", | 352 | " ${PLATFORM:MNetBSD-4.*}", | |
353 | ". endif", | 353 | ". endif", | |
354 | ".endif") | 354 | ".endif") | |
355 | } | 355 | } | |
356 | ||||
357 | func (s *Suite) Test_MkLineChecker_CheckVaruseShellword(c *check.C) { | |||
358 | t := s.Init(c) | |||
359 | ||||
360 | t.SetupCommandLine("-Wall") | |||
361 | G.globalData.InitVartypes() | |||
362 | lines := t.SetupFileLinesContinuation("options.mk", | |||
363 | MkRcsID, | |||
364 | "GOPATH=\t${WRKDIR}", | |||
365 | "do-build:", | |||
366 | "\tcd ${WRKSRC} && GOPATH=${GOPATH} PATH=${PATH} :") | |||
367 | mklines := NewMkLines(lines) | |||
368 | ||||
369 | mklines.Check() | |||
370 | ||||
371 | // For WRKSRC and GOPATH, no quoting is necessary since pkgsrc directories by | |||
372 | // definition don't contain special characters. Therefore they don't need the | |||
373 | // :Q, not even when used as part of a shell word. | |||
374 | ||||
375 | // For PATH, the quoting is necessary because it may contain directories outside | |||
376 | // of pkgsrc, and these may contain special characters. | |||
377 | ||||
378 | t.CheckOutputLines( | |||
379 | "WARN: ~/options.mk:4: The variable PATH should be quoted as part of a shell word.") | |||
380 | } |
@@ -1,30 +1,30 @@ | @@ -1,30 +1,30 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import ( | 3 | import ( | |
4 | "fmt" | 4 | "fmt" | |
5 | ) | 5 | ) | |
6 | 6 | |||
7 | //go:generate goyacc -o shellyacc.go -v shellyacc.log -p shyy shell.y | 7 | //go:generate goyacc -o shellyacc.go -v shellyacc.log -p shyy shell.y | |
8 | 8 | |||
9 | type ShAtomType uint8 | 9 | type ShAtomType uint8 | |
10 | 10 | |||
11 | const ( | 11 | const ( | |
12 | shtSpace ShAtomType = iota | 12 | shtSpace ShAtomType = iota | |
13 | shtVaruse // ${PREFIX} | 13 | shtVaruse // ${PREFIX} | |
14 | shtWord // | 14 | shtWord // while, cat, ENV=value | |
15 | shtOperator | 15 | shtOperator // (, ;, | | |
16 | shtComment // # ... | 16 | shtComment // # ... | |
17 | shtSubshell // $$( | 17 | shtSubshell // $$( | |
18 | ) | 18 | ) | |
19 | 19 | |||
20 | func (t ShAtomType) String() string { | 20 | func (t ShAtomType) String() string { | |
21 | return [...]string{ | 21 | return [...]string{ | |
22 | "space", | 22 | "space", | |
23 | "varuse", | 23 | "varuse", | |
24 | "word", | 24 | "word", | |
25 | "operator", | 25 | "operator", | |
26 | "comment", | 26 | "comment", | |
27 | "subshell", | 27 | "subshell", | |
28 | }[t] | 28 | }[t] | |
29 | } | 29 | } | |
30 | 30 | |||
@@ -46,29 +46,29 @@ type ShAtom struct { | @@ -46,29 +46,29 @@ type ShAtom struct { | |||
46 | 46 | |||
47 | func (token *ShAtom) String() string { | 47 | func (token *ShAtom) String() string { | |
48 | if token.Type == shtWord && token.Quoting == shqPlain && token.Data == nil { | 48 | if token.Type == shtWord && token.Quoting == shqPlain && token.Data == nil { | |
49 | return fmt.Sprintf("%q", token.MkText) | 49 | return fmt.Sprintf("%q", token.MkText) | |
50 | } | 50 | } | |
51 | if token.Type == shtVaruse { | 51 | if token.Type == shtVaruse { | |
52 | varuse := token.Data.(*MkVarUse) | 52 | varuse := token.Data.(*MkVarUse) | |
53 | return fmt.Sprintf("varuse(%q)", varuse.varname+varuse.Mod()) | 53 | return fmt.Sprintf("varuse(%q)", varuse.varname+varuse.Mod()) | |
54 | } | 54 | } | |
55 | return fmt.Sprintf("ShAtom(%v, %q, %s)", token.Type, token.MkText, token.Quoting) | 55 | return fmt.Sprintf("ShAtom(%v, %q, %s)", token.Type, token.MkText, token.Quoting) | |
56 | } | 56 | } | |
57 | 57 | |||
58 | // Returns nil for plain shell tokens. | 58 | // Returns nil for plain shell tokens. | |
59 | func (atom *ShAtom) VarUse() *MkVarUse { | 59 | func (token *ShAtom) VarUse() *MkVarUse { | |
60 | if atom.Type == shtVaruse { | 60 | if token.Type == shtVaruse { | |
61 | return atom.Data.(*MkVarUse) | 61 | return token.Data.(*MkVarUse) | |
62 | } | 62 | } | |
63 | return nil | 63 | return nil | |
64 | } | 64 | } | |
65 | 65 | |||
66 | // ShQuoting describes the context in which a string appears | 66 | // ShQuoting describes the context in which a string appears | |
67 | // and how it must be unescaped to get its literal value. | 67 | // and how it must be unescaped to get its literal value. | |
68 | type ShQuoting uint8 | 68 | type ShQuoting uint8 | |
69 | 69 | |||
70 | const ( | 70 | const ( | |
71 | shqPlain ShQuoting = iota | 71 | shqPlain ShQuoting = iota | |
72 | shqDquot | 72 | shqDquot | |
73 | shqSquot | 73 | shqSquot | |
74 | shqBackt | 74 | shqBackt | |
@@ -107,21 +107,13 @@ func (q ShQuoting) ToVarUseContext() vuc | @@ -107,21 +107,13 @@ func (q ShQuoting) ToVarUseContext() vuc | |||
107 | // See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_10_02 | 107 | // See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_10_02 | |
108 | type ShToken struct { | 108 | type ShToken struct { | |
109 | MkText string // The text as it appeared in the Makefile, after replacing `\#` with `#` | 109 | MkText string // The text as it appeared in the Makefile, after replacing `\#` with `#` | |
110 | Atoms []*ShAtom | 110 | Atoms []*ShAtom | |
111 | } | 111 | } | |
112 | 112 | |||
113 | func NewShToken(mkText string, atoms ...*ShAtom) *ShToken { | 113 | func NewShToken(mkText string, atoms ...*ShAtom) *ShToken { | |
114 | return &ShToken{mkText, atoms} | 114 | return &ShToken{mkText, atoms} | |
115 | } | 115 | } | |
116 | 116 | |||
117 | func (token *ShToken) String() string { | 117 | func (token *ShToken) String() string { | |
118 | return fmt.Sprintf("ShToken(%v)", token.Atoms) | 118 | return fmt.Sprintf("ShToken(%v)", token.Atoms) | |
119 | } | 119 | } | |
120 | ||||
121 | func (token *ShToken) IsAssignment() bool { | |||
122 | return matches(token.MkText, `^[A-Za-z_]\w*=`) | |||
123 | } | |||
124 | ||||
125 | func (token *ShToken) IsWord() bool { | |||
126 | return token.Atoms[0].Type.IsWord() | |||
127 | } |
@@ -11,102 +11,250 @@ func (s *Suite) Test_Package_pkgnameFrom | @@ -11,102 +11,250 @@ func (s *Suite) Test_Package_pkgnameFrom | |||
11 | c.Check(pkg.pkgnameFromDistname("pkgname-1.0", "whatever"), equals, "pkgname-1.0") | 11 | c.Check(pkg.pkgnameFromDistname("pkgname-1.0", "whatever"), equals, "pkgname-1.0") | |
12 | c.Check(pkg.pkgnameFromDistname("${DISTNAME}", "distname-1.0"), equals, "distname-1.0") | 12 | c.Check(pkg.pkgnameFromDistname("${DISTNAME}", "distname-1.0"), equals, "distname-1.0") | |
13 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S/dist/pkg/}", "distname-1.0"), equals, "pkgname-1.0") | 13 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S/dist/pkg/}", "distname-1.0"), equals, "pkgname-1.0") | |
14 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S|a|b|g}", "panama-0.13"), equals, "pbnbmb-0.13") | 14 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S|a|b|g}", "panama-0.13"), equals, "pbnbmb-0.13") | |
15 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S|^lib||}", "libncurses"), equals, "ncurses") | 15 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S|^lib||}", "libncurses"), equals, "ncurses") | |
16 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S|^lib||}", "mylib"), equals, "mylib") | 16 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S|^lib||}", "mylib"), equals, "mylib") | |
17 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:tl:S/-/./g:S/he/-/1}", "SaxonHE9-5-0-1J"), equals, "saxon-9.5.0.1j") | 17 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:tl:S/-/./g:S/he/-/1}", "SaxonHE9-5-0-1J"), equals, "saxon-9.5.0.1j") | |
18 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:C/beta/.0./}", "fspanel-0.8beta1"), equals, "${DISTNAME:C/beta/.0./}") | 18 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:C/beta/.0./}", "fspanel-0.8beta1"), equals, "${DISTNAME:C/beta/.0./}") | |
19 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S/-0$/.0/1}", "aspell-af-0.50-0"), equals, "aspell-af-0.50.0") | 19 | c.Check(pkg.pkgnameFromDistname("${DISTNAME:S/-0$/.0/1}", "aspell-af-0.50-0"), equals, "aspell-af-0.50.0") | |
20 | 20 | |||
21 | t.CheckOutputEmpty() | 21 | t.CheckOutputEmpty() | |
22 | } | 22 | } | |
23 | 23 | |||
24 | func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder(c *check.C) { | 24 | func (s *Suite) Test_Package_CheckVarorder(c *check.C) { | |
25 | t := s.Init(c) | 25 | t := s.Init(c) | |
26 | 26 | |||
27 | t.SetupCommandLine("-Worder") | 27 | t.SetupCommandLine("-Worder") | |
28 | pkg := NewPackage("x11/9term") | 28 | pkg := NewPackage("x11/9term") | |
29 | 29 | |||
30 | pkg.ChecklinesPackageMakefileVarorder(t.NewMkLines("Makefile", | 30 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |
31 | MkRcsId, | 31 | MkRcsID, | |
32 | "", | 32 | "", | |
33 | "GITHUB_PROJECT=project", | |||
33 | "DISTNAME=9term", | 34 | "DISTNAME=9term", | |
34 | "CATEGORIES=x11")) | 35 | "CATEGORIES=x11")) | |
35 | 36 | |||
36 | t.CheckOutputEmpty() | 37 | t.CheckOutputLines( | |
38 | "WARN: Makefile:3: The canonical order of the variables is " + | |||
39 | "GITHUB_PROJECT, DISTNAME, CATEGORIES, GITHUB_PROJECT, empty line, COMMENT, LICENSE.") | |||
37 | 40 | |||
38 | pkg.ChecklinesPackageMakefileVarorder(t.NewMkLines("Makefile", | 41 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |
39 | MkRcsId, | 42 | MkRcsID, | |
40 | "", | 43 | "", | |
41 | "DISTNAME=9term", | 44 | "DISTNAME=9term", | |
42 | "CATEGORIES=x11", | 45 | "CATEGORIES=x11", | |
43 | "", | 46 | "", | |
44 | ".include \"../../mk/bsd.pkg.mk\"")) | 47 | ".include \"../../mk/bsd.pkg.mk\"")) | |
45 | 48 | |||
46 | t.CheckOutputLines( | 49 | t.CheckOutputLines( | |
47 | "WARN: Makefile:6: The canonical position for the required variable COMMENT is here.", | 50 | "WARN: Makefile:3: The canonical order of the variables is " + | |
48 | "WARN: Makefile:6: The canonical position for the required variable LICENSE is here.") | 51 | "DISTNAME, CATEGORIES, empty line, COMMENT, LICENSE.") | |
52 | } | |||
53 | ||||
54 | // Ensure that comments and empty lines do not lead to panics. | |||
55 | func (s *Suite) Test_Package_CheckVarorder__comments_do_not_crash(c *check.C) { | |||
56 | t := s.Init(c) | |||
57 | ||||
58 | t.SetupCommandLine("-Worder") | |||
59 | pkg := NewPackage("x11/9term") | |||
60 | ||||
61 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |||
62 | MkRcsID, | |||
63 | "", | |||
64 | "GITHUB_PROJECT=project", | |||
65 | "", | |||
66 | "# comment", | |||
67 | "", | |||
68 | "DISTNAME=9term", | |||
69 | "# comment", | |||
70 | "CATEGORIES=x11")) | |||
71 | ||||
72 | t.CheckOutputLines( | |||
73 | "WARN: Makefile:3: The canonical order of the variables is " + | |||
74 | "GITHUB_PROJECT, DISTNAME, CATEGORIES, GITHUB_PROJECT, empty line, COMMENT, LICENSE.") | |||
75 | } | |||
76 | ||||
77 | func (s *Suite) Test_Package_CheckVarorder__comments_are_ignored(c *check.C) { | |||
78 | t := s.Init(c) | |||
79 | ||||
80 | t.SetupCommandLine("-Worder") | |||
81 | ||||
82 | pkg := NewPackage("x11/9term") | |||
83 | ||||
84 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |||
85 | MkRcsID, | |||
86 | "", | |||
87 | "DISTNAME=\tdistname-1.0", | |||
88 | "CATEGORIES=\tsysutils", | |||
89 | "", | |||
90 | "MAINTAINER=\tpkgsrc-users@pkgsrc.org", | |||
91 | "# comment", | |||
92 | "COMMENT=\tComment", | |||
93 | "LICENSE=\tgnu-gpl-v2")) | |||
94 | ||||
95 | t.CheckOutputEmpty() | |||
96 | } | |||
97 | ||||
98 | func (s *Suite) Test_Package_CheckVarorder__conditionals_skip(c *check.C) { | |||
99 | t := s.Init(c) | |||
100 | ||||
101 | t.SetupCommandLine("-Worder") | |||
102 | ||||
103 | pkg := NewPackage("x11/9term") | |||
104 | ||||
105 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |||
106 | MkRcsID, | |||
107 | "", | |||
108 | "DISTNAME=\tdistname-1.0", | |||
109 | "CATEGORIES=\tsysutils", | |||
110 | "", | |||
111 | ".if ${DISTNAME:Mdistname-*}", | |||
112 | "MAINTAINER=\tpkgsrc-users@pkgsrc.org", | |||
113 | ".endif", | |||
114 | "LICENSE=\tgnu-gpl-v2")) | |||
115 | ||||
116 | // No warning about the missing COMMENT since the conditional | |||
117 | // skips the whole check. | |||
118 | t.CheckOutputEmpty() | |||
119 | } | |||
120 | ||||
121 | func (s *Suite) Test_Package_CheckVarorder_GitHub(c *check.C) { | |||
122 | t := s.Init(c) | |||
123 | ||||
124 | t.SetupCommandLine("-Worder") | |||
125 | pkg := NewPackage("x11/9term") | |||
126 | ||||
127 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |||
128 | MkRcsID, | |||
129 | "", | |||
130 | "DISTNAME=\t\tautocutsel-0.10.0", | |||
131 | "CATEGORIES=\t\tx11", | |||
132 | "MASTER_SITES=\t\t${MASTER_SITE_GITHUB:=sigmike/}", | |||
133 | "GITHUB_PROJECT=\t\tautocutsel", | |||
134 | "GITHUB_TAG=\t\t${PKGVERSION_NOREV}", | |||
135 | "", | |||
136 | "COMMENT=\tComment", | |||
137 | "LICENSE=\tgnu-gpl-v2")) | |||
138 | ||||
139 | t.CheckOutputEmpty() | |||
49 | } | 140 | } | |
50 | 141 | |||
51 | func (s *Suite) Test_Package_varorder_license(c *check.C) { | 142 | func (s *Suite) Test_Package_varorder_license(c *check.C) { | |
52 | t := s.Init(c) | 143 | t := s.Init(c) | |
53 | 144 | |||
54 | t.SetupCommandLine("-Worder") | 145 | t.SetupCommandLine("-Worder") | |
55 | 146 | |||
56 | t.CreateFileLines("mk/bsd.pkg.mk", "# dummy") | 147 | t.CreateFileLines("mk/bsd.pkg.mk", "# dummy") | |
57 | t.CreateFileLines("x11/Makefile", MkRcsId) | 148 | t.CreateFileLines("x11/Makefile", MkRcsID) | |
58 | t.CreateFileLines("x11/9term/PLIST", PlistRcsId, "bin/9term") | 149 | t.CreateFileLines("x11/9term/PLIST", PlistRcsID, "bin/9term") | |
59 | t.CreateFileLines("x11/9term/distinfo", RcsId) | 150 | t.CreateFileLines("x11/9term/distinfo", RcsID) | |
60 | t.CreateFileLines("x11/9term/Makefile", | 151 | t.CreateFileLines("x11/9term/Makefile", | |
61 | MkRcsId, | 152 | MkRcsID, | |
62 | "", | 153 | "", | |
63 | "DISTNAME=9term-1.0", | 154 | "DISTNAME=9term-1.0", | |
64 | "CATEGORIES=x11", | 155 | "CATEGORIES=x11", | |
65 | "", | 156 | "", | |
66 | "COMMENT=Terminal", | 157 | "COMMENT=Terminal", | |
67 | "", | 158 | "", | |
68 | ".include \"../../mk/bsd.pkg.mk\"") | 159 | ".include \"../../mk/bsd.pkg.mk\"") | |
69 | 160 | |||
70 | G.globalData.InitVartypes() | 161 | G.globalData.InitVartypes() | |
71 | G.globalData.Pkgsrcdir = t.TmpDir() | 162 | G.globalData.Pkgsrcdir = t.TmpDir() | |
72 | G.CurrentDir = t.TmpDir() | 163 | G.CurrentDir = t.TmpDir() | |
73 | 164 | |||
74 | (&Pkglint{}).CheckDirent(t.TmpDir() + "/x11/9term") | 165 | (&Pkglint{}).CheckDirent(t.TmpDir() + "/x11/9term") | |
75 | 166 | |||
76 | // Since the error is grave enough, the warning about the correct position is suppressed. | 167 | // Since the error is grave enough, the warning about the correct position is suppressed. | |
77 | t.CheckOutputLines( | 168 | t.CheckOutputLines( | |
78 | "ERROR: ~/x11/9term/Makefile: Each package must define its LICENSE.") | 169 | "ERROR: ~/x11/9term/Makefile: Each package must define its LICENSE.") | |
79 | } | 170 | } | |
80 | 171 | |||
81 | // https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html | 172 | // https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html | |
82 | func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder__MASTER_SITES(c *check.C) { | 173 | func (s *Suite) Test_Package_CheckVarorder__MASTER_SITES(c *check.C) { | |
83 | t := s.Init(c) | 174 | t := s.Init(c) | |
84 | 175 | |||
85 | t.SetupCommandLine("-Worder") | 176 | t.SetupCommandLine("-Worder") | |
86 | pkg := NewPackage("category/package") | 177 | pkg := NewPackage("category/package") | |
87 | 178 | |||
88 | pkg.ChecklinesPackageMakefileVarorder(t.NewMkLines("Makefile", | 179 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |
89 | MkRcsId, | 180 | MkRcsID, | |
90 | "", | 181 | "", | |
91 | "PKGNAME=\tpackage-1.0", | 182 | "PKGNAME=\tpackage-1.0", | |
92 | "CATEGORIES=\tcategory", | 183 | "CATEGORIES=\tcategory", | |
93 | "MASTER_SITES=\thttp://example.org/", | 184 | "MASTER_SITES=\thttp://example.org/", | |
94 | "MASTER_SITES+=\thttp://mirror.example.org/")) | 185 | "MASTER_SITES+=\thttp://mirror.example.org/", | |
186 | "", | |||
187 | "COMMENT=\tComment", | |||
188 | "LICENSE=\tgnu-gpl-v2")) | |||
95 | 189 | |||
96 | // No warning that "MASTER_SITES appears too late" | 190 | // No warning that "MASTER_SITES appears too late" | |
97 | t.CheckOutputEmpty() | 191 | t.CheckOutputEmpty() | |
98 | } | 192 | } | |
99 | 193 | |||
194 | // The diagnostics must be helpful. | |||
195 | // In the case of wip/ioping, they were ambiguous and wrong. | |||
196 | func (s *Suite) Test_Package_CheckVarorder__diagnostics(c *check.C) { | |||
197 | t := s.Init(c) | |||
198 | ||||
199 | t.SetupCommandLine("-Worder") | |||
200 | G.globalData.InitVartypes() | |||
201 | pkg := NewPackage("category/package") | |||
202 | ||||
203 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |||
204 | MkRcsID, | |||
205 | "", | |||
206 | "CATEGORIES= net", | |||
207 | "", | |||
208 | "COMMENT= Comment", | |||
209 | "LICENSE= gnu-gpl-v3", | |||
210 | "", | |||
211 | "GITHUB_PROJECT= pkgbase", | |||
212 | "DISTNAME= v1.0", | |||
213 | "PKGNAME= ${GITHUB_PROJECT}-${DISTNAME}", | |||
214 | "MASTER_SITES= ${MASTER_SITE_GITHUB:=project/}", | |||
215 | "DIST_SUBDIR= ${GITHUB_PROJECT}", | |||
216 | "", | |||
217 | "MAINTAINER= maintainer@example.org", | |||
218 | "HOMEPAGE= https://github.com/project/pkgbase/", | |||
219 | "", | |||
220 | ".include \"../../mk/bsd.pkg.mk\"")) | |||
221 | ||||
222 | t.CheckOutputLines( | |||
223 | "WARN: Makefile:3: The canonical order of the variables is " + | |||
224 | "GITHUB_PROJECT, DISTNAME, PKGNAME, CATEGORIES, MASTER_SITES, GITHUB_PROJECT, DIST_SUBDIR, empty line, " + | |||
225 | "MAINTAINER, HOMEPAGE, COMMENT, LICENSE.") | |||
226 | ||||
227 | // After moving the variables according to the warning: | |||
228 | pkg.CheckVarorder(t.NewMkLines("Makefile", | |||
229 | MkRcsID, | |||
230 | "", | |||
231 | "GITHUB_PROJECT= pkgbase", | |||
232 | "DISTNAME= v1.0", | |||
233 | "PKGNAME= ${GITHUB_PROJECT}-${DISTNAME}", | |||
234 | "CATEGORIES= net", | |||
235 | "MASTER_SITES= ${MASTER_SITE_GITHUB:=project/}", | |||
236 | "DIST_SUBDIR= ${GITHUB_PROJECT}", | |||
237 | "", | |||
238 | "MAINTAINER= maintainer@example.org", | |||
239 | "HOMEPAGE= https://github.com/project/pkgbase/", | |||
240 | "COMMENT= Comment", | |||
241 | "LICENSE= gnu-gpl-v3", | |||
242 | "", | |||
243 | ".include \"../../mk/bsd.pkg.mk\"")) | |||
244 | ||||
245 | t.CheckOutputEmpty() | |||
246 | } | |||
247 | ||||
100 | func (s *Suite) Test_Package_getNbpart(c *check.C) { | 248 | func (s *Suite) Test_Package_getNbpart(c *check.C) { | |
101 | t := s.Init(c) | 249 | t := s.Init(c) | |
102 | 250 | |||
103 | pkg := NewPackage("category/pkgbase") | 251 | pkg := NewPackage("category/pkgbase") | |
104 | pkg.vardef["PKGREVISION"] = t.NewMkLine("Makefile", 1, "PKGREVISION=14") | 252 | pkg.vardef["PKGREVISION"] = t.NewMkLine("Makefile", 1, "PKGREVISION=14") | |
105 | 253 | |||
106 | c.Check(pkg.getNbpart(), equals, "nb14") | 254 | c.Check(pkg.getNbpart(), equals, "nb14") | |
107 | 255 | |||
108 | pkg.vardef["PKGREVISION"] = t.NewMkLine("Makefile", 1, "PKGREVISION=asdf") | 256 | pkg.vardef["PKGREVISION"] = t.NewMkLine("Makefile", 1, "PKGREVISION=asdf") | |
109 | 257 | |||
110 | c.Check(pkg.getNbpart(), equals, "") | 258 | c.Check(pkg.getNbpart(), equals, "") | |
111 | } | 259 | } | |
112 | 260 | |||
@@ -150,43 +298,43 @@ func (s *Suite) Test_Package_checkPossib | @@ -150,43 +298,43 @@ func (s *Suite) Test_Package_checkPossib | |||
150 | "WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15") | 298 | "WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15") | |
151 | 299 | |||
152 | G.globalData.LastChange["category/pkgbase"].Version = "1.0nb22" | 300 | G.globalData.LastChange["category/pkgbase"].Version = "1.0nb22" | |
153 | 301 | |||
154 | G.Pkg.checkPossibleDowngrade() | 302 | G.Pkg.checkPossibleDowngrade() | |
155 | 303 | |||
156 | t.CheckOutputEmpty() | 304 | t.CheckOutputEmpty() | |
157 | } | 305 | } | |
158 | 306 | |||
159 | func (s *Suite) Test_checkdirPackage(c *check.C) { | 307 | func (s *Suite) Test_checkdirPackage(c *check.C) { | |
160 | t := s.Init(c) | 308 | t := s.Init(c) | |
161 | 309 | |||
162 | t.SetupFileLines("Makefile", | 310 | t.SetupFileLines("Makefile", | |
163 | MkRcsId) | 311 | MkRcsID) | |
164 | G.CurrentDir = t.TmpDir() | 312 | G.CurrentDir = t.TmpDir() | |
165 | 313 | |||
166 | checkdirPackage(t.TmpDir()) | 314 | checkdirPackage(t.TmpDir()) | |
167 | 315 | |||
168 | t.CheckOutputLines( | 316 | t.CheckOutputLines( | |
169 | "WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?", | 317 | "WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?", | |
170 | "WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".", | 318 | "WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".", | |
171 | "ERROR: ~/Makefile: Each package must define its LICENSE.", | 319 | "ERROR: ~/Makefile: Each package must define its LICENSE.", | |
172 | "WARN: ~/Makefile: No COMMENT given.") | 320 | "WARN: ~/Makefile: No COMMENT given.") | |
173 | } | 321 | } | |
174 | 322 | |||
175 | func (s *Suite) Test_checkdirPackage__meta_package_without_license(c *check.C) { | 323 | func (s *Suite) Test_checkdirPackage__meta_package_without_license(c *check.C) { | |
176 | t := s.Init(c) | 324 | t := s.Init(c) | |
177 | 325 | |||
178 | t.CreateFileLines("Makefile", | 326 | t.CreateFileLines("Makefile", | |
179 | MkRcsId, | 327 | MkRcsID, | |
180 | "", | 328 | "", | |
181 | "META_PACKAGE=\tyes") | 329 | "META_PACKAGE=\tyes") | |
182 | G.CurrentDir = t.TmpDir() | 330 | G.CurrentDir = t.TmpDir() | |
183 | G.globalData.InitVartypes() | 331 | G.globalData.InitVartypes() | |
184 | 332 | |||
185 | checkdirPackage(t.TmpDir()) | 333 | checkdirPackage(t.TmpDir()) | |
186 | 334 | |||
187 | t.CheckOutputLines( | 335 | t.CheckOutputLines( | |
188 | "WARN: ~/Makefile: No COMMENT given.") // No error about missing LICENSE. | 336 | "WARN: ~/Makefile: No COMMENT given.") // No error about missing LICENSE. | |
189 | } | 337 | } | |
190 | 338 | |||
191 | func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) { | 339 | func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) { | |
192 | t := s.Init(c) | 340 | t := s.Init(c) | |
@@ -206,109 +354,109 @@ func (s *Suite) Test_Package__varuse_at_ | @@ -206,109 +354,109 @@ func (s *Suite) Test_Package__varuse_at_ | |||
206 | t.CreateFileLines("mk/defaults/mk.conf", | 354 | t.CreateFileLines("mk/defaults/mk.conf", | |
207 | "# dummy") | 355 | "# dummy") | |
208 | t.CreateFileLines("mk/tools/bsd.tools.mk", | 356 | t.CreateFileLines("mk/tools/bsd.tools.mk", | |
209 | ".include \"defaults.mk\"") | 357 | ".include \"defaults.mk\"") | |
210 | t.CreateFileLines("mk/tools/defaults.mk", | 358 | t.CreateFileLines("mk/tools/defaults.mk", | |
211 | "TOOLS_CREATE+=false", | 359 | "TOOLS_CREATE+=false", | |
212 | "TOOLS_CREATE+=nice", | 360 | "TOOLS_CREATE+=nice", | |
213 | "TOOLS_CREATE+=true", | 361 | "TOOLS_CREATE+=true", | |
214 | "_TOOLS_VARNAME.nice=NICE") | 362 | "_TOOLS_VARNAME.nice=NICE") | |
215 | t.CreateFileLines("mk/bsd.prefs.mk", | 363 | t.CreateFileLines("mk/bsd.prefs.mk", | |
216 | "# dummy") | 364 | "# dummy") | |
217 | 365 | |||
218 | t.CreateFileLines("category/pkgbase/Makefile", | 366 | t.CreateFileLines("category/pkgbase/Makefile", | |
219 | MkRcsId, | 367 | MkRcsID, | |
220 | "", | 368 | "", | |
221 | "COMMENT= Unit test", | 369 | "COMMENT= Unit test", | |
222 | "LICENSE= bsd-2", | 370 | "LICENSE= bsd-2", | |
223 | "PLIST_SRC=#none", | 371 | "PLIST_SRC=#none", | |
224 | "", | 372 | "", | |
225 | "USE_TOOLS+= echo false", | 373 | "USE_TOOLS+= echo false", | |
226 | "FALSE_BEFORE!= echo false=${FALSE}", | 374 | "FALSE_BEFORE!= echo false=${FALSE}", | |
227 | "NICE_BEFORE!= echo nice=${NICE}", | 375 | "NICE_BEFORE!= echo nice=${NICE}", | |
228 | "TRUE_BEFORE!= echo true=${TRUE}", | 376 | "TRUE_BEFORE!= echo true=${TRUE}", | |
229 | "", | 377 | "", | |
230 | ".include \"../../mk/bsd.prefs.mk\"", | 378 | ".include \"../../mk/bsd.prefs.mk\"", | |
231 | "", | 379 | "", | |
232 | "USE_TOOLS+= nice", | 380 | "USE_TOOLS+= nice", | |
233 | "FALSE_AFTER!= echo false=${FALSE}", | 381 | "FALSE_AFTER!= echo false=${FALSE}", | |
234 | "NICE_AFTER!= echo nice=${NICE}", | 382 | "NICE_AFTER!= echo nice=${NICE}", | |
235 | "TRUE_AFTER!= echo true=${TRUE}", | 383 | "TRUE_AFTER!= echo true=${TRUE}", | |
236 | "", | 384 | "", | |
237 | "do-build:", | 385 | "do-build:", | |
238 | "\t${ECHO} before: ${FALSE_BEFORE} ${NICE_BEFORE} ${TRUE_BEFORE}", | 386 | "\t${ECHO} before: ${FALSE_BEFORE} ${NICE_BEFORE} ${TRUE_BEFORE}", | |
239 | "\t${ECHO} after: ${FALSE_AFTER} ${NICE_AFTER} ${TRUE_AFTER}", | 387 | "\t${ECHO} after: ${FALSE_AFTER} ${NICE_AFTER} ${TRUE_AFTER}", | |
240 | "\t${ECHO}; ${FALSE}; ${NICE}; ${TRUE}", | 388 | "\t${ECHO}; ${FALSE}; ${NICE}; ${TRUE}", | |
241 | "", | 389 | "", | |
242 | ".include \"../../mk/bsd.pkg.mk\"") | 390 | ".include \"../../mk/bsd.pkg.mk\"") | |
243 | t.CreateFileLines("category/pkgbase/distinfo", | 391 | t.CreateFileLines("category/pkgbase/distinfo", | |
244 | RcsId) | 392 | RcsID) | |
245 | 393 | |||
246 | (&Pkglint{}).Main("pkglint", "-q", "-Wperm", t.TmpDir()+"/category/pkgbase") | 394 | (&Pkglint{}).Main("pkglint", "-q", "-Wperm", t.TmpDir()+"/category/pkgbase") | |
247 | 395 | |||
248 | t.CheckOutputLines( | 396 | t.CheckOutputLines( | |
249 | "WARN: ~/category/pkgbase/Makefile:8: To use the tool \"FALSE\" at load time, bsd.prefs.mk has to be included before.", | 397 | "WARN: ~/category/pkgbase/Makefile:8: To use the tool \"FALSE\" at load time, bsd.prefs.mk has to be included before.", | |
250 | "WARN: ~/category/pkgbase/Makefile:9: To use the tool \"NICE\" at load time, bsd.prefs.mk has to be included before.", | 398 | "WARN: ~/category/pkgbase/Makefile:9: To use the tool \"NICE\" at load time, bsd.prefs.mk has to be included before.", | |
251 | "WARN: ~/category/pkgbase/Makefile:10: To use the tool \"TRUE\" at load time, bsd.prefs.mk has to be included before.", | 399 | "WARN: ~/category/pkgbase/Makefile:10: To use the tool \"TRUE\" at load time, bsd.prefs.mk has to be included before.", | |
252 | "WARN: ~/category/pkgbase/Makefile:16: To use the tool \"NICE\" at load time, it has to be added to USE_TOOLS before including bsd.prefs.mk.") | 400 | "WARN: ~/category/pkgbase/Makefile:16: To use the tool \"NICE\" at load time, it has to be added to USE_TOOLS before including bsd.prefs.mk.") | |
253 | } | 401 | } | |
254 | 402 | |||
255 | func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) { | 403 | func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) { | |
256 | t := s.Init(c) | 404 | t := s.Init(c) | |
257 | 405 | |||
258 | t.SetupFileLines("category/package/Makefile", | 406 | t.SetupFileLines("category/package/Makefile", | |
259 | MkRcsId, | 407 | MkRcsID, | |
260 | "", | 408 | "", | |
261 | "PKGNAME=pkgname-1.67", | 409 | "PKGNAME=pkgname-1.67", | |
262 | "DISTNAME=distfile_1_67", | 410 | "DISTNAME=distfile_1_67", | |
263 | ".include \"../../category/package/Makefile\"") | 411 | ".include \"../../category/package/Makefile\"") | |
264 | pkg := NewPackage("category/package") | 412 | pkg := NewPackage("category/package") | |
265 | G.CurrentDir = t.TempFilename("category/package") | 413 | G.CurrentDir = t.TempFilename("category/package") | |
266 | G.CurPkgsrcdir = "../.." | 414 | G.CurPkgsrcdir = "../.." | |
267 | G.Pkg = pkg | 415 | G.Pkg = pkg | |
268 | 416 | |||
269 | pkg.loadPackageMakefile(t.TempFilename("category/package/Makefile")) | 417 | pkg.loadPackageMakefile(t.TempFilename("category/package/Makefile")) | |
270 | 418 | |||
271 | // Including a package Makefile directly is an error (in the last line), | 419 | // Including a package Makefile directly is an error (in the last line), | |
272 | // but that is checked later. | 420 | // but that is checked later. | |
273 | t.CheckOutputEmpty() | 421 | t.CheckOutputEmpty() | |
274 | } | 422 | } | |
275 | 423 | |||
276 | func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) { | 424 | func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) { | |
277 | t := s.Init(c) | 425 | t := s.Init(c) | |
278 | 426 | |||
279 | G.globalData.InitVartypes() | 427 | G.globalData.InitVartypes() | |
280 | t.CreateFileLines("category/package/Makefile", | 428 | t.CreateFileLines("category/package/Makefile", | |
281 | MkRcsId, | 429 | MkRcsID, | |
282 | "", | 430 | "", | |
283 | "COMMENT\t=Description", | 431 | "COMMENT\t=Description", | |
284 | "LICENSE\t= gnu-gpl-v2", | 432 | "LICENSE\t= gnu-gpl-v2", | |
285 | ".include \"../../devel/zlib/buildlink3.mk\"", | 433 | ".include \"../../devel/zlib/buildlink3.mk\"", | |
286 | ".if ${OPSYS} == \"Linux\"", | 434 | ".if ${OPSYS} == \"Linux\"", | |
287 | ".include \"../../sysutils/coreutils/buildlink3.mk\"", | 435 | ".include \"../../sysutils/coreutils/buildlink3.mk\"", | |
288 | ".endif", | 436 | ".endif", | |
289 | ".include \"../../mk/bsd.pkg.mk\"") | 437 | ".include \"../../mk/bsd.pkg.mk\"") | |
290 | t.CreateFileLines("category/package/options.mk", | 438 | t.CreateFileLines("category/package/options.mk", | |
291 | MkRcsId, | 439 | MkRcsID, | |
292 | "", | 440 | "", | |
293 | ".if !empty(PKG_OPTIONS:Mzlib)", | 441 | ".if !empty(PKG_OPTIONS:Mzlib)", | |
294 | ". include \"../../devel/zlib/buildlink3.mk\"", | 442 | ". include \"../../devel/zlib/buildlink3.mk\"", | |
295 | ".endif", | 443 | ".endif", | |
296 | ".include \"../../sysutils/coreutils/buildlink3.mk\"") | 444 | ".include \"../../sysutils/coreutils/buildlink3.mk\"") | |
297 | t.CreateFileLines("category/package/PLIST", | 445 | t.CreateFileLines("category/package/PLIST", | |
298 | PlistRcsId, | 446 | PlistRcsID, | |
299 | "bin/program") | 447 | "bin/program") | |
300 | t.CreateFileLines("category/package/distinfo", | 448 | t.CreateFileLines("category/package/distinfo", | |
301 | RcsId) | 449 | RcsID) | |
302 | 450 | |||
303 | t.CreateFileLines("devel/zlib/buildlink3.mk", "") | 451 | t.CreateFileLines("devel/zlib/buildlink3.mk", "") | |
304 | t.CreateFileLines("licenses/gnu-gpl-v2", "") | 452 | t.CreateFileLines("licenses/gnu-gpl-v2", "") | |
305 | t.CreateFileLines("mk/bsd.pkg.mk", "") | 453 | t.CreateFileLines("mk/bsd.pkg.mk", "") | |
306 | t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "") | 454 | t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "") | |
307 | 455 | |||
308 | pkg := NewPackage("category/package") | 456 | pkg := NewPackage("category/package") | |
309 | G.globalData.Pkgsrcdir = t.TmpDir() | 457 | G.globalData.Pkgsrcdir = t.TmpDir() | |
310 | G.CurrentDir = t.TmpDir() + "/category/package" | 458 | G.CurrentDir = t.TmpDir() + "/category/package" | |
311 | G.CurPkgsrcdir = "../.." | 459 | G.CurPkgsrcdir = "../.." | |
312 | G.Pkg = pkg | 460 | G.Pkg = pkg | |
313 | 461 | |||
314 | checkdirPackage("category/package") | 462 | checkdirPackage("category/package") |
@@ -115,50 +115,60 @@ func (ck *PatchChecker) checkUnifiedDiff | @@ -115,50 +115,60 @@ func (ck *PatchChecker) checkUnifiedDiff | |||
115 | trace.Stepf("guessFileType(%q) = %s", patchedFile, patchedFileType) | 115 | trace.Stepf("guessFileType(%q) = %s", patchedFile, patchedFileType) | |
116 | } | 116 | } | |
117 | 117 | |||
118 | hasHunks := false | 118 | hasHunks := false | |
119 | for ck.exp.AdvanceIfMatches(rePatchUniHunk) { | 119 | for ck.exp.AdvanceIfMatches(rePatchUniHunk) { | |
120 | hasHunks = true | 120 | hasHunks = true | |
121 | linesToDel := toInt(ck.exp.Group(2), 1) | 121 | linesToDel := toInt(ck.exp.Group(2), 1) | |
122 | linesToAdd := toInt(ck.exp.Group(4), 1) | 122 | linesToAdd := toInt(ck.exp.Group(4), 1) | |
123 | if trace.Tracing { | 123 | if trace.Tracing { | |
124 | trace.Stepf("hunk -%d +%d", linesToDel, linesToAdd) | 124 | trace.Stepf("hunk -%d +%d", linesToDel, linesToAdd) | |
125 | } | 125 | } | |
126 | ck.checktextUniHunkCr() | 126 | ck.checktextUniHunkCr() | |
127 | 127 | |||
128 | for linesToDel > 0 || linesToAdd > 0 || hasPrefix(ck.exp.CurrentLine().Text, "\\") { | 128 | for !ck.exp.EOF() && (linesToDel > 0 || linesToAdd > 0 || hasPrefix(ck.exp.CurrentLine().Text, "\\")) { | |
129 | line := ck.exp.CurrentLine() | 129 | line := ck.exp.CurrentLine() | |
130 | ck.exp.Advance() | 130 | ck.exp.Advance() | |
131 | text := line.Text | 131 | text := line.Text | |
132 | switch { | 132 | switch { | |
133 | case text == "": | 133 | case text == "": | |
134 | linesToDel-- | 134 | linesToDel-- | |
135 | linesToAdd-- | 135 | linesToAdd-- | |
136 | case hasPrefix(text, " "), hasPrefix(text, "\t"): | 136 | case hasPrefix(text, " "), hasPrefix(text, "\t"): | |
137 | linesToDel-- | 137 | linesToDel-- | |
138 | linesToAdd-- | 138 | linesToAdd-- | |
139 | ck.checklineContext(text[1:], patchedFileType) | 139 | ck.checklineContext(text[1:], patchedFileType) | |
140 | case hasPrefix(text, "-"): | 140 | case hasPrefix(text, "-"): | |
141 | linesToDel-- | 141 | linesToDel-- | |
142 | case hasPrefix(text, "+"): | 142 | case hasPrefix(text, "+"): | |
143 | linesToAdd-- | 143 | linesToAdd-- | |
144 | ck.checklineAdded(text[1:], patchedFileType) | 144 | ck.checklineAdded(text[1:], patchedFileType) | |
145 | case hasPrefix(text, "\\"): | 145 | case hasPrefix(text, "\\"): | |
146 | // \ No newline at end of file | 146 | // \ No newline at end of file | |
147 | default: | 147 | default: | |
148 | line.Errorf("Invalid line in unified patch hunk") | 148 | line.Errorf("Invalid line in unified patch hunk") | |
149 | return | 149 | return | |
150 | } | 150 | } | |
151 | } | 151 | } | |
152 | ||||
153 | // When these two counts are equal, they may refer to context | |||
154 | // lines that consist only of whitespace and have therefore | |||
155 | // been lost during transmission. There is no way to detect | |||
156 | // this by looking only at the patch file. | |||
157 | if linesToAdd != linesToDel { | |||
158 | line := ck.exp.PreviousLine() | |||
159 | line.Warnf("Premature end of patch hunk (expected %d lines to be deleted and %d lines to be added)", | |||
160 | linesToDel, linesToAdd) | |||
161 | } | |||
152 | } | 162 | } | |
153 | if !hasHunks { | 163 | if !hasHunks { | |
154 | ck.exp.CurrentLine().Errorf("No patch hunks for %q.", patchedFile) | 164 | ck.exp.CurrentLine().Errorf("No patch hunks for %q.", patchedFile) | |
155 | } | 165 | } | |
156 | if !ck.exp.EOF() { | 166 | if !ck.exp.EOF() { | |
157 | line := ck.exp.CurrentLine() | 167 | line := ck.exp.CurrentLine() | |
158 | if !ck.isEmptyLine(line.Text) && !matches(line.Text, rePatchUniFileDel) { | 168 | if !ck.isEmptyLine(line.Text) && !matches(line.Text, rePatchUniFileDel) { | |
159 | line.Warnf("Empty line or end of file expected.") | 169 | line.Warnf("Empty line or end of file expected.") | |
160 | Explain( | 170 | Explain( | |
161 | "This empty line makes the end of the patch clearly visible.", | 171 | "This empty line makes the end of the patch clearly visible.", | |
162 | "Otherwise the reader would have to count lines to see where", | 172 | "Otherwise the reader would have to count lines to see where", | |
163 | "the patch ends.") | 173 | "the patch ends.") | |
164 | } | 174 | } |
@@ -16,26 +16,28 @@ import ( | @@ -16,26 +16,28 @@ import ( | |||
16 | 16 | |||
17 | const confMake = "@BMAKE@" | 17 | const confMake = "@BMAKE@" | |
18 | const confVersion = "@VERSION@" | 18 | const confVersion = "@VERSION@" | |
19 | 19 | |||
20 | func main() { | 20 | func main() { | |
21 | G.logOut = NewSeparatorWriter(os.Stdout) | 21 | G.logOut = NewSeparatorWriter(os.Stdout) | |
22 | G.logErr = NewSeparatorWriter(os.Stderr) | 22 | G.logErr = NewSeparatorWriter(os.Stderr) | |
23 | trace.Out = os.Stdout | 23 | trace.Out = os.Stdout | |
24 | os.Exit(new(Pkglint).Main(os.Args...)) | 24 | os.Exit(new(Pkglint).Main(os.Args...)) | |
25 | } | 25 | } | |
26 | 26 | |||
27 | type Pkglint struct{} | 27 | type Pkglint struct{} | |
28 | 28 | |||
29 | // Main runs the main program with the given arguments. | |||
30 | // args[0] is the program name. | |||
29 | func (pkglint *Pkglint) Main(args ...string) (exitcode int) { | 31 | func (pkglint *Pkglint) Main(args ...string) (exitcode int) { | |
30 | defer func() { | 32 | defer func() { | |
31 | if r := recover(); r != nil { | 33 | if r := recover(); r != nil { | |
32 | if _, ok := r.(pkglintFatal); ok { | 34 | if _, ok := r.(pkglintFatal); ok { | |
33 | exitcode = 1 | 35 | exitcode = 1 | |
34 | } else { | 36 | } else { | |
35 | panic(r) | 37 | panic(r) | |
36 | } | 38 | } | |
37 | } | 39 | } | |
38 | }() | 40 | }() | |
39 | 41 | |||
40 | if exitcode := pkglint.ParseCommandLine(args); exitcode != nil { | 42 | if exitcode := pkglint.ParseCommandLine(args); exitcode != nil { | |
41 | return *exitcode | 43 | return *exitcode | |
@@ -471,27 +473,27 @@ func Checkfile(fname string) { | @@ -471,27 +473,27 @@ func Checkfile(fname string) { | |||
471 | 473 | |||
472 | case hasPrefix(basename, "PLIST"): | 474 | case hasPrefix(basename, "PLIST"): | |
473 | if G.opts.CheckPlist { | 475 | if G.opts.CheckPlist { | |
474 | if lines := LoadNonemptyLines(fname, false); lines != nil { | 476 | if lines := LoadNonemptyLines(fname, false); lines != nil { | |
475 | ChecklinesPlist(lines) | 477 | ChecklinesPlist(lines) | |
476 | } | 478 | } | |
477 | } | 479 | } | |
478 | 480 | |||
479 | case basename == "TODO" || basename == "README": | 481 | case basename == "TODO" || basename == "README": | |
480 | // Ok | 482 | // Ok | |
481 | 483 | |||
482 | case hasPrefix(basename, "CHANGES-"): | 484 | case hasPrefix(basename, "CHANGES-"): | |
483 | // This only checks the file, but doesn't register the changes globally. | 485 | // This only checks the file, but doesn't register the changes globally. | |
484 | G.globalData.loadDocChangesFromFile(fname) | 486 | _ = G.globalData.loadDocChangesFromFile(fname) | |
485 | 487 | |||
486 | case matches(fname, `(?:^|/)files/[^/]*$`): | 488 | case matches(fname, `(?:^|/)files/[^/]*$`): | |
487 | // Skip | 489 | // Skip | |
488 | 490 | |||
489 | case basename == "spec": | 491 | case basename == "spec": | |
490 | // Ok in regression tests | 492 | // Ok in regression tests | |
491 | 493 | |||
492 | default: | 494 | default: | |
493 | NewLineWhole(fname).Warnf("Unexpected file found.") | 495 | NewLineWhole(fname).Warnf("Unexpected file found.") | |
494 | if G.opts.CheckExtra { | 496 | if G.opts.CheckExtra { | |
495 | CheckfileExtra(fname) | 497 | CheckfileExtra(fname) | |
496 | } | 498 | } | |
497 | } | 499 | } |
@@ -32,32 +32,242 @@ func (s *Suite) Test_Pkglint_Main_no_arg | @@ -32,32 +32,242 @@ func (s *Suite) Test_Pkglint_Main_no_arg | |||
32 | 32 | |||
33 | exitcode := new(Pkglint).Main("pkglint") | 33 | exitcode := new(Pkglint).Main("pkglint") | |
34 | 34 | |||
35 | c.Check(exitcode, equals, 1) | 35 | c.Check(exitcode, equals, 1) | |
36 | t.CheckOutputLines( | 36 | t.CheckOutputLines( | |
37 | "FATAL: \".\" is not inside a pkgsrc tree.") | 37 | "FATAL: \".\" is not inside a pkgsrc tree.") | |
38 | } | 38 | } | |
39 | 39 | |||
40 | func (s *Suite) Test_Pkglint_Main__only(c *check.C) { | 40 | func (s *Suite) Test_Pkglint_Main__only(c *check.C) { | |
41 | t := s.Init(c) | 41 | t := s.Init(c) | |
42 | 42 | |||
43 | exitcode := new(Pkglint).ParseCommandLine([]string{"pkglint", "-Wall", "-o", ":Q", "--version"}) | 43 | exitcode := new(Pkglint).ParseCommandLine([]string{"pkglint", "-Wall", "-o", ":Q", "--version"}) | |
44 | 44 | |||
45 | c.Check(exitcode, deepEquals, new(int)) | 45 | if c.Check(exitcode, check.NotNil) { | |
46 | c.Check(*exitcode, equals, 0) | |||
47 | } | |||
46 | c.Check(G.opts.LogOnly, deepEquals, []string{":Q"}) | 48 | c.Check(G.opts.LogOnly, deepEquals, []string{":Q"}) | |
47 | t.CheckOutputLines( | 49 | t.CheckOutputLines( | |
48 | "@VERSION@") | 50 | "@VERSION@") | |
49 | } | 51 | } | |
50 | 52 | |||
53 | func (s *Suite) Test_Pkglint_Main__unknown_option(c *check.C) { | |||
54 | t := s.Init(c) | |||
55 | ||||
56 | exitcode := new(Pkglint).Main("pkglint", "--unknown-option") | |||
57 | ||||
58 | c.Check(exitcode, equals, 1) | |||
59 | t.CheckOutputLines( | |||
60 | "pkglint: unknown option: --unknown-option", | |||
61 | "", | |||
62 | "usage: pkglint [options] dir...", | |||
63 | "", | |||
64 | " -C, --check=check,... enable or disable specific checks", | |||
65 | " -d, --debug log verbose call traces for debugging", | |||
66 | " -e, --explain explain the diagnostics or give further help", | |||
67 | " -f, --show-autofix show what pkglint can fix automatically", | |||
68 | " -F, --autofix try to automatically fix some errors (experimental)", | |||
69 | " -g, --gcc-output-format mimic the gcc output format", | |||
70 | " -h, --help print a detailed usage message", | |||
71 | " -I, --dumpmakefile dump the Makefile after parsing", | |||
72 | " -i, --import prepare the import of a wip package", | |||
73 | " -m, --log-verbose allow the same log message more than once", | |||
74 | " -o, --only only log messages containing the given text", | |||
75 | " -p, --profiling profile the executing program", | |||
76 | " -q, --quiet don't print a summary line when finishing", | |||
77 | " -r, --recursive check subdirectories, too", | |||
78 | " -s, --source show the source lines together with diagnostics", | |||
79 | " -V, --version print the version number of pkglint", | |||
80 | " -W, --warning=warning,... enable or disable groups of warnings", | |||
81 | "", | |||
82 | " Flags for -C, --check:", | |||
83 | " all all of the following", | |||
84 | " none none of the following", | |||
85 | " ALTERNATIVES check ALTERNATIVES files (enabled)", | |||
86 | " bl3 check buildlink3.mk files (enabled)", | |||
87 | " DESCR check DESCR file (enabled)", | |||
88 | " distinfo check distinfo file (enabled)", | |||
89 | " extra check various additional files (disabled)", | |||
90 | " global inter-package checks (disabled)", | |||
91 | " INSTALL check INSTALL and DEINSTALL scripts (enabled)", | |||
92 | " Makefile check Makefiles (enabled)", | |||
93 | " MESSAGE check MESSAGE file (enabled)", | |||
94 | " mk check other .mk files (enabled)", | |||
95 | " patches check patches (enabled)", | |||
96 | " PLIST check PLIST files (enabled)", | |||
97 | "", | |||
98 | " Flags for -W, --warning:", | |||
99 | " all all of the following", | |||
100 | " none none of the following", | |||
101 | " absname warn about use of absolute file names (enabled)", | |||
102 | " directcmd warn about use of direct command names instead of Make variables (enabled)", | |||
103 | " extra enable some extra warnings (disabled)", | |||
104 | " order warn if Makefile entries are unordered (disabled)", | |||
105 | " perm warn about unforeseen variable definition and use (disabled)", | |||
106 | " plist-depr warn about deprecated paths in PLISTs (disabled)", | |||
107 | " plist-sort warn about unsorted entries in PLISTs (disabled)", | |||
108 | " quoting warn about quoting issues (disabled)", | |||
109 | " space warn about inconsistent use of white-space (disabled)", | |||
110 | " style warn about stylistic issues (disabled)", | |||
111 | " types do some simple type checking in Makefiles (enabled)", | |||
112 | "", | |||
113 | " (Prefix a flag with \"no-\" to disable it.)") | |||
114 | } | |||
115 | ||||
116 | // Demonstrates which infrastructure files are necessary to actually run | |||
117 | // pkglint in a realistic scenario. | |||
118 | // For most tests, this setup is too much work, therefore they | |||
119 | // initialize only those parts of the infrastructure they really | |||
120 | // need. | |||
121 | // | |||
122 | // Especially covers Pkglint.PrintSummary and Pkglint.Checkfile. | |||
123 | func (s *Suite) Test_Pkglint_Main__complete_package(c *check.C) { | |||
124 | t := s.Init(c) | |||
125 | ||||
126 | // This file is needed to locate the pkgsrc root directory. | |||
127 | // See findPkgsrcTopdir. | |||
128 | t.CreateFileLines("mk/bsd.pkg.mk", | |||
129 | "# dummy") | |||
130 | ||||
131 | // See GlobalData.loadDocChanges. | |||
132 | // FIXME: pkglint should warn that the latest version in this file | |||
133 | // (1.10) doesn't match the current version in the package (1.11). | |||
134 | t.CreateFileLines("doc/CHANGES-2018", | |||
135 | RcsID, | |||
136 | "", | |||
137 | "Changes to the packages collection and infrastructure in 2018:", | |||
138 | "", | |||
139 | "\tUpdated sysutils/checkperms to 1.10 [rillig 2018-01-05]") | |||
140 | ||||
141 | // See GlobalData.loadSuggestedUpdates. | |||
142 | t.CreateFileLines("doc/TODO", | |||
143 | RcsID, | |||
144 | "", | |||
145 | "Suggested package updates", | |||
146 | "", | |||
147 | "\to checkperms-1.13 [supports more file formats]") | |||
148 | ||||
149 | // The LICENSE in the package Makefile is searched here. | |||
150 | t.CreateFileLines("licenses/bsd-2", | |||
151 | "# dummy") | |||
152 | ||||
153 | // The MASTER_SITES in the package Makefile are searched here. | |||
154 | // See GlobalData.loadDistSites. | |||
155 | t.CreateFileLines("mk/fetch/sites.mk", | |||
156 | MkRcsID, | |||
157 | "", | |||
158 | "MASTER_SITE_GITHUB+=\thttps://github.com/") | |||
159 | ||||
160 | // The options for the PKG_OPTIONS framework must be readable. | |||
161 | // See GlobalData.loadPkgOptions. | |||
162 | t.CreateFileLines("mk/defaults/options.description", | |||
163 | "option Description") | |||
164 | ||||
165 | // The user-defined variables are read in to check for missing | |||
166 | // BUILD_DEFS declarations in the package Makefile. | |||
167 | t.CreateFileLines("mk/defaults/mk.conf", | |||
168 | "# dummy") | |||
169 | ||||
170 | // The tool definitions are read in to check for missing | |||
171 | // USE_TOOLS declarations in the package Makefile. | |||
172 | // They spread over several files from the pkgsrc infrastructure. | |||
173 | t.CreateFileLines("mk/tools/bsd.tools.mk", | |||
174 | ".include \"defaults.mk\"") | |||
175 | t.CreateFileLines("mk/tools/defaults.mk", | |||
176 | "# dummy") | |||
177 | t.CreateFileLines("mk/bsd.prefs.mk", | |||
178 | "# dummy") | |||
179 | ||||
180 | // The existence of this file makes the category "sysutils" valid. | |||
181 | // The category "tools" on the other hand is not valid. | |||
182 | t.CreateFileLines("sysutils/Makefile", | |||
183 | "# dummy") | |||
184 | ||||
185 | // The package Makefile is quite simple, containing just the | |||
186 | // standard variable definitions. The data for checking the variable | |||
187 | // values is partly defined in the pkgsrc infrastructure files | |||
188 | // (as defined in the previous lines), and partly in the pkglint | |||
189 | // code directly. Many details can be found in vartypecheck.go. | |||
190 | t.CreateFileLines("sysutils/checkperms/Makefile", | |||
191 | MkRcsID, | |||
192 | "", | |||
193 | "DISTNAME=\tcheckperms-1.11", | |||
194 | "CATEGORIES=\tsysutils tools", | |||
195 | "MASTER_SITES=\t${MASTER_SITE_GITHUB:=rillig/}", | |||
196 | "", | |||
197 | "MAINTAINER=\tpkgsrc-users@pkgsrc.org", | |||
198 | "HOMEPAGE=\thttps://github.com/rillig/checkperms/", | |||
199 | "COMMENT=\tCheck file permissions", | |||
200 | "LICENSE=\tbsd-2", | |||
201 | "", | |||
202 | ".include \"../../mk/bsd.pkg.mk\"") | |||
203 | ||||
204 | t.CreateFileLines("sysutils/checkperms/MESSAGE", | |||
205 | "===========================================================================", | |||
206 | RcsID, | |||
207 | "", | |||
208 | "After installation, this package has to be configured in a special way.", | |||
209 | "", | |||
210 | "===========================================================================") | |||
211 | ||||
212 | t.CreateFileLines("sysutils/checkperms/PLIST", | |||
213 | PlistRcsID, | |||
214 | "bin/checkperms", | |||
215 | "man/man1/checkperms.1") | |||
216 | ||||
217 | t.CreateFileLines("sysutils/checkperms/README", | |||
218 | "When updating this package, test the pkgsrc bootstrap.") | |||
219 | ||||
220 | t.CreateFileLines("sysutils/checkperms/TODO", | |||
221 | "Make the package work on MS-DOS") | |||
222 | ||||
223 | t.CreateFileLines("sysutils/checkperms/patches/patch-checkperms.c", | |||
224 | RcsID, | |||
225 | "", | |||
226 | "A simple patch demonstrating that pkglint checks for missing", | |||
227 | "removed lines. The hunk headers says that one line is to be", | |||
228 | "removed, but in fact, there is no deletion line below it.", | |||
229 | "", | |||
230 | "--- a/checkperms.c", | |||
231 | "+++ b/checkperms.c", | |||
232 | "@@ -1,1 +1,3 @@", // at line 1, delete 1 line; at line 1, add 3 lines | |||
233 | "+// Header 1", | |||
234 | "+// Header 2", | |||
235 | "+// Header 3") | |||
236 | t.CreateFileLines("sysutils/checkperms/distinfo", | |||
237 | RcsID, | |||
238 | "", | |||
239 | "SHA1 (checkperms-1.12.tar.gz) = 34c084b4d06bcd7a8bba922ff57677e651eeced5", | |||
240 | "RMD160 (checkperms-1.12.tar.gz) = cd95029aa930b6201e9580b3ab7e36dd30b8f925", | |||
241 | "SHA512 (checkperms-1.12.tar.gz) = 43e37b5963c63fdf716acdb470928d7e21a7bdfddd6c85cf626a11acc7f45fa52a53d4bcd83d543150328fe8cec5587987d2d9a7c5f0aaeb02ac1127ab41f8ae", | |||
242 | "Size (checkperms-1.12.tar.gz) = 6621 bytes", | |||
243 | "SHA1 (patch-checkperms.c) = asdfasdf") // Invalid SHA-1 checksum | |||
244 | ||||
245 | new(Pkglint).Main("pkglint", "-Wall", "-Call", t.TempFilename("sysutils/checkperms")) | |||
246 | ||||
247 | t.CheckOutputLines( | |||
248 | "WARN: ~/sysutils/checkperms/Makefile:3: This package should be updated to 1.13 ([supports more file formats]).", | |||
249 | "ERROR: ~/sysutils/checkperms/Makefile:4: Invalid category \"tools\".", | |||
250 | "ERROR: ~/sysutils/checkperms/distinfo:7: SHA1 hash of patches/patch-checkperms.c differs "+ | |||
251 | "(distinfo has asdfasdf, patch file has e775969de639ec703866c0336c4c8e0fdd96309c). "+ | |||
252 | "Run \"@BMAKE@ makepatchsum\".", | |||
253 | "WARN: ~/sysutils/checkperms/patches/patch-checkperms.c:12: Premature end of patch hunk "+ | |||
254 | "(expected 1 lines to be deleted and 0 lines to be added)", | |||
255 | "2 errors and 2 warnings found.", | |||
256 | "(Run \"pkglint -e\" to show explanations.)", | |||
257 | "(Run \"pkglint -fs\" to show what can be fixed automatically.)", | |||
258 | "(Run \"pkglint -F\" to automatically fix some issues.)") | |||
259 | } | |||
260 | ||||
51 | // go test -c -covermode count | 261 | // go test -c -covermode count | |
52 | // pkgsrcdir=... | 262 | // pkgsrcdir=... | |
53 | // env PKGLINT_TESTCMDLINE="$pkgsrcdir -r" ./pkglint.test -test.coverprofile pkglint.cov | 263 | // env PKGLINT_TESTCMDLINE="$pkgsrcdir -r" ./pkglint.test -test.coverprofile pkglint.cov | |
54 | // go tool cover -html=pkglint.cov -o coverage.html | 264 | // go tool cover -html=pkglint.cov -o coverage.html | |
55 | func (s *Suite) Test_Pkglint_coverage(c *check.C) { | 265 | func (s *Suite) Test_Pkglint_coverage(c *check.C) { | |
56 | cmdline := os.Getenv("PKGLINT_TESTCMDLINE") | 266 | cmdline := os.Getenv("PKGLINT_TESTCMDLINE") | |
57 | if cmdline != "" { | 267 | if cmdline != "" { | |
58 | G.logOut, G.logErr, trace.Out = NewSeparatorWriter(os.Stdout), NewSeparatorWriter(os.Stderr), os.Stdout | 268 | G.logOut, G.logErr, trace.Out = NewSeparatorWriter(os.Stdout), NewSeparatorWriter(os.Stderr), os.Stdout | |
59 | new(Pkglint).Main(append([]string{"pkglint"}, splitOnSpace(cmdline)...)...) | 269 | new(Pkglint).Main(append([]string{"pkglint"}, splitOnSpace(cmdline)...)...) | |
60 | } | 270 | } | |
61 | } | 271 | } | |
62 | 272 | |||
63 | func (s *Suite) Test_Pkglint_CheckDirent__outside(c *check.C) { | 273 | func (s *Suite) Test_Pkglint_CheckDirent__outside(c *check.C) { | |
@@ -194,34 +404,36 @@ func (s *Suite) Test_ChecklinesMessage__ | @@ -194,34 +404,36 @@ func (s *Suite) Test_ChecklinesMessage__ | |||
194 | t := s.Init(c) | 404 | t := s.Init(c) | |
195 | 405 | |||
196 | t.SetupCommandLine("-Wall", "--autofix") | 406 | t.SetupCommandLine("-Wall", "--autofix") | |
197 | lines := t.SetupFileLines("MESSAGE", | 407 | lines := t.SetupFileLines("MESSAGE", | |
198 | "1", | 408 | "1", | |
199 | "2", | 409 | "2", | |
200 | "3", | 410 | "3", | |
201 | "4", | 411 | "4", | |
202 | "5") | 412 | "5") | |
203 | 413 | |||
204 | ChecklinesMessage(lines) | 414 | ChecklinesMessage(lines) | |
205 | 415 | |||
206 | t.CheckOutputLines( | 416 | t.CheckOutputLines( | |
207 | "AUTOFIX: ~/MESSAGE:1: Inserting a line \"===================================="+ | 417 | "AUTOFIX: ~/MESSAGE:1: Inserting a line "+ | |
208 | "=======================================\" before this line.", | 418 | "\"===========================================================================\" "+ | |
209 | "AUTOFIX: ~/MESSAGE:1: Inserting a line \"$NetBSD: pkglint_test.go,v 1.14 2018/01/28 23:21:16 rillig Exp $\" before this line.", | 419 | "before this line.", | |
210 | "AUTOFIX: ~/MESSAGE:5: Inserting a line \"===================================="+ | 420 | "AUTOFIX: ~/MESSAGE:1: Inserting a line \"$"+"NetBSD$\" before this line.", | |
211 | "=======================================\" after this line.") | 421 | "AUTOFIX: ~/MESSAGE:5: Inserting a line "+ | |
422 | "\"===========================================================================\" "+ | |||
423 | "after this line.") | |||
212 | t.CheckFileLines("MESSAGE", | 424 | t.CheckFileLines("MESSAGE", | |
213 | "===========================================================================", | 425 | "===========================================================================", | |
214 | "$NetBSD: pkglint_test.go,v 1.14 2018/01/28 23:21:16 rillig Exp $", | 426 | RcsID, | |
215 | "1", | 427 | "1", | |
216 | "2", | 428 | "2", | |
217 | "3", | 429 | "3", | |
218 | "4", | 430 | "4", | |
219 | "5", | 431 | "5", | |
220 | "===========================================================================") | 432 | "===========================================================================") | |
221 | } | 433 | } | |
222 | 434 | |||
223 | func (s *Suite) Test_GlobalData_Latest(c *check.C) { | 435 | func (s *Suite) Test_GlobalData_Latest(c *check.C) { | |
224 | t := s.Init(c) | 436 | t := s.Init(c) | |
225 | 437 | |||
226 | G.globalData.Pkgsrcdir = t.TmpDir() | 438 | G.globalData.Pkgsrcdir = t.TmpDir() | |
227 | 439 |
@@ -332,37 +332,26 @@ func (ck *PlistChecker) checkpathMan(pli | @@ -332,37 +332,26 @@ func (ck *PlistChecker) checkpathMan(pli | |||
332 | fix.Explain( | 332 | fix.Explain( | |
333 | "Whether the manual pages are installed in compressed form or not is", | 333 | "Whether the manual pages are installed in compressed form or not is", | |
334 | "configured by the pkgsrc user. Compression and decompression takes", | 334 | "configured by the pkgsrc user. Compression and decompression takes", | |
335 | "place automatically, no matter if the .gz extension is mentioned in", | 335 | "place automatically, no matter if the .gz extension is mentioned in", | |
336 | "the PLIST or not.") | 336 | "the PLIST or not.") | |
337 | fix.ReplaceRegex(`\.gz\n`, "\n", 1) | 337 | fix.ReplaceRegex(`\.gz\n`, "\n", 1) | |
338 | fix.Apply() | 338 | fix.Apply() | |
339 | } | 339 | } | |
340 | } | 340 | } | |
341 | 341 | |||
342 | func (ck *PlistChecker) checkpathShare(pline *PlistLine) { | 342 | func (ck *PlistChecker) checkpathShare(pline *PlistLine) { | |
343 | line, text := pline.line, pline.text | 343 | line, text := pline.line, pline.text | |
344 | switch { | 344 | switch { | |
345 | // Disabled due to PR 46570, item "10. It should stop". | |||
346 | case false && hasPrefix(text, "share/applications/") && hasSuffix(text, ".desktop"): | |||
347 | f := "../../sysutils/desktop-file-utils/desktopdb.mk" | |||
348 | if G.opts.WarnExtra && G.Pkg != nil && G.Pkg.included[f] == nil { | |||
349 | line.Warnf("Packages that install a .desktop entry should .include %q.", f) | |||
350 | Explain( | |||
351 | "If *.desktop files contain MimeType keys, the global MIME type", | |||
352 | "registry must be updated by desktop-file-utils. Otherwise, this", | |||
353 | "warning is harmless.") | |||
354 | } | |||
355 | ||||
356 | case hasPrefix(text, "share/icons/") && G.Pkg != nil: | 345 | case hasPrefix(text, "share/icons/") && G.Pkg != nil: | |
357 | if hasPrefix(text, "share/icons/hicolor/") && G.Pkg.Pkgpath != "graphics/hicolor-icon-theme" { | 346 | if hasPrefix(text, "share/icons/hicolor/") && G.Pkg.Pkgpath != "graphics/hicolor-icon-theme" { | |
358 | f := "../../graphics/hicolor-icon-theme/buildlink3.mk" | 347 | f := "../../graphics/hicolor-icon-theme/buildlink3.mk" | |
359 | if G.Pkg.included[f] == nil && ck.once.FirstTime("hicolor-icon-theme") { | 348 | if G.Pkg.included[f] == nil && ck.once.FirstTime("hicolor-icon-theme") { | |
360 | line.Errorf("Packages that install hicolor icons must include %q in the Makefile.", f) | 349 | line.Errorf("Packages that install hicolor icons must include %q in the Makefile.", f) | |
361 | } | 350 | } | |
362 | } | 351 | } | |
363 | 352 | |||
364 | if hasPrefix(text, "share/icons/gnome") && G.Pkg.Pkgpath != "graphics/gnome-icon-theme" { | 353 | if hasPrefix(text, "share/icons/gnome") && G.Pkg.Pkgpath != "graphics/gnome-icon-theme" { | |
365 | f := "../../graphics/gnome-icon-theme/buildlink3.mk" | 354 | f := "../../graphics/gnome-icon-theme/buildlink3.mk" | |
366 | if G.Pkg.included[f] == nil { | 355 | if G.Pkg.included[f] == nil { | |
367 | line.Errorf("The package Makefile must include %q.", f) | 356 | line.Errorf("The package Makefile must include %q.", f) | |
368 | Explain( | 357 | Explain( |
@@ -44,89 +44,89 @@ func (s *Suite) Test_ChecklinesPlist(c * | @@ -44,89 +44,89 @@ func (s *Suite) Test_ChecklinesPlist(c * | |||
44 | "WARN: PLIST:11: IMAKE_MANNEWSUFFIX is not meant to appear in PLISTs.", | 44 | "WARN: PLIST:11: IMAKE_MANNEWSUFFIX is not meant to appear in PLISTs.", | |
45 | "WARN: PLIST:12: Please remove this line. It is no longer necessary.", | 45 | "WARN: PLIST:12: Please remove this line. It is no longer necessary.", | |
46 | "ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".", | 46 | "ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".", | |
47 | "WARN: PLIST:14: Packages that install icon theme files should set ICON_THEMES.", | 47 | "WARN: PLIST:14: Packages that install icon theme files should set ICON_THEMES.", | |
48 | "ERROR: PLIST:15: Packages that install hicolor icons "+ | 48 | "ERROR: PLIST:15: Packages that install hicolor icons "+ | |
49 | "must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.", | 49 | "must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.", | |
50 | "ERROR: PLIST:18: Duplicate filename \"share/tzinfo\", already appeared in line 17.") | 50 | "ERROR: PLIST:18: Duplicate filename \"share/tzinfo\", already appeared in line 17.") | |
51 | } | 51 | } | |
52 | 52 | |||
53 | func (s *Suite) Test_ChecklinesPlist__empty(c *check.C) { | 53 | func (s *Suite) Test_ChecklinesPlist__empty(c *check.C) { | |
54 | t := s.Init(c) | 54 | t := s.Init(c) | |
55 | 55 | |||
56 | lines := t.NewLines("PLIST", | 56 | lines := t.NewLines("PLIST", | |
57 | PlistRcsId) | 57 | PlistRcsID) | |
58 | 58 | |||
59 | ChecklinesPlist(lines) | 59 | ChecklinesPlist(lines) | |
60 | 60 | |||
61 | t.CheckOutputLines( | 61 | t.CheckOutputLines( | |
62 | "WARN: PLIST:1: PLIST files shouldn't be empty.") | 62 | "WARN: PLIST:1: PLIST files shouldn't be empty.") | |
63 | } | 63 | } | |
64 | 64 | |||
65 | func (s *Suite) Test_ChecklinesPlist__commonEnd(c *check.C) { | 65 | func (s *Suite) Test_ChecklinesPlist__commonEnd(c *check.C) { | |
66 | t := s.Init(c) | 66 | t := s.Init(c) | |
67 | 67 | |||
68 | t.SetupFileLines("PLIST.common", | 68 | t.SetupFileLines("PLIST.common", | |
69 | PlistRcsId, | 69 | PlistRcsID, | |
70 | "bin/common") | 70 | "bin/common") | |
71 | lines := t.SetupFileLines("PLIST.common_end", | 71 | lines := t.SetupFileLines("PLIST.common_end", | |
72 | PlistRcsId, | 72 | PlistRcsID, | |
73 | "sbin/common_end") | 73 | "sbin/common_end") | |
74 | 74 | |||
75 | ChecklinesPlist(lines) | 75 | ChecklinesPlist(lines) | |
76 | 76 | |||
77 | t.CheckOutputEmpty() | 77 | t.CheckOutputEmpty() | |
78 | } | 78 | } | |
79 | 79 | |||
80 | func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) { | 80 | func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) { | |
81 | t := s.Init(c) | 81 | t := s.Init(c) | |
82 | 82 | |||
83 | G.Pkg = NewPackage("category/pkgbase") | 83 | G.Pkg = NewPackage("category/pkgbase") | |
84 | G.Pkg.plistSubstCond["PLIST.bincmds"] = true | 84 | G.Pkg.plistSubstCond["PLIST.bincmds"] = true | |
85 | lines := t.NewLines("PLIST", | 85 | lines := t.NewLines("PLIST", | |
86 | PlistRcsId, | 86 | PlistRcsID, | |
87 | "${PLIST.bincmds}bin/subdir/command") | 87 | "${PLIST.bincmds}bin/subdir/command") | |
88 | 88 | |||
89 | ChecklinesPlist(lines) | 89 | ChecklinesPlist(lines) | |
90 | 90 | |||
91 | t.CheckOutputLines( | 91 | t.CheckOutputLines( | |
92 | "WARN: PLIST:2: The bin/ directory should not have subdirectories.") | 92 | "WARN: PLIST:2: The bin/ directory should not have subdirectories.") | |
93 | } | 93 | } | |
94 | 94 | |||
95 | func (s *Suite) Test_ChecklinesPlist__sorting(c *check.C) { | 95 | func (s *Suite) Test_ChecklinesPlist__sorting(c *check.C) { | |
96 | t := s.Init(c) | 96 | t := s.Init(c) | |
97 | 97 | |||
98 | t.SetupCommandLine("-Wplist-sort") | 98 | t.SetupCommandLine("-Wplist-sort") | |
99 | lines := t.NewLines("PLIST", | 99 | lines := t.NewLines("PLIST", | |
100 | PlistRcsId, | 100 | PlistRcsID, | |
101 | "@comment Do not remove", | 101 | "@comment Do not remove", | |
102 | "sbin/i386/6c", | 102 | "sbin/i386/6c", | |
103 | "sbin/program", | 103 | "sbin/program", | |
104 | "bin/otherprogram", | 104 | "bin/otherprogram", | |
105 | "${PLIST.conditional}bin/cat") | 105 | "${PLIST.conditional}bin/cat") | |
106 | 106 | |||
107 | ChecklinesPlist(lines) | 107 | ChecklinesPlist(lines) | |
108 | 108 | |||
109 | t.CheckOutputLines( | 109 | t.CheckOutputLines( | |
110 | "WARN: PLIST:5: \"bin/otherprogram\" should be sorted before \"sbin/program\".", | 110 | "WARN: PLIST:5: \"bin/otherprogram\" should be sorted before \"sbin/program\".", | |
111 | "WARN: PLIST:6: \"bin/cat\" should be sorted before \"bin/otherprogram\".") | 111 | "WARN: PLIST:6: \"bin/cat\" should be sorted before \"bin/otherprogram\".") | |
112 | } | 112 | } | |
113 | 113 | |||
114 | func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) { | 114 | func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) { | |
115 | t := s.Init(c) | 115 | t := s.Init(c) | |
116 | 116 | |||
117 | t.SetupCommandLine("--autofix") | 117 | t.SetupCommandLine("--autofix") | |
118 | lines := t.SetupFileLines("PLIST", | 118 | lines := t.SetupFileLines("PLIST", | |
119 | PlistRcsId, | 119 | PlistRcsID, | |
120 | "@comment Do not remove", | 120 | "@comment Do not remove", | |
121 | "A", | 121 | "A", | |
122 | "b", | 122 | "b", | |
123 | "CCC", | 123 | "CCC", | |
124 | "lib/${UNKNOWN}.la", | 124 | "lib/${UNKNOWN}.la", | |
125 | "C", | 125 | "C", | |
126 | "ddd", | 126 | "ddd", | |
127 | "@exec echo \"after ddd\"", // Makes the PLIST unsortable | 127 | "@exec echo \"after ddd\"", // Makes the PLIST unsortable | |
128 | "sbin/program", | 128 | "sbin/program", | |
129 | "${PLIST.one}bin/program", | 129 | "${PLIST.one}bin/program", | |
130 | "man/man1/program.1", | 130 | "man/man1/program.1", | |
131 | "${PLIST.two}bin/program2", | 131 | "${PLIST.two}bin/program2", | |
132 | "lib/before.la", | 132 | "lib/before.la", | |
@@ -140,108 +140,90 @@ func (s *Suite) Test_PlistLineSorter_Sor | @@ -140,108 +140,90 @@ func (s *Suite) Test_PlistLineSorter_Sor | |||
140 | c.Check(sorter1.unsortable, equals, lines[5]) | 140 | c.Check(sorter1.unsortable, equals, lines[5]) | |
141 | 141 | |||
142 | cleanedLines := append(append(lines[0:5], lines[6:8]...), lines[9:]...) // Remove ${UNKNOWN} and @exec | 142 | cleanedLines := append(append(lines[0:5], lines[6:8]...), lines[9:]...) // Remove ${UNKNOWN} and @exec | |
143 | 143 | |||
144 | sorter2 := NewPlistLineSorter((&PlistChecker{nil, nil, "", Once{}}).NewLines(cleanedLines)) | 144 | sorter2 := NewPlistLineSorter((&PlistChecker{nil, nil, "", Once{}}).NewLines(cleanedLines)) | |
145 | 145 | |||
146 | c.Check(sorter2.unsortable, check.IsNil) | 146 | c.Check(sorter2.unsortable, check.IsNil) | |
147 | 147 | |||
148 | sorter2.Sort() | 148 | sorter2.Sort() | |
149 | 149 | |||
150 | t.CheckOutputLines( | 150 | t.CheckOutputLines( | |
151 | "AUTOFIX: ~/PLIST:3: Sorting the whole file.") | 151 | "AUTOFIX: ~/PLIST:3: Sorting the whole file.") | |
152 | t.CheckFileLines("PLIST", | 152 | t.CheckFileLines("PLIST", | |
153 | PlistRcsId, | 153 | PlistRcsID, | |
154 | "@comment Do not remove", // The header ends here | 154 | "@comment Do not remove", // The header ends here | |
155 | "A", | 155 | "A", | |
156 | "C", | 156 | "C", | |
157 | "CCC", | 157 | "CCC", | |
158 | "b", | 158 | "b", | |
159 | "${PLIST.one}bin/program", // Conditionals are ignored while sorting | 159 | "${PLIST.one}bin/program", // Conditionals are ignored while sorting | |
160 | "${PLIST.two}bin/program2", | 160 | "${PLIST.two}bin/program2", | |
161 | "ddd", | 161 | "ddd", | |
162 | "lib/after.la", | 162 | "lib/after.la", | |
163 | "lib/before.la", | 163 | "lib/before.la", | |
164 | "${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", | 164 | "${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", | |
165 | "man/man1/program.1", | 165 | "man/man1/program.1", | |
166 | "sbin/program", | 166 | "sbin/program", | |
167 | "@exec echo \"after lib/after.la\"") // The footer starts here | 167 | "@exec echo \"after lib/after.la\"") // The footer starts here | |
168 | } | 168 | } | |
169 | 169 | |||
170 | func (s *Suite) Test_PlistChecker_checkpathShare_Desktop(c *check.C) { | |||
171 | // Disabled due to PR 46570, item "10. It should stop". | |||
172 | return | |||
173 | ||||
174 | t := s.Init(c) | |||
175 | ||||
176 | t.SetupCommandLine("-Wextra") | |||
177 | G.Pkg = NewPackage("category/pkgpath") | |||
178 | ||||
179 | ChecklinesPlist(t.NewLines("PLIST", | |||
180 | PlistRcsId, | |||
181 | "share/applications/pkgbase.desktop")) | |||
182 | ||||
183 | t.CheckOutputLines( | |||
184 | "WARN: PLIST:2: Packages that install a .desktop entry " + | |||
185 | "should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".") | |||
186 | } | |||
187 | ||||
188 | func (s *Suite) Test_PlistChecker_checkpathMan_gz(c *check.C) { | 170 | func (s *Suite) Test_PlistChecker_checkpathMan_gz(c *check.C) { | |
189 | t := s.Init(c) | 171 | t := s.Init(c) | |
190 | 172 | |||
191 | G.Pkg = NewPackage("category/pkgbase") | 173 | G.Pkg = NewPackage("category/pkgbase") | |
192 | lines := t.NewLines("PLIST", | 174 | lines := t.NewLines("PLIST", | |
193 | PlistRcsId, | 175 | PlistRcsID, | |
194 | "man/man3/strerror.3.gz") | 176 | "man/man3/strerror.3.gz") | |
195 | 177 | |||
196 | ChecklinesPlist(lines) | 178 | ChecklinesPlist(lines) | |
197 | 179 | |||
198 | t.CheckOutputLines( | 180 | t.CheckOutputLines( | |
199 | "NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.") | 181 | "NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.") | |
200 | } | 182 | } | |
201 | 183 | |||
202 | func (s *Suite) TestPlistChecker_checkpath__PKGMANDIR(c *check.C) { | 184 | func (s *Suite) TestPlistChecker_checkpath__PKGMANDIR(c *check.C) { | |
203 | t := s.Init(c) | 185 | t := s.Init(c) | |
204 | 186 | |||
205 | lines := t.NewLines("PLIST", | 187 | lines := t.NewLines("PLIST", | |
206 | PlistRcsId, | 188 | PlistRcsID, | |
207 | "${PKGMANDIR}/man1/sh.1") | 189 | "${PKGMANDIR}/man1/sh.1") | |
208 | 190 | |||
209 | ChecklinesPlist(lines) | 191 | ChecklinesPlist(lines) | |
210 | 192 | |||
211 | t.CheckOutputLines( | 193 | t.CheckOutputLines( | |
212 | "NOTE: PLIST:2: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".") | 194 | "NOTE: PLIST:2: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".") | |
213 | } | 195 | } | |
214 | 196 | |||
215 | func (s *Suite) TestPlistChecker_checkpath__python_egg(c *check.C) { | 197 | func (s *Suite) TestPlistChecker_checkpath__python_egg(c *check.C) { | |
216 | t := s.Init(c) | 198 | t := s.Init(c) | |
217 | 199 | |||
218 | lines := t.NewLines("PLIST", | 200 | lines := t.NewLines("PLIST", | |
219 | PlistRcsId, | 201 | PlistRcsID, | |
220 | "${PYSITELIB}/gdspy-${PKGVERSION}-py${PYVERSSUFFIX}.egg-info/PKG-INFO") | 202 | "${PYSITELIB}/gdspy-${PKGVERSION}-py${PYVERSSUFFIX}.egg-info/PKG-INFO") | |
221 | 203 | |||
222 | ChecklinesPlist(lines) | 204 | ChecklinesPlist(lines) | |
223 | 205 | |||
224 | t.CheckOutputLines( | 206 | t.CheckOutputLines( | |
225 | "WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.") | 207 | "WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.") | |
226 | } | 208 | } | |
227 | 209 | |||
228 | func (s *Suite) Test_PlistChecker__autofix(c *check.C) { | 210 | func (s *Suite) Test_PlistChecker__autofix(c *check.C) { | |
229 | t := s.Init(c) | 211 | t := s.Init(c) | |
230 | 212 | |||
231 | t.SetupCommandLine("-Wall") | 213 | t.SetupCommandLine("-Wall") | |
232 | 214 | |||
233 | fname := t.CreateFileLines("PLIST", | 215 | fname := t.CreateFileLines("PLIST", | |
234 | PlistRcsId, | 216 | PlistRcsID, | |
235 | "lib/libvirt/connection-driver/libvirt_driver_storage.la", | 217 | "lib/libvirt/connection-driver/libvirt_driver_storage.la", | |
236 | "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la", | 218 | "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la", | |
237 | "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la", | 219 | "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la", | |
238 | "lib/libvirt/lock-driver/lockd.la", | 220 | "lib/libvirt/lock-driver/lockd.la", | |
239 | "${PKGMANDIR}/man1/sh.1", | 221 | "${PKGMANDIR}/man1/sh.1", | |
240 | "share/augeas/lenses/virtlockd.aug", | 222 | "share/augeas/lenses/virtlockd.aug", | |
241 | "share/doc/pkgname-1.0/html/32favicon.png", | 223 | "share/doc/pkgname-1.0/html/32favicon.png", | |
242 | "share/doc/pkgname-1.0/html/404.html", | 224 | "share/doc/pkgname-1.0/html/404.html", | |
243 | "share/doc/pkgname-1.0/html/acl.html", | 225 | "share/doc/pkgname-1.0/html/acl.html", | |
244 | "share/doc/pkgname-1.0/html/aclpolkit.html", | 226 | "share/doc/pkgname-1.0/html/aclpolkit.html", | |
245 | "share/doc/pkgname-1.0/html/windows.html", | 227 | "share/doc/pkgname-1.0/html/windows.html", | |
246 | "share/examples/libvirt/libvirt.conf", | 228 | "share/examples/libvirt/libvirt.conf", | |
247 | "share/locale/zh_CN/LC_MESSAGES/libvirt.mo", | 229 | "share/locale/zh_CN/LC_MESSAGES/libvirt.mo", | |
@@ -261,27 +243,27 @@ func (s *Suite) Test_PlistChecker__autof | @@ -261,27 +243,27 @@ func (s *Suite) Test_PlistChecker__autof | |||
261 | "should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".", | 243 | "should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".", | |
262 | "NOTE: ~/PLIST:6: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".") | 244 | "NOTE: ~/PLIST:6: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".") | |
263 | 245 | |||
264 | t.SetupCommandLine("-Wall", "--autofix") | 246 | t.SetupCommandLine("-Wall", "--autofix") | |
265 | ChecklinesPlist(lines) | 247 | ChecklinesPlist(lines) | |
266 | 248 | |||
267 | fixedLines := LoadExistingLines(fname, false) | 249 | fixedLines := LoadExistingLines(fname, false) | |
268 | 250 | |||
269 | t.CheckOutputLines( | 251 | t.CheckOutputLines( | |
270 | "AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".", | 252 | "AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".", | |
271 | "AUTOFIX: ~/PLIST:2: Sorting the whole file.") | 253 | "AUTOFIX: ~/PLIST:2: Sorting the whole file.") | |
272 | c.Check(len(lines), equals, len(fixedLines)) | 254 | c.Check(len(lines), equals, len(fixedLines)) | |
273 | t.CheckFileLines("PLIST", | 255 | t.CheckFileLines("PLIST", | |
274 | PlistRcsId, | 256 | PlistRcsID, | |
275 | "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la", | 257 | "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la", | |
276 | "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la", | 258 | "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la", | |
277 | "lib/libvirt/connection-driver/libvirt_driver_storage.la", | 259 | "lib/libvirt/connection-driver/libvirt_driver_storage.la", | |
278 | "lib/libvirt/lock-driver/lockd.la", | 260 | "lib/libvirt/lock-driver/lockd.la", | |
279 | "man/man1/sh.1", | 261 | "man/man1/sh.1", | |
280 | "share/augeas/lenses/virtlockd.aug", | 262 | "share/augeas/lenses/virtlockd.aug", | |
281 | "share/doc/pkgname-1.0/html/32favicon.png", | 263 | "share/doc/pkgname-1.0/html/32favicon.png", | |
282 | "share/doc/pkgname-1.0/html/404.html", | 264 | "share/doc/pkgname-1.0/html/404.html", | |
283 | "share/doc/pkgname-1.0/html/acl.html", | 265 | "share/doc/pkgname-1.0/html/acl.html", | |
284 | "share/doc/pkgname-1.0/html/aclpolkit.html", | 266 | "share/doc/pkgname-1.0/html/aclpolkit.html", | |
285 | "share/doc/pkgname-1.0/html/windows.html", | 267 | "share/doc/pkgname-1.0/html/windows.html", | |
286 | "share/examples/libvirt/libvirt.conf", | 268 | "share/examples/libvirt/libvirt.conf", | |
287 | "share/locale/zh_CN/LC_MESSAGES/libvirt.mo", | 269 | "share/locale/zh_CN/LC_MESSAGES/libvirt.mo", | |
@@ -292,27 +274,27 @@ func (s *Suite) Test_PlistChecker__autof | @@ -292,27 +274,27 @@ func (s *Suite) Test_PlistChecker__autof | |||
292 | "@pkgdir etc/logrotate.d", | 274 | "@pkgdir etc/logrotate.d", | |
293 | "@pkgdir etc/sasl2") | 275 | "@pkgdir etc/sasl2") | |
294 | } | 276 | } | |
295 | 277 | |||
296 | // When the same entry appears both with and without a conditional, | 278 | // When the same entry appears both with and without a conditional, | |
297 | // the one with the conditional can be removed. | 279 | // the one with the conditional can be removed. | |
298 | // When the same entry appears with several different conditionals, | 280 | // When the same entry appears with several different conditionals, | |
299 | // all of them must stay. | 281 | // all of them must stay. | |
300 | func (s *Suite) Test_PlistChecker__remove_same_entries(c *check.C) { | 282 | func (s *Suite) Test_PlistChecker__remove_same_entries(c *check.C) { | |
301 | t := s.Init(c) | 283 | t := s.Init(c) | |
302 | 284 | |||
303 | t.SetupCommandLine("-Wall") | 285 | t.SetupCommandLine("-Wall") | |
304 | lines := t.SetupFileLines("PLIST", | 286 | lines := t.SetupFileLines("PLIST", | |
305 | PlistRcsId, | 287 | PlistRcsID, | |
306 | "${PLIST.option1}bin/true", | 288 | "${PLIST.option1}bin/true", | |
307 | "bin/true", | 289 | "bin/true", | |
308 | "${PLIST.option1}bin/true", | 290 | "${PLIST.option1}bin/true", | |
309 | "bin/true", | 291 | "bin/true", | |
310 | "${PLIST.option3}bin/false", | 292 | "${PLIST.option3}bin/false", | |
311 | "${PLIST.option2}bin/false", | 293 | "${PLIST.option2}bin/false", | |
312 | "bin/true") | 294 | "bin/true") | |
313 | 295 | |||
314 | ChecklinesPlist(lines) | 296 | ChecklinesPlist(lines) | |
315 | 297 | |||
316 | t.CheckOutputLines( | 298 | t.CheckOutputLines( | |
317 | "ERROR: ~/PLIST:2: Duplicate filename \"bin/true\", already appeared in line 3.", | 299 | "ERROR: ~/PLIST:2: Duplicate filename \"bin/true\", already appeared in line 3.", | |
318 | "ERROR: ~/PLIST:4: Duplicate filename \"bin/true\", already appeared in line 3.", | 300 | "ERROR: ~/PLIST:4: Duplicate filename \"bin/true\", already appeared in line 3.", | |
@@ -321,18 +303,18 @@ func (s *Suite) Test_PlistChecker__remov | @@ -321,18 +303,18 @@ func (s *Suite) Test_PlistChecker__remov | |||
321 | "ERROR: ~/PLIST:8: Duplicate filename \"bin/true\", already appeared in line 3.") | 303 | "ERROR: ~/PLIST:8: Duplicate filename \"bin/true\", already appeared in line 3.") | |
322 | 304 | |||
323 | t.SetupCommandLine("-Wall", "--autofix") | 305 | t.SetupCommandLine("-Wall", "--autofix") | |
324 | 306 | |||
325 | ChecklinesPlist(lines) | 307 | ChecklinesPlist(lines) | |
326 | 308 | |||
327 | t.CheckOutputLines( | 309 | t.CheckOutputLines( | |
328 | "AUTOFIX: ~/PLIST:2: Deleting this line.", | 310 | "AUTOFIX: ~/PLIST:2: Deleting this line.", | |
329 | "AUTOFIX: ~/PLIST:4: Deleting this line.", | 311 | "AUTOFIX: ~/PLIST:4: Deleting this line.", | |
330 | "AUTOFIX: ~/PLIST:5: Deleting this line.", | 312 | "AUTOFIX: ~/PLIST:5: Deleting this line.", | |
331 | "AUTOFIX: ~/PLIST:8: Deleting this line.", | 313 | "AUTOFIX: ~/PLIST:8: Deleting this line.", | |
332 | "AUTOFIX: ~/PLIST:2: Sorting the whole file.") | 314 | "AUTOFIX: ~/PLIST:2: Sorting the whole file.") | |
333 | t.CheckFileLines("PLIST", | 315 | t.CheckFileLines("PLIST", | |
334 | PlistRcsId, | 316 | PlistRcsID, | |
335 | "${PLIST.option2}bin/false", | 317 | "${PLIST.option2}bin/false", | |
336 | "${PLIST.option3}bin/false", | 318 | "${PLIST.option3}bin/false", | |
337 | "bin/true") | 319 | "bin/true") | |
338 | } | 320 | } |
@@ -14,27 +14,27 @@ const ( | @@ -14,27 +14,27 @@ const ( | |||
14 | reShVarexpansion = `(?:(?:#|##|%|%%|:-|:=|:\?|:\+|\+)[^$\\{}]*)` | 14 | reShVarexpansion = `(?:(?:#|##|%|%%|:-|:=|:\?|:\+|\+)[^$\\{}]*)` | |
15 | reShVaruse = `\$\$` + `(?:` + reShVarname + `|` + `\{` + reShVarname + `(?:` + reShVarexpansion + `)?` + `\})` | 15 | reShVaruse = `\$\$` + `(?:` + reShVarname + `|` + `\{` + reShVarname + `(?:` + reShVarexpansion + `)?` + `\})` | |
16 | reShDollar = `\\\$\$|` + reShVaruse + `|\$\$[,\-/|]` | 16 | reShDollar = `\\\$\$|` + reShVaruse + `|\$\$[,\-/|]` | |
17 | ) | 17 | ) | |
18 | 18 | |||
19 | type ShellLine struct { | 19 | type ShellLine struct { | |
20 | mkline MkLine | 20 | mkline MkLine | |
21 | } | 21 | } | |
22 | 22 | |||
23 | func NewShellLine(mkline MkLine) *ShellLine { | 23 | func NewShellLine(mkline MkLine) *ShellLine { | |
24 | return &ShellLine{mkline} | 24 | return &ShellLine{mkline} | |
25 | } | 25 | } | |
26 | 26 | |||
27 | var shellcommandsContextType = &Vartype{lkNone, BtShellCommands, []AclEntry{{"*", aclpAllRuntime}}, false} | 27 | var shellcommandsContextType = &Vartype{lkNone, BtShellCommands, []ACLEntry{{"*", aclpAllRuntime}}, false} | |
28 | var shellwordVuc = &VarUseContext{shellcommandsContextType, vucTimeUnknown, vucQuotPlain, false} | 28 | var shellwordVuc = &VarUseContext{shellcommandsContextType, vucTimeUnknown, vucQuotPlain, false} | |
29 | 29 | |||
30 | func (shline *ShellLine) CheckWord(token string, checkQuoting bool) { | 30 | func (shline *ShellLine) CheckWord(token string, checkQuoting bool) { | |
31 | if trace.Tracing { | 31 | if trace.Tracing { | |
32 | defer trace.Call(token, checkQuoting)() | 32 | defer trace.Call(token, checkQuoting)() | |
33 | } | 33 | } | |
34 | 34 | |||
35 | if token == "" || hasPrefix(token, "#") { | 35 | if token == "" || hasPrefix(token, "#") { | |
36 | return | 36 | return | |
37 | } | 37 | } | |
38 | 38 | |||
39 | var line = shline.mkline.Line | 39 | var line = shline.mkline.Line | |
40 | 40 | |||
@@ -762,27 +762,27 @@ func (spc *ShellProgramChecker) checkWor | @@ -762,27 +762,27 @@ func (spc *ShellProgramChecker) checkWor | |||
762 | for _, word := range words { | 762 | for _, word := range words { | |
763 | spc.checkWord(word, checkQuoting) | 763 | spc.checkWord(word, checkQuoting) | |
764 | } | 764 | } | |
765 | } | 765 | } | |
766 | 766 | |||
767 | func (spc *ShellProgramChecker) checkWord(word *ShToken, checkQuoting bool) { | 767 | func (spc *ShellProgramChecker) checkWord(word *ShToken, checkQuoting bool) { | |
768 | if trace.Tracing { | 768 | if trace.Tracing { | |
769 | defer trace.Call(word.MkText)() | 769 | defer trace.Call(word.MkText)() | |
770 | } | 770 | } | |
771 | 771 | |||
772 | spc.shline.CheckWord(word.MkText, checkQuoting) | 772 | spc.shline.CheckWord(word.MkText, checkQuoting) | |
773 | } | 773 | } | |
774 | 774 | |||
775 | func (scc *ShellProgramChecker) checkPipeExitcode(line Line, pipeline *MkShPipeline) { | 775 | func (spc *ShellProgramChecker) checkPipeExitcode(line Line, pipeline *MkShPipeline) { | |
776 | if trace.Tracing { | 776 | if trace.Tracing { | |
777 | defer trace.Call()() | 777 | defer trace.Call()() | |
778 | } | 778 | } | |
779 | 779 | |||
780 | oneOf := func(s string, others ...string) bool { | 780 | oneOf := func(s string, others ...string) bool { | |
781 | for _, other := range others { | 781 | for _, other := range others { | |
782 | if s == other { | 782 | if s == other { | |
783 | return true | 783 | return true | |
784 | } | 784 | } | |
785 | } | 785 | } | |
786 | return false | 786 | return false | |
787 | } | 787 | } | |
788 | 788 | |||
@@ -817,35 +817,35 @@ func (scc *ShellProgramChecker) checkPip | @@ -817,35 +817,35 @@ func (scc *ShellProgramChecker) checkPip | |||
817 | line.Warnf("The exitcode of the command at the left of the | operator is ignored.") | 817 | line.Warnf("The exitcode of the command at the left of the | operator is ignored.") | |
818 | } | 818 | } | |
819 | Explain( | 819 | Explain( | |
820 | "In a shell command like \"cat *.txt | grep keyword\", if the command", | 820 | "In a shell command like \"cat *.txt | grep keyword\", if the command", | |
821 | "on the left side of the \"|\" fails, this failure is ignored.", | 821 | "on the left side of the \"|\" fails, this failure is ignored.", | |
822 | "", | 822 | "", | |
823 | "If you need to detect the failure of the left-hand-side command, use", | 823 | "If you need to detect the failure of the left-hand-side command, use", | |
824 | "temporary files to save the output of the command. A good place to", | 824 | "temporary files to save the output of the command. A good place to", | |
825 | "create those files is in ${WRKDIR}.") | 825 | "create those files is in ${WRKDIR}.") | |
826 | } | 826 | } | |
827 | } | 827 | } | |
828 | } | 828 | } | |
829 | 829 | |||
830 | func (scc *ShellProgramChecker) checkSetE(list *MkShList, eflag *bool) { | 830 | func (spc *ShellProgramChecker) checkSetE(list *MkShList, eflag *bool) { | |
831 | if trace.Tracing { | 831 | if trace.Tracing { | |
832 | defer trace.Call()() | 832 | defer trace.Call()() | |
833 | } | 833 | } | |
834 | 834 | |||
835 | // Disabled until the shell parser can recognize "command || exit 1" reliably. | 835 | // Disabled until the shell parser can recognize "command || exit 1" reliably. | |
836 | if false && G.opts.WarnExtra && !*eflag && "the current token" == ";" { | 836 | if false && G.opts.WarnExtra && !*eflag && "the current token" == ";" { | |
837 | *eflag = true | 837 | *eflag = true | |
838 | scc.shline.mkline.Warnf("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", "previous token") | 838 | spc.shline.mkline.Warnf("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", "previous token") | |
839 | Explain( | 839 | Explain( | |
840 | "Normally, when a shell command fails (returns non-zero), the", | 840 | "Normally, when a shell command fails (returns non-zero), the", | |
841 | "remaining commands are still executed. For example, the following", | 841 | "remaining commands are still executed. For example, the following", | |
842 | "commands would remove all files from the HOME directory:", | 842 | "commands would remove all files from the HOME directory:", | |
843 | "", | 843 | "", | |
844 | "\tcd \"$HOME\"; cd /nonexistent; rm -rf *", | 844 | "\tcd \"$HOME\"; cd /nonexistent; rm -rf *", | |
845 | "", | 845 | "", | |
846 | "To fix this warning, you can:", | 846 | "To fix this warning, you can:", | |
847 | "", | 847 | "", | |
848 | "* insert ${RUN} at the beginning of the line", | 848 | "* insert ${RUN} at the beginning of the line", | |
849 | " (which among other things does \"set -e\")", | 849 | " (which among other things does \"set -e\")", | |
850 | "* insert \"set -e\" explicitly at the beginning of the line", | 850 | "* insert \"set -e\" explicitly at the beginning of the line", | |
851 | "* use \"&&\" instead of \";\" to separate the commands") | 851 | "* use \"&&\" instead of \";\" to separate the commands") |
@@ -579,27 +579,27 @@ func (s *Suite) Test_ShellLine_CheckShel | @@ -579,27 +579,27 @@ func (s *Suite) Test_ShellLine_CheckShel | |||
579 | shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2") | 579 | shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2") | |
580 | 580 | |||
581 | shline.CheckShellCommandLine(shline.mkline.Shellcmd()) | 581 | shline.CheckShellCommandLine(shline.mkline.Shellcmd()) | |
582 | 582 | |||
583 | t.CheckOutputLines( | 583 | t.CheckOutputLines( | |
584 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".", | 584 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".", | |
585 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".") | 585 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".") | |
586 | } | 586 | } | |
587 | 587 | |||
588 | func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) { | 588 | func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) { | |
589 | t := s.Init(c) | 589 | t := s.Init(c) | |
590 | 590 | |||
591 | lines := t.SetupFileLinesContinuation("Makefile", | 591 | lines := t.SetupFileLinesContinuation("Makefile", | |
592 | MkRcsId, | 592 | MkRcsID, | |
593 | "pre-install:", | 593 | "pre-install:", | |
594 | "\t"+"# comment\\", | 594 | "\t"+"# comment\\", | |
595 | "\t"+"echo \"hello\"") | 595 | "\t"+"echo \"hello\"") | |
596 | 596 | |||
597 | NewMkLines(lines).Check() | 597 | NewMkLines(lines).Check() | |
598 | 598 | |||
599 | t.CheckOutputLines( | 599 | t.CheckOutputLines( | |
600 | "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.") | 600 | "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.") | |
601 | } | 601 | } | |
602 | 602 | |||
603 | func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) { | 603 | func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) { | |
604 | t := s.Init(c) | 604 | t := s.Init(c) | |
605 | 605 | |||
@@ -612,23 +612,23 @@ func (s *Suite) Test_ShellLine_unescapeB | @@ -612,23 +612,23 @@ func (s *Suite) Test_ShellLine_unescapeB | |||
612 | backtCommand, newQuoting := shline.unescapeBackticks(text, repl, shqDquotBackt) | 612 | backtCommand, newQuoting := shline.unescapeBackticks(text, repl, shqDquotBackt) | |
613 | 613 | |||
614 | c.Check(backtCommand, equals, "echo \"foo bar\"") | 614 | c.Check(backtCommand, equals, "echo \"foo bar\"") | |
615 | c.Check(newQuoting, equals, shqDquot) | 615 | c.Check(newQuoting, equals, shqDquot) | |
616 | c.Check(repl.Rest(), equals, "\"") | 616 | c.Check(repl.Rest(), equals, "\"") | |
617 | } | 617 | } | |
618 | 618 | |||
619 | func (s *Suite) Test_ShellLine__variable_outside_quotes(c *check.C) { | 619 | func (s *Suite) Test_ShellLine__variable_outside_quotes(c *check.C) { | |
620 | t := s.Init(c) | 620 | t := s.Init(c) | |
621 | 621 | |||
622 | t.SetupCommandLine("-Wall") | 622 | t.SetupCommandLine("-Wall") | |
623 | G.globalData.InitVartypes() | 623 | G.globalData.InitVartypes() | |
624 | mklines := t.NewMkLines("dummy.mk", | 624 | mklines := t.NewMkLines("dummy.mk", | |
625 | MkRcsId, | 625 | MkRcsID, | |
626 | "GZIP=\t${ECHO} $$comment") | 626 | "GZIP=\t${ECHO} $$comment") | |
627 | 627 | |||
628 | mklines.Check() | 628 | mklines.Check() | |
629 | 629 | |||
630 | t.CheckOutputLines( | 630 | t.CheckOutputLines( | |
631 | "WARN: dummy.mk:2: The variable GZIP may not be set by any package.", | 631 | "WARN: dummy.mk:2: The variable GZIP may not be set by any package.", | |
632 | "WARN: dummy.mk:2: Unquoted shell variable \"comment\".", | 632 | "WARN: dummy.mk:2: Unquoted shell variable \"comment\".", | |
633 | "WARN: dummy.mk:2: ECHO should not be evaluated indirectly at load time.") | 633 | "WARN: dummy.mk:2: ECHO should not be evaluated indirectly at load time.") | |
634 | } | 634 | } |
@@ -575,26 +575,27 @@ func (gd *GlobalData) InitVartypes() { | @@ -575,26 +575,27 @@ func (gd *GlobalData) InitVartypes() { | |||
575 | pkglist("GENERATE_PLIST", lkNone, BtShellCommands) | 575 | pkglist("GENERATE_PLIST", lkNone, BtShellCommands) | |
576 | pkg("GITHUB_PROJECT", lkNone, BtIdentifier) | 576 | pkg("GITHUB_PROJECT", lkNone, BtIdentifier) | |
577 | pkg("GITHUB_TAG", lkNone, BtIdentifier) | 577 | pkg("GITHUB_TAG", lkNone, BtIdentifier) | |
578 | pkg("GITHUB_RELEASE", lkNone, BtFilename) | 578 | pkg("GITHUB_RELEASE", lkNone, BtFilename) | |
579 | pkg("GITHUB_TYPE", lkNone, enum("tag release")) | 579 | pkg("GITHUB_TYPE", lkNone, enum("tag release")) | |
580 | pkg("GMAKE_REQD", lkNone, BtVersion) | 580 | pkg("GMAKE_REQD", lkNone, BtVersion) | |
581 | acl("GNU_ARCH", lkNone, enum("mips"), "") | 581 | acl("GNU_ARCH", lkNone, enum("mips"), "") | |
582 | acl("GNU_CONFIGURE", lkNone, BtYes, "Makefile, Makefile.common: set") | 582 | acl("GNU_CONFIGURE", lkNone, BtYes, "Makefile, Makefile.common: set") | |
583 | acl("GNU_CONFIGURE_INFODIR", lkNone, BtPathname, "Makefile, Makefile.common: set") | 583 | acl("GNU_CONFIGURE_INFODIR", lkNone, BtPathname, "Makefile, Makefile.common: set") | |
584 | acl("GNU_CONFIGURE_LIBDIR", lkNone, BtPathname, "Makefile, Makefile.common: set") | 584 | acl("GNU_CONFIGURE_LIBDIR", lkNone, BtPathname, "Makefile, Makefile.common: set") | |
585 | pkg("GNU_CONFIGURE_LIBSUBDIR", lkNone, BtPathname) | 585 | pkg("GNU_CONFIGURE_LIBSUBDIR", lkNone, BtPathname) | |
586 | acl("GNU_CONFIGURE_MANDIR", lkNone, BtPathname, "Makefile, Makefile.common: set") | 586 | acl("GNU_CONFIGURE_MANDIR", lkNone, BtPathname, "Makefile, Makefile.common: set") | |
587 | acl("GNU_CONFIGURE_PREFIX", lkNone, BtPathname, "Makefile: set") | 587 | acl("GNU_CONFIGURE_PREFIX", lkNone, BtPathname, "Makefile: set") | |
588 | pkg("GOPATH", lkNone, BtPathname) | |||
588 | acl("HAS_CONFIGURE", lkNone, BtYes, "Makefile, Makefile.common: set") | 589 | acl("HAS_CONFIGURE", lkNone, BtYes, "Makefile, Makefile.common: set") | |
589 | pkglist("HEADER_TEMPLATES", lkShell, BtPathname) | 590 | pkglist("HEADER_TEMPLATES", lkShell, BtPathname) | |
590 | pkg("HOMEPAGE", lkNone, BtHomepage) | 591 | pkg("HOMEPAGE", lkNone, BtHomepage) | |
591 | pkg("ICON_THEMES", lkNone, BtYes) | 592 | pkg("ICON_THEMES", lkNone, BtYes) | |
592 | acl("IGNORE_PKG.*", lkNone, BtYes, "*: set, use-loadtime") | 593 | acl("IGNORE_PKG.*", lkNone, BtYes, "*: set, use-loadtime") | |
593 | sys("IMAKE", lkNone, BtShellCommand) | 594 | sys("IMAKE", lkNone, BtShellCommand) | |
594 | acl("INCOMPAT_CURSES", lkSpace, BtMachinePlatformPattern, "Makefile: set, append") | 595 | acl("INCOMPAT_CURSES", lkSpace, BtMachinePlatformPattern, "Makefile: set, append") | |
595 | acl("INCOMPAT_ICONV", lkSpace, BtMachinePlatformPattern, "") | 596 | acl("INCOMPAT_ICONV", lkSpace, BtMachinePlatformPattern, "") | |
596 | acl("INFO_DIR", lkNone, BtPathname, "") // relative to PREFIX | 597 | acl("INFO_DIR", lkNone, BtPathname, "") // relative to PREFIX | |
597 | pkg("INFO_FILES", lkNone, BtYes) | 598 | pkg("INFO_FILES", lkNone, BtYes) | |
598 | sys("INSTALL", lkNone, BtShellCommand) | 599 | sys("INSTALL", lkNone, BtShellCommand) | |
599 | pkglist("INSTALLATION_DIRS", lkShell, BtPrefixPathname) | 600 | pkglist("INSTALLATION_DIRS", lkShell, BtPrefixPathname) | |
600 | pkg("INSTALLATION_DIRS_FROM_PLIST", lkNone, BtYes) | 601 | pkg("INSTALLATION_DIRS_FROM_PLIST", lkNone, BtYes) | |
@@ -1005,57 +1006,57 @@ func enum(values string) *BasicType { | @@ -1005,57 +1006,57 @@ func enum(values string) *BasicType { | |||
1005 | return | 1006 | return | |
1006 | } | 1007 | } | |
1007 | 1008 | |||
1008 | if cv.Value == cv.ValueNoVar && !vmap[cv.Value] { | 1009 | if cv.Value == cv.ValueNoVar && !vmap[cv.Value] { | |
1009 | cv.Line.Warnf("%q is not valid for %s. Use one of { %s } instead.", cv.Value, cv.Varname, values) | 1010 | cv.Line.Warnf("%q is not valid for %s. Use one of { %s } instead.", cv.Value, cv.Varname, values) | |
1010 | } | 1011 | } | |
1011 | }} | 1012 | }} | |
1012 | } | 1013 | } | |
1013 | 1014 | |||
1014 | func acl(varname string, kindOfList KindOfList, checker *BasicType, aclentries string) { | 1015 | func acl(varname string, kindOfList KindOfList, checker *BasicType, aclentries string) { | |
1015 | m := mustMatch(varname, `^([A-Z_.][A-Z0-9_]*)(|\*|\.\*)$`) | 1016 | m := mustMatch(varname, `^([A-Z_.][A-Z0-9_]*)(|\*|\.\*)$`) | |
1016 | varbase, varparam := m[1], m[2] | 1017 | varbase, varparam := m[1], m[2] | |
1017 | 1018 | |||
1018 | vtype := &Vartype{kindOfList, checker, parseAclEntries(varname, aclentries), false} | 1019 | vtype := &Vartype{kindOfList, checker, parseACLEntries(varname, aclentries), false} | |
1019 | 1020 | |||
1020 | if G.globalData.vartypes == nil { | 1021 | if G.globalData.vartypes == nil { | |
1021 | G.globalData.vartypes = make(map[string]*Vartype) | 1022 | G.globalData.vartypes = make(map[string]*Vartype) | |
1022 | } | 1023 | } | |
1023 | if varparam == "" || varparam == "*" { | 1024 | if varparam == "" || varparam == "*" { | |
1024 | G.globalData.vartypes[varbase] = vtype | 1025 | G.globalData.vartypes[varbase] = vtype | |
1025 | } | 1026 | } | |
1026 | if varparam == "*" || varparam == ".*" { | 1027 | if varparam == "*" || varparam == ".*" { | |
1027 | G.globalData.vartypes[varbase+".*"] = vtype | 1028 | G.globalData.vartypes[varbase+".*"] = vtype | |
1028 | } | 1029 | } | |
1029 | } | 1030 | } | |
1030 | 1031 | |||
1031 | func parseAclEntries(varname string, aclentries string) []AclEntry { | 1032 | func parseACLEntries(varname string, aclentries string) []ACLEntry { | |
1032 | if aclentries == "" { | 1033 | if aclentries == "" { | |
1033 | return nil | 1034 | return nil | |
1034 | } | 1035 | } | |
1035 | var result []AclEntry | 1036 | var result []ACLEntry | |
1036 | prevperms := "(first)" | 1037 | prevperms := "(first)" | |
1037 | for _, arg := range strings.Split(aclentries, "; ") { | 1038 | for _, arg := range strings.Split(aclentries, "; ") { | |
1038 | var globs, perms string | 1039 | var globs, perms string | |
1039 | if fields := strings.SplitN(arg, ": ", 2); len(fields) == 2 { | 1040 | if fields := strings.SplitN(arg, ": ", 2); len(fields) == 2 { | |
1040 | globs, perms = fields[0], fields[1] | 1041 | globs, perms = fields[0], fields[1] | |
1041 | } else { | 1042 | } else { | |
1042 | globs = strings.TrimSuffix(arg, ":") | 1043 | globs = strings.TrimSuffix(arg, ":") | |
1043 | } | 1044 | } | |
1044 | if perms == prevperms { | 1045 | if perms == prevperms { | |
1045 | fmt.Printf("Repeated permissions for %s: %s\n", varname, perms) | 1046 | fmt.Printf("Repeated permissions for %s: %s\n", varname, perms) | |
1046 | } | 1047 | } | |
1047 | prevperms = perms | 1048 | prevperms = perms | |
1048 | var permissions AclPermissions | 1049 | var permissions ACLPermissions | |
1049 | for _, perm := range strings.Split(perms, ", ") { | 1050 | for _, perm := range strings.Split(perms, ", ") { | |
1050 | switch perm { | 1051 | switch perm { | |
1051 | case "append": | 1052 | case "append": | |
1052 | permissions |= aclpAppend | 1053 | permissions |= aclpAppend | |
1053 | case "default": | 1054 | case "default": | |
1054 | permissions |= aclpSetDefault | 1055 | permissions |= aclpSetDefault | |
1055 | case "set": | 1056 | case "set": | |
1056 | permissions |= aclpSet | 1057 | permissions |= aclpSet | |
1057 | case "use": | 1058 | case "use": | |
1058 | permissions |= aclpUse | 1059 | permissions |= aclpUse | |
1059 | case "use-loadtime": | 1060 | case "use-loadtime": | |
1060 | permissions |= aclpUseLoadtime | 1061 | permissions |= aclpUseLoadtime | |
1061 | case "": | 1062 | case "": | |
@@ -1069,18 +1070,18 @@ func parseAclEntries(varname string, acl | @@ -1069,18 +1070,18 @@ func parseAclEntries(varname string, acl | |||
1069 | case "*", | 1070 | case "*", | |
1070 | "Makefile", "Makefile.common", "Makefile.*", | 1071 | "Makefile", "Makefile.common", "Makefile.*", | |
1071 | "buildlink3.mk", "builtin.mk", "options.mk", "hacks.mk", "*.mk", | 1072 | "buildlink3.mk", "builtin.mk", "options.mk", "hacks.mk", "*.mk", | |
1072 | "bsd.options.mk", "pkgconfig-builtin.mk", "pyversion.mk": | 1073 | "bsd.options.mk", "pkgconfig-builtin.mk", "pyversion.mk": | |
1073 | break | 1074 | break | |
1074 | default: | 1075 | default: | |
1075 | print(fmt.Sprintf("Invalid ACL glob %q for varname %q.\n", glob, varname)) | 1076 | print(fmt.Sprintf("Invalid ACL glob %q for varname %q.\n", glob, varname)) | |
1076 | } | 1077 | } | |
1077 | for _, prev := range result { | 1078 | for _, prev := range result { | |
1078 | if matched, err := path.Match(prev.glob, glob); err != nil || matched { | 1079 | if matched, err := path.Match(prev.glob, glob); err != nil || matched { | |
1079 | print(fmt.Sprintf("Ineffective ACL glob %q for varname %q.\n", glob, varname)) | 1080 | print(fmt.Sprintf("Ineffective ACL glob %q for varname %q.\n", glob, varname)) | |
1080 | } | 1081 | } | |
1081 | } | 1082 | } | |
1082 | result = append(result, AclEntry{glob, permissions}) | 1083 | result = append(result, ACLEntry{glob, permissions}) | |
1083 | } | 1084 | } | |
1084 | } | 1085 | } | |
1085 | return result | 1086 | return result | |
1086 | } | 1087 | } |
@@ -1,25 +1,25 @@ | @@ -1,25 +1,25 @@ | |||
1 | package main | 1 | package main | |
2 | 2 | |||
3 | import ( | 3 | import ( | |
4 | check "gopkg.in/check.v1" | 4 | check "gopkg.in/check.v1" | |
5 | ) | 5 | ) | |
6 | 6 | |||
7 | func (s *Suite) Test_Vartype_EffectivePermissions(c *check.C) { | 7 | func (s *Suite) Test_Vartype_EffectivePermissions(c *check.C) { | |
8 | G.globalData.InitVartypes() | 8 | G.globalData.InitVartypes() | |
9 | 9 | |||
10 | if t := G.globalData.vartypes["PREFIX"]; c.Check(t, check.NotNil) { | 10 | if t := G.globalData.vartypes["PREFIX"]; c.Check(t, check.NotNil) { | |
11 | c.Check(t.basicType.name, equals, "Pathname") | 11 | c.Check(t.basicType.name, equals, "Pathname") | |
12 | c.Check(t.aclEntries, check.DeepEquals, []AclEntry{{glob: "*", permissions: aclpUse}}) | 12 | c.Check(t.aclEntries, check.DeepEquals, []ACLEntry{{glob: "*", permissions: aclpUse}}) | |
13 | c.Check(t.EffectivePermissions("Makefile"), equals, aclpUse) | 13 | c.Check(t.EffectivePermissions("Makefile"), equals, aclpUse) | |
14 | } | 14 | } | |
15 | 15 | |||
16 | if t := G.globalData.vartypes["EXTRACT_OPTS"]; c.Check(t, check.NotNil) { | 16 | if t := G.globalData.vartypes["EXTRACT_OPTS"]; c.Check(t, check.NotNil) { | |
17 | c.Check(t.basicType.name, equals, "ShellWord") | 17 | c.Check(t.basicType.name, equals, "ShellWord") | |
18 | c.Check(t.EffectivePermissions("Makefile"), equals, aclpAppend|aclpSet) | 18 | c.Check(t.EffectivePermissions("Makefile"), equals, aclpAppend|aclpSet) | |
19 | c.Check(t.EffectivePermissions("../Makefile"), equals, aclpAppend|aclpSet) | 19 | c.Check(t.EffectivePermissions("../Makefile"), equals, aclpAppend|aclpSet) | |
20 | c.Check(t.EffectivePermissions("options.mk"), equals, aclpUnknown) | 20 | c.Check(t.EffectivePermissions("options.mk"), equals, aclpUnknown) | |
21 | } | 21 | } | |
22 | } | 22 | } | |
23 | 23 | |||
24 | func (s *Suite) Test_VarChecker_HasEnum(c *check.C) { | 24 | func (s *Suite) Test_VarChecker_HasEnum(c *check.C) { | |
25 | vc := enum("catinstall middle maninstall") | 25 | vc := enum("catinstall middle maninstall") | |
@@ -28,17 +28,17 @@ func (s *Suite) Test_VarChecker_HasEnum( | @@ -28,17 +28,17 @@ func (s *Suite) Test_VarChecker_HasEnum( | |||
28 | c.Check(vc.HasEnum("middle"), equals, true) | 28 | c.Check(vc.HasEnum("middle"), equals, true) | |
29 | c.Check(vc.HasEnum("maninstall"), equals, true) | 29 | c.Check(vc.HasEnum("maninstall"), equals, true) | |
30 | } | 30 | } | |
31 | 31 | |||
32 | func (s *Suite) Test_AclPermissions_Contains(c *check.C) { | 32 | func (s *Suite) Test_AclPermissions_Contains(c *check.C) { | |
33 | perms := aclpAllRuntime | 33 | perms := aclpAllRuntime | |
34 | 34 | |||
35 | c.Check(perms.Contains(aclpAllRuntime), equals, true) | 35 | c.Check(perms.Contains(aclpAllRuntime), equals, true) | |
36 | c.Check(perms.Contains(aclpUse), equals, true) | 36 | c.Check(perms.Contains(aclpUse), equals, true) | |
37 | c.Check(perms.Contains(aclpUseLoadtime), equals, false) | 37 | c.Check(perms.Contains(aclpUseLoadtime), equals, false) | |
38 | } | 38 | } | |
39 | 39 | |||
40 | func (s *Suite) Test_AclPermissions_String(c *check.C) { | 40 | func (s *Suite) Test_AclPermissions_String(c *check.C) { | |
41 | c.Check(AclPermissions(0).String(), equals, "none") | 41 | c.Check(ACLPermissions(0).String(), equals, "none") | |
42 | c.Check(aclpAll.String(), equals, "set, set-default, append, use-loadtime, use") | 42 | c.Check(aclpAll.String(), equals, "set, set-default, append, use-loadtime, use") | |
43 | c.Check(aclpUnknown.String(), equals, "unknown") | 43 | c.Check(aclpUnknown.String(), equals, "unknown") | |
44 | } | 44 | } |
@@ -664,27 +664,28 @@ func (cv *VartypeCheck) Pathlist() { | @@ -664,27 +664,28 @@ func (cv *VartypeCheck) Pathlist() { | |||
664 | 664 | |||
665 | // Shell globbing including slashes. | 665 | // Shell globbing including slashes. | |
666 | // See Filemask | 666 | // See Filemask | |
667 | func (cv *VartypeCheck) Pathmask() { | 667 | func (cv *VartypeCheck) Pathmask() { | |
668 | if cv.Op == opUseMatch { | 668 | if cv.Op == opUseMatch { | |
669 | return | 669 | return | |
670 | } | 670 | } | |
671 | if !matches(cv.ValueNoVar, `^[#\-0-9A-Za-z._~+%*?/\[\]]*`) { | 671 | if !matches(cv.ValueNoVar, `^[#\-0-9A-Za-z._~+%*?/\[\]]*`) { | |
672 | cv.Line.Warnf("%q is not a valid pathname mask.", cv.Value) | 672 | cv.Line.Warnf("%q is not a valid pathname mask.", cv.Value) | |
673 | } | 673 | } | |
674 | CheckLineAbsolutePathname(cv.Line, cv.Value) | 674 | CheckLineAbsolutePathname(cv.Line, cv.Value) | |
675 | } | 675 | } | |
676 | 676 | |||
677 | // Like Filename, but including slashes | 677 | // Like Filename, but including slashes. | |
678 | // | |||
678 | // See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266 | 679 | // See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266 | |
679 | func (cv *VartypeCheck) Pathname() { | 680 | func (cv *VartypeCheck) Pathname() { | |
680 | if cv.Op == opUseMatch { | 681 | if cv.Op == opUseMatch { | |
681 | return | 682 | return | |
682 | } | 683 | } | |
683 | if !matches(cv.ValueNoVar, `^[#\-0-9A-Za-z._~+%/]*$`) { | 684 | if !matches(cv.ValueNoVar, `^[#\-0-9A-Za-z._~+%/]*$`) { | |
684 | cv.Line.Warnf("%q is not a valid pathname.", cv.Value) | 685 | cv.Line.Warnf("%q is not a valid pathname.", cv.Value) | |
685 | } | 686 | } | |
686 | CheckLineAbsolutePathname(cv.Line, cv.Value) | 687 | CheckLineAbsolutePathname(cv.Line, cv.Value) | |
687 | } | 688 | } | |
688 | 689 | |||
689 | func (cv *VartypeCheck) Perl5Packlist() { | 690 | func (cv *VartypeCheck) Perl5Packlist() { | |
690 | if cv.Value != cv.ValueNoVar { | 691 | if cv.Value != cv.ValueNoVar { |
@@ -21,32 +21,32 @@ type PrefixReplacer struct { | @@ -21,32 +21,32 @@ type PrefixReplacer struct { | |||
21 | 21 | |||
22 | func NewPrefixReplacer(s string) *PrefixReplacer { | 22 | func NewPrefixReplacer(s string) *PrefixReplacer { | |
23 | return &PrefixReplacer{s, "", nil} | 23 | return &PrefixReplacer{s, "", nil} | |
24 | } | 24 | } | |
25 | 25 | |||
26 | func (pr *PrefixReplacer) EOF() bool { | 26 | func (pr *PrefixReplacer) EOF() bool { | |
27 | return pr.rest == "" | 27 | return pr.rest == "" | |
28 | } | 28 | } | |
29 | 29 | |||
30 | func (pr *PrefixReplacer) Rest() string { | 30 | func (pr *PrefixReplacer) Rest() string { | |
31 | return pr.rest | 31 | return pr.rest | |
32 | } | 32 | } | |
33 | 33 | |||
34 | // Match returns a matching group from the last matched AdvanceRegexp. | 34 | // Group returns a matching group from the last matched AdvanceRegexp. | |
35 | func (pr *PrefixReplacer) Group(index int) string { | 35 | func (pr *PrefixReplacer) Group(index int) string { | |
36 | return pr.m[index] | 36 | return pr.m[index] | |
37 | } | 37 | } | |
38 | 38 | |||
39 | // Rest returns the last match from AdvanceStr, AdvanceBytesFunc or AdvanceHspace. | 39 | // Str returns the last match from AdvanceStr, AdvanceBytesFunc or AdvanceHspace. | |
40 | func (pr *PrefixReplacer) Str() string { | 40 | func (pr *PrefixReplacer) Str() string { | |
41 | return pr.s | 41 | return pr.s | |
42 | } | 42 | } | |
43 | 43 | |||
44 | func (pr *PrefixReplacer) AdvanceStr(prefix string) bool { | 44 | func (pr *PrefixReplacer) AdvanceStr(prefix string) bool { | |
45 | pr.m = nil | 45 | pr.m = nil | |
46 | pr.s = "" | 46 | pr.s = "" | |
47 | if strings.HasPrefix(pr.rest, prefix) { | 47 | if strings.HasPrefix(pr.rest, prefix) { | |
48 | if trace.Tracing { | 48 | if trace.Tracing { | |
49 | trace.Stepf("PrefixReplacer.AdvanceStr(%q, %q)", pr.rest, prefix) | 49 | trace.Stepf("PrefixReplacer.AdvanceStr(%q, %q)", pr.rest, prefix) | |
50 | } | 50 | } | |
51 | pr.s = prefix | 51 | pr.s = prefix | |
52 | pr.rest = pr.rest[len(prefix):] | 52 | pr.rest = pr.rest[len(prefix):] |