packages feed

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