language-docker 12.0.0 → 12.1.0
raw patch · 8 files changed
+198/−71 lines, 8 files
Files
- language-docker.cabal +4/−3
- src/Language/Docker/Parser/Arguments.hs +1/−1
- src/Language/Docker/Parser/Healthcheck.hs +6/−4
- src/Language/Docker/Parser/Prelude.hs +35/−9
- src/Language/Docker/Syntax.hs +1/−1
- test/Language/Docker/ParseHealthcheckSpec.hs +81/−0
- test/Language/Docker/ParseRunSpec.hs +70/−5
- test/Language/Docker/ParserSpec.hs +0/−48
language-docker.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.7.+-- This file has been generated from package.yaml by hpack version 0.35.0. -- -- see: https://github.com/sol/hpack ----- hash: f800aba94b9f6bbf2894ac78e2f4a135d3e9e89e04d9a7b0549bdd0941e97cbd+-- hash: 37c989b46891ef750c66b64a1dcbdfc30c1ee22a0ed4821aeb27c7c63c02d2a9 name: language-docker-version: 12.0.0+version: 12.1.0 synopsis: Dockerfile parser, pretty-printer and embedded DSL description: All functions for parsing and pretty-printing Dockerfiles are exported through @Language.Docker@. For more fine-grained operations look for specific modules that implement a certain functionality. See the <https://github.com/hadolint/language-docker GitHub project> for the source-code and examples.@@ -94,6 +94,7 @@ Language.Docker.ParseCmdSpec Language.Docker.ParseCopySpec Language.Docker.ParseExposeSpec+ Language.Docker.ParseHealthcheckSpec Language.Docker.ParsePragmaSpec Language.Docker.ParserSpec Language.Docker.ParseRunSpec
src/Language/Docker/Parser/Arguments.hs view
@@ -22,7 +22,7 @@ toEnd = untilEol "the shell arguments" -- Parse arguments of a command in the heredoc format-argumentsHeredoc :: Parser (Arguments Text)+argumentsHeredoc :: (?esc :: Char) => Parser (Arguments Text) argumentsHeredoc = ArgumentsText <$> heredoc arguments :: (?esc :: Char) => Parser (Arguments Text)
src/Language/Docker/Parser/Healthcheck.hs view
@@ -70,12 +70,14 @@ durationFlag :: Text -> Parser Duration durationFlag flagName = do void $ try (string flagName)- scale <- natural+ value <- try ( fromRational . realToFrac <$> fractional )+ <|> ( secondsToDiffTime . fromInteger <$> natural )+ <?> "a natural or fractional number" unit <- char 's' <|> char 'm' <|> char 'h' <?> "either 's', 'm' or 'h' as the unit" case unit of- 's' -> return $ Duration (secondsToDiffTime scale)- 'm' -> return $ Duration (secondsToDiffTime (scale * 60))- 'h' -> return $ Duration (secondsToDiffTime (scale * 60 * 60))+ 's' -> return $ Duration value+ 'm' -> return $ Duration (value * 60)+ 'h' -> return $ Duration (value * 60 * 60) _ -> fail "only 's', 'm' or 'h' are allowed as the duration" retriesFlag :: Parser Retries
src/Language/Docker/Parser/Prelude.hs view
@@ -14,6 +14,8 @@ doubleQuotedString, doubleQuotedStringEscaped, eol,+ escapedLineBreaks',+ fractional, heredoc, heredocContent, heredocMarker,@@ -133,6 +135,9 @@ natural :: Parser Integer natural = L.decimal <?> "positive number" +fractional :: Parser Float+fractional = L.float <?> "fractional number"+ commaSep :: (?esc :: Char) => Parser a -> Parser [a] commaSep p = sepBy (p <* whitespace) (symbol ",") @@ -170,7 +175,7 @@ s <- manyTill anySingle spaceChar return $ T.pack s -heredocMarker :: Parser Text+heredocMarker :: (?esc :: Char) => Parser Text heredocMarker = do void $ string "<<" void $ takeWhileP (Just "dash") (== '-')@@ -178,11 +183,14 @@ optional heredocRedirect pure m -heredocRedirect :: Parser Text+heredocRedirect :: (?esc :: Char) => Parser Text heredocRedirect = do- void $ char '>'- takeWhileP (Just "heredoc path") (/= '\n')+ void $ ( string "|" <|> string ">" <|> string ">>" ) *> onlySpaces+ untilEol "heredoc path" +-- | This tries to parse everything until there is the just the heredoc marker+-- on its own on a line. Making provisions for the case that the marker is+-- followed by the end of the file rather than another newline. heredocContent :: Text -> Parser Text heredocContent marker = do emptyHeredoc <- observing delimiter@@ -215,17 +223,24 @@ hidden eof pure t -heredoc :: Parser Text+heredoc :: (?esc :: Char) => Parser Text heredoc = do m <- heredocMarker heredocContent m -- | Parses text until a heredoc or newline is found. Will also consume the--- heredoc.-untilHeredoc :: Parser Text+-- heredoc. It will however respect escaped newlines.+untilHeredoc :: (?esc :: Char) => Parser Text untilHeredoc = do- txt <- manyTill (anySingleBut '\n') heredoc- return $ T.strip $ T.pack txt+ txt <- manyTill chars heredoc+ return $ T.strip $ mconcat txt+ where+ chars =+ choice+ [ castToSpace <$> escapedLineBreaks,+ charToTxt <$> anySingleBut '\n'+ ]+ charToTxt c = T.pack [c] onlySpaces :: Parser Text onlySpaces = takeWhileP (Just "spaces") (\c -> c == ' ' || c == '\t')@@ -248,6 +263,17 @@ -- Spaces before the next '\' have a special significance -- so we remembeer the fact that we found some FoundWhitespace <$ onlySpaces1 <|> pure MissingWhitespace+ newlines = takeWhile1P Nothing isNl++-- | This converts escaped line breaks, but keeps _all_ spaces before and after+escapedLineBreaks' :: (?esc :: Char) => Parser Text+escapedLineBreaks' = mconcat <$> breaks+ where+ breaks =+ some $ do+ try ( char ?esc *> onlySpaces *> newlines )+ skipMany . try $ onlySpaces *> comment *> newlines+ onlySpaces1 newlines = takeWhile1P Nothing isNl foundWhitespace :: (?esc :: Char) => Parser FoundWhitespace
src/Language/Docker/Syntax.hs view
@@ -161,7 +161,7 @@ = Duration { durationTime :: DiffTime }- deriving (Show, Eq, Ord, Num)+ deriving (Show, Eq, Ord, Num, Fractional) newtype Retries = Retries
+ test/Language/Docker/ParseHealthcheckSpec.hs view
@@ -0,0 +1,81 @@+module Language.Docker.ParseHealthcheckSpec where++import Data.Default.Class (def)+import Language.Docker.Syntax+import Test.Hspec+import TestHelper+import qualified Data.Set as Set+import qualified Data.Text as Text+++spec :: Spec+spec = do+ describe "parse HEALTHCHECK" $ do+ it "parse healthcheck with interval" $+ assertAst+ "HEALTHCHECK --interval=5m \\\nCMD curl -f http://localhost/"+ [ Healthcheck $+ Check $+ CheckArgs "curl -f http://localhost/" (Just 300) Nothing Nothing Nothing+ ]+ it "parse healthcheck with retries" $+ assertAst+ "HEALTHCHECK --retries=10 CMD curl -f http://localhost/"+ [ Healthcheck $+ Check $+ CheckArgs "curl -f http://localhost/" Nothing Nothing Nothing (Just $ Retries 10)+ ]+ it "parse healthcheck with timeout" $+ assertAst+ "HEALTHCHECK --timeout=10s CMD curl -f http://localhost/"+ [ Healthcheck $+ Check $+ CheckArgs "curl -f http://localhost/" Nothing (Just 10) Nothing Nothing+ ]+ it "parse healthcheck with start-period" $+ assertAst+ "HEALTHCHECK --start-period=2m CMD curl -f http://localhost/"+ [ Healthcheck $+ Check $+ CheckArgs "curl -f http://localhost/" Nothing Nothing (Just 120) Nothing+ ]+ it "parse healthcheck with all flags" $+ assertAst+ "HEALTHCHECK --start-period=2s --timeout=1m --retries=3 --interval=5s CMD curl -f http://localhost/"+ [ Healthcheck $+ Check $+ CheckArgs+ "curl -f http://localhost/"+ (Just 5)+ (Just 60)+ (Just 2)+ (Just $ Retries 3)+ ]+ it "parse healthcheck with no flags" $+ assertAst+ "HEALTHCHECK CMD curl -f http://localhost/"+ [ Healthcheck $+ Check $+ CheckArgs "curl -f http://localhost/" Nothing Nothing Nothing Nothing+ ]++ it "fractional arguments to flags" $+ let file =+ Text.unlines+ [ "HEALTHCHECK \\",+ " --interval=0.5s \\",+ " --timeout=0.1s \\",+ " --start-period=0.2s \\",+ " CMD curl -f http://localhost"+ ]+ in assertAst+ file+ [ Healthcheck $+ Check $+ CheckArgs+ "curl -f http://localhost"+ ( Just 0.5 )+ ( Just 0.10000000149 )+ ( Just 0.20000000298 )+ Nothing+ ]
test/Language/Docker/ParseRunSpec.hs view
@@ -14,6 +14,9 @@ it "escaped with space before" $ let dockerfile = Text.unlines ["RUN yum install -y \\", "imagemagick \\", "mysql"] in assertAst dockerfile [Run "yum install -y imagemagick mysql"]+ it "escaped linebreak, indented" $+ let file = Text.unlines [ "RUN foo ; \\", " bar" ]+ in assertAst file [ Run "foo ; bar" ] it "does not choke on unmatched brackets" $ let dockerfile = Text.unlines ["RUN [foo"] in assertAst dockerfile [Run "[foo"]@@ -501,17 +504,25 @@ in assertAst file [ Run $ RunArgs (ArgumentsText "foo\nbar EOF") flags ] it "heredoc with redirection to file" $ let file = Text.unlines [ "RUN <<EOF > /file", "foo", "EOF" ]- flags = def {security = Nothing }+ flags = def { security = Nothing } in assertAst file [ Run $ RunArgs (ArgumentsText "foo") flags ] it "heredoc to program stdin" $ let file = Text.unlines [ "RUN python <<EOF", "print(\"foo\")", "EOF" ]- flags = def {security = Nothing }+ flags = def { security = Nothing } in assertAst file [ Run $ RunArgs (ArgumentsText "python") flags ]- it "heredoc to program stdin with redirect to file" $+ it "heredoc to program stdin with redirect to file with '>'" $ let file = Text.unlines [ "RUN python <<EOF > /file", "print(\"foo\")", "EOF" ]- flags = def {security = Nothing }+ flags = def { security = Nothing } in assertAst file [ Run $ RunArgs (ArgumentsText "python") flags ]- it "heredoc with line continuation" $+ it "heredoc to program stdin with redirect to file with '>>'" $+ let file = Text.unlines [ "RUN python <<EOF >> /file", "print(\"foo\")", "EOF" ]+ flags = def { security = Nothing }+ in assertAst file [ Run $ RunArgs (ArgumentsText "python") flags ]+ it "heredoc pipe to program" $+ let file = Text.unlines [ "RUN cat <<EOF | sh", "echo foo", "EOF" ]+ flags = def { security = Nothing }+ in assertAst file [ Run $ RunArgs ( ArgumentsText "cat" ) flags ]+ it "heredoc with line continuation in the heredoc" $ let file = Text.unlines [ "RUN <<EOF", "apt-get update", "apt-get install foo bar \\", " buzz bar", "EOF" ] flags = def {security = Nothing } in assertAst@@ -571,4 +582,58 @@ (TargetPath "/foobar.sh") ) ( def :: CopyFlags )+ ]++ -- See https://github.com/hadolint/hadolint/issues/923 for the following+ -- tests+ it "heredoc in command chain with escaped newlines after redirect" $+ let file =+ Text.unlines+ [ "RUN ls && cat <<EOF >> go.mod && \\",+ " tac go.mod",+ "replace (",+ " github.com/user/repo => ../dir",+ ")",+ "EOF"+ ]+ flags = def++ in assertAst+ file+ [ Run $ RunArgs ( ArgumentsText "ls && cat" ) flags+ ]++ it "heredoc in command chain with escaped newlines before heredoc" $+ let file =+ Text.unlines+ [ "RUN ls && \\",+ " cat <<EOF >> go.mod && tac go.mod",+ "replace (",+ " github.com/user/repo => ../dir",+ ")",+ "EOF"+ ]+ flags = def++ in assertAst+ file+ [ Run $ RunArgs ( ArgumentsText "ls && cat" ) flags+ ]++ it "heredoc in command chain with escaped newlines before and after heredoc" $+ let file =+ Text.unlines+ [ "RUN ls && \\",+ " cat <<EOF >> go.mod && \\",+ " tac go.mod",+ "replace (",+ " github.com/user/repo => ../dir",+ ")",+ "EOF"+ ]+ flags = def++ in assertAst+ file+ [ Run $ RunArgs ( ArgumentsText "ls && cat" ) flags ]
test/Language/Docker/ParserSpec.hs view
@@ -174,54 +174,6 @@ describe "parse SHELL" $ it "quoted shell params" $ assertAst "SHELL [\"/bin/bash\", \"-c\"]" [Shell ["/bin/bash", "-c"]]- describe "parse HEALTHCHECK" $ do- it "parse healthcheck with interval" $- assertAst- "HEALTHCHECK --interval=5m \\\nCMD curl -f http://localhost/"- [ Healthcheck $- Check $- CheckArgs "curl -f http://localhost/" (Just 300) Nothing Nothing Nothing- ]- it "parse healthcheck with retries" $- assertAst- "HEALTHCHECK --retries=10 CMD curl -f http://localhost/"- [ Healthcheck $- Check $- CheckArgs "curl -f http://localhost/" Nothing Nothing Nothing (Just $ Retries 10)- ]- it "parse healthcheck with timeout" $- assertAst- "HEALTHCHECK --timeout=10s CMD curl -f http://localhost/"- [ Healthcheck $- Check $- CheckArgs "curl -f http://localhost/" Nothing (Just 10) Nothing Nothing- ]- it "parse healthcheck with start-period" $- assertAst- "HEALTHCHECK --start-period=2m CMD curl -f http://localhost/"- [ Healthcheck $- Check $- CheckArgs "curl -f http://localhost/" Nothing Nothing (Just 120) Nothing- ]- it "parse healthcheck with all flags" $- assertAst- "HEALTHCHECK --start-period=2s --timeout=1m --retries=3 --interval=5s CMD curl -f http://localhost/"- [ Healthcheck $- Check $- CheckArgs- "curl -f http://localhost/"- (Just 5)- (Just 60)- (Just 2)- (Just $ Retries 3)- ]- it "parse healthcheck with no flags" $- assertAst- "HEALTHCHECK CMD curl -f http://localhost/"- [ Healthcheck $- Check $- CheckArgs "curl -f http://localhost/" Nothing Nothing Nothing Nothing- ] describe "parse MAINTAINER" $ do it "maintainer of untagged scratch image" $ assertAst