Thu Jul 7 12:09:27 2016 UTC ()
Updated pkglint to 5.4.3.

Changes since 5.4.2:

* Variables like ${VAR_${OTHER_VAR}} are no longer checked for
  use/define mismatch
* The check for plural variable names has been removed
* The type of variables called *DESTDIR is no longer guessed to be a
  directory name
* The check for unknown shell commands is disabled in Makefile
  sections that depend on OPSYS
* The experimental hand-written shell parser has been replaced with
  a Yacc-generated one
* Meta packages don't need a LICENSE
* When PKGNAME is defined in terms of ${DISTNAME:S/from/to/:tl}, more
  modifiers (like :tl) are handled properly
* When the MAINTAINER or OWNER of a package is not the current user,
  a warning is printed for modified files
* The check for share/applications/*.desktop has been disabled, since
  pkglint would need to inspect the file's actual contents to see
  whether desktopdb.mk must be included or not
* SUBST_CLASSES may also be SUBST_CLASSES.NetBSD
* Loosened the usage restrictions for several variables, e.g. many
  variables that may be appended in a Makefile may also be set
  unconditionally
* PKG_OPTIONS_VAR must be of the form PKG_OPTIONS.*


(rillig)
diff -r1.487 -r1.488 pkgsrc/pkgtools/pkglint/Makefile
diff -r1.9 -r1.10 pkgsrc/pkgtools/pkglint/files/check_test.go
diff -r1.9 -r1.10 pkgsrc/pkgtools/pkglint/files/shell.go
diff -r1.9 -r1.10 pkgsrc/pkgtools/pkglint/files/shell_test.go
diff -r1.10 -r1.11 pkgsrc/pkgtools/pkglint/files/globaldata.go
diff -r1.10 -r1.11 pkgsrc/pkgtools/pkglint/files/vardefs.go
diff -r1.10 -r1.11 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
diff -r1.4 -r1.5 pkgsrc/pkgtools/pkglint/files/licenses.go
diff -r1.4 -r1.5 pkgsrc/pkgtools/pkglint/files/substcontext_test.go
diff -r1.12 -r1.13 pkgsrc/pkgtools/pkglint/files/mkline.go
diff -r1.12 -r1.13 pkgsrc/pkgtools/pkglint/files/mkline_test.go
diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/mklines_test.go
diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/plist.go
diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/plist_test.go
diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/substcontext.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/mkparser.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/mkparser_test.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/mkshparser.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/mkshparser_test.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/mkshtypes.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/mktypes_test.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/shtokenizer.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go
diff -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/shtypes.go
diff -r0 -r1.1 pkgsrc/pkgtools/pkglint/files/mkshwalker.go
diff -r0 -r1.1 pkgsrc/pkgtools/pkglint/files/mkshwalker_test.go
diff -r0 -r1.1 pkgsrc/pkgtools/pkglint/files/shell.y
diff -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/package.go
diff -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/pkglint.go
diff -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/package_test.go
diff -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/util.go
diff -r1.3 -r1.4 pkgsrc/pkgtools/pkglint/files/util_test.go
diff -r1.14 -r1.15 pkgsrc/pkgtools/pkglint/files/vartypecheck.go
diff -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/vercmp_test.go

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

--- pkgsrc/pkgtools/pkglint/Makefile 2016/06/19 18:03:29 1.487
+++ pkgsrc/pkgtools/pkglint/Makefile 2016/07/07 12:09:26 1.488
@@ -1,41 +1,44 @@ @@ -1,41 +1,44 @@
1# $NetBSD: Makefile,v 1.487 2016/06/19 18:03:29 wiz Exp $ 1# $NetBSD: Makefile,v 1.488 2016/07/07 12:09:26 rillig Exp $
2 2
3PKGNAME= pkglint-5.4.2 3PKGNAME= pkglint-5.4.3
4DISTFILES= # none 4DISTFILES= # none
5CATEGORIES= pkgtools 5CATEGORIES= pkgtools
6 6
7OWNER= rillig@NetBSD.org 7OWNER= rillig@NetBSD.org
8HOMEPAGE= http://www.NetBSD.org/docs/pkgsrc/ 8HOMEPAGE= http://www.NetBSD.org/docs/pkgsrc/
9COMMENT= Verifier for NetBSD packages 9COMMENT= Verifier for NetBSD packages
10LICENSE= 2-clause-bsd 10LICENSE= 2-clause-bsd
11CONFLICTS+= pkglint4-[0-9]* 11CONFLICTS+= pkglint4-[0-9]*
12 12
13WRKSRC= ${WRKDIR}/netbsd.org/pkglint 13WRKSRC= ${WRKDIR}/netbsd.org/pkglint
14NO_CHECKSUM= yes 14NO_CHECKSUM= yes
15USE_LANGUAGES= # none 15USE_LANGUAGES= # none
16USE_TOOLS+= pax 16USE_TOOLS+= pax
17AUTO_MKDIRS= yes 17AUTO_MKDIRS= yes
18GO_SRCPATH= netbsd.org/pkglint 18GO_SRCPATH= netbsd.org/pkglint
19 19
20SUBST_CLASSES+= pkglint 20SUBST_CLASSES+= pkglint
21SUBST_STAGE.pkglint= post-configure 21SUBST_STAGE.pkglint= post-configure
22SUBST_FILES.pkglint+= main.go package_test.go 22SUBST_FILES.pkglint+= main.go package_test.go
23SUBST_SED.pkglint+= -e s\|@VERSION@\|${PKGNAME:S/pkglint-//}\|g 23SUBST_SED.pkglint+= -e s\|@VERSION@\|${PKGNAME:S/pkglint-//}\|g
24SUBST_SED.pkglint+= -e s\|@BMAKE@\|${MAKE:Q}\|g 24SUBST_SED.pkglint+= -e s\|@BMAKE@\|${MAKE:Q}\|g
25 25
26do-extract: 26do-extract:
27 ${RUN} mkdir -p ${WRKDIR}/pkglint/plist-clash 27 ${RUN} mkdir -p ${WRKDIR}/pkglint/plist-clash
28 ${RUN} cd ${FILESDIR} && ${PAX} -rw *.go */*.go pkglint.[01] ${WRKDIR}/pkglint 28 ${RUN} cd ${FILESDIR} && ${PAX} -rw *.go *.y */*.go pkglint.[01] ${WRKDIR}/pkglint
 29
 30pre-build:
 31 ${RUN} env GOPATH=${WRKDIR}:${BUILDLINK_DIR}/gopkg go generate ${GO_BUILD_PATTERN}
29 32
30do-install: do-install-man 33do-install: do-install-man
31 34
32.include "../../mk/bsd.prefs.mk" 35.include "../../mk/bsd.prefs.mk"
33 36
34do-install-man: .PHONY 37do-install-man: .PHONY
35.if !empty(MANINSTALL:Mcatinstall) 38.if !empty(MANINSTALL:Mcatinstall)
36. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss]) 39. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss])
37 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/pkglint.1 40 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/pkglint.1
38. else 41. else
39 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1 42 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1
40. endif 43. endif
41.endif 44.endif

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

--- pkgsrc/pkgtools/pkglint/files/Attic/check_test.go 2016/06/05 11:24:32 1.9
+++ pkgsrc/pkgtools/pkglint/files/Attic/check_test.go 2016/07/07 12:09:27 1.10
@@ -65,32 +65,38 @@ func (s *Suite) NewRawLines(args ...inte @@ -65,32 +65,38 @@ func (s *Suite) NewRawLines(args ...inte
65func (s *Suite) NewLines(fname string, texts ...string) []*Line { 65func (s *Suite) NewLines(fname string, texts ...string) []*Line {
66 result := make([]*Line, len(texts)) 66 result := make([]*Line, len(texts))
67 for i, text := range texts { 67 for i, text := range texts {
68 textnl := text + "\n" 68 textnl := text + "\n"
69 result[i] = NewLine(fname, i+1, text, s.NewRawLines(i+1, textnl)) 69 result[i] = NewLine(fname, i+1, text, s.NewRawLines(i+1, textnl))
70 } 70 }
71 return result 71 return result
72} 72}
73 73
74func (s *Suite) NewMkLines(fname string, lines ...string) *MkLines { 74func (s *Suite) NewMkLines(fname string, lines ...string) *MkLines {
75 return NewMkLines(s.NewLines(fname, lines...)) 75 return NewMkLines(s.NewLines(fname, lines...))
76} 76}
77 77
78func (s *Suite) DebugToStdout() { 78func (s *Suite) BeginDebugToStdout() {
79 G.debugOut = os.Stdout 79 G.debugOut = os.Stdout
80 G.logOut = os.Stdout 80 G.logOut = os.Stdout
81 G.opts.Debug = true 81 G.opts.Debug = true
82} 82}
83 83
 84func (s *Suite) EndDebugToStdout() {
 85 G.debugOut = &s.stdout
 86 G.logOut = &s.stdout
 87 G.opts.Debug = false
 88}
 89
84func (s *Suite) UseCommandLine(c *check.C, args ...string) { 90func (s *Suite) UseCommandLine(c *check.C, args ...string) {
85 exitcode := new(Pkglint).ParseCommandLine(append([]string{"pkglint"}, args...)) 91 exitcode := new(Pkglint).ParseCommandLine(append([]string{"pkglint"}, args...))
86 if exitcode != nil && *exitcode != 0 { 92 if exitcode != nil && *exitcode != 0 {
87 c.Fatalf("Cannot parse command line: %#v", args) 93 c.Fatalf("Cannot parse command line: %#v", args)
88 } 94 }
89 G.opts.LogVerbose = true // See SetUpTest 95 G.opts.LogVerbose = true // See SetUpTest
90} 96}
91 97
92func (s *Suite) RegisterMasterSite(varname string, urls ...string) { 98func (s *Suite) RegisterMasterSite(varname string, urls ...string) {
93 name2url := &G.globalData.MasterSiteVarToURL 99 name2url := &G.globalData.MasterSiteVarToURL
94 url2name := &G.globalData.MasterSiteURLToVar 100 url2name := &G.globalData.MasterSiteURLToVar
95 if *name2url == nil { 101 if *name2url == nil {
96 *name2url = make(map[string]string) 102 *name2url = make(map[string]string)

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

--- pkgsrc/pkgtools/pkglint/files/Attic/shell.go 2016/06/05 11:24:32 1.9
+++ pkgsrc/pkgtools/pkglint/files/Attic/shell.go 2016/07/07 12:09:27 1.10
@@ -1,115 +1,30 @@ @@ -1,115 +1,30 @@
1package main 1package main
2 2
3// Parsing and checking shell commands embedded in Makefiles 3// Parsing and checking shell commands embedded in Makefiles
4 4
5import ( 5import (
6 "path" 6 "path"
7 "strings" 7 "strings"
8) 8)
9 9
10const ( 10const (
11 reShellToken = `^\s*(` + 
12 `#.*` + // shell comment 
13 `|(?:` + 
14 `'[^']*'` + // single quoted string 
15 "|\"`[^`]+`\"" + // backticks command execution in double quotes 
16 `|"(?:\\.|[^"])*"` + // double quoted string 
17 "|`[^`]*`" + // backticks command execution (very simple case) 
18 `|\\\$\$` + // a shell-escaped dollar sign 
19 `|\\[^\$]` + // other escaped characters 
20 `|\$[\w_]` + // one-character make(1) variable 
21 `|\$\$[0-9A-Z_a-z]+` + // shell variable 
22 `|\$\$[!#?@]` + // special shell variables 
23 `|\$\$[./]` + // unescaped dollar in shell, followed by punctuation 
24 `|\$\$\$\$` + // the special pid shell variable 
25 `|\$\$\{[0-9A-Z_a-z]+[#%:]?[^}]*\}` + // shell variable in braces 
26 `|[^\(\)'\"\\\s;&\|<>` + "`" + `\$]` + // non-special character 
27 `|\$\{[^\s\"'` + "`" + `]+` + // HACK: nested make(1) variables 
28 `)+` + // any of the above may be repeated 
29 `|\$\$\(` + // POSIX-style backticks replacement 
30 `|;;?` + 
31 `|&&?` + 
32 `|\|\|?` + 
33 `|\(` + 
34 `|\)` + 
35 `|>&` + 
36 `|<<?` + 
37 `|>>?` + 
38 `|#.*)` 
39 reShVarassign = `^([A-Z_a-z]\w*)=` 11 reShVarassign = `^([A-Z_a-z]\w*)=`
40 reShVarname = `(?:[!#*\-\d?@]|\$\$|[A-Za-z_]\w*)` 12 reShVarname = `(?:[!#*\-\d?@]|\$\$|[A-Za-z_]\w*)`
41 reShVarexpansion = `(?:(?:#|##|%|%%|:-|:=|:\?|:\+|\+)[^$\\{}]*)` 13 reShVarexpansion = `(?:(?:#|##|%|%%|:-|:=|:\?|:\+|\+)[^$\\{}]*)`
42 reShVaruse = `\$\$` + `(?:` + reShVarname + `|` + `\{` + reShVarname + `(?:` + reShVarexpansion + `)?` + `\})` 14 reShVaruse = `\$\$` + `(?:` + reShVarname + `|` + `\{` + reShVarname + `(?:` + reShVarexpansion + `)?` + `\})`
43 reShDollar = `\\\$\$|` + reShVaruse + `|\$\$[,\-/|]` 15 reShDollar = `\\\$\$|` + reShVaruse + `|\$\$[,\-/|]`
44) 16)
45 17
46// ShellCommandState 
47type scState uint8 
48 
49const ( 
50 scstStart scState = iota 
51 scstCont 
52 scstInstall 
53 scstInstallD 
54 scstMkdir 
55 scstPax 
56 scstPaxS 
57 scstSed 
58 scstSedE 
59 scstSet 
60 scstSetCont 
61 scstCond 
62 scstCondCont 
63 scstCase 
64 scstCaseIn 
65 scstCaseLabel 
66 scstCaseLabelCont 
67 scstFor 
68 scstForIn 
69 scstForCont 
70 scstEcho 
71 scstInstallDir 
72 scstInstallDir2 
73) 
74 
75func (st scState) String() string { 
76 return [...]string{ 
77 "start", 
78 "continuation", 
79 "install", 
80 "install -d", 
81 "mkdir", 
82 "pax", 
83 "pax -s", 
84 "sed", 
85 "sed -e", 
86 "set", 
87 "set-continuation", 
88 "cond", 
89 "cond-continuation", 
90 "case", 
91 "case in", 
92 "case label", 
93 "case-label-continuation", 
94 "for", 
95 "for-in", 
96 "for-continuation", 
97 "echo", 
98 "install-dir", 
99 "install-dir2", 
100 }[st] 
101} 
102 
103type ShellLine struct { 18type ShellLine struct {
104 line *Line 19 line *Line
105 mkline *MkLine 20 mkline *MkLine
106} 21}
107 22
108func NewShellLine(mkline *MkLine) *ShellLine { 23func NewShellLine(mkline *MkLine) *ShellLine {
109 return &ShellLine{mkline.Line, mkline} 24 return &ShellLine{mkline.Line, mkline}
110} 25}
111 26
112var shellcommandsContextType = &Vartype{lkNone, CheckvarShellCommands, []AclEntry{{"*", aclpAllRuntime}}, false} 27var shellcommandsContextType = &Vartype{lkNone, CheckvarShellCommands, []AclEntry{{"*", aclpAllRuntime}}, false}
113var shellwordVuc = &VarUseContext{shellcommandsContextType, vucTimeUnknown, vucQuotPlain, vucExtentWord} 28var shellwordVuc = &VarUseContext{shellcommandsContextType, vucTimeUnknown, vucQuotPlain, vucExtentWord}
114 29
115func (shline *ShellLine) CheckWord(token string, checkQuoting bool) { 30func (shline *ShellLine) CheckWord(token string, checkQuoting bool) {
@@ -345,32 +260,26 @@ func (shline *ShellLine) unescapeBacktic @@ -345,32 +260,26 @@ func (shline *ShellLine) unescapeBacktic
345 return unescaped, quoting 260 return unescaped, quoting
346} 261}
347 262
348func (shline *ShellLine) variableNeedsQuoting(shvarname string) bool { 263func (shline *ShellLine) variableNeedsQuoting(shvarname string) bool {
349 switch shvarname { 264 switch shvarname {
350 case "#", "?": 265 case "#", "?":
351 return false // Definitely ok 266 return false // Definitely ok
352 case "d", "f", "i", "dir", "file", "src", "dst": 267 case "d", "f", "i", "dir", "file", "src", "dst":
353 return false // Probably ok 268 return false // Probably ok
354 } 269 }
355 return true 270 return true
356} 271}
357 272
358type ShelltextContext struct { 
359 shline *ShellLine 
360 state scState 
361 shellword string 
362} 
363 
364func (shline *ShellLine) CheckShellCommandLine(shelltext string) { 273func (shline *ShellLine) CheckShellCommandLine(shelltext string) {
365 if G.opts.Debug { 274 if G.opts.Debug {
366 defer tracecall1(shelltext)() 275 defer tracecall1(shelltext)()
367 } 276 }
368 277
369 line := shline.line 278 line := shline.line
370 279
371 if contains(shelltext, "${SED}") && contains(shelltext, "${MV}") { 280 if contains(shelltext, "${SED}") && contains(shelltext, "${MV}") {
372 line.Note0("Please use the SUBST framework instead of ${SED} and ${MV}.") 281 line.Note0("Please use the SUBST framework instead of ${SED} and ${MV}.")
373 Explain( 282 Explain(
374 "Using the SUBST framework instead of explicit commands is easier", 283 "Using the SUBST framework instead of explicit commands is easier",
375 "to understand, since all the complexity of using sed and mv is", 284 "to understand, since all the complexity of using sed and mv is",
376 "hidden behind the scenes.", 285 "hidden behind the scenes.",
@@ -401,109 +310,93 @@ func (shline *ShellLine) CheckShellComma @@ -401,109 +310,93 @@ func (shline *ShellLine) CheckShellComma
401 shline.checkHiddenAndSuppress(repl.m[0], repl.rest) 310 shline.checkHiddenAndSuppress(repl.m[0], repl.rest)
402 } 311 }
403 setE := false 312 setE := false
404 if repl.AdvanceStr("${RUN}") { 313 if repl.AdvanceStr("${RUN}") {
405 setE = true 314 setE = true
406 } else { 315 } else {
407 repl.AdvanceStr("${_PKG_SILENT}${_PKG_DEBUG}") 316 repl.AdvanceStr("${_PKG_SILENT}${_PKG_DEBUG}")
408 } 317 }
409 318
410 shline.CheckShellCommand(repl.rest, &setE) 319 shline.CheckShellCommand(repl.rest, &setE)
411} 320}
412 321
413func (shline *ShellLine) CheckShellCommand(shellcmd string, pSetE *bool) { 322func (shline *ShellLine) CheckShellCommand(shellcmd string, pSetE *bool) {
414 if false { 323 if G.opts.Debug {
415 p := NewMkShParser(shline.line, shellcmd, false) 324 defer tracecall()()
416 cmds := p.Program() 
417 rest := p.tok.parser.Rest() 
418 if rest != "" { 
419 traceStep("shellcmd=%q", shellcmd) 
420 if cmds != nil { 
421 for _, andor := range cmds.AndOrs { 
422 traceStep("AndOr %v", andor) 
423 } 
424 } 
425 shline.line.Warnf("Pkglint parse error in ShellLine.CheckShellCommand at %q", p.peekText()+rest) 
426 } 
427 } 325 }
428 326
429 state := scstStart 327 program, err := parseShellProgram(shline.line, shellcmd)
430 tokens, rest := splitIntoShellTokens(shline.line, shellcmd) 328 if err != nil && contains(shellcmd, "$$(") { // Hack until the shell parser can handle subshells.
431 if rest != "" { 329 shline.line.Warn0("Invoking subshells via $(...) is not portable enough.")
432 shline.line.Warnf("Pkglint parse error in ShellLine.CheckShellCommand at %q (state=%s)", rest, state) 330 return
 331 }
 332 if err != nil {
 333 shline.line.Warnf("Pkglint ShellLine.CheckShellCommand: %s", err)
 334 return
433 } 335 }
434 336
435 prevToken := "" 337 spc := &ShellProgramChecker{shline}
436 for _, token := range tokens { 338 spc.checkConditionalCd(program)
437 if G.opts.Debug { 
438 traceStep("checkShellCommand state=%v token=%q", state, token) 
439 } 
440 339
441 { 340 (*MkShWalker).Walk(nil, program, func(node interface{}) {
442 noQuotingNeeded := state == scstCase || 341 if cmd, ok := node.(*MkShSimpleCommand); ok {
443 state == scstForCont || 342 scc := NewSimpleCommandChecker(shline, cmd)
444 state == scstSetCont || 343 scc.Check()
445 (state == scstStart && matches(token, reShVarassign)) 344 if scc.strcmd.Name == "set" && scc.strcmd.AnyArgMatches(`^-.*e`) {
446 shline.CheckWord(token, !noQuotingNeeded) 345 *pSetE = true
 346 }
447 } 347 }
448 348
449 st := &ShelltextContext{shline, state, token} 349 if cmd, ok := node.(*MkShList); ok {
450 st.checkCommandStart() 350 spc.checkSetE(cmd, pSetE)
451 st.checkConditionalCd() 
452 if state != scstPaxS && state != scstSedE && state != scstCaseLabel { 
453 shline.line.CheckAbsolutePathname(token) 
454 } 351 }
455 st.checkAutoMkdirs() 
456 st.checkInstallMulti() 
457 st.checkPaxPe() 
458 st.checkQuoteSubstitution() 
459 st.checkEchoN() 
460 st.checkPipeExitcode() 
461 st.checkSetE(pSetE, prevToken) 
462 352
463 if state == scstSet && hasPrefix(token, "-") && contains(token, "e") || state == scstStart && token == "${RUN}" { 353 if cmd, ok := node.(*MkShPipeline); ok {
464 *pSetE = true 354 spc.checkPipeExitcode(shline.line, cmd)
465 } 355 }
466 356
467 state = shline.nextState(state, token) 357 if word, ok := node.(*ShToken); ok {
468 prevToken = token 358 spc.checkWord(word, false)
469 } 359 }
 360 })
470} 361}
471 362
472func (shline *ShellLine) CheckShellCommands(shellcmds string) { 363func (shline *ShellLine) CheckShellCommands(shellcmds string) {
473 setE := true 364 setE := true
474 shline.CheckShellCommand(shellcmds, &setE) 365 shline.CheckShellCommand(shellcmds, &setE)
475 if !hasSuffix(shellcmds, ";") { 366 if !hasSuffix(shellcmds, ";") {
476 shline.line.Warn0("This shell command list should end with a semicolon.") 367 shline.line.Warn0("This shell command list should end with a semicolon.")
477 } 368 }
478} 369}
479 370
480func (shline *ShellLine) checkHiddenAndSuppress(hiddenAndSuppress, rest string) { 371func (shline *ShellLine) checkHiddenAndSuppress(hiddenAndSuppress, rest string) {
481 if G.opts.Debug { 372 if G.opts.Debug {
482 defer tracecall(hiddenAndSuppress, rest)() 373 defer tracecall(hiddenAndSuppress, rest)()
483 } 374 }
484 375
485 switch { 376 switch {
486 case !contains(hiddenAndSuppress, "@"): 377 case !contains(hiddenAndSuppress, "@"):
487 // Nothing is hidden at all. 378 // Nothing is hidden at all.
488 379
489 case hasPrefix(G.Mk.target, "show-") || hasSuffix(G.Mk.target, "-message"): 380 case hasPrefix(G.Mk.target, "show-") || hasSuffix(G.Mk.target, "-message"):
490 // In these targets, all commands may be hidden. 381 // In these targets, all commands may be hidden.
491 382
492 case hasPrefix(rest, "#"): 383 case hasPrefix(rest, "#"):
493 // Shell comments may be hidden, since they cannot have side effects. 384 // Shell comments may be hidden, since they cannot have side effects.
494 385
495 default: 386 default:
496 if m, cmd := match1(rest, reShellToken); m { 387 tokens, _ := splitIntoShellTokens(shline.line, rest)
 388 if len(tokens) > 0 {
 389 cmd := tokens[0]
497 switch cmd { 390 switch cmd {
498 case "${DELAYED_ERROR_MSG}", "${DELAYED_WARNING_MSG}", 391 case "${DELAYED_ERROR_MSG}", "${DELAYED_WARNING_MSG}",
499 "${DO_NADA}", 392 "${DO_NADA}",
500 "${ECHO}", "${ECHO_MSG}", "${ECHO_N}", "${ERROR_CAT}", "${ERROR_MSG}", 393 "${ECHO}", "${ECHO_MSG}", "${ECHO_N}", "${ERROR_CAT}", "${ERROR_MSG}",
501 "${FAIL_MSG}", 394 "${FAIL_MSG}",
502 "${PHASE_MSG}", "${PRINTF}", 395 "${PHASE_MSG}", "${PRINTF}",
503 "${SHCOMMENT}", "${STEP_MSG}", 396 "${SHCOMMENT}", "${STEP_MSG}",
504 "${WARNING_CAT}", "${WARNING_MSG}": 397 "${WARNING_CAT}", "${WARNING_MSG}":
505 break 398 break
506 default: 399 default:
507 shline.line.Warn1("The shell command %q should not be hidden.", cmd) 400 shline.line.Warn1("The shell command %q should not be hidden.", cmd)
508 Explain( 401 Explain(
509 "Hidden shell commands do not appear on the terminal or in the log", 402 "Hidden shell commands do not appear on the terminal or in the log",
@@ -515,129 +408,158 @@ func (shline *ShellLine) checkHiddenAndS @@ -515,129 +408,158 @@ func (shline *ShellLine) checkHiddenAndS
515 "PKG_DEBUG_LEVEL is set.") 408 "PKG_DEBUG_LEVEL is set.")
516 } 409 }
517 } 410 }
518 } 411 }
519 412
520 if contains(hiddenAndSuppress, "-") { 413 if contains(hiddenAndSuppress, "-") {
521 shline.line.Warn0("Using a leading \"-\" to suppress errors is deprecated.") 414 shline.line.Warn0("Using a leading \"-\" to suppress errors is deprecated.")
522 Explain2( 415 Explain2(
523 "If you really want to ignore any errors from this command, append", 416 "If you really want to ignore any errors from this command, append",
524 "\"|| ${TRUE}\" to the command.") 417 "\"|| ${TRUE}\" to the command.")
525 } 418 }
526} 419}
527 420
528func (ctx *ShelltextContext) checkCommandStart() { 421type SimpleCommandChecker struct {
 422 shline *ShellLine
 423 cmd *MkShSimpleCommand
 424 strcmd *StrCommand
 425}
 426
 427func NewSimpleCommandChecker(shline *ShellLine, cmd *MkShSimpleCommand) *SimpleCommandChecker {
 428 strcmd := NewStrCommand(cmd)
 429 return &SimpleCommandChecker{shline, cmd, strcmd}
 430
 431}
 432
 433func (c *SimpleCommandChecker) Check() {
529 if G.opts.Debug { 434 if G.opts.Debug {
530 defer tracecall2(ctx.state.String(), ctx.shellword)() 435 defer tracecall(c.strcmd)()
531 } 436 }
532 437
533 state, shellword := ctx.state, ctx.shellword 438 c.checkCommandStart()
534 if state != scstStart && state != scstCond { 439 c.checkAbsolutePathnames()
535 return 440 c.checkAutoMkdirs()
 441 c.checkInstallMulti()
 442 c.checkPaxPe()
 443 c.checkEchoN()
 444}
 445
 446func (ctx *SimpleCommandChecker) checkCommandStart() {
 447 if G.opts.Debug {
 448 defer tracecall()()
536 } 449 }
537 450
 451 shellword := ctx.strcmd.Name
538 switch { 452 switch {
539 case shellword == "${RUN}": 453 case shellword == "${RUN}" || shellword == "":
540 case ctx.handleForbiddenCommand(): 454 case ctx.handleForbiddenCommand():
541 case ctx.handleTool(): 455 case ctx.handleTool():
542 case ctx.handleCommandVariable(): 456 case ctx.handleCommandVariable():
543 case matches(shellword, `^(?:\$\$\(|\(|\)|:|;|;;|&&|\|\||\{|\}|break|case|cd|continue|do|done|elif|else|esac|eval|exec|exit|export|fi|for|if|read|set|shift|then|umask|unset|while)$`): 457 case matches(shellword, `^(?::|break|cd|continue|eval|exec|exit|export|read|set|shift|umask|unset)$`):
544 case matches(shellword, `^\w+=`): // Variable assignment 
545 case hasPrefix(shellword, "./"): // All commands from the current directory are fine. 458 case hasPrefix(shellword, "./"): // All commands from the current directory are fine.
546 case hasPrefix(shellword, "${PKGSRCDIR"): // With or without the :Q modifier 459 case hasPrefix(shellword, "${PKGSRCDIR"): // With or without the :Q modifier
547 case ctx.handleComment(): 460 case ctx.handleComment():
548 default: 461 default:
549 if G.opts.WarnExtra { 462 if G.opts.WarnExtra && !(G.Mk != nil && G.Mk.indentation.DependsOn("OPSYS")) {
550 ctx.shline.line.Warn1("Unknown shell command %q.", shellword) 463 ctx.shline.line.Warn1("Unknown shell command %q.", shellword)
551 Explain3( 464 Explain3(
552 "If you want your package to be portable to all platforms that pkgsrc", 465 "If you want your package to be portable to all platforms that pkgsrc",
553 "supports, you should only use shell commands that are covered by the", 466 "supports, you should only use shell commands that are covered by the",
554 "tools framework.") 467 "tools framework.")
555 } 468 }
556 } 469 }
557} 470}
558 471
559func (ctx *ShelltextContext) handleTool() bool { 472func (ctx *SimpleCommandChecker) handleTool() bool {
560 if G.opts.Debug { 473 if G.opts.Debug {
561 defer tracecall1(ctx.shellword)() 474 defer tracecall()()
562 } 475 }
563 476
564 shellword := ctx.shellword 477 shellword := ctx.strcmd.Name
565 tool := G.globalData.Tools.byName[shellword] 478 tool := G.globalData.Tools.byName[shellword]
566 if tool == nil { 479 if tool == nil {
567 return false 480 return false
568 } 481 }
569 482
570 if !G.Mk.tools[shellword] && !G.Mk.tools["g"+shellword] { 483 if !G.Mk.tools[shellword] && !G.Mk.tools["g"+shellword] {
571 ctx.shline.line.Warn1("The %q tool is used but not added to USE_TOOLS.", shellword) 484 ctx.shline.line.Warn1("The %q tool is used but not added to USE_TOOLS.", shellword)
572 } 485 }
573 486
574 if tool.MustUseVarForm { 487 if tool.MustUseVarForm {
575 ctx.shline.line.Warn2("Please use \"${%s}\" instead of %q.", tool.Varname, shellword) 488 ctx.shline.line.Warn2("Please use \"${%s}\" instead of %q.", tool.Varname, shellword)
576 } 489 }
577 490
578 ctx.shline.checkCommandUse(shellword) 491 ctx.shline.checkCommandUse(shellword)
579 return true 492 return true
580} 493}
581 494
582func (ctx *ShelltextContext) handleForbiddenCommand() bool { 495func (ctx *SimpleCommandChecker) handleForbiddenCommand() bool {
583 switch path.Base(ctx.shellword) { 496 if G.opts.Debug {
 497 defer tracecall()()
 498 }
 499
 500 shellword := ctx.strcmd.Name
 501 switch path.Base(shellword) {
584 case "ktrace", "mktexlsr", "strace", "texconfig", "truss": 502 case "ktrace", "mktexlsr", "strace", "texconfig", "truss":
585 ctx.shline.line.Error1("%q must not be used in Makefiles.", ctx.shellword) 503 ctx.shline.line.Error1("%q must not be used in Makefiles.", shellword)
586 Explain3( 504 Explain3(
587 "This command must appear in INSTALL scripts, not in the package", 505 "This command must appear in INSTALL scripts, not in the package",
588 "Makefile, so that the package also works if it is installed as a binary", 506 "Makefile, so that the package also works if it is installed as a binary",
589 "package via pkg_add.") 507 "package via pkg_add.")
590 return true 508 return true
591 } 509 }
592 return false 510 return false
593} 511}
594 512
595func (ctx *ShelltextContext) handleCommandVariable() bool { 513func (ctx *SimpleCommandChecker) handleCommandVariable() bool {
596 if G.opts.Debug { 514 if G.opts.Debug {
597 defer tracecall1(ctx.shellword)() 515 defer tracecall()()
598 } 516 }
599 517
600 shellword := ctx.shellword 518 shellword := ctx.strcmd.Name
601 if m, varname := match1(shellword, `^\$\{([\w_]+)\}$`); m { 519 if m, varname := match1(shellword, `^\$\{([\w_]+)\}$`); m {
602 520
603 if tool := G.globalData.Tools.byVarname[varname]; tool != nil { 521 if tool := G.globalData.Tools.byVarname[varname]; tool != nil {
604 if !G.Mk.tools[tool.Name] { 522 if !G.Mk.tools[tool.Name] {
605 ctx.shline.line.Warn1("The %q tool is used but not added to USE_TOOLS.", tool.Name) 523 ctx.shline.line.Warn1("The %q tool is used but not added to USE_TOOLS.", tool.Name)
606 } 524 }
607 ctx.shline.checkCommandUse(shellword) 525 ctx.shline.checkCommandUse(shellword)
608 return true 526 return true
609 } 527 }
610 528
611 if vartype := ctx.shline.mkline.getVariableType(varname); vartype != nil && vartype.checker.name == "ShellCommand" { 529 if vartype := ctx.shline.mkline.getVariableType(varname); vartype != nil && vartype.checker.name == "ShellCommand" {
612 ctx.shline.checkCommandUse(shellword) 530 ctx.shline.checkCommandUse(shellword)
613 return true 531 return true
614 } 532 }
615 533
616 // When the package author has explicitly defined a command 534 // When the package author has explicitly defined a command
617 // variable, assume it to be valid. 535 // variable, assume it to be valid.
618 if G.Pkg != nil && G.Pkg.vardef[varname] != nil { 536 if G.Pkg != nil && G.Pkg.vardef[varname] != nil {
619 return true 537 return true
620 } 538 }
621 } 539 }
622 return false 540 return false
623} 541}
624 542
625func (ctx *ShelltextContext) handleComment() bool { 543func (ctx *SimpleCommandChecker) handleComment() bool {
626 if G.opts.Debug { 544 if G.opts.Debug {
627 defer tracecall1(ctx.shellword)() 545 defer tracecall()()
 546 }
 547
 548 shellword := ctx.strcmd.Name
 549 if G.opts.Debug {
 550 defer tracecall1(shellword)()
628 } 551 }
629 552
630 shellword := ctx.shellword 
631 if !hasPrefix(shellword, "#") { 553 if !hasPrefix(shellword, "#") {
632 return false 554 return false
633 } 555 }
634 556
635 semicolon := contains(shellword, ";") 557 semicolon := contains(shellword, ";")
636 multiline := ctx.shline.line.IsMultiline() 558 multiline := ctx.shline.line.IsMultiline()
637 559
638 if semicolon { 560 if semicolon {
639 ctx.shline.line.Warn0("A shell comment should not contain semicolons.") 561 ctx.shline.line.Warn0("A shell comment should not contain semicolons.")
640 } 562 }
641 if multiline { 563 if multiline {
642 ctx.shline.line.Warn0("A shell comment does not stop at the end of line.") 564 ctx.shline.line.Warn0("A shell comment does not stop at the end of line.")
643 } 565 }
@@ -650,143 +572,249 @@ func (ctx *ShelltextContext) handleComme @@ -650,143 +572,249 @@ func (ctx *ShelltextContext) handleComme
650 "it _looks_ like that the comment only spans one line in the", 572 "it _looks_ like that the comment only spans one line in the",
651 "Makefile, in fact it spans until the end of the whole shell command.", 573 "Makefile, in fact it spans until the end of the whole shell command.",
652 "", 574 "",
653 "To insert a comment into shell code, you can write it like this:", 575 "To insert a comment into shell code, you can write it like this:",
654 "", 576 "",
655 "\t"+"${SHCOMMENT} \"The following command might fail; this is ok.\"", 577 "\t"+"${SHCOMMENT} \"The following command might fail; this is ok.\"",
656 "", 578 "",
657 "Note that any special characters in the comment are still", 579 "Note that any special characters in the comment are still",
658 "interpreted by the shell.") 580 "interpreted by the shell.")
659 } 581 }
660 return true 582 return true
661} 583}
662 584
663func (ctx *ShelltextContext) checkConditionalCd() { 585type ShellProgramChecker struct {
664 if ctx.state == scstCond && ctx.shellword == "cd" { 586 shline *ShellLine
665 ctx.shline.line.Error0("The Solaris /bin/sh cannot handle \"cd\" inside conditionals.") 
666 Explain3( 
667 "When the Solaris shell is in \"set -e\" mode and \"cd\" fails, the", 
668 "shell will exit, no matter if it is protected by an \"if\" or the", 
669 "\"||\" operator.") 
670 } 
671} 587}
672 588
673func (ctx *ShelltextContext) checkAutoMkdirs() { 589func (c *ShellProgramChecker) checkConditionalCd(list *MkShList) {
674 state, shellword := ctx.state, ctx.shellword 590 if G.opts.Debug {
 591 defer tracecall()()
 592 }
675 593
676 line := ctx.shline.line 594 getSimple := func(list *MkShList) *MkShSimpleCommand {
677 if (state == scstInstallD || state == scstMkdir) && matches(shellword, `^(?:\$\{DESTDIR\})?\$\{PREFIX(?:|:Q)\}/`) { 595 if len(list.AndOrs) == 1 {
678 line.Warn1("Please use AUTO_MKDIRS instead of %q.", 596 if len(list.AndOrs[0].Pipes) == 1 {
679 ifelseStr(state == scstMkdir, "${MKDIR}", "${INSTALL} -d")) 597 if len(list.AndOrs[0].Pipes[0].Cmds) == 1 {
680 Explain4( 598 return list.AndOrs[0].Pipes[0].Cmds[0].Simple
681 "Setting AUTO_MKDIRS=yes automatically creates all directories that", 599 }
682 "are mentioned in the PLIST. If you need additional directories,", 600 }
683 "specify them in INSTALLATION_DIRS, which is a list of directories", 601 }
684 "relative to ${PREFIX}.") 602 return nil
685 } 603 }
686 604
687 if (state == scstInstallDir || state == scstInstallDir2) && !contains(shellword, "$$") { 605 checkConditionalCd := func(cmd *MkShSimpleCommand) {
688 if m, dirname := match1(shellword, `^(?:\$\{DESTDIR\})?\$\{PREFIX(?:|:Q)\}/(.*)`); m { 606 if NewStrCommand(cmd).Name == "cd" {
689 line.Note1("You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= %s\" instead of this command.", dirname) 607 c.shline.line.Error0("The Solaris /bin/sh cannot handle \"cd\" inside conditionals.")
690 Explain( 608 Explain3(
691 "Many packages include a list of all needed directories in their", 609 "When the Solaris shell is in \"set -e\" mode and \"cd\" fails, the",
692 "PLIST file. In such a case, you can just set AUTO_MKDIRS=yes and", 610 "shell will exit, no matter if it is protected by an \"if\" or the",
693 "be done. The pkgsrc infrastructure will then create all directories", 611 "\"||\" operator.")
694 "in advance.", 
695 "", 
696 "To create directories that are not mentioned in the PLIST file, it", 
697 "is easier to just list them in INSTALLATION_DIRS than to execute the", 
698 "commands explicitly. That way, you don't have to think about which", 
699 "of the many INSTALL_*_DIR variables is appropriate, since", 
700 "INSTALLATION_DIRS takes care of that.") 
701 } 612 }
702 } 613 }
 614
 615 (*MkShWalker).Walk(nil, list, func(node interface{}) {
 616 if cmd, ok := node.(*MkShIfClause); ok {
 617 for _, cond := range cmd.Conds {
 618 if simple := getSimple(cond); simple != nil {
 619 checkConditionalCd(simple)
 620 }
 621 }
 622 }
 623 if cmd, ok := node.(*MkShLoopClause); ok {
 624 if simple := getSimple(cmd.Cond); simple != nil {
 625 checkConditionalCd(simple)
 626 }
 627 }
 628 })
703} 629}
704 630
705func (ctx *ShelltextContext) checkInstallMulti() { 631func (c *ShellProgramChecker) checkWords(words []*ShToken, checkQuoting bool) {
706 if ctx.state == scstInstallDir2 && hasPrefix(ctx.shellword, "$") { 632 if G.opts.Debug {
707 line := ctx.shline.line 633 defer tracecall()()
708 line.Warn0("The INSTALL_*_DIR commands can only handle one directory at a time.") 634 }
709 Explain2( 635
710 "Many implementations of install(1) can handle more, but pkgsrc aims", 636 for _, word := range words {
711 "at maximum portability.") 637 c.checkWord(word, checkQuoting)
712 } 638 }
713} 639}
714 640
715func (ctx *ShelltextContext) checkPaxPe() { 641func (c *ShellProgramChecker) checkWord(word *ShToken, checkQuoting bool) {
716 if ctx.state == scstPax && ctx.shellword == "-pe" { 642 if G.opts.Debug {
717 line := ctx.shline.line 643 defer tracecall(word.MkText)()
718 line.Warn0("Please use the -pp option to pax(1) instead of -pe.") 
719 Explain3( 
720 "The -pe option tells pax to preserve the ownership of the files, which", 
721 "means that the installed files will belong to the user that has built", 
722 "the package.") 
723 } 644 }
 645
 646 c.shline.CheckWord(word.MkText, checkQuoting)
724} 647}
725 648
726func (ctx *ShelltextContext) checkQuoteSubstitution() { 649func (c *SimpleCommandChecker) checkAbsolutePathnames() {
727 if ctx.state == scstPaxS || ctx.state == scstSedE { 650 if G.opts.Debug {
728 if false && !matches(ctx.shellword, `"^[\"\'].*[\"\']$`) { 651 defer tracecall()()
729 line := ctx.shline.line 652 }
730 line.Warn1("Substitution commands like %q should always be quoted.", ctx.shellword) 653
 654 cmdname := c.strcmd.Name
 655 isSubst := false
 656 for _, arg := range c.strcmd.Args {
 657 if !isSubst {
 658 c.shline.line.CheckAbsolutePathname(arg)
 659 }
 660 if false && isSubst && !matches(arg, `"^[\"\'].*[\"\']$`) {
 661 c.shline.line.Warn1("Substitution commands like %q should always be quoted.", arg)
731 Explain3( 662 Explain3(
732 "Usually these substitution commands contain characters like '*' or", 663 "Usually these substitution commands contain characters like '*' or",
733 "other shell metacharacters that might lead to lookup of matching", 664 "other shell metacharacters that might lead to lookup of matching",
734 "filenames and then expand to more than one word.") 665 "filenames and then expand to more than one word.")
735 } 666 }
 667 isSubst = cmdname == "${PAX}" && arg == "-s" || cmdname == "${SED}" && arg == "-e"
 668 }
 669}
 670
 671func (ctx *SimpleCommandChecker) checkAutoMkdirs() {
 672 if G.opts.Debug {
 673 defer tracecall()()
 674 }
 675
 676 cmdname := ctx.strcmd.Name
 677 switch {
 678 case cmdname == "${MKDIR}":
 679 break
 680 case cmdname == "${INSTALL}" && ctx.strcmd.HasOption("-d"):
 681 cmdname = "${INSTALL} -d"
 682 case matches(cmdname, `^\$\{INSTALL_.*_DIR\}$`):
 683 break
 684 default:
 685 return
 686 }
 687
 688 for _, arg := range ctx.strcmd.Args {
 689 if !contains(arg, "$$") && !matches(arg, `\$\{[_.]*[a-z]`) {
 690 if m, dirname := match1(arg, `^(?:\$\{DESTDIR\})?\$\{PREFIX(?:|:Q)\}/(.*)`); m {
 691 ctx.shline.line.Note2("You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= %s\" instead of %q.", dirname, cmdname)
 692 Explain(
 693 "Many packages include a list of all needed directories in their",
 694 "PLIST file. In such a case, you can just set AUTO_MKDIRS=yes and",
 695 "be done. The pkgsrc infrastructure will then create all directories",
 696 "in advance.",
 697 "",
 698 "To create directories that are not mentioned in the PLIST file, it",
 699 "is easier to just list them in INSTALLATION_DIRS than to execute the",
 700 "commands explicitly. That way, you don't have to think about which",
 701 "of the many INSTALL_*_DIR variables is appropriate, since",
 702 "INSTALLATION_DIRS takes care of that.")
 703 }
 704 }
 705 }
 706}
 707
 708func (ctx *SimpleCommandChecker) checkInstallMulti() {
 709 if G.opts.Debug {
 710 defer tracecall()()
 711 }
 712
 713 cmd := ctx.strcmd
 714
 715 if hasPrefix(cmd.Name, "${INSTALL_") && hasSuffix(cmd.Name, "_DIR}") {
 716 prevdir := ""
 717 for i, arg := range cmd.Args {
 718 switch {
 719 case hasPrefix(arg, "-"):
 720 break
 721 case i > 0 && (cmd.Args[i-1] == "-m" || cmd.Args[i-1] == "-o" || cmd.Args[i-1] == "-g"):
 722 break
 723 default:
 724 if prevdir != "" {
 725 ctx.shline.line.Warn0("The INSTALL_*_DIR commands can only handle one directory at a time.")
 726 Explain2(
 727 "Many implementations of install(1) can handle more, but pkgsrc aims",
 728 "at maximum portability.")
 729 return
 730 }
 731 prevdir = arg
 732 }
 733 }
 734 }
 735}
 736
 737func (ctx *SimpleCommandChecker) checkPaxPe() {
 738 if G.opts.Debug {
 739 defer tracecall()()
 740 }
 741
 742 if ctx.strcmd.Name == "${PAX}" && ctx.strcmd.HasOption("-pe") {
 743 ctx.shline.line.Warn0("Please use the -pp option to pax(1) instead of -pe.")
 744 Explain3(
 745 "The -pe option tells pax to preserve the ownership of the files, which",
 746 "means that the installed files will belong to the user that has built",
 747 "the package.")
736 } 748 }
737} 749}
738 750
739func (ctx *ShelltextContext) checkEchoN() { 751func (ctx *SimpleCommandChecker) checkEchoN() {
740 if ctx.state == scstEcho && ctx.shellword == "-n" { 752 if G.opts.Debug {
 753 defer tracecall()()
 754 }
 755
 756 if ctx.strcmd.Name == "${ECHO}" && ctx.strcmd.HasOption("-n") {
741 ctx.shline.line.Warn0("Please use ${ECHO_N} instead of \"echo -n\".") 757 ctx.shline.line.Warn0("Please use ${ECHO_N} instead of \"echo -n\".")
742 } 758 }
743} 759}
744 760
745func (ctx *ShelltextContext) checkPipeExitcode() { 761func (ctx *ShellProgramChecker) checkPipeExitcode(line *Line, pipeline *MkShPipeline) {
746 if G.opts.WarnExtra && ctx.state != scstCaseLabelCont && ctx.shellword == "|" { 762 if G.opts.Debug {
747 line := ctx.shline.line 763 defer tracecall()()
 764 }
 765
 766 if G.opts.WarnExtra && len(pipeline.Cmds) > 1 {
748 line.Warn0("The exitcode of the left-hand-side command of the pipe operator is ignored.") 767 line.Warn0("The exitcode of the left-hand-side command of the pipe operator is ignored.")
749 Explain( 768 Explain(
750 "In a shell command like \"cat *.txt | grep keyword\", if the command", 769 "In a shell command like \"cat *.txt | grep keyword\", if the command",
751 "on the left side of the \"|\" fails, this failure is ignored.", 770 "on the left side of the \"|\" fails, this failure is ignored.",
752 "", 771 "",
753 "If you need to detect the failure of the left-hand-side command, use", 772 "If you need to detect the failure of the left-hand-side command, use",
754 "temporary files to save the output of the command.") 773 "temporary files to save the output of the command.")
755 } 774 }
756} 775}
757 776
758func (ctx *ShelltextContext) checkSetE(eflag *bool, prevToken string) { 777func (ctx *ShellProgramChecker) checkSetE(list *MkShList, eflag *bool) {
759 if G.opts.WarnExtra && ctx.shellword == ";" && ctx.state != scstCondCont && ctx.state != scstForCont && !*eflag { 778 if G.opts.Debug {
 779 defer tracecall()()
 780 }
 781
 782 // Disabled until the shell parser can recognize "command || exit 1" reliably.
 783 if false && G.opts.WarnExtra && !*eflag && "the current token" == ";" {
760 *eflag = true 784 *eflag = true
761 ctx.shline.line.Warn1("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", prevToken) 785 ctx.shline.line.Warn1("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", "previous token")
762 Explain( 786 Explain(
763 "Normally, when a shell command fails (returns non-zero), the", 787 "Normally, when a shell command fails (returns non-zero), the",
764 "remaining commands are still executed. For example, the following", 788 "remaining commands are still executed. For example, the following",
765 "commands would remove all files from the HOME directory:", 789 "commands would remove all files from the HOME directory:",
766 "", 790 "",
767 "\tcd \"$HOME\"; cd /nonexistent; rm -rf *", 791 "\tcd \"$HOME\"; cd /nonexistent; rm -rf *",
768 "", 792 "",
769 "To fix this warning, you can:", 793 "To fix this warning, you can:",
770 "", 794 "",
771 "* insert ${RUN} at the beginning of the line", 795 "* insert ${RUN} at the beginning of the line",
772 " (which among other things does \"set -e\")", 796 " (which among other things does \"set -e\")",
773 "* insert \"set -e\" explicitly at the beginning of the line", 797 "* insert \"set -e\" explicitly at the beginning of the line",
774 "* use \"&&\" instead of \";\" to separate the commands") 798 "* use \"&&\" instead of \";\" to separate the commands")
775 } 799 }
776} 800}
777 801
778// Some shell commands should not be used in the install phase. 802// Some shell commands should not be used in the install phase.
779func (shline *ShellLine) checkCommandUse(shellcmd string) { 803func (shline *ShellLine) checkCommandUse(shellcmd string) {
 804 if G.opts.Debug {
 805 defer tracecall()()
 806 }
 807
780 if G.Mk == nil || !matches(G.Mk.target, `^(?:pre|do|post)-install$`) { 808 if G.Mk == nil || !matches(G.Mk.target, `^(?:pre|do|post)-install$`) {
781 return 809 return
782 } 810 }
783 811
784 line := shline.line 812 line := shline.line
785 switch shellcmd { 813 switch shellcmd {
786 case "${INSTALL}", 814 case "${INSTALL}",
787 "${INSTALL_DATA}", "${INSTALL_DATA_DIR}", 815 "${INSTALL_DATA}", "${INSTALL_DATA_DIR}",
788 "${INSTALL_LIB}", "${INSTALL_LIB_DIR}", 816 "${INSTALL_LIB}", "${INSTALL_LIB_DIR}",
789 "${INSTALL_MAN}", "${INSTALL_MAN_DIR}", 817 "${INSTALL_MAN}", "${INSTALL_MAN_DIR}",
790 "${INSTALL_PROGRAM}", "${INSTALL_PROGRAM_DIR}", 818 "${INSTALL_PROGRAM}", "${INSTALL_PROGRAM_DIR}",
791 "${INSTALL_SCRIPT}", 819 "${INSTALL_SCRIPT}",
792 "${LIBTOOL}", 820 "${LIBTOOL}",
@@ -805,180 +833,73 @@ func (shline *ShellLine) checkCommandUse @@ -805,180 +833,73 @@ func (shline *ShellLine) checkCommandUse
805 case "cp", "${CP}": 833 case "cp", "${CP}":
806 line.Warn0("${CP} should not be used to install files.") 834 line.Warn0("${CP} should not be used to install files.")
807 Explain( 835 Explain(
808 "The ${CP} command is highly platform dependent and cannot overwrite", 836 "The ${CP} command is highly platform dependent and cannot overwrite",
809 "read-only files. Please use ${PAX} instead.", 837 "read-only files. Please use ${PAX} instead.",
810 "", 838 "",
811 "For example, instead of", 839 "For example, instead of",
812 "\t${CP} -R ${WRKSRC}/* ${PREFIX}/foodir", 840 "\t${CP} -R ${WRKSRC}/* ${PREFIX}/foodir",
813 "you should use", 841 "you should use",
814 "\tcd ${WRKSRC} && ${PAX} -wr * ${PREFIX}/foodir") 842 "\tcd ${WRKSRC} && ${PAX} -wr * ${PREFIX}/foodir")
815 } 843 }
816} 844}
817 845
818func (shline *ShellLine) nextState(state scState, shellword string) scState { 
819 switch { 
820 case shellword == ";;": 
821 return scstCaseLabel 
822 case state == scstCaseLabelCont && shellword == "|": 
823 return scstCaseLabel 
824 case matches(shellword, `^[;&\|]+$`): 
825 return scstStart 
826 case state == scstStart: 
827 switch shellword { 
828 case "${INSTALL}": 
829 return scstInstall 
830 case "${MKDIR}": 
831 return scstMkdir 
832 case "${PAX}": 
833 return scstPax 
834 case "${SED}": 
835 return scstSed 
836 case "${ECHO}", "echo": 
837 return scstEcho 
838 case "${RUN}", "then", "else", "do", "(": 
839 return scstStart 
840 case "set": 
841 return scstSet 
842 case "if", "elif", "while": 
843 return scstCond 
844 case "case": 
845 return scstCase 
846 case "for": 
847 return scstFor 
848 default: 
849 switch { 
850 case matches(shellword, `^\$\{INSTALL_[A-Z]+_DIR\}$`): 
851 return scstInstallDir 
852 case matches(shellword, reShVarassign): 
853 return scstStart 
854 default: 
855 return scstCont 
856 } 
857 } 
858 case state == scstMkdir: 
859 return scstMkdir 
860 case state == scstInstall && shellword == "-d": 
861 return scstInstallD 
862 case state == scstInstall, state == scstInstallD: 
863 if matches(shellword, `^-[ogm]$`) { 
864 return scstCont // XXX: why not keep the state? 
865 } 
866 return state 
867 case state == scstInstallDir && hasPrefix(shellword, "-"): 
868 return scstCont 
869 case state == scstInstallDir && hasPrefix(shellword, "$"): 
870 return scstInstallDir2 
871 case state == scstInstallDir || state == scstInstallDir2: 
872 return state 
873 case state == scstPax && shellword == "-s": 
874 return scstPaxS 
875 case state == scstPax && hasPrefix(shellword, "-"): 
876 return scstPax 
877 case state == scstPax: 
878 return scstCont 
879 case state == scstPaxS: 
880 return scstPax 
881 case state == scstSed && shellword == "-e": 
882 return scstSedE 
883 case state == scstSed && hasPrefix(shellword, "-"): 
884 return scstSed 
885 case state == scstSed: 
886 return scstCont 
887 case state == scstSedE: 
888 return scstSed 
889 case state == scstSet: 
890 return scstSetCont 
891 case state == scstSetCont: 
892 return scstSetCont 
893 case state == scstCase: 
894 return scstCaseIn 
895 case state == scstCaseIn && shellword == "in": 
896 return scstCaseLabel 
897 case state == scstCaseLabel && shellword == "esac": 
898 return scstCont 
899 case state == scstCaseLabel: 
900 return scstCaseLabelCont 
901 case state == scstCaseLabelCont && shellword == ")": 
902 return scstStart 
903 case state == scstCont: 
904 return scstCont 
905 case state == scstCond: 
906 return scstCondCont 
907 case state == scstCondCont: 
908 return scstCondCont 
909 case state == scstFor: 
910 return scstForIn 
911 case state == scstForIn && shellword == "in": 
912 return scstForCont 
913 case state == scstForCont: 
914 return scstForCont 
915 case state == scstEcho: 
916 return scstCont 
917 default: 
918 if G.opts.Debug { 
919 traceStep("Internal pkglint error: shellword.nextState state=%s shellword=%q", state, shellword) 
920 } 
921 return scstStart 
922 } 
923} 
924 
925// Example: "word1 word2;;;" => "word1", "word2", ";;", ";" 846// Example: "word1 word2;;;" => "word1", "word2", ";;", ";"
926func splitIntoShellTokens(line *Line, text string) (tokens []string, rest string) { 847func splitIntoShellTokens(line *Line, text string) (tokens []string, rest string) {
927 if G.opts.Debug { 848 if G.opts.Debug {
928 defer tracecall(line, text)() 849 defer tracecall(line, text)()
929 } 850 }
930 851
931 word := "" 852 word := ""
932 emit := func() { 853 emit := func() {
933 if word != "" { 854 if word != "" {
934 tokens = append(tokens, word) 855 tokens = append(tokens, word)
935 word = "" 856 word = ""
936 } 857 }
937 } 858 }
938 p := NewShTokenizer(line, text, false) 859 p := NewShTokenizer(line, text, false)
939 atoms := p.ShAtoms() 860 atoms := p.ShAtoms()
940 q := shqPlain 861 q := shqPlain
941 for _, atom := range atoms { 862 for _, atom := range atoms {
942 q = atom.Quoting 863 q = atom.Quoting
943 if atom.Type == shtSpace && q == shqPlain { 864 if atom.Type == shtSpace && q == shqPlain {
944 emit() 865 emit()
945 } else if atom.Type == shtWord || atom.Type == shtVaruse || atom.Quoting != shqPlain { 866 } else if atom.Type == shtWord || atom.Type == shtVaruse || atom.Quoting != shqPlain {
946 word += atom.Text 867 word += atom.MkText
947 } else { 868 } else {
948 emit() 869 emit()
949 tokens = append(tokens, atom.Text) 870 tokens = append(tokens, atom.MkText)
950 } 871 }
951 } 872 }
952 emit() 873 emit()
953 return tokens, word + p.mkp.Rest() 874 return tokens, word + p.mkp.Rest()
954} 875}
955 876
956// Example: "word1 word2;;;" => "word1", "word2;;;" 877// Example: "word1 word2;;;" => "word1", "word2;;;"
957// Compare devel/bmake/files/str.c, function brk_string. 878// Compare devel/bmake/files/str.c, function brk_string.
958func splitIntoMkWords(line *Line, text string) (words []string, rest string) { 879func splitIntoMkWords(line *Line, text string) (words []string, rest string) {
959 if G.opts.Debug { 880 if G.opts.Debug {
960 defer tracecall(line, text)() 881 defer tracecall(line, text)()
961 } 882 }
962 883
963 p := NewShTokenizer(line, text, false) 884 p := NewShTokenizer(line, text, false)
964 atoms := p.ShAtoms() 885 atoms := p.ShAtoms()
965 word := "" 886 word := ""
966 for _, atom := range atoms { 887 for _, atom := range atoms {
967 if atom.Type == shtSpace && atom.Quoting == shqPlain { 888 if atom.Type == shtSpace && atom.Quoting == shqPlain {
968 words = append(words, word) 889 words = append(words, word)
969 word = "" 890 word = ""
970 } else { 891 } else {
971 word += atom.Text 892 word += atom.MkText
972 } 893 }
973 } 894 }
974 if word != "" && atoms[len(atoms)-1].Quoting == shqPlain { 895 if word != "" && atoms[len(atoms)-1].Quoting == shqPlain {
975 words = append(words, word) 896 words = append(words, word)
976 word = "" 897 word = ""
977 } 898 }
978 return words, word + p.mkp.Rest() 899 return words, word + p.mkp.Rest()
979} 900}
980 901
981type ShQuote struct { 902type ShQuote struct {
982 repl *PrefixReplacer 903 repl *PrefixReplacer
983 q ShQuoting 904 q ShQuoting
984} 905}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/shell_test.go 2016/06/05 11:24:32 1.9
+++ pkgsrc/pkgtools/pkglint/files/Attic/shell_test.go 2016/07/07 12:09:27 1.10
@@ -1,38 +1,21 @@ @@ -1,38 +1,21 @@
1package main 1package main
2 2
3import ( 3import (
4 "strings" 4 "strings"
5 5
6 check "gopkg.in/check.v1" 6 check "gopkg.in/check.v1"
7) 7)
8 8
9func (s *Suite) TestReShellToken(c *check.C) { 
10 re := `^(?:` + reShellToken + `)$` 
11 matches := check.NotNil 
12 doesntMatch := check.IsNil 
13 
14 c.Check(match("", re), doesntMatch) 
15 c.Check(match("$var", re), matches) 
16 c.Check(match("$var$var", re), matches) 
17 c.Check(match("$var;;", re), doesntMatch) // More than one token 
18 c.Check(match("'single-quoted'", re), matches) 
19 c.Check(match("\"", re), doesntMatch) // Incomplete string 
20 c.Check(match("'...'\"...\"", re), matches) // Mixed strings 
21 c.Check(match("\"...\"", re), matches) 
22 c.Check(match("`cat file`", re), matches) 
23 c.Check(match("${file%.c}.o", re), matches) 
24} 
25 
26func (s *Suite) Test_SplitIntoShellTokens_LineContinuation(c *check.C) { 9func (s *Suite) Test_SplitIntoShellTokens_LineContinuation(c *check.C) {
27 words, rest := splitIntoShellTokens(dummyLine, "if true; then \\") 10 words, rest := splitIntoShellTokens(dummyLine, "if true; then \\")
28 11
29 c.Check(words, check.DeepEquals, []string{"if", "true", ";", "then"}) 12 c.Check(words, check.DeepEquals, []string{"if", "true", ";", "then"})
30 c.Check(rest, equals, "\\") 13 c.Check(rest, equals, "\\")
31 14
32 c.Check(s.Output(), equals, "WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)\n") 15 c.Check(s.Output(), equals, "WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)\n")
33} 16}
34 17
35func (s *Suite) Test_SplitIntoShellTokens_DollarSlash(c *check.C) { 18func (s *Suite) Test_SplitIntoShellTokens_DollarSlash(c *check.C) {
36 words, rest := splitIntoShellTokens(dummyLine, "pax -s /.*~$$//g") 19 words, rest := splitIntoShellTokens(dummyLine, "pax -s /.*~$$//g")
37 20
38 c.Check(words, check.DeepEquals, []string{"pax", "-s", "/.*~$$//g"}) 21 c.Check(words, check.DeepEquals, []string{"pax", "-s", "/.*~$$//g"})
@@ -84,140 +67,176 @@ func (s *Suite) Test_SplitIntoShellToken @@ -84,140 +67,176 @@ func (s *Suite) Test_SplitIntoShellToken
84 words, rest := splitIntoShellTokens(dummyLine, "${VAR:S/ /_/g}") 67 words, rest := splitIntoShellTokens(dummyLine, "${VAR:S/ /_/g}")
85 68
86 c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"}) 69 c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"})
87 c.Check(rest, equals, "") 70 c.Check(rest, equals, "")
88} 71}
89 72
90func (s *Suite) Test_SplitIntoMkWords_VaruseSpace(c *check.C) { 73func (s *Suite) Test_SplitIntoMkWords_VaruseSpace(c *check.C) {
91 words, rest := splitIntoMkWords(dummyLine, "${VAR:S/ /_/g}") 74 words, rest := splitIntoMkWords(dummyLine, "${VAR:S/ /_/g}")
92 75
93 c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"}) 76 c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"})
94 c.Check(rest, equals, "") 77 c.Check(rest, equals, "")
95} 78}
96 79
 80func (s *Suite) Test_splitIntoShellTokens_Redirect(c *check.C) {
 81 words, rest := splitIntoShellTokens(dummyLine, "echo 1>output 2>>append 3>|clobber 4>&5 6<input >>append")
 82
 83 c.Check(words, deepEquals, []string{
 84 "echo",
 85 "1>", "output",
 86 "2>>", "append",
 87 "3>|", "clobber",
 88 "4>&", "5",
 89 "6<", "input",
 90 ">>", "append"})
 91 c.Check(rest, equals, "")
 92
 93 words, rest = splitIntoShellTokens(dummyLine, "echo 1> output 2>> append 3>| clobber 4>& 5 6< input >> append")
 94
 95 c.Check(words, deepEquals, []string{
 96 "echo",
 97 "1>", "output",
 98 "2>>", "append",
 99 "3>|", "clobber",
 100 "4>&", "5",
 101 "6<", "input",
 102 ">>", "append"})
 103 c.Check(rest, equals, "")
 104}
 105
97func (s *Suite) TestChecklineMkShellCommandLine(c *check.C) { 106func (s *Suite) TestChecklineMkShellCommandLine(c *check.C) {
98 s.UseCommandLine(c, "-Wall") 107 s.UseCommandLine(c, "-Wall")
99 G.Mk = s.NewMkLines("fname", 108 G.Mk = s.NewMkLines("fname",
100 "# dummy") 109 "# dummy")
101 shline := NewShellLine(G.Mk.mklines[0]) 110 shline := NewShellLine(G.Mk.mklines[0])
102 111
103 shline.CheckShellCommandLine("@# Comment") 112 shline.CheckShellCommandLine("@# Comment")
104 113
105 c.Check(s.Output(), equals, "") 114 c.Check(s.Output(), equals, "")
106 115
107 shline.CheckShellCommandLine("uname=`uname`; echo $$uname; echo") 116 shline.CheckShellCommandLine("uname=`uname`; echo $$uname; echo")
108 117
109 c.Check(s.Output(), equals, ""+ 118 c.Check(s.Output(), equals, ""+
110 "WARN: fname:1: Unknown shell command \"uname\".\n"+ 119 "WARN: fname:1: Unknown shell command \"uname\".\n"+
111 "WARN: fname:1: Please switch to \"set -e\" mode before using a semicolon (the one after \"uname=`uname`\") to separate commands.\n"+ 
112 "WARN: fname:1: Unknown shell command \"echo\".\n"+ 120 "WARN: fname:1: Unknown shell command \"echo\".\n"+
113 "WARN: fname:1: Unquoted shell variable \"uname\".\n"+ 
114 "WARN: fname:1: Unknown shell command \"echo\".\n") 121 "WARN: fname:1: Unknown shell command \"echo\".\n")
115 122
116 s.RegisterTool(&Tool{Name: "echo", Predefined: true}) 123 s.RegisterTool(&Tool{Name: "echo", Predefined: true})
117 G.Mk = s.NewMkLines("fname", 124 G.Mk = s.NewMkLines("fname",
118 "# dummy") 125 "# dummy")
119 G.globalData.InitVartypes() 126 G.globalData.InitVartypes()
120 127
121 shline.CheckShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain 128 shline.CheckShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain
122 129
123 c.Check(s.Output(), equals, ""+ 130 c.Check(s.Output(), equals, ""+
124 "WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+ 131 "WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
125 "NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.\n") 132 "NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
126 133
127 shline.CheckShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot 134 shline.CheckShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot
128 135
129 c.Check(s.Output(), equals, ""+ 136 c.Check(s.Output(), equals, ""+
130 "WARN: fname:1: Please don't use the :Q operator in double quotes.\n"+ 137 "WARN: fname:1: Please don't use the :Q operator in double quotes.\n"+
131 "WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.\n"+ 138 "WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.\n"+
132 "WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.\n") 139 "WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.\n")
133 140
134 shline.CheckShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot 141 shline.CheckShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot
135 142
136 c.Check(s.Output(), equals, ""+ 143 c.Check(s.Output(), equals, ""+
137 "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n"+ 144 "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n"+
138 "WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.\n") 145 "WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.\n")
139 146
 147 shline.CheckShellCommandLine("echo target=$@ exitcode=$$? '$$' \"\\$$\"")
 148
 149 c.Check(s.Output(), equals, ""+
 150 "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n"+
 151 "WARN: fname:1: The $? shell variable is often not available in \"set -e\" mode.\n")
 152
140 shline.CheckShellCommandLine("echo $$@") 153 shline.CheckShellCommandLine("echo $$@")
141 154
142 c.Check(s.Output(), equals, "WARN: fname:1: The $@ shell variable should only be used in double quotes.\n") 155 c.Check(s.Output(), equals, "WARN: fname:1: The $@ shell variable should only be used in double quotes.\n")
143 156
144 shline.CheckShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$" 157 shline.CheckShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$"
145 158
146 c.Check(s.Output(), equals, ""+ 159 c.Check(s.Output(), equals, ""+
147 "WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)\n"+ 160 "WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)\n"+
148 "WARN: fname:1: Pkglint parse error in ShellLine.CheckShellCommand at \"$$\\\"\" (state=start)\n") 161 "WARN: fname:1: Pkglint ShellLine.CheckShellCommand: parse error at [\"]\n")
149 162
150 shline.CheckShellCommandLine("echo \"\\n\"") // As seen by make(1); the shell sees: echo "\n" 163 shline.CheckShellCommandLine("echo \"\\n\"")
151 164
152 c.Check(s.Output(), equals, "") 165 c.Check(s.Output(), equals, "")
153 166
154 shline.CheckShellCommandLine("${RUN} for f in *.c; do echo $${f%.c}; done") 167 shline.CheckShellCommandLine("${RUN} for f in *.c; do echo $${f%.c}; done")
155 168
156 c.Check(s.Output(), equals, "") 169 c.Check(s.Output(), equals, "")
157 170
158 shline.CheckShellCommandLine("${RUN} echo $${variable+set}") 171 shline.CheckShellCommandLine("${RUN} echo $${variable+set}")
159 172
160 c.Check(s.Output(), equals, "") 173 c.Check(s.Output(), equals, "")
161 174
162 // Based on mail/thunderbird/Makefile, rev. 1.159 175 // Based on mail/thunderbird/Makefile, rev. 1.159
163 shline.CheckShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"") 176 shline.CheckShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")
164 177
165 c.Check(s.Output(), equals, ""+ 178 c.Check(s.Output(), equals, ""+
166 "WARN: fname:1: Unknown shell command \"unzip\".\n"+ 
167 "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+ 179 "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
 180 "WARN: fname:1: Unknown shell command \"unzip\".\n"+
168 "WARN: fname:1: Unknown shell command \"awk\".\n") 181 "WARN: fname:1: Unknown shell command \"awk\".\n")
169 182
170 // From mail/thunderbird/Makefile, rev. 1.159 183 // From mail/thunderbird/Makefile, rev. 1.159
171 shline.CheckShellCommandLine("" + 184 shline.CheckShellCommandLine("" +
172 "${RUN} for e in ${XPI_FILES}; do " + 185 "${RUN} for e in ${XPI_FILES}; do " +
173 " subdir=\"`${UNZIP_CMD} -c \"$$e\" install.rdf | awk '/^ <em:id>/ {sub(\".*<em:id>\",\"\");sub(\"</em:id>.*\",\"\");print;exit;}'`\" && " + 186 " subdir=\"`${UNZIP_CMD} -c \"$$e\" install.rdf | awk '/^ <em:id>/ {sub(\".*<em:id>\",\"\");sub(\"</em:id>.*\",\"\");print;exit;}'`\" && " +
174 " ${MKDIR} \"${WRKDIR}/extensions/$$subdir\" && " + 187 " ${MKDIR} \"${WRKDIR}/extensions/$$subdir\" && " +
175 " cd \"${WRKDIR}/extensions/$$subdir\" && " + 188 " cd \"${WRKDIR}/extensions/$$subdir\" && " +
176 " ${UNZIP_CMD} -aqo $$e; " + 189 " ${UNZIP_CMD} -aqo $$e; " +
177 "done") 190 "done")
178 191
179 c.Check(s.Output(), equals, ""+ 192 c.Check(s.Output(), equals, ""+
180 "WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?\n"+ 193 "WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?\n"+
181 "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n"+ 
182 "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+ 194 "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
 195 "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n"+
183 "WARN: fname:1: Unknown shell command \"awk\".\n"+ 196 "WARN: fname:1: Unknown shell command \"awk\".\n"+
184 "WARN: fname:1: MKDIR is used but not defined. Spelling mistake?\n"+ 
185 "WARN: fname:1: Unknown shell command \"${MKDIR}\".\n"+ 197 "WARN: fname:1: Unknown shell command \"${MKDIR}\".\n"+
186 "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n"+ 198 "WARN: fname:1: MKDIR is used but not defined. Spelling mistake?\n"+
187 "WARN: fname:1: Unquoted shell variable \"e\".\n") 199 "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n")
188 200
189 // From x11/wxGTK28/Makefile 201 // From x11/wxGTK28/Makefile
190 shline.CheckShellCommandLine("" + 202 shline.CheckShellCommandLine("" +
191 "set -e; cd ${WRKSRC}/locale; " + 203 "set -e; cd ${WRKSRC}/locale; " +
192 "for lang in *.po; do " + 204 "for lang in *.po; do " +
193 " [ \"$${lang}\" = \"wxstd.po\" ] && continue; " + 205 " [ \"$${lang}\" = \"wxstd.po\" ] && continue; " +
194 " ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; " + 206 " ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; " +
195 "done") 207 "done")
196 208
197 c.Check(s.Output(), equals, ""+ 209 c.Check(s.Output(), equals, ""+
198 "WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+ 210 "WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
199 "WARN: fname:1: Unknown shell command \"[\".\n"+ 211 "WARN: fname:1: Unknown shell command \"[\".\n"+
200 "WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".\n") 212 "WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".\n")
201 213
202 shline.CheckShellCommandLine("@cp from to") 214 shline.CheckShellCommandLine("@cp from to")
203 215
204 c.Check(s.Output(), equals, ""+ 216 c.Check(s.Output(), equals, ""+
205 "WARN: fname:1: The shell command \"cp\" should not be hidden.\n"+ 217 "WARN: fname:1: The shell command \"cp\" should not be hidden.\n"+
206 "WARN: fname:1: Unknown shell command \"cp\".\n") 218 "WARN: fname:1: Unknown shell command \"cp\".\n")
207 219
208 shline.CheckShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase") 220 shline.CheckShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase")
209 221
210 c.Check(s.Output(), equals, "NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of this command.\n") 222 c.Check(s.Output(), equals, ""+
 223 "NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of \"${INSTALL_DATA_DIR}\".\n"+
 224 "WARN: fname:1: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
 225
 226 // See PR 46570, item "1. It does not"
 227 shline.CheckShellCommandLine("for x in 1 2 3; do echo \"$$x\" || exit 1; done")
 228
 229 c.Check(s.Output(), equals, "") // No warning about missing error checking.
211} 230}
212 231
213func (s *Suite) TestShellLine_CheckShelltext_nofix(c *check.C) { 232func (s *Suite) TestShellLine_CheckShelltext_nofix(c *check.C) {
214 s.UseCommandLine(c, "-Wall") 233 s.UseCommandLine(c, "-Wall")
215 G.globalData.InitVartypes() 234 G.globalData.InitVartypes()
216 s.RegisterTool(&Tool{Name: "echo", Predefined: true}) 235 s.RegisterTool(&Tool{Name: "echo", Predefined: true})
217 G.Mk = s.NewMkLines("Makefile", 236 G.Mk = s.NewMkLines("Makefile",
218 "\techo ${PKGNAME:Q}") 237 "\techo ${PKGNAME:Q}")
219 shline := NewShellLine(G.Mk.mklines[0]) 238 shline := NewShellLine(G.Mk.mklines[0])
220 239
221 c.Check(shline.line.raw[0].textnl, equals, "\techo ${PKGNAME:Q}\n") 240 c.Check(shline.line.raw[0].textnl, equals, "\techo ${PKGNAME:Q}\n")
222 c.Check(shline.line.raw[0].Lineno, equals, 1) 241 c.Check(shline.line.raw[0].Lineno, equals, 1)
223 242
@@ -261,26 +280,30 @@ func (s *Suite) TestShellLine_CheckShell @@ -261,26 +280,30 @@ func (s *Suite) TestShellLine_CheckShell
261 G.globalData.InitVartypes() 280 G.globalData.InitVartypes()
262 G.Mk = s.NewMkLines("fname", 281 G.Mk = s.NewMkLines("fname",
263 "# dummy") 282 "# dummy")
264 shline := NewShellLine(G.Mk.mklines[0]) 283 shline := NewShellLine(G.Mk.mklines[0])
265 284
266 // foobar="`echo \"foo bar\"`" 285 // foobar="`echo \"foo bar\"`"
267 text := "foobar=\"`echo \\\"foo bar\\\"`\"" 286 text := "foobar=\"`echo \\\"foo bar\\\"`\""
268 287
269 tokens, rest := splitIntoShellTokens(dummyLine, text) 288 tokens, rest := splitIntoShellTokens(dummyLine, text)
270 289
271 c.Check(tokens, deepEquals, []string{text}) 290 c.Check(tokens, deepEquals, []string{text})
272 c.Check(rest, equals, "") 291 c.Check(rest, equals, "")
273 292
 293 shline.CheckWord(text, false)
 294
 295 c.Check(s.Output(), equals, "WARN: fname:1: Unknown shell command \"echo\".\n")
 296
274 shline.CheckShellCommandLine(text) 297 shline.CheckShellCommandLine(text)
275 298
276 c.Check(s.Output(), equals, ""+ // No parse errors 299 c.Check(s.Output(), equals, ""+ // No parse errors
277 "WARN: fname:1: Unknown shell command \"echo\".\n") 300 "WARN: fname:1: Unknown shell command \"echo\".\n")
278} 301}
279 302
280func (s *Suite) TestShellLine_CheckShelltext_DollarWithoutVariable(c *check.C) { 303func (s *Suite) TestShellLine_CheckShelltext_DollarWithoutVariable(c *check.C) {
281 G.globalData.InitVartypes() 304 G.globalData.InitVartypes()
282 G.Mk = s.NewMkLines("fname", 305 G.Mk = s.NewMkLines("fname",
283 "# dummy") 306 "# dummy")
284 shline := NewShellLine(G.Mk.mklines[0]) 307 shline := NewShellLine(G.Mk.mklines[0])
285 s.RegisterTool(&Tool{Name: "pax", Varname: "PAX"}) 308 s.RegisterTool(&Tool{Name: "pax", Varname: "PAX"})
286 G.Mk.tools["pax"] = true 309 G.Mk.tools["pax"] = true
@@ -291,27 +314,27 @@ func (s *Suite) TestShellLine_CheckShell @@ -291,27 +314,27 @@ func (s *Suite) TestShellLine_CheckShell
291} 314}
292 315
293func (s *Suite) Test_ShellLine_CheckWord(c *check.C) { 316func (s *Suite) Test_ShellLine_CheckWord(c *check.C) {
294 s.UseCommandLine(c, "-Wall") 317 s.UseCommandLine(c, "-Wall")
295 G.globalData.InitVartypes() 318 G.globalData.InitVartypes()
296 shline := NewShellLine(NewMkLine(NewLine("fname", 1, "# dummy", nil))) 319 shline := NewShellLine(NewMkLine(NewLine("fname", 1, "# dummy", nil)))
297 320
298 shline.CheckWord("${${list}}", false) 321 shline.CheckWord("${${list}}", false)
299 322
300 c.Check(s.Output(), equals, "") // No warning for variables that are completely indirect. 323 c.Check(s.Output(), equals, "") // No warning for variables that are completely indirect.
301 324
302 shline.CheckWord("${SED_FILE.${id}}", false) 325 shline.CheckWord("${SED_FILE.${id}}", false)
303 326
304 c.Check(s.Output(), equals, "WARN: fname:1: SED_FILE.${id} is used but not defined. Spelling mistake?\n") 327 c.Check(s.Output(), equals, "") // No warning for variables that are partly indirect.
305 328
306 shline.CheckWord("\"$@\"", false) 329 shline.CheckWord("\"$@\"", false)
307 330
308 c.Check(s.Output(), equals, "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n") 331 c.Check(s.Output(), equals, "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n")
309 332
310 shline.CheckWord("${COMMENT:Q}", true) 333 shline.CheckWord("${COMMENT:Q}", true)
311 334
312 c.Check(s.Output(), equals, "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n") 335 c.Check(s.Output(), equals, "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n")
313 336
314 shline.CheckWord("\"${DISTINFO_FILE:Q}\"", true) 337 shline.CheckWord("\"${DISTINFO_FILE:Q}\"", true)
315 338
316 c.Check(s.Output(), equals, ""+ 339 c.Check(s.Output(), equals, ""+
317 "WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+ 340 "WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
@@ -426,39 +449,52 @@ func (s *Suite) TestShellLine_CheckShell @@ -426,39 +449,52 @@ func (s *Suite) TestShellLine_CheckShell
426 shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} uname=$$(uname)", nil))) 449 shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} uname=$$(uname)", nil)))
427 450
428 shline.CheckShellCommandLine(shline.mkline.Shellcmd()) 451 shline.CheckShellCommandLine(shline.mkline.Shellcmd())
429 452
430 c.Check(s.Output(), equals, "WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.\n") 453 c.Check(s.Output(), equals, "WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.\n")
431} 454}
432 455
433func (s *Suite) TestShellLine_CheckShellCommandLine_InstallDirs(c *check.C) { 456func (s *Suite) TestShellLine_CheckShellCommandLine_InstallDirs(c *check.C) {
434 shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil))) 457 shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
435 458
436 shline.CheckShellCommandLine(shline.mkline.Shellcmd()) 459 shline.CheckShellCommandLine(shline.mkline.Shellcmd())
437 460
438 c.Check(s.Output(), equals, ""+ 461 c.Check(s.Output(), equals, ""+
439 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of this command.\n"+ 462 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
440 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of this command.\n"+ 463 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
 464 "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
 465
 466 shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/share/examples/gdchart")
 467
 468 // No warning about multiple directories, since 0755 is an option, not an argument.
 469 c.Check(s.Output(), equals, ""+
 470 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/examples/gdchart\" instead of \"${INSTALL_DATA_DIR}\".\n")
 471
 472 shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/dir1 ${PREFIX}/dir2")
 473
 474 c.Check(s.Output(), equals, ""+
 475 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
 476 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
441 "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n") 477 "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
442} 478}
443 479
444func (s *Suite) TestShellLine_CheckShellCommandLine_InstallD(c *check.C) { 480func (s *Suite) TestShellLine_CheckShellCommandLine_InstallD(c *check.C) {
445 shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil))) 481 shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
446 482
447 shline.CheckShellCommandLine(shline.mkline.Shellcmd()) 483 shline.CheckShellCommandLine(shline.mkline.Shellcmd())
448 484
449 c.Check(s.Output(), equals, ""+ 485 c.Check(s.Output(), equals, ""+
450 "WARN: Makefile:85: Please use AUTO_MKDIRS instead of \"${INSTALL} -d\".\n"+ 486 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".\n"+
451 "WARN: Makefile:85: Please use AUTO_MKDIRS instead of \"${INSTALL} -d\".\n") 487 "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".\n")
452} 488}
453 489
454func (s *Suite) TestShellLine_(c *check.C) { 490func (s *Suite) TestShellLine_(c *check.C) {
455 tmpfile := s.CreateTmpFile(c, "Makefile", ""+ 491 tmpfile := s.CreateTmpFile(c, "Makefile", ""+
456 "# $"+"NetBSD$\n"+ 492 "# $"+"NetBSD$\n"+
457 "pre-install:\n"+ 493 "pre-install:\n"+
458 "\t"+"# comment\\\n"+ 494 "\t"+"# comment\\\n"+
459 "\t"+"echo \"hello\"\n") 495 "\t"+"echo \"hello\"\n")
460 lines := LoadNonemptyLines(tmpfile, true) 496 lines := LoadNonemptyLines(tmpfile, true)
461 497
462 NewMkLines(lines).Check() 498 NewMkLines(lines).Check()
463 499
464 c.Check(s.Output(), equals, "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.\n") 500 c.Check(s.Output(), equals, "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.\n")

cvs diff -r1.10 -r1.11 pkgsrc/pkgtools/pkglint/files/Attic/globaldata.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/globaldata.go 2016/06/10 19:42:42 1.10
+++ pkgsrc/pkgtools/pkglint/files/Attic/globaldata.go 2016/07/07 12:09:27 1.11
@@ -506,26 +506,29 @@ func (gd *GlobalData) loadDeprecatedVars @@ -506,26 +506,29 @@ func (gd *GlobalData) loadDeprecatedVars
506 "SETGIDGAME": "Use USE_GAMESGROUP instead.", 506 "SETGIDGAME": "Use USE_GAMESGROUP instead.",
507 "GAMEGRP": "Use GAMES_GROUP instead.", 507 "GAMEGRP": "Use GAMES_GROUP instead.",
508 "GAMEOWN": "Use GAMES_USER instead.", 508 "GAMEOWN": "Use GAMES_USER instead.",
509 509
510 // July 2013 510 // July 2013
511 "USE_GNU_READLINE": "Include \"../../devel/readline/buildlink3.mk\" instead.", 511 "USE_GNU_READLINE": "Include \"../../devel/readline/buildlink3.mk\" instead.",
512 512
513 // October 2014 513 // October 2014
514 "SVR4_PKGNAME": "Just remove it.", 514 "SVR4_PKGNAME": "Just remove it.",
515 "PKG_INSTALLATION_TYPES": "Just remove it.", 515 "PKG_INSTALLATION_TYPES": "Just remove it.",
516 516
517 // January 2016 517 // January 2016
518 "SUBST_POSTCMD.*": "Has been removed, as it seemed unused.", 518 "SUBST_POSTCMD.*": "Has been removed, as it seemed unused.",
 519
 520 // June 2016
 521 "USE_CROSSBASE": "Has been removed.",
519 } 522 }
520} 523}
521 524
522// See `mk/tools/`. 525// See `mk/tools/`.
523type Tool struct { 526type Tool struct {
524 Name string // e.g. "sed", "gzip" 527 Name string // e.g. "sed", "gzip"
525 Varname string // e.g. "SED", "GZIP_CMD" 528 Varname string // e.g. "SED", "GZIP_CMD"
526 MustUseVarForm bool // True for `echo`, because of many differing implementations. 529 MustUseVarForm bool // True for `echo`, because of many differing implementations.
527 Predefined bool // This tool is used by the pkgsrc infrastructure, therefore the package does not need to add it to `USE_TOOLS` explicitly. 530 Predefined bool // This tool is used by the pkgsrc infrastructure, therefore the package does not need to add it to `USE_TOOLS` explicitly.
528 UsableAtLoadtime bool // May be used after including `bsd.prefs.mk`. 531 UsableAtLoadtime bool // May be used after including `bsd.prefs.mk`.
529} 532}
530 533
531type ToolRegistry struct { 534type ToolRegistry struct {

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

--- pkgsrc/pkgtools/pkglint/files/Attic/vardefs.go 2016/06/19 18:03:29 1.10
+++ pkgsrc/pkgtools/pkglint/files/Attic/vardefs.go 2016/07/07 12:09:27 1.11
@@ -134,103 +134,113 @@ func (gd *GlobalData) InitVartypes() { @@ -134,103 +134,113 @@ func (gd *GlobalData) InitVartypes() {
134 acl("BUILDLINK_DIR", lkNone, CheckvarPathname, "*: use") 134 acl("BUILDLINK_DIR", lkNone, CheckvarPathname, "*: use")
135 bl3list("BUILDLINK_FILES.*", lkShell, CheckvarPathmask) 135 bl3list("BUILDLINK_FILES.*", lkShell, CheckvarPathmask)
136 acl("BUILDLINK_FILES_CMD.*", lkNone, CheckvarShellCommand, "") 136 acl("BUILDLINK_FILES_CMD.*", lkNone, CheckvarShellCommand, "")
137 acl("BUILDLINK_INCDIRS.*", lkShell, CheckvarPathname, "buildlink3.mk: default, append; Makefile, Makefile.common, *.mk: use") 137 acl("BUILDLINK_INCDIRS.*", lkShell, CheckvarPathname, "buildlink3.mk: default, append; Makefile, Makefile.common, *.mk: use")
138 acl("BUILDLINK_JAVA_PREFIX.*", lkNone, CheckvarPathname, "buildlink3.mk: set, use") 138 acl("BUILDLINK_JAVA_PREFIX.*", lkNone, CheckvarPathname, "buildlink3.mk: set, use")
139 acl("BUILDLINK_LDADD.*", lkShell, CheckvarLdFlag, "builtin.mk: set, default, append, use; buildlink3.mk: append, use; Makefile, Makefile.common, *.mk: use") 139 acl("BUILDLINK_LDADD.*", lkShell, CheckvarLdFlag, "builtin.mk: set, default, append, use; buildlink3.mk: append, use; Makefile, Makefile.common, *.mk: use")
140 acl("BUILDLINK_LDFLAGS", lkShell, CheckvarLdFlag, "*: use") 140 acl("BUILDLINK_LDFLAGS", lkShell, CheckvarLdFlag, "*: use")
141 bl3list("BUILDLINK_LDFLAGS.*", lkShell, CheckvarLdFlag) 141 bl3list("BUILDLINK_LDFLAGS.*", lkShell, CheckvarLdFlag)
142 acl("BUILDLINK_LIBDIRS.*", lkShell, CheckvarPathname, "buildlink3.mk, builtin.mk: append; Makefile, Makefile.common, *.mk: use") 142 acl("BUILDLINK_LIBDIRS.*", lkShell, CheckvarPathname, "buildlink3.mk, builtin.mk: append; Makefile, Makefile.common, *.mk: use")
143 acl("BUILDLINK_LIBS.*", lkShell, CheckvarLdFlag, "buildlink3.mk: append") 143 acl("BUILDLINK_LIBS.*", lkShell, CheckvarLdFlag, "buildlink3.mk: append")
144 acl("BUILDLINK_PASSTHRU_DIRS", lkShell, CheckvarPathname, "Makefile, Makefile.common, buildlink3.mk, hacks.mk: append") 144 acl("BUILDLINK_PASSTHRU_DIRS", lkShell, CheckvarPathname, "Makefile, Makefile.common, buildlink3.mk, hacks.mk: append")
145 acl("BUILDLINK_PASSTHRU_RPATHDIRS", lkShell, CheckvarPathname, "Makefile, Makefile.common, buildlink3.mk, hacks.mk: append") 145 acl("BUILDLINK_PASSTHRU_RPATHDIRS", lkShell, CheckvarPathname, "Makefile, Makefile.common, buildlink3.mk, hacks.mk: append")
146 acl("BUILDLINK_PKGSRCDIR.*", lkNone, CheckvarRelativePkgDir, "buildlink3.mk: default, use-loadtime") 146 acl("BUILDLINK_PKGSRCDIR.*", lkNone, CheckvarRelativePkgDir, "buildlink3.mk: default, use-loadtime")
147 acl("BUILDLINK_PREFIX.*", lkNone, CheckvarPathname, "builtin.mk: set, use; buildlink3.mk: use; Makefile, Makefile.common, *.mk: use") 147 acl("BUILDLINK_PREFIX.*", lkNone, CheckvarPathname, "builtin.mk: set, use; Makefile, Makefile.common, *.mk: use")
148 acl("BUILDLINK_RPATHDIRS.*", lkShell, CheckvarPathname, "buildlink3.mk: append") 148 acl("BUILDLINK_RPATHDIRS.*", lkShell, CheckvarPathname, "buildlink3.mk: append")
149 acl("BUILDLINK_TARGETS", lkShell, CheckvarIdentifier, "") 149 acl("BUILDLINK_TARGETS", lkShell, CheckvarIdentifier, "")
150 acl("BUILDLINK_FNAME_TRANSFORM.*", lkNone, CheckvarSedCommands, "Makefile, buildlink3.mk, builtin.mk, hacks.mk: append") 150 acl("BUILDLINK_FNAME_TRANSFORM.*", lkNone, CheckvarSedCommands, "Makefile, buildlink3.mk, builtin.mk, hacks.mk: append")
151 acl("BUILDLINK_TRANSFORM", lkShell, CheckvarWrapperTransform, "*: append") 151 acl("BUILDLINK_TRANSFORM", lkShell, CheckvarWrapperTransform, "*: append")
 152 acl("BUILDLINK_TRANSFORM.*", lkShell, CheckvarWrapperTransform, "*: append")
152 acl("BUILDLINK_TREE", lkShell, CheckvarIdentifier, "buildlink3.mk: append") 153 acl("BUILDLINK_TREE", lkShell, CheckvarIdentifier, "buildlink3.mk: append")
153 acl("BUILD_DEFS", lkShell, CheckvarVarname, "Makefile, Makefile.common, options.mk: append") 154 acl("BUILD_DEFS", lkShell, CheckvarVarname, "Makefile, Makefile.common, options.mk: append")
154 acl("BUILD_DEPENDS", lkSpace, CheckvarDependencyWithPath, "Makefile, Makefile.common, *.mk: append") 155 acl("BUILD_DEPENDS", lkSpace, CheckvarDependencyWithPath, "Makefile, Makefile.common, *.mk: append")
155 pkglist("BUILD_DIRS", lkShell, CheckvarWrksrcSubdirectory) 156 pkglist("BUILD_DIRS", lkShell, CheckvarWrksrcSubdirectory)
156 pkglist("BUILD_ENV", lkShell, CheckvarShellWord) 157 pkglist("BUILD_ENV", lkShell, CheckvarShellWord)
157 sys("BUILD_MAKE_CMD", lkNone, CheckvarShellCommand) 158 sys("BUILD_MAKE_CMD", lkNone, CheckvarShellCommand)
158 pkglist("BUILD_MAKE_FLAGS", lkShell, CheckvarShellWord) 159 pkglist("BUILD_MAKE_FLAGS", lkShell, CheckvarShellWord)
159 pkglist("BUILD_TARGET", lkShell, CheckvarIdentifier) 160 pkglist("BUILD_TARGET", lkShell, CheckvarIdentifier)
 161 pkglist("BUILD_TARGET.*", lkShell, CheckvarIdentifier)
160 pkg("BUILD_USES_MSGFMT", lkNone, CheckvarYes) 162 pkg("BUILD_USES_MSGFMT", lkNone, CheckvarYes)
161 acl("BUILTIN_PKG", lkNone, CheckvarIdentifier, "builtin.mk: set, use-loadtime, use") 163 acl("BUILTIN_PKG", lkNone, CheckvarIdentifier, "builtin.mk: set, use-loadtime, use")
162 acl("BUILTIN_PKG.*", lkNone, CheckvarPkgName, "builtin.mk: set, use-loadtime, use") 164 acl("BUILTIN_PKG.*", lkNone, CheckvarPkgName, "builtin.mk: set, use-loadtime, use")
163 acl("BUILTIN_FIND_FILES_VAR", lkShell, CheckvarVarname, "builtin.mk: set") 165 acl("BUILTIN_FIND_FILES_VAR", lkShell, CheckvarVarname, "builtin.mk: set")
164 acl("BUILTIN_FIND_FILES.*", lkShell, CheckvarPathname, "builtin.mk: set") 166 acl("BUILTIN_FIND_FILES.*", lkShell, CheckvarPathname, "builtin.mk: set")
165 acl("BUILTIN_FIND_GREP.*", lkNone, CheckvarString, "builtin.mk: set") 167 acl("BUILTIN_FIND_GREP.*", lkNone, CheckvarString, "builtin.mk: set")
 168 acl("BUILTIN_FIND_HEADERS_VAR", lkShell, CheckvarVarname, "builtin.mk: set")
 169 acl("BUILTIN_FIND_HEADERS.*", lkShell, CheckvarPathname, "builtin.mk: set")
166 acl("BUILTIN_FIND_LIBS", lkShell, CheckvarPathname, "builtin.mk: set") 170 acl("BUILTIN_FIND_LIBS", lkShell, CheckvarPathname, "builtin.mk: set")
167 acl("BUILTIN_IMAKE_CHECK", lkShell, CheckvarUnchecked, "builtin.mk: set") 171 acl("BUILTIN_IMAKE_CHECK", lkShell, CheckvarUnchecked, "builtin.mk: set")
168 acl("BUILTIN_IMAKE_CHECK.*", lkNone, CheckvarYesNo, "") 172 acl("BUILTIN_IMAKE_CHECK.*", lkNone, CheckvarYesNo, "")
169 sys("BUILTIN_X11_TYPE", lkNone, CheckvarUnchecked) 173 sys("BUILTIN_X11_TYPE", lkNone, CheckvarUnchecked)
170 sys("BUILTIN_X11_VERSION", lkNone, CheckvarUnchecked) 174 sys("BUILTIN_X11_VERSION", lkNone, CheckvarUnchecked)
171 acl("CATEGORIES", lkShell, CheckvarCategory, "Makefile: set, append; Makefile.common: set, default, append") 175 acl("CATEGORIES", lkShell, CheckvarCategory, "Makefile: set, append; Makefile.common: set, default, append")
172 sys("CC_VERSION", lkNone, CheckvarMessage) 176 sys("CC_VERSION", lkNone, CheckvarMessage)
173 sys("CC", lkNone, CheckvarShellCommand) 177 sys("CC", lkNone, CheckvarShellCommand)
174 pkglist("CFLAGS*", lkShell, CheckvarCFlag) // may also be changed by the user 178 pkglist("CFLAGS", lkShell, CheckvarCFlag) // may also be changed by the user
 179 pkglist("CFLAGS.*", lkShell, CheckvarCFlag) // may also be changed by the user
175 acl("CHECK_BUILTIN", lkNone, CheckvarYesNo, "builtin.mk: default; Makefile: set") 180 acl("CHECK_BUILTIN", lkNone, CheckvarYesNo, "builtin.mk: default; Makefile: set")
176 acl("CHECK_BUILTIN.*", lkNone, CheckvarYesNo, "buildlink3.mk: set; builtin.mk: default; *: use-loadtime") 181 acl("CHECK_BUILTIN.*", lkNone, CheckvarYesNo, "Makefile, options.mk, buildlink3.mk: set; builtin.mk: default; *: use-loadtime")
177 acl("CHECK_FILES_SKIP", lkShell, CheckvarBasicRegularExpression, "Makefile, Makefile.common: append") 182 acl("CHECK_FILES_SKIP", lkShell, CheckvarBasicRegularExpression, "Makefile, Makefile.common: append")
178 pkg("CHECK_FILES_SUPPORTED", lkNone, CheckvarYesNo) 183 pkg("CHECK_FILES_SUPPORTED", lkNone, CheckvarYesNo)
179 usr("CHECK_HEADERS", lkNone, CheckvarYesNo) 184 usr("CHECK_HEADERS", lkNone, CheckvarYesNo)
180 pkglist("CHECK_HEADERS_SKIP", lkShell, CheckvarPathmask) 185 pkglist("CHECK_HEADERS_SKIP", lkShell, CheckvarPathmask)
181 usr("CHECK_INTERPRETER", lkNone, CheckvarYesNo) 186 usr("CHECK_INTERPRETER", lkNone, CheckvarYesNo)
182 pkglist("CHECK_INTERPRETER_SKIP", lkShell, CheckvarPathmask) 187 pkglist("CHECK_INTERPRETER_SKIP", lkShell, CheckvarPathmask)
183 usr("CHECK_PERMS", lkNone, CheckvarYesNo) 188 usr("CHECK_PERMS", lkNone, CheckvarYesNo)
184 pkglist("CHECK_PERMS_SKIP", lkShell, CheckvarPathmask) 189 pkglist("CHECK_PERMS_SKIP", lkShell, CheckvarPathmask)
185 usr("CHECK_PORTABILITY", lkNone, CheckvarYesNo) 190 usr("CHECK_PORTABILITY", lkNone, CheckvarYesNo)
186 pkglist("CHECK_PORTABILITY_SKIP", lkShell, CheckvarPathmask) 191 pkglist("CHECK_PORTABILITY_SKIP", lkShell, CheckvarPathmask)
187 acl("CHECK_SHLIBS", lkNone, CheckvarYesNo, "Makefile: set") 192 acl("CHECK_SHLIBS", lkNone, CheckvarYesNo, "Makefile: set")
188 pkglist("CHECK_SHLIBS_SKIP", lkShell, CheckvarPathmask) 193 pkglist("CHECK_SHLIBS_SKIP", lkShell, CheckvarPathmask)
189 acl("CHECK_SHLIBS_SUPPORTED", lkNone, CheckvarYesNo, "Makefile: set") 194 acl("CHECK_SHLIBS_SUPPORTED", lkNone, CheckvarYesNo, "Makefile: set")
190 pkglist("CHECK_WRKREF_SKIP", lkShell, CheckvarPathmask) 195 pkglist("CHECK_WRKREF_SKIP", lkShell, CheckvarPathmask)
191 pkg("CMAKE_ARG_PATH", lkNone, CheckvarPathname) 196 pkg("CMAKE_ARG_PATH", lkNone, CheckvarPathname)
192 pkglist("CMAKE_ARGS", lkShell, CheckvarShellWord) 197 pkglist("CMAKE_ARGS", lkShell, CheckvarShellWord)
 198 pkglist("CMAKE_ARGS.*", lkShell, CheckvarShellWord)
193 acl("COMMENT", lkNone, CheckvarComment, "Makefile, Makefile.common: set, append") 199 acl("COMMENT", lkNone, CheckvarComment, "Makefile, Makefile.common: set, append")
194 acl("COMPILER_RPATH_FLAG", lkNone, enum("-Wl,-rpath"), "*: use") 200 acl("COMPILER_RPATH_FLAG", lkNone, enum("-Wl,-rpath"), "*: use")
195 pkglist("CONFIGURE_ARGS", lkShell, CheckvarShellWord) 201 pkglist("CONFIGURE_ARGS", lkShell, CheckvarShellWord)
 202 pkglist("CONFIGURE_ARGS.*", lkShell, CheckvarShellWord)
196 pkglist("CONFIGURE_DIRS", lkShell, CheckvarWrksrcSubdirectory) 203 pkglist("CONFIGURE_DIRS", lkShell, CheckvarWrksrcSubdirectory)
197 acl("CONFIGURE_ENV", lkShell, CheckvarShellWord, "Makefile, Makefile.common: append, set, use; buildlink3.mk, builtin.mk: append; *.mk: append, use") 204 acl("CONFIGURE_ENV", lkShell, CheckvarShellWord, "Makefile, Makefile.common: append, set, use; buildlink3.mk, builtin.mk: append; *.mk: append, use")
 205 acl("CONFIGURE_ENV.*", lkShell, CheckvarShellWord, "Makefile, Makefile.common: append, set, use; buildlink3.mk, builtin.mk: append; *.mk: append, use")
198 pkg("CONFIGURE_HAS_INFODIR", lkNone, CheckvarYesNo) 206 pkg("CONFIGURE_HAS_INFODIR", lkNone, CheckvarYesNo)
199 pkg("CONFIGURE_HAS_LIBDIR", lkNone, CheckvarYesNo) 207 pkg("CONFIGURE_HAS_LIBDIR", lkNone, CheckvarYesNo)
200 pkg("CONFIGURE_HAS_MANDIR", lkNone, CheckvarYesNo) 208 pkg("CONFIGURE_HAS_MANDIR", lkNone, CheckvarYesNo)
201 pkg("CONFIGURE_SCRIPT", lkNone, CheckvarPathname) 209 pkg("CONFIGURE_SCRIPT", lkNone, CheckvarPathname)
202 acl("CONFIG_GUESS_OVERRIDE", lkShell, CheckvarPathmask, "Makefile, Makefile.common: set, append") 210 acl("CONFIG_GUESS_OVERRIDE", lkShell, CheckvarPathmask, "Makefile, Makefile.common: set, append")
203 acl("CONFIG_STATUS_OVERRIDE", lkShell, CheckvarPathmask, "Makefile, Makefile.common: set, append") 211 acl("CONFIG_STATUS_OVERRIDE", lkShell, CheckvarPathmask, "Makefile, Makefile.common: set, append")
204 acl("CONFIG_SHELL", lkNone, CheckvarPathname, "Makefile, Makefile.common: set") 212 acl("CONFIG_SHELL", lkNone, CheckvarPathname, "Makefile, Makefile.common: set")
205 acl("CONFIG_SUB_OVERRIDE", lkShell, CheckvarPathmask, "Makefile, Makefile.common: set, append") 213 acl("CONFIG_SUB_OVERRIDE", lkShell, CheckvarPathmask, "Makefile, Makefile.common: set, append")
206 pkglist("CONFLICTS", lkSpace, CheckvarDependency) 214 pkglist("CONFLICTS", lkSpace, CheckvarDependency)
207 pkglist("CONF_FILES", lkShell, CheckvarShellWord) 215 pkglist("CONF_FILES", lkShell, CheckvarShellWord)
208 pkg("CONF_FILES_MODE", lkNone, enum("0644 0640 0600 0400")) 216 pkg("CONF_FILES_MODE", lkNone, enum("0644 0640 0600 0400"))
209 pkglist("CONF_FILES_PERMS", lkShell, CheckvarPerms) 217 pkglist("CONF_FILES_PERMS", lkShell, CheckvarPerms)
210 sys("COPY", lkNone, enum("-c")) // The flag that tells ${INSTALL} to copy a file 218 sys("COPY", lkNone, enum("-c")) // The flag that tells ${INSTALL} to copy a file
211 sys("CPP", lkNone, CheckvarShellCommand) 219 sys("CPP", lkNone, CheckvarShellCommand)
212 pkglist("CPPFLAGS*", lkShell, CheckvarCFlag) 220 pkglist("CPPFLAGS", lkShell, CheckvarCFlag)
 221 pkglist("CPPFLAGS.*", lkShell, CheckvarCFlag)
213 acl("CRYPTO", lkNone, CheckvarYes, "Makefile: set") 222 acl("CRYPTO", lkNone, CheckvarYes, "Makefile: set")
214 sys("CXX", lkNone, CheckvarShellCommand) 223 sys("CXX", lkNone, CheckvarShellCommand)
215 pkglist("CXXFLAGS*", lkShell, CheckvarCFlag) 224 pkglist("CXXFLAGS", lkShell, CheckvarCFlag)
 225 pkglist("CXXFLAGS.*", lkShell, CheckvarCFlag)
216 acl("DEINSTALL_FILE", lkNone, CheckvarPathname, "Makefile: set") 226 acl("DEINSTALL_FILE", lkNone, CheckvarPathname, "Makefile: set")
217 acl("DEINSTALL_SRC", lkShell, CheckvarPathname, "Makefile: set; Makefile.common: default, set") 227 acl("DEINSTALL_SRC", lkShell, CheckvarPathname, "Makefile: set; Makefile.common: default, set")
218 acl("DEINSTALL_TEMPLATES", lkShell, CheckvarPathname, "Makefile: set, append; Makefile.common: set, default, append") 228 acl("DEINSTALL_TEMPLATES", lkShell, CheckvarPathname, "Makefile: set, append; Makefile.common: set, default, append")
219 sys("DELAYED_ERROR_MSG", lkNone, CheckvarShellCommand) 229 sys("DELAYED_ERROR_MSG", lkNone, CheckvarShellCommand)
220 sys("DELAYED_WARNING_MSG", lkNone, CheckvarShellCommand) 230 sys("DELAYED_WARNING_MSG", lkNone, CheckvarShellCommand)
221 pkglist("DEPENDS", lkSpace, CheckvarDependencyWithPath) 231 pkglist("DEPENDS", lkSpace, CheckvarDependencyWithPath)
222 usr("DEPENDS_TARGET", lkShell, CheckvarIdentifier) 232 usr("DEPENDS_TARGET", lkShell, CheckvarIdentifier)
223 acl("DESCR_SRC", lkShell, CheckvarPathname, "Makefile: set; Makefile.common: default, set") 233 acl("DESCR_SRC", lkShell, CheckvarPathname, "Makefile: set, append; Makefile.common: default, set")
224 sys("DESTDIR", lkNone, CheckvarPathname) 234 sys("DESTDIR", lkNone, CheckvarPathname)
225 acl("DESTDIR_VARNAME", lkNone, CheckvarVarname, "Makefile, Makefile.common: set") 235 acl("DESTDIR_VARNAME", lkNone, CheckvarVarname, "Makefile, Makefile.common: set")
226 sys("DEVOSSAUDIO", lkNone, CheckvarPathname) 236 sys("DEVOSSAUDIO", lkNone, CheckvarPathname)
227 sys("DEVOSSSOUND", lkNone, CheckvarPathname) 237 sys("DEVOSSSOUND", lkNone, CheckvarPathname)
228 pkglist("DISTFILES", lkShell, CheckvarFilename) 238 pkglist("DISTFILES", lkShell, CheckvarFilename)
229 pkg("DISTINFO_FILE", lkNone, CheckvarRelativePkgPath) 239 pkg("DISTINFO_FILE", lkNone, CheckvarRelativePkgPath)
230 pkg("DISTNAME", lkNone, CheckvarFilename) 240 pkg("DISTNAME", lkNone, CheckvarFilename)
231 pkg("DIST_SUBDIR", lkNone, CheckvarPathname) 241 pkg("DIST_SUBDIR", lkNone, CheckvarPathname)
232 acl("DJB_BUILD_ARGS", lkShell, CheckvarShellWord, "") 242 acl("DJB_BUILD_ARGS", lkShell, CheckvarShellWord, "")
233 acl("DJB_BUILD_TARGETS", lkShell, CheckvarIdentifier, "") 243 acl("DJB_BUILD_TARGETS", lkShell, CheckvarIdentifier, "")
234 acl("DJB_CONFIG_CMDS", lkNone, CheckvarShellCommands, "options.mk: set") 244 acl("DJB_CONFIG_CMDS", lkNone, CheckvarShellCommands, "options.mk: set")
235 acl("DJB_CONFIG_DIRS", lkShell, CheckvarWrksrcSubdirectory, "") 245 acl("DJB_CONFIG_DIRS", lkShell, CheckvarWrksrcSubdirectory, "")
236 acl("DJB_CONFIG_HOME", lkNone, CheckvarFilename, "") 246 acl("DJB_CONFIG_HOME", lkNone, CheckvarFilename, "")
@@ -366,54 +376,58 @@ func (gd *GlobalData) InitVartypes() { @@ -366,54 +376,58 @@ func (gd *GlobalData) InitVartypes() {
366 acl("IS_BUILTIN.*", lkNone, CheckvarYesNoIndirectly, "builtin.mk: set, use-loadtime, use") 376 acl("IS_BUILTIN.*", lkNone, CheckvarYesNoIndirectly, "builtin.mk: set, use-loadtime, use")
367 sys("JAVA_BINPREFIX", lkNone, CheckvarPathname) 377 sys("JAVA_BINPREFIX", lkNone, CheckvarPathname)
368 pkg("JAVA_CLASSPATH", lkNone, CheckvarShellWord) 378 pkg("JAVA_CLASSPATH", lkNone, CheckvarShellWord)
369 pkg("JAVA_HOME", lkNone, CheckvarPathname) 379 pkg("JAVA_HOME", lkNone, CheckvarPathname)
370 pkg("JAVA_NAME", lkNone, CheckvarFilename) 380 pkg("JAVA_NAME", lkNone, CheckvarFilename)
371 pkglist("JAVA_UNLIMIT", lkShell, enum("cmdsize datasize stacksize")) 381 pkglist("JAVA_UNLIMIT", lkShell, enum("cmdsize datasize stacksize"))
372 pkglist("JAVA_WRAPPERS", lkSpace, CheckvarFilename) 382 pkglist("JAVA_WRAPPERS", lkSpace, CheckvarFilename)
373 pkg("JAVA_WRAPPER_BIN.*", lkNone, CheckvarPathname) 383 pkg("JAVA_WRAPPER_BIN.*", lkNone, CheckvarPathname)
374 sys("KRB5BASE", lkNone, CheckvarPathname) 384 sys("KRB5BASE", lkNone, CheckvarPathname)
375 acl("KRB5_ACCEPTED", lkShell, enum("heimdal mit-krb5"), "") 385 acl("KRB5_ACCEPTED", lkShell, enum("heimdal mit-krb5"), "")
376 usr("KRB5_DEFAULT", lkNone, enum("heimdal mit-krb5")) 386 usr("KRB5_DEFAULT", lkNone, enum("heimdal mit-krb5"))
377 sys("KRB5_TYPE", lkNone, CheckvarIdentifier) 387 sys("KRB5_TYPE", lkNone, CheckvarIdentifier)
378 sys("LD", lkNone, CheckvarShellCommand) 388 sys("LD", lkNone, CheckvarShellCommand)
379 pkglist("LDFLAGS*", lkShell, CheckvarLdFlag) 389 pkglist("LDFLAGS", lkShell, CheckvarLdFlag)
 390 pkglist("LDFLAGS.*", lkShell, CheckvarLdFlag)
380 sys("LIBGRP", lkNone, CheckvarUserGroupName) 391 sys("LIBGRP", lkNone, CheckvarUserGroupName)
381 sys("LIBMODE", lkNone, CheckvarFileMode) 392 sys("LIBMODE", lkNone, CheckvarFileMode)
382 sys("LIBOWN", lkNone, CheckvarUserGroupName) 393 sys("LIBOWN", lkNone, CheckvarUserGroupName)
383 sys("LIBOSSAUDIO", lkNone, CheckvarPathname) 394 sys("LIBOSSAUDIO", lkNone, CheckvarPathname)
384 pkglist("LIBS*", lkShell, CheckvarLdFlag) 395 pkglist("LIBS", lkShell, CheckvarLdFlag)
 396 pkglist("LIBS.*", lkShell, CheckvarLdFlag)
385 sys("LIBTOOL", lkNone, CheckvarShellCommand) 397 sys("LIBTOOL", lkNone, CheckvarShellCommand)
386 acl("LIBTOOL_OVERRIDE", lkShell, CheckvarPathmask, "Makefile: set, append") 398 acl("LIBTOOL_OVERRIDE", lkShell, CheckvarPathmask, "Makefile: set, append")
387 pkglist("LIBTOOL_REQD", lkShell, CheckvarVersion) 399 pkglist("LIBTOOL_REQD", lkShell, CheckvarVersion)
388 acl("LICENCE", lkNone, CheckvarLicense, "Makefile, Makefile.common: set; options.mk: set") 400 acl("LICENCE", lkNone, CheckvarLicense, "Makefile, Makefile.common, options.mk: set")
389 acl("LICENSE", lkNone, CheckvarLicense, "Makefile, Makefile.common: set; options.mk: set") 401 acl("LICENSE", lkNone, CheckvarLicense, "Makefile, Makefile.common, options.mk: set")
390 pkg("LICENSE_FILE", lkNone, CheckvarPathname) 402 pkg("LICENSE_FILE", lkNone, CheckvarPathname)
391 sys("LINKER_RPATH_FLAG", lkNone, CheckvarShellWord) 403 sys("LINKER_RPATH_FLAG", lkNone, CheckvarShellWord)
392 sys("LOWER_OPSYS", lkNone, CheckvarIdentifier) 404 sys("LOWER_OPSYS", lkNone, CheckvarIdentifier)
393 acl("LTCONFIG_OVERRIDE", lkShell, CheckvarPathmask, "Makefile: set, append; Makefile.common: append") 405 acl("LTCONFIG_OVERRIDE", lkShell, CheckvarPathmask, "Makefile: set, append; Makefile.common: append")
394 sys("MACHINE_ARCH", lkNone, enumMachineArch) 406 sys("MACHINE_ARCH", lkNone, enumMachineArch)
395 sys("MACHINE_GNU_ARCH", lkNone, enumMachineGnuArch) 407 sys("MACHINE_GNU_ARCH", lkNone, enumMachineGnuArch)
396 sys("MACHINE_GNU_PLATFORM", lkNone, CheckvarMachineGnuPlatform) 408 sys("MACHINE_GNU_PLATFORM", lkNone, CheckvarMachineGnuPlatform)
397 sys("MACHINE_PLATFORM", lkNone, CheckvarMachinePlatform) 409 sys("MACHINE_PLATFORM", lkNone, CheckvarMachinePlatform)
398 acl("MAINTAINER", lkNone, CheckvarMailAddress, "Makefile: set; Makefile.common: default") 410 acl("MAINTAINER", lkNone, CheckvarMailAddress, "Makefile: set; Makefile.common: default")
399 sys("MAKE", lkNone, CheckvarShellCommand) 411 sys("MAKE", lkNone, CheckvarShellCommand)
400 pkglist("MAKEFLAGS", lkShell, CheckvarShellWord) 412 pkglist("MAKEFLAGS", lkShell, CheckvarShellWord)
401 acl("MAKEVARS", lkShell, CheckvarVarname, "builtin.mk: append; buildlink3.mk: append; hacks.mk: append") 413 acl("MAKEVARS", lkShell, CheckvarVarname, "buildlink3.mk, builtin.mk, hacks.mk: append")
402 pkglist("MAKE_DIRS", lkShell, CheckvarPathname) 414 pkglist("MAKE_DIRS", lkShell, CheckvarPathname)
403 pkglist("MAKE_DIRS_PERMS", lkShell, CheckvarPerms) 415 pkglist("MAKE_DIRS_PERMS", lkShell, CheckvarPerms)
404 acl("MAKE_ENV", lkShell, CheckvarShellWord, "Makefile: append, set, use; Makefile.common: append, set, use; buildlink3.mk: append; builtin.mk: append; *.mk: append, use") 416 acl("MAKE_ENV", lkShell, CheckvarShellWord, "Makefile, Makefile.common: append, set, use; buildlink3.mk, builtin.mk: append; *.mk: append, use")
 417 acl("MAKE_ENV.*", lkShell, CheckvarShellWord, "Makefile, Makefile.common: append, set, use; buildlink3.mk, builtin.mk: append; *.mk: append, use")
405 pkg("MAKE_FILE", lkNone, CheckvarPathname) 418 pkg("MAKE_FILE", lkNone, CheckvarPathname)
406 pkglist("MAKE_FLAGS", lkShell, CheckvarShellWord) 419 pkglist("MAKE_FLAGS", lkShell, CheckvarShellWord)
 420 pkglist("MAKE_FLAGS.*", lkShell, CheckvarShellWord)
407 usr("MAKE_JOBS", lkNone, CheckvarInteger) 421 usr("MAKE_JOBS", lkNone, CheckvarInteger)
408 pkg("MAKE_JOBS_SAFE", lkNone, CheckvarYesNo) 422 pkg("MAKE_JOBS_SAFE", lkNone, CheckvarYesNo)
409 pkg("MAKE_PROGRAM", lkNone, CheckvarShellCommand) 423 pkg("MAKE_PROGRAM", lkNone, CheckvarShellCommand)
410 acl("MANCOMPRESSED", lkNone, CheckvarYesNo, "Makefile: set; Makefile.common: default, set") 424 acl("MANCOMPRESSED", lkNone, CheckvarYesNo, "Makefile: set; Makefile.common: default, set")
411 acl("MANCOMPRESSED_IF_MANZ", lkNone, CheckvarYes, "Makefile: set; Makefile.common: default, set") 425 acl("MANCOMPRESSED_IF_MANZ", lkNone, CheckvarYes, "Makefile: set; Makefile.common: default, set")
412 sys("MANGRP", lkNone, CheckvarUserGroupName) 426 sys("MANGRP", lkNone, CheckvarUserGroupName)
413 sys("MANMODE", lkNone, CheckvarFileMode) 427 sys("MANMODE", lkNone, CheckvarFileMode)
414 sys("MANOWN", lkNone, CheckvarUserGroupName) 428 sys("MANOWN", lkNone, CheckvarUserGroupName)
415 pkglist("MASTER_SITES", lkShell, CheckvarFetchURL) 429 pkglist("MASTER_SITES", lkShell, CheckvarFetchURL)
416 sys("MASTER_SITE_APACHE", lkShell, CheckvarFetchURL) 430 sys("MASTER_SITE_APACHE", lkShell, CheckvarFetchURL)
417 sys("MASTER_SITE_BACKUP", lkShell, CheckvarFetchURL) 431 sys("MASTER_SITE_BACKUP", lkShell, CheckvarFetchURL)
418 sys("MASTER_SITE_CYGWIN", lkShell, CheckvarFetchURL) 432 sys("MASTER_SITE_CYGWIN", lkShell, CheckvarFetchURL)
419 sys("MASTER_SITE_DEBIAN", lkShell, CheckvarFetchURL) 433 sys("MASTER_SITE_DEBIAN", lkShell, CheckvarFetchURL)
@@ -435,27 +449,27 @@ func (gd *GlobalData) InitVartypes() { @@ -435,27 +449,27 @@ func (gd *GlobalData) InitVartypes() {
435 sys("MASTER_SITE_NETLIB", lkShell, CheckvarFetchURL) 449 sys("MASTER_SITE_NETLIB", lkShell, CheckvarFetchURL)
436 sys("MASTER_SITE_OPENOFFICE", lkShell, CheckvarFetchURL) 450 sys("MASTER_SITE_OPENOFFICE", lkShell, CheckvarFetchURL)
437 sys("MASTER_SITE_OSDN", lkShell, CheckvarFetchURL) 451 sys("MASTER_SITE_OSDN", lkShell, CheckvarFetchURL)
438 sys("MASTER_SITE_PERL_CPAN", lkShell, CheckvarFetchURL) 452 sys("MASTER_SITE_PERL_CPAN", lkShell, CheckvarFetchURL)
439 sys("MASTER_SITE_R_CRAN", lkShell, CheckvarFetchURL) 453 sys("MASTER_SITE_R_CRAN", lkShell, CheckvarFetchURL)
440 sys("MASTER_SITE_RUBYGEMS", lkShell, CheckvarFetchURL) 454 sys("MASTER_SITE_RUBYGEMS", lkShell, CheckvarFetchURL)
441 sys("MASTER_SITE_SOURCEFORGE", lkShell, CheckvarFetchURL) 455 sys("MASTER_SITE_SOURCEFORGE", lkShell, CheckvarFetchURL)
442 sys("MASTER_SITE_SUNSITE", lkShell, CheckvarFetchURL) 456 sys("MASTER_SITE_SUNSITE", lkShell, CheckvarFetchURL)
443 sys("MASTER_SITE_SUSE", lkShell, CheckvarFetchURL) 457 sys("MASTER_SITE_SUSE", lkShell, CheckvarFetchURL)
444 sys("MASTER_SITE_TEX_CTAN", lkShell, CheckvarFetchURL) 458 sys("MASTER_SITE_TEX_CTAN", lkShell, CheckvarFetchURL)
445 sys("MASTER_SITE_XCONTRIB", lkShell, CheckvarFetchURL) 459 sys("MASTER_SITE_XCONTRIB", lkShell, CheckvarFetchURL)
446 sys("MASTER_SITE_XEMACS", lkShell, CheckvarFetchURL) 460 sys("MASTER_SITE_XEMACS", lkShell, CheckvarFetchURL)
447 pkglist("MESSAGE_SRC", lkShell, CheckvarPathname) 461 pkglist("MESSAGE_SRC", lkShell, CheckvarPathname)
448 acl("MESSAGE_SUBST", lkShell, CheckvarShellWord, "Makefile.common: append; Makefile: append; options.mk: append") 462 acl("MESSAGE_SUBST", lkShell, CheckvarShellWord, "Makefile, Makefile.common, options.mk: append")
449 pkg("META_PACKAGE", lkNone, CheckvarYes) 463 pkg("META_PACKAGE", lkNone, CheckvarYes)
450 sys("MISSING_FEATURES", lkShell, CheckvarIdentifier) 464 sys("MISSING_FEATURES", lkShell, CheckvarIdentifier)
451 acl("MYSQL_VERSIONS_ACCEPTED", lkShell, enum("51 55 56"), "Makefile: set") 465 acl("MYSQL_VERSIONS_ACCEPTED", lkShell, enum("51 55 56"), "Makefile: set")
452 usr("MYSQL_VERSION_DEFAULT", lkNone, CheckvarVersion) 466 usr("MYSQL_VERSION_DEFAULT", lkNone, CheckvarVersion)
453 sys("NM", lkNone, CheckvarShellCommand) 467 sys("NM", lkNone, CheckvarShellCommand)
454 sys("NONBINMODE", lkNone, CheckvarFileMode) 468 sys("NONBINMODE", lkNone, CheckvarFileMode)
455 pkg("NOT_FOR_COMPILER", lkShell, enum("ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc")) 469 pkg("NOT_FOR_COMPILER", lkShell, enum("ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc"))
456 pkglist("NOT_FOR_PLATFORM", lkSpace, CheckvarMachinePlatformPattern) 470 pkglist("NOT_FOR_PLATFORM", lkSpace, CheckvarMachinePlatformPattern)
457 pkg("NOT_FOR_UNPRIVILEGED", lkNone, CheckvarYesNo) 471 pkg("NOT_FOR_UNPRIVILEGED", lkNone, CheckvarYesNo)
458 acl("NO_BIN_ON_CDROM", lkNone, CheckvarRestricted, "Makefile, Makefile.common: set") 472 acl("NO_BIN_ON_CDROM", lkNone, CheckvarRestricted, "Makefile, Makefile.common: set")
459 acl("NO_BIN_ON_FTP", lkNone, CheckvarRestricted, "Makefile, Makefile.common: set") 473 acl("NO_BIN_ON_FTP", lkNone, CheckvarRestricted, "Makefile, Makefile.common: set")
460 acl("NO_BUILD", lkNone, CheckvarYes, "Makefile, Makefile.common: set; Makefile.*: default, set") 474 acl("NO_BUILD", lkNone, CheckvarYes, "Makefile, Makefile.common: set; Makefile.*: default, set")
461 pkg("NO_CHECKSUM", lkNone, CheckvarYes) 475 pkg("NO_CHECKSUM", lkNone, CheckvarYes)
@@ -475,28 +489,28 @@ func (gd *GlobalData) InitVartypes() { @@ -475,28 +489,28 @@ func (gd *GlobalData) InitVartypes() {
475 sys("OS_VERSION", lkNone, CheckvarVersion) 489 sys("OS_VERSION", lkNone, CheckvarVersion)
476 pkg("OVERRIDE_DIRDEPTH*", lkNone, CheckvarInteger) 490 pkg("OVERRIDE_DIRDEPTH*", lkNone, CheckvarInteger)
477 pkg("OVERRIDE_GNU_CONFIG_SCRIPTS", lkNone, CheckvarYes) 491 pkg("OVERRIDE_GNU_CONFIG_SCRIPTS", lkNone, CheckvarYes)
478 acl("OWNER", lkNone, CheckvarMailAddress, "Makefile: set; Makefile.common: default") 492 acl("OWNER", lkNone, CheckvarMailAddress, "Makefile: set; Makefile.common: default")
479 pkglist("OWN_DIRS", lkShell, CheckvarPathname) 493 pkglist("OWN_DIRS", lkShell, CheckvarPathname)
480 pkglist("OWN_DIRS_PERMS", lkShell, CheckvarPerms) 494 pkglist("OWN_DIRS_PERMS", lkShell, CheckvarPerms)
481 sys("PAMBASE", lkNone, CheckvarPathname) 495 sys("PAMBASE", lkNone, CheckvarPathname)
482 usr("PAM_DEFAULT", lkNone, enum("linux-pam openpam solaris-pam")) 496 usr("PAM_DEFAULT", lkNone, enum("linux-pam openpam solaris-pam"))
483 acl("PATCHDIR", lkNone, CheckvarRelativePkgPath, "Makefile: set; Makefile.common: default, set") 497 acl("PATCHDIR", lkNone, CheckvarRelativePkgPath, "Makefile: set; Makefile.common: default, set")
484 pkglist("PATCHFILES", lkShell, CheckvarFilename) 498 pkglist("PATCHFILES", lkShell, CheckvarFilename)
485 acl("PATCH_ARGS", lkShell, CheckvarShellWord, "") 499 acl("PATCH_ARGS", lkShell, CheckvarShellWord, "")
486 acl("PATCH_DIST_ARGS", lkShell, CheckvarShellWord, "Makefile: set, append") 500 acl("PATCH_DIST_ARGS", lkShell, CheckvarShellWord, "Makefile: set, append")
487 acl("PATCH_DIST_CAT", lkNone, CheckvarShellCommand, "") 501 acl("PATCH_DIST_CAT", lkNone, CheckvarShellCommand, "")
488 acl("PATCH_DIST_STRIP*", lkNone, CheckvarShellWord, "Makefile, Makefile.common: set; buildlink3.mk:; builtin.mk:; *.mk: set") 502 acl("PATCH_DIST_STRIP*", lkNone, CheckvarShellWord, "buildlink3.mk, builtin.mk:; Makefile, Makefile.common, *.mk: set")
489 acl("PATCH_SITES", lkShell, CheckvarFetchURL, "Makefile: set; options.mk: set; Makefile.common: set") 503 acl("PATCH_SITES", lkShell, CheckvarFetchURL, "Makefile, Makefile.common, options.mk: set")
490 acl("PATCH_STRIP", lkNone, CheckvarShellWord, "") 504 acl("PATCH_STRIP", lkNone, CheckvarShellWord, "")
491 pkg("PERL5_USE_PACKLIST", lkNone, CheckvarYesNo) 505 pkg("PERL5_USE_PACKLIST", lkNone, CheckvarYesNo)
492 acl("PERL5_PACKLIST", lkShell, CheckvarPerl5Packlist, "Makefile: set; options.mk: set, append") 506 acl("PERL5_PACKLIST", lkShell, CheckvarPerl5Packlist, "Makefile: set; options.mk: set, append")
493 acl("PERL5_PACKLIST_DIR", lkNone, CheckvarPathname, "") 507 acl("PERL5_PACKLIST_DIR", lkNone, CheckvarPathname, "")
494 sys("PGSQL_PREFIX", lkNone, CheckvarPathname) 508 sys("PGSQL_PREFIX", lkNone, CheckvarPathname)
495 acl("PGSQL_VERSIONS_ACCEPTED", lkShell, enum("91 92 93 94"), "") 509 acl("PGSQL_VERSIONS_ACCEPTED", lkShell, enum("91 92 93 94"), "")
496 usr("PGSQL_VERSION_DEFAULT", lkNone, CheckvarVersion) 510 usr("PGSQL_VERSION_DEFAULT", lkNone, CheckvarVersion)
497 sys("PG_LIB_EXT", lkNone, enum("dylib so")) 511 sys("PG_LIB_EXT", lkNone, enum("dylib so"))
498 sys("PGSQL_TYPE", lkNone, enum("postgresql81-client postgresql80-client")) 512 sys("PGSQL_TYPE", lkNone, enum("postgresql81-client postgresql80-client"))
499 sys("PGPKGSRCDIR", lkNone, CheckvarPathname) 513 sys("PGPKGSRCDIR", lkNone, CheckvarPathname)
500 sys("PHASE_MSG", lkNone, CheckvarShellCommand) 514 sys("PHASE_MSG", lkNone, CheckvarShellCommand)
501 usr("PHP_VERSION_REQD", lkNone, CheckvarVersion) 515 usr("PHP_VERSION_REQD", lkNone, CheckvarVersion)
502 sys("PKGBASE", lkNone, CheckvarIdentifier) 516 sys("PKGBASE", lkNone, CheckvarIdentifier)
@@ -538,65 +552,65 @@ func (gd *GlobalData) InitVartypes() { @@ -538,65 +552,65 @@ func (gd *GlobalData) InitVartypes() {
538 acl("PKG_HOME.*", lkNone, CheckvarPathname, "Makefile: set") 552 acl("PKG_HOME.*", lkNone, CheckvarPathname, "Makefile: set")
539 acl("PKG_HACKS", lkShell, CheckvarIdentifier, "hacks.mk: append") 553 acl("PKG_HACKS", lkShell, CheckvarIdentifier, "hacks.mk: append")
540 sys("PKG_INFO", lkNone, CheckvarShellCommand) 554 sys("PKG_INFO", lkNone, CheckvarShellCommand)
541 sys("PKG_JAVA_HOME", lkNone, CheckvarPathname) 555 sys("PKG_JAVA_HOME", lkNone, CheckvarPathname)
542 jvms := enum("openjdk8 oracle-jdk8 openjdk7 sun-jdk7 sun-jdk6 jdk16 jdk15 kaffe") // See mk/java-vm.mk:/_PKG_JVMS/ 556 jvms := enum("openjdk8 oracle-jdk8 openjdk7 sun-jdk7 sun-jdk6 jdk16 jdk15 kaffe") // See mk/java-vm.mk:/_PKG_JVMS/
543 sys("PKG_JVM", lkNone, jvms) 557 sys("PKG_JVM", lkNone, jvms)
544 acl("PKG_JVMS_ACCEPTED", lkShell, jvms, "Makefile: set; Makefile.common: default, set") 558 acl("PKG_JVMS_ACCEPTED", lkShell, jvms, "Makefile: set; Makefile.common: default, set")
545 usr("PKG_JVM_DEFAULT", lkNone, jvms) 559 usr("PKG_JVM_DEFAULT", lkNone, jvms)
546 acl("PKG_LEGACY_OPTIONS", lkShell, CheckvarOption, "") 560 acl("PKG_LEGACY_OPTIONS", lkShell, CheckvarOption, "")
547 acl("PKG_LIBTOOL", lkNone, CheckvarPathname, "Makefile: set") 561 acl("PKG_LIBTOOL", lkNone, CheckvarPathname, "Makefile: set")
548 acl("PKG_OPTIONS", lkSpace, CheckvarOption, "bsd.options.mk: set; *: use-loadtime, use") 562 acl("PKG_OPTIONS", lkSpace, CheckvarOption, "bsd.options.mk: set; *: use-loadtime, use")
549 usr("PKG_OPTIONS.*", lkSpace, CheckvarOption) 563 usr("PKG_OPTIONS.*", lkSpace, CheckvarOption)
550 acl("PKG_OPTIONS_DEPRECATED_WARNINGS", lkShell, CheckvarShellWord, "") 564 acl("PKG_OPTIONS_DEPRECATED_WARNINGS", lkShell, CheckvarShellWord, "")
551 acl("PKG_OPTIONS_GROUP.*", lkSpace, CheckvarOption, "options.mk: set; Makefile: set") 565 acl("PKG_OPTIONS_GROUP.*", lkSpace, CheckvarOption, "Makefile, options.mk: set, append")
552 acl("PKG_OPTIONS_LEGACY_OPTS", lkSpace, CheckvarUnchecked, "Makefile, Makefile.common: append; options.mk: append") 566 acl("PKG_OPTIONS_LEGACY_OPTS", lkSpace, CheckvarUnchecked, "Makefile, Makefile.common, options.mk: append")
553 acl("PKG_OPTIONS_LEGACY_VARS", lkSpace, CheckvarUnchecked, "Makefile, Makefile.common: append; options.mk: append") 567 acl("PKG_OPTIONS_LEGACY_VARS", lkSpace, CheckvarUnchecked, "Makefile, Makefile.common, options.mk: append")
554 acl("PKG_OPTIONS_NONEMPTY_SETS", lkSpace, CheckvarIdentifier, "") 568 acl("PKG_OPTIONS_NONEMPTY_SETS", lkSpace, CheckvarIdentifier, "")
555 acl("PKG_OPTIONS_OPTIONAL_GROUPS", lkSpace, CheckvarIdentifier, "options.mk: set, append") 569 acl("PKG_OPTIONS_OPTIONAL_GROUPS", lkSpace, CheckvarIdentifier, "options.mk: set, append")
556 acl("PKG_OPTIONS_REQUIRED_GROUPS", lkSpace, CheckvarIdentifier, "options.mk: set; Makefile: set") 570 acl("PKG_OPTIONS_REQUIRED_GROUPS", lkSpace, CheckvarIdentifier, "Makefile, options.mk: set")
557 acl("PKG_OPTIONS_SET.*", lkSpace, CheckvarOption, "") 571 acl("PKG_OPTIONS_SET.*", lkSpace, CheckvarOption, "")
558 acl("PKG_OPTIONS_VAR", lkNone, CheckvarPkgOptionsVar, "options.mk: set; Makefile, Makefile.common: set; bsd.options.mk: use-loadtime") 572 acl("PKG_OPTIONS_VAR", lkNone, CheckvarPkgOptionsVar, "Makefile, Makefile.common, options.mk: set; bsd.options.mk: use-loadtime")
559 acl("PKG_PRESERVE", lkNone, CheckvarYes, "Makefile: set") 573 acl("PKG_PRESERVE", lkNone, CheckvarYes, "Makefile: set")
560 acl("PKG_SHELL", lkNone, CheckvarPathname, "Makefile, Makefile.common: set") 574 acl("PKG_SHELL", lkNone, CheckvarPathname, "Makefile, Makefile.common: set")
561 acl("PKG_SHELL.*", lkNone, CheckvarPathname, "Makefile, Makefile.common: set") 575 acl("PKG_SHELL.*", lkNone, CheckvarPathname, "Makefile, Makefile.common: set")
562 acl("PKG_SHLIBTOOL", lkNone, CheckvarPathname, "") 576 acl("PKG_SHLIBTOOL", lkNone, CheckvarPathname, "")
563 pkglist("PKG_SKIP_REASON", lkShell, CheckvarShellWord) 577 pkglist("PKG_SKIP_REASON", lkShell, CheckvarShellWord)
564 acl("PKG_SUGGESTED_OPTIONS", lkShell, CheckvarOption, "options.mk: set, append; Makefile: set, append; Makefile.common: set") 578 acl("PKG_SUGGESTED_OPTIONS", lkShell, CheckvarOption, "Makefile, Makefile.common, options.mk: set, append")
565 acl("PKG_SUPPORTED_OPTIONS", lkShell, CheckvarOption, "options.mk: set, append, use; Makefile: set, append; Makefile.common: set") 579 acl("PKG_SUPPORTED_OPTIONS", lkShell, CheckvarOption, "Makefile: set, append; Makefile.common: set; options.mk: set, append, use")
566 pkg("PKG_SYSCONFDIR*", lkNone, CheckvarPathname) 580 pkg("PKG_SYSCONFDIR*", lkNone, CheckvarPathname)
567 pkglist("PKG_SYSCONFDIR_PERMS", lkShell, CheckvarPerms) 581 pkglist("PKG_SYSCONFDIR_PERMS", lkShell, CheckvarPerms)
568 sys("PKG_SYSCONFBASEDIR", lkNone, CheckvarPathname) 582 sys("PKG_SYSCONFBASEDIR", lkNone, CheckvarPathname)
569 pkg("PKG_SYSCONFSUBDIR", lkNone, CheckvarPathname) 583 pkg("PKG_SYSCONFSUBDIR", lkNone, CheckvarPathname)
570 acl("PKG_SYSCONFVAR", lkNone, CheckvarIdentifier, "") // FIXME: name/type mismatch. 584 acl("PKG_SYSCONFVAR", lkNone, CheckvarIdentifier, "") // FIXME: name/type mismatch.
571 acl("PKG_UID", lkNone, CheckvarInteger, "Makefile: set") 585 acl("PKG_UID", lkNone, CheckvarInteger, "Makefile: set")
572 acl("PKG_USERS", lkShell, CheckvarShellWord, "Makefile: set, append") 586 acl("PKG_USERS", lkShell, CheckvarShellWord, "Makefile: set, append")
573 pkg("PKG_USERS_VARS", lkShell, CheckvarVarname) 587 pkg("PKG_USERS_VARS", lkShell, CheckvarVarname)
574 acl("PKG_USE_KERBEROS", lkNone, CheckvarYes, "Makefile, Makefile.common: set") 588 acl("PKG_USE_KERBEROS", lkNone, CheckvarYes, "Makefile, Makefile.common: set")
575 // PLIST.* has special handling code 589 // PLIST.* has special handling code
576 pkglist("PLIST_VARS", lkShell, CheckvarIdentifier) 590 pkglist("PLIST_VARS", lkShell, CheckvarIdentifier)
577 pkglist("PLIST_SRC", lkShell, CheckvarRelativePkgPath) 591 pkglist("PLIST_SRC", lkShell, CheckvarRelativePkgPath)
578 pkglist("PLIST_SUBST", lkShell, CheckvarShellWord) 592 pkglist("PLIST_SUBST", lkShell, CheckvarShellWord)
579 acl("PLIST_TYPE", lkNone, enum("dynamic static"), "") 593 acl("PLIST_TYPE", lkNone, enum("dynamic static"), "")
580 acl("PREPEND_PATH", lkShell, CheckvarPathname, "") 594 acl("PREPEND_PATH", lkShell, CheckvarPathname, "")
581 acl("PREFIX", lkNone, CheckvarPathname, "*: use") 595 acl("PREFIX", lkNone, CheckvarPathname, "*: use")
582 acl("PREV_PKGPATH", lkNone, CheckvarPathname, "*: use") // doesn't exist any longer 596 acl("PREV_PKGPATH", lkNone, CheckvarPathname, "*: use") // doesn't exist any longer
583 acl("PRINT_PLIST_AWK", lkNone, CheckvarAwkCommand, "*: append") 597 acl("PRINT_PLIST_AWK", lkNone, CheckvarAwkCommand, "*: append")
584 acl("PRIVILEGED_STAGES", lkShell, enum("install package clean"), "") 598 acl("PRIVILEGED_STAGES", lkShell, enum("install package clean"), "")
585 acl("PTHREAD_AUTO_VARS", lkNone, CheckvarYesNo, "Makefile: set") 599 acl("PTHREAD_AUTO_VARS", lkNone, CheckvarYesNo, "Makefile: set")
586 sys("PTHREAD_CFLAGS", lkShell, CheckvarCFlag) 600 sys("PTHREAD_CFLAGS", lkShell, CheckvarCFlag)
587 sys("PTHREAD_LDFLAGS", lkShell, CheckvarLdFlag) 601 sys("PTHREAD_LDFLAGS", lkShell, CheckvarLdFlag)
588 sys("PTHREAD_LIBS", lkShell, CheckvarLdFlag) 602 sys("PTHREAD_LIBS", lkShell, CheckvarLdFlag)
589 acl("PTHREAD_OPTS", lkShell, enum("native optional require"), "Makefile: set, append; Makefile.common: append; buildlink3.mk: append") 603 acl("PTHREAD_OPTS", lkShell, enum("native optional require"), "Makefile: set, append; Makefile.common, buildlink3.mk: append")
590 sys("PTHREAD_TYPE", lkNone, CheckvarIdentifier) // Or "native" or "none". 604 sys("PTHREAD_TYPE", lkNone, CheckvarIdentifier) // Or "native" or "none".
591 pkg("PY_PATCHPLIST", lkNone, CheckvarYes) 605 pkg("PY_PATCHPLIST", lkNone, CheckvarYes)
592 acl("PYPKGPREFIX", lkNone, enum("py27 py33 py34 py35"), "pyversion.mk: set; *: use-loadtime, use") 606 acl("PYPKGPREFIX", lkNone, enum("py27 py33 py34 py35"), "pyversion.mk: set; *: use-loadtime, use")
593 pkg("PYTHON_FOR_BUILD_ONLY", lkNone, CheckvarYes) 607 pkg("PYTHON_FOR_BUILD_ONLY", lkNone, CheckvarYes)
594 pkglist("REPLACE_PYTHON", lkShell, CheckvarPathmask) 608 pkglist("REPLACE_PYTHON", lkShell, CheckvarPathmask)
595 pkg("PYTHON_VERSIONS_ACCEPTED", lkShell, CheckvarVersion) 609 pkg("PYTHON_VERSIONS_ACCEPTED", lkShell, CheckvarVersion)
596 pkg("PYTHON_VERSIONS_INCOMPATIBLE", lkShell, CheckvarVersion) 610 pkg("PYTHON_VERSIONS_INCOMPATIBLE", lkShell, CheckvarVersion)
597 usr("PYTHON_VERSION_DEFAULT", lkNone, CheckvarVersion) 611 usr("PYTHON_VERSION_DEFAULT", lkNone, CheckvarVersion)
598 usr("PYTHON_VERSION_REQD", lkNone, CheckvarVersion) 612 usr("PYTHON_VERSION_REQD", lkNone, CheckvarVersion)
599 pkglist("PYTHON_VERSIONED_DEPENDENCIES", lkShell, CheckvarPythonDependency) 613 pkglist("PYTHON_VERSIONED_DEPENDENCIES", lkShell, CheckvarPythonDependency)
600 sys("RANLIB", lkNone, CheckvarShellCommand) 614 sys("RANLIB", lkNone, CheckvarShellCommand)
601 pkglist("RCD_SCRIPTS", lkShell, CheckvarFilename) 615 pkglist("RCD_SCRIPTS", lkShell, CheckvarFilename)
602 acl("RCD_SCRIPT_SRC.*", lkShell, CheckvarPathname, "Makefile: set") 616 acl("RCD_SCRIPT_SRC.*", lkShell, CheckvarPathname, "Makefile: set")
@@ -628,27 +642,28 @@ func (gd *GlobalData) InitVartypes() { @@ -628,27 +642,28 @@ func (gd *GlobalData) InitVartypes() {
628 usr("SETUID_ROOT_PERMS", lkShell, CheckvarShellWord) 642 usr("SETUID_ROOT_PERMS", lkShell, CheckvarShellWord)
629 sys("SHAREGRP", lkNone, CheckvarUserGroupName) 643 sys("SHAREGRP", lkNone, CheckvarUserGroupName)
630 sys("SHAREMODE", lkNone, CheckvarFileMode) 644 sys("SHAREMODE", lkNone, CheckvarFileMode)
631 sys("SHAREOWN", lkNone, CheckvarUserGroupName) 645 sys("SHAREOWN", lkNone, CheckvarUserGroupName)
632 sys("SHCOMMENT", lkNone, CheckvarShellCommand) 646 sys("SHCOMMENT", lkNone, CheckvarShellCommand)
633 acl("SHLIB_HANDLING", lkNone, enum("YES NO no"), "") 647 acl("SHLIB_HANDLING", lkNone, enum("YES NO no"), "")
634 acl("SHLIBTOOL", lkNone, CheckvarShellCommand, "Makefile: use") 648 acl("SHLIBTOOL", lkNone, CheckvarShellCommand, "Makefile: use")
635 acl("SHLIBTOOL_OVERRIDE", lkShell, CheckvarPathmask, "Makefile: set, append; Makefile.common: append") 649 acl("SHLIBTOOL_OVERRIDE", lkShell, CheckvarPathmask, "Makefile: set, append; Makefile.common: append")
636 acl("SITES.*", lkShell, CheckvarFetchURL, "Makefile, Makefile.common, options.mk: set, append, use") 650 acl("SITES.*", lkShell, CheckvarFetchURL, "Makefile, Makefile.common, options.mk: set, append, use")
637 pkglist("SPECIAL_PERMS", lkShell, CheckvarPerms) 651 pkglist("SPECIAL_PERMS", lkShell, CheckvarPerms)
638 sys("STEP_MSG", lkNone, CheckvarShellCommand) 652 sys("STEP_MSG", lkNone, CheckvarShellCommand)
639 acl("SUBDIR", lkShell, CheckvarFilename, "Makefile: append; *:") 653 acl("SUBDIR", lkShell, CheckvarFilename, "Makefile: append; *:")
640 acl("SUBST_CLASSES", lkShell, CheckvarIdentifier, "Makefile: set, append; *: append") 654 acl("SUBST_CLASSES", lkShell, CheckvarIdentifier, "Makefile: set, append; *: append")
641 acl("SUBST_FILES.*", lkShell, CheckvarPathmask, "Makefile: set, append; Makefile.*, *.mk: set, append") 655 acl("SUBST_CLASSES.*", lkShell, CheckvarIdentifier, "Makefile: set, append; *: append")
 656 acl("SUBST_FILES.*", lkShell, CheckvarPathmask, "Makefile, Makefile.*, *.mk: set, append")
642 acl("SUBST_FILTER_CMD.*", lkNone, CheckvarShellCommand, "Makefile, Makefile.*, *.mk: set") 657 acl("SUBST_FILTER_CMD.*", lkNone, CheckvarShellCommand, "Makefile, Makefile.*, *.mk: set")
643 acl("SUBST_MESSAGE.*", lkNone, CheckvarMessage, "Makefile, Makefile.*, *.mk: set") 658 acl("SUBST_MESSAGE.*", lkNone, CheckvarMessage, "Makefile, Makefile.*, *.mk: set")
644 acl("SUBST_SED.*", lkNone, CheckvarSedCommands, "Makefile, Makefile.*, *.mk: set, append") 659 acl("SUBST_SED.*", lkNone, CheckvarSedCommands, "Makefile, Makefile.*, *.mk: set, append")
645 pkg("SUBST_STAGE.*", lkNone, CheckvarStage) 660 pkg("SUBST_STAGE.*", lkNone, CheckvarStage)
646 pkglist("SUBST_VARS.*", lkShell, CheckvarVarname) 661 pkglist("SUBST_VARS.*", lkShell, CheckvarVarname)
647 pkglist("SUPERSEDES", lkSpace, CheckvarDependency) 662 pkglist("SUPERSEDES", lkSpace, CheckvarDependency)
648 pkglist("TEST_DIRS", lkShell, CheckvarWrksrcSubdirectory) 663 pkglist("TEST_DIRS", lkShell, CheckvarWrksrcSubdirectory)
649 pkglist("TEST_ENV", lkShell, CheckvarShellWord) 664 pkglist("TEST_ENV", lkShell, CheckvarShellWord)
650 acl("TEST_TARGET", lkShell, CheckvarIdentifier, "Makefile: set; Makefile.common: default, set; options.mk: set, append") 665 acl("TEST_TARGET", lkShell, CheckvarIdentifier, "Makefile: set; Makefile.common: default, set; options.mk: set, append")
651 acl("TEX_ACCEPTED", lkShell, enum("teTeX1 teTeX2 teTeX3"), "Makefile, Makefile.common: set") 666 acl("TEX_ACCEPTED", lkShell, enum("teTeX1 teTeX2 teTeX3"), "Makefile, Makefile.common: set")
652 acl("TEX_DEPMETHOD", lkNone, enum("build run"), "Makefile, Makefile.common: set") 667 acl("TEX_DEPMETHOD", lkNone, enum("build run"), "Makefile, Makefile.common: set")
653 pkglist("TEXINFO_REQD", lkShell, CheckvarVersion) 668 pkglist("TEXINFO_REQD", lkShell, CheckvarVersion)
654 acl("TOOL_DEPENDS", lkSpace, CheckvarDependencyWithPath, "Makefile, Makefile.common, *.mk: append") 669 acl("TOOL_DEPENDS", lkSpace, CheckvarDependencyWithPath, "Makefile, Makefile.common, *.mk: append")
@@ -662,43 +677,44 @@ func (gd *GlobalData) InitVartypes() { @@ -662,43 +677,44 @@ func (gd *GlobalData) InitVartypes() {
662 sys("TOOLS_PATH.*", lkNone, CheckvarPathname) 677 sys("TOOLS_PATH.*", lkNone, CheckvarPathname)
663 sys("TOOLS_PLATFORM.*", lkNone, CheckvarShellCommand) 678 sys("TOOLS_PLATFORM.*", lkNone, CheckvarShellCommand)
664 sys("TOUCH_FLAGS", lkShell, CheckvarShellWord) 679 sys("TOUCH_FLAGS", lkShell, CheckvarShellWord)
665 pkglist("UAC_REQD_EXECS", lkShell, CheckvarPrefixPathname) 680 pkglist("UAC_REQD_EXECS", lkShell, CheckvarPrefixPathname)
666 acl("UNLIMIT_RESOURCES", lkShell, enum("datasize stacksize memorysize"), "Makefile: set, append; Makefile.common: append") 681 acl("UNLIMIT_RESOURCES", lkShell, enum("datasize stacksize memorysize"), "Makefile: set, append; Makefile.common: append")
667 usr("UNPRIVILEGED_USER", lkNone, CheckvarUserGroupName) 682 usr("UNPRIVILEGED_USER", lkNone, CheckvarUserGroupName)
668 usr("UNPRIVILEGED_GROUP", lkNone, CheckvarUserGroupName) 683 usr("UNPRIVILEGED_GROUP", lkNone, CheckvarUserGroupName)
669 pkglist("UNWRAP_FILES", lkShell, CheckvarPathmask) 684 pkglist("UNWRAP_FILES", lkShell, CheckvarPathmask)
670 usr("UPDATE_TARGET", lkShell, CheckvarIdentifier) 685 usr("UPDATE_TARGET", lkShell, CheckvarIdentifier)
671 pkg("USE_BSD_MAKEFILE", lkNone, CheckvarYes) 686 pkg("USE_BSD_MAKEFILE", lkNone, CheckvarYes)
672 acl("USE_BUILTIN.*", lkNone, CheckvarYesNoIndirectly, "builtin.mk: set") 687 acl("USE_BUILTIN.*", lkNone, CheckvarYesNoIndirectly, "builtin.mk: set")
673 pkg("USE_CMAKE", lkNone, CheckvarYes) 688 pkg("USE_CMAKE", lkNone, CheckvarYes)
674 usr("USE_DESTDIR", lkNone, CheckvarYes) 689 usr("USE_DESTDIR", lkNone, CheckvarYes)
675 pkg("USE_FEATURES", lkShell, CheckvarIdentifier) 690 pkglist("USE_FEATURES", lkShell, CheckvarIdentifier)
676 pkg("USE_GCC_RUNTIME", lkNone, CheckvarYesNo) 691 pkg("USE_GCC_RUNTIME", lkNone, CheckvarYesNo)
677 pkg("USE_GNU_CONFIGURE_HOST", lkNone, CheckvarYesNo) 692 pkg("USE_GNU_CONFIGURE_HOST", lkNone, CheckvarYesNo)
678 acl("USE_GNU_ICONV", lkNone, CheckvarYes, "Makefile, Makefile.common: set; options.mk: set") 693 acl("USE_GNU_ICONV", lkNone, CheckvarYes, "Makefile, Makefile.common, options.mk: set")
679 acl("USE_IMAKE", lkNone, CheckvarYes, "Makefile: set") 694 acl("USE_IMAKE", lkNone, CheckvarYes, "Makefile: set")
680 pkg("USE_JAVA", lkNone, enum("run yes build")) 695 pkg("USE_JAVA", lkNone, enum("run yes build"))
681 pkg("USE_JAVA2", lkNone, enum("YES yes no 1.4 1.5 6 7 8")) 696 pkg("USE_JAVA2", lkNone, enum("YES yes no 1.4 1.5 6 7 8"))
682 acl("USE_LANGUAGES", lkShell, enum("ada c c99 c++ fortran fortran77 java objc"), "Makefile, Makefile.common, options.mk: set, append") 697 acl("USE_LANGUAGES", lkShell, enum("ada c c99 c++ fortran fortran77 java objc"), "Makefile, Makefile.common, options.mk: set, append")
683 pkg("USE_LIBTOOL", lkNone, CheckvarYes) 698 pkg("USE_LIBTOOL", lkNone, CheckvarYes)
684 pkg("USE_MAKEINFO", lkNone, CheckvarYes) 699 pkg("USE_MAKEINFO", lkNone, CheckvarYes)
685 pkg("USE_MSGFMT_PLURALS", lkNone, CheckvarYes) 700 pkg("USE_MSGFMT_PLURALS", lkNone, CheckvarYes)
686 pkg("USE_NCURSES", lkNone, CheckvarYes) 701 pkg("USE_NCURSES", lkNone, CheckvarYes)
687 pkg("USE_OLD_DES_API", lkNone, CheckvarYesNo) 702 pkg("USE_OLD_DES_API", lkNone, CheckvarYesNo)
688 pkg("USE_PKGINSTALL", lkNone, CheckvarYes) 703 pkg("USE_PKGINSTALL", lkNone, CheckvarYes)
689 pkg("USE_PKGLOCALEDIR", lkNone, CheckvarYesNo) 704 pkg("USE_PKGLOCALEDIR", lkNone, CheckvarYesNo)
690 usr("USE_PKGSRC_GCC", lkNone, CheckvarYes) 705 usr("USE_PKGSRC_GCC", lkNone, CheckvarYes)
691 acl("USE_TOOLS", lkShell, CheckvarTool, "*: append") 706 acl("USE_TOOLS", lkShell, CheckvarTool, "*: append")
 707 acl("USE_TOOLS.*", lkShell, CheckvarTool, "*: append")
692 pkg("USE_X11", lkNone, CheckvarYes) 708 pkg("USE_X11", lkNone, CheckvarYes)
693 sys("WARNING_MSG", lkNone, CheckvarShellCommand) 709 sys("WARNING_MSG", lkNone, CheckvarShellCommand)
694 sys("WARNING_CAT", lkNone, CheckvarShellCommand) 710 sys("WARNING_CAT", lkNone, CheckvarShellCommand)
695 acl("WRAPPER_REORDER_CMDS", lkShell, CheckvarWrapperReorder, "Makefile, Makefile.common, buildlink3.mk: append") 711 acl("WRAPPER_REORDER_CMDS", lkShell, CheckvarWrapperReorder, "Makefile, Makefile.common, buildlink3.mk: append")
696 acl("WRAPPER_TRANSFORM_CMDS", lkShell, CheckvarWrapperTransform, "Makefile, Makefile.common, buildlink3.mk: append") 712 acl("WRAPPER_TRANSFORM_CMDS", lkShell, CheckvarWrapperTransform, "Makefile, Makefile.common, buildlink3.mk: append")
697 sys("WRKDIR", lkNone, CheckvarPathname) 713 sys("WRKDIR", lkNone, CheckvarPathname)
698 pkg("WRKSRC", lkNone, CheckvarWrkdirSubdirectory) 714 pkg("WRKSRC", lkNone, CheckvarWrkdirSubdirectory)
699 sys("X11_PKGSRCDIR.*", lkNone, CheckvarPathname) 715 sys("X11_PKGSRCDIR.*", lkNone, CheckvarPathname)
700 usr("XAW_TYPE", lkNone, enum("3d neXtaw standard xpm")) 716 usr("XAW_TYPE", lkNone, enum("3d neXtaw standard xpm"))
701 acl("XMKMF_FLAGS", lkShell, CheckvarShellWord, "") 717 acl("XMKMF_FLAGS", lkShell, CheckvarShellWord, "")
702} 718}
703 719
704func enum(values string) *VarChecker { 720func enum(values string) *VarChecker {
@@ -743,33 +759,38 @@ func acl(varname string, kindOfList Kind @@ -743,33 +759,38 @@ func acl(varname string, kindOfList Kind
743 if varparam == "" || varparam == "*" { 759 if varparam == "" || varparam == "*" {
744 G.globalData.vartypes[varbase] = vtype 760 G.globalData.vartypes[varbase] = vtype
745 } 761 }
746 if varparam == "*" || varparam == ".*" { 762 if varparam == "*" || varparam == ".*" {
747 G.globalData.vartypes[varbase+".*"] = vtype 763 G.globalData.vartypes[varbase+".*"] = vtype
748 } 764 }
749} 765}
750 766
751func parseAclEntries(varname string, aclentries string) []AclEntry { 767func parseAclEntries(varname string, aclentries string) []AclEntry {
752 if aclentries == "" { 768 if aclentries == "" {
753 return nil 769 return nil
754 } 770 }
755 var result []AclEntry 771 var result []AclEntry
 772 prevperms := "(first)"
756 for _, arg := range strings.Split(aclentries, "; ") { 773 for _, arg := range strings.Split(aclentries, "; ") {
757 var globs, perms string 774 var globs, perms string
758 if fields := strings.SplitN(arg, ": ", 2); len(fields) == 2 { 775 if fields := strings.SplitN(arg, ": ", 2); len(fields) == 2 {
759 globs, perms = fields[0], fields[1] 776 globs, perms = fields[0], fields[1]
760 } else { 777 } else {
761 globs = strings.TrimSuffix(arg, ":") 778 globs = strings.TrimSuffix(arg, ":")
762 } 779 }
 780 if perms == prevperms {
 781 fmt.Printf("Repeated permissions for %s: %s\n", varname, perms)
 782 }
 783 prevperms = perms
763 var permissions AclPermissions 784 var permissions AclPermissions
764 for _, perm := range strings.Split(perms, ", ") { 785 for _, perm := range strings.Split(perms, ", ") {
765 switch perm { 786 switch perm {
766 case "append": 787 case "append":
767 permissions |= aclpAppend 788 permissions |= aclpAppend
768 case "default": 789 case "default":
769 permissions |= aclpSetDefault 790 permissions |= aclpSetDefault
770 case "set": 791 case "set":
771 permissions |= aclpSet 792 permissions |= aclpSet
772 case "use": 793 case "use":
773 permissions |= aclpUse 794 permissions |= aclpUse
774 case "use-loadtime": 795 case "use-loadtime":
775 permissions |= aclpUseLoadtime 796 permissions |= aclpUseLoadtime

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

--- pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck_test.go 2016/06/10 19:42:42 1.10
+++ pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck_test.go 2016/07/07 12:09:27 1.11
@@ -279,29 +279,31 @@ func (s *Suite) TestVartypeCheck_Pathlis @@ -279,29 +279,31 @@ func (s *Suite) TestVartypeCheck_Pathlis
279 279
280func (s *Suite) Test_VartypeCheck_Perms(c *check.C) { 280func (s *Suite) Test_VartypeCheck_Perms(c *check.C) {
281 runVartypeChecks("CONF_FILES_PERMS", opAssignAppend, (*VartypeCheck).Perms, 281 runVartypeChecks("CONF_FILES_PERMS", opAssignAppend, (*VartypeCheck).Perms,
282 "root", 282 "root",
283 "${ROOT_USER}", 283 "${ROOT_USER}",
284 "ROOT_USER", 284 "ROOT_USER",
285 "${REAL_ROOT_USER}") 285 "${REAL_ROOT_USER}")
286 286
287 c.Check(s.Output(), equals, "ERROR: fname:2: ROOT_USER must not be used in permission definitions. Use REAL_ROOT_USER instead.\n") 287 c.Check(s.Output(), equals, "ERROR: fname:2: ROOT_USER must not be used in permission definitions. Use REAL_ROOT_USER instead.\n")
288} 288}
289 289
290func (s *Suite) TestVartypeCheck_PkgOptionsVar(c *check.C) { 290func (s *Suite) TestVartypeCheck_PkgOptionsVar(c *check.C) {
291 runVartypeChecks("PKG_OPTIONS_VAR.screen", opAssign, (*VartypeCheck).PkgOptionsVar, 291 runVartypeChecks("PKG_OPTIONS_VAR.screen", opAssign, (*VartypeCheck).PkgOptionsVar,
292 "PKG_OPTIONS.${PKGBASE}") 292 "PKG_OPTIONS.${PKGBASE}",
 293 "PKG_OPTIONS.anypkgbase")
293 294
294 c.Check(s.Output(), equals, "ERROR: fname:1: PKGBASE must not be used in PKG_OPTIONS_VAR.\n") 295 c.Check(s.Output(), equals, ""+
 296 "ERROR: fname:1: PKGBASE must not be used in PKG_OPTIONS_VAR.\n")
295} 297}
296 298
297func (s *Suite) TestVartypeCheck_PkgRevision(c *check.C) { 299func (s *Suite) TestVartypeCheck_PkgRevision(c *check.C) {
298 runVartypeChecks("PKGREVISION", opAssign, (*VartypeCheck).PkgRevision, 300 runVartypeChecks("PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
299 "3a") 301 "3a")
300 302
301 c.Check(s.Output(), equals, ""+ 303 c.Check(s.Output(), equals, ""+
302 "WARN: fname:1: PKGREVISION must be a positive integer number.\n"+ 304 "WARN: fname:1: PKGREVISION must be a positive integer number.\n"+
303 "ERROR: fname:1: PKGREVISION only makes sense directly in the package Makefile.\n") 305 "ERROR: fname:1: PKGREVISION only makes sense directly in the package Makefile.\n")
304 306
305 runVartypeChecksFname("Makefile", "PKGREVISION", opAssign, (*VartypeCheck).PkgRevision, 307 runVartypeChecksFname("Makefile", "PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
306 "3") 308 "3")
307 309

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

--- pkgsrc/pkgtools/pkglint/files/Attic/licenses.go 2016/06/05 11:24:32 1.4
+++ pkgsrc/pkgtools/pkglint/files/Attic/licenses.go 2016/07/07 12:09:27 1.5
@@ -46,16 +46,21 @@ func checklineLicense(line *MkLine, valu @@ -46,16 +46,21 @@ func checklineLicense(line *MkLine, valu
46 } 46 }
47 47
48 if !fileExists(licenseFile) { 48 if !fileExists(licenseFile) {
49 line.Warn1("License file %s does not exist.", cleanpath(licenseFile)) 49 line.Warn1("License file %s does not exist.", cleanpath(licenseFile))
50 } 50 }
51 51
52 switch license { 52 switch license {
53 case "fee-based-commercial-use", 53 case "fee-based-commercial-use",
54 "no-commercial-use", 54 "no-commercial-use",
55 "no-profit", 55 "no-profit",
56 "no-redistribution", 56 "no-redistribution",
57 "shareware": 57 "shareware":
58 line.Warn1("License %q is deprecated.", license) 58 line.Warn1("License %q is deprecated.", license)
 59 Explain(
 60 "Instead of using these deprecated licenses, extract the actual",
 61 "license from the package into the pkgsrc/licenses/ directory",
 62 "and define LICENSE to that file name. See the pkgsrc guide,",
 63 "keyword LICENSE, for more information.")
59 } 64 }
60 } 65 }
61} 66}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/substcontext_test.go 2016/01/12 01:02:49 1.4
+++ pkgsrc/pkgtools/pkglint/files/Attic/substcontext_test.go 2016/07/07 12:09:27 1.5
@@ -39,26 +39,43 @@ func (s *Suite) TestSubstContext_Complet @@ -39,26 +39,43 @@ func (s *Suite) TestSubstContext_Complet
39 ctx.Varassign(newSubstLine(13, "SUBST_SED.p=s,@PREFIX@,${PREFIX},g")) 39 ctx.Varassign(newSubstLine(13, "SUBST_SED.p=s,@PREFIX@,${PREFIX},g"))
40 40
41 c.Check(ctx.IsComplete(), equals, false) 41 c.Check(ctx.IsComplete(), equals, false)
42 42
43 ctx.Varassign(newSubstLine(14, "SUBST_STAGE.p=post-configure")) 43 ctx.Varassign(newSubstLine(14, "SUBST_STAGE.p=post-configure"))
44 44
45 c.Check(ctx.IsComplete(), equals, true) 45 c.Check(ctx.IsComplete(), equals, true)
46 46
47 ctx.Finish(newSubstLine(15, "")) 47 ctx.Finish(newSubstLine(15, ""))
48 48
49 c.Check(s.Output(), equals, "") 49 c.Check(s.Output(), equals, "")
50} 50}
51 51
 52func (s *Suite) Test_SubstContext_OPSYSVARS(c *check.C) {
 53 G.opts.WarnExtra = true
 54 ctx := new(SubstContext)
 55
 56 ctx.Varassign(newSubstLine(11, "SUBST_CLASSES.SunOS+=prefix"))
 57 ctx.Varassign(newSubstLine(12, "SUBST_CLASSES.NetBSD+=prefix"))
 58 ctx.Varassign(newSubstLine(13, "SUBST_FILES.prefix=Makefile"))
 59 ctx.Varassign(newSubstLine(14, "SUBST_SED.prefix=s,@PREFIX@,${PREFIX},g"))
 60 ctx.Varassign(newSubstLine(15, "SUBST_STAGE.prefix=post-configure"))
 61
 62 c.Check(ctx.IsComplete(), equals, true)
 63
 64 ctx.Finish(newSubstLine(15, ""))
 65
 66 c.Check(s.Output(), equals, "")
 67}
 68
52func (s *Suite) TestSubstContext_NoClass(c *check.C) { 69func (s *Suite) TestSubstContext_NoClass(c *check.C) {
53 s.UseCommandLine(c, "-Wextra") 70 s.UseCommandLine(c, "-Wextra")
54 ctx := new(SubstContext) 71 ctx := new(SubstContext)
55 72
56 ctx.Varassign(newSubstLine(10, "UNRELATED=anything")) 73 ctx.Varassign(newSubstLine(10, "UNRELATED=anything"))
57 ctx.Varassign(newSubstLine(11, "SUBST_FILES.repl+=Makefile.in")) 74 ctx.Varassign(newSubstLine(11, "SUBST_FILES.repl+=Makefile.in"))
58 ctx.Varassign(newSubstLine(12, "SUBST_SED.repl+=-e s,from,to,g")) 75 ctx.Varassign(newSubstLine(12, "SUBST_SED.repl+=-e s,from,to,g"))
59 ctx.Finish(newSubstLine(13, "")) 76 ctx.Finish(newSubstLine(13, ""))
60 77
61 c.Check(s.Output(), equals, ""+ 78 c.Check(s.Output(), equals, ""+
62 "WARN: Makefile:11: SUBST_CLASSES should come before the definition of \"SUBST_FILES.repl\".\n"+ 79 "WARN: Makefile:11: SUBST_CLASSES should come before the definition of \"SUBST_FILES.repl\".\n"+
63 "WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.\n") 80 "WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.\n")
64} 81}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mkline.go 2016/06/10 19:42:42 1.12
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkline.go 2016/07/07 12:09:27 1.13
@@ -420,27 +420,27 @@ func (mkline *MkLine) CheckVaruse(varuse @@ -420,27 +420,27 @@ func (mkline *MkLine) CheckVaruse(varuse
420 defer tracecall(mkline, varuse, vuc)() 420 defer tracecall(mkline, varuse, vuc)()
421 } 421 }
422 422
423 if varuse.IsExpression() { 423 if varuse.IsExpression() {
424 return 424 return
425 } 425 }
426 426
427 varname := varuse.varname 427 varname := varuse.varname
428 vartype := mkline.getVariableType(varname) 428 vartype := mkline.getVariableType(varname)
429 if G.opts.WarnExtra && 429 if G.opts.WarnExtra &&
430 (vartype == nil || vartype.guessed) && 430 (vartype == nil || vartype.guessed) &&
431 !varIsUsed(varname) && 431 !varIsUsed(varname) &&
432 !(G.Mk != nil && G.Mk.forVars[varname]) && 432 !(G.Mk != nil && G.Mk.forVars[varname]) &&
433 !hasPrefix(varname, "${") { 433 !containsVarRef(varname) {
434 mkline.Warn1("%s is used but not defined. Spelling mistake?", varname) 434 mkline.Warn1("%s is used but not defined. Spelling mistake?", varname)
435 } 435 }
436 436
437 mkline.CheckVarusePermissions(varname, vartype, vuc) 437 mkline.CheckVarusePermissions(varname, vartype, vuc)
438 438
439 if varname == "LOCALBASE" && !G.Infrastructure { 439 if varname == "LOCALBASE" && !G.Infrastructure {
440 mkline.WarnVaruseLocalbase() 440 mkline.WarnVaruseLocalbase()
441 } 441 }
442 442
443 needsQuoting := mkline.variableNeedsQuoting(varname, vartype, vuc) 443 needsQuoting := mkline.variableNeedsQuoting(varname, vartype, vuc)
444 444
445 if vuc.quoting == vucQuotFor { 445 if vuc.quoting == vucQuotFor {
446 mkline.checkVaruseFor(varname, vartype, needsQuoting) 446 mkline.checkVaruseFor(varname, vartype, needsQuoting)
@@ -989,106 +989,45 @@ func (mkline *MkLine) checkVarassignPlis @@ -989,106 +989,45 @@ func (mkline *MkLine) checkVarassignPlis
989 "\t.if ...", 989 "\t.if ...",
990 "\tMY_VAR?=\tyes", 990 "\tMY_VAR?=\tyes",
991 "\t.endif") 991 "\t.endif")
992 } 992 }
993 993
994 // Mark the variable as PLIST condition. This is later used in checkfile_PLIST. 994 // Mark the variable as PLIST condition. This is later used in checkfile_PLIST.
995 if G.Pkg != nil { 995 if G.Pkg != nil {
996 if m, plistVarname := match1(value, `(.+)=.*@comment.*`); m { 996 if m, plistVarname := match1(value, `(.+)=.*@comment.*`); m {
997 G.Pkg.plistSubstCond[plistVarname] = true 997 G.Pkg.plistSubstCond[plistVarname] = true
998 } 998 }
999 } 999 }
1000} 1000}
1001 1001
1002const reVarnamePlural = `^(?:` + 
1003 `.*[Ss]` + 
1004 `|.*LIST` + 
1005 `|.*_AWK` + 
1006 `|.*_ENV` + 
1007 `|.*_OVERRIDE` + 
1008 `|.*_PREREQ` + 
1009 `|.*_REQD` + 
1010 `|.*_SED` + 
1011 `|.*_SKIP` + 
1012 `|.*_SRC` + 
1013 `|.*_SUBST` + 
1014 `|.*_TARGET` + 
1015 `|.*_TMPL` + 
1016 `|BROKEN_EXCEPT_ON_PLATFORM` + 
1017 `|BROKEN_ON_PLATFORM` + 
1018 `|BUILDLINK_DEPMETHOD` + 
1019 `|BUILDLINK_LDADD` + 
1020 `|BUILDLINK_TRANSFORM` + 
1021 `|COMMENT` + 
1022 `|CRYPTO` + 
1023 `|DEINSTALL_TEMPLATE` + 
1024 `|EVAL_PREFIX` + 
1025 `|EXTRACT_ONLY` + 
1026 `|FETCH_MESSAGE` + 
1027 `|FIX_RPATH` + 
1028 `|GENERATE_PLIST` + 
1029 `|INSTALL_TEMPLATE` + 
1030 `|INTERACTIVE_STAGE` + 
1031 `|LICENSE` + 
1032 `|MASTER_SITE_.*` + 
1033 `|MASTER_SORT_REGEX` + 
1034 `|NOT_FOR_COMPILER` + 
1035 `|NOT_FOR_PLATFORM` + 
1036 `|ONLY_FOR_COMPILER` + 
1037 `|ONLY_FOR_PLATFORM` + 
1038 `|PERL5_PACKLIST` + 
1039 `|PLIST_CAT` + 
1040 `|PLIST_PRE` + 
1041 `|PKG_FAIL_REASON` + 
1042 `|PKG_SKIP_REASON` + 
1043 `|PREPEND_PATH` + 
1044 `|PYTHON_VERSIONS_INCOMPATIBLE` + 
1045 `|REPLACE_INTERPRETER` + 
1046 `|REPLACE_PERL` + 
1047 `|REPLACE_RUBY` + 
1048 `|RESTRICTED` + 
1049 `|SITES_.+` + 
1050 `|TOOLS_ALIASES\..+` + 
1051 `|TOOLS_BROKEN` + 
1052 `|TOOLS_CREATE` + 
1053 `|TOOLS_GNU_MISSING` + 
1054 `|TOOLS_NOOP` + 
1055 `)$` 
1056 
1057func (mkline *MkLine) CheckVartype(varname string, op MkOperator, value, comment string) { 1002func (mkline *MkLine) CheckVartype(varname string, op MkOperator, value, comment string) {
1058 if G.opts.Debug { 1003 if G.opts.Debug {
1059 defer tracecall(varname, op, value, comment)() 1004 defer tracecall(varname, op, value, comment)()
1060 } 1005 }
1061 1006
1062 if !G.opts.WarnTypes { 1007 if !G.opts.WarnTypes {
1063 return 1008 return
1064 } 1009 }
1065 1010
1066 varbase := varnameBase(varname) 
1067 vartype := mkline.getVariableType(varname) 1011 vartype := mkline.getVariableType(varname)
1068 1012
1069 if op == opAssignAppend { 1013 if op == opAssignAppend {
1070 if vartype != nil { 1014 if vartype != nil && !vartype.MayBeAppendedTo() {
1071 if !vartype.MayBeAppendedTo() { 1015 mkline.Warn0("The \"+=\" operator should only be used with lists.")
1072 mkline.Warn0("The \"+=\" operator should only be used with lists.") 
1073 } 
1074 } else if !hasPrefix(varbase, "_") && !matches(varbase, reVarnamePlural) { 
1075 mkline.Warn1("As %s is modified using \"+=\", its name should indicate plural.", varname) 
1076 } 1016 }
1077 } 1017 }
1078 1018
1079 switch { 1019 switch {
1080 case vartype == nil: 1020 case vartype == nil:
1081 // Cannot check anything if the type is not known. 
1082 if G.opts.Debug { 1021 if G.opts.Debug {
1083 traceStep1("Unchecked variable assignment for %s.", varname) 1022 traceStep1("Unchecked variable assignment for %s.", varname)
1084 } 1023 }
1085 1024
1086 case op == opAssignShell: 1025 case op == opAssignShell:
1087 if G.opts.Debug { 1026 if G.opts.Debug {
1088 traceStep1("Unchecked use of !=: %q", value) 1027 traceStep1("Unchecked use of !=: %q", value)
1089 } 1028 }
1090 1029
1091 case vartype.kindOfList == lkNone: 1030 case vartype.kindOfList == lkNone:
1092 mkline.CheckVartypePrimitive(varname, vartype.checker, op, value, comment, vartype.IsConsideredList(), vartype.guessed) 1031 mkline.CheckVartypePrimitive(varname, vartype.checker, op, value, comment, vartype.IsConsideredList(), vartype.guessed)
1093 1032
1094 case value == "": 1033 case value == "":
@@ -1370,27 +1309,27 @@ func matchMkCond(text string) (m bool, i @@ -1370,27 +1309,27 @@ func matchMkCond(text string) (m bool, i
1370 return 1309 return
1371} 1310}
1372 1311
1373type NeedsQuoting uint8 1312type NeedsQuoting uint8
1374 1313
1375const ( 1314const (
1376 nqNo NeedsQuoting = iota 1315 nqNo NeedsQuoting = iota
1377 nqYes 1316 nqYes
1378 nqDoesntMatter 1317 nqDoesntMatter
1379 nqDontKnow 1318 nqDontKnow
1380) 1319)
1381 1320
1382func (nq NeedsQuoting) String() string { 1321func (nq NeedsQuoting) String() string {
1383 return [...]string{"no", "yes", "doesn't matter", "don't known"}[nq] 1322 return [...]string{"no", "yes", "doesn't matter", "don't know"}[nq]
1384} 1323}
1385 1324
1386func (mkline *MkLine) variableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting NeedsQuoting) { 1325func (mkline *MkLine) variableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting NeedsQuoting) {
1387 if G.opts.Debug { 1326 if G.opts.Debug {
1388 defer tracecall(varname, vartype, vuc, "=>", &needsQuoting)() 1327 defer tracecall(varname, vartype, vuc, "=>", &needsQuoting)()
1389 } 1328 }
1390 1329
1391 if vartype == nil || vuc.vartype == nil { 1330 if vartype == nil || vuc.vartype == nil {
1392 return nqDontKnow 1331 return nqDontKnow
1393 } 1332 }
1394 1333
1395 if vartype.checker.IsEnum() || vartype.IsBasicSafe() { 1334 if vartype.checker.IsEnum() || vartype.IsBasicSafe() {
1396 if vartype.kindOfList == lkNone { 1335 if vartype.kindOfList == lkNone {
@@ -1520,27 +1459,27 @@ func (mkline *MkLine) getVariableType(va @@ -1520,27 +1459,27 @@ func (mkline *MkLine) getVariableType(va
1520 if m, toolvarname := match1(varname, `^TOOLS_(.*)`); m && G.globalData.Tools.byVarname[toolvarname] != nil { 1459 if m, toolvarname := match1(varname, `^TOOLS_(.*)`); m && G.globalData.Tools.byVarname[toolvarname] != nil {
1521 return &Vartype{lkNone, CheckvarPathname, []AclEntry{{"*", aclpUse}}, false} 1460 return &Vartype{lkNone, CheckvarPathname, []AclEntry{{"*", aclpUse}}, false}
1522 } 1461 }
1523 1462
1524 allowAll := []AclEntry{{"*", aclpAll}} 1463 allowAll := []AclEntry{{"*", aclpAll}}
1525 allowRuntime := []AclEntry{{"*", aclpAllRuntime}} 1464 allowRuntime := []AclEntry{{"*", aclpAllRuntime}}
1526 1465
1527 // Guess the datatype of the variable based on naming conventions. 1466 // Guess the datatype of the variable based on naming conventions.
1528 varbase := varnameBase(varname) 1467 varbase := varnameBase(varname)
1529 var gtype *Vartype 1468 var gtype *Vartype
1530 switch { 1469 switch {
1531 case hasSuffix(varbase, "DIRS"): 1470 case hasSuffix(varbase, "DIRS"):
1532 gtype = &Vartype{lkShell, CheckvarPathmask, allowRuntime, true} 1471 gtype = &Vartype{lkShell, CheckvarPathmask, allowRuntime, true}
1533 case hasSuffix(varbase, "DIR"), hasSuffix(varname, "_HOME"): 1472 case hasSuffix(varbase, "DIR") && !hasSuffix(varbase, "DESTDIR"), hasSuffix(varname, "_HOME"):
1534 gtype = &Vartype{lkNone, CheckvarPathname, allowRuntime, true} 1473 gtype = &Vartype{lkNone, CheckvarPathname, allowRuntime, true}
1535 case hasSuffix(varbase, "FILES"): 1474 case hasSuffix(varbase, "FILES"):
1536 gtype = &Vartype{lkShell, CheckvarPathmask, allowRuntime, true} 1475 gtype = &Vartype{lkShell, CheckvarPathmask, allowRuntime, true}
1537 case hasSuffix(varbase, "FILE"): 1476 case hasSuffix(varbase, "FILE"):
1538 gtype = &Vartype{lkNone, CheckvarPathname, allowRuntime, true} 1477 gtype = &Vartype{lkNone, CheckvarPathname, allowRuntime, true}
1539 case hasSuffix(varbase, "PATH"): 1478 case hasSuffix(varbase, "PATH"):
1540 gtype = &Vartype{lkNone, CheckvarPathlist, allowRuntime, true} 1479 gtype = &Vartype{lkNone, CheckvarPathlist, allowRuntime, true}
1541 case hasSuffix(varbase, "PATHS"): 1480 case hasSuffix(varbase, "PATHS"):
1542 gtype = &Vartype{lkShell, CheckvarPathname, allowRuntime, true} 1481 gtype = &Vartype{lkShell, CheckvarPathname, allowRuntime, true}
1543 case hasSuffix(varbase, "_USER"): 1482 case hasSuffix(varbase, "_USER"):
1544 gtype = &Vartype{lkNone, CheckvarUserGroupName, allowAll, true} 1483 gtype = &Vartype{lkNone, CheckvarUserGroupName, allowAll, true}
1545 case hasSuffix(varbase, "_GROUP"): 1484 case hasSuffix(varbase, "_GROUP"):
1546 gtype = &Vartype{lkNone, CheckvarUserGroupName, allowAll, true} 1485 gtype = &Vartype{lkNone, CheckvarUserGroupName, allowAll, true}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mkline_test.go 2016/06/05 11:24:32 1.12
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkline_test.go 2016/07/07 12:09:27 1.13
@@ -282,36 +282,31 @@ func (s *Suite) TestVarUseContext_ToStri @@ -282,36 +282,31 @@ func (s *Suite) TestVarUseContext_ToStri
282 G.globalData.InitVartypes() 282 G.globalData.InitVartypes()
283 mkline := NewMkLine(NewLine("fname", 1, "# dummy", nil)) 283 mkline := NewMkLine(NewLine("fname", 1, "# dummy", nil))
284 vartype := mkline.getVariableType("PKGNAME") 284 vartype := mkline.getVariableType("PKGNAME")
285 vuc := &VarUseContext{vartype, vucTimeUnknown, vucQuotBackt, vucExtentWord} 285 vuc := &VarUseContext{vartype, vucTimeUnknown, vucQuotBackt, vucExtentWord}
286 286
287 c.Check(vuc.String(), equals, "(PkgName time:unknown quoting:backt extent:word)") 287 c.Check(vuc.String(), equals, "(PkgName time:unknown quoting:backt extent:word)")
288} 288}
289 289
290func (s *Suite) TestMkLine_(c *check.C) { 290func (s *Suite) TestMkLine_(c *check.C) {
291 G.globalData.InitVartypes() 291 G.globalData.InitVartypes()
292 292
293 G.Mk = s.NewMkLines("Makefile", 293 G.Mk = s.NewMkLines("Makefile",
294 "# $"+"NetBSD$", 294 "# $"+"NetBSD$",
295 "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib", // From math/clisp-pari/Makefile, rev. 1.8 295 "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8
296 "var+=value") 
297 296
298 G.Mk.mklines[1].checkVarassign() 297 G.Mk.mklines[1].checkVarassign()
299 G.Mk.mklines[2].checkVarassign() 
300 298
301 c.Check(s.Output(), equals, ""+ 299 c.Check(s.Output(), equals, "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?\n")
302 "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?\n"+ 
303 "WARN: Makefile:3: As var is modified using \"+=\", its name should indicate plural.\n"+ 
304 "WARN: Makefile:3: var is defined but not used. Spelling mistake?\n") 
305} 300}
306 301
307// In variable assignments, a plain '#' introduces a line comment, unless 302// In variable assignments, a plain '#' introduces a line comment, unless
308// it is escaped by a backslash. In shell commands, on the other hand, it 303// it is escaped by a backslash. In shell commands, on the other hand, it
309// is interpreted literally. 304// is interpreted literally.
310func (s *Suite) TestParselineMk(c *check.C) { 305func (s *Suite) TestParselineMk(c *check.C) {
311 line1 := NewMkLine(NewLine("fname", 1, "SED_CMD=\t's,\\#,hash,g'", nil)) 306 line1 := NewMkLine(NewLine("fname", 1, "SED_CMD=\t's,\\#,hash,g'", nil))
312 307
313 c.Check(line1.Varname(), equals, "SED_CMD") 308 c.Check(line1.Varname(), equals, "SED_CMD")
314 c.Check(line1.Value(), equals, "'s,#,hash,g'") 309 c.Check(line1.Value(), equals, "'s,#,hash,g'")
315 310
316 line2 := NewMkLine(NewLine("fname", 1, "\tsed -e 's,\\#,hash,g'", nil)) 311 line2 := NewMkLine(NewLine("fname", 1, "\tsed -e 's,\\#,hash,g'", nil))
317 312
@@ -669,26 +664,44 @@ func (s *Suite) TestMkLine_variableNeeds @@ -669,26 +664,44 @@ func (s *Suite) TestMkLine_variableNeeds
669func (s *Suite) TestMkLine_variableNeedsQuoting_18(c *check.C) { 664func (s *Suite) TestMkLine_variableNeedsQuoting_18(c *check.C) {
670 s.UseCommandLine(c, "-Wall") 665 s.UseCommandLine(c, "-Wall")
671 s.RegisterMasterSite("MASTER_SITE_GNOME", "http://ftp.gnome.org/") 666 s.RegisterMasterSite("MASTER_SITE_GNOME", "http://ftp.gnome.org/")
672 G.globalData.InitVartypes() 667 G.globalData.InitVartypes()
673 G.Mk = s.NewMkLines("x11/gtk3/Makefile", 668 G.Mk = s.NewMkLines("x11/gtk3/Makefile",
674 "# $"+"NetBSD$", 669 "# $"+"NetBSD$",
675 "MASTER_SITES=\tftp://ftp.gtk.org/${PKGNAME}/ ${MASTER_SITE_GNOME:=subdir/}") 670 "MASTER_SITES=\tftp://ftp.gtk.org/${PKGNAME}/ ${MASTER_SITE_GNOME:=subdir/}")
676 671
677 G.Mk.mklines[1].checkVarassignVaruse() 672 G.Mk.mklines[1].checkVarassignVaruse()
678 673
679 c.Check(s.Output(), equals, "") // Don’t warn about missing :Q operators. 674 c.Check(s.Output(), equals, "") // Don’t warn about missing :Q operators.
680} 675}
681 676
 677func (s *Suite) Test_MkLine_variableNeedsQuoting_tool_in_CONFIGURE_ENV(c *check.C) {
 678 s.UseCommandLine(c, "-Wall")
 679 G.globalData.InitVartypes()
 680 G.globalData.Tools = NewToolRegistry()
 681 G.globalData.Tools.RegisterVarname("tar", "TAR")
 682
 683 mklines := s.NewMkLines("Makefile",
 684 "# $"+"NetBSD$",
 685 "",
 686 "CONFIGURE_ENV+=\tSYS_TAR_COMMAND_PATH=${TOOLS_TAR:Q}")
 687
 688 mklines.mklines[2].checkVarassignVaruse()
 689
 690 // The TOOLS_* variables only contain the path to the tool,
 691 // without any additional arguments that might be necessary.
 692 c.Check(s.Output(), equals, "NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.\n")
 693}
 694
682func (s *Suite) Test_MkLine_Varuse_Modifier_L(c *check.C) { 695func (s *Suite) Test_MkLine_Varuse_Modifier_L(c *check.C) {
683 s.UseCommandLine(c, "-Wall") 696 s.UseCommandLine(c, "-Wall")
684 G.globalData.InitVartypes() 697 G.globalData.InitVartypes()
685 G.Mk = s.NewMkLines("x11/xkeyboard-config/Makefile", 698 G.Mk = s.NewMkLines("x11/xkeyboard-config/Makefile",
686 "FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}") 699 "FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}")
687 700
688 G.Mk.mklines[0].Check() 701 G.Mk.mklines[0].Check()
689 702
690 c.Check(s.Output(), equals, "") // Don’t warn that ${XKBBASE}/xkbcomp is used but not defined. 703 c.Check(s.Output(), equals, "") // Don’t warn that ${XKBBASE}/xkbcomp is used but not defined.
691} 704}
692 705
693func (s *Suite) Test_MkLine_Cond_ShellCommand(c *check.C) { 706func (s *Suite) Test_MkLine_Cond_ShellCommand(c *check.C) {
694 s.UseCommandLine(c, "-Wall") 707 s.UseCommandLine(c, "-Wall")
@@ -761,13 +774,38 @@ func (s *Suite) Test_MkLine_ShellCommand @@ -761,13 +774,38 @@ func (s *Suite) Test_MkLine_ShellCommand
761 774
762func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) { 775func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) {
763 s.UseCommandLine(c, "-Wall") 776 s.UseCommandLine(c, "-Wall")
764 G.globalData.InitVartypes() 777 G.globalData.InitVartypes()
765 mklines := s.NewMkLines("x11/motif/Makefile", 778 mklines := s.NewMkLines("x11/motif/Makefile",
766 "# $"+"NetBSD$", 779 "# $"+"NetBSD$",
767 "post-patch:", 780 "post-patch:",
768 "\tfiles=`${GREP} -l \".fB$${name}.fP(3)\" *.3`") 781 "\tfiles=`${GREP} -l \".fB$${name}.fP(3)\" *.3`")
769 782
770 mklines.Check() 783 mklines.Check()
771 784
772 c.Check(s.Output(), equals, "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".\n") // No parse errors. 785 c.Check(s.Output(), equals, "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".\n") // No parse errors.
773} 786}
 787
 788// See PR 46570, Ctrl+F "3. In lang/perl5".
 789func (s *Suite) Test_MkLine_getVariableType(c *check.C) {
 790 mkline := NewMkLine(dummyLine)
 791
 792 c.Check(mkline.getVariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil)
 793 c.Check(mkline.getVariableType("SOME_DIR").guessed, equals, true)
 794 c.Check(mkline.getVariableType("SOMEDIR").guessed, equals, true)
 795}
 796
 797// See PR 46570, Ctrl+F "4. Shell quoting".
 798// Pkglint is correct, since this definition for CPPFLAGS should be
 799// seen by the shell as three words, not one word.
 800func (s *Suite) Test_MkLine_Cflags(c *check.C) {
 801 G.globalData.InitVartypes()
 802 mklines := s.NewMkLines("Makefile",
 803 "# $"+"NetBSD$",
 804 "CPPFLAGS.SunOS+=\t-DPIPECOMMAND=\\\"/usr/sbin/sendmail -bs %s\\\"")
 805
 806 mklines.Check()
 807
 808 c.Check(s.Output(), equals, ""+
 809 "WARN: Makefile:2: Unknown compiler flag \"-bs\".\n"+
 810 "WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.\n")
 811}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mklines_test.go 2016/06/10 19:42:42 1.5
+++ pkgsrc/pkgtools/pkglint/files/Attic/mklines_test.go 2016/07/07 12:09:27 1.6
@@ -1,19 +1,21 @@ @@ -1,19 +1,21 @@
1package main 1package main
2 2
3import ( 3import (
4 check "gopkg.in/check.v1" 4 check "gopkg.in/check.v1"
5) 5)
6 6
 7const mkrcsid = "# $" + "NetBSD$"
 8
7func (s *Suite) TestMkLines_AutofixConditionalIndentation(c *check.C) { 9func (s *Suite) TestMkLines_AutofixConditionalIndentation(c *check.C) {
8 s.UseCommandLine(c, "--autofix", "-Wspace") 10 s.UseCommandLine(c, "--autofix", "-Wspace")
9 tmpfile := s.CreateTmpFile(c, "fname.mk", "") 11 tmpfile := s.CreateTmpFile(c, "fname.mk", "")
10 mklines := s.NewMkLines(tmpfile, 12 mklines := s.NewMkLines(tmpfile,
11 "# $"+"NetBSD$", 13 "# $"+"NetBSD$",
12 ".if defined(A)", 14 ".if defined(A)",
13 ".for a in ${A}", 15 ".for a in ${A}",
14 ".if defined(C)", 16 ".if defined(C)",
15 ".endif", 17 ".endif",
16 ".endfor", 18 ".endfor",
17 ".endif") 19 ".endif")
18 20
19 mklines.Check() 21 mklines.Check()
@@ -248,13 +250,64 @@ func (s *Suite) Test_MkLines_LoopModifie @@ -248,13 +250,64 @@ func (s *Suite) Test_MkLines_LoopModifie
248func (s *Suite) Test_MkLines_Indentation_DependsOn(c *check.C) { 250func (s *Suite) Test_MkLines_Indentation_DependsOn(c *check.C) {
249 G.globalData.InitVartypes() 251 G.globalData.InitVartypes()
250 mklines := s.NewMkLines("Makefile", 252 mklines := s.NewMkLines("Makefile",
251 "# $"+"NetBSD$", 253 "# $"+"NetBSD$",
252 "PKG_SKIP_REASON+=\t\"Fails everywhere\"", 254 "PKG_SKIP_REASON+=\t\"Fails everywhere\"",
253 ".if ${OPSYS} == \"Cygwin\"", 255 ".if ${OPSYS} == \"Cygwin\"",
254 "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"", 256 "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"",
255 ".endif") 257 ".endif")
256 258
257 mklines.Check() 259 mklines.Check()
258 260
259 c.Check(s.Output(), equals, "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.\n") 261 c.Check(s.Output(), equals, "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.\n")
260} 262}
 263
 264// PR 46570, item "15. net/uucp/Makefile has a make loop"
 265func (s *Suite) Test_MkLines_indirect_variables(c *check.C) {
 266 s.UseCommandLine(c, "-Wall")
 267 mklines := s.NewMkLines("net/uucp/Makefile",
 268 "# $"+"NetBSD$",
 269 "",
 270 "post-configure:",
 271 ".for var in MAIL_PROGRAM CMDPATH",
 272 "\t"+`${RUN} ${ECHO} "#define ${var} \""${UUCP_${var}}"\"`,
 273 ".endfor")
 274
 275 mklines.Check()
 276
 277 // No warning about UUCP_${var} being used but not defined.
 278 c.Check(s.Output(), equals, ""+
 279 "WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".\n")
 280}
 281
 282func (s *Suite) Test_MkLines_Check_list_variable_as_part_of_word(c *check.C) {
 283 s.UseCommandLine(c, "-Wall")
 284 mklines := s.NewMkLines("converters/chef/Makefile",
 285 mkrcsid,
 286 "\tcd ${WRKSRC} && tr '\\r' '\\n' < ${DISTDIR}/${DIST_SUBDIR}/${DISTFILES} > chef.l")
 287
 288 mklines.Check()
 289
 290 c.Check(s.Output(), equals, ""+
 291 "WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".\n"+
 292 "WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.\n")
 293}
 294
 295func (s *Suite) Test_MkLines_Check_absolute_pathname_depending_on_OPSYS(c *check.C) {
 296 s.UseCommandLine(c, "-Wall")
 297 G.globalData.InitVartypes()
 298 mklines := s.NewMkLines("games/heretic2-demo/Makefile",
 299 mkrcsid,
 300 ".if ${OPSYS} == \"DragonFly\"",
 301 "TOOLS_PLATFORM.gtar=\t/usr/bin/bsdtar",
 302 ".endif",
 303 "TOOLS_PLATFORM.gtar=\t/usr/bin/bsdtar")
 304
 305 mklines.Check()
 306
 307 // No warning about an unknown shell command in line 3,
 308 // since that line depends on OPSYS.
 309 c.Check(s.Output(), equals, ""+
 310 "WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.\n"+
 311 "WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.\n"+
 312 "WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".\n")
 313}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/plist.go 2016/06/05 11:24:32 1.5
+++ pkgsrc/pkgtools/pkglint/files/Attic/plist.go 2016/07/07 12:09:27 1.6
@@ -316,27 +316,28 @@ func (ck *PlistChecker) checkpathSbin(pl @@ -316,27 +316,28 @@ func (ck *PlistChecker) checkpathSbin(pl
316 pline.line.Warn1("Manual page missing for sbin/%s.", binname) 316 pline.line.Warn1("Manual page missing for sbin/%s.", binname)
317 Explain( 317 Explain(
318 "All programs that can be run directly by the user should have a", 318 "All programs that can be run directly by the user should have a",
319 "manual page for quick reference. The programs in the sbin/", 319 "manual page for quick reference. The programs in the sbin/",
320 "directory should have corresponding manual pages in section 8", 320 "directory should have corresponding manual pages in section 8",
321 "(filename program.8), while the programs in the bin/ directory", 321 "(filename program.8), while the programs in the bin/ directory",
322 "have their manual pages in section 1.") 322 "have their manual pages in section 1.")
323 } 323 }
324} 324}
325 325
326func (ck *PlistChecker) checkpathShare(pline *PlistLine) { 326func (ck *PlistChecker) checkpathShare(pline *PlistLine) {
327 line, text := pline.line, pline.text 327 line, text := pline.line, pline.text
328 switch { 328 switch {
329 case hasPrefix(text, "share/applications/") && hasSuffix(text, ".desktop"): 329 // Disabled due to PR 46570, item "10. It should stop".
 330 case false && hasPrefix(text, "share/applications/") && hasSuffix(text, ".desktop"):
330 f := "../../sysutils/desktop-file-utils/desktopdb.mk" 331 f := "../../sysutils/desktop-file-utils/desktopdb.mk"
331 if G.opts.WarnExtra && G.Pkg != nil && G.Pkg.included[f] == nil { 332 if G.opts.WarnExtra && G.Pkg != nil && G.Pkg.included[f] == nil {
332 line.Warn1("Packages that install a .desktop entry should .include %q.", f) 333 line.Warn1("Packages that install a .desktop entry should .include %q.", f)
333 Explain3( 334 Explain3(
334 "If *.desktop files contain MimeType keys, the global MIME type", 335 "If *.desktop files contain MimeType keys, the global MIME type",
335 "registry must be updated by desktop-file-utils. Otherwise, this", 336 "registry must be updated by desktop-file-utils. Otherwise, this",
336 "warning is harmless.") 337 "warning is harmless.")
337 } 338 }
338 339
339 case hasPrefix(text, "share/icons/hicolor/") && G.Pkg != nil && G.Pkg.Pkgpath != "graphics/hicolor-icon-theme": 340 case hasPrefix(text, "share/icons/hicolor/") && G.Pkg != nil && G.Pkg.Pkgpath != "graphics/hicolor-icon-theme":
340 f := "../../graphics/hicolor-icon-theme/buildlink3.mk" 341 f := "../../graphics/hicolor-icon-theme/buildlink3.mk"
341 if G.Pkg.included[f] == nil { 342 if G.Pkg.included[f] == nil {
342 line.Error1("Packages that install hicolor icons must include %q in the Makefile.", f) 343 line.Error1("Packages that install hicolor icons must include %q in the Makefile.", f)

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

--- pkgsrc/pkgtools/pkglint/files/Attic/plist_test.go 2016/01/27 21:55:51 1.5
+++ pkgsrc/pkgtools/pkglint/files/Attic/plist_test.go 2016/07/07 12:09:27 1.6
@@ -135,26 +135,29 @@ func (s *Suite) TestPlistChecker_sort(c  @@ -135,26 +135,29 @@ func (s *Suite) TestPlistChecker_sort(c
135 "b\n"+ 135 "b\n"+
136 "${PLIST.one}bin/program\n"+ // Conditionals are ignored while sorting 136 "${PLIST.one}bin/program\n"+ // Conditionals are ignored while sorting
137 "${PKGMANDIR}/man1/program.1\n"+ // Stays below the previous line 137 "${PKGMANDIR}/man1/program.1\n"+ // Stays below the previous line
138 "${PLIST.two}bin/program2\n"+ 138 "${PLIST.two}bin/program2\n"+
139 "ddd\n"+ 139 "ddd\n"+
140 "@exec echo \"after ddd\"\n"+ // Stays below the previous line 140 "@exec echo \"after ddd\"\n"+ // Stays below the previous line
141 "lib/after.la\n"+ 141 "lib/after.la\n"+
142 "@exec echo \"after lib/after.la\"\n"+ 142 "@exec echo \"after lib/after.la\"\n"+
143 "lib/before.la\n"+ 143 "lib/before.la\n"+
144 "sbin/program\n") 144 "sbin/program\n")
145} 145}
146 146
147func (s *Suite) TestPlistChecker_checkpathShare_Desktop(c *check.C) { 147func (s *Suite) TestPlistChecker_checkpathShare_Desktop(c *check.C) {
 148 // Disabled due to PR 46570, item "10. It should stop".
 149 return
 150
148 s.UseCommandLine(c, "-Wextra") 151 s.UseCommandLine(c, "-Wextra")
149 G.Pkg = NewPackage("category/pkgpath") 152 G.Pkg = NewPackage("category/pkgpath")
150 153
151 ChecklinesPlist(s.NewLines("PLIST", 154 ChecklinesPlist(s.NewLines("PLIST",
152 "@comment $"+"NetBSD$", 155 "@comment $"+"NetBSD$",
153 "share/applications/pkgbase.desktop")) 156 "share/applications/pkgbase.desktop"))
154 157
155 c.Check(s.Output(), equals, "WARN: PLIST:2: Packages that install a .desktop entry should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".\n") 158 c.Check(s.Output(), equals, "WARN: PLIST:2: Packages that install a .desktop entry should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".\n")
156} 159}
157 160
158func (s *Suite) TestPlistChecker_checkpathMan_gz(c *check.C) { 161func (s *Suite) TestPlistChecker_checkpathMan_gz(c *check.C) {
159 G.Pkg = NewPackage("category/pkgbase") 162 G.Pkg = NewPackage("category/pkgbase")
160 163

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

--- pkgsrc/pkgtools/pkglint/files/Attic/substcontext.go 2016/01/12 01:02:49 1.5
+++ pkgsrc/pkgtools/pkglint/files/Attic/substcontext.go 2016/07/07 12:09:27 1.6
@@ -10,32 +10,32 @@ type SubstContext struct { @@ -10,32 +10,32 @@ type SubstContext struct {
10 sed []string 10 sed []string
11 vars []string 11 vars []string
12 filterCmd string 12 filterCmd string
13} 13}
14 14
15func (ctx *SubstContext) Varassign(mkline *MkLine) { 15func (ctx *SubstContext) Varassign(mkline *MkLine) {
16 if !G.opts.WarnExtra { 16 if !G.opts.WarnExtra {
17 return 17 return
18 } 18 }
19 19
20 varname := mkline.Varname() 20 varname := mkline.Varname()
21 op := mkline.Op() 21 op := mkline.Op()
22 value := mkline.Value() 22 value := mkline.Value()
23 if varname == "SUBST_CLASSES" { 23 if varname == "SUBST_CLASSES" || hasPrefix(varname, "SUBST_CLASSES.") {
24 classes := splitOnSpace(value) 24 classes := splitOnSpace(value)
25 if len(classes) > 1 { 25 if len(classes) > 1 {
26 mkline.Warn0("Please add only one class at a time to SUBST_CLASSES.") 26 mkline.Warn0("Please add only one class at a time to SUBST_CLASSES.")
27 } 27 }
28 if ctx.id != "" { 28 if ctx.id != "" && ctx.id != classes[0] {
29 mkline.Warn0("SUBST_CLASSES should only appear once in a SUBST block.") 29 mkline.Warn0("SUBST_CLASSES should only appear once in a SUBST block.")
30 } 30 }
31 ctx.id = classes[0] 31 ctx.id = classes[0]
32 return 32 return
33 } 33 }
34 34
35 m, varbase, varparam := match2(varname, `^(SUBST_(?:STAGE|MESSAGE|FILES|SED|VARS|FILTER_CMD))\.([\-\w_]+)$`) 35 m, varbase, varparam := match2(varname, `^(SUBST_(?:STAGE|MESSAGE|FILES|SED|VARS|FILTER_CMD))\.([\-\w_]+)$`)
36 if !m { 36 if !m {
37 if ctx.id != "" { 37 if ctx.id != "" {
38 mkline.Warn1("Foreign variable %q in SUBST block.", varname) 38 mkline.Warn1("Foreign variable %q in SUBST block.", varname)
39 } 39 }
40 return 40 return
41 } 41 }

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mkparser.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkparser.go 2016/07/07 12:09:27 1.2
@@ -17,41 +17,36 @@ func (p *MkParser) MkTokens() []*MkToken @@ -17,41 +17,36 @@ func (p *MkParser) MkTokens() []*MkToken
17 17
18 var tokens []*MkToken 18 var tokens []*MkToken
19 for !p.EOF() { 19 for !p.EOF() {
20 if repl.AdvanceStr("#") { 20 if repl.AdvanceStr("#") {
21 repl.AdvanceRest() 21 repl.AdvanceRest()
22 } 22 }
23 23
24 mark := repl.Mark() 24 mark := repl.Mark()
25 if varuse := p.VarUse(); varuse != nil { 25 if varuse := p.VarUse(); varuse != nil {
26 tokens = append(tokens, &MkToken{Text: repl.Since(mark), Varuse: varuse}) 26 tokens = append(tokens, &MkToken{Text: repl.Since(mark), Varuse: varuse})
27 continue 27 continue
28 } 28 }
29 29
30 needsReplace := false 
31 again: 30 again:
32 dollar := strings.IndexByte(repl.rest, '$') 31 dollar := strings.IndexByte(repl.rest, '$')
33 if dollar == -1 { 32 if dollar == -1 {
34 dollar = len(repl.rest) 33 dollar = len(repl.rest)
35 } 34 }
36 repl.Skip(dollar) 35 repl.Skip(dollar)
37 if repl.AdvanceStr("$$") { 36 if repl.AdvanceStr("$$") {
38 needsReplace = true 
39 goto again 37 goto again
40 } 38 }
41 text := repl.Since(mark) 39 text := repl.Since(mark)
42 if needsReplace { 
43 text = strings.Replace(text, "$$", "$", -1) 
44 } 
45 if text != "" { 40 if text != "" {
46 tokens = append(tokens, &MkToken{Text: text}) 41 tokens = append(tokens, &MkToken{Text: text})
47 continue 42 continue
48 } 43 }
49 44
50 break 45 break
51 } 46 }
52 return tokens 47 return tokens
53} 48}
54 49
55func (p *MkParser) VarUse() *MkVarUse { 50func (p *MkParser) VarUse() *MkVarUse {
56 repl := p.repl 51 repl := p.repl
57 52
@@ -81,27 +76,27 @@ func (p *MkParser) VarUse() *MkVarUse { @@ -81,27 +76,27 @@ func (p *MkParser) VarUse() *MkVarUse {
81 if repl.AdvanceStr(closing) { 76 if repl.AdvanceStr(closing) {
82 return &MkVarUse{varexpr, modifiers} 77 return &MkVarUse{varexpr, modifiers}
83 } 78 }
84 } 79 }
85 repl.Reset(mark) 80 repl.Reset(mark)
86 } 81 }
87 82
88 if repl.AdvanceStr("$@") { 83 if repl.AdvanceStr("$@") {
89 return &MkVarUse{"@", nil} 84 return &MkVarUse{"@", nil}
90 } 85 }
91 if repl.AdvanceStr("$<") { 86 if repl.AdvanceStr("$<") {
92 return &MkVarUse{"<", nil} 87 return &MkVarUse{"<", nil}
93 } 88 }
94 if repl.AdvanceRegexp(`^\$(\w)`) { 89 if repl.PeekByte() == '$' && repl.AdvanceRegexp(`^\$(\w)`) {
95 varname := repl.m[1] 90 varname := repl.m[1]
96 if p.EmitWarnings { 91 if p.EmitWarnings {
97 p.Line.Warn1("$%[1]s is ambiguous. Use ${%[1]s} if you mean a Makefile variable or $$%[1]s if you mean a shell variable.", varname) 92 p.Line.Warn1("$%[1]s is ambiguous. Use ${%[1]s} if you mean a Makefile variable or $$%[1]s if you mean a shell variable.", varname)
98 } 93 }
99 return &MkVarUse{varname, nil} 94 return &MkVarUse{varname, nil}
100 } 95 }
101 return nil 96 return nil
102} 97}
103 98
104func (p *MkParser) VarUseModifiers(varname, closing string) []string { 99func (p *MkParser) VarUseModifiers(varname, closing string) []string {
105 repl := p.repl 100 repl := p.repl
106 101
107 var modifiers []string 102 var modifiers []string

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mkparser_test.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkparser_test.go 2016/07/07 12:09:27 1.2
@@ -27,27 +27,27 @@ func (s *Suite) Test_MkParser_MkTokens(c @@ -27,27 +27,27 @@ func (s *Suite) Test_MkParser_MkTokens(c
27 for _, modifier := range modifiers { 27 for _, modifier := range modifiers {
28 text += ":" + modifier 28 text += ":" + modifier
29 } 29 }
30 text += "}" 30 text += "}"
31 return &MkToken{Text: text, Varuse: &MkVarUse{varname: varname, modifiers: modifiers}} 31 return &MkToken{Text: text, Varuse: &MkVarUse{varname: varname, modifiers: modifiers}}
32 } 32 }
33 varuseText := func(text, varname string, modifiers ...string) *MkToken { 33 varuseText := func(text, varname string, modifiers ...string) *MkToken {
34 return &MkToken{Text: text, Varuse: &MkVarUse{varname: varname, modifiers: modifiers}} 34 return &MkToken{Text: text, Varuse: &MkVarUse{varname: varname, modifiers: modifiers}}
35 } 35 }
36 36
37 check("literal", literal("literal")) 37 check("literal", literal("literal"))
38 check("\\/share\\/ { print \"share directory\" }", literal("\\/share\\/ { print \"share directory\" }")) 38 check("\\/share\\/ { print \"share directory\" }", literal("\\/share\\/ { print \"share directory\" }"))
39 check("find . -name \\*.orig -o -name \\*.pre", literal("find . -name \\*.orig -o -name \\*.pre")) 39 check("find . -name \\*.orig -o -name \\*.pre", literal("find . -name \\*.orig -o -name \\*.pre"))
40 check("-e 's|\\$${EC2_HOME.*}|EC2_HOME}|g'", literal("-e 's|\\${EC2_HOME.*}|EC2_HOME}|g'")) 40 check("-e 's|\\$${EC2_HOME.*}|EC2_HOME}|g'", literal("-e 's|\\$${EC2_HOME.*}|EC2_HOME}|g'"))
41 41
42 check("${VARIABLE}", varuse("VARIABLE")) 42 check("${VARIABLE}", varuse("VARIABLE"))
43 check("${VARIABLE.param}", varuse("VARIABLE.param")) 43 check("${VARIABLE.param}", varuse("VARIABLE.param"))
44 check("${VARIABLE.${param}}", varuse("VARIABLE.${param}")) 44 check("${VARIABLE.${param}}", varuse("VARIABLE.${param}"))
45 check("${VARIABLE.hicolor-icon-theme}", varuse("VARIABLE.hicolor-icon-theme")) 45 check("${VARIABLE.hicolor-icon-theme}", varuse("VARIABLE.hicolor-icon-theme"))
46 check("${VARIABLE.gtk+extra}", varuse("VARIABLE.gtk+extra")) 46 check("${VARIABLE.gtk+extra}", varuse("VARIABLE.gtk+extra"))
47 check("${VARIABLE:S/old/new/}", varuse("VARIABLE", "S/old/new/")) 47 check("${VARIABLE:S/old/new/}", varuse("VARIABLE", "S/old/new/"))
48 check("${GNUSTEP_LFLAGS:S/-L//g}", varuse("GNUSTEP_LFLAGS", "S/-L//g")) 48 check("${GNUSTEP_LFLAGS:S/-L//g}", varuse("GNUSTEP_LFLAGS", "S/-L//g"))
49 check("${SUSE_VERSION:S/.//}", varuse("SUSE_VERSION", "S/.//")) 49 check("${SUSE_VERSION:S/.//}", varuse("SUSE_VERSION", "S/.//"))
50 check("${MASTER_SITE_GNOME:=sources/alacarte/0.13/}", varuse("MASTER_SITE_GNOME", "=sources/alacarte/0.13/")) 50 check("${MASTER_SITE_GNOME:=sources/alacarte/0.13/}", varuse("MASTER_SITE_GNOME", "=sources/alacarte/0.13/"))
51 check("${INCLUDE_DIRS:H:T}", varuse("INCLUDE_DIRS", "H", "T")) 51 check("${INCLUDE_DIRS:H:T}", varuse("INCLUDE_DIRS", "H", "T"))
52 check("${A.${B.${C.${D}}}}", varuse("A.${B.${C.${D}}}")) 52 check("${A.${B.${C.${D}}}}", varuse("A.${B.${C.${D}}}"))
53 check("${RUBY_VERSION:C/([0-9]+)\\.([0-9]+)\\.([0-9]+)/\\1/}", varuse("RUBY_VERSION", "C/([0-9]+)\\.([0-9]+)\\.([0-9]+)/\\1/")) 53 check("${RUBY_VERSION:C/([0-9]+)\\.([0-9]+)\\.([0-9]+)/\\1/}", varuse("RUBY_VERSION", "C/([0-9]+)\\.([0-9]+)\\.([0-9]+)/\\1/"))

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mkshparser.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkshparser.go 2016/07/07 12:09:27 1.2
@@ -1,655 +1,224 @@ @@ -1,655 +1,224 @@
1package main 1package main
2 2
3import ( 3import (
4 "fmt" 4 "fmt"
5 "strconv" 5 "strconv"
6) 6)
7 7
8type MkShParser struct { 8func parseShellProgram(line *Line, program string) (list *MkShList, err error) {
9 tok *ShTokenizer 9 if G.opts.Debug {
10 curr *ShToken 10 defer tracecall(program)()
11} 
12 
13func NewMkShParser(line *Line, text string, emitWarnings bool) *MkShParser { 
14 shp := NewShTokenizer(line, text, emitWarnings) 
15 return &MkShParser{shp, nil} 
16} 
17 
18func (p *MkShParser) Program() (retval *MkShList) { 
19 defer p.trace(&retval)() 
20 
21 list := p.List() 
22 if list == nil { 
23 return nil 
24 } 
25 separator := p.Separator() 
26 if separator == nil { 
27 return list 
28 } 
29 return &MkShList{list.AndOrs, append(list.Separators, *separator)} 
30} 
31 
32// ::= AndOr (SeparatorOp AndOr)* 
33func (p *MkShParser) List() (retval *MkShList) { 
34 defer p.trace(&retval)() 
35 ok := false 
36 defer p.rollback(&ok)() 
37 
38 var andors []*MkShAndOr 
39 var seps []MkShSeparator 
40 
41 if andor := p.AndOr(); andor != nil { 
42 andors = append(andors, andor) 
43 } else { 
44 return nil 
45 } 
46 
47next: 
48 mark := p.mark() 
49 if sep := p.SeparatorOp(); sep != nil { 
50 if andor := p.AndOr(); andor != nil { 
51 andors = append(andors, andor) 
52 seps = append(seps, *sep) 
53 goto next 
54 } 
55 } 
56 p.reset(mark) 
57 
58 ok = true 
59 return &MkShList{andors, seps} 
60} 
61 
62func (p *MkShParser) AndOr() (retval *MkShAndOr) { 
63 defer p.trace(&retval)() 
64 ok := false 
65 defer p.rollback(&ok) 
66 
67 var pipes []*MkShPipeline 
68 var ops []string 
69nextpipe: 
70 if pipe := p.Pipeline(); pipe != nil { 
71 pipes = append(pipes, pipe) 
72 switch op := p.peekText(); op { 
73 case "&&", "||": 
74 p.skip() 
75 p.Linebreak() 
76 ops = append(ops, op) 
77 goto nextpipe 
78 } 
79 } 
80 
81 if len(pipes) == len(ops) { 
82 return nil 
83 } 
84 ok = true 
85 return &MkShAndOr{pipes, ops} 
86} 
87 
88// ::= Command (msttPipe Linebreak Command)* 
89func (p *MkShParser) Pipeline() (retval *MkShPipeline) { 
90 defer p.trace(&retval)() 
91 ok := false 
92 defer p.rollback(&ok)() 
93 
94 bang := p.eat("!") 
95 var cmds []*MkShCommand 
96nextcmd: 
97 cmd := p.Command() 
98 if cmd == nil { 
99 return nil 
100 } 
101 cmds = append(cmds, cmd) 
102 if p.eat("|") { 
103 p.Linebreak() 
104 goto nextcmd 
105 } 
106 ok = true 
107 return &MkShPipeline{bang, cmds} 
108} 
109 
110func (p *MkShParser) Command() (retval *MkShCommand) { 
111 defer p.trace(&retval)() 
112 
113 if simple := p.SimpleCommand(); simple != nil { 
114 return &MkShCommand{Simple: simple} 
115 } 
116 if compound := p.CompoundCommand(); compound != nil { 
117 redirects := p.RedirectList() 
118 return &MkShCommand{Compound: compound, Redirects: redirects} 
119 } 
120 if funcdef := p.FunctionDefinition(); funcdef != nil { 
121 return &MkShCommand{FuncDef: funcdef} 
122 } 
123 return nil 
124} 
125 
126func (p *MkShParser) CompoundCommand() (retval *MkShCompoundCommand) { 
127 defer p.trace(&retval)() 
128 
129 if brace := p.BraceGroup(); brace != nil { 
130 return &MkShCompoundCommand{Brace: brace} 
131 } 
132 if subshell := p.Subshell(); subshell != nil { 
133 return &MkShCompoundCommand{Subshell: subshell} 
134 } 
135 if forclause := p.ForClause(); forclause != nil { 
136 return &MkShCompoundCommand{For: forclause} 
137 } 
138 if caseclause := p.CaseClause(); caseclause != nil { 
139 return &MkShCompoundCommand{Case: caseclause} 
140 } 
141 if ifclause := p.IfClause(); ifclause != nil { 
142 return &MkShCompoundCommand{If: ifclause} 
143 } 
144 if whileclause := p.WhileClause(); whileclause != nil { 
145 return &MkShCompoundCommand{While: whileclause} 
146 } 
147 if untilclause := p.UntilClause(); untilclause != nil { 
148 return &MkShCompoundCommand{Until: untilclause} 
149 } 
150 return nil 
151} 
152 
153func (p *MkShParser) Subshell() (retval *MkShList) { 
154 defer p.trace(&retval)() 
155 ok := false 
156 defer p.rollback(&ok)() 
157 
158 if !p.eat("(") { 
159 return nil 
160 } 
161 list := p.CompoundList() 
162 if list == nil { 
163 return nil 
164 } 
165 if !p.eat(")") { 
166 return nil 
167 } 
168 ok = true 
169 return list 
170} 
171 
172// ::= Newline* AndOr (Separator AndOr)* Separator? 
173func (p *MkShParser) CompoundList() (retval *MkShList) { 
174 defer p.trace(&retval)() 
175 ok := false 
176 defer p.rollback(&ok)() 
177 
178 p.Linebreak() 
179 var andors []*MkShAndOr 
180 var separators []MkShSeparator 
181nextandor: 
182 if andor := p.AndOr(); andor != nil { 
183 andors = append(andors, andor) 
184 if sep := p.Separator(); sep != nil { 
185 separators = append(separators, *sep) 
186 goto nextandor 
187 } 
188 } 
189 if len(andors) == 0 { 
190 return nil 
191 } 
192 ok = true 
193 return &MkShList{andors, separators} 
194} 
195 
196// ::= "for" msttWORD Linebreak DoGroup 
197// ::= "for" msttWORD Linebreak "in" SequentialSep DoGroup 
198// ::= "for" msttWORD Linebreak "in" Wordlist SequentialSep DoGroup 
199func (p *MkShParser) ForClause() (retval *MkShForClause) { 
200 defer p.trace(&retval)() 
201 ok := false 
202 defer p.rollback(&ok)() 
203 
204 if !p.eat("for") { 
205 return nil 
206 } 
207 varword := p.Word(false) 
208 if varword == nil || !matches(varword.MkText, `^[A-Z_a-z][0-9A-Za-z]*`) { 
209 return nil 
210 } 
211 varname := varword.MkText 
212 
213 var values []*ShToken 
214 if p.eat("in") { 
215 values = p.Wordlist() 
216 } else { 
217 values = []*ShToken{NewShToken("\"$$@\"", 
218 NewShAtom(shtWord, "\"", shqDquot), 
219 NewShAtom(shtWord, "$$@", shqDquot), 
220 NewShAtom(shtWord, "\"", shqPlain))} 
221 } 
222 if values == nil || !p.SequentialSep() { 
223 return nil 
224 } 
225 
226 p.Linebreak() 
227 body := p.DoGroup() 
228 if body == nil { 
229 return nil 
230 } 
231 
232 ok = true 
233 return &MkShForClause{varname, values, body} 
234} 
235 
236func (p *MkShParser) Wordlist() (retval []*ShToken) { 
237 defer p.trace(&retval)() 
238 
239 var words []*ShToken 
240nextword: 
241 word := p.Word(false) 
242 if word != nil { 
243 words = append(words, word) 
244 goto nextword 
245 } 
246 return words 
247} 
248 
249// ::= "case" msttWORD Linebreak "in" Linebreak CaseItem* "esac" 
250func (p *MkShParser) CaseClause() (retval *MkShCaseClause) { 
251 defer p.trace(&retval)() 
252 ok := false 
253 defer p.rollback(&ok)() 
254 
255 if !p.eat("case") { 
256 return nil 
257 } 
258 
259 panic("CaseClause") 
260 p.Linebreak() 
261 p.CaseItem() 
262 return nil 
263} 
264 
265// ::= "("? Pattern ")" (CompoundList | Linebreak) msttDSEMI? Linebreak 
266func (p *MkShParser) CaseItem() (retval *MkShCaseItem) { 
267 defer p.trace(&retval)() 
268 
269 panic("CaseItem") 
270 p.Pattern() 
271 p.Linebreak() 
272 p.CompoundList() 
273 return nil 
274} 
275 
276// ::= msttWORD 
277// ::= Pattern "|" msttWORD 
278func (p *MkShParser) Pattern() (retval []*ShToken) { 
279 defer p.trace(&retval)() 
280 ok := false 
281 defer p.rollback(&ok)() 
282 
283 var words []*ShToken 
284nextword: 
285 word := p.Word(false) 
286 if word == nil { 
287 return nil 
288 } 
289 words = append(words, word) 
290 if p.eat("|") { 
291 goto nextword 
292 
293 } 
294 ok = true 
295 return words 
296} 
297 
298func (p *MkShParser) IfClause() (retval *MkShIfClause) { 
299 defer p.trace(&retval)() 
300 ok := false 
301 defer p.rollback(&ok)() 
302 
303 var conds []*MkShList 
304 var actions []*MkShList 
305 var elseaction *MkShList 
306 if !p.eat("if") { 
307 return nil 
308 } 
309 
310nextcond: 
311 cond := p.CompoundList() 
312 if cond == nil || !p.eat("then") { 
313 return nil 
314 } 
315 action := p.CompoundList() 
316 if action == nil { 
317 return nil 
318 } 
319 conds = append(conds, cond) 
320 actions = append(actions, action) 
321 if p.eat("elif") { 
322 goto nextcond 
323 } 
324 if p.eat("else") { 
325 elseaction = p.CompoundList() 
326 if elseaction == nil { 
327 return nil 
328 } 
329 } 
330 if !p.eat("fi") { 
331 return nil 
332 } 
333 ok = true 
334 return &MkShIfClause{conds, actions, elseaction} 
335} 
336 
337// ::= "while" CompoundList DoGroup 
338func (p *MkShParser) WhileClause() (retval *MkShLoopClause) { 
339 defer p.trace(&retval)() 
340 ok := false 
341 defer p.rollback(&ok)() 
342 
343 if !p.eat("while") { 
344 return nil 
345 } 
346 
347 panic("WhileClause") 
348 p.CompoundList() 
349 p.DoGroup() 
350 return nil 
351} 
352 
353// ::= "until" CompoundList DoGroup 
354func (p *MkShParser) UntilClause() (retval *MkShLoopClause) { 
355 defer p.trace(&retval)() 
356 ok := false 
357 defer p.rollback(&ok)() 
358 
359 if !p.eat("until") { 
360 return nil 
361 } 
362 
363 panic("UntilClause") 
364 p.CompoundList() 
365 p.DoGroup() 
366 return nil 
367} 
368 
369// ::= msttNAME "(" ")" Linebreak CompoundCommand Redirect* 
370func (p *MkShParser) FunctionDefinition() (retval *MkShFunctionDefinition) { 
371 defer p.trace(&retval)() 
372 ok := false 
373 defer p.rollback(&ok)() 
374 
375 funcname := p.Word(true) 
376 if funcname == nil || !matches(funcname.MkText, `^[A-Z_a-z][0-9A-Z_a-z]*$`) { 
377 return nil 
378 } 
379 
380 if !p.eat("(") || !p.eat(")") { 
381 return nil 
382 } 
383 
384 p.Linebreak() 
385 
386 body := p.CompoundCommand() 
387 if body == nil { 
388 return nil 
389 } 
390 
391 redirects := p.RedirectList() 
392 ok = true 
393 return &MkShFunctionDefinition{funcname.MkText, body, redirects} 
394} 
395 
396func (p *MkShParser) BraceGroup() (retval *MkShList) { 
397 defer p.trace(&retval)() 
398 ok := false 
399 defer p.rollback(&ok)() 
400 
401 if !p.eat("{") { 
402 return nil 
403 } 
404 list := p.CompoundList() 
405 if list == nil { 
406 return nil 
407 } 
408 if !p.eat("}") { 
409 return nil 
410 } 
411 ok = true 
412 return list 
413} 
414 
415func (p *MkShParser) DoGroup() (retval *MkShList) { 
416 defer p.trace(&retval)() 
417 ok := false 
418 defer p.rollback(&ok)() 
419 
420 if !p.eat("do") { 
421 return nil 
422 } 
423 list := p.CompoundList() 
424 if list == nil { 
425 return nil 
426 } 
427 if !p.eat("done") { 
428 return nil 
429 } 11 }
430 ok = true 
431 return list 
432} 
433 12
434func (p *MkShParser) SimpleCommand() (retval *MkShSimpleCommand) { 13 tokens, rest := splitIntoShellTokens(line, program)
435 defer p.trace(&retval)() 14 lexer := NewShellLexer(tokens, rest)
436 ok := false 15 parser := &shyyParserImpl{}
437 defer p.rollback(&ok)() 
438 
439 var assignments []*ShToken 
440 var name *ShToken 
441 var args []*ShToken 
442 var redirections []*MkShRedirection 
443 first := true 
444 seenName := false 
445nextword: 
446 if word := p.Word(first); word != nil { 
447 first = false 
448 if !seenName && word.IsAssignment() { 
449 assignments = append(assignments, word) 
450 } else if !seenName { 
451 name = word 
452 seenName = true 
453 } else { 
454 args = append(args, word) 
455 } 
456 goto nextword 
457 } 
458 if len(assignments) == 0 && name == nil && len(args) == 0 && len(redirections) == 0 { 
459 return nil 
460 } 
461 ok = true 
462 return &MkShSimpleCommand{assignments, name, args, redirections} 
463} 
464 16
465func (p *MkShParser) RedirectList() (retval []*MkShRedirection) { 17 succeeded := parser.Parse(lexer)
466 defer p.trace(&retval)() 
467 18
468nextredirect: 19 if succeeded == 0 && lexer.error == "" {
469 if redirect := p.IoRedirect(); redirect != nil { 20 return lexer.result, nil
470 retval = append(retval, redirect) 
471 goto nextredirect 
472 } 21 }
473 return nil 22 return nil, &ParseError{append([]string{lexer.current}, lexer.remaining...)}
474} 23}
475 24
476func (p *MkShParser) IoRedirect() (retval *MkShRedirection) { 25type ParseError struct {
477 defer p.trace(&retval)() 26 RemainingTokens []string
478 
479 if m, redirect, fdstr, op := match3(p.peekText(), `^((\d*)\s*(<|<&|>|>&|>>|<>|>\||<<|<<-))`); m { 
480 target := p.peekText()[len(redirect):] 
481 _, _, _ = fdstr, op, target 
482 
483 fd, err := strconv.ParseInt(fdstr, 10, 32) 
484 if err != nil { 
485 fd = -1 
486 } 
487 p.skip() 
488 targetToken := NewShTokenizer(p.tok.mkp.Line, target, false).ShToken() 
489 return &MkShRedirection{int(fd), op, targetToken} 
490 } 
491 return nil 
492} 27}
493 28
494func (p *MkShParser) NewlineList() (retval bool) { 29func (e *ParseError) Error() string {
495 defer p.trace(&retval)() 30 return fmt.Sprintf("parse error at %v", e.RemainingTokens)
496 
497 ok := false 
498 for p.eat("\n") { 
499 ok = true 
500 } 
501 return ok 
502} 31}
503 32
504func (p *MkShParser) Linebreak() { 33type ShellLexer struct {
505 for p.eat("\n") { 34 current string
506 } 35 ioredirect string
 36 remaining []string
 37 atCommandStart bool
 38 sinceFor int
 39 sinceCase int
 40 error string
 41 result *MkShList
507} 42}
508 43
509func (p *MkShParser) SeparatorOp() (retval *MkShSeparator) { 44func NewShellLexer(tokens []string, rest string) *ShellLexer {
510 defer p.trace(&retval)() 45 return &ShellLexer{
511 46 current: "",
512 if p.eat(";") { 47 ioredirect: "",
513 op := MkShSeparator(";") 48 remaining: tokens,
514 return &op 49 atCommandStart: true,
515 } 50 error: rest}
516 if p.eat("&") { 
517 op := MkShSeparator("&") 
518 return &op 
519 } 
520 return nil 
521} 51}
522 52func (lex *ShellLexer) Lex(lval *shyySymType) (ttype int) {
523func (p *MkShParser) Separator() (retval *MkShSeparator) { 53 if len(lex.remaining) == 0 {
524 defer p.trace(&retval)() 54 return 0
525 
526 op := p.SeparatorOp() 
527 if op == nil && p.eat("\n") { 
528 sep := MkShSeparator('\n') 
529 op = &sep 
530 } 55 }
531 if op != nil { 
532 p.Linebreak() 
533 } 
534 return op 
535} 
536 56
537func (p *MkShParser) SequentialSep() (retval bool) { 57 if G.opts.Debug {
538 defer p.trace(&retval)() 58 defer func() {
539 59 tname := shyyTokname(shyyTok2[ttype-shyyPrivate])
540 if p.peekText() == ";" { 60 switch ttype {
541 p.skip() 61 case tkWORD, tkASSIGNMENT_WORD:
542 p.Linebreak() 62 traceStep("lex %v %q", tname, lval.Word.MkText)
543 return true 63 case tkIO_NUMBER:
544 } else { 64 traceStep("lex %v %v", tname, lval.IONum)
545 return p.NewlineList() 65 default:
546 } 66 traceStep("lex %v", tname)
547} 
548 
549func (p *MkShParser) Word(cmdstart bool) (retval *ShToken) { 
550 defer p.trace(&retval)() 
551 
552 if token := p.peek(); token != nil && token.IsWord() { 
553 if cmdstart { 
554 switch token.MkText { 
555 case "while", "until", "for", "do", "done", 
556 "if", "then", "else", "elif", "fi", 
557 "{", "}": 
558 return nil 
559 } 67 }
560 } 68 }()
561 p.skip() 
562 return token 
563 } 69 }
564 return nil 
565} 
566 
567func (p *MkShParser) EOF() bool { 
568 return p.peek() == nil 
569} 
570 70
571func (p *MkShParser) peek() *ShToken { 71 token := lex.ioredirect
572 if p.curr == nil { 72 lex.ioredirect = ""
573 nexttoken: 73 if token == "" {
574 p.curr = p.tok.ShToken() 74 token = lex.remaining[0]
575 if p.curr == nil && !p.tok.parser.EOF() { 75 lex.current = token
576 p.tok.mkp.Line.Warnf("Pkglint tokenize error at " + p.tok.parser.Rest()) 76 lex.remaining = lex.remaining[1:]
577 p.tok.mkp.Parser.repl.AdvanceRest() 77 }
578 return nil 78
579 } 79 switch token {
580 if p.curr != nil && hasPrefix(p.curr.MkText, "#") { 80 case ";":
581 goto nexttoken 81 lex.atCommandStart = true
582 } 82 return tkSEMI
 83 case ";;":
 84 lex.atCommandStart = true
 85 return tkSEMISEMI
 86 case "\n":
 87 lex.atCommandStart = true
 88 return tkNEWLINE
 89 case "&":
 90 lex.atCommandStart = true
 91 return tkBACKGROUND
 92 case "|":
 93 lex.atCommandStart = true
 94 return tkPIPE
 95 case "(":
 96 lex.atCommandStart = true
 97 return tkLPAREN
 98 case ")":
 99 lex.atCommandStart = true
 100 return tkRPAREN
 101 case "&&":
 102 lex.atCommandStart = true
 103 return tkAND
 104 case "||":
 105 lex.atCommandStart = true
 106 return tkOR
 107 case ">":
 108 lex.atCommandStart = false
 109 return tkGT
 110 case ">&":
 111 lex.atCommandStart = false
 112 return tkGTAND
 113 case "<":
 114 lex.atCommandStart = false
 115 return tkLT
 116 case "<&":
 117 lex.atCommandStart = false
 118 return tkLTAND
 119 case "<>":
 120 lex.atCommandStart = false
 121 return tkLTGT
 122 case ">>":
 123 lex.atCommandStart = false
 124 return tkGTGT
 125 case "<<":
 126 lex.atCommandStart = false
 127 return tkLTLT
 128 case "<<-":
 129 lex.atCommandStart = false
 130 return tkLTLTDASH
 131 case ">|":
 132 lex.atCommandStart = false
 133 return tkGTPIPE
 134 }
 135
 136 if m, fdstr, op := match2(token, `^(\d+)(<<-|<<|<>|<&|>>|>&|>\||<|>)$`); m {
 137 fd, _ := strconv.Atoi(fdstr)
 138 lval.IONum = fd
 139 lex.ioredirect = op
 140 return tkIO_NUMBER
 141 }
 142
 143 if lex.atCommandStart {
 144 lex.sinceCase = -1
 145 lex.sinceFor = -1
 146 switch token {
 147 case "if":
 148 return tkIF
 149 case "then":
 150 return tkTHEN
 151 case "elif":
 152 return tkELIF
 153 case "else":
 154 return tkELSE
 155 case "fi":
 156 return tkFI
 157 case "for":
 158 lex.atCommandStart = false
 159 lex.sinceFor = 0
 160 return tkFOR
 161 case "while":
 162 return tkWHILE
 163 case "until":
 164 return tkUNTIL
 165 case "do":
 166 return tkDO
 167 case "done":
 168 return tkDONE
 169 case "in":
 170 lex.atCommandStart = false
 171 return tkIN
 172 case "case":
 173 lex.atCommandStart = false
 174 lex.sinceCase = 0
 175 return tkCASE
 176 case "{":
 177 return tkLBRACE
 178 case "}":
 179 return tkRBRACE
 180 case "!":
 181 return tkEXCLAM
 182 }
 183 }
 184
 185 if lex.sinceFor >= 0 {
 186 lex.sinceFor++
 187 }
 188 if lex.sinceCase >= 0 {
 189 lex.sinceCase++
 190 }
 191
 192 switch {
 193 case matches(token, `^\d+$`) && len(lex.remaining) != 0 && matches(lex.remaining[0], `^[<>]`):
 194 ttype = tkIO_NUMBER
 195 lval.IONum, _ = strconv.Atoi(token)
 196 case lex.sinceFor == 2 && token == "in":
 197 ttype = tkIN
 198 lex.atCommandStart = false
 199 case lex.sinceFor == 2 && token == "do":
 200 ttype = tkDO
 201 lex.atCommandStart = true
 202 case lex.sinceCase == 2 && token == "in":
 203 ttype = tkIN
 204 lex.atCommandStart = false
 205 case (lex.atCommandStart || lex.sinceCase == 3) && token == "esac":
 206 ttype = tkESAC
 207 lex.atCommandStart = false
 208 case lex.atCommandStart && matches(token, `^[A-Za-z_]\w*=`):
 209 ttype = tkASSIGNMENT_WORD
 210 p := NewShTokenizer(dummyLine, token, false)
 211 lval.Word = p.ShToken()
 212 default:
 213 ttype = tkWORD
 214 p := NewShTokenizer(dummyLine, token, false)
 215 lval.Word = p.ShToken()
 216 lex.atCommandStart = false
583 } 217 }
584 //traceStep("MkShParser.peek %v rest=%q", p.curr, p.tok.mkp.repl.rest) 
585 return p.curr 
586} 
587 
588func (p *MkShParser) peekText() string { 
589 if next := p.peek(); next != nil { 
590 return next.MkText 
591 } 
592 return "" 
593} 
594 
595func (p *MkShParser) skip() { 
596 p.curr = nil 
597} 
598 
599func (p *MkShParser) eat(s string) bool { 
600 if p.peek() == nil { 
601 return false 
602 } 
603 if p.peek().MkText == s { 
604 p.skip() 
605 return true 
606 } 
607 return false 
608} 
609 
610func (p *MkShParser) rollback(pok *bool) func() { 
611 mark := p.mark() 
612 return func() { 
613 if !*pok { 
614 p.reset(mark) 
615 } 
616 } 
617} 
618 
619func (p *MkShParser) trace(retval interface{}) func() { 
620 if G.opts.Debug { 
621 return tracecallInternal(p.peek(), p.restref(), "=>", ref(retval)) 
622 } else { 
623 return func() {} 
624 } 
625} 
626 
627func (p *MkShParser) mark() MkShParserMark { 
628 return MkShParserMark{p.tok.parser.repl.Mark(), p.curr} 
629} 
630 
631func (p *MkShParser) reset(mark MkShParserMark) { 
632 p.tok.parser.repl.Reset(mark.rest) 
633 p.curr = mark.curr 
634} 
635 
636func (p *MkShParser) restref() MkShParserRest { 
637 return MkShParserRest{&p.tok.mkp.repl.rest} 
638} 
639 
640func (p *MkShParser) Rest() string { 
641 return p.peekText() + p.tok.mkp.repl.AdvanceRest() 
642} 
643 
644type MkShParserMark struct { 
645 rest PrefixReplacerMark 
646 curr *ShToken 
647} 
648 218
649type MkShParserRest struct { 219 return ttype
650 restref *string 
651} 220}
652 221
653func (rest MkShParserRest) String() string { 222func (lex *ShellLexer) Error(s string) {
654 return fmt.Sprintf("rest=%q", *rest.restref) 223 lex.error = s
655} 224}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mkshparser_test.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkshparser_test.go 2016/07/07 12:09:27 1.2
@@ -1,352 +1,595 @@ @@ -1,352 +1,595 @@
1package main 1package main
2 2
3import ( 3import (
4 check "gopkg.in/check.v1" 4 "encoding/json"
 5 "gopkg.in/check.v1"
 6 "strconv"
5) 7)
6 8
7func (s *Suite) Test_MkShParser_Program(c *check.C) { 9type ShSuite struct {
8 parse := func(cmd string, expected *MkShList) { 10 c *check.C
9 p := NewMkShParser(dummyLine, cmd, false) 
10 program := p.Program() 
11 c.Check(program, deepEquals, expected) 
12 c.Check(p.tok.parser.Rest(), equals, "") 
13 c.Check(s.Output(), equals, "") 
14 } 
15 
16 if false { 
17 parse(""+ 
18 "\tcd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2>/dev/null "+ 
19 "| pax -rw -pm ${DESTDIR}${PREFIX}/${${_dir_}}", 
20 NewMkShList()) 
21 } 
22} 
23 
24func (s *Suite) Test_MkShParser_List(c *check.C) { 
25 
26} 
27 
28func (s *Suite) Test_MkShParser_AndOr(c *check.C) { 
29 parse := func(cmd string, expected *MkShAndOr) { 
30 p := NewMkShParser(dummyLine, cmd, false) 
31 andor := p.AndOr() 
32 c.Check(andor, deepEquals, expected) 
33 c.Check(p.tok.parser.Rest(), equals, "") 
34 c.Check(s.Output(), equals, "") 
35 } 
36 tester := &MkShTester{c} 
37 
38 parse("simplecmd", 
39 NewMkShAndOr(NewMkShPipeline(false, tester.ParseCommand("simplecmd")))) 
40 
41 expected := NewMkShAndOr(NewMkShPipeline(false, tester.ParseCommand("simplecmd1"))) 
42 expected.Add("&&", NewMkShPipeline(false, tester.ParseCommand("simplecmd2"))) 
43 parse("simplecmd1 && simplecmd2", expected) 
44} 
45 
46func (s *Suite) Test_MkShParser_Pipeline(c *check.C) { 
47 
48} 
49 
50func (s *Suite) Test_MkShParser_Command(c *check.C) { 
51 parse := func(cmd string, expected *MkShCommand) { 
52 p := NewMkShParser(dummyLine, cmd, false) 
53 command := p.Command() 
54 c.Check(command, deepEquals, expected) 
55 c.Check(p.tok.parser.Rest(), equals, "") 
56 c.Check(s.Output(), equals, "") 
57 } 
58 tester := &MkShTester{c} 
59 
60 parse("simple", 
61 &MkShCommand{Simple: tester.ParseSimpleCommand("simple")}) 
62} 
63 
64func (s *Suite) Test_MkShParser_CompoundCommand(c *check.C) { 
65 
66} 11}
67 12
68func (s *Suite) Test_MkShParser_Subshell(c *check.C) { 13var _ = check.Suite(&ShSuite{})
69 
70} 
71 14
72func (s *Suite) Test_MkShParser_CompoundList(c *check.C) { 15func (s *ShSuite) Test_ShellParser_program(c *check.C) {
73 parse := func(cmd string, expected *MkShList) { 16 b := s.init(c)
74 p := NewMkShParser(dummyLine, cmd, false) 
75 compoundList := p.CompoundList() 
76 c.Check(compoundList, deepEquals, expected) 
77 c.Check(p.tok.parser.Rest(), equals, "") 
78 c.Check(s.Output(), equals, "") 
79 } 
80 tester := &MkShTester{c} 
81 17
82 parse("simplecmd", 18 s.test("",
83 NewMkShList().AddAndOr(NewMkShAndOr(NewMkShPipeline(false, tester.ParseCommand("simplecmd"))))) 19 b.List())
84 20
85 simplecmd1 := NewMkShPipeline(false, tester.ParseCommand("simplecmd1")) 21 s.test("echo ;",
86 simplecmd2 := NewMkShPipeline(false, tester.ParseCommand("simplecmd2")) 22 b.List().AddCommand(b.SimpleCommand("echo")).AddSeparator(";"))
87 expected := NewMkShList().AddAndOr(NewMkShAndOr(simplecmd1).Add("&&", simplecmd2)) 23
88 parse("simplecmd1 && simplecmd2", expected) 24 s.test("echo",
89} 25 b.List().AddCommand(b.SimpleCommand("echo")))
90 26
91func (s *Suite) Test_MkShParser_ForClause(c *check.C) { 27 s.test(""+
92 parse := func(cmd string, expected *MkShForClause) { 28 "cd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2 > /dev/null "+
93 p := NewMkShParser(dummyLine, cmd, false) 29 "| pax -rw -pm ${DESTDIR}${PREFIX}/${${_dir_}}",
94 forclause := p.ForClause() 30 b.List().AddAndOr(b.AndOr(
95 c.Check(forclause, deepEquals, expected) 31 b.Pipeline(false, b.SimpleCommand("cd", "${WRKSRC}"))).Add("&&",
96 c.Check(p.tok.parser.Rest(), equals, "") 32 b.Pipeline(false,
97 c.Check(s.Output(), equals, "") 33 b.SimpleCommand("${FIND}", "${${_list_}}", "-type", "f", "!", "-name", "'*.orig'", "2>/dev/null"),
 34 b.SimpleCommand("pax", "-rw", "-pm", "${DESTDIR}${PREFIX}/${${_dir_}}")))))
 35
 36 s.test("${CAT} ${PKGDIR}/PLIST | while read entry ; do : ; done",
 37 b.List().AddAndOr(b.AndOr(b.Pipeline(false,
 38 b.SimpleCommand("${CAT}", "${PKGDIR}/PLIST"),
 39 b.While(
 40 b.List().AddCommand(b.SimpleCommand("read", "entry")).AddSeparator(";"),
 41 b.List().AddCommand(b.SimpleCommand(":")).AddSeparator(";"))))))
 42
 43 s.test("while read entry ; do case \"$$entry\" in include/c-client/* ) ${INSTALL_DATA} $$src $$dest ; esac ; done",
 44 b.List().AddCommand(b.While(
 45 b.List().AddCommand(b.SimpleCommand("read", "entry")).AddSeparator(";"),
 46 b.List().AddCommand(b.Case(
 47 b.Token("\"$$entry\""),
 48 b.CaseItem(
 49 b.Words("include/c-client/*"),
 50 b.List().AddCommand(b.SimpleCommand("${INSTALL_DATA}", "$$src", "$$dest")),
 51 &SEP_SEMI))).AddSeparator(";"))))
 52
 53 s.test("command | while condition ; do case selector in pattern ) : ; esac ; done",
 54 b.List().AddAndOr(b.AndOr(b.Pipeline(false,
 55 b.SimpleCommand("command"),
 56 b.While(
 57 b.List().AddCommand(b.SimpleCommand("condition")).AddSeparator(";"),
 58 b.List().AddCommand(b.Case(
 59 b.Token("selector"),
 60 b.CaseItem(
 61 b.Words("pattern"),
 62 b.List().AddCommand(b.SimpleCommand(":")),
 63 &SEP_SEMI))).AddSeparator(";"))))))
 64
 65 s.test("command1 \n command2 \n command3",
 66 b.List().
 67 AddCommand(b.SimpleCommand("command1")).
 68 AddSeparator(SEP_NEWLINE).
 69 AddCommand(b.SimpleCommand("command2")).
 70 AddSeparator(SEP_NEWLINE).
 71 AddCommand(b.SimpleCommand("command3")))
 72
 73 s.test("if condition; then action; else case selector in pattern) case-item-action ;; esac; fi",
 74 b.List().AddCommand(b.If(
 75 b.List().AddCommand(b.SimpleCommand("condition")).AddSeparator(";"),
 76 b.List().AddCommand(b.SimpleCommand("action")).AddSeparator(";"),
 77 b.List().AddCommand(b.Case(
 78 b.Token("selector"),
 79 b.CaseItem(
 80 b.Words("pattern"),
 81 b.List().AddCommand(b.SimpleCommand("case-item-action")), nil))).AddSeparator(";"))))
 82}
 83
 84func (s *ShSuite) Test_ShellParser_list(c *check.C) {
 85 b := s.init(c)
 86
 87 s.test("echo1 && echo2",
 88 b.List().AddAndOr(
 89 b.AndOr(b.Pipeline(false, b.SimpleCommand("echo1"))).
 90 Add("&&", b.Pipeline(false, b.SimpleCommand("echo2")))))
 91
 92 s.test("echo1 ; echo2",
 93 b.List().
 94 AddCommand(b.SimpleCommand("echo1")).
 95 AddSeparator(";").
 96 AddCommand(b.SimpleCommand("echo2")))
 97
 98 s.test("echo1 ; echo2 &",
 99 b.List().
 100 AddCommand(b.SimpleCommand("echo1")).
 101 AddSeparator(";").
 102 AddCommand(b.SimpleCommand("echo2")).
 103 AddSeparator("&"))
 104}
 105
 106func (s *ShSuite) Test_ShellParser_and_or(c *check.C) {
 107 b := s.init(c)
 108
 109 s.test("echo1 | echo2",
 110 b.List().AddAndOr(b.AndOr(b.Pipeline(false,
 111 b.SimpleCommand("echo1"),
 112 b.SimpleCommand("echo2")))))
 113
 114 s.test("echo1 | echo2 && echo3 | echo4",
 115 b.List().AddAndOr(b.AndOr(
 116 b.Pipeline(false,
 117 b.SimpleCommand("echo1"),
 118 b.SimpleCommand("echo2")),
 119 ).Add("&&",
 120 b.Pipeline(false,
 121 b.SimpleCommand("echo3"),
 122 b.SimpleCommand("echo4")))))
 123
 124 s.test("echo1 | echo2 || ! echo3 | echo4",
 125 b.List().AddAndOr(b.AndOr(
 126 b.Pipeline(false,
 127 b.SimpleCommand("echo1"),
 128 b.SimpleCommand("echo2")),
 129 ).Add("||",
 130 b.Pipeline(true,
 131 b.SimpleCommand("echo3"),
 132 b.SimpleCommand("echo4")))))
 133}
 134
 135func (s *ShSuite) Test_ShellParser_pipeline(c *check.C) {
 136 b := s.init(c)
 137
 138 s.test("command1 | command2",
 139 b.List().AddAndOr(b.AndOr(b.Pipeline(false,
 140 b.SimpleCommand("command1"),
 141 b.SimpleCommand("command2")))))
 142
 143 s.test("! command1 | command2",
 144 b.List().AddAndOr(b.AndOr(b.Pipeline(true,
 145 b.SimpleCommand("command1"),
 146 b.SimpleCommand("command2")))))
 147}
 148
 149func (s *ShSuite) Test_ShellParser_pipe_sequence(c *check.C) {
 150 b := s.init(c)
 151
 152 s.test("command1 | if true ; then : ; fi",
 153 b.List().AddAndOr(b.AndOr(b.Pipeline(false,
 154 b.SimpleCommand("command1"),
 155 b.If(
 156 b.List().AddCommand(b.SimpleCommand("true")).AddSeparator(";"),
 157 b.List().AddCommand(b.SimpleCommand(":")).AddSeparator(";"))))))
 158}
 159
 160func (s *ShSuite) Test_ShellParser_command(c *check.C) {
 161 b := s.init(c)
 162
 163 s.test("simple_command",
 164 b.List().AddAndOr(b.AndOr(b.Pipeline(false, b.SimpleCommand("simple_command")))))
 165
 166 s.test("while 1 ; do 2 ; done",
 167 b.List().AddAndOr(b.AndOr(b.Pipeline(false,
 168 b.While(
 169 b.List().AddCommand(b.SimpleCommand("1")).AddSeparator(";"),
 170 b.List().AddCommand(b.SimpleCommand("2")).AddSeparator(";"))))))
 171
 172 s.test("while 1 ; do 2 ; done 1 >& 2",
 173 b.List().AddAndOr(b.AndOr(b.Pipeline(false,
 174 b.While(
 175 b.List().AddCommand(b.SimpleCommand("1")).AddSeparator(";"),
 176 b.List().AddCommand(b.SimpleCommand("2")).AddSeparator(";"),
 177 b.Redirection(1, ">&", "2"))))))
 178
 179 s.test("func ( ) { echo hello ; } 2 >& 1",
 180 b.List().AddCommand(b.Function(
 181 "func",
 182 b.Brace(b.List().AddCommand(b.SimpleCommand("echo", "hello")).AddSeparator(";")).Compound,
 183 b.Redirection(2, ">&", "1"))))
 184}
 185
 186func (s *ShSuite) Test_ShellParser_compound_command(c *check.C) {
 187 b := s.init(c)
 188
 189 s.test("{ brace ; }",
 190 b.List().AddCommand(b.Brace(
 191 b.List().AddCommand(b.SimpleCommand("brace")).AddSeparator(";"))))
 192
 193 s.test("( subshell )",
 194 b.List().AddCommand(b.Subshell(
 195 b.List().AddCommand(b.SimpleCommand("subshell")))))
 196
 197 s.test("for i in * ; do echo $i ; done",
 198 b.List().AddCommand(b.For(
 199 "i",
 200 b.Words("*"),
 201 b.List().AddCommand(b.SimpleCommand("echo", "$i")).AddSeparator(";"))))
 202
 203 s.test("case $i in esac",
 204 b.List().AddCommand(b.Case(
 205 b.Token("$i"))))
 206
 207}
 208
 209func (s *ShSuite) Test_ShellParser_subshell(c *check.C) {
 210 b := s.init(c)
 211
 212 sub3 := b.Subshell(b.List().AddCommand(b.SimpleCommand("sub3")))
 213 sub2 := b.Subshell(b.List().AddCommand(sub3).AddSeparator(";").AddCommand(b.SimpleCommand("sub2")))
 214 sub1 := b.Subshell(b.List().AddCommand(sub2).AddSeparator(";").AddCommand(b.SimpleCommand("sub1")))
 215 s.test("( ( ( sub3 ) ; sub2 ) ; sub1 )", b.List().AddCommand(sub1))
 216}
 217
 218func (s *ShSuite) Test_ShellParser_compound_list(c *check.C) {
 219 b := s.init(c)
 220
 221 s.test("( \n echo )",
 222 b.List().AddCommand(b.Subshell(
 223 b.List().AddCommand(b.SimpleCommand("echo")))))
 224}
 225
 226func (s *ShSuite) Test_ShellParser_term(c *check.C) {
 227 b := s.init(c)
 228
 229 _ = b
 230}
 231
 232func (s *ShSuite) Test_ShellParser_for_clause(c *check.C) {
 233 b := s.init(c)
 234
 235 s.test("for var do echo $var ; done",
 236 b.List().AddCommand(b.For(
 237 "var",
 238 b.Words("\"$$@\""),
 239 b.List().AddCommand(b.SimpleCommand("echo", "$var")).AddSeparator(";"))))
 240
 241 // Only linebreak is allowed, but not semicolon.
 242 s.test("for var \n do echo $var ; done",
 243 b.List().AddCommand(b.For(
 244 "var",
 245 b.Words("\"$$@\""),
 246 b.List().AddCommand(b.SimpleCommand("echo", "$var")).AddSeparator(";"))))
 247
 248 s.test("for var in a b c ; do echo $var ; done",
 249 b.List().AddCommand(b.For(
 250 "var",
 251 b.Words("a", "b", "c"),
 252 b.List().AddCommand(b.SimpleCommand("echo", "$var")).AddSeparator(";"))))
 253
 254 s.test("for var \n \n \n in a b c ; do echo $var ; done",
 255 b.List().AddCommand(b.For(
 256 "var",
 257 b.Words("a", "b", "c"),
 258 b.List().AddCommand(b.SimpleCommand("echo", "$var")).AddSeparator(";"))))
 259
 260 s.test("for var in in esac ; do echo $var ; done",
 261 b.List().AddCommand(b.For(
 262 "var",
 263 b.Words("in", "esac"),
 264 b.List().AddCommand(b.SimpleCommand("echo", "$var")).AddSeparator(";"))))
 265
 266 // No semicolon necessary between the two “done”.
 267 s.test("for i in 1; do for j in 1; do echo $$i$$j; done done",
 268 b.List().AddCommand(b.For(
 269 "i",
 270 b.Words("1"),
 271 b.List().AddCommand(b.For(
 272 "j",
 273 b.Words("1"),
 274 b.List().AddCommand(b.SimpleCommand("echo", "$$i$$j")).AddSeparator(";"))))))
 275}
 276
 277func (s *ShSuite) Test_ShellParser_case_clause(c *check.C) {
 278 b := s.init(c)
 279
 280 s.test("case $var in esac",
 281 b.List().AddCommand(b.Case(b.Token("$var"))))
 282
 283 s.test("case selector in pattern) ;; pattern) esac",
 284 b.List().AddCommand(b.Case(
 285 b.Token("selector"),
 286 b.CaseItem(b.Words("pattern"), b.List(), nil),
 287 b.CaseItem(b.Words("pattern"), b.List(), nil))))
 288
 289 s.test("case $$i in *.c | *.h ) echo C ;; * ) echo Other ; esac",
 290 b.List().AddCommand(b.Case(
 291 b.Token("$$i"),
 292 b.CaseItem(b.Words("*.c", "*.h"), b.List().AddCommand(b.SimpleCommand("echo", "C")), nil),
 293 b.CaseItem(b.Words("*"), b.List().AddCommand(b.SimpleCommand("echo", "Other")), &SEP_SEMI))))
 294
 295 s.test("case $$i in *.c ) echo ; esac",
 296 b.List().AddCommand(b.Case(
 297 b.Token("$$i"),
 298 b.CaseItem(b.Words("*.c"), b.List().AddCommand(b.SimpleCommand("echo")), &SEP_SEMI))))
 299
 300 s.test("case selector in pattern) case-item-action ; esac",
 301 b.List().AddCommand(b.Case(
 302 b.Token("selector"),
 303 b.CaseItem(
 304 b.Words("pattern"),
 305 b.List().AddCommand(b.SimpleCommand("case-item-action")), &SEP_SEMI))))
 306
 307 s.test("case selector in pattern) case-item-action ;; esac",
 308 b.List().AddCommand(b.Case(
 309 b.Token("selector"),
 310 b.CaseItem(
 311 b.Words("pattern"),
 312 b.List().AddCommand(b.SimpleCommand("case-item-action")), nil))))
 313
 314}
 315
 316func (s *ShSuite) Test_ShellParser_if_clause(c *check.C) {
 317 b := s.init(c)
 318
 319 s.test(
 320 "if true ; then echo yes ; else echo no ; fi",
 321 b.List().AddCommand(b.If(
 322 b.List().AddCommand(b.SimpleCommand("true")).AddSeparator(";"),
 323 b.List().AddCommand(b.SimpleCommand("echo", "yes")).AddSeparator(";"),
 324 b.List().AddCommand(b.SimpleCommand("echo", "no")).AddSeparator(";"))))
 325
 326 // No semicolon necessary between the two “fi”.
 327 s.test("if cond1; then if cond2; then action; fi fi",
 328 b.List().AddCommand(b.If(
 329 b.List().AddCommand(b.SimpleCommand("cond1")).AddSeparator(";"),
 330 b.List().AddCommand(b.If(
 331 b.List().AddCommand(b.SimpleCommand("cond2")).AddSeparator(";"),
 332 b.List().AddCommand(b.SimpleCommand("action")).AddSeparator(";"))))))
 333}
 334
 335func (s *ShSuite) Test_ShellParser_while_clause(c *check.C) {
 336 b := s.init(c)
 337
 338 s.test("while condition ; do action ; done",
 339 b.List().AddCommand(b.While(
 340 b.List().AddCommand(b.SimpleCommand("condition")).AddSeparator(";"),
 341 b.List().AddCommand(b.SimpleCommand("action")).AddSeparator(";"))))
 342}
 343
 344func (s *ShSuite) Test_ShellParser_until_clause(c *check.C) {
 345 b := s.init(c)
 346
 347 s.test("until condition ; do action ; done",
 348 b.List().AddCommand(b.Until(
 349 b.List().AddCommand(b.SimpleCommand("condition")).AddSeparator(";"),
 350 b.List().AddCommand(b.SimpleCommand("action")).AddSeparator(";"))))
 351}
 352
 353func (s *ShSuite) Test_ShellParser_function_definition(c *check.C) {
 354 b := s.init(c)
 355
 356 _ = b
 357}
 358
 359func (s *ShSuite) Test_ShellParser_brace_group(c *check.C) {
 360 b := s.init(c)
 361
 362 // No semicolon necessary after the closing brace.
 363 s.test("if true; then { echo yes; } fi",
 364 b.List().AddCommand(b.If(
 365 b.List().AddCommand(b.SimpleCommand("true")).AddSeparator(";"),
 366 b.List().AddCommand(b.Brace(
 367 b.List().AddCommand(b.SimpleCommand("echo", "yes")).AddSeparator(";"))))))
 368}
 369
 370func (s *ShSuite) Test_ShellParser_simple_command(c *check.C) {
 371 b := s.init(c)
 372
 373 s.test(
 374 "echo hello, world",
 375 b.List().AddCommand(b.SimpleCommand("echo", "hello,", "world")))
 376
 377 s.test("echo ${PKGNAME:Q}",
 378 b.List().AddCommand(b.SimpleCommand("echo", "${PKGNAME:Q}")))
 379
 380 s.test("${ECHO} \"Double-quoted\" 'Single-quoted'",
 381 b.List().AddCommand(b.SimpleCommand("${ECHO}", "\"Double-quoted\"", "'Single-quoted'")))
 382
 383 s.test("`cat plain` \"`cat double`\" '`cat single`'",
 384 b.List().AddCommand(b.SimpleCommand("`cat plain`", "\"`cat double`\"", "'`cat single`'")))
 385
 386 s.test("`\"one word\"`",
 387 b.List().AddCommand(b.SimpleCommand("`\"one word\"`")))
 388
 389 s.test("PAGES=\"`ls -1 | ${SED} -e 's,3qt$$,3,'`\"",
 390 b.List().AddCommand(b.SimpleCommand("PAGES=\"`ls -1 | ${SED} -e 's,3qt$$,3,'`\"")))
 391
 392 s.test("var=Plain var=\"Dquot\" var='Squot' var=Plain\"Dquot\"'Squot'",
 393 b.List().AddCommand(b.SimpleCommand("var=Plain", "var=\"Dquot\"", "var='Squot'", "var=Plain\"Dquot\"'Squot'")))
 394
 395 // RUN is a special Make variable since it ends with a semicolon;
 396 // therefore it needs to be split off before passing the rest of
 397 // the command to the shell command parser.
 398 s.test("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"",
 399 b.List().AddCommand(b.SimpleCommand("${RUN}", "subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")))
 400
 401 s.test("PATH=/nonexistent env PATH=${PATH:Q} true",
 402 b.List().AddCommand(b.SimpleCommand("PATH=/nonexistent", "env", "PATH=${PATH:Q}", "true")))
 403
 404 s.test("{OpenGrok args",
 405 b.List().AddCommand(b.SimpleCommand("{OpenGrok", "args")))
 406}
 407
 408func (s *ShSuite) Test_ShellParser_io_redirect(c *check.C) {
 409 b := s.init(c)
 410
 411 s.test("echo >> ${PLIST_SRC}",
 412 b.List().AddCommand(b.SimpleCommand("echo", ">>${PLIST_SRC}")))
 413
 414 s.test("echo >> ${PLIST_SRC}",
 415 b.List().AddCommand(b.SimpleCommand("echo", ">>${PLIST_SRC}")))
 416
 417 s.test("echo 1>output 2>>append 3>|clobber 4>&5 6<input >>append",
 418 b.List().AddCommand(&MkShCommand{Simple: &MkShSimpleCommand{
 419 Assignments: nil,
 420 Name: b.Token("echo"),
 421 Args: nil,
 422 Redirections: []*MkShRedirection{
 423 {1, ">", b.Token("output")},
 424 {2, ">>", b.Token("append")},
 425 {3, ">|", b.Token("clobber")},
 426 {4, ">&", b.Token("5")},
 427 {6, "<", b.Token("input")},
 428 {-1, ">>", b.Token("append")}}}}))
 429
 430 s.test("echo 1> output 2>> append 3>| clobber 4>& 5 6< input >> append",
 431 b.List().AddCommand(&MkShCommand{Simple: &MkShSimpleCommand{
 432 Assignments: nil,
 433 Name: b.Token("echo"),
 434 Args: nil,
 435 Redirections: []*MkShRedirection{
 436 {1, ">", b.Token("output")},
 437 {2, ">>", b.Token("append")},
 438 {3, ">|", b.Token("clobber")},
 439 {4, ">&", b.Token("5")},
 440 {6, "<", b.Token("input")},
 441 {-1, ">>", b.Token("append")}}}}))
 442}
 443
 444func (s *ShSuite) Test_ShellParser_io_here(c *check.C) {
 445 b := s.init(c)
 446
 447 _ = b
 448}
 449
 450func (s *ShSuite) init(c *check.C) *MkShBuilder {
 451 s.c = c
 452 return NewMkShBuilder()
 453}
 454
 455func (s *ShSuite) test(program string, expected *MkShList) {
 456 tokens, rest := splitIntoShellTokens(dummyLine, program)
 457 s.c.Check(rest, equals, "")
 458 lexer := &ShellLexer{
 459 current: "",
 460 remaining: tokens,
 461 atCommandStart: true,
 462 error: ""}
 463 parser := &shyyParserImpl{}
 464
 465 succeeded := parser.Parse(lexer)
 466
 467 c := s.c
 468
 469 if ok1, ok2 := c.Check(succeeded, equals, 0), c.Check(lexer.error, equals, ""); ok1 && ok2 {
 470 if !c.Check(lexer.result, deepEquals, expected) {
 471 actualJson, actualErr := json.MarshalIndent(lexer.result, "", " ")
 472 expectedJson, expectedErr := json.MarshalIndent(expected, "", " ")
 473 if c.Check(actualErr, check.IsNil) && c.Check(expectedErr, check.IsNil) {
 474 c.Check(string(actualJson), deepEquals, string(expectedJson))
 475 }
 476 }
 477 } else {
 478 c.Check(lexer.remaining, deepEquals, []string{})
98 } 479 }
99 tester := &MkShTester{c} 
100 
101 params := []*ShToken{tester.Token("\"$$@\"")} 
102 action := tester.ParseCompoundList("action;") 
103 parse("for var; do action; done", 
104 &MkShForClause{"var", params, action}) 
105 
106 abc := []*ShToken{tester.Token("a"), tester.Token("b"), tester.Token("c")} 
107 parse("for var in a b c; do action; done", 
108 &MkShForClause{"var", abc, action}) 
109 
110 actions := tester.ParseCompoundList("action1 && action2;") 
111 parse("for var in a b c; do action1 && action2; done", 
112 &MkShForClause{"var", abc, actions}) 
113} 
114 
115func (s *Suite) Test_MkShParser_Wordlist(c *check.C) { 
116 
117} 
118 
119func (s *Suite) Test_MkShParser_CaseClause(c *check.C) { 
120 
121} 
122 
123func (s *Suite) Test_MkShParser_CaseItem(c *check.C) { 
124 
125} 
126 
127func (s *Suite) Test_MkShParser_Pattern(c *check.C) { 
128 
129} 480}
130 481
131func (s *Suite) Test_MkShParser_IfClause(c *check.C) { 482type MkShBuilder struct {
132 
133} 483}
134 484
135func (s *Suite) Test_MkShParser_WhileClause(c *check.C) { 485func NewMkShBuilder() *MkShBuilder {
136 486 return &MkShBuilder{}
137} 487}
138 488
139func (s *Suite) Test_MkShParser_UntilClause(c *check.C) { 489func (b *MkShBuilder) List() *MkShList {
140 490 return NewMkShList()
141} 491}
142 492
143func (s *Suite) Test_MkShParser_FunctionDefinition(c *check.C) { 493func (b *MkShBuilder) AndOr(pipeline *MkShPipeline) *MkShAndOr {
144 494 return NewMkShAndOr(pipeline)
145} 495}
146 496
147func (s *Suite) Test_MkShParser_BraceGroup(c *check.C) { 497func (b *MkShBuilder) Pipeline(negated bool, cmds ...*MkShCommand) *MkShPipeline {
148 498 return NewMkShPipeline(negated, cmds...)
149} 499}
150 500
151func (s *Suite) Test_MkShParser_DoGroup(c *check.C) { 501func (b *MkShBuilder) SimpleCommand(words ...string) *MkShCommand {
152 tester := &MkShTester{c} 502 cmd := &MkShSimpleCommand{}
153 check := func(str string, expected *MkShList) { 503 assignments := true
154 p := NewMkShParser(dummyLine, str, false) 504 for _, word := range words {
155 dogroup := p.DoGroup() 505 if assignments && matches(word, `^\w+=`) {
156 if c.Check(dogroup, check.NotNil) { 506 cmd.Assignments = append(cmd.Assignments, b.Token(word))
157 if !c.Check(dogroup, deepEquals, expected) { 507 } else if m, fdstr, op, rest := match3(word, `^(\d*)(<<-|<<|<&|>>|>&|>\||<|>)(.*)$`); m {
158 for i, andor := range dogroup.AndOrs { 508 fd, err := strconv.Atoi(fdstr)
159 c.Check(andor, deepEquals, expected.AndOrs[i]) 509 if err != nil {
160 } 510 fd = -1
161 } 511 }
162 } 512 cmd.Redirections = append(cmd.Redirections, b.Redirection(fd, op, rest))
163 c.Check(p.tok.parser.Rest(), equals, "") 513 } else {
164 c.Check(s.Output(), equals, "") 514 assignments = false
165 } 515 if cmd.Name == nil {
166 516 cmd.Name = b.Token(word)
167 andor := NewMkShAndOr(NewMkShPipeline(false, tester.ParseCommand("action"))) 517 } else {
168 check("do action; done", 518 cmd.Args = append(cmd.Args, b.Token(word))
169 &MkShList{[]*MkShAndOr{andor}, []MkShSeparator{";"}}) 
170} 
171 
172func (s *Suite) Test_MkShParser_SimpleCommand(c *check.C) { 
173 parse := func(cmd string, builder *SimpleCommandBuilder) { 
174 expected := builder.Cmd 
175 p := NewMkShParser(dummyLine, cmd, false) 
176 shcmd := p.SimpleCommand() 
177 if c.Check(shcmd, check.NotNil) { 
178 if !c.Check(shcmd, deepEquals, expected) { 
179 for i, assignment := range shcmd.Assignments { 
180 c.Check(assignment, deepEquals, expected.Assignments[i]) 
181 } 
182 c.Check(shcmd.Name, deepEquals, expected.Name) 
183 for i, word := range shcmd.Args { 
184 c.Check(word, deepEquals, expected.Args[i]) 
185 } 
186 for i, redirection := range shcmd.Redirections { 
187 c.Check(redirection, deepEquals, expected.Redirections[i]) 
188 } 
189 } 519 }
190 } 520 }
191 c.Check(p.tok.parser.Rest(), equals, "") 
192 c.Check(s.Output(), equals, "") 
193 } 
194 
195 fail := func(noncmd string, expectedRest string) { 
196 p := NewMkShParser(dummyLine, noncmd, false) 
197 shcmd := p.SimpleCommand() 
198 c.Check(shcmd, check.IsNil) 
199 c.Check(p.tok.parser.Rest(), equals, expectedRest) 
200 c.Check(s.Output(), equals, "") 
201 } 521 }
202 tester := &MkShTester{c} 522 return &MkShCommand{Simple: cmd}
203 
204 parse("echo ${PKGNAME:Q}", 
205 NewSimpleCommandBuilder(). 
206 Name(tester.Token("echo")). 
207 Arg(tester.Token("${PKGNAME:Q}"))) 
208 
209 parse("${ECHO} \"Double-quoted\" 'Single-quoted'", 
210 NewSimpleCommandBuilder(). 
211 Name(tester.Token("${ECHO}")). 
212 Arg(tester.Token("\"Double-quoted\"")). 
213 Arg(tester.Token("'Single-quoted'"))) 
214 
215 parse("`cat plain` \"`cat double`\" '`cat single`'", 
216 NewSimpleCommandBuilder(). 
217 Name(tester.Token("`cat plain`")). 
218 Arg(tester.Token("\"`cat double`\"")). 
219 Arg(tester.Token("'`cat single`'"))) 
220 
221 parse("`\"one word\"`", 
222 NewSimpleCommandBuilder(). 
223 Name(tester.Token("`\"one word\"`"))) 
224 
225 parse("PAGES=\"`ls -1 | ${SED} -e 's,3qt$$,3,'`\"", 
226 NewSimpleCommandBuilder(). 
227 Assignment(tester.Token("PAGES=\"`ls -1 | ${SED} -e 's,3qt$$,3,'`\""))) 
228 
229 parse("var=Plain var=\"Dquot\" var='Squot' var=Plain\"Dquot\"'Squot'", 
230 NewSimpleCommandBuilder(). 
231 Assignment(tester.Token("var=Plain")). 
232 Assignment(tester.Token("var=\"Dquot\"")). 
233 Assignment(tester.Token("var='Squot'")). 
234 Assignment(tester.Token("var=Plain\"Dquot\"'Squot'"))) 
235 
236 parse("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"", 
237 NewSimpleCommandBuilder(). 
238 Name(tester.Token("${RUN}")). 
239 Arg(tester.Token("subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\""))) 
240 
241 parse("PATH=/nonexistent env PATH=${PATH:Q} true", 
242 NewSimpleCommandBuilder(). 
243 Assignment(tester.Token("PATH=/nonexistent")). 
244 Name(tester.Token("env")). 
245 Arg(tester.Token("PATH=${PATH:Q}")). 
246 Arg(tester.Token("true"))) 
247 
248 parse("{OpenGrok args", 
249 NewSimpleCommandBuilder(). 
250 Name(tester.Token("{OpenGrok")). 
251 Arg(tester.Token("args"))) 
252 
253 fail("if clause", "if clause") 
254 fail("{ group; }", "{ group; }") 
255 
256} 
257 
258func (s *Suite) Test_MkShParser_RedirectList(c *check.C) { 
259} 
260 
261func (s *Suite) Test_MkShParser_IoRedirect(c *check.C) { 
262} 
263 
264func (s *Suite) Test_MkShParser_IoFile(c *check.C) { 
265} 
266 
267func (s *Suite) Test_MkShParser_IoHere(c *check.C) { 
268} 
269 
270func (s *Suite) Test_MkShParser_NewlineList(c *check.C) { 
271} 523}
272 524
273func (s *Suite) Test_MkShParser_Linebreak(c *check.C) { 525func (b *MkShBuilder) If(condActionElse ...*MkShList) *MkShCommand {
 526 ifclause := &MkShIfClause{}
 527 for i, part := range condActionElse {
 528 if i%2 == 0 && i != len(condActionElse)-1 {
 529 ifclause.Conds = append(ifclause.Conds, part)
 530 } else if i%2 == 1 {
 531 ifclause.Actions = append(ifclause.Actions, part)
 532 } else {
 533 ifclause.Else = part
 534 }
 535 }
 536 return &MkShCommand{Compound: &MkShCompoundCommand{If: ifclause}}
274} 537}
275 538
276func (s *Suite) Test_MkShParser_SeparatorOp(c *check.C) { 539func (b *MkShBuilder) For(varname string, items []*ShToken, action *MkShList) *MkShCommand {
277 540 return &MkShCommand{Compound: &MkShCompoundCommand{For: &MkShForClause{varname, items, action}}}
278} 541}
279 542
280func (s *Suite) Test_MkShParser_Separator(c *check.C) { 543func (b *MkShBuilder) Case(selector *ShToken, items ...*MkShCaseItem) *MkShCommand {
281 544 return &MkShCommand{Compound: &MkShCompoundCommand{Case: &MkShCaseClause{selector, items}}}
282} 545}
283 546
284func (s *Suite) Test_MkShParser_SequentialSep(c *check.C) { 547func (b *MkShBuilder) CaseItem(patterns []*ShToken, action *MkShList, separator *MkShSeparator) *MkShCaseItem {
285 548 return &MkShCaseItem{patterns, action, separator}
286} 549}
287 550
288func (s *Suite) Test_MkShParser_Word(c *check.C) { 551func (b *MkShBuilder) While(cond, action *MkShList, redirects ...*MkShRedirection) *MkShCommand {
289 552 return &MkShCommand{
 553 Compound: &MkShCompoundCommand{
 554 Loop: &MkShLoopClause{cond, action, false}},
 555 Redirects: redirects}
290} 556}
291 557
292type MkShTester struct { 558func (b *MkShBuilder) Until(cond, action *MkShList, redirects ...*MkShRedirection) *MkShCommand {
293 c *check.C 559 return &MkShCommand{
 560 Compound: &MkShCompoundCommand{
 561 Loop: &MkShLoopClause{cond, action, true}},
 562 Redirects: redirects}
294} 563}
295 564
296func (t *MkShTester) ParseCommand(str string) *MkShCommand { 565func (b *MkShBuilder) Function(name string, body *MkShCompoundCommand, redirects ...*MkShRedirection) *MkShCommand {
297 p := NewMkShParser(dummyLine, str, false) 566 return &MkShCommand{
298 cmd := p.Command() 567 FuncDef: &MkShFunctionDefinition{name, body},
299 t.c.Check(cmd, check.NotNil) 568 Redirects: redirects}
300 t.c.Check(p.Rest(), equals, "") 
301 return cmd 
302} 569}
303 570
304func (t *MkShTester) ParseSimpleCommand(str string) *MkShSimpleCommand { 571func (b *MkShBuilder) Brace(list *MkShList) *MkShCommand {
305 p := NewMkShParser(dummyLine, str, false) 572 return &MkShCommand{Compound: &MkShCompoundCommand{Brace: list}}
306 parsed := p.SimpleCommand() 
307 t.c.Check(parsed, check.NotNil) 
308 t.c.Check(p.Rest(), equals, "") 
309 return parsed 
310} 573}
311 574
312func (t *MkShTester) ParseCompoundList(str string) *MkShList { 575func (b *MkShBuilder) Subshell(list *MkShList) *MkShCommand {
313 p := NewMkShParser(dummyLine, str, false) 576 return &MkShCommand{Compound: &MkShCompoundCommand{Subshell: list}}
314 parsed := p.CompoundList() 
315 t.c.Check(parsed, check.NotNil) 
316 t.c.Check(p.Rest(), equals, "") 
317 return parsed 
318} 577}
319 578
320func (t *MkShTester) Token(str string) *ShToken { 579func (b *MkShBuilder) Token(mktext string) *ShToken {
321 p := NewMkShParser(dummyLine, str, false) 580 tokenizer := NewShTokenizer(dummyLine, mktext, false)
322 parsed := p.peek() 581 token := tokenizer.ShToken()
323 p.skip() 582 return token
324 t.c.Check(parsed, check.NotNil) 
325 t.c.Check(p.Rest(), equals, "") 
326 return parsed 
327} 583}
328 584
329type SimpleCommandBuilder struct { 585func (b *MkShBuilder) Words(words ...string) []*ShToken {
330 Cmd *MkShSimpleCommand 586 tokens := make([]*ShToken, len(words))
 587 for i, word := range words {
 588 tokens[i] = b.Token(word)
 589 }
 590 return tokens
331} 591}
332 592
333func NewSimpleCommandBuilder() *SimpleCommandBuilder { 593func (b *MkShBuilder) Redirection(fd int, op string, target string) *MkShRedirection {
334 cmd := &MkShSimpleCommand{} 594 return &MkShRedirection{fd, op, b.Token(target)}
335 return &SimpleCommandBuilder{cmd} 
336} 
337func (b *SimpleCommandBuilder) Name(name *ShToken) *SimpleCommandBuilder { 
338 b.Cmd.Name = name 
339 return b 
340} 
341func (b *SimpleCommandBuilder) Assignment(assignment *ShToken) *SimpleCommandBuilder { 
342 b.Cmd.Assignments = append(b.Cmd.Assignments, assignment) 
343 return b 
344} 
345func (b *SimpleCommandBuilder) Arg(arg *ShToken) *SimpleCommandBuilder { 
346 b.Cmd.Args = append(b.Cmd.Args, arg) 
347 return b 
348} 
349func (b *SimpleCommandBuilder) Redirection(redirection *MkShRedirection) *SimpleCommandBuilder { 
350 b.Cmd.Redirections = append(b.Cmd.Redirections, redirection) 
351 return b 
352} 595}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mkshtypes.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/mkshtypes.go 2016/07/07 12:09:27 1.2
@@ -1,231 +1,173 @@ @@ -1,231 +1,173 @@
1package main 1package main
2 2
3import ( 3import "fmt"
4 "fmt" 
5) 
6 4
7type MkShList struct { 5type MkShList struct {
8 AndOrs []*MkShAndOr 6 AndOrs []*MkShAndOr
9 Separators []MkShSeparator 7 Separators []MkShSeparator
10} 8}
11 9
12func NewMkShList() *MkShList { 10func NewMkShList() *MkShList {
13 return &MkShList{nil, nil} 11 return &MkShList{nil, nil}
14} 12}
15 13
16func (list *MkShList) String() string { 
17 return fmt.Sprintf("MkShList(%v)", list.AndOrs) 
18} 
19 
20func (list *MkShList) AddAndOr(andor *MkShAndOr) *MkShList { 14func (list *MkShList) AddAndOr(andor *MkShAndOr) *MkShList {
21 list.AndOrs = append(list.AndOrs, andor) 15 list.AndOrs = append(list.AndOrs, andor)
22 return list 16 return list
23} 17}
24 18
25func (list *MkShList) AddSeparator(separator MkShSeparator) *MkShList { 19func (list *MkShList) AddSeparator(separator MkShSeparator) *MkShList {
26 list.Separators = append(list.Separators, separator) 20 list.Separators = append(list.Separators, separator)
27 return list 21 return list
28} 22}
29 23
30type MkShAndOr struct { 24type MkShAndOr struct {
31 Pipes []*MkShPipeline 25 Pipes []*MkShPipeline
32 Ops []string // Either "&&" or "||" 26 Ops []string // Either "&&" or "||"
33} 27}
34 28
35func NewMkShAndOr(pipeline *MkShPipeline) *MkShAndOr { 29func NewMkShAndOr(pipeline *MkShPipeline) *MkShAndOr {
36 return &MkShAndOr{[]*MkShPipeline{pipeline}, nil} 30 return &MkShAndOr{[]*MkShPipeline{pipeline}, nil}
37} 31}
38 32
39func (andor *MkShAndOr) String() string { 
40 return fmt.Sprintf("MkShAndOr(%v)", andor.Pipes) 
41} 
42 
43func (andor *MkShAndOr) Add(op string, pipeline *MkShPipeline) *MkShAndOr { 33func (andor *MkShAndOr) Add(op string, pipeline *MkShPipeline) *MkShAndOr {
44 andor.Pipes = append(andor.Pipes, pipeline) 34 andor.Pipes = append(andor.Pipes, pipeline)
45 andor.Ops = append(andor.Ops, op) 35 andor.Ops = append(andor.Ops, op)
46 return andor 36 return andor
47} 37}
48 38
49type MkShPipeline struct { 39type MkShPipeline struct {
50 Negated bool 40 Negated bool
51 Cmds []*MkShCommand 41 Cmds []*MkShCommand
52} 42}
53 43
54func NewMkShPipeline(negated bool, cmds ...*MkShCommand) *MkShPipeline { 44func NewMkShPipeline(negated bool, cmds ...*MkShCommand) *MkShPipeline {
55 return &MkShPipeline{negated, cmds} 45 return &MkShPipeline{negated, cmds}
56} 46}
57 47
58func (pipe *MkShPipeline) String() string { 
59 return fmt.Sprintf("MkShPipeline(%v)", pipe.Cmds) 
60} 
61 
62func (pipe *MkShPipeline) Add(cmd *MkShCommand) *MkShPipeline { 48func (pipe *MkShPipeline) Add(cmd *MkShCommand) *MkShPipeline {
63 pipe.Cmds = append(pipe.Cmds, cmd) 49 pipe.Cmds = append(pipe.Cmds, cmd)
64 return pipe 50 return pipe
65} 51}
66 52
67type MkShCommand struct { 53type MkShCommand struct {
68 Simple *MkShSimpleCommand 54 Simple *MkShSimpleCommand
69 Compound *MkShCompoundCommand 55 Compound *MkShCompoundCommand
70 FuncDef *MkShFunctionDefinition 56 FuncDef *MkShFunctionDefinition
71 Redirects []*MkShRedirection // For Compound and FuncDef 57 Redirects []*MkShRedirection // For Compound and FuncDef
72} 58}
73 59
74func (cmd *MkShCommand) String() string { 
75 switch { 
76 case cmd.Simple != nil: 
77 return cmd.Simple.String() 
78 case cmd.Compound != nil: 
79 return cmd.Compound.String() 
80 case cmd.FuncDef != nil: 
81 return cmd.FuncDef.String() 
82 } 
83 return "MkShCommand(?)" 
84} 
85 
86type MkShCompoundCommand struct { 60type MkShCompoundCommand struct {
87 Brace *MkShList 61 Brace *MkShList
88 Subshell *MkShList 62 Subshell *MkShList
89 For *MkShForClause 63 For *MkShForClause
90 Case *MkShCaseClause 64 Case *MkShCaseClause
91 If *MkShIfClause 65 If *MkShIfClause
92 While *MkShLoopClause 66 Loop *MkShLoopClause
93 Until *MkShLoopClause 
94} 
95 
96func (cmd *MkShCompoundCommand) String() string { 
97 switch { 
98 case cmd.Brace != nil: 
99 return cmd.Brace.String() 
100 case cmd.Subshell != nil: 
101 return cmd.Subshell.String() 
102 case cmd.For != nil: 
103 return cmd.For.String() 
104 case cmd.Case != nil: 
105 return cmd.Case.String() 
106 case cmd.If != nil: 
107 return cmd.If.String() 
108 case cmd.While != nil: 
109 return cmd.While.String() 
110 case cmd.Until != nil: 
111 return cmd.Until.String() 
112 } 
113 return "MkShCompoundCommand(?)" 
114} 67}
115 68
116type MkShForClause struct { 69type MkShForClause struct {
117 Varname string 70 Varname string
118 Values []*ShToken 71 Values []*ShToken
119 Body *MkShList 72 Body *MkShList
120} 73}
121 74
122func (cl *MkShForClause) String() string { 
123 return fmt.Sprintf("MkShForClause(%v, %v, %v)", cl.Varname, cl.Values, cl.Body) 
124} 
125 
126type MkShCaseClause struct { 75type MkShCaseClause struct {
127 Word *ShToken 76 Word *ShToken
128 Cases []*MkShCaseItem 77 Cases []*MkShCaseItem
129} 78}
130 79
131func (cl *MkShCaseClause) String() string { 
132 return fmt.Sprintf("MkShCaseClause(...)") 
133} 
134 
135type MkShCaseItem struct { 80type MkShCaseItem struct {
136 Patterns []*ShToken 81 Patterns []*ShToken
137 Action *MkShList 82 Action *MkShList
 83 Separator *MkShSeparator
138} 84}
139 85
140type MkShIfClause struct { 86type MkShIfClause struct {
141 Conds []*MkShList 87 Conds []*MkShList
142 Actions []*MkShList 88 Actions []*MkShList
143 Else *MkShList 89 Else *MkShList
144} 90}
145 91
146func (cl *MkShIfClause) String() string { 
147 return "MkShIf(...)" 
148} 
149 
150func (cl *MkShIfClause) Prepend(cond *MkShList, action *MkShList) { 92func (cl *MkShIfClause) Prepend(cond *MkShList, action *MkShList) {
151 cl.Conds = append([]*MkShList{cond}, cl.Conds...) 93 cl.Conds = append([]*MkShList{cond}, cl.Conds...)
152 cl.Actions = append([]*MkShList{action}, cl.Actions...) 94 cl.Actions = append([]*MkShList{action}, cl.Actions...)
153} 95}
154 96
155type MkShLoopClause struct { 97type MkShLoopClause struct {
156 Cond *MkShList 98 Cond *MkShList
157 Action *MkShList 99 Action *MkShList
158 Until bool 100 Until bool
159} 101}
160 102
161func (cl *MkShLoopClause) String() string { 
162 return "MkShLoop(...)" 
163} 
164 
165type MkShFunctionDefinition struct { 103type MkShFunctionDefinition struct {
166 Name string 104 Name string
167 Body *MkShCompoundCommand 105 Body *MkShCompoundCommand
168 Redirects []*MkShRedirection 
169} 
170 
171func (def *MkShFunctionDefinition) String() string { 
172 return "MkShFunctionDef(...)" 
173} 106}
174 107
175type MkShSimpleCommand struct { 108type MkShSimpleCommand struct {
176 Assignments []*ShToken 109 Assignments []*ShToken
177 Name *ShToken 110 Name *ShToken
178 Args []*ShToken 111 Args []*ShToken
179 Redirections []*MkShRedirection 112 Redirections []*MkShRedirection
180} 113}
181 114
182func (scmd *MkShSimpleCommand) String() string { 115func NewStrCommand(cmd *MkShSimpleCommand) *StrCommand {
183 str := "SimpleCommand(" 116 strcmd := &StrCommand{
184 first := true 117 make([]string, len(cmd.Assignments)),
185 sep := func() { 118 "",
186 if first { 119 make([]string, len(cmd.Args))}
187 first = false 120 for i, assignment := range cmd.Assignments {
188 } else { 121 strcmd.Assignments[i] = assignment.MkText
189 str += ", " 
190 } 
191 } 122 }
192 for _, word := range scmd.Assignments { 123 if cmd.Name != nil {
193 sep() 124 strcmd.Name = cmd.Name.MkText
194 str += word.MkText 
195 } 125 }
196 if word := scmd.Name; word != nil { 126 for i, arg := range cmd.Args {
197 sep() 127 strcmd.Args[i] = arg.MkText
198 str += word.MkText 
199 } 128 }
200 for _, word := range scmd.Args { 129 return strcmd
201 sep() 130}
202 str += word.MkText 131
 132type StrCommand struct {
 133 Assignments []string
 134 Name string
 135 Args []string
 136}
 137
 138func (c *StrCommand) HasOption(opt string) bool {
 139 for _, arg := range c.Args {
 140 if arg == opt {
 141 return true
 142 }
203 } 143 }
204 for _, redirection := range scmd.Redirections { 144 return false
205 sep() 145}
206 str += redirection.String() 146
 147func (c *StrCommand) AnyArgMatches(pattern string) bool {
 148 for _, arg := range c.Args {
 149 if matches(arg, pattern) {
 150 return true
 151 }
207 } 152 }
208 return str + ")" 153 return false
 154}
 155
 156func (c *StrCommand) String() string {
 157 return fmt.Sprintf("%v %v %v", c.Assignments, c.Name, c.Args)
209} 158}
210 159
211type MkShRedirection struct { 160type MkShRedirection struct {
212 Fd int // Or -1 161 Fd int // Or -1
213 Op string 162 Op string
214 Target *ShToken 163 Target *ShToken
215} 164}
216 165
217func (r *MkShRedirection) String() string { 
218 if r.Fd != -1 { 
219 return fmt.Sprintf("%d%s%s", r.Fd, r.Op, r.Target.MkText) 
220 } else { 
221 return r.Op + r.Target.MkText 
222 } 
223} 
224 
225// One of ";", "&", "\n" 166// One of ";", "&", "\n"
226type MkShSeparator string 167type MkShSeparator string
227 168
228func (sep *MkShSeparator) String() string { 169var (
229 return fmt.Sprintf("%q", sep) 170 SEP_SEMI MkShSeparator = ";"
230 171 SEP_BACKGROUND MkShSeparator = "&"
231} 172 SEP_NEWLINE MkShSeparator = "\n"
 173)

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

--- pkgsrc/pkgtools/pkglint/files/Attic/mktypes_test.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/mktypes_test.go 2016/07/07 12:09:27 1.2
@@ -1,11 +1,17 @@ @@ -1,11 +1,17 @@
1package main 1package main
2 2
3import ( 3import (
4 check "gopkg.in/check.v1" 4 check "gopkg.in/check.v1"
5) 5)
6 6
7func (s *Suite) Test_MkVarUse_Mod(c *check.C) { 7func (s *Suite) Test_MkVarUse_Mod(c *check.C) {
8 varuse := &MkVarUse{"varname", []string{"Q"}} 8 varuse := &MkVarUse{"varname", []string{"Q"}}
9 9
10 c.Check(varuse.Mod(), equals, ":Q") 10 c.Check(varuse.Mod(), equals, ":Q")
11} 11}
 12
 13func (list *MkShList) AddCommand(command *MkShCommand) *MkShList {
 14 pipeline := NewMkShPipeline(false, command)
 15 andOr := NewMkShAndOr(pipeline)
 16 return list.AddAndOr(andOr)
 17}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/shtokenizer.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/shtokenizer.go 2016/07/07 12:09:27 1.2
@@ -24,74 +24,80 @@ func (p *ShTokenizer) ShAtom(quoting ShQ @@ -24,74 +24,80 @@ func (p *ShTokenizer) ShAtom(quoting ShQ
24 return &ShAtom{shtVaruse, repl.Since(mark), quoting, varuse} 24 return &ShAtom{shtVaruse, repl.Since(mark), quoting, varuse}
25 } 25 }
26 26
27 var atom *ShAtom 27 var atom *ShAtom
28 switch quoting { 28 switch quoting {
29 case shqPlain: 29 case shqPlain:
30 atom = p.shAtomPlain() 30 atom = p.shAtomPlain()
31 case shqDquot: 31 case shqDquot:
32 atom = p.shAtomDquot() 32 atom = p.shAtomDquot()
33 case shqSquot: 33 case shqSquot:
34 atom = p.shAtomSquot() 34 atom = p.shAtomSquot()
35 case shqBackt: 35 case shqBackt:
36 atom = p.shAtomBackt() 36 atom = p.shAtomBackt()
 37 case shqSubsh:
 38 atom = p.shAtomSub()
37 case shqDquotBackt: 39 case shqDquotBackt:
38 atom = p.shAtomDquotBackt() 40 atom = p.shAtomDquotBackt()
39 case shqBacktDquot: 41 case shqBacktDquot:
40 atom = p.shAtomBacktDquot() 42 atom = p.shAtomBacktDquot()
41 case shqBacktSquot: 43 case shqBacktSquot:
42 atom = p.shAtomBacktSquot() 44 atom = p.shAtomBacktSquot()
 45 case shqSubshSquot:
 46 atom = p.shAtomSubshSquot()
43 case shqDquotBacktDquot: 47 case shqDquotBacktDquot:
44 atom = p.shAtomDquotBacktDquot() 48 atom = p.shAtomDquotBacktDquot()
45 case shqDquotBacktSquot: 49 case shqDquotBacktSquot:
46 atom = p.shAtomDquotBacktSquot() 50 atom = p.shAtomDquotBacktSquot()
47 } 51 }
48 52
49 if atom == nil { 53 if atom == nil {
50 repl.Reset(mark) 54 repl.Reset(mark)
51 p.parser.Line.Warnf("Pkglint parse error in ShTokenizer.ShAtom at %q (quoting=%s)", repl.rest, quoting) 55 p.parser.Line.Warnf("Pkglint parse error in ShTokenizer.ShAtom at %q (quoting=%s)", repl.rest, quoting)
52 } 56 }
53 return atom 57 return atom
54} 58}
55 59
56func (p *ShTokenizer) shAtomPlain() *ShAtom { 60func (p *ShTokenizer) shAtomPlain() *ShAtom {
57 q := shqPlain 61 q := shqPlain
58 repl := p.parser.repl 62 repl := p.parser.repl
59 switch { 63 switch {
60 case repl.AdvanceHspace(): 64 case repl.AdvanceHspace():
61 return &ShAtom{shtSpace, repl.s, q, nil} 65 return &ShAtom{shtSpace, repl.s, q, nil}
 66 case repl.AdvanceStr("\n"):
 67 return &ShAtom{shtNewline, repl.s, q, nil}
62 case repl.AdvanceStr(";;"): 68 case repl.AdvanceStr(";;"):
63 return &ShAtom{shtCaseSeparator, repl.s, q, nil} 69 return &ShAtom{shtCaseSeparator, repl.s, q, nil}
64 case repl.AdvanceStr(";"): 70 case repl.AdvanceStr(";"):
65 return &ShAtom{shtSemicolon, repl.s, q, nil} 71 return &ShAtom{shtSemicolon, repl.s, q, nil}
66 case repl.AdvanceStr("("): 72 case repl.AdvanceStr("("):
67 return &ShAtom{shtParenOpen, repl.s, q, nil} 73 return &ShAtom{shtParenOpen, repl.s, q, nil}
68 case repl.AdvanceStr(")"): 74 case repl.AdvanceStr(")"):
69 return &ShAtom{shtParenClose, repl.s, q, nil} 75 return &ShAtom{shtParenClose, repl.s, q, nil}
70 case repl.AdvanceStr("||"): 76 case repl.AdvanceStr("||"):
71 return &ShAtom{shtOr, repl.s, q, nil} 77 return &ShAtom{shtOr, repl.s, q, nil}
72 case repl.AdvanceStr("&&"): 78 case repl.AdvanceStr("&&"):
73 return &ShAtom{shtAnd, repl.s, q, nil} 79 return &ShAtom{shtAnd, repl.s, q, nil}
74 case repl.AdvanceStr("|"): 80 case repl.AdvanceStr("|"):
75 return &ShAtom{shtPipe, repl.s, q, nil} 81 return &ShAtom{shtPipe, repl.s, q, nil}
76 case repl.AdvanceStr("&"): 82 case repl.AdvanceStr("&"):
77 return &ShAtom{shtBackground, repl.s, q, nil} 83 return &ShAtom{shtBackground, repl.s, q, nil}
78 case repl.AdvanceStr("\""): 84 case repl.AdvanceStr("\""):
79 return &ShAtom{shtWord, repl.s, shqDquot, nil} 85 return &ShAtom{shtWord, repl.s, shqDquot, nil}
80 case repl.AdvanceStr("'"): 86 case repl.AdvanceStr("'"):
81 return &ShAtom{shtWord, repl.s, shqSquot, nil} 87 return &ShAtom{shtWord, repl.s, shqSquot, nil}
82 case repl.AdvanceStr("`"): 88 case repl.AdvanceStr("`"):
83 return &ShAtom{shtWord, repl.s, shqBackt, nil} 89 return &ShAtom{shtWord, repl.s, shqBackt, nil}
84 case repl.AdvanceRegexp(`^(?:<|<<|>|>>|>&)`): 90 case repl.AdvanceRegexp(`^\d*(?:<<-|<<|<&|<>|>>|>&|>\||<|>)`):
85 return &ShAtom{shtRedirect, repl.m[0], q, nil} 91 return &ShAtom{shtRedirect, repl.m[0], q, nil}
86 case repl.AdvanceRegexp(`^#.*`): 92 case repl.AdvanceRegexp(`^#.*`):
87 return &ShAtom{shtComment, repl.m[0], q, nil} 93 return &ShAtom{shtComment, repl.m[0], q, nil}
88 case repl.AdvanceStr("$$("): 94 case repl.AdvanceStr("$$("):
89 return &ShAtom{shtSubshell, repl.s, q, nil} 95 return &ShAtom{shtSubshell, repl.s, q, nil}
90 case repl.AdvanceRegexp(`^(?:[!#%*+,\-./0-9:=?@A-Z\[\]^_a-z{}~]+|\\[^$]|` + reShDollar + `)+`): 96 case repl.AdvanceRegexp(`^(?:[!#%*+,\-./0-9:=?@A-Z\[\]^_a-z{}~]+|\\[^$]|` + reShDollar + `)+`):
91 return &ShAtom{shtWord, repl.m[0], q, nil} 97 return &ShAtom{shtWord, repl.m[0], q, nil}
92 } 98 }
93 return nil 99 return nil
94} 100}
95 101
96func (p *ShTokenizer) shAtomDquot() *ShAtom { 102func (p *ShTokenizer) shAtomDquot() *ShAtom {
97 repl := p.parser.repl 103 repl := p.parser.repl
@@ -145,26 +151,66 @@ func (p *ShTokenizer) shAtomBackt() *ShA @@ -145,26 +151,66 @@ func (p *ShTokenizer) shAtomBackt() *ShA
145 return &ShAtom{shtPipe, repl.s, q, nil} 151 return &ShAtom{shtPipe, repl.s, q, nil}
146 case repl.AdvanceStr("&"): 152 case repl.AdvanceStr("&"):
147 return &ShAtom{shtBackground, repl.s, q, nil} 153 return &ShAtom{shtBackground, repl.s, q, nil}
148 case repl.AdvanceRegexp(`^(?:<|<<|>|>>|>&)`): 154 case repl.AdvanceRegexp(`^(?:<|<<|>|>>|>&)`):
149 return &ShAtom{shtRedirect, repl.s, q, nil} 155 return &ShAtom{shtRedirect, repl.s, q, nil}
150 case repl.AdvanceRegexp("^#[^`]*"): 156 case repl.AdvanceRegexp("^#[^`]*"):
151 return &ShAtom{shtComment, repl.s, q, nil} 157 return &ShAtom{shtComment, repl.s, q, nil}
152 case repl.AdvanceRegexp(`^(?:[!#%*+,\-./0-9:=?@A-Z\[\]_a-z~]+|\\[^$]|` + reShDollar + `)+`): 158 case repl.AdvanceRegexp(`^(?:[!#%*+,\-./0-9:=?@A-Z\[\]_a-z~]+|\\[^$]|` + reShDollar + `)+`):
153 return &ShAtom{shtWord, repl.s, q, nil} 159 return &ShAtom{shtWord, repl.s, q, nil}
154 } 160 }
155 return nil 161 return nil
156} 162}
157 163
 164func (p *ShTokenizer) shAtomSub() *ShAtom {
 165 const q = shqSubsh
 166 repl := p.parser.repl
 167 mark := repl.Mark()
 168 atom := func(typ ShAtomType) *ShAtom {
 169 return NewShAtom(typ, repl.Since(mark), shqSubsh)
 170 }
 171 switch {
 172 case repl.AdvanceHspace():
 173 return atom(shtSpace)
 174 case repl.AdvanceStr(";;"):
 175 return atom(shtCaseSeparator)
 176 case repl.AdvanceStr(";"):
 177 return atom(shtSemicolon)
 178 case repl.AdvanceStr("||"):
 179 return atom(shtOr)
 180 case repl.AdvanceStr("&&"):
 181 return atom(shtAnd)
 182 case repl.AdvanceStr("|"):
 183 return atom(shtPipe)
 184 case repl.AdvanceStr("&"):
 185 return atom(shtBackground)
 186 case repl.AdvanceStr("\""):
 187 //return &ShAtom{shtWord, repl.s, shqDquot, nil}
 188 case repl.AdvanceStr("'"):
 189 return &ShAtom{shtWord, repl.s, shqSubshSquot, nil}
 190 case repl.AdvanceStr("`"):
 191 //return &ShAtom{shtWord, repl.s, shqBackt, nil}
 192 case repl.AdvanceRegexp(`^\d*(?:<<-|<<|<&|<>|>>|>&|>\||<|>)`):
 193 return &ShAtom{shtRedirect, repl.m[0], q, nil}
 194 case repl.AdvanceRegexp(`^#.*`):
 195 return &ShAtom{shtComment, repl.m[0], q, nil}
 196 case repl.AdvanceStr(")"):
 197 return NewShAtom(shtWord, repl.s, shqPlain)
 198 case repl.AdvanceRegexp(`^(?:[!#%*+,\-./0-9:=?@A-Z\[\]^_a-z{}~]+|\\[^$]|` + reShDollar + `)+`):
 199 return &ShAtom{shtWord, repl.m[0], q, nil}
 200 }
 201 return nil
 202}
 203
158func (p *ShTokenizer) shAtomDquotBackt() *ShAtom { 204func (p *ShTokenizer) shAtomDquotBackt() *ShAtom {
159 const q = shqDquotBackt 205 const q = shqDquotBackt
160 repl := p.parser.repl 206 repl := p.parser.repl
161 switch { 207 switch {
162 case repl.AdvanceStr("`"): 208 case repl.AdvanceStr("`"):
163 return &ShAtom{shtWord, repl.s, shqDquot, nil} 209 return &ShAtom{shtWord, repl.s, shqDquot, nil}
164 case repl.AdvanceStr("\""): 210 case repl.AdvanceStr("\""):
165 return &ShAtom{shtWord, repl.s, shqDquotBacktDquot, nil} 211 return &ShAtom{shtWord, repl.s, shqDquotBacktDquot, nil}
166 case repl.AdvanceStr("'"): 212 case repl.AdvanceStr("'"):
167 return &ShAtom{shtWord, repl.s, shqDquotBacktSquot, nil} 213 return &ShAtom{shtWord, repl.s, shqDquotBacktSquot, nil}
168 case repl.AdvanceRegexp("^#[^`]*"): 214 case repl.AdvanceRegexp("^#[^`]*"):
169 return &ShAtom{shtComment, repl.s, q, nil} 215 return &ShAtom{shtComment, repl.s, q, nil}
170 case repl.AdvanceStr(";;"): 216 case repl.AdvanceStr(";;"):
@@ -206,26 +252,38 @@ func (p *ShTokenizer) shAtomBacktDquot() @@ -206,26 +252,38 @@ func (p *ShTokenizer) shAtomBacktDquot()
206 252
207func (p *ShTokenizer) shAtomBacktSquot() *ShAtom { 253func (p *ShTokenizer) shAtomBacktSquot() *ShAtom {
208 const q = shqBacktSquot 254 const q = shqBacktSquot
209 repl := p.parser.repl 255 repl := p.parser.repl
210 switch { 256 switch {
211 case repl.AdvanceStr("'"): 257 case repl.AdvanceStr("'"):
212 return &ShAtom{shtWord, repl.s, shqBackt, nil} 258 return &ShAtom{shtWord, repl.s, shqBackt, nil}
213 case repl.AdvanceRegexp(`^([\t !"#%&()*+,\-./0-9:;<=>?@A-Z\[\\\]^_` + "`" + `a-z{|}~]+|\$\$)+`): 259 case repl.AdvanceRegexp(`^([\t !"#%&()*+,\-./0-9:;<=>?@A-Z\[\\\]^_` + "`" + `a-z{|}~]+|\$\$)+`):
214 return &ShAtom{shtWord, repl.m[0], q, nil} 260 return &ShAtom{shtWord, repl.m[0], q, nil}
215 } 261 }
216 return nil 262 return nil
217} 263}
218 264
 265func (p *ShTokenizer) shAtomSubshSquot() *ShAtom {
 266 const q = shqSubshSquot
 267 repl := p.parser.repl
 268 switch {
 269 case repl.AdvanceStr("'"):
 270 return &ShAtom{shtWord, repl.s, shqSubsh, nil}
 271 case repl.AdvanceRegexp(`^([\t !"#%&()*+,\-./0-9:;<=>?@A-Z\[\\\]^_` + "`" + `a-z{|}~]+|\$\$)+`):
 272 return &ShAtom{shtWord, repl.m[0], q, nil}
 273 }
 274 return nil
 275}
 276
219func (p *ShTokenizer) shAtomDquotBacktDquot() *ShAtom { 277func (p *ShTokenizer) shAtomDquotBacktDquot() *ShAtom {
220 const q = shqDquotBacktDquot 278 const q = shqDquotBacktDquot
221 repl := p.parser.repl 279 repl := p.parser.repl
222 switch { 280 switch {
223 case repl.AdvanceStr("\""): 281 case repl.AdvanceStr("\""):
224 return &ShAtom{shtWord, repl.s, shqDquotBackt, nil} 282 return &ShAtom{shtWord, repl.s, shqDquotBackt, nil}
225 case repl.AdvanceRegexp(`^(?:[\t !%&()*+,\-./0-9:;<=>?@A-Z\[\]^_a-z{|}~]+|\\[^$]|` + reShDollar + `)+`): 283 case repl.AdvanceRegexp(`^(?:[\t !%&()*+,\-./0-9:;<=>?@A-Z\[\]^_a-z{|}~]+|\\[^$]|` + reShDollar + `)+`):
226 return &ShAtom{shtWord, repl.m[0], q, nil} 284 return &ShAtom{shtWord, repl.m[0], q, nil}
227 } 285 }
228 return nil 286 return nil
229} 287}
230 288
231func (p *ShTokenizer) shAtomDquotBacktSquot() *ShAtom { 289func (p *ShTokenizer) shAtomDquotBacktSquot() *ShAtom {
@@ -271,27 +329,27 @@ func (p *ShTokenizer) ShToken() *ShToken @@ -271,27 +329,27 @@ func (p *ShTokenizer) ShToken() *ShToken
271 repl := p.parser.repl 329 repl := p.parser.repl
272 inimark := repl.Mark() 330 inimark := repl.Mark()
273 var atoms []*ShAtom 331 var atoms []*ShAtom
274 332
275 for peek() != nil && peek().Type == shtSpace { 333 for peek() != nil && peek().Type == shtSpace {
276 skip() 334 skip()
277 inimark = repl.Mark() 335 inimark = repl.Mark()
278 } 336 }
279 337
280 if peek() == nil { 338 if peek() == nil {
281 return nil 339 return nil
282 } 340 }
283 if atom := peek(); !atom.Type.IsWord() { 341 if atom := peek(); !atom.Type.IsWord() {
284 return NewShToken(atom.Text, atom) 342 return NewShToken(atom.MkText, atom)
285 } 343 }
286 344
287nextatom: 345nextatom:
288 mark := repl.Mark() 346 mark := repl.Mark()
289 atom := peek() 347 atom := peek()
290 if atom != nil && (atom.Type.IsWord() || atom.Quoting != shqPlain) { 348 if atom != nil && (atom.Type.IsWord() || atom.Quoting != shqPlain) {
291 skip() 349 skip()
292 atoms = append(atoms, atom) 350 atoms = append(atoms, atom)
293 goto nextatom 351 goto nextatom
294 } 352 }
295 repl.Reset(mark) 353 repl.Reset(mark)
296 354
297 if len(atoms) == 0 { 355 if len(atoms) == 0 {

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

--- pkgsrc/pkgtools/pkglint/files/Attic/shtokenizer_test.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/shtokenizer_test.go 2016/07/07 12:09:27 1.2
@@ -5,49 +5,50 @@ import ( @@ -5,49 +5,50 @@ import (
5) 5)
6 6
7// @Beta 7// @Beta
8func (s *Suite) Test_ShTokenizer_ShAtom(c *check.C) { 8func (s *Suite) Test_ShTokenizer_ShAtom(c *check.C) {
9 checkRest := func(s string, expected ...*ShAtom) string { 9 checkRest := func(s string, expected ...*ShAtom) string {
10 p := NewShTokenizer(dummyLine, s, false) 10 p := NewShTokenizer(dummyLine, s, false)
11 q := shqPlain 11 q := shqPlain
12 for _, exp := range expected { 12 for _, exp := range expected {
13 c.Check(p.ShAtom(q), deepEquals, exp) 13 c.Check(p.ShAtom(q), deepEquals, exp)
14 q = exp.Quoting 14 q = exp.Quoting
15 } 15 }
16 return p.Rest() 16 return p.Rest()
17 } 17 }
18 check := func(s string, expected ...*ShAtom) { 18 check := func(str string, expected ...*ShAtom) {
19 rest := checkRest(s, expected...) 19 rest := checkRest(str, expected...)
20 c.Check(rest, equals, "") 20 c.Check(rest, equals, "")
 21 c.Check(s.Output(), equals, "")
21 } 22 }
22 23
23 token := func(typ ShAtomType, text string, quoting ShQuoting) *ShAtom { 24 token := func(typ ShAtomType, text string, quoting ShQuoting) *ShAtom {
24 return &ShAtom{typ, text, quoting, nil} 25 return &ShAtom{typ, text, quoting, nil}
25 } 26 }
26 word := func(s string) *ShAtom { return token(shtWord, s, shqPlain) } 27 word := func(s string) *ShAtom { return token(shtWord, s, shqPlain) }
27 dquot := func(s string) *ShAtom { return token(shtWord, s, shqDquot) } 28 dquot := func(s string) *ShAtom { return token(shtWord, s, shqDquot) }
28 squot := func(s string) *ShAtom { return token(shtWord, s, shqSquot) } 29 squot := func(s string) *ShAtom { return token(shtWord, s, shqSquot) }
29 backt := func(s string) *ShAtom { return token(shtWord, s, shqBackt) } 30 backt := func(s string) *ShAtom { return token(shtWord, s, shqBackt) }
30 varuse := func(varname string, modifiers ...string) *ShAtom { 31 varuse := func(varname string, modifiers ...string) *ShAtom {
31 text := "${" + varname 32 text := "${" + varname
32 for _, modifier := range modifiers { 33 for _, modifier := range modifiers {
33 text += ":" + modifier 34 text += ":" + modifier
34 } 35 }
35 text += "}" 36 text += "}"
36 varuse := &MkVarUse{varname: varname, modifiers: modifiers} 37 varuse := &MkVarUse{varname: varname, modifiers: modifiers}
37 return &ShAtom{shtVaruse, text, shqPlain, varuse} 38 return &ShAtom{shtVaruse, text, shqPlain, varuse}
38 } 39 }
39 q := func(q ShQuoting, token *ShAtom) *ShAtom { 40 q := func(q ShQuoting, token *ShAtom) *ShAtom {
40 return &ShAtom{token.Type, token.Text, q, token.Data} 41 return &ShAtom{token.Type, token.MkText, q, token.Data}
41 } 42 }
42 whitespace := func(s string) *ShAtom { return token(shtSpace, s, shqPlain) } 43 whitespace := func(s string) *ShAtom { return token(shtSpace, s, shqPlain) }
43 space := token(shtSpace, " ", shqPlain) 44 space := token(shtSpace, " ", shqPlain)
44 semicolon := token(shtSemicolon, ";", shqPlain) 45 semicolon := token(shtSemicolon, ";", shqPlain)
45 pipe := token(shtPipe, "|", shqPlain) 46 pipe := token(shtPipe, "|", shqPlain)
46 47
47 check("" /* none */) 48 check("" /* none */)
48 49
49 check("$$var", 50 check("$$var",
50 word("$$var")) 51 word("$$var"))
51 52
52 check("$$var$$var", 53 check("$$var$$var",
53 word("$$var$$var")) 54 word("$$var$$var"))
@@ -292,39 +293,55 @@ func (s *Suite) Test_ShTokenizer_ShAtom( @@ -292,39 +293,55 @@ func (s *Suite) Test_ShTokenizer_ShAtom(
292 token(shtWord, "\"", shqDquotBacktDquot), 293 token(shtWord, "\"", shqDquotBacktDquot),
293 token(shtWord, "\\`echo foo\\`", shqDquotBacktDquot), // One token, since it doesn’t influence parsing. 294 token(shtWord, "\\`echo foo\\`", shqDquotBacktDquot), // One token, since it doesn’t influence parsing.
294 token(shtWord, "\"", shqDquotBackt), 295 token(shtWord, "\"", shqDquotBackt),
295 token(shtWord, "`", shqDquot), 296 token(shtWord, "`", shqDquot),
296 token(shtWord, "\"", shqPlain)) 297 token(shtWord, "\"", shqPlain))
297 298
298 check("if cond1; then action1; elif cond2; then action2; else action3; fi", 299 check("if cond1; then action1; elif cond2; then action2; else action3; fi",
299 word("if"), space, word("cond1"), semicolon, space, 300 word("if"), space, word("cond1"), semicolon, space,
300 word("then"), space, word("action1"), semicolon, space, 301 word("then"), space, word("action1"), semicolon, space,
301 word("elif"), space, word("cond2"), semicolon, space, 302 word("elif"), space, word("cond2"), semicolon, space,
302 word("then"), space, word("action2"), semicolon, space, 303 word("then"), space, word("action2"), semicolon, space,
303 word("else"), space, word("action3"), semicolon, space, 304 word("else"), space, word("action3"), semicolon, space,
304 word("fi")) 305 word("fi"))
 306
 307 if false {
 308 check("$$(cat)",
 309 token(shtWord, "$$(", shqSubsh),
 310 token(shtWord, "cat", shqSubsh),
 311 token(shtWord, ")", shqPlain))
 312
 313 check("$$(cat 'file')",
 314 token(shtWord, "$$(", shqSubsh),
 315 token(shtWord, "cat", shqSubsh),
 316 token(shtSpace, " ", shqSubsh),
 317 token(shtWord, "'", shqSubshSquot),
 318 token(shtWord, "file", shqSubshSquot),
 319 token(shtWord, "'", shqSubsh),
 320 token(shtWord, ")", shqPlain))
 321 }
305} 322}
306 323
307func (s *Suite) Test_Shtokenizer_ShAtom_Quoting(c *check.C) { 324func (s *Suite) Test_Shtokenizer_ShAtom_Quoting(c *check.C) {
308 checkQuotingChange := func(input, expectedOutput string) { 325 checkQuotingChange := func(input, expectedOutput string) {
309 p := NewShTokenizer(dummyLine, input, false) 326 p := NewShTokenizer(dummyLine, input, false)
310 q := shqPlain 327 q := shqPlain
311 result := "" 328 result := ""
312 for { 329 for {
313 token := p.ShAtom(q) 330 token := p.ShAtom(q)
314 if token == nil { 331 if token == nil {
315 break 332 break
316 } 333 }
317 result += token.Text 334 result += token.MkText
318 if token.Quoting != q { 335 if token.Quoting != q {
319 q = token.Quoting 336 q = token.Quoting
320 result += "[" + q.String() + "]" 337 result += "[" + q.String() + "]"
321 } 338 }
322 } 339 }
323 c.Check(result, equals, expectedOutput) 340 c.Check(result, equals, expectedOutput)
324 c.Check(p.Rest(), equals, "") 341 c.Check(p.Rest(), equals, "")
325 } 342 }
326 343
327 checkQuotingChange("hello, world", "hello, world") 344 checkQuotingChange("hello, world", "hello, world")
328 checkQuotingChange("hello, \"world\"", "hello, \"[d]world\"[plain]") 345 checkQuotingChange("hello, \"world\"", "hello, \"[d]world\"[plain]")
329 checkQuotingChange("1 \"\" 2 '' 3 `` 4", "1 \"[d]\"[plain] 2 '[s]'[plain] 3 `[b]`[plain] 4") 346 checkQuotingChange("1 \"\" 2 '' 3 `` 4", "1 \"[d]\"[plain] 2 '[s]'[plain] 3 `[b]`[plain] 4")
330 checkQuotingChange("\"\"", "\"[d]\"[plain]") 347 checkQuotingChange("\"\"", "\"[d]\"[plain]")

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

--- pkgsrc/pkgtools/pkglint/files/Attic/shtypes.go 2016/06/05 11:24:32 1.1
+++ pkgsrc/pkgtools/pkglint/files/Attic/shtypes.go 2016/07/07 12:09:27 1.2
@@ -13,108 +13,112 @@ const ( @@ -13,108 +13,112 @@ const (
13 shtVaruse // ${PREFIX} 13 shtVaruse // ${PREFIX}
14 shtWord // 14 shtWord //
15 shtSemicolon // ; 15 shtSemicolon // ;
16 shtCaseSeparator // ;; 16 shtCaseSeparator // ;;
17 shtParenOpen // ( 17 shtParenOpen // (
18 shtParenClose // ) 18 shtParenClose // )
19 shtPipe // | 19 shtPipe // |
20 shtBackground // & 20 shtBackground // &
21 shtOr // || 21 shtOr // ||
22 shtAnd // && 22 shtAnd // &&
23 shtRedirect // >, <, >> 23 shtRedirect // >, <, >>
24 shtComment // # ... 24 shtComment // # ...
25 shtSubshell // $$( 25 shtSubshell // $$(
 26 shtNewline // \n
26) 27)
27 28
28func (t ShAtomType) String() string { 29func (t ShAtomType) String() string {
29 return [...]string{ 30 return [...]string{
30 "space", 31 "space",
31 "varuse", 32 "varuse",
32 "word", 33 "word",
33 "semicolon", 34 "semicolon",
34 "caseSeparator", 35 "caseSeparator",
35 "parenOpen", "parenClose", 36 "parenOpen", "parenClose",
36 "pipe", "background", 37 "pipe", "background",
37 "or", "and", 38 "or", "and",
38 "redirect", 39 "redirect",
39 "comment", 40 "comment",
 41 "newline",
40 }[t] 42 }[t]
41} 43}
42 44
43func (t ShAtomType) IsWord() bool { 45func (t ShAtomType) IsWord() bool {
44 switch t { 46 switch t {
45 case shtVaruse, shtWord, shtRedirect: 47 case shtVaruse, shtWord, shtRedirect:
46 return true 48 return true
47 } 49 }
48 return false 50 return false
49} 51}
50 52
51func (t ShAtomType) IsCommandDelimiter() bool { 53func (t ShAtomType) IsCommandDelimiter() bool {
52 switch t { 54 switch t {
53 case shtSemicolon, shtPipe, shtBackground, shtAnd, shtOr, shtCaseSeparator: 55 case shtSemicolon, shtNewline, shtPipe, shtBackground, shtAnd, shtOr, shtCaseSeparator:
54 return true 56 return true
55 } 57 }
56 return false 58 return false
57} 59}
58 60
59// @Beta 61// @Beta
60type ShAtom struct { 62type ShAtom struct {
61 Type ShAtomType 63 Type ShAtomType
62 Text string 64 MkText string
63 Quoting ShQuoting 65 Quoting ShQuoting
64 Data interface{} 66 Data interface{}
65} 67}
66 68
67func NewShAtom(typ ShAtomType, text string, quoting ShQuoting) *ShAtom { 69func NewShAtom(typ ShAtomType, text string, quoting ShQuoting) *ShAtom {
68 return &ShAtom{typ, text, quoting, nil} 70 return &ShAtom{typ, text, quoting, nil}
69} 71}
70 72
71func NewShAtomVaruse(text string, quoting ShQuoting, varname string, modifiers ...string) *ShAtom { 73func NewShAtomVaruse(text string, quoting ShQuoting, varname string, modifiers ...string) *ShAtom {
72 return &ShAtom{shtVaruse, text, quoting, NewMkVarUse(varname, modifiers...)} 74 return &ShAtom{shtVaruse, text, quoting, NewMkVarUse(varname, modifiers...)}
73} 75}
74 76
75func (token *ShAtom) String() string { 77func (token *ShAtom) String() string {
76 if token.Type == shtWord && token.Quoting == shqPlain && token.Data == nil { 78 if token.Type == shtWord && token.Quoting == shqPlain && token.Data == nil {
77 return fmt.Sprintf("%q", token.Text) 79 return fmt.Sprintf("%q", token.MkText)
78 } 80 }
79 if token.Type == shtVaruse { 81 if token.Type == shtVaruse {
80 varuse := token.Data.(*MkVarUse) 82 varuse := token.Data.(*MkVarUse)
81 return fmt.Sprintf("varuse(%q)", varuse.varname+varuse.Mod()) 83 return fmt.Sprintf("varuse(%q)", varuse.varname+varuse.Mod())
82 } 84 }
83 return fmt.Sprintf("ShAtom(%v, %q, %s)", token.Type, token.Text, token.Quoting) 85 return fmt.Sprintf("ShAtom(%v, %q, %s)", token.Type, token.MkText, token.Quoting)
84} 86}
85 87
86// ShQuoting describes the context in which a string appears 88// ShQuoting describes the context in which a string appears
87// and how it must be unescaped to get its literal value. 89// and how it must be unescaped to get its literal value.
88type ShQuoting uint8 90type ShQuoting uint8
89 91
90const ( 92const (
91 shqPlain ShQuoting = iota 93 shqPlain ShQuoting = iota
92 shqDquot 94 shqDquot
93 shqSquot 95 shqSquot
94 shqBackt 96 shqBackt
 97 shqSubsh
95 shqDquotBackt 98 shqDquotBackt
96 shqBacktDquot 99 shqBacktDquot
97 shqBacktSquot 100 shqBacktSquot
 101 shqSubshSquot
98 shqDquotBacktDquot 102 shqDquotBacktDquot
99 shqDquotBacktSquot 103 shqDquotBacktSquot
100 shqUnknown 104 shqUnknown
101) 105)
102 106
103func (q ShQuoting) String() string { 107func (q ShQuoting) String() string {
104 return [...]string{ 108 return [...]string{
105 "plain", 109 "plain",
106 "d", "s", "b", 110 "d", "s", "b", "S",
107 "db", "bd", "bs", 111 "db", "bd", "bs", "Ss",
108 "dbd", "dbs", 112 "dbd", "dbs",
109 "unknown", 113 "unknown",
110 }[q] 114 }[q]
111} 115}
112 116
113func (q ShQuoting) ToVarUseContext() vucQuoting { 117func (q ShQuoting) ToVarUseContext() vucQuoting {
114 switch q { 118 switch q {
115 case shqPlain: 119 case shqPlain:
116 return vucQuotPlain 120 return vucQuotPlain
117 case shqDquot: 121 case shqDquot:
118 return vucQuotDquot 122 return vucQuotDquot
119 case shqSquot: 123 case shqSquot:
120 return vucQuotSquot 124 return vucQuotSquot

File Added: pkgsrc/pkgtools/pkglint/files/Attic/mkshwalker.go
package main

type MkShWalker struct {
}

func (w *MkShWalker) Walk(list *MkShList, callback func(node interface{})) {
	for element := range w.iterate(list) {
		callback(element)
	}
}

func (w *MkShWalker) iterate(list *MkShList) chan interface{} {
	elements := make(chan interface{})

	go func() {
		w.walkList(list, elements)
		close(elements)
	}()

	return elements
}

func (w *MkShWalker) walkList(list *MkShList, collector chan interface{}) {
	collector <- list

	for _, andor := range list.AndOrs {
		w.walkAndOr(andor, collector)
	}
}

func (w *MkShWalker) walkAndOr(andor *MkShAndOr, collector chan interface{}) {
	collector <- andor

	for _, pipeline := range andor.Pipes {
		w.walkPipeline(pipeline, collector)
	}
}

func (w *MkShWalker) walkPipeline(pipeline *MkShPipeline, collector chan interface{}) {
	collector <- pipeline

	for _, command := range pipeline.Cmds {
		w.walkCommand(command, collector)
	}
}

func (w *MkShWalker) walkCommand(command *MkShCommand, collector chan interface{}) {
	collector <- command

	switch {
	case command.Simple != nil:
		w.walkSimpleCommand(command.Simple, collector)
	case command.Compound != nil:
		w.walkCompoundCommand(command.Compound, collector)
		w.walkRedirects(command.Redirects, collector)
	case command.FuncDef != nil:
		w.walkFunctionDefinition(command.FuncDef, collector)
		w.walkRedirects(command.Redirects, collector)
	}
}

func (w *MkShWalker) walkSimpleCommand(command *MkShSimpleCommand, collector chan interface{}) {
	collector <- command

	w.walkWords(command.Assignments, collector)
	if command.Name != nil {
		w.walkWord(command.Name, collector)
	}
	w.walkWords(command.Args, collector)
	w.walkRedirects(command.Redirections, collector)
}

func (w *MkShWalker) walkCompoundCommand(command *MkShCompoundCommand, collector chan interface{}) {
	collector <- command

	switch {
	case command.Brace != nil:
		w.walkList(command.Brace, collector)
	case command.Case != nil:
		w.walkCase(command.Case, collector)
	case command.For != nil:
		w.walkFor(command.For, collector)
	case command.If != nil:
		w.walkIf(command.If, collector)
	case command.Loop != nil:
		w.walkLoop(command.Loop, collector)
	case command.Subshell != nil:
		w.walkList(command.Subshell, collector)
	}
}

func (w *MkShWalker) walkCase(caseClause *MkShCaseClause, collector chan interface{}) {
	collector <- caseClause

	w.walkWord(caseClause.Word, collector)
	for _, caseItem := range caseClause.Cases {
		collector <- caseItem
		w.walkWords(caseItem.Patterns, collector)
		w.walkList(caseItem.Action, collector)
	}
}

func (w *MkShWalker) walkFunctionDefinition(funcdef *MkShFunctionDefinition, collector chan interface{}) {
	collector <- funcdef

	w.walkCompoundCommand(funcdef.Body, collector)
}

func (w *MkShWalker) walkIf(ifClause *MkShIfClause, collector chan interface{}) {
	collector <- ifClause
	for i, cond := range ifClause.Conds {
		w.walkList(cond, collector)
		w.walkList(ifClause.Actions[i], collector)
	}
	if ifClause.Else != nil {
		w.walkList(ifClause.Else, collector)
	}
}

func (w *MkShWalker) walkLoop(loop *MkShLoopClause, collector chan interface{}) {
	collector <- loop
	w.walkList(loop.Cond, collector)
	w.walkList(loop.Action, collector)
}

func (w *MkShWalker) walkWords(words []*ShToken, collector chan interface{}) {
	collector <- words

	for _, word := range words {
		w.walkWord(word, collector)
	}
}

func (w *MkShWalker) walkWord(word *ShToken, collector chan interface{}) {
	collector <- word
}

func (w *MkShWalker) walkRedirects(redirects []*MkShRedirection, collector chan interface{}) {
	collector <- redirects

	for _, redirect := range redirects {
		collector <- redirect
		w.walkWord(redirect.Target, collector)
	}
}

func (w *MkShWalker) walkFor(forClause *MkShForClause, collector chan interface{}) {
	collector <- forClause

	collector <- forClause.Varname
	w.walkWords(forClause.Values, collector)
	w.walkList(forClause.Body, collector)
}

File Added: pkgsrc/pkgtools/pkglint/files/Attic/mkshwalker_test.go
package main

import (
	"gopkg.in/check.v1"
)

func (s *Suite) Test_MkShWalker_Walk(c *check.C) {
	list, err := parseShellProgram(dummyLine, ""+
		"if condition; then action; else case selector in pattern) case-item-action ;; esac; fi; "+
		"set -e; cd ${WRKSRC}/locale; "+
		"for lang in *.po; do "+
		"  [ \"$${lang}\" = \"wxstd.po\" ] && continue; "+
		"  ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; "+
		"done")
	if c.Check(err, check.IsNil) && c.Check(list, check.NotNil) {
		var commands []string
		(*MkShWalker).Walk(nil, list, func(node interface{}) {
			if cmd, ok := node.(*MkShSimpleCommand); ok {
				commands = append(commands, NewStrCommand(cmd).String())
			}
		})
		c.Check(commands, deepEquals, []string{
			"[] condition []",
			"[] action []",
			"[] case-item-action []",
			"[] set [-e]",
			"[] cd [${WRKSRC}/locale]",
			"[] [ [\"$${lang}\" = \"wxstd.po\" ]]",
			"[] continue []",
			"[] ${TOOLS_PATH.msgfmt} [-c -o \"$${lang%.po}.mo\" \"$${lang}\"]"})
	}
}

File Added: pkgsrc/pkgtools/pkglint/files/Attic/shell.y
%{
package main
%}

%token <Word> tkWORD
%token <Word> tkASSIGNMENT_WORD
%token tkNEWLINE
%token <IONum> tkIO_NUMBER
%token tkBACKGROUND
%token tkPIPE tkSEMI
%token tkAND tkOR tkSEMISEMI
%token tkLT tkGT tkLTLT tkGTGT tkLTAND tkGTAND  tkLTGT tkLTLTDASH tkGTPIPE
%token tkIF tkTHEN tkELSE tkELIF tkFI tkDO tkDONE
%token tkCASE tkESAC tkWHILE tkUNTIL tkFOR
%token tkLPAREN tkRPAREN tkLBRACE tkRBRACE tkEXCLAM
%token tkIN

%union {
	IONum int
	List *MkShList
	AndOr *MkShAndOr
	Pipeline *MkShPipeline
	Command *MkShCommand
	CompoundCommand *MkShCompoundCommand
	Separator MkShSeparator
	Simple *MkShSimpleCommand
	FuncDef *MkShFunctionDefinition
	For *MkShForClause
	If *MkShIfClause
	Case *MkShCaseClause
	CaseItem *MkShCaseItem
	Loop *MkShLoopClause
	Words []*ShToken
	Word *ShToken
	Redirections []*MkShRedirection
	Redirection *MkShRedirection
}

%type <List> start program compound_list brace_group subshell term do_group
%type <AndOr> and_or
%type <Pipeline> pipeline pipe_sequence
%type <Command> command
%type <CompoundCommand> compound_command
%type <Separator> separator separator_op sequential_sep
%type <Simple> simple_command cmd_prefix cmd_suffix
%type <FuncDef> function_definition
%type <For> for_clause
%type <If> if_clause else_part
%type <Case> case_clause case_list case_list_ns
%type <CaseItem> case_item case_item_ns
%type <Loop> while_clause until_clause
%type <Words> wordlist case_selector pattern
%type <Word> filename cmd_word here_end
%type <Redirections> redirect_list
%type <Redirection> io_redirect io_file io_here

%%

start : program {
	shyylex.(*ShellLexer).result = $$
}

program : compound_list {
	$$ = $1
}
program : /* empty */ {
	$$ = &MkShList{}
}

and_or : pipeline {
	$$ = NewMkShAndOr($1)
}
and_or : and_or tkAND linebreak pipeline {
	$$.Add("&&", $4)
}
and_or : and_or tkOR linebreak pipeline {
	$$.Add("||", $4)
}

pipeline : pipe_sequence {
	/* empty */
}
pipeline : tkEXCLAM pipe_sequence {
	$$ = $2
	$$.Negated = true
}

pipe_sequence : command {
	$$ = NewMkShPipeline(false, $1)
}
pipe_sequence : pipe_sequence tkPIPE linebreak command {
	$$.Add($4)
}

command : simple_command {
	$$ = &MkShCommand{Simple: $1}
}
command : compound_command {
	$$ = &MkShCommand{Compound: $1}
}
command : compound_command redirect_list {
	$$ = &MkShCommand{Compound: $1, Redirects: $2}
}
command : function_definition {
	$$ = &MkShCommand{FuncDef: $1}
}
command : function_definition redirect_list {
	$$ = &MkShCommand{FuncDef: $1, Redirects: $2}
}

compound_command : brace_group {
	$$ = &MkShCompoundCommand{Brace: $1}
}
compound_command : subshell {
	$$ = &MkShCompoundCommand{Subshell: $1}
}
compound_command : for_clause {
	$$ = &MkShCompoundCommand{For: $1}
}
compound_command : case_clause {
	$$ = &MkShCompoundCommand{Case: $1}
}
compound_command : if_clause {
	$$ = &MkShCompoundCommand{If: $1}
}
compound_command : while_clause {
	$$ = &MkShCompoundCommand{Loop: $1}
}
compound_command : until_clause {
	$$ = &MkShCompoundCommand{Loop: $1}
}

subshell : tkLPAREN compound_list tkRPAREN {
	$$ = $2
}

compound_list : linebreak term {
	$$ = $2
}
compound_list : linebreak term separator {
	$$ = $2
	$$.AddSeparator($3)
}

term : and_or {
	$$ = NewMkShList()
	$$.AddAndOr($1)
}
term : term separator and_or {
	$$.AddSeparator($2)
	$$.AddAndOr($3)
}

for_clause : tkFOR tkWORD linebreak do_group {
	args := NewShToken("\"$$@\"",
		NewShAtom(shtWord, "\"",shqDquot),
		NewShAtom(shtWord, "$$@",shqDquot),
		NewShAtom(shtWord,"\"",shqPlain))
	$$ = &MkShForClause{$2.MkText, []*ShToken{args}, $4}
}
for_clause : tkFOR tkWORD linebreak tkIN sequential_sep do_group {
	$$ = &MkShForClause{$2.MkText, nil, $6}
}
for_clause : tkFOR tkWORD linebreak tkIN wordlist sequential_sep do_group {
	$$ = &MkShForClause{$2.MkText, $5, $7}
}

wordlist : tkWORD {
	$$ = append($$, $1)
}
wordlist : wordlist tkWORD {
	$$ = append($$, $2)
}

case_clause : tkCASE tkWORD linebreak tkIN linebreak case_list tkESAC {
	$$ = $6
	$$.Word = $2
}
case_clause : tkCASE tkWORD linebreak tkIN linebreak case_list_ns tkESAC {
	$$ = $6
	$$.Word = $2
}
case_clause : tkCASE tkWORD linebreak tkIN linebreak tkESAC {
	$$ = &MkShCaseClause{$2, nil}
}

case_list_ns : case_item_ns {
	$$ = &MkShCaseClause{nil, nil}
	$$.Cases = append($$.Cases, $1)
}
case_list_ns : case_list case_item_ns {
	$$.Cases = append($$.Cases, $2)
}

case_list : case_item {
	$$ = &MkShCaseClause{nil, nil}
	$$.Cases = append($$.Cases, $1)
}
case_list : case_list case_item {
	$$.Cases = append($$.Cases, $2)
}

case_selector : tkLPAREN pattern tkRPAREN {
	$$ = $2
}
case_selector : pattern tkRPAREN {
	/* empty */
}

case_item_ns : case_selector linebreak {
	$$ = &MkShCaseItem{$1, &MkShList{}, nil}
}
case_item_ns : case_selector linebreak term linebreak {
	$$ = &MkShCaseItem{$1, $3, nil}
}
case_item_ns : case_selector linebreak term separator_op linebreak {
	$$ = &MkShCaseItem{$1, $3, &$4}
}

case_item : case_selector linebreak tkSEMISEMI linebreak {
	$$ = &MkShCaseItem{$1, &MkShList{}, nil}
}
case_item : case_selector compound_list tkSEMISEMI linebreak {
	$$ = &MkShCaseItem{$1, $2, nil}
}

pattern : tkWORD {
	$$ = nil
	$$ = append($$, $1)
}
pattern : pattern tkPIPE tkWORD {
	$$ = append($$, $3)
}

if_clause : tkIF compound_list tkTHEN compound_list else_part tkFI {
	$$ = $5
	$$.Prepend($2, $4)
}
if_clause : tkIF compound_list tkTHEN compound_list tkFI {
	$$ = &MkShIfClause{}
	$$.Prepend($2, $4)
}

else_part : tkELIF compound_list tkTHEN compound_list {
	$$ = &MkShIfClause{}
	$$.Prepend($2, $4)
}
else_part : tkELIF compound_list tkTHEN compound_list else_part {
	$$ = $5
	$$.Prepend($2, $4)
}
else_part : tkELSE compound_list {
	$$ = &MkShIfClause{nil, nil, $2}
}

while_clause : tkWHILE compound_list do_group {
	$$ = &MkShLoopClause{$2, $3, false}
}
until_clause : tkUNTIL compound_list do_group {
	$$ = &MkShLoopClause{$2, $3, true}
}

function_definition : tkWORD tkLPAREN tkRPAREN linebreak compound_command { /* Apply rule 9 */
	$$ = &MkShFunctionDefinition{$1.MkText, $5}
}

brace_group : tkLBRACE compound_list tkRBRACE {
	$$ = $2
}

do_group : tkDO compound_list tkDONE {
	$$ = $2
}

simple_command : cmd_prefix cmd_word cmd_suffix {
	$$.Name = $2
	$$.Args = append($$.Args, $3.Args...)
	$$.Redirections = append($$.Redirections, $3.Redirections...)
}
simple_command : cmd_prefix cmd_word {
	$$.Name = $2
}
simple_command : cmd_prefix {
	/* empty */
}
simple_command : tkWORD cmd_suffix {
	$$ = $2
	$$.Name = $1
}
simple_command : tkWORD {
	$$ = &MkShSimpleCommand{Name: $1}
}

cmd_word : tkWORD { /* Apply rule 7b */
	/* empty */
}

cmd_prefix : io_redirect {
	$$ = &MkShSimpleCommand{}
	$$.Redirections = append($$.Redirections, $1)
}
cmd_prefix : tkASSIGNMENT_WORD {
	$$ = &MkShSimpleCommand{}
	$$.Assignments = append($$.Assignments, $1)
}
cmd_prefix : cmd_prefix io_redirect {
	$$.Redirections = append($$.Redirections, $2)
}
cmd_prefix : cmd_prefix tkASSIGNMENT_WORD {
	$$.Assignments = append($$.Assignments, $2)
}

cmd_suffix : io_redirect {
	$$ = &MkShSimpleCommand{}
	$$.Redirections = append($$.Redirections, $1)
}
cmd_suffix : tkWORD {
	$$ = &MkShSimpleCommand{}
	$$.Args = append($$.Args, $1)
}
cmd_suffix : cmd_suffix io_redirect {
	$$.Redirections = append($$.Redirections, $2)
}
cmd_suffix : cmd_suffix tkWORD {
	$$.Args = append($$.Args, $2)
}

redirect_list : io_redirect {
	$$ = nil
	$$ = append($$, $1)
}
redirect_list : redirect_list io_redirect {
	$$ = append($$, $2)
}

io_redirect : io_file {
	/* empty */
}
io_redirect : tkIO_NUMBER io_file {
	$$ = $2
	$$.Fd = $1
}

io_redirect : io_here {
	/* empty */
}
io_redirect : tkIO_NUMBER io_here {
	$$ = $2
	$$.Fd = $1
}

io_file : tkLT filename {
	$$ = &MkShRedirection{-1, "<", $2}
}
io_file : tkLTAND filename {
	$$ = &MkShRedirection{-1, "<&", $2}
}
io_file : tkGT filename {
	$$ = &MkShRedirection{-1, ">", $2}
}
io_file : tkGTAND filename {
	$$ = &MkShRedirection{-1, ">&", $2}
}
io_file : tkGTGT filename {
	$$ = &MkShRedirection{-1, ">>", $2}
}
io_file : tkLTGT filename {
	$$ = &MkShRedirection{-1, "<>", $2}
}
io_file : tkGTPIPE filename {
	$$ = &MkShRedirection{-1, ">|", $2}
}

filename : tkWORD { /* Apply rule 2 */
	/* empty */
}

io_here : tkLTLT here_end {
	$$ = &MkShRedirection{-1, "<<", $2}
}
io_here : tkLTLTDASH here_end {
	$$ = &MkShRedirection{-1, "<<-", $2}
}

here_end : tkWORD { /* Apply rule 3 */
	/* empty */
}

newline_list : tkNEWLINE {
	/* empty */
}
newline_list : newline_list tkNEWLINE {
	/* empty */
}

linebreak : newline_list {
	/* empty */
}
linebreak : /* empty */ {
	/* empty */
}

separator_op : tkBACKGROUND {
	$$ = "&"
}
separator_op : tkSEMI {
	$$ = ";"
}

separator : separator_op linebreak {
	/* empty */
}
separator : newline_list {
	$$ = "\n"
}

sequential_sep : tkSEMI linebreak {
	$$ = ";"
}
sequential_sep : tkNEWLINE linebreak {
	$$ = "\n"
}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/package.go 2016/06/05 11:24:32 1.8
+++ pkgsrc/pkgtools/pkglint/files/Attic/package.go 2016/07/07 12:09:27 1.9
@@ -1,17 +1,18 @@ @@ -1,17 +1,18 @@
1package main 1package main
2 2
3import ( 3import (
4 "fmt" 4 "fmt"
 5 "os/user"
5 "path" 6 "path"
6 "regexp" 7 "regexp"
7 "strconv" 8 "strconv"
8 "strings" 9 "strings"
9) 10)
10 11
11// Package contains data for the pkgsrc package that is currently checked. 12// Package contains data for the pkgsrc package that is currently checked.
12type Package struct { 13type Package struct {
13 Pkgpath string // e.g. "category/pkgdir" 14 Pkgpath string // e.g. "category/pkgdir"
14 Pkgdir string // PKGDIR from the package Makefile 15 Pkgdir string // PKGDIR from the package Makefile
15 Filesdir string // FILESDIR from the package Makefile 16 Filesdir string // FILESDIR from the package Makefile
16 Patchdir string // PATCHDIR from the package Makefile 17 Patchdir string // PATCHDIR from the package Makefile
17 DistinfoFile string // DISTINFO_FILE from the package Makefile 18 DistinfoFile string // DISTINFO_FILE from the package Makefile
@@ -186,26 +187,27 @@ func checkdirPackage(pkgpath string) { @@ -186,26 +187,27 @@ func checkdirPackage(pkgpath string) {
186 } 187 }
187 if fname == G.CurrentDir+"/Makefile" { 188 if fname == G.CurrentDir+"/Makefile" {
188 if G.opts.CheckMakefile { 189 if G.opts.CheckMakefile {
189 pkg.checkfilePackageMakefile(fname, lines) 190 pkg.checkfilePackageMakefile(fname, lines)
190 } 191 }
191 } else { 192 } else {
192 Checkfile(fname) 193 Checkfile(fname)
193 } 194 }
194 if contains(fname, "/patches/patch-") { 195 if contains(fname, "/patches/patch-") {
195 havePatches = true 196 havePatches = true
196 } else if hasSuffix(fname, "/distinfo") { 197 } else if hasSuffix(fname, "/distinfo") {
197 haveDistinfo = true 198 haveDistinfo = true
198 } 199 }
 200 pkg.checkLocallyModified(fname)
199 } 201 }
200 202
201 if G.opts.CheckDistinfo && G.opts.CheckPatches { 203 if G.opts.CheckDistinfo && G.opts.CheckPatches {
202 if havePatches && !haveDistinfo { 204 if havePatches && !haveDistinfo {
203 NewLineWhole(G.CurrentDir+"/"+pkg.DistinfoFile).Warn1("File not found. Please run \"%s makepatchsum\".", confMake) 205 NewLineWhole(G.CurrentDir+"/"+pkg.DistinfoFile).Warn1("File not found. Please run \"%s makepatchsum\".", confMake)
204 } 206 }
205 } 207 }
206 208
207 if !isEmptyDir(G.CurrentDir + "/scripts") { 209 if !isEmptyDir(G.CurrentDir + "/scripts") {
208 NewLineWhole(G.CurrentDir + "/scripts").Warn0("This directory and its contents are deprecated! Please call the script(s) explicitly from the corresponding target(s) in the pkg's Makefile.") 210 NewLineWhole(G.CurrentDir + "/scripts").Warn0("This directory and its contents are deprecated! Please call the script(s) explicitly from the corresponding target(s) in the pkg's Makefile.")
209 } 211 }
210} 212}
211 213
@@ -377,27 +379,27 @@ func (pkg *Package) checkfilePackageMake @@ -377,27 +379,27 @@ func (pkg *Package) checkfilePackageMake
377 if distinfoFile := G.CurrentDir + "/" + pkg.DistinfoFile; fileExists(distinfoFile) { 379 if distinfoFile := G.CurrentDir + "/" + pkg.DistinfoFile; fileExists(distinfoFile) {
378 NewLineWhole(distinfoFile).Warn0("This file should not exist if NO_CHECKSUM or META_PACKAGE is set.") 380 NewLineWhole(distinfoFile).Warn0("This file should not exist if NO_CHECKSUM or META_PACKAGE is set.")
379 } 381 }
380 } else { 382 } else {
381 if distinfoFile := G.CurrentDir + "/" + pkg.DistinfoFile; !containsVarRef(distinfoFile) && !fileExists(distinfoFile) { 383 if distinfoFile := G.CurrentDir + "/" + pkg.DistinfoFile; !containsVarRef(distinfoFile) && !fileExists(distinfoFile) {
382 NewLineWhole(distinfoFile).Warn1("File not found. Please run \"%s makesum\".", confMake) 384 NewLineWhole(distinfoFile).Warn1("File not found. Please run \"%s makesum\".", confMake)
383 } 385 }
384 } 386 }
385 387
386 if perlLine, noconfLine := vardef["REPLACE_PERL"], vardef["NO_CONFIGURE"]; perlLine != nil && noconfLine != nil { 388 if perlLine, noconfLine := vardef["REPLACE_PERL"], vardef["NO_CONFIGURE"]; perlLine != nil && noconfLine != nil {
387 perlLine.Warn1("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.Line.ReferenceFrom(perlLine.Line)) 389 perlLine.Warn1("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.Line.ReferenceFrom(perlLine.Line))
388 } 390 }
389 391
390 if vardef["LICENSE"] == nil { 392 if vardef["LICENSE"] == nil && vardef["META_PACKAGE"] == nil {
391 NewLineWhole(fname).Error0("Each package must define its LICENSE.") 393 NewLineWhole(fname).Error0("Each package must define its LICENSE.")
392 } 394 }
393 395
394 if gnuLine, useLine := vardef["GNU_CONFIGURE"], vardef["USE_LANGUAGES"]; gnuLine != nil && useLine != nil { 396 if gnuLine, useLine := vardef["GNU_CONFIGURE"], vardef["USE_LANGUAGES"]; gnuLine != nil && useLine != nil {
395 if matches(useLine.Comment(), `(?-i)\b(?:c|empty|none)\b`) { 397 if matches(useLine.Comment(), `(?-i)\b(?:c|empty|none)\b`) {
396 // Don't emit a warning, since the comment 398 // Don't emit a warning, since the comment
397 // probably contains a statement that C is 399 // probably contains a statement that C is
398 // really not needed. 400 // really not needed.
399 401
400 } else if !matches(useLine.Value(), `(?:^|\s+)(?:c|c99|objc)(?:\s+|$)`) { 402 } else if !matches(useLine.Value(), `(?:^|\s+)(?:c|c99|objc)(?:\s+|$)`) {
401 gnuLine.Warn1("GNU_CONFIGURE almost always needs a C compiler, but \"c\" is not added to USE_LANGUAGES in %s.", 403 gnuLine.Warn1("GNU_CONFIGURE almost always needs a C compiler, but \"c\" is not added to USE_LANGUAGES in %s.",
402 useLine.Line.ReferenceFrom(gnuLine.Line)) 404 useLine.Line.ReferenceFrom(gnuLine.Line))
403 } 405 }
@@ -474,39 +476,63 @@ func (pkg *Package) determineEffectivePk @@ -474,39 +476,63 @@ func (pkg *Package) determineEffectivePk
474 pkg.EffectivePkgbase = m1 476 pkg.EffectivePkgbase = m1
475 pkg.EffectivePkgversion = m2 477 pkg.EffectivePkgversion = m2
476 } 478 }
477 } 479 }
478 if pkg.EffectivePkgnameLine != nil { 480 if pkg.EffectivePkgnameLine != nil {
479 if G.opts.Debug { 481 if G.opts.Debug {
480 traceStep("Effective name=%q base=%q version=%q", 482 traceStep("Effective name=%q base=%q version=%q",
481 pkg.EffectivePkgname, pkg.EffectivePkgbase, pkg.EffectivePkgversion) 483 pkg.EffectivePkgname, pkg.EffectivePkgbase, pkg.EffectivePkgversion)
482 } 484 }
483 } 485 }
484} 486}
485 487
486func (pkg *Package) pkgnameFromDistname(pkgname, distname string) string { 488func (pkg *Package) pkgnameFromDistname(pkgname, distname string) string {
487 pkgname = strings.Replace(pkgname, "${DISTNAME}", distname, -1) 489 tokens := NewMkParser(dummyLine, pkgname, false).MkTokens()
488 490
489 if m, before, sep, subst, after := match4(pkgname, `^(.*)\$\{DISTNAME:S(.)([^\\}:]+)\}(.*)$`); m { 491 subst := func(str, smod string) (result string) {
490 qsep := regexp.QuoteMeta(sep) 492 if G.opts.Debug {
491 if m, left, from, right, to, mod := match5(subst, `^(\^?)([^:]*)(\$?)`+qsep+`([^:]*)`+qsep+`(g?)$`); m { 493 defer tracecall(str, smod, ref(result))()
492 newPkgname := before + mkopSubst(distname, left != "", from, right != "", to, mod != "") + after 494 }
 495 qsep := regexp.QuoteMeta(smod[1:2])
 496 if m, left, from, right, to, flags := match5(smod, `^S`+qsep+`(\^?)([^:]*?)(\$?)`+qsep+`([^:]*)`+qsep+`([1g]*)$`); m {
 497 result := mkopSubst(str, left != "", from, right != "", to, flags)
493 if G.opts.Debug { 498 if G.opts.Debug {
494 traceStep("%s: pkgnameFromDistname %q => %q", pkg.vardef["PKGNAME"], pkgname, newPkgname) 499 traceStep("subst %q %q => %q", str, smod, result)
495 } 500 }
496 pkgname = newPkgname 501 return result
497 } 502 }
 503 return str
498 } 504 }
499 return pkgname 505
 506 result := ""
 507 for _, token := range tokens {
 508 if token.Varuse != nil && token.Varuse.varname == "DISTNAME" {
 509 newDistname := distname
 510 for _, mod := range token.Varuse.modifiers {
 511 if mod == "tl" {
 512 newDistname = strings.ToLower(newDistname)
 513 } else if hasPrefix(mod, "S") {
 514 newDistname = subst(newDistname, mod)
 515 } else {
 516 newDistname = token.Text
 517 break
 518 }
 519 }
 520 result += newDistname
 521 } else {
 522 result += token.Text
 523 }
 524 }
 525 return result
500} 526}
501 527
502func (pkg *Package) checkUpdate() { 528func (pkg *Package) checkUpdate() {
503 if pkg.EffectivePkgbase != "" { 529 if pkg.EffectivePkgbase != "" {
504 for _, sugg := range G.globalData.GetSuggestedPackageUpdates() { 530 for _, sugg := range G.globalData.GetSuggestedPackageUpdates() {
505 if pkg.EffectivePkgbase != sugg.Pkgname { 531 if pkg.EffectivePkgbase != sugg.Pkgname {
506 continue 532 continue
507 } 533 }
508 534
509 suggver, comment := sugg.Version, sugg.Comment 535 suggver, comment := sugg.Version, sugg.Comment
510 if comment != "" { 536 if comment != "" {
511 comment = " (" + comment + ")" 537 comment = " (" + comment + ")"
512 } 538 }
@@ -748,13 +774,63 @@ func (mklines *MkLines) checkForUsedComm @@ -748,13 +774,63 @@ func (mklines *MkLines) checkForUsedComm
748 insertLine.Warn1("Please add a line %q here.", expected) 774 insertLine.Warn1("Please add a line %q here.", expected)
749 Explain( 775 Explain(
750 "Since Makefile.common files usually don't have any comments and", 776 "Since Makefile.common files usually don't have any comments and",
751 "therefore not a clearly defined interface, they should at least", 777 "therefore not a clearly defined interface, they should at least",
752 "contain references to all files that include them, so that it is", 778 "contain references to all files that include them, so that it is",
753 "easier to see what effects future changes may have.", 779 "easier to see what effects future changes may have.",
754 "", 780 "",
755 "If there are more than five packages that use a Makefile.common,", 781 "If there are more than five packages that use a Makefile.common,",
756 "you should think about giving it a proper name (maybe plugin.mk) and", 782 "you should think about giving it a proper name (maybe plugin.mk) and",
757 "documenting its interface.") 783 "documenting its interface.")
758 } 784 }
759 SaveAutofixChanges(lines) 785 SaveAutofixChanges(lines)
760} 786}
 787
 788func (pkg *Package) checkLocallyModified(fname string) {
 789 if G.opts.Debug {
 790 defer tracecall(fname)()
 791 }
 792
 793 ownerLine := pkg.vardef["OWNER"]
 794 maintainerLine := pkg.vardef["MAINTAINER"]
 795 owner := ""
 796 maintainer := ""
 797 if ownerLine != nil && !containsVarRef(ownerLine.Value()) {
 798 owner = ownerLine.Value()
 799 }
 800 if maintainerLine != nil && !containsVarRef(maintainerLine.Value()) && maintainerLine.Value() != "pkgsrc-users@NetBSD.org" {
 801 maintainer = maintainerLine.Value()
 802 }
 803 if owner == "" && maintainer == "" {
 804 return
 805 }
 806
 807 user, err := user.Current()
 808 if err != nil || user.Username == "" {
 809 return
 810 }
 811 // On Windows, this is `Computername\Username`.
 812 username := regcomp(`^.*\\`).ReplaceAllString(user.Username, "")
 813
 814 if G.opts.Debug {
 815 traceStep("user=%q owner=%q maintainer=%q", username, owner, maintainer)
 816 }
 817
 818 if username == strings.Split(owner, "@")[0] || username == strings.Split(maintainer, "@")[0] {
 819 return
 820 }
 821
 822 if isLocallyModified(fname) {
 823 if owner != "" {
 824 NewLineWhole(fname).Warn1("Don't commit changes to this file without asking the OWNER, %s.", owner)
 825 Explain2(
 826 "See the pkgsrc guide, section \"Package components\",",
 827 "keyword \"owner\", for more information.")
 828 }
 829 if maintainer != "" {
 830 NewLineWhole(fname).Note1("Please only commit changes that %s would approve.", maintainer)
 831 Explain2(
 832 "See the pkgsrc guide, section \"Package components\",",
 833 "keyword \"maintainer\", for more information.")
 834 }
 835 }
 836}

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

--- pkgsrc/pkgtools/pkglint/files/Attic/pkglint.go 2016/06/05 11:24:32 1.8
+++ pkgsrc/pkgtools/pkglint/files/Attic/pkglint.go 2016/07/07 12:09:27 1.9
@@ -192,27 +192,27 @@ func Checkfile(fname string) { @@ -192,27 +192,27 @@ func Checkfile(fname string) {
192 192
193 switch { 193 switch {
194 case st.Mode().IsDir(): 194 case st.Mode().IsDir():
195 switch { 195 switch {
196 case basename == "files" || basename == "patches" || basename == "CVS": 196 case basename == "files" || basename == "patches" || basename == "CVS":
197 // Ok 197 // Ok
198 case matches(fname, `(?:^|/)files/[^/]*$`): 198 case matches(fname, `(?:^|/)files/[^/]*$`):
199 // Ok 199 // Ok
200 case !isEmptyDir(fname): 200 case !isEmptyDir(fname):
201 NewLineWhole(fname).Warn0("Unknown directory name.") 201 NewLineWhole(fname).Warn0("Unknown directory name.")
202 } 202 }
203 203
204 case st.Mode()&os.ModeSymlink != 0: 204 case st.Mode()&os.ModeSymlink != 0:
205 if !matches(basename, `^work`) { 205 if !hasPrefix(basename, "work") {
206 NewLineWhole(fname).Warn0("Unknown symlink name.") 206 NewLineWhole(fname).Warn0("Unknown symlink name.")
207 } 207 }
208 208
209 case !st.Mode().IsRegular(): 209 case !st.Mode().IsRegular():
210 NewLineWhole(fname).Error0("Only files and directories are allowed in pkgsrc.") 210 NewLineWhole(fname).Error0("Only files and directories are allowed in pkgsrc.")
211 211
212 case basename == "ALTERNATIVES": 212 case basename == "ALTERNATIVES":
213 if G.opts.CheckAlternatives { 213 if G.opts.CheckAlternatives {
214 CheckfileExtra(fname) 214 CheckfileExtra(fname)
215 } 215 }
216 216
217 case basename == "buildlink3.mk": 217 case basename == "buildlink3.mk":
218 if G.opts.CheckBuildlink3 { 218 if G.opts.CheckBuildlink3 {
@@ -274,26 +274,29 @@ func Checkfile(fname string) { @@ -274,26 +274,29 @@ func Checkfile(fname string) {
274 } 274 }
275 } 275 }
276 276
277 case basename == "TODO" || basename == "README": 277 case basename == "TODO" || basename == "README":
278 // Ok 278 // Ok
279 279
280 case hasPrefix(basename, "CHANGES-"): 280 case hasPrefix(basename, "CHANGES-"):
281 // This only checks the file, but doesn’t register the changes globally. 281 // This only checks the file, but doesn’t register the changes globally.
282 G.globalData.loadDocChangesFromFile(fname) 282 G.globalData.loadDocChangesFromFile(fname)
283 283
284 case matches(fname, `(?:^|/)files/[^/]*$`): 284 case matches(fname, `(?:^|/)files/[^/]*$`):
285 // Skip 285 // Skip
286 286
 287 case basename == "spec":
 288 // Ok in regression tests
 289
287 default: 290 default:
288 NewLineWhole(fname).Warn0("Unexpected file found.") 291 NewLineWhole(fname).Warn0("Unexpected file found.")
289 if G.opts.CheckExtra { 292 if G.opts.CheckExtra {
290 CheckfileExtra(fname) 293 CheckfileExtra(fname)
291 } 294 }
292 } 295 }
293} 296}
294 297
295func ChecklinesTrailingEmptyLines(lines []*Line) { 298func ChecklinesTrailingEmptyLines(lines []*Line) {
296 max := len(lines) 299 max := len(lines)
297 last := max 300 last := max
298 for last > 1 && lines[last-1].Text == "" { 301 for last > 1 && lines[last-1].Text == "" {
299 last-- 302 last--

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

--- pkgsrc/pkgtools/pkglint/files/Attic/package_test.go 2016/06/05 11:24:32 1.7
+++ pkgsrc/pkgtools/pkglint/files/Attic/package_test.go 2016/07/07 12:09:27 1.8
@@ -4,26 +4,29 @@ import ( @@ -4,26 +4,29 @@ import (
4 check "gopkg.in/check.v1" 4 check "gopkg.in/check.v1"
5) 5)
6 6
7func (s *Suite) TestPkgnameFromDistname(c *check.C) { 7func (s *Suite) TestPkgnameFromDistname(c *check.C) {
8 pkg := NewPackage("dummy") 8 pkg := NewPackage("dummy")
9 pkg.vardef["PKGNAME"] = NewMkLine(NewLine("Makefile", 5, "PKGNAME=dummy", nil)) 9 pkg.vardef["PKGNAME"] = NewMkLine(NewLine("Makefile", 5, "PKGNAME=dummy", nil))
10 10
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")
 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")
17 20
18 c.Check(s.Output(), equals, "") 21 c.Check(s.Output(), equals, "")
19} 22}
20 23
21func (s *Suite) TestChecklinesPackageMakefileVarorder(c *check.C) { 24func (s *Suite) TestChecklinesPackageMakefileVarorder(c *check.C) {
22 s.UseCommandLine(c, "-Worder") 25 s.UseCommandLine(c, "-Worder")
23 pkg := NewPackage("x11/9term") 26 pkg := NewPackage("x11/9term")
24 27
25 pkg.ChecklinesPackageMakefileVarorder(s.NewMkLines("Makefile", 28 pkg.ChecklinesPackageMakefileVarorder(s.NewMkLines("Makefile",
26 "# $"+"NetBSD$", 29 "# $"+"NetBSD$",
27 "", 30 "",
28 "DISTNAME=9term", 31 "DISTNAME=9term",
29 "CATEGORIES=x11")) 32 "CATEGORIES=x11"))
@@ -147,26 +150,39 @@ func (s *Suite) TestCheckdirPackage(c *c @@ -147,26 +150,39 @@ func (s *Suite) TestCheckdirPackage(c *c
147 s.CreateTmpFile(c, "Makefile", ""+ 150 s.CreateTmpFile(c, "Makefile", ""+
148 "# $"+"NetBSD$\n") 151 "# $"+"NetBSD$\n")
149 G.CurrentDir = s.tmpdir 152 G.CurrentDir = s.tmpdir
150 153
151 checkdirPackage(s.tmpdir) 154 checkdirPackage(s.tmpdir)
152 155
153 c.Check(s.Output(), equals, ""+ 156 c.Check(s.Output(), equals, ""+
154 "WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?\n"+ 157 "WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?\n"+
155 "WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".\n"+ 158 "WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".\n"+
156 "ERROR: ~/Makefile: Each package must define its LICENSE.\n"+ 159 "ERROR: ~/Makefile: Each package must define its LICENSE.\n"+
157 "WARN: ~/Makefile: No COMMENT given.\n") 160 "WARN: ~/Makefile: No COMMENT given.\n")
158} 161}
159 162
 163func (s *Suite) Test_Package_Meta_package_License(c *check.C) {
 164 s.CreateTmpFileLines(c, "Makefile",
 165 "# $"+"NetBSD$",
 166 "",
 167 "META_PACKAGE=\tyes")
 168 G.CurrentDir = s.tmpdir
 169 G.globalData.InitVartypes()
 170
 171 checkdirPackage(s.tmpdir)
 172
 173 c.Check(s.Output(), equals, "WARN: ~/Makefile: No COMMENT given.\n") // No error about missing LICENSE.
 174}
 175
160func (s *Suite) Test_Package_Varuse_LoadTime(c *check.C) { 176func (s *Suite) Test_Package_Varuse_LoadTime(c *check.C) {
161 s.CreateTmpFileLines(c, "doc/CHANGES-2016", 177 s.CreateTmpFileLines(c, "doc/CHANGES-2016",
162 "# dummy") 178 "# dummy")
163 s.CreateTmpFileLines(c, "doc/TODO", 179 s.CreateTmpFileLines(c, "doc/TODO",
164 "# dummy") 180 "# dummy")
165 s.CreateTmpFileLines(c, "licenses/bsd-2", 181 s.CreateTmpFileLines(c, "licenses/bsd-2",
166 "# dummy") 182 "# dummy")
167 s.CreateTmpFileLines(c, "mk/fetch/sites.mk", 183 s.CreateTmpFileLines(c, "mk/fetch/sites.mk",
168 "# dummy") 184 "# dummy")
169 s.CreateTmpFileLines(c, "mk/bsd.pkg.mk", 185 s.CreateTmpFileLines(c, "mk/bsd.pkg.mk",
170 "# dummy") 186 "# dummy")
171 s.CreateTmpFileLines(c, "mk/defaults/options.description", 187 s.CreateTmpFileLines(c, "mk/defaults/options.description",
172 "option Description") 188 "option Description")

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

--- pkgsrc/pkgtools/pkglint/files/Attic/util.go 2016/06/05 11:24:32 1.7
+++ pkgsrc/pkgtools/pkglint/files/Attic/util.go 2016/07/07 12:09:27 1.8
@@ -74,26 +74,54 @@ func isCommitted(fname string) bool { @@ -74,26 +74,54 @@ func isCommitted(fname string) bool {
74 basename := path.Base(fname) 74 basename := path.Base(fname)
75 lines, err := readLines(path.Dir(fname)+"/CVS/Entries", false) 75 lines, err := readLines(path.Dir(fname)+"/CVS/Entries", false)
76 if err != nil { 76 if err != nil {
77 return false 77 return false
78 } 78 }
79 for _, line := range lines { 79 for _, line := range lines {
80 if hasPrefix(line.Text, "/"+basename+"/") { 80 if hasPrefix(line.Text, "/"+basename+"/") {
81 return true 81 return true
82 } 82 }
83 } 83 }
84 return false 84 return false
85} 85}
86 86
 87func isLocallyModified(fname string) bool {
 88 basename := path.Base(fname)
 89 lines, err := readLines(path.Dir(fname)+"/CVS/Entries", false)
 90 if err != nil {
 91 return false
 92 }
 93 for _, line := range lines {
 94 if hasPrefix(line.Text, "/"+basename+"/") {
 95 cvsModTime, err := time.Parse(time.ANSIC, strings.Split(line.Text, "/")[3])
 96 if err != nil {
 97 return false
 98 }
 99 st, err := os.Stat(fname)
 100 if err != nil {
 101 return false
 102 }
 103
 104 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724290(v=vs.85).aspx
 105 delta := cvsModTime.Unix() - st.ModTime().Unix()
 106 if G.opts.Debug {
 107 traceStep("cvs.time=%v fs.time=%v delta=%v", cvsModTime, st.ModTime(), delta)
 108 }
 109 return !(-2 <= delta && delta <= 2)
 110 }
 111 }
 112 return false
 113}
 114
87// Returns the number of columns that a string occupies when printed with 115// Returns the number of columns that a string occupies when printed with
88// a tabulator size of 8. 116// a tabulator size of 8.
89func tabLength(s string) int { 117func tabLength(s string) int {
90 length := 0 118 length := 0
91 for _, r := range s { 119 for _, r := range s {
92 if r == '\t' { 120 if r == '\t' {
93 length = length - length%8 + 8 121 length = length - length%8 + 8
94 } else { 122 } else {
95 length++ 123 length++
96 } 124 }
97 } 125 }
98 return length 126 return length
99} 127}
@@ -488,32 +516,36 @@ type Ref struct { @@ -488,32 +516,36 @@ type Ref struct {
488} 516}
489 517
490func ref(rv interface{}) Ref { 518func ref(rv interface{}) Ref {
491 return Ref{rv} 519 return Ref{rv}
492} 520}
493 521
494func (r Ref) String() string { 522func (r Ref) String() string {
495 ptr := reflect.ValueOf(r.intf) 523 ptr := reflect.ValueOf(r.intf)
496 ref := reflect.Indirect(ptr) 524 ref := reflect.Indirect(ptr)
497 return fmt.Sprintf("%v", ref) 525 return fmt.Sprintf("%v", ref)
498} 526}
499 527
500// Emulates make(1)’s :S substitution operator. 528// Emulates make(1)’s :S substitution operator.
501func mkopSubst(s string, left bool, from string, right bool, to string, all bool) string { 529func mkopSubst(s string, left bool, from string, right bool, to string, flags string) string {
 530 if G.opts.Debug {
 531 defer tracecall(s, left, from, right, to, flags)()
 532 }
502 re := ifelseStr(left, "^", "") + regexp.QuoteMeta(from) + ifelseStr(right, "$", "") 533 re := ifelseStr(left, "^", "") + regexp.QuoteMeta(from) + ifelseStr(right, "$", "")
503 done := false 534 done := false
 535 gflag := contains(flags, "g")
504 return regcomp(re).ReplaceAllStringFunc(s, func(match string) string { 536 return regcomp(re).ReplaceAllStringFunc(s, func(match string) string {
505 if all || !done { 537 if gflag || !done {
506 done = !all 538 done = !gflag
507 return to 539 return to
508 } 540 }
509 return match 541 return match
510 }) 542 })
511} 543}
512 544
513func relpath(from, to string) string { 545func relpath(from, to string) string {
514 absFrom, err1 := filepath.Abs(from) 546 absFrom, err1 := filepath.Abs(from)
515 absTo, err2 := filepath.Abs(to) 547 absTo, err2 := filepath.Abs(to)
516 rel, err3 := filepath.Rel(absFrom, absTo) 548 rel, err3 := filepath.Rel(absFrom, absTo)
517 if err1 != nil || err2 != nil || err3 != nil { 549 if err1 != nil || err2 != nil || err3 != nil {
518 panic("relpath" + argsStr(from, to, err1, err2, err3)) 550 panic("relpath" + argsStr(from, to, err1, err2, err3))
519 } 551 }

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

--- pkgsrc/pkgtools/pkglint/files/Attic/util_test.go 2016/01/12 01:02:49 1.3
+++ pkgsrc/pkgtools/pkglint/files/Attic/util_test.go 2016/07/07 12:09:27 1.4
@@ -1,44 +1,44 @@ @@ -1,44 +1,44 @@
1package main 1package main
2 2
3import ( 3import (
4 check "gopkg.in/check.v1" 4 check "gopkg.in/check.v1"
5) 5)
6 6
7func (s *Suite) TestMkopSubst_middle(c *check.C) { 7func (s *Suite) TestMkopSubst_middle(c *check.C) {
8 c.Check(mkopSubst("pkgname", false, "kgna", false, "ri", false), equals, "prime") 8 c.Check(mkopSubst("pkgname", false, "kgna", false, "ri", ""), equals, "prime")
9 c.Check(mkopSubst("pkgname", false, "pkgname", false, "replacement", false), equals, "replacement") 9 c.Check(mkopSubst("pkgname", false, "pkgname", false, "replacement", ""), equals, "replacement")
10} 10}
11 11
12func (s *Suite) TestMkopSubst_left(c *check.C) { 12func (s *Suite) TestMkopSubst_left(c *check.C) {
13 c.Check(mkopSubst("pkgname", true, "kgna", false, "ri", false), equals, "pkgname") 13 c.Check(mkopSubst("pkgname", true, "kgna", false, "ri", ""), equals, "pkgname")
14 c.Check(mkopSubst("pkgname", true, "pkgname", false, "replacement", false), equals, "replacement") 14 c.Check(mkopSubst("pkgname", true, "pkgname", false, "replacement", ""), equals, "replacement")
15} 15}
16 16
17func (s *Suite) TestMkopSubst_right(c *check.C) { 17func (s *Suite) TestMkopSubst_right(c *check.C) {
18 c.Check(mkopSubst("pkgname", false, "kgna", true, "ri", false), equals, "pkgname") 18 c.Check(mkopSubst("pkgname", false, "kgna", true, "ri", ""), equals, "pkgname")
19 c.Check(mkopSubst("pkgname", false, "pkgname", true, "replacement", false), equals, "replacement") 19 c.Check(mkopSubst("pkgname", false, "pkgname", true, "replacement", ""), equals, "replacement")
20} 20}
21 21
22func (s *Suite) TestMkopSubst_leftRight(c *check.C) { 22func (s *Suite) TestMkopSubst_leftRight(c *check.C) {
23 c.Check(mkopSubst("pkgname", true, "kgna", true, "ri", false), equals, "pkgname") 23 c.Check(mkopSubst("pkgname", true, "kgna", true, "ri", ""), equals, "pkgname")
24 c.Check(mkopSubst("pkgname", false, "pkgname", false, "replacement", false), equals, "replacement") 24 c.Check(mkopSubst("pkgname", false, "pkgname", false, "replacement", ""), equals, "replacement")
25} 25}
26 26
27func (s *Suite) TestMkopSubst_all(c *check.C) { 27func (s *Suite) TestMkopSubst_gflag(c *check.C) {
28 c.Check(mkopSubst("aaaaa", false, "a", false, "b", true), equals, "bbbbb") 28 c.Check(mkopSubst("aaaaa", false, "a", false, "b", "g"), equals, "bbbbb")
29 c.Check(mkopSubst("aaaaa", true, "a", false, "b", true), equals, "baaaa") 29 c.Check(mkopSubst("aaaaa", true, "a", false, "b", "g"), equals, "baaaa")
30 c.Check(mkopSubst("aaaaa", false, "a", true, "b", true), equals, "aaaab") 30 c.Check(mkopSubst("aaaaa", false, "a", true, "b", "g"), equals, "aaaab")
31 c.Check(mkopSubst("aaaaa", true, "a", true, "b", true), equals, "aaaaa") 31 c.Check(mkopSubst("aaaaa", true, "a", true, "b", "g"), equals, "aaaaa")
32} 32}
33 33
34func (s *Suite) TestReplaceFirst(c *check.C) { 34func (s *Suite) TestReplaceFirst(c *check.C) {
35 m, rest := replaceFirst("a+b+c+d", `(\w)(.)(\w)`, "X") 35 m, rest := replaceFirst("a+b+c+d", `(\w)(.)(\w)`, "X")
36 36
37 c.Assert(m, check.NotNil) 37 c.Assert(m, check.NotNil)
38 c.Check(m, check.DeepEquals, []string{"a+b", "a", "+", "b"}) 38 c.Check(m, check.DeepEquals, []string{"a+b", "a", "+", "b"})
39 c.Check(rest, equals, "X+c+d") 39 c.Check(rest, equals, "X+c+d")
40} 40}
41 41
42func (s *Suite) TestTabLength(c *check.C) { 42func (s *Suite) TestTabLength(c *check.C) {
43 c.Check(tabLength("12345"), equals, 5) 43 c.Check(tabLength("12345"), equals, 5)
44 c.Check(tabLength("\t"), equals, 8) 44 c.Check(tabLength("\t"), equals, 8)

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

--- pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck.go 2016/06/10 19:42:42 1.14
+++ pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck.go 2016/07/07 12:09:27 1.15
@@ -674,26 +674,31 @@ func (cv *VartypeCheck) PkgName() { @@ -674,26 +674,31 @@ func (cv *VartypeCheck) PkgName() {
674 cv.line.Warn1("%q is not a valid package name. A valid package name has the form packagename-version, where version consists only of digits, letters and dots.", cv.value) 674 cv.line.Warn1("%q is not a valid package name. A valid package name has the form packagename-version, where version consists only of digits, letters and dots.", cv.value)
675 } 675 }
676} 676}
677 677
678func (cv *VartypeCheck) PkgOptionsVar() { 678func (cv *VartypeCheck) PkgOptionsVar() {
679 cv.mkline.CheckVartypePrimitive(cv.varname, CheckvarVarname, cv.op, cv.value, cv.comment, false, cv.guessed) 679 cv.mkline.CheckVartypePrimitive(cv.varname, CheckvarVarname, cv.op, cv.value, cv.comment, false, cv.guessed)
680 if matches(cv.value, `\$\{PKGBASE[:\}]`) { 680 if matches(cv.value, `\$\{PKGBASE[:\}]`) {
681 cv.line.Error0("PKGBASE must not be used in PKG_OPTIONS_VAR.") 681 cv.line.Error0("PKGBASE must not be used in PKG_OPTIONS_VAR.")
682 Explain3( 682 Explain3(
683 "PKGBASE is defined in bsd.pkg.mk, which is included as the", 683 "PKGBASE is defined in bsd.pkg.mk, which is included as the",
684 "very last file, but PKG_OPTIONS_VAR is evaluated earlier.", 684 "very last file, but PKG_OPTIONS_VAR is evaluated earlier.",
685 "Use ${PKGNAME:C/-[0-9].*//} instead.") 685 "Use ${PKGNAME:C/-[0-9].*//} instead.")
686 } 686 }
 687
 688 // PR 46570, item "6. It should complain in PKG_OPTIONS_VAR is wrong"
 689 if !hasPrefix(cv.value, "PKG_OPTIONS.") {
 690 cv.line.Error2("PKG_OPTIONS_VAR must be of the form %q, not %q.", "PKG_OPTIONS.*", cv.value)
 691 }
687} 692}
688 693
689// A directory name relative to the top-level pkgsrc directory. 694// A directory name relative to the top-level pkgsrc directory.
690// Despite its name, it is more similar to RelativePkgDir than to RelativePkgPath. 695// Despite its name, it is more similar to RelativePkgDir than to RelativePkgPath.
691func (cv *VartypeCheck) PkgPath() { 696func (cv *VartypeCheck) PkgPath() {
692 cv.mkline.CheckRelativePkgdir(G.CurPkgsrcdir + "/" + cv.value) 697 cv.mkline.CheckRelativePkgdir(G.CurPkgsrcdir + "/" + cv.value)
693} 698}
694 699
695func (cv *VartypeCheck) PkgRevision() { 700func (cv *VartypeCheck) PkgRevision() {
696 if !matches(cv.value, `^[1-9]\d*$`) { 701 if !matches(cv.value, `^[1-9]\d*$`) {
697 cv.line.Warn1("%s must be a positive integer number.", cv.varname) 702 cv.line.Warn1("%s must be a positive integer number.", cv.varname)
698 } 703 }
699 if path.Base(cv.line.Fname) != "Makefile" { 704 if path.Base(cv.line.Fname) != "Makefile" {

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

--- pkgsrc/pkgtools/pkglint/files/Attic/vercmp_test.go 2016/01/12 01:02:49 1.2
+++ pkgsrc/pkgtools/pkglint/files/Attic/vercmp_test.go 2016/07/07 12:09:27 1.3
@@ -5,25 +5,60 @@ import ( @@ -5,25 +5,60 @@ import (
5) 5)
6 6
7func (s *Suite) TestMkversion(c *check.C) { 7func (s *Suite) TestMkversion(c *check.C) {
8 c.Check(newVersion("5.0"), check.DeepEquals, &version{[]int{5, 0, 0}, 0}) 8 c.Check(newVersion("5.0"), check.DeepEquals, &version{[]int{5, 0, 0}, 0})
9 c.Check(newVersion("5.0nb5"), check.DeepEquals, &version{[]int{5, 0, 0}, 5}) 9 c.Check(newVersion("5.0nb5"), check.DeepEquals, &version{[]int{5, 0, 0}, 5})
10 c.Check(newVersion("0.0.1-SNAPSHOT"), check.DeepEquals, &version{[]int{0, 0, 0, 0, 1, 19, 14, 1, 16, 19, 8, 15, 20}, 0}) 10 c.Check(newVersion("0.0.1-SNAPSHOT"), check.DeepEquals, &version{[]int{0, 0, 0, 0, 1, 19, 14, 1, 16, 19, 8, 15, 20}, 0})
11 c.Check(newVersion("1.0alpha3"), check.DeepEquals, &version{[]int{1, 0, 0, -3, 3}, 0}) 11 c.Check(newVersion("1.0alpha3"), check.DeepEquals, &version{[]int{1, 0, 0, -3, 3}, 0})
12 c.Check(newVersion("2.5beta"), check.DeepEquals, &version{[]int{2, 0, 5, -2}, 0}) 12 c.Check(newVersion("2.5beta"), check.DeepEquals, &version{[]int{2, 0, 5, -2}, 0})
13 c.Check(newVersion("20151110"), check.DeepEquals, &version{[]int{20151110}, 0}) 13 c.Check(newVersion("20151110"), check.DeepEquals, &version{[]int{20151110}, 0})
14 c.Check(newVersion("0"), check.DeepEquals, &version{[]int{0}, 0}) 14 c.Check(newVersion("0"), check.DeepEquals, &version{[]int{0}, 0})
15 c.Check(newVersion("nb1"), check.DeepEquals, &version{nil, 1}) 15 c.Check(newVersion("nb1"), check.DeepEquals, &version{nil, 1})
16 c.Check(newVersion("1.0.1a"), deepEquals, &version{[]int{1, 0, 0, 0, 1, 1}, 0}) 16 c.Check(newVersion("1.0.1a"), deepEquals, &version{[]int{1, 0, 0, 0, 1, 1}, 0})
17 c.Check(newVersion("1.0.1z"), deepEquals, &version{[]int{1, 0, 0, 0, 1, 26}, 0}) 17 c.Check(newVersion("1.0.1z"), deepEquals, &version{[]int{1, 0, 0, 0, 1, 26}, 0})
 18 c.Check(newVersion("0pre20160620"), deepEquals, &version{[]int{0, -1, 20160620}, 0})
18} 19}
19 20
20func (s *Suite) TestPkgverCmp(c *check.C) { 21func (s *Suite) TestPkgverCmp(c *check.C) {
21 c.Check(pkgverCmp("1.0", "1.0alpha"), equals, 1) 22 var versions = [][]string{
22 c.Check(pkgverCmp("1.0alpha", "1.0"), equals, -1) 23 {"0pre20160620"},
23 c.Check(pkgverCmp("1.0nb1", "1.0"), equals, 1) 24 {"0"},
24 c.Check(pkgverCmp("1.0nb2", "1.0nb1"), equals, 1) 25 {"nb1"},
25 c.Check(pkgverCmp("2.0.1nb17", "2.0.1nb4"), equals, 1) 26 {"0.0.1-SNAPSHOT"},
26 c.Check(pkgverCmp("2.0.1nb4", "2.0.1nb17"), equals, -1) 27 {"1.0alpha"},
27 c.Check(pkgverCmp("2.0pre", "2.0rc"), equals, 0) 28 {"1.0alpha3"},
28 c.Check(pkgverCmp("2.0pre", "2.0pl"), equals, -1) 29 {"1", "1.0", "1.0.0"},
 30 {"1.0nb1"},
 31 {"1.0nb2"},
 32 {"1.0.1a"},
 33 {"1.0.1z"},
 34 {"2.0pre", "2.0rc"},
 35 {"2.0", "2.0pl"},
 36 {"2.0.1nb4"},
 37 {"2.0.1nb17"},
 38 {"2.5beta"},
 39 {"5.0"},
 40 {"5.0nb5"},
 41 {"5.5", "5.005"},
 42 {"20151110"},
 43 }
 44
 45 for i, iversions := range versions {
 46 for _, iversion := range iversions {
 47 for j, jversions := range versions {
 48 for _, jversion := range jversions {
 49 actual := pkgverCmp(iversion, jversion)
 50 if i < j && !(actual < 0) {
 51 c.Check([]interface{}{i, iversion, j, jversion, "<0"}, deepEquals, []interface{}{i, iversion, j, jversion, actual})
 52 }
 53 if i == j && !(actual == 0) {
 54 c.Check([]interface{}{i, iversion, j, jversion, "==0"}, deepEquals, []interface{}{i, iversion, j, jversion, actual})
 55 }
 56 if i > j && !(actual > 0) {
 57 c.Check([]interface{}{i, iversion, j, jversion, ">0"}, deepEquals, []interface{}{i, iversion, j, jversion, actual})
 58 }
 59 }
 60 }
 61
 62 }
 63 }
29} 64}