Search code examples
haskellpostscotty

Execute shell script from a POST request with scotty


I'm using scotty and I'm getting the same type error any way I try to execute a shell script from a POST request.

main = scotty 3000 $ do    
  post "MyPage/ScriptTime/run" $ do
      aparameter <- param "aparameter"
      bparameter <- param "bparameter"
      cparameter <- param "cparameter"
      dparameter <- param "dparameter"
      eparameter <- param "eparameter"
      rawSystem "./shellscript.sh" [ "-a"
                                   , aparameter
                                   , "-b"
                                   , bparameter
                                   , "-c"
                                   , cparameter
                                   , dparameter
                                   , eparameter
                                   ]

Using the answers on Is it possible to invoke bash or shell scripts from a haskell program? and Executing a system command in Haskell have not helped me change the error message.

The error reads:

Main.hs:68:5: error:
• Couldn't match type ‘IO’
                 with ‘Web.Scotty.Internal.Types.ActionT
                         Data.Text.Internal.Lazy.Text IO’
  Expected type: Web.Scotty.Internal.Types.ActionT
                   Data.Text.Internal.Lazy.Text IO ()
    Actual type: IO GHC.IO.Exception.ExitCode
• In a stmt of a 'do' block:
    rawSystem "./shellscript.sh" ["-a", aparameter, "-b", bparameter, ....]
  In the second argument of ‘($)’, namely
    ‘do aparameter <- param "aparameter"
        bparameter <- param "bparameter"
        cparameter <- param "cparameter"
        dparameter <- param "dparameter"
        ....’

I've changed the function and library used for invoking the shell script several ways, including:

() <- createProcess (proc "./shellscript.sh" ["-a", aparameter, "-b", bparameter, ...])

runProcess (shell "./shellscript.sh -a aparameter -b bparameter ...") >>= print

I have tried using System.Process, System.Process.Typed, and System.Cmd libraries.

Can someone help me understand my type mismatch.


Solution

  • The mismatch is in the monad in which the functions run. rawSystem runs in the IO monad, as indicated by its type, as well as in the error message. But scotty's run function expects a thing that runs in the ActionT e m monad.

    The error message tells you as much: cannot match type IO _ with ActionT Text IO _.

    Since ActionT has an instance of MonadTrans, you can just lift an IO function into ActionT _ IO:

    lift $ rawSystem "./shellscript.sh" [...]
    

    After you have done that, your next problem will be the return type: rawSystem returns an ExitCode, while scotty's run function expects unit. If you're ok just throwing away the exit code (though I don't recomment it), you can either bind it to an unnamed variable:

    _ <- lift $ rawSystem ...
    pure ()
    

    Or, better yet, you can use void to discard the value:

    void . lift $ rawSystem ...