module Pier.Core.Download
( askDownload
, Download(..)
, downloadRules
, DownloadLocation(..)
) where
import Control.Exception (bracketOnError)
import Control.Monad (unless)
import Development.Shake
import Development.Shake.Classes
import Development.Shake.FilePath
import GHC.Generics
import Network.HTTP.Client
import Network.HTTP.Client.TLS
import Network.HTTP.Types.Status
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Lazy as L
import qualified System.Directory as Directory
import Pier.Core.Artifact
import Pier.Core.Directory
import Pier.Core.Persistent
import Pier.Core.Run
data Download = Download
{ downloadUrlPrefix :: String
, downloadName :: FilePath
, downloadFilePrefix :: FilePath
}
deriving (Typeable, Eq, Generic)
instance Show Download where
show d = "Download " ++ show (downloadName d)
++ " from " ++ show (downloadUrlPrefix d)
++ " into " ++ show (downloadFilePrefix d)
instance Hashable Download
instance Binary Download
instance NFData Download
type instance RuleResult Download = Artifact
askDownload :: Download -> Action Artifact
askDownload = askPersistent
downloadRules :: DownloadLocation -> Rules ()
downloadRules loc = do
manager <- liftIO $ newManager tlsManagerSettings
addPersistent $ \d -> do
downloadsDir <- liftIO $ pierDownloadsDir loc
let result = downloadsDir </> downloadFilePrefix d
</> downloadName d
exists <- liftIO $ Directory.doesFileExist result
unless exists $ do
putNormal $ "Downloading " ++ downloadName d
liftIO $ bracketOnError
(createPierTempFile $ takeFileName $ downloadName d)
Directory.removeFile
$ \tmp -> do
let url = downloadUrlPrefix d ++ "/" ++ downloadName d
req <- parseRequest url
resp <- httpLbs req manager
unless (statusIsSuccessful . responseStatus $ resp)
$ error $ "Unable to download " ++ show url
++ "\nStatus: " ++ showStatus (responseStatus resp)
liftIO . L.writeFile tmp . responseBody $ resp
createParentIfMissing result
Directory.renameFile tmp result
return $ externalFile result
where
showStatus s = show (statusCode s) ++ " " ++ BC.unpack (statusMessage s)
pierDownloadsDir :: DownloadLocation -> IO FilePath
pierDownloadsDir DownloadToHome = do
home <- Directory.getHomeDirectory
return $ home </> ".pier/downloads"
pierDownloadsDir DownloadLocal = return $ pierFile "downloads"
data DownloadLocation
= DownloadToHome
| DownloadLocal