Annotation of pkgsrc/pkgtools/pkglint/files/vartype.go, Revision 1.17
1.1 rillig 1: package main
2:
3: import (
4: "path"
5: "strings"
6: )
7:
8: // Vartype is a combination of a data type and a permission specification.
9: // See vardefs.go for examples, and vartypecheck.go for the implementation.
10: type Vartype struct {
11: kindOfList KindOfList
1.10 rillig 12: basicType *BasicType
1.13 rillig 13: aclEntries []ACLEntry
1.5 rillig 14: guessed bool
1.1 rillig 15: }
16:
1.5 rillig 17: type KindOfList uint8
1.1 rillig 18:
19: const (
1.3 rillig 20: lkNone KindOfList = iota // Plain data type
21: lkSpace // List entries are separated by whitespace; used in .for loops.
22: lkShell // List entries are shell words; used in the :M, :S modifiers.
1.1 rillig 23: )
24:
1.13 rillig 25: type ACLEntry struct {
1.1 rillig 26: glob string // Examples: "Makefile", "*.mk"
1.13 rillig 27: permissions ACLPermissions
1.1 rillig 28: }
29:
1.13 rillig 30: type ACLPermissions uint8
1.1 rillig 31:
32: const (
1.13 rillig 33: aclpSet ACLPermissions = 1 << iota // VAR = value
1.5 rillig 34: aclpSetDefault // VAR ?= value
35: aclpAppend // VAR += value
36: aclpUseLoadtime // OTHER := ${VAR}, OTHER != ${VAR}
37: aclpUse // OTHER = ${VAR}
38: aclpUnknown
1.13 rillig 39: aclpAll = aclpAppend | aclpSetDefault | aclpSet | aclpUseLoadtime | aclpUse
40: aclpAllRuntime = aclpAppend | aclpSetDefault | aclpSet | aclpUse
41: aclpAllWrite = aclpSet | aclpSetDefault | aclpAppend
42: aclpAllRead = aclpUseLoadtime | aclpUse
1.1 rillig 43: )
44:
1.13 rillig 45: func (perms ACLPermissions) Contains(subset ACLPermissions) bool {
1.5 rillig 46: return perms&subset == subset
47: }
48:
1.13 rillig 49: func (perms ACLPermissions) String() string {
1.5 rillig 50: if perms == 0 {
51: return "none"
52: }
53: result := "" +
54: ifelseStr(perms.Contains(aclpSet), "set, ", "") +
55: ifelseStr(perms.Contains(aclpSetDefault), "set-default, ", "") +
56: ifelseStr(perms.Contains(aclpAppend), "append, ", "") +
57: ifelseStr(perms.Contains(aclpUseLoadtime), "use-loadtime, ", "") +
58: ifelseStr(perms.Contains(aclpUse), "use, ", "") +
59: ifelseStr(perms.Contains(aclpUnknown), "unknown, ", "")
60: return strings.TrimRight(result, ", ")
61: }
62:
1.13 rillig 63: func (perms ACLPermissions) HumanString() string {
1.5 rillig 64: result := "" +
65: ifelseStr(perms.Contains(aclpSet), "set, ", "") +
66: ifelseStr(perms.Contains(aclpSetDefault), "given a default value, ", "") +
67: ifelseStr(perms.Contains(aclpAppend), "appended to, ", "") +
68: ifelseStr(perms.Contains(aclpUseLoadtime), "used at load time, ", "") +
69: ifelseStr(perms.Contains(aclpUse), "used, ", "")
70: return strings.TrimRight(result, ", ")
71: }
72:
1.13 rillig 73: func (vt *Vartype) EffectivePermissions(fname string) ACLPermissions {
1.2 rillig 74: for _, aclEntry := range vt.aclEntries {
1.1 rillig 75: if m, _ := path.Match(aclEntry.glob, path.Base(fname)); m {
76: return aclEntry.permissions
77: }
78: }
1.5 rillig 79: return aclpUnknown
1.1 rillig 80: }
81:
1.16 rillig 82: // Union returns the union of all possible permissions.
83: // This can be used to check whether a variable may be defined or used
84: // at all, or if it is read-only.
1.13 rillig 85: func (vt *Vartype) Union() ACLPermissions {
86: var permissions ACLPermissions
1.2 rillig 87: for _, aclEntry := range vt.aclEntries {
1.5 rillig 88: permissions |= aclEntry.permissions
1.1 rillig 89: }
90: return permissions
91: }
92:
1.13 rillig 93: func (vt *Vartype) AllowedFiles(perms ACLPermissions) string {
1.5 rillig 94: files := make([]string, 0, len(vt.aclEntries))
95: for _, aclEntry := range vt.aclEntries {
96: if aclEntry.permissions.Contains(perms) {
97: files = append(files, aclEntry.glob)
98: }
99: }
100: return strings.Join(files, ", ")
101: }
102:
1.16 rillig 103: // IsConsideredList returns whether the type is considered a shell list.
1.11 rillig 104: // This distinction between "real lists" and "considered a list" makes
1.1 rillig 105: // the implementation of checklineMkVartype easier.
1.5 rillig 106: func (vt *Vartype) IsConsideredList() bool {
1.2 rillig 107: switch vt.kindOfList {
1.3 rillig 108: case lkShell:
1.1 rillig 109: return true
1.3 rillig 110: case lkSpace:
1.1 rillig 111: return false
112: }
1.10 rillig 113: switch vt.basicType {
1.12 rillig 114: case BtAwkCommand, BtSedCommands, BtShellCommand, BtShellCommands, BtLicense, BtConfFiles:
1.1 rillig 115: return true
116: }
117: return false
118: }
119:
1.5 rillig 120: func (vt *Vartype) MayBeAppendedTo() bool {
121: return vt.kindOfList != lkNone || vt.IsConsideredList()
1.1 rillig 122: }
123:
1.2 rillig 124: func (vt *Vartype) String() string {
1.16 rillig 125: listPrefix := [...]string{"", "SpaceList of ", "ShellList of "}[vt.kindOfList]
1.15 rillig 126: guessedSuffix := ifelseStr(vt.guessed, " (guessed)", "")
127: return listPrefix + vt.basicType.name + guessedSuffix
1.1 rillig 128: }
129:
1.7 rillig 130: func (vt *Vartype) IsShell() bool {
1.10 rillig 131: switch vt.basicType {
132: case BtCFlag, // Subtype of ShellWord
133: BtLdFlag, // Subtype of ShellWord
134: BtSedCommands,
135: BtShellCommand,
136: BtShellCommands,
137: BtShellWord:
1.7 rillig 138: return true
139: }
140: return false
141: }
142:
1.11 rillig 143: // IsBasicSafe returns whether the basic vartype consists only of
144: // characters that don't need escaping in most contexts, like A-Za-z0-9-_.
1.7 rillig 145: func (vt *Vartype) IsBasicSafe() bool {
1.10 rillig 146: switch vt.basicType {
147: case BtBuildlinkDepmethod,
148: BtCategory,
149: BtDistSuffix,
150: BtEmulPlatform,
151: BtFileMode,
152: BtFilename,
153: BtIdentifier,
154: BtInteger,
155: BtMachineGnuPlatform,
156: BtMachinePlatform,
157: BtOption,
158: BtPathname,
159: BtPerl5Packlist,
160: BtPkgName,
161: BtPkgOptionsVar,
162: BtPkgPath,
163: BtPkgRevision,
164: BtPrefixPathname,
165: BtPythonDependency,
166: BtRelativePkgDir,
167: BtRelativePkgPath,
168: BtStage,
1.14 rillig 169: BtTool, // Sometimes contains a colon, but that should be ok.
1.10 rillig 170: BtUserGroupName,
171: BtVersion,
172: BtWrkdirSubdirectory,
173: BtYesNo,
174: BtYesNoIndirectly:
1.7 rillig 175: return true
176: }
177: return false
178: }
179:
180: func (vt *Vartype) IsPlainString() bool {
1.10 rillig 181: switch vt.basicType {
182: case BtComment, BtMessage, BtUnknown:
1.7 rillig 183: return true
184: }
185: return false
186: }
187:
1.10 rillig 188: type BasicType struct {
1.1 rillig 189: name string
190: checker func(*VartypeCheck)
191: }
192:
1.10 rillig 193: func (bt *BasicType) IsEnum() bool {
194: return hasPrefix(bt.name, "enum: ")
1.1 rillig 195: }
1.10 rillig 196: func (bt *BasicType) HasEnum(value string) bool {
197: return !contains(value, " ") && contains(bt.name, " "+value+" ")
1.1 rillig 198: }
1.10 rillig 199: func (bt *BasicType) AllowedEnums() string {
200: return bt.name[6 : len(bt.name)-1]
1.1 rillig 201: }
202:
203: var (
1.10 rillig 204: BtAwkCommand = &BasicType{"AwkCommand", (*VartypeCheck).AwkCommand}
205: BtBasicRegularExpression = &BasicType{"BasicRegularExpression", (*VartypeCheck).BasicRegularExpression}
206: BtBuildlinkDepmethod = &BasicType{"BuildlinkDepmethod", (*VartypeCheck).BuildlinkDepmethod}
207: BtCategory = &BasicType{"Category", (*VartypeCheck).Category}
208: BtCFlag = &BasicType{"CFlag", (*VartypeCheck).CFlag}
209: BtComment = &BasicType{"Comment", (*VartypeCheck).Comment}
1.12 rillig 210: BtConfFiles = &BasicType{"ConfFiles", (*VartypeCheck).ConfFiles}
1.10 rillig 211: BtDependency = &BasicType{"Dependency", (*VartypeCheck).Dependency}
212: BtDependencyWithPath = &BasicType{"DependencyWithPath", (*VartypeCheck).DependencyWithPath}
213: BtDistSuffix = &BasicType{"DistSuffix", (*VartypeCheck).DistSuffix}
214: BtEmulPlatform = &BasicType{"EmulPlatform", (*VartypeCheck).EmulPlatform}
215: BtFetchURL = &BasicType{"FetchURL", (*VartypeCheck).FetchURL}
216: BtFilename = &BasicType{"Filename", (*VartypeCheck).Filename}
217: BtFilemask = &BasicType{"Filemask", (*VartypeCheck).Filemask}
218: BtFileMode = &BasicType{"FileMode", (*VartypeCheck).FileMode}
219: BtHomepage = &BasicType{"Homepage", (*VartypeCheck).Homepage}
220: BtIdentifier = &BasicType{"Identifier", (*VartypeCheck).Identifier}
221: BtInteger = &BasicType{"Integer", (*VartypeCheck).Integer}
222: BtLdFlag = &BasicType{"LdFlag", (*VartypeCheck).LdFlag}
223: BtLicense = &BasicType{"License", (*VartypeCheck).License}
224: BtMachineGnuPlatform = &BasicType{"MachineGnuPlatform", (*VartypeCheck).MachineGnuPlatform}
225: BtMachinePlatform = &BasicType{"MachinePlatform", (*VartypeCheck).MachinePlatform}
226: BtMachinePlatformPattern = &BasicType{"MachinePlatformPattern", (*VartypeCheck).MachinePlatformPattern}
227: BtMailAddress = &BasicType{"MailAddress", (*VartypeCheck).MailAddress}
228: BtMessage = &BasicType{"Message", (*VartypeCheck).Message}
229: BtOption = &BasicType{"Option", (*VartypeCheck).Option}
230: BtPathlist = &BasicType{"Pathlist", (*VartypeCheck).Pathlist}
231: BtPathmask = &BasicType{"Pathmask", (*VartypeCheck).Pathmask}
232: BtPathname = &BasicType{"Pathname", (*VartypeCheck).Pathname}
233: BtPerl5Packlist = &BasicType{"Perl5Packlist", (*VartypeCheck).Perl5Packlist}
234: BtPerms = &BasicType{"Perms", (*VartypeCheck).Perms}
1.17 ! rillig 235: BtPkgName = &BasicType{"Pkgname", (*VartypeCheck).Pkgname}
1.10 rillig 236: BtPkgPath = &BasicType{"PkgPath", (*VartypeCheck).PkgPath}
237: BtPkgOptionsVar = &BasicType{"PkgOptionsVar", (*VartypeCheck).PkgOptionsVar}
238: BtPkgRevision = &BasicType{"PkgRevision", (*VartypeCheck).PkgRevision}
239: BtPrefixPathname = &BasicType{"PrefixPathname", (*VartypeCheck).PrefixPathname}
240: BtPythonDependency = &BasicType{"PythonDependency", (*VartypeCheck).PythonDependency}
241: BtRelativePkgDir = &BasicType{"RelativePkgDir", (*VartypeCheck).RelativePkgDir}
242: BtRelativePkgPath = &BasicType{"RelativePkgPath", (*VartypeCheck).RelativePkgPath}
243: BtRestricted = &BasicType{"Restricted", (*VartypeCheck).Restricted}
244: BtSedCommand = &BasicType{"SedCommand", (*VartypeCheck).SedCommand}
245: BtSedCommands = &BasicType{"SedCommands", (*VartypeCheck).SedCommands}
246: BtShellCommand = &BasicType{"ShellCommand", nil}
247: BtShellCommands = &BasicType{"ShellCommands", nil}
248: BtShellWord = &BasicType{"ShellWord", nil}
249: BtStage = &BasicType{"Stage", (*VartypeCheck).Stage}
250: BtTool = &BasicType{"Tool", (*VartypeCheck).Tool}
251: BtUnknown = &BasicType{"Unknown", (*VartypeCheck).Unknown}
252: BtURL = &BasicType{"URL", (*VartypeCheck).URL}
253: BtUserGroupName = &BasicType{"UserGroupName", (*VartypeCheck).UserGroupName}
254: BtVariableName = &BasicType{"VariableName", (*VartypeCheck).VariableName}
255: BtVersion = &BasicType{"Version", (*VartypeCheck).Version}
256: BtWrapperReorder = &BasicType{"WrapperReorder", (*VartypeCheck).WrapperReorder}
257: BtWrapperTransform = &BasicType{"WrapperTransform", (*VartypeCheck).WrapperTransform}
258: BtWrkdirSubdirectory = &BasicType{"WrkdirSubdirectory", (*VartypeCheck).WrkdirSubdirectory}
259: BtWrksrcSubdirectory = &BasicType{"WrksrcSubdirectory", (*VartypeCheck).WrksrcSubdirectory}
260: BtYes = &BasicType{"Yes", (*VartypeCheck).Yes}
261: BtYesNo = &BasicType{"YesNo", (*VartypeCheck).YesNo}
262: BtYesNoIndirectly = &BasicType{"YesNoIndirectly", (*VartypeCheck).YesNoIndirectly}
1.1 rillig 263: )
264:
265: func init() { // Necessary due to circular dependency
1.10 rillig 266: BtShellCommand.checker = (*VartypeCheck).ShellCommand
267: BtShellCommands.checker = (*VartypeCheck).ShellCommands
268: BtShellWord.checker = (*VartypeCheck).ShellWord
1.1 rillig 269: }
CVSweb <webmaster@jp.NetBSD.org>