2021-07-22 23:46:12 +03:00
|
|
|
{-# language MultiWayIf #-}
|
|
|
|
{-# language TypeFamilies #-}
|
|
|
|
{-# language RecordWildCards #-}
|
2018-03-30 01:35:12 +03:00
|
|
|
|
2021-06-14 15:31:11 +03:00
|
|
|
module Main ( main ) where
|
2015-06-24 00:53:07 +03:00
|
|
|
|
2022-01-13 00:17:07 +03:00
|
|
|
import Nix.Prelude
|
2021-08-14 01:42:29 +03:00
|
|
|
import Relude as Prelude ( force )
|
2019-03-18 04:43:23 +03:00
|
|
|
import Control.Comonad ( extract )
|
2021-07-16 02:39:24 +03:00
|
|
|
import qualified Control.Exception as Exception
|
2021-03-21 19:21:59 +03:00
|
|
|
import GHC.Err ( errorWithoutStackTrace )
|
2021-05-31 16:30:22 +03:00
|
|
|
import Control.Monad.Free
|
|
|
|
import Control.Monad.Ref ( MonadRef(readRef) )
|
2018-04-21 08:36:40 +03:00
|
|
|
import Control.Monad.Catch
|
2021-08-14 01:42:29 +03:00
|
|
|
import System.IO ( hPutStrLn )
|
2019-03-18 00:47:38 +03:00
|
|
|
import qualified Data.HashMap.Lazy as M
|
|
|
|
import qualified Data.Map as Map
|
2018-05-03 07:32:00 +03:00
|
|
|
import Data.Time
|
2019-03-18 00:47:38 +03:00
|
|
|
import qualified Data.Text.IO as Text
|
2021-07-16 02:39:24 +03:00
|
|
|
import Text.Show.Pretty ( ppShow )
|
|
|
|
import Nix hiding ( force )
|
2018-04-18 00:24:52 +03:00
|
|
|
import Nix.Convert
|
2018-12-09 21:57:58 +03:00
|
|
|
import Nix.Json
|
2018-05-09 02:40:56 +03:00
|
|
|
import Nix.Options.Parser
|
2019-03-23 01:16:01 +03:00
|
|
|
import Nix.Standard
|
2019-03-11 18:04:15 +03:00
|
|
|
import Nix.Thunk.Basic
|
2021-06-01 18:23:01 +03:00
|
|
|
import Nix.Type.Env ( Env(..) )
|
|
|
|
import Nix.Type.Type ( Scheme )
|
2019-03-18 00:47:38 +03:00
|
|
|
import qualified Nix.Type.Infer as HM
|
2019-03-19 03:04:11 +03:00
|
|
|
import Nix.Value.Monad
|
2019-03-18 00:47:38 +03:00
|
|
|
import Options.Applicative hiding ( ParserResult(..) )
|
2021-03-30 17:41:17 +03:00
|
|
|
import Prettyprinter hiding ( list )
|
2021-07-16 02:39:24 +03:00
|
|
|
import Prettyprinter.Render.Text ( renderIO )
|
2018-04-18 00:24:52 +03:00
|
|
|
import qualified Repl
|
2021-07-15 21:45:19 +03:00
|
|
|
import Nix.Eval
|
2015-06-24 00:53:07 +03:00
|
|
|
|
|
|
|
main :: IO ()
|
2021-03-30 17:41:17 +03:00
|
|
|
main =
|
|
|
|
do
|
2021-11-07 01:21:26 +03:00
|
|
|
currentTime <- getCurrentTime
|
|
|
|
opts <- execParser $ nixOptionsInfo currentTime
|
2021-03-06 20:34:16 +03:00
|
|
|
|
2021-06-14 15:31:11 +03:00
|
|
|
main' opts
|
2021-03-06 20:34:16 +03:00
|
|
|
|
2021-06-14 15:31:11 +03:00
|
|
|
main' :: Options -> IO ()
|
2021-07-15 21:45:19 +03:00
|
|
|
main' opts@Options{..} = runWithBasicEffectsIO opts execContentsFilesOrRepl
|
2021-03-06 20:34:16 +03:00
|
|
|
where
|
2021-07-15 21:45:19 +03:00
|
|
|
-- 2021-07-15: NOTE: This logic should be weaved stronger through CLI options logic (OptParse-Applicative code)
|
|
|
|
-- As this logic is not stated in the CLI documentation, for example. So user has no knowledge of these.
|
2021-11-05 18:36:10 +03:00
|
|
|
execContentsFilesOrRepl :: StdIO
|
2021-06-14 15:31:11 +03:00
|
|
|
execContentsFilesOrRepl =
|
2021-07-15 21:45:19 +03:00
|
|
|
fromMaybe
|
2021-08-14 01:42:29 +03:00
|
|
|
loadFromCliFilePathList
|
2021-11-05 18:40:10 +03:00
|
|
|
$ loadBinaryCacheFile <|>
|
2021-07-15 21:45:19 +03:00
|
|
|
loadLiteralExpression <|>
|
|
|
|
loadExpressionFromFile
|
|
|
|
where
|
|
|
|
-- | The base case: read expressions from the last CLI directive (@[FILE]@) listed on the command line.
|
2021-11-05 18:36:10 +03:00
|
|
|
loadFromCliFilePathList :: StdIO
|
2021-08-14 01:42:29 +03:00
|
|
|
loadFromCliFilePathList =
|
2021-11-06 02:56:26 +03:00
|
|
|
case getFilePaths of
|
2021-07-15 21:45:19 +03:00
|
|
|
[] -> runRepl
|
|
|
|
["-"] -> readExpressionFromStdin
|
2021-07-23 02:30:07 +03:00
|
|
|
_paths -> processSeveralFiles (coerce _paths)
|
2021-07-15 21:45:19 +03:00
|
|
|
where
|
|
|
|
-- | Fall back to running the REPL
|
|
|
|
runRepl = withEmptyNixContext Repl.main
|
2021-06-14 15:31:11 +03:00
|
|
|
|
2021-07-15 21:45:19 +03:00
|
|
|
readExpressionFromStdin =
|
2021-11-05 18:40:10 +03:00
|
|
|
processExpr =<< liftIO Text.getContents
|
2021-06-14 15:31:11 +03:00
|
|
|
|
2021-11-05 18:36:10 +03:00
|
|
|
processSeveralFiles :: [Path] -> StdIO
|
2021-10-13 14:12:59 +03:00
|
|
|
processSeveralFiles = traverse_ processFile
|
2021-07-15 21:45:19 +03:00
|
|
|
where
|
|
|
|
processFile path = handleResult (pure path) =<< parseNixFileLoc path
|
|
|
|
|
|
|
|
-- | The `--read` option: load expression from a serialized file.
|
2021-11-05 18:36:10 +03:00
|
|
|
loadBinaryCacheFile :: Maybe StdIO
|
2021-07-15 21:45:19 +03:00
|
|
|
loadBinaryCacheFile =
|
2021-08-14 02:10:05 +03:00
|
|
|
(\ (binaryCacheFile :: Path) ->
|
2021-07-15 21:45:19 +03:00
|
|
|
do
|
2021-10-13 15:26:29 +03:00
|
|
|
let file = replaceExtension binaryCacheFile "nixc"
|
2021-11-05 18:40:10 +03:00
|
|
|
processCLIOptions (pure file) =<< liftIO (readCache binaryCacheFile)
|
2021-11-06 02:56:26 +03:00
|
|
|
) <$> getReadFrom
|
2021-06-14 15:31:11 +03:00
|
|
|
|
2021-07-15 21:45:19 +03:00
|
|
|
-- | The `--expr` option: read expression from the argument string
|
2021-11-05 18:36:10 +03:00
|
|
|
loadLiteralExpression :: Maybe StdIO
|
2021-11-06 02:56:26 +03:00
|
|
|
loadLiteralExpression = processExpr <$> getExpression
|
2021-06-14 15:31:11 +03:00
|
|
|
|
2021-07-15 21:45:19 +03:00
|
|
|
-- | The `--file` argument: read expressions from the files listed in the argument file
|
2021-11-05 18:36:10 +03:00
|
|
|
loadExpressionFromFile :: Maybe StdIO
|
2021-07-15 21:45:19 +03:00
|
|
|
loadExpressionFromFile =
|
2021-07-23 02:30:07 +03:00
|
|
|
-- We can start use Text as in the base case, requires changing Path -> Text
|
2021-07-15 21:45:19 +03:00
|
|
|
-- But that is a gradual process:
|
|
|
|
-- https://github.com/haskell-nix/hnix/issues/912
|
2021-08-14 01:42:29 +03:00
|
|
|
(processSeveralFiles . (coerce . toString <$>) . lines <=< liftIO) .
|
2021-07-15 21:45:19 +03:00
|
|
|
(\case
|
2021-08-14 01:42:29 +03:00
|
|
|
"-" -> Text.getContents
|
2021-08-14 02:24:00 +03:00
|
|
|
_fp -> readFile _fp
|
2021-11-06 02:56:26 +03:00
|
|
|
) <$> getFromFile
|
2021-06-14 15:31:11 +03:00
|
|
|
|
2021-11-05 18:36:10 +03:00
|
|
|
processExpr :: Text -> StdIO
|
2021-11-05 18:40:10 +03:00
|
|
|
processExpr = handleResult mempty . parseNixTextLoc
|
2021-03-06 20:34:16 +03:00
|
|
|
|
2021-07-15 21:45:19 +03:00
|
|
|
withEmptyNixContext = withNixContext mempty
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-07-16 02:39:24 +03:00
|
|
|
-- 2021-07-15: NOTE: @handleResult@ & @process@ - have atrocious size & compexity, they need to be decomposed & refactored.
|
2021-06-14 15:31:11 +03:00
|
|
|
handleResult mpath =
|
2021-03-12 17:15:21 +03:00
|
|
|
either
|
|
|
|
(\ err ->
|
|
|
|
bool
|
|
|
|
errorWithoutStackTrace
|
|
|
|
(liftIO . hPutStrLn stderr)
|
2021-11-06 02:56:26 +03:00
|
|
|
isIgnoreErrors
|
2021-03-12 17:15:21 +03:00
|
|
|
$ "Parse failed: " <> show err
|
|
|
|
)
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-03-11 23:17:26 +03:00
|
|
|
(\ expr ->
|
|
|
|
do
|
2021-11-06 02:56:26 +03:00
|
|
|
when isCheck $
|
2021-03-11 23:17:26 +03:00
|
|
|
do
|
2021-07-15 21:45:19 +03:00
|
|
|
expr' <- liftIO $ reduceExpr mpath expr
|
2021-03-11 23:17:26 +03:00
|
|
|
either
|
2021-07-16 02:39:24 +03:00
|
|
|
(\ err -> errorWithoutStackTrace $ "Type error: " <> ppShow err)
|
2021-11-05 18:40:10 +03:00
|
|
|
(liftIO . putStrLn . (<>) "Type of expression: " .
|
|
|
|
ppShow . maybeToMonoid . Map.lookup @VarName @[Scheme] "it" . coerce
|
2021-03-11 23:17:26 +03:00
|
|
|
)
|
2021-11-05 18:40:10 +03:00
|
|
|
$ HM.inferTop mempty $ curry one "it" $ stripAnnotation expr'
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-03-11 23:17:26 +03:00
|
|
|
-- liftIO $ putStrLn $ runST $
|
|
|
|
-- runLintM opts . renderSymbolic =<< lint opts expr
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-07-15 21:45:19 +03:00
|
|
|
catch (processCLIOptions mpath expr) $
|
2021-03-11 23:17:26 +03:00
|
|
|
\case
|
|
|
|
NixException frames ->
|
2021-03-30 17:41:17 +03:00
|
|
|
errorWithoutStackTrace . show =<<
|
|
|
|
renderFrames
|
2021-11-05 18:36:10 +03:00
|
|
|
@StdVal
|
|
|
|
@StdThun
|
2021-03-30 17:41:17 +03:00
|
|
|
frames
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-11-06 02:56:26 +03:00
|
|
|
when isRepl $
|
2021-07-15 21:45:19 +03:00
|
|
|
withEmptyNixContext $
|
2021-03-11 23:17:26 +03:00
|
|
|
bool
|
|
|
|
Repl.main
|
2021-11-05 18:40:10 +03:00
|
|
|
((Repl.main' . pure) =<< nixEvalExprLoc (coerce mpath) expr)
|
2021-11-06 02:56:26 +03:00
|
|
|
isEvaluate
|
2021-03-11 23:17:26 +03:00
|
|
|
)
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-07-15 21:45:19 +03:00
|
|
|
-- 2021-07-15: NOTE: Logic of CLI Option processing is scattered over several functions, needs to be consolicated.
|
2021-11-05 18:36:10 +03:00
|
|
|
processCLIOptions :: Maybe Path -> NExprLoc -> StdIO
|
2021-07-15 21:45:19 +03:00
|
|
|
processCLIOptions mpath expr
|
2021-11-06 02:56:26 +03:00
|
|
|
| isEvaluate =
|
2021-03-06 21:02:11 +03:00
|
|
|
if
|
2021-11-06 02:56:26 +03:00
|
|
|
| isTrace -> evaluateExprWith nixTracingEvalExprLoc expr
|
2022-01-11 17:24:27 +03:00
|
|
|
| Just path <- getReduce -> evaluateExprWith (reduction path . coerce) expr
|
|
|
|
| null getArg || null getArgstr -> evaluateExprWith nixEvalExprLoc expr
|
2021-07-23 02:30:07 +03:00
|
|
|
| otherwise -> processResult printer <=< nixEvalExprLoc (coerce mpath) $ expr
|
2021-11-06 02:56:26 +03:00
|
|
|
| isXml = fail "Rendering expression trees to XML is not yet implemented"
|
|
|
|
| isJson = fail "Rendering expression trees to JSON is not implemented"
|
2022-01-11 17:24:27 +03:00
|
|
|
| getVerbosity >= DebugInfo = liftIO . putStr . ppShow . stripAnnotation $ expr
|
|
|
|
| isCache , Just path <- mpath = liftIO . writeCache (replaceExtension path "nixc") $ expr
|
|
|
|
| isParseOnly = void . liftIO . Exception.evaluate . force $ expr
|
|
|
|
| otherwise =
|
2021-07-16 02:39:24 +03:00
|
|
|
liftIO .
|
2021-03-06 21:02:11 +03:00
|
|
|
renderIO
|
|
|
|
stdout
|
|
|
|
. layoutPretty (LayoutOptions $ AvailablePerLine 80 0.4)
|
|
|
|
. prettyNix
|
2021-06-14 15:31:11 +03:00
|
|
|
. stripAnnotation
|
|
|
|
$ expr
|
2019-03-18 00:47:38 +03:00
|
|
|
where
|
2021-11-06 00:24:32 +03:00
|
|
|
evaluateExprWith evaluator = evaluateExpression (coerce mpath) evaluator printer
|
2021-07-16 02:39:24 +03:00
|
|
|
|
2019-03-18 00:47:38 +03:00
|
|
|
printer
|
2021-11-05 18:36:10 +03:00
|
|
|
:: StdVal
|
|
|
|
-> StdIO
|
|
|
|
printer
|
2021-11-06 02:56:26 +03:00
|
|
|
| isFinder = findAttrs <=< fromValue @(AttrSet StdVal)
|
2021-07-16 02:39:24 +03:00
|
|
|
| otherwise = printer'
|
2019-03-18 00:47:38 +03:00
|
|
|
where
|
2022-01-11 18:20:59 +03:00
|
|
|
-- 2021-05-27: NOTE: With naive fix of the #941
|
|
|
|
-- This is overall a naive printer implementation, as options should interact/respect one another.
|
|
|
|
-- A nice question: "Should respect one another to what degree?": Go full combinator way, for which
|
|
|
|
-- old Nix CLI is nototrious for (and that would mean to reimplement the old Nix CLI),
|
|
|
|
-- OR: https://github.com/haskell-nix/hnix/issues/172 and have some sane standart/default behaviour for (most) keys.
|
2021-07-16 02:39:24 +03:00
|
|
|
printer'
|
2022-01-11 18:20:59 +03:00
|
|
|
| isXml = out (ignoreContext . toXML) normalForm
|
|
|
|
| isJson = out (ignoreContext . mempty . toJSONNixString) normalForm
|
|
|
|
| isStrict = out (show . prettyNValue) normalForm
|
|
|
|
| isValues = out (show . prettyNValueProv) removeEffects
|
|
|
|
| otherwise = out (show . prettyNValue) removeEffects
|
2021-07-16 02:39:24 +03:00
|
|
|
where
|
2022-01-11 18:20:59 +03:00
|
|
|
out
|
2021-07-16 02:39:24 +03:00
|
|
|
:: (b -> Text)
|
2021-11-05 18:36:10 +03:00
|
|
|
-> (a -> StandardIO b)
|
2021-07-16 02:39:24 +03:00
|
|
|
-> a
|
2021-11-05 18:36:10 +03:00
|
|
|
-> StdIO
|
2022-01-11 18:20:59 +03:00
|
|
|
out transform val = liftIO . Text.putStrLn . transform <=< val
|
2021-07-16 02:39:24 +03:00
|
|
|
|
2019-03-27 07:21:12 +03:00
|
|
|
findAttrs
|
2021-11-05 18:36:10 +03:00
|
|
|
:: AttrSet StdVal
|
|
|
|
-> StdIO
|
2021-02-25 20:42:09 +03:00
|
|
|
findAttrs = go mempty
|
2019-03-18 00:47:38 +03:00
|
|
|
where
|
2021-11-05 18:36:10 +03:00
|
|
|
go :: Text -> AttrSet StdVal -> StdIO
|
2021-03-30 17:41:17 +03:00
|
|
|
go prefix s =
|
2021-11-05 18:43:00 +03:00
|
|
|
traverse_
|
|
|
|
(\ (k, mv) ->
|
|
|
|
do
|
|
|
|
let
|
|
|
|
path = prefix <> k
|
|
|
|
(report, descend) = filterEntry path k
|
|
|
|
when report $
|
|
|
|
do
|
|
|
|
liftIO $ Text.putStrLn path
|
|
|
|
when descend $
|
|
|
|
maybe
|
|
|
|
stub
|
|
|
|
(\case
|
|
|
|
NVSet _ s' -> go (path <> ".") s'
|
|
|
|
_ -> stub
|
|
|
|
)
|
|
|
|
mv
|
|
|
|
)
|
|
|
|
=<< traverse
|
2021-03-30 17:41:17 +03:00
|
|
|
(\ (k, nv) ->
|
2021-05-31 16:40:23 +03:00
|
|
|
(k, ) <$>
|
2021-04-14 23:23:48 +03:00
|
|
|
free
|
2021-03-30 17:41:17 +03:00
|
|
|
(\ (StdThunk (extract -> Thunk _ _ ref)) ->
|
|
|
|
do
|
|
|
|
let
|
2021-04-03 20:37:30 +03:00
|
|
|
path = prefix <> k
|
2021-03-30 17:41:17 +03:00
|
|
|
(_, descend) = filterEntry path k
|
|
|
|
|
2021-11-05 18:36:10 +03:00
|
|
|
val <- readRef @StandardIO ref
|
2021-05-31 16:40:23 +03:00
|
|
|
bool
|
|
|
|
(pure Nothing)
|
|
|
|
(forceEntry path nv)
|
|
|
|
(descend &&
|
2021-11-05 18:43:00 +03:00
|
|
|
deferred
|
2022-01-11 17:24:27 +03:00
|
|
|
(const False)
|
|
|
|
(const True)
|
|
|
|
val
|
2021-05-31 16:40:23 +03:00
|
|
|
)
|
2021-03-30 17:41:17 +03:00
|
|
|
)
|
2021-05-31 16:40:23 +03:00
|
|
|
(pure . pure . Free)
|
2021-03-30 17:41:17 +03:00
|
|
|
nv
|
|
|
|
)
|
2021-07-17 02:22:22 +03:00
|
|
|
(sortWith fst $ M.toList $ M.mapKeys coerce s)
|
2019-03-18 00:47:38 +03:00
|
|
|
where
|
|
|
|
filterEntry path k = case (path, k) of
|
2021-03-30 17:41:17 +03:00
|
|
|
("stdenv", "stdenv" ) -> (True , True )
|
2019-03-18 00:47:38 +03:00
|
|
|
(_ , "stdenv" ) -> (False, False)
|
2021-03-30 17:41:17 +03:00
|
|
|
(_ , "out" ) -> (True , False)
|
|
|
|
(_ , "src" ) -> (True , False)
|
|
|
|
(_ , "mirrorsFile" ) -> (True , False)
|
|
|
|
(_ , "buildPhase" ) -> (True , False)
|
2019-03-18 00:47:38 +03:00
|
|
|
(_ , "builder" ) -> (False, False)
|
|
|
|
(_ , "drvPath" ) -> (False, False)
|
|
|
|
(_ , "outPath" ) -> (False, False)
|
|
|
|
(_ , "__impureHostDeps") -> (False, False)
|
|
|
|
(_ , "__sandboxProfile") -> (False, False)
|
2021-03-30 17:41:17 +03:00
|
|
|
("pkgs" , "pkgs" ) -> (True , True )
|
2019-03-18 00:47:38 +03:00
|
|
|
(_ , "pkgs" ) -> (False, False)
|
|
|
|
(_ , "drvAttrs" ) -> (False, False)
|
2021-03-30 17:41:17 +03:00
|
|
|
_ -> (True , True )
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-04-03 20:37:30 +03:00
|
|
|
forceEntry
|
2021-11-05 18:36:10 +03:00
|
|
|
:: MonadValue a StandardIO
|
2021-04-03 20:37:30 +03:00
|
|
|
=> Text
|
|
|
|
-> a
|
2021-11-05 18:36:10 +03:00
|
|
|
-> StandardIO (Maybe a)
|
2019-03-18 00:47:38 +03:00
|
|
|
forceEntry k v =
|
2021-03-30 17:41:17 +03:00
|
|
|
catch
|
2021-04-15 16:05:42 +03:00
|
|
|
(pure <$> demand v)
|
2021-11-05 18:43:00 +03:00
|
|
|
fun
|
|
|
|
where
|
|
|
|
fun :: NixException -> StandardIO (Maybe a)
|
|
|
|
fun (coerce -> frames) =
|
|
|
|
do
|
|
|
|
liftIO
|
|
|
|
. Text.putStrLn
|
|
|
|
. (("Exception forcing " <> k <> ": ") <>)
|
|
|
|
. show =<<
|
|
|
|
renderFrames
|
|
|
|
@StdVal
|
|
|
|
@StdThun
|
|
|
|
frames
|
|
|
|
pure Nothing
|
2019-03-18 00:47:38 +03:00
|
|
|
|
2021-07-15 21:45:19 +03:00
|
|
|
reduction path mpathToContext annExpr =
|
2021-03-30 17:41:17 +03:00
|
|
|
do
|
|
|
|
eres <-
|
2021-07-15 21:45:19 +03:00
|
|
|
withNixContext
|
|
|
|
mpathToContext
|
2021-11-05 18:43:00 +03:00
|
|
|
$ reducingEvalExpr
|
|
|
|
evalContent
|
|
|
|
mpathToContext
|
|
|
|
annExpr
|
2021-03-30 17:41:17 +03:00
|
|
|
handleReduced path eres
|
2019-03-18 00:47:38 +03:00
|
|
|
|
|
|
|
handleReduced
|
|
|
|
:: (MonadThrow m, MonadIO m)
|
2021-07-23 02:30:07 +03:00
|
|
|
=> Path
|
2019-03-18 00:47:38 +03:00
|
|
|
-> (NExprLoc, Either SomeException (NValue t f m))
|
|
|
|
-> m (NValue t f m)
|
2021-07-23 02:30:07 +03:00
|
|
|
handleReduced (coerce -> path) (expr', eres) =
|
2021-03-30 17:41:17 +03:00
|
|
|
do
|
|
|
|
liftIO $
|
|
|
|
do
|
2021-05-25 17:25:00 +03:00
|
|
|
putStrLn $ "Wrote sifted expression tree to " <> path
|
2021-05-25 14:27:50 +03:00
|
|
|
writeFile path $ show $ prettyNix $ stripAnnotation expr'
|
2021-05-28 12:01:35 +03:00
|
|
|
either throwM pure eres
|