summoner-2.0.0.0: src/Summoner/Template/Cabal.hs
{-# LANGUAGE QuasiQuotes #-}
{- |
Copyright: (c) 2017-2019 Kowainik
SPDX-License-Identifier: MPL-2.0
Maintainer: Kowainik <xrom.xkov@gmail.com>
@.cabal@ file template.
-}
module Summoner.Template.Cabal
( cabalFile
) where
import NeatInterpolation (text)
import Summoner.CustomPrelude (CustomPrelude (..))
import Summoner.Default (defaultCabal)
import Summoner.GhcVer (cabalBaseVersions, showGhcVer)
import Summoner.License (LicenseName (..))
import Summoner.Settings (Settings (..))
import Summoner.Template.Mempty (memptyIfFalse)
import Summoner.Text (endLine, intercalateMap, packageToModule)
import Summoner.Tree (TreeFs (..))
import qualified Data.Text as T
-- | Creates a `.cabal` file from the given 'Settings'.
cabalFile :: Settings -> TreeFs
cabalFile Settings{..} = File (toString settingsRepo ++ ".cabal") cabalFileContent
where
cabalFileContent :: Text
cabalFileContent = T.concat
[ cabalHeader
, memptyIfFalse settingsGitHub sourceRepository
, commonStanza
, memptyIfFalse settingsIsLib libraryStanza
, memptyIfFalse settingsIsExe executableStanza
, memptyIfFalse settingsTest testSuiteStanza
, memptyIfFalse settingsBench $ benchmarkStanza $ memptyIfFalse settingsIsLib $ ", " <> settingsRepo
]
-- TODO: do something to not have empty lines
cabalHeader :: Text
cabalHeader = unlines $
[ "cabal-version: " <> defaultCabal
, "name: " <> settingsRepo
, "version: 0.0.0.0"
, "synopsis: " <> settingsDescription
, "description: " <> settingsDescription ] ++
[ "homepage: " <> githubUrl | settingsGitHub ] ++
[ "bug-reports: " <> githubBugReports | settingsGitHub ] ++
( "license: " <> licenseName) :
[ "license-file: LICENSE" | settingsLicenseName /= NONE] ++
[ "author: " <> settingsFullName
, "maintainer: " <> settingsFullName <> " <" <> settingsEmail <> ">"
, "copyright: " <> settingsYear <> " " <> settingsFullName ] ++
[ "category: " <> settingsCategories | "" /= settingsCategories ] ++
[ "build-type: Simple"
, "extra-doc-files: README.md"
, " CHANGELOG.md"
, "tested-with: " <> testedGhcs
]
githubUrl, githubBugReports :: Text
githubUrl = "https://github.com/" <> settingsOwner <> "/" <> settingsRepo
githubBugReports = githubUrl <> "/issues"
licenseName, libModuleName :: Text
licenseName = show settingsLicenseName
libModuleName = packageToModule settingsRepo
testedGhcs :: Text
testedGhcs = intercalateMap
("\n" <> T.replicate 21 " ")
(mappend "GHC == " . showGhcVer)
settingsTestedVersions
sourceRepository :: Text
sourceRepository =
[text|
$endLine
source-repository head
type: git
location: ${githubUrl}.git
|]
commonStanza :: Text
commonStanza =
[text|
$endLine
common common-options
build-depends: base $baseBounds
$customPrelude
$ghcOptions
default-language: Haskell2010
|] <> defaultExtensions
baseBounds :: Text
baseBounds = cabalBaseVersions settingsTestedVersions
ghcOptions :: Text
ghcOptions = case settingsGhcOptions of
[] -> defaultGhcOptions
x:xs ->
let customGhcOptions = T.intercalate "\n" $ x : map (T.replicate 21 " " <>) xs in
[text|
ghc-options: $customGhcOptions
|]
defaultGhcOptions :: Text
defaultGhcOptions =
[text|
ghc-options: -Wall
-Wcompat
-Widentities
-Wincomplete-uni-patterns
-Wincomplete-record-updates
if impl(ghc >= 8.0)
ghc-options: -Wredundant-constraints
if impl(ghc >= 8.2)
ghc-options: -fhide-source-paths
if impl(ghc >= 8.4)
ghc-options: -Wmissing-export-lists
-Wpartial-fields
if impl(ghc >= 8.8)
ghc-options: -Wmissing-deriving-strategies
|]
libraryStanza :: Text
libraryStanza =
[text|
$endLine
library
import: common-options
hs-source-dirs: src
exposed-modules: $libModuleName
|]
executableStanza :: Text
executableStanza =
[text|
$endLine
executable $settingsRepo
import: common-options
hs-source-dirs: app
main-is: Main.hs
$buildDepends
$rtsOptions
|]
testSuiteStanza :: Text
testSuiteStanza =
[text|
$endLine
test-suite ${settingsRepo}-test
import: common-options
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Spec.hs
$buildDepends
$rtsOptions
|]
benchmarkStanza :: Text -> Text
benchmarkStanza commaRepo =
[text|
$endLine
benchmark ${settingsRepo}-benchmark
import: common-options
type: exitcode-stdio-1.0
hs-source-dirs: benchmark
main-is: Main.hs
build-depends: gauge
$commaRepo
$rtsOptions
|]
-- | @build-depends@ for the repo, only if the library is on.
buildDepends :: Text
buildDepends =
if settingsIsLib
then "build-depends: " <> settingsRepo
else ""
rtsOptions :: Text
rtsOptions =
[text|
ghc-options: -threaded
-rtsopts
-with-rtsopts=-N
|]
customPrelude :: Text
customPrelude = case settingsPrelude of
Nothing -> ""
Just CustomPrelude{..} ->
" , " <> cpPackage <> "\n" <>
[text|
$endLine
mixins: base hiding (Prelude)
, $cpPackage ($cpModule as Prelude)
$endLine
|]
defaultExtensions :: Text
defaultExtensions = case settingsExtensions of
[] -> ""
xs -> " default-extensions: "
<> T.intercalate "\n " xs
<> "\n"