Make some commands work

This commit is contained in:
Robert Hensing 2019-09-27 21:01:57 +02:00
parent c0e995043a
commit b9488b7f49
5 changed files with 168 additions and 28 deletions

View file

@ -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

View file

@ -28,6 +28,7 @@ in
buildInputs = [ buildInputs = [
haskellPkgs.cabal-install haskellPkgs.cabal-install
haskellPkgs.ghcid haskellPkgs.ghcid
super.docker-compose
]; ];
}; };
}; };

View file

@ -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 ()

View 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

View file

@ -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" ]