import Control.Exception (throw) import Control.Monad (forM_, when) import Data.Maybe (isNothing) 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 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 prepDeps (fromFlag $ configVerbosity flags) pure emptyHookedBuildInfo --, confHook = \a flags -> confHook simpleUserHooks a flags >>= rsAddDirs } execCargo :: Verbosity -> String -> [String] -> IO () execCargo verbosity command args = do cargoPath <- findProgramOnSearchPath Verbosity.silent 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" [] prepDeps :: Verbosity -> IO () prepDeps verbosity = do ldPath <- lookupEnv "LD_LIBRARY_PATH" pkgPath <- lookupEnv "PKG_CONFIG_PATH" if maybe False (matchTest (mkRegex ".*zcash-haskell.*")) ldPath && maybe False (matchTest (mkRegex ".*zcash-haskell.*")) pkgPath then do execCargo verbosity "cbuild" [] localData <- getXdgDirectory XdgData "zcash-haskell" createDirectoryIfMissing True localData dir <- getCurrentDirectory let rustLibDir = dir rsFolder "target/x86_64-unknown-linux-gnu/debug" copyDir rustLibDir localData else throw $ userError "Paths not set correctly, please run the 'configure' script." rsFolder :: FilePath rsFolder = "zcash-haskell/librustzcash-wrapper" rsAddDirs :: LocalBuildInfo -> IO LocalBuildInfo rsAddDirs lbi' = do 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 } pure $ updateLbi lbi' 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