hadolint-1.13.0: app/Main.hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE NamedFieldPuns #-}
module Main where
import Control.Applicative
import qualified Data.List.NonEmpty as NonEmpty
import Data.Semigroup ((<>))
import qualified Data.Set as Set
import Data.String
import qualified Data.Version
import qualified Development.GitRev
import Options.Applicative hiding (ParseError)
import qualified Paths_hadolint -- version from hadolint.cabal file
import System.Exit (exitFailure, exitSuccess)
import qualified Hadolint
data CommandOptions = CommandOptions
{ showVersion :: Bool
, configFile :: Maybe FilePath
, format :: Hadolint.OutputFormat
, dockerfiles :: [String]
, lintingOptions :: Hadolint.LintOptions
}
toOutputFormat :: String -> Maybe Hadolint.OutputFormat
toOutputFormat "json" = Just Hadolint.Json
toOutputFormat "tty" = Just Hadolint.TTY
toOutputFormat "codeclimate" = Just Hadolint.CodeclimateJson
toOutputFormat "checkstyle" = Just Hadolint.Checkstyle
toOutputFormat "codacy" = Just Hadolint.Codacy
toOutputFormat _ = Nothing
showFormat :: Hadolint.OutputFormat -> String
showFormat Hadolint.Json = "json"
showFormat Hadolint.TTY = "tty"
showFormat Hadolint.CodeclimateJson = "codeclimate"
showFormat Hadolint.Checkstyle = "checkstyle"
showFormat Hadolint.Codacy = "codacy"
parseOptions :: Parser CommandOptions
parseOptions =
CommandOptions <$> -- CLI options parser definition
version <*>
configFile <*>
outputFormat <*>
files <*>
lintOptions
where
version = switch (long "version" <> short 'v' <> help "Show version")
--
-- | Parse the config filename to use
configFile =
optional
(strOption
(long "config" <> short 'c' <> metavar "FILENAME" <>
help "Path to the configuration file"))
--
-- | Parse the output format option
outputFormat =
option
(maybeReader toOutputFormat)
(long "format" <> -- options for the output format
short 'f' <>
help
"The output format for the results [tty | json | checkstyle | codeclimate | codacy]" <>
value Hadolint.TTY <> -- The default value
showDefaultWith showFormat <>
completeWith ["tty", "json", "checkstyle", "codeclimate", "codacy"])
--
-- | Parse a list of ignored rules
ignoreList =
many
(strOption
(long "ignore" <>
help "A rule to ignore. If present, the ignore list in the config file is ignored" <>
metavar "RULECODE"))
--
-- | Parse a list of dockerfile names
files = many (argument str (metavar "DOCKERFILE..." <> action "file"))
--
-- | Parse the rule ignore list and the rules configuration into a LintOptions
lintOptions = Hadolint.LintOptions <$> ignoreList <*> parseRulesConfig
--
-- | Parse all the optional rules configuration
parseRulesConfig =
Hadolint.RulesConfig . Set.fromList . fmap fromString <$>
many
(strOption
(long "trusted-registry" <>
help "A docker registry to allow to appear in FROM instructions" <>
metavar "REGISTRY (e.g. docker.io)"))
main :: IO ()
main = do
cmd <- execParser opts
execute cmd
where
execute CommandOptions {showVersion = True} = putStrLn getVersion >> exitSuccess
execute CommandOptions {dockerfiles = []} =
putStrLn "Please provide a Dockerfile" >> exitFailure
execute cmd = do
lintConfig <- Hadolint.applyConfig (configFile cmd) (lintingOptions cmd)
let files = NonEmpty.fromList (dockerfiles cmd)
case lintConfig of
Left err -> error err
Right conf -> do
res <- Hadolint.lint conf files
Hadolint.printResultsAndExit (format cmd) res
opts =
info
(helper <*> parseOptions)
(fullDesc <> progDesc "Lint Dockerfile for errors and best practices" <>
header "hadolint - Dockerfile Linter written in Haskell")
getVersion :: String
getVersion
| $(Development.GitRev.gitDescribe) == "UNKNOWN" =
"Haskell Dockerfile Linter " ++ Data.Version.showVersion Paths_hadolint.version ++ "-no-git"
| otherwise = "Haskell Dockerfile Linter " ++ $(Development.GitRev.gitDescribe)