-
Notifications
You must be signed in to change notification settings - Fork 113
/
Copy pathTask.hs
116 lines (80 loc) · 2.7 KB
/
Task.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
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE OverloadedStrings #-}
module Task
( Task
, run
, Transaction
, bail
, attempt
, fetchGithub
)
where
import Control.Exception (SomeException, catch, try)
import Control.Monad.Except (ExceptT, runExceptT, throwError)
import Control.Monad.Reader (ReaderT, runReaderT, ask)
import Control.Monad.Trans (liftIO)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as Text
import qualified System.Directory as Dir
import System.Exit (exitFailure)
import System.FilePath ((</>))
import System.IO (hPutStrLn, stderr)
import qualified Elm.Package as Pkg
import qualified Http
import qualified Json.Decode as Decode
-- TASKS
type Task =
ExceptT String (ReaderT Http.Token IO)
run :: String -> Task a -> IO ()
run githubToken task =
do token <- Http.init githubToken
result <- runReaderT (runExceptT task) token
case result of
Right _ ->
putStrLn "Success!"
Left msg ->
do hPutStrLn stderr msg
exitFailure
-- ERROR
type Transaction =
ExceptT Error (ReaderT Http.Token IO)
newtype Error = Error String
bail :: String -> Transaction a
bail msg =
throwError (Error msg)
attempt :: Pkg.Name -> Pkg.Version -> Transaction a -> Task a
attempt pkg vsn transaction =
do token <- ask
result <- liftIO $ runReaderT (runExceptT transaction) token
`catch` \e -> return (Left (Error (show (e :: SomeException))))
case result of
Right a ->
return a
Left (Error msg) ->
do liftIO $ hPutStrLn stderr $
"Bailed out of " ++ Pkg.toString pkg ++ " " ++ Pkg.versionToString vsn ++ " transaction."
liftIO $ removeDirectory pkg vsn
throwError msg
removeDirectory :: Pkg.Name -> Pkg.Version -> IO ()
removeDirectory (Pkg.Name user project) version =
do let usr = Text.unpack user
let prj = Text.unpack project
let vsn = Pkg.versionToString version
Dir.removeDirectoryRecursive ("packages" </> usr </> prj </> vsn)
_ <- try $ Dir.removeDirectory ("packages" </> usr </> prj) :: IO (Either SomeException ())
_ <- try $ Dir.removeDirectory ("packages" </> usr) :: IO (Either SomeException ())
return ()
-- HTTP
fetchGithub :: Decode.Decoder e a -> String -> Task a
fetchGithub decoder path =
do token <- ask
result <- liftIO $ Http.fetchGithub token path
case result of
Left msg ->
throwError msg
Right bytestring ->
case Decode.parse "github" (\_ -> []) decoder (LBS.toStrict bytestring) of
Left _ ->
throwError ("Bad JSON from GitHub for " ++ path)
Right value ->
return value