module Data.GI.CodeGen.Cabal
( genCabalProject
, cabalConfig
, setupHs
, tryPkgConfig
) where
import Control.Monad (forM_)
import Data.Maybe (fromMaybe)
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>))
#endif
import Data.Version (Version(..))
import qualified Data.Map as M
import qualified Data.Text as T
import Data.Text (Text)
import Text.Read
import Data.GI.CodeGen.API (GIRInfo(..))
import Data.GI.CodeGen.Code
import Data.GI.CodeGen.Config (Config(..))
import Data.GI.CodeGen.Overrides (cabalPkgVersion)
import Data.GI.CodeGen.PkgConfig (pkgConfigGetVersion)
import qualified Data.GI.CodeGen.ProjectInfo as PI
import Data.GI.CodeGen.Util (padTo, tshow)
import Paths_haskell_gi (version)
cabalConfig :: Text
cabalConfig :: Text
cabalConfig = [Text] -> Text
T.unlines [Text
"optimization: False"]
setupHs :: Text
setupHs :: Text
setupHs = [Text] -> Text
T.unlines [Text
"#!/usr/bin/env runhaskell",
Text
"import Distribution.Simple",
Text
"main = defaultMain"]
haskellGIAPIVersion :: Int
haskellGIAPIVersion :: Int
haskellGIAPIVersion = (forall a. [a] -> a
head forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> [Int]
versionBranch) Version
version
minorVersion :: [Int] -> Int
minorVersion :: [Int] -> Int
minorVersion (Int
_:Int
y:[Int]
_) = Int
y
minorVersion [Int]
v = forall a. HasCallStack => [Char] -> a
error forall a b. (a -> b) -> a -> b
$ [Char]
"Programming error: the haskell-gi version does not have at least two components: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show [Int]
v forall a. [a] -> [a] -> [a]
++ [Char]
"."
haskellGIMinor :: Int
haskellGIMinor :: Int
haskellGIMinor = [Int] -> Int
minorVersion (Version -> [Int]
versionBranch Version
version)
giModuleVersion :: Int -> Int -> Text
giModuleVersion :: Int -> Int -> Text
giModuleVersion Int
major Int
minor =
(Text -> [Text] -> Text
T.intercalate Text
"." forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a. Show a => a -> Text
tshow) [Int
haskellGIAPIVersion, Int
major, Int
minor,
Int
haskellGIMinor]
giNextMinor :: Int -> Int -> Text
giNextMinor :: Int -> Int -> Text
giNextMinor Int
major Int
minor = (Text -> [Text] -> Text
T.intercalate Text
"." forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a. Show a => a -> Text
tshow)
[Int
haskellGIAPIVersion, Int
major, Int
minorforall a. Num a => a -> a -> a
+Int
1]
data PkgInfo = PkgInfo { PkgInfo -> Text
pkgName :: Text
, PkgInfo -> Int
pkgMajor :: Int
, PkgInfo -> Int
pkgMinor :: Int
} deriving Int -> PkgInfo -> ShowS
[PkgInfo] -> ShowS
PkgInfo -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [PkgInfo] -> ShowS
$cshowList :: [PkgInfo] -> ShowS
show :: PkgInfo -> [Char]
$cshow :: PkgInfo -> [Char]
showsPrec :: Int -> PkgInfo -> ShowS
$cshowsPrec :: Int -> PkgInfo -> ShowS
Show
tryPkgConfig :: GIRInfo -> Bool -> M.Map Text Text -> IO (Either Text PkgInfo)
tryPkgConfig :: GIRInfo -> Bool -> Map Text Text -> IO (Either Text PkgInfo)
tryPkgConfig GIRInfo
gir Bool
verbose Map Text Text
overridenNames = do
let name :: Text
name = GIRInfo -> Text
girNSName GIRInfo
gir
version :: Text
version = GIRInfo -> Text
girNSVersion GIRInfo
gir
packages :: [Text]
packages = GIRInfo -> [Text]
girPCPackages GIRInfo
gir
Text
-> Text
-> [Text]
-> Bool
-> Map Text Text
-> IO (Maybe (Text, Text))
pkgConfigGetVersion Text
name Text
version [Text]
packages Bool
verbose Map Text Text
overridenNames forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just (Text
n,Text
v) ->
case Text -> Maybe (Int, Int)
readMajorMinor Text
v of
Just (Int
major, Int
minor) ->
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right (PkgInfo { pkgName :: Text
pkgName = Text
n
, pkgMajor :: Int
pkgMajor = Int
major
, pkgMinor :: Int
pkgMinor = Int
minor})
Maybe (Int, Int)
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Text
"Cannot parse version \"" forall a. Semigroup a => a -> a -> a
<> Text
v forall a. Semigroup a => a -> a -> a
<>
Text
"\" for module " forall a. Semigroup a => a -> a -> a
<> Text
name
Maybe (Text, Text)
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$
Text
"Could not determine the pkg-config name corresponding to \"" forall a. Semigroup a => a -> a -> a
<> Text
name forall a. Semigroup a => a -> a -> a
<> Text
"\".\n" forall a. Semigroup a => a -> a -> a
<>
Text
"Try adding an override with the proper package name:\n"
forall a. Semigroup a => a -> a -> a
<> Text
"pkg-config-name " forall a. Semigroup a => a -> a -> a
<> Text
name forall a. Semigroup a => a -> a -> a
<> Text
" [matching pkg-config name here]"
readMajorMinor :: Text -> Maybe (Int, Int)
readMajorMinor :: Text -> Maybe (Int, Int)
readMajorMinor Text
version =
case Text -> Text -> [Text]
T.splitOn Text
"." Text
version of
(Text
a:Text
b:[Text]
_) -> (,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Read a => [Char] -> Maybe a
readMaybe (Text -> [Char]
T.unpack Text
a) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Read a => [Char] -> Maybe a
readMaybe (Text -> [Char]
T.unpack Text
b)
[Text]
_ -> forall a. Maybe a
Nothing
genCabalProject :: (GIRInfo, PkgInfo) -> [(GIRInfo, PkgInfo)] ->
[Text] -> BaseVersion -> CodeGen e ()
genCabalProject :: forall e.
(GIRInfo, PkgInfo)
-> [(GIRInfo, PkgInfo)] -> [Text] -> BaseVersion -> CodeGen e ()
genCabalProject (GIRInfo
gir, PkgInfo {pkgName :: PkgInfo -> Text
pkgName = Text
pcName, pkgMajor :: PkgInfo -> Int
pkgMajor = Int
major,
pkgMinor :: PkgInfo -> Int
pkgMinor = Int
minor})
[(GIRInfo, PkgInfo)]
deps [Text]
exposedModules BaseVersion
minBaseVersion = do
Config
cfg <- forall e. CodeGen e Config
config
let name :: Text
name = GIRInfo -> Text
girNSName GIRInfo
gir
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Text
"-- Autogenerated, do not edit."
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"name:" forall a. Semigroup a => a -> a -> a
<> Text
"gi-" forall a. Semigroup a => a -> a -> a
<> Text -> Text
T.toLower Text
name
let cabalVersion :: Text
cabalVersion = forall a. a -> Maybe a -> a
fromMaybe (Int -> Int -> Text
giModuleVersion Int
major Int
minor)
(Overrides -> Maybe Text
cabalPkgVersion forall a b. (a -> b) -> a -> b
$ Config -> Overrides
overrides Config
cfg)
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"version:" forall a. Semigroup a => a -> a -> a
<> Text
cabalVersion
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"synopsis:" forall a. Semigroup a => a -> a -> a
<> Text
name
forall a. Semigroup a => a -> a -> a
<> Text
" bindings"
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"description:" forall a. Semigroup a => a -> a -> a
<> Text
"Bindings for " forall a. Semigroup a => a -> a -> a
<> Text
name
forall a. Semigroup a => a -> a -> a
<> Text
", autogenerated by haskell-gi."
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"homepage:" forall a. Semigroup a => a -> a -> a
<> Text
PI.homepage
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"license:" forall a. Semigroup a => a -> a -> a
<> Text
PI.license
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"license-file:" forall a. Semigroup a => a -> a -> a
<> Text
"LICENSE"
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"author:" forall a. Semigroup a => a -> a -> a
<> Text
PI.authors
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"maintainer:" forall a. Semigroup a => a -> a -> a
<> Text
PI.maintainers
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"category:" forall a. Semigroup a => a -> a -> a
<> Text
PI.category
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"build-type:" forall a. Semigroup a => a -> a -> a
<> Text
"Simple"
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"cabal-version:" forall a. Semigroup a => a -> a -> a
<> Text
">=1.10"
forall e. CodeGen e ()
blank
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Text
"library"
forall e a. CodeGen e a -> CodeGen e a
indent forall a b. (a -> b) -> a -> b
$ do
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"default-language:" forall a. Semigroup a => a -> a -> a
<> Text
PI.defaultLanguage
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"default-extensions:" forall a. Semigroup a => a -> a -> a
<>
Text -> [Text] -> Text
T.intercalate Text
", " [Text]
PI.defaultExtensions
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"other-extensions:" forall a. Semigroup a => a -> a -> a
<>
Text -> [Text] -> Text
T.intercalate Text
", " [Text]
PI.otherExtensions
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"ghc-options:" forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
" " [Text]
PI.ghcOptions
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"exposed-modules:" forall a. Semigroup a => a -> a -> a
<> forall a. [a] -> a
head [Text]
exposedModules
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall a. [a] -> [a]
tail [Text]
exposedModules) forall a b. (a -> b) -> a -> b
$ \Text
mod ->
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"" forall a. Semigroup a => a -> a -> a
<> Text
mod
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
padTo Int
20 Text
"pkgconfig-depends:" forall a. Semigroup a => a -> a -> a
<> Text
pcName forall a. Semigroup a => a -> a -> a
<> Text
" >= " forall a. Semigroup a => a -> a -> a
<>
forall a. Show a => a -> Text
tshow Int
major forall a. Semigroup a => a -> a -> a
<> Text
"." forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
tshow Int
minor
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Text
"build-depends:"
forall e a. CodeGen e a -> CodeGen e a
indent forall a b. (a -> b) -> a -> b
$ do
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Text
"haskell-gi-base >= "
forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
tshow Int
haskellGIAPIVersion forall a. Semigroup a => a -> a -> a
<> Text
"." forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
tshow Int
haskellGIMinor
forall a. Semigroup a => a -> a -> a
<> Text
" && < " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
tshow (Int
haskellGIAPIVersion forall a. Num a => a -> a -> a
+ Int
1) forall a. Semigroup a => a -> a -> a
<> Text
","
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(GIRInfo, PkgInfo)]
deps forall a b. (a -> b) -> a -> b
$ \(GIRInfo
dep, PkgInfo Text
_ Int
depMajor Int
depMinor) -> do
let depName :: Text
depName = GIRInfo -> Text
girNSName GIRInfo
dep
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Text
"gi-" forall a. Semigroup a => a -> a -> a
<> Text -> Text
T.toLower Text
depName forall a. Semigroup a => a -> a -> a
<> Text
" >= "
forall a. Semigroup a => a -> a -> a
<> Int -> Int -> Text
giModuleVersion Int
depMajor Int
depMinor
forall a. Semigroup a => a -> a -> a
<> Text
" && < "
forall a. Semigroup a => a -> a -> a
<> Int -> Int -> Text
giNextMinor Int
depMajor Int
depMinor
forall a. Semigroup a => a -> a -> a
<> Text
","
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Text]
PI.standardDeps (forall e. Text -> CodeGen e ()
line forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Semigroup a => a -> a -> a
<> Text
","))
forall e. Text -> CodeGen e ()
line forall a b. (a -> b) -> a -> b
$ Text
"base >= " forall a. Semigroup a => a -> a -> a
<> BaseVersion -> Text
showBaseVersion BaseVersion
minBaseVersion forall a. Semigroup a => a -> a -> a
<> Text
" && <5"