Add --show-trace, eval unit test
This commit is contained in:
parent
381c3ec37f
commit
6d6361e7e8
10 changed files with 182 additions and 30 deletions
|
@ -27,6 +27,7 @@ data-dir: src
|
|||
common deps
|
||||
build-depends: base ^>=4.12.0.0
|
||||
, aeson
|
||||
, aeson-pretty
|
||||
, async
|
||||
, bytestring
|
||||
, process
|
||||
|
@ -41,6 +42,7 @@ flag ghci
|
|||
library
|
||||
import: deps
|
||||
exposed-modules: Arion.Nix
|
||||
Arion.Aeson
|
||||
other-modules: Paths_arion_compose
|
||||
-- other-extensions:
|
||||
hs-source-dirs: src/haskell/lib
|
||||
|
@ -52,7 +54,6 @@ executable arion
|
|||
-- other-modules:
|
||||
-- other-extensions:
|
||||
build-depends: optparse-applicative
|
||||
, aeson-pretty
|
||||
, arion-compose
|
||||
hs-source-dirs: src/haskell/exe
|
||||
default-language: Haskell2010
|
||||
|
@ -64,7 +65,8 @@ test-suite arion-unit-tests
|
|||
ghc-options: -Wno-missing-home-modules
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: TestMain.hs
|
||||
-- other-modules:
|
||||
other-modules: Spec
|
||||
, Arion.NixSpec
|
||||
-- other-extensions:
|
||||
build-depends: arion-compose
|
||||
, hspec
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
self: super: hself: hsuper: {
|
||||
arion-compose = hself.callCabal2nix "arion-compose" ./.. {};
|
||||
self: super: hself: hsuper:
|
||||
let
|
||||
inherit (self.haskell.lib) addBuildTools overrideCabal;
|
||||
in
|
||||
{
|
||||
arion-compose = overrideCabal (addBuildTools (hself.callCabal2nix "arion-compose" ./.. {}) [self.nix]) (o: o // {
|
||||
preCheck = ''
|
||||
export NIX_LOG_DIR=$TMPDIR
|
||||
export NIX_STATE_DIR=$TMPDIR
|
||||
export NIX_PATH=nixpkgs=${self.path}
|
||||
'';
|
||||
});
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
import Protolude hiding (Down)
|
||||
|
||||
import Arion.Nix
|
||||
import Arion.Aeson
|
||||
|
||||
import Options.Applicative
|
||||
import Control.Applicative
|
||||
|
@ -26,6 +27,7 @@ data CommonOptions =
|
|||
CommonOptions
|
||||
{ files :: NonEmpty FilePath
|
||||
, pkgs :: Text
|
||||
, nixArgs :: [Text]
|
||||
}
|
||||
deriving (Show)
|
||||
|
||||
|
@ -54,7 +56,15 @@ parseOptions = do
|
|||
<> value "./arion-pkgs.nix"
|
||||
<> help "Use Nix expression EXPR to get the Nixpkgs attrset used for bootstrapping \
|
||||
\and evaluating the configuration." )
|
||||
pure CommonOptions{..}
|
||||
showTrace <- flag False True (long "show-trace"
|
||||
<> help "Causes Nix to print out a stack trace in case of Nix expression evaluation errors.")
|
||||
-- TODO --option support (https://github.com/pcapriotti/optparse-applicative/issues/284)
|
||||
userNixArgs <- many (T.pack <$> strOption (long "nix-arg" <> metavar "ARG" <> help "Pass an extra argument to nix. Example: --nix-arg --option --nix-arg substitute --nix-arg false"))
|
||||
pure $
|
||||
let nixArgs = userNixArgs <|> "--show-trace" <$ guard showTrace
|
||||
in CommonOptions{..}
|
||||
|
||||
textArgument = fmap T.pack . strArgument
|
||||
|
||||
parseCommand :: Parser (CommonOptions -> IO ())
|
||||
parseCommand =
|
||||
|
@ -135,14 +145,16 @@ runEvalAndDC cmd dopts opts = do
|
|||
runDC cmd dopts opts
|
||||
|
||||
runCat :: CommonOptions -> IO ()
|
||||
runCat (CommonOptions files pkgs) = do
|
||||
runCat co = do
|
||||
v <- Arion.Nix.evaluate EvaluationArgs
|
||||
{ evalUid = 0 -- TODO
|
||||
, evalModules = files
|
||||
, evalPkgs = pkgs
|
||||
, evalModules = files co
|
||||
, evalPkgs = pkgs co
|
||||
, evalWorkDir = Nothing
|
||||
, evalMode = ReadWrite
|
||||
, evalUserArgs = nixArgs co
|
||||
}
|
||||
T.hPutStrLn stderr (TL.toStrict $ TB.toLazyText $ Data.Aeson.Encode.Pretty.encodePrettyToTextBuilder v)
|
||||
T.hPutStrLn stderr (pretty v)
|
||||
|
||||
runRepl :: CommonOptions -> IO ()
|
||||
runRepl opts =
|
||||
|
|
20
src/haskell/lib/Arion/Aeson.hs
Normal file
20
src/haskell/lib/Arion/Aeson.hs
Normal file
|
@ -0,0 +1,20 @@
|
|||
module Arion.Aeson where
|
||||
|
||||
import Data.Aeson
|
||||
import qualified Data.Text.Lazy as TL
|
||||
import qualified Data.Text.Lazy.IO as TL
|
||||
import qualified Data.Text.Lazy.Builder as TB
|
||||
import qualified Data.Aeson.Encode.Pretty
|
||||
import Data.Aeson.Encode.Pretty ( defConfig
|
||||
, keyOrder
|
||||
, confCompare
|
||||
, confTrailingNewline
|
||||
)
|
||||
import Protolude
|
||||
|
||||
pretty :: ToJSON a => a -> Text
|
||||
pretty =
|
||||
TL.toStrict
|
||||
. TB.toLazyText
|
||||
. Data.Aeson.Encode.Pretty.encodePrettyToTextBuilder' config
|
||||
where config = defConfig { confCompare = compare, confTrailingNewline = True }
|
|
@ -21,24 +21,30 @@ import Data.List.NonEmpty ( NonEmpty(..) )
|
|||
|
||||
import Control.Arrow ( (>>>) )
|
||||
|
||||
data EvaluationMode =
|
||||
ReadWrite | ReadOnly
|
||||
|
||||
data EvaluationArgs = EvaluationArgs
|
||||
{ evalUid :: Int
|
||||
, evalModules :: NonEmpty FilePath
|
||||
, evalPkgs :: Text
|
||||
, evalWorkDir :: Maybe FilePath
|
||||
, evalMode :: EvaluationMode
|
||||
, evalUserArgs :: [Text]
|
||||
}
|
||||
|
||||
evaluate :: EvaluationArgs -> IO Value
|
||||
evaluate ea = do
|
||||
evalComposition <- getDataFileName "nix/eval-composition.nix"
|
||||
let args =
|
||||
[ evalComposition
|
||||
, "--eval"
|
||||
let commandArgs =
|
||||
[ "--eval"
|
||||
, "--strict"
|
||||
, "--read-write-mode"
|
||||
, "--json"
|
||||
, "--show-trace"
|
||||
, "--argstr"
|
||||
, "--attr"
|
||||
, "config.build.dockerComposeYamlAttrs"
|
||||
]
|
||||
argArgs =
|
||||
[ "--argstr"
|
||||
, "uid"
|
||||
, show $ evalUid ea
|
||||
, "--arg"
|
||||
|
@ -47,9 +53,13 @@ evaluate ea = do
|
|||
, "--arg"
|
||||
, "pkgs"
|
||||
, toS $ evalPkgs ea
|
||||
, "--attr"
|
||||
, "config.build.dockerComposeYamlAttrs"
|
||||
]
|
||||
args =
|
||||
[ evalComposition ]
|
||||
++ commandArgs
|
||||
++ modeArguments (evalMode ea)
|
||||
++ argArgs
|
||||
++ map toS (evalUserArgs ea)
|
||||
stdin = mempty
|
||||
procSpec = (proc "nix-instantiate" args) { cwd = evalWorkDir ea }
|
||||
|
||||
|
@ -73,6 +83,9 @@ evaluate ea = do
|
|||
Right r -> pure r
|
||||
Left e -> throwIO $ FatalError "Couldn't parse nix-instantiate output"
|
||||
|
||||
modeArguments :: EvaluationMode -> [[Char]]
|
||||
modeArguments ReadWrite = [ "--read-write-mode" ]
|
||||
modeArguments ReadOnly = [ "--readonly-mode" ]
|
||||
|
||||
modulesNixExpr :: NonEmpty FilePath -> [Char]
|
||||
modulesNixExpr =
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
module Arion.FooSpec
|
||||
( spec
|
||||
)
|
||||
where
|
||||
|
||||
import Test.Hspec
|
||||
import Test.QuickCheck
|
||||
|
||||
spec :: Spec
|
||||
spec = do
|
||||
it "foo" $ property True
|
49
src/haskell/test/Arion/NixSpec.hs
Normal file
49
src/haskell/test/Arion/NixSpec.hs
Normal file
|
@ -0,0 +1,49 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module Arion.NixSpec
|
||||
( spec
|
||||
)
|
||||
where
|
||||
|
||||
import Protolude
|
||||
import Test.Hspec
|
||||
import Test.QuickCheck
|
||||
import qualified Data.List.NonEmpty as NEL
|
||||
import Arion.Aeson
|
||||
import Arion.Nix
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as T
|
||||
import qualified Data.Text.Lazy.IO as TL
|
||||
import qualified Data.Text.Lazy.Builder as TB
|
||||
import qualified Data.Aeson.Encode.Pretty
|
||||
import Data.Char (isSpace)
|
||||
|
||||
spec :: Spec
|
||||
spec = describe "evaluate" $ it "matches an example" $ do
|
||||
x <- Arion.Nix.evaluate EvaluationArgs
|
||||
{ evalUid = 123
|
||||
, evalModules = NEL.fromList
|
||||
["src/haskell/testdata/Arion/NixSpec/arion-compose.nix"]
|
||||
, evalPkgs = "import <nixpkgs> {}"
|
||||
, evalWorkDir = Nothing
|
||||
, evalMode = ReadOnly
|
||||
, evalUserArgs = ["--show-trace"]
|
||||
}
|
||||
let actual = pretty x
|
||||
expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-compose.json"
|
||||
censorPaths actual `shouldBe` censorPaths expected
|
||||
|
||||
censorPaths :: Text -> Text
|
||||
censorPaths x = case T.breakOn "/nix/store/" x of
|
||||
(prefix, tl) | (tl :: Text) == "" -> prefix
|
||||
(prefix, tl) -> prefix <> "<STOREPATH>" <> censorPaths
|
||||
(T.dropWhile isNixNameChar $ T.drop (T.length "/nix/store/") tl)
|
||||
|
||||
-- | WARNING: THIS IS LIKELY WRONG: DON'T REUSE
|
||||
isNixNameChar :: Char -> Bool
|
||||
isNixNameChar c | c >= '0' && c <= '9' = True
|
||||
isNixNameChar c | c >= 'a' && c <= 'z' = True
|
||||
isNixNameChar c | c >= 'A' && c <= 'Z' = True
|
||||
isNixNameChar c | c == '-' = True
|
||||
isNixNameChar c | c == '.' = True
|
||||
isNixNameChar c | c == '_' = True -- WRONG?
|
||||
isNixNameChar c = False -- WRONG?
|
|
@ -4,8 +4,8 @@ module Spec
|
|||
where
|
||||
|
||||
import Test.Hspec
|
||||
import qualified Arion.FooSpec
|
||||
import qualified Arion.NixSpec
|
||||
|
||||
spec :: Spec
|
||||
spec = do
|
||||
describe "Arion.Foo" Arion.FooSpec.spec
|
||||
describe "Arion.Nix" Arion.NixSpec.spec
|
||||
|
|
45
src/haskell/testdata/Arion/NixSpec/arion-compose.json
vendored
Normal file
45
src/haskell/testdata/Arion/NixSpec/arion-compose.json
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"services": {
|
||||
"webserver": {
|
||||
"build": {
|
||||
"context": "/nix/store/l6jwin74n93d66ralxzb001c22yjii9x-arion-image"
|
||||
},
|
||||
"command": [
|
||||
"/nix/store/b9w61w4g8sqgrm3rid6ca22krslqghb3-nixos-system-unnamed-19.03.173100.e726e8291b2/init"
|
||||
],
|
||||
"environment": {
|
||||
"NIX_REMOTE": "",
|
||||
"container": "docker"
|
||||
},
|
||||
"image": "arion-base",
|
||||
"ports": [
|
||||
"8000:80"
|
||||
],
|
||||
"stop_signal": "SIGRTMIN+3",
|
||||
"sysctls": {},
|
||||
"tmpfs": [
|
||||
"/run",
|
||||
"/run/wrappers",
|
||||
"/tmp:exec,mode=777"
|
||||
],
|
||||
"tty": true,
|
||||
"volumes": [
|
||||
"/sys/fs/cgroup:/sys/fs/cgroup:ro",
|
||||
"/nix/store:/nix/store",
|
||||
"/nix/store/pssdmhzjnhflawv7rwk1yw39350iv40g-container-system-env:/run/system"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "3.4",
|
||||
"x-arion": {
|
||||
"images": [],
|
||||
"serviceInfo": {
|
||||
"webserver": {
|
||||
"defaultExec": [
|
||||
"/run/current-system/sw/bin/bash",
|
||||
"-l"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
src/haskell/testdata/Arion/NixSpec/arion-compose.nix
vendored
Normal file
12
src/haskell/testdata/Arion/NixSpec/arion-compose.nix
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
docker-compose.services.webserver = { pkgs, ... }: {
|
||||
nixos.useSystemd = true;
|
||||
nixos.configuration.boot.tmpOnTmpfs = true;
|
||||
nixos.configuration.services.nginx.enable = true;
|
||||
nixos.configuration.services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual";
|
||||
service.useHostStore = true;
|
||||
service.ports = [
|
||||
"8000:80" # host:container
|
||||
];
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue