Make some commands work
This commit is contained in:
parent
c0e995043a
commit
b9488b7f49
5 changed files with 168 additions and 28 deletions
|
@ -30,8 +30,10 @@ common deps
|
||||||
, aeson-pretty
|
, aeson-pretty
|
||||||
, async
|
, async
|
||||||
, bytestring
|
, bytestring
|
||||||
|
, directory
|
||||||
, process
|
, process
|
||||||
, process-extras
|
, process-extras
|
||||||
|
, temporary
|
||||||
, text
|
, text
|
||||||
, protolude
|
, protolude
|
||||||
|
|
||||||
|
@ -43,6 +45,7 @@ library
|
||||||
import: deps
|
import: deps
|
||||||
exposed-modules: Arion.Nix
|
exposed-modules: Arion.Nix
|
||||||
Arion.Aeson
|
Arion.Aeson
|
||||||
|
Arion.DockerCompose
|
||||||
other-modules: Paths_arion_compose
|
other-modules: Paths_arion_compose
|
||||||
-- other-extensions:
|
-- other-extensions:
|
||||||
hs-source-dirs: src/haskell/lib
|
hs-source-dirs: src/haskell/lib
|
||||||
|
|
|
@ -28,6 +28,7 @@ in
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
haskellPkgs.cabal-install
|
haskellPkgs.cabal-install
|
||||||
haskellPkgs.ghcid
|
haskellPkgs.ghcid
|
||||||
|
super.docker-compose
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Protolude hiding (Down)
|
||||||
|
|
||||||
import Arion.Nix
|
import Arion.Nix
|
||||||
import Arion.Aeson
|
import Arion.Aeson
|
||||||
|
import qualified Arion.DockerCompose as DockerCompose
|
||||||
|
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
|
@ -131,29 +132,43 @@ commandDC run cmdStr help =
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
runDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
runDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
||||||
runDC cmd (DockerComposeArgs args) opts =
|
runDC cmd (DockerComposeArgs args) opts = do
|
||||||
panic $ "TODO: docker-compose " <> cmd <> " " <> T.unwords args
|
DockerCompose.run DockerCompose.Args
|
||||||
|
{ files = []
|
||||||
|
, otherArgs = [cmd] ++ args
|
||||||
|
}
|
||||||
|
|
||||||
runBuildAndDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
runBuildAndDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
||||||
runBuildAndDC cmd dopts opts = do
|
runBuildAndDC cmd dopts opts = do
|
||||||
T.putStrLn "TODO: build"
|
ea <- defaultEvaluationArgs opts
|
||||||
runDC cmd dopts opts
|
Arion.Nix.withBuiltComposition ea $ \path ->
|
||||||
|
DockerCompose.run DockerCompose.Args
|
||||||
|
{ files = [path]
|
||||||
|
, otherArgs = [cmd] ++ unDockerComposeArgs dopts
|
||||||
|
}
|
||||||
|
|
||||||
runEvalAndDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
runEvalAndDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
||||||
runEvalAndDC cmd dopts opts = do
|
runEvalAndDC cmd dopts opts = do
|
||||||
T.putStrLn "TODO: eval"
|
ea <- defaultEvaluationArgs opts
|
||||||
runDC cmd dopts opts
|
Arion.Nix.withEvaluatedComposition ea $ \path ->
|
||||||
|
DockerCompose.run DockerCompose.Args
|
||||||
|
{ files = [path]
|
||||||
|
, otherArgs = [cmd] ++ unDockerComposeArgs dopts
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultEvaluationArgs :: CommonOptions -> IO EvaluationArgs
|
||||||
|
defaultEvaluationArgs co = pure EvaluationArgs
|
||||||
|
{ evalUid = 0 -- TODO
|
||||||
|
, evalModules = files co
|
||||||
|
, evalPkgs = pkgs co
|
||||||
|
, evalWorkDir = Nothing
|
||||||
|
, evalMode = ReadWrite
|
||||||
|
, evalUserArgs = nixArgs co
|
||||||
|
}
|
||||||
|
|
||||||
runCat :: CommonOptions -> IO ()
|
runCat :: CommonOptions -> IO ()
|
||||||
runCat co = do
|
runCat co = do
|
||||||
v <- Arion.Nix.evaluateComposition EvaluationArgs
|
v <- Arion.Nix.evaluateComposition =<< defaultEvaluationArgs co
|
||||||
{ evalUid = 0 -- TODO
|
|
||||||
, evalModules = files co
|
|
||||||
, evalPkgs = pkgs co
|
|
||||||
, evalWorkDir = Nothing
|
|
||||||
, evalMode = ReadWrite
|
|
||||||
, evalUserArgs = nixArgs co
|
|
||||||
}
|
|
||||||
T.hPutStrLn stdout (pretty v)
|
T.hPutStrLn stdout (pretty v)
|
||||||
|
|
||||||
runRepl :: CommonOptions -> IO ()
|
runRepl :: CommonOptions -> IO ()
|
||||||
|
|
51
src/haskell/lib/Arion/DockerCompose.hs
Normal file
51
src/haskell/lib/Arion/DockerCompose.hs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
module Arion.DockerCompose where
|
||||||
|
|
||||||
|
import Prelude ( )
|
||||||
|
import Protolude
|
||||||
|
import Arion.Aeson ( pretty )
|
||||||
|
import Data.Aeson
|
||||||
|
import qualified Data.String
|
||||||
|
import System.Process
|
||||||
|
import qualified Data.ByteString as BS
|
||||||
|
import qualified Data.ByteString.Lazy as BL
|
||||||
|
import qualified System.Process.ByteString.Lazy
|
||||||
|
as PBL
|
||||||
|
import Paths_arion_compose
|
||||||
|
import Control.Applicative
|
||||||
|
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.IO as T
|
||||||
|
|
||||||
|
import qualified Data.List.NonEmpty as NE
|
||||||
|
import Data.List.NonEmpty ( NonEmpty(..) )
|
||||||
|
|
||||||
|
import Control.Arrow ( (>>>) )
|
||||||
|
import System.IO.Temp ( withTempFile )
|
||||||
|
import System.IO ( hClose )
|
||||||
|
|
||||||
|
data Args = Args
|
||||||
|
{ files :: [FilePath]
|
||||||
|
, otherArgs :: [Text]
|
||||||
|
}
|
||||||
|
|
||||||
|
run :: Args -> IO ()
|
||||||
|
run args = do
|
||||||
|
let fileArgs = files args >>= \f -> ["--file", f]
|
||||||
|
allArgs = fileArgs ++ map toS (otherArgs args)
|
||||||
|
|
||||||
|
procSpec = proc "docker-compose" allArgs
|
||||||
|
|
||||||
|
-- hPutStrLn stderr ("Running docker-compose with " <> show allArgs :: Text)
|
||||||
|
|
||||||
|
withCreateProcess procSpec $ \_in _out _err procHandle -> do
|
||||||
|
|
||||||
|
-- Wait for process exit and 'err' printout
|
||||||
|
exitCode <- waitForProcess procHandle
|
||||||
|
|
||||||
|
case exitCode of
|
||||||
|
ExitSuccess -> pass
|
||||||
|
ExitFailure 1 -> exitFailure
|
||||||
|
e@ExitFailure {} -> do
|
||||||
|
throwIO $ FatalError $ "docker-compose failed with " <> show exitCode
|
||||||
|
exitWith e
|
|
@ -1,10 +1,18 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module Arion.Nix where
|
module Arion.Nix
|
||||||
|
( evaluateComposition
|
||||||
|
, withEvaluatedComposition
|
||||||
|
, withBuiltComposition
|
||||||
|
, EvaluationArgs(..)
|
||||||
|
, EvaluationMode(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import Prelude ( )
|
import Prelude ( )
|
||||||
import Protolude
|
import Protolude
|
||||||
|
import Arion.Aeson ( pretty )
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import qualified Data.String
|
import qualified Data.String
|
||||||
|
import qualified System.Directory as Directory
|
||||||
import System.Process
|
import System.Process
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
|
@ -20,6 +28,8 @@ import qualified Data.List.NonEmpty as NE
|
||||||
import Data.List.NonEmpty ( NonEmpty(..) )
|
import Data.List.NonEmpty ( NonEmpty(..) )
|
||||||
|
|
||||||
import Control.Arrow ( (>>>) )
|
import Control.Arrow ( (>>>) )
|
||||||
|
import System.IO.Temp ( withTempFile )
|
||||||
|
import System.IO ( hClose )
|
||||||
|
|
||||||
data EvaluationMode =
|
data EvaluationMode =
|
||||||
ReadWrite | ReadOnly
|
ReadWrite | ReadOnly
|
||||||
|
@ -35,7 +45,7 @@ data EvaluationArgs = EvaluationArgs
|
||||||
|
|
||||||
evaluateComposition :: EvaluationArgs -> IO Value
|
evaluateComposition :: EvaluationArgs -> IO Value
|
||||||
evaluateComposition ea = do
|
evaluateComposition ea = do
|
||||||
evalComposition <- getDataFileName "nix/eval-composition.nix"
|
evalComposition <- getEvalCompositionFile
|
||||||
let commandArgs =
|
let commandArgs =
|
||||||
[ "--eval"
|
[ "--eval"
|
||||||
, "--strict"
|
, "--strict"
|
||||||
|
@ -43,22 +53,11 @@ evaluateComposition ea = do
|
||||||
, "--attr"
|
, "--attr"
|
||||||
, "config.build.dockerComposeYamlAttrs"
|
, "config.build.dockerComposeYamlAttrs"
|
||||||
]
|
]
|
||||||
argArgs =
|
|
||||||
[ "--argstr"
|
|
||||||
, "uid"
|
|
||||||
, show $ evalUid ea
|
|
||||||
, "--arg"
|
|
||||||
, "modules"
|
|
||||||
, modulesNixExpr $ evalModules ea
|
|
||||||
, "--arg"
|
|
||||||
, "pkgs"
|
|
||||||
, toS $ evalPkgs ea
|
|
||||||
]
|
|
||||||
args =
|
args =
|
||||||
[ evalComposition ]
|
[ evalComposition ]
|
||||||
++ commandArgs
|
++ commandArgs
|
||||||
++ modeArguments (evalMode ea)
|
++ modeArguments (evalMode ea)
|
||||||
++ argArgs
|
++ argArgs ea
|
||||||
++ map toS (evalUserArgs ea)
|
++ map toS (evalUserArgs ea)
|
||||||
stdin = mempty
|
stdin = mempty
|
||||||
procSpec = (proc "nix-instantiate" args) { cwd = evalWorkDir ea }
|
procSpec = (proc "nix-instantiate" args) { cwd = evalWorkDir ea }
|
||||||
|
@ -83,6 +82,77 @@ evaluateComposition ea = do
|
||||||
Right r -> pure r
|
Right r -> pure r
|
||||||
Left e -> throwIO $ FatalError "Couldn't parse nix-instantiate output"
|
Left e -> throwIO $ FatalError "Couldn't parse nix-instantiate output"
|
||||||
|
|
||||||
|
-- | Run with docker-compose.yaml tmpfile
|
||||||
|
withEvaluatedComposition :: EvaluationArgs -> (FilePath -> IO r) -> IO r
|
||||||
|
withEvaluatedComposition ea f = do
|
||||||
|
v <- evaluateComposition ea
|
||||||
|
withTempFile "." ".tmp-arion-docker-compose.yaml" $ \path handle -> do
|
||||||
|
T.hPutStrLn handle (pretty v)
|
||||||
|
hClose handle
|
||||||
|
f path
|
||||||
|
|
||||||
|
|
||||||
|
buildComposition :: FilePath -> EvaluationArgs -> IO ()
|
||||||
|
buildComposition outLink ea = do
|
||||||
|
evalComposition <- getEvalCompositionFile
|
||||||
|
let commandArgs =
|
||||||
|
[ "--attr"
|
||||||
|
, "config.build.dockerComposeYaml"
|
||||||
|
, "--out-link"
|
||||||
|
, outLink
|
||||||
|
]
|
||||||
|
args =
|
||||||
|
[ evalComposition ]
|
||||||
|
++ commandArgs
|
||||||
|
++ argArgs ea
|
||||||
|
++ map toS (evalUserArgs ea)
|
||||||
|
stdin = mempty
|
||||||
|
procSpec = (proc "nix-build" args) { cwd = evalWorkDir ea }
|
||||||
|
|
||||||
|
-- TODO: lazy IO is tricky. Let's use conduit/pipes instead?
|
||||||
|
(exitCode, out, err) <- PBL.readCreateProcessWithExitCode procSpec stdin
|
||||||
|
|
||||||
|
-- Stream 'err'
|
||||||
|
errDone <- async (BL.hPutStr stderr err)
|
||||||
|
|
||||||
|
-- Force 'out'
|
||||||
|
-- TODO: use it?
|
||||||
|
_v <- Protolude.evaluate out
|
||||||
|
|
||||||
|
-- Wait for process exit and 'err' printout
|
||||||
|
wait errDone
|
||||||
|
|
||||||
|
case exitCode of
|
||||||
|
ExitSuccess -> pass
|
||||||
|
ExitFailure e -> throwIO $ FatalError "Build failed" -- TODO: don't print this exception in main
|
||||||
|
|
||||||
|
-- | Do something with a docker-compose.yaml.
|
||||||
|
withBuiltComposition :: EvaluationArgs -> (FilePath -> IO r) -> IO r
|
||||||
|
withBuiltComposition ea f = do
|
||||||
|
withTempFile "." ".tmp-arion-docker-compose.yaml" $ \path handle -> do
|
||||||
|
hClose handle
|
||||||
|
-- Known problem: kills atomicity of withTempFile; won't fix because we should manage gc roots,
|
||||||
|
-- impl of which will probably avoid this "problem". It seems unlikely to cause issues.
|
||||||
|
Directory.removeFile path
|
||||||
|
buildComposition path ea
|
||||||
|
f path
|
||||||
|
|
||||||
|
argArgs :: EvaluationArgs -> [[Char]]
|
||||||
|
argArgs ea =
|
||||||
|
[ "--argstr"
|
||||||
|
, "uid"
|
||||||
|
, show $ evalUid ea
|
||||||
|
, "--arg"
|
||||||
|
, "modules"
|
||||||
|
, modulesNixExpr $ evalModules ea
|
||||||
|
, "--arg"
|
||||||
|
, "pkgs"
|
||||||
|
, toS $ evalPkgs ea
|
||||||
|
]
|
||||||
|
|
||||||
|
getEvalCompositionFile :: IO FilePath
|
||||||
|
getEvalCompositionFile = getDataFileName "nix/eval-composition.nix"
|
||||||
|
|
||||||
modeArguments :: EvaluationMode -> [[Char]]
|
modeArguments :: EvaluationMode -> [[Char]]
|
||||||
modeArguments ReadWrite = [ "--read-write-mode" ]
|
modeArguments ReadWrite = [ "--read-write-mode" ]
|
||||||
modeArguments ReadOnly = [ "--readonly-mode" ]
|
modeArguments ReadOnly = [ "--readonly-mode" ]
|
||||||
|
|
Loading…
Reference in a new issue