diff --git a/CHANGELOG.md b/CHANGELOG.md index cef16f4..c363eb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ based on control flow rather than just syntax. Existing checks will gradually start using it, which may cause them to trigger differently (but more accurately). +- Values in directives/shellcheckrc can now be quoted with '' or "" ## v0.8.0 - 2021-11-06 diff --git a/shellcheck.1.md b/shellcheck.1.md index 146d791..c345a2b 100644 --- a/shellcheck.1.md +++ b/shellcheck.1.md @@ -282,6 +282,9 @@ Here is an example `.shellcheckrc`: source-path=SCRIPTDIR source-path=/mnt/chroot + # Since 0.9.0, values can be quoted with '' or "" to allow spaces + source-path="My Documents/scripts" + # Allow opening any 'source'd file, even if not specified as input external-sources=true diff --git a/src/ShellCheck/Checker.hs b/src/ShellCheck/Checker.hs index db793f1..6518e0d 100644 --- a/src/ShellCheck/Checker.hs +++ b/src/ShellCheck/Checker.hs @@ -244,6 +244,9 @@ prop_canStripPrefixAndSource2 = prop_canSourceDynamicWhenRedirected = null $ checkWithIncludes [("lib", "")] "#shellcheck source=lib\n. \"$1\"" +prop_canRedirectWithSpaces = + null $ checkWithIncludes [("my file", "")] "#shellcheck source=\"my file\"\n. \"$1\"" + prop_recursiveAnalysis = [2086] == checkRecursive [("lib", "echo $1")] "source lib" @@ -413,6 +416,15 @@ prop_sourcePathAddsAnnotation = result == [2086] csCheckSourced = True } +prop_sourcePathWorksWithSpaces = result == [2086] + where + f "dir/myscript" _ ["my path"] "lib" = return "foo/lib" + result = checkWithIncludesAndSourcePath [("foo/lib", "echo $1")] f emptyCheckSpec { + csScript = "#!/bin/bash\n# shellcheck source-path='my path'\nsource lib", + csFilename = "dir/myscript", + csCheckSourced = True + } + prop_sourcePathRedirectsDirective = result == [2086] where f "dir/myscript" _ _ "lib" = return "foo/lib" diff --git a/src/ShellCheck/Parser.hs b/src/ShellCheck/Parser.hs index 0dd6621..4ff45ed 100644 --- a/src/ShellCheck/Parser.hs +++ b/src/ShellCheck/Parser.hs @@ -992,6 +992,10 @@ prop_readAnnotation5 = isOk readAnnotation "# shellcheck disable=SC2002 # All ca prop_readAnnotation6 = isOk readAnnotation "# shellcheck disable=SC1234 # shellcheck foo=bar\n" prop_readAnnotation7 = isOk readAnnotation "# shellcheck disable=SC1000,SC2000-SC3000,SC1001\n" prop_readAnnotation8 = isOk readAnnotation "# shellcheck disable=all\n" +prop_readAnnotation9 = isOk readAnnotation "# shellcheck source='foo bar' source-path=\"baz etc\"\n" +prop_readAnnotation10 = isOk readAnnotation "# shellcheck disable='SC1234,SC2345' enable=\"foo\" shell='bash'\n" +prop_readAnnotation11 = isOk (readAnnotationWithoutPrefix False) "external-sources='true'" + readAnnotation = called "shellcheck directive" $ do try readAnnotationPrefix many1 linewhitespace @@ -1007,12 +1011,19 @@ readAnnotationWithoutPrefix sandboxed = do many linewhitespace return $ concat values where + plainOrQuoted p = quoted p <|> p + quoted p = do + c <- oneOf "'\"" + start <- getPosition + str <- many1 $ noneOf (c:"\n") + char c <|> fail "Missing terminating quote for directive." + subParse start p str readKey = do keyPos <- getPosition key <- many1 (letter <|> char '-') char '=' <|> fail "Expected '=' after directive key" annotations <- case key of - "disable" -> readElement `sepBy` char ',' + "disable" -> plainOrQuoted $ readElement `sepBy` char ',' where readElement = readRange <|> readAll readAll = do @@ -1027,21 +1038,21 @@ readAnnotationWithoutPrefix sandboxed = do int <- many1 digit return $ read int - "enable" -> readName `sepBy` char ',' + "enable" -> plainOrQuoted $ readName `sepBy` char ',' where readName = EnableComment <$> many1 (letter <|> char '-') "source" -> do - filename <- many1 $ noneOf " \n" + filename <- quoted (many1 anyChar) <|> (many1 $ noneOf " \n") return [SourceOverride filename] "source-path" -> do - dirname <- many1 $ noneOf " \n" + dirname <- quoted (many1 anyChar) <|> (many1 $ noneOf " \n") return [SourcePath dirname] "shell" -> do pos <- getPosition - shell <- many1 $ noneOf " \n" + shell <- quoted (many1 anyChar) <|> (many1 $ noneOf " \n") when (isNothing $ shellForExecutable shell) $ parseNoteAt pos ErrorC 1103 "This shell type is unknown. Use e.g. sh or bash." @@ -1049,7 +1060,7 @@ readAnnotationWithoutPrefix sandboxed = do "external-sources" -> do pos <- getPosition - value <- many1 letter + value <- plainOrQuoted $ many1 letter case value of "true" -> if sandboxed