@@ -17,8 +17,13 @@ module Stack.Nix
1717 ) where
1818
1919import qualified Data.Text as T
20+ import qualified Data.ByteString.Lazy.Char8 as S8
21+ import Path ( parseAbsFile )
2022import Path.IO ( resolveFile )
21- import RIO.Process ( exec , processContextL )
23+ import RIO.Process
24+ ( HasProcessContext (.. ), exec , proc , processContextL
25+ , readProcess
26+ )
2227import Stack.Config ( getInContainer , withBuildConfig )
2328import Stack.Config.Nix ( nixCompiler , nixCompilerVersion )
2429import Stack.Constants
@@ -41,13 +46,58 @@ import qualified System.FilePath as F
4146data NixPrettyException
4247 = CannotDetermineProjectRoot
4348 -- ^ Can't determine the project root (location of the shell file if any).
49+ | NixInstantiateCommandFailure ! [String ] ! S8. ByteString
50+ | NixInstantiateCommandNoDerivationPath ! [String ]
51+ | NixInstantiateCommandNoSingleDerivationPath ! [String ] ! [S8. ByteString ]
52+ | NixInstantiateCommandInvalidDerivationPath ! [String ] ! String
4453 deriving Show
4554
4655instance Pretty NixPrettyException where
4756 pretty CannotDetermineProjectRoot =
4857 " [S-7384]"
4958 <> line
5059 <> flow " Cannot determine project root directory."
60+ pretty (NixInstantiateCommandFailure args e) =
61+ " [S-1264]"
62+ <> line
63+ <> whileUsingNixInstantiate args
64+ <> flow " Stack encountered the following error:"
65+ <> blankLine
66+ <> string (T. unpack . textDisplay . displayBytesUtf8 $ S8. toStrict e)
67+ pretty (NixInstantiateCommandNoDerivationPath args) =
68+ " [S-3220]"
69+ <> line
70+ <> whileUsingNixInstantiate args
71+ <> flow " the command succeeded but did not output a path to a store \
72+ \derivation."
73+ pretty (NixInstantiateCommandNoSingleDerivationPath args drvPaths) =
74+ " [S-5924]"
75+ <> line
76+ <> whileUsingNixInstantiate args
77+ <> flow " the command succeeded but expected a single path to a store \
78+ \derivation and output was:"
79+ <> line
80+ <> bulletedList (map (style File . string . S8. unpack) drvPaths)
81+ <> line
82+ pretty (NixInstantiateCommandInvalidDerivationPath args drvPath) =
83+ " [S-1537]"
84+ <> line
85+ <> whileUsingNixInstantiate args
86+ <> flow " the command succeeded but expected a valid path to a store \
87+ \derivation and output was:"
88+ <> line
89+ <> style Error (string drvPath)
90+
91+ whileUsingNixInstantiate :: [String ] -> StyleDoc
92+ whileUsingNixInstantiate args =
93+ fillSep
94+ [ flow " While using"
95+ , style Shell " nix-instantiate" <> " ,"
96+ , flow " with arguments:"
97+ ]
98+ <> line
99+ <> bulletedList (map (style Shell . string) args)
100+ <> blankLine
51101
52102instance Exception NixPrettyException
53103
@@ -129,24 +179,31 @@ runShellAndExit = do
129179 , " } \"\" "
130180 ]
131181 ]
132-
133- fullArgs = concat
134- [ [ " --pure" | pureShell ]
135- , if addGCRoots
182+ instantiateArgs = concat
183+ [ if addGCRoots
136184 then [ " --indirect"
185+ -- From Nix 2.4, the --indirect flag is a no op and
186+ -- --add-root always generates indirect GC roots.
137187 , " --add-root"
138188 , toFilePath
139189 config. workDir
140190 F. </> " nix-gc-symlinks"
141191 F. </> " gc-root"
142192 ]
143193 else []
144- , map T. unpack config. nix. shellOptions
145194 , nixopts
146- , [" --run" , unwords (cmnd: " $STACK_IN_NIX_EXTRA_ARGS" : args')]
147- -- Using --run instead of --command so we cannot end up in the
148- -- nix-shell if stack build is Ctrl-C'd
195+ , map T. unpack config. nix. instantiateOptions
196+ , [ " --show-trace" ]
149197 ]
198+ shellArgs = concat
199+ [ [ " --pure" | pureShell ]
200+ , map T. unpack config. nix. shellOptions
201+ , [ " --run"
202+ -- Using --run instead of --command so we cannot end up in the
203+ -- nix-shell if stack build is Ctrl-C'd
204+ , unwords (cmnd : " $STACK_IN_NIX_EXTRA_ARGS" : args')
205+ ]
206+ ]
150207 pathVar <- liftIO $ lookupEnv " PATH"
151208 logDebug $ " PATH is: " <> displayShow pathVar
152209 logDebug $
@@ -159,7 +216,44 @@ runShellAndExit = do
159216 " with nix packages: "
160217 <> display (T. intercalate " , " pkgs)
161218 )
162- exec " nix-shell" fullArgs
219+ runNixShellExec instantiateArgs shellArgs
220+
221+ runNixShellExec
222+ :: (HasProcessContext env , HasLogFunc env )
223+ => [String ]
224+ -- ^ nix-instantiate args
225+ -> [String ]
226+ -- ^ nix-shell args
227+ -> RIO env a
228+ runNixShellExec instantiateArgs shellArgs = do
229+ -- The nix-instantiate command instantiates (produces) a store derivation
230+ -- from a Nix expression and prints the path of the store derivation on
231+ -- standard output:
232+ (ec, out, err) <- proc " nix-instantiate" instantiateArgs readProcess
233+ case ec of
234+ ExitFailure _ ->
235+ -- As of Nix 2.34, there appears to be no way to capture coloured output
236+ prettyThrowIO (NixInstantiateCommandFailure instantiateArgs err)
237+ ExitSuccess -> do
238+ drvPath <- case S8. lines out of
239+ [] -> prettyThrowIO $
240+ NixInstantiateCommandNoDerivationPath instantiateArgs
241+ -- nix-instantiate prints the .drv path
242+ [drvPath'] ->
243+ let drvPath'' = S8. unpack drvPath'
244+ in if isJust $ parseAbsFile drvPath''
245+ then
246+ pure drvPath''
247+ else
248+ prettyThrowIO $
249+ NixInstantiateCommandInvalidDerivationPath
250+ instantiateArgs
251+ drvPath''
252+ drvPaths -> prettyThrowIO $
253+ NixInstantiateCommandNoSingleDerivationPath
254+ instantiateArgs
255+ drvPaths
256+ exec " nix-shell" (drvPath : shellArgs)
163257
164258-- | Shell-escape quotes inside the string and enclose it in quotes.
165259escape :: String -> String
0 commit comments