stylish-cabal 0.1.0.0 → 0.2.0.0
raw patch · 9 files changed
+261/−45 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- StylishCabal: parse :: String -> Result GenericPackageDescription
+ StylishCabal: data Doc :: *
+ StylishCabal: displayIO :: Handle -> SimpleDoc -> IO ()
+ StylishCabal: displayS :: SimpleDoc -> ShowS
+ StylishCabal: parseCabalFile :: String -> Result GenericPackageDescription
+ StylishCabal: plain :: Doc -> Doc
+ StylishCabal: prettyWithIndent :: Int -> GenericPackageDescription -> Doc
+ StylishCabal: readCabalFile :: Maybe FilePath -> String -> IO GenericPackageDescription
+ StylishCabal: render :: Int -> Doc -> SimpleDoc
+ StylishCabal: result :: (Maybe LineNo -> String -> b) -> ([PWarning] -> b) -> (a -> b) -> Result a -> b
- StylishCabal: displayError :: Show a => Maybe [Char] -> Maybe a -> [Char] -> IO b
+ StylishCabal: displayError :: Maybe FilePath -> Maybe LineNo -> String -> IO a
- StylishCabal: pretty :: Int -> GenericPackageDescription -> Doc
+ StylishCabal: pretty :: GenericPackageDescription -> Doc
Files
- Main.hs +14/−14
- src/Parse.hs +55/−12
- src/StylishCabal.hs +35/−7
- src/Transform.hs +1/−1
- stylish-cabal.cabal +28/−3
- tests/example.cabal +119/−0
- tests/roundtrip/SortedDesc.hs +2/−1
- tests/roundtrip/Utils.hs +6/−6
- tests/strictness/Main.hs +1/−1
Main.hs view
@@ -1,16 +1,19 @@+{-# Language CPP #-} {-# Language NoMonomorphismRestriction #-} {-# Language OverloadedStrings #-} module Main where import Data.Char-import Data.Monoid import Options.Applicative hiding (ParserResult(..)) import StylishCabal import System.Exit import System.IO-import Text.PrettyPrint.ANSI.Leijen (Doc, displayIO, displayS, plain, renderSmart) +#if !MIN_VERSION_base(4,11,0)+import Data.Monoid+#endif+ data Opts = Opts { file :: Maybe FilePath , inPlace :: Bool@@ -41,8 +44,8 @@ value 2 <> metavar "INT") -render :: Opts -> Doc -> Handle -> IO ()-render o doc h = do+output :: Opts -> Doc -> Handle -> IO ()+output o doc h = do isTerminal <- hIsTerminalDevice stdout if color o && isTerminal then displayIO h (f doc)@@ -50,7 +53,7 @@ let docStr = unlines . map stripBlank . lines $ displayS (f $ plain doc) "" hPutStr h docStr where- f = renderSmart 1.0 (width o)+ f = render (width o) stripBlank x | all isSpace x = [] | otherwise = x@@ -59,14 +62,11 @@ main = do o <- execParser $ info (opts <**> helper) (fullDesc <> progDesc "Format a Cabal file") f <- maybe getContents readFile (file o)- case pretty (indent o) <$> parse f of- Error m s -> displayError (file o) m s- Warn warnings -> printWarnings warnings- Success doc ->- if inPlace o- then case file o of- Just fname -> withFile fname WriteMode (render o doc)- Nothing -> hPutStrLn stderr inPlaceErr >> exitFailure- else render o doc stdout+ doc <- prettyWithIndent (indent o) <$> readCabalFile (file o) f+ if inPlace o+ then case file o of+ Just fname -> withFile fname WriteMode (output o doc)+ Nothing -> hPutStrLn stderr inPlaceErr >> exitFailure+ else output o doc stdout where inPlaceErr = "stylish-cabal: --in-place specified, but I'm reading from stdin"
src/Parse.hs view
@@ -1,38 +1,83 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# Language CPP #-}+{-# Language StandaloneDeriving #-}+{-# Language DeriveGeneric #-}+{-# Language DeriveDataTypeable #-}+{-# Language DeriveFunctor #-}+ module Parse- ( parse+ ( parseCabalFile+ , readCabalFile , displayError , printWarnings , Result(..)+ , result ) where +import Control.DeepSeq+import Data.Data import Data.Maybe import Distribution.PackageDescription.Parse import Distribution.ParseUtils import Distribution.Simple.Utils import Distribution.Verbosity+import GHC.Generics import System.Environment import System.Exit import System.IO +-- | Like Cabal's @ParseResult@, but treats warnings as a separate failure+-- case. data Result a = Error (Maybe LineNo)- String- | Warn [PWarning]- | Success a- deriving (Show)+ String -- ^ Parse error on the given line.+ | Warn [PWarning] -- ^ Warnings emitted during parse.+ | Success a -- ^ The input is a compliant package description.+ deriving (Show, Eq, Functor, Generic, Typeable, Data) -instance Functor Result where- fmap f (Success a) = Success (f a)- fmap _ (Warn ps) = Warn ps- fmap _ (Error m s) = Error m s+-- | Case analysis for 'Result'.+result :: (Maybe LineNo -> String -> b) -> ([PWarning] -> b) -> (a -> b) -> Result a -> b+result e w s p =+ case p of+ Error l m -> e l m+ Warn ws -> w ws+ Success r -> s r -parse input =+instance NFData a => NFData (Result a)++deriving instance Generic PWarning++deriving instance Data PWarning++#if !MIN_VERSION_base(4,8,0)+deriving instance Typeable PWarning+#endif++instance NFData PWarning++-- | This function is similar to Cabal's own file parser, except that it+-- treats warnings as a separate failure case. There are a wide range of+-- different behaviors accepted by different Cabal parser versions. Parse+-- warnings generally indicate a version-related inconsistency, so we play+-- it safe here.+parseCabalFile input = case parseGenericPackageDescription input of ParseFailed e -> uncurry Error $ locatedErrorMsg e ParseOk warnings x | null warnings -> Success x | otherwise -> Warn $ reverse warnings +-- | Shorthand to combine 'parseCabalFile' and one of 'printWarnings' or+-- 'displayError'. The given 'FilePath' is used only for error messages and+-- is not read from.+readCabalFile fpath = result (displayError fpath) printWarnings return . parseCabalFile++-- | Print some warnings to 'stderr' and exit.+printWarnings ps = mapM_ (warn normal . showPWarning "<input>") ps >> exitFailure++-- | Print a parse error to 'stderr', annotated with filepath and line+-- number (if available), then exit.+displayError :: Maybe FilePath -> Maybe LineNo -> String -> IO a displayError fpath line' message = do prog <- getProgName hPutStrLn stderr $@@ -44,5 +89,3 @@ Nothing -> "") ++ ": " ++ message exitFailure--printWarnings ps = mapM_ (warn normal . showPWarning "<input>") ps >> exitFailure
src/StylishCabal.hs view
@@ -1,16 +1,44 @@+{-# Language CPP #-}++-- | Cabal file formatter. module StylishCabal- ( pretty- , displayError+ ( -- * Formatting Cabal files+ pretty+ , prettyWithIndent+ , render+ -- * Parsing utilities+ , parseCabalFile+ , readCabalFile+ , Result(..)+ , result , printWarnings- , Result (..)- , parse+ , displayError+ -- * Reexports+ , Doc+ , plain+ , displayIO+ , displayS ) where -import Data.Monoid-import Text.PrettyPrint.ANSI.Leijen (line)+import Text.PrettyPrint.ANSI.Leijen (Doc, displayIO, displayS, line, plain, renderSmart) import Parse import Render import Transform -pretty i gpd = uncurry (blockBodyToDoc i) (toBlocks gpd) <> line+#if !MIN_VERSION_base(4,11,0)+import Data.Monoid+#endif++-- | @pretty pkg@ produces a colorized, formatted textual representation of+-- a given 'Distribution.PackageDescription.GenericPackageDescription',+-- with a default indent width of 2.+--+-- To remove syntax highlighting, you can use 'plain'.+pretty = prettyWithIndent 2++-- | Like 'pretty', but allows you to specify an indent size.+prettyWithIndent i gpd = uncurry (blockBodyToDoc i) (toBlocks gpd) <> line++-- | Render the given 'Doc' with the given width.+render = renderSmart 1.0
src/Transform.hs view
@@ -23,7 +23,7 @@ import Distribution.Types.PackageName import Distribution.Types.UnqualComponentName import Distribution.Version-#if __GLASGOW_HASKELL__ < 710+#if !MIN_VERSION_base(4,8,0) import Data.Functor ((<$>)) #endif
stylish-cabal.cabal view
@@ -1,21 +1,28 @@ name: stylish-cabal-version: 0.1.0.0+version: 0.2.0.0 synopsis: Format Cabal files description: A tool for nicely formatting your Cabal file. license: BSD3 license-file: LICENSE author: Jude Taylor maintainer: me@jude.xyz-tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2+tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2,+ GHC == 8.4.0.20180204 category: Language build-type: Simple extra-source-files: ChangeLog.md+ tests/example.cabal cabal-version: >= 1.10 source-repository head type: git location: https://github.com/pikajude/stylish-cabal.git +flag werror+ default: False+ manual: True+ description: build with -Werror+ flag test-hackage default: False manual: True@@ -29,7 +36,6 @@ on Hackage, and thus is disabled by default. library- exposed: False exposed-modules: StylishCabal other-modules: Parse Render@@ -43,19 +49,29 @@ default-extensions: NoMonomorphismRestriction ghc-options: -Wall -fno-warn-missing-signatures + if flag(werror)+ ghc-options: -Werror+ executable stylish-cabal main-is: Main.hs build-depends: base, ansi-wl-pprint, optparse-applicative, stylish-cabal default-language: Haskell2010 ghc-options: -Wall + if flag(werror)+ ghc-options: -Werror+ test-suite hlint type: exitcode-stdio-1.0 main-is: hlint.hs hs-source-dirs: tests build-depends: base, hlint default-language: Haskell2010+ ghc-options: -Wall + if flag(werror)+ ghc-options: -Werror+ test-suite strictness type: exitcode-stdio-1.0 main-is: Main.hs@@ -76,6 +92,9 @@ default-extensions: CPP ghc-options: -freduction-depth=0 + if flag(werror)+ ghc-options: -Werror+ if !(flag(test-strictness) && impl(ghc >= 8.2)) buildable: False @@ -97,6 +116,9 @@ default-extensions: CPP ghc-options: -Wall -fno-warn-missing-signatures + if flag(werror)+ ghc-options: -Werror+ test-suite roundtrip-hackage type: exitcode-stdio-1.0 main-is: Hackage.hs@@ -119,6 +141,9 @@ , wreq default-language: Haskell2010 ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -fno-warn-missing-signatures++ if flag(werror)+ ghc-options: -Werror if !flag(test-hackage) buildable: False
+ tests/example.cabal view
@@ -0,0 +1,119 @@+name: example-package+version: 1.2.3.4+cabal-version: >=1.8+build-type: Custom+license: MIT+license-files: LICENSE1, "license with spaces"+copyright: (c) 2018 John Doe+author: John Doe+maintainer: johndoe@example.com+stability: experimental+homepage: https://example.com/cabal+bug-reports: https://github.com/example/cabal+package-url: https://gituh.bcom/example/Cabal/downloads/1.cabal+synopsis: A short synopsis for this package+description:+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sagittis neque magna, eu accumsan velit convallis at. In at odio eu risus facilisis vehicula vel non elit. Vestibulum volutpat id tellus ac malesuada.+ .+ Fusce rutrum elit libero, ac malesuada nibh semper ut. Donec commodo viverra felis. Quisque tincidunt ultrices turpis. Vestibulum gravida, urna ac pharetra consectetur, nulla lacus sollicitudin diam, quis dignissim libero neque at nulla.+category: Example+tested-with: GHC >= 7.4 && < 8.4+data-files: "file1 with spaces", data/*+data-dir: .+extra-source-files: extra-file1, extra-file2+extra-doc-files: docfile1, docfile2+extra-tmp-files: tmpfile1, tmpfile2++custom-setup+ setup-depends: base >= 4.5 && < 4.11, Cabal < 1.25++source-repository head+ type: git+ location: https://github.com/pikajude/stylish-cabal.cabal+ tag: latest+ branch: master+ subdir: tests++source-repository this+ type: cvs+ location: anoncvs@cvs.foo.org:/cvs+ module: cvsmodule++flag neat-flag {+ default: False+ manual: True+ description: This is a flag with a nice little description+}++library example-internal+ exposed-modules: Example.Internal+ build-depends: base++library+ exposed-modules: Example+ exposed: False+ reexported-modules: base:Numeric as MyNumericModule+ signatures: ExampleSig+ mixins: short (Mixin as Foo.Mixin) requires (Bar as Foo.Bar), example-mixin2 (Mixin as Foo.Mixin2, Mixina as Foo.Mixina2, Mixinb as Foo.Mixinb2, Mixinc as Foo.Mixinc2), example-mixin3 (Mixin as Bar.Mixin) requires hiding (Mixin4, Mixin5), example-mixin4+ build-depends: base == 4.*, attoparsec, foo >= 1.2.3 && < 1.4, somelib ^>= 1.2.3.4, bar ^>= 3.4+ other-modules: Example.Module1, Example.Module2+ autogen-modules: Example.AutogenModule+ other-languages: Haskell98+ hs-source-dirs: src+ default-extensions: NoMonomorphismRestriction+ other-extensions: OverloadedStrings+ build-tool-depends: cpphs:cpphs >= 4.0, foo:bar == 1.2.*+ ghc-options: -Wall+ ghc-prof-options: -fcaf-all+ ghc-shared-options: -fobject-code+ build-tools: hsc2hs, unknown-build-tool+ includes: example.h+ install-includes: output.h+ include-dirs: include+ c-sources: csource.c+ js-sources: jssource.js+ extra-libraries: iconv+ extra-ghci-libraries: webkit+ extra-lib-dirs: lib, lib2+ cc-options: -compat+ cpp-options: -DFOO=1+ ld-options: -static+ pkgconfig-depends: gtk+-2.0 >= 2.10, cairo >= 1.0+ frameworks: CoreAudio+ extra-framework-dirs: frameworks+ x-a-custom-field: "Some Custom Value"++ if impl(ghc >= 7.5) && (os(darwin) || !arch(i386))+ other-extensions: PolyKinds++executable example {+ main-is: example.hs+ scope: private+}++test-suite testname+ type: exitcode-stdio-1.0+ main-is: test.hs++test-suite detailed+ type: detailed-0.9+ test-module: Example.Test++benchmark bench+ type: exitcode-stdio-1.0+ main-is: benchmark.hs++foreign-library examplelib+ type: native-shared+ lib-version-info: 6:3:2+ lib-version-linux: 4.3.2++ if os(windows)+ options: standalone+ mod-def-file: ExampleLib.def, ExampleLib2.def++ other-modules: ExampleLib.SomeModule+ build-depends: base == 4.*+ hs-source-dirs: src+ c-sources: csrc/ExampleLib.c+ default-language: Haskell2010
tests/roundtrip/SortedDesc.hs view
@@ -1,4 +1,5 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# Language CPP #-} {-# Language NamedFieldPuns #-} {-# Language RecordWildCards #-} {-# Language StandaloneDeriving #-}@@ -22,7 +23,7 @@ import Distribution.Types.UnqualComponentName import Distribution.Version import Language.Haskell.Extension-#if __GLASGOW_HASKELL__ < 710+#if !MIN_VERSION_base(4,8,0) import Data.Functor ((<$>)) #endif
tests/roundtrip/Utils.hs view
@@ -12,16 +12,16 @@ import StylishCabal import Test.Hspec.Core.Spec import Test.Hspec.Expectations.Pretty-import Text.PrettyPrint.ANSI.Leijen (displayS, plain, renderSmart)-#if __GLASGOW_HASKELL__ < 710+#if !MIN_VERSION_base(4,8,0) import Control.Applicative (pure) import Data.Functor ((<$>)) #endif- deriving instance Eq a => Eq (ParseResult a) expectParse cabalStr = do- let doc = (`displayS` "") . renderSmart 1.0 80 . plain . pretty 2 <$> parse cabalStr+ let doc =+ (`displayS` "") . render 80 . plain . pretty <$>+ parseCabalFile cabalStr case doc of StylishCabal.Success rendered -> do let original =@@ -48,8 +48,8 @@ i { itemExample = \a b c -> do- result <- itemExample i a b c- case result of+ res <- itemExample i a b c+ case res of Right (Failure _ (Reason r)) | "SKIP " `isPrefixOf` r -> pure $ Right $ Pending $ Just $ drop 5 r
tests/strictness/Main.hs view
@@ -32,7 +32,7 @@ , C.foreignLibs pd , C.testSuites pd , C.benchmarks pd)- (length $ show $ pretty 2 gpd)+ (length $ show $ pretty gpd) where pd = packageDescription gpd