on master help sign in
Use custom 'ProcessSpec' type to facilitate custom process environments
commit14fb243eecdbfcc18b76ae2809378906737a3033 authorElliot Cameron <eacameron@gmail.com> dateTue 24 Dec 2019, 23:57 (7 years ago) parent9543601
12 files changed+113−72
lib/cliapp/obelisk-cliapp.cabal+1 lib/cliapp/src/Obelisk/CliApp.hs+13−6 lib/cliapp/src/Obelisk/CliApp/Demo.hs−1 lib/cliapp/src/Obelisk/CliApp/Process.hs+81−34 lib/command/src/Obelisk/Command.hs+2−2 lib/command/src/Obelisk/Command/Deploy.hs+5−6 lib/command/src/Obelisk/Command/Nix.hs−1 lib/command/src/Obelisk/Command/Project.hs+2−8 lib/command/src/Obelisk/Command/Run.hs+1−2 lib/command/src/Obelisk/Command/Thunk.hs−1 lib/command/src/Obelisk/Command/Utils.hs+8−10 lib/command/src/Obelisk/Command/VmBuilder.hs−1
lib/cliapp/obelisk-cliapp.cabal+1
@@ -10,6 +10,7 @@ library
1010 ansi-terminal
1111 , base
1212 , bytestring
13+ , containers
1314 , exceptions
1415 , io-streams
1516 , lens
lib/cliapp/src/Obelisk/CliApp.hs+13−6
@@ -33,16 +33,23 @@ module Obelisk.CliApp
3333 , Severity (..)
3434
3535 -- .Process
36− , ProcessFailure (..)
3736 , AsProcessFailure (..)
38− , readProcessAndLogStderr
39− , readProcessAndLogOutput
40− , readCreateProcessWithExitCode
37+ , ProcessFailure (..)
38+ , ProcessSpec (..)
39+ , callCommand
40+ , callProcess
4141 , callProcessAndLogOutput
4242 , createProcess_
43− , callProcess
44− , callCommand
43+ , overCreateProcess
44+ , proc
45+ , readCreateProcessWithExitCode
46+ , readProcessAndLogOutput
47+ , readProcessAndLogStderr
4548 , reconstructCommand
49+ , setCwd
50+ , setDelegateCtlc
51+ , setEnvOverride
52+ , shell
4653 ) where
4754
4855import Control.Monad.Log (Severity (..))
lib/cliapp/src/Obelisk/CliApp/Demo.hs−1
@@ -8,7 +8,6 @@ import Control.Monad.Fail
88import Control.Monad.IO.Class
99import Data.Semigroup ((<>))
1010import qualified Data.Text as T
11−import System.Process (proc)
1211
1312import Control.Monad.Catch (MonadMask)
1413
lib/cliapp/src/Obelisk/CliApp/Process.hs+81−34
@@ -9,17 +9,24 @@
99-- | An extension of `System.Process` that integrates with logging (`Obelisk.CLI.Logging`)
1010-- and is thus spinner friendly.
1111module Obelisk.CliApp.Process
12− ( ProcessFailure (..)
13− , AsProcessFailure (..)
14− , readProcessAndLogStderr
15− , readProcessAndLogOutput
16− , readCreateProcessWithExitCode
12+ ( AsProcessFailure (..)
13+ , ProcessFailure (..)
14+ , ProcessSpec (..)
15+ , callCommand
16+ , callProcess
1717 , callProcessAndLogOutput
1818 , createProcess
1919 , createProcess_
20− , callProcess
21− , callCommand
20+ , overCreateProcess
21+ , proc
22+ , readCreateProcessWithExitCode
23+ , readProcessAndLogOutput
24+ , readProcessAndLogStderr
2225 , reconstructCommand
26+ , setCwd
27+ , setDelegateCtlc
28+ , setEnvOverride
29+ , shell
2330 ) where
2431
2532import Control.Monad ((<=<), join, void)
@@ -30,24 +37,50 @@ import Control.Lens (Prism', review)
3037import qualified Data.ByteString as BS
3138import qualified Data.ByteString.Char8 as BSC
3239import Data.Function (fix)
40+import Data.Map (Map)
41+import qualified Data.Map as Map
3342import Data.Monoid ((<>))
3443import Data.Text (Text)
3544import qualified Data.Text as T
3645import qualified Data.Text.Encoding as T
3746import Data.Text.Encoding.Error (lenientDecode)
47+import System.Environment (getEnvironment)
3848import System.Exit (ExitCode (..))
3949import System.IO (Handle)
4050import System.IO.Streams (InputStream, handleToInputStream)
4151import qualified System.IO.Streams as Streams
4252import System.IO.Streams.Concurrent (concurrentMerge)
43−import System.Process (CreateProcess, ProcessHandle, StdStream (CreatePipe), cmdspec, std_err, std_out,
44− waitForProcess)
53+import System.Process (CreateProcess, ProcessHandle, StdStream (CreatePipe), std_err, std_out, waitForProcess)
4554import qualified System.Process as Process
4655
4756import Control.Monad.Log (Severity (..))
4857import Obelisk.CliApp.Logging (putLog, putLogRaw)
4958import Obelisk.CliApp.Types (CliLog, CliThrow)
5059
60+data ProcessSpec = ProcessSpec
61+ { _processSpec_createProcess :: !CreateProcess
62+ , _processSpec_overrideEnv :: !(Maybe (Map String String -> Map String String))
63+ }
64+
65+proc :: FilePath -> [String] -> ProcessSpec
66+proc cmd args = ProcessSpec (Process.proc cmd args) Nothing
67+
68+shell :: String -> ProcessSpec
69+shell cmd = ProcessSpec (Process.shell cmd) Nothing
70+
71+setEnvOverride :: (Map String String -> Map String String) -> ProcessSpec -> ProcessSpec
72+setEnvOverride f p = p { _processSpec_overrideEnv = Just f }
73+
74+overCreateProcess :: (CreateProcess -> CreateProcess) -> ProcessSpec -> ProcessSpec
75+overCreateProcess f (ProcessSpec p x) = ProcessSpec (f p) x
76+
77+setDelegateCtlc :: Bool -> ProcessSpec -> ProcessSpec
78+setDelegateCtlc b = overCreateProcess (\p -> p { Process.delegate_ctlc = b })
79+
80+setCwd :: Maybe FilePath -> ProcessSpec -> ProcessSpec
81+setCwd fp = overCreateProcess (\p -> p { Process.cwd = fp })
82+
83+
5184-- TODO put back in `Obelisk.CliApp.Process` and use prisms for extensible exceptions
5285data ProcessFailure = ProcessFailure Process.CmdSpec Int -- exit code
5386 deriving Show
@@ -62,7 +95,7 @@ instance AsProcessFailure ProcessFailure where
6295
6396readProcessAndLogStderr
6497 :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e, MonadFail m)
65− => Severity -> CreateProcess -> m Text
98+ => Severity -> ProcessSpec -> m Text
6699readProcessAndLogStderr sev process = do
67100 (out, _err) <- withProcess process $ \_out err -> do
68101 streamToLog =<< liftIO (streamHandle sev err)
@@ -70,9 +103,10 @@ readProcessAndLogStderr sev process = do
70103
71104readCreateProcessWithExitCode
72105 :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e)
73− => CreateProcess -> m (ExitCode, String, String)
74−readCreateProcessWithExitCode process = do
75− putLog Debug $ "Creating process: " <> reconstructCommand (cmdspec process)
106+ => ProcessSpec -> m (ExitCode, String, String)
107+readCreateProcessWithExitCode procSpec = do
108+ process <- mkCreateProcess procSpec
109+ putLog Debug $ "Creating process: " <> reconstructProcSpec procSpec
76110 liftIO $ Process.readCreateProcessWithExitCode process ""
77111
78112-- | Like `System.Process.readProcess` but logs the combined output (stdout and stderr)
@@ -84,10 +118,10 @@ readCreateProcessWithExitCode process = do
84118-- `callProcessAndLogOutput (Debug, Debug)`.
85119readProcessAndLogOutput
86120 :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e, MonadFail m)
87− => (Severity, Severity) -> CreateProcess -> m Text
121+ => (Severity, Severity) -> ProcessSpec -> m Text
88122readProcessAndLogOutput (sev_out, sev_err) process = do
89− (_, Just out, Just err, p) <- createProcess $ process
90− { std_out = CreatePipe , std_err = CreatePipe }
123+ (_, Just out, Just err, p) <- createProcess $ overCreateProcess
124+ (\p -> p { std_out = CreatePipe , std_err = CreatePipe }) process
91125
92126 -- TODO interleave stdout and stderr in log correctly
93127 streamToLog =<< liftIO (streamHandle sev_err err)
@@ -96,9 +130,9 @@ readProcessAndLogOutput (sev_out, sev_err) process = do
96130
97131 liftIO (waitForProcess p) >>= \case
98132 ExitSuccess -> pure outText
99− ExitFailure code -> throwError $ review asProcessFailure $ ProcessFailure (cmdspec process) code
133+ ExitFailure code -> throwError $ review asProcessFailure $ ProcessFailure (Process.cmdspec $ _processSpec_createProcess process) code
100134
101−-- | Like `System.Process.callProcess` but logs the combined output (stdout and stderr)
135+-- | Like 'System.Process.callProcess' but logs the combined output (stdout and stderr)
102136-- with the corresponding severity.
103137--
104138-- Usually this function is called as `callProcessAndLogOutput (Debug, Error)`. However
@@ -106,9 +140,8 @@ readProcessAndLogOutput (sev_out, sev_err) process = do
106140-- which case it is advisable to call it with a non-Error severity for stderr, like
107141-- `callProcessAndLogOutput (Debug, Debug)`.
108142callProcessAndLogOutput
109−
110143 :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e, MonadFail m)
111− => (Severity, Severity) -> CreateProcess -> m ()
144+ => (Severity, Severity) -> ProcessSpec -> m ()
112145callProcessAndLogOutput (sev_out, sev_err) process =
113146 void $ withProcess process $ \out err -> do
114147 stream <- liftIO $ join $ combineStream
@@ -118,21 +151,31 @@ callProcessAndLogOutput (sev_out, sev_err) process =
118151 where
119152 combineStream s1 s2 = concurrentMerge [s1, s2]
120153
121−-- | Like `System.Process.createProcess` but also logs (debug) the process being run
154+-- | Like 'System.Process.createProcess' but also logs (debug) the process being run
122155createProcess
123156 :: (MonadIO m, CliLog m)
124− => CreateProcess -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
125−createProcess p = do
126− putLog Debug $ "Creating process: " <> reconstructCommand (cmdspec p)
157+ => ProcessSpec -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
158+createProcess procSpec = do
159+ p <- mkCreateProcess procSpec
160+ putLog Debug $ "Creating process: " <> reconstructProcSpec procSpec
127161 liftIO $ Process.createProcess p
128162
129163-- | Like `System.Process.createProcess_` but also logs (debug) the process being run
130164createProcess_
131165 :: (MonadIO m, CliLog m)
132− => String -> CreateProcess -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
133−createProcess_ name p = do
134− putLog Debug $ "Creating process " <> T.pack name <> ": " <> reconstructCommand (cmdspec p)
135− liftIO $ Process.createProcess p
166+ => String -> ProcessSpec -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
167+createProcess_ name procSpec = do
168+ p <- mkCreateProcess procSpec
169+ putLog Debug $ "Creating process " <> T.pack name <> ": " <> reconstructProcSpec procSpec
170+ liftIO $ Process.createProcess_ name p
171+
172+mkCreateProcess :: MonadIO m => ProcessSpec -> m Process.CreateProcess
173+mkCreateProcess (ProcessSpec p override') = do
174+ case override' of
175+ Nothing -> pure p
176+ Just override -> do
177+ procEnv <- Map.fromList <$> maybe (liftIO getEnvironment) pure (Process.env p)
178+ pure $ p { Process.env = Just $ Map.toAscList (override procEnv) }
136179
137180-- | Like `System.Process.callProcess` but also logs (debug) the process being run
138181callProcess
@@ -152,17 +195,17 @@ callCommand cmd = do
152195
153196withProcess
154197 :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e, MonadFail m)
155− => CreateProcess -> (Handle -> Handle -> m ()) -> m (Handle, Handle)
198+ => ProcessSpec -> (Handle -> Handle -> m ()) -> m (Handle, Handle)
156199withProcess process f = do -- TODO: Use bracket.
157200 -- FIXME: Using `withCreateProcess` here leads to something operating illegally on closed handles.
158− (_, Just out, Just err, p) <- createProcess $ process
159− { std_out = CreatePipe , std_err = CreatePipe }
201+ (_, Just out, Just err, p) <- createProcess $ overCreateProcess
202+ (\x -> x { std_out = CreatePipe , std_err = CreatePipe }) process
160203
161204 f out err -- Pass the handles to the passed function
162205
163206 liftIO (waitForProcess p) >>= \case
164207 ExitSuccess -> return (out, err)
165− ExitFailure code -> throwError $ review asProcessFailure $ ProcessFailure (cmdspec process) code
208+ ExitFailure code -> throwError $ review asProcessFailure $ ProcessFailure (Process.cmdspec $ _processSpec_createProcess process) code
166209
167210-- Create an input stream from the file handle, associating each item with the given severity.
168211streamHandle :: Severity -> Handle -> IO (InputStream (Severity, BSC.ByteString))
@@ -179,8 +222,12 @@ streamToLog stream = fix $ \loop -> do
179222
180223-- | Pretty print a 'CmdSpec'
181224reconstructCommand :: Process.CmdSpec -> Text
182−reconstructCommand (Process.ShellCommand str) = T.pack str
183−reconstructCommand (Process.RawCommand c as) = processToShellString c as
225+reconstructCommand p = case p of
226+ Process.ShellCommand str -> T.pack str
227+ Process.RawCommand c as -> processToShellString c as
184228 where
185229 processToShellString cmd args = T.unwords $ map quoteAndEscape (cmd : args)
186230 quoteAndEscape x = "'" <> T.replace "'" "'\''" (T.pack x) <> "'"
231+
232+reconstructProcSpec :: ProcessSpec -> Text
233+reconstructProcSpec = reconstructCommand . Process.cmdspec . _processSpec_createProcess
lib/command/src/Obelisk/Command.hs+2−2
@@ -398,8 +398,8 @@ ob = \case
398398 ObCommand_Watch -> inNixShell' $ static runWatch
399399 ObCommand_Shell so -> withProjectRoot "." $ \root ->
400400 projectShell root False (_shellOpts_shell so) (_shellOpts_command so)
401− ObCommand_Doc shell pkgs -> withProjectRoot "." $ \root ->
402− projectShell root False shell (Just $ haddockCommand pkgs)
401+ ObCommand_Doc shell' pkgs -> withProjectRoot "." $ \root ->
402+ projectShell root False shell' (Just $ haddockCommand pkgs)
403403 ObCommand_Internal icmd -> case icmd of
404404 ObInternal_RunStaticIO k -> liftIO (unsafeLookupStaticPtr @(ObeliskT IO ()) k) >>= \case
405405 Nothing -> failWith $ "ObInternal_RunStaticIO: no such StaticKey: " <> T.pack (show k)
lib/command/src/Obelisk/Command/Deploy.hs+5−6
@@ -25,17 +25,17 @@ import Nix.Pretty
2525import Nix.String (principledMakeNixStringWithoutContext)
2626import Nix.Value
2727import System.Directory
28−import System.Environment (getEnvironment)
2928import System.FilePath
3029import System.IO
3130import System.Posix.Files
32−import System.Process (delegate_ctlc, env, proc, cwd)
3331import Text.URI (URI)
3432import qualified Text.URI as URI
3533import Text.URI.Lens
3634
3735import Obelisk.App (MonadObelisk)
38−import Obelisk.CliApp (Severity (..), callProcessAndLogOutput, failWith, putLog, withSpinner)
36+import Obelisk.CliApp (
37+ Severity (..), callProcessAndLogOutput, failWith, proc, putLog,
38+ setCwd, setDelegateCtlc, setEnvOverride, withSpinner)
3939import Obelisk.Command.Nix
4040import Obelisk.Command.Project
4141import Obelisk.Command.Thunk
@@ -165,8 +165,7 @@ deployPush deployPath getNixBuilders = do
165165 putLog Notice $ "Deployed => " <> T.pack route
166166 where
167167 callProcess' envMap cmd args = do
168− processEnv <- Map.toList . (envMap <>) . Map.fromList <$> liftIO getEnvironment
169− let p = (proc cmd args) { delegate_ctlc = True, env = Just processEnv }
168+ let p = setEnvOverride (envMap <>) $ setDelegateCtlc True $ proc cmd args
170169 callProcessAndLogOutput (Notice, Notice) p
171170
172171deployUpdate :: MonadObelisk m => FilePath -> m ()
@@ -275,7 +274,7 @@ instance ToJSON KeytoolConfig
275274createKeystore :: MonadObelisk m => FilePath -> KeytoolConfig -> m ()
276275createKeystore root config = do
277276 let expr = "with (import " <> toImplDir root <> ").reflex-platform.nixpkgs; pkgs.mkShell { buildInputs = [ pkgs.jdk ]; }"
278− callProcessAndLogOutput (Notice,Notice) $ (proc "nix-shell" ["default.nix", "-E" , expr, "--run" , keytoolCmd]) { cwd = Just root }
277+ callProcessAndLogOutput (Notice,Notice) $ setCwd (Just root) $ proc "nix-shell" ["default.nix", "-E" , expr, "--run" , keytoolCmd]
279278 where
280279 keytoolCmd = processToShellString "keytool"
281280 [ "-genkeypair", "-noprompt"
lib/command/src/Obelisk/Command/Nix.hs−1
@@ -37,7 +37,6 @@ import Data.List (intercalate)
3737import Data.Maybe
3838import Data.Monoid ((<>))
3939import qualified Data.Text as T
40−import System.Process (proc)
4140
4241import Obelisk.App (MonadObelisk)
4342import Obelisk.CliApp
lib/command/src/Obelisk/Command/Project.hs+2−8
@@ -30,7 +30,7 @@ import System.IO.Temp
3030import System.IO.Unsafe (unsafePerformIO)
3131import System.Posix (FileStatus, FileMode, CMode (..), UserID, deviceID, fileID, fileMode, fileOwner, getFileStatus, getRealUserID)
3232import System.Posix.Files
33−import System.Process (CreateProcess, cwd, proc, waitForProcess, delegate_ctlc)
33+import System.Process (waitForProcess)
3434import System.Which (staticWhich)
3535
3636import GitHub.Data.GitData (Branch)
@@ -248,7 +248,7 @@ projectShell root isPure shellName command = do
248248 let nixPath = $(staticWhich "nix")
249249 nixpkgsPath <- fmap T.strip $ readProcessAndLogStderr Debug $ setCwd (Just root) $ proc nixPath ["eval", "(import .obelisk/impl {}).nixpkgs.path"]
250250 nixRemote <- liftIO $ lookupEnv "NIX_REMOTE"
251− (_, _, _, ph) <- createProcess_ "runNixShellAttr" $ setCtlc $ setCwd (Just root) $ proc "nix-shell" $
251+ (_, _, _, ph) <- createProcess_ "runNixShellAttr" $ setDelegateCtlc True $ setCwd (Just root) $ proc "nix-shell" $
252252 [ "default.nix"] <>
253253 ["--pure" | isPure] <>
254254 [ "-A"
@@ -263,9 +263,3 @@ projectShell root isPure shellName command = do
263263 c
264264 ]
265265 void $ liftIO $ waitForProcess ph
266−
267−setCtlc :: CreateProcess -> CreateProcess
268−setCtlc cfg = cfg { delegate_ctlc = True }
269−
270−setCwd :: Maybe FilePath -> CreateProcess -> CreateProcess
271−setCwd fp cfg = cfg { cwd = fp }
lib/command/src/Obelisk/Command/Run.hs+1−2
@@ -31,7 +31,6 @@ import Language.Haskell.Extension
3131import Network.Socket hiding (Debug)
3232import System.Directory
3333import System.FilePath
34−import System.Process (proc)
3534import System.IO.Temp (withSystemTempDirectory)
3635import System.Which (staticWhich)
3736import Data.ByteString (ByteString)
@@ -39,7 +38,7 @@ import Data.ByteString (ByteString)
3938import Obelisk.App (MonadObelisk, ObeliskT)
4039import Obelisk.CliApp
4140 ( CliT (..), HasCliConfig, Severity (..)
42− , callCommand, failWith, getCliConfig, putLog
41+ , callCommand, failWith, getCliConfig, putLog, proc
4342 , readProcessAndLogStderr, runCli)
4443import Obelisk.Command.Project (inProjectShell, withProjectRoot)
4544
lib/command/src/Obelisk/Command/Thunk.hs−1
@@ -71,7 +71,6 @@ import System.FilePath
7171import System.IO.Error
7272import System.IO.Temp
7373import System.Posix (getSymbolicLinkStatus, modificationTime)
74−import System.Process (proc)
7574import Text.URI
7675
7776import Obelisk.App (MonadObelisk)
lib/command/src/Obelisk/Command/Utils.hs+8−10
@@ -23,7 +23,6 @@ import Data.Void (Void)
2323import System.Directory (canonicalizePath)
2424import System.Environment (getExecutablePath)
2525import System.Exit (ExitCode)
26−import qualified System.Process as P
2726import Text.Megaparsec as MP
2827import Text.Megaparsec.Char as MP
2928
@@ -61,11 +60,10 @@ initGit repo = do
6160 git ["add", "."]
6261 git ["commit", "-m", "Initial commit."]
6362
64−gitProcNoRepo :: [String] -> P.CreateProcess
65−gitProcNoRepo = P.proc "git"
63+gitProcNoRepo :: [String] -> ProcessSpec
64+gitProcNoRepo args = setEnvOverride (M.singleton "GIT_TERMINAL_PROMPT" "0" <>) $ proc "git" args
6665
67−-- TODO: GIT_TERMINAL_PROMPT=0
68−gitProc :: FilePath -> [String] -> P.CreateProcess
66+gitProc :: FilePath -> [String] -> ProcessSpec
6967gitProc repo = gitProcNoRepo . runGitInDir
7068 where
7169 runGitInDir args' = case filter (not . null) args' of
@@ -73,9 +71,9 @@ gitProc repo = gitProcNoRepo . runGitInDir
7371 args -> ["-C", repo] <> args
7472
7573-- | Recursively copy a directory using `cp -a` -- TODO: Should use -rT instead of -a
76−copyDir :: FilePath -> FilePath -> P.CreateProcess
74+copyDir :: FilePath -> FilePath -> ProcessSpec
7775copyDir src dest =
78− (P.proc "cp" ["-a", ".", dest]) { P.cwd = Just src } -- TODO: This will break if dest is relative since we change cwd
76+ setCwd (Just src) $ proc "cp" ["-a", ".", dest] -- TODO: This will break if dest is relative since we change cwd
7977
8078readGitProcess :: MonadObelisk m => FilePath -> [String] -> m Text
8179readGitProcess repo = readProcessAndLogOutput (Debug, Notice) . gitProc repo
@@ -88,15 +86,15 @@ processToShellString cmd args = unwords $ map quoteAndEscape (cmd : args)
8886 where quoteAndEscape x = T.unpack $ "'" <> T.replace "'" "'\''" (T.pack x) <> "'"
8987
9088-- | A simpler wrapper for CliApp's most used process function with sensible defaults.
91−runProc :: MonadObelisk m => P.CreateProcess -> m ()
89+runProc :: MonadObelisk m => ProcessSpec -> m ()
9290runProc = callProcessAndLogOutput (Notice, Error)
9391
9492-- | Like runProc, but all output goes to Debug logging level
95−runProcSilently :: MonadObelisk m => P.CreateProcess -> m ()
93+runProcSilently :: MonadObelisk m => ProcessSpec -> m ()
9694runProcSilently = callProcessAndLogOutput (Debug, Debug)
9795
9896-- | A simpler wrapper for CliApp's readProcessAndLogStderr with sensible defaults.
99−readProc :: MonadObelisk m => P.CreateProcess -> m Text
97+readProc :: MonadObelisk m => ProcessSpec -> m Text
10098readProc = readProcessAndLogOutput (Debug, Error)
10199
102100tshow :: Show a => a -> Text
lib/command/src/Obelisk/Command/VmBuilder.hs−1
@@ -18,7 +18,6 @@ import System.Directory (createDirectoryIfMissing)
1818import System.Exit (ExitCode(..))
1919import System.FilePath ((<.>), (</>))
2020import qualified System.Info
21−import System.Process (proc)
2221
2322import Obelisk.App (MonadObelisk, getObeliskUserStateDir)
2423import Obelisk.CliApp