hpack 0.18.1 → 0.19.0
raw patch · 10 files changed
+464/−228 lines, 10 filesdep +Cabaldep +HUnitdep +prettydep −aeson-qqdep ~basedep ~base-compatPVP ok
version bump matches the API change (PVP)
Dependencies added: Cabal, HUnit, pretty
Dependencies removed: aeson-qq
Dependency ranges changed: base, base-compat
API changes (from Hackage documentation)
- Hpack.Config: Dependency :: String -> Maybe AddSource -> Dependency
- Hpack.Config: [dependencyGitRef] :: Dependency -> Maybe AddSource
- Hpack.Config: [dependencyName] :: Dependency -> String
- Hpack.Config: data AddSource
- Hpack.Config: data Dependency
- Hpack.Config: instance Data.Aeson.Types.FromJSON.FromJSON Hpack.Config.Dependency
- Hpack.Config: instance Data.String.IsString Hpack.Config.Dependency
- Hpack.Config: instance GHC.Classes.Eq Hpack.Config.AddSource
- Hpack.Config: instance GHC.Classes.Eq Hpack.Config.Dependency
- Hpack.Config: instance GHC.Classes.Ord Hpack.Config.AddSource
- Hpack.Config: instance GHC.Classes.Ord Hpack.Config.Dependency
- Hpack.Config: instance GHC.Generics.Generic Hpack.Config.Dependency
- Hpack.Config: instance GHC.Show.Show Hpack.Config.AddSource
- Hpack.Config: instance GHC.Show.Show Hpack.Config.Dependency
+ Hpack.Config: AnyVersion :: DependencyVersion
+ Hpack.Config: Dependencies :: Map String DependencyVersion -> Dependencies
+ Hpack.Config: SourceDependency :: SourceDependency -> DependencyVersion
+ Hpack.Config: VersionRange :: String -> DependencyVersion
+ Hpack.Config: [unDependencies] :: Dependencies -> Map String DependencyVersion
+ Hpack.Config: data DependencyVersion
+ Hpack.Config: data SourceDependency
+ Hpack.Config: newtype Dependencies
- Hpack.Config: CustomSetup :: [Dependency] -> CustomSetup
+ Hpack.Config: CustomSetup :: Dependencies -> CustomSetup
- Hpack.Config: GitRef :: GitUrl -> GitRef -> (Maybe FilePath) -> AddSource
+ Hpack.Config: GitRef :: GitUrl -> GitRef -> (Maybe FilePath) -> SourceDependency
- Hpack.Config: Local :: FilePath -> AddSource
+ Hpack.Config: Local :: FilePath -> SourceDependency
- Hpack.Config: Section :: a -> [FilePath] -> [Dependency] -> [String] -> [String] -> [GhcOption] -> [GhcProfOption] -> [GhcjsOption] -> [CppOption] -> [CcOption] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [LdOption] -> Maybe Bool -> [Conditional] -> [Dependency] -> Section a
+ Hpack.Config: Section :: a -> [FilePath] -> Dependencies -> [String] -> [String] -> [GhcOption] -> [GhcProfOption] -> [GhcjsOption] -> [CppOption] -> [CcOption] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> [LdOption] -> Maybe Bool -> [Conditional] -> Dependencies -> Section a
- Hpack.Config: [customSetupDependencies] :: CustomSetup -> [Dependency]
+ Hpack.Config: [customSetupDependencies] :: CustomSetup -> Dependencies
- Hpack.Config: [sectionBuildTools] :: Section a -> [Dependency]
+ Hpack.Config: [sectionBuildTools] :: Section a -> Dependencies
- Hpack.Config: [sectionDependencies] :: Section a -> [Dependency]
+ Hpack.Config: [sectionDependencies] :: Section a -> Dependencies
- Hpack.Config: packageDependencies :: Package -> [Dependency]
+ Hpack.Config: packageDependencies :: Package -> [(String, DependencyVersion)]
Files
- CHANGELOG.md +5/−1
- hpack.cabal +36/−24
- src/Hpack/Config.hs +45/−79
- src/Hpack/Dependency.hs +149/−0
- src/Hpack/GenericsUtil.hs +4/−5
- src/Hpack/Run.hs +14/−11
- test/Hpack/ConfigSpec.hs +41/−83
- test/Hpack/DependencySpec.hs +150/−0
- test/Hpack/RunSpec.hs +14/−14
- test/Hpack/UtilSpec.hs +6/−11
CHANGELOG.md view
@@ -1,4 +1,8 @@-## next+## next (0.19.0)+ - Add Paths_* module to executables (see #195, for GHC 8.2.1 compatibility)+ - Allow specifying dependencies as a hash (see #198)++## Change in 0.18.1 - Output generated cabal file to `stdout` when `-` is given as a command-line option (see #113) - Recognize `.chs`, `.y`, `.ly` and `.x` as Haskell modules when inferring
hpack.cabal view
@@ -1,9 +1,9 @@--- This file has been generated from package.yaml by hpack version 0.18.0.+-- This file has been generated from package.yaml by hpack version 0.19.0. -- -- see: https://github.com/sol/hpack name: hpack-version: 0.18.1+version: 0.19.0 synopsis: An alternative format for Haskell packages description: See README at <https://github.com/sol/hpack#readme> category: Development@@ -27,24 +27,27 @@ src ghc-options: -Wall build-depends:- base >= 4.7 && < 5- , base-compat >= 0.8+ Cabal+ , Glob+ , aeson >=0.11+ , base >=4.7 && <5+ , base-compat >=0.8 , bytestring+ , containers , deepseq , directory , filepath- , Glob+ , pretty , text- , containers , unordered-containers , yaml- , aeson >= 0.11 exposed-modules: Hpack Hpack.Config Hpack.Run Hpack.Yaml other-modules:+ Hpack.Dependency Hpack.FormattingHints Hpack.GenericsUtil Hpack.Haskell@@ -60,19 +63,23 @@ driver ghc-options: -Wall build-depends:- base >= 4.7 && < 5- , base-compat >= 0.8+ Cabal+ , Glob+ , aeson >=0.11+ , base >=4.7 && <5+ , base-compat >=0.8 , bytestring+ , containers , deepseq , directory , filepath- , Glob+ , hpack+ , pretty , text- , containers , unordered-containers , yaml- , aeson >= 0.11- , hpack+ other-modules:+ Paths_hpack default-language: Haskell2010 test-suite spec@@ -84,27 +91,30 @@ ghc-options: -Wall cpp-options: -DTEST build-depends:- base >= 4.7 && < 5- , base-compat >= 0.8+ Cabal+ , Glob+ , HUnit >=1.6.0.0+ , QuickCheck+ , aeson >=0.11+ , base >=4.7 && <5+ , base-compat >=0.8 , bytestring+ , containers , deepseq , directory , filepath- , Glob+ , hspec ==2.*+ , interpolate+ , mockery >=0.3+ , pretty+ , temporary , text- , containers , unordered-containers , yaml- , aeson >= 0.11- , hspec == 2.*- , QuickCheck- , temporary- , mockery >= 0.3- , interpolate- , aeson-qq other-modules: Helper Hpack.ConfigSpec+ Hpack.DependencySpec Hpack.FormattingHintsSpec Hpack.GenericsUtilSpec Hpack.HaskellSpec@@ -115,6 +125,7 @@ HpackSpec Hpack Hpack.Config+ Hpack.Dependency Hpack.FormattingHints Hpack.GenericsUtil Hpack.Haskell@@ -123,4 +134,5 @@ Hpack.Run Hpack.Util Hpack.Yaml+ Paths_hpack default-language: Haskell2010
src/Hpack/Config.hs view
@@ -11,6 +11,8 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-} module Hpack.Config ( packageConfig , readPackageConfig@@ -19,10 +21,11 @@ , package , section , Package(..)-, Dependency(..)-, AddSource(..)-, GitUrl+, Dependencies(..)+, DependencyVersion(..)+, SourceDependency(..) , GitRef+, GitUrl , GhcOption , CustomSetup(..) , Section(..)@@ -51,6 +54,7 @@ import qualified Data.HashMap.Lazy as HashMap import Data.List.Compat (nub, (\\), sortBy, isPrefixOf) import Data.Maybe+import Data.Monoid import Data.Ord import Data.String import Data.Text (Text)@@ -64,6 +68,7 @@ import Hpack.GenericsUtil import Hpack.Util import Hpack.Yaml+import Hpack.Dependency package :: String -> String -> Package package name version = Package {@@ -102,35 +107,34 @@ } renameDependencies :: String -> String -> Section a -> Section a-renameDependencies old new sect@Section{..} = sect {sectionDependencies = map rename sectionDependencies, sectionConditionals = map renameConditional sectionConditionals}+renameDependencies old new sect@Section{..} = sect {sectionDependencies = (Dependencies . Map.fromList . map rename . Map.toList . unDependencies) sectionDependencies, sectionConditionals = map renameConditional sectionConditionals} where- rename dep- | dependencyName dep == old = dep {dependencyName = new}+ rename dep@(name, version)+ | name == old = (new, version) | otherwise = dep renameConditional :: Conditional -> Conditional renameConditional (Conditional condition then_ else_) = Conditional condition (renameDependencies old new then_) (renameDependencies old new <$> else_) -packageDependencies :: Package -> [Dependency]-packageDependencies Package{..} = nub . sortBy (comparing (lexicographically . dependencyName)) $- (concatMap sectionDependencies packageExecutables)- ++ (concatMap sectionDependencies packageTests)- ++ (concatMap sectionDependencies packageBenchmarks)- ++ maybe [] sectionDependencies packageLibrary+packageDependencies :: Package -> [(String, DependencyVersion)]+packageDependencies Package{..} = nub . sortBy (comparing (lexicographically . fst)) $+ (concatMap deps packageExecutables)+ ++ (concatMap deps packageTests)+ ++ (concatMap deps packageBenchmarks)+ ++ maybe [] deps packageLibrary+ where+ deps xs = [(name, version) | (name, version) <- (Map.toList . unDependencies . sectionDependencies) xs] section :: a -> Section a-section a = Section a [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] []+section a = Section a [] mempty [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] mempty packageConfig :: FilePath packageConfig = "package.yaml" -githubBaseUrl :: String-githubBaseUrl = "https://github.com/"- #if MIN_VERSION_aeson(1,0,0)-genericParseJSON_ :: forall a. (Generic a, GFromJSON Zero (Rep a), HasTypeName a) => Value -> Parser a+genericParseJSON_ :: forall a d m. (GFromJSON Zero (Rep a), HasTypeName a d m) => Value -> Parser a #else-genericParseJSON_ :: forall a. (Generic a, GFromJSON (Rep a), HasTypeName a) => Value -> Parser a+genericParseJSON_ :: forall a d m. (GFromJSON (Rep a), HasTypeName a d m) => Value -> Parser a #endif genericParseJSON_ = genericParseJSON defaultOptions {fieldLabelModifier = hyphenize name} where@@ -151,7 +155,7 @@ class HasFieldNames a where fieldNames :: Proxy a -> [FieldName] - default fieldNames :: (HasTypeName a, Selectors (Rep a)) => Proxy a -> [String]+ default fieldNames :: (HasTypeName a d m, Selectors (Rep a)) => Proxy a -> [String] fieldNames proxy = map (hyphenize $ typeName proxy) (selectors proxy) ignoreUnderscoredUnknownFields :: Proxy a -> Bool@@ -193,7 +197,7 @@ _ -> [] data CustomSetupSection = CustomSetupSection {- customSetupSectionDependencies :: Maybe (List Dependency)+ customSetupSectionDependencies :: Maybe Dependencies } deriving (Eq, Show, Generic) instance HasFieldNames CustomSetupSection@@ -225,7 +229,7 @@ data CommonOptions = CommonOptions { commonOptionsSourceDirs :: Maybe (List FilePath)-, commonOptionsDependencies :: Maybe (List Dependency)+, commonOptionsDependencies :: Maybe Dependencies , commonOptionsDefaultExtensions :: Maybe (List String) , commonOptionsOtherExtensions :: Maybe (List String) , commonOptionsGhcOptions :: Maybe (List GhcOption)@@ -242,7 +246,7 @@ , commonOptionsLdOptions :: Maybe (List LdOption) , commonOptionsBuildable :: Maybe Bool , commonOptionsWhen :: Maybe (List ConditionalSection)-, commonOptionsBuildTools :: Maybe (List Dependency)+, commonOptionsBuildTools :: Maybe Dependencies } deriving (Eq, Show, Generic) instance HasFieldNames CommonOptions@@ -373,49 +377,6 @@ dir <- takeDirectory <$> canonicalizePath file Right <$> mkPackage dir config -data Dependency = Dependency {- dependencyName :: String-, dependencyGitRef :: Maybe AddSource-} deriving (Eq, Show, Ord, Generic)--instance IsString Dependency where- fromString name = Dependency name Nothing--instance FromJSON Dependency where- parseJSON v = case v of- String _ -> fromString <$> parseJSON v- Object o -> addSourceDependency o- _ -> typeMismatch "String or an Object" v- where- addSourceDependency o = Dependency <$> name <*> (Just <$> (local <|> git))- where- name :: Parser String- name = o .: "name"-- local :: Parser AddSource- local = Local <$> o .: "path"-- git :: Parser AddSource- git = GitRef <$> url <*> ref <*> subdir-- url :: Parser String- url =- ((githubBaseUrl ++) <$> o .: "github")- <|> (o .: "git")- <|> fail "neither key \"git\" nor key \"github\" present"-- ref :: Parser String- ref = o .: "ref"-- subdir :: Parser (Maybe FilePath)- subdir = o .:? "subdir"--data AddSource = GitRef GitUrl GitRef (Maybe FilePath) | Local FilePath- deriving (Eq, Show, Ord)--type GitUrl = String-type GitRef = String- data Package = Package { packageName :: String , packageVersion :: String@@ -444,7 +405,7 @@ } deriving (Eq, Show) data CustomSetup = CustomSetup {- customSetupDependencies :: [Dependency]+ customSetupDependencies :: Dependencies } deriving (Eq, Show) data Library = Library {@@ -463,7 +424,7 @@ data Section a = Section { sectionData :: a , sectionSourceDirs :: [FilePath]-, sectionDependencies :: [Dependency]+, sectionDependencies :: Dependencies , sectionDefaultExtensions :: [String] , sectionOtherExtensions :: [String] , sectionGhcOptions :: [GhcOption]@@ -480,7 +441,7 @@ , sectionLdOptions :: [LdOption] , sectionBuildable :: Maybe Bool , sectionConditionals :: [Conditional]-, sectionBuildTools :: [Dependency]+, sectionBuildTools :: Dependencies } deriving (Eq, Show, Functor, Foldable, Traversable) data Conditional = Conditional {@@ -544,9 +505,9 @@ libraryWarnings :: [String] libraryWarnings = maybe [] fst libraryResult - (executablesWarnings, executables) <- toExecutables dir globalOptions executableSections- (testsWarnings, tests) <- toExecutables dir globalOptions (map (fmap captureUnknownFieldsValue) testsSections)- (benchmarksWarnings, benchmarks) <- toExecutables dir globalOptions (map (fmap captureUnknownFieldsValue) benchmarkSections)+ (executablesWarnings, executables) <- toExecutables dir packageName_ globalOptions executableSections+ (testsWarnings, tests) <- toExecutables dir packageName_ globalOptions (map (fmap captureUnknownFieldsValue) testsSections)+ (benchmarksWarnings, benchmarks) <- toExecutables dir packageName_ globalOptions (map (fmap captureUnknownFieldsValue) benchmarkSections) licenseFileExists <- doesFileExist (dir </> "LICENSE") @@ -712,7 +673,7 @@ toCustomSetup :: CustomSetupSection -> CustomSetup toCustomSetup CustomSetupSection{..} = CustomSetup- { customSetupDependencies = fromMaybeList customSetupSectionDependencies }+ { customSetupDependencies = fromMaybe mempty customSetupSectionDependencies } toLibrary :: FilePath -> String -> Section global -> Section LibrarySection -> IO ([String], Section Library) toLibrary dir name globalOptions library = traverse fromLibrarySection sect >>= expandForeignSources dir@@ -730,8 +691,8 @@ reexportedModules = fromMaybeList librarySectionReexportedModules return (Library librarySectionExposed exposedModules otherModules reexportedModules) -toExecutables :: FilePath -> Section global -> [(String, Section ExecutableSection)] -> IO ([String], [Section Executable])-toExecutables dir globalOptions executables = do+toExecutables :: FilePath -> String -> Section global -> [(String, Section ExecutableSection)] -> IO ([String], [Section Executable])+toExecutables dir packageName_ globalOptions executables = do result <- mapM toExecutable sections >>= mapM (expandForeignSources dir) let (warnings, xs) = unzip result return (concat warnings, xs)@@ -746,9 +707,14 @@ where fromExecutableSection :: ExecutableSection -> IO (Executable, [GhcOption]) fromExecutableSection ExecutableSection{..} = do- modules <- maybe (filterMain . concat <$> mapM (getModules dir) sectionSourceDirs) (return . fromList) executableSectionOtherModules+ modules <- maybe inferModules (return . fromList) executableSectionOtherModules return (Executable name mainSrcFile modules, ghcOptions) where+ inferModules :: IO [String]+ inferModules = filterMain . (++ [pathsModule]) . concat <$> mapM (getModules dir) sectionSourceDirs++ pathsModule = pathsModuleFromPackageName packageName_+ filterMain :: [String] -> [String] filterMain = maybe id (filter . (/=)) (toModule $ splitDirectories executableSectionMain) @@ -774,9 +740,9 @@ , sectionInstallIncludes = sectionInstallIncludes globalOptions ++ sectionInstallIncludes options , sectionLdOptions = sectionLdOptions globalOptions ++ sectionLdOptions options , sectionBuildable = sectionBuildable options <|> sectionBuildable globalOptions- , sectionDependencies = sectionDependencies globalOptions ++ sectionDependencies options+ , sectionDependencies = sectionDependencies options <> sectionDependencies globalOptions , sectionConditionals = sectionConditionals globalOptions ++ sectionConditionals options- , sectionBuildTools = sectionBuildTools globalOptions ++ sectionBuildTools options+ , sectionBuildTools = sectionBuildTools options <> sectionBuildTools globalOptions } toSection :: a -> CommonOptions -> ([FieldName], Section a)@@ -800,9 +766,9 @@ , sectionInstallIncludes = fromMaybeList commonOptionsInstallIncludes , sectionLdOptions = fromMaybeList commonOptionsLdOptions , sectionBuildable = commonOptionsBuildable- , sectionDependencies = fromMaybeList commonOptionsDependencies+ , sectionDependencies = fromMaybe mempty commonOptionsDependencies , sectionConditionals = conditionals- , sectionBuildTools = fromMaybeList commonOptionsBuildTools+ , sectionBuildTools = fromMaybe mempty commonOptionsBuildTools } ) where
+ src/Hpack/Dependency.hs view
@@ -0,0 +1,149 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Hpack.Dependency (+ Dependencies(..)+, DependencyVersion(..)+, SourceDependency(..)+, GitRef+, GitUrl+, githubBaseUrl+) where++import Prelude ()+import Prelude.Compat++import qualified Data.Text as T+import Text.PrettyPrint (renderStyle, Style(..), Mode(..))+import Control.Monad+import qualified Distribution.Compat.ReadP as D+import qualified Distribution.Package as D+import qualified Distribution.Text as D+import qualified Distribution.Version as D+import Data.Map.Lazy (Map)+import qualified Data.Map.Lazy as Map+import Data.Aeson.Types+import Control.Applicative++githubBaseUrl :: String+githubBaseUrl = "https://github.com/"++newtype Dependencies = Dependencies {+ unDependencies :: Map String DependencyVersion+} deriving (Eq, Show, Monoid)++data DependencyVersion =+ AnyVersion+ | VersionRange String+ | SourceDependency SourceDependency+ deriving (Eq, Show)++data SourceDependency = GitRef GitUrl GitRef (Maybe FilePath) | Local FilePath+ deriving (Eq, Show)++type GitUrl = String+type GitRef = String++instance FromJSON Dependencies where+ parseJSON v = case v of+ String _ -> dependenciesFromList . return <$> parseJSON v+ Array _ -> dependenciesFromList <$> parseJSON v+ Object _ -> Dependencies <$> parseJSON v+ _ -> typeMismatch "Array, Object, or String" v+ where+ fromDependency :: Dependency -> (String, DependencyVersion)+ fromDependency (Dependency name version) = (name, version)++ dependenciesFromList :: [Dependency] -> Dependencies+ dependenciesFromList = Dependencies . Map.fromList . map fromDependency++instance FromJSON DependencyVersion where+ parseJSON v = case v of+ Null -> return AnyVersion+ Object _ -> SourceDependency <$> parseJSON v+ String s -> parseVersionRange ("== " ++ input) <|> parseVersionRange input+ where+ input = T.unpack s++ _ -> typeMismatch "Null, Object, or String" v++instance FromJSON SourceDependency where+ parseJSON = withObject "SourceDependency" (\o -> let+ local :: Parser SourceDependency+ local = Local <$> o .: "path"++ git :: Parser SourceDependency+ git = GitRef <$> url <*> ref <*> subdir++ url :: Parser String+ url =+ ((githubBaseUrl ++) <$> o .: "github")+ <|> (o .: "git")+ <|> fail "neither key \"git\" nor key \"github\" present"++ ref :: Parser String+ ref = o .: "ref"++ subdir :: Parser (Maybe FilePath)+ subdir = o .:? "subdir"++ in local <|> git)++data Dependency = Dependency {+ _dependencyName :: String+, _dependencyVersion :: DependencyVersion+} deriving (Eq, Show)++instance FromJSON Dependency where+ parseJSON v = case v of+ String _ -> do+ (name, versionRange) <- parseJSON v >>= parseDependency+ return (Dependency name versionRange)+ Object o -> addSourceDependency o+ _ -> typeMismatch "String or an Object" v+ where+ addSourceDependency o = Dependency <$> name <*> (SourceDependency <$> parseJSON v)+ where+ name :: Parser String+ name = o .: "name"++depPkgName :: D.Dependency -> String+#if MIN_VERSION_Cabal(2,0,0)+depPkgName = D.unPackageName . D.depPkgName+#else+depPkgName (D.Dependency (D.PackageName name) _) = name+#endif++depVerRange :: D.Dependency -> D.VersionRange+#if MIN_VERSION_Cabal(2,0,0)+depVerRange = D.depVerRange+#else+depVerRange (D.Dependency _ versionRange) = versionRange+#endif++parseDependency :: Monad m => String -> m (String, DependencyVersion)+parseDependency = liftM fromCabal . parseCabalDependency+ where+ fromCabal :: D.Dependency -> (String, DependencyVersion)+ fromCabal d = (depPkgName d, dependencyVersionFromCabal $ depVerRange d)++dependencyVersionFromCabal :: D.VersionRange -> DependencyVersion+dependencyVersionFromCabal versionRange+ | D.isAnyVersion versionRange = AnyVersion+ | otherwise = VersionRange . renderStyle style . D.disp $ versionRange+ where+ style = Style OneLineMode 0 0++parseCabalDependency :: Monad m => String -> m D.Dependency+parseCabalDependency = cabalParse "dependency"++parseVersionRange :: Monad m => String -> m DependencyVersion+parseVersionRange = liftM dependencyVersionFromCabal . parseCabalVersionRange++parseCabalVersionRange :: Monad m => String -> m D.VersionRange+parseCabalVersionRange = cabalParse "constraint"++cabalParse :: (Monad m, D.Text a) => String -> String -> m a+cabalParse subject s = case [d | (d, "") <- D.readP_to_S D.parse s] of+ [d] -> return d+ _ -> fail $ unwords ["invalid", subject, show s]
src/Hpack/GenericsUtil.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ConstraintKinds #-} module Hpack.GenericsUtil ( HasTypeName , typeName@@ -15,11 +15,10 @@ import Data.Proxy import GHC.Generics -class HasTypeName a where- typeName :: Proxy a -> String+type HasTypeName a d m = (Datatype d, Generic a, Rep a ~ M1 D d m) -instance (Datatype d, Generic a, Rep a ~ M1 D d m) => HasTypeName a where- typeName _ = datatypeName (undefined :: M1 D d x y)+typeName :: forall a d m. (Datatype d, Generic a, Rep a ~ M1 D d m) => Proxy a -> String+typeName _ = datatypeName (undefined :: M1 D d x y) selectors :: (Selectors (Rep a)) => Proxy a -> [String] selectors = f
src/Hpack/Run.hs view
@@ -28,6 +28,7 @@ import Data.List.Compat import System.Exit.Compat import System.FilePath+import qualified Data.Map.Lazy as Map import Hpack.Util import Hpack.Config@@ -200,7 +201,7 @@ renderCustomSetup :: CustomSetup -> Element renderCustomSetup CustomSetup{..} =- Stanza "custom-setup" [renderSetupDepends customSetupDependencies]+ Stanza "custom-setup" [renderDependencies "setup-depends" customSetupDependencies] renderLibrary :: Section Library -> Element renderLibrary sect@(sectionData -> Library{..}) = Stanza "library" $@@ -232,8 +233,8 @@ , renderDirectories "extra-lib-dirs" sectionExtraLibDirs , Field "extra-libraries" (LineSeparatedList sectionExtraLibraries) , renderLdOptions sectionLdOptions- , renderDependencies sectionDependencies- , renderBuildTools sectionBuildTools+ , renderDependencies "build-depends" sectionDependencies+ , renderDependencies "build-tools" sectionBuildTools ] ++ maybe [] (return . renderBuildable) sectionBuildable ++ map renderConditional sectionConditionals@@ -265,9 +266,17 @@ renderReexportedModules :: [String] -> Element renderReexportedModules = Field "reexported-modules" . LineSeparatedList -renderDependencies :: [Dependency] -> Element-renderDependencies = Field "build-depends" . CommaSeparatedList . map dependencyName+renderDependencies :: String -> Dependencies -> Element+renderDependencies name = Field name . CommaSeparatedList . map renderDependency . Map.toList . unDependencies +renderDependency :: (String, DependencyVersion) -> String+renderDependency (name, version) = name ++ v+ where+ v = case version of+ AnyVersion -> ""+ VersionRange x -> " " ++ x+ SourceDependency _ -> ""+ renderGhcOptions :: [GhcOption] -> Element renderGhcOptions = Field "ghc-options" . WordList @@ -294,9 +303,3 @@ renderOtherExtensions :: [String] -> Element renderOtherExtensions = Field "other-extensions" . WordList--renderBuildTools :: [Dependency] -> Element-renderBuildTools = Field "build-tools" . CommaSeparatedList . map dependencyName--renderSetupDepends :: [Dependency] -> Element-renderSetupDepends = Field "setup-depends" . CommaSeparatedList . map dependencyName
test/Hpack/ConfigSpec.hs view
@@ -1,32 +1,37 @@ {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module Hpack.ConfigSpec ( spec , package-, executable+, deps ) where import Helper -import Data.Aeson.QQ import Data.Aeson.Types import Data.String.Interpolate.IsString import Control.Arrow import System.Directory (createDirectory) import Data.Yaml import Data.Either.Compat+import qualified Data.Map.Lazy as Map import Hpack.Util+import Hpack.Dependency import Hpack.Config hiding (package) import qualified Hpack.Config as Config +deps :: [String] -> Dependencies+deps = Dependencies . Map.fromList . map (flip (,) AnyVersion)+ package :: Package package = Config.package "foo" "0.0.0" executable :: String -> String -> Executable-executable name main_ = Executable name main_ []+executable name main_ = Executable name main_ ["Paths_foo"] library :: Library library = Library Nothing [] ["Paths_foo"] []@@ -59,11 +64,11 @@ renamePackage "bar" package `shouldBe` package {packageName = "bar"} it "renames dependencies on self" $ do- let packageWithExecutable dependencies = package {packageExecutables = [(section $ executable "main" "Main.hs") {sectionDependencies = dependencies}]}+ let packageWithExecutable dependencies = package {packageExecutables = [(section $ executable "main" "Main.hs") {sectionDependencies = deps dependencies}]} renamePackage "bar" (packageWithExecutable ["foo"]) `shouldBe` (packageWithExecutable ["bar"]) {packageName = "bar"} describe "renameDependencies" $ do- let sectionWithDeps dependencies = (section ()) {sectionDependencies = dependencies}+ let sectionWithDeps dependencies = (section ()) {sectionDependencies = deps dependencies} it "renames dependencies" $ do renameDependencies "bar" "baz" (sectionWithDeps ["foo", "bar"]) `shouldBe` sectionWithDeps ["foo", "baz"]@@ -87,7 +92,7 @@ dependencies: hpack |] captureUnknownFieldsValue <$> decodeEither input- `shouldBe` Right (section Empty){sectionDependencies = ["hpack"]}+ `shouldBe` Right (section Empty){sectionDependencies = deps ["hpack"]} it "accepts includes-dirs" $ do let input = [i|@@ -152,7 +157,7 @@ |] conditionals = [ Conditional "os(windows)"- (section ()){sectionDependencies = ["Win32"]}+ (section ()){sectionDependencies = deps ["Win32"]} Nothing ] captureUnknownFieldsValue <$> decodeEither input@@ -185,8 +190,8 @@ |] conditionals = [ Conditional "os(windows)"- (section ()){sectionDependencies = ["Win32"]}- (Just (section ()){sectionDependencies = ["unix"]})+ (section ()){sectionDependencies = deps ["Win32"]}+ (Just (section ()){sectionDependencies = deps ["unix"]}) ] r :: Either String (Section Empty) r = captureUnknownFieldsValue <$> decodeEither input@@ -218,69 +223,6 @@ 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)-- it "accepts git dependencies" $ do- let value = [aesonQQ|{- name: "hpack",- git: "https://github.com/sol/hpack",- ref: "master"- }|]- source = GitRef "https://github.com/sol/hpack" "master" Nothing- parseEither parseJSON value `shouldBe` Right (Dependency "hpack" (Just source))-- it "accepts github dependencies" $ do- let value = [aesonQQ|{- name: "hpack",- github: "sol/hpack",- ref: "master"- }|]- source = GitRef "https://github.com/sol/hpack" "master" Nothing- parseEither parseJSON value `shouldBe` Right (Dependency "hpack" (Just source))-- it "accepts an optional subdirectory for git dependencies" $ do- let value = [aesonQQ|{- name: "warp",- github: "yesodweb/wai",- ref: "master",- subdir: "warp"- }|]- source = GitRef "https://github.com/yesodweb/wai" "master" (Just "warp")- parseEither parseJSON value `shouldBe` Right (Dependency "warp" (Just source))-- it "accepts local dependencies" $ do- let value = [aesonQQ|{- name: "hpack",- path: "../hpack"- }|]- source = Local "../hpack"- parseEither parseJSON value `shouldBe` Right (Dependency "hpack" (Just source))-- context "when parsing fails" $ do- it "returns an error message" $ do- let value = Number 23- parseEither parseJSON value `shouldBe` (Left "Error in $: expected String or an Object, encountered Number" :: Either String Dependency)-- context "when ref is missing" $ do- it "produces accurate error messages" $ do- let value = [aesonQQ|{- name: "hpack",- git: "sol/hpack",- ef: "master"- }|]- parseEither parseJSON value `shouldBe` (Left "Error in $: key \"ref\" not present" :: Either String Dependency)-- context "when both git and github are missing" $ do- it "produces accurate error messages" $ do- let value = [aesonQQ|{- name: "hpack",- gi: "sol/hpack",- ref: "master"- }|]- parseEither parseJSON value `shouldBe` (Left "Error in $: neither key \"git\" nor key \"github\" present" :: Either String Dependency)- describe "getModules" $ around withTempDirectory $ do it "returns Haskell modules in specified source directory" $ \dir -> do touch (dir </> "src/Foo.hs")@@ -721,10 +663,14 @@ withPackageConfig_ [i| custom-setup: dependencies:- - foo >1.0- - bar ==2.0+ - foo > 1.0+ - bar == 2.0 |]- (packageCustomSetup >>> fmap customSetupDependencies >>> (`shouldBe` Just ["foo >1.0", "bar ==2.0"]))+ (packageCustomSetup >>> fmap customSetupDependencies >>> fmap unDependencies >>> fmap Map.toList >>> (`shouldBe` Just [+ ("bar", VersionRange "==2.0")+ , ("foo", VersionRange ">1.0")+ ])+ ) it "allows yaml merging and overriding fields" $ do withPackageConfig_ [i|@@ -766,7 +712,7 @@ - alex - happy |]- (packageLibrary >>> (`shouldBe` Just (section library) {sectionBuildTools = ["alex", "happy"]}))+ (packageLibrary >>> (`shouldBe` Just (section library) {sectionBuildTools = deps ["alex", "happy"]})) it "accepts default-extensions" $ do withPackageConfig_ [i|@@ -802,7 +748,7 @@ - happy library: {} |]- (packageLibrary >>> (`shouldBe` Just (section library) {sectionBuildTools = ["alex", "happy"]}))+ (packageLibrary >>> (`shouldBe` Just (section library) {sectionBuildTools = deps ["alex", "happy"]})) it "accepts c-sources" $ do withPackageConfig [i|@@ -1007,7 +953,7 @@ - alex - happy |]- (packageExecutables >>> (`shouldBe` [(section $ executable "foo" "Main.hs") {sectionBuildTools = ["alex", "happy"]}]))+ (packageExecutables >>> (`shouldBe` [(section $ executable "foo" "Main.hs") {sectionBuildTools = deps ["alex", "happy"]}])) it "accepts global source-dirs" $ do withPackageConfig_ [i|@@ -1029,7 +975,7 @@ foo: main: Main.hs |]- (packageExecutables >>> (`shouldBe` [(section $ executable "foo" "Main.hs") {sectionBuildTools = ["alex", "happy"]}]))+ (packageExecutables >>> (`shouldBe` [(section $ executable "foo" "Main.hs") {sectionBuildTools = deps ["alex", "happy"]}])) it "infers other-modules" $ do withPackageConfig [i|@@ -1042,7 +988,7 @@ touch "src/Main.hs" touch "src/Foo.hs" )- (map (executableOtherModules . sectionData) . packageExecutables >>> (`shouldBe` [["Foo"]]))+ (map (executableOtherModules . sectionData) . packageExecutables >>> (`shouldBe` [["Foo", "Paths_foo"]])) it "allows to specify other-modules" $ do withPackageConfig [i|@@ -1219,7 +1165,7 @@ main: test/Spec.hs dependencies: hspec |]- (`shouldBe` package {packageTests = [(section $ executable "spec" "test/Spec.hs") {sectionDependencies = ["hspec"]}]})+ (`shouldBe` package {packageTests = [(section $ executable "spec" "test/Spec.hs") {sectionDependencies = deps ["hspec"]}]}) it "accepts list of dependencies" $ do withPackageConfig_ [i|@@ -1230,7 +1176,7 @@ - hspec - QuickCheck |]- (`shouldBe` package {packageTests = [(section $ executable "spec" "test/Spec.hs") {sectionDependencies = ["hspec", "QuickCheck"]}]})+ (`shouldBe` package {packageTests = [(section $ executable "spec" "test/Spec.hs") {sectionDependencies = deps ["hspec", "QuickCheck"]}]}) context "when both global and section specific dependencies are specified" $ do it "combines dependencies" $ do@@ -1243,7 +1189,19 @@ main: test/Spec.hs dependencies: hspec |]- (`shouldBe` package {packageTests = [(section $ executable "spec" "test/Spec.hs") {sectionDependencies = ["base", "hspec"]}]})+ (`shouldBe` package {packageTests = [(section $ executable "spec" "test/Spec.hs") {sectionDependencies = deps ["base", "hspec"]}]})++ it "gives section specific dependencies precedence" $ do+ withPackageConfig_ [i|+ dependencies:+ - base++ tests:+ spec:+ main: test/Spec.hs+ dependencies: base >= 2+ |]+ (packageTests >>> map (Map.toList . unDependencies . sectionDependencies) >>> (`shouldBe` [[("base", VersionRange ">=2")]])) context "when a specified source directory does not exist" $ do it "warns" $ do
+ test/Hpack/DependencySpec.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}+module Hpack.DependencySpec (spec) where++import Helper+import Test.HUnit++import Data.Aeson.Types+import qualified Data.Map.Lazy as Map+import Data.String.Interpolate.IsString+import Data.Yaml+import Data.ByteString (ByteString)++import Hpack.Dependency++parsesAs :: HasCallStack => ByteString -> Either String [(String, DependencyVersion)] -> Expectation+parsesAs input expected = do+ value <- either assertFailure return (decodeEither input)+ parseEither parseJSON value `shouldBe` (Dependencies . Map.fromList <$> expected)+++spec :: Spec+spec = do+ describe "parseJSON" $ do+ context "when parsing Dependencies" $ do+ context "with a scalar" $ do+ it "accepts dependencies without constraints" $ do+ [i|+ hpack+ |] `parsesAs` Right [("hpack", AnyVersion)]++ it "accepts dependencies with constraints" $ do+ [i|+ hpack >= 2 && < 3+ |] `parsesAs` Right [("hpack", VersionRange ">=2 && <3")]++ context "with invalid constraint" $ do+ it "returns an error message" $ do+ [i|+ hpack ==+ |] `parsesAs` Left "Error in $: invalid dependency \"hpack ==\""++ context "with a list" $ do+ it "accepts dependencies without constraints" $ do+ [i|+ - hpack+ |] `parsesAs` Right [("hpack", AnyVersion)]++ it "accepts dependencies with constraints" $ do+ [i|+ - hpack >= 2 && < 3+ |] `parsesAs` Right [("hpack", VersionRange ">=2 && <3")]++ it "accepts git dependencies" $ do+ let source = GitRef "https://github.com/sol/hpack" "master" Nothing+ [i|+ - name: hpack+ git: https://github.com/sol/hpack+ ref: master+ |] `parsesAs` Right [("hpack", SourceDependency source)]++ it "accepts github dependencies" $ do+ let source = GitRef "https://github.com/sol/hpack" "master" Nothing+ [i|+ - name: hpack+ github: sol/hpack+ ref: master+ |] `parsesAs` Right [("hpack", SourceDependency source)]++ it "accepts an optional subdirectory for git dependencies" $ do+ let source = GitRef "https://github.com/yesodweb/wai" "master" (Just "warp")+ [i|+ - name: warp+ github: yesodweb/wai+ ref: master+ subdir: warp+ |] `parsesAs` Right [("warp", SourceDependency source)]++ it "accepts local dependencies" $ do+ let source = Local "../hpack"+ [i|+ - name: hpack+ path: ../hpack+ |] `parsesAs` Right [("hpack", SourceDependency source)]++ context "when ref is missing" $ do+ it "produces accurate error messages" $ do+ [i|+ - name: hpack+ git: sol/hpack+ ef: master+ |] `parsesAs` Left "Error in $[0]: key \"ref\" not present"++ context "when both git and github are missing" $ do+ it "produces accurate error messages" $ do+ [i|+ - name: hpack+ gi: sol/hpack+ ref: master+ |] `parsesAs` Left "Error in $[0]: neither key \"git\" nor key \"github\" present"++ context "with a mapping from dependency names to constraints" $ do+ it "accepts dependencies without constraints" $ do+ [i|+ array:+ |] `parsesAs` Right [("array", AnyVersion)]++ it "rejects invalid values" $ do+ [i|+ hpack: 23+ |] `parsesAs` Left "Error in $.hpack: expected Null, Object, or String, encountered Number"++ context "when the constraint is a String" $ do+ it "accepts version ranges" $ do+ [i|+ hpack: '>=2'+ |] `parsesAs` Right [("hpack", VersionRange ">=2")]++ it "accepts specific versions" $ do+ [i|+ hpack: 0.10.8.2+ |] `parsesAs` Right [("hpack", VersionRange "==0.10.8.2")]++ it "accepts wildcard versions" $ do+ [i|+ hpack: 2.*+ |] `parsesAs` Right [("hpack", VersionRange "==2.*")]++ it "reports parse errors" $ do+ [i|+ hpack: foo+ |] `parsesAs` Left "Error in $.hpack: invalid constraint \"foo\""++ context "when the constraint is an Object" $ do+ it "accepts github dependencies" $ do+ [i|+ Cabal:+ github: haskell/cabal+ ref: d53b6e0d908dfedfdf4337b2935519fb1d689e76+ subdir: Cabal+ |] `parsesAs` Right [("Cabal", SourceDependency (GitRef "https://github.com/haskell/cabal" "d53b6e0d908dfedfdf4337b2935519fb1d689e76" (Just "Cabal")))]++ it "ignores names in nested hashes" $ do+ [i|+ outer-name:+ name: inner-name+ path: somewhere+ |] `parsesAs` Right [("outer-name", SourceDependency (Local "somewhere"))]
test/Hpack/RunSpec.hs view
@@ -3,6 +3,7 @@ import Helper import Data.List.Compat+import qualified Data.Map.Lazy as Map import Hpack.ConfigSpec hiding (spec) import Hpack.Config hiding (package)@@ -128,7 +129,7 @@ context "when rendering custom-setup section" $ do it "includes setup-depends" $ do let setup = CustomSetup- { customSetupDependencies = ["foo >1.0", "bar ==2.0"] }+ { customSetupDependencies = deps ["foo", "bar"] } renderPackage_ package {packageCustomSetup = Just setup} `shouldBe` unlines [ "name: foo" , "version: 0.0.0"@@ -137,8 +138,8 @@ , "" , "custom-setup" , " setup-depends:"- , " foo >1.0"- , " , bar ==2.0"+ , " bar"+ , " , foo" ] context "when rendering library section" $ do@@ -210,7 +211,7 @@ ] it "retains section field order" $ do- renderPackage defaultRenderSettings 0 [] [("executable foo", ["default-language", "main-is", "ghc-options"])] package {packageExecutables = [(section $ executable "foo" "Main.hs") {sectionGhcOptions = ["-Wall", "-Werror"]}]} `shouldBe` unlines [+ renderPackage defaultRenderSettings 0 [] [("executable foo", ["default-language", "main-is", "ghc-options"])] package {packageExecutables = [(section $ Executable "foo" "Main.hs" []) {sectionGhcOptions = ["-Wall", "-Werror"]}]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -225,7 +226,8 @@ context "when rendering executable section" $ do it "includes dependencies" $ do- renderPackage_ package {packageExecutables = [(section $ executable "foo" "Main.hs") {sectionDependencies = ["foo", "bar", "foo", "baz"]}]} `shouldBe` unlines [+ renderPackage_ package {packageExecutables = [(section $ Executable "foo" "Main.hs" []) {sectionDependencies = Dependencies $ Map.fromList+ [("foo", VersionRange "== 0.1.0"), ("bar", AnyVersion)]}]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -234,15 +236,13 @@ , "executable foo" , " main-is: Main.hs" , " build-depends:"- , " foo"- , " , bar"- , " , foo"- , " , baz"+ , " bar"+ , " , foo == 0.1.0" , " default-language: Haskell2010" ] it "includes GHC options" $ do- renderPackage_ package {packageExecutables = [(section $ executable "foo" "Main.hs") {sectionGhcOptions = ["-Wall", "-Werror"]}]} `shouldBe` unlines [+ renderPackage_ package {packageExecutables = [(section $ Executable "foo" "Main.hs" []) {sectionGhcOptions = ["-Wall", "-Werror"]}]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -255,7 +255,7 @@ ] it "includes GHC profiling options" $ do- renderPackage_ package {packageExecutables = [(section $ executable "foo" "Main.hs") {sectionGhcProfOptions = ["-fprof-auto", "-rtsopts"]}]} `shouldBe` unlines [+ renderPackage_ package {packageExecutables = [(section $ Executable "foo" "Main.hs" []) {sectionGhcProfOptions = ["-fprof-auto", "-rtsopts"]}]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -269,7 +269,7 @@ describe "renderConditional" $ do it "renders conditionals" $ do- let conditional = Conditional "os(windows)" (section ()) {sectionDependencies = ["Win32"]} Nothing+ let conditional = Conditional "os(windows)" (section ()) {sectionDependencies = deps ["Win32"]} Nothing render defaultRenderSettings 0 (renderConditional conditional) `shouldBe` [ "if os(windows)" , " build-depends:"@@ -277,7 +277,7 @@ ] it "renders conditionals with else-branch" $ do- let conditional = Conditional "os(windows)" (section ()) {sectionDependencies = ["Win32"]} (Just $ (section ()) {sectionDependencies = ["unix"]})+ let conditional = Conditional "os(windows)" (section ()) {sectionDependencies = deps ["Win32"]} (Just $ (section ()) {sectionDependencies = deps ["unix"]}) render defaultRenderSettings 0 (renderConditional conditional) `shouldBe` [ "if os(windows)" , " build-depends:"@@ -289,7 +289,7 @@ it "renders nested conditionals" $ do let conditional = Conditional "arch(i386)" (section ()) {sectionGhcOptions = ["-threaded"], sectionConditionals = [innerConditional]} Nothing- innerConditional = Conditional "os(windows)" (section ()) {sectionDependencies = ["Win32"]} Nothing+ innerConditional = Conditional "os(windows)" (section ()) {sectionDependencies = deps ["Win32"]} Nothing render defaultRenderSettings 0 (renderConditional conditional) `shouldBe` [ "if arch(i386)" , " ghc-options: -threaded"
test/Hpack/UtilSpec.hs view
@@ -3,12 +3,10 @@ module Hpack.UtilSpec (main, spec) where import Data.Aeson-import Data.Aeson.QQ import Data.Aeson.Types import Helper import System.Directory -import Hpack.Config import Hpack.Util main :: IO ()@@ -72,26 +70,23 @@ getModuleFilesRecursive "foo" `shouldReturn` empty describe "List" $ do- let invalid = [aesonQQ|{- name: "hpack",- gi: "sol/hpack",- ref: "master"- }|]- parseError :: String -> Either String (List Dependency)- parseError prefix = Left (prefix ++ ": neither key \"git\" nor key \"github\" present")+ let+ parseError :: String -> Either String (List Int)+ parseError prefix = Left (prefix ++ ": expected Int, encountered String")+ context "when parsing single values" $ do it "returns the value in a singleton list" $ do fromJSON (toJSON $ Number 23) `shouldBe` Success (List [23 :: Int]) it "returns error messages from element parsing" $ do- parseEither parseJSON invalid `shouldBe` parseError "Error in $"+ parseEither parseJSON (String "foo") `shouldBe` parseError "Error in $" context "when parsing a list of values" $ do it "returns the list" $ do fromJSON (toJSON [Number 23, Number 42]) `shouldBe` Success (List [23, 42 :: Int]) it "propagates parse error messages of invalid elements" $ do- parseEither parseJSON (toJSON [String "foo", invalid]) `shouldBe` parseError "Error in $[1]"+ parseEither parseJSON (toJSON [Number 23, String "foo"]) `shouldBe` parseError "Error in $[1]" describe "tryReadFile" $ do it "reads file" $ do