hpack 0.29.7 → 0.30.0
raw patch · 14 files changed
+633/−166 lines, 14 filesdep ~yamlPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: yaml
API changes (from Hackage documentation)
+ Hpack.Config: BuildTool :: String -> String -> BuildTool
+ Hpack.Config: LocalBuildTool :: String -> BuildTool
+ Hpack.Config: SystemBuildTools :: Map String DependencyVersion -> SystemBuildTools
+ Hpack.Config: [sectionSystemBuildTools] :: Section a -> SystemBuildTools
+ Hpack.Config: [unSystemBuildTools] :: SystemBuildTools -> Map String DependencyVersion
+ Hpack.Config: data BuildTool
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.BuildTool
+ Hpack.Config: instance GHC.Classes.Ord Hpack.Config.BuildTool
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.BuildTool
+ Hpack.Config: newtype SystemBuildTools
- Hpack: setDecode :: (FilePath -> IO (Either String Value)) -> Options -> Options
+ Hpack: setDecode :: (FilePath -> IO (Either String ([String], Value))) -> Options -> Options
- Hpack.Config: DecodeOptions :: ProgramName -> FilePath -> Maybe FilePath -> FilePath -> IO (Either String Value) -> DecodeOptions
+ Hpack.Config: DecodeOptions :: ProgramName -> FilePath -> Maybe FilePath -> FilePath -> IO (Either String ([String], Value)) -> DecodeOptions
- Hpack.Config: Section :: a -> [FilePath] -> Dependencies -> [String] -> [String] -> [String] -> [GhcOption] -> [GhcProfOption] -> [GhcjsOption] -> [CppOption] -> [CcOption] -> [FilePath] -> [CxxOption] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [LdOption] -> Maybe Bool -> [Conditional (Section a)] -> Dependencies -> [Verbatim] -> Section a
+ Hpack.Config: Section :: a -> [FilePath] -> Dependencies -> [String] -> [String] -> [String] -> [GhcOption] -> [GhcProfOption] -> [GhcjsOption] -> [CppOption] -> [CcOption] -> [FilePath] -> [CxxOption] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [LdOption] -> Maybe Bool -> [Conditional (Section a)] -> Map BuildTool DependencyVersion -> SystemBuildTools -> [Verbatim] -> Section a
- Hpack.Config: [decodeOptionsDecode] :: DecodeOptions -> FilePath -> IO (Either String Value)
+ Hpack.Config: [decodeOptionsDecode] :: DecodeOptions -> FilePath -> IO (Either String ([String], Value))
- Hpack.Config: [sectionBuildTools] :: Section a -> Dependencies
+ Hpack.Config: [sectionBuildTools] :: Section a -> Map BuildTool DependencyVersion
- Hpack.Yaml: decodeYaml :: FilePath -> IO (Either String Value)
+ Hpack.Yaml: decodeYaml :: FilePath -> IO (Either String ([String], Value))
Files
- CHANGELOG.md +11/−0
- hpack.cabal +8/−5
- src/Data/Aeson/Config/Parser.hs +3/−0
- src/Hpack.hs +1/−1
- src/Hpack/Config.hs +149/−29
- src/Hpack/Render.hs +37/−6
- src/Hpack/Syntax/BuildTools.hs +94/−0
- src/Hpack/Syntax/Dependency.hs +1/−0
- src/Hpack/Util.hs +2/−2
- src/Hpack/Yaml.hs +12/−4
- test/EndToEndSpec.hs +173/−78
- test/Hpack/ConfigSpec.hs +34/−40
- test/Hpack/Syntax/BuildToolsSpec.hs +102/−0
- test/Hpack/UtilSpec.hs +6/−1
CHANGELOG.md view
@@ -1,3 +1,14 @@+## Changes in 0.30.0+ - Warn on duplicate fields (see #283)+ - Always render `cabal-version` as `x.y` instead of `>= x.y` so that `cabal+ check` does not complain (see #322)+ - Extend `build-tools` so that it subsumes Cabal's `build-tools` and+ `build-tool-depends` (see #254)+ - Add support for `system-build-tools`+ - Keep declaration order for literal files in c-sources (and other fields+ that accept glob patterns). This is crucial as a workaround for+ https://ghc.haskell.org/trac/ghc/ticket/13786 (see #324)+ ## Changes in 0.29.7 - Expose more stuff from `Hpack.Yaml` so that it can be used by third parties
hpack.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 8d1eb0679326dc7c31be647812822700dc8277a27737239f5a704e45f367abdf+-- hash: a1136b4a83bc50abf6e1fac6ef221b3df0c837b248aa357568449996e9d20078 name: hpack-version: 0.29.7+version: 0.30.0 synopsis: A modern format for Haskell packages description: See README at <https://github.com/sol/hpack#readme> category: Development@@ -50,7 +50,7 @@ , transformers , unordered-containers , vector- , yaml+ , yaml >=0.10.0 exposed-modules: Hpack Hpack.Config@@ -68,6 +68,7 @@ Hpack.Options Hpack.Render.Dsl Hpack.Render.Hints+ Hpack.Syntax.BuildTools Hpack.Syntax.Defaults Hpack.Syntax.Dependency Hpack.Syntax.DependencyVersion@@ -105,7 +106,7 @@ , transformers , unordered-containers , vector- , yaml+ , yaml >=0.10.0 other-modules: Paths_hpack default-language: Haskell2010@@ -147,7 +148,7 @@ , transformers , unordered-containers , vector- , yaml >=0.8.28+ , yaml >=0.10.0 other-modules: Data.Aeson.Config.FromValueSpec Data.Aeson.Config.TypesSpec@@ -163,6 +164,7 @@ Hpack.Render.DslSpec Hpack.Render.HintsSpec Hpack.RenderSpec+ Hpack.Syntax.BuildToolsSpec Hpack.Syntax.DefaultsSpec Hpack.Syntax.DependencySpec Hpack.Syntax.GitSpec@@ -183,6 +185,7 @@ Hpack.Render Hpack.Render.Dsl Hpack.Render.Hints+ Hpack.Syntax.BuildTools Hpack.Syntax.Defaults Hpack.Syntax.Dependency Hpack.Syntax.DependencyVersion
src/Data/Aeson/Config/Parser.hs view
@@ -24,6 +24,9 @@ , Array , liftParser++, fromAesonPath+, formatPath ) where import Control.Monad
src/Hpack.hs view
@@ -118,7 +118,7 @@ setProgramName name options@Options{..} = options {optionsDecodeOptions = optionsDecodeOptions {decodeOptionsProgramName = name}} -setDecode :: (FilePath -> IO (Either String Value)) -> Options -> Options+setDecode :: (FilePath -> IO (Either String ([String], Value))) -> Options -> Options setDecode decode options@Options{..} = options {optionsDecodeOptions = optionsDecodeOptions {decodeOptionsDecode = decode}}
src/Hpack/Config.hs view
@@ -42,6 +42,8 @@ , SourceDependency(..) , GitRef , GitUrl+, BuildTool(..)+, SystemBuildTools(..) , GhcOption , Verbatim(..) , VerbatimValue(..)@@ -69,12 +71,15 @@ , LibrarySection(..) , fromLibrarySectionInConditional , formatOrList++, toBuildTool #endif ) where import Control.Applicative-import Control.Arrow ((>>>))+import Control.Arrow ((>>>), (&&&)) import Control.Monad+import Data.Either import Data.Bifunctor import Data.Bitraversable import Data.Map.Lazy (Map)@@ -110,6 +115,7 @@ import qualified Hpack.Yaml as Yaml import Hpack.Syntax.DependencyVersion import Hpack.Syntax.Dependency+import Hpack.Syntax.BuildTools import Hpack.License import Hpack.CabalFile (parseVersion) @@ -175,7 +181,7 @@ deps xs = [(name, version) | (name, version) <- (Map.toList . unDependencies . sectionDependencies) xs] section :: a -> Section a-section a = Section a [] mempty [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] mempty []+section a = Section a [] mempty [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] mempty mempty [] packageConfig :: FilePath packageConfig = "package.yaml"@@ -277,7 +283,8 @@ , commonOptionsLdOptions :: Maybe (List LdOption) , commonOptionsBuildable :: Maybe Bool , commonOptionsWhen :: Maybe (List (ConditionalSection cSources cxxSources jsSources a))-, commonOptionsBuildTools :: Maybe Dependencies+, commonOptionsBuildTools :: Maybe BuildTools+, commonOptionsSystemBuildTools :: Maybe SystemBuildTools , commonOptionsVerbatim :: Maybe (List Verbatim) } deriving (Functor, Generic) @@ -310,6 +317,7 @@ , commonOptionsBuildable = Nothing , commonOptionsWhen = Nothing , commonOptionsBuildTools = Nothing+ , commonOptionsSystemBuildTools = Nothing , commonOptionsVerbatim = Nothing } mappend = (<>)@@ -339,7 +347,8 @@ , commonOptionsLdOptions = commonOptionsLdOptions a <> commonOptionsLdOptions b , commonOptionsBuildable = commonOptionsBuildable b <|> commonOptionsBuildable a , commonOptionsWhen = commonOptionsWhen a <> commonOptionsWhen b- , commonOptionsBuildTools = commonOptionsBuildTools b <> commonOptionsBuildTools a+ , commonOptionsBuildTools = commonOptionsBuildTools a <> commonOptionsBuildTools b+ , commonOptionsSystemBuildTools = commonOptionsSystemBuildTools b <> commonOptionsSystemBuildTools a , commonOptionsVerbatim = commonOptionsVerbatim a <> commonOptionsVerbatim b } @@ -561,13 +570,16 @@ type Errors = ExceptT String decodeYaml :: FromValue a => ProgramName -> FilePath -> Warnings (Errors IO) a-decodeYaml programName file = lift (ExceptT $ Yaml.decodeYaml file) >>= decodeValue programName file+decodeYaml programName file = do+ (warnings, a) <- lift (ExceptT $ Yaml.decodeYaml file)+ tell warnings+ decodeValue programName file a data DecodeOptions = DecodeOptions { decodeOptionsProgramName :: ProgramName , decodeOptionsTarget :: FilePath , decodeOptionsUserDataDir :: Maybe FilePath-, decodeOptionsDecode :: FilePath -> IO (Either String Value)+, decodeOptionsDecode :: FilePath -> IO (Either String ([String], Value)) } newtype ProgramName = ProgramName String@@ -588,7 +600,8 @@ readPackageConfig :: DecodeOptions -> IO (Either String DecodeResult) readPackageConfig (DecodeOptions programName file mUserDataDir readValue) = runExceptT $ fmap addCabalFile . runWriterT $ do- value <- lift . ExceptT $ readValue file+ (warnings, value) <- lift . ExceptT $ readValue file+ tell warnings config <- decodeValue programName file value dir <- liftIO $ takeDirectory <$> canonicalizePath file userDataDir <- liftIO $ maybe (getAppUserDataDirectory "hpack") return mUserDataDir@@ -652,11 +665,9 @@ Nothing -> Nothing inferredCabalVersion :: String- inferredCabalVersion- | version >= makeVersion [2,1] = showVersion version- | otherwise = (">= " ++) . showVersion $ version+ inferredCabalVersion = showVersion version - version = fromMaybe (makeVersion [1,10]) $ maximum [+ version = fromMaybe (makeVersion [1,12]) $ maximum [ packageCabalVersion , packageLibrary >>= libraryCabalVersion , internalLibsCabalVersion packageInternalLibraries@@ -705,16 +716,64 @@ executableHasGeneratedModules = any (not . null . executableGeneratedModules) sectionCabalVersion :: Section a -> Maybe Version- sectionCabalVersion sect = maximum [+ sectionCabalVersion sect = maximum $ [ makeVersion [2,2] <$ guard (sectionSatisfies (not . null . sectionCxxSources) sect) , makeVersion [2,2] <$ guard (sectionSatisfies (not . null . sectionCxxOptions) sect)- ]+ ] ++ map versionFromSystemBuildTool systemBuildTools+ where+ versionFromSystemBuildTool name+ | name `elem` known_1_10 = Nothing+ | name `elem` known_1_14 = Just (makeVersion [1,14])+ | name `elem` known_1_22 = Just (makeVersion [1,22])+ | otherwise = Just (makeVersion [2,0]) + known_1_10 = [+ "ghc"+ , "ghc-pkg"+ , "hugs"+ , "ffihugs"+ , "nhc98"+ , "hmake"+ , "jhc"+ , "lhc"+ , "lhc-pkg"+ , "uhc"+ , "gcc"+ , "ranlib"+ , "ar"+ , "strip"+ , "ld"+ , "tar"+ , "pkg-config"+ ] \\ [+ -- Support for these build tools has been removed from Cabal at some point+ "hugs"+ , "ffihugs"+ , "nhc98"+ , "ranlib"+ , "lhc"+ , "lhc-pkg"+ ]+ known_1_14 = [+ "hpc"+ ]+ known_1_22 = [+ "ghcjs"+ , "ghcjs-pkg"+ -- , "haskell-suite" // not a real build tool+ -- , "haskell-suite-pkg" // not a real build tool+ ]++ systemBuildTools :: [String]+ systemBuildTools = Map.keys $ unSystemBuildTools $ sectionAll sectionSystemBuildTools sect+ sectionSatisfies :: (Section a -> Bool) -> Section a -> Bool sectionSatisfies p sect = or [ p sect , any (any (sectionSatisfies p)) (sectionConditionals sect) ]+ sectionAll :: (Semigroup b, Monoid b) => (Section a -> b) -> Section a -> b+ sectionAll f sect = f sect <> foldMap (foldMap $ sectionAll f) (sectionConditionals sect) decodeValue :: FromValue a => ProgramName -> FilePath -> Value -> Warnings (Errors IO) a decodeValue (ProgramName programName) file value = do@@ -798,6 +857,9 @@ , executableGeneratedModules :: [String] } deriving (Eq, Show) +data BuildTool = BuildTool String String | LocalBuildTool String+ deriving (Show, Eq, Ord)+ data Section a = Section { sectionData :: a , sectionSourceDirs :: [FilePath]@@ -823,7 +885,8 @@ , sectionLdOptions :: [LdOption] , sectionBuildable :: Maybe Bool , sectionConditionals :: [Conditional (Section a)]-, sectionBuildTools :: Dependencies+, sectionBuildTools :: Map BuildTool DependencyVersion+, sectionSystemBuildTools :: SystemBuildTools , sectionVerbatim :: [Verbatim] } deriving (Eq, Show, Functor, Foldable, Traversable) @@ -962,20 +1025,23 @@ toPackage_ :: MonadIO m => FilePath -> Product GlobalOptions (PackageConfig CSources CxxSources JsSources) -> Warnings m (Package, String) toPackage_ dir (Product g PackageConfig{..}) = do+ executableMap <- toExecutableMap packageName_ packageConfigExecutables packageConfigExecutable let globalVerbatim = commonOptionsVerbatim g globalOptions = g {commonOptionsVerbatim = Nothing} - toSect :: Monoid a => WithCommonOptions CSources CxxSources JsSources a -> Section a- toSect = toSection . first ((mempty <$ globalOptions) <>)+ executableNames = maybe [] Map.keys executableMap - toLib = toLibrary dir packageName_ . toSect- toExecutables = liftIO . maybe mempty (traverse $ toExecutable dir packageName_ . toSect)+ toSect :: (Monad m, Monoid a) => WithCommonOptions CSources CxxSources JsSources a -> Warnings m (Section a)+ toSect = toSection packageName_ executableNames . first ((mempty <$ globalOptions) <>) - mLibrary <- liftIO $ traverse toLib packageConfigLibrary- internalLibraries <- liftIO $ maybe mempty (traverse toLib) packageConfigInternalLibraries+ toLib = toSect >=> liftIO . toLibrary dir packageName_+ toExecutables = maybe (return mempty) (traverse $ toSect >=> liftIO . toExecutable dir packageName_) - executables <- toExecutableMap packageName_ packageConfigExecutables packageConfigExecutable >>= toExecutables+ mLibrary <- traverse toLib packageConfigLibrary+ internalLibraries <- maybe (return mempty) (traverse toLib) packageConfigInternalLibraries++ executables <- toExecutables executableMap tests <- toExecutables packageConfigTests benchmarks <- toExecutables packageConfigBenchmarks @@ -1237,10 +1303,14 @@ , sectionConditionals = map (fmap flatten) sectionConditionals } -toSection :: WithCommonOptions CSources CxxSources JsSources a -> Section a-toSection = go+toSection :: Monad m => String -> [String] -> WithCommonOptions CSources CxxSources JsSources a -> Warnings m (Section a)+toSection packageName_ executableNames = go where- go (Product CommonOptions{..} a) = Section {+ go (Product CommonOptions{..} a) = do+ (systemBuildTools, buildTools) <- maybe (return mempty) toBuildTools commonOptionsBuildTools++ conditionals <- mapM toConditional (fromMaybeList commonOptionsWhen)+ return Section { sectionData = a , sectionSourceDirs = fromMaybeList commonOptionsSourceDirs , sectionDefaultExtensions = fromMaybeList commonOptionsDefaultExtensions@@ -1264,17 +1334,67 @@ , sectionBuildable = commonOptionsBuildable , sectionDependencies = fromMaybe mempty commonOptionsDependencies , sectionPkgConfigDependencies = fromMaybeList commonOptionsPkgConfigDependencies- , sectionConditionals = map toConditional (fromMaybeList commonOptionsWhen)- , sectionBuildTools = fromMaybe mempty commonOptionsBuildTools+ , sectionConditionals = conditionals+ , sectionBuildTools = buildTools+ , sectionSystemBuildTools = systemBuildTools <> fromMaybe mempty commonOptionsSystemBuildTools , sectionVerbatim = fromMaybeList commonOptionsVerbatim }+ toBuildTools :: Monad m => BuildTools -> Warnings m (SystemBuildTools, Map BuildTool DependencyVersion)+ toBuildTools = fmap (mkSystemBuildTools &&& mkBuildTools) . mapM toBuildTool_ . unBuildTools+ where+ mkSystemBuildTools = SystemBuildTools . Map.fromList . lefts+ mkBuildTools = Map.fromList . rights+ toBuildTool_ (t, v) = bimap addVersion addVersion <$> toBuildTool packageName_ executableNames t+ where+ addVersion = flip (,) v - toConditional :: ConditionalSection CSources CxxSources JsSources a -> Conditional (Section a)+ toConditional :: Monad m => ConditionalSection CSources CxxSources JsSources a -> Warnings m (Conditional (Section a)) toConditional x = case x of- ThenElseConditional (Product (ThenElse then_ else_) c) -> conditional c (go then_) (Just $ go else_)- FlatConditional (Product sect c) -> conditional c (go sect) Nothing+ ThenElseConditional (Product (ThenElse then_ else_) c) -> conditional c <$> (go then_) <*> (Just <$> go else_)+ FlatConditional (Product sect c) -> conditional c <$> (go sect) <*> pure Nothing where conditional (Condition (Cond c)) = Conditional c++toBuildTool :: Monad m => String -> [String] -> ParseBuildTool -> Warnings m (Either String BuildTool)+toBuildTool packageName_ executableNames = \ case+ QualifiedBuildTool pkg executable+ | pkg == packageName_ && executable `elem` executableNames -> localBuildTool executable+ | otherwise -> buildTool pkg executable+ UnqualifiedBuildTool executable+ | executable `elem` executableNames -> localBuildTool executable+ | Just pkg <- lookup executable legacyTools -> legacyBuildTool pkg executable+ | executable `elem` legacySystemTools -> legacySystemBuildTool executable+ | otherwise -> buildTool executable executable+ where+ buildTool pkg = return . Right . BuildTool pkg+ systemBuildTool = return . Left+ localBuildTool = return . Right . LocalBuildTool+ legacyBuildTool pkg executable = warnLegacyTool pkg executable >> buildTool pkg executable+ legacySystemBuildTool executable = warnLegacySystemTool executable >> systemBuildTool executable+ legacyTools = [+ ("gtk2hsTypeGen", "gtk2hs-buildtools")+ , ("gtk2hsHookGenerator", "gtk2hs-buildtools")+ , ("gtk2hsC2hs", "gtk2hs-buildtools")+ , ("cabal", "cabal-install")+ , ("grgen", "cgen")+ , ("cgen-hs", "cgen")+ ]+ legacySystemTools = [+ "ghc"+ , "git"+ , "llvm-config"+ , "gfortran"+ , "gcc"+ , "couchdb"+ , "mcc"+ , "nix-store"+ , "nix-instantiate"+ , "nix-hash"+ , "nix-env"+ , "nix-build"+ ]+ warnLegacyTool pkg name = tell ["Usage of the unqualified build-tool name " ++ show name ++ " is deprecated! Please use the qualified name \"" ++ pkg ++ ":" ++ name ++ "\" instead!"]+ warnLegacySystemTool name = tell ["Listing " ++ show name ++ " under build-tools is deperecated! Please list system executables under system-build-tools instead!"] pathsModuleFromPackageName :: String -> String pathsModuleFromPackageName name = "Paths_" ++ map f name
src/Hpack/Render.hs view
@@ -241,8 +241,8 @@ , renderLdOptions sectionLdOptions , renderDependencies "build-depends" sectionDependencies , Field "pkgconfig-depends" (CommaSeparatedList sectionPkgConfigDependencies)- , renderDependencies "build-tools" sectionBuildTools ]+ ++ renderBuildTools sectionBuildTools sectionSystemBuildTools ++ maybe [] (return . renderBuildable) sectionBuildable ++ map (renderConditional renderSectionData) sectionConditionals ++ extraFieldsEnd@@ -313,12 +313,43 @@ renderDependencies name = Field name . CommaSeparatedList . map renderDependency . Map.toList . unDependencies renderDependency :: (String, DependencyVersion) -> String-renderDependency (name, version) = name ++ v+renderDependency (name, version) = name ++ renderVersion version++renderVersion :: DependencyVersion -> String+renderVersion version = case version of+ AnyVersion -> ""+ VersionRange x -> " " ++ x+ SourceDependency _ -> ""++renderBuildTools :: Map BuildTool DependencyVersion -> SystemBuildTools -> [Element]+renderBuildTools (map renderBuildTool . Map.toList -> xs) systemBuildTools = [+ Field "build-tools" (CommaSeparatedList $ [x | BuildTools x <- xs] ++ renderSystemBuildTools systemBuildTools)+ , Field "build-tool-depends" (CommaSeparatedList [x | BuildToolDepends x <- xs])+ ]++data RenderBuildTool = BuildTools String | BuildToolDepends String++renderBuildTool :: (BuildTool, DependencyVersion) -> RenderBuildTool+renderBuildTool (buildTool, renderVersion -> version) = case buildTool of+ LocalBuildTool executable -> BuildTools (executable ++ version)+ BuildTool pkg executable+ | pkg == executable && executable `elem` knownBuildTools -> BuildTools (executable ++ version)+ | otherwise -> BuildToolDepends (pkg ++ ":" ++ executable ++ version) where- v = case version of- AnyVersion -> ""- VersionRange x -> " " ++ x- SourceDependency _ -> ""+ knownBuildTools :: [String]+ knownBuildTools = [+ "alex"+ , "c2hs"+ , "cpphs"+ , "greencard"+ , "haddock"+ , "happy"+ , "hsc2hs"+ , "hscolour"+ ]++renderSystemBuildTools :: SystemBuildTools -> [String]+renderSystemBuildTools = map renderDependency . Map.toList . unSystemBuildTools renderGhcOptions :: [GhcOption] -> Element renderGhcOptions = Field "ghc-options" . WordList
+ src/Hpack/Syntax/BuildTools.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ViewPatterns #-}+module Hpack.Syntax.BuildTools (+ BuildTools(..)+, ParseBuildTool(..)+, SystemBuildTools(..)+) where++import Data.Text (Text)+import qualified Data.Text as T+import Data.Semigroup (Semigroup(..))+import Data.Bifunctor+import Control.Applicative+import qualified Distribution.Package as D+import Data.Map.Lazy (Map)+import qualified Data.Map.Lazy as Map++import qualified Distribution.Types.ExeDependency as D+import qualified Distribution.Types.UnqualComponentName as D+import qualified Distribution.Types.LegacyExeDependency as D++import Data.Aeson.Config.FromValue++import Hpack.Syntax.DependencyVersion+import Hpack.Syntax.Dependency (parseDependency)++newtype BuildTools = BuildTools {+ unBuildTools :: [(ParseBuildTool, DependencyVersion)]+} deriving (Show, Eq, Semigroup, Monoid)++data ParseBuildTool = QualifiedBuildTool String String | UnqualifiedBuildTool String+ deriving (Show, Eq)++instance FromValue BuildTools where+ fromValue v = case v of+ String s -> BuildTools . return <$> buildToolFromString s+ Array xs -> BuildTools <$> parseArray buildToolFromValue xs+ Object _ -> BuildTools . map (first nameToBuildTool) . Map.toList <$> fromValue v+ _ -> typeMismatch "Array, Object, or String" v++nameToBuildTool :: String -> ParseBuildTool+nameToBuildTool name = case break (== ':') name of+ (executable, "") -> UnqualifiedBuildTool executable+ (package, executable) -> QualifiedBuildTool package (drop 1 executable)++buildToolFromValue :: Value -> Parser (ParseBuildTool, DependencyVersion)+buildToolFromValue v = case v of+ String s -> buildToolFromString s+ Object o -> sourceDependency o+ _ -> typeMismatch "Object or String" v+ where+ sourceDependency o = (,) <$> (nameToBuildTool <$> name) <*> (SourceDependency <$> fromValue v)+ where+ name :: Parser String+ name = o .: "name"++buildToolFromString :: Text -> Parser (ParseBuildTool, DependencyVersion)+buildToolFromString s = parseQualifiedBuildTool s <|> parseUnqualifiedBuildTool s++parseQualifiedBuildTool :: Monad m => Text -> m (ParseBuildTool, DependencyVersion)+parseQualifiedBuildTool = fmap f . cabalParse "build tool" . T.unpack+ where+ f :: D.ExeDependency -> (ParseBuildTool, DependencyVersion)+ f (D.ExeDependency package executable version) = (+ QualifiedBuildTool (D.unPackageName package) (D.unUnqualComponentName executable)+ , dependencyVersionFromCabal version+ )++parseUnqualifiedBuildTool :: Monad m => Text -> m (ParseBuildTool, DependencyVersion)+parseUnqualifiedBuildTool = fmap (first UnqualifiedBuildTool) . parseDependency "build tool"++newtype SystemBuildTools = SystemBuildTools {+ unSystemBuildTools :: Map String DependencyVersion+} deriving (Show, Eq, Semigroup, Monoid)++instance FromValue SystemBuildTools where+ fromValue v = case v of+ String s -> fromList . return <$> parseSystemBuildTool s+ Array xs -> fromList <$> parseArray (withText parseSystemBuildTool) xs+ Object _ -> SystemBuildTools <$> fromValue v+ _ -> typeMismatch "Array, Object, or String" v+ where+ fromList :: [(String, DependencyVersion)] -> SystemBuildTools+ fromList = SystemBuildTools . Map.fromList++parseSystemBuildTool :: Monad m => Text -> m (String, DependencyVersion)+parseSystemBuildTool = fmap fromCabal . parseCabalBuildTool . T.unpack+ where+ fromCabal :: D.LegacyExeDependency -> (String, DependencyVersion)+ fromCabal (D.LegacyExeDependency name version) = (name, dependencyVersionFromCabal version)++ parseCabalBuildTool :: Monad m => String -> m D.LegacyExeDependency+ parseCabalBuildTool = cabalParse "system build tool"
src/Hpack/Syntax/Dependency.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE TypeFamilies #-} module Hpack.Syntax.Dependency ( Dependencies(..)+, parseDependency ) where import Data.Text (Text)
src/Hpack/Util.hs view
@@ -113,11 +113,11 @@ files <- globDir compiledPatterns dir >>= mapM removeDirectories let results :: [GlobResult]- results = map (uncurry $ uncurry GlobResult) $ zip (zip patterns compiledPatterns) files+ results = map (uncurry $ uncurry GlobResult) $ zip (zip patterns compiledPatterns) (map sort files) return (combineResults results) where combineResults :: [GlobResult] -> ([String], [FilePath])- combineResults = bimap concat (nub . sort . concat) . unzip . map fromResult+ combineResults = bimap concat (nub . concat) . unzip . map fromResult fromResult :: GlobResult -> ([String], [FilePath]) fromResult (GlobResult pattern compiledPattern files) = case files of
src/Hpack/Yaml.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE LambdaCase #-} module Hpack.Yaml ( -- | /__NOTE:__/ This module is exposed to allow integration of Hpack into -- other tools. It is not meant for general use by end users. The following@@ -16,14 +17,21 @@ , module Data.Aeson.Config.FromValue ) where -import Data.Yaml hiding (decodeFile, decodeFileEither)+import Data.Bifunctor+import Data.Yaml hiding (decodeFile, decodeFileWithWarnings) import Data.Yaml.Include+import Data.Yaml.Internal (Warning(..)) import Data.Aeson.Config.FromValue+import Data.Aeson.Config.Parser (fromAesonPath, formatPath) -decodeYaml :: FilePath -> IO (Either String Value)+formatWarning :: FilePath -> Warning -> String+formatWarning file = \ case+ DuplicateKey path -> file ++ ": Duplicate field " ++ formatPath (fromAesonPath path)++decodeYaml :: FilePath -> IO (Either String ([String], Value)) decodeYaml file = do- result <- decodeFileEither file- return $ either (Left . errToString) Right result+ result <- decodeFileWithWarnings file+ return $ either (Left . errToString) (Right . first (map $ formatWarning file)) result where errToString err = file ++ case err of AesonException e -> ": " ++ e
test/EndToEndSpec.hs view
@@ -39,6 +39,15 @@ other-modules: Paths_foo |]++ it "warns on duplicate fields" $ do+ [i|+ name: foo+ name: foo+ |] `shouldWarn` [+ "package.yaml: Duplicate field $.name"+ ]+ describe "spec-version" $ do it "accepts spec-version" $ do [i|@@ -448,7 +457,7 @@ extra-doc-files: CHANGES.markdown README.markdown- |]) {packageCabalVersion = ">= 1.18"}+ |]) {packageCabalVersion = "1.18"} it "accepts glob patterns" $ do touch "CHANGES.markdown"@@ -460,7 +469,7 @@ extra-doc-files: CHANGES.markdown README.markdown- |]) {packageCabalVersion = ">= 1.18"}+ |]) {packageCabalVersion = "1.18"} it "warns if a glob pattern does not match anything" $ do [i|@@ -469,6 +478,124 @@ - "*.markdown" |] `shouldWarn` ["Specified pattern \"*.markdown\" for extra-doc-files does not match any files"] + describe "build-tools" $ do+ it "adds known build tools to build-tools" $ do+ [i|+ executable:+ build-tools:+ alex == 0.1.0+ |] `shouldRenderTo` executable_ "foo" [i|+ build-tools:+ alex ==0.1.0+ |]++ it "adds other build tools to build-tool-depends" $ do+ [i|+ executable:+ build-tools:+ hspec-discover: 0.1.0+ |] `shouldRenderTo` (executable_ "foo" [i|+ build-tool-depends:+ hspec-discover:hspec-discover ==0.1.0+ |]) {+ -- NOTE: We do not set this to 2.0 on purpose, so that the .cabal+ -- file is compatible with a wider range of Cabal versions!+ packageCabalVersion = "1.12"+ }++ context "when the name of a build tool matches an executable from the same package" $ do+ it "adds it to build-tools" $ do+ [i|+ executables:+ bar:+ build-tools:+ - bar+ |] `shouldRenderTo` executable_ "bar" [i|+ build-tools:+ bar+ |]++ it "gives per-section unqualified names precedence over global qualified names" $ do+ [i|+ build-tools:+ - foo:bar == 0.1.0+ executables:+ bar:+ build-tools:+ - bar == 0.2.0+ |] `shouldRenderTo` executable_ "bar" [i|+ build-tools:+ bar ==0.2.0+ |]++ it "gives per-section qualified names precedence over global unqualified names" $ do+ [i|+ build-tools:+ - bar == 0.1.0+ executables:+ bar:+ build-tools:+ - foo:bar == 0.2.0+ |] `shouldRenderTo` executable_ "bar" [i|+ build-tools:+ bar ==0.2.0+ |]++ context "when the name of a build tool matches a legacy system build tool" $ do+ it "adds it to build-tools" $ do+ [i|+ executable:+ build-tools:+ ghc >= 7.10+ |] `shouldRenderTo` (executable_ "foo" [i|+ build-tools:+ ghc >=7.10+ |]) { packageWarnings = ["Listing \"ghc\" under build-tools is deperecated! Please list system executables under system-build-tools instead!"] }++ describe "system-build-tools" $ do+ it "adds system build tools to build-tools" $ do+ [i|+ executable:+ system-build-tools:+ ghc >= 7.10+ |] `shouldRenderTo` executable_ "foo" [i|+ build-tools:+ ghc >=7.10+ |]++ context "with hpc" $ do+ it "infers cabal-version 1.14" $ do+ [i|+ executable:+ system-build-tools:+ hpc+ |] `shouldRenderTo` (executable_ "foo" [i|+ build-tools:+ hpc+ |]) {packageCabalVersion = "1.14"}++ context "with ghcjs" $ do+ it "infers cabal-version 1.22" $ do+ [i|+ executable:+ system-build-tools:+ ghcjs+ |] `shouldRenderTo` (executable_ "foo" [i|+ build-tools:+ ghcjs+ |]) {packageCabalVersion = "1.22"}++ context "with an unknown system build tool" $ do+ it "infers cabal-version 2.0" $ do+ [i|+ executable:+ system-build-tools:+ g++ >= 5.4.0+ |] `shouldRenderTo` (executable_ "foo" [i|+ build-tools:+ g++ >=5.4.0+ |]) {packageCabalVersion = "2.0"}+ describe "dependencies" $ do it "accepts single dependency" $ do [i|@@ -615,8 +742,8 @@ - cxxbits/*.cc |] `shouldRenderTo` (executable_ "foo" [i| cxx-sources:- cxxbits/bar.cc foo.cc+ cxxbits/bar.cc |]) {packageCabalVersion = "2.2"} describe "extra-lib-dirs" $ do@@ -671,72 +798,39 @@ bar |] - describe "c-sources" $ before_ (touch "cbits/foo.c" >> touch "cbits/bar.c") $ do- context "with internal-libraries" $ do- it "warns when a glob pattern does not match any files" $ do- [i|- name: foo- internal-libraries:- bar:- c-sources: foo/*.c- |] `shouldWarn` pure "Specified pattern \"foo/*.c\" for c-sources does not match any files"-- context "with library" $ do- it "accepts global c-sources" $ do- [i|- c-sources: cbits/*.c- library: {}- |] `shouldRenderTo` library_ [i|- c-sources:- cbits/bar.c- cbits/foo.c- |]-- it "accepts c-sources" $ do- [i|- library:- c-sources: cbits/*.c- |] `shouldRenderTo` library_ [i|+ describe "c-sources" $ before_ (touch "cbits/foo.c" >> touch "cbits/bar.c" >> touch "cbits/baz.c") $ do+ it "keeps declaration order" $ do+ -- IMPORTANT: This is crucial as a workaround for https://ghc.haskell.org/trac/ghc/ticket/13786+ [i|+ library: c-sources:- cbits/bar.c- cbits/foo.c- |]-- it "accepts c-sources in conditional" $ do- [i|- library:- when:- condition: os(windows)- c-sources: cbits/*.c- |] `shouldRenderTo` library_ [i|- if os(windows)- c-sources:- cbits/bar.c- cbits/foo.c- |]+ - cbits/foo.c+ - cbits/bar.c+ - cbits/baz.c+ |] `shouldRenderTo` library_ [i|+ c-sources:+ cbits/foo.c+ cbits/bar.c+ cbits/baz.c+ |] - context "with executables" $ do- it "accepts global c-sources" $ do- [i|+ it "accepts glob patterns" $ do+ [i|+ library: c-sources: cbits/*.c- executables:- foo: {}- |] `shouldRenderTo` executable_ "foo" [i|- c-sources:- cbits/bar.c- cbits/foo.c- |]+ |] `shouldRenderTo` library_ [i|+ c-sources:+ cbits/bar.c+ cbits/baz.c+ cbits/foo.c+ |] - it "accepts c-sources" $ do- [i|- executables:- foo:- c-sources: cbits/*.c- |] `shouldRenderTo` executable_ "foo" [i|- c-sources:- cbits/bar.c- cbits/foo.c- |]+ it "warns when a glob pattern does not match any files" $ do+ [i|+ name: foo+ library:+ c-sources: foo/*.c+ |] `shouldWarn` pure "Specified pattern \"foo/*.c\" for c-sources does not match any files" describe "custom-setup" $ do it "warns on unknown fields" $ do@@ -779,7 +873,7 @@ |] `shouldRenderTo` (library_ [i| reexported-modules: Baz- |]) {packageCabalVersion = ">= 1.22"}+ |]) {packageCabalVersion = "1.22"} it "accepts signatures" $ do [i|@@ -788,7 +882,7 @@ |] `shouldRenderTo` (library_ [i| signatures: Foo- |]) {packageCabalVersion = ">= 2.0"}+ |]) {packageCabalVersion = "2.0"} context "when package.yaml contains duplicate modules" $ do it "generates a cabal file with duplicate modules" $ do@@ -957,7 +1051,7 @@ autogen-modules: Foo Bar- |]) {packageCabalVersion = ">= 2.0"}+ |]) {packageCabalVersion = "2.0"} it "does not infer any mentioned generated modules" $ do touch "src/Exposed.hs"@@ -978,7 +1072,7 @@ autogen-modules: Exposed Other- |]) {packageCabalVersion = ">= 2.0"}+ |]) {packageCabalVersion = "2.0"} it "does not infer any generated modules mentioned inside conditionals" $ do touch "src/Exposed.hs"@@ -1003,7 +1097,7 @@ autogen-modules: Other Exposed- |]) {packageCabalVersion = ">= 2.0"}+ |]) {packageCabalVersion = "2.0"} describe "internal-libraries" $ do it "accepts internal-libraries" $ do@@ -1108,7 +1202,7 @@ Foo autogen-modules: Foo- |]) {packageCabalVersion = ">= 2.0"}+ |]) {packageCabalVersion = "2.0"} context "with conditional" $ do it "doesn't infer any modules mentioned in that conditional" $ do@@ -1320,8 +1414,8 @@ it "overrides header fields" $ do [i| verbatim:- cabal-version: ">= 2.0"- |] `shouldRenderTo` (package "") {packageCabalVersion = ">= 2.0"}+ cabal-version: foo+ |] `shouldRenderTo` (package "") {packageCabalVersion = "foo"} it "overrides other fields" $ do touch "foo"@@ -1382,7 +1476,7 @@ deriving Eq instance Show RenderResult where- show (RenderResult warnings output) = unlines (map ("WARNING in " ++) warnings) ++ output+ show (RenderResult warnings output) = unlines (map ("WARNING: " ++) warnings) ++ output shouldRenderTo :: HasCallStack => String -> Package -> Expectation shouldRenderTo input p = do@@ -1391,7 +1485,7 @@ createDirectory currentDirectory withCurrentDirectory currentDirectory $ do (warnings, output) <- run ".." (".." </> packageConfig) expected- RenderResult warnings (dropEmptyLines output) `shouldBe` RenderResult [] expected+ RenderResult warnings (dropEmptyLines output) `shouldBe` RenderResult (packageWarnings p) expected where expected = dropEmptyLines (renderPackage p) dropEmptyLines = unlines . filter (not . null) . lines@@ -1408,7 +1502,7 @@ run_ "" packageConfig "" `shouldReturn` Left expected customSetup :: String -> Package-customSetup a = (package content) {packageCabalVersion = ">= 1.24", packageBuildType = "Custom"}+customSetup a = (package content) {packageCabalVersion = "1.24", packageBuildType = "Custom"} where content = [i| custom-setup@@ -1436,7 +1530,7 @@ |] internalLibrary :: String -> String -> Package-internalLibrary name e = (package content) {packageCabalVersion = ">= 2.0"}+internalLibrary name e = (package content) {packageCabalVersion = "2.0"} where content = [i| library #{name}@@ -1465,7 +1559,7 @@ |] package :: String -> Package-package = Package "foo" "0.0.0" "Simple" ">= 1.10"+package c = Package "foo" "0.0.0" "Simple" "1.12" c [] data Package = Package { packageName :: String@@ -1473,6 +1567,7 @@ , packageBuildType :: String , packageCabalVersion :: String , packageContent :: String+, packageWarnings :: [String] } renderPackage :: Package -> String
test/Hpack/ConfigSpec.hs view
@@ -23,8 +23,10 @@ import System.Directory (createDirectory) import Data.Either import qualified Data.Map.Lazy as Map+import Control.Monad.Trans.Writer (runWriter) import Hpack.Syntax.Dependency+import Hpack.Syntax.BuildTools import Hpack.Config hiding (package) import qualified Hpack.Config as Config @@ -158,6 +160,38 @@ touch (dir </> "Setup.hs") getModules dir "./." `shouldReturn` ["Foo"] + describe "toBuildTool" $ do+ let toBuildTool_ = runWriter . toBuildTool "my-package" ["foo"]+ context "with an UnqualifiedBuildTool" $ do+ context "when name does not match a local executable" $ do+ it "returns a BuildTool" $ do+ toBuildTool_ (UnqualifiedBuildTool "bar") `shouldBe` (Right (BuildTool "bar" "bar"), [])++ context "when name matches a local executable" $ do+ it "returns a LocalBuildTool" $ do+ toBuildTool_ (UnqualifiedBuildTool "foo") `shouldBe` (Right (LocalBuildTool "foo"), [])++ context "when name matches a legacy executable" $ do+ it "warns" $ do+ toBuildTool_ (UnqualifiedBuildTool "gtk2hsTypeGen") `shouldBe` (Right (BuildTool "gtk2hs-buildtools" "gtk2hsTypeGen"), ["Usage of the unqualified build-tool name \"gtk2hsTypeGen\" is deprecated! Please use the qualified name \"gtk2hs-buildtools:gtk2hsTypeGen\" instead!"])++ context "when name matches a legacy system build tool" $ do+ it "warns" $ do+ toBuildTool_ (UnqualifiedBuildTool "ghc") `shouldBe` (Left "ghc", ["Listing \"ghc\" under build-tools is deperecated! Please list system executables under system-build-tools instead!"])++ context "with a QualifiedBuildTool" $ do+ context "when only package matches the current package" $ do+ it "returns a BuildTool" $ do+ toBuildTool_ (QualifiedBuildTool "my-package" "bar") `shouldBe` (Right (BuildTool "my-package" "bar"), [])++ context "when only executable matches a local executable" $ do+ it "returns a BuildTool" $ do+ toBuildTool_ (QualifiedBuildTool "other-package" "foo") `shouldBe` (Right (BuildTool "other-package" "foo"), [])++ context "when both package matches the current package and executable matches a local executable" $ do+ it "returns a LocalBuildTool" $ do+ toBuildTool_ (QualifiedBuildTool "my-package" "foo") `shouldBe` (Right (LocalBuildTool "foo"), [])+ describe "readPackageConfig" $ do it "warns on missing name" $ do withPackageWarnings_ [i|@@ -401,15 +435,6 @@ |] (packageLibrary >>> (`shouldBe` Just (section library) {sectionSourceDirs = ["foo", "bar"]})) - it "accepts build-tools" $ do- withPackageConfig_ [i|- library:- build-tools:- - alex- - happy- |]- (packageLibrary >>> (`shouldBe` Just (section library) {sectionBuildTools = deps ["alex", "happy"]}))- it "accepts default-extensions" $ do withPackageConfig_ [i| library:@@ -437,15 +462,6 @@ |] (packageLibrary >>> (`shouldBe` Just (section library) {sectionSourceDirs = ["foo", "bar"]})) - it "accepts global build-tools" $ do- withPackageConfig_ [i|- build-tools:- - alex- - happy- library: {}- |]- (packageLibrary >>> (`shouldBe` Just (section library) {sectionBuildTools = deps ["alex", "happy"]}))- it "allows to specify exposed" $ do withPackageConfig_ [i| library:@@ -502,17 +518,6 @@ |] (packageExecutables >>> (`shouldBe` Map.fromList [("foo", (section (executable "Main.hs") {executableOtherModules = ["Paths_foo"]}) {sectionSourceDirs = ["foo", "bar"]})])) - it "accepts build-tools" $ do- withPackageConfig_ [i|- executables:- foo:- main: Main.hs- build-tools:- - alex- - happy- |]- (packageExecutables >>> (`shouldBe` Map.fromList [("foo", (section $ executable "Main.hs") {sectionBuildTools = deps ["alex", "happy"]})]))- it "accepts global source-dirs" $ do withPackageConfig_ [i| source-dirs:@@ -523,17 +528,6 @@ main: Main.hs |] (packageExecutables >>> (`shouldBe` Map.fromList [("foo", (section (executable "Main.hs") {executableOtherModules = ["Paths_foo"]}) {sectionSourceDirs = ["foo", "bar"]})]))-- it "accepts global build-tools" $ do- withPackageConfig_ [i|- build-tools:- - alex- - happy- executables:- foo:- main: Main.hs- |]- (packageExecutables >>> (`shouldBe` Map.fromList [("foo", (section $ executable "Main.hs") {sectionBuildTools = deps ["alex", "happy"]})])) it "accepts default-extensions" $ do withPackageConfig_ [i|
+ test/Hpack/Syntax/BuildToolsSpec.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE OverloadedLists #-}+module Hpack.Syntax.BuildToolsSpec (spec) where++import Helper++import Data.Aeson.Config.FromValueSpec (shouldDecodeTo_)++import Hpack.Syntax.DependencyVersion+import Hpack.Syntax.BuildTools++spec :: Spec+spec = do+ describe "fromValue" $ do+ context "when parsing BuildTools" $ do+ context "with a scalar" $ do+ it "accepts qualified names" $ do+ [yaml|+ foo:bar+ |] `shouldDecodeTo_` BuildTools [(QualifiedBuildTool "foo" "bar", AnyVersion)]++ it "accepts qualified names with a version" $ do+ [yaml|+ foo:bar >= 0.1.0+ |] `shouldDecodeTo_` BuildTools [(QualifiedBuildTool "foo" "bar", VersionRange ">=0.1.0")]++ it "accepts unqualified names" $ do+ [yaml|+ foo+ |] `shouldDecodeTo_` BuildTools [(UnqualifiedBuildTool "foo", AnyVersion)]++ it "accepts unqualified names with a version" $ do+ [yaml|+ foo >= 0.1.0+ |] `shouldDecodeTo_` BuildTools [(UnqualifiedBuildTool "foo", VersionRange ">=0.1.0")]++ context "with a mapping" $ do+ it "accepts qualified names" $ do+ [yaml|+ foo:bar: 0.1.0+ |] `shouldDecodeTo_` BuildTools [(QualifiedBuildTool "foo" "bar", VersionRange "==0.1.0")]++ it "accepts unqualified names" $ do+ [yaml|+ foo: 0.1.0+ |] `shouldDecodeTo_` BuildTools [(UnqualifiedBuildTool "foo", VersionRange "==0.1.0")]++ context "with a list" $ do+ it "accepts a list of build tools" $ do+ [yaml|+ - foo:one+ - bar:two >= 0.1.0+ - baz == 0.2.0+ |] `shouldDecodeTo_` BuildTools [+ (QualifiedBuildTool "foo" "one", AnyVersion)+ , (QualifiedBuildTool "bar" "two", VersionRange ">=0.1.0")+ , (UnqualifiedBuildTool "baz", VersionRange "==0.2.0")+ ]++ it "accepts source dependencies with a qualified name" $ do+ let source = GitRef "https://github.com/sol/hpack" "master" Nothing+ [yaml|+ - name: hpack:foo+ github: sol/hpack+ ref: master+ |] `shouldDecodeTo_` BuildTools [(QualifiedBuildTool "hpack" "foo", SourceDependency source)]++ it "accepts source dependencies with an unqualified name" $ do+ let source = GitRef "https://github.com/sol/hpack" "master" Nothing+ [yaml|+ - name: hpack+ github: sol/hpack+ ref: master+ |] `shouldDecodeTo_` BuildTools [(UnqualifiedBuildTool "hpack", SourceDependency source)]++ context "when parsing SystemBuildTools" $ do+ context "with a scalar" $ do+ it "accepts system build tools" $ do+ [yaml|+ g+++ |] `shouldDecodeTo_` SystemBuildTools [("g++", AnyVersion)]++ it "accepts system build tools with a version" $ do+ [yaml|+ g++ >= 0.1.0+ |] `shouldDecodeTo_` SystemBuildTools [("g++", VersionRange ">=0.1.0")]++ context "with a mapping" $ do+ it "accepts system build tools" $ do+ [yaml|+ g++: 0.1.0+ |] `shouldDecodeTo_` SystemBuildTools [("g++", VersionRange "==0.1.0")]++ context "with a list" $ do+ it "accepts a list of system build tools" $ do+ [yaml|+ - foo+ - bar >= 0.1.0+ |] `shouldDecodeTo_` SystemBuildTools [+ ("foo", AnyVersion)+ , ("bar", VersionRange ">=0.1.0")+ ]
test/Hpack/UtilSpec.hs view
@@ -76,9 +76,14 @@ tryReadFile "foo" `shouldReturn` Nothing describe "expandGlobs" $ around withTempDirectory $ do- it "accepts simple files" $ \dir -> do+ it "accepts literal files" $ \dir -> do touch (dir </> "foo.js") expandGlobs "field-name" dir ["foo.js"] `shouldReturn` ([], ["foo.js"])++ it "keeps declaration order for literal files" $ \dir -> do+ touch (dir </> "foo.js")+ touch (dir </> "bar.js")+ expandGlobs "field-name" dir ["foo.js", "bar.js"] `shouldReturn` ([], ["foo.js", "bar.js"]) it "removes duplicates" $ \dir -> do touch (dir </> "foo.js")