packages feed

haskus-system-build-1.0: src/apps/Haskus/Apps/System/Build/Utils.hs

{-# LANGUAGE LambdaCase #-}

module Haskus.Apps.System.Build.Utils
   ( shellWait
   , shellWaitErr
   , shellIn
   , shellInErr
   , untar
   , subTitle
   , showStep
   , failWith
   , download
   , getAppDir
   , getWorkDir
   , getDownloadPath
   , copyDirectory
   )
where

import System.Process
import System.Exit
import System.Directory
import System.FilePath
import System.IO.Temp
import Haskus.Utils.Flow
import qualified Haskus.Apps.System.Build.Download as D

-- | Execute a command
shellWait :: String -> IO ExitCode 
shellWait cmd = do
   (_,_,_,hdl) <- createProcess (shell cmd)
   waitForProcess hdl

-- | Execute a command, call callback on error
shellWaitErr :: String -> IO () -> IO () 
shellWaitErr cmd err = do
   shellWait cmd >>= \case
      ExitSuccess   -> return ()
      ExitFailure _ -> err

-- | Execute a command in the given directory
shellIn :: FilePath -> String -> IO ExitCode 
shellIn fp cmd = do
   (_,_,_,hdl) <- createProcess ((shell cmd) { cwd = Just fp })
   waitForProcess hdl


-- | Execute a command in the given directory, call callback on error
shellInErr :: FilePath -> String -> IO () -> IO ()
shellInErr fp cmd err = do
   shellIn fp cmd >>= \case
      ExitSuccess   -> return ()
      ExitFailure _ -> err

-- | Uncompress an archive
untar :: FilePath -> FilePath -> IO ()
untar src tgt = shellInErr tgt ("tar xf " ++ src) $
   failWith "Cannot uncompress archive"

-- | Add a subline to a text
subTitle :: String -> String
subTitle t = t ++ "\n" ++ replicate (length t) '-' ++ "\n"

-- | Show progress step
showStep :: String -> IO ()
showStep t = putStrLn $ "==> " ++ t

-- | Print error message
failWith :: String -> IO a
failWith s = die $ "Error: " ++ s

-- | Download a file
download :: String -> FilePath -> IO ()
download url tgt = do
   withSystemTempDirectory "haskus-system-build" $ \fp -> do
      let fp2 = fp </> "download.tmp"
      D.download url fp2
      copyFile fp2 tgt

-- | Return app directory
getAppDir :: IO FilePath
getAppDir = do
   fp <- getAppUserDataDirectory "haskus"
   let d = fp </> "system" </> "build"
   createDirectoryIfMissing True d
   return d

-- | Return work directory
getWorkDir :: IO FilePath
getWorkDir = do
   fp <- getCurrentDirectory
   let d = fp </> ".system-work"
   createDirectoryIfMissing True d
   return d

-- | Return download path
getDownloadPath :: IO FilePath
getDownloadPath = do
   fp <- getAppDir
   let d = fp </> "downloads"
   createDirectoryIfMissing True d
   return d

-- | Copy a directory (optionally keeping the structure). Use a predicate to filter
copyDirectory :: FilePath -> FilePath -> Bool -> (FilePath -> IO Bool) -> IO ()
copyDirectory src dst flattenDirs filt = go src
   where
      go currentDir = do
         fs <- listDirectory currentDir
         forM_ fs $ \f -> do
            let fileAbs = currentDir </> f
            isDir <- doesDirectoryExist fileAbs
            if isDir
               then go (currentDir </> f)
               else do
                  -- filter
                  whenM (filt fileAbs) $ do
                     let
                        fileRel = makeRelative src fileAbs
                        dstAbs  = if flattenDirs
                           then dst </> takeFileName (fileAbs)
                           else dst </> fileRel
                     createDirectoryIfMissing True (dropFileName dstAbs)
                     copyFile fileAbs dstAbs