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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
package main
import (
"io/ioutil"
)
//go:generate go tool yacc -p liyy -o licenseyacc.go -v licenseyacc.log license.y
// LicenseCondition describes a complex license condition.
// It has either `Name` or `Main` set.
type LicenseCondition struct {
Name string
Main *LicenseCondition
And []*LicenseCondition
Or []*LicenseCondition
}
func (lc *LicenseCondition) Walk(callback func(*LicenseCondition)) {
callback(lc)
if lc.Main != nil {
lc.Main.Walk(callback)
}
for _, and := range lc.And {
and.Walk(callback)
}
for _, or := range lc.Or {
or.Walk(callback)
}
}
type licenseLexer struct {
repl *PrefixReplacer
result *LicenseCondition
error string
}
func (lexer *licenseLexer) Lex(llval *liyySymType) int {
repl := lexer.repl
repl.AdvanceHspace()
switch {
case repl.rest == "":
return 0
case repl.AdvanceStr("("):
return ltOPEN
case repl.AdvanceStr(")"):
return ltCLOSE
case repl.AdvanceRegexp(`^[\w-.]+`):
word := repl.m[0]
switch word {
case "AND":
return ltAND
case "OR":
return ltOR
default:
llval.Node = &LicenseCondition{Name: word}
return ltNAME
}
}
return -1
}
func (lexer *licenseLexer) Error(s string) {
lexer.error = s
}
func parseLicenses(licenses string) *LicenseCondition {
expanded := resolveVariableRefs(licenses) // For ${PERL5_LICENSE}
lexer := &licenseLexer{repl: NewPrefixReplacer(expanded)}
result := liyyNewParser().Parse(lexer)
if result == 0 {
return lexer.result
}
return nil
}
func checkToplevelUnusedLicenses() {
if G.UsedLicenses == nil {
return
}
licensedir := G.globalData.Pkgsrcdir + "/licenses"
files, _ := ioutil.ReadDir(licensedir)
for _, licensefile := range files {
licensename := licensefile.Name()
licensepath := licensedir + "/" + licensename
if fileExists(licensepath) {
if !G.UsedLicenses[licensename] {
NewLineWhole(licensepath).Warn0("This license seems to be unused.")
}
}
}
}
type LicenseChecker struct {
MkLine *MkLine
}
func (lc *LicenseChecker) Check(value string, op MkOperator) {
licenses := parseLicenses(ifelseStr(op == opAssignAppend, "append-placeholder ", "") + value)
if licenses == nil {
if op == opAssign {
lc.MkLine.Line.Error1("Parse error for license condition %q.", value)
} else {
lc.MkLine.Line.Error1("Parse error for appended license condition %q.", value)
}
return
}
licenses.Walk(lc.checkNode)
}
func (lc *LicenseChecker) checkNode(cond *LicenseCondition) {
license := cond.Name
if license == "" || license == "append-placeholder" {
return
}
var licenseFile string
if G.Pkg != nil {
if licenseFileValue, ok := G.Pkg.varValue("LICENSE_FILE"); ok {
licenseFile = G.CurrentDir + "/" + resolveVarsInRelativePath(licenseFileValue, false)
}
}
if licenseFile == "" {
licenseFile = G.globalData.Pkgsrcdir + "/licenses/" + license
if G.UsedLicenses != nil {
G.UsedLicenses[license] = true
}
}
if !fileExists(licenseFile) {
lc.MkLine.Warn1("License file %s does not exist.", cleanpath(licenseFile))
}
switch license {
case "fee-based-commercial-use",
"no-commercial-use",
"no-profit",
"no-redistribution",
"shareware":
lc.MkLine.Error1("License %q must not be used.", license)
Explain(
"Instead of using these deprecated licenses, extract the actual",
"license from the package into the pkgsrc/licenses/ directory",
"and define LICENSE to that file name. See the pkgsrc guide,",
"keyword LICENSE, for more information.")
}
if len(cond.And) > 0 && len(cond.Or) > 0 {
lc.MkLine.Line.Error0("AND and OR operators in license conditions can only be combined using parentheses.")
Explain(
"Examples for valid license conditions are:",
"",
"\tlicense1 AND license2 AND (license3 OR license4)",
"\t(((license1 OR license2) AND (license3 OR license4)))")
}
}
|