Add option to look for sources in alternate root paths
Add a new optional flag "-r|--root ROOTPATHS", where ROOTPATHS is a colon separated list of paths, that will look for external sources in alternate roots. This is particular useful when the run-time environment does not fully match the development environment. The #shellcheck source=file directive is useful, but has its limitations in certain scenarios. Also, in many cases the directive could be removed from scripts when the root flag is used. Script example.bash: #!/bin/bash source /etc/foo/config Example usage where etc/foo/config exists in skel/foo: # shellcheck -x -r skel/foo:skel/core example.bash
This commit is contained in:
parent
b824294961
commit
af46758ff1
|
@ -69,6 +69,7 @@ instance Monoid Status where
|
||||||
data Options = Options {
|
data Options = Options {
|
||||||
checkSpec :: CheckSpec,
|
checkSpec :: CheckSpec,
|
||||||
externalSources :: Bool,
|
externalSources :: Bool,
|
||||||
|
rootPaths :: [FilePath],
|
||||||
formatterOptions :: FormatterOptions,
|
formatterOptions :: FormatterOptions,
|
||||||
minSeverity :: Severity
|
minSeverity :: Severity
|
||||||
}
|
}
|
||||||
|
@ -76,6 +77,7 @@ data Options = Options {
|
||||||
defaultOptions = Options {
|
defaultOptions = Options {
|
||||||
checkSpec = emptyCheckSpec,
|
checkSpec = emptyCheckSpec,
|
||||||
externalSources = False,
|
externalSources = False,
|
||||||
|
rootPaths = [],
|
||||||
formatterOptions = newFormatterOptions {
|
formatterOptions = newFormatterOptions {
|
||||||
foColorOption = ColorAuto
|
foColorOption = ColorAuto
|
||||||
},
|
},
|
||||||
|
@ -98,6 +100,9 @@ options = [
|
||||||
"Output format (" ++ formatList ++ ")",
|
"Output format (" ++ formatList ++ ")",
|
||||||
Option "" ["norc"]
|
Option "" ["norc"]
|
||||||
(NoArg $ Flag "norc" "true") "Don't look for .shellcheckrc files",
|
(NoArg $ Flag "norc" "true") "Don't look for .shellcheckrc files",
|
||||||
|
Option "r" ["root"]
|
||||||
|
(ReqArg (Flag "root") "ROOTPATHS")
|
||||||
|
"Specify alternate root path(s) when looking for sources (colon separated)",
|
||||||
Option "s" ["shell"]
|
Option "s" ["shell"]
|
||||||
(ReqArg (Flag "shell") "SHELLNAME")
|
(ReqArg (Flag "shell") "SHELLNAME")
|
||||||
"Specify dialect (sh, bash, dash, ksh)",
|
"Specify dialect (sh, bash, dash, ksh)",
|
||||||
|
@ -311,6 +316,12 @@ parseOption flag options =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Flag "root" str -> do
|
||||||
|
let paths = filter (not . null) $ split ':' str
|
||||||
|
return options {
|
||||||
|
rootPaths = paths
|
||||||
|
}
|
||||||
|
|
||||||
Flag "sourced" _ ->
|
Flag "sourced" _ ->
|
||||||
return options {
|
return options {
|
||||||
checkSpec = (checkSpec options) {
|
checkSpec = (checkSpec options) {
|
||||||
|
@ -362,8 +373,10 @@ ioInterface options files = do
|
||||||
inputs <- mapM normalize files
|
inputs <- mapM normalize files
|
||||||
cache <- newIORef emptyCache
|
cache <- newIORef emptyCache
|
||||||
configCache <- newIORef ("", Nothing)
|
configCache <- newIORef ("", Nothing)
|
||||||
|
let rootPathsCache = rootPaths options
|
||||||
return SystemInterface {
|
return SystemInterface {
|
||||||
siReadFile = get cache inputs,
|
siReadFile = get cache inputs,
|
||||||
|
siFindSource = findSourceFile rootPathsCache,
|
||||||
siGetConfig = getConfig configCache
|
siGetConfig = getConfig configCache
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
@ -455,6 +468,23 @@ ioInterface options files = do
|
||||||
putStrLn $ file ++ ": " ++ show err
|
putStrLn $ file ++ ": " ++ show err
|
||||||
return ("", True)
|
return ("", True)
|
||||||
|
|
||||||
|
findSourceFile rootPaths file = do
|
||||||
|
case file of
|
||||||
|
('/':root) -> do
|
||||||
|
source <- find root
|
||||||
|
return source
|
||||||
|
_ ->
|
||||||
|
return file
|
||||||
|
where
|
||||||
|
find root = do
|
||||||
|
sources <- filterM doesFileExist paths
|
||||||
|
case sources of
|
||||||
|
[] -> return file
|
||||||
|
(first:_) -> return first
|
||||||
|
where
|
||||||
|
paths = map join rootPaths
|
||||||
|
join path = joinPath [path, root]
|
||||||
|
|
||||||
inputFile file = do
|
inputFile file = do
|
||||||
(handle, shouldCache) <-
|
(handle, shouldCache) <-
|
||||||
if file == "-"
|
if file == "-"
|
||||||
|
|
|
@ -73,6 +73,8 @@ import qualified Data.Map as Map
|
||||||
data SystemInterface m = SystemInterface {
|
data SystemInterface m = SystemInterface {
|
||||||
-- Read a file by filename, or return an error
|
-- Read a file by filename, or return an error
|
||||||
siReadFile :: String -> m (Either ErrorMessage String),
|
siReadFile :: String -> m (Either ErrorMessage String),
|
||||||
|
-- Find source file in alternate root paths
|
||||||
|
siFindSource :: String -> m (FilePath),
|
||||||
-- Get the configuration file (name, contents) for a filename
|
-- Get the configuration file (name, contents) for a filename
|
||||||
siGetConfig :: String -> m (Maybe (FilePath, String))
|
siGetConfig :: String -> m (Maybe (FilePath, String))
|
||||||
}
|
}
|
||||||
|
@ -287,6 +289,7 @@ data ColorOption =
|
||||||
mockedSystemInterface :: [(String, String)] -> SystemInterface Identity
|
mockedSystemInterface :: [(String, String)] -> SystemInterface Identity
|
||||||
mockedSystemInterface files = SystemInterface {
|
mockedSystemInterface files = SystemInterface {
|
||||||
siReadFile = rf,
|
siReadFile = rf,
|
||||||
|
siFindSource = fs,
|
||||||
siGetConfig = const $ return Nothing
|
siGetConfig = const $ return Nothing
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
@ -294,6 +297,7 @@ mockedSystemInterface files = SystemInterface {
|
||||||
case filter ((== file) . fst) files of
|
case filter ((== file) . fst) files of
|
||||||
[] -> return $ Left "File not included in mock."
|
[] -> return $ Left "File not included in mock."
|
||||||
[(_, contents)] -> return $ Right contents
|
[(_, contents)] -> return $ Right contents
|
||||||
|
fs file = return file
|
||||||
|
|
||||||
mockRcFile rcfile mock = mock {
|
mockRcFile rcfile mock = mock {
|
||||||
siGetConfig = const . return $ Just (".shellcheckrc", rcfile)
|
siGetConfig = const . return $ Just (".shellcheckrc", rcfile)
|
||||||
|
|
|
@ -2087,7 +2087,9 @@ readSource t@(T_Redirecting _ _ (T_SimpleCommand cmdId _ (cmd:file':rest'))) = d
|
||||||
input <-
|
input <-
|
||||||
if filename == "/dev/null" -- always allow /dev/null
|
if filename == "/dev/null" -- always allow /dev/null
|
||||||
then return (Right "")
|
then return (Right "")
|
||||||
else system $ siReadFile sys filename
|
else do
|
||||||
|
filename' <- system $ siFindSource sys filename
|
||||||
|
system $ siReadFile sys filename'
|
||||||
case input of
|
case input of
|
||||||
Left err -> do
|
Left err -> do
|
||||||
parseNoteAtId (getId file) InfoC 1091 $
|
parseNoteAtId (getId file) InfoC 1091 $
|
||||||
|
|
Loading…
Reference in New Issue