packages feed

temporal-sdk-core-2025.10.1.0: Setup.hs

import Control.Monad
import Data.Char (toLower)
import Data.Functor (($>))
import Data.Maybe (fromMaybe)
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo (
  InstallDirs (..),
  LocalBuildInfo (..),
  absoluteInstallDirs,
  buildDir,
  localPkgDescr,
 )
import Distribution.Simple.Program.Find (
  defaultProgramSearchPath,
  findProgramOnSearchPath,
 )
import Distribution.Simple.Setup
import Distribution.Simple.Utils (
  IODataMode (IODataModeBinary),
  installExecutableFile,
  maybeExit,
  rawSystemStdInOut,
 )
import Distribution.System
import Distribution.Verbosity (Verbosity)
import qualified Distribution.Verbosity as Verbosity
import System.Directory (
  getCurrentDirectory,
 )
import System.Environment (getEnv)
import System.FilePath ((</>))
import System.Posix.Files (createSymbolicLink)


main :: IO ()
main = defaultMainWithHooks hooks
  where
    hooks =
      simpleUserHooks
        { preConf = \_ flags -> do
            unlessFlagM externalLibFlag flags $ rsMake (fromFlag $ configVerbosity flags)
            pure emptyHookedBuildInfo
        , confHook = \a flags -> do
            lbi <- confHook simpleUserHooks a flags >>= rsAddLibraryInfo flags
            unless (cabalFlag externalLibFlag flags) $ do
              copyTemporalBridge lbi (buildDir lbi)
            pure lbi
        , postClean = \_ flags _ _ ->
            rsClean (fromFlag $ cleanVerbosity flags)
        , postCopy =
            installTemporalBridge
        }


rsFolder :: FilePath
rsFolder = "rust"


externalLibFlagStr :: String
externalLibFlagStr = "external_lib"


externalLibFlag :: FlagName
externalLibFlag = mkFlagName externalLibFlagStr


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 = execCargo verbosity "build" ["--release", "--lib"]


rsAddLibraryInfo :: ConfigFlags -> LocalBuildInfo -> IO LocalBuildInfo
rsAddLibraryInfo fl lbi' = do
  dir <- getCurrentDirectory
  let external = getCabalFlag externalLibFlagStr fl
  let updateLbi lbi =
        lbi
          { localPkgDescr = updatePkgDescr (localPkgDescr lbi)
          }
      updatePkgDescr pkgDescr =
        pkgDescr
          { library = updateLib <$> library pkgDescr
          }
      updateLib lib =
        lib
          { libBuildInfo = updateLibBi (libBuildInfo lib)
          }
      updateLibBi libBuild =
        libBuild
          { extraLibDirs =
              if external
                then extraLibDirs libBuild
                else (dir </> buildDir lbi') : extraLibDirs libBuild
          }
  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 = do
      putStrLn "Skipping cargo action because external_lib flag is set"
      pure ()
  | otherwise = do
      putStrLn ("Running cargo action because we don't have the flag: " ++ show name)
      action


copyLib :: ConfigFlags -> FilePath -> Bool -> IO ()
copyLib fl libPref shared = do
  libraryPath <- getLibraryPath
  installExecutableFile
    verb
    libraryPath
    (libPref ++ "/libtemporal_bridge." ++ ext)
  where
    verb = fromFlag $ configVerbosity fl
    external = getCabalFlag externalLibFlagStr fl
    ext =
      if shared
        then case buildOS of
          Windows -> "dll"
          OSX -> "dylib"
          _ -> "so"
        else "a"
    getLibraryPath =
      pure ("rust/target/release/libtemporal_bridge." ++ ext)


copyTemporalBridge :: LocalBuildInfo -> FilePath -> IO ()
copyTemporalBridge lbi fp = do
  copyLib config fp False
  where
    config = configFlags lbi


installTemporalBridge :: Args -> CopyFlags -> PackageDescription -> LocalBuildInfo -> IO ()
installTemporalBridge _ flags pkg_descr lbi = do
  let
    libPref =
      libdir
        . absoluteInstallDirs pkg_descr lbi
        . fromFlag
        . copyDest
        $ flags
    config = configFlags lbi

  unless (cabalFlag externalLibFlag $ configFlags lbi) $ do
    copyLib config libPref True
    copyLib config libPref False


getCabalFlag :: String -> ConfigFlags -> Bool
getCabalFlag name flags = fromMaybe False (lookupFlagAssignment (mkFlagName name') allFlags)
  where
    allFlags = configConfigurationsFlags flags
    name' = map toLower name