Allow specifying an entire script

This commit is contained in:
Tom Sydney Kerckhove 2022-03-06 18:46:08 +01:00
parent 370303ca97
commit 727a18d349
5 changed files with 74 additions and 27 deletions

View File

@ -1,5 +1,5 @@
loops:
ci: nix-build ci.nix --no-out-link
install: stack build --fast --exec='feedback --help' --no-nix --system-ghc --with-hpack hpack
install: stack install --fast --exec='feedback --help' --no-nix --system-ghc --with-hpack hpack
test: stack build --fast --exec='feedback-test --debug ci' --no-nix --system-ghc --with-hpack hpack

View File

@ -33,7 +33,7 @@ data LoopSettings = LoopSettings
deriving (Show, Eq, Generic)
data RunSettings = RunSettings
{ runSettingCommand :: !String,
{ runSettingCommand :: !Command,
runSettingExtraEnv :: !(Map String String)
}
deriving (Show, Eq, Generic)
@ -73,7 +73,7 @@ instance HasCodec Configuration where
<*> optionalField "output" "default output configuration" .= configOutputConfiguration
data LoopConfiguration = LoopConfiguration
{ loopConfigCommand :: !String,
{ loopConfigCommand :: !Command,
loopConfigExtraEnv :: !(Map String String),
loopConfigOutputConfiguration :: !(Maybe OutputConfiguration)
}
@ -84,23 +84,23 @@ instance HasCodec LoopConfiguration where
codec =
named "LoopConfiguration" $
dimapCodec f g $
disjointEitherCodec codec $
eitherCodec (codec <?> "A bare command without any extra configuration") $
object "LoopConfiguration" $
LoopConfiguration
<$> requiredField "command" "the command to run on change" .= loopConfigCommand
<$> commandObjectCodec .= loopConfigCommand
<*> optionalFieldWithOmittedDefault "env" M.empty "extra environment variables to set" .= loopConfigExtraEnv
<*> optionalField "output" "output configuration for this loop" .= loopConfigOutputConfiguration
where
f = \case
Left c -> makeLoopConfiguration c
Left s -> makeLoopConfiguration (CommandArgs s)
Right loopConfig -> loopConfig
g loopConfig =
let c = loopConfigCommand loopConfig
in if loopConfig == makeLoopConfiguration c
then Left c
else Right loopConfig
in case c of
CommandArgs cmd | loopConfig == makeLoopConfiguration c -> Left cmd
_ -> Right loopConfig
makeLoopConfiguration :: String -> LoopConfiguration
makeLoopConfiguration :: Command -> LoopConfiguration
makeLoopConfiguration c =
LoopConfiguration
{ loopConfigCommand = c,
@ -217,24 +217,45 @@ parseFlags =
]
)
)
<*> ( unwords
<$> many
( strArgument
( mconcat
[ help "The command to run",
metavar "COMMAND"
]
)
)
)
<*> parseCommandFlags
<*> parseOutputFlags
<*> switch (mconcat [long "debug", help "show debug information"])
parseCommandFlags :: OptParse.Parser String
parseCommandFlags =
let commandArg =
strArgument
( mconcat
[ help "The command to run",
metavar "COMMAND"
]
)
in unwords <$> some commandArg
parseOutputFlags :: OptParse.Parser OutputFlags
parseOutputFlags =
OutputFlags
<$> parseClearFlag
data Command
= CommandArgs !String
| CommandScript !String
deriving (Show, Eq, Generic)
commandObjectCodec :: JSONObjectCodec Command
commandObjectCodec =
dimapCodec f g $
eitherCodec
(requiredField "command" "the command to run on change")
(requiredField "script" "the script to run on change")
where
f = \case
Left c -> CommandArgs c
Right s -> CommandScript s
g = \case
CommandArgs c -> Left c
CommandScript s -> Right s
data Clear = ClearScreen | DoNotClearScreen
deriving (Show, Eq, Generic)

View File

@ -32,11 +32,18 @@ commandChunk = fore blue . chunk . T.pack
startingLines :: RunSettings -> [[Chunk]]
startingLines RunSettings {..} =
concat
[ [ [ indicatorChunk "starting",
" ",
commandChunk runSettingCommand
]
],
[ case runSettingCommand of
CommandArgs command ->
[ [ indicatorChunk "starting",
" ",
commandChunk command
]
]
CommandScript script ->
[ [ indicatorChunk "starting script\n",
chunk $ T.pack script
]
],
[ [ indicatorChunk "extra env",
" ",
chunk $ T.pack $ show $ M.toList runSettingExtraEnv

View File

@ -3,11 +3,16 @@
module Feedback.Common.Process where
import Data.Map as M
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Feedback.Common.OptParse
import Path
import Path.IO
import System.Environment as System (getEnvironment)
import System.Exit
import System.Process.Typed as Typed
import UnliftIO
import UnliftIO.IO.File
data ProcessHandle = ProcessHandle
{ processHandleProcess :: !P,
@ -34,12 +39,26 @@ makeProcessConfigFor :: RunSettings -> IO (ProcessConfig () () ())
makeProcessConfigFor RunSettings {..} = do
env <- System.getEnvironment
let envForProcess = M.toList $ M.union runSettingExtraEnv (M.fromList env)
commandString <- case runSettingCommand of
CommandArgs c -> pure c
CommandScript s -> do
-- Write the script to a file
systemTempDir <- getTempDir
scriptFile <- resolveFile systemTempDir "feedback-script.sh"
writeBinaryFileDurableAtomic (fromAbsFile scriptFile) (TE.encodeUtf8 (T.pack s))
-- Make the script executable
oldPermissions <- getPermissions scriptFile
let newPermissions = setOwnerExecutable True oldPermissions
setPermissions scriptFile newPermissions
pure $ fromAbsFile scriptFile
pure $
setStdout inherit
. setStderr inherit
. setStdin closed -- TODO make this configurable?
. setEnv envForProcess
$ shell runSettingCommand
$ shell commandString
stopProcessHandle :: ProcessHandle -> IO ()
stopProcessHandle ProcessHandle {..} = do

View File

@ -26,7 +26,7 @@ combineToSettings flags@Flags {..} environment mConf = do
show flagCommand <> ",",
"interpreting it as a standalone command."
]
pure $ makeLoopConfiguration flagCommand
pure $ makeLoopConfiguration $ CommandArgs flagCommand
Just config -> do
putStrLn $
unwords