Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support building only drvs that lack substitutes (aka nix-build-uncached) #3946

Open
colemickens opened this issue Aug 20, 2020 · 27 comments · May be fixed by #7587
Open

support building only drvs that lack substitutes (aka nix-build-uncached) #3946

colemickens opened this issue Aug 20, 2020 · 27 comments · May be fixed by #7587

Comments

@colemickens
Copy link
Member

Is your feature request related to a problem? Please describe.
Not necessarily, since nix-build-uncached exists, but it seems like a nice-to-have in nix itself. Also, I think the implementation in nix itself would likely be much more simple than nix-build-uncached itself, just due to how it works.

Describe the solution you'd like
nix build --lacking-substitutes .#packages would build only the packages which can not be substituted from a known store or trusted binary cache.

Also, a more-eloquent flag name would work, but I can't think of any :).

Describe alternatives you've considered
Just using nix-build-uncached.

Additional context
This makes using Nix in CI scenarios a bit easier. For example, nixpkgs-wayland cuts down on wasted resources significantly by using nix-build-uncached. Otherwise the builder will download hundreds of MBs of store paths just to fulfill the build, even though in reality we only want to build binary artifacts that aren't already in our CI's binary cache.

Alternatively

It seems like nix-build-uncached has to resolve unsubstitutable-derivations by parsing the output of nix-build supposedly because nix build's dry-run doesn't work; maybe that could be fixed.

cc: @Mic92

@Mic92
Copy link
Member

Mic92 commented Aug 20, 2020

If I correctly recall nix build --dry-run does not allow import-from-derivation, which is why I had to use nix-build instead. nix build without dry-run allows that.

@Ericson2314
Copy link
Member

Ericson2314 commented Aug 21, 2020

Here's an idea:

nix-build --store $remote_store --builders auto

This flips things around so that the goal is just making paths exist in the remote store, but the local store (auto means directly or via daemon) is allowed to help build missing pieces.

I think that should do exactly what you want. it probably doesn't yet not yet work, but we should fix that.

@matthewbauer
Copy link
Member

I'm not sure if we want to limit ourselves to one remote store here though. nix-build-uncached will look for any substitution, so we don't end up duplicating things in https://cache.nixos.org in or another cache too. nix-build --store will guarantee that everything exists in the binary cache, even if some other binary cache already has it.

I think a better way to do this is by augmenting Nix copy to be more specific in what is copied over:

nix copy --realise-mode outputs-if-missing --upstream-substituter https://cache.nixos.org --substitute-on-destination --to http://my-cache .#packages

It would add two new options:


Here's a command to get missing paths for a cache that works with flakes (at least in flake-compat mode):

$ nix-store -q --outputs $(nix-instantiate --no-gc-warning -E '(import (builtins.fetchTarball https://github.com/edolstra/flake-compat/archive/master.tar.gz) { src = ./.; }).defaultNix.checks.${builtins.currentSystem}') | while read storePath; do nix path-info --store https://nixiosk.cachix.org $storePath >/dev/null 2>&1 || echo $storePath; done

@Ericson2314
Copy link
Member

@matthewbauer to solve the "don't duplicate stores" issue, I rather just be able to layer stores:

nix-build --store "layered://?layers=$remote_store, https://cache.nixos.org" --builders auto

As that I think that is a generally useful concept, especially once Nix tries to deal with secrets in the store.

@domenkozar
Copy link
Member

Refs #3428

@colemickens
Copy link
Member Author

@matthewbauer What if I'm trying to just get a list of store paths and not actually do a copy (my final destination store is not supported natively by cachix/nix)?

@Ericson2314
Copy link
Member

I'm starting on this. I think if it I put off splitting up derivation-goal.cc until after, I'll be able to keep my sanity. I got it to build and not regress with Store instead of LocalStore and (surprisingly few!) downcasts; now I'm trying to make some new fucuntional come of that ugly change.

@stale
Copy link

stale bot commented Jun 18, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the stale label Jun 18, 2021
@cole-h
Copy link
Member

cole-h commented Jun 19, 2021

Still desirable.

@domenkozar
Copy link
Member

@Ericson2314 see #5025

@Ericson2314
Copy link
Member

Per #4364, which is closed as a duplicate of this, one should be able to do

nix-build --store my-remote-store --builders 'auto - - 1 1'

to achieve this.

@stale
Copy link

stale bot commented Apr 17, 2022

I marked this as stale due to inactivity. → More info

@stale stale bot added the stale label Apr 17, 2022
@endgame
Copy link
Contributor

endgame commented Apr 17, 2022

Still important, and stalebot is still a jerk.

@stale stale bot removed the stale label Apr 17, 2022
@nrdxp
Copy link

nrdxp commented Sep 21, 2022

nix-build --store my-remote-store --builders 'auto - - 1 1'

That doesn't work in the case of an s3 cache, which has no daemon

@SuperSandro2000
Copy link
Member

Still important, and stalebot is still a jerk.

stale bot in NixOS is configured to be purely informational and to help identify old and stale issues. It will not close issues and you do not need to comment on the issue just for the comment.

@nrdxp
Copy link

nrdxp commented Dec 9, 2022

Just realized that nix path-info --json --store <remote-uri> almost already does this. It contains a boolean "valid" marking whether or not the given path is valid. The only thing is that it will error if it doesn't know about the drv file at all. If we could just have it simply return false instead and continue we could pass multiple paths at once.

Perhaps one way we could do this and still ensure the derivation is a valid artifact would be to teach path-info to use the --eval-store as a backup, if the derivation exists in the eval-store but not the store, consider it uncached (`"valid": false) in the current schema instead of erroring.

If we did that with the output of nix-store --query --requisites --include-outputs we would have our uncached build closure in two commands and without even having to explicitly build it (assuming we at least have the drv).

As a further optimization, we could easily guarantee we can do this in a single invocation with something like: #7437

@nrdxp
Copy link

nrdxp commented Dec 13, 2022

I'd like to correct my previous comment a bit, I must have been misremembering or working with a different tool but there is no such "valid" attribute after all, however we can still do this. Basically we could implement something like --keep-going for path-info and it will simply store the path as invalid if the --json flag is also passed and that would just about do it.

Maybe an additional flag --all-caches could be added to check all caches and not just a single one, but that would just about do it.

@Ericson2314
Copy link
Member

nix-build --store my-remote-store --builders 'auto - - 1 1'

is still the right idea conceptually, and works. Rather than thinking of new work-arounds, we should just investigate what if anything about it doesn't work well and fix them.

For example, it will fail with a read-only store because it doesn't know how to upload things. Fine. Then we should come up with a new solution like an "overlay store", or a way for people to tell nix how to do uploads for their substitutor store.

@nrdxp
Copy link

nrdxp commented Dec 13, 2022

I like the idea of querying the caches independant of building personally, but I don't see a problem with doing both either. In std-action, for example, we are doing all evaluation before hand in its own run, and produce a json that is used to build various job matrices. The runners in these matrices don't do any evaluation but use the json to know about the derivation paths ahead of time so they can skip any extra nix evaluation and get straight to work.

If we had a simple way to query all caches during the eval phase, we could conditionally skip certain builds from even starting if they are already cached. That's why I suggest augmenting nix path-info. Right now we still do that, but the task builder has to start up, install nix, then we parse the output of nix-build --dry-run (basically exactly what nix-build-uncached does), to see if there is actually anything to build or not. It would be better to skip all that setup and just not spawn a build job at all, but in order to make that feasible we need a more efficient way to query if a package is cached than calling nix path-info or nix-build --dry-run n times sequentially.

@colemickens
Copy link
Member Author

Not to mix issues but in a CI scenario with a "clean" builder, can you not rely on nix-eval-jobs's --check-cache-status?

@nrdxp
Copy link

nrdxp commented Dec 14, 2022

Not to mix issues but in a CI scenario with a "clean" builder, can you not rely on nix-eval-jobs's --check-cache-status?

It depends on the scenario, but if there is any sort of IFD, even a small amount, nix-eval-jobs can actually be exponentially more expensive, both in space and time, since each thread pays that cost again and again. In my own personal projects, nix-eval-jobs worked really well in my initial testing, but at work haskell.nix relies of IFD for dependancy resolution so nix-eval-jobs is a definite no-go there.

I wanted a solution that is generally applicable. I definitely didn't want some inexperienced user accidentally adding some IFD to their project due to lack of experience and all of a sudden their CI runner is OOMing.

Actually the eval is really not all that expensive even with IFD if basically all of the derivations that are produced during the eval (from IFD) are already reified before it starts. The difference is fairly drastic, from about 25m (no cache) to only 2m, for everything that will be run in CI in my current work project. If we could get the eval-cache working for nix eval that cost might come down to a few seconds, ideally: #4279

Also, just in principal, I'd rather support fixing and augmenting upstream than working from a fork that may or may not be maintained in the long term. If it would be possible, I'd rather the official Nix evalautor itself learn how to use threads, and in a more efficient manner (some kind of shared state) than nix-eval-jobs seems to, at least from my own testing.

nrdxp added a commit to nrdxp/nix that referenced this issue Dec 29, 2022
Resolves NixOS#3946 by providing an efficient means of querying cache status
of the passed paths.

For every path passed, it will be returned on standard output only if it
is not available in any of the configured substituters.
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
Resolves NixOS#3946 by providing an efficient means of querying cache status
of the passed paths.

For every path passed, it will be returned on standard output only if it
is not available in any of the configured substituters.
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
@nrdxp
Copy link

nrdxp commented Jan 11, 2023

Just pinging here that you can use either #7587 or #7526 to resolve this. The latter may never be merged which is why I decided to split them up into separate PRs. With nix path-info --query-substitutes --json you can trivally pass the derivations of unbuilt outputs to be built by passing outputs (or flake refs) and then grabbing the derivations from the json and sending them to your build command.

nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
Resolves NixOS#3946 by providing an efficient means of querying cache status
of the passed paths.

For every path passed, it will be returned on standard output only if it
is not available in any of the configured substituters.
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
Resolves NixOS#3946 by providing an efficient means of querying cache status
of the passed paths.

For every path passed, it will be returned on standard output only if it
is not available in any of the configured substituters.
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 11, 2023
Resolves NixOS#3946 by providing an efficient means of querying cache status
of the passed paths.

For every path passed, it will be returned on standard output only if it
is not available in any of the configured substituters.
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 12, 2023
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 12, 2023
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 12, 2023
nrdxp added a commit to nrdxp/nix that referenced this issue Jan 31, 2023
Fixes NixOS#3946

Filters out any paths from the output which are already available in
the configured substituters. Useful in CI environments, to avoid builds
that are already cached.
@Mic92
Copy link
Member

Mic92 commented Apr 13, 2023

I expanded the documentation off nix-eval-jobs also a bit w.r.t. to concurrency and memory usage: https://github.com/nix-community/nix-eval-jobs/pull/202/files

@Mic92
Copy link
Member

Mic92 commented Oct 1, 2023

https://github.com/Mic92/nix-fast-build is the spiritual successor of nix-build-uncached. Check the --skip-cached flag: https://github.com/Mic92/nix-fast-build#avoiding-redundant-package-downloads

@tomberek
Copy link
Contributor

tomberek commented Nov 29, 2023

nix-build --store $remote_store --builders auto

@Ericson2314: This almost works now, but I run into this:

querying info about '/nix/store/pa10z4ngm0g83kx9mssrqzz30s84vq7k-hello-2.12.1.tar.gz' on 'https://cache.nixos.org'...
downloading 'https://cache.nixos.org/pa10z4ngm0g83kx9mssrqzz30s84vq7k.narinfo'...
warning: ignoring substitute for '/nix/store/pa10z4ngm0g83kx9mssrqzz30s84vq7k-hello-2.12.1.tar.gz' from 'https://cache.nixos.org', as it's not signed by any of the keys in 'trusted-public-keys'

when attempting:

nix build --store s3://my-store nixpkgs#hello --builders auto -vv

I guess my local settings are not passing along trusted-public-keys? And I've not been able to convince the client/daemon to accept those keys via any combination of attempts so far.

(@Mic92: while this isn't quite the UX we want, it is conceptually quite consistent with other notions. I'd like to ensure the underlying mechanism is good and then we can expose it in a more intuitive manner.)

Edit: This seems to be due to the remote store not trusting pathInfo

diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 8b6bf9aed..985c6dfaf 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -400,7 +400,7 @@ public:
      */
     virtual bool pathInfoIsUntrusted(const ValidPathInfo &)
     {
-        return true;
+        return false;
     }

     virtual bool realisationIsUntrusted(const Realisation & )

makes things work. Likely we want this to either use global settings, or better would be for each store to have trust+policy settings apply to them.

arianvp added a commit to arianvp/nixos-village that referenced this issue Jun 7, 2024
@arianvp
Copy link
Member

arianvp commented Jun 7, 2024

I tried the trick above but it doesn't seem to work with flakes:

nix build \
    --extra-substituters 's3://cache20240603113122461500000001?region=eu-central-1' \
    --extra-trusted-public-keys 'nixos-village:6yZ26qopUY/jErtM/YtjB0jFshjx4jgUYxEmhqKEcQE=' \
    --store "s3://cache20240603113122461500000001?region=eu-central-1&secret-key=$(realpath ./cache-secret-key)" \
    --builders 'auto' \
    .#nixosConfigurations.web-push.config.system.build.toplevel 
uploaded 's3://cache20240603113122461500000001/nar/05063mx0m30fkb17h7hjnj7yl4kb9k5a88xnym00aj0bniig8201.nar.xz' (19856 bytes) in 293 ms
uploaded 's3://cache20240603113122461500000001/17g3406b7014sk07w9khd4lsylw3pldg.narinfo' (510 bytes) in 204 ms
error: path '/nix/store/17g3406b7014sk07w9khd4lsylw3pldg-source/flake.nix' does not exist

@arianvp
Copy link
Member

arianvp commented Jun 7, 2024

Doing a nix flake archive && nix flake archive --store 's3://' beforehand seems to solve the issue. But now running into the same issue as Tomberek where the path info is not trusted

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet