summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhallgren <hallgren@chalmers.se>2013-11-19 15:18:58 +0000
committerhallgren <hallgren@chalmers.se>2013-11-19 15:18:58 +0000
commitddac5f9e5aa935f4c154253831a36e49a48cdc8d (patch)
treea58846318676f398077d4779fd15d3a589eed2ec
parent5b83da558327b53e857ba88f91cba76821ecf763 (diff)
GF shell: improved system_pipe (aka "?") command
1. No temporary files are created. 2. The output of a system command is read lazily, making it feasible to process large or even infinite output, e.g. the following works as expected: ? "yes" | ? "head -5" | ps -lextext
-rw-r--r--src/compiler/GF/Command/Commands.hs6
-rw-r--r--src/compiler/GF/System/Process.hs18
2 files changed, 23 insertions, 1 deletions
diff --git a/src/compiler/GF/Command/Commands.hs b/src/compiler/GF/Command/Commands.hs
index 0d1b9695a..44d514a2f 100644
--- a/src/compiler/GF/Command/Commands.hs
+++ b/src/compiler/GF/Command/Commands.hs
@@ -46,6 +46,7 @@ import Data.List(intersperse,nub)
import Data.Maybe
import qualified Data.Map as Map
--import System.Cmd(system) -- use GF.Infra.UseIO.restricedSystem instead!
+import GF.System.Process
import Text.PrettyPrint
import Data.List (sort)
--import Debug.Trace
@@ -866,12 +867,15 @@ allCommands = Map.fromList [
synopsis = "send argument to a system command",
syntax = "sp -command=\"SYSTEMCOMMAND\", alt. ? SYSTEMCOMMAND",
exec = \_ opts arg -> do
+ let syst = optComm opts -- ++ " " ++ tmpi
+ {-
let tmpi = "_tmpi" ---
let tmpo = "_tmpo"
restricted $ writeFile tmpi $ toString arg
- let syst = optComm opts -- ++ " " ++ tmpi
restrictedSystem $ syst ++ " <" ++ tmpi ++ " >" ++ tmpo
fmap fromString $ restricted $ readFile tmpo,
+ -}
+ fmap fromString . restricted . readShellProcess syst $ toString arg,
flags = [
("command","the system command applied to the argument")
],
diff --git a/src/compiler/GF/System/Process.hs b/src/compiler/GF/System/Process.hs
new file mode 100644
index 000000000..415f8a50a
--- /dev/null
+++ b/src/compiler/GF/System/Process.hs
@@ -0,0 +1,18 @@
+module GF.System.Process where
+import System.Process
+import System.IO(hGetContents,hClose,hPutStr)
+import Control.Concurrent(forkIO)
+import GF.System.Catch(try)
+
+-- | Feed some input to a shell process and read the output lazily
+readShellProcess :: String -- ^ shell command
+ -> String -- ^ input to shell command
+ -> IO String -- ^ output from shell command
+readShellProcess cmd input =
+ do (Just stdin,Just stdout,Nothing,ph) <-
+ createProcess (shell cmd){std_in=CreatePipe,std_out=CreatePipe}
+ forkIO $ do try $ hPutStr stdin input
+ try $ hClose stdin
+ waitForProcess ph
+ return ()
+ hGetContents stdout