Make arion cat work
This commit is contained in:
parent
77eadf4c41
commit
6882a92e56
11 changed files with 143 additions and 32 deletions
|
@ -3,3 +3,4 @@
|
|||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
||||
* *BREAKING:* useHostStore now uses a proper empty base image, like `scratch`.
|
||||
|
|
|
@ -19,6 +19,7 @@ data-files: nix/*.nix
|
|||
, nix/modules/composition/*.nix
|
||||
, nix/modules/nixos/*.nix
|
||||
, nix/modules/service/*.nix
|
||||
, arion-image/Dockerfile
|
||||
|
||||
-- all data is verbatim from some sources
|
||||
data-dir: src
|
||||
|
@ -26,16 +27,19 @@ data-dir: src
|
|||
common deps
|
||||
build-depends: base ^>=4.12.0.0
|
||||
, aeson
|
||||
, async
|
||||
, bytestring
|
||||
, process
|
||||
, process-extras
|
||||
, text
|
||||
, protolude
|
||||
|
||||
|
||||
library
|
||||
import: deps
|
||||
-- exposed-modules:
|
||||
-- other-modules:
|
||||
exposed-modules: Arion.Nix
|
||||
other-modules: Paths_arion_compose
|
||||
-- other-extensions:
|
||||
build-depends: process
|
||||
hs-source-dirs: src/haskell/lib
|
||||
default-language: Haskell2010
|
||||
|
||||
|
@ -45,7 +49,8 @@ executable arion
|
|||
-- other-modules:
|
||||
-- other-extensions:
|
||||
build-depends: optparse-applicative
|
||||
, process
|
||||
, aeson-pretty
|
||||
, arion-compose
|
||||
hs-source-dirs: src/haskell/exe
|
||||
default-language: Haskell2010
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
}:
|
||||
let
|
||||
|
||||
# TODO: Replace by a new expression for the new Haskell main
|
||||
arion = stdenv.mkDerivation {
|
||||
name = "arion";
|
||||
src = ./src;
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
self: super:
|
||||
let
|
||||
inherit (self.arion-project) haskellPkgs;
|
||||
|
||||
srcDir = ../src; # TODO gitignoreSource + whitelist nix and arion-image
|
||||
eval = import (srcDir + "/nix/eval-composition.nix");
|
||||
build = args@{...}:
|
||||
let composition = eval args;
|
||||
in composition.config.build.dockerComposeYaml;
|
||||
hlib = super.haskell.lib;
|
||||
in
|
||||
{
|
||||
|
||||
arion-v0 = super.callPackage ../arion.nix {};
|
||||
arion = super.haskell.lib.justStaticExecutables haskellPkgs.arion-compose;
|
||||
arion = hlib.justStaticExecutables (hlib.overrideCabal haskellPkgs.arion-compose (o: {
|
||||
passthru = o.passthru // {
|
||||
inherit eval build;
|
||||
};
|
||||
}));
|
||||
tests = super.callPackage ../tests {};
|
||||
doc = super.callPackage ../doc {};
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
FROM scratch
|
||||
COPY passwd /etc/passwd
|
||||
ADD tarball.tar.gz /
|
||||
# scratch itself can't be run.
|
||||
|
||||
# This seems like a no-op:
|
||||
CMD []
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
root:x:0:0:System administrator:/root:/bin/sh
|
||||
nobody:x:65534:65534:Unprivileged account (don't use!):/var/empty:/run/current-system/sw/bin/nologin
|
|
@ -1 +0,0 @@
|
|||
/run/system/bin/sh
|
|
@ -1 +0,0 @@
|
|||
/run/system/usr/bin/env
|
|
@ -5,15 +5,21 @@
|
|||
|
||||
import Protolude hiding (Down)
|
||||
|
||||
import Arion.Nix
|
||||
|
||||
import Options.Applicative
|
||||
import Control.Applicative
|
||||
|
||||
import qualified Data.Aeson.Encode.Pretty
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as T
|
||||
import qualified Data.Text.Lazy as TL
|
||||
import qualified Data.Text.Lazy.Builder as TB
|
||||
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
import Data.List.NonEmpty (NonEmpty(..))
|
||||
|
||||
|
||||
import Control.Arrow ((>>>))
|
||||
|
||||
data CommonOptions =
|
||||
|
@ -46,7 +52,7 @@ parseOptions = do
|
|||
<> metavar "EXPR"
|
||||
<> showDefault
|
||||
<> value "./arion-pkgs.nix"
|
||||
<> help "Use EXPR to get the Nixpkgs attrset used for bootstrapping \
|
||||
<> help "Use Nix expression EXPR to get the Nixpkgs attrset used for bootstrapping \
|
||||
\and evaluating the configuration." )
|
||||
pure CommonOptions{..}
|
||||
|
||||
|
@ -111,28 +117,12 @@ commandDC run cmdStr help =
|
|||
(run cmdStr <$> parseDockerComposeArgs)
|
||||
(progDesc (T.unpack help) <> fullDesc <> forwardOptions))
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
modulesNixExpr :: NonEmpty FilePath -> Text
|
||||
modulesNixExpr =
|
||||
NE.toList
|
||||
>>> fmap pathExpr
|
||||
>>> T.unwords
|
||||
>>> wrapList
|
||||
where
|
||||
pathExpr path | isAbsolute path = "(/. + \"" <> T.pack path <> "\")"
|
||||
| otherwise = "(./. + \"" <> T.pack path <> "\")"
|
||||
|
||||
isAbsolute ('/':_) = True
|
||||
isAbsolute _ = False
|
||||
|
||||
wrapList s = "[ " <> s <> " ]"
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
runDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
||||
runDC cmd (DockerComposeArgs args) opts =
|
||||
T.putStrLn $ "TODO: docker-compose " <> cmd <> " " <> T.unwords args
|
||||
panic $ "TODO: docker-compose " <> cmd <> " " <> T.unwords args
|
||||
|
||||
runBuildAndDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
|
||||
runBuildAndDC cmd dopts opts = do
|
||||
|
@ -146,8 +136,13 @@ runEvalAndDC cmd dopts opts = do
|
|||
|
||||
runCat :: CommonOptions -> IO ()
|
||||
runCat (CommonOptions files pkgs) = do
|
||||
T.putStrLn "Running cat ... TODO"
|
||||
T.putStrLn (modulesNixExpr files)
|
||||
v <- Arion.Nix.evaluate EvaluationArgs
|
||||
{ evalUid = 0 -- TODO
|
||||
, evalModules = files
|
||||
, evalPkgs = pkgs
|
||||
, evalWorkDir = Nothing
|
||||
}
|
||||
T.hPutStrLn stderr (TL.toStrict $ TB.toLazyText $ Data.Aeson.Encode.Pretty.encodePrettyToTextBuilder v)
|
||||
|
||||
runRepl :: CommonOptions -> IO ()
|
||||
runRepl opts =
|
||||
|
|
91
src/haskell/lib/Arion/Nix.hs
Normal file
91
src/haskell/lib/Arion/Nix.hs
Normal file
|
@ -0,0 +1,91 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module Arion.Nix where
|
||||
|
||||
import Prelude ( )
|
||||
import Protolude
|
||||
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 ( (>>>) )
|
||||
|
||||
data EvaluationArgs = EvaluationArgs
|
||||
{ evalUid :: Int
|
||||
, evalModules :: NonEmpty FilePath
|
||||
, evalPkgs :: Text
|
||||
, evalWorkDir :: Maybe FilePath
|
||||
}
|
||||
|
||||
evaluate :: EvaluationArgs -> IO Value
|
||||
evaluate ea = do
|
||||
evalComposition <- getDataFileName "nix/eval-composition.nix"
|
||||
let args =
|
||||
[ evalComposition
|
||||
, "--eval"
|
||||
, "--strict"
|
||||
, "--read-write-mode"
|
||||
, "--json"
|
||||
, "--show-trace"
|
||||
, "--argstr"
|
||||
, "uid"
|
||||
, show $ evalUid ea
|
||||
, "--arg"
|
||||
, "modules"
|
||||
, modulesNixExpr $ evalModules ea
|
||||
, "--arg"
|
||||
, "pkgs"
|
||||
, toS $ evalPkgs ea
|
||||
, "--attr"
|
||||
, "config.build.dockerComposeYamlAttrs"
|
||||
]
|
||||
stdin = mempty
|
||||
procSpec = (proc "nix-instantiate" 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'
|
||||
v <- Protolude.evaluate (eitherDecode out)
|
||||
|
||||
-- Wait for process exit and 'err' printout
|
||||
wait errDone
|
||||
|
||||
case exitCode of
|
||||
ExitSuccess -> pass
|
||||
ExitFailure e -> throwIO $ FatalError "Evaluation failed" -- TODO: don't print this exception in main
|
||||
|
||||
case v of
|
||||
Right r -> pure r
|
||||
Left e -> throwIO $ FatalError "Couldn't parse nix-instantiate output"
|
||||
|
||||
|
||||
modulesNixExpr :: NonEmpty FilePath -> [Char]
|
||||
modulesNixExpr =
|
||||
NE.toList >>> fmap pathExpr >>> Data.String.unwords >>> wrapList
|
||||
where
|
||||
pathExpr :: FilePath -> [Char]
|
||||
pathExpr path | isAbsolute path = "(/. + \"/${" <> toNixStringLiteral path <> "}\")"
|
||||
| otherwise = "(./. + \"/${" <> toNixStringLiteral path <> "}\")"
|
||||
|
||||
isAbsolute ('/' : _) = True
|
||||
isAbsolute _ = False
|
||||
|
||||
wrapList s = "[ " <> s <> " ]"
|
||||
|
||||
toNixStringLiteral :: [Char] -> [Char]
|
||||
toNixStringLiteral = show -- FIXME: custom escaping including '$'
|
|
@ -19,10 +19,17 @@ in
|
|||
build.dockerComposeYaml = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
description = "A derivation that produces a docker-compose.yaml file for this composition.";
|
||||
readOnly = true;
|
||||
};
|
||||
build.dockerComposeYamlText = lib.mkOption {
|
||||
type = lib.types.string;
|
||||
description = "The text of build.dockerComposeYaml.";
|
||||
readOnly = true;
|
||||
};
|
||||
build.dockerComposeYamlAttrs = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.unspecified;
|
||||
description = "The text of build.dockerComposeYaml.";
|
||||
readOnly = true;
|
||||
};
|
||||
docker-compose.raw = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
|
@ -45,7 +52,8 @@ in
|
|||
};
|
||||
config = {
|
||||
build.dockerComposeYaml = pkgs.writeText "docker-compose.yaml" config.build.dockerComposeYamlText;
|
||||
build.dockerComposeYamlText = builtins.toJSON (config.docker-compose.raw);
|
||||
build.dockerComposeYamlText = builtins.toJSON (config.build.dockerComposeYamlAttrs);
|
||||
build.dockerComposeYamlAttrs = config.docker-compose.raw;
|
||||
|
||||
docker-compose.evaluatedServices = lib.mapAttrs evalService config.docker-compose.services;
|
||||
docker-compose.raw = {
|
||||
|
|
Loading…
Reference in a new issue