{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP, QuasiQuotes, ScopedTypeVariables, NamedFieldPuns, Rank2Types #-}

module Test.Sandwich.WebDriver.Internal.Binaries (
  obtainSelenium
  , obtainChromeDriver
  , obtainGeckoDriver
  , downloadSeleniumIfNecessary
  , downloadChromeDriverIfNecessary
  ) where

import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Logger
import Control.Monad.Trans.Control (MonadBaseControl)
import Control.Monad.Trans.Except
import Data.String.Interpolate
import qualified Data.Text as T
import GHC.Stack
import System.Directory
import System.FilePath
import System.Process
import Test.Sandwich.Logging
import Test.Sandwich.WebDriver.Internal.Binaries.Util
import Test.Sandwich.WebDriver.Internal.Types
import Test.Sandwich.WebDriver.Internal.Util

type Constraints m = (HasCallStack, MonadLogger m, MonadIO m, MonadBaseControl IO m)

-- * Obtaining binaries

  -- TODO: remove curl dependencies here

-- | Manually obtain a Selenium server JAR file, according to the 'SeleniumToUse' policy,
-- storing it under the provided 'FilePath' if necessary and returning the exact path.
obtainSelenium :: (MonadIO m, MonadLogger m) => FilePath -> SeleniumToUse -> m (Either T.Text FilePath)
obtainSelenium :: forall (m :: * -> *).
(MonadIO m, MonadLogger m) =>
FilePath -> SeleniumToUse -> m (Either Text FilePath)
obtainSelenium FilePath
toolsDir (DownloadSeleniumFrom FilePath
url) = do
  let seleniumPath :: FilePath
seleniumPath = [i|#{toolsDir}/selenium-server-standalone.jar|]
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
seleniumPath)
  forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
seleniumPath) forall a b. (a -> b) -> a -> b
$
    forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|curl #{url} -o #{seleniumPath}|]) FilePath
""
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right FilePath
seleniumPath
obtainSelenium FilePath
toolsDir SeleniumToUse
DownloadSeleniumDefault = do
  let seleniumPath :: FilePath
seleniumPath = [i|#{toolsDir}/selenium-server-standalone-3.141.59.jar|]
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
seleniumPath)
  forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
seleniumPath) forall a b. (a -> b) -> a -> b
$
    forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|curl https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar -o #{seleniumPath}|]) FilePath
""
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right FilePath
seleniumPath
obtainSelenium FilePath
_ (UseSeleniumAt FilePath
path) =
  (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
False -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left [i|Path '#{path}' didn't exist|]
    Bool
True -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right FilePath
path

-- | Manually obtain a chromedriver binary, according to the 'ChromeDriverToUse' policy,
-- storing it under the provided 'FilePath' if necessary and returning the exact path.
obtainChromeDriver :: (MonadIO m, MonadLogger m, MonadBaseControl IO m) => FilePath -> ChromeDriverToUse -> m (Either T.Text FilePath)
obtainChromeDriver :: forall (m :: * -> *).
(MonadIO m, MonadLogger m, MonadBaseControl IO m) =>
FilePath -> ChromeDriverToUse -> m (Either Text FilePath)
obtainChromeDriver FilePath
toolsDir (DownloadChromeDriverFrom FilePath
url) = do
  let path :: FilePath
path = [i|#{toolsDir}/#{chromeDriverExecutable}|]
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
path)
  forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path) forall a b. (a -> b) -> a -> b
$
    forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|curl #{url} -o #{path}|]) FilePath
""
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right FilePath
path
obtainChromeDriver FilePath
toolsDir (DownloadChromeDriverVersion ChromeDriverVersion
chromeDriverVersion) = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
  let path :: FilePath
path = FilePath -> ChromeDriverVersion -> FilePath
getChromeDriverPath FilePath
toolsDir ChromeDriverVersion
chromeDriverVersion
  (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
True -> forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
path
    Bool
False -> do
      let downloadPath :: Text
downloadPath = ChromeDriverVersion -> Platform -> Text
getChromeDriverDownloadUrl ChromeDriverVersion
chromeDriverVersion Platform
detectPlatform
      forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
(MonadIO m, MonadBaseControl IO m, MonadLogger m) =>
Text -> FilePath -> m (Either Text ())
downloadAndUnzipToPath Text
downloadPath FilePath
path
      forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
path
obtainChromeDriver FilePath
toolsDir (DownloadChromeDriverAutodetect Maybe FilePath
maybeChromePath) = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
  ChromeDriverVersion
version <- forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Maybe FilePath -> IO (Either Text ChromeDriverVersion)
getChromeDriverVersion Maybe FilePath
maybeChromePath
  forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
(MonadIO m, MonadLogger m, MonadBaseControl IO m) =>
FilePath -> ChromeDriverToUse -> m (Either Text FilePath)
obtainChromeDriver FilePath
toolsDir (ChromeDriverVersion -> ChromeDriverToUse
DownloadChromeDriverVersion ChromeDriverVersion
version)
obtainChromeDriver FilePath
_ (UseChromeDriverAt FilePath
path) =
  (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
False -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left [i|Path '#{path}' didn't exist|]
    Bool
True -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right FilePath
path

-- | Manually obtain a geckodriver binary, according to the 'GeckoDriverToUse' policy,
-- storing it under the provided 'FilePath' if necessary and returning the exact path.
obtainGeckoDriver :: (MonadIO m, MonadLogger m, MonadBaseControl IO m) => FilePath -> GeckoDriverToUse -> m (Either T.Text FilePath)
obtainGeckoDriver :: forall (m :: * -> *).
(MonadIO m, MonadLogger m, MonadBaseControl IO m) =>
FilePath -> GeckoDriverToUse -> m (Either Text FilePath)
obtainGeckoDriver FilePath
toolsDir (DownloadGeckoDriverFrom FilePath
url) = do
  let path :: FilePath
path = [i|#{toolsDir}/#{geckoDriverExecutable}|]
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
path)
  forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path) forall a b. (a -> b) -> a -> b
$
    forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|curl #{url} -o #{path}|]) FilePath
""
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right FilePath
path
obtainGeckoDriver FilePath
toolsDir (DownloadGeckoDriverVersion GeckoDriverVersion
geckoDriverVersion) = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
  let path :: FilePath
path = FilePath -> GeckoDriverVersion -> FilePath
getGeckoDriverPath FilePath
toolsDir GeckoDriverVersion
geckoDriverVersion
  (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
True -> forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
path
    Bool
False -> do
      let downloadPath :: Text
downloadPath = GeckoDriverVersion -> Platform -> Text
getGeckoDriverDownloadUrl GeckoDriverVersion
geckoDriverVersion Platform
detectPlatform
      forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
(MonadIO m, MonadBaseControl IO m, MonadLogger m) =>
Text -> FilePath -> m (Either Text ())
downloadAndUntarballToPath Text
downloadPath FilePath
path
      forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
path
obtainGeckoDriver FilePath
toolsDir (DownloadGeckoDriverAutodetect Maybe FilePath
maybeFirefoxPath) = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
  GeckoDriverVersion
version <- forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Maybe FilePath -> IO (Either Text GeckoDriverVersion)
getGeckoDriverVersion Maybe FilePath
maybeFirefoxPath
  forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
(MonadIO m, MonadLogger m, MonadBaseControl IO m) =>
FilePath -> GeckoDriverToUse -> m (Either Text FilePath)
obtainGeckoDriver FilePath
toolsDir (GeckoDriverVersion -> GeckoDriverToUse
DownloadGeckoDriverVersion GeckoDriverVersion
version)
obtainGeckoDriver FilePath
_ (UseGeckoDriverAt FilePath
path) =
  (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
False -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left [i|Path '#{path}' didn't exist|]
    Bool
True -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right FilePath
path

-- * Lower level helpers


downloadSeleniumIfNecessary :: Constraints m => FilePath -> m (Either T.Text FilePath)
downloadSeleniumIfNecessary :: forall (m :: * -> *).
Constraints m =>
FilePath -> m (Either Text FilePath)
downloadSeleniumIfNecessary FilePath
toolsDir = forall (m :: * -> *) a.
(MonadIO m, MonadBaseControl IO m) =>
m a -> m (Either Text a)
leftOnException' forall a b. (a -> b) -> a -> b
$ do
  let seleniumPath :: FilePath
seleniumPath = [i|#{toolsDir}/selenium-server.jar|]
  (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (FilePath -> IO Bool
doesFileExist FilePath
seleniumPath) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (m :: * -> *). Constraints m => FilePath -> m ()
downloadSelenium FilePath
seleniumPath))
  forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
seleniumPath

downloadSelenium :: Constraints m => FilePath -> m ()
downloadSelenium :: forall (m :: * -> *). Constraints m => FilePath -> m ()
downloadSelenium FilePath
seleniumPath = forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ do
  forall (m :: * -> *). (HasCallStack, MonadLogger m) => Text -> m ()
info [i|Downloading selenium-server.jar to #{seleniumPath}|]
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
seleniumPath)
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|curl https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar -o #{seleniumPath}|]) FilePath
""

downloadChromeDriverIfNecessary' :: Constraints m => FilePath -> ChromeDriverVersion -> m (Either T.Text FilePath)
downloadChromeDriverIfNecessary' :: forall (m :: * -> *).
Constraints m =>
FilePath -> ChromeDriverVersion -> m (Either Text FilePath)
downloadChromeDriverIfNecessary' FilePath
toolsDir ChromeDriverVersion
chromeDriverVersion = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
  let chromeDriverPath :: FilePath
chromeDriverPath = FilePath -> ChromeDriverVersion -> FilePath
getChromeDriverPath FilePath
toolsDir ChromeDriverVersion
chromeDriverVersion

  forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
chromeDriverPath) forall a b. (a -> b) -> a -> b
$ do
    let downloadPath :: Text
downloadPath = ChromeDriverVersion -> Platform -> Text
getChromeDriverDownloadUrl ChromeDriverVersion
chromeDriverVersion Platform
detectPlatform
    forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
(MonadIO m, MonadBaseControl IO m, MonadLogger m) =>
Text -> FilePath -> m (Either Text ())
downloadAndUnzipToPath Text
downloadPath FilePath
chromeDriverPath

  forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
chromeDriverPath

downloadChromeDriverIfNecessary :: Constraints m => Maybe FilePath -> FilePath -> m (Either T.Text FilePath)
downloadChromeDriverIfNecessary :: forall (m :: * -> *).
Constraints m =>
Maybe FilePath -> FilePath -> m (Either Text FilePath)
downloadChromeDriverIfNecessary Maybe FilePath
maybeChromePath FilePath
toolsDir = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
  ChromeDriverVersion
chromeDriverVersion <- forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Maybe FilePath -> IO (Either Text ChromeDriverVersion)
getChromeDriverVersion Maybe FilePath
maybeChromePath
  forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
Constraints m =>
FilePath -> ChromeDriverVersion -> m (Either Text FilePath)
downloadChromeDriverIfNecessary' FilePath
toolsDir ChromeDriverVersion
chromeDriverVersion

getChromeDriverPath :: FilePath -> ChromeDriverVersion -> FilePath
getChromeDriverPath :: FilePath -> ChromeDriverVersion -> FilePath
getChromeDriverPath FilePath
toolsDir (ChromeDriverVersion (Int
w, Int
x, Int
y, Int
z)) = [i|#{toolsDir}/chromedrivers/#{w}.#{x}.#{y}.#{z}/#{chromeDriverExecutable}|]

getGeckoDriverPath :: FilePath -> GeckoDriverVersion -> FilePath
getGeckoDriverPath :: FilePath -> GeckoDriverVersion -> FilePath
getGeckoDriverPath FilePath
toolsDir (GeckoDriverVersion (Int
x, Int
y, Int
z)) = [i|#{toolsDir}/geckodrivers/#{x}.#{y}.#{z}/#{geckoDriverExecutable}|]

chromeDriverExecutable :: T.Text
chromeDriverExecutable :: Text
chromeDriverExecutable = case Platform
detectPlatform of
  Platform
Windows -> Text
"chromedriver.exe"
  Platform
_ -> Text
"chromedriver"

geckoDriverExecutable :: T.Text
geckoDriverExecutable :: Text
geckoDriverExecutable = case Platform
detectPlatform of
  Platform
Windows -> Text
"geckodriver.exe"
  Platform
_ -> Text
"geckodriver"

downloadAndUnzipToPath :: (MonadIO m, MonadBaseControl IO m, MonadLogger m) => T.Text -> FilePath -> m (Either T.Text ())
downloadAndUnzipToPath :: forall (m :: * -> *).
(MonadIO m, MonadBaseControl IO m, MonadLogger m) =>
Text -> FilePath -> m (Either Text ())
downloadAndUnzipToPath Text
downloadPath FilePath
localPath = forall (m :: * -> *) a.
(MonadIO m, MonadBaseControl IO m) =>
m a -> m (Either Text a)
leftOnException' forall a b. (a -> b) -> a -> b
$ do
  forall (m :: * -> *). (HasCallStack, MonadLogger m) => Text -> m ()
info [i|Downloading #{downloadPath} to #{localPath}|]
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
localPath)
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|wget -nc -O - #{downloadPath} | gunzip - > #{localPath}|]) FilePath
""
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|chmod u+x #{localPath}|]) FilePath
""

downloadAndUntarballToPath :: (MonadIO m, MonadBaseControl IO m, MonadLogger m) => T.Text -> FilePath -> m (Either T.Text ())
downloadAndUntarballToPath :: forall (m :: * -> *).
(MonadIO m, MonadBaseControl IO m, MonadLogger m) =>
Text -> FilePath -> m (Either Text ())
downloadAndUntarballToPath Text
downloadPath FilePath
localPath = forall (m :: * -> *) a.
(MonadIO m, MonadBaseControl IO m) =>
m a -> m (Either Text a)
leftOnException' forall a b. (a -> b) -> a -> b
$ do
  forall (m :: * -> *). (HasCallStack, MonadLogger m) => Text -> m ()
info [i|Downloading #{downloadPath} to #{localPath}|]
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
localPath)
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|wget -qO- #{downloadPath} | tar xvz  -C #{takeDirectory localPath}|]) FilePath
""
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ CreateProcess -> FilePath -> IO FilePath
readCreateProcess (FilePath -> CreateProcess
shell [i|chmod u+x #{localPath}|]) FilePath
""

unlessM :: Monad m => m Bool -> m () -> m ()
unlessM :: forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM m Bool
b m ()
s = m Bool
b forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (\Bool
t -> forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
t m ()
s)