forked from hadolint/hadolint
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
It is a more modern alternative and the default option for the haskell language server
- Loading branch information
Showing
14 changed files
with
2,028 additions
and
1,970 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,93 @@ | ||
{-# LANGUAGE DeriveGeneric #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE FlexibleContexts #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
|
||
module Hadolint.Config (applyConfig, ConfigFile(..)) where | ||
module Hadolint.Config (applyConfig, ConfigFile (..)) where | ||
|
||
import Control.Monad (filterM) | ||
import qualified Data.ByteString as Bytes | ||
import Data.Coerce (coerce) | ||
import Data.Maybe (fromMaybe, listToMaybe) | ||
import qualified Data.ByteString as Bytes | ||
import qualified Data.Set as Set | ||
import qualified Data.YAML as Yaml | ||
import Data.YAML ((.:?)) | ||
import GHC.Generics | ||
import qualified Data.YAML as Yaml | ||
import GHC.Generics (Generic) | ||
import qualified Hadolint.Lint as Lint | ||
import qualified Hadolint.Rules as Rules | ||
import qualified Language.Docker as Docker | ||
import System.Directory | ||
(XdgDirectory(..), doesFileExist, getCurrentDirectory, | ||
getXdgDirectory) | ||
( XdgDirectory (..), | ||
doesFileExist, | ||
getCurrentDirectory, | ||
getXdgDirectory, | ||
) | ||
import System.FilePath ((</>)) | ||
|
||
import qualified Hadolint.Lint as Lint | ||
import qualified Hadolint.Rules as Rules | ||
|
||
data ConfigFile = ConfigFile | ||
{ ignoredRules :: Maybe [Lint.IgnoreRule] | ||
, trustedRegistries :: Maybe [Lint.TrustedRegistry] | ||
} deriving (Show, Eq, Generic) | ||
{ ignoredRules :: Maybe [Lint.IgnoreRule], | ||
trustedRegistries :: Maybe [Lint.TrustedRegistry] | ||
} | ||
deriving (Show, Eq, Generic) | ||
|
||
instance Yaml.FromYAML ConfigFile where | ||
parseYAML = Yaml.withMap "ConfigFile" $ \m -> ConfigFile | ||
<$> m .:? "ignored" | ||
<*> m .:? "trustedRegistries" | ||
parseYAML = Yaml.withMap "ConfigFile" $ \m -> | ||
ConfigFile | ||
<$> m .:? "ignored" | ||
<*> m .:? "trustedRegistries" | ||
|
||
-- | If both the ignoreRules and rulesConfig properties of Lint options are empty | ||
-- then this function will fill them with the default found in the passed config | ||
-- file. If there is an error parsing the default config file, this function will | ||
-- return the error string. | ||
applyConfig :: Maybe FilePath -> Lint.LintOptions -> IO (Either String Lint.LintOptions) | ||
applyConfig maybeConfig o | ||
| not (null (Lint.ignoreRules o)) && Lint.rulesConfig o /= mempty = return (Right o) | ||
| otherwise = do | ||
theConfig <- | ||
case maybeConfig of | ||
Nothing -> findConfig | ||
c -> return c | ||
case theConfig of | ||
Nothing -> return (Right o) | ||
Just config -> parseAndApply config | ||
| not (null (Lint.ignoreRules o)) && Lint.rulesConfig o /= mempty = return (Right o) | ||
| otherwise = do | ||
theConfig <- | ||
case maybeConfig of | ||
Nothing -> findConfig | ||
c -> return c | ||
case theConfig of | ||
Nothing -> return (Right o) | ||
Just config -> parseAndApply config | ||
where | ||
findConfig = do | ||
localConfigFile <- (</> ".hadolint.yaml") <$> getCurrentDirectory | ||
configFile <- getXdgDirectory XdgConfig "hadolint.yaml" | ||
listToMaybe <$> filterM doesFileExist [localConfigFile, configFile] | ||
localConfigFile <- (</> ".hadolint.yaml") <$> getCurrentDirectory | ||
configFile <- getXdgDirectory XdgConfig "hadolint.yaml" | ||
listToMaybe <$> filterM doesFileExist [localConfigFile, configFile] | ||
|
||
parseAndApply :: FilePath -> IO (Either String Lint.LintOptions) | ||
parseAndApply configFile = do | ||
contents <- Bytes.readFile configFile | ||
case Yaml.decode1Strict contents of | ||
Left (_, err) -> return $ Left (formatError err configFile) | ||
Right (ConfigFile ignore trusted) -> return (Right (override ignore trusted)) | ||
-- | Applies the configuration found in the file to the passed Lint.LintOptions | ||
contents <- Bytes.readFile configFile | ||
case Yaml.decode1Strict contents of | ||
Left (_, err) -> return $ Left (formatError err configFile) | ||
Right (ConfigFile ignore trusted) -> return (Right (override ignore trusted)) | ||
|
||
override ignore trusted = applyTrusted trusted . applyIgnore ignore $ o | ||
applyIgnore ignore opts = | ||
case Lint.ignoreRules opts of | ||
[] -> opts {Lint.ignoreRules = fromMaybe [] ignore} | ||
_ -> opts | ||
case Lint.ignoreRules opts of | ||
[] -> opts {Lint.ignoreRules = fromMaybe [] ignore} | ||
_ -> opts | ||
|
||
applyTrusted trusted opts | ||
| null (Rules.allowedRegistries (Lint.rulesConfig opts)) = | ||
opts {Lint.rulesConfig = toRules trusted <> Lint.rulesConfig opts} | ||
| otherwise = opts | ||
-- | Converts a list of TrustedRegistry to a RulesConfig record | ||
| null (Rules.allowedRegistries (Lint.rulesConfig opts)) = | ||
opts {Lint.rulesConfig = toRules trusted <> Lint.rulesConfig opts} | ||
| otherwise = opts | ||
|
||
toRules (Just trusted) = Rules.RulesConfig (Set.fromList . coerce $ trusted) | ||
toRules _ = mempty | ||
|
||
formatError err config = | ||
unlines | ||
[ "Error parsing your config file in '" ++ config ++ "':" | ||
, "It should contain one of the keys 'ignored' or 'trustedRegistries'. For example:\n" | ||
, "ignored:" | ||
, "\t- DL3000" | ||
, "\t- SC1099\n\n" | ||
, "The key 'trustedRegistries' should contain the names of the allowed docker registries:\n" | ||
, "allowedRegistries:" | ||
, "\t- docker.io" | ||
, "\t- my-company.com" | ||
, "" | ||
, err | ||
] | ||
[ "Error parsing your config file in '" ++ config ++ "':", | ||
"It should contain one of the keys 'ignored' or 'trustedRegistries'. For example:\n", | ||
"ignored:", | ||
"\t- DL3000", | ||
"\t- SC1099\n\n", | ||
"The key 'trustedRegistries' should contain the names of the allowed docker registries:\n", | ||
"allowedRegistries:", | ||
"\t- docker.io", | ||
"\t- my-company.com", | ||
"", | ||
err | ||
] |
Oops, something went wrong.