hadolint-2.8.0: src/Hadolint/Config/Configfile.hs
module Hadolint.Config.Configfile
( getConfigFromFile
)
where
import Control.Monad (when, filterM)
import Data.Maybe (listToMaybe)
import Data.YAML as Yaml
import qualified Data.ByteString as Bytes
import Hadolint.Config.Configuration (PartialConfiguration (..))
import System.Directory
( XdgDirectory (..),
doesFileExist,
getCurrentDirectory,
getAppUserDataDirectory,
getUserDocumentsDirectory,
getXdgDirectory,
)
import System.FilePath ((</>))
import System.IO (hPrint, stderr)
getConfigFromFile ::
Maybe FilePath -> Bool -> IO (Either String PartialConfiguration)
getConfigFromFile maybeExplicitPath verbose = do
maybePath <- getConfig maybeExplicitPath
when verbose $ hPrint stderr $ getFilePathDescription maybePath
case maybePath of
Nothing -> return $ Right mempty
Just path -> readConfig path
readConfig :: FilePath -> IO (Either String PartialConfiguration)
readConfig path = do
contents <- Bytes.readFile path
return $ case Yaml.decode1Strict contents of
Left (_, err) -> Left (formatError err path)
Right config -> Right config
getFilePathDescription :: Maybe FilePath -> String
getFilePathDescription Nothing =
"No configuration was specified. Using default configuration"
getFilePathDescription (Just filepath) = "Configuration file used: " ++ filepath
formatError :: String -> String -> String
formatError err config =
Prelude.unlines
[ "Error parsing your config file in '" ++ config ++ "':",
"It should contain one of the keys 'override', 'ignored'",
"or 'trustedRegistries'. For example:\n",
"ignored:",
"\t- DL3000",
"\t- SC1099\n\n",
"The key 'override' should contain only lists with names 'error',",
"'warning', 'info' or 'style', which each name rules to override the",
"severity on. For example:\n",
"override:",
"\terror:",
"\t\t- DL3008\n\n",
"The key 'trustedRegistries' should contain the names of the allowed",
"docker registries:\n",
"trustedRegistries:",
"\t- docker.io",
"\t- my-company.com",
"",
err
]
-- | Gets the configuration file which Hadolint uses
getConfig :: Maybe FilePath -> IO (Maybe FilePath)
getConfig maybeConfig =
case maybeConfig of
Nothing -> findConfig
_ -> return maybeConfig
-- | If no configuration file path was given on the command line, Hadolint
-- searches these locations or their equivalents on MacOS/Windows:
-- - $(pwd)/.hadolint.{yaml|yml}
-- - $HOME/.config/hadolint.{yaml|yml}
-- - $HOME/.hadolint/{hadolint|config}.{yaml|yml}
-- - $HOME/.hadolint.{yaml|yml}
-- The first file found is used, all other are ignored.
findConfig :: IO (Maybe FilePath)
findConfig = do
filesInCWD <- traverse
(\filePath -> (</> filePath) <$> getCurrentDirectory)
hiddenConfigs
filesInXdgConfig <- traverse (getXdgDirectory XdgConfig) visibleConfigs
filesInAppData <- traverse
(\fp -> (</> fp) <$> getAppUserDataDirectory "hadolint")
(visibleConfigs <> moreConfigs)
filesInHome <- traverse
(\fp -> (</> fp) <$> getUserDocumentsDirectory)
hiddenConfigs
listToMaybe
<$> filterM
doesFileExist
(filesInCWD <> filesInXdgConfig <> filesInAppData <> filesInHome)
where
hiddenConfigs = [".hadolint.yaml", ".hadolint.yml"]
visibleConfigs = ["hadolint.yaml", "hadolint.yml"]
moreConfigs = ["config.yaml", "config.yml"]