cabal-gild 1.1.2.0 → 1.1.3.0
raw patch · 11 files changed
+153/−21 lines, 11 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ CabalGild.Exception.InvalidLeniency: InvalidLeniency :: String -> InvalidLeniency
+ CabalGild.Exception.InvalidLeniency: fromString :: String -> InvalidLeniency
+ CabalGild.Exception.InvalidLeniency: instance GHC.Classes.Eq CabalGild.Exception.InvalidLeniency.InvalidLeniency
+ CabalGild.Exception.InvalidLeniency: instance GHC.Exception.Type.Exception CabalGild.Exception.InvalidLeniency.InvalidLeniency
+ CabalGild.Exception.InvalidLeniency: instance GHC.Show.Show CabalGild.Exception.InvalidLeniency.InvalidLeniency
+ CabalGild.Exception.InvalidLeniency: newtype InvalidLeniency
+ CabalGild.Exception.SpecifiedCrlfWithFormatMode: SpecifiedCrlfWithFormatMode :: SpecifiedCrlfWithFormatMode
+ CabalGild.Exception.SpecifiedCrlfWithFormatMode: data SpecifiedCrlfWithFormatMode
+ CabalGild.Exception.SpecifiedCrlfWithFormatMode: instance GHC.Classes.Eq CabalGild.Exception.SpecifiedCrlfWithFormatMode.SpecifiedCrlfWithFormatMode
+ CabalGild.Exception.SpecifiedCrlfWithFormatMode: instance GHC.Exception.Type.Exception CabalGild.Exception.SpecifiedCrlfWithFormatMode.SpecifiedCrlfWithFormatMode
+ CabalGild.Exception.SpecifiedCrlfWithFormatMode: instance GHC.Show.Show CabalGild.Exception.SpecifiedCrlfWithFormatMode.SpecifiedCrlfWithFormatMode
+ CabalGild.Extra.ByteString: replace :: ByteString -> ByteString -> ByteString -> ByteString
+ CabalGild.Extra.ByteString: splitOn :: ByteString -> ByteString -> [ByteString]
+ CabalGild.Type.Config: [crlf] :: Config -> Optional Leniency
+ CabalGild.Type.Context: [crlf] :: Context -> Leniency
+ CabalGild.Type.Flag: CRLF :: String -> Flag
+ CabalGild.Type.Leniency: Lenient :: Leniency
+ CabalGild.Type.Leniency: Strict :: Leniency
+ CabalGild.Type.Leniency: data Leniency
+ CabalGild.Type.Leniency: fromString :: MonadThrow m => String -> m Leniency
+ CabalGild.Type.Leniency: instance GHC.Classes.Eq CabalGild.Type.Leniency.Leniency
+ CabalGild.Type.Leniency: instance GHC.Show.Show CabalGild.Type.Leniency.Leniency
- CabalGild.Type.Config: Config :: Optional Bool -> Optional Input -> Optional Mode -> Optional Output -> Optional FilePath -> Optional Bool -> Config
+ CabalGild.Type.Config: Config :: Optional Leniency -> Optional Bool -> Optional Input -> Optional Mode -> Optional Output -> Optional FilePath -> Optional Bool -> Config
- CabalGild.Type.Context: Context :: Input -> Mode -> Output -> FilePath -> Context
+ CabalGild.Type.Context: Context :: Leniency -> Input -> Mode -> Output -> FilePath -> Context
Files
- README.md +9/−0
- cabal-gild.cabal +5/−1
- source/library/CabalGild/Exception/InvalidLeniency.hs +16/−0
- source/library/CabalGild/Exception/SpecifiedCrlfWithFormatMode.hs +13/−0
- source/library/CabalGild/Extra/ByteString.hs +32/−0
- source/library/CabalGild/Main.hs +9/−12
- source/library/CabalGild/Type/Config.hs +8/−2
- source/library/CabalGild/Type/Context.hs +12/−2
- source/library/CabalGild/Type/Flag.hs +7/−1
- source/library/CabalGild/Type/Leniency.hs +18/−0
- source/test-suite/Main.hs +24/−3
README.md view
@@ -130,6 +130,15 @@ - `--version`: Prints the version number to STDOUT then exits successfully. +- `--crlf=LENIENCY`: Sets the CRLF handling mode, which must be either+ `lenient` (the default) or `strict`. When checking if the input is formatted,+ setting this to `lenient` will treat CRLF line endings the same as LF.+ Setting this to `strict` will require the input to be byte-for-byte identical+ to the expected output. (Note that Gild will never produce CRLF line endings+ when formatting.)++ It is an error to provide a value for this option unless the mode is `check`.+ - `--input=FILE`: Uses `FILE` as the input. If this is `-` (which is the default), then the input will be read from STDIN.
cabal-gild.cabal view
@@ -11,7 +11,7 @@ maintainer: Taylor Fausak name: cabal-gild synopsis: Formats package descriptions.-version: 1.1.2.0+version: 1.1.3.0 source-repository head type: git@@ -86,13 +86,16 @@ CabalGild.Class.MonadWalk CabalGild.Class.MonadWrite CabalGild.Exception.CheckFailure+ CabalGild.Exception.InvalidLeniency CabalGild.Exception.InvalidMode CabalGild.Exception.InvalidOption CabalGild.Exception.ParseError+ CabalGild.Exception.SpecifiedCrlfWithFormatMode CabalGild.Exception.SpecifiedOutputWithCheckMode CabalGild.Exception.SpecifiedStdinWithFileInput CabalGild.Exception.UnexpectedArgument CabalGild.Exception.UnknownOption+ CabalGild.Extra.ByteString CabalGild.Extra.Either CabalGild.Extra.Field CabalGild.Extra.FieldLine@@ -115,6 +118,7 @@ CabalGild.Type.Input CabalGild.Type.Language CabalGild.Type.LegacyExeDependency+ CabalGild.Type.Leniency CabalGild.Type.Line CabalGild.Type.List CabalGild.Type.Mode
+ source/library/CabalGild/Exception/InvalidLeniency.hs view
@@ -0,0 +1,16 @@+module CabalGild.Exception.InvalidLeniency where++import qualified Control.Monad.Catch as Exception++-- | This exception is thrown when the given+-- 'CabalGild.Type.Leniency.Leniency' is invalid.+newtype InvalidLeniency+ = InvalidLeniency String+ deriving (Eq, Show)++instance Exception.Exception InvalidLeniency where+ displayException (InvalidLeniency s) = "invalid leniency: " <> s++-- | Constructs an 'InvalidLeniency' from the given 'String'.+fromString :: String -> InvalidLeniency+fromString = InvalidLeniency
+ source/library/CabalGild/Exception/SpecifiedCrlfWithFormatMode.hs view
@@ -0,0 +1,13 @@+module CabalGild.Exception.SpecifiedCrlfWithFormatMode where++import qualified Control.Monad.Catch as Exception++-- | This exception is thrown when the user specifies the CRLF leniency while+-- using the format mode. In other words, when @--mode=format@ and+-- @--crlf=anything@.+data SpecifiedCrlfWithFormatMode+ = SpecifiedCrlfWithFormatMode+ deriving (Eq, Show)++instance Exception.Exception SpecifiedCrlfWithFormatMode where+ displayException = const "cannot use --crlf when --mode is format"
+ source/library/CabalGild/Extra/ByteString.hs view
@@ -0,0 +1,32 @@+module CabalGild.Extra.ByteString where++import qualified Data.ByteString as ByteString++-- | Calling @replace needle replacement haystack@ will replace every+-- non-overlapping occurrence of @needle@ in @haystack@ with @replacement@.+--+-- <https://github.com/haskell/bytestring/issues/307>+replace ::+ ByteString.ByteString ->+ ByteString.ByteString ->+ ByteString.ByteString ->+ ByteString.ByteString+replace needle replacement = ByteString.intercalate replacement . splitOn needle++-- | Calling @splitOn needle haystack@ will split @haystack@ into a list of+-- substrings using @needle@ as the delimiter.+--+-- <https://github.com/haskell/bytestring/issues/100>+splitOn ::+ ByteString.ByteString ->+ ByteString.ByteString ->+ [ByteString.ByteString]+splitOn needle =+ let split = ByteString.breakSubstring needle+ go haystack =+ let (before, after) = split haystack+ in before+ : if ByteString.null after+ then []+ else go (ByteString.drop (ByteString.length needle) after)+ in go
source/library/CabalGild/Main.hs view
@@ -16,15 +16,16 @@ import qualified CabalGild.Class.MonadWrite as MonadWrite import qualified CabalGild.Exception.CheckFailure as CheckFailure import qualified CabalGild.Exception.ParseError as ParseError+import qualified CabalGild.Extra.ByteString as ByteString import qualified CabalGild.Type.Config as Config import qualified CabalGild.Type.Context as Context import qualified CabalGild.Type.Flag as Flag import qualified CabalGild.Type.Input as Input+import qualified CabalGild.Type.Leniency as Leniency import qualified CabalGild.Type.Mode as Mode import qualified Control.Monad as Monad import qualified Control.Monad.Catch as Exception import qualified Data.ByteString as ByteString-import qualified Data.ByteString.Char8 as Latin1 import qualified Distribution.Fields as Fields import qualified System.Environment as Environment import qualified System.Exit as Exit@@ -89,17 +90,13 @@ case Context.mode context of Mode.Check -> do- -- The input might have CRLF ("\r\n", 0x0d 0x0a) line endings, but the- -- output will always have LF line endings. For the purposes of the check- -- command, we'll consider the input formatted if it only differs from- -- the output in line endings.- let outputLines = Latin1.lines output- stripCR x = case ByteString.unsnoc x of- Just (y, 0x0d) -> y- _ -> x- inputLines = stripCR <$> Latin1.lines input- Monad.when (outputLines /= inputLines) $- Exception.throwM CheckFailure.CheckFailure+ let formatted = case Context.crlf context of+ Leniency.Lenient ->+ let lf = ByteString.singleton 0x0a+ crlf = ByteString.cons 0x0d lf+ in output == ByteString.replace crlf lf input+ Leniency.Strict -> output == input+ Monad.unless formatted $ Exception.throwM CheckFailure.CheckFailure Mode.Format -> do let target = Context.output context MonadWrite.write target output
source/library/CabalGild/Type/Config.hs view
@@ -3,6 +3,7 @@ import qualified CabalGild.Type.Flag as Flag import qualified CabalGild.Type.Input as Input+import qualified CabalGild.Type.Leniency as Leniency import qualified CabalGild.Type.Mode as Mode import qualified CabalGild.Type.Optional as Optional import qualified CabalGild.Type.Output as Output@@ -12,7 +13,8 @@ -- | This data type represents the configuration for the command line utility. -- Each field typically corresponds to a flag. data Config = Config- { help :: Optional.Optional Bool,+ { crlf :: Optional.Optional Leniency.Leniency,+ help :: Optional.Optional Bool, input :: Optional.Optional Input.Input, mode :: Optional.Optional Mode.Mode, output :: Optional.Optional Output.Output,@@ -25,7 +27,8 @@ initial :: Config initial = Config- { help = Optional.Default,+ { crlf = Optional.Default,+ help = Optional.Default, input = Optional.Default, mode = Optional.Default, output = Optional.Default,@@ -36,6 +39,9 @@ -- | Applies a flag to the config, returning the new config. applyFlag :: (Exception.MonadThrow m) => Config -> Flag.Flag -> m Config applyFlag config flag = case flag of+ Flag.CRLF s -> do+ l <- Leniency.fromString s+ pure config {crlf = Optional.Specific l} Flag.Help b -> pure config {help = Optional.Specific b} Flag.Input s -> pure config {input = Optional.Specific $ Input.fromString s} Flag.IO s ->
source/library/CabalGild/Type/Context.hs view
@@ -1,11 +1,13 @@ module CabalGild.Type.Context where import qualified CabalGild.Class.MonadLog as MonadLog+import qualified CabalGild.Exception.SpecifiedCrlfWithFormatMode as SpecifiedCrlfWithFormatMode import qualified CabalGild.Exception.SpecifiedOutputWithCheckMode as SpecifiedOutputWithCheckMode import qualified CabalGild.Exception.SpecifiedStdinWithFileInput as SpecifiedStdinWithFileInput import qualified CabalGild.Type.Config as Config import qualified CabalGild.Type.Flag as Flag import qualified CabalGild.Type.Input as Input+import qualified CabalGild.Type.Leniency as Leniency import qualified CabalGild.Type.Mode as Mode import qualified CabalGild.Type.Optional as Optional import qualified CabalGild.Type.Output as Output@@ -21,7 +23,8 @@ -- | Represents the context necessary to run the program. This is essentially a -- simplified 'Config.Config'. data Context = Context- { input :: Input.Input,+ { crlf :: Leniency.Leniency,+ input :: Input.Input, mode :: Mode.Mode, output :: Output.Output, stdin :: FilePath@@ -64,9 +67,16 @@ Exception.throwM SpecifiedOutputWithCheckMode.SpecifiedOutputWithCheckMode _ -> pure () + case Config.crlf config of+ Optional.Specific _+ | Config.mode config /= Optional.Specific Mode.Check ->+ Exception.throwM SpecifiedCrlfWithFormatMode.SpecifiedCrlfWithFormatMode+ _ -> pure ()+ pure Context- { input = Optional.withDefault Input.Stdin $ Config.input config,+ { crlf = Optional.withDefault Leniency.Lenient $ Config.crlf config,+ input = Optional.withDefault Input.Stdin $ Config.input config, mode = Optional.withDefault Mode.Format $ Config.mode config, output = Optional.withDefault Output.Stdout $ Config.output config, stdin = Optional.withDefault "." $ Config.stdin config
source/library/CabalGild/Type/Flag.hs view
@@ -11,7 +11,8 @@ -- the flags are typically not parsed. These just handle the structure of -- command line options. data Flag- = Help Bool+ = CRLF String+ | Help Bool | Input String | IO String | Mode String@@ -43,6 +44,11 @@ ["no-version"] (GetOpt.NoArg $ Version False) "",+ GetOpt.Option+ []+ ["crlf"]+ (GetOpt.ReqArg CRLF "LENIENCY")+ "Sets the CRLF handling mode. Must be either 'lenient' or 'strict'.\nDefault: 'lenient'", GetOpt.Option ['i'] ["input"]
+ source/library/CabalGild/Type/Leniency.hs view
@@ -0,0 +1,18 @@+module CabalGild.Type.Leniency where++import qualified CabalGild.Exception.InvalidLeniency as InvalidLeniency+import qualified Control.Monad.Catch as Exception++-- | Represents the leniency of a setting. In other words, should something be+-- lenient\/permissive or strict\/pedantic?+data Leniency+ = Lenient+ | Strict+ deriving (Eq, Show)++-- | Attempts to parse a string as a 'Leniency'.+fromString :: (Exception.MonadThrow m) => String -> m Leniency+fromString s = case s of+ "lenient" -> pure Lenient+ "strict" -> pure Strict+ _ -> Exception.throwM $ InvalidLeniency.fromString s
source/test-suite/Main.hs view
@@ -5,6 +5,7 @@ import qualified CabalGild.Class.MonadWalk as MonadWalk import qualified CabalGild.Class.MonadWrite as MonadWrite import qualified CabalGild.Exception.CheckFailure as CheckFailure+import qualified CabalGild.Exception.SpecifiedCrlfWithFormatMode as SpecifiedCrlfWithFormatMode import qualified CabalGild.Exception.SpecifiedOutputWithCheckMode as SpecifiedOutputWithCheckMode import qualified CabalGild.Exception.SpecifiedStdinWithFileInput as SpecifiedStdinWithFileInput import qualified CabalGild.Extra.String as String@@ -70,7 +71,7 @@ let (a, s, w) = runTest (Gild.mainWith ["--mode", "check"])- (Map.singleton Input.Stdin (String.toUtf8 ""), Map.empty)+ (Map.singleton Input.Stdin (String.toUtf8 "pass: yes\n"), Map.empty) Map.empty a `Hspec.shouldBe` Right () w `Hspec.shouldBe` []@@ -80,13 +81,13 @@ let (a, s, w) = runTest (Gild.mainWith ["--mode", "check"])- (Map.singleton Input.Stdin (String.toUtf8 "fail:yes"), Map.empty)+ (Map.singleton Input.Stdin (String.toUtf8 "pass: no"), Map.empty) Map.empty a `Hspec.shouldBe` Left (Problem $ Exception.toException CheckFailure.CheckFailure) w `Hspec.shouldBe` [] s `Hspec.shouldBe` Map.empty - Hspec.it "succeeds when checking CRLF input" $ do+ Hspec.it "succeeds when checking CRLF input leniently" $ do let (a, s, w) = runTest (Gild.mainWith ["--mode", "check"])@@ -96,6 +97,16 @@ w `Hspec.shouldBe` [] s `Hspec.shouldBe` Map.empty + Hspec.it "fails when checking CRLF input strictly" $ do+ let (a, s, w) =+ runTest+ (Gild.mainWith ["--crlf", "strict", "--mode", "check"])+ (Map.singleton Input.Stdin (String.toUtf8 "pass: no\r\n"), Map.empty)+ Map.empty+ a `Hspec.shouldBe` Left (Problem $ Exception.toException CheckFailure.CheckFailure)+ w `Hspec.shouldBe` []+ s `Hspec.shouldBe` Map.empty+ Hspec.it "fails when --stdin is given with an input file" $ do let (a, s, w) = runTest@@ -125,6 +136,16 @@ a `Hspec.shouldBe` Right () w `Hspec.shouldBe` [] s `Hspec.shouldSatisfy` Map.member (Output.File "io.cabal")++ Hspec.it "fails when --crlf is given with format mode" $ do+ let (a, s, w) =+ runTest+ (Gild.mainWith ["--crlf", "strict"])+ (Map.empty, Map.empty)+ Map.empty+ a `Hspec.shouldBe` Left (Problem $ Exception.toException SpecifiedCrlfWithFormatMode.SpecifiedCrlfWithFormatMode)+ w `Hspec.shouldBe` []+ s `Hspec.shouldBe` Map.empty Hspec.it "succeeds with empty input" $ do expectGilded