-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshake
executable file
·154 lines (132 loc) · 5.24 KB
/
shake
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
#!/usr/bin/env runhaskell +RTS -I0 -RTS
{-# OPTIONS_GHC -with-rtsopts=-I0 -threaded -rtsopts #-}
-- Copyright 2013-2014 Samplecount S.L.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
import Control.Applicative
import Control.Concurrent
import Control.Concurrent.MVar
import Control.Monad
import Data.Char (toLower)
import qualified Data.List as List
import qualified Distribution.PackageDescription as Dist
import qualified Distribution.PackageDescription.Configuration as Dist
import qualified Distribution.PackageDescription.Parse as Dist
import qualified Distribution.Verbosity as Dist
import GHC.Conc (getNumProcessors)
import qualified System.Directory as Dir
import qualified System.Environment as Env
import System.Exit (ExitCode(..), exitFailure)
import System.FilePath
import System.IO
import qualified System.IO.Error as IO
import qualified System.Process as Proc
-- Cabal configuration fields:
configFieldPackageDirs :: String
configFieldPackageDirs = "x-shake-package-dirs"
-- Process utilities
execError :: FilePath -> Int -> IO ()
execError path code = error $ takeFileName path ++ " failed with exit code " ++ show code
checkExitCode :: FilePath -> ExitCode -> IO ()
checkExitCode _ ExitSuccess = return ()
checkExitCode path (ExitFailure code) = execError path code
traceCommand :: String -> [String] -> IO ()
traceCommand path args = do
debug <- Env.lookupEnv "SHAKE_CABAL_BUILD_DEBUG"
case debug of
Nothing -> return ()
Just _ -> hPutStrLn stderr $ "TRACE: " ++ unwords ([path] ++ args)
-- Not yet in process-1.1
callProcess :: String -> [String] -> IO ()
callProcess path args = do
traceCommand path args
Proc.rawSystem path args >>= checkExitCode path
-- Ignore exit code
callProcess_ :: String -> [String] -> IO ()
callProcess_ path args = do
traceCommand path args
_ <- Proc.rawSystem path args
return ()
findExecutable :: String -> IO FilePath
findExecutable exe = maybe (error $ exe ++ " executable not found") id
<$> Dir.findExecutable exe
getCabalFile :: IO (FilePath, Dist.PackageDescription)
getCabalFile = do
cabalFiles <- filter (List.isSuffixOf ".cabal")
<$> Dir.getDirectoryContents "."
case cabalFiles of
[] -> error "No cabal file found"
(_:_:_) -> error $ "Multiple cabal files found: " ++ List.intercalate ", " cabalFiles
[cabalFile] -> do
pkg <- Dist.flattenPackageDescription
<$> Dist.readPackageDescription Dist.silent cabalFile
return (cabalFile, pkg)
getBuildCommand :: FilePath -> Dist.PackageDescription -> IO FilePath
getBuildCommand cabalFile pkg =
case Dist.executables pkg of
[] -> error $ "No executables found in " ++ cabalFile
(spec:rest) -> do
let exe = Dist.exeName spec
when (not (null rest)) $
hPutStrLn stderr $ "Multiple executables found in " ++ cabalFile ++ ", using " ++ exe
return $ ".cabal-sandbox/bin" </> exe
configPackageDirs :: [(String, String)] -> [FilePath]
configPackageDirs = maybe [] id
. fmap lines
. lookup configFieldPackageDirs
sandboxDir :: FilePath
sandboxDir = ".cabal-sandbox"
main :: IO ()
main = do
(cabalFile, pkg) <- getCabalFile
let config = Dist.customFieldsPD pkg
progName <- Env.getProgName
let logLine msg = putStrLn $ progName ++ ": " ++ msg
cabalExe <- findExecutable "cabal"
let cabal cmd args = callProcess cabalExe (cmd:args)
j <- (("-j"++) . show) <$> getNumProcessors
let update = do
logLine "Updating build system ..."
cabal "sandbox" ["init"]
mapM_ (\dir -> cabal "sandbox" ["add-source", dir])
(configPackageDirs config)
cabal "install" [ "--force-reinstalls"
, "--disable-library-profiling"
, "--disable-executable-profiling"
, "--disable-documentation"
, j ]
args <- Env.getArgs
case args of
(".update":_) -> do
-- Update build script and dependencies
update
(".repl":_) -> do
-- Load build script in ghci
cabal "repl" []
(".scrub":_) -> do
-- Clean everything
exe <- getBuildCommand cabalFile pkg
exeExists <- Dir.doesFileExist exe
when exeExists $ callProcess_ exe ["clean"]
hasSandbox <- Dir.doesDirectoryExist sandboxDir
when hasSandbox $
cabal "sandbox" ["delete"]
(('.':cmd):_) -> do
hPutStrLn stderr $ "Usage: " ++ progName ++ " .update|.repl|.scrub|SHAKE_ARGS..."
exitFailure
shakeArgs -> do
-- Call build command with arguments
exe <- getBuildCommand cabalFile pkg
exeExists <- Dir.doesFileExist exe
unless exeExists $ update
callProcess exe (j:shakeArgs)