1 Commits

Author SHA1 Message Date
Vidar Holen
4f5dc7094b ppc64le build producing 50MB executables 2021-02-23 18:28:56 -08:00
22 changed files with 108 additions and 103 deletions

View File

@@ -1,4 +1,4 @@
name: Build ShellCheck name: Build Lol
# Run this workflow every time a new commit pushed to your repository # Run this workflow every time a new commit pushed to your repository
on: push on: push
@@ -21,7 +21,7 @@ jobs:
run: | run: |
mkdir source mkdir source
cabal sdist cabal sdist
mv dist-newstyle/sdist/*.tar.gz source/source.tar.gz mv dist/*.tar.gz source/source.tar.gz
- name: Deduce tags - name: Deduce tags
run: | run: |

View File

@@ -1,14 +1,13 @@
## v0.7.2 - 2021-04-19 ## Git
### Added ### Added
- `disable` directives can now be a range, e.g. `disable=SC3000-SC4000` - `disable` directives can now be a range, e.g. `disable=SC3000-SC4000`
- SC1143: Warn about line continuations in comments
- SC2259/SC2260: Warn when redirections override pipes - SC2259/SC2260: Warn when redirections override pipes
- SC2261: Warn about multiple competing redirections - SC2261: Warn about multiple competing redirections
- SC2262/SC2263: Warn about aliases declared and used in the same parsing unit - SC2262/SC2263: Warn about aliases declared and used in the same parsing unit
- SC2264: Warn about wrapper functions that blatantly recurse - SC2264: Warn about wrapper functions that blatantly recurse
- SC2265/SC2266: Warn when using & or | with test statements - SC2265/SC2266: Warn when using & or | with test statements
- SC2267: Warn when using xargs -i instead of -I - SC2267: Warn when using xargs -i instead of -I
- SC2268: Warn about unnecessary x-comparisons like `[ x$var = xval ]` - Optional avoid-x-comparisons: Style warning SC2268 for `[ x$var = xval ]`
### Fixed ### Fixed
- SC1072/SC1073 now respond to disable annotations, though ignoring parse errors - SC1072/SC1073 now respond to disable annotations, though ignoring parse errors
@@ -22,7 +21,7 @@
- POSIX/dash unsupported feature warnings now have individual SC3xxx codes - POSIX/dash unsupported feature warnings now have individual SC3xxx codes
- SC1090: A leading `$x/` or `$(x)/` is now treated as `./` when locating files - SC1090: A leading `$x/` or `$(x)/` is now treated as `./` when locating files
- SC2154: Variables appearing in -z/-n tests are no longer considered unassigned - SC2154: Variables appearing in -z/-n tests are no longer considered unassigned
- SC2270-SC2285: Improved warnings about misused `=`, e.g. `${var}=42` - SC2270-SC2285: Improved warnings about misused =, e.g. `${var}=42`
## v0.7.1 - 2020-04-04 ## v0.7.1 - 2020-04-04
@@ -165,7 +164,7 @@
- SC2204/SC2205: Warn about `( -z foo )` and `( foo -eq bar )` - SC2204/SC2205: Warn about `( -z foo )` and `( foo -eq bar )`
- SC2200/SC2201: Warn about brace expansion in [/[[ - SC2200/SC2201: Warn about brace expansion in [/[[
- SC2198/SC2199: Warn about arrays in [/[[ - SC2198/SC2199: Warn about arrays in [/[[
- SC2196/SC2197: Warn about deprecated egrep/fgrep - SC2196/SC2197: Warn about deprected egrep/fgrep
- SC2195: Warn about unmatchable case branches - SC2195: Warn about unmatchable case branches
- SC2194: Warn about constant 'case' statements - SC2194: Warn about constant 'case' statements
- SC2193: Warn about `[[ file.png == *.mp3 ]]` and other unmatchables - SC2193: Warn about `[[ file.png == *.mp3 ]]` and other unmatchables
@@ -182,7 +181,7 @@
### Fixed ### Fixed
- `-c` no longer suggested when using `grep -o | wc` - `-c` no longer suggested when using `grep -o | wc`
- Comments and whitespace are now allowed before filewide directives - Comments and whitespace are now allowed before filewide directives
- Here doc delimiters with esoteric quoting like `foo""` are now handled - Here doc delimters with esoteric quoting like `foo""` are now handled
- SC2095 about `ssh` in while read loops is now suppressed when using `-n` - SC2095 about `ssh` in while read loops is now suppressed when using `-n`
- `%(%Y%M%D)T` now recognized as a single formatter in `printf` checks - `%(%Y%M%D)T` now recognized as a single formatter in `printf` checks
- `grep -F` now suppresses regex related suggestions - `grep -F` now suppresses regex related suggestions

View File

@@ -1,5 +1,5 @@
Name: ShellCheck Name: ShellCheck
Version: 0.7.2 Version: 0.7.1
Synopsis: Shell script analysis tool Synopsis: Shell script analysis tool
License: GPL-3 License: GPL-3
License-file: LICENSE License-file: LICENSE

View File

@@ -22,7 +22,7 @@ RUN curl -L "https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-in
ENV CABALOPTS "--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg" ENV CABALOPTS "--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg"
# Prebuild the dependencies # Prebuild the dependencies
RUN cabal update && IFS=';' && cabal install --dependencies-only $CABALOPTS ShellCheck RUN cabal update && IFS=';' && cabal install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
# Copy the build script # Copy the build script
COPY build /usr/bin COPY build /usr/bin

View File

@@ -2,7 +2,7 @@
set -xe set -xe
{ {
tar xzv --strip-components=1 tar xzv --strip-components=1
chmod +x striptests && ./striptests ./striptests
mkdir "$TARGETNAME" mkdir "$TARGETNAME"
cabal update cabal update
( IFS=';'; cabal build $CABALOPTS ) ( IFS=';'; cabal build $CABALOPTS )

View File

@@ -21,7 +21,7 @@ RUN curl -L "https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-in
ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections;--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg" ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections;--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg"
# Prebuild the dependencies # Prebuild the dependencies
RUN cabal update && IFS=';' && cabal install --dependencies-only $CABALOPTS ShellCheck RUN cabal update && IFS=';' && cabal install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
# Copy the build script # Copy the build script
COPY build /usr/bin COPY build /usr/bin

View File

@@ -2,7 +2,7 @@
set -xe set -xe
{ {
tar xzv --strip-components=1 tar xzv --strip-components=1
chmod +x striptests && ./striptests ./striptests
mkdir "$TARGETNAME" mkdir "$TARGETNAME"
cabal update cabal update
( IFS=';'; cabal build $CABALOPTS --enable-executable-static ) ( IFS=';'; cabal build $CABALOPTS --enable-executable-static )

View File

@@ -51,7 +51,7 @@ RUN pirun apt-get install -y ghc cabal-install
# Finally we can build the current dependencies. This takes hours. # Finally we can build the current dependencies. This takes hours.
ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections;--gcc-options;-Os -Wl,--gc-sections -ffunction-sections -fdata-sections" ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections;--gcc-options;-Os -Wl,--gc-sections -ffunction-sections -fdata-sections"
RUN pirun cabal update RUN pirun cabal update
RUN IFS=";" && pirun cabal install --dependencies-only $CABALOPTS ShellCheck RUN IFS=";" && pirun cabal install --lib $CABALOPTS Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.1.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.1 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.4 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.6.0
# Copy the build script # Copy the build script
WORKDIR /pi/scratch WORKDIR /pi/scratch

View File

@@ -3,7 +3,7 @@ set -xe
cd /scratch cd /scratch
{ {
tar xzv --strip-components=1 tar xzv --strip-components=1
chmod +x striptests && ./striptests ./striptests
mkdir "$TARGETNAME" mkdir "$TARGETNAME"
# This script does not cabal update because compiling anything new is slow # This script does not cabal update because compiling anything new is slow
( IFS=';'; cabal build $CABALOPTS --enable-executable-static ) ( IFS=';'; cabal build $CABALOPTS --enable-executable-static )

View File

@@ -0,0 +1,30 @@
FROM ubuntu:20.04
ENV TARGET powerpc64le-linux-gnu
ENV TARGETNAME linux.ppc64le
# Build dependencies
USER root
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y ghc automake autoconf build-essential llvm curl qemu-user-static gcc-$TARGET
# Build GHC
WORKDIR /ghc
RUN curl -L "https://downloads.haskell.org/~ghc/8.10.4/ghc-8.10.4-src.tar.xz" | tar xJ --strip-components=1
RUN ./boot && ./configure --host x86_64-linux-gnu --build x86_64-linux-gnu --target "$TARGET" --enable-unregisterised
RUN cp mk/flavours/quick-cross.mk mk/build.mk && make -j "$(nproc)"
RUN make install
RUN curl -L "https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz" | tar xJv -C /usr/local/bin
# Due to an apparent cabal bug, we specify our options directly to cabal
# It won't reuse caches if ghc-options are specified in ~/.cabal/config
ENV CABALOPTS "--ghc-options;-optl-Wl,-fuse-ld=bfd -split-sections -optc-Os -optc-Wl,--gc-sections;--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg"
# Prebuild the dependencies
#RUN cabal update && IFS=';' && cabal install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
# Copy the build script
COPY build /usr/bin
WORKDIR /scratch
ENTRYPOINT ["/usr/bin/build"]

15
build/linux.ppc64le/build Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
set -xe
{
tar xzv --strip-components=1
./striptests
mkdir "$TARGETNAME"
cabal update
( IFS=';'; cabal build $CABALOPTS --enable-executable-static )
find . -name shellcheck -type f -exec mv {} "$TARGETNAME/" \;
ls -l "$TARGETNAME"
"$TARGET-strip" -s "$TARGETNAME/shellcheck"
ls -l "$TARGETNAME"
qemu-ppc64le-static "$TARGETNAME/shellcheck" --version
} >&2
tar czv "$TARGETNAME"

1
build/linux.ppc64le/tag Normal file
View File

@@ -0,0 +1 @@
koalaman/scbuilder-linux-ppc64le

View File

@@ -2,7 +2,7 @@
set -xe set -xe
{ {
tar xzv --strip-components=1 tar xzv --strip-components=1
chmod +x striptests && ./striptests ./striptests
mkdir "$TARGETNAME" mkdir "$TARGETNAME"
cabal update cabal update
( IFS=';'; cabal build $CABALOPTS --enable-executable-static ) ( IFS=';'; cabal build $CABALOPTS --enable-executable-static )

View File

@@ -5,7 +5,7 @@ ENV TARGETNAME windows.x86_64
# We don't need wine32, even though it complains # We don't need wine32, even though it complains
USER root USER root
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y curl busybox wine winbind RUN apt-get update && apt-get install -y curl busybox wine
# Fetch Windows version, will be available under z:\haskell # Fetch Windows version, will be available under z:\haskell
WORKDIR /haskell WORKDIR /haskell
@@ -19,8 +19,8 @@ ENV WINEPATH /haskell/bin
# that necessitated this but I don't care enough to find out # that necessitated this but I don't care enough to find out
ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections" ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections"
# Precompile some deps to speed up later builds # Precompile some deps to speed up later builds. This list is just copied from `cabal build`
RUN wine /haskell/bin/cabal.exe update && IFS=';' && wine /haskell/bin/cabal.exe install --lib --dependencies-only $CABALOPTS ShellCheck RUN wine /haskell/bin/cabal.exe update && IFS=';' && wine /haskell/bin/cabal.exe install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
COPY build /usr/bin COPY build /usr/bin
WORKDIR /scratch WORKDIR /scratch

View File

@@ -6,7 +6,7 @@ cabal() {
set -xe set -xe
{ {
tar xzv --strip-components=1 tar xzv --strip-components=1
chmod +x striptests && ./striptests ./striptests
mkdir "$TARGETNAME" mkdir "$TARGETNAME"
cabal update cabal update
( IFS=';'; cabal build $CABALOPTS ) ( IFS=';'; cabal build $CABALOPTS )

View File

@@ -17,11 +17,9 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
-} -}
{-# LANGUAGE TemplateHaskell #-}
module ShellCheck.ASTLib where module ShellCheck.ASTLib where
import ShellCheck.AST import ShellCheck.AST
import ShellCheck.Regex
import Control.Monad.Writer import Control.Monad.Writer
import Control.Monad import Control.Monad
@@ -33,8 +31,6 @@ import Data.Maybe
import qualified Data.Map as Map import qualified Data.Map as Map
import Numeric (showHex) import Numeric (showHex)
import Test.QuickCheck
arguments (T_SimpleCommand _ _ (cmd:args)) = args arguments (T_SimpleCommand _ _ (cmd:args)) = args
-- Is this a type of loop? -- Is this a type of loop?
@@ -676,43 +672,3 @@ isAnnotationIgnoringCode code t =
where where
hasNum (DisableComment from to) = code >= from && code < to hasNum (DisableComment from to) = code >= from && code < to
hasNum _ = False hasNum _ = False
prop_executableFromShebang1 = executableFromShebang "/bin/sh" == "sh"
prop_executableFromShebang2 = executableFromShebang "/bin/bash" == "bash"
prop_executableFromShebang3 = executableFromShebang "/usr/bin/env ksh" == "ksh"
prop_executableFromShebang4 = executableFromShebang "/usr/bin/env -S foo=bar bash -x" == "bash"
prop_executableFromShebang5 = executableFromShebang "/usr/bin/env --split-string=bash -x" == "bash"
prop_executableFromShebang6 = executableFromShebang "/usr/bin/env --split-string=foo=bar bash -x" == "bash"
prop_executableFromShebang7 = executableFromShebang "/usr/bin/env --split-string bash -x" == "bash"
prop_executableFromShebang8 = executableFromShebang "/usr/bin/env --split-string foo=bar bash -x" == "bash"
prop_executableFromShebang9 = executableFromShebang "/usr/bin/env foo=bar dash" == "dash"
prop_executableFromShebang10 = executableFromShebang "/bin/busybox sh" == "ash"
prop_executableFromShebang11 = executableFromShebang "/bin/busybox ash" == "ash"
-- Get the shell executable from a string like '/usr/bin/env bash'
executableFromShebang :: String -> String
executableFromShebang = shellFor
where
re = mkRegex "/env +(-S|--split-string=?)? *(.*)"
shellFor s | s `matches` re =
case matchRegex re s of
Just [flag, shell] -> fromEnvArgs (words shell)
_ -> ""
shellFor sb =
case words sb of
[] -> ""
[x] -> basename x
(first:second:args) | basename first == "busybox" ->
case basename second of
"sh" -> "ash" -- busybox sh is ash
x -> x
(first:args) | basename first == "env" ->
fromEnvArgs args
(first:_) -> basename first
fromEnvArgs args = fromMaybe "" $ find (notElem '=') $ skipFlags args
basename s = reverse . takeWhile (/= '/') . reverse $ s
skipFlags = dropWhile ("-" `isPrefixOf`)
return []
runTests = $quickCheckAll

View File

@@ -196,7 +196,6 @@ nodeChecks = [
,checkAssignToSelf ,checkAssignToSelf
,checkEqualsInCommand ,checkEqualsInCommand
,checkSecondArgIsComparison ,checkSecondArgIsComparison
,checkComparisonWithLeadingX
] ]
optionalChecks = map fst optionalTreeChecks optionalChecks = map fst optionalTreeChecks
@@ -244,6 +243,13 @@ optionalTreeChecks = [
cdPositive = "echo $VAR", cdPositive = "echo $VAR",
cdNegative = "VAR=hello; echo $VAR" cdNegative = "VAR=hello; echo $VAR"
}, checkUnassignedReferences' True) }, checkUnassignedReferences' True)
,(newCheckDescription {
cdName = "avoid-x-comparisons",
cdDescription = "Warn about 'x'-prefix in comparisons",
cdPositive = "[ \"x$var\" = xval ]",
cdNegative = "[ \"$var\" = val ]"
}, nodeChecksToTreeCheck [checkComparisonWithLeadingX])
] ]
optionalCheckMap :: Map.Map String (Parameters -> Token -> [TokenComment]) optionalCheckMap :: Map.Map String (Parameters -> Token -> [TokenComment])
@@ -584,12 +590,6 @@ prop_checkShebang9 = verifyNotTree checkShebang "# shellcheck shell=sh\ntrue"
prop_checkShebang10= verifyNotTree checkShebang "#!foo\n# shellcheck shell=sh ignore=SC2239\ntrue" prop_checkShebang10= verifyNotTree checkShebang "#!foo\n# shellcheck shell=sh ignore=SC2239\ntrue"
prop_checkShebang11= verifyTree checkShebang "#!/bin/sh/\ntrue" prop_checkShebang11= verifyTree checkShebang "#!/bin/sh/\ntrue"
prop_checkShebang12= verifyTree checkShebang "#!/bin/sh/ -xe\ntrue" prop_checkShebang12= verifyTree checkShebang "#!/bin/sh/ -xe\ntrue"
prop_checkShebang13= verifyTree checkShebang "#!/bin/busybox sh"
prop_checkShebang14= verifyNotTree checkShebang "#!/bin/busybox sh\n# shellcheck shell=sh\n"
prop_checkShebang15= verifyNotTree checkShebang "#!/bin/busybox sh\n# shellcheck shell=dash\n"
prop_checkShebang16= verifyTree checkShebang "#!/bin/busybox ash"
prop_checkShebang17= verifyNotTree checkShebang "#!/bin/busybox ash\n# shellcheck shell=dash\n"
prop_checkShebang18= verifyNotTree checkShebang "#!/bin/busybox ash\n# shellcheck shell=sh\n"
checkShebang params (T_Annotation _ list t) = checkShebang params (T_Annotation _ list t) =
if any isOverride list then [] else checkShebang params t if any isOverride list then [] else checkShebang params t
where where
@@ -1015,7 +1015,6 @@ checkSingleQuotedVariables params t@(T_SingleQuoted id s) =
,"alias" ,"alias"
,"sudo" -- covering "sudo sh" and such ,"sudo" -- covering "sudo sh" and such
,"docker" -- like above ,"docker" -- like above
,"podman"
,"dpkg-query" ,"dpkg-query"
,"jq" -- could also check that user provides --arg ,"jq" -- could also check that user provides --arg
,"rename" ,"rename"
@@ -1217,8 +1216,8 @@ checkQuotedCondRegex _ (TC_Binary _ _ "=~" _ rhs) =
where where
error t = error t =
unless (isConstantNonRe t) $ unless (isConstantNonRe t) $
warn (getId t) 2076 err (getId t) 2076
"Remove quotes from right-hand side of =~ to match as a regex rather than literally." "Don't quote right-hand side of =~, it'll match literally rather than as a regex."
re = mkRegex "[][*.+()|]" re = mkRegex "[][*.+()|]"
hasMetachars s = s `matches` re hasMetachars s = s `matches` re
isConstantNonRe t = fromMaybe False $ do isConstantNonRe t = fromMaybe False $ do
@@ -4000,7 +3999,7 @@ checkComparisonWithLeadingX params t =
check lhs rhs check lhs rhs
_ -> return () _ -> return ()
where where
msg = "Avoid x-prefix in comparisons as it no longer serves a purpose." msg = "Avoid outdated x-prefix in comparisons as it no longer serves a purpose."
check lhs rhs = sequence_ $ do check lhs rhs = sequence_ $ do
l <- fixLeadingX lhs l <- fixLeadingX lhs
r <- fixLeadingX rhs r <- fixLeadingX rhs

View File

@@ -240,8 +240,6 @@ prop_determineShell7 = determineShellTest "#! /bin/ash" == Dash
prop_determineShell8 = determineShellTest' (Just Ksh) "#!/bin/sh" == Sh prop_determineShell8 = determineShellTest' (Just Ksh) "#!/bin/sh" == Sh
prop_determineShell9 = determineShellTest "#!/bin/env -S dash -x" == Dash prop_determineShell9 = determineShellTest "#!/bin/env -S dash -x" == Dash
prop_determineShell10 = determineShellTest "#!/bin/env --split-string= dash -x" == Dash prop_determineShell10 = determineShellTest "#!/bin/env --split-string= dash -x" == Dash
prop_determineShell11 = determineShellTest "#!/bin/busybox sh" == Dash -- busybox sh is a specific shell, not posix sh
prop_determineShell12 = determineShellTest "#!/bin/busybox ash" == Dash
determineShellTest = determineShellTest' Nothing determineShellTest = determineShellTest' Nothing
determineShellTest' fallbackShell = determineShell fallbackShell . fromJust . prRoot . pScript determineShellTest' fallbackShell = determineShell fallbackShell . fromJust . prRoot . pScript
@@ -255,6 +253,19 @@ determineShell fallbackShell t = fromMaybe Bash $
headOrDefault (fromShebang s) [s | ShellOverride s <- annotations] headOrDefault (fromShebang s) [s | ShellOverride s <- annotations]
fromShebang (T_Script _ (T_Literal _ s) _) = executableFromShebang s fromShebang (T_Script _ (T_Literal _ s) _) = executableFromShebang s
-- Given a string like "/bin/bash" or "/usr/bin/env dash",
-- return the shell basename like "bash" or "dash"
executableFromShebang :: String -> String
executableFromShebang = shellFor
where
shellFor s | "/env " `isInfixOf` s = case matchRegex re s of
Just [flag, shell] -> shell
_ -> ""
shellFor s | ' ' `elem` s = shellFor $ takeWhile (/= ' ') s
shellFor s = reverse . takeWhile (/= '/') . reverse $ s
re = mkRegex "/env +(-S|--split-string=?)? *([^ ]*)"
-- Given a root node, make a map from Id to parent Token. -- Given a root node, make a map from Id to parent Token.
-- This is used to populate parentMap in Parameters -- This is used to populate parentMap in Parameters
getParentTree :: Token -> Map.Map Id Token getParentTree :: Token -> Map.Map Id Token

View File

@@ -1056,7 +1056,7 @@ checkFindRedirections = CommandCheck (Basename "find") f
prop_checkWhich = verify checkWhich "which '.+'" prop_checkWhich = verify checkWhich "which '.+'"
checkWhich = CommandCheck (Basename "which") $ checkWhich = CommandCheck (Basename "which") $
\t -> info (getId $ getCommandTokenOrThis t) 2230 "'which' is non-standard. Use builtin 'command -v' instead." \t -> info (getId $ getCommandTokenOrThis t) 2230 "which is non-standard. Use builtin 'command -v' instead."
prop_checkSudoRedirect1 = verify checkSudoRedirect "sudo echo 3 > /proc/file" prop_checkSudoRedirect1 = verify checkSudoRedirect "sudo echo 3 > /proc/file"
prop_checkSudoRedirect2 = verify checkSudoRedirect "sudo cmd < input" prop_checkSudoRedirect2 = verify checkSudoRedirect "sudo cmd < input"

View File

@@ -73,15 +73,15 @@ 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),
-- | Given: -- Given:
-- the current script, -- the current script,
-- a list of source-path annotations in effect, -- a list of source-path annotations in effect,
-- and a sourced file, -- and a sourced file,
-- find the sourced file -- find the sourced file
siFindSource :: String -> [String] -> String -> m FilePath, siFindSource :: String -> [String] -> 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))
} }

View File

@@ -24,7 +24,7 @@
module ShellCheck.Parser (parseScript, runTests) where module ShellCheck.Parser (parseScript, runTests) where
import ShellCheck.AST import ShellCheck.AST
import ShellCheck.ASTLib hiding (runTests) import ShellCheck.ASTLib
import ShellCheck.Data import ShellCheck.Data
import ShellCheck.Interface import ShellCheck.Interface
@@ -87,23 +87,11 @@ extglobStart = oneOf extglobStartChars
unicodeDoubleQuotes = "\x201C\x201D\x2033\x2036" unicodeDoubleQuotes = "\x201C\x201D\x2033\x2036"
unicodeSingleQuotes = "\x2018\x2019" unicodeSingleQuotes = "\x2018\x2019"
prop_spacing1 = isOk spacing " \\\n # Comment" prop_spacing = isOk spacing " \\\n # Comment"
prop_spacing2 = isOk spacing "# We can continue lines with \\"
prop_spacing3 = isWarning spacing " \\\n # --verbose=true \\"
spacing = do spacing = do
x <- many (many1 linewhitespace <|> continuation) x <- many (many1 linewhitespace <|> try (string "\\\n" >> return ""))
optional readComment optional readComment
return $ concat x return $ concat x
where
continuation = do
try (string "\\\n")
-- The line was continued. Warn if this next line is a comment with a trailing \
whitespace <- many linewhitespace
optional $ do
x <- readComment
when ("\\" `isSuffixOf` x) $
parseProblem ErrorC 1143 "This backslash is part of a comment and does not continue the line."
return whitespace
spacing1 = do spacing1 = do
spacing <- spacing spacing <- spacing
@@ -1051,7 +1039,6 @@ readComment = do
unexpecting "shellcheck annotation" readAnnotationPrefix unexpecting "shellcheck annotation" readAnnotationPrefix
readAnyComment readAnyComment
prop_readAnyComment = isOk readAnyComment "# Comment"
readAnyComment = do readAnyComment = do
char '#' char '#'
many $ noneOf "\r\n" many $ noneOf "\r\n"
@@ -1417,8 +1404,6 @@ readNormalEscaped = called "escaped char" $ do
do do
next <- quotable <|> oneOf "?*@!+[]{}.,~#" next <- quotable <|> oneOf "?*@!+[]{}.,~#"
when (next == ' ') $ checkTrailingSpaces pos <|> return () when (next == ' ') $ checkTrailingSpaces pos <|> return ()
-- Check if this line is followed by a commented line with a trailing backslash
when (next == '\n') $ try . lookAhead $ void spacing
return $ if next == '\n' then "" else [next] return $ if next == '\n' then "" else [next]
<|> <|>
do do
@@ -3231,8 +3216,8 @@ readScriptFile sourced = do
let ignoreShebang = shellAnnotationSpecified || shellFlagSpecified let ignoreShebang = shellAnnotationSpecified || shellFlagSpecified
unless ignoreShebang $ unless ignoreShebang $
verifyShebang pos (executableFromShebang shebangString) verifyShebang pos (getShell shebangString)
if ignoreShebang || isValidShell (executableFromShebang shebangString) /= Just False if ignoreShebang || isValidShell (getShell shebangString) /= Just False
then do then do
commands <- withAnnotations annotations readCompoundListOrEmpty commands <- withAnnotations annotations readCompoundListOrEmpty
id <- endSpan start id <- endSpan start
@@ -3246,6 +3231,17 @@ readScriptFile sourced = do
return $ T_Script id shebang [] return $ T_Script id shebang []
where where
basename s = reverse . takeWhile (/= '/') . reverse $ s
skipFlags = dropWhile ("-" `isPrefixOf`)
getShell sb =
case words sb of
[] -> ""
[x] -> basename x
(first:args) ->
if basename first == "env"
then fromMaybe "" $ find (notElem '=') $ skipFlags args
else basename first
verifyShebang pos s = do verifyShebang pos s = do
case isValidShell s of case isValidShell s of
Just True -> return () Just True -> return ()

View File

@@ -4,7 +4,6 @@ import Control.Monad
import System.Exit import System.Exit
import qualified ShellCheck.Analytics import qualified ShellCheck.Analytics
import qualified ShellCheck.AnalyzerLib import qualified ShellCheck.AnalyzerLib
import qualified ShellCheck.ASTLib
import qualified ShellCheck.Checker import qualified ShellCheck.Checker
import qualified ShellCheck.Checks.Commands import qualified ShellCheck.Checks.Commands
import qualified ShellCheck.Checks.Custom import qualified ShellCheck.Checks.Custom
@@ -18,7 +17,6 @@ main = do
results <- sequence [ results <- sequence [
ShellCheck.Analytics.runTests ShellCheck.Analytics.runTests
,ShellCheck.AnalyzerLib.runTests ,ShellCheck.AnalyzerLib.runTests
,ShellCheck.ASTLib.runTests
,ShellCheck.Checker.runTests ,ShellCheck.Checker.runTests
,ShellCheck.Checks.Commands.runTests ,ShellCheck.Checks.Commands.runTests
,ShellCheck.Checks.Custom.runTests ,ShellCheck.Checks.Custom.runTests