Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Annlix
ShellCheck
提交
8dd40efb
S
ShellCheck
项目概览
Annlix
/
ShellCheck
与 Fork 源项目一致
Fork自
镜像 / koalaman / ShellCheck
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
ShellCheck
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8dd40efb
编写于
8月 13, 2017
作者:
V
Vidar Holen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add support for -a: emit for sourced files.
上级
73d06c4f
变更
11
显示空白变更内容
内联
并排
Showing
11 changed file
with
182 addition
and
71 deletion
+182
-71
ShellCheck/Analyzer.hs
ShellCheck/Analyzer.hs
+1
-1
ShellCheck/AnalyzerLib.hs
ShellCheck/AnalyzerLib.hs
+7
-4
ShellCheck/Checker.hs
ShellCheck/Checker.hs
+23
-7
ShellCheck/Formatter/CheckStyle.hs
ShellCheck/Formatter/CheckStyle.hs
+17
-4
ShellCheck/Formatter/Format.hs
ShellCheck/Formatter/Format.hs
+2
-1
ShellCheck/Formatter/GCC.hs
ShellCheck/Formatter/GCC.hs
+15
-4
ShellCheck/Formatter/TTY.hs
ShellCheck/Formatter/TTY.hs
+10
-3
ShellCheck/Interface.hs
ShellCheck/Interface.hs
+6
-2
ShellCheck/Parser.hs
ShellCheck/Parser.hs
+33
-15
shellcheck.1.md
shellcheck.1.md
+7
-0
shellcheck.hs
shellcheck.hs
+61
-30
未找到文件。
ShellCheck/Analyzer.hs
浏览文件 @
8dd40efb
...
@@ -32,7 +32,7 @@ import qualified ShellCheck.Checks.ShellSupport
...
@@ -32,7 +32,7 @@ import qualified ShellCheck.Checks.ShellSupport
analyzeScript
::
AnalysisSpec
->
AnalysisResult
analyzeScript
::
AnalysisSpec
->
AnalysisResult
analyzeScript
spec
=
AnalysisResult
{
analyzeScript
spec
=
AnalysisResult
{
arComments
=
arComments
=
filterByAnnotation
(
asScript
spec
)
.
nub
$
filterByAnnotation
spec
params
.
nub
$
runAnalytics
spec
runAnalytics
spec
++
runChecker
params
(
checkers
params
)
++
runChecker
params
(
checkers
params
)
}
}
...
...
ShellCheck/AnalyzerLib.hs
浏览文件 @
8dd40efb
...
@@ -109,6 +109,7 @@ data VariableState = Dead Token String | Alive deriving (Show)
...
@@ -109,6 +109,7 @@ data VariableState = Dead Token String | Alive deriving (Show)
defaultSpec
root
=
AnalysisSpec
{
defaultSpec
root
=
AnalysisSpec
{
asScript
=
root
,
asScript
=
root
,
asShellType
=
Nothing
,
asShellType
=
Nothing
,
asCheckSourced
=
False
,
asExecutionMode
=
Executed
asExecutionMode
=
Executed
}
}
...
@@ -116,7 +117,8 @@ pScript s =
...
@@ -116,7 +117,8 @@ pScript s =
let
let
pSpec
=
ParseSpec
{
pSpec
=
ParseSpec
{
psFilename
=
"script"
,
psFilename
=
"script"
,
psScript
=
s
psScript
=
s
,
psCheckSourced
=
False
}
}
in
prRoot
.
runIdentity
$
parseScript
(
mockedSystemInterface
[]
)
pSpec
in
prRoot
.
runIdentity
$
parseScript
(
mockedSystemInterface
[]
)
pSpec
...
@@ -801,9 +803,10 @@ whenShell l c = do
...
@@ -801,9 +803,10 @@ whenShell l c = do
when
(
shell
`
elem
`
l
)
c
when
(
shell
`
elem
`
l
)
c
filterByAnnotation
token
=
filterByAnnotation
asSpec
params
=
filter
(
not
.
shouldIgnore
)
filter
(
not
.
shouldIgnore
)
where
where
token
=
asScript
asSpec
idFor
(
TokenComment
id
_
)
=
id
idFor
(
TokenComment
id
_
)
=
id
shouldIgnore
note
=
shouldIgnore
note
=
any
(
shouldIgnoreFor
(
getCode
note
))
$
any
(
shouldIgnoreFor
(
getCode
note
))
$
...
@@ -813,9 +816,9 @@ filterByAnnotation token =
...
@@ -813,9 +816,9 @@ filterByAnnotation token =
where
where
hasNum
(
DisableComment
ts
)
=
num
==
ts
hasNum
(
DisableComment
ts
)
=
num
==
ts
hasNum
_
=
False
hasNum
_
=
False
shouldIgnoreFor
_
T_Include
{}
=
True
-- Ignore included files
shouldIgnoreFor
_
T_Include
{}
=
not
$
asCheckSourced
asSpec
shouldIgnoreFor
_
_
=
False
shouldIgnoreFor
_
_
=
False
parents
=
getParentTree
token
parents
=
parentMap
params
getCode
(
TokenComment
_
(
Comment
_
c
_
))
=
c
getCode
(
TokenComment
_
(
Comment
_
c
_
))
=
c
-- Is this a ${#anything}, to get string length or array count?
-- Is this a ${#anything}, to get string length or array count?
...
...
ShellCheck/Checker.hs
浏览文件 @
8dd40efb
...
@@ -54,7 +54,8 @@ checkScript sys spec = do
...
@@ -54,7 +54,8 @@ checkScript sys spec = do
checkScript
contents
=
do
checkScript
contents
=
do
result
<-
parseScript
sys
ParseSpec
{
result
<-
parseScript
sys
ParseSpec
{
psFilename
=
csFilename
spec
,
psFilename
=
csFilename
spec
,
psScript
=
contents
psScript
=
contents
,
psCheckSourced
=
csCheckSourced
spec
}
}
let
parseMessages
=
prComments
result
let
parseMessages
=
prComments
result
let
analysisMessages
=
let
analysisMessages
=
...
@@ -77,6 +78,7 @@ checkScript sys spec = do
...
@@ -77,6 +78,7 @@ checkScript sys spec = do
AnalysisSpec
{
AnalysisSpec
{
asScript
=
root
,
asScript
=
root
,
asShellType
=
csShellTypeOverride
spec
,
asShellType
=
csShellTypeOverride
spec
,
asCheckSourced
=
csCheckSourced
spec
,
asExecutionMode
=
Executed
asExecutionMode
=
Executed
}
}
...
@@ -88,14 +90,22 @@ getErrors sys spec =
...
@@ -88,14 +90,22 @@ getErrors sys spec =
check
=
checkWithIncludes
[]
check
=
checkWithIncludes
[]
checkWithSpec
includes
=
getErrors
(
mockedSystemInterface
includes
)
checkWithIncludes
includes
src
=
checkWithIncludes
includes
src
=
getErrors
checkWithSpec
includes
emptyCheckSpec
{
(
mockedSystemInterface
includes
)
emptyCheckSpec
{
csScript
=
src
,
csScript
=
src
,
csExcludedWarnings
=
[
2148
]
csExcludedWarnings
=
[
2148
]
}
}
checkRecursive
includes
src
=
checkWithSpec
includes
emptyCheckSpec
{
csScript
=
src
,
csExcludedWarnings
=
[
2148
],
csCheckSourced
=
True
}
prop_findsParseIssue
=
check
"echo
\"
$12
\"
"
==
[
1037
]
prop_findsParseIssue
=
check
"echo
\"
$12
\"
"
==
[
1037
]
prop_commentDisablesParseIssue1
=
prop_commentDisablesParseIssue1
=
...
@@ -153,6 +163,12 @@ prop_cantSourceDynamic2 =
...
@@ -153,6 +163,12 @@ prop_cantSourceDynamic2 =
prop_canSourceDynamicWhenRedirected
=
prop_canSourceDynamicWhenRedirected
=
null
$
checkWithIncludes
[(
"lib"
,
""
)]
"#shellcheck source=lib
\n
.
\"
$1
\"
"
null
$
checkWithIncludes
[(
"lib"
,
""
)]
"#shellcheck source=lib
\n
.
\"
$1
\"
"
prop_recursiveAnalysis
=
[
2086
]
==
checkRecursive
[(
"lib"
,
"echo $1"
)]
"source lib"
prop_recursiveParsing
=
[
1037
]
==
checkRecursive
[(
"lib"
,
"echo
\"
$10
\"
"
)]
"source lib"
prop_sourceDirectiveDoesntFollowFile
=
prop_sourceDirectiveDoesntFollowFile
=
null
$
checkWithIncludes
null
$
checkWithIncludes
[(
"foo"
,
"source bar"
),
(
"bar"
,
"baz=3"
)]
[(
"foo"
,
"source bar"
),
(
"bar"
,
"baz=3"
)]
...
...
ShellCheck/Formatter/CheckStyle.hs
浏览文件 @
8dd40efb
...
@@ -34,14 +34,27 @@ format = return Formatter {
...
@@ -34,14 +34,27 @@ format = return Formatter {
putStrLn
"<checkstyle version='4.3'>"
,
putStrLn
"<checkstyle version='4.3'>"
,
onFailure
=
outputError
,
onFailure
=
outputError
,
onResult
=
outputResult
,
onResult
=
outputResult
s
,
footer
=
putStrLn
"</checkstyle>"
footer
=
putStrLn
"</checkstyle>"
}
}
outputResult
result
contents
=
do
outputResults
cr
sys
=
let
comments
=
makeNonVirtual
(
crComments
result
)
contents
if
null
comments
putStrLn
.
formatFile
(
crFilename
result
)
$
comments
then
outputFile
(
crFilename
cr
)
""
[]
else
mapM_
outputGroup
fileGroups
where
comments
=
crComments
cr
fileGroups
=
groupWith
sourceFile
comments
outputGroup
group
=
do
let
filename
=
sourceFile
(
head
group
)
result
<-
(
siReadFile
sys
)
filename
let
contents
=
either
(
const
""
)
id
result
outputFile
filename
contents
group
outputFile
filename
contents
warnings
=
do
let
comments
=
makeNonVirtual
warnings
contents
putStrLn
.
formatFile
filename
$
comments
formatFile
name
comments
=
concat
[
formatFile
name
comments
=
concat
[
"<file "
,
attr
"name"
name
,
">
\n
"
,
"<file "
,
attr
"name"
name
,
">
\n
"
,
...
...
ShellCheck/Formatter/Format.hs
浏览文件 @
8dd40efb
...
@@ -25,11 +25,12 @@ import ShellCheck.Interface
...
@@ -25,11 +25,12 @@ import ShellCheck.Interface
-- A formatter that carries along an arbitrary piece of data
-- A formatter that carries along an arbitrary piece of data
data
Formatter
=
Formatter
{
data
Formatter
=
Formatter
{
header
::
IO
()
,
header
::
IO
()
,
onResult
::
CheckResult
->
S
tring
->
IO
()
,
onResult
::
CheckResult
->
S
ystemInterface
IO
->
IO
()
,
onFailure
::
FilePath
->
ErrorMessage
->
IO
()
,
onFailure
::
FilePath
->
ErrorMessage
->
IO
()
,
footer
::
IO
()
footer
::
IO
()
}
}
sourceFile
(
PositionedComment
pos
_
_
)
=
posFile
pos
lineNo
(
PositionedComment
pos
_
_
)
=
posLine
pos
lineNo
(
PositionedComment
pos
_
_
)
=
posLine
pos
endLineNo
(
PositionedComment
_
end
_
)
=
posLine
end
endLineNo
(
PositionedComment
_
end
_
)
=
posLine
end
colNo
(
PositionedComment
pos
_
_
)
=
posColumn
pos
colNo
(
PositionedComment
pos
_
_
)
=
posColumn
pos
...
...
ShellCheck/Formatter/GCC.hs
浏览文件 @
8dd40efb
...
@@ -31,14 +31,25 @@ format = return Formatter {
...
@@ -31,14 +31,25 @@ format = return Formatter {
header
=
return
()
,
header
=
return
()
,
footer
=
return
()
,
footer
=
return
()
,
onFailure
=
outputError
,
onFailure
=
outputError
,
onResult
=
output
Result
onResult
=
output
All
}
}
outputError
file
error
=
hPutStrLn
stderr
$
file
++
": "
++
error
outputError
file
error
=
hPutStrLn
stderr
$
file
++
": "
++
error
outputResult
result
contents
=
do
outputAll
cr
sys
=
mapM_
f
groups
let
comments
=
makeNonVirtual
(
crComments
result
)
contents
where
mapM_
(
putStrLn
.
formatComment
(
crFilename
result
))
comments
comments
=
crComments
cr
groups
=
groupWith
sourceFile
comments
f
::
[
PositionedComment
]
->
IO
()
f
group
=
do
let
filename
=
sourceFile
(
head
group
)
result
<-
(
siReadFile
sys
)
filename
let
contents
=
either
(
const
""
)
id
result
outputResult
filename
contents
group
outputResult
filename
contents
warnings
=
do
let
comments
=
makeNonVirtual
warnings
contents
mapM_
(
putStrLn
.
formatComment
filename
)
comments
formatComment
filename
c
=
concat
[
formatComment
filename
c
=
concat
[
filename
,
":"
,
filename
,
":"
,
...
...
ShellCheck/Formatter/TTY.hs
浏览文件 @
8dd40efb
...
@@ -43,15 +43,22 @@ colorForLevel level =
...
@@ -43,15 +43,22 @@ colorForLevel level =
"style"
->
32
-- green
"style"
->
32
-- green
"message"
->
1
-- bold
"message"
->
1
-- bold
"source"
->
0
-- none
"source"
->
0
-- none
otherwise
->
0
-- none
_
->
0
-- none
outputError
options
file
error
=
do
outputError
options
file
error
=
do
color
<-
getColorFunc
$
foColorOption
options
color
<-
getColorFunc
$
foColorOption
options
hPutStrLn
stderr
$
color
"error"
$
file
++
": "
++
error
hPutStrLn
stderr
$
color
"error"
$
file
++
": "
++
error
outputResult
options
result
content
s
=
do
outputResult
options
result
sy
s
=
do
color
<-
getColorFunc
$
foColorOption
options
color
<-
getColorFunc
$
foColorOption
options
let
comments
=
crComments
result
let
comments
=
crComments
result
let
fileGroups
=
groupWith
sourceFile
comments
mapM_
(
outputForFile
color
sys
)
fileGroups
outputForFile
color
sys
comments
=
do
let
fileName
=
sourceFile
(
head
comments
)
result
<-
(
siReadFile
sys
)
fileName
let
contents
=
either
(
const
""
)
id
result
let
fileLines
=
lines
contents
let
fileLines
=
lines
contents
let
lineCount
=
fromIntegral
$
length
fileLines
let
lineCount
=
fromIntegral
$
length
fileLines
let
groups
=
groupWith
lineNo
comments
let
groups
=
groupWith
lineNo
comments
...
@@ -62,7 +69,7 @@ outputResult options result contents = do
...
@@ -62,7 +69,7 @@ outputResult options result contents = do
else
fileLines
!!
fromIntegral
(
lineNum
-
1
)
else
fileLines
!!
fromIntegral
(
lineNum
-
1
)
putStrLn
""
putStrLn
""
putStrLn
$
color
"message"
$
putStrLn
$
color
"message"
$
"In "
++
crFilename
result
++
" line "
++
show
lineNum
++
":"
"In "
++
fileName
++
" line "
++
show
lineNum
++
":"
putStrLn
(
color
"source"
line
)
putStrLn
(
color
"source"
line
)
mapM_
(
\
c
->
putStrLn
(
color
(
severityText
c
)
$
cuteIndent
c
))
x
mapM_
(
\
c
->
putStrLn
(
color
(
severityText
c
)
$
cuteIndent
c
))
x
putStrLn
""
putStrLn
""
...
...
ShellCheck/Interface.hs
浏览文件 @
8dd40efb
...
@@ -33,6 +33,7 @@ newtype SystemInterface m = SystemInterface {
...
@@ -33,6 +33,7 @@ newtype SystemInterface m = SystemInterface {
data
CheckSpec
=
CheckSpec
{
data
CheckSpec
=
CheckSpec
{
csFilename
::
String
,
csFilename
::
String
,
csScript
::
String
,
csScript
::
String
,
csCheckSourced
::
Bool
,
csExcludedWarnings
::
[
Integer
],
csExcludedWarnings
::
[
Integer
],
csShellTypeOverride
::
Maybe
Shell
csShellTypeOverride
::
Maybe
Shell
}
deriving
(
Show
,
Eq
)
}
deriving
(
Show
,
Eq
)
...
@@ -46,6 +47,7 @@ emptyCheckSpec :: CheckSpec
...
@@ -46,6 +47,7 @@ emptyCheckSpec :: CheckSpec
emptyCheckSpec
=
CheckSpec
{
emptyCheckSpec
=
CheckSpec
{
csFilename
=
""
,
csFilename
=
""
,
csScript
=
""
,
csScript
=
""
,
csCheckSourced
=
False
,
csExcludedWarnings
=
[]
,
csExcludedWarnings
=
[]
,
csShellTypeOverride
=
Nothing
csShellTypeOverride
=
Nothing
}
}
...
@@ -53,7 +55,8 @@ emptyCheckSpec = CheckSpec {
...
@@ -53,7 +55,8 @@ emptyCheckSpec = CheckSpec {
-- Parser input and output
-- Parser input and output
data
ParseSpec
=
ParseSpec
{
data
ParseSpec
=
ParseSpec
{
psFilename
::
String
,
psFilename
::
String
,
psScript
::
String
psScript
::
String
,
psCheckSourced
::
Bool
}
deriving
(
Show
,
Eq
)
}
deriving
(
Show
,
Eq
)
data
ParseResult
=
ParseResult
{
data
ParseResult
=
ParseResult
{
...
@@ -66,7 +69,8 @@ data ParseResult = ParseResult {
...
@@ -66,7 +69,8 @@ data ParseResult = ParseResult {
data
AnalysisSpec
=
AnalysisSpec
{
data
AnalysisSpec
=
AnalysisSpec
{
asScript
::
Token
,
asScript
::
Token
,
asShellType
::
Maybe
Shell
,
asShellType
::
Maybe
Shell
,
asExecutionMode
::
ExecutionMode
asExecutionMode
::
ExecutionMode
,
asCheckSourced
::
Bool
}
}
newtype
AnalysisResult
=
AnalysisResult
{
newtype
AnalysisResult
=
AnalysisResult
{
...
...
ShellCheck/Parser.hs
浏览文件 @
8dd40efb
...
@@ -47,7 +47,7 @@ import qualified Data.Map as Map
...
@@ -47,7 +47,7 @@ import qualified Data.Map as Map
import
Test.QuickCheck.All
(
quickCheckAll
)
import
Test.QuickCheck.All
(
quickCheckAll
)
type
SCBase
m
=
Mr
.
ReaderT
(
SystemInterface
m
)
(
Ms
.
StateT
SystemState
m
)
type
SCBase
m
=
Mr
.
ReaderT
(
Environment
m
)
(
Ms
.
StateT
SystemState
m
)
type
SCParser
m
v
=
ParsecT
String
UserState
(
SCBase
m
)
v
type
SCParser
m
v
=
ParsecT
String
UserState
(
SCBase
m
)
v
backslash
::
Monad
m
=>
SCParser
m
Char
backslash
::
Monad
m
=>
SCParser
m
Char
...
@@ -248,12 +248,14 @@ addParseNote n = do
...
@@ -248,12 +248,14 @@ addParseNote n = do
shouldIgnoreCode
code
=
do
shouldIgnoreCode
code
=
do
context
<-
getCurrentContexts
context
<-
getCurrentContexts
return
$
any
disabling
context
checkSourced
<-
Mr
.
asks
checkSourced
return
$
any
(
disabling
checkSourced
)
context
where
where
disabling
(
ContextAnnotation
list
)
=
disabling
checkSourced
item
=
any
disabling'
list
case
item
of
disabling
(
ContextSource
_
)
=
True
-- Don't add messages for sourced files
ContextAnnotation
list
->
any
disabling'
list
disabling
_
=
False
ContextSource
_
->
not
$
checkSourced
_
->
False
disabling'
(
DisableComment
n
)
=
code
==
n
disabling'
(
DisableComment
n
)
=
code
==
n
disabling'
_
=
False
disabling'
_
=
False
...
@@ -297,6 +299,11 @@ initialSystemState = SystemState {
...
@@ -297,6 +299,11 @@ initialSystemState = SystemState {
parseProblems
=
[]
parseProblems
=
[]
}
}
data
Environment
m
=
Environment
{
systemInterface
::
SystemInterface
m
,
checkSourced
::
Bool
}
parseProblem
level
code
msg
=
do
parseProblem
level
code
msg
=
do
pos
<-
getPosition
pos
<-
getPosition
parseProblemAt
pos
level
code
msg
parseProblemAt
pos
level
code
msg
...
@@ -1879,7 +1886,7 @@ readSource pos t@(T_Redirecting _ _ (T_SimpleCommand _ _ (cmd:file:_))) = do
...
@@ -1879,7 +1886,7 @@ readSource pos t@(T_Redirecting _ _ (T_SimpleCommand _ _ (cmd:file:_))) = do
"This file appears to be recursively sourced. Ignoring."
"This file appears to be recursively sourced. Ignoring."
return
t
return
t
else
do
else
do
sys
<-
Mr
.
ask
sys
<-
Mr
.
ask
s
systemInterface
input
<-
input
<-
if
filename
==
"/dev/null"
-- always allow /dev/null
if
filename
==
"/dev/null"
-- always allow /dev/null
then
return
(
Right
""
)
then
return
(
Right
""
)
...
@@ -2788,16 +2795,22 @@ readScript = do
...
@@ -2788,16 +2795,22 @@ readScript = do
-- Interactively run a parser in ghci:
-- Interactively run a parser in ghci:
-- debugParse readScript "echo 'hello world'"
-- debugParse readScript "echo 'hello world'"
debugParse
p
string
=
runIdentity
$
do
debugParse
p
string
=
runIdentity
$
do
(
res
,
_
)
<-
runParser
(
mockedSystemInterface
[]
)
p
"-"
string
(
res
,
_
)
<-
runParser
testEnvironment
p
"-"
string
return
res
return
res
testEnvironment
=
Environment
{
systemInterface
=
(
mockedSystemInterface
[]
),
checkSourced
=
False
}
isOk
p
s
=
parsesCleanly
p
s
==
Just
True
-- The string parses with no warnings
isOk
p
s
=
parsesCleanly
p
s
==
Just
True
-- The string parses with no warnings
isWarning
p
s
=
parsesCleanly
p
s
==
Just
False
-- The string parses with warnings
isWarning
p
s
=
parsesCleanly
p
s
==
Just
False
-- The string parses with warnings
isNotOk
p
s
=
parsesCleanly
p
s
==
Nothing
-- The string does not parse
isNotOk
p
s
=
parsesCleanly
p
s
==
Nothing
-- The string does not parse
parsesCleanly
parser
string
=
runIdentity
$
do
parsesCleanly
parser
string
=
runIdentity
$
do
(
res
,
sys
)
<-
runParser
(
mockedSystemInterface
[]
)
(
res
,
sys
)
<-
runParser
testEnvironment
(
parser
>>
eof
>>
getState
)
"-"
string
(
parser
>>
eof
>>
getState
)
"-"
string
case
(
res
,
sys
)
of
case
(
res
,
sys
)
of
(
Right
userState
,
systemState
)
->
(
Right
userState
,
systemState
)
->
...
@@ -2842,22 +2855,22 @@ getStringFromParsec errors =
...
@@ -2842,22 +2855,22 @@ getStringFromParsec errors =
Message
s
->
if
null
s
then
Nothing
else
return
$
s
++
"."
Message
s
->
if
null
s
then
Nothing
else
return
$
s
++
"."
runParser
::
Monad
m
=>
runParser
::
Monad
m
=>
SystemInterface
m
->
Environment
m
->
SCParser
m
v
->
SCParser
m
v
->
String
->
String
->
String
->
String
->
m
(
Either
ParseError
v
,
SystemState
)
m
(
Either
ParseError
v
,
SystemState
)
runParser
sys
p
filename
contents
=
runParser
env
p
filename
contents
=
Ms
.
runStateT
Ms
.
runStateT
(
Mr
.
runReaderT
(
Mr
.
runReaderT
(
runParserT
p
initialUserState
filename
contents
)
(
runParserT
p
initialUserState
filename
contents
)
sys
)
env
)
initialSystemState
initialSystemState
system
=
lift
.
lift
.
lift
system
=
lift
.
lift
.
lift
parseShell
sys
name
contents
=
do
parseShell
env
name
contents
=
do
(
result
,
state
)
<-
runParser
sys
(
parseWithNotes
readScript
)
name
contents
(
result
,
state
)
<-
runParser
env
(
parseWithNotes
readScript
)
name
contents
case
result
of
case
result
of
Right
(
script
,
userstate
)
->
Right
(
script
,
userstate
)
->
return
ParseResult
{
return
ParseResult
{
...
@@ -2943,7 +2956,12 @@ posToPos sp = Position {
...
@@ -2943,7 +2956,12 @@ posToPos sp = Position {
parseScript
::
Monad
m
=>
parseScript
::
Monad
m
=>
SystemInterface
m
->
ParseSpec
->
m
ParseResult
SystemInterface
m
->
ParseSpec
->
m
ParseResult
parseScript
sys
spec
=
parseScript
sys
spec
=
parseShell
sys
(
psFilename
spec
)
(
psScript
spec
)
parseShell
env
(
psFilename
spec
)
(
psScript
spec
)
where
env
=
Environment
{
systemInterface
=
sys
,
checkSourced
=
psCheckSourced
spec
}
return
[]
return
[]
...
...
shellcheck.1.md
浏览文件 @
8dd40efb
...
@@ -32,6 +32,12 @@ not warn at all, as `ksh` supports decimals in arithmetic contexts.
...
@@ -32,6 +32,12 @@ not warn at all, as `ksh` supports decimals in arithmetic contexts.
# OPTIONS
# OPTIONS
**-a**
,
\
**--check-sourced**
: Emit warnings in sourced files. Normally,
`shellcheck`
will only warn
about issues in the specified files. With this option, any issues in
sourced files files will also be reported.
**-C**
[
*WHEN*
],
\
**--color**
[=
*WHEN*
]
**-C**
[
*WHEN*
],
\
**--color**
[=
*WHEN*
]
: For TTY output, enable colors
*always*
,
*never*
or
*auto*
. The default
: For TTY output, enable colors
*always*
,
*never*
or
*auto*
. The default
...
@@ -67,6 +73,7 @@ not warn at all, as `ksh` supports decimals in arithmetic contexts.
...
@@ -67,6 +73,7 @@ not warn at all, as `ksh` supports decimals in arithmetic contexts.
line (plus
`/dev/null`
). This option allows following any file the script
line (plus
`/dev/null`
). This option allows following any file the script
may
`source`
.
may
`source`
.
# FORMATS
# FORMATS
**tty**
**tty**
...
...
shellcheck.hs
浏览文件 @
8dd40efb
...
@@ -33,8 +33,9 @@ import Control.Monad
...
@@ -33,8 +33,9 @@ import Control.Monad
import
Control.Monad.Except
import
Control.Monad.Except
import
Data.Bits
import
Data.Bits
import
Data.Char
import
Data.Char
import
Data.Functor
import
Data.Either
import
Data.Either
import
Data.Functor
import
Data.IORef
import
Data.List
import
Data.List
import
qualified
Data.Map
as
Map
import
qualified
Data.Map
as
Map
import
Data.Maybe
import
Data.Maybe
...
@@ -75,21 +76,23 @@ defaultOptions = Options {
...
@@ -75,21 +76,23 @@ defaultOptions = Options {
usageHeader
=
"Usage: shellcheck [OPTIONS...] FILES..."
usageHeader
=
"Usage: shellcheck [OPTIONS...] FILES..."
options
=
[
options
=
[
Option
"e"
[
"exclude"
]
Option
"a"
[
"check-sourced"
]
(
ReqArg
(
Flag
"exclude"
)
"CODE1,CODE2.."
)
"exclude types of warnings"
,
(
NoArg
$
Flag
"sourced"
"false"
)
"Include warnings from sourced files"
,
Option
"f"
[
"format"
]
(
ReqArg
(
Flag
"format"
)
"FORMAT"
)
$
"output format ("
++
formatList
++
")"
,
Option
"C"
[
"color"
]
Option
"C"
[
"color"
]
(
OptArg
(
maybe
(
Flag
"color"
"always"
)
(
Flag
"color"
))
"WHEN"
)
(
OptArg
(
maybe
(
Flag
"color"
"always"
)
(
Flag
"color"
))
"WHEN"
)
"Use color (auto, always, never)"
,
"Use color (auto, always, never)"
,
Option
"e"
[
"exclude"
]
(
ReqArg
(
Flag
"exclude"
)
"CODE1,CODE2.."
)
"Exclude types of warnings"
,
Option
"f"
[
"format"
]
(
ReqArg
(
Flag
"format"
)
"FORMAT"
)
$
"Output format ("
++
formatList
++
")"
,
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)"
,
Option
"x"
[
"external-sources"
]
(
NoArg
$
Flag
"externals"
"true"
)
"Allow 'source' outside of FILES."
,
Option
"V"
[
"version"
]
Option
"V"
[
"version"
]
(
NoArg
$
Flag
"version"
"true"
)
"Print version information"
(
NoArg
$
Flag
"version"
"true"
)
"Print version information"
,
Option
"x"
[
"external-sources"
]
(
NoArg
$
Flag
"externals"
"true"
)
"Allow 'source' outside of FILES"
]
]
printErr
=
lift
.
hPutStrLn
stderr
printErr
=
lift
.
hPutStrLn
stderr
...
@@ -136,7 +139,7 @@ getExclusions options =
...
@@ -136,7 +139,7 @@ getExclusions options =
in
in
map
(
Prelude
.
read
.
clean
)
elements
::
[
Int
]
map
(
Prelude
.
read
.
clean
)
elements
::
[
Int
]
toStatus
=
liftM
(
either
id
id
)
.
runExceptT
toStatus
=
fmap
(
either
id
id
)
.
runExceptT
getEnvArgs
=
do
getEnvArgs
=
do
opts
<-
getEnv
"SHELLCHECK_OPTS"
`
catch
`
cantWaitForLookupEnv
opts
<-
getEnv
"SHELLCHECK_OPTS"
`
catch
`
cantWaitForLookupEnv
...
@@ -193,19 +196,23 @@ runFormatter sys format options files = do
...
@@ -193,19 +196,23 @@ runFormatter sys format options files = do
newStatus
<-
process
file
`
catch
`
handler
file
newStatus
<-
process
file
`
catch
`
handler
file
return
$
status
`
mappend
`
newStatus
return
$
status
`
mappend
`
newStatus
handler
::
FilePath
->
IOException
->
IO
Status
handler
::
FilePath
->
IOException
->
IO
Status
handler
file
e
=
do
handler
file
e
=
reportFailure
file
(
show
e
)
onFailure
format
file
(
show
e
)
reportFailure
file
str
=
do
onFailure
format
file
str
return
RuntimeException
return
RuntimeException
process
::
FilePath
->
IO
Status
process
::
FilePath
->
IO
Status
process
filename
=
do
process
filename
=
do
contents
<-
inputFile
filename
input
<-
(
siReadFile
sys
)
filename
either
(
reportFailure
filename
)
check
input
where
check
contents
=
do
let
checkspec
=
(
checkSpec
options
)
{
let
checkspec
=
(
checkSpec
options
)
{
csFilename
=
filename
,
csFilename
=
filename
,
csScript
=
contents
csScript
=
contents
}
}
result
<-
checkScript
sys
checkspec
result
<-
checkScript
sys
checkspec
onResult
format
result
content
s
onResult
format
result
sy
s
return
$
return
$
if
null
(
crComments
result
)
if
null
(
crComments
result
)
then
NoProblems
then
NoProblems
...
@@ -254,6 +261,13 @@ parseOption flag options =
...
@@ -254,6 +261,13 @@ parseOption flag options =
}
}
}
}
Flag
"sourced"
_
->
return
options
{
checkSpec
=
(
checkSpec
options
)
{
csCheckSourced
=
True
}
}
_
->
return
options
_
->
return
options
where
where
die
s
=
do
die
s
=
do
...
@@ -268,14 +282,28 @@ parseOption flag options =
...
@@ -268,14 +282,28 @@ parseOption flag options =
ioInterface
options
files
=
do
ioInterface
options
files
=
do
inputs
<-
mapM
normalize
files
inputs
<-
mapM
normalize
files
cache
<-
newIORef
emptyCache
return
SystemInterface
{
return
SystemInterface
{
siReadFile
=
get
inputs
siReadFile
=
get
cache
inputs
}
}
where
where
get
inputs
file
=
do
emptyCache
::
Map
.
Map
FilePath
String
emptyCache
=
Map
.
empty
get
cache
inputs
file
=
do
map
<-
readIORef
cache
case
Map
.
lookup
file
map
of
Just
x
->
return
$
Right
x
Nothing
->
fetch
cache
inputs
file
fetch
cache
inputs
file
=
do
ok
<-
allowable
inputs
file
ok
<-
allowable
inputs
file
if
ok
if
ok
then
(
Right
<$>
inputFile
file
)
`
catch
`
handler
then
(
do
(
contents
,
shouldCache
)
<-
inputFile
file
when
shouldCache
$
modifyIORef
cache
$
Map
.
insert
file
contents
return
$
Right
contents
)
`
catch
`
handler
else
return
$
Left
(
file
++
" was not specified as input (see shellcheck -x)."
)
else
return
$
Left
(
file
++
" was not specified as input (see shellcheck -x)."
)
where
where
...
@@ -296,16 +324,19 @@ ioInterface options files = do
...
@@ -296,16 +324,19 @@ ioInterface options files = do
fallback
path
_
=
return
path
fallback
path
_
=
return
path
inputFile
file
=
do
inputFile
file
=
do
handle
<-
(
handle
,
shouldCache
)
<-
if
file
==
"-"
if
file
==
"-"
then
return
stdin
then
return
(
stdin
,
True
)
else
openBinaryFile
file
ReadMode
else
do
h
<-
openBinaryFile
file
ReadMode
reopenable
<-
hIsSeekable
h
return
(
h
,
not
reopenable
)
hSetBinaryMode
handle
True
hSetBinaryMode
handle
True
contents
<-
decodeString
<$>
hGetContents
handle
-- closes handle
contents
<-
decodeString
<$>
hGetContents
handle
-- closes handle
seq
(
length
contents
)
$
seq
(
length
contents
)
$
return
contents
return
(
contents
,
shouldCache
)
-- Decode a char8 string into a utf8 string, with fallback on
-- Decode a char8 string into a utf8 string, with fallback on
-- ISO-8859-1. This avoids depending on additional libraries.
-- ISO-8859-1. This avoids depending on additional libraries.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录