pkgtools/pkglint: Update to 5.5.16 Changes since 5.5.15: * Add checks for options.mk files * Treat redundant variable definitions as notes, not as warnings * Check doc/CHANGES-* for typos in the dates (only for 2018 and later) * Lots of cleanup in the test codediff -r1.543 -r1.544 pkgsrc/pkgtools/pkglint/Makefile
(rillig)
@@ -1,16 +1,16 @@ | @@ -1,16 +1,16 @@ | |||
1 | # $NetBSD: Makefile,v 1.543 2018/07/28 18:31:23 rillig Exp $ | 1 | # $NetBSD: Makefile,v 1.544 2018/08/09 20:08:12 rillig Exp $ | |
2 | 2 | |||
3 | PKGNAME= pkglint-5.5.15 | 3 | PKGNAME= pkglint-5.5.16 | |
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_TOOLS+= pax | 14 | USE_TOOLS+= pax | |
15 | AUTO_MKDIRS= yes | 15 | AUTO_MKDIRS= yes | |
16 | GO_SRCPATH= netbsd.org/pkglint | 16 | GO_SRCPATH= netbsd.org/pkglint |
@@ -247,32 +247,32 @@ func (s *Suite) Test_Autofix_multiple_mo | @@ -247,32 +247,32 @@ func (s *Suite) Test_Autofix_multiple_mo | |||
247 | "between before and middle\n"}) | 247 | "between before and middle\n"}) | |
248 | c.Check(line.autofix.lines[0].textnl, equals, "") | 248 | c.Check(line.autofix.lines[0].textnl, equals, "") | |
249 | c.Check(line.autofix.linesAfter, deepEquals, []string{ | 249 | c.Check(line.autofix.linesAfter, deepEquals, []string{ | |
250 | "between middle and after\n", | 250 | "between middle and after\n", | |
251 | "after\n"}) | 251 | "after\n"}) | |
252 | t.CheckOutputLines( | 252 | t.CheckOutputLines( | |
253 | "AUTOFIX: fname:1: Deleting this line.") | 253 | "AUTOFIX: fname:1: Deleting this line.") | |
254 | } | 254 | } | |
255 | 255 | |||
256 | func (s *Suite) Test_Autofix_show_source_code(c *check.C) { | 256 | func (s *Suite) Test_Autofix_show_source_code(c *check.C) { | |
257 | t := s.Init(c) | 257 | t := s.Init(c) | |
258 | 258 | |||
259 | t.SetupCommandLine("--show-autofix", "--source") | 259 | t.SetupCommandLine("--show-autofix", "--source") | |
260 | lines := t.SetupFileLinesContinuation("Makefile", | 260 | mklines := t.SetupFileMkLines("Makefile", | |
261 | MkRcsID, | 261 | MkRcsID, | |
262 | "before \\", | 262 | "before \\", | |
263 | "The old song \\", | 263 | "The old song \\", | |
264 | "after") | 264 | "after") | |
265 | line := lines[1] | 265 | line := mklines.lines[1] | |
266 | 266 | |||
267 | { | 267 | { | |
268 | fix := line.Autofix() | 268 | fix := line.Autofix() | |
269 | fix.Warnf("Using \"old\" is deprecated.") | 269 | fix.Warnf("Using \"old\" is deprecated.") | |
270 | fix.Replace("old", "new") | 270 | fix.Replace("old", "new") | |
271 | fix.Apply() | 271 | fix.Apply() | |
272 | } | 272 | } | |
273 | 273 | |||
274 | t.CheckOutputLines( | 274 | t.CheckOutputLines( | |
275 | "WARN: ~/Makefile:2--4: Using \"old\" is deprecated.", | 275 | "WARN: ~/Makefile:2--4: Using \"old\" is deprecated.", | |
276 | "AUTOFIX: ~/Makefile:3: Replacing \"old\" with \"new\".", | 276 | "AUTOFIX: ~/Makefile:3: Replacing \"old\" with \"new\".", | |
277 | ">\tbefore \\", | 277 | ">\tbefore \\", | |
278 | "-\tThe old song \\", | 278 | "-\tThe old song \\", |
@@ -144,29 +144,30 @@ func (t *Tester) SetupTool(tool *Tool) { | @@ -144,29 +144,30 @@ func (t *Tester) SetupTool(tool *Tool) { | |||
144 | reg.byVarname[tool.Varname] = tool | 144 | reg.byVarname[tool.Varname] = tool | |
145 | } | 145 | } | |
146 | } | 146 | } | |
147 | 147 | |||
148 | // SetupFileLines creates a temporary file and writes the given lines to it. | 148 | // SetupFileLines creates a temporary file and writes the given lines to it. | |
149 | // The file is then read in, without considering line continuations. | 149 | // The file is then read in, without considering line continuations. | |
150 | func (t *Tester) SetupFileLines(relativeFilename string, lines ...string) []Line { | 150 | func (t *Tester) SetupFileLines(relativeFilename string, lines ...string) []Line { | |
151 | filename := t.CreateFileLines(relativeFilename, lines...) | 151 | filename := t.CreateFileLines(relativeFilename, lines...) | |
152 | return LoadExistingLines(filename, false) | 152 | return LoadExistingLines(filename, false) | |
153 | } | 153 | } | |
154 | 154 | |||
155 | // SetupFileLines creates a temporary file and writes the given lines to it. | 155 | // SetupFileLines creates a temporary file and writes the given lines to it. | |
156 | // The file is then read in, handling line continuations for Makefiles. | 156 | // The file is then read in, handling line continuations for Makefiles. | |
157 | func (t *Tester) SetupFileLinesContinuation(relativeFilename string, lines ...string) []Line { | 157 | func (t *Tester) SetupFileMkLines(relativeFilename string, lines ...string) *MkLines { | |
158 | filename := t.CreateFileLines(relativeFilename, lines...) | 158 | filename := t.CreateFileLines(relativeFilename, lines...) | |
159 | return LoadExistingLines(filename, true) | 159 | plainLines := LoadExistingLines(filename, true) | |
160 | return NewMkLines(plainLines) | |||
160 | } | 161 | } | |
161 | 162 | |||
162 | func (t *Tester) CreateFileLines(relativeFilename string, lines ...string) (filename string) { | 163 | func (t *Tester) CreateFileLines(relativeFilename string, lines ...string) (filename string) { | |
163 | content := "" | 164 | content := "" | |
164 | for _, line := range lines { | 165 | for _, line := range lines { | |
165 | content += line + "\n" | 166 | content += line + "\n" | |
166 | } | 167 | } | |
167 | 168 | |||
168 | filename = t.TempFilename(relativeFilename) | 169 | filename = t.TempFilename(relativeFilename) | |
169 | err := os.MkdirAll(path.Dir(filename), 0777) | 170 | err := os.MkdirAll(path.Dir(filename), 0777) | |
170 | t.c().Assert(err, check.IsNil) | 171 | t.c().Assert(err, check.IsNil) | |
171 | 172 | |||
172 | err = ioutil.WriteFile(filename, []byte(content), 0666) | 173 | err = ioutil.WriteFile(filename, []byte(content), 0666) |
@@ -72,26 +72,36 @@ func (exp *Expecter) AdvanceIfPrefix(pre | @@ -72,26 +72,36 @@ func (exp *Expecter) AdvanceIfPrefix(pre | |||
72 | } | 72 | } | |
73 | 73 | |||
74 | return !exp.EOF() && strings.HasPrefix(exp.lines[exp.index].Text, prefix) && exp.Advance() | 74 | return !exp.EOF() && strings.HasPrefix(exp.lines[exp.index].Text, prefix) && exp.Advance() | |
75 | } | 75 | } | |
76 | 76 | |||
77 | func (exp *Expecter) AdvanceIfEquals(text string) bool { | 77 | func (exp *Expecter) AdvanceIfEquals(text string) bool { | |
78 | if trace.Tracing { | 78 | if trace.Tracing { | |
79 | defer trace.Call2(exp.CurrentLine().Text, text)() | 79 | defer trace.Call2(exp.CurrentLine().Text, text)() | |
80 | } | 80 | } | |
81 | 81 | |||
82 | return !exp.EOF() && exp.lines[exp.index].Text == text && exp.Advance() | 82 | return !exp.EOF() && exp.lines[exp.index].Text == text && exp.Advance() | |
83 | } | 83 | } | |
84 | 84 | |||
85 | func (exp *Expecter) AdvanceWhile(pred func(line Line) bool) { | |||
86 | if trace.Tracing { | |||
87 | defer trace.Call(exp.CurrentLine().Text)() | |||
88 | } | |||
89 | ||||
90 | for !exp.EOF() && !pred(exp.CurrentLine()) { | |||
91 | exp.Advance() | |||
92 | } | |||
93 | } | |||
94 | ||||
85 | func (exp *Expecter) ExpectEmptyLine(warnSpace bool) bool { | 95 | func (exp *Expecter) ExpectEmptyLine(warnSpace bool) bool { | |
86 | if exp.AdvanceIfEquals("") { | 96 | if exp.AdvanceIfEquals("") { | |
87 | return true | 97 | return true | |
88 | } | 98 | } | |
89 | 99 | |||
90 | if warnSpace { | 100 | if warnSpace { | |
91 | fix := exp.CurrentLine().Autofix() | 101 | fix := exp.CurrentLine().Autofix() | |
92 | fix.Notef("Empty line expected.") | 102 | fix.Notef("Empty line expected.") | |
93 | fix.InsertBefore("") | 103 | fix.InsertBefore("") | |
94 | fix.Apply() | 104 | fix.Apply() | |
95 | } | 105 | } | |
96 | return false | 106 | return false | |
97 | } | 107 | } | |
@@ -100,13 +110,41 @@ func (exp *Expecter) ExpectText(text str | @@ -100,13 +110,41 @@ func (exp *Expecter) ExpectText(text str | |||
100 | if !exp.EOF() && exp.lines[exp.index].Text == text { | 110 | if !exp.EOF() && exp.lines[exp.index].Text == text { | |
101 | exp.index++ | 111 | exp.index++ | |
102 | exp.m = nil | 112 | exp.m = nil | |
103 | return true | 113 | return true | |
104 | } | 114 | } | |
105 | 115 | |||
106 | exp.CurrentLine().Warnf("This line should contain the following text: %s", text) | 116 | exp.CurrentLine().Warnf("This line should contain the following text: %s", text) | |
107 | return false | 117 | return false | |
108 | } | 118 | } | |
109 | 119 | |||
110 | func (exp *Expecter) SkipToFooter() { | 120 | func (exp *Expecter) SkipToFooter() { | |
111 | exp.index = len(exp.lines) - 2 | 121 | exp.index = len(exp.lines) - 2 | |
112 | } | 122 | } | |
123 | ||||
124 | // MkExpecter records the state when checking a list of Makefile lines from top to bottom. | |||
125 | type MkExpecter struct { | |||
126 | mklines *MkLines | |||
127 | Expecter | |||
128 | } | |||
129 | ||||
130 | func NewMkExpecter(mklines *MkLines) *MkExpecter { | |||
131 | return &MkExpecter{mklines, *NewExpecter(mklines.lines)} | |||
132 | } | |||
133 | ||||
134 | func (exp *MkExpecter) CurrentMkLine() MkLine { | |||
135 | return exp.mklines.mklines[exp.index] | |||
136 | } | |||
137 | ||||
138 | func (exp *MkExpecter) PreviousMkLine() MkLine { | |||
139 | return exp.mklines.mklines[exp.index-1] | |||
140 | } | |||
141 | ||||
142 | func (exp *MkExpecter) AdvanceWhile(pred func(mkline MkLine) bool) { | |||
143 | if trace.Tracing { | |||
144 | defer trace.Call(exp.CurrentMkLine().Text)() | |||
145 | } | |||
146 | ||||
147 | for !exp.EOF() && pred(exp.CurrentMkLine()) { | |||
148 | exp.Advance() | |||
149 | } | |||
150 | } |
@@ -320,81 +320,78 @@ func (s *Suite) Test_MkLineChecker_Check | @@ -320,81 +320,78 @@ func (s *Suite) Test_MkLineChecker_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 | t.SetupVartypes() | 332 | t.SetupVartypes() | |
333 | lines := t.SetupFileLinesContinuation("options.mk", | 333 | mklines := t.SetupFileMkLines("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) | |||
341 | 340 | |||
342 | mklines.Check() | 341 | mklines.Check() | |
343 | 342 | |||
344 | t.CheckOutputLines( | 343 | t.CheckOutputLines( | |
345 | "AUTOFIX: ~/options.mk:3: Replacing \".\" with \". \".", | 344 | "AUTOFIX: ~/options.mk:3: Replacing \".\" with \". \".", | |
346 | "AUTOFIX: ~/options.mk:5: Replacing \".\" with \". \".") | 345 | "AUTOFIX: ~/options.mk:5: Replacing \".\" with \". \".") | |
347 | 346 | |||
348 | t.CheckFileLines("options.mk", | 347 | t.CheckFileLines("options.mk", | |
349 | MkRcsID, | 348 | MkRcsID, | |
350 | ".if ${PKGNAME} == pkgname", | 349 | ".if ${PKGNAME} == pkgname", | |
351 | ". if \\", | 350 | ". if \\", | |
352 | " ${PLATFORM:MNetBSD-4.*}", | 351 | " ${PLATFORM:MNetBSD-4.*}", | |
353 | ". endif", | 352 | ". endif", | |
354 | ".endif") | 353 | ".endif") | |
355 | } | 354 | } | |
356 | 355 | |||
357 | func (s *Suite) Test_MkLineChecker_CheckVaruseShellword(c *check.C) { | 356 | func (s *Suite) Test_MkLineChecker_CheckVaruseShellword(c *check.C) { | |
358 | t := s.Init(c) | 357 | t := s.Init(c) | |
359 | 358 | |||
360 | t.SetupCommandLine("-Wall") | 359 | t.SetupCommandLine("-Wall") | |
361 | t.SetupVartypes() | 360 | t.SetupVartypes() | |
362 | lines := t.SetupFileLinesContinuation("options.mk", | 361 | mklines := t.SetupFileMkLines("options.mk", | |
363 | MkRcsID, | 362 | MkRcsID, | |
364 | "GOPATH=\t${WRKDIR}", | 363 | "GOPATH=\t${WRKDIR}", | |
365 | "do-build:", | 364 | "do-build:", | |
366 | "\tcd ${WRKSRC} && GOPATH=${GOPATH} PATH=${PATH} :") | 365 | "\tcd ${WRKSRC} && GOPATH=${GOPATH} PATH=${PATH} :") | |
367 | mklines := NewMkLines(lines) | |||
368 | 366 | |||
369 | mklines.Check() | 367 | mklines.Check() | |
370 | 368 | |||
371 | // For WRKSRC and GOPATH, no quoting is necessary since pkgsrc directories by | 369 | // 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 | 370 | // definition don't contain special characters. Therefore they don't need the | |
373 | // :Q, not even when used as part of a shell word. | 371 | // :Q, not even when used as part of a shell word. | |
374 | 372 | |||
375 | // For PATH, the quoting is necessary because it may contain directories outside | 373 | // For PATH, the quoting is necessary because it may contain directories outside | |
376 | // of pkgsrc, and these may contain special characters. | 374 | // of pkgsrc, and these may contain special characters. | |
377 | 375 | |||
378 | t.CheckOutputLines( | 376 | t.CheckOutputLines( | |
379 | "WARN: ~/options.mk:4: The variable PATH should be quoted as part of a shell word.") | 377 | "WARN: ~/options.mk:4: The variable PATH should be quoted as part of a shell word.") | |
380 | } | 378 | } | |
381 | 379 | |||
382 | // The ${VARNAME:=suffix} should only be used with lists. | 380 | // The ${VARNAME:=suffix} should only be used with lists. | |
383 | // It typically appears in MASTER_SITE definitions. | 381 | // It typically appears in MASTER_SITE definitions. | |
384 | func (s *Suite) Test_MkLineChecker_CheckVaruse_eq_nonlist(c *check.C) { | 382 | func (s *Suite) Test_MkLineChecker_CheckVaruse_eq_nonlist(c *check.C) { | |
385 | t := s.Init(c) | 383 | t := s.Init(c) | |
386 | 384 | |||
387 | t.SetupCommandLine("-Wall") | 385 | t.SetupCommandLine("-Wall") | |
388 | t.SetupVartypes() | 386 | t.SetupVartypes() | |
389 | t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/") | 387 | t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/") | |
390 | lines := t.SetupFileLinesContinuation("options.mk", | 388 | mklines := t.SetupFileMkLines("options.mk", | |
391 | MkRcsID, | 389 | MkRcsID, | |
392 | "WRKSRC=\t\t${WRKDIR:=/subdir}", | 390 | "WRKSRC=\t\t${WRKDIR:=/subdir}", | |
393 | "MASTER_SITES=\t${MASTER_SITE_GITHUB:=organization/}") | 391 | "MASTER_SITES=\t${MASTER_SITE_GITHUB:=organization/}") | |
394 | mklines := NewMkLines(lines) | |||
395 | 392 | |||
396 | mklines.Check() | 393 | mklines.Check() | |
397 | 394 | |||
398 | t.CheckOutputLines( | 395 | t.CheckOutputLines( | |
399 | "WARN: ~/options.mk:2: The :from=to modifier should only be used with lists.") | 396 | "WARN: ~/options.mk:2: The :from=to modifier should only be used with lists.") | |
400 | } | 397 | } |
@@ -24,76 +24,76 @@ func (s *Suite) Test_convertToLogicalLin | @@ -24,76 +24,76 @@ func (s *Suite) Test_convertToLogicalLin | |||
24 | 24 | |||
25 | lines := convertToLogicalLines("fname_cont", rawText, true) | 25 | lines := convertToLogicalLines("fname_cont", rawText, true) | |
26 | 26 | |||
27 | c.Check(lines, check.HasLen, 2) | 27 | c.Check(lines, check.HasLen, 2) | |
28 | c.Check(lines[0].String(), equals, "fname_cont:1--2: first line second line") | 28 | c.Check(lines[0].String(), equals, "fname_cont:1--2: first line second line") | |
29 | c.Check(lines[1].String(), equals, "fname_cont:3: third") | 29 | c.Check(lines[1].String(), equals, "fname_cont:3: third") | |
30 | } | 30 | } | |
31 | 31 | |||
32 | // In Makefiles, comment lines can also have continuations. | 32 | // In Makefiles, comment lines can also have continuations. | |
33 | // See devel/bmake/files/unit-tests/comment.mk | 33 | // See devel/bmake/files/unit-tests/comment.mk | |
34 | func (s *Suite) Test_convertToLogicalLines__comments(c *check.C) { | 34 | func (s *Suite) Test_convertToLogicalLines__comments(c *check.C) { | |
35 | t := s.Init(c) | 35 | t := s.Init(c) | |
36 | 36 | |||
37 | lines := t.SetupFileLinesContinuation("comment.mk", | 37 | mklines := t.SetupFileMkLines("comment.mk", | |
38 | "# This is a comment", | 38 | "# This is a comment", | |
39 | "", | 39 | "", | |
40 | "#\\", | 40 | "#\\", | |
41 | "\tMultiline comment", | 41 | "\tMultiline comment", | |
42 | "# Another escaped comment \\", | 42 | "# Another escaped comment \\", | |
43 | "that \\", | 43 | "that \\", | |
44 | "goes \\", | 44 | "goes \\", | |
45 | "on", | 45 | "on", | |
46 | "# This is NOT an escaped comment due to the double backslashes \\\\", | 46 | "# This is NOT an escaped comment due to the double backslashes \\\\", | |
47 | "VAR=\tThis is not a comment", | 47 | "VAR=\tThis is not a comment", | |
48 | "", | 48 | "", | |
49 | "#\\", | 49 | "#\\", | |
50 | "This is a comment", | 50 | "This is a comment", | |
51 | "#\\\\", | 51 | "#\\\\", | |
52 | "This is no comment", | 52 | "This is no comment", | |
53 | "#\\\\\\", | 53 | "#\\\\\\", | |
54 | "This is a comment", | 54 | "This is a comment", | |
55 | "#\\\\\\\\", | 55 | "#\\\\\\\\", | |
56 | "This is no comment", | 56 | "This is no comment", | |
57 | "#\\\\\\\\\\", | 57 | "#\\\\\\\\\\", | |
58 | "This is a comment", | 58 | "This is a comment", | |
59 | "#\\\\\\\\\\\\", | 59 | "#\\\\\\\\\\\\", | |
60 | "This is no comment") | 60 | "This is no comment") | |
61 | 61 | |||
62 | var texts []string | 62 | var texts []string | |
63 | for _, line := range lines { | 63 | for _, line := range mklines.lines { | |
64 | texts = append(texts, line.Text) | 64 | texts = append(texts, line.Text) | |
65 | } | 65 | } | |
66 | 66 | |||
67 | c.Check(texts, deepEquals, []string{ | 67 | c.Check(texts, deepEquals, []string{ | |
68 | "# This is a comment", | 68 | "# This is a comment", | |
69 | "", | 69 | "", | |
70 | "# Multiline comment", | 70 | "# Multiline comment", | |
71 | "# Another escaped comment that goes on", | 71 | "# Another escaped comment that goes on", | |
72 | "# This is NOT an escaped comment due to the double backslashes \\", | 72 | "# This is NOT an escaped comment due to the double backslashes \\", | |
73 | "VAR=\tThis is not a comment", | 73 | "VAR=\tThis is not a comment", | |
74 | "", | 74 | "", | |
75 | "# This is a comment", | 75 | "# This is a comment", | |
76 | "#\\", | 76 | "#\\", | |
77 | "This is no comment", | 77 | "This is no comment", | |
78 | "#\\ This is a comment", | 78 | "#\\ This is a comment", | |
79 | "#\\\\", | 79 | "#\\\\", | |
80 | "This is no comment", | 80 | "This is no comment", | |
81 | "#\\\\ This is a comment", | 81 | "#\\\\ This is a comment", | |
82 | "#\\\\\\", | 82 | "#\\\\\\", | |
83 | "This is no comment"}) | 83 | "This is no comment"}) | |
84 | 84 | |||
85 | var rawTexts []string | 85 | var rawTexts []string | |
86 | for _, line := range lines { | 86 | for _, line := range mklines.lines { | |
87 | for _, rawLine := range line.raw { | 87 | for _, rawLine := range line.raw { | |
88 | rawTexts = append(rawTexts, rawLine.textnl) | 88 | rawTexts = append(rawTexts, rawLine.textnl) | |
89 | } | 89 | } | |
90 | } | 90 | } | |
91 | 91 | |||
92 | c.Check(rawTexts, deepEquals, []string{ | 92 | c.Check(rawTexts, deepEquals, []string{ | |
93 | "# This is a comment\n", | 93 | "# This is a comment\n", | |
94 | "\n", | 94 | "\n", | |
95 | "#\\\n", | 95 | "#\\\n", | |
96 | "\tMultiline comment\n", | 96 | "\tMultiline comment\n", | |
97 | "# Another escaped comment \\\n", | 97 | "# Another escaped comment \\\n", | |
98 | "that \\\n", | 98 | "that \\\n", | |
99 | "goes \\\n", | 99 | "goes \\\n", | |
@@ -103,26 +103,32 @@ func (s *Suite) Test_convertToLogicalLin | @@ -103,26 +103,32 @@ func (s *Suite) Test_convertToLogicalLin | |||
103 | "\n", | 103 | "\n", | |
104 | "#\\\n", | 104 | "#\\\n", | |
105 | "This is a comment\n", | 105 | "This is a comment\n", | |
106 | "#\\\\\n", | 106 | "#\\\\\n", | |
107 | "This is no comment\n", | 107 | "This is no comment\n", | |
108 | "#\\\\\\\n", | 108 | "#\\\\\\\n", | |
109 | "This is a comment\n", | 109 | "This is a comment\n", | |
110 | "#\\\\\\\\\n", | 110 | "#\\\\\\\\\n", | |
111 | "This is no comment\n", | 111 | "This is no comment\n", | |
112 | "#\\\\\\\\\\\n", | 112 | "#\\\\\\\\\\\n", | |
113 | "This is a comment\n", | 113 | "This is a comment\n", | |
114 | "#\\\\\\\\\\\\\n", | 114 | "#\\\\\\\\\\\\\n", | |
115 | "This is no comment\n"}) | 115 | "This is no comment\n"}) | |
116 | ||||
117 | // This is just a side-effect and not relevant for this particular test. | |||
118 | t.CheckOutputLines( | |||
119 | "ERROR: ~/comment.mk:15: Unknown Makefile line format.", | |||
120 | "ERROR: ~/comment.mk:19: Unknown Makefile line format.", | |||
121 | "ERROR: ~/comment.mk:23: Unknown Makefile line format.") | |||
116 | } | 122 | } | |
117 | 123 | |||
118 | func (s *Suite) Test_convertToLogicalLines_continuationInLastLine(c *check.C) { | 124 | func (s *Suite) Test_convertToLogicalLines_continuationInLastLine(c *check.C) { | |
119 | t := s.Init(c) | 125 | t := s.Init(c) | |
120 | 126 | |||
121 | rawText := "" + | 127 | rawText := "" + | |
122 | "last line\\" | 128 | "last line\\" | |
123 | 129 | |||
124 | lines := convertToLogicalLines("fname_contlast", rawText, true) | 130 | lines := convertToLogicalLines("fname_contlast", rawText, true) | |
125 | 131 | |||
126 | c.Check(lines, check.HasLen, 1) | 132 | c.Check(lines, check.HasLen, 1) | |
127 | c.Check(lines[0].String(), equals, "fname_contlast:1: last line\\") | 133 | c.Check(lines[0].String(), equals, "fname_contlast:1: last line\\") | |
128 | t.CheckOutputLines( | 134 | t.CheckOutputLines( |
@@ -669,33 +669,32 @@ func (s *Suite) Test_MkLine_variableNeed | @@ -669,33 +669,32 @@ func (s *Suite) Test_MkLine_variableNeed | |||
669 | "WARN: Makefile:4: The variable COMMENT should be quoted as part of a shell word.") | 669 | "WARN: Makefile:4: The variable COMMENT should be quoted as part of a shell word.") | |
670 | } | 670 | } | |
671 | 671 | |||
672 | // For some well-known directory variables like WRKDIR, PREFIX, LOCALBASE, | 672 | // For some well-known directory variables like WRKDIR, PREFIX, LOCALBASE, | |
673 | // 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 | |
674 | // having special characters in these directory names. | 674 | // having special characters in these directory names. | |
675 | // For guessed variable types be cautious and don't autofix them. | 675 | // For guessed variable types be cautious and don't autofix them. | |
676 | 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) { | |
677 | t := s.Init(c) | 677 | t := s.Init(c) | |
678 | 678 | |||
679 | t.SetupCommandLine("-Wall", "--autofix") | 679 | t.SetupCommandLine("-Wall", "--autofix") | |
680 | t.SetupVartypes() | 680 | t.SetupVartypes() | |
681 | 681 | |||
682 | lines := t.SetupFileLinesContinuation("Makefile", | 682 | mklines := t.SetupFileMkLines("Makefile", | |
683 | MkRcsID, | 683 | MkRcsID, | |
684 | "", | 684 | "", | |
685 | "demo: .PHONY", | 685 | "demo: .PHONY", | |
686 | "\t${ECHO} ${WRKSRC:Q}", | 686 | "\t${ECHO} ${WRKSRC:Q}", | |
687 | "\t${ECHO} ${FOODIR:Q}") | 687 | "\t${ECHO} ${FOODIR:Q}") | |
688 | mklines := NewMkLines(lines) | |||
689 | 688 | |||
690 | mklines.Check() | 689 | mklines.Check() | |
691 | 690 | |||
692 | t.CheckOutputLines( | 691 | t.CheckOutputLines( | |
693 | "AUTOFIX: ~/Makefile:4: Replacing \"${WRKSRC:Q}\" with \"${WRKSRC}\".") | 692 | "AUTOFIX: ~/Makefile:4: Replacing \"${WRKSRC:Q}\" with \"${WRKSRC}\".") | |
694 | t.CheckFileLines("Makefile", | 693 | t.CheckFileLines("Makefile", | |
695 | MkRcsID, | 694 | MkRcsID, | |
696 | "", | 695 | "", | |
697 | "demo: .PHONY", | 696 | "demo: .PHONY", | |
698 | "\t${ECHO} ${WRKSRC}", | 697 | "\t${ECHO} ${WRKSRC}", | |
699 | "\t${ECHO} ${FOODIR:Q}") | 698 | "\t${ECHO} ${FOODIR:Q}") | |
700 | } | 699 | } | |
701 | 700 |
@@ -589,24 +589,36 @@ func (s *Suite) Test_MkLines_CheckRedund | @@ -589,24 +589,36 @@ func (s *Suite) Test_MkLines_CheckRedund | |||
589 | } | 589 | } | |
590 | 590 | |||
591 | func (s *Suite) Test_MkLines_CheckRedundantVariables__different_value(c *check.C) { | 591 | func (s *Suite) Test_MkLines_CheckRedundantVariables__different_value(c *check.C) { | |
592 | t := s.Init(c) | 592 | t := s.Init(c) | |
593 | mklines := t.NewMkLines("module.mk", | 593 | mklines := t.NewMkLines("module.mk", | |
594 | "VAR=\tvalue ${OTHER}", | 594 | "VAR=\tvalue ${OTHER}", | |
595 | "VAR?=\tdifferent value") | 595 | "VAR?=\tdifferent value") | |
596 | 596 | |||
597 | mklines.CheckRedundantVariables() | 597 | mklines.CheckRedundantVariables() | |
598 | 598 | |||
599 | t.CheckOutputEmpty() | 599 | t.CheckOutputEmpty() | |
600 | } | 600 | } | |
601 | 601 | |||
602 | func (s *Suite) Test_MkLines_CheckRedundantVariables__overwrite_same_value(c *check.C) { | |||
603 | t := s.Init(c) | |||
604 | mklines := t.NewMkLines("module.mk", | |||
605 | "VAR=\tvalue ${OTHER}", | |||
606 | "VAR=\tvalue ${OTHER}") | |||
607 | ||||
608 | mklines.CheckRedundantVariables() | |||
609 | ||||
610 | t.CheckOutputLines( | |||
611 | "NOTE: module.mk:1: Definition of VAR is redundant because of line 2.") | |||
612 | } | |||
613 | ||||
602 | func (s *Suite) Test_MkLines_CheckRedundantVariables__procedure_call(c *check.C) { | 614 | func (s *Suite) Test_MkLines_CheckRedundantVariables__procedure_call(c *check.C) { | |
603 | t := s.Init(c) | 615 | t := s.Init(c) | |
604 | mklines := t.NewMkLines("mk/pthread.buildlink3.mk", | 616 | mklines := t.NewMkLines("mk/pthread.buildlink3.mk", | |
605 | "CHECK_BUILTIN.pthread:=\tyes", | 617 | "CHECK_BUILTIN.pthread:=\tyes", | |
606 | ".include \"../../mk/pthread.builtin.mk\"", | 618 | ".include \"../../mk/pthread.builtin.mk\"", | |
607 | "CHECK_BUILTIN.pthread:=\tno") | 619 | "CHECK_BUILTIN.pthread:=\tno") | |
608 | 620 | |||
609 | mklines.CheckRedundantVariables() | 621 | mklines.CheckRedundantVariables() | |
610 | 622 | |||
611 | t.CheckOutputEmpty() | 623 | t.CheckOutputEmpty() | |
612 | } | 624 | } |
@@ -42,48 +42,45 @@ func (vt *VaralignTester) Fixed(lines .. | @@ -42,48 +42,45 @@ func (vt *VaralignTester) Fixed(lines .. | |||
42 | // Once for getting the diagnostics and once for automatically fixing them. | 42 | // Once for getting the diagnostics and once for automatically fixing them. | |
43 | func (vt *VaralignTester) Run() { | 43 | func (vt *VaralignTester) Run() { | |
44 | vt.runDefault() | 44 | vt.runDefault() | |
45 | vt.runAutofix() | 45 | vt.runAutofix() | |
46 | } | 46 | } | |
47 | 47 | |||
48 | func (vt *VaralignTester) runDefault() { | 48 | func (vt *VaralignTester) runDefault() { | |
49 | cmdline := []string{"-Wall"} | 49 | cmdline := []string{"-Wall"} | |
50 | if vt.source { | 50 | if vt.source { | |
51 | cmdline = append(cmdline, "--source") | 51 | cmdline = append(cmdline, "--source") | |
52 | } | 52 | } | |
53 | vt.tester.SetupCommandLine(cmdline...) | 53 | vt.tester.SetupCommandLine(cmdline...) | |
54 | 54 | |||
55 | lines := vt.tester.SetupFileLinesContinuation("Makefile", vt.input...) | 55 | mklines := vt.tester.SetupFileMkLines("Makefile", vt.input...) | |
56 | mklines := NewMkLines(lines) | |||
57 | 56 | |||
58 | varalign := VaralignBlock{} | 57 | varalign := VaralignBlock{} | |
59 | for _, mkline := range mklines.mklines { | 58 | for _, mkline := range mklines.mklines { | |
60 | varalign.Check(mkline) | 59 | varalign.Check(mkline) | |
61 | } | 60 | } | |
62 | varalign.Finish() | 61 | varalign.Finish() | |
63 | 62 | |||
64 | vt.tester.CheckOutputLines(vt.diagnostics...) | 63 | vt.tester.CheckOutputLines(vt.diagnostics...) | |
65 | } | 64 | } | |
66 | 65 | |||
67 | func (vt *VaralignTester) runAutofix() { | 66 | func (vt *VaralignTester) runAutofix() { | |
68 | cmdline := []string{"-Wall", "--autofix"} | 67 | cmdline := []string{"-Wall", "--autofix"} | |
69 | if vt.source { | 68 | if vt.source { | |
70 | cmdline = append(cmdline, "--source") | 69 | cmdline = append(cmdline, "--source") | |
71 | } | 70 | } | |
72 | vt.tester.SetupCommandLine(cmdline...) | 71 | vt.tester.SetupCommandLine(cmdline...) | |
73 | 72 | |||
74 | lines := vt.tester.SetupFileLinesContinuation("Makefile", vt.input...) | 73 | mklines := vt.tester.SetupFileMkLines("Makefile", vt.input...) | |
75 | ||||
76 | mklines := NewMkLines(lines) | |||
77 | 74 | |||
78 | var varalign VaralignBlock | 75 | var varalign VaralignBlock | |
79 | for _, mkline := range mklines.mklines { | 76 | for _, mkline := range mklines.mklines { | |
80 | varalign.Check(mkline) | 77 | varalign.Check(mkline) | |
81 | } | 78 | } | |
82 | varalign.Finish() | 79 | varalign.Finish() | |
83 | 80 | |||
84 | vt.tester.CheckOutputLines(vt.autofixes...) | 81 | vt.tester.CheckOutputLines(vt.autofixes...) | |
85 | 82 | |||
86 | SaveAutofixChanges(mklines.lines) | 83 | SaveAutofixChanges(mklines.lines) | |
87 | vt.tester.CheckFileLinesDetab("Makefile", vt.fixed...) | 84 | vt.tester.CheckFileLinesDetab("Makefile", vt.fixed...) | |
88 | } | 85 | } | |
89 | 86 |
package main
import "netbsd.org/pkglint/trace"
func ChecklinesOptionsMk(mklines *MkLines) {
if trace.Tracing {
defer trace.Call1(mklines.lines[0].Filename)()
}
mklines.Check()
exp := NewMkExpecter(mklines)
exp.AdvanceWhile(func(mkline MkLine) bool { return mkline.IsComment() || mkline.IsEmpty() })
if exp.EOF() || !(exp.CurrentMkLine().IsVarassign() && exp.CurrentMkLine().Varname() == "PKG_OPTIONS_VAR") {
exp.CurrentLine().Warnf("Expected definition of PKG_OPTIONS_VAR.")
Explain(
"The input variables in an options.mk file should always be",
"mentioned in the same order: PKG_OPTIONS_VAR, ",
"PKG_SUPPORTED_OPTIONS, PKG_SUGGESTED_OPTIONS. This way, the",
"options.mk files have the same structure and are easy to understand.")
return
}
exp.Advance()
declaredOptions := make(map[string]MkLine)
handledOptions := make(map[string]MkLine)
var optionsInDeclarationOrder []string
// The conditionals are typically for OPSYS and MACHINE_ARCH.
loop:
for ; !exp.EOF(); exp.Advance() {
mkline := exp.CurrentMkLine()
switch {
case mkline.IsComment():
case mkline.IsEmpty():
case mkline.IsVarassign():
varname := mkline.Varname()
if varname == "PKG_SUPPORTED_OPTIONS" || hasPrefix(varname, "PKG_OPTIONS_GROUP.") {
for _, option := range splitOnSpace(mkline.Value()) {
if option == mkline.WithoutMakeVariables(option) {
declaredOptions[option] = mkline
optionsInDeclarationOrder = append(optionsInDeclarationOrder, option)
}
}
}
case mkline.IsCond():
case mkline.IsInclude():
includedFile := mkline.IncludeFile()
switch {
case matches(includedFile, `/[^/]+\.buildlink3\.mk$`):
case matches(includedFile, `/[^/]+\.builtin\.mk$`):
case includedFile == "../../mk/bsd.prefs.mk":
case includedFile == "../../mk/bsd.fast.prefs.mk":
case includedFile == "../../mk/bsd.options.mk":
exp.Advance()
break loop
}
default:
exp.CurrentLine().Warnf("Expected inclusion of \"../../mk/bsd.options.mk\".")
Explain(
"After defining the input variables (PKG_OPTIONS_VAR, etc.),",
"bsd.options.mk should be included to do the actual processing.",
"No other actions should take place in this part of the file",
"in order to have the same structure in all options.mk files.")
return
}
}
for ; !exp.EOF(); exp.Advance() {
mkline := exp.CurrentMkLine()
if mkline.IsCond() && mkline.Directive() == "if" {
cond := NewMkParser(mkline.Line, mkline.Args(), false).MkCond()
if cond != nil {
cond.Visit("empty", func(t *Tree) {
varuse := t.args[0].(MkVarUse)
if varuse.varname == "PKG_OPTIONS" && len(varuse.modifiers) == 1 && hasPrefix(varuse.modifiers[0], "M") {
option := varuse.modifiers[0][1:]
handledOptions[option] = mkline
optionsInDeclarationOrder = append(optionsInDeclarationOrder, option)
}
})
}
}
}
for _, option := range optionsInDeclarationOrder {
declared := declaredOptions[option]
handled := handledOptions[option]
if declared != nil && handled == nil {
declared.Warnf("Option %q should be handled below in an .if block.", option)
Explain(
"If an option is not processed in this file, it may either be a",
"typo, or the option does not have any effect.")
}
if declared == nil && handled != nil {
handled.Warnf("Option %q is handled but not declared above.", option)
Explain(
"This block of code will never be run since PKG_OPTIONS cannot",
"contain this value. This is most probably a typo.")
}
}
SaveAutofixChanges(mklines.lines)
}
package main
import "gopkg.in/check.v1"
func (s *Suite) Test_ChecklinesOptionsMk(c *check.C) {
t := s.Init(c)
t.SetupCommandLine("-Wno-space")
t.SetupVartypes()
t.SetupOption("mc-charset", "")
t.SetupOption("ncurses", "")
t.SetupOption("slang", "")
t.SetupOption("x11", "")
t.SetupFileMkLines("mk/bsd.options.mk",
MkRcsID)
mklines := t.SetupFileMkLines("category/package/options.mk",
MkRcsID,
"",
"PKG_OPTIONS_VAR= PKG_OPTIONS.mc",
"PKG_OPTIONS_REQUIRED_GROUPS= screen",
"PKG_OPTIONS_GROUP.screen= ncurses slang",
"PKG_SUPPORTED_OPTIONS= mc-charset x11 lang-${l}",
"PKG_SUGGESTED_OPTIONS= mc-charset slang",
"",
".include \"../../mk/bsd.options.mk\"",
"",
".if !empty(PKG_OPTIONS:Mx11)",
".endif",
"",
".if !empty(PKG_OPTIONS:Mundeclared)",
".endif")
G.CurrentDir = t.TmpDir()
G.CurPkgsrcdir = "."
ChecklinesOptionsMk(mklines)
t.CheckOutputLines(
"WARN: ~/category/package/options.mk:14: Unknown option \"undeclared\".",
"WARN: ~/category/package/options.mk:5: Option \"ncurses\" should be handled below in an .if block.",
"WARN: ~/category/package/options.mk:5: Option \"slang\" should be handled below in an .if block.",
"WARN: ~/category/package/options.mk:6: Option \"mc-charset\" should be handled below in an .if block.",
"WARN: ~/category/package/options.mk:14: Option \"undeclared\" is handled but not declared above.")
}
func (s *Suite) Test_ChecklinesOptionsMk__unexpected_line(c *check.C) {
t := s.Init(c)
t.SetupCommandLine("-Wno-space")
t.SetupVartypes()
t.SetupOption("mc-charset", "")
t.SetupOption("ncurses", "")
t.SetupOption("slang", "")
t.SetupOption("x11", "")
t.SetupFileMkLines("mk/bsd.options.mk",
MkRcsID)
mklines := t.SetupFileMkLines("category/package/options.mk",
MkRcsID,
"",
"PKG_OPTIONS_VAR= PKG_OPTIONS.mc",
"PKG_SUPPORTED_OPTIONS= mc-charset x11 lang-${l}",
"PKG_SUGGESTED_OPTIONS= mc-charset",
"",
"pre-configure:",
"\techo \"In the pre-configure stage.\"")
G.CurrentDir = t.TmpDir()
G.CurPkgsrcdir = "."
ChecklinesOptionsMk(mklines)
t.CheckOutputLines(
"WARN: ~/category/package/options.mk:7: Expected inclusion of \"../../mk/bsd.options.mk\".")
}
@@ -412,28 +412,28 @@ func (s *Suite) Test_Package_loadPackage | @@ -412,28 +412,28 @@ func (s *Suite) Test_Package_loadPackage | |||
412 | ".include \"../../category/package/Makefile\"") | 412 | ".include \"../../category/package/Makefile\"") | |
413 | pkg := NewPackage("category/package") | 413 | pkg := NewPackage("category/package") | |
414 | G.CurrentDir = t.TempFilename("category/package") | 414 | G.CurrentDir = t.TempFilename("category/package") | |
415 | G.CurPkgsrcdir = "../.." | 415 | G.CurPkgsrcdir = "../.." | |
416 | G.Pkg = pkg | 416 | G.Pkg = pkg | |
417 | 417 | |||
418 | pkg.loadPackageMakefile(t.TempFilename("category/package/Makefile")) | 418 | pkg.loadPackageMakefile(t.TempFilename("category/package/Makefile")) | |
419 | 419 | |||
420 | // Including a package Makefile directly is an error (in the last line), | 420 | // Including a package Makefile directly is an error (in the last line), | |
421 | // but that is checked later. | 421 | // but that is checked later. | |
422 | // A file including itself does not lead to an endless loop while parsing | 422 | // A file including itself does not lead to an endless loop while parsing | |
423 | // but may still produce unexpected warnings, such as redundant definitions. | 423 | // but may still produce unexpected warnings, such as redundant definitions. | |
424 | t.CheckOutputLines( | 424 | t.CheckOutputLines( | |
425 | "WARN: ~/category/package/Makefile:3: Variable PKGNAME is overwritten in Makefile:3.", | 425 | "NOTE: ~/category/package/Makefile:3: Definition of PKGNAME is redundant because of Makefile:3.", | |
426 | "WARN: ~/category/package/Makefile:4: Variable DISTNAME is overwritten in Makefile:4.") | 426 | "NOTE: ~/category/package/Makefile:4: Definition of DISTNAME is redundant because of Makefile:4.") | |
427 | } | 427 | } | |
428 | 428 | |||
429 | func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) { | 429 | func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) { | |
430 | t := s.Init(c) | 430 | t := s.Init(c) | |
431 | 431 | |||
432 | t.SetupVartypes() | 432 | t.SetupVartypes() | |
433 | t.CreateFileLines("category/package/Makefile", | 433 | t.CreateFileLines("category/package/Makefile", | |
434 | MkRcsID, | 434 | MkRcsID, | |
435 | "", | 435 | "", | |
436 | "COMMENT\t=Description", | 436 | "COMMENT\t=Description", | |
437 | "LICENSE\t= gnu-gpl-v2", | 437 | "LICENSE\t= gnu-gpl-v2", | |
438 | ".include \"../../devel/zlib/buildlink3.mk\"", | 438 | ".include \"../../devel/zlib/buildlink3.mk\"", | |
439 | ".if ${OPSYS} == \"Linux\"", | 439 | ".if ${OPSYS} == \"Linux\"", | |
@@ -461,27 +461,28 @@ func (s *Suite) Test_Package_conditional | @@ -461,27 +461,28 @@ func (s *Suite) Test_Package_conditional | |||
461 | pkg := NewPackage("category/package") | 461 | pkg := NewPackage("category/package") | |
462 | G.CurrentDir = t.TmpDir() + "/category/package" | 462 | G.CurrentDir = t.TmpDir() + "/category/package" | |
463 | G.CurPkgsrcdir = "../.." | 463 | G.CurPkgsrcdir = "../.." | |
464 | G.Pkg = pkg | 464 | G.Pkg = pkg | |
465 | 465 | |||
466 | G.checkdirPackage("category/package") | 466 | G.checkdirPackage("category/package") | |
467 | 467 | |||
468 | t.CheckOutputLines( | 468 | t.CheckOutputLines( | |
469 | "WARN: ~/category/package/Makefile:3: The canonical order of the variables is CATEGORIES, empty line, COMMENT, LICENSE.", | 469 | "WARN: ~/category/package/Makefile:3: The canonical order of the variables is CATEGORIES, empty line, COMMENT, LICENSE.", | |
470 | "WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".", | 470 | "WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".", | |
471 | "WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is "+ | 471 | "WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is "+ | |
472 | "included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.", | 472 | "included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.", | |
473 | "WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is "+ | 473 | "WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is "+ | |
474 | "included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).") | 474 | "included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).", | |
475 | "WARN: ~/category/package/options.mk:3: Expected definition of PKG_OPTIONS_VAR.") | |||
475 | } | 476 | } | |
476 | 477 | |||
477 | // See https://github.com/rillig/pkglint/issues/1 | 478 | // See https://github.com/rillig/pkglint/issues/1 | |
478 | func (s *Suite) Test_Package_includeWithoutExists(c *check.C) { | 479 | func (s *Suite) Test_Package_includeWithoutExists(c *check.C) { | |
479 | t := s.Init(c) | 480 | t := s.Init(c) | |
480 | 481 | |||
481 | t.SetupVartypes() | 482 | t.SetupVartypes() | |
482 | t.CreateFileLines("mk/bsd.pkg.mk") | 483 | t.CreateFileLines("mk/bsd.pkg.mk") | |
483 | t.CreateFileLines("category/package/Makefile", | 484 | t.CreateFileLines("category/package/Makefile", | |
484 | MkRcsID, | 485 | MkRcsID, | |
485 | "", | 486 | "", | |
486 | ".include \"options.mk\"", | 487 | ".include \"options.mk\"", | |
487 | "", | 488 | "", |
@@ -558,27 +558,27 @@ func naturalLess(str1, str2 string) bool | @@ -558,27 +558,27 @@ func naturalLess(str1, str2 string) bool | |||
558 | // They're identical so far, so continue comparing. | 558 | // They're identical so far, so continue comparing. | |
559 | } | 559 | } | |
560 | // So far they are identical. At least one is ended. If the other continues, | 560 | // So far they are identical. At least one is ended. If the other continues, | |
561 | // it sorts last. | 561 | // it sorts last. | |
562 | return len1 < len2 | 562 | return len1 < len2 | |
563 | } | 563 | } | |
564 | 564 | |||
565 | // RedundantScope checks for redundant variable definitions and accidentally | 565 | // RedundantScope checks for redundant variable definitions and accidentally | |
566 | // overwriting variables. It tries to be as correct as possible by not flagging | 566 | // overwriting variables. It tries to be as correct as possible by not flagging | |
567 | // anything that is defined conditionally. There may be some edge cases though | 567 | // anything that is defined conditionally. There may be some edge cases though | |
568 | // like defining PKGNAME, then evaluating it using :=, then defining it again. | 568 | // like defining PKGNAME, then evaluating it using :=, then defining it again. | |
569 | // This pattern is so error-prone that it should not appear in pkgsrc at all, | 569 | // This pattern is so error-prone that it should not appear in pkgsrc at all, | |
570 | // thus pkglint doesn't even expect it. (Well, except for the PKGNAME case, | 570 | // thus pkglint doesn't even expect it. (Well, except for the PKGNAME case, | |
571 | // but that's deep in the infrastructure and only affects the "nb13" extension. | 571 | // but that's deep in the infrastructure and only affects the "nb13" extension.) | |
572 | type RedundantScope struct { | 572 | type RedundantScope struct { | |
573 | vars map[string]*redundantScopeVarinfo | 573 | vars map[string]*redundantScopeVarinfo | |
574 | condLevel int | 574 | condLevel int | |
575 | OnIgnore func(old, new MkLine) | 575 | OnIgnore func(old, new MkLine) | |
576 | OnOverwrite func(old, new MkLine) | 576 | OnOverwrite func(old, new MkLine) | |
577 | } | 577 | } | |
578 | type redundantScopeVarinfo struct { | 578 | type redundantScopeVarinfo struct { | |
579 | mkline MkLine | 579 | mkline MkLine | |
580 | value string | 580 | value string | |
581 | } | 581 | } | |
582 | 582 | |||
583 | func NewRedundantScope() *RedundantScope { | 583 | func NewRedundantScope() *RedundantScope { | |
584 | return &RedundantScope{vars: make(map[string]*redundantScopeVarinfo)} | 584 | return &RedundantScope{vars: make(map[string]*redundantScopeVarinfo)} | |
@@ -600,26 +600,29 @@ func (s *RedundantScope) Handle(mkline M | @@ -600,26 +600,29 @@ func (s *RedundantScope) Handle(mkline M | |||
600 | op = opAssign // They are effectively the same in this case. | 600 | op = opAssign // They are effectively the same in this case. | |
601 | } | 601 | } | |
602 | existing, found := s.vars[varname] | 602 | existing, found := s.vars[varname] | |
603 | if !found { | 603 | if !found { | |
604 | if op == opAssignShell || op == opAssignEval { | 604 | if op == opAssignShell || op == opAssignEval { | |
605 | s.vars[varname] = nil | 605 | s.vars[varname] = nil | |
606 | } else { | 606 | } else { | |
607 | if op == opAssignAppend { | 607 | if op == opAssignAppend { | |
608 | value = " " + value | 608 | value = " " + value | |
609 | } | 609 | } | |
610 | s.vars[varname] = &redundantScopeVarinfo{mkline, value} | 610 | s.vars[varname] = &redundantScopeVarinfo{mkline, value} | |
611 | } | 611 | } | |
612 | } else if existing != nil { | 612 | } else if existing != nil { | |
613 | if op == opAssign && existing.value == value { | |||
614 | op = opAssignDefault | |||
615 | } | |||
613 | switch op { | 616 | switch op { | |
614 | case opAssign: | 617 | case opAssign: | |
615 | if s.OnOverwrite != nil { | 618 | if s.OnOverwrite != nil { | |
616 | s.OnOverwrite(existing.mkline, mkline) | 619 | s.OnOverwrite(existing.mkline, mkline) | |
617 | } | 620 | } | |
618 | existing.value = value | 621 | existing.value = value | |
619 | case opAssignAppend: | 622 | case opAssignAppend: | |
620 | existing.value += " " + value | 623 | existing.value += " " + value | |
621 | case opAssignDefault: | 624 | case opAssignDefault: | |
622 | if s.OnIgnore != nil { | 625 | if s.OnIgnore != nil { | |
623 | s.OnIgnore(existing.mkline, mkline) | 626 | s.OnIgnore(existing.mkline, mkline) | |
624 | } | 627 | } | |
625 | case opAssignShell: | 628 | case opAssignShell: |
@@ -55,26 +55,27 @@ type Pkglint struct { | @@ -55,26 +55,27 @@ type Pkglint struct { | |||
55 | } | 55 | } | |
56 | 56 | |||
57 | type CmdOpts struct { | 57 | type CmdOpts struct { | |
58 | CheckAlternatives, | 58 | CheckAlternatives, | |
59 | CheckBuildlink3, | 59 | CheckBuildlink3, | |
60 | CheckDescr, | 60 | CheckDescr, | |
61 | CheckDistinfo, | 61 | CheckDistinfo, | |
62 | CheckExtra, | 62 | CheckExtra, | |
63 | CheckGlobal, | 63 | CheckGlobal, | |
64 | CheckInstall, | 64 | CheckInstall, | |
65 | CheckMakefile, | 65 | CheckMakefile, | |
66 | CheckMessage, | 66 | CheckMessage, | |
67 | CheckMk, | 67 | CheckMk, | |
68 | CheckOptions, | |||
68 | CheckPatches, | 69 | CheckPatches, | |
69 | CheckPlist bool | 70 | CheckPlist bool | |
70 | 71 | |||
71 | WarnAbsname, | 72 | WarnAbsname, | |
72 | WarnDirectcmd, | 73 | WarnDirectcmd, | |
73 | WarnExtra, | 74 | WarnExtra, | |
74 | WarnOrder, | 75 | WarnOrder, | |
75 | WarnPerm, | 76 | WarnPerm, | |
76 | WarnPlistDepr, | 77 | WarnPlistDepr, | |
77 | WarnPlistSort, | 78 | WarnPlistSort, | |
78 | WarnQuoting, | 79 | WarnQuoting, | |
79 | WarnSpace, | 80 | WarnSpace, | |
80 | WarnStyle, | 81 | WarnStyle, | |
@@ -210,26 +211,27 @@ func (pkglint *Pkglint) ParseCommandLine | @@ -210,26 +211,27 @@ func (pkglint *Pkglint) ParseCommandLine | |||
210 | opts.AddFlagVar('V', "version", &gopts.PrintVersion, false, "print the version number of pkglint") | 211 | opts.AddFlagVar('V', "version", &gopts.PrintVersion, false, "print the version number of pkglint") | |
211 | warn := opts.AddFlagGroup('W', "warning", "warning,...", "enable or disable groups of warnings") | 212 | warn := opts.AddFlagGroup('W', "warning", "warning,...", "enable or disable groups of warnings") | |
212 | 213 | |||
213 | check.AddFlagVar("ALTERNATIVES", &gopts.CheckAlternatives, true, "check ALTERNATIVES files") | 214 | check.AddFlagVar("ALTERNATIVES", &gopts.CheckAlternatives, true, "check ALTERNATIVES files") | |
214 | check.AddFlagVar("bl3", &gopts.CheckBuildlink3, true, "check buildlink3.mk files") | 215 | check.AddFlagVar("bl3", &gopts.CheckBuildlink3, true, "check buildlink3.mk files") | |
215 | check.AddFlagVar("DESCR", &gopts.CheckDescr, true, "check DESCR file") | 216 | check.AddFlagVar("DESCR", &gopts.CheckDescr, true, "check DESCR file") | |
216 | check.AddFlagVar("distinfo", &gopts.CheckDistinfo, true, "check distinfo file") | 217 | check.AddFlagVar("distinfo", &gopts.CheckDistinfo, true, "check distinfo file") | |
217 | check.AddFlagVar("extra", &gopts.CheckExtra, false, "check various additional files") | 218 | check.AddFlagVar("extra", &gopts.CheckExtra, false, "check various additional files") | |
218 | check.AddFlagVar("global", &gopts.CheckGlobal, false, "inter-package checks") | 219 | check.AddFlagVar("global", &gopts.CheckGlobal, false, "inter-package checks") | |
219 | check.AddFlagVar("INSTALL", &gopts.CheckInstall, true, "check INSTALL and DEINSTALL scripts") | 220 | check.AddFlagVar("INSTALL", &gopts.CheckInstall, true, "check INSTALL and DEINSTALL scripts") | |
220 | check.AddFlagVar("Makefile", &gopts.CheckMakefile, true, "check Makefiles") | 221 | check.AddFlagVar("Makefile", &gopts.CheckMakefile, true, "check Makefiles") | |
221 | check.AddFlagVar("MESSAGE", &gopts.CheckMessage, true, "check MESSAGE file") | 222 | check.AddFlagVar("MESSAGE", &gopts.CheckMessage, true, "check MESSAGE file") | |
222 | check.AddFlagVar("mk", &gopts.CheckMk, true, "check other .mk files") | 223 | check.AddFlagVar("mk", &gopts.CheckMk, true, "check other .mk files") | |
224 | check.AddFlagVar("options", &gopts.CheckOptions, true, "check options.mk files") | |||
223 | check.AddFlagVar("patches", &gopts.CheckPatches, true, "check patches") | 225 | check.AddFlagVar("patches", &gopts.CheckPatches, true, "check patches") | |
224 | check.AddFlagVar("PLIST", &gopts.CheckPlist, true, "check PLIST files") | 226 | check.AddFlagVar("PLIST", &gopts.CheckPlist, true, "check PLIST files") | |
225 | 227 | |||
226 | warn.AddFlagVar("absname", &gopts.WarnAbsname, true, "warn about use of absolute file names") | 228 | warn.AddFlagVar("absname", &gopts.WarnAbsname, true, "warn about use of absolute file names") | |
227 | warn.AddFlagVar("directcmd", &gopts.WarnDirectcmd, true, "warn about use of direct command names instead of Make variables") | 229 | warn.AddFlagVar("directcmd", &gopts.WarnDirectcmd, true, "warn about use of direct command names instead of Make variables") | |
228 | warn.AddFlagVar("extra", &gopts.WarnExtra, false, "enable some extra warnings") | 230 | warn.AddFlagVar("extra", &gopts.WarnExtra, false, "enable some extra warnings") | |
229 | warn.AddFlagVar("order", &gopts.WarnOrder, true, "warn if Makefile entries are unordered") | 231 | warn.AddFlagVar("order", &gopts.WarnOrder, true, "warn if Makefile entries are unordered") | |
230 | warn.AddFlagVar("perm", &gopts.WarnPerm, false, "warn about unforeseen variable definition and use") | 232 | warn.AddFlagVar("perm", &gopts.WarnPerm, false, "warn about unforeseen variable definition and use") | |
231 | warn.AddFlagVar("plist-depr", &gopts.WarnPlistDepr, false, "warn about deprecated paths in PLISTs") | 233 | warn.AddFlagVar("plist-depr", &gopts.WarnPlistDepr, false, "warn about deprecated paths in PLISTs") | |
232 | warn.AddFlagVar("plist-sort", &gopts.WarnPlistSort, false, "warn about unsorted entries in PLISTs") | 234 | warn.AddFlagVar("plist-sort", &gopts.WarnPlistSort, false, "warn about unsorted entries in PLISTs") | |
233 | warn.AddFlagVar("quoting", &gopts.WarnQuoting, false, "warn about quoting issues") | 235 | warn.AddFlagVar("quoting", &gopts.WarnQuoting, false, "warn about quoting issues") | |
234 | warn.AddFlagVar("space", &gopts.WarnSpace, false, "warn about inconsistent use of white-space") | 236 | warn.AddFlagVar("space", &gopts.WarnSpace, false, "warn about inconsistent use of white-space") | |
235 | warn.AddFlagVar("style", &gopts.WarnStyle, false, "warn about stylistic issues") | 237 | warn.AddFlagVar("style", &gopts.WarnStyle, false, "warn about stylistic issues") | |
@@ -533,26 +535,33 @@ func (pkglint *Pkglint) Checkfile(fname | @@ -533,26 +535,33 @@ func (pkglint *Pkglint) Checkfile(fname | |||
533 | 535 | |||
534 | case basename == "DEINSTALL" || basename == "INSTALL": | 536 | case basename == "DEINSTALL" || basename == "INSTALL": | |
535 | if pkglint.opts.CheckInstall { | 537 | if pkglint.opts.CheckInstall { | |
536 | CheckfileExtra(fname) | 538 | CheckfileExtra(fname) | |
537 | } | 539 | } | |
538 | 540 | |||
539 | case hasPrefix(basename, "MESSAGE"): | 541 | case hasPrefix(basename, "MESSAGE"): | |
540 | if pkglint.opts.CheckMessage { | 542 | if pkglint.opts.CheckMessage { | |
541 | if lines := LoadNonemptyLines(fname, false); lines != nil { | 543 | if lines := LoadNonemptyLines(fname, false); lines != nil { | |
542 | ChecklinesMessage(lines) | 544 | ChecklinesMessage(lines) | |
543 | } | 545 | } | |
544 | } | 546 | } | |
545 | 547 | |||
548 | case basename == "options.mk": | |||
549 | if pkglint.opts.CheckOptions { | |||
550 | if lines := LoadNonemptyLines(fname, true); lines != nil { | |||
551 | ChecklinesOptionsMk(NewMkLines(lines)) | |||
552 | } | |||
553 | } | |||
554 | ||||
546 | case matches(basename, `^patch-[-A-Za-z0-9_.~+]*[A-Za-z0-9_]$`): | 555 | case matches(basename, `^patch-[-A-Za-z0-9_.~+]*[A-Za-z0-9_]$`): | |
547 | if pkglint.opts.CheckPatches { | 556 | if pkglint.opts.CheckPatches { | |
548 | if lines := LoadNonemptyLines(fname, false); lines != nil { | 557 | if lines := LoadNonemptyLines(fname, false); lines != nil { | |
549 | ChecklinesPatch(lines) | 558 | ChecklinesPatch(lines) | |
550 | } | 559 | } | |
551 | } | 560 | } | |
552 | 561 | |||
553 | case matches(fname, `(?:^|/)patches/manual[^/]*$`): | 562 | case matches(fname, `(?:^|/)patches/manual[^/]*$`): | |
554 | if trace.Tracing { | 563 | if trace.Tracing { | |
555 | trace.Step1("Unchecked file %q.", fname) | 564 | trace.Step1("Unchecked file %q.", fname) | |
556 | } | 565 | } | |
557 | 566 | |||
558 | case matches(fname, `(?:^|/)patches/[^/]*$`): | 567 | case matches(fname, `(?:^|/)patches/[^/]*$`): |
@@ -82,26 +82,27 @@ func (s *Suite) Test_Pkglint_Main__unkno | @@ -82,26 +82,27 @@ func (s *Suite) Test_Pkglint_Main__unkno | |||
82 | " Flags for -C, --check:", | 82 | " Flags for -C, --check:", | |
83 | " all all of the following", | 83 | " all all of the following", | |
84 | " none none of the following", | 84 | " none none of the following", | |
85 | " ALTERNATIVES check ALTERNATIVES files (enabled)", | 85 | " ALTERNATIVES check ALTERNATIVES files (enabled)", | |
86 | " bl3 check buildlink3.mk files (enabled)", | 86 | " bl3 check buildlink3.mk files (enabled)", | |
87 | " DESCR check DESCR file (enabled)", | 87 | " DESCR check DESCR file (enabled)", | |
88 | " distinfo check distinfo file (enabled)", | 88 | " distinfo check distinfo file (enabled)", | |
89 | " extra check various additional files (disabled)", | 89 | " extra check various additional files (disabled)", | |
90 | " global inter-package checks (disabled)", | 90 | " global inter-package checks (disabled)", | |
91 | " INSTALL check INSTALL and DEINSTALL scripts (enabled)", | 91 | " INSTALL check INSTALL and DEINSTALL scripts (enabled)", | |
92 | " Makefile check Makefiles (enabled)", | 92 | " Makefile check Makefiles (enabled)", | |
93 | " MESSAGE check MESSAGE file (enabled)", | 93 | " MESSAGE check MESSAGE file (enabled)", | |
94 | " mk check other .mk files (enabled)", | 94 | " mk check other .mk files (enabled)", | |
95 | " options check options.mk files (enabled)", | |||
95 | " patches check patches (enabled)", | 96 | " patches check patches (enabled)", | |
96 | " PLIST check PLIST files (enabled)", | 97 | " PLIST check PLIST files (enabled)", | |
97 | "", | 98 | "", | |
98 | " Flags for -W, --warning:", | 99 | " Flags for -W, --warning:", | |
99 | " all all of the following", | 100 | " all all of the following", | |
100 | " none none of the following", | 101 | " none none of the following", | |
101 | " absname warn about use of absolute file names (enabled)", | 102 | " absname warn about use of absolute file names (enabled)", | |
102 | " directcmd warn about use of direct command names instead of Make variables (enabled)", | 103 | " directcmd warn about use of direct command names instead of Make variables (enabled)", | |
103 | " extra enable some extra warnings (disabled)", | 104 | " extra enable some extra warnings (disabled)", | |
104 | " order warn if Makefile entries are unordered (enabled)", | 105 | " order warn if Makefile entries are unordered (enabled)", | |
105 | " perm warn about unforeseen variable definition and use (disabled)", | 106 | " perm warn about unforeseen variable definition and use (disabled)", | |
106 | " plist-depr warn about deprecated paths in PLISTs (disabled)", | 107 | " plist-depr warn about deprecated paths in PLISTs (disabled)", | |
107 | " plist-sort warn about unsorted entries in PLISTs (disabled)", | 108 | " plist-sort warn about unsorted entries in PLISTs (disabled)", |
@@ -291,30 +291,54 @@ func (src *Pkgsrc) loadDocChangesFromFil | @@ -291,30 +291,54 @@ func (src *Pkgsrc) loadDocChangesFromFil | |||
291 | switch { | 291 | switch { | |
292 | case action == "Added" && f[2] == "version" && n == 6: | 292 | case action == "Added" && f[2] == "version" && n == 6: | |
293 | return &Change{line, action, pkgpath, f[3], author, date} | 293 | return &Change{line, action, pkgpath, f[3], author, date} | |
294 | case (action == "Updated" || action == "Downgraded") && f[2] == "to" && n == 6: | 294 | case (action == "Updated" || action == "Downgraded") && f[2] == "to" && n == 6: | |
295 | return &Change{line, action, pkgpath, f[3], author, date} | 295 | return &Change{line, action, pkgpath, f[3], author, date} | |
296 | case action == "Removed" && (n == 6 && f[2] == "successor" || n == 4): | 296 | case action == "Removed" && (n == 6 && f[2] == "successor" || n == 4): | |
297 | return &Change{line, action, pkgpath, "", author, date} | 297 | return &Change{line, action, pkgpath, "", author, date} | |
298 | case (action == "Renamed" || action == "Moved") && f[2] == "to" && n == 6: | 298 | case (action == "Renamed" || action == "Moved") && f[2] == "to" && n == 6: | |
299 | return &Change{line, action, pkgpath, "", author, date} | 299 | return &Change{line, action, pkgpath, "", author, date} | |
300 | } | 300 | } | |
301 | return nil | 301 | return nil | |
302 | } | 302 | } | |
303 | 303 | |||
304 | year := "" | |||
305 | if m, yyyy := match1(fname, `-(\d+)$`); m && yyyy >= "2018" { | |||
306 | year = yyyy | |||
307 | } | |||
308 | ||||
304 | var changes []*Change | 309 | var changes []*Change | |
305 | for _, line := range lines { | 310 | for _, line := range lines { | |
306 | if change := parseChange(line); change != nil { | 311 | if change := parseChange(line); change != nil { | |
307 | changes = append(changes, change) | 312 | changes = append(changes, change) | |
313 | if year != "" && change.Date[0:4] != year { | |||
314 | line.Warnf("Year %s for %s does not match the file name %s.", change.Date[0:4], change.Pkgpath, fname) | |||
315 | } | |||
316 | if len(changes) >= 2 && year != "" { | |||
317 | if prev := changes[len(changes)-2]; change.Date < prev.Date { | |||
318 | line.Warnf("Date %s for %s is earlier than %s for %s.", change.Date, change.Pkgpath, prev.Date, prev.Pkgpath) | |||
319 | Explain( | |||
320 | "The entries in doc/CHANGES should be in chronological order, and", | |||
321 | "all dates are assumed to be in the UTC timezone, to prevent time", | |||
322 | "warps.", | |||
323 | "", | |||
324 | "To fix this, determine which of the involved dates are correct", | |||
325 | "and which aren't.", | |||
326 | "", | |||
327 | "To prevent this kind of mistakes in the future, make sure that", | |||
328 | "your system time is correct and use \""+confMake+" cce\" to commit", | |||
329 | "the changes entry.") | |||
330 | } | |||
331 | } | |||
308 | } else if text := line.Text; len(text) >= 2 && text[0] == '\t' && 'A' <= text[1] && text[1] <= 'Z' { | 332 | } else if text := line.Text; len(text) >= 2 && text[0] == '\t' && 'A' <= text[1] && text[1] <= 'Z' { | |
309 | line.Warnf("Unknown doc/CHANGES line: %q", text) | 333 | line.Warnf("Unknown doc/CHANGES line: %q", text) | |
310 | Explain("See mk/misc/developer.mk for the rules.") | 334 | Explain("See mk/misc/developer.mk for the rules.") | |
311 | } | 335 | } | |
312 | } | 336 | } | |
313 | return changes | 337 | return changes | |
314 | } | 338 | } | |
315 | 339 | |||
316 | func (src *Pkgsrc) GetSuggestedPackageUpdates() []SuggestedUpdate { | 340 | func (src *Pkgsrc) GetSuggestedPackageUpdates() []SuggestedUpdate { | |
317 | if G.Wip { | 341 | if G.Wip { | |
318 | return src.suggestedWipUpdates | 342 | return src.suggestedWipUpdates | |
319 | } else { | 343 | } else { | |
320 | return src.suggestedUpdates | 344 | return src.suggestedUpdates |
@@ -116,45 +116,49 @@ func (s *Suite) Test_Pkgsrc_loadTools(c | @@ -116,45 +116,49 @@ func (s *Suite) Test_Pkgsrc_loadTools(c | |||
116 | "TRACE: 1 tool &{Name:m4 Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}", | 116 | "TRACE: 1 tool &{Name:m4 Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}", | |
117 | "TRACE: 1 tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}", | 117 | "TRACE: 1 tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}", | |
118 | "TRACE: 1 tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadtime:false}", | 118 | "TRACE: 1 tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadtime:false}", | |
119 | "TRACE: 1 tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadtime:true}", | 119 | "TRACE: 1 tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadtime:true}", | |
120 | "TRACE: 1 tool &{Name:strip Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}", | 120 | "TRACE: 1 tool &{Name:strip Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}", | |
121 | "TRACE: 1 tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadtime:true}", | 121 | "TRACE: 1 tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadtime:true}", | |
122 | "TRACE: 1 tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadtime:true}", | 122 | "TRACE: 1 tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadtime:true}", | |
123 | "TRACE: - (*ToolRegistry).Trace()") | 123 | "TRACE: - (*ToolRegistry).Trace()") | |
124 | } | 124 | } | |
125 | 125 | |||
126 | func (s *Suite) Test_Pkgsrc_loadDocChangesFromFile(c *check.C) { | 126 | func (s *Suite) Test_Pkgsrc_loadDocChangesFromFile(c *check.C) { | |
127 | t := s.Init(c) | 127 | t := s.Init(c) | |
128 | 128 | |||
129 | t.SetupFileLines("doc/CHANGES-2015", | 129 | t.SetupFileLines("doc/CHANGES-2018", | |
130 | "\tAdded category/package version 1.0 [author1 2015-01-01]", | 130 | "\tAdded category/package version 1.0 [author1 2015-01-01]", // Wrong year | |
131 | "\tUpdated category/package to 1.5 [author2 2015-01-02]", | 131 | "\tUpdated category/package to 1.5 [author2 2018-01-02]", | |
132 | "\tRenamed category/package to category/pkg [author3 2015-01-03]", | 132 | "\tRenamed category/package to category/pkg [author3 2018-01-03]", | |
133 | "\tMoved category/package to other/package [author4 2015-01-04]", | 133 | "\tMoved category/package to other/package [author4 2018-01-04]", | |
134 | "\tRemoved category/package [author5 2015-01-05]", | 134 | "\tRemoved category/package [author5 2018-01-09]", // Too far in the future | |
135 | "\tRemoved category/package successor category/package2 [author6 2015-01-06]", | 135 | "\tRemoved category/package successor category/package2 [author6 2018-01-06]", | |
136 | "\tDowngraded category/package to 1.2 [author7 2015-01-07]") | 136 | "\tDowngraded category/package to 1.2 [author7 2018-01-07]") | |
137 | 137 | |||
138 | changes := G.Pkgsrc.loadDocChangesFromFile(t.TmpDir() + "/doc/CHANGES-2015") | 138 | changes := G.Pkgsrc.loadDocChangesFromFile(t.TmpDir() + "/doc/CHANGES-2018") | |
139 | 139 | |||
140 | c.Assert(len(changes), equals, 7) | 140 | c.Assert(len(changes), equals, 7) | |
141 | c.Check(*changes[0], equals, Change{changes[0].Line, "Added", "category/package", "1.0", "author1", "2015-01-01"}) | 141 | c.Check(*changes[0], equals, Change{changes[0].Line, "Added", "category/package", "1.0", "author1", "2015-01-01"}) | |
142 | c.Check(*changes[1], equals, Change{changes[1].Line, "Updated", "category/package", "1.5", "author2", "2015-01-02"}) | 142 | c.Check(*changes[1], equals, Change{changes[1].Line, "Updated", "category/package", "1.5", "author2", "2018-01-02"}) | |
143 | c.Check(*changes[2], equals, Change{changes[2].Line, "Renamed", "category/package", "", "author3", "2015-01-03"}) | 143 | c.Check(*changes[2], equals, Change{changes[2].Line, "Renamed", "category/package", "", "author3", "2018-01-03"}) | |
144 | c.Check(*changes[3], equals, Change{changes[3].Line, "Moved", "category/package", "", "author4", "2015-01-04"}) | 144 | c.Check(*changes[3], equals, Change{changes[3].Line, "Moved", "category/package", "", "author4", "2018-01-04"}) | |
145 | c.Check(*changes[4], equals, Change{changes[4].Line, "Removed", "category/package", "", "author5", "2015-01-05"}) | 145 | c.Check(*changes[4], equals, Change{changes[4].Line, "Removed", "category/package", "", "author5", "2018-01-09"}) | |
146 | c.Check(*changes[5], equals, Change{changes[5].Line, "Removed", "category/package", "", "author6", "2015-01-06"}) | 146 | c.Check(*changes[5], equals, Change{changes[5].Line, "Removed", "category/package", "", "author6", "2018-01-06"}) | |
147 | c.Check(*changes[6], equals, Change{changes[6].Line, "Downgraded", "category/package", "1.2", "author7", "2015-01-07"}) | 147 | c.Check(*changes[6], equals, Change{changes[6].Line, "Downgraded", "category/package", "1.2", "author7", "2018-01-07"}) | |
148 | ||||
149 | t.CheckOutputLines( | |||
150 | "WARN: ~/doc/CHANGES-2018:1: Year 2015 for category/package does not match the file name ~/doc/CHANGES-2018.", | |||
151 | "WARN: ~/doc/CHANGES-2018:6: Date 2018-01-06 for category/package is earlier than 2018-01-09 for category/package.") | |||
148 | } | 152 | } | |
149 | 153 | |||
150 | func (s *Suite) Test_Pkgsrc_deprecated(c *check.C) { | 154 | func (s *Suite) Test_Pkgsrc_deprecated(c *check.C) { | |
151 | t := s.Init(c) | 155 | t := s.Init(c) | |
152 | 156 | |||
153 | G.Pkgsrc.initDeprecatedVars() | 157 | G.Pkgsrc.initDeprecatedVars() | |
154 | mkline := t.NewMkLine("Makefile", 5, "USE_PERL5=\tyes") | 158 | mkline := t.NewMkLine("Makefile", 5, "USE_PERL5=\tyes") | |
155 | 159 | |||
156 | MkLineChecker{mkline}.checkVarassign() | 160 | MkLineChecker{mkline}.checkVarassign() | |
157 | 161 | |||
158 | t.CheckOutputLines( | 162 | t.CheckOutputLines( | |
159 | "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.") | 163 | "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.") | |
160 | } | 164 | } |
@@ -626,33 +626,33 @@ func (s *Suite) Test_ShellLine_CheckShel | @@ -626,33 +626,33 @@ func (s *Suite) Test_ShellLine_CheckShel | |||
626 | 626 | |||
627 | shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2") | 627 | shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2") | |
628 | 628 | |||
629 | shline.CheckShellCommandLine(shline.mkline.ShellCommand()) | 629 | shline.CheckShellCommandLine(shline.mkline.ShellCommand()) | |
630 | 630 | |||
631 | t.CheckOutputLines( | 631 | t.CheckOutputLines( | |
632 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".", | 632 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".", | |
633 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".") | 633 | "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".") | |
634 | } | 634 | } | |
635 | 635 | |||
636 | func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) { | 636 | func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) { | |
637 | t := s.Init(c) | 637 | t := s.Init(c) | |
638 | 638 | |||
639 | lines := t.SetupFileLinesContinuation("Makefile", | 639 | mklines := t.SetupFileMkLines("Makefile", | |
640 | MkRcsID, | 640 | MkRcsID, | |
641 | "pre-install:", | 641 | "pre-install:", | |
642 | "\t"+"# comment\\", | 642 | "\t"+"# comment\\", | |
643 | "\t"+"echo \"hello\"") | 643 | "\t"+"echo \"hello\"") | |
644 | 644 | |||
645 | NewMkLines(lines).Check() | 645 | mklines.Check() | |
646 | 646 | |||
647 | t.CheckOutputLines( | 647 | t.CheckOutputLines( | |
648 | "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.") | 648 | "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.") | |
649 | } | 649 | } | |
650 | 650 | |||
651 | func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) { | 651 | func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) { | |
652 | t := s.Init(c) | 652 | t := s.Init(c) | |
653 | 653 | |||
654 | shline := t.NewShellLine("dummy.mk", 13, "# dummy") | 654 | shline := t.NewShellLine("dummy.mk", 13, "# dummy") | |
655 | // foobar="`echo \"foo bar\"`" | 655 | // foobar="`echo \"foo bar\"`" | |
656 | text := "foobar=\"`echo \\\"foo bar\\\"`\"" | 656 | text := "foobar=\"`echo \\\"foo bar\\\"`\"" | |
657 | repl := textproc.NewPrefixReplacer(text) | 657 | repl := textproc.NewPrefixReplacer(text) | |
658 | repl.AdvanceStr("foobar=\"`") | 658 | repl.AdvanceStr("foobar=\"`") |