hpack 0.10.0 → 0.11.0
raw patch · 6 files changed
+367/−69 lines, 6 filesdep +containersPVP ok
version bump matches the API change (PVP)
Dependencies added: containers
API changes (from Hackage documentation)
- Hpack.Config: Condition :: String -> Condition
- Hpack.Config: [conditionCondition] :: Condition -> String
- Hpack.Config: newtype Condition
+ Hpack.Config: Conditional :: String -> Section () -> Maybe (Section ()) -> Conditional
+ Hpack.Config: Flag :: String -> Maybe String -> Bool -> Bool -> Flag
+ Hpack.Config: [conditionalCondition] :: Conditional -> String
+ Hpack.Config: [conditionalElse] :: Conditional -> Maybe (Section ())
+ Hpack.Config: [conditionalThen] :: Conditional -> Section ()
+ Hpack.Config: [flagDefault] :: Flag -> Bool
+ Hpack.Config: [flagDescription] :: Flag -> Maybe String
+ Hpack.Config: [flagManual] :: Flag -> Bool
+ Hpack.Config: [flagName] :: Flag -> String
+ Hpack.Config: [libraryExposed] :: Library -> Maybe Bool
+ Hpack.Config: [packageFlags] :: Package -> [Flag]
+ Hpack.Config: [sectionBuildable] :: Section a -> Maybe Bool
+ Hpack.Config: [sectionIncludeDirs] :: Section a -> [FilePath]
+ Hpack.Config: [sectionInstallIncludes] :: Section a -> [FilePath]
+ Hpack.Config: [sectionLdOptions] :: Section a -> [LdOption]
+ Hpack.Config: data Conditional
+ Hpack.Config: data Flag
+ Hpack.Config: instance Data.Aeson.Types.Class.FromJSON (Hpack.Config.CaptureUnknownFields Hpack.Config.FlagSection)
+ Hpack.Config: instance Data.Aeson.Types.Class.FromJSON (Hpack.Config.CaptureUnknownFields Hpack.Config.ThenElse)
+ Hpack.Config: instance Data.Aeson.Types.Class.FromJSON Hpack.Config.ConditionalSection
+ Hpack.Config: instance Data.Aeson.Types.Class.FromJSON Hpack.Config.Empty
+ Hpack.Config: instance Data.Aeson.Types.Class.FromJSON Hpack.Config.FlagSection
+ Hpack.Config: instance Data.Aeson.Types.Class.FromJSON Hpack.Config.ThenElse
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.Conditional
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.ConditionalSection
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.Empty
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.Flag
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.FlagSection
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.ThenElse
+ Hpack.Config: instance GHC.Generics.Constructor Hpack.Config.C1_0FlagSection
+ Hpack.Config: instance GHC.Generics.Constructor Hpack.Config.C1_0ThenElse
+ Hpack.Config: instance GHC.Generics.Datatype Hpack.Config.D1FlagSection
+ Hpack.Config: instance GHC.Generics.Datatype Hpack.Config.D1ThenElse
+ Hpack.Config: instance GHC.Generics.Generic Hpack.Config.FlagSection
+ Hpack.Config: instance GHC.Generics.Generic Hpack.Config.ThenElse
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_0FlagSection
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_0ThenElse
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_10CommonOptions
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_11CommonOptions
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_1FlagSection
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_1ThenElse
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_21PackageConfig
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_22PackageConfig
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_2FlagSection
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_2ThenElse
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_3LibrarySection
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_8CommonOptions
+ Hpack.Config: instance GHC.Generics.Selector Hpack.Config.S1_0_9CommonOptions
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.Conditional
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.ConditionalSection
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.Empty
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.Flag
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.FlagSection
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.ThenElse
+ Hpack.Config: instance Hpack.Config.HasFieldNames Hpack.Config.Empty
+ Hpack.Config: instance Hpack.Config.HasFieldNames Hpack.Config.FlagSection
+ Hpack.Config: instance Hpack.Config.HasFieldNames Hpack.Config.ThenElse
- Hpack.Config: Library :: [String] -> [String] -> [String] -> Library
+ Hpack.Config: Library :: Maybe Bool -> [String] -> [String] -> [String] -> Library
- Hpack.Config: Package :: String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> [String] -> [String] -> [String] -> Maybe String -> Maybe FilePath -> Maybe String -> [FilePath] -> [FilePath] -> Maybe SourceRepository -> Maybe (Section Library) -> [Section Executable] -> [Section Executable] -> [Section Executable] -> Package
+ Hpack.Config: Package :: String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> [String] -> [String] -> [String] -> Maybe String -> Maybe FilePath -> Maybe String -> [Flag] -> [FilePath] -> [FilePath] -> Maybe SourceRepository -> Maybe (Section Library) -> [Section Executable] -> [Section Executable] -> [Section Executable] -> Package
- Hpack.Config: Section :: a -> [FilePath] -> [Dependency] -> [String] -> [String] -> [GhcOption] -> [GhcProfOption] -> [CppOption] -> [Section Condition] -> Section a
+ Hpack.Config: Section :: a -> [FilePath] -> [Dependency] -> [String] -> [String] -> [GhcOption] -> [GhcProfOption] -> [CppOption] -> [FilePath] -> [FilePath] -> [LdOption] -> Maybe Bool -> [Conditional] -> Section a
- Hpack.Config: [sectionConditionals] :: Section a -> [Section Condition]
+ Hpack.Config: [sectionConditionals] :: Section a -> [Conditional]
Files
- hpack.cabal +5/−2
- src/Hpack/Config.hs +137/−23
- src/Hpack/Run.hs +34/−11
- src/Hpack/Util.hs +2/−0
- test/Hpack/ConfigSpec.hs +151/−28
- test/Hpack/RunSpec.hs +38/−5
hpack.cabal view
@@ -1,9 +1,9 @@--- This file has been generated from package.yaml by hpack version 0.9.1.+-- This file has been generated from package.yaml by hpack version 0.10.0. -- -- see: https://github.com/sol/hpack name: hpack-version: 0.10.0+version: 0.11.0 synopsis: An alternative format for Haskell packages category: Development homepage: https://github.com/sol/hpack#readme@@ -30,6 +30,7 @@ , filepath , Glob , text+ , containers , unordered-containers , yaml , aeson >= 0.8@@ -59,6 +60,7 @@ , filepath , Glob , text+ , containers , unordered-containers , yaml , hpack@@ -81,6 +83,7 @@ , filepath , Glob , text+ , containers , unordered-containers , yaml , hspec == 2.*
src/Hpack/Config.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-} module Hpack.Config ( packageConfig , readPackageConfig@@ -24,11 +25,13 @@ , Section(..) , Library(..) , Executable(..)-, Condition(..)+, Conditional(..)+, Flag(..) , SourceRepository(..) #ifdef TEST , HasFieldNames(..) , CaptureUnknownFields(..)+, Empty(..) , getModules , determineModules #endif@@ -38,8 +41,9 @@ import Control.Monad.Compat import Data.Aeson.Types import Data.Data-import Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as Map+import Data.Map.Lazy (Map)+import qualified Data.Map.Lazy as Map+import qualified Data.HashMap.Lazy as HashMap import Data.List (nub, (\\), sortBy) import Data.Maybe import Data.Ord@@ -57,10 +61,10 @@ import Hpack.Yaml package :: String -> String -> Package-package name version = Package name version Nothing Nothing Nothing Nothing Nothing Nothing [] [] [] Nothing Nothing Nothing [] [] Nothing Nothing [] [] []+package name version = Package name version Nothing Nothing Nothing Nothing Nothing Nothing [] [] [] Nothing Nothing Nothing [] [] [] Nothing Nothing [] [] [] section :: a -> Section a-section a = Section a [] [] [] [] [] [] [] []+section a = Section a [] [] [] [] [] [] [] [] [] [] Nothing [] packageConfig :: FilePath packageConfig = "package.yaml"@@ -81,7 +85,7 @@ #else camelTo #endif- '-' . drop (length name)+ '-' . drop (length name) . dropWhile (== '_') type FieldName = String @@ -96,6 +100,11 @@ , captureUnknownFieldsValue :: a } deriving (Eq, Show, Generic) +captureUnknownFields :: forall a. (HasFieldNames a, FromJSON a) => Value -> Parser (CaptureUnknownFields a)+captureUnknownFields v = CaptureUnknownFields unknown <$> parseJSON v+ where+ unknown = getUnknownFields v (Proxy :: Proxy a)+ instance (HasFieldNames a, FromJSON a) => FromJSON (CaptureUnknownFields (Section a)) where parseJSON v = do (unknownFields, sect) <- toSection <$> parseJSON v <*> parseJSON v@@ -103,17 +112,21 @@ where unknownSectionFields = getUnknownFields v (Proxy :: Proxy (Section a)) +instance FromJSON (CaptureUnknownFields FlagSection) where+ parseJSON = captureUnknownFields+ getUnknownFields :: forall a. HasFieldNames a => Value -> Proxy a -> [FieldName] getUnknownFields v _ = case v of Object o -> unknown where unknown = keys \\ fields- keys = map T.unpack (Map.keys o)+ keys = map T.unpack (HashMap.keys o) fields = fieldNames (Proxy :: Proxy a) _ -> [] data LibrarySection = LibrarySection {- librarySectionExposedModules :: Maybe (List String)+ librarySectionExposed :: Maybe Bool+, librarySectionExposedModules :: Maybe (List String) , librarySectionOtherModules :: Maybe (List String) , librarySectionReexportedModules :: Maybe (List String) } deriving (Eq, Show, Generic)@@ -141,7 +154,11 @@ , commonOptionsGhcOptions :: Maybe (List GhcOption) , commonOptionsGhcProfOptions :: Maybe (List GhcProfOption) , commonOptionsCppOptions :: Maybe (List CppOption)-, commonOptionsWhen :: Maybe (List (CaptureUnknownFields (Section Condition)))+, commonOptionsIncludeDirs :: Maybe (List FilePath)+, commonOptionsInstallIncludes :: Maybe (List FilePath)+, commonOptionsLdOptions :: Maybe (List LdOption)+, commonOptionsBuildable :: Maybe Bool+, commonOptionsWhen :: Maybe (List ConditionalSection) } deriving (Eq, Show, Generic) instance HasFieldNames CommonOptions@@ -149,6 +166,18 @@ instance FromJSON CommonOptions where parseJSON = genericParseJSON_ +data ConditionalSection = ThenElseConditional (CaptureUnknownFields ThenElse) | FlatConditional (CaptureUnknownFields (Section Condition))+ deriving (Eq, Show)++instance FromJSON ConditionalSection where+ parseJSON v+ | hasKey "then" v || hasKey "else" v = ThenElseConditional <$> parseJSON v+ | otherwise = FlatConditional <$> parseJSON v++hasKey :: Text -> Value -> Bool+hasKey key (Object o) = HashMap.member key o+hasKey _ _ = False+ newtype Condition = Condition { conditionCondition :: String } deriving (Eq, Show, Generic)@@ -158,6 +187,29 @@ instance HasFieldNames Condition +data ThenElse = ThenElse {+ _thenElseCondition :: String+, _thenElseThen :: (CaptureUnknownFields (Section Empty))+, _thenElseElse :: (CaptureUnknownFields (Section Empty))+} deriving (Eq, Show, Generic)++instance FromJSON (CaptureUnknownFields ThenElse) where+ parseJSON = captureUnknownFields++instance HasFieldNames ThenElse++instance FromJSON ThenElse where+ parseJSON = genericParseJSON_++data Empty = Empty+ deriving (Eq, Show)++instance FromJSON Empty where+ parseJSON _ = return Empty++instance HasFieldNames Empty where+ fieldNames _ = []+ data PackageConfig = PackageConfig { packageConfigName :: Maybe String , packageConfigVersion :: Maybe String@@ -173,13 +225,15 @@ , packageConfigLicense :: Maybe String , packageConfigLicenseFile :: Maybe String , packageConfigTestedWith :: Maybe String+, packageConfigFlags :: Maybe (Map String (CaptureUnknownFields FlagSection)) , packageConfigExtraSourceFiles :: Maybe (List FilePath) , packageConfigDataFiles :: Maybe (List FilePath) , packageConfigGithub :: Maybe Text+, packageConfigGit :: Maybe String , packageConfigLibrary :: Maybe (CaptureUnknownFields (Section LibrarySection))-, packageConfigExecutables :: Maybe (HashMap String (CaptureUnknownFields (Section ExecutableSection)))-, packageConfigTests :: Maybe (HashMap String (CaptureUnknownFields (Section ExecutableSection)))-, packageConfigBenchmarks :: Maybe (HashMap String (CaptureUnknownFields (Section ExecutableSection)))+, packageConfigExecutables :: Maybe (Map String (CaptureUnknownFields (Section ExecutableSection)))+, packageConfigTests :: Maybe (Map String (CaptureUnknownFields (Section ExecutableSection)))+, packageConfigBenchmarks :: Maybe (Map String (CaptureUnknownFields (Section ExecutableSection))) } deriving (Eq, Show, Generic) instance HasFieldNames PackageConfig@@ -275,6 +329,7 @@ , packageLicense :: Maybe String , packageLicenseFile :: Maybe FilePath , packageTestedWith :: Maybe String+, packageFlags :: [Flag] , packageExtraSourceFiles :: [FilePath] , packageDataFiles :: [FilePath] , packageSourceRepository :: Maybe SourceRepository@@ -285,7 +340,8 @@ } deriving (Eq, Show) data Library = Library {- libraryExposedModules :: [String]+ libraryExposed :: Maybe Bool+, libraryExposedModules :: [String] , libraryOtherModules :: [String] , libraryReexportedModules :: [String] } deriving (Eq, Show)@@ -305,12 +361,43 @@ , sectionGhcOptions :: [GhcOption] , sectionGhcProfOptions :: [GhcProfOption] , sectionCppOptions :: [CppOption]-, sectionConditionals :: [Section Condition]+, sectionIncludeDirs :: [FilePath]+, sectionInstallIncludes :: [FilePath]+, sectionLdOptions :: [LdOption]+, sectionBuildable :: Maybe Bool+, sectionConditionals :: [Conditional] } deriving (Eq, Show, Functor, Foldable, Traversable) +data Conditional = Conditional {+ conditionalCondition :: String+, conditionalThen :: Section ()+, conditionalElse :: Maybe (Section ())+} deriving (Eq, Show)+ instance HasFieldNames a => HasFieldNames (Section a) where fieldNames Proxy = fieldNames (Proxy :: Proxy a) ++ fieldNames (Proxy :: Proxy CommonOptions) +data FlagSection = FlagSection {+ _flagSectionDescription :: Maybe String+, _flagSectionManual :: Bool+, _flagSectionDefault :: Bool+} deriving (Eq, Show, Generic)++instance HasFieldNames FlagSection++instance FromJSON FlagSection where+ parseJSON = genericParseJSON_++data Flag = Flag {+ flagName :: String+, flagDescription :: Maybe String+, flagManual :: Bool+, flagDefault :: Bool+} deriving (Eq, Show)++toFlag :: (String, FlagSection) -> Flag+toFlag (name, FlagSection description manual def) = Flag name description manual def+ data SourceRepository = SourceRepository { sourceRepositoryUrl :: String , sourceRepositorySubdir :: Maybe String@@ -355,6 +442,7 @@ , packageLicense = packageConfigLicense , packageLicenseFile = packageConfigLicenseFile <|> (guard licenseFileExists >> Just "LICENSE") , packageTestedWith = packageConfigTestedWith+ , packageFlags = flags , packageExtraSourceFiles = extraSourceFiles , packageDataFiles = dataFiles , packageSourceRepository = sourceRepository@@ -366,6 +454,7 @@ warnings = formatUnknownFields "package description" unknownFields+ ++ flagWarnings ++ maybe [] (formatUnknownFields "library section") (captureUnknownFieldsFields <$> packageConfigLibrary) ++ formatUnknownSectionFields "executable" executableSections ++ formatUnknownSectionFields "test" testsSections@@ -384,7 +473,16 @@ benchmarkSections :: [(String, CaptureUnknownFields (Section ExecutableSection))] benchmarkSections = toList packageConfigBenchmarks - toList :: Maybe (HashMap String a) -> [(String, a)]+ (flagWarnings, flags) = (concatMap formatUnknownFlagFields xs, map (toFlag . fmap captureUnknownFieldsValue) xs)+ where+ xs :: [(String, CaptureUnknownFields FlagSection)]+ xs = toList packageConfigFlags++ formatUnknownFlagFields :: (String, CaptureUnknownFields a) -> [String]+ formatUnknownFlagFields (name, fields) = map f (captureUnknownFieldsFields fields)+ where f field = "Ignoring unknown field " ++ show field ++ " for flag " ++ show name++ toList :: Maybe (Map String a) -> [(String, a)] toList = Map.toList . fromMaybe mempty mLibrarySection :: Maybe (Section LibrarySection)@@ -406,7 +504,10 @@ f name = "Specified source-dir " ++ show name ++ " does not exist" sourceRepository :: Maybe SourceRepository- sourceRepository = parseGithub <$> packageConfigGithub+ sourceRepository = github <|> (`SourceRepository` Nothing) <$> packageConfigGit++ github :: Maybe SourceRepository+ github = parseGithub <$> packageConfigGithub where parseGithub :: Text -> SourceRepository parseGithub input = case map T.unpack $ T.splitOn "/" input of@@ -419,14 +520,14 @@ Just Nothing -> Nothing _ -> join packageConfigHomepage <|> fromGithub where- fromGithub = (++ "#readme") . sourceRepositoryUrl <$> sourceRepository+ fromGithub = (++ "#readme") . sourceRepositoryUrl <$> github bugReports :: Maybe String bugReports = case packageConfigBugReports of Just Nothing -> Nothing _ -> join packageConfigBugReports <|> fromGithub where- fromGithub = (++ "/issues") . sourceRepositoryUrl <$> sourceRepository+ fromGithub = (++ "/issues") . sourceRepositoryUrl <$> github toLibrary :: FilePath -> String -> Section global -> Section LibrarySection -> IO (Section Library) toLibrary dir name globalOptions library = traverse fromLibrarySection sect@@ -442,7 +543,7 @@ modules <- concat <$> mapM (getModules dir) sourceDirs let (exposedModules, otherModules) = determineModules name modules librarySectionExposedModules librarySectionOtherModules reexportedModules = fromMaybeList librarySectionReexportedModules- return (Library exposedModules otherModules reexportedModules)+ return (Library librarySectionExposed exposedModules otherModules reexportedModules) toExecutables :: FilePath -> Section global -> [(String, Section ExecutableSection)] -> IO [Section Executable] toExecutables dir globalOptions executables = mapM toExecutable sections@@ -467,7 +568,7 @@ mergeSections :: Section global -> Section a -> Section a mergeSections globalOptions options- = Section a sourceDirs dependencies defaultExtensions otherExtensions ghcOptions ghcProfOptions cppOptions conditionals+ = Section a sourceDirs dependencies defaultExtensions otherExtensions ghcOptions ghcProfOptions cppOptions includeDirs installIncludes ldOptions buildable conditionals where a = sectionData options sourceDirs = sectionSourceDirs globalOptions ++ sectionSourceDirs options@@ -476,12 +577,16 @@ ghcOptions = sectionGhcOptions globalOptions ++ sectionGhcOptions options ghcProfOptions = sectionGhcProfOptions globalOptions ++ sectionGhcProfOptions options cppOptions = sectionCppOptions globalOptions ++ sectionCppOptions options+ includeDirs = sectionIncludeDirs globalOptions ++ sectionIncludeDirs options+ installIncludes = sectionInstallIncludes globalOptions ++ sectionInstallIncludes options+ ldOptions = sectionLdOptions globalOptions ++ sectionLdOptions options+ buildable = sectionBuildable options <|> sectionBuildable globalOptions dependencies = sectionDependencies globalOptions ++ sectionDependencies options conditionals = sectionConditionals globalOptions ++ sectionConditionals options toSection :: a -> CommonOptions -> ([FieldName], Section a) toSection a CommonOptions{..}- = (concat unknownFields, Section a sourceDirs dependencies defaultExtensions otherExtensions ghcOptions ghcProfOptions cppOptions conditionals)+ = (concat unknownFields, Section a sourceDirs dependencies defaultExtensions otherExtensions ghcOptions ghcProfOptions cppOptions includeDirs installIncludes ldOptions buildable conditionals) where sourceDirs = fromMaybeList commonOptionsSourceDirs defaultExtensions = fromMaybeList commonOptionsDefaultExtensions@@ -489,9 +594,18 @@ ghcOptions = fromMaybeList commonOptionsGhcOptions ghcProfOptions = fromMaybeList commonOptionsGhcProfOptions cppOptions = fromMaybeList commonOptionsCppOptions+ includeDirs = fromMaybeList commonOptionsIncludeDirs+ installIncludes = fromMaybeList commonOptionsInstallIncludes+ ldOptions = fromMaybeList commonOptionsLdOptions+ buildable = commonOptionsBuildable dependencies = fromMaybeList commonOptionsDependencies- (unknownFields, conditionals) =- unzip [(field, value) | CaptureUnknownFields field value <- fromMaybeList commonOptionsWhen]+ (unknownFields, conditionals) = unzip (map toConditional $ fromMaybeList commonOptionsWhen)++toConditional :: ConditionalSection -> ([FieldName], Conditional)+toConditional x = case x of+ ThenElseConditional (CaptureUnknownFields fields (ThenElse condition (CaptureUnknownFields fieldsThen then_) (CaptureUnknownFields fieldsElse else_))) ->+ (fields ++ fieldsThen ++ fieldsElse, Conditional condition (() <$ then_) (Just (() <$ else_)))+ FlatConditional (CaptureUnknownFields fields sect) -> (fields, Conditional (conditionCondition $ sectionData sect) (() <$ sect) Nothing) pathsModuleFromPackageName :: String -> String pathsModuleFromPackageName name = "Paths_" ++ map f name
src/Hpack/Run.hs view
@@ -11,6 +11,7 @@ , defaultRenderSettings #ifdef TEST , renderConditional+, renderFlag , renderSourceRepository , formatDescription #endif@@ -67,6 +68,7 @@ stanzas = extraSourceFiles : dataFiles : sourceRepository+ ++ map renderFlag packageFlags ++ library ++ renderExecutables packageExecutables ++ renderTests packageTests@@ -157,6 +159,14 @@ , Field "subdir" (maybe "" Literal sourceRepositorySubdir) ] +renderFlag :: Flag -> Element+renderFlag Flag {..} = Stanza ("flag " ++ flagName) $ description ++ [+ Field "manual" (Literal $ show flagManual)+ , Field "default" (Literal $ show flagDefault)+ ]+ where+ description = maybe [] (return . Field "description" . Literal) flagDescription+ renderExecutables :: [Section Executable] -> [Element] renderExecutables = map renderExecutable @@ -189,13 +199,17 @@ renderLibrary :: Section Library -> Element renderLibrary sect@(sectionData -> Library{..}) = Stanza "library" $- renderSection sect ++ [+ renderSection sect +++ maybe [] (return . renderExposed) libraryExposed ++ [ renderExposedModules libraryExposedModules , renderOtherModules libraryOtherModules , renderReexportedModules libraryReexportedModules , defaultLanguage ] +renderExposed :: Bool -> Element+renderExposed = Field "exposed" . Literal . show+ renderSection :: Section a -> [Element] renderSection Section{..} = [ renderSourceDirs sectionSourceDirs@@ -204,33 +218,36 @@ , renderGhcOptions sectionGhcOptions , renderGhcProfOptions sectionGhcProfOptions , renderCppOptions sectionCppOptions+ , Field "include-dirs" (LineSeparatedList sectionIncludeDirs)+ , Field "install-includes" (LineSeparatedList sectionInstallIncludes)+ , renderLdOptions sectionLdOptions , renderDependencies sectionDependencies ]- ++ map renderConditional sectionConditionals+ ++ maybe [] (return . renderBuildable) sectionBuildable+ ++ concatMap renderConditional sectionConditionals -renderConditional :: Section Condition -> Element-renderConditional sect = Stanza condition (renderSection sect)+renderConditional :: Conditional -> [Element]+renderConditional (Conditional condition sect mElse) = Stanza ("if " ++ condition) (renderSection sect) : else_ where- condition :: String- condition = "if " ++ conditionCondition (sectionData sect)+ else_ = maybe [] (return . Stanza "else" . renderSection) mElse defaultLanguage :: Element defaultLanguage = Field "default-language" "Haskell2010" renderSourceDirs :: [String] -> Element-renderSourceDirs dirs = Field "hs-source-dirs" (CommaSeparatedList dirs)+renderSourceDirs = Field "hs-source-dirs" . CommaSeparatedList renderExposedModules :: [String] -> Element-renderExposedModules modules = Field "exposed-modules" (LineSeparatedList modules)+renderExposedModules = Field "exposed-modules" . LineSeparatedList renderOtherModules :: [String] -> Element-renderOtherModules modules = Field "other-modules" (LineSeparatedList modules)+renderOtherModules = Field "other-modules" . LineSeparatedList renderReexportedModules :: [String] -> Element-renderReexportedModules modules = Field "reexported-modules" (LineSeparatedList modules)+renderReexportedModules = Field "reexported-modules" . LineSeparatedList renderDependencies :: [Dependency] -> Element-renderDependencies dependencies = Field "build-depends" (CommaSeparatedList $ map dependencyName dependencies)+renderDependencies = Field "build-depends" . CommaSeparatedList . map dependencyName renderGhcOptions :: [GhcOption] -> Element renderGhcOptions = Field "ghc-options" . WordList@@ -240,6 +257,12 @@ renderCppOptions :: [CppOption] -> Element renderCppOptions = Field "cpp-options" . WordList++renderLdOptions :: [LdOption] -> Element+renderLdOptions = Field "ld-options" . WordList++renderBuildable :: Bool -> Element+renderBuildable = Field "buildable" . Literal . show renderDefaultExtensions :: [String] -> Element renderDefaultExtensions = Field "default-extensions" . WordList
src/Hpack/Util.hs view
@@ -5,6 +5,7 @@ , GhcOption , GhcProfOption , CppOption+, LdOption , parseMain , toModule , getFilesRecursive@@ -53,6 +54,7 @@ type GhcOption = String type GhcProfOption = String type CppOption = String+type LdOption = String parseMain :: String -> (FilePath, [GhcOption]) parseMain main = case reverse name of
test/Hpack/ConfigSpec.hs view
@@ -17,6 +17,7 @@ import Control.Arrow import System.Directory (createDirectory) import Data.Yaml+import Data.Either.Compat import Hpack.Util import Hpack.Config hiding (package)@@ -29,7 +30,7 @@ executable name main_ = Executable name main_ [] library :: Library-library = Library [] [] []+library = Library Nothing [] [] [] withPackage :: String -> IO () -> (([String], Package) -> Expectation) -> Expectation withPackage content beforeAction expectation = withTempDirectory $ \dir_ -> do@@ -52,15 +53,6 @@ withPackageWarnings_ :: String -> ([String] -> Expectation) -> Expectation withPackageWarnings_ content = withPackageWarnings content (return ()) -data Dummy = Dummy- deriving (Eq, Show)--instance FromJSON Dummy where- parseJSON _ = return Dummy--instance HasFieldNames Dummy where- fieldNames _ = []- spec :: Spec spec = do describe "parseJSON" $ do@@ -70,33 +62,101 @@ dependencies: hpack |] captureUnknownFieldsValue <$> decodeEither input- `shouldBe` Right (section Dummy){sectionDependencies = ["hpack"]}+ `shouldBe` Right (section Empty){sectionDependencies = ["hpack"]} - it "accepts conditionals" $ do+ it "accepts includes-dirs" $ do let input = [i|- when:- condition: os(windows)- dependencies: Win32+ include-dirs:+ - foo+ - bar |]- conditionals = [(section $ Condition "os(windows)"){sectionDependencies = ["Win32"]}] captureUnknownFieldsValue <$> decodeEither input- `shouldBe` Right (section Dummy){sectionConditionals = conditionals}+ `shouldBe` Right (section Empty){sectionIncludeDirs = ["foo", "bar"]} - it "warns on unknown fields" $ do+ it "accepts install-includes" $ do let input = [i|- foo: 23- when:- - condition: os(windows)- bar: 23+ install-includes:+ - foo.h+ - bar.h+ |]+ captureUnknownFieldsValue <$> decodeEither input+ `shouldBe` Right (section Empty){sectionInstallIncludes = ["foo.h", "bar.h"]}++ context "when parsing conditionals" $ do+ it "accepts conditionals" $ do+ let input = [i|+ when:+ condition: os(windows)+ dependencies: Win32+ |]+ conditionals = [+ Conditional "os(windows)"+ (section ()){sectionDependencies = ["Win32"]}+ Nothing+ ]+ captureUnknownFieldsValue <$> decodeEither input+ `shouldBe` Right (section Empty){sectionConditionals = conditionals}++ it "warns on unknown fields" $ do+ let input = [i|+ foo: 23+ when:+ - condition: os(windows)+ bar: 23+ when:+ condition: os(windows)+ bar2: 23+ - condition: os(windows)+ baz: 23+ |]+ captureUnknownFieldsFields <$> (decodeEither input :: Either String (CaptureUnknownFields (Section Empty)))+ `shouldBe` Right ["foo", "bar", "bar2", "baz"]++ context "when parsing conditionals with else-branch" $ do+ it "accepts conditionals with else-branch" $ do+ let input = [i| when: condition: os(windows)- bar2: 23- - condition: os(windows)- baz: 23- |]- captureUnknownFieldsFields <$> (decodeEither input :: Either String (CaptureUnknownFields (Section Dummy)))- `shouldBe` Right ["foo", "bar", "bar2", "baz"]+ then:+ dependencies: Win32+ else:+ dependencies: unix+ |]+ conditionals = [+ Conditional "os(windows)"+ (section ()){sectionDependencies = ["Win32"]}+ (Just (section ()){sectionDependencies = ["unix"]})+ ]+ r :: Either String (Section Empty)+ r = captureUnknownFieldsValue <$> decodeEither input+ sectionConditionals <$> r `shouldBe` Right conditionals + it "rejects invalid conditionals" $ do+ let input = [i|+ when:+ condition: os(windows)+ then:+ dependencies: Win32+ else: null+ |]++ r :: Either String (Section Empty)+ r = captureUnknownFieldsValue <$> decodeEither input+ sectionConditionals <$> r `shouldSatisfy` isLeft++ it "warns on unknown fields" $ do+ let input = [i|+ when:+ condition: os(windows)+ foo: null+ then:+ bar: null+ else:+ baz: null+ |]+ captureUnknownFieldsFields <$> (decodeEither input :: Either String (CaptureUnknownFields (Section Empty)))+ `shouldBe` Right ["foo", "bar", "baz"]+ context "when parsing a Dependency" $ do it "accepts simple dependencies" $ do parseEither parseJSON "hpack" `shouldBe` Right (Dependency "hpack" Nothing)@@ -334,6 +394,30 @@ |] (packageLicenseFile >>> (`shouldBe` Just "FOO")) + it "accepts flags" $ do+ withPackageConfig_ [i|+ flags:+ integration-tests:+ description: Run the integration test suite+ manual: yes+ default: no+ |]+ (packageFlags >>> (`shouldBe` [Flag "integration-tests" (Just "Run the integration test suite") True False]))++ it "warns on unknown fields in flag sections" $ do+ withPackageWarnings_ [i|+ flags:+ integration-tests:+ description: Run the integration test suite+ manual: yes+ default: no+ foo: 23+ |]+ (`shouldBe` [+ "Ignoring unknown field \"foo\" for flag \"integration-tests\""+ ]+ )+ it "accepts extra-source-files" $ do withPackageConfig [i| extra-source-files:@@ -369,6 +453,12 @@ |] (packageSourceRepository >>> (`shouldBe` Just (SourceRepository "https://github.com/hspec/hspec" (Just "hspec-core")))) + it "accepts arbitrary git URLs as source repository" $ do+ withPackageConfig_ [i|+ git: https://gitlab.com/gitlab-org/gitlab-ce.git+ |]+ (packageSourceRepository >>> (`shouldBe` Just (SourceRepository "https://gitlab.com/gitlab-org/gitlab-ce.git" Nothing)))+ it "accepts CPP options" $ do withPackageConfig_ [i| cpp-options: -DFOO@@ -393,6 +483,32 @@ } ) + it "accepts ld-options" $ do+ withPackageConfig_ [i|+ library:+ ld-options: -static+ |]+ (`shouldBe` package {+ packageLibrary = Just (section library) {sectionLdOptions = ["-static"]}+ }+ )++ it "accepts buildable" $ do+ withPackageConfig_ [i|+ buildable: no+ library:+ buildable: yes++ executables:+ foo:+ main: Main.hs+ |]+ (`shouldBe` package {+ packageLibrary = Just (section library) {sectionBuildable = Just True}+ , packageExecutables = [(section $ executable "foo" "Main.hs") {sectionBuildable = Just False}]+ }+ )+ context "when reading library section" $ do it "warns on unknown fields" $ do withPackageWarnings_ [i|@@ -441,6 +557,13 @@ library: {} |] (packageLibrary >>> (`shouldBe` Just (section library) {sectionSourceDirs = ["foo", "bar"]}))++ it "allows to specify exposed" $ do+ withPackageConfig_ [i|+ library:+ exposed: no+ |]+ (packageLibrary >>> (`shouldBe` Just (section library{libraryExposed = Just False}))) it "allows to specify exposed-modules" $ do withPackageConfig [i|
test/Hpack/RunSpec.hs view
@@ -91,6 +91,18 @@ , " bar" ] + it "includes buildable" $ do+ renderPackage_ 0 [] package {packageLibrary = Just (section library){sectionBuildable = Just False}} `shouldBe` unlines [+ "name: foo"+ , "version: 0.0.0"+ , "build-type: Simple"+ , "cabal-version: >= 1.10"+ , ""+ , "library"+ , " buildable: False"+ , " default-language: Haskell2010"+ ]+ context "when rendering library section" $ do it "renders library section" $ do renderPackage_ 0 [] package {packageLibrary = Just $ section library} `shouldBe` unlines [@@ -204,22 +216,43 @@ ] describe "renderConditional" $ do it "renders conditionals" $ do- let conditional = (section $ Condition "os(windows)"){sectionDependencies = ["Win32"]}- render defaultRenderSettings 0 (renderConditional conditional) `shouldBe` [+ let conditional = Conditional "os(windows)" (section ()) {sectionDependencies = ["Win32"]} Nothing+ concatMap (render defaultRenderSettings 0) (renderConditional conditional) `shouldBe` [ "if os(windows)" , " build-depends:" , " Win32" ] + it "renders conditionals with else-branch" $ do+ let conditional = Conditional "os(windows)" (section ()) {sectionDependencies = ["Win32"]} (Just $ (section ()) {sectionDependencies = ["unix"]})+ concatMap (render defaultRenderSettings 0) (renderConditional conditional) `shouldBe` [+ "if os(windows)"+ , " build-depends:"+ , " Win32"+ , "else"+ , " build-depends:"+ , " unix"+ ]+ it "renders nested conditionals" $ do- let conditional = (section $ Condition "arch(i386)"){sectionGhcOptions = ["-threaded"], sectionConditionals = [innerConditional]}- innerConditional = (section $ Condition "os(windows)"){sectionDependencies = ["Win32"]}- render defaultRenderSettings 0 (renderConditional conditional) `shouldBe` [+ let conditional = Conditional "arch(i386)" (section ()) {sectionGhcOptions = ["-threaded"], sectionConditionals = [innerConditional]} Nothing+ innerConditional = Conditional "os(windows)" (section ()) {sectionDependencies = ["Win32"]} Nothing+ concatMap (render defaultRenderSettings 0) (renderConditional conditional) `shouldBe` [ "if arch(i386)" , " ghc-options: -threaded" , " if os(windows)" , " build-depends:" , " Win32"+ ]++ describe "renderFlag" $ do+ it "renders flags" $ do+ let flag = (Flag "foo" (Just "some flag") True False)+ render defaultRenderSettings 0 (renderFlag flag) `shouldBe` [+ "flag foo"+ , " description: some flag"+ , " manual: True"+ , " default: False" ] describe "formatDescription" $ do