@@ -1,10 +1,14 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE FlexibleContexts #-}
2−module Elm.Utils ((|>), (<|), getAsset) where
3+module Elm.Utils ((|>), (<|), getAsset, run, unwrappedRun, CommandError(..)) where
5+import Control.Monad.Error (MonadError, MonadIO, liftIO, throwError)
4import System.Directory (doesFileExist)
6import System.Directory (doesFileExist)
5import System.Environment (getEnv)
7import System.Environment (getEnv)
8+import System.Exit (ExitCode(ExitSuccess, ExitFailure))
6import System.FilePath ((</>))
9import System.FilePath ((</>))
7import System.IO.Error (tryIOError)
10import System.IO.Error (tryIOError)
11+import System.Process (readProcessWithExitCode)
10{-| Forward function application `x |> f == f x`. This function is useful
14{-| Forward function application `x |> f == f x`. This function is useful
@@ -25,6 +29,49 @@ infixr 0 <|
25infixl 0 |>
29infixl 0 |>
36+ | CommandFailed String
39+{-| Run a command, throw an error if the command is not found or if something
42+run :: (MonadError String m, MonadIO m) => String -> [String] -> m String
44+ do result <- liftIO (unwrappedRun command args)
46+ Right out -> return out
48+ throwError (context (message err))
51+ "failure when running:" ++ concatMap (' ':) (command:args) ++ "\n" ++ msg
55+ CommandFailed msg -> msg
57+ "Could not find command '" ++ command ++ "'. Do you have it installed?\n\
58+ \ Can it be run from anywhere? Is it on your PATH?"
61+unwrappedRun :: String -> [String] -> IO (Either CommandError String)
62+unwrappedRun command args =
63+ do (exitCode, stdout, stderr) <- readProcessWithExitCode command args ""
66+ ExitSuccess -> Right stdout
68+ | code == 127 -> Left MissingExe -- UNIX
69+ | code == 9009 -> Left MissingExe -- Windows
70+ | otherwise -> Left (CommandFailed stderr)
28{-| Get the absolute path to a data file. If you install with cabal it will look
75{-| Get the absolute path to a data file. If you install with cabal it will look
30getAsset :: String -> (FilePath -> IO FilePath) -> FilePath -> IO FilePath
77getAsset :: String -> (FilePath -> IO FilePath) -> FilePath -> IO FilePath