提交 4968e7d9 编写于 作者: V Vidar Holen

Added -s flag to override dialect, e.g. -s ksh

上级 075d58ee
......@@ -15,7 +15,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-}
module ShellCheck.Analytics (AnalysisOption(..), filterByAnnotation, runAnalytics) where
module ShellCheck.Analytics (AnalysisOption(..), filterByAnnotation, runAnalytics, shellForExecutable) where
import ShellCheck.AST
import ShellCheck.Data
......@@ -41,7 +41,7 @@ data Parameters = Parameters {
shellType :: Shell
}
data AnalysisOption = NotImplemented
data AnalysisOption = ForceShell Shell
-- Checks that are run on the AST root
treeChecks :: [Parameters -> Token -> [Note]]
......@@ -75,36 +75,41 @@ checksFor Bash = [
]
runAnalytics :: [AnalysisOption] -> Token -> [Note]
runAnalytics options root = runList root treeChecks
runAnalytics options root = runList options root treeChecks
runList root list = notes
runList options root list = notes
where
params = Parameters {
shellType = determineShell root,
shellType = getShellOption,
parentMap = getParentTree root,
variableFlow = getVariableFlow (shellType params) (parentMap params) root
}
notes = concatMap (\f -> f params root) list
getShellOption =
fromMaybe (determineShell root) . msum $
map ((\option ->
case option of
ForceShell x -> return x
)) options
checkList l t = concatMap (\f -> f t) l
prop_determineShell0 = determineShell (T_Script (Id 0) "#!/bin/sh" []) == Sh
prop_determineShell1 = determineShell (T_Script (Id 0) "#!/usr/bin/env ksh" []) == Ksh
prop_determineShell2 = determineShell (T_Script (Id 0) "" []) == Bash
determineShell (T_Script _ shebang _) = normalize $ shellFor shebang
determineShell (T_Script _ shebang _) = fromMaybe Bash . shellForExecutable $ shellFor shebang
where shellFor s | "/env " `isInfixOf` s = head ((drop 1 $ words s)++[""])
shellFor s = reverse . takeWhile (/= '/') . reverse $ s
normalize "sh" = Sh
normalize "ash" = Sh
normalize "dash" = Sh
normalize "ksh" = Ksh
normalize "ksh93" = Ksh
normalize "zsh" = Zsh
normalize "bash" = Bash
normalize _ = Bash
shellForExecutable "sh" = return Sh
shellForExecutable "ash" = return Sh
shellForExecutable "dash" = return Sh
shellForExecutable "ksh" = return Ksh
shellForExecutable "ksh93" = return Ksh
shellForExecutable "zsh" = return Zsh
shellForExecutable "bash" = return Bash
shellForExecutable _ = Nothing
-- Checks that are run on each node in the AST
runNodeAnalysis f p t = execWriter (doAnalysis (f p) t)
......@@ -288,7 +293,7 @@ verifyNotTree f s = checkTree f s == Just False
checkNode f s = checkTree (runNodeAnalysis f) s
checkTree f s = case parseShell "-" s of
(ParseResult (Just (t, m)) _) -> Just . not . null $ runList t [f]
(ParseResult (Just (t, m)) _) -> Just . not . null $ runList [] t [f]
_ -> Nothing
......
......@@ -25,27 +25,27 @@ import Data.List
prop_findsParseIssue =
let comments = shellCheck "echo \"$12\"" in
let comments = shellCheck "echo \"$12\"" [] in
(length comments) == 1 && (scCode $ head comments) == 1037
prop_commentDisablesParseIssue1 =
null $ shellCheck "#shellcheck disable=SC1037\necho \"$12\""
null $ shellCheck "#shellcheck disable=SC1037\necho \"$12\"" []
prop_commentDisablesParseIssue2 =
null $ shellCheck "#shellcheck disable=SC1037\n#lol\necho \"$12\""
null $ shellCheck "#shellcheck disable=SC1037\n#lol\necho \"$12\"" []
prop_findsAnalysisIssue =
let comments = shellCheck "echo $1" in
let comments = shellCheck "echo $1" [] in
(length comments) == 1 && (scCode $ head comments) == 2086
prop_commentDisablesAnalysisIssue1 =
null $ shellCheck "#shellcheck disable=SC2086\necho $1"
null $ shellCheck "#shellcheck disable=SC2086\necho $1" []
prop_commentDisablesAnalysisIssue2 =
null $ shellCheck "#shellcheck disable=SC2086\n#lol\necho $1"
null $ shellCheck "#shellcheck disable=SC2086\n#lol\necho $1" []
shellCheck :: String -> [ShellCheckComment]
shellCheck script =
shellCheck :: String -> [AnalysisOption] -> [ShellCheckComment]
shellCheck script options =
let (ParseResult result notes) = parseShell "-" script in
let allNotes = notes ++ (concat $ maybeToList $ do
(tree, posMap) <- result
let list = runAnalytics [] tree
let list = runAnalytics options tree
return $ map (noteToParseNote posMap) $ filterByAnnotation tree list
)
in
......
......@@ -18,10 +18,12 @@
import Control.Exception
import Control.Monad
import Data.Char
import Data.Maybe
import GHC.Exts
import GHC.IO.Device
import Prelude hiding (catch)
import ShellCheck.Simple
import ShellCheck.Analytics
import System.Console.GetOpt
import System.Directory
import System.Environment
......@@ -37,7 +39,9 @@ options = [
Option ['f'] ["format"]
(ReqArg (Flag "format") "FORMAT") "output format",
Option ['e'] ["exclude"]
(ReqArg (Flag "exclude") "CODE1,CODE2..") "exclude types of warnings"
(ReqArg (Flag "exclude") "CODE1,CODE2..") "exclude types of warnings",
Option ['s'] ["shell"]
(ReqArg (Flag "shell") "SHELLNAME") "Specify dialect (bash,sh,ksh,zsh)"
]
printErr = hPutStrLn stderr
......@@ -200,7 +204,14 @@ commentsFor options file =
liftM (getComments options) $ readContents file
getComments options contents =
excludeCodes (getExclusions options) $ shellCheck contents
excludeCodes (getExclusions options) $ shellCheck contents analysisOptions
where
analysisOptions = catMaybes [ shellOption ]
shellOption = do
option <- getOption options "shell"
sh <- shellForExecutable option
return $ ForceShell sh
readContents file = if file == "-" then getContents else readFile file
......@@ -216,9 +227,9 @@ makeNonVirtual comments contents =
real rest (r+1) (v + 8 - (v `mod` 8)) target
real (_:rest) r v target = real rest (r+1) (v+1) target
getOption [] _ def = def
getOption ((Flag var val):_) name _ | name == var = val
getOption (_:rest) flag def = getOption rest flag def
getOption [] _ = Nothing
getOption ((Flag var val):_) name | name == var = return val
getOption (_:rest) flag = getOption rest flag
getOptions options name =
map (\(Flag _ val) -> val) . filter (\(Flag var _) -> var == name) $ options
......@@ -256,8 +267,9 @@ main = do
exitWith code
process Nothing = return False
process (Just (options, files)) =
let format = getOption options "format" "tty" in
process (Just (options, files)) = do
verifyShellOption options
let format = fromMaybe "tty" $ getOption options "format" in
case Map.lookup format formats of
Nothing -> do
printErr $ "Unknown format " ++ format
......@@ -268,3 +280,10 @@ process (Just (options, files)) =
Just f -> do
f options files
verifyShellOption options =
let shell = getOption options "shell" in
if isNothing shell
then return ()
else when (isNothing $ shell >>= shellForExecutable) $ do
printErr $ "Unknown shell: " ++ (fromJust shell)
exitWith supportFailure
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册