@@ -4,8 +4,8 @@
4{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE PatternGuards #-}
5{-# LANGUAGE PatternGuards #-}
6{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE ViewPatterns #-}
8{-# LANGUAGE TemplateHaskell #-}
7{-# LANGUAGE TemplateHaskell #-}
8+{-# LANGUAGE ViewPatterns #-}
9module Obelisk.SelfTest where
9module Obelisk.SelfTest where
11import Control.Exception (bracket, throw)
11import Control.Exception (bracket, throw)
@@ -17,26 +17,24 @@ import Data.Semigroup ((<>))
17import qualified Data.Set as Set
17import qualified Data.Set as Set
18import Data.String
18import Data.String
19import Data.Text (Text)
19import Data.Text (Text)
21import qualified Data.Text as T
20import qualified Data.Text as T
22import qualified Data.Text.IO as T
21import qualified Data.Text.IO as T
23import qualified Network.HTTP.Client as HTTP
22import qualified Network.HTTP.Client as HTTP
24import qualified Network.HTTP.Types as HTTP
23import qualified Network.HTTP.Types as HTTP
25import qualified Network.Socket as Socket
24import qualified Network.Socket as Socket
26−import Shelly hiding (cp)
25+import Shelly
27import System.Directory (getCurrentDirectory, withCurrentDirectory, getDirectoryContents)
26import System.Directory (getCurrentDirectory, withCurrentDirectory, getDirectoryContents)
28import System.Environment
27import System.Environment
29import System.Exit (ExitCode (..))
28import System.Exit (ExitCode (..))
30−import System.Which (staticWhich)
29+import System.FilePath (addTrailingPathSeparator)
31import qualified System.Info
30import qualified System.Info
32import System.IO (Handle, hClose, hIsEOF, hGetContents)
31import System.IO (Handle, hClose, hIsEOF, hGetContents)
33import System.IO.Temp
32import System.IO.Temp
34−import System.Process (readProcessWithExitCode, CreateProcess(cwd), readCreateProcessWithExitCode, proc)
33+import System.Process (readProcessWithExitCode)
34+import System.Which (staticWhich)
35import Test.Hspec
35import Test.Hspec
36import Test.HUnit.Base
36import Test.HUnit.Base
38−import Obelisk.CliApp hiding (runCli, readCreateProcessWithExitCode)
39−import qualified Obelisk.CliApp as CliApp
40import Obelisk.ExecutableConfig.Lookup (getConfigs)
38import Obelisk.ExecutableConfig.Lookup (getConfigs)
41import Obelisk.Run (getConfigRoute)
39import Obelisk.Run (getConfigRoute)
@@ -46,8 +44,8 @@ data ObRunState
46 | ObRunState_BackendStarted
44 | ObRunState_BackendStarted
47 deriving (Eq, Show)
45 deriving (Eq, Show)
49−cp :: FilePath
47+cpPath :: FilePath
50−cp = $(staticWhich "cp")
48+cpPath = $(staticWhich "cp")
52cabalPath :: FilePath
50cabalPath :: FilePath
53cabalPath = $(staticWhich "cabal")
51cabalPath = $(staticWhich "cabal")
@@ -73,6 +71,9 @@ lnPath = $(staticWhich "ln")
73rmPath :: FilePath
71rmPath :: FilePath
74rmPath = $(staticWhich "rm")
72rmPath = $(staticWhich "rm")
75+rsyncPath = $(staticWhich "rsync")
76gitUserConfig :: [Text]
77gitUserConfig :: [Text]
77gitUserConfig = ["-c", "user.name=Obelisk Selftest", "-c", "user.email=noreply@example.com"]
78gitUserConfig = ["-c", "user.name=Obelisk Selftest", "-c", "user.email=noreply@example.com"]
@@ -84,12 +85,6 @@ commit msg = void $ run gitPath $ gitUserConfig <> [ "commit"
87−-- TODO replace Void and stop using loosely typed synchronous exceptions
88−runCli :: MonadIO m => CliT Void IO a -> m a
89−runCli f = liftIO $ do
90− c <- newCliConfig Notice False False (\case {})
93tshow :: Show a => a -> Text
88tshow :: Show a => a -> Text
94tshow = T.pack . show
89tshow = T.pack . show
@@ -106,228 +101,252 @@ ob = "ob"
106augmentWithVerbosity :: (String -> [Text] -> a) -> String -> Bool -> [Text] -> a
101augmentWithVerbosity :: (String -> [Text] -> a) -> String -> Bool -> [Text] -> a
107augmentWithVerbosity runner executable isVerbose args = runner executable $ (if isVerbose then ("-v" :) else id) args
102augmentWithVerbosity runner executable isVerbose args = runner executable $ (if isVerbose then ("-v" :) else id) args
104+-- | Copies a git repo to a new location and "resets" the git history to include
105+-- exactly one commit with all files added. It then restricts writing and reading
106+-- for group and user to make the repo ideal for being a valid git remote for thunks.
108+-- Using this allows dirty repos to be used as git remotes during the test since 'git clone'ing
109+-- a dirty repo will not include the uncommitted changes.
110+copyForGitRemote :: Bool -> FilePath -> FilePath -> IO ()
111+copyForGitRemote isVerbose origDir copyDir = shelly $ bool silently verbosely isVerbose $ do
112+ setenv "HOME" "/dev/null"
113+ setenv "GIT_CONFIG_NOSYSTEM" "1"
115+ [ "-r", "--no-perms", "--no-owner", "--no-group", "--exclude", ".git"
116+ , toTextIgnore (addTrailingPathSeparator origDir), toTextIgnore copyDir
119+ git ["config", "user.name", "SelfTest"]
120+ git ["config", "user.email", "self@test"]
121+ git ["add", "--all"]
122+ git ["commit", "-m", "Copy repo"]
123+ run_ chmodPath ["-R", "u-w,g-rw,o-rw", toTextIgnore copyDir] -- Freeze this state
125+ git args = run_ gitPath $ ["-C", toTextIgnore copyDir] <> args
109main :: IO ()
127main :: IO ()
111 -- Note: you can pass hspec arguments as well, eg: `-m <pattern>`
129 -- Note: you can pass hspec arguments as well, eg: `-m <pattern>`
112 isVerbose <- elem "-v" <$> getArgs
130 isVerbose <- elem "-v" <$> getArgs
113 unless isVerbose $
131 unless isVerbose $
114 putStrLn "Tests may take longer to run if there are unbuilt derivations: use -v for verbose output"
132 putStrLn "Tests may take longer to run if there are unbuilt derivations: use -v for verbose output"
115− let verbosity = bool silently verbosely isVerbose
133+
116− nixBuild args = run nixBuildPath ("--no-out-link" : args)
134+ obeliskImplDirtyReadOnly <- getCurrentDirectory
117− obeliskImplDirtyReadOnly <- fromString <$> getCurrentDirectory
135+ httpManager <- HTTP.newManager HTTP.defaultManagerSettings
118− let runOb_ = augmentWithVerbosity run_ ob isVerbose
136+
119− let runOb = augmentWithVerbosity run ob isVerbose
137+ withSystemTempDirectory "obelisk-repo-git-remote" $ \copyDir -> do
120− let testObRunInDir' = augmentWithVerbosity testObRunInDir ob isVerbose ["run"]
138+ copyForGitRemote isVerbose obeliskImplDirtyReadOnly copyDir
121− let testThunkPack' = augmentWithVerbosity testThunkPack ob isVerbose []
139+ main' isVerbose httpManager copyDir
141+main' :: Bool -> HTTP.Manager -> FilePath -> IO ()
142+main' isVerbose httpManager obeliskRepoReadOnly = withInitCache $ \initCache -> hspec $ parallel $ do
144+ inTmpObInit' dirname f = inTmp' dirname $ \dir -> do
145+ run_ cpPath ["-rT", fromString initCache, toTextIgnore dir]
147+ inTmpObInit = inTmpObInit' defaultTmpDirName
149+ -- To be used in tests that change the obelisk impl directory
150+ inTmpObInitWithImplCopy f = inTmpObInit $ \dir ->
123− withObeliskImplClean f =
151+ withObeliskImplClean $ \(fromString -> implClean) -> do
153+ run_ lnPath ["-s", implClean, thunk]
156+ describe "ob init" $ parallel $ do
157+ it "works with default impl" $ inTmp $ \_ -> runOb ["init"]
158+ it "works with master branch impl" $ inTmp $ \_ -> runOb ["init", "--branch", "master"]
159+ it "works with symlink" $ inTmp $ \_ -> runOb ["init", "--symlink", toTextIgnore obeliskRepoReadOnly]
160+ it "doesn't silently overwrite existing files" $ inTmp $ \_ -> do
161+ let p force = errExit False $ do
162+ run_ ob $ "--no-handoff" : "-v" : "init" : ["--force"|force]
163+ (== 0) <$> lastExitCode
170+ it "doesn't create anything when given an invalid impl" $ inTmp $ \tmp -> do
171+ void $ errExit False $ runOb ["init", "--symlink", "/dev/null"]
172+ ls tmp >>= liftIO . assertEqual "" []
174+ it "produces a valid route config" $ inTmpObInit $ \tmp -> liftIO $
175+ withCurrentDirectory (T.unpack $ toTextIgnore tmp) $ do
176+ configs <- getConfigs
177+ return (either (const Nothing) Just $ getConfigRoute configs) `shouldNotReturn` Nothing
179+ -- These tests fail with "Could not find module 'Obelisk.Generated.Static'"
180+ -- when not run by 'nix-build --attr selftest'
181+ describe "ob run" $ {- NOT parallel $ -} do
182+ it "works in root directory" $ inTmpObInit $ \_ -> testObRunInDir' Nothing httpManager
183+ it "works in sub directory" $ inTmpObInit $ \_ -> testObRunInDir' (Just "frontend") httpManager
185+ describe "obelisk project" $ parallel $ do
186+ it "can build obelisk command" $ inTmpObInit $ \_ -> nixBuild ["-A", "command" , toTextIgnore obeliskRepoReadOnly]
187+ it "can build obelisk skeleton" $ inTmpObInit $ \_ -> nixBuild ["-A", "skeleton", toTextIgnore obeliskRepoReadOnly]
188+ it "can build obelisk shell" $ inTmpObInit $ \_ -> nixBuild ["-A", "shell", toTextIgnore obeliskRepoReadOnly]
189+ it "can build everything" $ inTmpObInit $ \_ -> nixBuild [toTextIgnore obeliskRepoReadOnly]
191+ describe "blank initialized project" $ parallel $ do
193+ it "can build ghc.backend" $ inTmpObInit $ \_ -> nixBuild ["-A", "ghc.backend"]
194+ it "can build ghcjs.frontend" $ inTmpObInit $ \_ -> nixBuild ["-A", "ghcjs.frontend"]
196+ if System.Info.os == "darwin"
197+ then it "can build ios" $ inTmpObInit $ \_ -> nixBuild ["-A", "ios.frontend"]
198+ else it "can build android after accepting license" $ inTmpObInit $ \dir -> do
199+ let defaultNixPath = dir </> ("default.nix" :: FilePath)
200+ writefile defaultNixPath
202+ "# config.android_sdk.accept_license = false;"
203+ "config.android_sdk.accept_license = true;"
204+ <$> readfile defaultNixPath
205+ nixBuild ["-A", "android.frontend"]
207+ forM_ ["ghc", "ghcjs"] $ \compiler -> do
209+ shellName = "shells." <> compiler
210+ inShell cmd' = run_ "nix-shell" ["default.nix", "-A", fromString shellName, "--run", cmd']
211+ it ("can enter " <> shellName) $ inTmpObInit $ \_ -> inShell "exit"
212+ -- NOTE: We override the temporary directory name because cabal has a bug preventing new-build from working
213+ -- in a path that has unicode characters.
214+ it ("can build in " <> shellName) $ inTmpObInit' "test" $ \_ -> inShell $
215+ T.pack cabalPath <> " --version; " <> T.pack cabalPath <> " new-build --" <> T.pack compiler <> " all"
217+ it "has idempotent thunk update" $ inTmpObInitWithImplCopy $ \_ -> do
223+ describe "ob thunk pack/unpack" $ parallel $ do
224+ it "has thunk pack and unpack inverses" $ inTmpObInitWithImplCopy $ \_ -> do
237+ it "unpacks the correct branch" $ withTmp $ \dir -> do
238+ let branch = "master"
239+ run_ gitPath ["clone", "https://github.com/reflex-frp/reflex.git", toTextIgnore dir, "--branch", branch]
240+ runOb_ ["thunk", "pack", toTextIgnore dir]
241+ runOb_ ["thunk", "unpack", toTextIgnore dir]
242+ branch' <- chdir dir $ run gitPath ["rev-parse", "--abbrev-ref", "HEAD"]
243+ liftIO $ assertEqual "" branch (T.strip branch')
245+ it "can pack and unpack plain git repos" $
124− withSystemTempDirectory "obelisk-impl-clean" $ \(fromString -> obeliskImpl) -> do
246+ shelly_ $ withSystemTempDirectory "git-repo" $ \dir -> do
125− void . shellyOb verbosity $ chdir obeliskImpl $ do
247+ let repo = toTextIgnore $ dir </> ("repo" :: FilePath)
126− run_ gitPath ["clone", "file://" <> toTextIgnore obeliskImplDirtyReadOnly, toTextIgnore obeliskImpl]
248+ run_ gitPath ["clone", "https://github.com/haskell/process.git", repo]
127− f obeliskImpl
249+ origHash <- chdir (fromText repo) revParseHead
251+ runOb_ ["thunk", "pack", repo]
252+ packedFiles <- Set.fromList <$> ls (fromText repo)
253+ liftIO $ assertEqual "" packedFiles $ Set.fromList $ (repo </>) <$>
254+ ["default.nix", "github.json", ".attr-cache" :: FilePath]
256+ runOb_ ["thunk", "unpack", repo]
257+ chdir (fromText repo) $ do
258+ unpackHash <- revParseHead
259+ assertRevEQ origHash unpackHash
261+ testThunkPack' $ fromText repo
263+ it "aborts thunk pack when there are uncommitted files" $ inTmpObInitWithImplCopy $ \dir -> do
264+ testThunkPack' (dir </> thunk)
266+ describe "ob thunk update --branch" $ parallel $ do
267+ it "can change a thunk to the latest version of a desired branch" $ withTmp $ \dir -> do
268+ let branch1 = "master"
270+ run_ gitPath ["clone", "https://github.com/reflex-frp/reflex.git", toTextIgnore dir, "--branch", branch1]
271+ runOb_ ["thunk" , "pack", toTextIgnore dir]
272+ runOb_ ["thunk", "update", toTextIgnore dir, "--branch", branch2]
274+ it "doesn't create anything when given an invalid branch" $ withTmp $ \dir -> do
275+ let checkDir dir' = liftIO $ getDirectoryContents $ T.unpack $ toTextIgnore dir'
276+ run_ gitPath ["clone", "https://github.com/reflex-frp/reflex.git", toTextIgnore dir, "--branch", "master"]
277+ runOb_ ["thunk" , "pack", toTextIgnore dir]
278+ startingContents <- checkDir dir
279+ void $ errExit False $ runOb ["thunk", "update", toTextIgnore dir, "--branch", "dumble-palooza"]
280+ checkDir dir >>= liftIO . assertEqual "" startingContents
282+ describe "ob hoogle" $ {- NOT parallel -} do
283+ it "starts a hoogle server on the given port" $ inTmpObInit $ \_ -> do
284+ [p0] <- liftIO $ getFreePorts 1
285+ maskExitSuccess $ runHandle "ob" ["hoogle", "--port", T.pack (show p0)] $ \stdout -> fix $ \loop -> do
286+ ln <- liftIO $ T.hGetLine stdout
288+ let search = "Server starting on port " <> T.pack (show p0)
289+ case search `T.isInfixOf` ln of
290+ False -> loop -- keep waiting
292+ let req uri = liftIO $ HTTP.parseRequest uri >>= flip HTTP.httpLbs httpManager
293+ req ("http://127.0.0.1:" <> show p0) >>= \r -> case HTTP.responseStatus r == HTTP.ok200 of
294+ False -> errorExit $ "Request to hoogle server failed: " <> T.pack (show r)
297+ verbosity = bool silently verbosely isVerbose
298+ nixBuild args = run nixBuildPath ("--no-out-link" : args)
300+ runOb_ = augmentWithVerbosity run_ ob isVerbose
301+ runOb = augmentWithVerbosity run ob isVerbose
302+ testObRunInDir' = augmentWithVerbosity testObRunInDir ob isVerbose ["run"]
303+ testThunkPack' = augmentWithVerbosity testThunkPack ob isVerbose []
129− withObeliskImplDirty f =
305+ withObeliskImplClean f =
130− withSystemTempDirectory "obelisk-impl-copy" $ \(fromString -> obeliskImpl) -> do
306+ withSystemTempDirectory "obelisk-impl-clean" $ \obeliskImpl -> do
131 void . shellyOb verbosity $ chdir obeliskImpl $ do
307 void . shellyOb verbosity $ chdir obeliskImpl $ do
132− user <- T.strip <$> run whoamiPath []
308+ dirtyFiles <- T.strip <$> run gitPath ["-C", toTextIgnore obeliskRepoReadOnly, "diff", "--stat"]
133− run_ cp ["-rT", "--no-preserve=mode", toTextIgnore obeliskImplDirtyReadOnly, toTextIgnore obeliskImpl]
309+ () <- when (dirtyFiles /= "") $ error "SelfTest does not work correctly with dirty obelisk repos as remote"
134− run_ chownPath ["-R", user, toTextIgnore obeliskImpl]
135− run_ chmodPath ["-R", "g-rw,o-rw", toTextIgnore obeliskImpl]
310+ run_ gitPath ["clone", "file://" <> toTextIgnore obeliskRepoReadOnly, toTextIgnore obeliskImpl]
136 f obeliskImpl
311 f obeliskImpl
138− withInitCache f obeliskImpl =
313+ withInitCache f =
139 withSystemTempDirectory "init Cache λ" $ \initCache -> do
314 withSystemTempDirectory "init Cache λ" $ \initCache -> do
140 -- Setup the ob init cache
315 -- Setup the ob init cache
141 void . shellyOb verbosity $ chdir initCache $ do
316 void . shellyOb verbosity $ chdir initCache $ do
142− runOb_ ["init", "--symlink", toTextIgnore obeliskImpl]
317+ runOb_ ["init", "--symlink", toTextIgnore obeliskRepoReadOnly]
143 run_ gitPath ["init"]
318 run_ gitPath ["init"]
145 f initCache
320 f initCache
147− withObeliskImplDirtyAndInitCache f =
322+ shelly_ = void . shellyOb verbosity
148− withObeliskImplDirty $ \impl -> withInitCache (f impl) impl
150− httpManager <- HTTP.newManager HTTP.defaultManagerSettings
324+ defaultTmpDirName = "test λ"
326+ inTmp' :: FilePath -> (FilePath -> Sh a) -> IO ()
327+ inTmp' dirname f = withTmp' dirname (chdir <*> f)
328+ inTmp = inTmp' defaultTmpDirName
330+ withTmp' dirname f = shelly_ . withSystemTempDirectory dirname $ f . fromString
331+ withTmp = withTmp' defaultTmpDirName
333+ assertRevEQ a b = liftIO . assertEqual "" "" =<< diff a b
334+ assertRevNE a b = liftIO . assertBool "" . (/= "") =<< diff a b
336+ revParseHead = T.strip <$> run gitPath ["rev-parse", "HEAD"]
339+ run_ gitPath ["add", "."]
343+ thunk = ".obelisk/impl"
344+ update = runOb ["thunk", "update", thunk] *> commitAll
345+ pack = runOb ["thunk", "pack", thunk] *> commitAll
346+ unpack = runOb ["thunk", "unpack", thunk] *> commitAll
348+ diff a b = run gitPath ["diff", a, b]
152− withObeliskImplDirtyAndInitCache $ \obeliskImplDirty initCache ->
153− hspec $ parallel $ do
154− let shelly_ = void . shellyOb verbosity
156− defaultTmpDirName = "test λ"
158− inTmp' :: FilePath -> (FilePath -> Sh a) -> IO ()
159− inTmp' dirname f = withTmp' dirname (chdir <*> f)
160− inTmp = inTmp' defaultTmpDirName
162− withTmp' dirname f = shelly_ . withSystemTempDirectory dirname $ f . fromString
163− withTmp = withTmp' defaultTmpDirName
165− inTmpObInit' dirname f = inTmp' dirname $ \dir -> do
166− run_ cp ["-rT", fromString initCache, toTextIgnore dir]
168− inTmpObInit = inTmpObInit' defaultTmpDirName
170− -- To be used in tests that change the obelisk impl directory
171− inTmpObInitWithImplCopy f = inTmpObInit $ \dir ->
172− withObeliskImplClean $ \(fromString -> implClean) -> do
174− run_ lnPath ["-s", implClean, thunk]
177− assertRevEQ a b = liftIO . assertEqual "" "" =<< diff a b
178− assertRevNE a b = liftIO . assertBool "" . (/= "") =<< diff a b
180− revParseHead = T.strip <$> run gitPath ["rev-parse", "HEAD"]
183− run_ gitPath ["add", "."]
187− thunk = ".obelisk/impl"
188− update = runOb ["thunk", "update", thunk] >> commitAll
189− pack = runOb ["thunk", "pack", thunk] >> commitAll
190− unpack = runOb ["thunk", "unpack", thunk] >> commitAll
192− diff a b = run gitPath ["diff", a, b]
194− describe "ob init" $ parallel $ do
195− it "works with default impl" $ inTmp $ \_ -> runOb ["init"]
196− it "works with master branch impl" $ inTmp $ \_ -> runOb ["init", "--branch", "master"]
197− it "works with symlink" $ inTmp $ \_ -> runOb ["init", "--symlink", toTextIgnore obeliskImplDirty]
198− it "doesn't silently overwrite existing files" $ withSystemTempDirectory "ob-init λ" $ \dir -> do
199− let p force = (System.Process.proc ob $ "--no-handoff" : "-v" : "init" : ["--force"|force]) { cwd = Just dir }
200− (ExitSuccess, _, _) <- readCreateProcessWithExitCode (p False) ""
201− (ExitFailure _, _, _) <- readCreateProcessWithExitCode (p False) ""
202− (ExitSuccess, _, _) <- readCreateProcessWithExitCode (p True) ""
205− it "doesn't create anything when given an invalid impl" $ inTmp $ \tmp -> do
206− void $ errExit False $ runOb ["init", "--symlink", "/dev/null"]
207− ls tmp >>= liftIO . assertEqual "" []
209− it "produces a valid route config" $ inTmpObInit $ \tmp -> liftIO $
210− withCurrentDirectory (T.unpack $ toTextIgnore tmp) $ do
211− configs <- getConfigs
212− return (either (const Nothing) Just $ getConfigRoute configs) `shouldNotReturn` Nothing
214− -- These tests fail with "Could not find module 'Obelisk.Generated.Static'"
215− -- when not run by 'nix-build --attr selftest'
216− describe "ob run" $ {- NOT parallel $ -} do
217− it "works in root directory" $ inTmpObInit $ \_ -> testObRunInDir' Nothing httpManager
218− it "works in sub directory" $ inTmpObInit $ \_ -> testObRunInDir' (Just "frontend") httpManager
220− describe "obelisk project" $ parallel $ do
221− it "can build obelisk command" $ inTmpObInit $ \_ -> nixBuild ["-A", "command" , toTextIgnore obeliskImplDirty]
222− it "can build obelisk skeleton" $ inTmpObInit $ \_ -> nixBuild ["-A", "skeleton", toTextIgnore obeliskImplDirty]
223− it "can build obelisk shell" $ inTmpObInit $ \_ -> nixBuild ["-A", "shell", toTextIgnore obeliskImplDirty]
224− it "can build everything" $ inTmpObInit $ \_ -> nixBuild [toTextIgnore obeliskImplDirty]
226− describe "blank initialized project" $ parallel $ do
228− it "can build ghc.backend" $ inTmpObInit $ \_ -> nixBuild ["-A", "ghc.backend"]
229− it "can build ghcjs.frontend" $ inTmpObInit $ \_ -> nixBuild ["-A", "ghcjs.frontend"]
231− if System.Info.os == "darwin"
232− then it "can build ios" $ inTmpObInit $ \_ -> nixBuild ["-A", "ios.frontend"]
233− else it "can build android after accepting license" $ inTmpObInit $ \dir -> do
234− let defaultNixPath = dir </> ("default.nix" :: FilePath)
235− writefile defaultNixPath
237− "# config.android_sdk.accept_license = false;"
238− "config.android_sdk.accept_license = true;"
239− <$> readfile defaultNixPath
240− nixBuild ["-A", "android.frontend"]
242− forM_ ["ghc", "ghcjs"] $ \compiler -> do
244− shellName = "shells." <> compiler
245− inShell cmd' = run_ "nix-shell" ["default.nix", "-A", fromString shellName, "--run", cmd']
246− it ("can enter " <> shellName) $ inTmpObInit $ \_ -> inShell "exit"
247− -- NOTE: We override the temporary directory name because cabal has a bug preventing new-build from working
248− -- in a path that has unicode characters.
249− it ("can build in " <> shellName) $ inTmpObInit' "test" $ \_ -> inShell $
250− T.pack cabalPath <> " --version; " <> T.pack cabalPath <> " new-build --" <> T.pack compiler <> " all"
252− it "has idempotent thunk update" $ inTmpObInitWithImplCopy $ \_ -> do
258− describe "ob thunk pack/unpack" $ parallel $ do
259− it "has thunk pack and unpack inverses" $ inTmpObInitWithImplCopy $ \_ -> do
272− it "unpacks the correct branch" $ withTmp $ \dir -> do
273− let branch = "master"
274− run_ gitPath ["clone", "https://github.com/reflex-frp/reflex.git", toTextIgnore dir, "--branch", branch]
275− runOb_ ["thunk", "pack", toTextIgnore dir]
276− runOb_ ["thunk", "unpack", toTextIgnore dir]
277− branch' <- chdir dir $ run gitPath ["rev-parse", "--abbrev-ref", "HEAD"]
278− liftIO $ assertEqual "" branch (T.strip branch')
280− it "can pack and unpack plain git repos" $
281− shelly_ $ withSystemTempDirectory "git-repo" $ \dir -> do
282− let repo = toTextIgnore $ dir </> ("repo" :: String)
283− run_ gitPath ["clone", "https://github.com/haskell/process.git", repo]
284− origHash <- chdir (fromText repo) revParseHead
286− runOb_ ["thunk", "pack", repo]
287− packedFiles <- Set.fromList <$> ls (fromText repo)
288− liftIO $ assertEqual "" packedFiles $ Set.fromList $ (repo </>) <$>
289− ["default.nix", "github.json", ".attr-cache" :: String]
291− runOb_ ["thunk", "unpack", repo]
292− chdir (fromText repo) $ do
293− unpackHash <- revParseHead
294− assertRevEQ origHash unpackHash
296− testThunkPack' $ fromText repo
298− it "aborts thunk pack when there are uncommitted files" $ inTmpObInitWithImplCopy $ \dir -> do
299− testThunkPack' (dir </> thunk)
301− describe "ob thunk update --branch" $ parallel $ do
302− it "can change a thunk to the latest version of a desired branch" $ withTmp $ \dir -> do
303− let branch1 = "master"
305− run_ gitPath ["clone", "https://github.com/reflex-frp/reflex.git", toTextIgnore dir, "--branch", branch1]
306− runOb_ ["thunk" , "pack", toTextIgnore dir]
307− runOb_ ["thunk", "update", toTextIgnore dir, "--branch", branch2]
309− it "doesn't create anything when given an invalid branch" $ withTmp $ \dir -> do
310− let checkDir dir' = liftIO $ getDirectoryContents $ T.unpack $ toTextIgnore dir'
311− run_ gitPath ["clone", "https://github.com/reflex-frp/reflex.git", toTextIgnore dir, "--branch", "master"]
312− runOb_ ["thunk" , "pack", toTextIgnore dir]
313− startingContents <- checkDir dir
314− void $ errExit False $ runOb ["thunk", "update", toTextIgnore dir, "--branch", "dumble-palooza"]
315− checkDir dir >>= liftIO . assertEqual "" startingContents
317− describe "ob hoogle" $ {- NOT parallel -} do
318− it "starts a hoogle server on the given port" $ inTmpObInit $ \_ -> do
319− [p0] <- liftIO $ getFreePorts 1
320− maskExitSuccess $ runHandle "ob" ["hoogle", "--port", T.pack (show p0)] $ \stdout -> fix $ \loop -> do
321− ln <- liftIO $ T.hGetLine stdout
323− let search = "Server starting on port " <> T.pack (show p0)
324− case search `T.isInfixOf` ln of
325− False -> loop -- keep waiting
327− let req uri = liftIO $ HTTP.parseRequest uri >>= flip HTTP.httpLbs httpManager
328− req ("http://127.0.0.1:" <> show p0) >>= \r -> case HTTP.responseStatus r == HTTP.ok200 of
329− False -> errorExit $ "Request to hoogle server failed: " <> T.pack (show r)
332maskExitSuccess :: Sh () -> Sh ()
351maskExitSuccess :: Sh () -> Sh ()
333maskExitSuccess = handle_sh (\case ExitSuccess -> pure (); e -> throw e)
352maskExitSuccess = handle_sh (\case ExitSuccess -> pure (); e -> throw e)