packages feed

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 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")