chromatin-0.1.0.0: lib/Chromatin/Rebuild/Build.hs
module Chromatin.Rebuild.Build(
installRplugin,
InstallResult(..),
venvDir,
) where
import Control.Monad.IO.Class (MonadIO)
import Data.List.Split (linesBy)
import GHC.IO.Exception (ExitCode(ExitFailure))
import GHC.IO.Handle.Types (Handle)
import qualified Data.ByteString.Lazy.Internal as B (unpackChars)
import System.FilePath ((</>))
import System.Process.Typed (ProcessConfig, setStdout, useHandleClose, readProcessStderr, proc, setWorkingDir)
import UnliftIO.Temporary (withSystemTempFile)
import UnliftIO.Directory (
getXdgDirectory,
XdgDirectory(XdgData, XdgCache),
createDirectoryIfMissing,
removePathForcibly,
)
import Neovim (Buffer, vim_command', vim_get_current_buffer', vim_command, buffer_get_number')
import Ribosome.Api.Echo (echom)
import Chromatin.Data.Rplugin (Rplugin(Rplugin))
import Chromatin.Data.RpluginName (RpluginName(..))
import Chromatin.Data.RpluginSource (RpluginSource(Hackage, Stack, Pypi), HackageDepspec(..), PypiDepspec(..))
import Chromatin.Data.Chromatin (Chromatin)
data InstallResult =
Success Rplugin
|
Failure [String]
deriving (Show, Eq)
tailInTerminal :: FilePath -> Chromatin Buffer
tailInTerminal path = do
vim_command' $ "15split term://tail -f " ++ path
vim_get_current_buffer'
closeTerminal :: Buffer -> Chromatin ()
closeTerminal buf = do
num <- buffer_get_number' buf
_ <- vim_command $ "silent! " ++ show num ++ "bwipeout!"
return ()
processWithStdoutFile :: MonadIO m => ProcessConfig stdin stdout stderr -> Handle -> m (Either String ())
processWithStdoutFile processConfig logHandle = do
let pipe = setStdout (useHandleClose logHandle)
(code, err) <- readProcessStderr $ pipe processConfig
return $ case code of
ExitFailure _ -> Left (B.unpackChars err)
_ -> Right ()
hackageProcess :: FilePath -> HackageDepspec -> ProcessConfig () () ()
hackageProcess bindir (HackageDepspec spec) =
proc "cabal" ["new-install", "--symlink-bindir", bindir, spec]
stackProcess :: FilePath -> ProcessConfig () () ()
stackProcess path =
setWorkingDir path $ proc "stack" ["build"]
processWithLog :: RpluginName -> ProcessConfig stdin stdout sderr -> Chromatin (Either String ())
processWithLog (RpluginName name) processConfig =
withSystemTempFile "test-chromatin" $ \logFile logHandle -> do
buf <- tailInTerminal logFile
result <- processWithStdoutFile processConfig logHandle
case result of
Right _ -> do
echom $ "installed `" ++ name ++ "`"
closeTerminal buf
Left _ -> echom $ "failed to install `" ++ name ++ "`"
return result
installHackageProcess :: RpluginName -> FilePath -> HackageDepspec -> Chromatin (Either String ())
installHackageProcess name bindir spec =
processWithLog name $ hackageProcess bindir spec
installStackProcess :: RpluginName -> FilePath -> Chromatin (Either String ())
installStackProcess name path =
processWithLog name $ stackProcess path
venvProcess :: FilePath -> ProcessConfig () () ()
venvProcess dir =
proc "python3" ["-m", "venv", dir, "--upgrade"]
venvDir :: RpluginName -> Chromatin FilePath
venvDir (RpluginName name) = getXdgDirectory XdgCache ("chromatin-hs" </> "venvs" </> name)
createVenvProcess :: RpluginName -> Chromatin (Either String FilePath)
createVenvProcess name = do
dir <- venvDir name
removePathForcibly dir
r <- processWithLog name (venvProcess dir)
return $ dir <$ r
pipProcess :: PypiDepspec -> FilePath -> ProcessConfig () () ()
pipProcess (PypiDepspec spec) venv =
proc (venv </> "bin" </> "pip") ["install", "--no-cache", "--upgrade", spec]
installPypiProcess :: RpluginName -> PypiDepspec -> FilePath -> Chromatin (Either String ())
installPypiProcess name spec venv =
processWithLog name (pipProcess spec venv)
binaryDir :: Chromatin FilePath
binaryDir = getXdgDirectory XdgData ("chromatin" </> "bin")
installRpluginFromSource :: RpluginName -> RpluginSource -> Chromatin (Either String ())
installRpluginFromSource name (Hackage spec) = do
bindir <- binaryDir
createDirectoryIfMissing True bindir
installHackageProcess name bindir spec
installRpluginFromSource name (Stack path) =
installStackProcess name path
installRpluginFromSource name (Pypi spec) = do
dir <- createVenvProcess name
case dir of
Right d -> installPypiProcess name spec d
Left e -> return $ Left e
installRplugin :: RpluginName -> RpluginSource -> Chromatin InstallResult
installRplugin name source = do
result <- installRpluginFromSource name source
return $ case result of
Right _ -> Success $ Rplugin name source
Left err -> Failure $ linesBy (=='\n') err