zcash-haskell/Setup.hs

138 lines
4.2 KiB
Haskell

import Control.Exception (throw)
import Control.Monad (forM_, when)
import Data.Maybe (fromMaybe)
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(..), localPkgDescr)
import Distribution.Simple.PreProcess
import Distribution.Simple.Program.Find
( defaultProgramSearchPath
, findProgramOnSearchPath
)
import Distribution.Simple.Setup
import Distribution.Simple.Utils
( IODataMode(IODataModeBinary)
, maybeExit
, rawSystemStdInOut
)
import Distribution.Verbosity (Verbosity)
import qualified Distribution.Verbosity as Verbosity
import GHC.Generics
import System.Directory
( XdgDirectory(..)
, copyFile
, createDirectory
, createDirectoryIfMissing
, doesDirectoryExist
, doesFileExist
, getCurrentDirectory
, getDirectoryContents
, getHomeDirectory
, getXdgDirectory
)
import System.Environment
import System.FilePath ((</>))
import Text.Regex
import Text.Regex.Base
main :: IO ()
main = defaultMainWithHooks hooks
where
hooks =
simpleUserHooks
{ preConf =
\_ flags -> do
rsMake (fromFlag $ configVerbosity flags)
pure emptyHookedBuildInfo
, hookedPreProcessors = knownSuffixHandlers
, confHook = \a flags -> confHook simpleUserHooks a flags >>= rsAddDirs
, postClean = \_ flags _ _ -> rsClean (fromFlag $ cleanVerbosity flags)
}
rsFolder :: FilePath
rsFolder = "librustzcash-wrapper"
execCargo :: Verbosity -> String -> [String] -> IO ()
execCargo verbosity command args = do
cargoPath <-
findProgramOnSearchPath Verbosity.normal defaultProgramSearchPath "cargo"
dir <- getCurrentDirectory
let cargoExec =
case cargoPath of
Just (p, _) -> p
Nothing -> "cargo"
cargoArgs = command : args
workingDir = Just (dir </> rsFolder)
thirdComponent (_, _, c) = c
maybeExit . fmap thirdComponent $
rawSystemStdInOut
verbosity
cargoExec
cargoArgs
workingDir
Nothing
Nothing
IODataModeBinary
rsMake :: Verbosity -> IO ()
rsMake verbosity = do
execCargo verbosity "cbuild" []
rsAddDirs :: LocalBuildInfo -> IO LocalBuildInfo
rsAddDirs lbi' = do
localData <- getXdgDirectory XdgData "zcash-haskell"
createDirectoryIfMissing True localData
dir <- getCurrentDirectory
let rustIncludeDir =
dir </> rsFolder </> "target/x86_64-unknown-linux-gnu/debug"
rustLibDir = dir </> rsFolder </> "target/x86_64-unknown-linux-gnu/debug"
updateLbi lbi = lbi {localPkgDescr = updatePkgDescr (localPkgDescr lbi)}
updatePkgDescr pkgDescr =
pkgDescr {library = updateLib <$> library pkgDescr}
updateLib lib = lib {libBuildInfo = updateLibBi (libBuildInfo lib)}
updateLibBi libBuild =
libBuild
{ includeDirs = rustIncludeDir : includeDirs libBuild
, extraLibDirs = rustLibDir : extraLibDirs libBuild
}
copyDir rustLibDir localData
pure $ updateLbi lbi'
rsClean :: Verbosity -> IO ()
rsClean verbosity = execCargo verbosity "clean" []
cabalFlag :: FlagName -> ConfigFlags -> Bool
cabalFlag name =
fromMaybe False . lookupFlagAssignment name . configConfigurationsFlags
unlessFlagM :: FlagName -> ConfigFlags -> IO () -> IO ()
unlessFlagM name flags action
| cabalFlag name flags = pure ()
| otherwise = action
applyUnlessM :: FlagName -> ConfigFlags -> (a -> IO a) -> a -> IO a
applyUnlessM name flags apply a
| cabalFlag name flags = pure a
| otherwise = apply a
copyDir :: FilePath -> FilePath -> IO ()
copyDir src dst = do
whenM (not <$> doesDirectoryExist src) $
throw (userError "source does not exist")
--whenM (doesFileOrDirectoryExist dst) $
--throw (userError "destination already exists")
createDirectoryIfMissing True dst
content <- getDirectoryContents src
let xs = filter (`notElem` [".", ".."]) content
forM_ xs $ \name -> do
let srcPath = src </> name
let dstPath = dst </> name
isDirectory <- doesDirectoryExist srcPath
if isDirectory
then copyDir srcPath dstPath
else copyFile srcPath dstPath
where
doesFileOrDirectoryExist x = orM [doesDirectoryExist x, doesFileExist x]
orM xs = or <$> sequence xs
whenM s r = s >>= flip when r