@@ -6,10 +6,19 @@
66{-# LANGUAGE OverloadedStrings #-}
77{-# LANGUAGE Rank2Types #-}
88{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE TemplateHaskell #-}
910{-# LANGUAGE TypeApplications #-}
1011module Obelisk.Command.Nix
11− ( nixBuild
12+ ( nixCmd
13+ , NixCmd (..)
14+ , nixCmdConfig_target
15+ , nixCmdConfig_args
16+ , nixCmdConfig_builders
1217 , NixBuildConfig (..)
18+ , nixBuildConfig_outLink
19+ , NixInstantiateConfig (..)
20+ , nixInstantiateConfig_eval
21+ , NixCommonConfig (..)
1322 , Target (..)
1423 , OutLink (..)
1524 , Arg (..)
@@ -18,9 +27,13 @@ module Obelisk.Command.Nix
1827 , strArg
1928 ) where
2029
30+import Control.Monad (guard)
31+import Control.Lens
32+
2133import Data.Bool (bool)
2234import Data.Default
2335import Data.List (intercalate)
36+import Data.Maybe
2437import Data.Monoid ((<>))
2538import qualified Data.Text as T
2639import System.Process (proc)
@@ -28,25 +41,19 @@ import System.Process (proc)
2841import Obelisk.App (MonadObelisk)
2942import Obelisk.CliApp
3043
31−-- | Where to put nix-build output
32−data OutLink
33− = OutLink_Default
34− | OutLink_None
35− | OutLink_IndirectRoot FilePath
36−
37−instance Default OutLink where
38− def = OutLink_Default
39−
4044-- | What to build
4145data Target = Target
42− { _target_path :: FilePath
46+ { _target_path :: Maybe FilePath
4347 , _target_attr :: Maybe String
48+ , _target_expr :: Maybe String
4449 }
50+makeClassy ''Target
4551
4652instance Default Target where
4753 def = Target
48− { _target_path = "."
54+ { _target_path = Just "."
4955 , _target_attr = Nothing
56+ , _target_expr = Nothing
5057 }
5158
5259data Arg
@@ -68,36 +75,108 @@ cliFromArgs = concatMap $ \case
6875 Arg_Str k v -> ["--argstr", k, v]
6976 Arg_Expr k v -> ["--arg", k, v]
7077
71−data NixBuildConfig = NixBuildConfig
72− { _nixBuildConfig_target :: Target
73− , _nixBuildConfig_outLink :: OutLink
74− , _nixBuildConfig_args :: [Arg]
75− , _nixBuildConfig_builders :: [String]
78+data NixCommonConfig = NixCommonConfig
79+ { _nixCmdConfig_target :: Target
80+ , _nixCmdConfig_args :: [Arg]
81+ , _nixCmdConfig_builders :: [String]
7682 }
83+makeClassy ''NixCommonConfig
7784
78−instance Default NixBuildConfig where
79− def = NixBuildConfig def def mempty mempty
85+instance Default NixCommonConfig where
86+ def = NixCommonConfig def mempty mempty
8087
81−nixBuild :: MonadObelisk m => NixBuildConfig -> m FilePath
82−nixBuild cfg = withSpinner' ("Running nix-build on " <> desc) (Just $ const $ "Built " <> desc) $ do
83− output <- readProcessAndLogStderr Debug $ proc "nix-build" $ mconcat
84− [[path], attrArg, args, outLink, buildersArg]
85− -- Remove final newline that Nix appends
86− Just (outPath, '\n') <- pure $ T.unsnoc output
87− pure $ T.unpack outPath
88+runNixCommonConfig :: NixCommonConfig -> [FilePath]
89+runNixCommonConfig cfg = mconcat [maybeToList path, attrArg, exprArg, args, buildersArg]
8890 where
89− path = _target_path $ _nixBuildConfig_target cfg
90− attr = _target_attr $ _nixBuildConfig_target cfg
91+ path = _target_path $ _nixCmdConfig_target cfg
92+ attr = _target_attr $ _nixCmdConfig_target cfg
93+ expr = _target_expr $ _nixCmdConfig_target cfg
9194 attrArg = case attr of
9295 Nothing -> []
9396 Just a -> ["-A", a]
94− args = cliFromArgs $ _nixBuildConfig_args cfg
95− outLink = case _nixBuildConfig_outLink cfg of
97+ exprArg = case expr of
98+ Nothing -> []
99+ Just a -> ["-E", a]
100+ args = cliFromArgs $ _nixCmdConfig_args cfg
101+ buildersArg = case _nixCmdConfig_builders cfg of
102+ [] -> []
103+ builders -> ["--builders", intercalate ";" builders]
104+
105+-- | Where to put nix-build output
106+data OutLink
107+ = OutLink_Default
108+ | OutLink_None
109+ | OutLink_IndirectRoot FilePath
110+
111+instance Default OutLink where
112+ def = OutLink_Default
113+
114+data NixBuildConfig = NixBuildConfig
115+ { _nixBuildConfig_common :: NixCommonConfig
116+ , _nixBuildConfig_outLink :: OutLink
117+ }
118+makeLenses ''NixBuildConfig
119+
120+instance HasNixCommonConfig NixBuildConfig where
121+ nixCommonConfig = nixBuildConfig_common
122+
123+instance Default NixBuildConfig where
124+ def = NixBuildConfig def def
125+
126+runNixBuildConfig :: NixBuildConfig -> [FilePath]
127+runNixBuildConfig cfg = mconcat
128+ [ runNixCommonConfig $ cfg ^. nixCommonConfig
129+ , case _nixBuildConfig_outLink cfg of
96130 OutLink_Default -> []
97131 OutLink_None -> ["--no-out-link"]
98132 OutLink_IndirectRoot l -> ["--out-link", l]
99− desc = T.pack $ path <> maybe "" (\a -> " [" <> a <> "]") attr
100− buildersArg = case _nixBuildConfig_builders cfg of
101− [] -> []
102− builders -> ["--builders", intercalate ";" builders]
133+ ]
103134
135+data NixInstantiateConfig = NixInstantiateConfig
136+ { _nixInstantiateConfig_common :: NixCommonConfig
137+ , _nixInstantiateConfig_eval :: Bool
138+ }
139+makeLenses ''NixInstantiateConfig
140+
141+instance HasNixCommonConfig NixInstantiateConfig where
142+ nixCommonConfig = nixInstantiateConfig_common
143+
144+instance Default NixInstantiateConfig where
145+ def = NixInstantiateConfig def False
146+
147+runNixInstantiateConfig :: NixInstantiateConfig -> [FilePath]
148+runNixInstantiateConfig cfg = mconcat
149+ [ runNixCommonConfig $ cfg ^. nixCommonConfig
150+ , "--eval" <$ guard (_nixInstantiateConfig_eval cfg)
151+ ]
152+
153+data NixCmd
154+ = NixCmd_Build NixBuildConfig
155+ | NixCmd_Instantiate NixInstantiateConfig
156+
157+instance Default NixCmd where
158+ def = NixCmd_Build def
159+
160+nixCmd :: MonadObelisk m => NixCmd -> m FilePath
161+nixCmd cmdCfg = withSpinner' ("Running " <> cmd <> desc) (Just $ const $ "Built " <> desc) $ do
162+ output <- readProcessAndLogStderr Debug $ proc (T.unpack cmd) $ options
163+ -- Remove final newline that Nix appends
164+ Just (outPath, '\n') <- pure $ T.unsnoc output
165+ pure $ T.unpack outPath
166+ where
167+ (cmd, options, commonCfg) = case cmdCfg of
168+ NixCmd_Build cfg' ->
169+ ( "nix-build"
170+ , runNixBuildConfig cfg'
171+ , cfg' ^. nixCommonConfig
172+ )
173+ NixCmd_Instantiate cfg' ->
174+ ( "nix-instantiate"
175+ , runNixInstantiateConfig cfg'
176+ , cfg' ^. nixCommonConfig
177+ )
178+ path = commonCfg ^. nixCmdConfig_target . target_path
179+ desc = T.pack $ mconcat $ catMaybes
180+ [ (" on " <>) <$> path
181+ , (\a -> " [" <> a <> "]") <$> (commonCfg ^. nixCmdConfig_target . target_attr)
182+ ]