/
Reconfig.hs
182 lines (166 loc) · 4.99 KB
/
Reconfig.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
{-# LANGUAGE OverloadedStrings #-}
module Reconfig where
import Data.Yaml
import Data.Text (Text, unpack)
import Filesystem.Path.CurrentOS
( FilePath, fromText, (</>), directory, encodeString, decodeString
)
import Filesystem
( listDirectory, isFile, isDirectory, canonicalizePath, rename
)
import Prelude hiding (FilePath, writeFile)
import Control.Applicative ((<$>), (<*>))
import Control.Monad (mzero, foldM)
import qualified Data.Map as Map
import Data.Maybe (catMaybes)
import System.Cmd (rawSystem)
import qualified Prelude
data Deploy = Deploy
{ deployName :: Text
, deployDirectory :: FilePath
, deployWebapps :: [Webapp]
, deployStatics :: [Static]
}
deriving Show
instance FromJSON Deploy where
parseJSON (Object o) = Deploy
<$> o .: "name"
<*> return ""
<*> o .: "webapps"
<*> o .: "statics"
parseJSON _ = mzero
data Webapp = Webapp
{ webappHost :: Text
, webappExec :: FilePath
}
deriving Show
instance FromJSON Webapp where
parseJSON (Object o) = Webapp
<$> o .: "host"
<*> (fromText <$> o .: "exec")
parseJSON _ = mzero
data Static = Static
{ staticHost :: Text
, staticDirectory :: FilePath
}
deriving Show
instance FromJSON Static where
parseJSON (Object o) = Static
<$> o .: "host"
<*> (fromText <$> o .: "directory")
parseJSON _ = mzero
loadDeploy :: FilePath -> IO Deploy
loadDeploy fp = do
putStrLn $ "Loading deploy config from: " ++ show fp
Just deploy <- decodeFile $ encodeString fp
dir <- canonicalizePath $ directory fp
makeAbsolute deploy { deployDirectory = dir }
makeAbsolute :: Deploy -> IO Deploy
makeAbsolute (Deploy name dir ws ss) =
Deploy <$> return name
<*> return dir
<*> mapM goW ws
<*> mapM goS ss
where
goW (Webapp h e) = do
path <- canonicalizePath $ dir </> e
return $ Webapp h path
goS (Static h d) = do
path <- canonicalizePath $ dir </> d
return $ Static h path
loadDeploys :: FilePath -> IO (Map.Map Text Deploy)
loadDeploys root = do
contents <- listDirectory root
deploys <- catMaybes <$> mapM go contents
foldM addDeploy Map.empty deploys
where
go folder = do
isD <- isDirectory folder
if isD
then do
let fp = folder </> "deploy.yaml"
isF <- isFile fp
if isF
then Just <$> loadDeploy fp
else return Nothing
else return Nothing
addDeploy m d =
case Map.lookup (deployName d) m of
Nothing -> return $ Map.insert (deployName d) d m
Just _ -> error $ "Duplicate name: " ++ show (deployName d)
webappsPorts :: Map.Map Text Deploy -> [((Deploy, Webapp), Int)]
webappsPorts m = zip webapps [4000..]
where
webapps = concatMap (\d -> zip (repeat d) (deployWebapps d))
$ Map.elems m
angelBlock :: ((Deploy, Webapp), Int) -> String
angelBlock ((d, w), p) = unlines
[ concat [unpack $ deployName d, "-", unpack $ webappHost w, " {"]
, concat
[ " exec = \"env PORT="
, show p
, " "
, encodeString $ webappExec w
, "\""
]
, concat
[ " directory = \""
, encodeString $ deployDirectory d
, "\""
]
, "}"
]
nginxBlockWebapp :: ((Deploy, Webapp), Int) -> String
nginxBlockWebapp ((_, w), p) = unlines
[ "server {"
, concat [" server_name ", unpack $ webappHost w, ";"]
, " location / {"
, concat
[ " proxy_pass http://127.0.0.1:"
, show p
, ";"
]
, " }"
, "}"
]
nginxBlockStatic :: Static -> String
nginxBlockStatic s = unlines
[ "server {"
, concat [" server_name ", unpack $ staticHost s, ";"]
, concat
[ " root "
, encodeString $ staticDirectory s
, ";"
]
, "}"
]
reconfig :: String -> String -> String -> String -> IO ()
reconfig rootDir unpackedFolder angelConfig nginxConfig = do
let deploy = unlines
[ "deploy {"
, concat
[ " exec = \""
, rootDir
, "bin/deploy "
, rootDir
, "\""
]
, "}"
]
deploys <- loadDeploys $ decodeString unpackedFolder
let was = webappsPorts deploys
let statics = concatMap deployStatics $ Map.elems deploys
let rootDir' = decodeString rootDir
writeFile rootDir' angelConfig
$ deploy ++ concatMap angelBlock was
writeFile rootDir' nginxConfig
$ concatMap nginxBlockWebapp was ++
concatMap nginxBlockStatic statics
_ <- rawSystem "reload" ["yesod-deploy-angel"]
_ <- rawSystem "/etc/init.d/nginx" ["reload"]
return ()
writeFile :: FilePath -> String -> String -> IO ()
writeFile rootDir file contents = do
let fp = rootDir </> "tmp"
Prelude.writeFile (encodeString fp) contents
rename fp $ decodeString file