Skip to content

Commit

Permalink
Muti Build Support
Browse files Browse the repository at this point in the history
- Stack, Cabal default support with GHC as standard build setting
- new config value `  "script": "stack"` where you can select `stack`, `cabal` & `ghc`
  • Loading branch information
Frost-Lord committed Jul 22, 2023
1 parent 8dd7084 commit c6872d6
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 34 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ cabal.project.local~
test/test.exe
test/test.hi
test/test.o
code.txt
code.txt
test/stack.yaml.lock
test/app/test.exe
4 changes: 2 additions & 2 deletions HaskMate.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ executable HaskMate
import: warnings
main-is: HaskMate.hs
other-modules: Commands, Settings
build-depends: base, process, directory, time, aeson, bytestring, text, http-client, http-conduit, http-types
build-depends: base, process, directory, time, aeson, bytestring, text, http-client, http-conduit, http-types, filepath
hs-source-dirs: app
default-language: Haskell2010
default-language: Haskell2010
71 changes: 41 additions & 30 deletions app/HaskMate.hs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import Control.Concurrent (threadDelay)
import System.Directory (doesFileExist, getModificationTime, getCurrentDirectory)
import System.Process (createProcess, proc, terminateProcess, waitForProcess, callCommand, ProcessHandle)
import Control.Concurrent.MVar (newEmptyMVar, putMVar, tryTakeMVar, MVar)
import System.Process (terminateProcess, waitForProcess, callCommand, ProcessHandle)
import Control.Concurrent.MVar (newEmptyMVar, tryTakeMVar, MVar)
import Data.Time.Clock (getCurrentTime, UTCTime)
import System.FilePath (takeDirectory)
import System.Environment (getArgs)
import Commands (displayHelpData, displayVersionData)
import Settings (Settings(..), loadSettings)
Expand All @@ -26,28 +27,36 @@ getLastModified path = do
then getModificationTime path
else getCurrentTime

-- Monitor the script for changes and rerun it
monitorScript :: Int -> FilePath -> UTCTime -> MVar (Maybe ProcessHandle) -> IO ()
monitorScript delayTime path lastModified handleMVar = do
currentModified <- getLastModified path
if currentModified > lastModified
then do
putStrLn $ yellow ++ projectName ++ white ++ " Detected file modification. Rebuilding and running..."
let exePath = take (length path - 3) path
callCommand $ "stack ghc -- " ++ path
oldHandle <- tryTakeMVar handleMVar
case oldHandle of
Just (Just handle) -> do
terminateProcess handle
_ <- waitForProcess handle
return ()
_ -> return ()
(_, _, _, newHandle) <- createProcess (proc exePath [])
putMVar handleMVar (Just newHandle)
monitorScript delayTime path currentModified handleMVar
else do
threadDelay delayTime
monitorScript delayTime path lastModified handleMVar
-- Decide which command to run based on the script
runScript :: String -> FilePath -> IO ()
runScript script' path = do
let rootPath = takeDirectory path
case script' of
"ghc" -> callCommand $ "stack ghc -- " ++ path
"stack" -> callCommand $ "stack build && stack run " ++ rootPath
"cabal" -> callCommand $ "cabal build && cabal run " ++ rootPath
_ -> callCommand $ "stack ghc -- " ++ path -- default

-- Monitor file changes
monitorScript :: Int -> FilePath -> UTCTime -> MVar (Maybe ProcessHandle) -> String -> IO ()
monitorScript delayTime path lastModified handleMVar script' = do
let loop currentLastModified = do
threadDelay delayTime
currentModified <- getLastModified path
if currentModified > currentLastModified
then do
putStrLn $ yellow ++ projectName ++ white ++ " Detected file modification. Rebuilding and running..."
oldHandle <- tryTakeMVar handleMVar
case oldHandle of
Just (Just handle) -> do
terminateProcess handle
_ <- waitForProcess handle
return ()
_ -> return ()
runScript script' path
loop currentModified
else loop currentLastModified
loop lastModified

main :: IO ()
main = do
Expand All @@ -66,16 +75,18 @@ main = do
putStrLn $ green ++ projectName ++ white ++ " Loaded settings from HaskMate.json"
loadSettings jsonPath
else do
putStrLn (yellow ++ projectName ++ white ++ " No HaskMate.json file found. Using default settings.")
return Nothing

let delayTime = maybe 1000000 id (delay =<< settings) -- use default if not found in settings
putStrLn (yellow ++ projectName ++ white ++ " No HaskMate.json file found. Using default settings.")
return Nothing
let delayTime = maybe 1000000 id (delay =<< settings)
let scriptType = case settings of
Just s -> script s
Nothing -> "ghc"

let fullPath = currentDir ++ "/" ++ scriptPath
putStrLn $ green ++ projectName ++ white ++ " Starting HaskMate v1.0.0..."
putStrLn $ green ++ projectName ++ white ++ " Running script in directory: " ++ fullPath
putStrLn $ green ++ projectName ++ white ++ " Watching for file modifications. Press " ++ red ++ "Ctrl+C" ++ white ++ " to exit."
lastModified <- getLastModified fullPath
handleMVar <- newEmptyMVar
monitorScript delayTime fullPath lastModified handleMVar
[] -> putStrLn "Please provide a file to monitor as an argument." >> putStrLn "Example: HaskMate app/Main.hs"
monitorScript delayTime fullPath lastModified handleMVar scriptType
[] -> putStrLn "Please provide a file to monitor as an argument." >> putStrLn "Example: HaskMate app/Main.hs"
2 changes: 2 additions & 0 deletions app/Settings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import System.Directory (doesFileExist)
data Settings = Settings
{ ignore :: [String]
, delay :: Maybe Int
, script :: String
} deriving (Show)

instance FromJSON Settings where
parseJSON = withObject "Settings" $ \v ->
Settings <$> v .: (fromString "ignore")
<*> v .:? (fromString "delay")
<*> v .: (fromString "script")

-- Load the settings from a JSON file
loadSettings :: FilePath -> IO (Maybe Settings)
Expand Down
2 changes: 1 addition & 1 deletion test/HaskMate.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"delay": 1000000,
"ignore": ["./logs.txt", "./src/loop.hs"],
"script": "ghc"
"script": "stack"
}
File renamed without changes.
14 changes: 14 additions & 0 deletions test/stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
resolver: lts-18.20

packages:
- .

extra-deps: []

flags: {}

extra-package-dbs: []

system-ghc: true

arch: x86_64
22 changes: 22 additions & 0 deletions test/test.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
cabal-version: 3.0
name: test
version: 0.1.0.0
synopsis: Haskell File Monitor test script
homepage: https://github.com/Frost-Lord/HaskMate

author: Frost Lord
maintainer: 51778028+Frost-Lord@users.noreply.github.com

category: System
build-type: Simple
extra-doc-files: CHANGELOG.md

common warnings
ghc-options: -Wall

executable HaskMate
import: warnings
main-is: test.hs
build-depends: base
hs-source-dirs: app
default-language: Haskell2010

0 comments on commit c6872d6

Please sign in to comment.