pkglint

package module
v5.6.10+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 21, 2018 License: BSD-2-Clause Imports: 26 Imported by: 0

README

Build Status codecov

pkglint checks whether a pkgsrc package conforms to the various conventions established over the years. It produces warnings, errors and notes and, upon request, explains them.

Before importing a new package or making changes to an existing package, pkglint should be run in the package's directory to check for common errors.

See https://www.pkgsrc.org/.


For an introduction to programming and extending pkglint, see The pkglint tour.

Documentation

Index

Constants

View Source
const AutofixFormat = "AutofixFormat"

AutofixFormat is a special value that is used for logging diagnostics like "Replacing \"old\" with \"new\".".

Since these are not really diagnostics, duplicates are not suppressed.

View Source
const SilentAutofixFormat = "SilentAutofixFormat"

SilentAutofixFormat is used in exceptional situations when an autofix action is not directly related to a diagnostic.

To prevent confusion, the code using this magic value must ensure to log a diagnostic by other means.

Variables

View Source
var (
	Fatal           = &LogLevel{"FATAL", "fatal"}
	Error           = &LogLevel{"ERROR", "error"}
	Warn            = &LogLevel{"WARN", "warning"}
	Note            = &LogLevel{"NOTE", "note"}
	AutofixLogLevel = &LogLevel{"AUTOFIX", "autofix"}
)
View Source
var (
	LowerDash = textproc.NewByteSet("a-z---")
	AlnumDot  = textproc.NewByteSet("A-Za-z0-9_.")
)
View Source
var (
	BtAwkCommand             = &BasicType{"AwkCommand", (*VartypeCheck).AwkCommand}
	BtBasicRegularExpression = &BasicType{"BasicRegularExpression", (*VartypeCheck).BasicRegularExpression}
	BtBuildlinkDepmethod     = &BasicType{"BuildlinkDepmethod", (*VartypeCheck).BuildlinkDepmethod}
	BtCategory               = &BasicType{"Category", (*VartypeCheck).Category}
	BtCFlag                  = &BasicType{"CFlag", (*VartypeCheck).CFlag}
	BtComment                = &BasicType{"Comment", (*VartypeCheck).Comment}
	BtConfFiles              = &BasicType{"ConfFiles", (*VartypeCheck).ConfFiles}
	BtDependency             = &BasicType{"Dependency", (*VartypeCheck).Dependency}
	BtDependencyWithPath     = &BasicType{"DependencyWithPath", (*VartypeCheck).DependencyWithPath}
	BtDistSuffix             = &BasicType{"DistSuffix", (*VartypeCheck).DistSuffix}
	BtEmulPlatform           = &BasicType{"EmulPlatform", (*VartypeCheck).EmulPlatform}
	BtFetchURL               = &BasicType{"FetchURL", (*VartypeCheck).FetchURL}
	BtFileName               = &BasicType{"Filename", (*VartypeCheck).Filename}
	BtFileMask               = &BasicType{"FileMask", (*VartypeCheck).FileMask}
	BtFileMode               = &BasicType{"FileMode", (*VartypeCheck).FileMode}
	BtGccReqd                = &BasicType{"GccReqd", (*VartypeCheck).GccReqd}
	BtHomepage               = &BasicType{"Homepage", (*VartypeCheck).Homepage}
	BtIdentifier             = &BasicType{"Identifier", (*VartypeCheck).Identifier}
	BtInteger                = &BasicType{"Integer", (*VartypeCheck).Integer}
	BtLdFlag                 = &BasicType{"LdFlag", (*VartypeCheck).LdFlag}
	BtLicense                = &BasicType{"License", (*VartypeCheck).License}
	BtMachineGnuPlatform     = &BasicType{"MachineGnuPlatform", (*VartypeCheck).MachineGnuPlatform}
	BtMachinePlatform        = &BasicType{"MachinePlatform", (*VartypeCheck).MachinePlatform}
	BtMachinePlatformPattern = &BasicType{"MachinePlatformPattern", (*VartypeCheck).MachinePlatformPattern}
	BtMailAddress            = &BasicType{"MailAddress", (*VartypeCheck).MailAddress}
	BtMessage                = &BasicType{"Message", (*VartypeCheck).Message}
	BtOption                 = &BasicType{"Option", (*VartypeCheck).Option}
	BtPathlist               = &BasicType{"Pathlist", (*VartypeCheck).Pathlist}
	BtPathmask               = &BasicType{"PathMask", (*VartypeCheck).PathMask}
	BtPathname               = &BasicType{"Pathname", (*VartypeCheck).Pathname}
	BtPerl5Packlist          = &BasicType{"Perl5Packlist", (*VartypeCheck).Perl5Packlist}
	BtPerms                  = &BasicType{"Perms", (*VartypeCheck).Perms}
	BtPkgName                = &BasicType{"Pkgname", (*VartypeCheck).Pkgname}
	BtPkgPath                = &BasicType{"PkgPath", (*VartypeCheck).PkgPath}
	BtPkgOptionsVar          = &BasicType{"PkgOptionsVar", (*VartypeCheck).PkgOptionsVar}
	BtPkgRevision            = &BasicType{"PkgRevision", (*VartypeCheck).PkgRevision}
	BtPrefixPathname         = &BasicType{"PrefixPathname", (*VartypeCheck).PrefixPathname}
	BtPythonDependency       = &BasicType{"PythonDependency", (*VartypeCheck).PythonDependency}
	BtRelativePkgDir         = &BasicType{"RelativePkgDir", (*VartypeCheck).RelativePkgDir}
	BtRelativePkgPath        = &BasicType{"RelativePkgPath", (*VartypeCheck).RelativePkgPath}
	BtRestricted             = &BasicType{"Restricted", (*VartypeCheck).Restricted}
	BtSedCommands            = &BasicType{"SedCommands", (*VartypeCheck).SedCommands}
	BtShellCommand           = &BasicType{"ShellCommand", nil}
	BtShellCommands          = &BasicType{"ShellCommands", nil}
	BtShellWord              = &BasicType{"ShellWord", nil}
	BtStage                  = &BasicType{"Stage", (*VartypeCheck).Stage}
	BtTool                   = &BasicType{"Tool", (*VartypeCheck).Tool}
	BtUnknown                = &BasicType{"Unknown", (*VartypeCheck).Unknown}
	BtURL                    = &BasicType{"URL", (*VartypeCheck).URL}
	BtUserGroupName          = &BasicType{"UserGroupName", (*VartypeCheck).UserGroupName}
	BtVariableName           = &BasicType{"VariableName", (*VartypeCheck).VariableName}
	BtVersion                = &BasicType{"Version", (*VartypeCheck).Version}
	BtWrapperReorder         = &BasicType{"WrapperReorder", (*VartypeCheck).WrapperReorder}
	BtWrapperTransform       = &BasicType{"WrapperTransform", (*VartypeCheck).WrapperTransform}
	BtWrkdirSubdirectory     = &BasicType{"WrkdirSubdirectory", (*VartypeCheck).WrkdirSubdirectory}
	BtWrksrcSubdirectory     = &BasicType{"WrksrcSubdirectory", (*VartypeCheck).WrksrcSubdirectory}
	BtYes                    = &BasicType{"Yes", (*VartypeCheck).Yes}
	BtYesNo                  = &BasicType{"YesNo", (*VartypeCheck).YesNo}
	BtYesNoIndirectly        = &BasicType{"YesNoIndirectly", (*VartypeCheck).YesNoIndirectly}
)
View Source
var (
	G = NewPkglint()
)

G is the abbreviation for "global state"; these are the only global variable in this Go package

View Source
var VarnameBytes = textproc.NewByteSet("A-Za-z_0-9*+---.[")

VarnameBytes contains characters that may be used in variable names. The bracket is included only for the tool of the same name, e.g. "TOOLS_PATH.[".

This approach differs from the one in devel/bmake/files/parse.c:/^Parse_IsVar, but in practice it works equally well. Luckily there aren't many situations where a complicated variable name contains unbalanced parentheses or braces, which would confuse the devel/bmake parser.

Functions

func AutofixDistinfo

func AutofixDistinfo(oldSha1, newSha1 string)

func CheckFileAlternatives

func CheckFileAlternatives(filename string)

func CheckFileMk

func CheckFileMk(filename string)

func CheckFileOther

func CheckFileOther(filename string)

func CheckLinesBuildlink3Mk

func CheckLinesBuildlink3Mk(mklines MkLines)

func CheckLinesDescr

func CheckLinesDescr(lines Lines)

func CheckLinesDistinfo

func CheckLinesDistinfo(lines Lines)

func CheckLinesMessage

func CheckLinesMessage(lines Lines)

func CheckLinesOptionsMk

func CheckLinesOptionsMk(mklines MkLines)

func CheckLinesPatch

func CheckLinesPatch(lines Lines)

func CheckLinesPlist

func CheckLinesPlist(lines Lines)

func CheckLinesTrailingEmptyLines

func CheckLinesTrailingEmptyLines(lines Lines)

func CheckdirCategory

func CheckdirCategory(dir string)

func CheckdirToplevel

func CheckdirToplevel(dir string)

func IsPrefs

func IsPrefs(filename string) bool

IsPrefs returns whether the given file, when included, loads the user preferences.

func Main

func Main() int

func MatchMkInclude

func MatchMkInclude(text string) (m bool, indentation, directive, filename string)

func MatchVarassign

func MatchVarassign(text string) (m, commented bool, varname, spaceAfterVarname, op, valueAlign, value, spaceAfterValue, comment string)

func NewPlistLineSorter

func NewPlistLineSorter(plines []*PlistLine) *plistLineSorter

func SaveAutofixChanges

func SaveAutofixChanges(lines Lines) (autofixed bool)

SaveAutofixChanges writes the given lines back into their files, applying the autofix changes. The lines may come from different files. Only files that actually have changed lines are saved.

Types

type ACLEntry

type ACLEntry struct {
	// contains filtered or unexported fields
}

type ACLPermissions

type ACLPermissions uint8

func (ACLPermissions) Contains

func (perms ACLPermissions) Contains(subset ACLPermissions) bool

func (ACLPermissions) HumanString

func (perms ACLPermissions) HumanString() string

func (ACLPermissions) String

func (perms ACLPermissions) String() string

type Autofix

type Autofix struct {
	// contains filtered or unexported fields
}

Autofix handles all modifications to a single line, describes them in a human-readable form and formats the output. The modifications are kept in memory only, until they are written to disk by SaveAutofixChanges.

func NewAutofix

func NewAutofix(line Line) *Autofix

func (*Autofix) Apply

func (fix *Autofix) Apply()

Apply does the actual work. Depending on the pkglint mode, it either:

* logs the associated message (default) but does not record the fixes in the line

* logs what would be fixed (--show-autofix) and records the fixes in the line

* records the fixes in the line (--autofix), ready for SaveAutofixChanges

func (*Autofix) Custom

func (fix *Autofix) Custom(fixer func(showAutofix, autofix bool))

Custom runs a custom fix action, unless the fix is skipped anyway because of the --only option.

The fixer function must check whether it can actually fix something, and if so, call Describef to describe the actual fix.

If showAutofix and autofix are both false, the fix must only be described by calling Describef. No observable modification must be done, not even in memory.

If showAutofix is true but autofix is false, the fix should be done in memory as far as possible. For example, changing the text of Line.raw is appropriate, but changing files in the file system is not.

Only if autofix is true, fixes other than modifying the current Line should be done persistently, such as changes to the file system.

In any case, changes to the current Line will be written back to disk by SaveAutofixChanges, after fixing all the lines in the file at once.

func (*Autofix) Delete

func (fix *Autofix) Delete()

Delete removes the current line completely. It can be combined with InsertAfter or InsertBefore to replace the complete line with some different text.

func (*Autofix) Describef

func (fix *Autofix) Describef(lineno int, format string, args ...interface{})

Describef is used while Autofix.Custom is called to remember a description of the actual fix for logging it later when Apply is called. Describef may be called multiple times before calling Apply.

func (*Autofix) Errorf

func (fix *Autofix) Errorf(format string, args ...interface{})

Errorf remembers the error for logging it later when Apply is called.

func (*Autofix) Explain

func (fix *Autofix) Explain(explanation ...string)

Explain remembers the explanation for logging it later when Apply is called.

func (*Autofix) InsertAfter

func (fix *Autofix) InsertAfter(text string)

InsertAfter appends a line after the current line. The newline is added internally.

func (*Autofix) InsertBefore

func (fix *Autofix) InsertBefore(text string)

InsertBefore prepends a line before the current line. The newline is added internally.

func (*Autofix) Notef

func (fix *Autofix) Notef(format string, args ...interface{})

Notef remembers the note for logging it later when Apply is called.

func (*Autofix) Realign

func (fix *Autofix) Realign(mkline MkLine, newWidth int)

func (*Autofix) Replace

func (fix *Autofix) Replace(from string, to string)

ReplaceAfter replaces "from" with "to", a single time.

func (*Autofix) ReplaceAfter

func (fix *Autofix) ReplaceAfter(prefix, from string, to string)

ReplaceAfter replaces the text "prefix+from" with "prefix+to", a single time. In the diagnostic, only the replacement of "from" with "to" is mentioned.

func (*Autofix) ReplaceRegex

func (fix *Autofix) ReplaceRegex(from regex.Pattern, toText string, howOften int)

ReplaceRegex replaces the first howOften or all occurrences (if negative) of the `from` pattern with the fixed string `toText`.

Placeholders like `$1` are _not_ expanded in the `toText`. (If you know how to do the expansion correctly, feel free to implement it.)

func (*Autofix) Warnf

func (fix *Autofix) Warnf(format string, args ...interface{})

Warnf remembers the warning for logging it later when Apply is called.

type BasicType

type BasicType struct {
	// contains filtered or unexported fields
}

func (*BasicType) AllowedEnums

func (bt *BasicType) AllowedEnums() string

func (*BasicType) HasEnum

func (bt *BasicType) HasEnum(value string) bool

func (*BasicType) IsEnum

func (bt *BasicType) IsEnum() bool

func (*BasicType) NeedsQ

func (bt *BasicType) NeedsQ() bool

NeedsQ returns whether variables of this type need the :Q modifier to be safely embedded in other variables or shell programs.

Variables that can consists only of characters like A-Za-z0-9-._ don't need the :Q modifier. All others do, for safety reasons.

type Buildlink3Checker

type Buildlink3Checker struct {
	// contains filtered or unexported fields
}

func (*Buildlink3Checker) Check

func (ck *Buildlink3Checker) Check()

type Change

type Change struct {
	Line    Line
	Action  string
	Pkgpath string
	Version string
	Author  string
	Date    string
}

Change is a change entry from the `doc/CHANGES-*` files.

type CmdOpts

type CmdOpts struct {
	CheckAlternatives,
	CheckBuildlink3,
	CheckDescr,
	CheckDistinfo,
	CheckExtra,
	CheckGlobal,
	CheckInstall,
	CheckMakefile,
	CheckMessage,
	CheckMk,
	CheckOptions,
	CheckPatches,
	CheckPlist bool

	WarnAbsname,
	WarnDirectcmd,
	WarnExtra,
	WarnOrder,
	WarnPerm,
	WarnPlistDepr,
	WarnPlistSort,
	WarnQuoting,
	WarnSpace,
	WarnStyle,
	WarnTypes bool

	Profiling,
	ShowHelp,
	DumpMakefile,
	Import,
	Recursive,
	ShowVersion bool

	LogOnly []string
	// contains filtered or unexported fields
}

type DependencyPattern

type DependencyPattern struct {
	Pkgbase  string // "freeciv-client", "{gcc48,gcc48-libs}", "${EMACS_REQD}"
	LowerOp  string // ">=", ">"
	Lower    string // "2.5.0", "${PYVER}"
	UpperOp  string // "<", "<="
	Upper    string // "3.0", "${PYVER}"
	Wildcard string // "[0-9]*", "1.5.*", "${PYVER}"
}

type Expecter

type Expecter struct {
	// contains filtered or unexported fields
}

Expecter records the state when checking a list of lines from top to bottom.

TODO: Maybe rename to LineLexer.

func NewExpecter

func NewExpecter(lines Lines) *Expecter

func (*Expecter) Advance

func (exp *Expecter) Advance() bool

Advance skips the current line and returns true.

func (*Expecter) AdvanceIfEquals

func (exp *Expecter) AdvanceIfEquals(text string) bool

func (*Expecter) AdvanceIfMatches

func (exp *Expecter) AdvanceIfMatches(re regex.Pattern) bool

func (*Expecter) AdvanceIfPrefix

func (exp *Expecter) AdvanceIfPrefix(prefix string) bool

func (*Expecter) CurrentLine

func (exp *Expecter) CurrentLine() Line

func (*Expecter) EOF

func (exp *Expecter) EOF() bool

func (*Expecter) ExpectEmptyLine

func (exp *Expecter) ExpectEmptyLine() bool

func (*Expecter) ExpectText

func (exp *Expecter) ExpectText(text string) bool

func (*Expecter) Group

func (exp *Expecter) Group(index int) string

func (*Expecter) PreviousLine

func (exp *Expecter) PreviousLine() Line

func (*Expecter) StepBack

func (exp *Expecter) StepBack()

type FileCache

type FileCache struct {
	// contains filtered or unexported fields
}

FileCache reduces the IO load for commonly loaded files by about 50%, especially for buildlink3.mk and *.buildlink3.mk files.

func NewFileCache

func NewFileCache(size int) *FileCache

func (*FileCache) Evict

func (c *FileCache) Evict(filename string)

func (*FileCache) Get

func (c *FileCache) Get(filename string, options LoadOptions) Lines

func (*FileCache) Put

func (c *FileCache) Put(filename string, options LoadOptions, lines Lines)

type FileType

type FileType uint8

func (FileType) String

func (ft FileType) String() string

type Hash

type Hash struct {
	// contains filtered or unexported fields
}

type Indentation

type Indentation struct {
	// contains filtered or unexported fields
}

Indentation remembers the stack of preprocessing directives and their indentation. By convention, each directive is indented by 2 spaces. An excepting are multiple-inclusion guards, they don't increase the indentation.

func NewIndentation

func NewIndentation() *Indentation

func (*Indentation) AddCheckedFile

func (ind *Indentation) AddCheckedFile(filename string)

func (*Indentation) AddVar

func (ind *Indentation) AddVar(varname string)

AddVar remembers that the current indentation depends on the given variable, most probably because that variable is used in a .if directive.

Variables named *_MK are ignored since they are usually not interesting.

func (*Indentation) Args

func (ind *Indentation) Args() string

Args returns the arguments of the innermost .if, .elif or .for.

func (*Indentation) CheckFinish

func (ind *Indentation) CheckFinish(filename string)

func (*Indentation) DependsOn

func (ind *Indentation) DependsOn(varname string) bool

func (*Indentation) Depth

func (ind *Indentation) Depth(directive string) int

Depth returns the number of space characters by which the directive should be indented.

This is typically two more than the surrounding level, except for multiple-inclusion guards.

func (*Indentation) IsCheckedFile

func (ind *Indentation) IsCheckedFile(filename string) bool

func (*Indentation) IsConditional

func (ind *Indentation) IsConditional() bool

IsConditional returns whether the current line depends on evaluating any variable in an .if or .elif expression or from a .for loop.

Variables named *_MK are excluded since they are usually not interesting.

func (*Indentation) Len

func (ind *Indentation) Len() int

func (*Indentation) Pop

func (ind *Indentation) Pop()

func (*Indentation) Push

func (ind *Indentation) Push(mkline MkLine, indent int, condition string)

func (*Indentation) RememberUsedVariables

func (ind *Indentation) RememberUsedVariables(cond MkCond)

func (*Indentation) String

func (ind *Indentation) String() string

func (*Indentation) TrackAfter

func (ind *Indentation) TrackAfter(mkline MkLine)

func (*Indentation) TrackBefore

func (ind *Indentation) TrackBefore(mkline MkLine)

func (*Indentation) Varnames

func (ind *Indentation) Varnames() []string

Varnames returns the list of all variables that are mentioned in any condition or loop surrounding the current line.

Variables named *_MK are excluded since they are usually not interesting.

type KindOfList

type KindOfList uint8

type LicenseChecker

type LicenseChecker struct {
	MkLine MkLine
}

func (*LicenseChecker) Check

func (lc *LicenseChecker) Check(value string, op MkOperator)

type Line

type Line = *LineImpl

Line represents a line of text from a file. It aliases a pointer type to reduces the number of *Line occurrences in the code. Using a type alias is more efficient than an interface type, I guess.

func NewLine

func NewLine(filename string, lineno int, text string, rawLine *RawLine) Line

func NewLineEOF

func NewLineEOF(filename string) Line

NewLineEOF creates a dummy line for logging, with the "line number" EOF.

func NewLineMulti

func NewLineMulti(filename string, firstLine, lastLine int, text string, rawLines []*RawLine) Line

NewLineMulti is for logical Makefile lines that end with backslash.

func NewLineWhole

func NewLineWhole(filename string) Line

NewLineWhole creates a dummy line for logging messages that affect a file as a whole.

type LineChecker

type LineChecker struct {
	// contains filtered or unexported fields
}

func (LineChecker) CheckAbsolutePathname

func (ck LineChecker) CheckAbsolutePathname(text string)

CheckAbsolutePathname checks whether any absolute pathnames occur in the line.

XXX: Is this check really useful? It had been added 10 years ago because some style guide said that "absolute pathnames should be avoided", but there was no evidence for that.

func (LineChecker) CheckLength

func (ck LineChecker) CheckLength(maxLength int)

func (LineChecker) CheckTrailingWhitespace

func (ck LineChecker) CheckTrailingWhitespace()

func (LineChecker) CheckValidCharacters

func (ck LineChecker) CheckValidCharacters()

func (LineChecker) CheckWordAbsolutePathname

func (ck LineChecker) CheckWordAbsolutePathname(word string)

CheckWordAbsolutePathname checks the given word (which is often part of a shell command) for absolute pathnames.

XXX: Is this check really useful? It had been added 10 years ago because some style guide said that "absolute pathnames should be avoided", but there was no evidence for that.

type LineImpl

type LineImpl struct {
	// TODO: Consider storing pointers to the Filename and Basename instead of strings to save memory.
	// But first find out where and why pkglint needs so much memory (200 MB for a full recursive run over pkgsrc + wip).
	Filename string // uses / as directory separator on all platforms
	Basename string // the last component of the Filename

	// without the trailing newline character;
	// in Makefiles, also contains the text from the continuation lines
	Text string

	Once
	// contains filtered or unexported fields
}

func (*LineImpl) Autofix

func (line *LineImpl) Autofix() *Autofix

Autofix returns the autofix instance belonging to the line.

Usage:

fix := line.Autofix()

fix.Errorf("Must not be ...")
fix.Warnf("Should not be ...")
fix.Notef("It is also possible ...")

fix.Explain(
    "Explanation ...",
    "... end of explanation.")

fix.Replace("from", "to")
fix.ReplaceAfter("prefix", "from", "to")
fix.ReplaceRegex(`[\t ]+`, "space", -1)
fix.InsertBefore("new line")
fix.InsertAfter("new line")
fix.Delete()
fix.Custom(func(showAutofix, autofix bool) {})

fix.Apply()

func (*LineImpl) Errorf

func (line *LineImpl) Errorf(format string, args ...interface{})

func (*LineImpl) Explain

func (line *LineImpl) Explain(explanation ...string)

func (*LineImpl) Fatalf

func (line *LineImpl) Fatalf(format string, args ...interface{})

func (*LineImpl) IsMultiline

func (line *LineImpl) IsMultiline() bool

func (*LineImpl) Linenos

func (line *LineImpl) Linenos() string

func (*LineImpl) Notef

func (line *LineImpl) Notef(format string, args ...interface{})

func (*LineImpl) PathToFile

func (line *LineImpl) PathToFile(filePath string) string

PathToFile returns the relative path from this line to the given file path. This is typically used for arguments in diagnostics, which should always be relative to the line with which the diagnostic is associated.

func (*LineImpl) RefTo

func (line *LineImpl) RefTo(other Line) string

RefTo returns a reference to another line, which can be in the same file or in a different file.

func (*LineImpl) String

func (line *LineImpl) String() string

func (*LineImpl) Warnf

func (line *LineImpl) Warnf(format string, args ...interface{})

type Lines

type Lines = *LinesImpl

func Load

func Load(filename string, options LoadOptions) Lines

func NewLines

func NewLines(filename string, lines []Line) Lines

type LinesImpl

type LinesImpl struct {
	FileName string
	BaseName string
	Lines    []Line
}

func (*LinesImpl) CheckRcsID

func (ls *LinesImpl) CheckRcsID(index int, prefixRe regex.Pattern, suggestedPrefix string) bool

func (*LinesImpl) EOFLine

func (ls *LinesImpl) EOFLine() Line

func (*LinesImpl) Errorf

func (ls *LinesImpl) Errorf(format string, args ...interface{})

func (*LinesImpl) LastLine

func (ls *LinesImpl) LastLine() Line

func (*LinesImpl) Len

func (ls *LinesImpl) Len() int

func (*LinesImpl) SaveAutofixChanges

func (ls *LinesImpl) SaveAutofixChanges()

func (*LinesImpl) Warnf

func (ls *LinesImpl) Warnf(format string, args ...interface{})

type LoadOptions

type LoadOptions uint8
const (
	MustSucceed LoadOptions = 1 << iota // It's a fatal error if loading fails.
	NotEmpty                            // It is an error if the file is empty.
	Makefile                            // Lines ending in a backslash are continued in the next line.
	LogErrors                           //
)

type LogLevel

type LogLevel struct {
	TraditionalName string
	GccName         string
}

type Logger

type Logger struct {
	Opts LoggerOpts
	// contains filtered or unexported fields
}

func (*Logger) Diag

func (l *Logger) Diag(line Line, level *LogLevel, format string, args ...interface{})

Diag logs a diagnostic. These are filtered by the --only command line option, and duplicates are suppressed unless the --log-verbose command line option is given.

See Logf for logging arbitrary messages.

func (*Logger) Explain

func (l *Logger) Explain(explanation ...string)

Explain outputs an explanation for the preceding diagnostic if the --explain option is given. Otherwise it just records that an explanation is available.

func (*Logger) FirstTime

func (l *Logger) FirstTime(filename, linenos, msg string) bool

func (*Logger) IsAutofix

func (l *Logger) IsAutofix() bool

func (*Logger) Logf

func (l *Logger) Logf(level *LogLevel, filename, lineno, format, msg string)

func (*Logger) Relevant

func (l *Logger) Relevant(format string) bool

Relevant decides and remembers whether the given diagnostic is relevant and should be logged.

The result of the decision affects all log items until Relevant is called for the next time.

func (*Logger) ShowSummary

func (l *Logger) ShowSummary()

type LoggerOpts

type LoggerOpts struct {
	ShowAutofix,
	Autofix,
	Explain,
	ShowSource,
	LogVerbose,
	GccOutput,
	Quiet bool
}

type MkCond

type MkCond = *mkCond

MkCond is a condition in a Makefile, such as ${OPSYS} == NetBSD.

The representation is somewhere between syntactic and semantic. Unnecessary parentheses are omitted in this representation, but !empty(VARNAME) is represented differently from ${VARNAME} != "". For higher level analysis, a unified representation might be better.

type MkCondCall

type MkCondCall struct {
	Name string
	Arg  string
}

type MkCondCallback

type MkCondCallback struct {
	Defined       func(varname string)
	Empty         func(empty *MkVarUse)
	CompareVarNum func(varuse *MkVarUse, op string, num string)
	CompareVarStr func(varuse *MkVarUse, op string, str string)
	CompareVarVar func(left *MkVarUse, op string, right *MkVarUse)
	Call          func(name string, arg string)
	VarUse        func(varuse *MkVarUse)
}

type MkCondCompareVarNum

type MkCondCompareVarNum struct {
	Var *MkVarUse
	Op  string // One of <, <=, ==, !=, >=, >.
	Num string
}

type MkCondCompareVarStr

type MkCondCompareVarStr struct {
	Var *MkVarUse
	Op  string // One of ==, !=.
	Str string
}

type MkCondCompareVarVar

type MkCondCompareVarVar struct {
	Left  *MkVarUse
	Op    string // One of <, <=, ==, !=, >=, >.
	Right *MkVarUse
}

type MkCondWalker

type MkCondWalker struct{}

func (*MkCondWalker) Walk

func (w *MkCondWalker) Walk(cond MkCond, callback *MkCondCallback)

type MkExpecter

type MkExpecter struct {
	Expecter
	// contains filtered or unexported fields
}

MkExpecter records the state when checking a list of Makefile lines from top to bottom.

func NewMkExpecter

func NewMkExpecter(mklines MkLines) *MkExpecter

func (*MkExpecter) AdvanceIf

func (exp *MkExpecter) AdvanceIf(pred func(mkline MkLine) bool) bool

func (*MkExpecter) AdvanceWhile

func (exp *MkExpecter) AdvanceWhile(pred func(mkline MkLine) bool)

func (*MkExpecter) CurrentMkLine

func (exp *MkExpecter) CurrentMkLine() MkLine

func (*MkExpecter) PreviousMkLine

func (exp *MkExpecter) PreviousMkLine() MkLine

type MkLine

type MkLine = *MkLineImpl

MkLine is a line from a Makefile fragment. There are several types of lines. The most common types in pkgsrc are variable assignments, shell commands and directives like .if and .for.

type MkLineChecker

type MkLineChecker struct {
	MkLine MkLine
}

func (MkLineChecker) Check

func (ck MkLineChecker) Check()

func (MkLineChecker) CheckRelativePath

func (ck MkLineChecker) CheckRelativePath(relativePath string, mustExist bool)

CheckRelativePath checks a relative path that leads to the directory of another package or to a subdirectory thereof or a file within there.

func (MkLineChecker) CheckRelativePkgdir

func (ck MkLineChecker) CheckRelativePkgdir(pkgdir string)

CheckRelativePkgdir checks a reference from one pkgsrc package to another. These references should always have the form ../../category/package.

When used in DEPENDS or similar variables, these directories could theoretically also be relative to the pkgsrc root, which would save a few keystrokes. This, however, is not implemented in pkgsrc and suggestions regarding this topic have not been made in the last two decades on the public mailing lists. While being a bit redundant, the current scheme works well.

When used in .include directives, the relative package directories must be written with the leading ../.. anyway, so the benefit might not be too big at all.

func (MkLineChecker) CheckVartypeBasic

func (ck MkLineChecker) CheckVartypeBasic(varname string, checker *BasicType, op MkOperator, value, comment string, guessed bool)

CheckVartypeBasic checks a single list element of the given type.

For some variables (like `BuildlinkDepth`), `op` influences the valid values. The `comment` parameter comes from a variable assignment, when a part of the line is commented out.

func (MkLineChecker) CheckVaruse

func (ck MkLineChecker) CheckVaruse(varuse *MkVarUse, vuc *VarUseContext)

CheckVaruse checks a single use of a variable in a specific context.

func (MkLineChecker) CheckVaruseShellword

func (ck MkLineChecker) CheckVaruseShellword(varname string, vartype *Vartype, vuc *VarUseContext, mod string, needsQuoting YesNoUnknown)

CheckVaruseShellword checks whether a variable use of the form ${VAR} or ${VAR:modifiers} is allowed in a certain context.

type MkLineImpl

type MkLineImpl struct {
	Line
	// contains filtered or unexported fields
}

func NewMkLine

func NewMkLine(line Line) *MkLineImpl

NewMkLine parses the text of a Makefile line to see what kind of line it is: variable assignment, include, comment, etc.

See devel/bmake/parse.c:/^Parse_File/

func (*MkLineImpl) Args

func (mkline *MkLineImpl) Args() string

Args returns the arguments from an .if, .ifdef, .ifndef, .elif, .for, .undef.

func (*MkLineImpl) Cond

func (mkline *MkLineImpl) Cond() MkCond

Cond applies to an .if or .elif line and returns the parsed condition.

If a parse error occurs, it is silently swallowed, returning a best-effort part of the condition, or even nil.

func (*MkLineImpl) ConditionalVars

func (mkline *MkLineImpl) ConditionalVars() []string

ConditionalVars applies to .include lines and is a space-separated list of those variable names on which the inclusion depends. It is initialized later, step by step, when parsing other lines.

func (*MkLineImpl) DetermineUsedVariables

func (mkline *MkLineImpl) DetermineUsedVariables() []string

func (*MkLineImpl) Directive

func (mkline *MkLineImpl) Directive() string

Directive returns the preprocessing directive, like "if", "for", "endfor", etc.

See matchMkDirective.

func (*MkLineImpl) DirectiveComment

func (mkline *MkLineImpl) DirectiveComment() string

DirectiveComment is the trailing end-of-line comment, typically at a deeply nested .endif or .endfor.

func (*MkLineImpl) ExplainRelativeDirs

func (mkline *MkLineImpl) ExplainRelativeDirs()

func (*MkLineImpl) Fields

func (mkline *MkLineImpl) Fields() []string

Fields applies to variable assignments and .for loops. For variable assignments, it returns the right-hand side, properly split into words. For .for loops, it returns all arguments (including variable names), properly split into words.

func (*MkLineImpl) HasElseBranch

func (mkline *MkLineImpl) HasElseBranch() bool

func (*MkLineImpl) IncludedFile

func (mkline *MkLineImpl) IncludedFile() string

func (*MkLineImpl) Indent

func (mkline *MkLineImpl) Indent() string

func (*MkLineImpl) IsComment

func (mkline *MkLineImpl) IsComment() bool

IsComment returns true for lines that consist entirely of a comment.

func (*MkLineImpl) IsCommentedVarassign

func (mkline *MkLineImpl) IsCommentedVarassign() bool

IsCommentedVarassign returns true for commented-out variable assignments. In most cases these are treated as ordinary comments, but in some others they are treated like variable assignments, just inactive ones.

func (*MkLineImpl) IsDependency

func (mkline *MkLineImpl) IsDependency() bool

IsDependency returns true for dependency lines like "target: source".

func (*MkLineImpl) IsDirective

func (mkline *MkLineImpl) IsDirective() bool

IsDirective returns true for conditionals (.if/.elif/.else/.if) or loops (.for/.endfor).

See IsInclude.

func (*MkLineImpl) IsEmpty

func (mkline *MkLineImpl) IsEmpty() bool

func (*MkLineImpl) IsInclude

func (mkline *MkLineImpl) IsInclude() bool

IsInclude returns true for lines like: .include "other.mk"

See IsSysinclude for lines like: .include <sys.mk>

func (*MkLineImpl) IsShellCommand

func (mkline *MkLineImpl) IsShellCommand() bool

IsShellCommand returns true for tab-indented lines that are assigned to a Make target. Example:

pre-configure:    # IsDependency
        ${ECHO}   # IsShellCommand

func (*MkLineImpl) IsSysinclude

func (mkline *MkLineImpl) IsSysinclude() bool

IsSysinclude returns true for lines like: .include <sys.mk>

See IsInclude for lines like: .include "other.mk"

func (*MkLineImpl) IsVarassign

func (mkline *MkLineImpl) IsVarassign() bool

IsVarassign returns true for variable assignments of the form VAR=value.

See IsCommentedVarassign.

func (*MkLineImpl) MustExist

func (mkline *MkLineImpl) MustExist() bool

func (*MkLineImpl) Op

func (mkline *MkLineImpl) Op() MkOperator

Op applies to variable assignments and returns the assignment operator.

func (*MkLineImpl) RefTo

func (mkline *MkLineImpl) RefTo(other MkLine) string

RefTo returns a reference to another line, which can be in the same file or in a different file.

If there is a type mismatch when calling this function, try to add ".line" to either the method receiver or the other line.

func (*MkLineImpl) ResolveVarsInRelativePath

func (mkline *MkLineImpl) ResolveVarsInRelativePath(relativePath string) string

func (*MkLineImpl) SetConditionalVars

func (mkline *MkLineImpl) SetConditionalVars(varnames []string)

func (*MkLineImpl) SetHasElseBranch

func (mkline *MkLineImpl) SetHasElseBranch(elseLine MkLine)

func (*MkLineImpl) ShellCommand

func (mkline *MkLineImpl) ShellCommand() string

func (*MkLineImpl) Sources

func (mkline *MkLineImpl) Sources() string

func (*MkLineImpl) String

func (mkline *MkLineImpl) String() string

func (*MkLineImpl) Targets

func (mkline *MkLineImpl) Targets() string

func (*MkLineImpl) Tokenize

func (mkline *MkLineImpl) Tokenize(s string, warn bool) []*MkToken

Tokenize extracts variable uses and other text from the string.

TODO: Check this paragraph for correctness. Either: The given s must have exactly the format from the file, i.e. an escaped comment is written as \#. Or: The given s must have the format after parsing comments, i.e. the trailing comment is already removed, and a # does not introduce another comment.

Example:

input:  ${PREFIX}/bin abc
output: [MkToken("${PREFIX}", MkVarUse("PREFIX")), MkToken("/bin abc")]

See ValueTokens, which is the tokenized version of Value.

func (*MkLineImpl) Value

func (mkline *MkLineImpl) Value() string

func (*MkLineImpl) ValueAlign

func (mkline *MkLineImpl) ValueAlign() string

ValueAlign applies to variable assignments and returns all the text before the variable value, e.g. "VARNAME+=\t".

func (*MkLineImpl) ValueFields

func (mkline *MkLineImpl) ValueFields(value string) []string

ValueFields splits the given value, taking care of variable references. Example:

ValueFields("${VAR:Udefault value} ${VAR2}two words")
=> "${VAR:Udefault value}"
   "${VAR2}two"
   "words"

Note that even though the first word contains a space, it is not split at that point since the space is inside a variable use.

func (*MkLineImpl) ValueSplit

func (mkline *MkLineImpl) ValueSplit(value string, separator string) []string

ValueSplit splits the given value, taking care of variable references. Example:

ValueSplit("${VAR:Udefault}::${VAR2}two:words", ":")
=> "${VAR:Udefault}"
   ""
   "${VAR2}two"
   "words"

Note that even though the first word contains a colon, it is not split at that point since the colon is inside a variable use.

When several separators are adjacent, this results in empty words in the output.

func (*MkLineImpl) ValueTokens

func (mkline *MkLineImpl) ValueTokens() []*MkToken

func (*MkLineImpl) VarassignComment

func (mkline *MkLineImpl) VarassignComment() string

VarassignComment applies to variable assignments and returns the comment.

Example:

VAR=value # comment

In the above line, the comment is "# comment".

The leading "#" is included so that pkglint can distinguish between no comment at all and an empty comment.

func (*MkLineImpl) Varcanon

func (mkline *MkLineImpl) Varcanon() string

Varcanon applies to variable assignments and returns the canonicalized variable name for parameterized variables. Examples:

HOMEPAGE           => "HOMEPAGE"
SUBST_SED.anything => "SUBST_SED.*"
SUBST_SED.${param} => "SUBST_SED.*"

func (*MkLineImpl) VariableNeedsQuoting

func (mkline *MkLineImpl) VariableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting YesNoUnknown)

VariableNeedsQuoting determines whether the given variable needs the :Q operator in the given context.

This decision depends on many factors, such as whether the type of the context is a list of things, whether the variable is a list, whether it can contain only safe characters, and so on.

func (*MkLineImpl) Varname

func (mkline *MkLineImpl) Varname() string

Varname applies to variable assignments and returns the name of the variable that is assigned or appended to.

Example:

VARNAME.${param}?=      value   # Varname is "VARNAME.${param}"

func (*MkLineImpl) Varparam

func (mkline *MkLineImpl) Varparam() string

Varparam applies to variable assignments and returns the parameter for parameterized variables. Examples:

HOMEPAGE           => ""
SUBST_SED.anything => "anything"
SUBST_SED.${param} => "${param}"

func (*MkLineImpl) WithoutMakeVariables

func (mkline *MkLineImpl) WithoutMakeVariables(value string) string

type MkLines

type MkLines = *MkLinesImpl

MkLines contains data for the Makefile (or *.mk) that is currently checked.

func LoadMk

func LoadMk(filename string, options LoadOptions) MkLines

func NewMkLines

func NewMkLines(lines Lines) MkLines

type MkLinesImpl

type MkLinesImpl struct {
	Tools *Tools // Tools defined in file scope.

	Once
	// contains filtered or unexported fields
}

func (*MkLinesImpl) Check

func (mklines *MkLinesImpl) Check()

func (*MkLinesImpl) CheckForUsedComment

func (mklines *MkLinesImpl) CheckForUsedComment(relativeName string)

CheckForUsedComment checks that this file (a Makefile.common) has the given relativeName in one of the "# used by" comments at the beginning of the file.

func (*MkLinesImpl) CheckRedundantAssignments

func (mklines *MkLinesImpl) CheckRedundantAssignments()

func (*MkLinesImpl) ForEach

func (mklines *MkLinesImpl) ForEach(action func(mkline MkLine))

ForEach calls the action for each line, until the action returns false. It keeps track of the indentation (see MkLines.indentation) and all conditional variables (see Indentation.IsConditional).

func (*MkLinesImpl) ForEachEnd

func (mklines *MkLinesImpl) ForEachEnd(action func(mkline MkLine) bool, atEnd func(lastMkline MkLine))

ForEachEnd calls the action for each line, until the action returns false. It keeps track of the indentation and all conditional variables. At the end, atEnd is called with the last line as its argument.

func (*MkLinesImpl) SaveAutofixChanges

func (mklines *MkLinesImpl) SaveAutofixChanges()

func (*MkLinesImpl) UseVar

func (mklines *MkLinesImpl) UseVar(mkline MkLine, varname string)

UseVar remembers that the given variable is used in the given line. This controls the "defined but not used" warning.

type MkOperator

type MkOperator uint8

func NewMkOperator

func NewMkOperator(op string) MkOperator

func (MkOperator) String

func (op MkOperator) String() string

type MkParser

type MkParser struct {
	*Parser
}

MkParser wraps a Parser and provides methods for parsing things related to Makefiles.

func NewMkParser

func NewMkParser(line Line, text string, emitWarnings bool) *MkParser

NewMkParser creates a new parser for the given text. If emitWarnings is false, line may be nil.

TODO: Document what exactly text is. Is it the form taken from the file, or is it after unescaping "\#" to #?

TODO: Remove the emitWarnings argument in order to separate parsing from checking.

func (*MkParser) MkCond

func (p *MkParser) MkCond() MkCond

MkCond parses a condition like ${OPSYS} == "NetBSD". See devel/bmake/files/cond.c.

func (*MkParser) MkTokens

func (p *MkParser) MkTokens() []*MkToken

MkTokens splits a text like in the following example:

Text${VAR:Mmodifier}${VAR2}more text${VAR3}

into tokens like these:

Text
${VAR:Mmodifier}
${VAR2}
more text
${VAR3}

func (*MkParser) VarUse

func (p *MkParser) VarUse() *MkVarUse

func (*MkParser) VarUseModifiers

func (p *MkParser) VarUseModifiers(varname string, closing byte) []MkVarUseModifier

VarUseModifiers parses the modifiers of a variable being used, such as :Q, :Mpattern.

See the bmake manual page.

func (*MkParser) Varname

func (p *MkParser) Varname() string

type MkShAndOr

type MkShAndOr struct {
	Pipes []*MkShPipeline
	Ops   []string // Each element is either "&&" or "||"
}

MkShAndOr is a group of commands that are connected with && or || conditions.

The operators && and || have the same precedence and are evaluated strictly from left to right.

Example:

cd $dir && echo "In $dir" || echo "Cannot cd into $dir"

func NewMkShAndOr

func NewMkShAndOr(pipeline *MkShPipeline) *MkShAndOr

func (*MkShAndOr) Add

func (andor *MkShAndOr) Add(op string, pipeline *MkShPipeline) *MkShAndOr

type MkShCase

type MkShCase struct {
	Word  *ShToken
	Cases []*MkShCaseItem
}

MkShCase is a "case" statement, including all its branches.

Example:

case $filename in *.c) echo "C source" ;; esac

type MkShCaseItem

type MkShCaseItem struct {
	Patterns  []*ShToken
	Action    *MkShList
	Separator MkShSeparator
}

MkShCaseItem is one branch of a "case" statement.

Example:

*.c) echo "C source" ;;

type MkShCommand

type MkShCommand struct {
	Simple    *MkShSimpleCommand
	Compound  *MkShCompoundCommand
	FuncDef   *MkShFunctionDefinition
	Redirects []*MkShRedirection // For Compound and FuncDef
}

MkShCommand is a simple or compound shell command.

Examples:

LC_ALL=C sort */*.c > sorted
dir() { ls -l "$@"; }
{ echo "first"; echo "second"; }

type MkShCompoundCommand

type MkShCompoundCommand struct {
	Brace    *MkShList
	Subshell *MkShList
	For      *MkShFor
	Case     *MkShCase
	If       *MkShIf
	Loop     *MkShLoop
}

MkShCompoundCommand is a group of commands.

Examples:

{ echo "first"; echo "second"; }
for f in *.c; do compile "$f"; done
if [ -f "$file" ]; then echo "It exists"; fi
while sleep 1; do printf .; done

type MkShFor

type MkShFor struct {
	Varname string
	Values  []*ShToken
	Body    *MkShList
}

MkShFor is a "for" loop.

Example:

for f in *.c; do compile "$f"; done

type MkShFunctionDefinition

type MkShFunctionDefinition struct {
	Name string
	Body *MkShCompoundCommand
}

MkShFunctionDefinition is the definition of a shell function.

Example:

dir() { ls -l "$@"; }

type MkShIf

type MkShIf struct {
	Conds   []*MkShList
	Actions []*MkShList
	Else    *MkShList
}

MkShIf is a conditional statement, possibly having many branches.

Example:

if [ -f "$file" ]; then echo "It exists"; fi

func (*MkShIf) Prepend

func (cl *MkShIf) Prepend(cond *MkShList, action *MkShList)

type MkShList

type MkShList struct {
	AndOrs []*MkShAndOr

	// The separators after each AndOr.
	// There may be one less entry than in AndOrs.
	Separators []MkShSeparator
}

MkShList is a list of shell commands, separated by newlines or semicolons.

Example:

cd $dir && echo "In $dir"; cd ..; ls -l

func NewMkShList

func NewMkShList() *MkShList

func (*MkShList) AddAndOr

func (list *MkShList) AddAndOr(andor *MkShAndOr) *MkShList

func (*MkShList) AddSeparator

func (list *MkShList) AddSeparator(separator MkShSeparator) *MkShList

type MkShLoop

type MkShLoop struct {
	Cond   *MkShList
	Action *MkShList
	Until  bool
}

MkShLoop is a "while" or "until" loop.

Example:

while sleep 1; do printf .; done

type MkShPipeline

type MkShPipeline struct {
	Negated bool
	Cmds    []*MkShCommand
}

MkShPipeline is a group of commands, connected by pipelines.

Example: grep word file | sed s,^,---,

func NewMkShPipeline

func NewMkShPipeline(negated bool, cmds []*MkShCommand) *MkShPipeline

func (*MkShPipeline) Add

func (pipe *MkShPipeline) Add(cmd *MkShCommand) *MkShPipeline

type MkShRedirection

type MkShRedirection struct {
	Fd     int      // Or -1
	Op     string   // See io_file in shell.y for possible values
	Target *ShToken // The filename or &fd
}

MkShRedirection is a single file descriptor redirection.

Examples:

> sorted
2>&1

type MkShSeparator

type MkShSeparator uint8

MkShSeparator is one of ; & newline.

type MkShSimpleCommand

type MkShSimpleCommand struct {
	Assignments  []*ShToken
	Name         *ShToken
	Args         []*ShToken
	Redirections []*MkShRedirection
}

MkShSimpleCommand is a shell command that does not involve any pipeline or conditionals.

Example:

LC_ALL=C sort */*.c > sorted

type MkShWalker

type MkShWalker struct {
	Callback struct {
		List               func(list *MkShList)
		AndOr              func(andor *MkShAndOr)
		Pipeline           func(pipeline *MkShPipeline)
		Command            func(command *MkShCommand)
		SimpleCommand      func(command *MkShSimpleCommand)
		CompoundCommand    func(command *MkShCompoundCommand)
		Case               func(caseClause *MkShCase)
		CaseItem           func(caseItem *MkShCaseItem)
		FunctionDefinition func(funcdef *MkShFunctionDefinition)
		If                 func(ifClause *MkShIf)
		Loop               func(loop *MkShLoop)
		Words              func(words []*ShToken)
		Word               func(word *ShToken)
		Redirects          func(redirects []*MkShRedirection)
		Redirect           func(redirect *MkShRedirection)
		For                func(forClause *MkShFor)

		// For variable definition in a for loop.
		Varname func(varname string)
	}

	// Context[0] is the currently visited element,
	// Context[1] is its immediate parent element, and so on.
	// This is useful when the check for a CaseItem needs to look at the enclosing Case.
	Context []MkShWalkerPathElement
}

func NewMkShWalker

func NewMkShWalker() *MkShWalker

func (*MkShWalker) Current

func (w *MkShWalker) Current() MkShWalkerPathElement

Current provides access to the element that the walker is currently processing, especially its index as seen from its parent element.

func (*MkShWalker) Parent

func (w *MkShWalker) Parent(steps int) interface{}

Parent returns an ancestor element from the currently visited path. Parent(0) is the element that is currently visited, Parent(1) is its direct parent, and so on.

func (*MkShWalker) Path

func (w *MkShWalker) Path() string

Path returns a representation of the path in the AST that is currently visited.

It is used for debugging only.

See Test_MkShWalker_Walk, Callback.SimpleCommand for examples.

func (*MkShWalker) Walk

func (w *MkShWalker) Walk(list *MkShList)

Walk calls the given callback for each node of the parsed shell program, in visiting order from large to small.

type MkShWalkerPathElement

type MkShWalkerPathElement struct {

	// For fields that can be repeated, this is the index as seen from the parent element.
	// For fields that cannot be repeated, it is -1.
	//
	// For example, in the SimpleCommand "var=value cmd arg1 arg2",
	// there are multiple child elements of type Words.
	//
	// The first Words are the variable assignments, which have index 0.
	//
	// The command "cmd" has type Word, therefore it cannot be confused
	// with either of the Words lists and has index -1.
	//
	// The second Words are the arguments, which have index 1.
	// In this example, there are two arguments, so when visiting the
	// arguments individually, arg1 will have index 0 and arg2 will have index 1.
	//
	// TODO: It might be worth defining negative indexes to correspond
	// to the fields "Cond", "Action", "Else", etc.
	Index int

	Element interface{}
}

type MkToken

type MkToken struct {
	Text   string    // Used for both literal text and variable uses
	Varuse *MkVarUse // For literal text, it is nil
}

MkToken represents a contiguous string from a Makefile. It is either a literal string or a variable use.

Example: /usr/share/${PKGNAME}/data consists of 3 tokens:

  1. MkToken{Text: "/usr/share/"}
  2. MkToken{Text: "${PKGNAME}", Varuse: &MkVarUse{varname: "PKGNAME"}}
  3. MkToken{Text: "/data"}

type MkVarUse

type MkVarUse struct {
	// contains filtered or unexported fields
}

MkVarUse represents a reference to a Make variable, with optional modifiers.

For nested variable expressions, the variable name can contain references to other variables. For example, ${TOOLS.${t}} is a MkVarUse with varname "TOOLS.${t}" and no modifiers.

Example: ${PKGNAME}

Example: ${PKGNAME:S/from/to/}

func (*MkVarUse) IsExpression

func (vu *MkVarUse) IsExpression() bool

IsExpression returns whether the varname is interpreted as a variable name (the usual case) or as an expression (rare, only the modifiers "?:" and "L" do this).

func (*MkVarUse) IsQ

func (vu *MkVarUse) IsQ() bool

func (*MkVarUse) Mod

func (vu *MkVarUse) Mod() string

func (*MkVarUse) String

func (vu *MkVarUse) String() string

type MkVarUseModifier

type MkVarUseModifier struct {
	Text string
}

func (MkVarUseModifier) IsQ

func (m MkVarUseModifier) IsQ() bool

func (MkVarUseModifier) IsSuffixSubst

func (m MkVarUseModifier) IsSuffixSubst() bool

func (MkVarUseModifier) IsToLower

func (m MkVarUseModifier) IsToLower() bool

func (MkVarUseModifier) MatchMatch

func (m MkVarUseModifier) MatchMatch() (ok bool, positive bool, pattern string)

func (MkVarUseModifier) MatchSubst

func (m MkVarUseModifier) MatchSubst() (ok bool, regex bool, from string, to string, options string)

func (MkVarUseModifier) Subst

func (m MkVarUseModifier) Subst(str string) string

Subst evaluates an S/from/to/ modifier.

Example:

MkVarUseModifier{"S,name,file,g"}.Subst("distname-1.0") => "distfile-1.0"

type Once

type Once struct {
	// contains filtered or unexported fields
}

Once remembers with which arguments its FirstTime method has been called and only returns true on each first call.

func (*Once) FirstTime

func (o *Once) FirstTime(what string) bool

func (*Once) FirstTimeSlice

func (o *Once) FirstTimeSlice(whats ...string) bool

type Package

type Package struct {
	Pkgpath              string       // e.g. "category/pkgdir"
	Pkgdir               string       // PKGDIR from the package Makefile
	Filesdir             string       // FILESDIR from the package Makefile
	Patchdir             string       // PATCHDIR from the package Makefile
	DistinfoFile         string       // DISTINFO_FILE from the package Makefile
	EffectivePkgname     string       // PKGNAME or DISTNAME from the package Makefile, including nb13
	EffectivePkgbase     string       // EffectivePkgname without the version
	EffectivePkgversion  string       // The version part of the effective PKGNAME, excluding nb13
	EffectivePkgnameLine MkLine       // The origin of the three Effective* values
	Plist                PlistContent // Files and directories mentioned in the PLIST files

	IgnoreMissingPatches bool // In distinfo, don't warn about patches that cannot be found.
	// contains filtered or unexported fields
}

Package is the pkgsrc package that is currently checked.

Most of the information is loaded first, and after loading the actual checks take place. This is necessary because variables in Makefiles may be used before they are defined, and such dependencies often span multiple files that are included indirectly.

func NewPackage

func NewPackage(dir string) *Package

func (*Package) CheckVarorder

func (pkg *Package) CheckVarorder(mklines MkLines)

CheckVarorder checks that in simple package Makefiles, the most common variables appear in a fixed order. The order itself is a little arbitrary but provides at least a bit of consistency.

func (*Package) File

func (pkg *Package) File(relativeFileName string) string

File returns the (possibly absolute) path to relativeFileName, as resolved from the package's directory. Variables that are known in the package are resolved, e.g. ${PKGDIR}.

type ParseError

type ParseError struct {
	RemainingTokens []string
}

func (*ParseError) Error

func (e *ParseError) Error() string

type Parser

type Parser struct {
	Line Line

	EmitWarnings bool
	// contains filtered or unexported fields
}

func NewParser

func NewParser(line Line, s string, emitWarnings bool) *Parser

func (*Parser) Dependency

func (p *Parser) Dependency() *DependencyPattern

func (*Parser) EOF

func (p *Parser) EOF() bool

func (*Parser) PkgbasePattern

func (p *Parser) PkgbasePattern() (pkgbase string)

func (*Parser) Rest

func (p *Parser) Rest() string

type PatchChecker

type PatchChecker struct {
	// contains filtered or unexported fields
}

func (*PatchChecker) Check

func (ck *PatchChecker) Check()

type Pkglint

type Pkglint struct {
	Opts   CmdOpts  // Command line options.
	Pkgsrc *Pkgsrc  // Global data, mostly extracted from mk/*, never nil.
	Pkg    *Package // The package that is currently checked, or nil.
	Mk     MkLines  // The Makefile (or fragment) that is currently checked, or nil.

	Todo            []string // The files or directories that still need to be checked.
	Wip             bool     // Is the currently checked file or package from pkgsrc-wip?
	Infrastructure  bool     // Is the currently checked file from the pkgsrc infrastructure?
	Testing         bool     // Is pkglint in self-testing mode (only during development)?
	Username        string   // For checking against OWNER and MAINTAINER
	CvsEntriesDir   string   // Cached to avoid I/O
	CvsEntriesLines Lines

	Logger
	// contains filtered or unexported fields
}

Pkglint is a container for all global variables of this Go package.

func NewPkglint

func NewPkglint() Pkglint

func (*Pkglint) Assertf

func (pkglint *Pkglint) Assertf(cond bool, format string, args ...interface{})

Assertf checks that the condition is true. Otherwise it terminates the process with a fatal error message, prefixed with "Pkglint internal error".

This method must only be used for programming errors. For runtime errors, use dummyLine.Fatalf.

func (*Pkglint) Check

func (pkglint *Pkglint) Check(dirent string)

Check checks a directory entry, which can be a regular file, a directory or a symlink (only allowed for the working directory).

This is the method that is called for each command line argument.

It sets up all the global state (infrastructure, wip) for accurately classifying the entry.

During tests, it assumes that Pkgsrc.LoadInfrastructure has been called. It is the most high-level method for testing pkglint.

func (*Pkglint) Main

func (pkglint *Pkglint) Main(argv ...string) (exitCode int)

Main runs the main program with the given arguments. argv[0] is the program name.

Note: during tests, calling this method disables tracing because the command line option --debug sets trace.Tracing back to false.

It also discards the -Wall option that is used by default in other tests.

func (*Pkglint) ParseCommandLine

func (pkglint *Pkglint) ParseCommandLine(args []string) int

func (*Pkglint) Tool

func (pkglint *Pkglint) Tool(command string, time ToolTime) (tool *Tool, usable bool)

Tool returns the tool definition from the closest scope (file, global), or nil. The command can be "sed" or "gsed" or "${SED}". If a tool is returned, usable tells whether that tool has been added to USE_TOOLS in the current scope.

func (*Pkglint) ToolByVarname

func (pkglint *Pkglint) ToolByVarname(varname string) *Tool

ToolByVarname looks up the tool by its variable name, e.g. "SED".

The returned tool may come either from the current Makefile or the current package. It is not guaranteed to be usable, only defined; that must be checked by the calling code, see Tool.UsableAtLoadTime and Tool.UsableAtRunTime.

type Pkgsrc

type Pkgsrc struct {
	Tools *Tools

	MasterSiteURLToVar map[string]string // "https://github.com/" => "MASTER_SITE_GITHUB"
	MasterSiteVarToURL map[string]string // "MASTER_SITE_GITHUB" => "https://github.com/"

	PkgOptions map[string]string // "x11" => "Provides X11 support"

	LastChange map[string]*Change //

	// Variables that may be overridden by the pkgsrc user. Used for checking BUILD_DEFS.
	UserDefinedVars Scope

	Deprecated map[string]string //

	Hashes       map[string]*Hash // Maps "alg:filename" => hash (inter-package check).
	UsedLicenses map[string]bool  // Maps "license name" => true (inter-package check).
	// contains filtered or unexported fields
}

Pkgsrc describes a pkgsrc installation. In each pkglint run, only a single pkgsrc installation is ever loaded. It just doesn't make sense to check multiple pkgsrc installations at once.

func NewPkgsrc

func NewPkgsrc(dir string) *Pkgsrc

func (*Pkgsrc) AddBuildDefs

func (src *Pkgsrc) AddBuildDefs(varnames ...string)

func (*Pkgsrc) File

func (src *Pkgsrc) File(relativeName string) string

File resolves a filename relative to the pkgsrc top directory.

Example:

NewPkgsrc("/usr/pkgsrc").File("distfiles") => "/usr/pkgsrc/distfiles"

func (*Pkgsrc) GetSuggestedPackageUpdates

func (src *Pkgsrc) GetSuggestedPackageUpdates() []SuggestedUpdate

func (*Pkgsrc) InitVartypes

func (src *Pkgsrc) InitVartypes()

InitVartypes initializes the long list of predefined pkgsrc variables. After this is done, ${PKGNAME}, ${MAKE_ENV} and all the other variables can be used in Makefiles without triggering warnings about typos.

func (*Pkgsrc) IsBuildDef

func (src *Pkgsrc) IsBuildDef(varname string) bool

func (*Pkgsrc) Latest

func (src *Pkgsrc) Latest(category string, re regex.Pattern, repl string) string

Latest returns the latest package matching the given pattern. It searches the category for subdirectories matching the given regular expression, takes the latest of them and replaces its name with repl.

Example:

Latest("lang", `^php[0-9]+$`, "../../lang/$0")
    => "../../lang/php72"

func (*Pkgsrc) ListVersions

func (src *Pkgsrc) ListVersions(category string, re regex.Pattern, repl string, errorIfEmpty bool) []string

ListVersions searches the category for subdirectories matching the given regular expression, replaces their names with repl and returns a slice of them, properly sorted from early to late.

Example:

ListVersions("lang", `^php[0-9]+$`, "php-$0")
    => {"php-53", "php-56", "php-73"}

func (*Pkgsrc) Load

func (src *Pkgsrc) Load(filename string, options LoadOptions) Lines

Load loads the file relative to the pkgsrc top directory.

func (*Pkgsrc) LoadInfrastructure

func (src *Pkgsrc) LoadInfrastructure()

LoadInfrastructure reads the pkgsrc infrastructure files to extract information like the tools, packages to update, user-defined variables.

This work is not done in the constructor to keep the tests simple, since setting up a realistic pkgsrc environment requires a lot of files.

func (*Pkgsrc) LoadMk

func (src *Pkgsrc) LoadMk(filename string, options LoadOptions) MkLines

LoadMk loads the Makefile relative to the pkgsrc top directory.

func (*Pkgsrc) ReadDir

func (src *Pkgsrc) ReadDir(dirName string) []os.FileInfo

ReadDir reads the file listing from the given directory (relative to the pkgsrc root), filtering out any ignored files (CVS/*) and empty directories.

func (*Pkgsrc) ToRel

func (src *Pkgsrc) ToRel(filename string) string

ToRel returns the path of `filename`, relative to the pkgsrc top directory.

Example:

NewPkgsrc("/usr/pkgsrc").ToRel("/usr/pkgsrc/distfiles") => "distfiles"

func (*Pkgsrc) VariableType

func (src *Pkgsrc) VariableType(varname string) (vartype *Vartype)

VariableType returns the type of the variable (possibly guessed based on the variable name), or nil if the type cannot even be guessed.

type PlistChecker

type PlistChecker struct {
	// contains filtered or unexported fields
}

func (*PlistChecker) Check

func (ck *PlistChecker) Check(plainLines Lines)

func (*PlistChecker) NewLines

func (ck *PlistChecker) NewLines(lines Lines) []*PlistLine

type PlistContent

type PlistContent struct {
	Dirs  map[string]bool
	Files map[string]bool
}

func NewPlistContent

func NewPlistContent() PlistContent

type PlistLine

type PlistLine struct {
	Line
	// contains filtered or unexported fields
}

func (*PlistLine) CheckDirective

func (pline *PlistLine) CheckDirective(cmd, arg string)

func (*PlistLine) CheckTrailingWhitespace

func (pline *PlistLine) CheckTrailingWhitespace()

type RawLine

type RawLine struct {
	Lineno int // Counting starts at 1; 0 means inserted by Autofix
	// contains filtered or unexported fields
}

func (*RawLine) String

func (rline *RawLine) String() string

type RedundantScope

type RedundantScope struct {
	OnIgnore    func(old, new MkLine)
	OnOverwrite func(old, new MkLine)
	// contains filtered or unexported fields
}

RedundantScope checks for redundant variable definitions and accidentally overwriting variables. It tries to be as correct as possible by not flagging anything that is defined conditionally. There may be some edge cases though like defining PKGNAME, then evaluating it using :=, then defining it again. This pattern is so error-prone that it should not appear in pkgsrc at all, thus pkglint doesn't even expect it. (Well, except for the PKGNAME case, but that's deep in the infrastructure and only affects the "nb13" extension.)

func NewRedundantScope

func NewRedundantScope() *RedundantScope

func (*RedundantScope) Handle

func (s *RedundantScope) Handle(mkline MkLine)

type Scope

type Scope struct {
	// contains filtered or unexported fields
}

Scope remembers which variables are defined and which are used in a certain scope, such as a package or a file.

func NewScope

func NewScope() Scope

func (*Scope) Define

func (s *Scope) Define(varname string, mkline MkLine)

Define marks the variable and its canonicalized form as defined.

func (*Scope) DefineAll

func (s *Scope) DefineAll(other Scope)

func (*Scope) Defined

func (s *Scope) Defined(varname string) bool

Defined tests whether the variable is defined. It does NOT test the canonicalized variable name.

Even if Defined returns true, FirstDefinition doesn't necessarily return true since the latter ignores the default definitions from vardefs.go, keyword dummyVardefMkline.

func (*Scope) DefinedSimilar

func (s *Scope) DefinedSimilar(varname string) bool

DefinedSimilar tests whether the variable or its canonicalized form is defined.

func (*Scope) Fallback

func (s *Scope) Fallback(varname string, value string)

func (*Scope) FirstDefinition

func (s *Scope) FirstDefinition(varname string) MkLine

FirstDefinition returns the line in which the variable has been defined first. Having multiple definitions is typical in the branches of "if" statements.

func (*Scope) FirstUse

func (s *Scope) FirstUse(varname string) MkLine

func (*Scope) Use

func (s *Scope) Use(varname string, line MkLine)

Use marks the variable and its canonicalized form as used.

func (*Scope) Used

func (s *Scope) Used(varname string) bool

Used tests whether the variable is used. It does NOT test the canonicalized variable name.

func (*Scope) UsedSimilar

func (s *Scope) UsedSimilar(varname string) bool

UsedSimilar tests whether the variable or its canonicalized form is used.

func (*Scope) Value

func (s *Scope) Value(varname string) (value string, found bool)

type SeparatorWriter

type SeparatorWriter struct {
	// contains filtered or unexported fields
}

SeparatorWriter writes output, occasionally separated by an empty line. This is used for separating the diagnostics when --source is combined with --show-autofix, where each log message consists of multiple lines.

func NewSeparatorWriter

func NewSeparatorWriter(out io.Writer) *SeparatorWriter

func (*SeparatorWriter) Flush

func (wr *SeparatorWriter) Flush()

func (*SeparatorWriter) Separate

func (wr *SeparatorWriter) Separate()

Separate remembers to output an empty line before the next character. If the writer is currently in the middle of a line, that line is terminated immediately.

func (*SeparatorWriter) Write

func (wr *SeparatorWriter) Write(text string)

func (*SeparatorWriter) WriteLine

func (wr *SeparatorWriter) WriteLine(text string)

type ShAtom

type ShAtom struct {
	Type    ShAtomType
	MkText  string
	Quoting ShQuoting // The quoting state at the end of the token
	// contains filtered or unexported fields
}

func (*ShAtom) ShVarname

func (atom *ShAtom) ShVarname() string

ShVarname applies to shell variable atoms like $$varname or $${varname:-modifier} and returns the name of the shell variable.

func (*ShAtom) String

func (atom *ShAtom) String() string

func (*ShAtom) VarUse

func (atom *ShAtom) VarUse() *MkVarUse

VarUse returns a read access to a Makefile variable, or nil for plain shell tokens.

type ShAtomType

type ShAtomType uint8

func (ShAtomType) IsWord

func (t ShAtomType) IsWord() bool

IsWord checks whether the atom counts as text. Makefile variables, shell variables and other text counts, but keywords, operators and separators don't.

func (ShAtomType) String

func (t ShAtomType) String() string

type ShQuoting

type ShQuoting uint8

ShQuoting describes the context in which a string appears and how it must be unescaped to get its literal value.

func (ShQuoting) String

func (q ShQuoting) String() string

func (ShQuoting) ToVarUseContext

func (q ShQuoting) ToVarUseContext() vucQuoting

type ShToken

type ShToken struct {
	MkText string // The text as it appeared in the Makefile, after replacing `\#` with `#`
	Atoms  []*ShAtom
}

ShToken is an operator or a keyword or some text intermingled with variables.

Examples:

;
then
"The number of pkgsrc packages in ${PREFIX} is $$packages."

See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_10_02

func NewShToken

func NewShToken(mkText string, atoms ...*ShAtom) *ShToken

func (*ShToken) String

func (token *ShToken) String() string

type ShTokenizer

type ShTokenizer struct {
	// contains filtered or unexported fields
}

func NewShTokenizer

func NewShTokenizer(line Line, text string, emitWarnings bool) *ShTokenizer

func (*ShTokenizer) Rest

func (p *ShTokenizer) Rest() string

func (*ShTokenizer) ShAtom

func (p *ShTokenizer) ShAtom(quoting ShQuoting) *ShAtom

ShAtom parses a basic building block of a shell program. Examples for such atoms are: variable reference (both make and shell), operator, text, quote, space.

See ShQuote.Feed

func (*ShTokenizer) ShAtoms

func (p *ShTokenizer) ShAtoms() []*ShAtom

func (*ShTokenizer) ShToken

func (p *ShTokenizer) ShToken() *ShToken

type ShellLexer

type ShellLexer struct {
	// contains filtered or unexported fields
}

ShellLexer categorizes tokens for shell commands, providing the lexer required by the yacc-generated parser.

The main work of tokenizing is done in ShellTokenizer though.

Example:

while :; do var=$$other; done

=>

while
space " "
word ":"
semicolon
space " "
do
space " "
assign "var=$$other"
semicolon
space " "
done

See splitIntoShellTokens and ShellTokenizer.

func NewShellLexer

func NewShellLexer(tokens []string, rest string) *ShellLexer

func (*ShellLexer) Error

func (lex *ShellLexer) Error(s string)

func (*ShellLexer) Lex

func (lex *ShellLexer) Lex(lval *shyySymType) (ttype int)

type ShellLine

type ShellLine struct {
	// contains filtered or unexported fields
}

ShellLine is either a line from a Makefile starting with a tab, thereby containing shell commands to be executed.

Or it is a variable assignment line from a Makefile with a left-hand side variable that is of some shell-like type; see Vartype.IsShell.

func NewShellLine

func NewShellLine(mkline MkLine) *ShellLine

func (*ShellLine) CheckShellCommand

func (shline *ShellLine) CheckShellCommand(shellcmd string, pSetE *bool, time ToolTime)

func (*ShellLine) CheckShellCommandLine

func (shline *ShellLine) CheckShellCommandLine(shelltext string)

func (*ShellLine) CheckShellCommands

func (shline *ShellLine) CheckShellCommands(shellcmds string, time ToolTime)

func (*ShellLine) CheckWord

func (shline *ShellLine) CheckWord(token string, checkQuoting bool, time ToolTime)

type ShellProgramChecker

type ShellProgramChecker struct {
	// contains filtered or unexported fields
}

type SimpleCommandChecker

type SimpleCommandChecker struct {
	// contains filtered or unexported fields
}

func NewSimpleCommandChecker

func NewSimpleCommandChecker(shline *ShellLine, cmd *MkShSimpleCommand, time ToolTime) *SimpleCommandChecker

func (*SimpleCommandChecker) Check

func (scc *SimpleCommandChecker) Check()

type StrCommand

type StrCommand struct {
	Assignments []string
	Name        string
	Args        []string
}

StrCommand is structurally similar to MkShSimpleCommand, but all components are converted to strings to allow for simpler checks, especially for analyzing command line options.

Example:

LC_ALL=C sort */*.c > sorted

func NewStrCommand

func NewStrCommand(cmd *MkShSimpleCommand) *StrCommand

func (*StrCommand) AnyArgMatches

func (c *StrCommand) AnyArgMatches(pattern regex.Pattern) bool

func (*StrCommand) HasOption

func (c *StrCommand) HasOption(opt string) bool

HasOption checks whether one of the arguments is exactly the given opt.

func (*StrCommand) String

func (c *StrCommand) String() string

type SubstContext

type SubstContext struct {
	// contains filtered or unexported fields
}

SubstContext records the state of a block of variable assignments that make up a SUBST class (see `mk/subst.mk`).

func NewSubstContext

func NewSubstContext() *SubstContext

func (*SubstContext) Directive

func (ctx *SubstContext) Directive(mkline MkLine)

func (*SubstContext) Finish

func (ctx *SubstContext) Finish(mkline MkLine)

func (*SubstContext) IsComplete

func (ctx *SubstContext) IsComplete() bool

func (*SubstContext) Varassign

func (ctx *SubstContext) Varassign(mkline MkLine)

type SubstContextStats

type SubstContextStats struct {
	// contains filtered or unexported fields
}

func (*SubstContextStats) And

func (st *SubstContextStats) And(other *SubstContextStats)

func (*SubstContextStats) Copy

func (*SubstContextStats) Or

func (st *SubstContextStats) Or(other SubstContextStats)

type SuggestedUpdate

type SuggestedUpdate struct {
	Line    Line
	Pkgname string
	Version string
	Comment string
}

SuggestedUpdate is from the `doc/TODO` file.

type Tool

type Tool struct {
	Name           string // e.g. "sed", "gzip"
	Varname        string // e.g. "SED", "GZIP_CMD"
	MustUseVarForm bool   // True for `echo`, because of many differing implementations.
	Validity       Validity
}

Tool is one of the many standard shell utilities that are typically provided by the operating system, or, if missing, are installed via pkgsrc.

See `mk/tools/`.

TODO: MustUseVarForm does not really depend on the tool but only depends on where the tool is used (load time, run time). This had already been modeled wrong in pkglint 4, more than 10 years ago.

func (*Tool) String

func (tool *Tool) String() string

func (*Tool) UsableAtLoadTime

func (tool *Tool) UsableAtLoadTime(seenPrefs bool) bool

UsableAtLoadTime means that the tool may be used by its variable name after bsd.prefs.mk has been included.

Additionally, all allowed cases from UsableAtRunTime are allowed.

VAR:=   ${TOOL}           # Not allowed since bsd.prefs.mk is not
                          # included yet.

.include "../../bsd.prefs.mk"

VAR:=   ${TOOL}           # Allowed.
VAR!=   ${TOOL}           # Allowed.

VAR=    ${${TOOL}:sh}     # Allowed; the :sh modifier is evaluated
                          # lazily, but when VAR should ever be
                          # evaluated at load time, this still means
                          # load time.

.if ${TOOL:T} == "tool"   # Allowed.
.endif

func (*Tool) UsableAtRunTime

func (tool *Tool) UsableAtRunTime() bool

UsableAtRunTime means that the tool may be used by its simple name in all {pre,do,post}-* targets, and by its variable name in all runtime contexts.

VAR:=   ${TOOL}           # Not allowed; TOOL might not be initialized yet.
VAR!=   ${TOOL}           # Not allowed; TOOL might not be initialized yet.

VAR=    ${${TOOL}:sh}     # Probably ok; the :sh modifier is evaluated at
                          # run time. But if VAR should ever be evaluated
                          # at load time (see the "Not allowed" cases
                          # above), it doesn't work. Currently pkglint
                          # cannot detect these cases reliably.

own-target:
        ${TOOL}           # Allowed.
        tool              # Not allowed because the PATH might not be set
                          # up for this target.

pre-configure:
        ${TOOL}           # Allowed.
        tool              # Allowed.

type ToolTime

type ToolTime uint8
const (
	LoadTime ToolTime = iota
	RunTime
)

func (ToolTime) String

func (t ToolTime) String() string

type Tools

type Tools struct {
	TraceName string // Only for the trace log

	// Determines the effect of adding the tool to USE_TOOLS.
	//
	// As long as bsd.prefs.mk has definitely not been included by the current file,
	// tools added to USE_TOOLS are available at load time, but only after bsd.prefs.mk
	// has been included.
	//
	// Adding a tool to USE_TOOLS _after_ bsd.prefs.mk has been included, on the other
	// hand, only makes the tool available at run time.
	SeenPrefs bool
	// contains filtered or unexported fields
}

Tools collects all tools for a certain scope (global or file) and remembers whether these tools are defined at all, and whether they are declared to be used via USE_TOOLS.

func NewTools

func NewTools(traceName string) *Tools

func (*Tools) ByName

func (tr *Tools) ByName(name string) *Tool

func (*Tools) ByVarname

func (tr *Tools) ByVarname(varname string) *Tool

func (*Tools) Define

func (tr *Tools) Define(name, varname string, mkline MkLine) *Tool

Define registers the tool by its name and the corresponding variable name (if nonempty). Depending on the given mkline, it may be added to USE_TOOLS automatically.

After this tool is added to USE_TOOLS, it may be used by this name (e.g. "awk") or by its variable (e.g. ${AWK}).

func (*Tools) Fallback

func (tr *Tools) Fallback(other *Tools)

func (*Tools) IsValidToolName

func (tr *Tools) IsValidToolName(name string) bool

func (*Tools) ParseToolLine

func (tr *Tools) ParseToolLine(mkline MkLine, fromInfrastructure bool, addToUseTools bool)

ParseToolLine updates the tool definitions according to the given line from a Makefile.

If fromInfrastructure is true, the tool is defined even when it is only added to USE_TOOLS (which normally doesn't define anything). This way, pkglint also finds those tools whose definitions are too difficult to parse from the code.

If addToUseTools is true, a USE_TOOLS line makes a tool immediately usable. This should only be done if the current line is unconditional.

func (*Tools) Trace

func (tr *Tools) Trace()

func (*Tools) Usable

func (tr *Tools) Usable(tool *Tool, time ToolTime) bool

type Toplevel

type Toplevel struct {
	// contains filtered or unexported fields
}

type Validity

type Validity uint8
const (
	// Nowhere means that the tool has not been added
	// to USE_TOOLS and therefore cannot be used at all.
	Nowhere Validity = iota

	// AtRunTime means that the tool has been added to USE_TOOLS
	// after including bsd.prefs.mk and therefore cannot be used
	// at load time.
	//
	// The tool may be used as ${TOOL} in all targets.
	// The tool may be used by its plain name in {pre,do,post}-* targets.
	AtRunTime

	// AfterPrefsMk means that the tool has been added to USE_TOOLS
	// before including bsd.prefs.mk and therefore can be used at
	// load time after bsd.prefs.mk has been included.
	//
	// The tool may be used as ${TOOL} everywhere.
	// The tool may be used by its plain name in {pre,do,post}-* targets.
	AfterPrefsMk
)

func (Validity) String

func (time Validity) String() string

type Var

type Var struct {
	Name string
	Type *Vartype
}

Var describes a variable in a Makefile snippet.

TODO: Remove this type in June 2019 if it is still a stub.

func NewVar

func NewVar(name string) *Var

func (*Var) Constant

func (v *Var) Constant() bool

Constant returns whether the variable is only ever assigned a single value, without being dependent on any other variable.

Multiple assignments (such as VAR=1, VAR+=2, VAR+=3) are considered constant as well, as long as the variable is not used in-between these assignments. That is, no .include or .if may appear there, and none of the ::= modifiers may be involved.

Simple .for loops that append to the variable are ok though.

func (*Var) ConstantValue

func (v *Var) ConstantValue() string

type VarUseContext

type VarUseContext struct {
	IsWordPart bool // Example: LOCALBASE=${LOCALBASE}
	// contains filtered or unexported fields
}

VarUseContext defines the context in which a variable is defined or used. Whether that is allowed depends on:

* The variable's data type, as defined in vardefs.go.

* When used on the right-hand side of an assigment, the variable can represent a list of words, a single word or even only part of a word. This distinction decides upon the correct use of the :Q operator.

* When used in preprocessing statements like .if or .for, the other operands of that statement should fit to the variable and are checked against the variable type. For example, comparing OPSYS to x86_64 doesn't make sense.

func (*VarUseContext) String

func (vuc *VarUseContext) String() string

type VaralignBlock

type VaralignBlock struct {
	// contains filtered or unexported fields
}

VaralignBlock checks that all variable assignments from a paragraph use the same indentation depth for their values. It also checks that the indentation uses tabs instead of spaces.

In general, all values should be aligned using tabs. As an exception, very long lines may be aligned with a single space. A typical example is a SITES.very-long-file-name.tar.gz variable between HOMEPAGE and DISTFILES.

func (*VaralignBlock) Finish

func (va *VaralignBlock) Finish()

func (*VaralignBlock) Process

func (va *VaralignBlock) Process(mkline MkLine)

type Vartype

type Vartype struct {
	// contains filtered or unexported fields
}

Vartype is a combination of a data type and a permission specification. See vardefs.go for examples, and vartypecheck.go for the implementation.

func (*Vartype) AllowedFiles

func (vt *Vartype) AllowedFiles(perms ACLPermissions) string

func (*Vartype) EffectivePermissions

func (vt *Vartype) EffectivePermissions(basename string) ACLPermissions

func (*Vartype) IsConsideredList

func (vt *Vartype) IsConsideredList() bool

IsConsideredList returns whether the type is considered a shell list. This distinction between "real lists" and "considered a list" makes the implementation of checklineMkVartype easier.

func (*Vartype) IsPlainString

func (vt *Vartype) IsPlainString() bool

func (*Vartype) IsShell

func (vt *Vartype) IsShell() bool

func (*Vartype) MayBeAppendedTo

func (vt *Vartype) MayBeAppendedTo() bool

func (*Vartype) String

func (vt *Vartype) String() string

func (*Vartype) Union

func (vt *Vartype) Union() ACLPermissions

Union returns the union of all possible permissions. This can be used to check whether a variable may be defined or used at all, or if it is read-only.

type VartypeCheck

type VartypeCheck struct {
	MkLine MkLine
	Line   Line

	// The name of the variable being checked.
	//
	// In some cases (see WithVarnameValueMatch) it contains not the
	// variable name but more a "description" of a part of a variable.
	// See MachinePlatform for an example.
	Varname    string
	Op         MkOperator
	Value      string
	ValueNoVar string
	MkComment  string
	Guessed    bool // Whether the type definition is guessed (based on the variable name) or explicitly defined (see vardefs.go).
}

func (*VartypeCheck) Autofix

func (cv *VartypeCheck) Autofix() *Autofix

Autofix returns the autofix instance belonging to the line.

Usage:

fix := cv.Autofix()

fix.Errorf("Must not be ...")
fix.Warnf("Should not be ...")
fix.Notef("It is also possible ...")

fix.Explain(
    "Explanation ...",
    "... end of explanation.")

fix.Replace("from", "to")
fix.ReplaceAfter("prefix", "from", "to")
fix.ReplaceRegex(`[\t ]+`, "space", -1)
fix.InsertBefore("new line")
fix.InsertAfter("new line")
fix.Delete()
fix.Custom(func(showAutofix, autofix bool) {})

fix.Apply()

func (*VartypeCheck) AwkCommand

func (cv *VartypeCheck) AwkCommand()

func (*VartypeCheck) BasicRegularExpression

func (cv *VartypeCheck) BasicRegularExpression()

func (*VartypeCheck) BuildlinkDepmethod

func (cv *VartypeCheck) BuildlinkDepmethod()

func (*VartypeCheck) CFlag

func (cv *VartypeCheck) CFlag()

CFlag is a single option to the C/C++ compiler.

XXX: How can flags like "-D NAME" be handled?

func (*VartypeCheck) Category

func (cv *VartypeCheck) Category()

func (*VartypeCheck) Comment

func (cv *VartypeCheck) Comment()

Comment checks for the single-line description of the package.

func (*VartypeCheck) ConfFiles

func (cv *VartypeCheck) ConfFiles()

ConfFiles checks pairs of example file, configuration file.

When a package is installed, the example file is installed as usual and is then copied to its final location.

func (*VartypeCheck) Dependency

func (cv *VartypeCheck) Dependency()

func (*VartypeCheck) DependencyWithPath

func (cv *VartypeCheck) DependencyWithPath()

func (*VartypeCheck) DistSuffix

func (cv *VartypeCheck) DistSuffix()

func (*VartypeCheck) EmulPlatform

func (cv *VartypeCheck) EmulPlatform()

func (*VartypeCheck) Enum

func (cv *VartypeCheck) Enum(vmap map[string]bool, basicType *BasicType)

func (*VartypeCheck) Errorf

func (cv *VartypeCheck) Errorf(format string, args ...interface{})

func (*VartypeCheck) FetchURL

func (cv *VartypeCheck) FetchURL()

func (*VartypeCheck) FileMask

func (cv *VartypeCheck) FileMask()

func (*VartypeCheck) FileMode

func (cv *VartypeCheck) FileMode()

func (*VartypeCheck) Filename

func (cv *VartypeCheck) Filename()

Filename checks that filenames use only limited special characters.

See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_169

func (*VartypeCheck) GccReqd

func (cv *VartypeCheck) GccReqd()

func (*VartypeCheck) Homepage

func (cv *VartypeCheck) Homepage()

func (*VartypeCheck) Identifier

func (cv *VartypeCheck) Identifier()

func (*VartypeCheck) Integer

func (cv *VartypeCheck) Integer()

func (*VartypeCheck) LdFlag

func (cv *VartypeCheck) LdFlag()

func (*VartypeCheck) License

func (cv *VartypeCheck) License()

func (*VartypeCheck) MachineGnuPlatform

func (cv *VartypeCheck) MachineGnuPlatform()

func (*VartypeCheck) MachinePlatform

func (cv *VartypeCheck) MachinePlatform()

func (*VartypeCheck) MachinePlatformPattern

func (cv *VartypeCheck) MachinePlatformPattern()

func (*VartypeCheck) MailAddress

func (cv *VartypeCheck) MailAddress()

func (*VartypeCheck) Message

func (cv *VartypeCheck) Message()

Message is a plain string. It should not be enclosed in quotes since that is the job of the code that uses the message.

Lists of messages use a different type since they need the quotes around each message; see PKG_FAIL_REASON.

func (*VartypeCheck) Notef

func (cv *VartypeCheck) Notef(format string, args ...interface{})

func (*VartypeCheck) Option

func (cv *VartypeCheck) Option()

Option checks whether a single package option from options.mk conforms to the naming conventions.

func (*VartypeCheck) PathMask

func (cv *VartypeCheck) PathMask()

PathMask is a shell pattern for pathnames, possibly including slashes.

See FileMask.

func (*VartypeCheck) Pathlist

func (cv *VartypeCheck) Pathlist()

Pathlist checks variables like the PATH environment variable.

func (*VartypeCheck) Pathname

func (cv *VartypeCheck) Pathname()

Pathname checks for pathnames.

Like Filename, but including slashes.

See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266

func (*VartypeCheck) Perl5Packlist

func (cv *VartypeCheck) Perl5Packlist()

func (*VartypeCheck) Perms

func (cv *VartypeCheck) Perms()

func (*VartypeCheck) PkgOptionsVar

func (cv *VartypeCheck) PkgOptionsVar()

func (*VartypeCheck) PkgPath

func (cv *VartypeCheck) PkgPath()

PkgPath checks a directory name relative to the top-level pkgsrc directory. Despite its name, it is more similar to RelativePkgDir than to RelativePkgPath.

func (*VartypeCheck) PkgRevision

func (cv *VartypeCheck) PkgRevision()

func (*VartypeCheck) Pkgname

func (cv *VartypeCheck) Pkgname()

func (*VartypeCheck) PrefixPathname

func (cv *VartypeCheck) PrefixPathname()

PrefixPathname checks for a pathname relative to ${PREFIX}.

func (*VartypeCheck) PythonDependency

func (cv *VartypeCheck) PythonDependency()

func (*VartypeCheck) RelativePkgDir

func (cv *VartypeCheck) RelativePkgDir()

RelativePkgDir refers to a package directory, e.g. ../../category/pkgbase.

func (*VartypeCheck) RelativePkgPath

func (cv *VartypeCheck) RelativePkgPath()

RelativePkgPath refers to a file or directory, e.g. ../../category/pkgbase, ../../category/pkgbase/Makefile.

See RelativePkgDir, which requires a directory, not a file.

func (*VartypeCheck) Restricted

func (cv *VartypeCheck) Restricted()

func (*VartypeCheck) SedCommands

func (cv *VartypeCheck) SedCommands()

func (*VartypeCheck) ShellCommand

func (cv *VartypeCheck) ShellCommand()

func (*VartypeCheck) ShellCommands

func (cv *VartypeCheck) ShellCommands()

ShellCommands checks for zero or more shell commands, each terminated with a semicolon.

func (*VartypeCheck) ShellWord

func (cv *VartypeCheck) ShellWord()

func (*VartypeCheck) Stage

func (cv *VartypeCheck) Stage()

func (*VartypeCheck) Tool

func (cv *VartypeCheck) Tool()

Tool checks for tool names like "awk", "m4:pkgsrc", "digest:bootstrap".

func (*VartypeCheck) URL

func (cv *VartypeCheck) URL()

func (*VartypeCheck) Unknown

func (cv *VartypeCheck) Unknown()

Unknown doesn't check for anything.

func (*VartypeCheck) UserGroupName

func (cv *VartypeCheck) UserGroupName()

func (*VartypeCheck) VariableName

func (cv *VartypeCheck) VariableName()

VariableName checks that the value is a valid variable name to be used in Makefiles.

func (*VartypeCheck) Version

func (cv *VartypeCheck) Version()

func (*VartypeCheck) Warnf

func (cv *VartypeCheck) Warnf(format string, args ...interface{})

func (*VartypeCheck) WithValue

func (cv *VartypeCheck) WithValue(value string) *VartypeCheck

WithValue returns a new VartypeCheck context by copying all fields except the value.

This is typically used when calling a related check.

func (*VartypeCheck) WithVarnameValue

func (cv *VartypeCheck) WithVarnameValue(varname, value string) *VartypeCheck

WithVarnameValue returns a new VartypeCheck context by copying all fields except the variable name and the value.

This is typically used when checking parts of composite types.

func (*VartypeCheck) WithVarnameValueMatch

func (cv *VartypeCheck) WithVarnameValueMatch(varname, value string) *VartypeCheck

WithVarnameValueMatch returns a new VartypeCheck context by copying all fields except the variable name, the operator (it is set to opUseMatch) and the value.

This is typically used when checking parts of composite types, especially patterns.

func (*VartypeCheck) WrapperReorder

func (cv *VartypeCheck) WrapperReorder()

func (*VartypeCheck) WrapperTransform

func (cv *VartypeCheck) WrapperTransform()

func (*VartypeCheck) WrkdirSubdirectory

func (cv *VartypeCheck) WrkdirSubdirectory()

func (*VartypeCheck) WrksrcSubdirectory

func (cv *VartypeCheck) WrksrcSubdirectory()

WrksrcSubdirectory checks a directory relative to ${WRKSRC}, for use in CONFIGURE_DIRS and similar variables.

func (*VartypeCheck) Yes

func (cv *VartypeCheck) Yes()

func (*VartypeCheck) YesNo

func (cv *VartypeCheck) YesNo()

func (*VartypeCheck) YesNoIndirectly

func (cv *VartypeCheck) YesNoIndirectly()

type YesNoUnknown

type YesNoUnknown uint8

func (YesNoUnknown) String

func (ynu YesNoUnknown) String() string

Directories

Path Synopsis
cmd
Package getopt provides a parser for command line options, supporting multi-value options such as -Wall,no-extra.
Package getopt provides a parser for command line options, supporting multi-value options such as -Wall,no-extra.
Package intqa provides quality assurance for the pkglint code.
Package intqa provides quality assurance for the pkglint code.
Package regex provides a registry of precompiled regular expressions to allow reusing them without the syntactic overhead of declaring pattern variables everywhere in the code.
Package regex provides a registry of precompiled regular expressions to allow reusing them without the syntactic overhead of declaring pattern variables everywhere in the code.
Package trace traces function calls and steps in-between.
Package trace traces function calls and steps in-between.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL