Open nmattia opened 4 years ago
That's a strange limitation of how flakes are being evaluated. All of the data structures must be pretty much JSON-like data. The only place where more complex nix code is allowed is within the outputs function.
but maybe that's on purpose to ensure the flake.nix stays as simple as possible?
That's right. It ensures that a command like nix flake info
doesn't have to evaluate an arbitrarily complex (and possibly non-terminating) Nix expression.
Ok I realize it's actually terribly picky, even thunks are forbidden (i.e. in an input's { url = "foo" + "bar"; }
):
/tmp/tmp.7jJ3XRKbVP$ nix develop
error: --- Error ------------------------------------------------------------------------------------- nix
expected a string but got a thunk at /nix/store/4yiaxz02925lr1ssyir8nc7cs8dp7bf0-source/flake.nix:2:3
(use '--show-trace' to show detailed location information)
Why then use nix syntax if it is not nix? I'd say, either use a clearly defined subset of nix code, at best with another name and file ending (tnix – total nix) or the flake file shall be in a total language like plain json and the outputs attr refers to nix expressions, or dhall (but a comparatively complex new language).
If it looks like nix but isn't, to me it is confusing unexpected (”strange“ – zimbatm) behaviour.
Edit: Why not split the flake.nix
into flake.json
containing metadata and inputs and flake.nix
/outputs.nix
containing only the outputs
function in real Nix lang?
I like the idea of specifying inputs and metadata in json. It's easier to work with for Nix itself and for external tools. With niv
I often use niv update some-input -b feature-branch
to test things out. nix flake
doesn't have such a command and it'd be relatively hard to implement given the current flake format, because we don't have a way to write back modified asts without touching unmodified whitespace and comments.
I always used to think of the Nix language as a predictable element in an otherwise messy domain. Just a lazy evaluator that implicitly writes derivations. I don't think flakes need to change that.
I like the idea of specifying inputs and metadata in json.
The configs
branch adds support for TOML as an alternative to flake.nix
(1dc3f5355a3786cab37a4de98ca46a859e015d89). This allows the flake to be modified from the command line (e.g. 3632593bfc2daa82b2527c601604c8d9ae91840e).
nix flake doesn't have such a command
Well there is the --override-input
flag. Since it only overwrites the lock file it doesn't have to deal with rewriting Nix expressions.
Ugh. I just spent 8 hours writing a nix expression that dynamically generates flake inputs from an external registry and now I find out that it won't work. Is this limitation really such a great idea? If it's just there to improve the UX of nix flake info
I would consider dropping it and allowing arbitrary Nix code in flakes.
Would it be difficult to disallow most builtins instead? :thinking: This would more or less solve the problem with people writing complex expressions and would allow for some flexibility which would be neat.
Why are we trying to protect users from their own non-terminating nix expressions? On the other hand, why only in commands like nix flake info
?
Why are we trying to protect users from their own non-terminating nix expressions?
E.g. because you want to safely list an unknown online flake.
Ok I realize it's actually terribly picky, even thunks are forbidden (i.e. in an input's
{ url = "foo" + "bar"; }
):/tmp/tmp.7jJ3XRKbVP$ nix develop error: --- Error ------------------------------------------------------------------------------------- nix expected a string but got a thunk at /nix/store/4yiaxz02925lr1ssyir8nc7cs8dp7bf0-source/flake.nix:2:3 (use '--show-trace' to show detailed location information)
I just faced the same issue, very confusing to know I can't even concatenate strings inside flake inputs. Maybe improving the error message would help, although i like the suggestion to just use json/toml
Can I add to this issue as well. I understand that limiting the computability of flakes are important, but I have some usecases where using expressions in flakes would be very useful.
For example, when all inputs comes from the same server. Here we have a Haskell flake that requires some specific versions of many packages from hackage:
{
description = "My Picky Haskell Program";
inputs = let
hackage = name: {
url = "https://hackage.haskell.org/package/${name}/${name}.tar.gz";
flake = false;
};
in {
package1 = hackage "package1-1.2.3";
package2 = hackage "package2-3.2.1";
...
};
outputs = { self, package1, package2, ...}:
#...
;
}
Having to write out "http://hackage.haskell.org..." for every entry, is very error prone, and is hard to change. Being able to template the flakes inputs would really be a huge usability boon.
I agree, something like this would be very useful
{
inputs = {
foo = rec {
type = "tarball";
version = "1.2.3";
url = "https://very.long/url/${version}/that/${version}/includes/${version}/a/lot/of/${version}"
};
# or:
bar = let version = "1.2.3"; in { ... };
};
}
好的,我意识到它实际上非常挑剔,甚至禁止重击(即在输入中
{ url = "foo" + "bar"; }
):/tmp/tmp.7jJ3XRKbVP$ nix develop error: --- Error ------------------------------------------------------------------------------------- nix expected a string but got a thunk at /nix/store/4yiaxz02925lr1ssyir8nc7cs8dp7bf0-source/flake.nix:2:3 (use '--show-trace' to show detailed location information)
Same issues here : (
.
.devcontainer/Dockerfile # can use files from parent directory
.devcontainer/flake.nix # Each GitHub devcontainer is setup via nix
flake.nix # I want to reuse setup .devcontainer/flake.nix so that local devs use same nix
that does not work.
will try to optimize child flake.nix so that replicating it in parent is easy.
so I was using nix because it is not json. so I read above that flake.nix is more like json. not nix. and for sure errors are bad.
😢
may be nix flake info
should run some kind of isolation to get info or fail with timeout? may be use docker? or may be slit out static info into json?
I wonder if it is possible to allow for curried flake, where the inputs can be specified in multiple stages. For example, suppose you have a Python project, where the requirements.txt
includes some git+https
urls (e.g. https://github.com/tloen/alpaca-lora/blob/630d1146c8b5a968f5bf4f02f50f153a0c9d449d/requirements.txt#L9) , you can create a Flake github:example-org/requirement-parser
to parse requirements.txt
into Flake inputs:
{
inputs = {
requirementParser.url = "github:example-org/requirement-parser";
};
outputs = { self, nixpkgs, requirementParser}: {
inputs = requirementParser.lib.parse ./requirements.txt;
outputs = inputs: {
packages.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.python3.withPackages (requirementParser.lib.buildPythonPackages (builtins.attrValues inputs));
};
};
}
Now Nix can generate a flake.lock
for the Python dependencies.
I'm currently using this simple patch so I can separate the inputs to many files. So this works.
@FlafyDev Create a PR, please!
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/nix-flake-does-not-support-the-full-nix-language/27697/2
Related: #4945
Darn. I got stuck on this for a few hours also. Definitely could use a better error message at least, if things like top-level let
aren't going to be allowed. I'm so glad I found this because I was just about to give up. The last thing I tried was builtins.isAttrs (import ./flake.nix)
in the repl which returned true
, which just makes the error file '/nix/store/*/flake.nix' must be an attribute set
even more confusing.
There is also a restriction on the form of outputs
. This yields an error:
outputs = import ./outputs.nix;
error: expected a function but got a thunk
I don't see why this limitation should be needed for nix flake info
. However, it can be worked around by η-expanding:
outputs = inputs: import ./outputs.nix inputs;
This works without issue.
I think the main rationale behind using a subset of Nix for inputs is to be able to define both inputs and outputs in a single file (having completely different languages is out of question, but one being a subset of another kinda works).
Letting computations in inputs would let the whole ecosystem bloat, be volatile, less readable, mostly losing the point of Nix flakes (for most users). At least some building blocks of the ecosystem should have fixed semantics, IMHO.
Though, I did encounter myself the input restrictions when trying to read inputs URLs using builtins.fromJSON
, but realized it would be an overuse even if possible.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/programmatic-editing-of-flake-nix/35321/1
hello. so there are 2 issues:
a. nix is not actually nix, but part of it like flake.json. so kind of flake.json flake.lock flake.nix trio. b. bad errors/tooling for that nix not nix. but some turing decidable nix. turing decidable resource limited(stack/heap/references) nix is interesting subset feature.
either one fix of a or b will make else less important. will donate more to nix if a or be handled, as it seems good for increased adoption.
thank you
I'm sure tooling is the key.
We develop a product which includes a server machine based on NixOS with some software modules (developed by us). As for servers, it also implies remote deployment and support.
So we somehow have survived with plain channels (by pinning them using a few forbidden techniques), but now I'm migrating all of this to flakes (because it refuses to build now).
The prime issue is dependency tracking. Every our software module is a separate folder in the monorepo, though they interconnect as dependencies (e.g. libraries). The first plan was just importing nixpkgs commit hash from a certain file. But as that's a very unsafe approach, now I'm brewing a single channel dispatcher to somehow provide a unified nixpkgs revision to all the modules in need.
Thus, yes, tooling is the key, but some unsafe-ty (at least possible to enable implicitly) could help.
Here is some tooling proposed in the other issue: https://github.com/NixOS/nix/issues/4945#issuecomment-1877896238.
The idea is, you have a flake.template.nix
written in ordinary Nix, which is used to generate the actual flake.nix.
With this, you can write your flake in normal Nix. When it is really worth it (!), then also the small overhead is justified.
The generation of flake.nix
could even be wrapped as a flake app. One could make a flake template (that can be used by nix flake init
– not the flake.template.nix
) that provides a seed flake.nix
only containing the generation app.
The generation of
flake.nix
could even be wrapped as a flake app. One could make a flake template (that can be used bynix flake init
– not theflake.template.nix
) that provides a seedflake.nix
only containing the generation app.
Implemented: https://github.com/jorsn/flakegen.
Describe the bug
This flake.nix evaluates to an attribute set:
however
nix develop
(ornix build .#devShell
) results in the following error:I can make nix happy by moving the
let
inside theoutputs
definition:Expected behavior
I'm expecting the flake commands to allow top-level
let
bindings; but maybe that's on purpose to ensure theflake.nix
stays as simple as possible?nix-env --version
outputnix-env (Nix) 2.4pre20200721_ff314f1