Conversation
| }; | ||
| } | ||
| // | ||
| # TODO: As of now, construcFiles does not accept keys like 'nix-direnv.sh'. |
There was a problem hiding this comment.
config.constructFiles.<name>.key
The current convention for this:
nix-wrapper-modules/wrapperModules/h/helix/module.nix
Lines 112 to 126 in d9fdf67
(the mkOverrides in that example are to make sure it remains grouped in the generated directory)
There was a problem hiding this comment.
it only matters for the created value in drv
The name in config.constructFiles.<name> can still be anything, but you have to set .key if it could be an invalid shell variable
Unfortunately, I have not found a way around this yet (without forcing everyone to use __structuredAttrs)
The problem is that "${name}Path" must be a valid shell variable.
nix-wrapper-modules/modules/constructFiles/module.nix
Lines 111 to 112 in d9fdf67
^ I promise I really tried, and I at least got it to give a warning that makes sense.
Yeah I kinda expected to have some kind of similar trouble with this one... if you figure it out, let me know lol On first inspection of the comment about it in the code though, it looks like you are fighting with placeholders. Which isnt necessarily the first place I would expect the problem to start. Maybe using wrapperVariants to wrap something other than the main binary in context of the final wrapper derivation can help you here? Or using buildCommand directly? I will look into this further when I get time to sit down with it properly. |
d2d5be2 to
c140e06
Compare
The "proper" fix would be to get this PR merged I created but I think the chances are rather slim. I tested this already by rebuilding direnv with that patch. |
|
Oh, also, unrelated, this discussion, #370 <- thoughts? (there though if you have any). You usually have good input so figured I would ask. |
|
That PR is not a bad idea actually. It doesn't feel like it is special-cased just for us. I didn't read the whole implementation, to see all the things around the changes, but the idea seems relatively non-intrusive and the tool itself is somewhat intrusive so more escape hatches seems like a good idea. I will look into the implementation of the wrapper module properly sometime soonish beyond just the constructFiles thing, and see if there is anything we can do on our end too |
|
Also maybe of interest Having a direnv wrapper module would maybe let us pass through stuff like that? |
c140e06 to
030dac6
Compare
hmm... I think as long we don't have the possibility to configure As of now, the native, unwrapped I share your view about not switching directories from within neovim and if I occasionally do I'd rather not want direnv to change the environment so I would not have this issue. |
52c82d6 to
661e463
Compare
|
@BirdeeHub is there a way to run only the checks for a given wrapper? I never used |
e05c6ea to
4da9d42
Compare
|
@BirdeeHub I made a proof of concept on how to write tests in a more flexible and readable way. Can you quickly tell me if you're ok with this approach? I plan to write more tests this way and want to make sure it does not get rejected :-) If you think this is useful we can also think about how to make this reusable for other modules. |
|
It is a good start. I think breaking them up into separate drvs every time they use the helper is probably too much though. If you want to develop it a bit and help fix up CONTRIBUTING.md maybe we could pass it to the tests nix-wrapper-modules/ci/flake.nix Lines 16 to 56 in 364e000 ^ tests get called from there, pass whatever extra, add extra options for things you can return, as long as the existing ones still run and receive pkgs and self, you can pretty much do whatever, thats why it is in a separate flake, you can even pull an input if you want in that flake. An extra thing to add, your helper should also check Maybe we also edit the receiving code in that flake such that it would also be able to return a set of drvs which get combined with the final set of tests, for if you really really want to return a few properly separate tests, that can also be ran separately? You shouldn't be making so many intermediate drvs and running them all in an outer test drv. If you want actually separate ones, you should add the ability to return multiple. You could then have runTests, which runs several "scripts" within 1 drv, as well. This is for speed reasons, and because if you are going to have them as separate drvs, you may as well allow yourself to actually run them separately too. If you do that, maybe as a separate PR would be preferred? |
I swear I tried this yesterday but must have done something wrong. Thanks! |
Good point. Agreed.
You shouldn't be making so many intermediate drvs and running them all in an outer test drv. If you want actually separate ones, you should add the ability to return multiple. You could then have runTests, which runs several "scripts" within 1 drv, as well. Although I agree that introducing the There was an error in the direnv wrapper (test-group-direnv)... Maybe this is overkill for a rather simple wrapper such as direnv but i can see this being usefull in the more sophisticated wrappers where we might group related tests around specific features. That being said, I can live with not having this hierarchical grouping and just be able to define a flat list of tests that can be returned. I was planning on returning a list of drv instead of just a drv but I am not sure whether this is what you suggested in this quote:
Can you clarify what you mean by this?
Does this really hurt us? If tests become more readable and mainainers are encouraged to write more tests, longer running tests would be a worthy sacrifice to me. Am I underestimating the negative impact of this?
Yes if we agree on what needs to be done, and this seems to be touching |
|
If from {
testa = pkgs.runCommand...
testb = pkgs.runCommand...
}And have that map to The warning would be like
pkgs.runCommand {} ''
${builtins.concatStringsSep "\n" scripts}
touch $out
''but with better error printouts and checks stuff from the wrapper module like meta.platforms as well, and maybe makes the path to it available as $src for each test or something |
So this still has multiple drvs. This would be fine with me. pkgs.runCommand {} ''
${builtins.concatStringsSep "\n" scripts}
touch $out
''But this is an alternative solution right? |
|
Not alternative, we should offer both. They should be allowed to return a set containing multiple tests, (which would be achieved by editing the code in And they should also be allowed to use our helper to nicely build 1 or multiple cases into a single test, with access to your test helpers in the bash code for the test, and checked for meta.platform. Which would look like that second snippet but, with more stuff in it and actually thought out arguments and stuff. That way they can break them up into separate DRVs, but also have an ergonomic experience creating each individual test which each may contain 1 or more cases. in short, a {
pkgs, self, testlib??
}:
{ # <- first snippet
testa = testlib.runthetests { ?? }; # <- second snippet
testb = testlib.runthetests { ?? };
}And then in the You could also have some kind of recursive import that returns that structure, if you want to add a file-based helper too. {
pkgs, self, testlib??
}:
testlib.returntestdir { ?? } ./checks #<- returns a set of tests rather than just 1Or, if they just want 1 test drv, then they can just do this {
pkgs, self, testlib??
}:
testlib.runthetests { ?? }; # <- second snippet, returns just 1 test (or null)And then everyone benefits from the new helpers, you can still disable particular tests by returning null instead, and you can run them all individually when you break them up into multiple |
|
For the sake of this PR I came up with a solution that:
The format is as follows: runTests "direnv-test" [ # <-- will create a single drv by running `runCommand`
# and transforming the test list and its assertions to a single large script
(runTest "test-a" ( # <-- a test groups together assertions. If any assertion fails, the test fails.
[
(isDirectory "some-directory") # <-- we provide pre-defined assertions functions
(isCheckingXyz "some-arg") # <-- but we can easily define our own using `createAssertion`
''[ 1 -eq 0 ] || echo "One does not equal zero" >&2; return 1'' # <-- or write plain bash assertions
]
))
(runTest "test-b" (isDirectory (getDotdir wrapper))) # <-- single assertions will automatically be transformed a listI would like to merge this directly within the direnv wrapper and refactor it out + add the Having had some time to play around with it, I think I would not extend the ci flake to handle lists or sets of tests but keep that part as it is. Here are some points why:
So yeah, let me know if this is worth being moved to the ci flake. |
| ''; | ||
|
|
||
| runTest = name: assertions: '' | ||
| run() { |
There was a problem hiding this comment.
Yes, the run function gets redefined every test but it is working fine (which is why I'd rather use this instead of using the testname (name) because I would have to ensure that the name does not contain chars that cannot be used in a function definition)
There was a problem hiding this comment.
It is fine to redefine a bash function each time you call runTest
Defining a bash function is plenty fast enough.
A bunch of nested derivations would be slower, which is why I asked that either we split them up into actually separate tests, or improve the case where you have many cases within 1 derivation.
Within that derivation you can do basically whatever, although you should still preferably avoid IFD still.
There was a problem hiding this comment.
Within that derivation you can do basically whatever, although you should still preferably avoid IFD still.
What does "IFD" mean?
There was a problem hiding this comment.
import from derivation
https://nix.dev/manual/nix/2.26/language/import-from-derivation
When you take a file from inside a derivation, and use it in nix code rather than another derivation.
|
|
||
| runTest = name: assertions: '' | ||
| run() { | ||
| ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList assertions)} |
There was a problem hiding this comment.
We need to "&&" each assertion to ensure the error state is correctly propagated.
If we simply had newlines here, the error code of the function would be the error code of the last statement only.
68114d2 to
3806dcb
Compare
|
I added documentation, lifted There is one more thing that I am a bit lost still and might need some input @BirdeeHub : Even though The problem is that I cannot simply set it to I initially set it to I use the direnv wrapper as a subWrapperModule option in my zsh wrapper config. When my zsh config is built, the placeholder points to the zsh wrapper. Do you have an idea how to solve this? |
You would do the first of those, the one you originally were doing for passthru You would not be able to
you can only This is because the env options need to be evaluated and placed inside the derivation, whereas passthru does not, it just gets // into the resulting derivation at the end. It is also because attrsOf is not lazy, which env uses, but passthru uses lazyAttrsRecursive for its option type (constructFiles gets around this problem by being a submodule option, so attrsOf doesnt trigger evaluation of And then in your zsh wrapper you would grab the value from passthru however and add it to its env option. |
It will work when used by config.wrapper of that subWrapperModule, or when passed to other options which go there. But yes, if you use them outside of that submodule, that is the case. That is why Every file made with constructFiles is accessible from outside of the derivation in this way. # in some other wrapper module or derivation
''
${yourWrappedPackage.configuration.constructFiles.<name>}
or
${yourWrappedPackage.configuration.constructFiles.<name>.outPath}
or
${config.wrappers.<wrappername>.constructFiles.<name>}
or
${config.wrappers.<wrappername>.constructFiles.<name>.outPath}
''And if you use a different derivation for the DIRENV_CONFIG dir thing, placeholders in there would refer to that derivation. So, they could still use placeholders in the options and if you used those options values from config, those would still fail just like they do now. It would just be less useful to use them, so less people would Definitely still prefer to have it all be in the final derivation, and make anything extra needed that isnt already handled by In short, |
bd37bb6 to
50f7245
Compare
|
Thanks for the explanation. I don't access any of the constructFiles options of my wrapper in zsh. What I am doing now is exporting I then integrate the direnv wrapper as a subwrapperModule in my zsh wrapper. Either I had a bug which unintentionally got fixed or I am halucinating. I think it should be fine the way it is now.
No hurry. I will keep using the feature branch for now and also smoke test it in the following days. |
|
well, so, the stuff in env goes into the file, with the hash of the direnv drv, when it is used by the direnv wrapper. As long as you access the one you exported via It is just The other method of accessing it with This is because most of the options in a wrapper module are necessary to create
|
50f7245 to
b901eea
Compare
|
I rebased and removed the |
|
Correct. And there are 2 phases First, the option uses .apply to call the sanitization function However, this cannot prevent duplicates, it only knows about that 1 item Then when they are collected and added to |
b901eea to
3816c69
Compare
3816c69 to
0b1773e
Compare
This way we have a way to join assertions using '&&' and can group assertions. If any assertion fails it will print the error message of the given assertin as well as the name of the test
construcFiles sanitizes the key by default now
0b1773e to
cf4c435
Compare
I think this should cover all configuration options (
direnv.toml,direnvrc, andlib/*.sh)There is still some things left to do, mainly
I also have a question about
constructFiles(marked with TODO).Similar to the issue in the zsh wrapper where adding
extraPackagesas env vars to the wrapper script did not work, addingDIRENV_CONFIGwon't work here as well. I tried to outline why in the comments.Would be glad to get some feedback on this.