forked from commercialhaskell/stack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStack.hs
More file actions
139 lines (127 loc) · 5.03 KB
/
Stack.hs
File metadata and controls
139 lines (127 loc) · 5.03 KB
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
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
-- | Main Stack tool entry point.
module Stack
( main
) where
import GHC.IO.Encoding ( mkTextEncoding, textEncodingName )
import Options.Applicative.Builder.Extra ( execExtraHelp )
import Stack.BuildInfo ( versionString' )
import Stack.CLI ( commandLineHandler )
import Stack.Constants ( stackProgName )
import Stack.Docker ( dockerCmdName, dockerHelpOptName )
import Stack.Nix ( nixCmdName, nixHelpOptName )
import Stack.Options.DockerParser ( dockerOptsParser )
import Stack.Options.GlobalParser ( globalOptsFromMonoid )
import Stack.Options.NixParser ( nixOptsParser )
import Stack.Prelude
import Stack.Runners
( ShouldReexec (..), withConfig, withRunnerGlobal )
import Stack.Types.GlobalOpts ( GlobalOpts (..) )
import Stack.Types.Runner ( Runner )
import Stack.Types.Version
( VersionCheck (..), checkVersion, showStackVersion
, stackVersion
)
import System.Directory ( getCurrentDirectory )
import System.Environment ( getArgs, getProgName )
import System.IO ( hGetEncoding, hPutStrLn, hSetEncoding )
import System.Terminal ( hIsTerminalDeviceOrMinTTY )
-- | Type representing exceptions thrown by functions in the "Stack" module.
data StackException
= InvalidReExecVersion String String
deriving (Show, Typeable)
instance Exception StackException where
displayException (InvalidReExecVersion expected actual) = concat
[ "Error: [S-2186]\n"
, "When re-executing '"
, stackProgName
, "' in a container, the incorrect version was found\nExpected: "
, expected
, "; found: "
, actual
]
main :: IO ()
main = do
-- Line buffer the output by default, particularly for non-terminal runs.
-- See https://github.com/commercialhaskell/stack/pull/360
hSetBuffering stdout LineBuffering
hSetBuffering stdin LineBuffering
hSetBuffering stderr LineBuffering
hSetTranslit stdout
hSetTranslit stderr
args <- getArgs
progName <- getProgName
isTerminal <- hIsTerminalDeviceOrMinTTY stdout
execExtraHelp
args
dockerHelpOptName
(dockerOptsParser False)
("Only showing --" ++ dockerCmdName ++ "* options.")
execExtraHelp
args
nixHelpOptName
(nixOptsParser False)
("Only showing --" ++ nixCmdName ++ "* options.")
currentDir <- getCurrentDirectory
eGlobalRun <- try $ commandLineHandler currentDir progName False
case eGlobalRun of
Left (exitCode :: ExitCode) ->
throwIO exitCode
Right (globalMonoid, run) -> do
global <- globalOptsFromMonoid isTerminal globalMonoid
when (global.logLevel == LevelDebug) $
hPutStrLn stderr versionString'
case global.reExecVersion of
Just expectVersion -> do
expectVersion' <- parseVersionThrowing expectVersion
unless (checkVersion MatchMinor expectVersion' stackVersion) $
throwIO $
InvalidReExecVersion expectVersion showStackVersion
_ -> pure ()
withRunnerGlobal global $ run `catches`
[ Handler handleExitCode
, Handler handlePrettyException
, Handler handlePantryException
, Handler handleSomeException
]
-- | Change the character encoding of the given Handle to transliterate on
-- unsupported characters instead of throwing an exception
hSetTranslit :: Handle -> IO ()
hSetTranslit h = do
menc <- hGetEncoding h
case fmap textEncodingName menc of
Just name
| '/' `notElem` name -> do
enc' <- mkTextEncoding $ name ++ "//TRANSLIT"
hSetEncoding h enc'
_ -> pure ()
-- | Handle ExitCode exceptions.
handleExitCode :: ExitCode -> RIO Runner a
handleExitCode = exitWith
-- | Handle PrettyException exceptions.
handlePrettyException :: PrettyException -> RIO Runner a
handlePrettyException = handleAnyPrettyException
-- | Handle (pretty) PantryException exceptions.
handlePantryException :: PantryException -> RIO Runner a
handlePantryException = handleAnyPrettyException
-- | Handle any pretty exception.
handleAnyPrettyException :: (Exception e, Pretty e) => e -> RIO Runner a
handleAnyPrettyException e = do
-- The code below loads the entire Stack configuration, when all that is
-- needed are the Stack colours. A tailored approach may be better.
result <- tryAny $ withConfig NoReexec $ prettyError $ pretty e
case result of
-- Falls back to the command line's Stack colours if there is any error in
-- loading the entire Stack configuration.
Left _ -> prettyError $ pretty e
Right _ -> pure ()
exitFailure
-- | Handle SomeException exceptions. This special handler stops "stack: " from
-- being printed before the exception.
handleSomeException :: SomeException -> RIO Runner a
handleSomeException (SomeException e) = do
logError $ fromString $ displayException e
exitFailure