hpack 0.37.0 → 0.38.0
raw patch · 8 files changed
+325/−188 lines, 8 filesdep ~CabalPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: Cabal
API changes (from Hackage documentation)
+ Hpack.Config: CabalVersion :: Version -> CabalVersion
+ Hpack.Config: VerbatimCabalVersion :: String -> CabalVersion
+ Hpack.Config: [packageCabalVersion] :: Package -> CabalVersion
+ Hpack.Config: data CabalVersion
+ Hpack.Config: instance GHC.Classes.Eq Hpack.Config.CabalVersion
+ Hpack.Config: instance GHC.Classes.Ord Hpack.Config.CabalVersion
+ Hpack.Config: instance GHC.Show.Show Hpack.Config.CabalVersion
+ Hpack.Config: makeCabalVersion :: [Int] -> CabalVersion
- Hpack.Config: Package :: String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> [String] -> [String] -> [String] -> BuildType -> Maybe String -> [FilePath] -> [String] -> [Flag] -> [Path] -> [Path] -> [Path] -> Maybe FilePath -> Maybe SourceRepository -> Maybe CustomSetup -> Maybe (Section Library) -> Map String (Section Library) -> Map String (Section Executable) -> Map String (Section Executable) -> Map String (Section Executable) -> [Verbatim] -> Package
+ Hpack.Config: Package :: CabalVersion -> String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> [String] -> [String] -> [String] -> BuildType -> Maybe String -> [FilePath] -> [String] -> [Flag] -> [Path] -> [Path] -> [Path] -> Maybe FilePath -> Maybe SourceRepository -> Maybe CustomSetup -> Maybe (Section Library) -> Map String (Section Library) -> Map String (Section Executable) -> Map String (Section Executable) -> Map String (Section Executable) -> [Verbatim] -> Package
Files
- CHANGELOG.md +4/−0
- LICENSE +1/−1
- hpack.cabal +2/−2
- resources/test/hpack.cabal +2/−2
- src/Hpack/Config.hs +97/−57
- src/Hpack/Render.hs +119/−86
- test/EndToEndSpec.hs +89/−36
- test/Hpack/RenderSpec.hs +11/−4
CHANGELOG.md view
@@ -1,3 +1,7 @@+## Changes in 0.38.0+ - Generate `build-tool-depends` instead of `build-tools` starting with+ `cabal-version: 2` (fixes #596)+ ## Changes in 0.37.0 - Add support for `asm-options` and `asm-sources` (see #573)
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014-2023 Simon Hengel <sol@typeful.net>+Copyright (c) 2014-2025 Simon Hengel <sol@typeful.net> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
hpack.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.0 --- This file has been generated from package.yaml by hpack version 0.36.0.+-- This file has been generated from package.yaml by hpack version 0.38.0. -- -- see: https://github.com/sol/hpack name: hpack-version: 0.37.0+version: 0.38.0 synopsis: A modern format for Haskell packages description: See README at <https://github.com/sol/hpack#readme> category: Development
resources/test/hpack.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.0 --- This file has been generated from package.yaml by hpack version 0.36.0.+-- This file has been generated from package.yaml by hpack version 0.38.0. -- -- see: https://github.com/sol/hpack name: hpack-version: 0.37.0+version: 0.38.0 synopsis: A modern format for Haskell packages description: See README at <https://github.com/sol/hpack#readme> category: Development
src/Hpack/Config.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-}@@ -41,6 +42,8 @@ , package , section , Package(..)+, CabalVersion(..)+, makeCabalVersion , Dependencies(..) , DependencyInfo(..) , VersionConstraint(..)@@ -104,7 +107,8 @@ import qualified Control.Monad.State as State import Control.Monad.Writer (MonadWriter, WriterT, runWriterT, tell) import Control.Monad.Except-import Data.Version (Version, makeVersion, showVersion)+import Data.Version (Version, showVersion)+import qualified Data.Version as Version import Distribution.Pretty (prettyShow) import qualified Distribution.SPDX.License as SPDX@@ -132,9 +136,13 @@ import qualified Paths_hpack as Hpack (version) +defaultCabalVersion :: Version+defaultCabalVersion = Version.makeVersion [1,12]+ package :: String -> String -> Package package name version = Package {- packageName = name+ packageCabalVersion = CabalVersion defaultCabalVersion+ , packageName = name , packageVersion = version , packageSynopsis = Nothing , packageDescription = Nothing@@ -698,8 +706,13 @@ userDataDir <- liftIO $ maybe (getAppUserDataDirectory "hpack") return mUserDataDir toPackage formatYamlParseError userDataDir dir config where- addCabalFile :: ((Package, String), [String]) -> DecodeResult- addCabalFile ((pkg, cabalVersion), warnings) = DecodeResult pkg cabalVersion (takeDirectory_ file </> (packageName pkg ++ ".cabal")) warnings+ addCabalFile :: (Package, [String]) -> DecodeResult+ addCabalFile (pkg, warnings) = DecodeResult {+ decodeResultPackage = pkg+ , decodeResultCabalVersion = "cabal-version: " ++ showCabalVersion (packageCabalVersion pkg) ++ "\n\n"+ , decodeResultCabalFile = takeDirectory_ file </> packageName pkg <.> "cabal"+ , decodeResultWarnings = warnings+ } takeDirectory_ :: FilePath -> FilePath takeDirectory_ p@@ -718,9 +731,9 @@ VerbatimBool b -> show b VerbatimNull -> "" -addPathsModuleToGeneratedModules :: Package -> Version -> Package-addPathsModuleToGeneratedModules pkg cabalVersion- | cabalVersion < makeVersion [2] = pkg+addPathsModuleToGeneratedModules :: Package -> Package+addPathsModuleToGeneratedModules pkg+ | packageCabalVersion pkg < makeCabalVersion [2] = pkg | otherwise = pkg { packageLibrary = fmap mapLibrary <$> packageLibrary pkg , packageInternalLibraries = fmap mapLibrary <$> packageInternalLibraries pkg@@ -749,22 +762,53 @@ where generatedModules = executableGeneratedModules executable -determineCabalVersion :: Maybe (License SPDX.License) -> Package -> (Package, String, Maybe Version)-determineCabalVersion inferredLicense pkg@Package{..} = (- pkg {- packageVerbatim = deleteVerbatimField "cabal-version" packageVerbatim- , packageLicense = formatLicense <$> license- }- , "cabal-version: " ++ effectiveCabalVersion ++ "\n\n"- , parseVersion effectiveCabalVersion- )+data CabalVersion = CabalVersion Version | VerbatimCabalVersion String+ deriving (Eq, Ord, Show)++makeCabalVersion :: [Int] -> CabalVersion+makeCabalVersion = CabalVersion . Version.makeVersion++showCabalVersion :: CabalVersion -> String+showCabalVersion = \ case+ CabalVersion v -> showVersion v+ VerbatimCabalVersion v -> v++extractVerbatimCabalVersion :: [Verbatim] -> (Maybe CabalVersion, [Verbatim])+extractVerbatimCabalVersion verbatim = case listToMaybe (mapMaybe extractCabalVersion verbatim) of+ Nothing -> (Nothing, verbatim)+ Just verbatimVersion -> (Just cabalVersion, deleteVerbatimField "cabal-version" verbatim)+ where+ cabalVersion :: CabalVersion+ cabalVersion = case parseVersion verbatimVersion of+ Nothing -> VerbatimCabalVersion verbatimVersion+ Just v -> CabalVersion v where- effectiveCabalVersion = fromMaybe inferredCabalVersion verbatimCabalVersion+ extractCabalVersion :: Verbatim -> Maybe String+ extractCabalVersion = \ case+ VerbatimLiteral _ -> Nothing+ VerbatimObject o -> case Map.lookup "cabal-version" o of+ Just v -> Just (verbatimValueToString v)+ Nothing -> Nothing +ensureRequiredCabalVersion :: Maybe (License SPDX.License) -> Package -> Package+ensureRequiredCabalVersion inferredLicense pkg@Package{..} = pkg {+ packageCabalVersion = version+ , packageLicense = formatLicense <$> license+ , packageVerbatim = verbatim+ }+ where+ makeVersion :: [Int] -> CabalVersion+ makeVersion = makeCabalVersion++ (verbatimCabalVersion, verbatim) = extractVerbatimCabalVersion packageVerbatim++ license :: Maybe (License String) license = fmap prettyShow <$> (parsedLicense <|> inferredLicense) + parsedLicense :: Maybe (License SPDX.License) parsedLicense = parseLicense <$> packageLicense + formatLicense :: License String -> String formatLicense = \ case MustSPDX spdx -> spdx CanSPDX _ spdx | version >= makeVersion [2,2] -> spdx@@ -779,21 +823,14 @@ CanSPDX _ _ -> False MustSPDX _ -> True - verbatimCabalVersion :: Maybe String- verbatimCabalVersion = listToMaybe (mapMaybe f packageVerbatim)- where- f :: Verbatim -> Maybe String- f = \ case- VerbatimLiteral _ -> Nothing- VerbatimObject o -> case Map.lookup "cabal-version" o of- Just v -> Just (verbatimValueToString v)- Nothing -> Nothing-- inferredCabalVersion :: String- inferredCabalVersion = showVersion version+ version :: CabalVersion+ version = fromMaybe inferredVersion verbatimCabalVersion - version = fromMaybe (makeVersion [1,12]) $ maximum [- packageCabalVersion+ inferredVersion :: CabalVersion+ inferredVersion = fromMaybe packageCabalVersion $ maximum [+ makeVersion [2,2] <$ guard mustSPDX+ , makeVersion [1,24] <$ packageCustomSetup+ , makeVersion [1,18] <$ guard (not (null packageExtraDocFiles)) , packageLibrary >>= libraryCabalVersion , internalLibsCabalVersion packageInternalLibraries , executablesCabalVersion packageExecutables@@ -801,15 +838,7 @@ , executablesCabalVersion packageBenchmarks ] - packageCabalVersion :: Maybe Version- packageCabalVersion = maximum [- Nothing- , makeVersion [2,2] <$ guard mustSPDX- , makeVersion [1,24] <$ packageCustomSetup- , makeVersion [1,18] <$ guard (not (null packageExtraDocFiles))- ]-- libraryCabalVersion :: Section Library -> Maybe Version+ libraryCabalVersion :: Section Library -> Maybe CabalVersion libraryCabalVersion sect = maximum [ makeVersion [1,22] <$ guard (has libraryReexportedModules) , makeVersion [2,0] <$ guard (has librarySignatures)@@ -820,17 +849,17 @@ where has field = any (not . null . field) sect - internalLibsCabalVersion :: Map String (Section Library) -> Maybe Version+ internalLibsCabalVersion :: Map String (Section Library) -> Maybe CabalVersion internalLibsCabalVersion internalLibraries | Map.null internalLibraries = Nothing | otherwise = foldr max (Just $ makeVersion [2,0]) versions where versions = libraryCabalVersion <$> Map.elems internalLibraries - executablesCabalVersion :: Map String (Section Executable) -> Maybe Version+ executablesCabalVersion :: Map String (Section Executable) -> Maybe CabalVersion executablesCabalVersion = foldr max Nothing . map executableCabalVersion . Map.elems - executableCabalVersion :: Section Executable -> Maybe Version+ executableCabalVersion :: Section Executable -> Maybe CabalVersion executableCabalVersion sect = maximum [ makeVersion [2,0] <$ guard (executableHasGeneratedModules sect) , sectionCabalVersion (concatMap getExecutableModules) sect@@ -839,7 +868,7 @@ executableHasGeneratedModules :: Section Executable -> Bool executableHasGeneratedModules = any (not . null . executableGeneratedModules) - sectionCabalVersion :: (Section a -> [Module]) -> Section a -> Maybe Version+ sectionCabalVersion :: (Section a -> [Module]) -> Section a -> Maybe CabalVersion sectionCabalVersion getMentionedModules sect = maximum $ [ makeVersion [2,2] <$ guard (sectionSatisfies (not . null . sectionCxxSources) sect) , makeVersion [2,2] <$ guard (sectionSatisfies (not . null . sectionCxxOptions) sect)@@ -853,17 +882,23 @@ && pathsModule `elem` getMentionedModules sect) ] ++ map versionFromSystemBuildTool systemBuildTools where+ defaultExtensions :: [String] defaultExtensions = sectionAll sectionDefaultExtensions sect++ uses :: String -> Bool uses = (`elem` defaultExtensions) + pathsModule :: Module pathsModule = pathsModuleFromPackageName packageName + versionFromSystemBuildTool :: String -> Maybe CabalVersion 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 :: [String] known_1_10 = [ "ghc" , "ghc-pkg"@@ -891,9 +926,13 @@ , "lhc" , "lhc-pkg" ]++ known_1_14 :: [String] known_1_14 = [ "hpc" ]++ known_1_22 :: [String] known_1_22 = [ "ghcjs" , "ghcjs-pkg"@@ -966,7 +1005,8 @@ Nothing -> fail ("invalid value " ++ show s) data Package = Package {- packageName :: String+ packageCabalVersion :: CabalVersion+, packageName :: String , packageVersion :: String , packageSynopsis :: Maybe String , packageDescription :: Maybe String@@ -1093,7 +1133,7 @@ type CommonOptionsWithDefaults a = Product DefaultsConfig (CommonOptions ParseAsmSources ParseCSources ParseCxxSources ParseJsSources a) type WithCommonOptionsWithDefaults a = Product DefaultsConfig (WithCommonOptions ParseAsmSources ParseCSources ParseCxxSources ParseJsSources a) -toPackage :: FormatYamlParseError -> FilePath -> FilePath -> ConfigWithDefaults -> ConfigM IO (Package, String)+toPackage :: FormatYamlParseError -> FilePath -> FilePath -> ConfigWithDefaults -> ConfigM IO Package toPackage formatYamlParseError userDataDir dir = expandDefaultsInConfig formatYamlParseError userDataDir dir >=> setDefaultLanguage "Haskell2010"@@ -1195,9 +1235,9 @@ type GlobalOptions = CommonOptions AsmSources CSources CxxSources JsSources Empty -toPackage_ :: (MonadIO m, Warnings m, State m) => FilePath -> Product GlobalOptions (PackageConfig AsmSources CSources CxxSources JsSources) -> m (Package, String)+toPackage_ :: (MonadIO m, Warnings m, State m) => FilePath -> Product GlobalOptions (PackageConfig AsmSources CSources CxxSources JsSources) -> m Package toPackage_ dir (Product g PackageConfig{..}) = do- executableMap <- toExecutableMap packageName_ packageConfigExecutables packageConfigExecutable+ executableMap <- toExecutableMap packageName packageConfigExecutables packageConfigExecutable let globalVerbatim = commonOptionsVerbatim g globalOptions = g {commonOptionsVerbatim = Nothing}@@ -1205,13 +1245,13 @@ executableNames = maybe [] Map.keys executableMap toSect :: (Warnings m, Monoid a) => WithCommonOptions AsmSources CSources CxxSources JsSources a -> m (Section a)- toSect = toSection packageName_ executableNames . first ((mempty <$ globalOptions) <>)+ toSect = toSection packageName executableNames . first ((mempty <$ globalOptions) <>) toSections :: (Warnings m, Monoid a) => Maybe (Map String (WithCommonOptions AsmSources CSources CxxSources JsSources a)) -> m (Map String (Section a)) toSections = maybe (return mempty) (traverse toSect) - toLib = toLibrary dir packageName_- toExecutables = toSections >=> traverse (toExecutable dir packageName_)+ toLib = toLibrary dir packageName+ toExecutables = toSections >=> traverse (toExecutable dir packageName) mLibrary <- traverse (toSect >=> toLib) packageConfigLibrary internalLibraries <- toSections packageConfigInternalLibraries >>= traverse toLib@@ -1257,7 +1297,8 @@ defaultBuildType = maybe Simple (const Custom) mCustomSetup pkg = Package {- packageName = packageName_+ packageCabalVersion = CabalVersion defaultCabalVersion+ , packageName , packageVersion = maybe "0.0.0" unPackageVersion packageConfigVersion , packageSynopsis = packageConfigSynopsis , packageDescription = packageConfigDescription@@ -1290,12 +1331,11 @@ tell nameWarnings tell (formatMissingSourceDirs missingSourceDirs) - let (pkg_, renderedCabalVersion, cabalVersion) = determineCabalVersion inferredLicense pkg- return (maybe pkg_ (addPathsModuleToGeneratedModules pkg_) cabalVersion, renderedCabalVersion)+ return $ addPathsModuleToGeneratedModules $ ensureRequiredCabalVersion inferredLicense pkg where nameWarnings :: [String]- packageName_ :: String- (nameWarnings, packageName_) = case packageConfigName of+ packageName :: String+ (nameWarnings, packageName) = case packageConfigName of Nothing -> let inferredName = takeBaseName dir in (["Package name not specified, inferred " ++ show inferredName], inferredName) Just n -> ([], n)@@ -1418,7 +1458,7 @@ let pathsModule :: [Module] pathsModule = case specVersion of- SpecVersion v | v >= makeVersion [0,36,0] -> []+ SpecVersion v | v >= Version.makeVersion [0,36,0] -> [] _ -> [pathsModuleFromPackageName packageName_] removeConditionalsThatAreAlwaysFalse <$> traverseSectionAndConditionals
src/Hpack/Render.hs view
@@ -23,6 +23,7 @@ , Alignment(..) , CommaStyle(..) #ifdef TEST+, RenderEnv(..) , renderConditional , renderDependencies , renderLibraryFields@@ -40,6 +41,7 @@ import Data.Maybe import Data.Map.Lazy (Map) import qualified Data.Map.Lazy as Map+import Control.Monad.Reader import Hpack.Util import Hpack.Config@@ -47,6 +49,19 @@ import Hpack.Render.Dsl hiding (sortFieldsBy) import qualified Hpack.Render.Dsl as Dsl +data RenderEnv = RenderEnv {+ renderEnvCabalVersion :: CabalVersion+, renderEnvPackageName :: String+}++type RenderM = Reader RenderEnv++getCabalVersion :: RenderM CabalVersion+getCabalVersion = asks renderEnvCabalVersion++getPackageName :: RenderM String+getPackageName = asks renderEnvPackageName+ renderPackage :: [String] -> Package -> String renderPackage oldCabalFile = renderPackageWith settings headerFieldsAlignment formattingHintsFieldOrder formattingHintsSectionsFieldOrder where@@ -78,20 +93,23 @@ customSetup :: [Element] customSetup = maybe [] (return . renderCustomSetup) packageCustomSetup - library :: [Element]- library = maybe [] (return . renderLibrary) packageLibrary- stanzas :: [Element]- stanzas = concat [- sourceRepository- , customSetup- , map renderFlag packageFlags- , library- , renderInternalLibraries packageInternalLibraries- , renderExecutables packageExecutables- , renderTests packageTests- , renderBenchmarks packageBenchmarks- ]+ stanzas = flip runReader (RenderEnv packageCabalVersion packageName) $ do+ library <- maybe (return []) (fmap return . renderLibrary) packageLibrary+ internalLibraries <- renderInternalLibraries packageInternalLibraries+ executables <- renderExecutables packageExecutables+ tests <- renderTests packageTests+ benchmarks <- renderBenchmarks packageBenchmarks+ return $ concat [+ sourceRepository+ , customSetup+ , map renderFlag packageFlags+ , library+ , internalLibraries+ , executables+ , tests+ , benchmarks+ ] headerFields :: [Element] headerFields = mapMaybe (\(name, value) -> Field name . Literal <$> value) $ [@@ -155,37 +173,37 @@ where description = maybe [] (return . Field "description" . Literal) flagDescription -renderInternalLibraries :: Map String (Section Library) -> [Element]-renderInternalLibraries = map renderInternalLibrary . Map.toList+renderInternalLibraries :: Map String (Section Library) -> RenderM [Element]+renderInternalLibraries = traverse renderInternalLibrary . Map.toList -renderInternalLibrary :: (String, Section Library) -> Element-renderInternalLibrary (name, sect) =- Stanza ("library " ++ name) (renderLibrarySection sect)+renderInternalLibrary :: (String, Section Library) -> RenderM Element+renderInternalLibrary (name, sect) = do+ Stanza ("library " ++ name) <$> renderLibrarySection sect -renderExecutables :: Map String (Section Executable) -> [Element]-renderExecutables = map renderExecutable . Map.toList+renderExecutables :: Map String (Section Executable) -> RenderM [Element]+renderExecutables = traverse renderExecutable . Map.toList -renderExecutable :: (String, Section Executable) -> Element-renderExecutable (name, sect) =- Stanza ("executable " ++ name) (renderExecutableSection [] sect)+renderExecutable :: (String, Section Executable) -> RenderM Element+renderExecutable (name, sect) = do+ Stanza ("executable " ++ name) <$> renderExecutableSection [] sect -renderTests :: Map String (Section Executable) -> [Element]-renderTests = map renderTest . Map.toList+renderTests :: Map String (Section Executable) -> RenderM [Element]+renderTests = traverse renderTest . Map.toList -renderTest :: (String, Section Executable) -> Element-renderTest (name, sect) =- Stanza ("test-suite " ++ name)- (renderExecutableSection [Field "type" "exitcode-stdio-1.0"] sect)+renderTest :: (String, Section Executable) -> RenderM Element+renderTest (name, sect) = do+ Stanza ("test-suite " ++ name) <$>+ renderExecutableSection [Field "type" "exitcode-stdio-1.0"] sect -renderBenchmarks :: Map String (Section Executable) -> [Element]-renderBenchmarks = map renderBenchmark . Map.toList+renderBenchmarks :: Map String (Section Executable) -> RenderM [Element]+renderBenchmarks = traverse renderBenchmark . Map.toList -renderBenchmark :: (String, Section Executable) -> Element-renderBenchmark (name, sect) =- Stanza ("benchmark " ++ name)- (renderExecutableSection [Field "type" "exitcode-stdio-1.0"] sect)+renderBenchmark :: (String, Section Executable) -> RenderM Element+renderBenchmark (name, sect) = do+ Stanza ("benchmark " ++ name) <$>+ renderExecutableSection [Field "type" "exitcode-stdio-1.0"] sect -renderExecutableSection :: [Element] -> Section Executable -> [Element]+renderExecutableSection :: [Element] -> Section Executable -> RenderM [Element] renderExecutableSection extraFields = renderSection renderExecutableFields extraFields renderExecutableFields :: Executable -> [Element]@@ -199,10 +217,10 @@ renderCustomSetup CustomSetup{..} = Stanza "custom-setup" $ renderDependencies "setup-depends" customSetupDependencies -renderLibrary :: Section Library -> Element-renderLibrary sect = Stanza "library" $ renderLibrarySection sect+renderLibrary :: Section Library -> RenderM Element+renderLibrary sect = Stanza "library" <$> renderLibrarySection sect -renderLibrarySection :: Section Library -> [Element]+renderLibrarySection :: Section Library -> RenderM [Element] renderLibrarySection = renderSection renderLibraryFields [] renderLibraryFields :: Library -> [Element]@@ -222,39 +240,43 @@ renderVisibility :: String -> Element renderVisibility = Field "visibility" . Literal -renderSection :: (a -> [Element]) -> [Element] -> Section a -> [Element]-renderSection renderSectionData extraFieldsStart Section{..} = addVerbatim sectionVerbatim $- extraFieldsStart- ++ renderSectionData sectionData ++ [- renderDirectories "hs-source-dirs" sectionSourceDirs- , renderDefaultExtensions sectionDefaultExtensions- , renderOtherExtensions sectionOtherExtensions- , renderGhcOptions sectionGhcOptions- , renderGhcProfOptions sectionGhcProfOptions- , renderGhcSharedOptions sectionGhcSharedOptions- , renderGhcjsOptions sectionGhcjsOptions- , renderCppOptions sectionCppOptions- , renderAsmOptions sectionAsmOptions- , renderCcOptions sectionCcOptions- , renderCxxOptions sectionCxxOptions- , renderDirectories "include-dirs" sectionIncludeDirs- , Field "install-includes" (LineSeparatedList sectionInstallIncludes)- , Field "asm-sources" (renderPaths sectionAsmSources)- , Field "c-sources" (renderPaths sectionCSources)- , Field "cxx-sources" (renderPaths sectionCxxSources)- , Field "js-sources" (renderPaths sectionJsSources)- , renderDirectories "extra-lib-dirs" sectionExtraLibDirs- , Field "extra-libraries" (LineSeparatedList sectionExtraLibraries)- , renderDirectories "extra-frameworks-dirs" sectionExtraFrameworksDirs- , Field "frameworks" (LineSeparatedList sectionFrameworks)- , renderLdOptions sectionLdOptions- , Field "pkgconfig-depends" (CommaSeparatedList sectionPkgConfigDependencies)- ]- ++ renderBuildTools sectionBuildTools sectionSystemBuildTools- ++ renderDependencies "build-depends" sectionDependencies- ++ maybe [] (return . renderBuildable) sectionBuildable- ++ maybe [] (return . renderLanguage) sectionLanguage- ++ map (renderConditional renderSectionData) sectionConditionals+renderSection :: (a -> [Element]) -> [Element] -> Section a -> RenderM [Element]+renderSection renderSectionData extraFieldsStart Section{..} = do+ buildTools <- renderBuildTools sectionBuildTools sectionSystemBuildTools+ conditionals <- traverse (renderConditional renderSectionData) sectionConditionals+ return . addVerbatim sectionVerbatim $+ extraFieldsStart+ ++ renderSectionData sectionData+ ++ [+ renderDirectories "hs-source-dirs" sectionSourceDirs+ , renderDefaultExtensions sectionDefaultExtensions+ , renderOtherExtensions sectionOtherExtensions+ , renderGhcOptions sectionGhcOptions+ , renderGhcProfOptions sectionGhcProfOptions+ , renderGhcSharedOptions sectionGhcSharedOptions+ , renderGhcjsOptions sectionGhcjsOptions+ , renderCppOptions sectionCppOptions+ , renderAsmOptions sectionAsmOptions+ , renderCcOptions sectionCcOptions+ , renderCxxOptions sectionCxxOptions+ , renderDirectories "include-dirs" sectionIncludeDirs+ , Field "install-includes" (LineSeparatedList sectionInstallIncludes)+ , Field "asm-sources" (renderPaths sectionAsmSources)+ , Field "c-sources" (renderPaths sectionCSources)+ , Field "cxx-sources" (renderPaths sectionCxxSources)+ , Field "js-sources" (renderPaths sectionJsSources)+ , renderDirectories "extra-lib-dirs" sectionExtraLibDirs+ , Field "extra-libraries" (LineSeparatedList sectionExtraLibraries)+ , renderDirectories "extra-frameworks-dirs" sectionExtraFrameworksDirs+ , Field "frameworks" (LineSeparatedList sectionFrameworks)+ , renderLdOptions sectionLdOptions+ , Field "pkgconfig-depends" (CommaSeparatedList sectionPkgConfigDependencies)+ ]+ ++ buildTools+ ++ renderDependencies "build-depends" sectionDependencies+ ++ maybe [] (return . renderBuildable) sectionBuildable+ ++ maybe [] (return . renderLanguage) sectionLanguage+ ++ conditionals addVerbatim :: [Verbatim] -> [Element] -> [Element] addVerbatim verbatim fields = filterVerbatim verbatim fields ++ renderVerbatim verbatim@@ -285,12 +307,12 @@ [x] -> Field key (Literal x) xs -> Field key (LineSeparatedList xs) -renderConditional :: (a -> [Element]) -> Conditional (Section a) -> Element+renderConditional :: (a -> [Element]) -> Conditional (Section a) -> RenderM Element renderConditional renderSectionData (Conditional condition sect mElse) = case mElse of Nothing -> if_- Just else_ -> Group if_ (Stanza "else" $ renderSection renderSectionData [] else_)+ Just else_ -> Group <$> if_ <*> (Stanza "else" <$> renderSection renderSectionData [] else_) where- if_ = Stanza ("if " ++ renderCond condition) (renderSection renderSectionData [] sect)+ if_ = Stanza ("if " ++ renderCond condition) <$> renderSection renderSectionData [] sect renderCond :: Cond -> String renderCond = \ case@@ -343,21 +365,32 @@ AnyVersion -> "" VersionRange x -> " " ++ x -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])- ]+renderBuildTools :: Map BuildTool DependencyVersion -> SystemBuildTools -> RenderM [Element]+renderBuildTools buildTools systemBuildTools = do+ xs <- traverse renderBuildTool $ Map.toList buildTools+ return [+ 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)+renderBuildTool :: (BuildTool, DependencyVersion) -> RenderM RenderBuildTool+renderBuildTool (buildTool, renderVersion -> version) = do+ cabalVersion <- getCabalVersion+ packageName <- getPackageName+ let supportsBuildTools = cabalVersion < makeCabalVersion [2]+ return $ case buildTool of+ LocalBuildTool executable+ | supportsBuildTools -> BuildTools (executable ++ version)+ | otherwise -> BuildToolDepends (packageName ++ ":" ++ executable ++ version)+ BuildTool pkg executable+ | supportsBuildTools && isknownBuildTool pkg executable -> BuildTools (executable ++ version)+ | otherwise -> BuildToolDepends (pkg ++ ":" ++ executable ++ version) where+ isknownBuildTool :: String -> String -> Bool+ isknownBuildTool pkg executable = pkg == executable && executable `elem` knownBuildTools+ knownBuildTools :: [String] knownBuildTools = [ "alex"
test/EndToEndSpec.hs view
@@ -19,7 +19,7 @@ import Data.Version (showVersion) import qualified Hpack.Render as Hpack-import Hpack.Config (packageConfig, readPackageConfig, DecodeOptions(..), DecodeResult(..), defaultDecodeOptions)+import Hpack.Config (packageConfig, readPackageConfig, DecodeOptions(..), defaultDecodeOptions, DecodeResult(..)) import Hpack.Render.Hints (FormattingHints(..), sniffFormattingHints) import qualified Paths_hpack as Hpack (version)@@ -639,43 +639,63 @@ |] `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_ "my-package" [i|- build-tools:- alex ==0.1.0- |]+ context "with known build tools" $ do+ context "when cabal-version < 2" $ do+ it "adds them to build-tools" $ do+ [i|+ executable:+ build-tools:+ alex == 0.1.0+ |] `shouldRenderTo` executable_ "my-package" [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_ "my-package" [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 cabal-version >= 2" $ do+ it "adds them to build-tool-depends" $ do+ [i|+ verbatim:+ cabal-version: 2.0+ executable:+ build-tools:+ alex == 0.1.0+ |] `shouldRenderTo` (executable_ "my-package" [i|+ autogen-modules:+ Paths_my_package+ build-tool-depends:+ alex:alex ==0.1.0+ |]) {+ packageCabalVersion = "2.0"+ } - it "accepts build-tool-depends as an alias" $ do- [i|- executable:+ context "with other build tools" $ do+ it "adds them to build-tool-depends" $ do+ [i|+ executable:+ build-tools:+ hspec-discover: 0.1.0+ |] `shouldRenderTo` (executable_ "my-package" [i| build-tool-depends:- hspec-discover: 0.1.0- |] `shouldRenderTo` (executable_ "my-package" [i|- build-tool-depends:- hspec-discover:hspec-discover ==0.1.0- |]) {- packageCabalVersion = "1.12"- , packageWarnings = ["package.yaml: $.executable.build-tool-depends is deprecated, use $.executable.build-tools instead"]- }+ 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"+ } + it "accepts build-tool-depends as an alias" $ do+ [i|+ executable:+ build-tool-depends:+ hspec-discover: 0.1.0+ |] `shouldRenderTo` (executable_ "my-package" [i|+ build-tool-depends:+ hspec-discover:hspec-discover ==0.1.0+ |]) {+ packageCabalVersion = "1.12"+ , packageWarnings = ["package.yaml: $.executable.build-tool-depends is deprecated, use $.executable.build-tools instead"]+ }+ context "when the name of a build tool matches an executable from the same package" $ do it "adds it to build-tools" $ do [i|@@ -714,6 +734,22 @@ bar ==0.2.0 |] + context "when cabal-version >= 2" $ do+ it "adds it to build-tool-depends" $ do+ [i|+ verbatim:+ cabal-version: 2.0+ executables:+ bar:+ build-tools:+ - bar+ |] `shouldRenderTo` (executable_ "bar" [i|+ autogen-modules:+ Paths_my_package+ build-tool-depends:+ my-package:bar+ |]) {packageCabalVersion = "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|@@ -1888,8 +1924,25 @@ it "overrides header fields" $ do [i| verbatim:- cabal-version: foo- |] `shouldRenderTo` (package "") {packageCabalVersion = "foo"}+ build-type: foo+ |] `shouldRenderTo` (package "") {packageBuildType = "foo"}++ context "with cabal-version" $ do+ context "with a string value" $ do+ it "takes precedence over inferred version" $ do+ [i|+ license: BSD-3-Clause+ verbatim:+ cabal-version: foo+ |] `shouldRenderTo` (package "license: BSD-3-Clause") {packageCabalVersion = "foo"}++ context "with a version" $ do+ it "takes precedence over inferred version" $ do+ [i|+ license: BSD-3-Clause+ verbatim:+ cabal-version: 0.8+ |] `shouldRenderTo` (package "license: BSD-3-Clause") {packageCabalVersion = "0.8"} it "overrides other fields" $ do touch "foo"
test/Hpack/RenderSpec.hs view
@@ -4,6 +4,8 @@ import Helper +import Control.Monad.Reader (runReader)+ import Hpack.Syntax.DependencyVersion import Hpack.ConfigSpec hiding (spec) import Hpack.Config hiding (package)@@ -21,6 +23,9 @@ renderEmptySection :: Empty -> [Element] renderEmptySection Empty = [] +cabalVersion :: CabalVersion+cabalVersion = makeCabalVersion [1,12]+ spec :: Spec spec = do describe "renderPackageWith" $ do@@ -220,9 +225,11 @@ ] describe "renderConditional" $ do+ let run = flip runReader (RenderEnv cabalVersion "foo")+ it "renders conditionals" $ do let conditional = Conditional "os(windows)" (section Empty) {sectionDependencies = deps ["Win32"]} Nothing- render defaultRenderSettings 0 (renderConditional renderEmptySection conditional) `shouldBe` [+ render defaultRenderSettings 0 (run $ renderConditional renderEmptySection conditional) `shouldBe` [ "if os(windows)" , " build-depends:" , " Win32"@@ -230,7 +237,7 @@ it "renders conditionals with else-branch" $ do let conditional = Conditional "os(windows)" (section Empty) {sectionDependencies = deps ["Win32"]} (Just $ (section Empty) {sectionDependencies = deps ["unix"]})- render defaultRenderSettings 0 (renderConditional renderEmptySection conditional) `shouldBe` [+ render defaultRenderSettings 0 (run $ renderConditional renderEmptySection conditional) `shouldBe` [ "if os(windows)" , " build-depends:" , " Win32"@@ -242,7 +249,7 @@ it "renders nested conditionals" $ do let conditional = Conditional "arch(i386)" (section Empty) {sectionGhcOptions = ["-threaded"], sectionConditionals = [innerConditional]} Nothing innerConditional = Conditional "os(windows)" (section Empty) {sectionDependencies = deps ["Win32"]} Nothing- render defaultRenderSettings 0 (renderConditional renderEmptySection conditional) `shouldBe` [+ render defaultRenderSettings 0 (run $ renderConditional renderEmptySection conditional) `shouldBe` [ "if arch(i386)" , " ghc-options: -threaded" , " if os(windows)"@@ -253,7 +260,7 @@ it "conditionalises both build-depends and mixins" $ do let conditional = Conditional "os(windows)" (section Empty) {sectionDependencies = [("Win32", depInfo)]} Nothing depInfo = defaultInfo { dependencyInfoMixins = ["hiding (Blah)"] }- render defaultRenderSettings 0 (renderConditional renderEmptySection conditional) `shouldBe` [+ render defaultRenderSettings 0 (run $ renderConditional renderEmptySection conditional) `shouldBe` [ "if os(windows)" , " build-depends:" , " Win32"