hnix 0.11.1 → 0.12.0
raw patch · 35 files changed
+784/−221 lines, 35 filesdep +hnix-store-remotedep ~base16-bytestringdep ~hnix-store-coredep ~http-clientPVP ok
version bump matches the API change (PVP)
Dependencies added: hnix-store-remote
Dependency ranges changed: base16-bytestring, hnix-store-core, http-client
API changes (from Hackage documentation)
- Nix.Effects: addPath' :: MonadStore m => FilePath -> m (Either ErrorCall StorePath)
- Nix.Effects: toFile_' :: MonadStore m => FilePath -> String -> m (Either ErrorCall StorePath)
- Nix.Effects.Basic: defaultDerivationStrict :: forall e t f m. MonadNix e t f m => NValue t f m -> m (NValue t f m)
- Nix.Reduce: instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState (Data.HashMap.Internal.HashMap GHC.IO.FilePath Nix.Expr.Types.Annotated.NExprLoc) (Nix.Reduce.Reducer m)
- Nix.Standard: instance (Control.Monad.Fix.MonadFix m, Nix.Render.MonadFile m, Control.Monad.Catch.MonadCatch m, Nix.Effects.MonadEnv m, Nix.Effects.MonadPaths m, Nix.Effects.MonadExec m, Nix.Effects.MonadHttp m, Nix.Effects.MonadInstantiate m, Nix.Effects.MonadIntrospect m, GHC.Base.MonadPlus m, Nix.Effects.MonadPutStr m, Nix.Effects.MonadStore m, Control.Monad.Ref.MonadAtomicRef m, Data.Typeable.Internal.Typeable m, Nix.Scope.Scoped (Nix.Standard.StdValue m) m, Control.Monad.Reader.Class.MonadReader (Nix.Context.Context m (Nix.Standard.StdValue m)) m, Control.Monad.State.Class.MonadState (Data.HashMap.Internal.HashMap GHC.IO.FilePath Nix.Expr.Types.Annotated.NExprLoc) m, Nix.Value.MonadDataErrorContext (Nix.Standard.StdThunk m) (Nix.Standard.StdCited m) m, Nix.Thunk.MonadThunk (Nix.Standard.StdThunk m) m (Nix.Standard.StdValue m), Nix.Value.Monad.MonadValue (Nix.Standard.StdValue m) m) => Nix.Effects.MonadEffects (Nix.Standard.StdThunk m) (Nix.Standard.StdCited m) m
- Nix.Standard: instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState (Data.HashMap.Internal.HashMap GHC.IO.FilePath Nix.Expr.Types.Annotated.NExprLoc) (Nix.Standard.StandardTF r m)
+ Nix.Effects: addTextToStore :: (Framed e m, MonadStore m) => StorePathName -> Text -> StorePathSet -> RepairFlag -> m StorePath
+ Nix.Effects: addTextToStore' :: (MonadStore m, MonadTrans t, MonadStore m', m ~ t m') => StorePathName -> Text -> StorePathSet -> RepairFlag -> m (Either ErrorCall StorePath)
+ Nix.Effects: addToStore :: (MonadStore m, MonadTrans t, MonadStore m', m ~ t m') => StorePathName -> FilePath -> RecursiveFlag -> RepairFlag -> m (Either ErrorCall StorePath)
+ Nix.Effects: parseStoreResult :: Monad m => String -> (Either String a, [Logger]) -> m (Either ErrorCall a)
+ Nix.Effects: type FilePathFilter m = FilePath -> m Bool
+ Nix.Effects: type RecursiveFlag = Bool
+ Nix.Effects: type RepairFlag = Bool
+ Nix.Effects: type StorePathName = Text
+ Nix.Effects: type StorePathSet = HashSet StorePath
+ Nix.Effects.Derivation: defaultDerivationStrict :: forall e t f m b. (MonadNix e t f m, MonadState (b, HashMap Text Text) m) => NValue t f m -> m (NValue t f m)
+ Nix.Effects.Derivation: instance GHC.Classes.Eq Nix.Effects.Derivation.HashMode
+ Nix.Effects.Derivation: instance GHC.Show.Show Nix.Effects.Derivation.Derivation
+ Nix.Effects.Derivation: instance GHC.Show.Show Nix.Effects.Derivation.HashMode
+ Nix.Reduce: instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState (Data.HashMap.Internal.HashMap GHC.IO.FilePath Nix.Expr.Types.Annotated.NExprLoc, Data.HashMap.Internal.HashMap Data.Text.Internal.Text Data.Text.Internal.Text) (Nix.Reduce.Reducer m)
+ Nix.Standard: instance (Control.Monad.Fix.MonadFix m, Nix.Render.MonadFile m, Control.Monad.Catch.MonadCatch m, Nix.Effects.MonadEnv m, Nix.Effects.MonadPaths m, Nix.Effects.MonadExec m, Nix.Effects.MonadHttp m, Nix.Effects.MonadInstantiate m, Nix.Effects.MonadIntrospect m, GHC.Base.MonadPlus m, Nix.Effects.MonadPutStr m, Nix.Effects.MonadStore m, Control.Monad.Ref.MonadAtomicRef m, Data.Typeable.Internal.Typeable m, Nix.Scope.Scoped (Nix.Standard.StdValue m) m, Control.Monad.Reader.Class.MonadReader (Nix.Context.Context m (Nix.Standard.StdValue m)) m, Control.Monad.State.Class.MonadState (Data.HashMap.Internal.HashMap GHC.IO.FilePath Nix.Expr.Types.Annotated.NExprLoc, Data.HashMap.Internal.HashMap Data.Text.Internal.Text Data.Text.Internal.Text) m, Nix.Value.MonadDataErrorContext (Nix.Standard.StdThunk m) (Nix.Standard.StdCited m) m, Nix.Thunk.MonadThunk (Nix.Standard.StdThunk m) m (Nix.Standard.StdValue m), Nix.Value.Monad.MonadValue (Nix.Standard.StdValue m) m) => Nix.Effects.MonadEffects (Nix.Standard.StdThunk m) (Nix.Standard.StdCited m) m
+ Nix.Standard: instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState (Data.HashMap.Internal.HashMap GHC.IO.FilePath Nix.Expr.Types.Annotated.NExprLoc, Data.HashMap.Internal.HashMap Data.Text.Internal.Text Data.Text.Internal.Text) (Nix.Standard.StandardTF r m)
+ Nix.String: runWithStringContext' :: WithStringContextT Identity a -> (a, HashSet StringContext)
+ Nix.String: runWithStringContextT' :: Monad m => WithStringContextT m a -> m (a, HashSet StringContext)
- Nix.Effects.Basic: defaultImportPath :: (MonadNix e t f m, MonadState (HashMap FilePath NExprLoc) m) => FilePath -> m (NValue t f m)
+ Nix.Effects.Basic: defaultImportPath :: (MonadNix e t f m, MonadState (HashMap FilePath NExprLoc, b) m) => FilePath -> m (NValue t f m)
- Nix.Standard: StandardTF :: ReaderT (Context r (StdValue r)) (StateT (HashMap FilePath NExprLoc) m) a -> StandardTF r m a
+ Nix.Standard: StandardTF :: ReaderT (Context r (StdValue r)) (StateT (HashMap FilePath NExprLoc, HashMap Text Text) m) a -> StandardTF r m a
- Nix.Standard: mkStandardT :: ReaderT (Context (StandardT m) (StdValue (StandardT m))) (StateT (HashMap FilePath NExprLoc) m) a -> StandardT m a
+ Nix.Standard: mkStandardT :: ReaderT (Context (StandardT m) (StdValue (StandardT m))) (StateT (HashMap FilePath NExprLoc, HashMap Text Text) m) a -> StandardT m a
- Nix.Standard: runStandardT :: StandardT m a -> ReaderT (Context (StandardT m) (StdValue (StandardT m))) (StateT (HashMap FilePath NExprLoc) m) a
+ Nix.Standard: runStandardT :: StandardT m a -> ReaderT (Context (StandardT m) (StdValue (StandardT m))) (StateT (HashMap FilePath NExprLoc, HashMap Text Text) m) a
- Nix.Utils: infixl 6 -
+ Nix.Utils: infixl 6 +
- Nix.Utils: seq :: a -> b -> b
+ Nix.Utils: seq :: forall (r :: RuntimeRep) a (b :: TYPE r). a -> b -> b
Files
- CHANGELOG.md +50/−7
- README.md +26/−25
- data/nix/corepkgs/fetchurl.nix +41/−0
- data/nix/corepkgs/imported-drv-to-derivation.nix +21/−0
- data/nix/corepkgs/unpack-channel.nix +39/−0
- hnix.cabal +16/−4
- main/Repl.hs +12/−12
- src/Nix/Atoms.hs +4/−4
- src/Nix/Builtins.hs +12/−4
- src/Nix/Cache.hs +2/−1
- src/Nix/Convert.hs +7/−7
- src/Nix/Effects.hs +55/−27
- src/Nix/Effects/Basic.hs +6/−49
- src/Nix/Effects/Derivation.hs +395/−0
- src/Nix/Exec.hs +1/−1
- src/Nix/Expr/Types.hs +6/−6
- src/Nix/Frames.hs +1/−0
- src/Nix/Fresh/Basic.hs +1/−3
- src/Nix/Normal.hs +4/−1
- src/Nix/Options.hs +1/−0
- src/Nix/Options/Parser.hs +1/−0
- src/Nix/Parser.hs +2/−1
- src/Nix/Reduce.hs +9/−8
- src/Nix/Render.hs +1/−1
- src/Nix/Render/Frame.hs +3/−2
- src/Nix/Standard.hs +12/−9
- src/Nix/String.hs +18/−2
- src/Nix/Type/Env.hs +3/−3
- src/Nix/Type/Infer.hs +9/−9
- src/Nix/Type/Type.hs +3/−1
- src/Nix/Value.hs +19/−30
- tests/EvalTests.hs +1/−1
- tests/Main.hs +1/−1
- tests/ParserTests.hs +1/−1
- tests/PrettyTests.hs +1/−1
CHANGELOG.md view
@@ -1,17 +1,60 @@ # Changelog -## [(diff)](https://github.com/haskell-nix/hnix/compare/0.11.0...master#files_bucket) Progress+## [(diff)](https://github.com/haskell-nix/hnix/compare/0.12.0...master#files_bucket) Progress ++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.11.1...0.12.0#files_bucket) 0.12.0 (2020-12-31)++* *Disclaimer*: Current `derivationStrict` primOp implementation and so every evaluation of a derivation into a store path currently relies on the `hnix-store-remote`, which for those operations relies on the running `nix-daemon`, and so operations use/produce effects into the `/nix/store`. Be cautious - it is effectful.++* Introduction:+ * New module `Nix.Effects.Derivation`.+ * Operations on derivations:+ * old got principled implementations.+ * also new operations got introduced.+ * Implementation of the `derivationStrict` primOp.++* Breaking:+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: **class** `MonadStore` got principled implementation.+ * `addPath'` got principled into `addToStore`.+ * `toFile_` got principled into `addTextToStore'`.+ * For help & easy migration you may use `addPath` & `toFile_` `addTextToStore` standalone functions in the module.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects.Basic`: `defaultDerivationStrict` got reimplemented & moved into `Nix.Effects.Derivation`.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Standard`: instance for `MonadStore (Fix1T t m)` got principled accoding to class `MonadStore` changes.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Fresh.Basic`: instance for `MonadStore (StdIdT m)` got principled.++* Additional:+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) **New module `Nix.Effects.Derivation`**: [HNix(0.12.0):Nix.Effects.Derivation documentation](https://hackage.haskell.org/package/hnix-0.12.0/docs/Nix-Effects-Derivation.html).+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/9bcfbbe88ff0bd8d803296193ee1d8603dc5289e) `Nix.Convert`: Principled `NVPath -> NixString` coercion.+ * In a form of principled `instance FromValue NixString m (NValue' t f m (NValue t f m))`.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/a8e6d28fdb98a1c34f425c8395338fdabe96becc) `Nix.String`: Allow custom computations inside string contexts.+ * By providing `runWithStringContext{T,}'` methods into the API.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/e45f7632c51a9657f6e8d54c39fd4d21c466d85f) Includded support for new `base16-bytestring`, which advertices 2x-4x speed increase of its operations.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: `addPath` & `toFile_` standalone functions got principled implementation through the internal use of the new `MonadStore` type class implementation.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: added `addTextToStore`, `parseStoreResult` implementations.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: added type synonyms `{RecursiveFlag, RepairFlag, StorePathName, FilePathFilter, StorePathSet}`.+ * [(link)](https://github.com/haskell-nix/hnix/pull/760) `Nix.Exec`: Fixed the rendering of internal `Frames`.+ * Which is an internal mechanism of a project to passing around messages with their context, still to be used internally).+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/3bba5549273c892c60aad5dd6d5058a8db40efbf) `HNix / Nix`: The library now also uses `hnix-store-remote`.+ * [(link)](https://github.com/haskell-nix/hnix/pull/554/06b0fca9fd607eb2e995f003424e797a41ffa5b7) `cabal.project`: project uses `cryptohash-sha512` override, the `hnix-store-core` requires it from `hnix` and uses that override also. [Detailed info](https://github.com/haskell-hvr/cryptohash-sha512/pull/5#issuecomment-752796913). We promise to attend to this issue, probably by migrating to `cryptonite` in the nearest releases.++Future note: The HNix is a big project. During the initial development and currently the API for simplicity exposes allmost all functions, types, etc. Big open API means a big effort to create/maintain a quite noisy changelog and you parsing through it, and also creates a frequent requirements to mark releases as major and bother you due to some type changes in some parts that may not be used or applicable to be public API.++This year the most gracious API clean-up would happen, we would check and keep open what Hackage projects are using from the API, and the other parts would be open on the request by a way of rapid minor releases. That clean-up is also a work toward splitting the project into several packages some time in the future (split would be into something like Expressions, Evaluation, Executable, Extra), which migration also would be done most thoughful and graceful as possible, with as much easiness and automation provided for migration downstream as possible. If all goes as planned - all downstream would need to do is to get and run our script that would migrate our old map of module imports to new ones, and maybe manually add those newly formed packages into `.cabal` description.++If it is possible, please, try to switch & use the higher-level API functions where it is applicable. Thank you.++ ### [(diff)](https://github.com/haskell-nix/hnix/compare/0.11.0...0.11.1#files_bucket) 0.11.1 (2020-12-09) * Additional:- * [(link)](https://github.com/haskell-nix/hnix/commit/d32a6fbaf3df1c8879d1b19a18f21c031a73e56c) `Nix/Builtins`: `isString` fixed - It used to return `True` for values coercible to string like derivations and paths. It only accepts string values now.- * [(link)](https://github.com/haskell-nix/hnix/commit/53b4db2525a8f074d8c262fa7b66ce97e5820890) `Nix/Builtins`: `substring` fixed - Negative lengths used to capture an empty string. Now they capture the whole rmeainder of the string.- * [(link)](https://github.com/haskell-nix/hnix/commit/dc31c5e64f8c7aaaea14cac0134bd47544533e67) `Nix/Effects`: `pathExists` fixed - Now also works with directories.- * [(link)](https://github.com/haskell-nix/hnix/commit/e2ad934492eeac9881527610e4a1c1cf31ea1115) `Nix/Parser`: `->` is now properly right-associative (was non-associative).- * [(link)](https://github.com/haskell-nix/hnix/commit/50baea5e1e482be3c4fcc13c9a45b1083243f681) `Nix/Parser`: Nix `assert` parser (`nixAssert` function) now accepts top-level Nix format also (which means also accepts all kinds of statements), before that it accepted only regular Nix expressions.- * [(link)](https://github.com/haskell-nix/hnix/commit/59698de7185dfae508e5ccea4377a82023c4a0d5) `Nix/Render`: `renderLocation` now also shows/handles location of errors in raw strings.+ * [(link)](https://github.com/haskell-nix/hnix/commit/d32a6fbaf3df1c8879d1b19a18f21c031a73e56c) `Nix.Builtins`: `isString` fixed - It used to return `True` for values coercible to string like derivations and paths. It only accepts string values now.+ * [(link)](https://github.com/haskell-nix/hnix/commit/53b4db2525a8f074d8c262fa7b66ce97e5820890) `Nix.Builtins`: `substring` fixed - Negative lengths used to capture an empty string. Now they capture the whole rmeainder of the string.+ * [(link)](https://github.com/haskell-nix/hnix/commit/dc31c5e64f8c7aaaea14cac0134bd47544533e67) `Nix.Effects`: `pathExists` fixed - Now also works with directories.+ * [(link)](https://github.com/haskell-nix/hnix/commit/e2ad934492eeac9881527610e4a1c1cf31ea1115) `Nix.Parser`: `->` is now properly right-associative (was non-associative).+ * [(link)](https://github.com/haskell-nix/hnix/commit/50baea5e1e482be3c4fcc13c9a45b1083243f681) `Nix.Parser`: Nix `assert` parser (`nixAssert` function) now accepts top-level Nix format also (which means also accepts all kinds of statements), before that it accepted only regular Nix expressions.+ * [(link)](https://github.com/haskell-nix/hnix/commit/59698de7185dfae508e5ccea4377a82023c4a0d5) `Nix.Render`: `renderLocation` now also shows/handles location of errors in raw strings. ## [(diff)](https://github.com/haskell-nix/hnix/compare/0.10.1...0.11.0#files_bucket) 0.11.0 (2020-11-02)
README.md view
@@ -17,7 +17,6 @@ <!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> - - [Prerequisites](#prerequisites) - [Getting Started](#getting-started) - [Cachix prebuild binary caches](#cachix-prebuild-binary-caches)@@ -44,11 +43,13 @@ ## Prerequisites Tooling is WIP, `nix-shell` and `nix-store` are still used for their purpose, so, to access them Nix is required to be installed. +*Disclaimer*: Current `derivationStrict` primOp implementation and so every evaluation of a derivation into a store path currently relies on the `hnix-store-remote`, which for those operations relies on the running `nix-daemon`, and so operations use/produce effects into the `/nix/store`. Be cautious - it is effectful.+ ## Getting Started -```+```shell # Note: --recursive-git clone --recursive https://github.com/haskell-nix/hnix.git+git clone --recursive 'https://github.com/haskell-nix/hnix.git' cd hnix ``` @@ -67,35 +68,35 @@ Cabal [Quickstart](https://cabal.readthedocs.io/en/3.4/nix-local-build.html). 1. (Optional), to enter the projects reproducible Nix environment:-```+```shell nix-shell ``` 2. Building:-```+```shell cabal v2-configure cabal v2-build ``` 3. Loading the project into `ghci` REPL:-```+```shell cabal v2-repl ``` 4. Testing: * Default suite:-```+```shell cabal v2-test ``` * All available tests:-```+```shell env ALL_TESTS=yes cabal v2-test ``` * Selected (list of tests is in `tests/Main.hs`):-```+```shell env NIXPKGS_TESTS=yes PRETTY_TESTS=1 cabal v2-test ``` @@ -105,7 +106,7 @@ To run benchmarks: -```+```shell cabal v2-bench ``` @@ -113,7 +114,7 @@ To build `hnix` with profiling enabled: -```+```shell cabal v2-configure --enable-tests --enable-profiling --flags=profiling cabal v2-run hnix -- <args> +RTS -p ```@@ -122,7 +123,7 @@ To build `hnix` for debugging, with full tracing output and stack traces: -```+```shell cabal v2-configure --enable-tests --enable-profiling --flags=profiling --flags=tracing cabal v2-run hnix -- -v5 --trace <args> +RTS -xc ```@@ -131,7 +132,7 @@ #### Run HNix-```+```shell cabal v2-run hnix -- --help ``` (`--` is for separation between `cabal` & `hnix` args)@@ -142,7 +143,7 @@ There is a number of build options to use with `nix-build`, documentation of them is in: `./default.nix`, keys essentially pass-through the [Nixpkgs Haskell Lib API](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/lib.nix). Options can be used as:-```+```shell nix-build \ --arg <option1> <argument1> \ --arg <option2> <argument2> \@@ -151,7 +152,7 @@ #### Run benchmarks -```+```shell nix-build \ --arg disableOptimization false \ --arg enableDeadCodeElimination true \@@ -161,7 +162,7 @@ #### With profiling -```+```shell nix-build \ --arg disableOptimization false \ --arg enableDeadCodeElimination true \@@ -171,7 +172,7 @@ #### With full debug info -```+```shell nix-build \ --arg disableOptimization false \ --arg enableDeadCodeElimination true \@@ -185,13 +186,13 @@ #### Run the result -```+```shell ./result/bin/hnix ``` ## Development status loop with amazing [`ghcid`](https://github.com/ndmitchell/ghcid) -```+```shell ghcid --command="cabal v2-repl --repl-options=-fno-code --repl-options=-fno-break-on-exception --repl-options=-fno-break-on-error --repl-options=-v1 --repl-options=-ferror-spans --repl-options=-j" ``` (optional) To use projects reproducible environment, wrap `ghcid ...` command into a `nix-shell --command ' '`.@@ -202,12 +203,12 @@ ## Using the HNix REPL Enter in:-```+```shell hnix --repl ``` Evaluate an expression:-```+```shell hnix --eval -E '(import <nixpkgs> {}).pkgs.hello' --repl ``` This also binds the evaluated expression result to the `input` variable, so that variable can be inspected.@@ -218,7 +219,7 @@ Nix is a lazy language with the ability of recursion, so by default REPL and eval prints are lazy: -```+```shell hnix \ --eval \ --expr '{ x = true; }'@@ -228,7 +229,7 @@ To disable laziness add the `--strict` to commands or `:set strict` in the REPL. -```+```shell hnix \ --eval \ # Strictly \@@ -246,7 +247,7 @@ 3. When the pull request is ready to be submitted, to save time - please, test it with: -```+```shell git submodule update --init --recursive nix-shell --run "LANGUAGE_TESTS=yes cabal v2-test" ```@@ -257,6 +258,6 @@ Currently, the main high-level goal is to be able to evaluate all of Nixpkgs: -```+```shell hnix --eval -E "import <nixpkgs> {}" --find ```
+ data/nix/corepkgs/fetchurl.nix view
@@ -0,0 +1,41 @@+{ system ? "" # obsolete+, url+, hash ? "" # an SRI ash++# Legacy hash specification+, md5 ? "", sha1 ? "", sha256 ? "", sha512 ? ""+, outputHash ?+ if hash != "" then hash else if sha512 != "" then sha512 else if sha1 != "" then sha1 else if md5 != "" then md5 else sha256+, outputHashAlgo ?+ if hash != "" then "" else if sha512 != "" then "sha512" else if sha1 != "" then "sha1" else if md5 != "" then "md5" else "sha256"++, executable ? false+, unpack ? false+, name ? baseNameOf (toString url)+}:++derivation {+ builder = "builtin:fetchurl";++ # New-style output content requirements.+ inherit outputHashAlgo outputHash;+ outputHashMode = if unpack || executable then "recursive" else "flat";++ inherit name url executable unpack;++ system = "builtin";++ # No need to double the amount of network traffic+ preferLocalBuild = true;++ impureEnvVars = [+ # We borrow these environment variables from the caller to allow+ # easy proxy configuration. This is impure, but a fixed-output+ # derivation like fetchurl is allowed to do so since its result is+ # by definition pure.+ "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"+ ];++ # To make "nix-prefetch-url" work.+ urls = [ url ];+}
+ data/nix/corepkgs/imported-drv-to-derivation.nix view
@@ -0,0 +1,21 @@+attrs @ { drvPath, outputs, name, ... }:++let++ commonAttrs = (builtins.listToAttrs outputsList) //+ { all = map (x: x.value) outputsList;+ inherit drvPath name;+ type = "derivation";+ };++ outputToAttrListElement = outputName:+ { name = outputName;+ value = commonAttrs // {+ outPath = builtins.getAttr outputName attrs;+ inherit outputName;+ };+ };+ + outputsList = map outputToAttrListElement outputs;+ +in (builtins.head outputsList).value
+ data/nix/corepkgs/unpack-channel.nix view
@@ -0,0 +1,39 @@+with import <nix/config.nix>;++let++ builder = builtins.toFile "unpack-channel.sh"+ ''+ mkdir $out+ cd $out+ xzpat="\.xz\$"+ gzpat="\.gz\$"+ if [[ "$src" =~ $xzpat ]]; then+ ${xz} -d < $src | ${tar} xf - ${tarFlags}+ elif [[ "$src" =~ $gzpat ]]; then+ ${gzip} -d < $src | ${tar} xf - ${tarFlags}+ else+ ${bzip2} -d < $src | ${tar} xf - ${tarFlags}+ fi+ if [ * != $channelName ]; then+ mv * $out/$channelName+ fi+ '';++in++{ name, channelName, src }:++derivation {+ system = builtins.currentSystem;+ builder = shell;+ args = [ "-e" builder ];+ inherit name channelName src;++ PATH = "${nixBinDir}:${coreutils}";++ # No point in doing this remotely.+ preferLocalBuild = true;++ inherit chrootDeps;+}
hnix.cabal view
@@ -1,5 +1,5 @@ name: hnix-version: 0.11.1+version: 0.12.0 synopsis: Haskell implementation of the Nix language description: Haskell implementation of the Nix language. category: System, Data, Nix@@ -11,9 +11,19 @@ license-file: LICENSE build-type: Simple cabal-version: >= 1.10+data-dir: data/+data-files:+ nix/corepkgs/buildenv.nix+ nix/corepkgs/unpack-channel.nix+ nix/corepkgs/derivation.nix+ nix/corepkgs/fetchurl.nix+ nix/corepkgs/imported-drv-to-derivation.nix extra-source-files: data/nix/corepkgs/buildenv.nix+ data/nix/corepkgs/unpack-channel.nix data/nix/corepkgs/derivation.nix+ data/nix/corepkgs/fetchurl.nix+ data/nix/corepkgs/imported-drv-to-derivation.nix data/nix/tests/lang/binary-data data/nix/tests/lang/data data/nix/tests/lang/dir1/a.nix@@ -341,6 +351,7 @@ Nix.Convert Nix.Effects Nix.Effects.Basic+ Nix.Effects.Derivation Nix.Eval Nix.Exec Nix.Expr@@ -401,8 +412,9 @@ , gitrev >= 1.1.0 && < 1.4 , hashable >= 1.2.5 && < 1.4 , hashing >= 0.1.0 && < 0.2- , hnix-store-core >= 0.1.0 && < 0.3- , http-client >= 0.5.14 && < 0.6 || >= 0.6.4 && < 0.8+ , hnix-store-core >= 0.4.0 && < 0.5+ , hnix-store-remote >= 0.4.0 && < 0.5+ , http-client >= 0.5.14 && < 0.6 || >= 0.6.4 && < 0.7 , http-client-tls >= 0.3.5 && < 0.4 , http-types >= 0.12.2 && < 0.13 , lens-family >= 1.2.2 && < 2.2@@ -442,7 +454,7 @@ exposed-modules: Nix.Options.Parser build-depends:- base16-bytestring >= 0.1.1 && < 0.2+ base16-bytestring >= 0.1.1 && < 1.1 , pretty-show >= 1.9.5 && < 1.11 , serialise >= 0.2.1 && < 0.3 -- if !flag(profiling)
main/Repl.hs view
@@ -124,9 +124,9 @@ | s `Data.List.isPrefixOf` x = m args | otherwise = optMatcher s xs args ----------------------------------------------------------------------------------- Types--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Types+--------------------------------------------------------------------------------- data IState t f m = IState { replIt :: Maybe NExprLoc -- ^ Last expression entered@@ -171,9 +171,9 @@ type Repl e t f m = HaskelineT (StateT (IState t f m) m) ----------------------------------------------------------------------------------- Execution--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Execution+--------------------------------------------------------------------------------- exec :: forall e t f m@@ -257,9 +257,9 @@ | cfgValues cfg -> liftIO . print . prettyNValueProv =<< removeEffects val | otherwise -> liftIO . print . prettyNValue =<< removeEffects val ----------------------------------------------------------------------------------- Commands--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Commands+--------------------------------------------------------------------------------- -- :browse command browse :: (MonadNix e t f m, MonadIO m)@@ -315,9 +315,9 @@ [opt] -> modify (\s -> s { replCfg = helpSetOptionFunction opt (replCfg s) }) _ -> liftIO $ putStrLn "No such option" ----------------------------------------------------------------------------------- Interactive Shell--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Interactive Shell+--------------------------------------------------------------------------------- -- Prefix tab completer defaultMatcher :: MonadIO m => [(String, CompletionFunc m)]
src/Nix/Atoms.hs view
@@ -45,9 +45,9 @@ atomText (NURI t) = t atomText (NInt i) = pack (show i) atomText (NFloat f) = pack (showNixFloat f)- where- showNixFloat x- | x `mod'` 1 /= 0 = show x- | otherwise = show (truncate x :: Int)+ where+ showNixFloat x+ | x `mod'` 1 /= 0 = show x+ | otherwise = show (truncate x :: Int) atomText (NBool b) = if b then "true" else "false" atomText NNull = "null"
src/Nix/Builtins.hs view
@@ -22,6 +22,7 @@ {-# OPTIONS_GHC -Wno-missing-signatures #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-} +-- | Code that implements Nix builtins. Lists the functions that are built into the Nix expression evaluator. Some built-ins (aka `derivation`), are always in the scope, so they can be accessed by the name. To keap the namespace clean, most built-ins are inside the `builtins` scope - a set that contains all what is a built-in. module Nix.Builtins (withNixContext, builtins) where import Control.Comonad@@ -1197,6 +1198,7 @@ -- prim_hashString from nix/src/libexpr/primops.cc -- fail if context in the algo arg -- propagate context from the s arg+-- | The result coming out of hashString is base16 encoded hashString :: forall e t f m. MonadNix e t f m => NixString -> NixString -> Prim m NixString hashString nsAlgo ns = Prim $ do@@ -1232,10 +1234,16 @@ $ principledMakeNixStringWithoutContext $ Text.cons '/' $ Base32.encode- $ fst -- The result coming out of hashString is base16 encoded- $ Base16.decode- $ encodeUtf8- $ principledStringIgnoreContext h+ $ case Base16.decode (text h) of -- The result coming out of hashString is base16 encoded+#if MIN_VERSION_base16_bytestring(1,0,0)+ Right d -> d+ Left e -> error $ "Couldn't Base16 decode the text: '" <> show (text h) <> "'.\nThe Left error content: '" <> e <> "'."+#else+ (d, "") -> d+ (_, e) -> error $ "Couldn't Base16 decode the text: '" <> show (text h) <> "'.\nUndecodable remainder: '" <> show e <> "'."+#endif+ where+ text h = encodeUtf8 $ principledStringIgnoreContext h absolutePathFromValue :: MonadNix e t f m => NValue t f m -> m FilePath absolutePathFromValue = \case
src/Nix/Cache.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} +-- | Reading and writing Nix cache files module Nix.Cache where import qualified Data.ByteString.Lazy as BS@@ -38,7 +39,7 @@ writeCache :: FilePath -> NExprLoc -> IO () writeCache path expr = #ifdef USE_COMPACT- C.writeCompact path =<< C.compact expr+ C.writeCompact path =<< C.compact expr #else #ifdef MIN_VERSION_serialise BS.writeFile path (S.serialise expr)
src/Nix/Convert.hs view
@@ -61,9 +61,9 @@ -} -{------------------------------------------------------------------------ FromValue- -----------------------------------------------------------------------}+---------------------------------------------------------------------------------+-- * FromValue+--------------------------------------------------------------------------------- class FromValue a m v where fromValue :: v -> m a@@ -151,7 +151,7 @@ NVStr' ns -> pure $ Just ns NVPath' p -> Just- . hackyMakeNixStringWithoutContext+ . (\s -> principledMakeNixStringWithSingletonContext s (StringContext s DirectPath)) . Text.pack . unStorePath <$> addPath p@@ -260,9 +260,9 @@ fromValueMay = fromValueMay . getDeeper fromValue = fromValue . getDeeper -{------------------------------------------------------------------------ ToValue- -----------------------------------------------------------------------}+---------------------------------------------------------------------------------+-- * ToValue+--------------------------------------------------------------------------------- class ToValue a m v where toValue :: a -> m v
src/Nix/Effects.hs view
@@ -7,6 +7,8 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeApplications #-} module Nix.Effects where @@ -17,24 +19,31 @@ import qualified Prelude import Control.Monad.Trans+import qualified Data.HashSet as HS import Data.Text ( Text ) import qualified Data.Text as T-import Network.HTTP.Client hiding ( path )+import qualified Data.Text.Encoding as T+import Network.HTTP.Client hiding ( path, Proxy ) import Network.HTTP.Client.TLS import Network.HTTP.Types import Nix.Expr-import Nix.Frames+import Nix.Frames hiding ( Proxy ) import Nix.Parser import Nix.Render import Nix.Utils import Nix.Value import qualified Paths_hnix-import qualified System.Directory as S import System.Environment import System.Exit+import System.FilePath ( takeFileName ) import qualified System.Info import System.Process +import qualified System.Nix.Hash as Store+import qualified System.Nix.Store.Remote as Store+import qualified System.Nix.Store.Remote.Types as Store+import qualified System.Nix.StorePath as Store+ -- | A path into the nix store newtype StorePath = StorePath { unStorePath :: FilePath } @@ -226,36 +235,55 @@ instance MonadPutStr IO where putStr = Prelude.putStr ++type RecursiveFlag = Bool+type RepairFlag = Bool+type StorePathName = Text+type FilePathFilter m = FilePath -> m Bool+type StorePathSet = HS.HashSet StorePath+ class Monad m => MonadStore m where- -- | Import a path into the nix store, and return the resulting path- addPath' :: FilePath -> m (Either ErrorCall StorePath) - -- | Add a file with the given name and contents to the nix store- toFile_' :: FilePath -> String -> m (Either ErrorCall StorePath)+ -- | Copy the contents of a local path to the store. The resulting store+ -- path is returned. Note: This does not support yet support the expected+ -- `filter` function that allows excluding some files.+ addToStore :: StorePathName -> FilePath -> RecursiveFlag -> RepairFlag -> m (Either ErrorCall StorePath)+ default addToStore :: (MonadTrans t, MonadStore m', m ~ t m') => StorePathName -> FilePath -> RecursiveFlag -> RepairFlag -> m (Either ErrorCall StorePath)+ addToStore a b c d = lift $ addToStore a b c d + -- | Like addToStore, but the contents written to the output path is a+ -- regular file containing the given string.+ addTextToStore' :: StorePathName -> Text -> Store.StorePathSet -> RepairFlag -> m (Either ErrorCall StorePath)+ default addTextToStore' :: (MonadTrans t, MonadStore m', m ~ t m') => StorePathName -> Text -> Store.StorePathSet -> RepairFlag -> m (Either ErrorCall StorePath)+ addTextToStore' a b c d = lift $ addTextToStore' a b c d++parseStoreResult :: Monad m => String -> (Either String a, [Store.Logger]) -> m (Either ErrorCall a)+parseStoreResult name res = case res of+ (Left msg, logs) -> return $ Left $ ErrorCall $ "Failed to execute '" ++ name ++ "': " ++ msg ++ "\n" ++ show logs+ (Right result, _) -> return $ Right result+ instance MonadStore IO where- addPath' path = do- (exitCode, out, _) <- readProcessWithExitCode "nix-store" ["--add", path] ""- case exitCode of- ExitSuccess -> do- let dropTrailingLinefeed p = take (length p - 1) p- pure $ Right $ StorePath $ dropTrailingLinefeed out- _ ->- pure- $ Left- $ ErrorCall- $ "addPath: failed: nix-store --add "- ++ show path - --TODO: Use a temp directory so we don't overwrite anything important- toFile_' filepath content = do- writeFile filepath content- storepath <- addPath' filepath- S.removeFile filepath- pure storepath+ addToStore name path recursive repair = case Store.makeStorePathName name of+ Left err -> return $ Left $ ErrorCall $ "String '" ++ show name ++ "' is not a valid path name: " ++ err+ Right pathName -> do+ -- TODO: redesign the filter parameter+ res <- Store.runStore $ Store.addToStore @'Store.SHA256 pathName path recursive (const False) repair+ parseStoreResult "addToStore" res >>= \case+ Left err -> return $ Left err+ Right storePath -> return $ Right $ StorePath $ T.unpack $ T.decodeUtf8 $ Store.storePathToRawFilePath storePath + addTextToStore' name text references repair = do+ res <- Store.runStore $ Store.addTextToStore name text references repair+ parseStoreResult "addTextToStore" res >>= \case+ Left err -> return $ Left err+ Right path -> return $ Right $ StorePath $ T.unpack $ T.decodeUtf8 $ Store.storePathToRawFilePath path++addTextToStore :: (Framed e m, MonadStore m) => StorePathName -> Text -> Store.StorePathSet -> RepairFlag -> m StorePath+addTextToStore a b c d = either throwError return =<< addTextToStore' a b c d+ addPath :: (Framed e m, MonadStore m) => FilePath -> m StorePath-addPath p = either throwError pure =<< addPath' p+addPath p = either throwError return =<< addToStore (T.pack $ takeFileName p) p True False toFile_ :: (Framed e m, MonadStore m) => FilePath -> String -> m StorePath-toFile_ p contents = either throwError pure =<< toFile_' p contents+toFile_ p contents = addTextToStore (T.pack p) (T.pack contents) HS.empty False
src/Nix/Effects/Basic.hs view
@@ -8,10 +8,6 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-} -{-# OPTIONS_GHC -Wno-missing-signatures #-}-{-# OPTIONS_GHC -Wno-orphans #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}- module Nix.Effects.Basic where import Control.Monad@@ -20,30 +16,24 @@ import qualified Data.HashMap.Lazy as M import Data.List import Data.List.Split-import Data.Maybe ( maybeToList ) import Data.Text ( Text ) import qualified Data.Text as Text-import Nix.Atoms+import Data.Text.Prettyprint.Doc import Nix.Convert import Nix.Effects import Nix.Exec ( MonadNix- , callFunc , evalExprLoc , nixInstantiateExpr ) import Nix.Expr import Nix.Frames-import Nix.Normal import Nix.Parser-import Nix.Pretty import Nix.Render import Nix.Scope import Nix.String-import Nix.String.Coerce import Nix.Utils import Nix.Value import Nix.Value.Monad-import Prettyprinter import System.FilePath #ifdef MIN_VERSION_ghc_datasize@@ -126,8 +116,8 @@ -> [NValue t f m] -> FilePath -> m FilePath-findPathBy finder l name = do- mpath <- foldM go Nothing l+findPathBy finder ls name = do+ mpath <- foldM go Nothing ls case mpath of Nothing -> throwError@@ -235,13 +225,13 @@ pure $ if exists then Just apath else Nothing defaultImportPath- :: (MonadNix e t f m, MonadState (HashMap FilePath NExprLoc) m)+ :: (MonadNix e t f m, MonadState (HashMap FilePath NExprLoc, b) m) => FilePath -> m (NValue t f m) defaultImportPath path = do traceM $ "Importing file " ++ path withFrame Info (ErrorCall $ "While importing file " ++ show path) $ do- imports <- get+ imports <- gets fst evalExprLoc =<< case M.lookup path imports of Just expr -> pure expr Nothing -> do@@ -252,7 +242,7 @@ $ ErrorCall . show $ fillSep ["Parse during import failed:", err] Success expr -> do- modify (M.insert path expr)+ modify (\(a, b) -> (M.insert path expr a, b)) pure expr defaultPathToDefaultNix :: MonadNix e t f m => FilePath -> m FilePath@@ -263,39 +253,6 @@ pathToDefaultNixFile p = do isDir <- doesDirectoryExist p pure $ if isDir then p </> "default.nix" else p--defaultDerivationStrict- :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)-defaultDerivationStrict = fromValue @(AttrSet (NValue t f m)) >=> \s -> do- nn <- maybe (pure False) (demand ?? fromValue) (M.lookup "__ignoreNulls" s)- s' <- M.fromList <$> mapMaybeM (handleEntry nn) (M.toList s)- v' <- normalForm =<< toValue @(AttrSet (NValue t f m)) @_ @(NValue t f m) s'- nixInstantiateExpr $ "derivationStrict " ++ show (prettyNValue v')- where- mapMaybeM :: (a -> m (Maybe b)) -> [a] -> m [b]- mapMaybeM op = foldr f (pure [])- where f x xs = op x >>= (<$> xs) . (++) . maybeToList-- handleEntry :: Bool -> (Text, NValue t f m) -> m (Maybe (Text, NValue t f m))- handleEntry ignoreNulls (k, v) = fmap (k, ) <$> case k of- -- The `args' attribute is special: it supplies the command-line- -- arguments to the builder.- -- TODO This use of coerceToString is probably not right and may- -- not have the right arguments.- "args" -> demand v $ fmap Just . coerceNixList- "__ignoreNulls" -> pure Nothing- _ -> demand v $ \case- NVConstant NNull | ignoreNulls -> pure Nothing- v' -> Just <$> coerceNix v'- where- coerceNix :: NValue t f m -> m (NValue t f m)- coerceNix = toValue <=< coerceToString callFunc CopyToStore CoerceAny-- coerceNixList :: NValue t f m -> m (NValue t f m)- coerceNixList v = do- xs <- fromValue @[NValue t f m] v- ys <- traverse (`demand` coerceNix) xs- toValue @[NValue t f m] ys defaultTraceEffect :: MonadPutStr m => String -> m () defaultTraceEffect = Nix.Effects.putStrLn
+ src/Nix/Effects/Derivation.hs view
@@ -0,0 +1,395 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+ ++module Nix.Effects.Derivation ( defaultDerivationStrict ) where++import Prelude hiding ( readFile )++import Control.Arrow ( first, second )+import Control.Monad ( (>=>), forM, when )+import Control.Monad.Writer ( join, lift )+import Control.Monad.State ( MonadState, gets, modify )++import Data.Char ( isAscii, isAlphaNum )+import qualified Data.HashMap.Lazy as M+import qualified Data.HashMap.Strict as MS+import qualified Data.HashSet as S+import Data.List+import qualified Data.Map.Strict as Map+import Data.Map.Strict ( Map )+import qualified Data.Set as Set+import Data.Set ( Set )+import Data.Text ( Text )+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text++import Nix.Atoms+import Nix.Convert+import Nix.Effects+import Nix.Exec ( MonadNix , callFunc)+import Nix.Frames+import Nix.Json ( nvalueToJSONNixString )+import Nix.Render+import Nix.String+import Nix.String.Coerce+import Nix.Utils hiding ( readFile )+import Nix.Value+import Nix.Value.Monad++import qualified System.Nix.ReadonlyStore as Store+import qualified System.Nix.Hash as Store+import qualified System.Nix.StorePath as Store++import Text.Megaparsec+import Text.Megaparsec.Char+++data Derivation = Derivation+ { name :: Text+ , outputs :: Map Text Text+ , inputs :: (Set Text, Map Text [Text])+ , platform :: Text+ , builder :: Text -- should be typed as a store path+ , args :: [ Text ]+ , env :: Map Text Text+ , mFixed :: Maybe Store.SomeNamedDigest+ , hashMode :: HashMode+ , useJson :: Bool+ }+ deriving Show++defaultDerivation :: Derivation+defaultDerivation = Derivation+ { name = undefined+ , outputs = Map.empty+ , inputs = (Set.empty, Map.empty)+ , platform = undefined+ , builder = undefined+ , args = []+ , env = Map.empty+ , mFixed = Nothing+ , hashMode = Flat+ , useJson = False+ }++data HashMode = Flat | Recursive+ deriving (Show, Eq)++makeStorePathName :: (Framed e m) => Text -> m Store.StorePathName+makeStorePathName name = case Store.makeStorePathName name of+ Left err -> throwError $ ErrorCall $ "Invalid name '" ++ show name ++ "' for use in a store path: " ++ err+ Right spname -> return spname++parsePath :: (Framed e m) => Text -> m Store.StorePath+parsePath p = case Store.parsePath "/nix/store" (Text.encodeUtf8 p) of+ Left err -> throwError $ ErrorCall $ "Cannot parse store path " ++ show p ++ ":\n" ++ show err+ Right path -> return path++writeDerivation :: (Framed e m, MonadStore m) => Derivation -> m Store.StorePath+writeDerivation (drv@Derivation {inputs, name}) = do+ let (inputSrcs, inputDrvs) = inputs+ references <- Set.fromList <$> (mapM parsePath $ Set.toList $ inputSrcs `Set.union` (Set.fromList $ Map.keys inputDrvs))+ path <- addTextToStore (Text.append name ".drv") (unparseDrv drv) (S.fromList $ Set.toList references) False+ parsePath $ Text.pack $ unStorePath path++-- | Traverse the graph of inputDrvs to replace fixed output derivations with their fixed output hash.+-- this avoids propagating changes to their .drv when the output hash stays the same.+hashDerivationModulo :: (MonadNix e t f m, MonadState (b, MS.HashMap Text Text) m) => Derivation -> m (Store.Digest 'Store.SHA256)+hashDerivationModulo (Derivation {+ mFixed = Just (Store.SomeDigest (digest :: Store.Digest hashType)),+ outputs,+ hashMode+ }) = case Map.toList outputs of+ [("out", path)] -> return $ Store.hash @'Store.SHA256 $ Text.encodeUtf8+ $ "fixed:out"+ <> (if hashMode == Recursive then ":r" else "")+ <> ":" <> (Store.algoName @hashType)+ <> ":" <> (Store.encodeInBase Store.Base16 digest)+ <> ":" <> path+ outputsList -> throwError $ ErrorCall $ "This is weird. A fixed output drv should only have one output named 'out'. Got " ++ show outputsList+hashDerivationModulo drv@(Derivation {inputs = (inputSrcs, inputDrvs)}) = do+ cache <- gets snd+ inputsModulo <- Map.fromList <$> forM (Map.toList inputDrvs) (\(path, outs) ->+ case MS.lookup path cache of+ Just hash -> return (hash, outs)+ Nothing -> do+ drv' <- readDerivation $ Text.unpack path+ hash <- Store.encodeInBase Store.Base16 <$> hashDerivationModulo drv'+ return (hash, outs)+ )+ return $ Store.hash @'Store.SHA256 $ Text.encodeUtf8 $ unparseDrv (drv {inputs = (inputSrcs, inputsModulo)})++unparseDrv :: Derivation -> Text+unparseDrv (Derivation {..}) = Text.append "Derive" $ parens+ [ -- outputs: [("out", "/nix/store/.....-out", "", ""), ...]+ list $ flip map (Map.toList outputs) (\(outputName, outputPath) ->+ let prefix = if hashMode == Recursive then "r:" else "" in+ case mFixed of+ Nothing -> parens [s outputName, s outputPath, s "", s ""]+ Just (Store.SomeDigest (digest :: Store.Digest hashType)) ->+ parens [s outputName, s outputPath, s $ prefix <> Store.algoName @hashType, s $ Store.encodeInBase Store.Base16 digest]+ )+ , -- inputDrvs+ list $ flip map (Map.toList $ snd inputs) (\(path, outs) ->+ parens [s path, list $ map s $ sort outs])+ , -- inputSrcs+ list (map s $ Set.toList $ fst inputs)+ , s platform+ , s builder+ , -- run script args+ list $ map s args+ , -- env (key value pairs)+ list $ flip map (Map.toList env) (\(k, v) ->+ parens [s k, s v])+ ]+ where+ parens :: [Text] -> Text+ parens ts = Text.concat ["(", Text.intercalate "," ts, ")"]+ list :: [Text] -> Text+ list ls = Text.concat ["[", Text.intercalate "," ls, "]"]+ s = (Text.cons '\"') . (flip Text.snoc '\"') . Text.concatMap escape+ escape :: Char -> Text+ escape '\\' = "\\\\"+ escape '\"' = "\\\""+ escape '\n' = "\\n"+ escape '\r' = "\\r"+ escape '\t' = "\\t"+ escape c = Text.singleton c++readDerivation :: (Framed e m, MonadFile m) => FilePath -> m Derivation+readDerivation path = do+ content <- Text.decodeUtf8 <$> readFile path+ case parse derivationParser path content of+ Left err -> throwError $ ErrorCall $ "Failed to parse " ++ show path ++ ":\n" ++ show err+ Right drv -> return drv++derivationParser :: Parsec () Text Derivation+derivationParser = do+ _ <- "Derive("+ fullOutputs <- list $+ fmap (\[n, p, ht, h] -> (n, p, ht, h)) $ parens s+ _ <- ","+ inputDrvs <- fmap Map.fromList $ list $+ fmap (,) ("(" *> s <* ",") <*> (list s <* ")")+ _ <- ","+ inputSrcs <- fmap Set.fromList $ list s+ _ <- ","+ platform <- s+ _ <- ","+ builder <- s+ _ <- ","+ args <- list s+ _ <- ","+ env <- fmap Map.fromList $ list $ fmap (\[a, b] -> (a, b)) $ parens s+ _ <- ")"+ eof++ let outputs = Map.fromList $ map (\(a, b, _, _) -> (a, b)) fullOutputs+ let (mFixed, hashMode) = parseFixed fullOutputs+ let name = "" -- FIXME (extract from file path ?)+ let useJson = ["__json"] == Map.keys env++ return $ Derivation {inputs = (inputSrcs, inputDrvs), ..}+ where+ s :: Parsec () Text Text+ s = fmap Text.pack $ string "\"" *> manyTill (escaped <|> regular) (string "\"")+ escaped = char '\\' *>+ ( '\n' <$ string "n"+ <|> '\r' <$ string "r"+ <|> '\t' <$ string "t"+ <|> anySingle+ )+ regular = noneOf ['\\', '"']++ parens :: Parsec () Text a -> Parsec () Text [a]+ parens p = (string "(") *> sepBy p (string ",") <* (string ")")+ list p = (string "[") *> sepBy p (string ",") <* (string "]")++ parseFixed :: [(Text, Text, Text, Text)] -> (Maybe Store.SomeNamedDigest, HashMode)+ parseFixed fullOutputs = case fullOutputs of+ [("out", _path, rht, hash)] | rht /= "" && hash /= "" ->+ let (hashType, hashMode) = case Text.splitOn ":" rht of+ ["r", ht] -> (ht, Recursive)+ [ht] -> (ht, Flat)+ _ -> error $ "Unsupported hash type for output of fixed-output derivation in .drv file: " ++ show fullOutputs+ in case Store.mkNamedDigest hashType hash of+ Right digest -> (Just digest, hashMode)+ Left err -> error $ "Unsupported hash " ++ show (hashType <> ":" <> hash) ++ "in .drv file: " ++ err+ _ -> (Nothing, Flat)+++defaultDerivationStrict :: forall e t f m b. (MonadNix e t f m, MonadState (b, MS.HashMap Text Text) m) => NValue t f m -> m (NValue t f m)+defaultDerivationStrict = fromValue @(AttrSet (NValue t f m)) >=> \s -> do+ (drv, ctx) <- runWithStringContextT' $ buildDerivationWithContext s+ drvName <- makeStorePathName $ name drv+ let inputs = toStorePaths ctx++ -- Compute the output paths, and add them to the environment if needed.+ -- Also add the inputs, just computed from the strings contexts.+ drv' <- case mFixed drv of+ Just (Store.SomeDigest digest) -> do+ let out = pathToText $ Store.makeFixedOutputPath "/nix/store" (hashMode drv == Recursive) digest drvName+ let env' = if useJson drv then env drv else Map.insert "out" out (env drv)+ return $ drv { inputs, env = env', outputs = Map.singleton "out" out }++ Nothing -> do+ hash <- hashDerivationModulo $ drv+ { inputs+ --, outputs = Map.map (const "") (outputs drv) -- not needed, this is already the case+ , env = if useJson drv then env drv+ else foldl' (\m k -> Map.insert k "" m) (env drv) (Map.keys $ outputs drv)+ }+ outputs' <- sequence $ Map.mapWithKey (\o _ -> makeOutputPath o hash drvName) (outputs drv)+ return $ drv+ { inputs+ , outputs = outputs'+ , env = if useJson drv then env drv else Map.union outputs' (env drv)+ }++ drvPath <- pathToText <$> writeDerivation drv'++ -- Memoize here, as it may be our last chance in case of readonly stores.+ drvHash <- Store.encodeInBase Store.Base16 <$> hashDerivationModulo drv'+ modify (\(a, b) -> (a, MS.insert drvPath drvHash b))++ let outputsWithContext = Map.mapWithKey (\out path -> principledMakeNixStringWithSingletonContext path (StringContext drvPath (DerivationOutput out))) (outputs drv')+ drvPathWithContext = principledMakeNixStringWithSingletonContext drvPath (StringContext drvPath AllOutputs)+ attrSet = M.map nvStr $ M.fromList $ ("drvPath", drvPathWithContext): Map.toList outputsWithContext+ -- TODO: Add location information for all the entries.+ -- here --v+ return $ nvSet attrSet M.empty++ where++ pathToText = Text.decodeUtf8 . Store.storePathToRawFilePath++ makeOutputPath o h n = do+ name <- makeStorePathName (Store.unStorePathName n <> if o == "out" then "" else "-" <> o)+ return $ pathToText $ Store.makeStorePath "/nix/store" ("output:" <> Text.encodeUtf8 o) h name++ toStorePaths ctx = foldl (flip addToInputs) (Set.empty, Map.empty) ctx+ addToInputs (StringContext path kind) = case kind of+ DirectPath -> first (Set.insert path)+ DerivationOutput o -> second (Map.insertWith (++) path [o])+ AllOutputs ->+ -- TODO: recursive lookup. See prim_derivationStrict+ -- XXX: When is this really used ?+ error "Not implemented: derivations depending on a .drv file are not yet supported."+++-- | Build a derivation in a context collecting string contexts.+-- This is complex from a typing standpoint, but it allows to perform the+-- full computation without worrying too much about all the string's contexts.+buildDerivationWithContext :: forall e t f m. (MonadNix e t f m) => AttrSet (NValue t f m) -> WithStringContextT m Derivation+buildDerivationWithContext drvAttrs = do+ -- Parse name first, so we can add an informative frame+ drvName <- getAttr "name" $ extractNixString >=> assertDrvStoreName+ withFrame' Info (ErrorCall $ "While evaluating derivation " ++ show drvName) $ do++ useJson <- getAttrOr "__structuredAttrs" False $ return+ ignoreNulls <- getAttrOr "__ignoreNulls" False $ return++ args <- getAttrOr "args" [] $ mapM (fromValue' >=> extractNixString)+ builder <- getAttr "builder" $ extractNixString+ platform <- getAttr "system" $ extractNoCtx >=> assertNonNull+ mHash <- getAttrOr "outputHash" Nothing $ extractNoCtx >=> (return . Just)+ hashMode <- getAttrOr "outputHashMode" Flat $ extractNoCtx >=> parseHashMode+ outputs <- getAttrOr "outputs" ["out"] $ mapM (fromValue' >=> extractNoCtx)++ mFixedOutput <- case mHash of+ Nothing -> return Nothing+ Just hash -> do+ when (outputs /= ["out"]) $ lift $ throwError $ ErrorCall $ "Multiple outputs are not supported for fixed-output derivations"+ hashType <- getAttr "outputHashAlgo" $ extractNoCtx+ digest <- lift $ either (throwError . ErrorCall) return $ Store.mkNamedDigest hashType hash+ return $ Just digest++ -- filter out null values if needed.+ attrs <- if not ignoreNulls+ then return drvAttrs+ else M.mapMaybe id <$> forM drvAttrs (demand' ?? (\case+ NVConstant NNull -> return Nothing+ value -> return $ Just value+ ))++ env <- if useJson+ then do+ jsonString :: NixString <- lift $ nvalueToJSONNixString $ flip nvSet M.empty $+ deleteKeys [ "args", "__ignoreNulls", "__structuredAttrs" ] attrs+ rawString :: Text <- extractNixString jsonString+ return $ Map.singleton "__json" rawString+ else+ mapM (lift . coerceToString callFunc CopyToStore CoerceAny >=> extractNixString) $+ Map.fromList $ M.toList $ deleteKeys [ "args", "__ignoreNulls" ] attrs++ return $ defaultDerivation { platform, builder, args, env, hashMode, useJson+ , name = drvName+ , outputs = Map.fromList $ map (\o -> (o, "")) outputs+ , mFixed = mFixedOutput+ }+ where+ -- common functions, lifted to WithStringContextT++ demand' :: NValue t f m -> (NValue t f m -> WithStringContextT m a) -> WithStringContextT m a+ demand' v f = join $ lift $ demand v (return . f)++ fromValue' :: (FromValue a m (NValue' t f m (NValue t f m)), MonadNix e t f m) => NValue t f m -> WithStringContextT m a+ fromValue' = lift . fromValue++ withFrame' :: (Framed e m, Exception s) => NixLevel -> s -> WithStringContextT m a -> WithStringContextT m a+ withFrame' level f = join . lift . withFrame level f . return++ -- shortcuts to get the (forced) value of an AttrSet field++ getAttrOr' :: forall v a. (MonadNix e t f m, FromValue v m (NValue' t f m (NValue t f m)))+ => Text -> m a -> (v -> WithStringContextT m a) -> WithStringContextT m a+ getAttrOr' n d f = case M.lookup n drvAttrs of+ Nothing -> lift d+ Just v -> withFrame' Info (ErrorCall $ "While evaluating attribute '" ++ show n ++ "'") $+ fromValue' v >>= f++ getAttrOr n d f = getAttrOr' n (return d) f++ getAttr n = getAttrOr' n (throwError $ ErrorCall $ "Required attribute '" ++ show n ++ "' not found.")++ -- Test validity for fields++ assertDrvStoreName :: MonadNix e t f m => Text -> WithStringContextT m Text+ assertDrvStoreName name = lift $ do+ let invalid c = not $ isAscii c && (isAlphaNum c || c `elem` ("+-._?=" :: String)) -- isAlphaNum allows non-ascii chars.+ let failWith reason = throwError $ ErrorCall $ "Store name " ++ show name ++ " " ++ reason+ when ("." `Text.isPrefixOf` name) $ failWith "cannot start with a period"+ when (Text.length name > 211) $ failWith "must be no longer than 211 characters"+ when (Text.any invalid name) $ failWith "contains some invalid character"+ when (".drv" `Text.isSuffixOf` name) $ failWith "is not allowed to end in '.drv'"+ return name++ extractNoCtx :: MonadNix e t f m => NixString -> WithStringContextT m Text+ extractNoCtx ns = case principledGetStringNoContext ns of+ Nothing -> lift $ throwError $ ErrorCall $ "The string " ++ show ns ++ " is not allowed to have a context."+ Just v -> return v++ assertNonNull :: MonadNix e t f m => Text -> WithStringContextT m Text+ assertNonNull t = do+ when (Text.null t) $ lift $ throwError $ ErrorCall "Value must not be empty"+ return t++ parseHashMode :: MonadNix e t f m => Text -> WithStringContextT m HashMode+ parseHashMode = \case+ "flat" -> return Flat+ "recursive" -> return Recursive+ other -> lift $ throwError $ ErrorCall $ "Hash mode " ++ show other ++ " is not valid. It must be either 'flat' or 'recursive'"++ -- Other helpers++ deleteKeys :: [Text] -> AttrSet a -> AttrSet a+ deleteKeys keys attrSet = foldl' (flip M.delete) attrSet keys+
src/Nix/Exec.hs view
@@ -301,7 +301,7 @@ f arg NVBuiltin name f -> do span <- currentPos- withFrame Info (Calling @m @t name span) (f arg)+ withFrame Info (Calling @m @(NValue t f m) name span) (f arg) s@(NVSet m _) | Just f <- M.lookup "__functor" m -> do demand f $ (`callFunc` s) >=> (`callFunc` arg) x -> throwError $ ErrorCall $ "Attempt to call non-function: " ++ show x
src/Nix/Expr/Types.hs view
@@ -8,7 +8,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}@@ -16,6 +15,7 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE InstanceSigs #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-missing-signatures #-}@@ -27,8 +27,8 @@ module Nix.Expr.Types where #ifdef MIN_VERSION_serialise+import qualified Codec.Serialise ( Serialise(decode, encode) ) -- For instance implementation function disamburgation import Codec.Serialise ( Serialise )-import qualified Codec.Serialise as Ser #endif import Control.Applicative import Control.DeepSeq@@ -348,12 +348,12 @@ instance Serialise r => Serialise (NKeyName r) instance Serialise Pos where- encode x = Ser.encode (unPos x)- decode = mkPos <$> Ser.decode+ encode x = Codec.Serialise.encode (unPos x)+ decode = mkPos <$> Codec.Serialise.decode instance Serialise SourcePos where- encode (SourcePos f l c) = Ser.encode f <> Ser.encode l <> Ser.encode c- decode = SourcePos <$> Ser.decode <*> Ser.decode <*> Ser.decode+ encode (SourcePos f l c) = Codec.Serialise.encode f <> Codec.Serialise.encode l <> Codec.Serialise.encode c+ decode = SourcePos <$> Codec.Serialise.decode <*> Codec.Serialise.decode <*> Codec.Serialise.decode #endif instance Hashable Pos where
src/Nix/Frames.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} +-- | Definitions of Frames. Frames are messages that gather and ship themself with a context related to the message. For example - the message about some exception would also gather, keep and bring with it the tracing information. module Nix.Frames ( NixLevel(..) , Frames
src/Nix/Fresh/Basic.hs view
@@ -22,9 +22,7 @@ instance (MonadFail m, MonadFile m) => MonadFile (StdIdT m) instance MonadIntrospect m => MonadIntrospect (StdIdT m)-instance MonadStore m => MonadStore (StdIdT m) where- addPath' = lift . addPath'- toFile_' = (lift .) . toFile_'+instance MonadStore m => MonadStore (StdIdT m) instance MonadPutStr m => MonadPutStr (StdIdT m) instance MonadHttp m => MonadHttp (StdIdT m) instance MonadEnv m => MonadEnv (StdIdT m)
src/Nix/Normal.hs view
@@ -9,6 +9,9 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} +-- | Code for normalization (reduction into a normal form) of Nix expressions.+-- Nix language allows recursion, so some expressions do not converge.+-- And so do not converge into a normal form. module Nix.Normal where import Control.Monad@@ -117,7 +120,7 @@ removeEffects = iterNValueM id- (flip queryM (pure opaque))+ (`queryM` pure opaque) (fmap Free . sequenceNValue' id) opaque :: Applicative f => NValue t f m
src/Nix/Options.hs view
@@ -1,3 +1,4 @@+-- | Definitions & defaults for the CLI options module Nix.Options where import Data.Text ( Text )
src/Nix/Options/Parser.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE TemplateHaskell #-} +-- | Code that configures presentation parser for the CLI options module Nix.Options.Parser where import Control.Arrow ( second )
src/Nix/Parser.hs view
@@ -9,6 +9,7 @@ {-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# OPTIONS_GHC -Wno-missing-signatures #-} +-- | Main module for parsing Nix expressions. module Nix.Parser ( parseNixFile , parseNixFileLoc@@ -90,7 +91,7 @@ (<+>) :: MonadPlus m => m a -> m a -> m a (<+>) = mplus ---------------------------------------------------------------------------------+--------------------------------------------------------------------------------- nixExpr :: Parser NExprLoc nixExpr = makeExprParser nixTerm $ map (map snd) (nixOperators nixSelector)
src/Nix/Reduce.hs view
@@ -42,6 +42,7 @@ import Data.Fix ( Fix(..), foldFix, foldFixM ) import Data.HashMap.Lazy ( HashMap ) import qualified Data.HashMap.Lazy as M+import qualified Data.HashMap.Strict as MS import Data.IORef import Data.List.NonEmpty ( NonEmpty(..) ) import qualified Data.List.NonEmpty as NE@@ -66,11 +67,11 @@ newtype Reducer m a = Reducer { runReducer :: ReaderT (Maybe FilePath, Scopes (Reducer m) NExprLoc)- (StateT (HashMap FilePath NExprLoc) m) a }+ (StateT (HashMap FilePath NExprLoc, MS.HashMap Text Text) m) a } deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadFix, MonadIO, MonadFail, MonadReader (Maybe FilePath, Scopes (Reducer m) NExprLoc),- MonadState (HashMap FilePath NExprLoc))+ MonadState (HashMap FilePath NExprLoc, MS.HashMap Text Text)) staticImport :: forall m@@ -78,7 +79,7 @@ , Scoped NExprLoc m , MonadFail m , MonadReader (Maybe FilePath, Scopes m NExprLoc) m- , MonadState (HashMap FilePath NExprLoc) m+ , MonadState (HashMap FilePath NExprLoc, HashMap Text Text) m ) => SrcSpan -> FilePath@@ -89,7 +90,7 @@ path' <- liftIO $ pathToDefaultNixFile =<< canonicalizePath (maybe path (\p -> takeDirectory p </> path) mfile) - imports <- get+ imports <- gets fst case M.lookup path' imports of Just expr -> pure expr Nothing -> go path'@@ -108,10 +109,10 @@ (Fix (NLiteralPath_ pann path)) pos x' = Fix (NLet_ span [cur] x)- modify (M.insert path x')+ modify (\(a, b) -> (M.insert path x' a, b)) local (const (Just path, emptyScopes @m @NExprLoc)) $ do x'' <- foldFix reduce x'- modify (M.insert path x'')+ modify (\(a, b) -> (M.insert path x'' a, b)) return x'' -- gatherNames :: NExprLoc -> HashSet VarName@@ -122,7 +123,7 @@ reduceExpr :: (MonadIO m, MonadFail m) => Maybe FilePath -> NExprLoc -> m NExprLoc reduceExpr mpath expr =- (`evalStateT` M.empty)+ (`evalStateT` (M.empty, MS.empty)) . (`runReaderT` (mpath, emptyScopes)) . runReducer $ foldFix reduce expr@@ -133,7 +134,7 @@ , Scoped NExprLoc m , MonadFail m , MonadReader (Maybe FilePath, Scopes m NExprLoc) m- , MonadState (HashMap FilePath NExprLoc) m+ , MonadState (HashMap FilePath NExprLoc, MS.HashMap Text Text) m ) => NExprLocF (m NExprLoc) -> m NExprLoc
src/Nix/Render.hs view
@@ -128,5 +128,5 @@ | otherwise = " " ++ n ls' = zipWith (<+>) (map (pretty . pad) nums')- (map ((<+>) "| ") ls)+ (map ("| " <+>) ls) pure $ vsep $ ls' ++ [msg]
src/Nix/Render/Frame.hs view
@@ -10,6 +10,8 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} ++-- | Code for rendering/representation of the messages packaged with their context (Frames). module Nix.Render.Frame where import Control.Monad.Reader@@ -152,8 +154,7 @@ | otherwise = prettyNix (Fix (Fix (NSym "<?>") <$ x)) pure $ if verbose opts >= Chatty then- vsep- $ [pretty (longLabel ++ ":\n>>>>>>>>"), indent 2 rendered, "<<<<<<<<"]+ vsep [pretty (longLabel ++ ":\n>>>>>>>>"), indent 2 rendered, "<<<<<<<<"] else pretty shortLabel <> fillSep [": ", rendered] renderValueFrame
src/Nix/Standard.hs view
@@ -30,6 +30,8 @@ import Control.Monad.Ref import Control.Monad.State import Data.HashMap.Lazy ( HashMap )+import qualified Data.HashMap.Strict+import Data.Text ( Text ) import Data.Typeable import GHC.Generics import Nix.Cited@@ -37,6 +39,7 @@ import Nix.Context import Nix.Effects import Nix.Effects.Basic+import Nix.Effects.Derivation import Nix.Expr.Types.Annotated import Nix.Fresh import Nix.Fresh.Basic@@ -82,10 +85,10 @@ instance (MonadFix1T t m, MonadFail (Fix1T t m), MonadFile m) => MonadFile (Fix1T t m) instance (MonadFix1T t m, MonadStore m) => MonadStore (Fix1T t m) where- addPath' = lift . addPath'- toFile_' n = lift . toFile_' n+ addToStore a b c d = lift $ addToStore a b c d+ addTextToStore' a b c d = lift $ addTextToStore' a b c d -{------------------------------------------------------------------------}+--------------------------------------------------------------------------------- newtype StdCited m a = StdCited { _stdCited :: Cited (StdThunk m) (StdCited m) m a }@@ -138,7 +141,7 @@ , Typeable m , Scoped (StdValue m) m , MonadReader (Context m (StdValue m)) m- , MonadState (HashMap FilePath NExprLoc) m+ , MonadState (HashMap FilePath NExprLoc, Data.HashMap.Strict.HashMap Text Text) m , MonadDataErrorContext (StdThunk m) (StdCited m) m , MonadThunk (StdThunk m) m (StdValue m) , MonadValue (StdValue m) m@@ -191,7 +194,7 @@ newtype StandardTF r m a = StandardTF (ReaderT (Context r (StdValue r))- (StateT (HashMap FilePath NExprLoc) m) a)+ (StateT (HashMap FilePath NExprLoc, HashMap Text Text) m) a) deriving ( Functor , Applicative@@ -205,7 +208,7 @@ , MonadThrow , MonadMask , MonadReader (Context r (StdValue r))- , MonadState (HashMap FilePath NExprLoc)+ , MonadState (HashMap FilePath NExprLoc, HashMap Text Text) ) instance MonadTrans (StandardTF r) where@@ -219,7 +222,7 @@ instance (MonadExec r, MonadExec m) => MonadExec (StandardTF r m) instance (MonadIntrospect r, MonadIntrospect m) => MonadIntrospect (StandardTF r m) -{------------------------------------------------------------------------}+--------------------------------------------------------------------------------- type StandardT m = Fix1T StandardTF m @@ -232,7 +235,7 @@ mkStandardT :: ReaderT (Context (StandardT m) (StdValue (StandardT m)))- (StateT (HashMap FilePath NExprLoc) m)+ (StateT (HashMap FilePath NExprLoc, Data.HashMap.Strict.HashMap Text Text) m) a -> StandardT m a mkStandardT = Fix1T . StandardTF@@ -241,7 +244,7 @@ :: StandardT m a -> ReaderT (Context (StandardT m) (StdValue (StandardT m)))- (StateT (HashMap FilePath NExprLoc) m)+ (StateT (HashMap FilePath NExprLoc, Data.HashMap.Strict.HashMap Text Text) m) a runStandardT (Fix1T (StandardTF m)) = m
src/Nix/String.hs view
@@ -32,7 +32,9 @@ , addStringContext , addSingletonStringContext , runWithStringContextT+ , runWithStringContextT' , runWithStringContext+ , runWithStringContext' ) where @@ -130,6 +132,8 @@ principledStringMappend (NixString s1 t1) (NixString s2 t2) = NixString (s1 <> s2) (t1 <> t2) +-- 2021-01-02: NOTE: This function is ERRADICATED from the source code.+-- ERRADICATE it from the API. -- | Combine two NixStrings using mappend hackyStringMappend :: NixString -> NixString -> NixString hackyStringMappend (NixString s1 t1) (NixString s2 t2) =@@ -144,9 +148,11 @@ contents = Text.intercalate (nsContents sep) (map nsContents nss) ctx = S.unions (nsContext sep : map nsContext nss) +-- 2021-01-02: NOTE: This function is ERRADICATED from the source code.+-- ERRADICATE it from the API. -- | Combine NixStrings using mconcat hackyStringMConcat :: [NixString] -> NixString-hackyStringMConcat = foldr hackyStringMappend (NixString mempty mempty)+hackyStringMConcat = foldr principledStringMappend (NixString mempty mempty) -- | Empty string with empty context. principledStringMempty :: NixString@@ -205,7 +211,7 @@ -- | Create a NixString from a Text and context principledMakeNixString :: Text -> S.HashSet StringContext -> NixString-principledMakeNixString s c = NixString s c+principledMakeNixString = NixString -- | A monad for accumulating string context while producing a result string. newtype WithStringContextT m a = WithStringContextT (WriterT (S.HashSet StringContext) m a)@@ -231,6 +237,16 @@ runWithStringContextT (WithStringContextT m) = uncurry NixString <$> runWriterT m +-- | Run an action that manipulates nix strings, and collect the contexts encountered.+-- Warning: this may be unsafe, depending on how you handle the resulting context list.+runWithStringContextT' :: Monad m => WithStringContextT m a -> m (a, S.HashSet StringContext)+runWithStringContextT' (WithStringContextT m) = runWriterT m+ -- | Run an action producing a string with a context and put those into a 'NixString'. runWithStringContext :: WithStringContextT Identity Text -> NixString runWithStringContext = runIdentity . runWithStringContextT++-- | Run an action that manipulates nix strings, and collect the contexts encountered.+-- Warning: this may be unsafe, depending on how you handle the resulting context list.+runWithStringContext' :: WithStringContextT Identity a -> (a, S.HashSet StringContext)+runWithStringContext' = runIdentity . runWithStringContextT'
src/Nix/Type/Env.hs view
@@ -21,9 +21,9 @@ import Data.Foldable hiding ( toList ) import qualified Data.Map as Map ----------------------------------------------------------------------------------- Typing Environment--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Typing Environment+--------------------------------------------------------------------------------- newtype Env = TypeEnv { types :: Map.Map Name [Scheme] } deriving (Eq, Show)
src/Nix/Type/Infer.hs view
@@ -69,9 +69,9 @@ import Nix.Value.Monad import Nix.Var ----------------------------------------------------------------------------------- Classes--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Classes+--------------------------------------------------------------------------------- -- | Inference monad newtype InferT s m a = InferT@@ -210,9 +210,9 @@ mempty = TypeInferenceAborted mappend = (<>) ----------------------------------------------------------------------------------- Inference--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Inference+--------------------------------------------------------------------------------- -- | Run the inference monad runInfer' :: MonadInfer m => InferT s m a -> m (Either InferError a)@@ -591,9 +591,9 @@ Just x -> TVar x Nothing -> error "type variable not in signature" ----------------------------------------------------------------------------------- Constraint Solver--------------------------------------------------------------------------------+---------------------------------------------------------------------------------+-- * Constraint Solver+--------------------------------------------------------------------------------- newtype Solver m a = Solver (LogicT (StateT [TypeError] m) a) deriving (Functor, Applicative, Alternative, Monad, MonadPlus,
src/Nix/Type/Type.hs view
@@ -2,7 +2,9 @@ import qualified Data.HashMap.Lazy as M import Data.Text ( Text )-import Nix.Utils+import Nix.Utils ( AttrSet )++-- | Hindrey-Milner type interface newtype TVar = TV String deriving (Show, Eq, Ord)
src/Nix/Value.hs view
@@ -1,25 +1,16 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wno-missing-signatures #-}@@ -242,12 +233,11 @@ -> r iterNValue' k f = f . fmap (\a -> k a (iterNValue' k f)) --- | An 'NValueNF' is a fully evaluated value in normal form. An 'NValue f t m' is+-- | A 'NValue t f m' is -- a value in head normal form, where only the "top layer" has been--- evaluated. An action of type 'm (NValue f t m)' is a pending evaluation that+-- evaluated. An action of type 'm (NValue t f m)' is a pending evaluation that -- has yet to be performed. An 't' is either a pending evaluation, or--- a value in head normal form. A 'NThunkSet' is a set of mappings from keys--- to thunks.+-- a value in head normal form. -- -- The 'Free' structure is used here to represent the possibility that -- cycles may appear during normalization.@@ -307,64 +297,63 @@ pattern NVConstant x <- Free (NVConstant' x) nvConstant' :: Applicative f => NAtom -> NValue' t f m r-nvConstant' x = NValue (pure (NVConstantF x))+nvConstant' = NValue . pure . NVConstantF nvConstant :: Applicative f => NAtom -> NValue t f m-nvConstant x = Free (NValue (pure (NVConstantF x)))+nvConstant = Free . nvConstant' pattern NVStr' ns <- NValue (extract -> NVStrF ns) pattern NVStr ns <- Free (NVStr' ns) nvStr' :: Applicative f => NixString -> NValue' t f m r-nvStr' ns = NValue (pure (NVStrF ns))+nvStr' = NValue . pure . NVStrF nvStr :: Applicative f => NixString -> NValue t f m-nvStr ns = Free (NValue (pure (NVStrF ns)))+nvStr = Free . nvStr' pattern NVPath' x <- NValue (extract -> NVPathF x) pattern NVPath x <- Free (NVPath' x) nvPath' :: Applicative f => FilePath -> NValue' t f m r-nvPath' x = NValue (pure (NVPathF x))+nvPath' = NValue . pure . NVPathF nvPath :: Applicative f => FilePath -> NValue t f m-nvPath x = Free (NValue (pure (NVPathF x)))+nvPath = Free . nvPath' pattern NVList' l <- NValue (extract -> NVListF l) pattern NVList l <- Free (NVList' l) nvList' :: Applicative f => [r] -> NValue' t f m r-nvList' l = NValue (pure (NVListF l))+nvList' = NValue . pure . NVListF nvList :: Applicative f => [NValue t f m] -> NValue t f m-nvList l = Free (NValue (pure (NVListF l)))+nvList = Free . nvList' pattern NVSet' s x <- NValue (extract -> NVSetF s x) pattern NVSet s x <- Free (NVSet' s x) nvSet' :: Applicative f => HashMap Text r -> HashMap Text SourcePos -> NValue' t f m r-nvSet' s x = NValue (pure (NVSetF s x))+nvSet' s x = NValue $ pure $ NVSetF s x nvSet :: Applicative f => HashMap Text (NValue t f m) -> HashMap Text SourcePos -> NValue t f m-nvSet s x = Free (NValue (pure (NVSetF s x)))+nvSet s x = Free $ nvSet' s x pattern NVClosure' x f <- NValue (extract -> NVClosureF x f) pattern NVClosure x f <- Free (NVClosure' x f) nvClosure' :: (Applicative f, Functor m) => Params () -> (NValue t f m -> m r) -> NValue' t f m r-nvClosure' x f = NValue (pure (NVClosureF x f))+nvClosure' x f = NValue $ pure $ NVClosureF x f nvClosure :: (Applicative f, Functor m) => Params () -> (NValue t f m -> m (NValue t f m)) -> NValue t f m-nvClosure x f = Free (NValue (pure (NVClosureF x f)))+nvClosure x f = Free $ nvClosure' x f pattern NVBuiltin' name f <- NValue (extract -> NVBuiltinF name f) pattern NVBuiltin name f <- Free (NVBuiltin' name f) nvBuiltin' :: (Applicative f, Functor m) => String -> (NValue t f m -> m r) -> NValue' t f m r-nvBuiltin' name f = NValue (pure (NVBuiltinF name f))+nvBuiltin' name f = NValue $ pure $ NVBuiltinF name f nvBuiltin :: (Applicative f, Functor m) => String -> (NValue t f m -> m (NValue t f m)) -> NValue t f m-nvBuiltin name f =- Free (NValue (pure (NVBuiltinF name f)))+nvBuiltin name f = Free $ nvBuiltin' name f builtin :: forall m f t
tests/EvalTests.hs view
@@ -429,7 +429,7 @@ case_concat_thunk_rigth = constantEqualText "[1 2 3]" "[1] ++ builtins.tail [1 2 3]" ------------------------+--------------------------------------------------------------------------------- tests :: TestTree tests = $testGroupGenerator
tests/Main.hs view
@@ -95,7 +95,7 @@ prettyTestsEnv <- lookupEnv "PRETTY_TESTS" pwd <- getCurrentDirectory- setEnv "NIX_REMOTE" ("local?root=" ++ pwd ++ "/")+ setEnv "NIX_REMOTE" (pwd ++ "/real-store") setEnv "NIX_DATA_DIR" (pwd ++ "/data") defaultMain $ testGroup "hnix" $
tests/ParserTests.hs view
@@ -361,7 +361,7 @@ tests :: TestTree tests = $testGroupGenerator ---------------------------------------------------------------------------------+--------------------------------------------------------------------------------- assertParseText :: Text -> NExpr -> Assertion assertParseText str expected = case parseNixText str of
tests/PrettyTests.hs view
@@ -32,7 +32,7 @@ tests :: TestTree tests = $testGroupGenerator ---------------------------------------------------------------------------------+--------------------------------------------------------------------------------- assertPretty :: NExpr -> String -> Assertion assertPretty e s = assertEqual ("When pretty-printing " ++ show e) s . show $ prettyNix e