1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
package main
import (
"fmt"
"netbsd.org/pkglint/regex"
"strings"
)
func CheckLineAbsolutePathname(line Line, text string) {
if trace.Tracing {
defer trace.Call1(text)()
}
// In the GNU coding standards, DESTDIR is defined as a (usually
// empty) prefix that can be used to install files to a different
// location from what they have been built for. Therefore
// everything following it is considered an absolute pathname.
//
// Another context where absolute pathnames usually appear is in
// assignments like "bindir=/bin".
if m, path := match1(text, `(?:^|[\t ]|\$[{(]DESTDIR[)}]|[\w_]+[\t ]*=[\t ]*)(/(?:[^"' \t\\]|"[^"*]"|'[^']*')*)`); m {
if matches(path, `^/\w`) {
CheckwordAbsolutePathname(line, path)
}
}
}
func CheckLineLength(line Line, maxlength int) {
if len(line.Text) > maxlength {
line.Warnf("Line too long (should be no more than %d characters).", maxlength)
Explain(
"Back in the old time, terminals with 80x25 characters were common.",
"And this is still the default size of many terminal emulators.",
"Moderately short lines also make reading easier.")
}
}
func CheckLineValidCharacters(line Line) {
uni := ""
for _, r := range line.Text {
if r != '\t' && !(' ' <= r && r <= '~') {
uni += fmt.Sprintf(" %U", r)
}
}
if uni != "" {
line.Warnf("Line contains invalid characters (%s).", uni[1:])
}
}
func CheckLineTrailingWhitespace(line Line) {
if strings.HasSuffix(line.Text, " ") || strings.HasSuffix(line.Text, "\t") {
fix := line.Autofix()
fix.Notef("Trailing white-space.")
fix.Explain(
"When a line ends with some white-space, that space is in most cases",
"irrelevant and can be removed.")
fix.ReplaceRegex(`[ \t\r]+\n$`, "\n", 1)
fix.Apply()
}
}
func CheckLineRcsid(line Line, prefixRe regex.Pattern, suggestedPrefix string) bool {
if trace.Tracing {
defer trace.Call(prefixRe, suggestedPrefix)()
}
if matches(line.Text, `^`+prefixRe+`\$`+`NetBSD(?::[^\$]+)?\$$`) {
return true
}
fix := line.Autofix()
fix.Errorf("Expected %q.", suggestedPrefix+"$"+"NetBSD$")
fix.Explain(
"Several files in pkgsrc must contain the CVS Id, so that their",
"current version can be traced back later from a binary package.",
"This is to ensure reproducible builds, for example for finding bugs.")
fix.InsertBefore(suggestedPrefix + "$" + "NetBSD$")
fix.Apply()
return false
}
func CheckwordAbsolutePathname(line Line, word string) {
if trace.Tracing {
defer trace.Call1(word)()
}
switch {
case matches(word, `^/dev/(?:null|tty|zero)$`):
// These are defined by POSIX.
case word == "/bin/sh":
// This is usually correct, although on Solaris, it's pretty feature-crippled.
case matches(word, `/s\W`):
// Probably a sed(1) command, e.g. /find/s,replace,with,
case matches(word, `^/(?:[a-z]|\$[({])`):
// Absolute paths probably start with a lowercase letter.
line.Warnf("Found absolute pathname: %s", word)
if contains(line.Text, "DESTDIR") {
Explain(
"Absolute pathnames are often an indicator for unportable code. As",
"pkgsrc aims to be a portable system, absolute pathnames should be",
"avoided whenever possible.",
"",
"A special variable in this context is ${DESTDIR}, which is used in",
"GNU projects to specify a different directory for installation than",
"what the programs see later when they are executed. Usually it is",
"empty, so if anything after that variable starts with a slash, it is",
"considered an absolute pathname.")
} else {
Explain(
"Absolute pathnames are often an indicator for unportable code. As",
"pkgsrc aims to be a portable system, absolute pathnames should be",
"avoided whenever possible.")
}
}
}
|