Wed Dec 30 04:16:57 2015 UTC ()
Add Bitrig and MirBSD to the list of OSes.


(dholland)
diff -r1.473 -r1.474 pkgsrc/pkgtools/pkglint/Makefile
diff -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/vartypecheck.go

cvs diff -r1.473 -r1.474 pkgsrc/pkgtools/pkglint/Makefile (switch to unified diff)

--- pkgsrc/pkgtools/pkglint/Makefile 2015/12/10 08:23:15 1.473
+++ pkgsrc/pkgtools/pkglint/Makefile 2015/12/30 04:16:56 1.474
@@ -1,49 +1,49 @@ @@ -1,49 +1,49 @@
1# $NetBSD: Makefile,v 1.473 2015/12/10 08:23:15 wiz Exp $ 1# $NetBSD: Makefile,v 1.474 2015/12/30 04:16:56 dholland Exp $
2 2
3PKGNAME= pkglint-5.2.2.1 3PKGNAME= pkglint-5.2.2.2
4DISTFILES= # none 4DISTFILES= # none
5CATEGORIES= pkgtools 5CATEGORIES= pkgtools
6 6
7OWNER= wiz@NetBSD.org 7OWNER= wiz@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
16AUTO_MKDIRS= yes 16AUTO_MKDIRS= yes
17GO_SRCPATH= netbsd.org/pkglint 17GO_SRCPATH= netbsd.org/pkglint
18 18
19SUBST_CLASSES+= pkglint 19SUBST_CLASSES+= pkglint
20SUBST_STAGE.pkglint= post-configure 20SUBST_STAGE.pkglint= post-configure
21SUBST_FILES.pkglint+= main.go 21SUBST_FILES.pkglint+= main.go
22SUBST_SED.pkglint+= -e s\|@VERSION@\|${PKGNAME:S/pkglint-//}\|g 22SUBST_SED.pkglint+= -e s\|@VERSION@\|${PKGNAME:S/pkglint-//}\|g
23SUBST_SED.pkglint+= -e s\|@BMAKE@\|${MAKE:Q}\|g 23SUBST_SED.pkglint+= -e s\|@BMAKE@\|${MAKE:Q}\|g
24 24
25do-extract: 25do-extract:
26 mkdir -p ${WRKDIR}/pkglint/plist-clash 26 mkdir -p ${WRKDIR}/pkglint/plist-clash
27 cd ${FILESDIR} && ${PAX} -rw *.go */*.go pkglint.[01] ${WRKDIR}/pkglint 27 cd ${FILESDIR} && ${PAX} -rw *.go */*.go pkglint.[01] ${WRKDIR}/pkglint
28 28
29do-test: 29do-test:
30 cd ${WRKSRC} && go test 30 cd ${WRKSRC} && go test
31 31
32do-install: do-install-man 32do-install: do-install-man
33 33
34.include "../../mk/bsd.prefs.mk" 34.include "../../mk/bsd.prefs.mk"
35 35
36do-install-man: 36do-install-man:
37.if !empty(MANINSTALL:Mcatinstall) 37.if !empty(MANINSTALL:Mcatinstall)
38. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss]) 38. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss])
39 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/pkglint.1 39 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/pkglint.1
40. else 40. else
41 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1 41 ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1
42. endif 42. endif
43.endif 43.endif
44.if !empty(MANINSTALL:Mmaninstall) 44.if !empty(MANINSTALL:Mmaninstall)
45 ${INSTALL_MAN} ${WRKSRC}/pkglint.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1 45 ${INSTALL_MAN} ${WRKSRC}/pkglint.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1
46.endif 46.endif
47 47
48.include "../../lang/go/go-package.mk" 48.include "../../lang/go/go-package.mk"
49.include "../../mk/bsd.pkg.mk" 49.include "../../mk/bsd.pkg.mk"

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

--- pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck.go 2015/12/05 21:00:42 1.7
+++ pkgsrc/pkgtools/pkglint/files/Attic/vartypecheck.go 2015/12/30 04:16:57 1.8
@@ -1,747 +1,747 @@ @@ -1,747 +1,747 @@
1package main 1package main
2 2
3import ( 3import (
4 "path" 4 "path"
5 "strings" 5 "strings"
6) 6)
7 7
8type VartypeCheck struct { 8type VartypeCheck struct {
9 line *Line 9 line *Line
10 varname string 10 varname string
11 op string 11 op string
12 value string 12 value string
13 valueNovar string 13 valueNovar string
14 comment string 14 comment string
15 listContext bool 15 listContext bool
16 guessed Guessed 16 guessed Guessed
17} 17}
18 18
19func (cv *VartypeCheck) AwkCommand() { 19func (cv *VartypeCheck) AwkCommand() {
20 _ = G.opts.DebugUnchecked && cv.line.debugf("Unchecked AWK command: %q", cv.value) 20 _ = G.opts.DebugUnchecked && cv.line.debugf("Unchecked AWK command: %q", cv.value)
21} 21}
22 22
23func (cv *VartypeCheck) BasicRegularExpression() { 23func (cv *VartypeCheck) BasicRegularExpression() {
24 _ = G.opts.DebugUnchecked && cv.line.debugf("Unchecked basic regular expression: %q", cv.value) 24 _ = G.opts.DebugUnchecked && cv.line.debugf("Unchecked basic regular expression: %q", cv.value)
25} 25}
26 26
27func (cv *VartypeCheck) BuildlinkDepmethod() { 27func (cv *VartypeCheck) BuildlinkDepmethod() {
28 if !containsVarRef(cv.value) && cv.value != "build" && cv.value != "full" { 28 if !containsVarRef(cv.value) && cv.value != "build" && cv.value != "full" {
29 cv.line.warnf("Invalid dependency method %q. Valid methods are \"build\" or \"full\".", cv.value) 29 cv.line.warnf("Invalid dependency method %q. Valid methods are \"build\" or \"full\".", cv.value)
30 } 30 }
31} 31}
32 32
33func (cv *VartypeCheck) Category() { 33func (cv *VartypeCheck) Category() {
34 if fileExists(G.currentDir + "/" + G.curPkgsrcdir + "/" + cv.value + "/Makefile") { 34 if fileExists(G.currentDir + "/" + G.curPkgsrcdir + "/" + cv.value + "/Makefile") {
35 return 35 return
36 } 36 }
37 switch cv.value { 37 switch cv.value {
38 case 38 case
39 "chinese", "crosspkgtools", 39 "chinese", "crosspkgtools",
40 "gnome", "gnustep", 40 "gnome", "gnustep",
41 "japanese", "java", 41 "japanese", "java",
42 "kde", "korean", 42 "kde", "korean",
43 "linux", "local", 43 "linux", "local",
44 "packages", "perl5", "plan9", "python", 44 "packages", "perl5", "plan9", "python",
45 "ruby", 45 "ruby",
46 "scm", 46 "scm",
47 "tcl", "tk", 47 "tcl", "tk",
48 "windowmaker", 48 "windowmaker",
49 "xmms": 49 "xmms":
50 default: 50 default:
51 cv.line.errorf("Invalid category %q.", cv.value) 51 cv.line.errorf("Invalid category %q.", cv.value)
52 } 52 }
53} 53}
54 54
55// A single option to the C/C++ compiler. 55// A single option to the C/C++ compiler.
56func (cv *VartypeCheck) CFlag() { 56func (cv *VartypeCheck) CFlag() {
57 line, value := cv.line, cv.value 57 line, value := cv.line, cv.value
58 58
59 switch { 59 switch {
60 case matches(value, `^-[DILOUWfgm]`), 60 case matches(value, `^-[DILOUWfgm]`),
61 hasPrefix(value, "-std="), 61 hasPrefix(value, "-std="),
62 value == "-c99": 62 value == "-c99":
63 case hasPrefix(value, "-"): 63 case hasPrefix(value, "-"):
64 line.warnf("Unknown compiler flag %q.", value) 64 line.warnf("Unknown compiler flag %q.", value)
65 case !containsVarRef(value): 65 case !containsVarRef(value):
66 line.warnf("Compiler flag %q should start with a hyphen.", value) 66 line.warnf("Compiler flag %q should start with a hyphen.", value)
67 } 67 }
68} 68}
69 69
70// The single-line description of the package. 70// The single-line description of the package.
71func (cv *VartypeCheck) Comment() { 71func (cv *VartypeCheck) Comment() {
72 line, value := cv.line, cv.value 72 line, value := cv.line, cv.value
73 73
74 if value == "SHORT_DESCRIPTION_OF_THE_PACKAGE" { 74 if value == "SHORT_DESCRIPTION_OF_THE_PACKAGE" {
75 line.errorf("COMMENT must be set.") 75 line.errorf("COMMENT must be set.")
76 } 76 }
77 if m, first := match1(value, `^(?i)(a|an)\s`); m { 77 if m, first := match1(value, `^(?i)(a|an)\s`); m {
78 line.warnf("COMMENT should not begin with %q.", first) 78 line.warnf("COMMENT should not begin with %q.", first)
79 } 79 }
80 if matches(value, `^[a-z]`) { 80 if matches(value, `^[a-z]`) {
81 line.warnf("COMMENT should start with a capital letter.") 81 line.warnf("COMMENT should start with a capital letter.")
82 } 82 }
83 if hasSuffix(value, ".") { 83 if hasSuffix(value, ".") {
84 line.warnf("COMMENT should not end with a period.") 84 line.warnf("COMMENT should not end with a period.")
85 } 85 }
86 if len(value) > 70 { 86 if len(value) > 70 {
87 line.warnf("COMMENT should not be longer than 70 characters.") 87 line.warnf("COMMENT should not be longer than 70 characters.")
88 } 88 }
89} 89}
90 90
91func (cv *VartypeCheck) Dependency() { 91func (cv *VartypeCheck) Dependency() {
92 line, value := cv.line, cv.value 92 line, value := cv.line, cv.value
93 93
94 if m, depbase, depop, depversion := match3(value, `^(`+rePkgbase+`)(<|=|>|<=|>=|!=|-)(`+rePkgversion+`)$`); m { 94 if m, depbase, depop, depversion := match3(value, `^(`+rePkgbase+`)(<|=|>|<=|>=|!=|-)(`+rePkgversion+`)$`); m {
95 _, _, _ = depbase, depop, depversion 95 _, _, _ = depbase, depop, depversion
96 return 96 return
97 } 97 }
98 98
99 if m, depbase, bracket, version, versionWildcard, other := match5(value, `^(`+rePkgbase+`)-(?:\[(.*)\]\*|(\d+(?:\.\d+)*(?:\.\*)?)(\{,nb\*\}|\*|)|(.*))?$`); m { 99 if m, depbase, bracket, version, versionWildcard, other := match5(value, `^(`+rePkgbase+`)-(?:\[(.*)\]\*|(\d+(?:\.\d+)*(?:\.\*)?)(\{,nb\*\}|\*|)|(.*))?$`); m {
100 switch { 100 switch {
101 case bracket != "": 101 case bracket != "":
102 if bracket != "0-9" { 102 if bracket != "0-9" {
103 line.warnf("Only [0-9]* is allowed in the numeric part of a dependency.") 103 line.warnf("Only [0-9]* is allowed in the numeric part of a dependency.")
104 } 104 }
105 105
106 case version != "" && versionWildcard != "": 106 case version != "" && versionWildcard != "":
107 // Fine. 107 // Fine.
108 108
109 case version != "": 109 case version != "":
110 line.warnf("Please append \"{,nb*}\" to the version number of this dependency.") 110 line.warnf("Please append \"{,nb*}\" to the version number of this dependency.")
111 line.explain( 111 line.explain(
112 "Usually, a dependency should stay valid when the PKGREVISION is", 112 "Usually, a dependency should stay valid when the PKGREVISION is",
113 "increased, since those changes are most often editorial. In the", 113 "increased, since those changes are most often editorial. In the",
114 "current form, the dependency only matches if the PKGREVISION is", 114 "current form, the dependency only matches if the PKGREVISION is",
115 "undefined.") 115 "undefined.")
116 116
117 case other == "*": 117 case other == "*":
118 line.warnf("Please use \"%s-[0-9]*\" instead of \"%s-*\".", depbase, depbase) 118 line.warnf("Please use \"%s-[0-9]*\" instead of \"%s-*\".", depbase, depbase)
119 line.explain( 119 line.explain(
120 "If you use a * alone, the package specification may match other", 120 "If you use a * alone, the package specification may match other",
121 "packages that have the same prefix, but a longer name. For example,", 121 "packages that have the same prefix, but a longer name. For example,",
122 "foo-* matches foo-1.2, but also foo-client-1.2 and foo-server-1.2.") 122 "foo-* matches foo-1.2, but also foo-client-1.2 and foo-server-1.2.")
123 123
124 default: 124 default:
125 line.errorf("Unknown dependency pattern %q.", value) 125 line.errorf("Unknown dependency pattern %q.", value)
126 } 126 }
127 return 127 return
128 } 128 }
129 129
130 switch { 130 switch {
131 case contains(value, "{"): 131 case contains(value, "{"):
132 // No check yet for alternative dependency patterns. 132 // No check yet for alternative dependency patterns.
133 _ = G.opts.DebugUnchecked && line.debugf("Unchecked alternative dependency pattern: %s", value) 133 _ = G.opts.DebugUnchecked && line.debugf("Unchecked alternative dependency pattern: %s", value)
134 134
135 case value != cv.valueNovar: 135 case value != cv.valueNovar:
136 _ = G.opts.DebugUnchecked && line.debugf("Unchecked dependency: %s", value) 136 _ = G.opts.DebugUnchecked && line.debugf("Unchecked dependency: %s", value)
137 137
138 default: 138 default:
139 line.warnf("Unknown dependency format: %s", value) 139 line.warnf("Unknown dependency format: %s", value)
140 line.explain( 140 line.explain(
141 "Typical dependencies have the following forms:", 141 "Typical dependencies have the following forms:",
142 "", 142 "",
143 "* package>=2.5", 143 "* package>=2.5",
144 "* package-[0-9]*", 144 "* package-[0-9]*",
145 "* package-3.141") 145 "* package-3.141")
146 } 146 }
147} 147}
148 148
149func (cv *VartypeCheck) DependencyWithPath() { 149func (cv *VartypeCheck) DependencyWithPath() {
150 line, value := cv.line, cv.value 150 line, value := cv.line, cv.value
151 if value != cv.valueNovar { 151 if value != cv.valueNovar {
152 return // It's probably not worth checking this. 152 return // It's probably not worth checking this.
153 } 153 }
154 154
155 if m, pattern, relpath, _, pkg := match4(value, `(.*):(\.\./\.\./([^/]+)/([^/]+))$`); m { 155 if m, pattern, relpath, _, pkg := match4(value, `(.*):(\.\./\.\./([^/]+)/([^/]+))$`); m {
156 checklineRelativePkgdir(line, relpath) 156 checklineRelativePkgdir(line, relpath)
157 157
158 switch pkg { 158 switch pkg {
159 case "msgfmt", "gettext": 159 case "msgfmt", "gettext":
160 line.warnf("Please use USE_TOOLS+=msgfmt instead of this dependency.") 160 line.warnf("Please use USE_TOOLS+=msgfmt instead of this dependency.")
161 case "perl5": 161 case "perl5":
162 line.warnf("Please use USE_TOOLS+=perl:run instead of this dependency.") 162 line.warnf("Please use USE_TOOLS+=perl:run instead of this dependency.")
163 case "gmake": 163 case "gmake":
164 line.warnf("Please use USE_TOOLS+=gmake instead of this dependency.") 164 line.warnf("Please use USE_TOOLS+=gmake instead of this dependency.")
165 } 165 }
166 166
167 if !matches(pattern, reDependencyCmp) && !matches(pattern, reDependencyWildcard) { 167 if !matches(pattern, reDependencyCmp) && !matches(pattern, reDependencyWildcard) {
168 line.errorf("Unknown dependency pattern %q.", pattern) 168 line.errorf("Unknown dependency pattern %q.", pattern)
169 } 169 }
170 return 170 return
171 } 171 }
172 172
173 if matches(value, `:\.\./[^/]+$`) { 173 if matches(value, `:\.\./[^/]+$`) {
174 line.warnf("Dependencies should have the form \"../../category/package\".") 174 line.warnf("Dependencies should have the form \"../../category/package\".")
175 explainRelativeDirs(line) 175 explainRelativeDirs(line)
176 return 176 return
177 } 177 }
178 178
179 line.warnf("Unknown dependency format.") 179 line.warnf("Unknown dependency format.")
180 line.explain( 180 line.explain(
181 "Examples for valid dependencies are:", 181 "Examples for valid dependencies are:",
182 " package-[0-9]*:../../category/package", 182 " package-[0-9]*:../../category/package",
183 " package>=3.41:../../category/package", 183 " package>=3.41:../../category/package",
184 " package-2.718:../../category/package") 184 " package-2.718:../../category/package")
185} 185}
186 186
187func (cv *VartypeCheck) DistSuffix() { 187func (cv *VartypeCheck) DistSuffix() {
188 if cv.value == ".tar.gz" { 188 if cv.value == ".tar.gz" {
189 cv.line.notef("%s is \".tar.gz\" by default, so this definition may be redundant.", cv.varname) 189 cv.line.notef("%s is \".tar.gz\" by default, so this definition may be redundant.", cv.varname)
190 } 190 }
191} 191}
192 192
193func (cv *VartypeCheck) EmulPlatform() { 193func (cv *VartypeCheck) EmulPlatform() {
194 194
195 if m, opsys, arch := match2(cv.value, `^(\w+)-(\w+)$`); m { 195 if m, opsys, arch := match2(cv.value, `^(\w+)-(\w+)$`); m {
196 if !matches(opsys, `^(?:bsdos|cygwin|darwin|dragonfly|freebsd|haiku|hpux|interix|irix|linux|netbsd|openbsd|osf1|sunos|solaris)$`) { 196 if !matches(opsys, `^(?:bitrig|bsdos|cygwin|darwin|dragonfly|freebsd|haiku|hpux|interix|irix|linux|mirbsd|netbsd|openbsd|osf1|sunos|solaris)$`) {
197 cv.line.warnf("Unknown operating system: %s", opsys) 197 cv.line.warnf("Unknown operating system: %s", opsys)
198 } 198 }
199 // no check for os_version 199 // no check for os_version
200 if !matches(arch, `^(?:i386|alpha|amd64|arc|arm|arm32|cobalt|convex|dreamcast|hpcmips|hpcsh|hppa|ia64|m68k|m88k|mips|mips64|mipsel|mipseb|mipsn32|ns32k|pc532|pmax|powerpc|rs6000|s390|sparc|sparc64|vax|x86_64)$`) { 200 if !matches(arch, `^(?:i386|alpha|amd64|arc|arm|arm32|cobalt|convex|dreamcast|hpcmips|hpcsh|hppa|ia64|m68k|m88k|mips|mips64|mipsel|mipseb|mipsn32|ns32k|pc532|pmax|powerpc|rs6000|s390|sparc|sparc64|vax|x86_64)$`) {
201 cv.line.warnf("Unknown hardware architecture: %s", arch) 201 cv.line.warnf("Unknown hardware architecture: %s", arch)
202 } 202 }
203 203
204 } else { 204 } else {
205 cv.line.warnf("%q is not a valid emulation platform.", cv.value) 205 cv.line.warnf("%q is not a valid emulation platform.", cv.value)
206 cv.line.explain( 206 cv.line.explain(
207 "An emulation platform has the form <OPSYS>-<MACHINE_ARCH>.", 207 "An emulation platform has the form <OPSYS>-<MACHINE_ARCH>.",
208 "OPSYS is the lower-case name of the operating system, and MACHINE_ARCH", 208 "OPSYS is the lower-case name of the operating system, and MACHINE_ARCH",
209 "is the hardware architecture.", 209 "is the hardware architecture.",
210 "", 210 "",
211 "Examples: linux-i386, irix-mipsel.") 211 "Examples: linux-i386, irix-mipsel.")
212 } 212 }
213} 213}
214 214
215func (cv *VartypeCheck) FetchURL() { 215func (cv *VartypeCheck) FetchURL() {
216 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarURL, cv.op, cv.value, cv.comment, cv.listContext, cv.guessed) 216 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarURL, cv.op, cv.value, cv.comment, cv.listContext, cv.guessed)
217 217
218 for siteUrl, siteName := range G.globalData.masterSiteUrls { 218 for siteUrl, siteName := range G.globalData.masterSiteUrls {
219 if hasPrefix(cv.value, siteUrl) { 219 if hasPrefix(cv.value, siteUrl) {
220 subdir := cv.value[len(siteUrl):] 220 subdir := cv.value[len(siteUrl):]
221 isGithub := hasPrefix(cv.value, "https://github.com/") 221 isGithub := hasPrefix(cv.value, "https://github.com/")
222 if isGithub { 222 if isGithub {
223 subdir = strings.SplitAfter(subdir, "/")[0] 223 subdir = strings.SplitAfter(subdir, "/")[0]
224 } 224 }
225 cv.line.warnf("Please use ${%s:=%s} instead of %q.", siteName, subdir, cv.value) 225 cv.line.warnf("Please use ${%s:=%s} instead of %q.", siteName, subdir, cv.value)
226 if isGithub { 226 if isGithub {
227 cv.line.warnf("Run \"%s help topic=github\" for further tips.", confMake) 227 cv.line.warnf("Run \"%s help topic=github\" for further tips.", confMake)
228 } 228 }
229 return 229 return
230 } 230 }
231 } 231 }
232} 232}
233 233
234// See Pathname 234// See Pathname
235// See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_169 235// See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_169
236func (cv *VartypeCheck) Filename() { 236func (cv *VartypeCheck) Filename() {
237 switch { 237 switch {
238 case contains(cv.valueNovar, "/"): 238 case contains(cv.valueNovar, "/"):
239 cv.line.warnf("A filename should not contain a slash.") 239 cv.line.warnf("A filename should not contain a slash.")
240 case !matches(cv.valueNovar, `^[-0-9@A-Za-z.,_~+%]*$`): 240 case !matches(cv.valueNovar, `^[-0-9@A-Za-z.,_~+%]*$`):
241 cv.line.warnf("%q is not a valid filename.", cv.value) 241 cv.line.warnf("%q is not a valid filename.", cv.value)
242 } 242 }
243} 243}
244 244
245func (cv *VartypeCheck) Filemask() { 245func (cv *VartypeCheck) Filemask() {
246 if !matches(cv.valueNovar, `^[-0-9A-Za-z._~+%*?]*$`) { 246 if !matches(cv.valueNovar, `^[-0-9A-Za-z._~+%*?]*$`) {
247 cv.line.warnf("%q is not a valid filename mask.", cv.value) 247 cv.line.warnf("%q is not a valid filename mask.", cv.value)
248 } 248 }
249} 249}
250 250
251func (cv *VartypeCheck) FileMode() { 251func (cv *VartypeCheck) FileMode() {
252 switch { 252 switch {
253 case cv.value != "" && cv.valueNovar == "": 253 case cv.value != "" && cv.valueNovar == "":
254 // Fine. 254 // Fine.
255 case matches(cv.value, `^[0-7]{3,4}`): 255 case matches(cv.value, `^[0-7]{3,4}`):
256 // Fine. 256 // Fine.
257 default: 257 default:
258 cv.line.warnf("Invalid file mode %q.", cv.value) 258 cv.line.warnf("Invalid file mode %q.", cv.value)
259 } 259 }
260} 260}
261 261
262func (cv *VartypeCheck) Identifier() { 262func (cv *VartypeCheck) Identifier() {
263 if cv.value != cv.valueNovar { 263 if cv.value != cv.valueNovar {
264 //line.logWarning("Identifiers should be given directly.") 264 //line.logWarning("Identifiers should be given directly.")
265 } 265 }
266 switch { 266 switch {
267 case matches(cv.valueNovar, `^[+\-.0-9A-Z_a-z]+$`): 267 case matches(cv.valueNovar, `^[+\-.0-9A-Z_a-z]+$`):
268 // Fine. 268 // Fine.
269 case cv.value != "" && cv.valueNovar == "": 269 case cv.value != "" && cv.valueNovar == "":
270 // Don't warn here. 270 // Don't warn here.
271 default: 271 default:
272 cv.line.warnf("Invalid identifier %q.", cv.value) 272 cv.line.warnf("Invalid identifier %q.", cv.value)
273 } 273 }
274} 274}
275 275
276func (cv *VartypeCheck) Integer() { 276func (cv *VartypeCheck) Integer() {
277 if !matches(cv.value, `^\d+$`) { 277 if !matches(cv.value, `^\d+$`) {
278 cv.line.warnf("Invalid integer %q.", cv.value) 278 cv.line.warnf("Invalid integer %q.", cv.value)
279 } 279 }
280} 280}
281 281
282func (cv *VartypeCheck) LdFlag() { 282func (cv *VartypeCheck) LdFlag() {
283 if matches(cv.value, `^-[Ll]`) || cv.value == "-static" { 283 if matches(cv.value, `^-[Ll]`) || cv.value == "-static" {
284 return 284 return
285 } else if m, rpathFlag := match1(cv.value, `^(-Wl,(?:-R|-rpath|--rpath))`); m { 285 } else if m, rpathFlag := match1(cv.value, `^(-Wl,(?:-R|-rpath|--rpath))`); m {
286 cv.line.warnf("Please use ${COMPILER_RPATH_FLAG} instead of %s.", rpathFlag) 286 cv.line.warnf("Please use ${COMPILER_RPATH_FLAG} instead of %s.", rpathFlag)
287 287
288 } else if hasPrefix(cv.value, "-") { 288 } else if hasPrefix(cv.value, "-") {
289 cv.line.warnf("Unknown linker flag %q.", cv.value) 289 cv.line.warnf("Unknown linker flag %q.", cv.value)
290 290
291 } else if cv.value == cv.valueNovar { 291 } else if cv.value == cv.valueNovar {
292 cv.line.warnf("Linker flag %q does not start with a dash.", cv.value) 292 cv.line.warnf("Linker flag %q does not start with a dash.", cv.value)
293 } 293 }
294} 294}
295 295
296func (cv *VartypeCheck) License() { 296func (cv *VartypeCheck) License() {
297 checklineLicense(cv.line, cv.value) 297 checklineLicense(cv.line, cv.value)
298} 298}
299 299
300func (cv *VartypeCheck) MailAddress() { 300func (cv *VartypeCheck) MailAddress() {
301 line, value := cv.line, cv.value 301 line, value := cv.line, cv.value
302 302
303 if m, _, domain := match2(value, `^([+\-.0-9A-Z_a-z]+)@([-\w\d.]+)$`); m { 303 if m, _, domain := match2(value, `^([+\-.0-9A-Z_a-z]+)@([-\w\d.]+)$`); m {
304 if strings.EqualFold(domain, "NetBSD.org") && domain != "NetBSD.org" { 304 if strings.EqualFold(domain, "NetBSD.org") && domain != "NetBSD.org" {
305 line.warnf("Please write \"NetBSD.org\" instead of %q.", domain) 305 line.warnf("Please write \"NetBSD.org\" instead of %q.", domain)
306 } 306 }
307 if matches(value, `(?i)^(tech-pkg|packages)@NetBSD\.org$`) { 307 if matches(value, `(?i)^(tech-pkg|packages)@NetBSD\.org$`) {
308 line.errorf("This mailing list address is obsolete. Use pkgsrc-users@NetBSD.org instead.") 308 line.errorf("This mailing list address is obsolete. Use pkgsrc-users@NetBSD.org instead.")
309 } 309 }
310 310
311 } else { 311 } else {
312 line.warnf("\"%s\" is not a valid mail address.", value) 312 line.warnf("\"%s\" is not a valid mail address.", value)
313 } 313 }
314} 314}
315 315
316// See ${STEP_MSG}, ${PKG_FAIL_REASON} 316// See ${STEP_MSG}, ${PKG_FAIL_REASON}
317func (cv *VartypeCheck) Message() { 317func (cv *VartypeCheck) Message() {
318 line, varname, value := cv.line, cv.varname, cv.value 318 line, varname, value := cv.line, cv.varname, cv.value
319 319
320 if matches(value, `^[\"'].*[\"']$`) { 320 if matches(value, `^[\"'].*[\"']$`) {
321 line.warnf("%s should not be quoted.", varname) 321 line.warnf("%s should not be quoted.", varname)
322 line.explain( 322 line.explain(
323 "The quoting is only needed for variables which are interpreted as", 323 "The quoting is only needed for variables which are interpreted as",
324 "multiple words (or, generally speaking, a list of something). A single", 324 "multiple words (or, generally speaking, a list of something). A single",
325 "text message does not belong to this class, since it is only printed", 325 "text message does not belong to this class, since it is only printed",
326 "as a whole.", 326 "as a whole.",
327 "", 327 "",
328 "On the other hand, PKG_FAIL_REASON is a _list_ of text messages, so in", 328 "On the other hand, PKG_FAIL_REASON is a _list_ of text messages, so in",
329 "that case, the quoting has to be done.`") 329 "that case, the quoting has to be done.`")
330 } 330 }
331} 331}
332 332
333// A package option from options.mk 333// A package option from options.mk
334func (cv *VartypeCheck) Option() { 334func (cv *VartypeCheck) Option() {
335 line, value, valueNovar := cv.line, cv.value, cv.valueNovar 335 line, value, valueNovar := cv.line, cv.value, cv.valueNovar
336 336
337 if value != valueNovar { 337 if value != valueNovar {
338 _ = G.opts.DebugUnchecked && line.debugf("Unchecked option name: %q", value) 338 _ = G.opts.DebugUnchecked && line.debugf("Unchecked option name: %q", value)
339 return 339 return
340 } 340 }
341 341
342 if m, optname := match1(value, `^-?([a-z][-0-9a-z\+]*)$`); m { 342 if m, optname := match1(value, `^-?([a-z][-0-9a-z\+]*)$`); m {
343 if _, found := G.globalData.pkgOptions[optname]; !found { // There’s a difference between empty and absent here. 343 if _, found := G.globalData.pkgOptions[optname]; !found { // There’s a difference between empty and absent here.
344 line.warnf("Unknown option \"%s\".", optname) 344 line.warnf("Unknown option \"%s\".", optname)
345 line.explain( 345 line.explain(
346 "This option is not documented in the mk/defaults/options.description", 346 "This option is not documented in the mk/defaults/options.description",
347 "file. If this is not a typo, please think of a brief but precise", 347 "file. If this is not a typo, please think of a brief but precise",
348 "description and either update that file yourself or ask on the", 348 "description and either update that file yourself or ask on the",
349 "tech-pkg@NetBSD.org mailing list.") 349 "tech-pkg@NetBSD.org mailing list.")
350 } 350 }
351 return 351 return
352 } 352 }
353 353
354 if matches(value, `^-?([a-z][-0-9a-z_\+]*)$`) { 354 if matches(value, `^-?([a-z][-0-9a-z_\+]*)$`) {
355 line.warnf("Use of the underscore character in option names is deprecated.") 355 line.warnf("Use of the underscore character in option names is deprecated.")
356 return 356 return
357 } 357 }
358 358
359 line.errorf("Invalid option name.") 359 line.errorf("Invalid option name.")
360} 360}
361 361
362// The PATH environment variable 362// The PATH environment variable
363func (cv *VartypeCheck) Pathlist() { 363func (cv *VartypeCheck) Pathlist() {
364 if !contains(cv.value, ":") && cv.guessed == guGuessed { 364 if !contains(cv.value, ":") && cv.guessed == guGuessed {
365 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarPathname, cv.op, cv.value, cv.comment, cv.listContext, cv.guessed) 365 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarPathname, cv.op, cv.value, cv.comment, cv.listContext, cv.guessed)
366 return 366 return
367 } 367 }
368 368
369 for _, path := range strings.Split(cv.value, ":") { 369 for _, path := range strings.Split(cv.value, ":") {
370 if contains(path, "${") { 370 if contains(path, "${") {
371 continue 371 continue
372 } 372 }
373 373
374 if !matches(path, `^[-0-9A-Za-z._~+%/]*$`) { 374 if !matches(path, `^[-0-9A-Za-z._~+%/]*$`) {
375 cv.line.warnf("%q is not a valid pathname.", path) 375 cv.line.warnf("%q is not a valid pathname.", path)
376 } 376 }
377 377
378 if !hasPrefix(path, "/") { 378 if !hasPrefix(path, "/") {
379 cv.line.warnf("All components of %s (in this case %q) should be absolute paths.", cv.varname, path) 379 cv.line.warnf("All components of %s (in this case %q) should be absolute paths.", cv.varname, path)
380 } 380 }
381 } 381 }
382} 382}
383 383
384// Shell globbing including slashes. 384// Shell globbing including slashes.
385// See Filemask 385// See Filemask
386func (cv *VartypeCheck) Pathmask() { 386func (cv *VartypeCheck) Pathmask() {
387 if !matches(cv.valueNovar, `^[#\-0-9A-Za-z._~+%*?/\[\]]*`) { 387 if !matches(cv.valueNovar, `^[#\-0-9A-Za-z._~+%*?/\[\]]*`) {
388 cv.line.warnf("%q is not a valid pathname mask.", cv.value) 388 cv.line.warnf("%q is not a valid pathname mask.", cv.value)
389 } 389 }
390 cv.line.checkAbsolutePathname(cv.value) 390 cv.line.checkAbsolutePathname(cv.value)
391} 391}
392 392
393// Like Filename, but including slashes 393// Like Filename, but including slashes
394// See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266 394// See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266
395func (cv *VartypeCheck) Pathname() { 395func (cv *VartypeCheck) Pathname() {
396 if !matches(cv.valueNovar, `^[#\-0-9A-Za-z._~+%/]*$`) { 396 if !matches(cv.valueNovar, `^[#\-0-9A-Za-z._~+%/]*$`) {
397 cv.line.warnf("%q is not a valid pathname.", cv.value) 397 cv.line.warnf("%q is not a valid pathname.", cv.value)
398 } 398 }
399 cv.line.checkAbsolutePathname(cv.value) 399 cv.line.checkAbsolutePathname(cv.value)
400} 400}
401 401
402func (cv *VartypeCheck) Perl5Packlist() { 402func (cv *VartypeCheck) Perl5Packlist() {
403 if cv.value != cv.valueNovar { 403 if cv.value != cv.valueNovar {
404 cv.line.warnf("%s should not depend on other variables.", cv.varname) 404 cv.line.warnf("%s should not depend on other variables.", cv.varname)
405 } 405 }
406} 406}
407 407
408func (cv *VartypeCheck) PkgName() { 408func (cv *VartypeCheck) PkgName() {
409 if cv.value == cv.valueNovar && !matches(cv.value, rePkgname) { 409 if cv.value == cv.valueNovar && !matches(cv.value, rePkgname) {
410 cv.line.warnf("%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) 410 cv.line.warnf("%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)
411 } 411 }
412} 412}
413 413
414func (cv *VartypeCheck) PkgOptionsVar() { 414func (cv *VartypeCheck) PkgOptionsVar() {
415 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarVarname, cv.op, cv.value, cv.comment, false, cv.guessed) 415 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarVarname, cv.op, cv.value, cv.comment, false, cv.guessed)
416 if matches(cv.value, `\$\{PKGBASE[:\}]`) { 416 if matches(cv.value, `\$\{PKGBASE[:\}]`) {
417 cv.line.errorf("PKGBASE must not be used in PKG_OPTIONS_VAR.") 417 cv.line.errorf("PKGBASE must not be used in PKG_OPTIONS_VAR.")
418 cv.line.explain( 418 cv.line.explain(
419 "PKGBASE is defined in bsd.pkg.mk, which is included as the", 419 "PKGBASE is defined in bsd.pkg.mk, which is included as the",
420 "very last file, but PKG_OPTIONS_VAR is evaluated earlier.", 420 "very last file, but PKG_OPTIONS_VAR is evaluated earlier.",
421 "Use ${PKGNAME:C/-[0-9].*//} instead.") 421 "Use ${PKGNAME:C/-[0-9].*//} instead.")
422 } 422 }
423} 423}
424 424
425// A directory name relative to the top-level pkgsrc directory. 425// A directory name relative to the top-level pkgsrc directory.
426// Despite its name, it is more similar to RelativePkgDir than to RelativePkgPath. 426// Despite its name, it is more similar to RelativePkgDir than to RelativePkgPath.
427func (cv *VartypeCheck) PkgPath() { 427func (cv *VartypeCheck) PkgPath() {
428 checklineRelativePkgdir(cv.line, G.curPkgsrcdir+"/"+cv.value) 428 checklineRelativePkgdir(cv.line, G.curPkgsrcdir+"/"+cv.value)
429} 429}
430 430
431func (cv *VartypeCheck) PkgRevision() { 431func (cv *VartypeCheck) PkgRevision() {
432 if !matches(cv.value, `^[1-9]\d*$`) { 432 if !matches(cv.value, `^[1-9]\d*$`) {
433 cv.line.warnf("%s must be a positive integer number.", cv.varname) 433 cv.line.warnf("%s must be a positive integer number.", cv.varname)
434 } 434 }
435 if path.Base(cv.line.fname) != "Makefile" { 435 if path.Base(cv.line.fname) != "Makefile" {
436 cv.line.errorf("%s only makes sense directly in the package Makefile.", cv.varname) 436 cv.line.errorf("%s only makes sense directly in the package Makefile.", cv.varname)
437 cv.line.explain( 437 cv.line.explain(
438 "Usually, different packages using the same Makefile.common have", 438 "Usually, different packages using the same Makefile.common have",
439 "different dependencies and will be bumped at different times (e.g. for", 439 "different dependencies and will be bumped at different times (e.g. for",
440 "shlib major bumps) and thus the PKGREVISIONs must be in the separate", 440 "shlib major bumps) and thus the PKGREVISIONs must be in the separate",
441 "Makefiles. There is no practical way of having this information in a", 441 "Makefiles. There is no practical way of having this information in a",
442 "commonly used Makefile.") 442 "commonly used Makefile.")
443 } 443 }
444} 444}
445 445
446func (cv *VartypeCheck) PlatformTriple() { 446func (cv *VartypeCheck) PlatformTriple() {
447 if cv.value != cv.valueNovar { 447 if cv.value != cv.valueNovar {
448 return 448 return
449 } 449 }
450 450
451 rePart := `(?:\[[^\]]+\]|[^-\[])+` 451 rePart := `(?:\[[^\]]+\]|[^-\[])+`
452 reTriple := `^(` + rePart + `)-(` + rePart + `)-(` + rePart + `)$` 452 reTriple := `^(` + rePart + `)-(` + rePart + `)-(` + rePart + `)$`
453 if m, opsys, _, arch := match3(cv.value, reTriple); m { 453 if m, opsys, _, arch := match3(cv.value, reTriple); m {
454 if !matches(opsys, `^(?:\*|BSDOS|Cygwin|Darwin|DragonFly|FreeBSD|Haiku|HPUX|Interix|IRIX|Linux|NetBSD|OpenBSD|OSF1|QNX|SunOS)$`) { 454 if !matches(opsys, `^(?:\*|Bitrig|BSDOS|Cygwin|Darwin|DragonFly|FreeBSD|Haiku|HPUX|Interix|IRIX|Linux|MirBSD|NetBSD|OpenBSD|OSF1|QNX|SunOS)$`) {
455 cv.line.warnf("Unknown operating system: %s", opsys) 455 cv.line.warnf("Unknown operating system: %s", opsys)
456 } 456 }
457 // no check for os_version 457 // no check for os_version
458 if !matches(arch, `^(?:\*|i386|alpha|amd64|arc|arm|arm32|cobalt|convex|dreamcast|hpcmips|hpcsh|hppa|ia64|m68k|m88k|mips|mips64|mipsel|mipseb|mipsn32|ns32k|pc532|pmax|powerpc|rs6000|s390|sparc|sparc64|vax|x86_64)$`) { 458 if !matches(arch, `^(?:\*|i386|alpha|amd64|arc|arm|arm32|cobalt|convex|dreamcast|hpcmips|hpcsh|hppa|ia64|m68k|m88k|mips|mips64|mipsel|mipseb|mipsn32|ns32k|pc532|pmax|powerpc|rs6000|s390|sparc|sparc64|vax|x86_64)$`) {
459 cv.line.warnf("Unknown hardware architecture: %s", arch) 459 cv.line.warnf("Unknown hardware architecture: %s", arch)
460 } 460 }
461 461
462 } else { 462 } else {
463 cv.line.warnf("%q is not a valid platform triple.", cv.value) 463 cv.line.warnf("%q is not a valid platform triple.", cv.value)
464 cv.line.explain( 464 cv.line.explain(
465 "A platform triple has the form <OPSYS>-<OS_VERSION>-<MACHINE_ARCH>.", 465 "A platform triple has the form <OPSYS>-<OS_VERSION>-<MACHINE_ARCH>.",
466 "Each of these components may be a shell globbing expression.", 466 "Each of these components may be a shell globbing expression.",
467 "Examples: NetBSD-*-i386, *-*-*, Linux-*-*.") 467 "Examples: NetBSD-*-i386, *-*-*, Linux-*-*.")
468 } 468 }
469} 469}
470 470
471func (cv *VartypeCheck) PrefixPathname() { 471func (cv *VartypeCheck) PrefixPathname() {
472 if m, mansubdir := match1(cv.value, `^man/(.+)`); m { 472 if m, mansubdir := match1(cv.value, `^man/(.+)`); m {
473 cv.line.warnf("Please use \"${PKGMANDIR}/%s\" instead of %q.", mansubdir, cv.value) 473 cv.line.warnf("Please use \"${PKGMANDIR}/%s\" instead of %q.", mansubdir, cv.value)
474 } 474 }
475} 475}
476 476
477func (cv *VartypeCheck) PythonDependency() { 477func (cv *VartypeCheck) PythonDependency() {
478 if cv.value != cv.valueNovar { 478 if cv.value != cv.valueNovar {
479 cv.line.warnf("Python dependencies should not contain variables.") 479 cv.line.warnf("Python dependencies should not contain variables.")
480 } 480 }
481 if !matches(cv.valueNovar, `^[+\-.0-9A-Z_a-z]+(?:|:link|:build)$`) { 481 if !matches(cv.valueNovar, `^[+\-.0-9A-Z_a-z]+(?:|:link|:build)$`) {
482 cv.line.warnf("Invalid Python dependency %q.", cv.value) 482 cv.line.warnf("Invalid Python dependency %q.", cv.value)
483 cv.line.explain( 483 cv.line.explain(
484 "Python dependencies must be an identifier for a package, as specified", 484 "Python dependencies must be an identifier for a package, as specified",
485 "in lang/python/versioned_dependencies.mk. This identifier may be", 485 "in lang/python/versioned_dependencies.mk. This identifier may be",
486 "followed by :build for a build-time only dependency, or by :link for", 486 "followed by :build for a build-time only dependency, or by :link for",
487 "a run-time only dependency.") 487 "a run-time only dependency.")
488 } 488 }
489} 489}
490 490
491// Refers to a package directory. 491// Refers to a package directory.
492func (cv *VartypeCheck) RelativePkgDir() { 492func (cv *VartypeCheck) RelativePkgDir() {
493 checklineRelativePkgdir(cv.line, cv.value) 493 checklineRelativePkgdir(cv.line, cv.value)
494} 494}
495 495
496// Refers to a file or directory. 496// Refers to a file or directory.
497func (cv *VartypeCheck) RelativePkgPath() { 497func (cv *VartypeCheck) RelativePkgPath() {
498 checklineRelativePath(cv.line, cv.value, true) 498 checklineRelativePath(cv.line, cv.value, true)
499} 499}
500 500
501func (cv *VartypeCheck) Restricted() { 501func (cv *VartypeCheck) Restricted() {
502 if cv.value != "${RESTRICTED}" { 502 if cv.value != "${RESTRICTED}" {
503 cv.line.warnf("The only valid value for %s is ${RESTRICTED}.", cv.varname) 503 cv.line.warnf("The only valid value for %s is ${RESTRICTED}.", cv.varname)
504 cv.line.explain( 504 cv.line.explain(
505 "These variables are used to control which files may be mirrored on FTP", 505 "These variables are used to control which files may be mirrored on FTP",
506 "servers or CD-ROM collections. They are not intended to mark packages", 506 "servers or CD-ROM collections. They are not intended to mark packages",
507 "whose only MASTER_SITES are on ftp.NetBSD.org.") 507 "whose only MASTER_SITES are on ftp.NetBSD.org.")
508 } 508 }
509} 509}
510 510
511func (cv *VartypeCheck) SedCommand() { 511func (cv *VartypeCheck) SedCommand() {
512} 512}
513 513
514func (cv *VartypeCheck) SedCommands() { 514func (cv *VartypeCheck) SedCommands() {
515 line := cv.line 515 line := cv.line
516 516
517 words, rest := splitIntoShellwords(line, cv.value) 517 words, rest := splitIntoShellwords(line, cv.value)
518 if rest != "" { 518 if rest != "" {
519 if contains(cv.value, "#") { 519 if contains(cv.value, "#") {
520 line.errorf("Invalid shell words in sed commands.") 520 line.errorf("Invalid shell words in sed commands.")
521 line.explain( 521 line.explain(
522 "When sed commands have embedded \"#\" characters, they need to be", 522 "When sed commands have embedded \"#\" characters, they need to be",
523 "escaped with a backslash, otherwise make(1) will interpret them as a", 523 "escaped with a backslash, otherwise make(1) will interpret them as a",
524 "comment, no matter if they occur in single or double quotes or", 524 "comment, no matter if they occur in single or double quotes or",
525 "whatever.") 525 "whatever.")
526 } 526 }
527 return 527 return
528 } 528 }
529 529
530 nwords := len(words) 530 nwords := len(words)
531 ncommands := 0 531 ncommands := 0
532 532
533 for i := 0; i < nwords; i++ { 533 for i := 0; i < nwords; i++ {
534 word := words[i] 534 word := words[i]
535 NewMkShellLine(cv.line).checkShellword(word, true) 535 NewMkShellLine(cv.line).checkShellword(word, true)
536 536
537 switch { 537 switch {
538 case word == "-e": 538 case word == "-e":
539 if i+1 < nwords { 539 if i+1 < nwords {
540 // Check the real sed command here. 540 // Check the real sed command here.
541 i++ 541 i++
542 ncommands++ 542 ncommands++
543 if ncommands > 1 { 543 if ncommands > 1 {
544 line.notef("Each sed command should appear in an assignment of its own.") 544 line.notef("Each sed command should appear in an assignment of its own.")
545 line.explain( 545 line.explain(
546 "For example, instead of", 546 "For example, instead of",
547 " SUBST_SED.foo+= -e s,command1,, -e s,command2,,", 547 " SUBST_SED.foo+= -e s,command1,, -e s,command2,,",
548 "use", 548 "use",
549 " SUBST_SED.foo+= -e s,command1,,", 549 " SUBST_SED.foo+= -e s,command1,,",
550 " SUBST_SED.foo+= -e s,command2,,", 550 " SUBST_SED.foo+= -e s,command2,,",
551 "", 551 "",
552 "This way, short sed commands cannot be hidden at the end of a line.") 552 "This way, short sed commands cannot be hidden at the end of a line.")
553 } 553 }
554 NewMkShellLine(line).checkShellword(words[i-1], true) 554 NewMkShellLine(line).checkShellword(words[i-1], true)
555 NewMkShellLine(line).checkShellword(words[i], true) 555 NewMkShellLine(line).checkShellword(words[i], true)
556 NewMkLine(line).checkVartypePrimitive(cv.varname, CheckvarSedCommand, cv.op, words[i], cv.comment, cv.listContext, cv.guessed) 556 NewMkLine(line).checkVartypePrimitive(cv.varname, CheckvarSedCommand, cv.op, words[i], cv.comment, cv.listContext, cv.guessed)
557 } else { 557 } else {
558 line.errorf("The -e option to sed requires an argument.") 558 line.errorf("The -e option to sed requires an argument.")
559 } 559 }
560 case word == "-E": 560 case word == "-E":
561 // Switch to extended regular expressions mode. 561 // Switch to extended regular expressions mode.
562 562
563 case word == "-n": 563 case word == "-n":
564 // Don't print lines per default. 564 // Don't print lines per default.
565 565
566 case i == 0 && matches(word, `^(["']?)(?:\d*|/.*/)s.+["']?$`): 566 case i == 0 && matches(word, `^(["']?)(?:\d*|/.*/)s.+["']?$`):
567 line.notef("Please always use \"-e\" in sed commands, even if there is only one substitution.") 567 line.notef("Please always use \"-e\" in sed commands, even if there is only one substitution.")
568 568
569 default: 569 default:
570 line.warnf("Unknown sed command %q.", word) 570 line.warnf("Unknown sed command %q.", word)
571 } 571 }
572 } 572 }
573} 573}
574 574
575func (cv *VartypeCheck) ShellCommand() { 575func (cv *VartypeCheck) ShellCommand() {
576 NewMkShellLine(cv.line).checkShelltext(cv.value) 576 NewMkShellLine(cv.line).checkShelltext(cv.value)
577} 577}
578 578
579func (cv *VartypeCheck) ShellWord() { 579func (cv *VartypeCheck) ShellWord() {
580 if !cv.listContext { 580 if !cv.listContext {
581 NewMkShellLine(cv.line).checkShellword(cv.value, true) 581 NewMkShellLine(cv.line).checkShellword(cv.value, true)
582 } 582 }
583} 583}
584 584
585func (cv *VartypeCheck) Stage() { 585func (cv *VartypeCheck) Stage() {
586 if !matches(cv.value, `^(?:pre|do|post)-(?:extract|patch|configure|build|test|install)`) { 586 if !matches(cv.value, `^(?:pre|do|post)-(?:extract|patch|configure|build|test|install)`) {
587 cv.line.warnf("Invalid stage name %q. Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.", cv.value) 587 cv.line.warnf("Invalid stage name %q. Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.", cv.value)
588 } 588 }
589} 589}
590 590
591func (cv *VartypeCheck) String() { 591func (cv *VartypeCheck) String() {
592 // No further checks possible. 592 // No further checks possible.
593} 593}
594 594
595func (cv *VartypeCheck) Tool() { 595func (cv *VartypeCheck) Tool() {
596 if cv.varname == "TOOLS_NOOP" && cv.op == "+=" { 596 if cv.varname == "TOOLS_NOOP" && cv.op == "+=" {
597 // no warning for package-defined tool definitions 597 // no warning for package-defined tool definitions
598 598
599 } else if m, toolname, tooldep := match2(cv.value, `^([-\w]+|\[)(?::(\w+))?$`); m { 599 } else if m, toolname, tooldep := match2(cv.value, `^([-\w]+|\[)(?::(\w+))?$`); m {
600 if !G.globalData.tools[toolname] { 600 if !G.globalData.tools[toolname] {
601 cv.line.errorf("Unknown tool %q.", toolname) 601 cv.line.errorf("Unknown tool %q.", toolname)
602 } 602 }
603 switch tooldep { 603 switch tooldep {
604 case "", "bootstrap", "build", "pkgsrc", "run": 604 case "", "bootstrap", "build", "pkgsrc", "run":
605 default: 605 default:
606 cv.line.errorf("Unknown tool dependency %q. Use one of \"build\", \"pkgsrc\" or \"run\".", tooldep) 606 cv.line.errorf("Unknown tool dependency %q. Use one of \"build\", \"pkgsrc\" or \"run\".", tooldep)
607 } 607 }
608 } else { 608 } else {
609 cv.line.errorf("Invalid tool syntax: %q.", cv.value) 609 cv.line.errorf("Invalid tool syntax: %q.", cv.value)
610 } 610 }
611} 611}
612 612
613func (cv *VartypeCheck) Unchecked() { 613func (cv *VartypeCheck) Unchecked() {
614 // Do nothing, as the name says. 614 // Do nothing, as the name says.
615} 615}
616 616
617func (cv *VartypeCheck) URL() { 617func (cv *VartypeCheck) URL() {
618 line, value := cv.line, cv.value 618 line, value := cv.line, cv.value
619 619
620 if value == "" && hasPrefix(cv.comment, "#") { 620 if value == "" && hasPrefix(cv.comment, "#") {
621 // Ok 621 // Ok
622 622
623 } else if m, name, subdir := match2(value, `\$\{(MASTER_SITE_[^:]*).*:=(.*)\}$`); m { 623 } else if m, name, subdir := match2(value, `\$\{(MASTER_SITE_[^:]*).*:=(.*)\}$`); m {
624 if !G.globalData.masterSiteVars[name] { 624 if !G.globalData.masterSiteVars[name] {
625 line.errorf("%s does not exist.", name) 625 line.errorf("%s does not exist.", name)
626 } 626 }
627 if !hasSuffix(subdir, "/") { 627 if !hasSuffix(subdir, "/") {
628 line.errorf("The subdirectory in %s must end with a slash.", name) 628 line.errorf("The subdirectory in %s must end with a slash.", name)
629 } 629 }
630 630
631 } else if containsVarRef(value) { 631 } else if containsVarRef(value) {
632 // No further checks 632 // No further checks
633 633
634 } else if m, _, host, _, _ := match4(value, `^(https?|ftp|gopher)://([-0-9A-Za-z.]+)(?::(\d+))?/([-%&+,./0-9:=?@A-Z_a-z~]|#)*$`); m { 634 } else if m, _, host, _, _ := match4(value, `^(https?|ftp|gopher)://([-0-9A-Za-z.]+)(?::(\d+))?/([-%&+,./0-9:=?@A-Z_a-z~]|#)*$`); m {
635 if matches(host, `(?i)\.NetBSD\.org$`) && !matches(host, `\.NetBSD\.org$`) { 635 if matches(host, `(?i)\.NetBSD\.org$`) && !matches(host, `\.NetBSD\.org$`) {
636 line.warnf("Please write NetBSD.org instead of %s.", host) 636 line.warnf("Please write NetBSD.org instead of %s.", host)
637 } 637 }
638 638
639 } else if m, scheme, _, absPath := match3(value, `^([0-9A-Za-z]+)://([^/]+)(.*)$`); m { 639 } else if m, scheme, _, absPath := match3(value, `^([0-9A-Za-z]+)://([^/]+)(.*)$`); m {
640 switch { 640 switch {
641 case scheme != "ftp" && scheme != "http" && scheme != "https" && scheme != "gopher": 641 case scheme != "ftp" && scheme != "http" && scheme != "https" && scheme != "gopher":
642 line.warnf("%q is not a valid URL. Only ftp, gopher, http, and https URLs are allowed here.", value) 642 line.warnf("%q is not a valid URL. Only ftp, gopher, http, and https URLs are allowed here.", value)
643 643
644 case absPath == "": 644 case absPath == "":
645 line.notef("For consistency, please add a trailing slash to %q.", value) 645 line.notef("For consistency, please add a trailing slash to %q.", value)
646 646
647 default: 647 default:
648 line.warnf("%q is not a valid URL.", value) 648 line.warnf("%q is not a valid URL.", value)
649 } 649 }
650 650
651 } else { 651 } else {
652 line.warnf("%q is not a valid URL.", value) 652 line.warnf("%q is not a valid URL.", value)
653 } 653 }
654} 654}
655 655
656func (cv *VartypeCheck) UserGroupName() { 656func (cv *VartypeCheck) UserGroupName() {
657 if cv.value == cv.valueNovar && !matches(cv.value, `^[0-9_a-z]+$`) { 657 if cv.value == cv.valueNovar && !matches(cv.value, `^[0-9_a-z]+$`) {
658 cv.line.warnf("Invalid user or group name %q.", cv.value) 658 cv.line.warnf("Invalid user or group name %q.", cv.value)
659 } 659 }
660} 660}
661 661
662func (cv *VartypeCheck) Varname() { 662func (cv *VartypeCheck) Varname() {
663 if cv.value == cv.valueNovar && !matches(cv.value, `^[A-Z_][0-9A-Z_]*(?:[.].*)?$`) { 663 if cv.value == cv.valueNovar && !matches(cv.value, `^[A-Z_][0-9A-Z_]*(?:[.].*)?$`) {
664 cv.line.warnf("%q is not a valid variable name.", cv.value) 664 cv.line.warnf("%q is not a valid variable name.", cv.value)
665 cv.line.explain( 665 cv.line.explain(
666 "Variable names are restricted to only uppercase letters and the", 666 "Variable names are restricted to only uppercase letters and the",
667 "underscore in the basename, and arbitrary characters in the", 667 "underscore in the basename, and arbitrary characters in the",
668 "parameterized part, following the dot.", 668 "parameterized part, following the dot.",
669 "", 669 "",
670 "Examples:", 670 "Examples:",
671 "\t* PKGNAME", 671 "\t* PKGNAME",
672 "\t* PKG_OPTIONS.gnuchess") 672 "\t* PKG_OPTIONS.gnuchess")
673 } 673 }
674} 674}
675 675
676func (cv *VartypeCheck) Version() { 676func (cv *VartypeCheck) Version() {
677 if !matches(cv.value, `^([\d.])+$`) { 677 if !matches(cv.value, `^([\d.])+$`) {
678 cv.line.warnf("Invalid version number %q.", cv.value) 678 cv.line.warnf("Invalid version number %q.", cv.value)
679 } 679 }
680} 680}
681 681
682func (cv *VartypeCheck) WrapperReorder() { 682func (cv *VartypeCheck) WrapperReorder() {
683 if !matches(cv.value, `^reorder:l:([\w\-]+):([\w\-]+)$`) { 683 if !matches(cv.value, `^reorder:l:([\w\-]+):([\w\-]+)$`) {
684 cv.line.warnf("Unknown wrapper reorder command %q.", cv.value) 684 cv.line.warnf("Unknown wrapper reorder command %q.", cv.value)
685 } 685 }
686} 686}
687 687
688func (cv *VartypeCheck) WrapperTransform() { 688func (cv *VartypeCheck) WrapperTransform() {
689 switch { 689 switch {
690 case matches(cv.value, `^rm:(?:-[DILOUWflm].*|-std=.*)$`): 690 case matches(cv.value, `^rm:(?:-[DILOUWflm].*|-std=.*)$`):
691 case matches(cv.value, `^l:([^:]+):(.+)$`): 691 case matches(cv.value, `^l:([^:]+):(.+)$`):
692 case matches(cv.value, `^'?(?:opt|rename|rm-optarg|rmdir):.*$`): 692 case matches(cv.value, `^'?(?:opt|rename|rm-optarg|rmdir):.*$`):
693 case cv.value == "-e": 693 case cv.value == "-e":
694 case matches(cv.value, `^\"?'?s[|:,]`): 694 case matches(cv.value, `^\"?'?s[|:,]`):
695 default: 695 default:
696 cv.line.warnf("Unknown wrapper transform command %q.", cv.value) 696 cv.line.warnf("Unknown wrapper transform command %q.", cv.value)
697 } 697 }
698} 698}
699 699
700func (cv *VartypeCheck) WrkdirSubdirectory() { 700func (cv *VartypeCheck) WrkdirSubdirectory() {
701 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarPathname, cv.op, cv.value, cv.comment, cv.listContext, cv.guessed) 701 NewMkLine(cv.line).checkVartypePrimitive(cv.varname, CheckvarPathname, cv.op, cv.value, cv.comment, cv.listContext, cv.guessed)
702} 702}
703 703
704// A directory relative to ${WRKSRC}, for use in CONFIGURE_DIRS and similar variables. 704// A directory relative to ${WRKSRC}, for use in CONFIGURE_DIRS and similar variables.
705func (cv *VartypeCheck) WrksrcSubdirectory() { 705func (cv *VartypeCheck) WrksrcSubdirectory() {
706 if m, _, rest := match2(cv.value, `^(\$\{WRKSRC\})(?:/(.*))?`); m { 706 if m, _, rest := match2(cv.value, `^(\$\{WRKSRC\})(?:/(.*))?`); m {
707 if rest == "" { 707 if rest == "" {
708 rest = "." 708 rest = "."
709 } 709 }
710 cv.line.notef("You can use %q instead of %q.", rest, cv.value) 710 cv.line.notef("You can use %q instead of %q.", rest, cv.value)
711 711
712 } else if cv.value != "" && cv.valueNovar == "" { 712 } else if cv.value != "" && cv.valueNovar == "" {
713 // The value of another variable 713 // The value of another variable
714 714
715 } else if !matches(cv.valueNovar, `^(?:\.|[0-9A-Za-z_@][-0-9A-Za-z_@./+]*)$`) { 715 } else if !matches(cv.valueNovar, `^(?:\.|[0-9A-Za-z_@][-0-9A-Za-z_@./+]*)$`) {
716 cv.line.warnf("%q is not a valid subdirectory of ${WRKSRC}.", cv.value) 716 cv.line.warnf("%q is not a valid subdirectory of ${WRKSRC}.", cv.value)
717 } 717 }
718} 718}
719 719
720// Used for variables that are checked using `.if defined(VAR)`. 720// Used for variables that are checked using `.if defined(VAR)`.
721func (cv *VartypeCheck) Yes() { 721func (cv *VartypeCheck) Yes() {
722 if !matches(cv.value, `^(?:YES|yes)(?:\s+#.*)?$`) { 722 if !matches(cv.value, `^(?:YES|yes)(?:\s+#.*)?$`) {
723 cv.line.warnf("%s should be set to YES or yes.", cv.varname) 723 cv.line.warnf("%s should be set to YES or yes.", cv.varname)
724 cv.line.explain( 724 cv.line.explain(
725 "This variable means \"yes\" if it is defined, and \"no\" if it is", 725 "This variable means \"yes\" if it is defined, and \"no\" if it is",
726 "undefined. Even when it has the value \"no\", this means \"yes\".", 726 "undefined. Even when it has the value \"no\", this means \"yes\".",
727 "Therefore when it is defined, its value should correspond to its", 727 "Therefore when it is defined, its value should correspond to its",
728 "meaning.") 728 "meaning.")
729 } 729 }
730} 730}
731 731
732// The type YesNo is used for variables that are checked using 732// The type YesNo is used for variables that are checked using
733// .if defined(VAR) && !empty(VAR:M[Yy][Ee][Ss]) 733// .if defined(VAR) && !empty(VAR:M[Yy][Ee][Ss])
734// 734//
735func (cv *VartypeCheck) YesNo() { 735func (cv *VartypeCheck) YesNo() {
736 if !matches(cv.value, `^(?:YES|yes|NO|no)(?:\s+#.*)?$`) { 736 if !matches(cv.value, `^(?:YES|yes|NO|no)(?:\s+#.*)?$`) {
737 cv.line.warnf("%s should be set to YES, yes, NO, or no.", cv.varname) 737 cv.line.warnf("%s should be set to YES, yes, NO, or no.", cv.varname)
738 } 738 }
739} 739}
740 740
741// Like YesNo, but the value may be produced by a shell command using the 741// Like YesNo, but the value may be produced by a shell command using the
742// != operator. 742// != operator.
743func (cv *VartypeCheck) YesNoIndirectly() { 743func (cv *VartypeCheck) YesNoIndirectly() {
744 if cv.valueNovar != "" && !matches(cv.value, `^(?:YES|yes|NO|no)(?:\s+#.*)?$`) { 744 if cv.valueNovar != "" && !matches(cv.value, `^(?:YES|yes|NO|no)(?:\s+#.*)?$`) {
745 cv.line.warnf("%s should be set to YES, yes, NO, or no.", cv.varname) 745 cv.line.warnf("%s should be set to YES, yes, NO, or no.", cv.varname)
746 } 746 }
747} 747}