summaryrefslogtreecommitdiff
path: root/pkgtools/pkglint/files/substcontext.go
blob: 2eef82b5101297a57372b6e5551b8182aae78f79 (plain)
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
package main

// SubstContext records the state of a block of variable assignments
// that make up a SUBST class (see `mk/subst.mk`).
type SubstContext struct {
	id        string
	stage     string
	message   string
	files     []string
	sed       []string
	vars      []string
	filterCmd string
}

func (ctx *SubstContext) Varassign(mkline *MkLine) {
	if !G.opts.WarnExtra {
		return
	}

	varname := mkline.Varname()
	op := mkline.Op()
	value := mkline.Value()
	if varname == "SUBST_CLASSES" || hasPrefix(varname, "SUBST_CLASSES.") {
		classes := splitOnSpace(value)
		if len(classes) > 1 {
			mkline.Warnf("Please add only one class at a time to SUBST_CLASSES.")
		}
		if ctx.id != "" && ctx.id != classes[0] {
			mkline.Warnf("SUBST_CLASSES should only appear once in a SUBST block.")
		}
		ctx.id = classes[0]
		return
	}

	m, varbase, varparam := match2(varname, `^(SUBST_(?:STAGE|MESSAGE|FILES|SED|VARS|FILTER_CMD))\.([\-\w_]+)$`)
	if !m {
		if ctx.id != "" {
			mkline.Warnf("Foreign variable %q in SUBST block.", varname)
		}
		return
	}

	if ctx.id == "" {
		mkline.Warnf("SUBST_CLASSES should come before the definition of %q.", varname)
		ctx.id = varparam
	}

	if varparam != ctx.id {
		if ctx.IsComplete() {
			// XXX: This code sometimes produces weird warnings. See
			// meta-pkgs/xorg/Makefile.common 1.41 for an example.
			ctx.Finish(mkline)

			// The following assignment prevents an additional warning,
			// but from a technically viewpoint, it is incorrect.
			ctx.id = varparam
		} else {
			mkline.Warnf("Variable %q does not match SUBST class %q.", varname, ctx.id)
		}
		return
	}

	switch varbase {
	case "SUBST_STAGE":
		ctx.dup(mkline, &ctx.stage, varname, value)
	case "SUBST_MESSAGE":
		ctx.dup(mkline, &ctx.message, varname, value)
	case "SUBST_FILES":
		ctx.duplist(mkline, &ctx.files, varname, op, value)
	case "SUBST_SED":
		ctx.duplist(mkline, &ctx.sed, varname, op, value)
	case "SUBST_FILTER_CMD":
		ctx.dup(mkline, &ctx.filterCmd, varname, value)
	case "SUBST_VARS":
		ctx.duplist(mkline, &ctx.vars, varname, op, value)
	default:
		mkline.Warnf("Foreign variable %q in SUBST block.", varname)
	}
}

func (ctx *SubstContext) IsComplete() bool {
	return ctx.id != "" &&
		ctx.stage != "" &&
		len(ctx.files) != 0 &&
		(len(ctx.sed) != 0 || len(ctx.vars) != 0 || ctx.filterCmd != "")
}

func (ctx *SubstContext) Finish(mkline *MkLine) {
	if ctx.id == "" || !G.opts.WarnExtra {
		return
	}
	if ctx.stage == "" {
		mkline.Warnf("Incomplete SUBST block: %s missing.", ctx.varname("SUBST_STAGE"))
	}
	if len(ctx.files) == 0 {
		mkline.Warnf("Incomplete SUBST block: %s missing.", ctx.varname("SUBST_FILES"))
	}
	if len(ctx.sed) == 0 && len(ctx.vars) == 0 && ctx.filterCmd == "" {
		mkline.Line.Warnf("Incomplete SUBST block: %s, %s or %s missing.",
			ctx.varname("SUBST_SED"), ctx.varname("SUBST_VARS"), ctx.varname("SUBST_FILTER_CMD"))
	}
	ctx.id = ""
	ctx.stage = ""
	ctx.message = ""
	ctx.files = nil
	ctx.sed = nil
	ctx.vars = nil
	ctx.filterCmd = ""
}

func (ctx *SubstContext) varname(varbase string) string {
	if ctx.id != "" {
		return varbase + "." + ctx.id
	} else {
		return varbase
	}
}

func (ctx *SubstContext) dup(mkline *MkLine, pstr *string, varname, value string) {
	if *pstr != "" {
		mkline.Warnf("Duplicate definition of %q.", varname)
	}
	*pstr = value
}

func (ctx *SubstContext) duplist(mkline *MkLine, plist *[]string, varname string, op MkOperator, value string) {
	if len(*plist) > 0 && op != opAssignAppend {
		mkline.Warnf("All but the first %q lines should use the \"+=\" operator.", varname)
	}
	*plist = append(*plist, value)
}