2017-02-06 18:04:00 +03:00
|
|
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
2015-09-24 23:57:44 +03:00
|
|
|
|
|
|
|
|
|
module Main (main) where
|
2014-06-04 01:15:39 +04:00
|
|
|
|
|
2017-02-06 18:04:00 +03:00
|
|
|
|
import Control.Monad
|
|
|
|
|
import Data.Monoid ((<>))
|
2017-01-28 16:05:37 +03:00
|
|
|
|
import Data.Version (showVersion)
|
2017-02-06 18:04:00 +03:00
|
|
|
|
import Numeric.Natural
|
|
|
|
|
import Options.Applicative
|
2017-02-20 18:09:21 +03:00
|
|
|
|
import Path
|
|
|
|
|
import Path.IO
|
2017-02-06 18:04:00 +03:00
|
|
|
|
import Paths_hapistrano (version)
|
|
|
|
|
import System.Exit
|
|
|
|
|
import System.Hapistrano.Types
|
2017-02-20 17:33:12 +03:00
|
|
|
|
import qualified Config as C
|
|
|
|
|
import qualified Data.Yaml as Yaml
|
2017-02-06 18:04:00 +03:00
|
|
|
|
import qualified System.Hapistrano as Hap
|
|
|
|
|
import qualified System.Hapistrano.Core as Hap
|
2017-01-28 16:43:45 +03:00
|
|
|
|
|
|
|
|
|
#if !MIN_VERSION_base(4,8,0)
|
|
|
|
|
import Control.Applicative
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-02-06 18:04:00 +03:00
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
|
-- Command line options
|
|
|
|
|
|
|
|
|
|
-- | Command line options.
|
|
|
|
|
|
|
|
|
|
data Opts = Opts
|
|
|
|
|
{ optsCommand :: Command
|
|
|
|
|
, optsVersion :: Bool
|
2017-02-20 17:33:12 +03:00
|
|
|
|
, optsConfigFile :: FilePath
|
2017-02-06 18:04:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-- | Command to execute and command-specific options.
|
|
|
|
|
|
|
|
|
|
data Command
|
|
|
|
|
= Deploy ReleaseFormat Natural -- ^ Deploy a new release (with timestamp
|
|
|
|
|
-- format and how many releases to keep)
|
|
|
|
|
| Rollback Natural -- ^ Rollback to Nth previous release
|
|
|
|
|
|
|
|
|
|
parserInfo :: ParserInfo Opts
|
|
|
|
|
parserInfo = info (helper <*> optionParser)
|
|
|
|
|
( fullDesc <>
|
|
|
|
|
progDesc "Deploy tool for Haskell applications" <>
|
|
|
|
|
header "Hapistrano - A deployment library for Haskell applications" )
|
|
|
|
|
|
|
|
|
|
optionParser :: Parser Opts
|
|
|
|
|
optionParser = Opts
|
|
|
|
|
<$> subparser
|
|
|
|
|
( command "deploy"
|
|
|
|
|
(info deployParser (progDesc "Deploy a new release")) <>
|
|
|
|
|
command "rollback"
|
|
|
|
|
(info rollbackParser (progDesc "Roll back to Nth previous release")) )
|
|
|
|
|
<*> switch
|
|
|
|
|
( long "version"
|
|
|
|
|
<> short 'v'
|
|
|
|
|
<> help "Show version of the program" )
|
2017-02-20 17:33:12 +03:00
|
|
|
|
<*> strOption
|
|
|
|
|
( long "config"
|
|
|
|
|
<> short 'c'
|
|
|
|
|
<> value "hap.yaml"
|
|
|
|
|
<> metavar "PATH"
|
|
|
|
|
<> showDefault
|
|
|
|
|
<> help "Configuration file to use" )
|
2017-02-06 18:04:00 +03:00
|
|
|
|
|
|
|
|
|
deployParser :: Parser Command
|
|
|
|
|
deployParser = Deploy
|
|
|
|
|
<$> option pReleaseFormat
|
|
|
|
|
( long "release-format"
|
|
|
|
|
<> short 'r'
|
|
|
|
|
<> value ReleaseShort
|
|
|
|
|
<> help "Which format release timestamp format to use: ‘long’ or ‘short’, default is ‘short’." )
|
|
|
|
|
<*> option auto
|
|
|
|
|
( long "keep-releases"
|
|
|
|
|
<> short 'k'
|
|
|
|
|
<> value 5
|
2017-02-20 17:33:12 +03:00
|
|
|
|
<> showDefault
|
|
|
|
|
<> help "How many releases to keep" )
|
2017-02-06 18:04:00 +03:00
|
|
|
|
|
|
|
|
|
rollbackParser :: Parser Command
|
|
|
|
|
rollbackParser = Rollback
|
|
|
|
|
<$> option auto
|
|
|
|
|
( long "use-nth"
|
|
|
|
|
<> short 'n'
|
|
|
|
|
<> value 1
|
2017-02-20 17:33:12 +03:00
|
|
|
|
<> showDefault
|
|
|
|
|
<> help "How many deployments back to go?" )
|
2017-02-06 18:04:00 +03:00
|
|
|
|
|
|
|
|
|
pReleaseFormat :: ReadM ReleaseFormat
|
|
|
|
|
pReleaseFormat = eitherReader $ \s ->
|
|
|
|
|
case s of
|
|
|
|
|
"long" -> Right ReleaseLong
|
|
|
|
|
"short" -> Right ReleaseShort
|
|
|
|
|
_ -> Left ("Unknown format: " ++ s ++ ", try ‘long’ or ‘short’.")
|
|
|
|
|
|
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
|
-- Main
|
2014-06-04 01:15:39 +04:00
|
|
|
|
|
|
|
|
|
main :: IO ()
|
2017-02-06 18:04:00 +03:00
|
|
|
|
main = do
|
|
|
|
|
Opts {..} <- execParser parserInfo
|
|
|
|
|
when optsVersion $ do
|
|
|
|
|
putStrLn $ "Hapistrano " ++ showVersion version
|
|
|
|
|
exitSuccess
|
|
|
|
|
|
2017-02-20 17:33:12 +03:00
|
|
|
|
econfig <- Yaml.decodeFileEither optsConfigFile
|
|
|
|
|
case econfig of
|
|
|
|
|
Left err -> do
|
|
|
|
|
putStrLn (Yaml.prettyPrintParseException err)
|
|
|
|
|
exitFailure
|
|
|
|
|
Right C.Config {..} ->
|
|
|
|
|
Hap.runHapistrano (SshOptions <$> configHost <*> pure configPort) $ case optsCommand of
|
|
|
|
|
Deploy releaseFormat n -> do
|
|
|
|
|
release <- Hap.pushRelease Task
|
|
|
|
|
{ taskDeployPath = configDeployPath
|
|
|
|
|
, taskRepository = configRepo
|
|
|
|
|
, taskRevision = configRevision
|
|
|
|
|
, taskReleaseFormat = releaseFormat }
|
2017-02-20 18:09:21 +03:00
|
|
|
|
rpath <- Hap.releasePath configDeployPath release
|
|
|
|
|
forM_ configCopyFiles $ \(C.CopyThing src dest) -> do
|
|
|
|
|
srcPath <- resolveFile' src
|
|
|
|
|
destPath <- parseRelFile dest
|
|
|
|
|
Hap.scpFile srcPath (rpath </> destPath)
|
|
|
|
|
forM_ configCopyDirs $ \(C.CopyThing src dest) -> do
|
|
|
|
|
srcPath <- resolveDir' src
|
|
|
|
|
destPath <- parseRelDir dest
|
|
|
|
|
Hap.scpDir srcPath (rpath </> destPath)
|
2017-02-20 17:33:12 +03:00
|
|
|
|
forM_ configBuildScript (Hap.playScript configDeployPath release)
|
|
|
|
|
Hap.registerReleaseAsComplete configDeployPath release
|
|
|
|
|
Hap.activateRelease configDeployPath release
|
|
|
|
|
Hap.dropOldReleases configDeployPath n
|
2017-02-21 19:44:54 +03:00
|
|
|
|
forM_ configRestartCommand Hap.exec
|
2017-02-20 17:33:12 +03:00
|
|
|
|
Rollback n -> do
|
|
|
|
|
Hap.rollback configDeployPath n
|
|
|
|
|
forM_ configRestartCommand Hap.exec
|