packages feed

craft-0.0.0.1: src/Craft/Run/Vagrant.hs

module Craft.Run.Vagrant where

import           Control.Lens
import           Control.Monad.Logger (LoggingT)
import qualified Control.Monad.Trans  as Trans
import qualified Data.Map.Strict      as Map
import           Data.Maybe           (fromMaybe)
import qualified System.Directory
import qualified System.Environment

import           Craft
import           Craft.Config.SSH     (SSHConfig (..), cfgLookup, parser)


data VagrantSettings
  = VagrantSettings
    { vagrantUp  :: Bool
    , vagrantBox :: String
    }


vagrantSettings :: VagrantSettings
vagrantSettings =
  VagrantSettings
  { vagrantUp = False
  , vagrantBox = "default"
  }


runCraftVagrant :: VagrantSettings -> CraftEnv -> Craft a -> LoggingT IO a
runCraftVagrant settings env configs = do
  let box = vagrantBox settings
  sysEnv <- Trans.lift System.Environment.getEnvironment
  cwd <- parseAbsDir =<< Trans.lift System.Directory.getCurrentDirectory
  -- vagrant ssh-config
  sshcfg <-
    runCraft
      runLocal
      (craftEnv (env ^. craftPackageManager)
       & craftExecEnv .~ Map.fromList sysEnv
       & craftExecCWD .~ cwd)
      $ do
        when (vagrantUp settings) $ exec_ "vagrant" ["up", box]
        SSHConfig <$> parseExecStdout parser "vagrant" ["ssh-config", box]
  let addr = cfgLookupOrError box "hostname" sshcfg
  let port = read $ cfgLookupOrError box "port" sshcfg
  let user = cfgLookupOrError box "user" sshcfg
  key <- parseAbsFile $ cfgLookupOrError box "identityfile" sshcfg
  -- vagrant ssh
  withSession
    (sshEnv addr key
     & sshUser .~ user
     & sshPort .~ port
     & sshSudo .~ True)
    $ \session ->
        runCraft
          (runSSHSession session)
          env
          configs


cfgLookupOrError :: String -> String -> SSHConfig -> String
cfgLookupOrError box name sshcfg =
  fromMaybe
    (error $ "'"++name++"' not found in output of 'vagrant ssh-config "++box++"'")
    (cfgLookup box name sshcfg)