Initial support for portage

Portage (Gentoo's package manager) packages are made up of ebuild and
eclass files.  These are essentially bash scripts with a bunch of
predefined functions, global variables, and some external semantics
(e.g. "inherit" is a wrapper around "source" that incorporates an
expected filesystem layout).

Add automatic detection of portage by mapping .ebuild and .eclass files
to bash with an extra Parameters flag that indicates they're a portage
build file.  This leaves all the bash checks as they are, but allows
additional tweaks to be made for "portage mode".  No actual checks are
added here; subsequent changes will add portage-specific behavior.
This commit is contained in:
Benjamin Gordon 2019-07-02 09:39:46 -06:00
commit f6e4bc828f
5 changed files with 23 additions and 9 deletions

View file

@ -16,6 +16,7 @@
- json1 format like --format=json but treats tabs as single characters
- Recognize FLAGS variables created by the shflags library.
- Site-specific changes can now be made in Custom.hs for ease of patching
- Add portage as a bash-like shell for ebuild/eclass files.
- SC2154: Also warn about unassigned uppercase variables (optional)
- SC2252: Warn about `[ $a != x ] || [ $a != y ]`, similar to SC2055
- SC2251: Inform about ineffectual ! in front of commands

View file

@ -87,8 +87,9 @@ not warn at all, as `ksh` supports decimals in arithmetic contexts.
: Specify Bourne shell dialect. Valid values are *sh*, *bash*, *dash* and *ksh*.
The default is to deduce the shell from the file's `shell` directive,
shebang, or `.bash/.bats/.dash/.ksh` extension, in that order. *sh* refers to
POSIX `sh` (not the system's), and will warn of portability issues.
shebang, or `.bash/.bats/.dash/.ksh/.ebuild/.eclass` extension, in that
order. *sh* refers to POSIX `sh` (not the system's), and will warn of
portability issues.
**-S**\ *SEVERITY*,\ **--severity=***severity*

View file

@ -92,7 +92,9 @@ data Parameters = Parameters {
-- The root node of the AST
rootNode :: Token,
-- map from token id to start and end position
tokenPositions :: Map.Map Id (Position, Position)
tokenPositions :: Map.Map Id (Position, Position),
-- True if script is being used as a portage build file
isPortageBuild :: Bool
} deriving (Show)
-- TODO: Cache results of common AST ops here
@ -195,7 +197,8 @@ makeParameters spec =
shellTypeSpecified = isJust (asShellType spec) || isJust (asFallbackShell spec),
parentMap = getParentTree root,
variableFlow = getVariableFlow params root,
tokenPositions = asTokenPositions spec
tokenPositions = asTokenPositions spec,
isPortageBuild = asIsPortageBuild spec
} in params
where root = asScript spec

View file

@ -53,12 +53,18 @@ shellFromFilename filename = foldl mplus Nothing candidates
shellExtensions = [(".ksh", Ksh)
,(".bash", Bash)
,(".bats", Bash)
,(".dash", Dash)]
,(".dash", Dash)
,(".ebuild", Bash)
,(".eclass", Bash)]
-- The `.sh` is too generic to determine the shell:
-- We fallback to Bash in this case and emit SC2148 if there is no shebang
candidates =
map (\(ext,sh) -> if ext `isSuffixOf` filename then Just sh else Nothing) shellExtensions
isPortageBuildFile filename = any (\x -> isSuffixOf x filename) portageExtensions
where
portageExtensions = [".ebuild", ".eclass"]
checkScript :: Monad m => SystemInterface m -> CheckSpec -> m CheckResult
checkScript sys spec = do
results <- checkScript (csScript spec)
@ -85,7 +91,8 @@ checkScript sys spec = do
asCheckSourced = csCheckSourced spec,
asExecutionMode = Executed,
asTokenPositions = tokenPositions,
asOptionalChecks = csOptionalChecks spec
asOptionalChecks = csOptionalChecks spec,
asIsPortageBuild = isPortageBuildFile $ csFilename spec
} where as = newAnalysisSpec root
let analysisMessages =
fromMaybe [] $

View file

@ -25,7 +25,7 @@ module ShellCheck.Interface
, CheckResult(crFilename, crComments)
, ParseSpec(psFilename, psScript, psCheckSourced, psIgnoreRC, psShellTypeOverride)
, ParseResult(prComments, prTokenPositions, prRoot)
, AnalysisSpec(asScript, asShellType, asFallbackShell, asExecutionMode, asCheckSourced, asTokenPositions, asOptionalChecks)
, AnalysisSpec(asScript, asShellType, asFallbackShell, asExecutionMode, asCheckSourced, asTokenPositions, asOptionalChecks, asIsPortageBuild)
, AnalysisResult(arComments)
, FormatterOptions(foColorOption, foWikiLinkCount)
, Shell(Ksh, Sh, Bash, Dash)
@ -161,7 +161,8 @@ data AnalysisSpec = AnalysisSpec {
asExecutionMode :: ExecutionMode,
asCheckSourced :: Bool,
asOptionalChecks :: [String],
asTokenPositions :: Map.Map Id (Position, Position)
asTokenPositions :: Map.Map Id (Position, Position),
asIsPortageBuild :: Bool
}
newAnalysisSpec token = AnalysisSpec {
@ -171,7 +172,8 @@ newAnalysisSpec token = AnalysisSpec {
asExecutionMode = Executed,
asCheckSourced = False,
asOptionalChecks = [],
asTokenPositions = Map.empty
asTokenPositions = Map.empty,
asIsPortageBuild = False
}
newtype AnalysisResult = AnalysisResult {