{- Program: runhs [-e] script [args...] -- Author: Malcolm Wallace -- Copyright: 2005 -- Licence: GPL -- Description: A simple utility to run a Haskell program from source. The given script can be either a .hs, .lhs, or with no extension. Just put #!/path/to/runhs on the first line. This implementation * copies the script to /tmp, adding a .hs extension if required, and stripping the #! line if required; * uses hmake (with your default haskell compiler) to build the program; * then runs it with the given arguments. If you don't change the script between uses, the executable cached in /tmp is not rebuilt. -} #if defined(__HBC__) || defined (__NHC__) import Time (ClockTime) import Monad (when) import System (system,getArgs,exitWith,ExitCode(..)) import Directory (doesFileExist,getModificationTime) #else import Control.Monad (when) import System.Cmd (system) import System.Directory (doesFileExist, getModificationTime) import System.Environment (getArgs) import System.Exit (exitWith, ExitCode(..)) #if __GLASGOW_HASKELL__ >= 604 #define HASCOPYFILE #endif #endif #ifdef HASCOPYFILE import System.Directory (copyFile) #else copyFile src dst = do shell (unwords ["cp",src,dst]); return () #endif {- original shell script: (Haskell now departs from this slightly) #!/bin/sh runhs [-e] script [args...] case $1 in -?) shift ;; *) ;; esac src=$1 shift case $src in *.hs) prog=`basename $src .hs`; tmpsrc=/tmp/`basename $src` ;; *.lhs) prog=`basename $src .lhs`; tmpsrc=/tmp/`basename $src` ;; *) prog=`basename $src`; tmpsrc=/tmp/`basename $src`.hs ;; esac tmpexe=/tmp/$prog if [ ! -f $tmpsrc -o $src -nt $tmpsrc ] then if head -n 1 $src | grep '^#!' >/dev/null then tail +2 $src >$tmpsrc else cp $src $tmpsrc fi fi { hmake $tmpexe >/dev/null 2>&1 ||\ { echo "$prog: compilation error" && exit 1; } \ } && $tmpexe "$@" -} main = do argv <- getArgs (src:args) <- case argv of [] -> exitWith ExitSuccess (('-':_):as) -> return as _ -> return argv let prog = basename (case reverse src of ('s':'h':'.':f) -> reverse f ('s':'h':'l':'.':f) -> reverse f _ -> src) tmpsrc = "/tmp/"++(case reverse src of ('s':'h':'.':f) -> basename src ('s':'h':'l':'.':f) -> basename src _ -> basename src++".hs") tmpexe = "/tmp/"++prog exists <- doesFileExist tmpsrc copy <- if exists then do t0 <- getModificationTime src t1 <- getModificationTime tmpsrc return (t0>t1) else return True when copy (do txt <- readFile src case txt of ('#':'!':_) -> do shell ("{ echo; tail +2 "++src++"; } >"++tmpsrc) return () _ -> copyFile src tmpsrc) -- now compile and run it e <- shell ("hmake "++tmpexe++">/dev/null") ifErr e (\c-> do putStrLn ("runhs: error in "++prog); exitWith c) err <- shell (tmpexe++" "++unwords args) exitWith err -- | Strip directory and suffix from filenames (analogous to the shell -- command of the same name). basename :: String -> String basename = reverse . takeWhile (not.(`elem`"\\/")) . reverse -- | Strip non-directory suffix from file name (analogous to the shell -- command of the same name). dirname :: String -> String dirname = reverse . safetail . dropWhile (not.(`elem`"\\/")) . reverse where safetail [] = [] safetail (_:x) = x shell :: String -> IO ExitCode shell = system -- only on Unix ifErr :: ExitCode -> (ExitCode->IO ()) -> IO () ifErr code@(ExitFailure _) err = err code ifErr _ _ = return ()