-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add optional date
argument to builtins.fetchGit
#7362
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
base: master
Are you sure you want to change the base?
Conversation
This allows users to specify an absolute or relative date (basically, anything that git accepts as a date specification) when fetching a repository. The motivation for this change is to enable support for incremental builds for Haskell packages for this Nixpkgs branch: https://github.com/MercuryTechnologies/nixpkgs/tree/gabriella/incremental … inspired by this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ Keep in mind that this new feature can power incremental builds for other package managers, too. There is not much that is Haskell-specific about this feature. The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The two main approaches I considered were: - Approach 1 (this PR) Patch Nix to add a `date` argument to `builtins.fetchGit` - Approach 2 - Patch `nix-prefetch-git` to support a new `--date` option - Disable the sandbox - Run `nix-prefetch-git` at evaluation time using import-from-derivation to fetch and rehash the repository at an older point in time Approach 1 seemed the more desirable of the two.
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too.
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
No. → https://felixspringer.xyz/homepage/blog/incrementalHaskellBuildsWithNix had a concise answer for me. |
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too.
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too.
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too.
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too.
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too.
I'm not sure what is the etiquette or protocol to ping for a review for this repository |
go to the nix dev matrix channel, find someone there (at least it was for nixpkgs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I say let's put this behind an unstable feature an then accept it. I hope there will be better solutions for this problem so we can rip out this feature later, but I recognize those alternatives are not yet available.
Nix team meeting notes That is a bit ad-hoc, and highly impure. It's a very clever abuse of Nix, but an abuse nonetheless, so we wouldn't want this to go upstream, especially since it can be worked around with a bit of infrastructure (like setting-up a cron job to update a tag/branch that Nix can pull from) |
Also the team reminded me we don't want to give out "false hope" by accepting experimental features we never intend to stabilize, which was what I was suggesting. Fair enough. |
@thufschmitt: The corresponding blog post explains the problem with using a
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2023-05-26-nix-team-meeting-minutes-58/28572/1 |
I also dislike this feature, but I think this assertion is unfair (I think @Gabriella439 already explained this somewhere, but I can't find the comment anymore): |
Also, even if this were impure, I don't see how that would argue against including this. |
The impurity wasn't about the fetching itself (which is actually pure if you specify an immutable rev as the baseline), but the use-case.
I don't really buy this argument. Every non-trivial project will have some CI system that could be used to update a tag every so often. It is indeed slightly more complicated, but not to the point of being a blocker if this approach is indeed worth it |
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too. Lower required version … so that it works against the upstream PR I'll change the required version to an official release if the PR is merged. s/pkgs/pkg/g … as caught by @cdepillabout Co-authored-by: Dennis Gosnell <[email protected]> Skip the use of `tar` We can store the `dist` directory decompressed, which speeds up the dist export/import This potentially requires more disk space *but* by storing the files unpacked it may actually improve disk utilization in some cases if `auto-optimise-store` is enabled by permitting deduplication of `dist` files. Add an `installDist` phase … which is disabled by default The motivation for this is to bring the behavior of `enableSeparateDistOutput` more in line with the other options where it doesn't change *whether* or not something is exported, but rather *where* it is exported. Now `installDist` controls whether or not the `dist` directory is exported. Based on this discussion: https://github.com/NixOS/nixpkgs/pull/203499/files#r1034150076 Document `interval` argument … as suggested by @cdepillabout s/for use for/for use with/ … based on feedback from @MaxGabriel Move `installDistPhase` to `postPhases` There are two reasons for doing this: - We can get rid of the hack to remove the dist output from the outputs - We can ensure that any changes that happen in the install phase are correctly reflected in the `dist` export Disable dylib workaround for incremental build Improve correctness of `incremental` function Typically we don't want to just roll back the source code that is the input for the Haskell package because the dependencies for the package may have changed In other words, if you roll back the source code for the top-level package without also rolling back the Nix-supplied dependencies for that build then you run the risk of an unexpected build failure (due to an older version of the Haskell package being built against a newer version of the Nix-supplied dependencies). What you actually want to do is to roll back the entire repository (i.e. the Haskell source code and the supporting Nix code) to ensure that the Haskell source code and Nix code stay in sync. This more generalized rollback complicates the UX for the `incremental` function. I did my best to try to streamline the UX so that the user just needs to specify how to locate the matching (older) package after a rollback. Make date relative to revision (if possible) This way if you attempt to incrementally build an older revision then the full rebuild will be relative to the older revision instead of being relative to the present. Add `extraFetchGitArgs` option This in particular comes in handy if you want to specify `ref = "main";` to ensure that the older build comes from the `main` branch of your repository.
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too. --- Lower required version … so that it works against the upstream PR I'll change the required version to an official release if the PR is merged. --- s/pkgs/pkg/g … as caught by @cdepillabout Co-authored-by: Dennis Gosnell <[email protected]> --- Skip the use of `tar` We can store the `dist` directory decompressed, which speeds up the dist export/import This potentially requires more disk space *but* by storing the files unpacked it may actually improve disk utilization in some cases if `auto-optimise-store` is enabled by permitting deduplication of `dist` files. --- Add an `installDist` phase … which is disabled by default The motivation for this is to bring the behavior of `enableSeparateDistOutput` more in line with the other options where it doesn't change *whether* or not something is exported, but rather *where* it is exported. Now `installDist` controls whether or not the `dist` directory is exported. Based on this discussion: https://github.com/NixOS/nixpkgs/pull/203499/files#r1034150076 --- Document `interval` argument … as suggested by @cdepillabout --- s/for use for/for use with/ … based on feedback from @MaxGabriel --- Move `installDistPhase` to `postPhases` There are two reasons for doing this: - We can get rid of the hack to remove the dist output from the outputs - We can ensure that any changes that happen in the install phase are correctly reflected in the `dist` export --- Disable dylib workaround for incremental build --- Improve correctness of `incremental` function Typically we don't want to just roll back the source code that is the input for the Haskell package because the dependencies for the package may have changed In other words, if you roll back the source code for the top-level package without also rolling back the Nix-supplied dependencies for that build then you run the risk of an unexpected build failure (due to an older version of the Haskell package being built against a newer version of the Nix-supplied dependencies). What you actually want to do is to roll back the entire repository (i.e. the Haskell source code and the supporting Nix code) to ensure that the Haskell source code and Nix code stay in sync. This more generalized rollback complicates the UX for the `incremental` function. I did my best to try to streamline the UX so that the user just needs to specify how to locate the matching (older) package after a rollback. --- Make date relative to revision (if possible) This way if you attempt to incrementally build an older revision then the full rebuild will be relative to the older revision instead of being relative to the present. --- Add `extraFetchGitArgs` option This in particular comes in handy if you want to specify `ref = "main";` to ensure that the older build comes from the `main` branch of your repository.
We ran into another situation at work where this support would have been really helpful: We currently use Nix to build a snapshot of our database with all migrations up to that point having been already run. However, this snapshot build is somewhat expensive and people are adding new migrations multiple times a day. The ideal case would be if we could have this expensive build always "snap" to the last commit before the last UTC midnight so that way it would only be rebuilt once per day so that we'd get a lot of cache reuse from that one build (even as new migrations were still being merged that day). If we were to merge this PR we could implement that functionality using something like this { lib }:
# "Truncate" a `git` source repository to the nearest time interval (specified
# in seconds). For example `truncate { duration = 60; src = …; }` will
# return the last commit before the last minute boundary.
{ interval
, src
, extraFetchGitArgs ? { }
}:
let
srcAttributes =
if lib.isAttrs src
then src
else { url = src; };
url = srcAttributes.url or null;
name = srcAttributes.name or null;
submodules = srcAttributes.fetchSubmodules or null;
arguments = {
${ if name == null then null else "name" } = name;
${ if url == null then null else "url" } = url;
${ if submodules == null then null else "submodules" } = submodules;
};
startingTime =
if srcAttributes ? rev
&& srcAttributes.rev != "0000000000000000000000000000000000000000"
then
let
startingRepository = builtins.fetchGit (arguments // {
inherit (srcAttributes) rev;
});
in
startingRepository.lastModified
else
builtins.currentTime;
in
builtins.fetchGit (arguments // {
date = "${toString ((startingTime / interval) * interval)}";
} // extraFetchGitArgs) Then with that lib.truncate {
src = …;
interval = 24 * 60 * 60;
} Now, this PR needs to be fixed to work against the latest changes on Alternatively, if they know a better way to accomplish what we're trying to do I would welcome that, but "setting up a cron job that sets a tag or adds a commit every day to our |
I should probably also add one more thing that might not be obvious based on the previous discussion:
The |
This adds a new `incremental` utility for Haskell CI that supports incremental builds based on the approach outlined in this blog post: https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/ The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds: - A full build at an older point in time e.g. a daily or weekly time boundary - An incremental build relative to the last full build This incremental build reuses the build products left over from the most recent full build. In order to do this, though, we need a way to "snap" a package's `git` source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary. The approach I went with to make that possible was to extend Nix's `builtins.fetchGit` to support a new `date` argument and you can find the corresponding PR for that here: NixOS/nix#7362 That is why the `incremental` utility added here requires a sufficiently new version of Nix (one that would incorporate that change, presuming it is merged). This also requires GHC 9.4 or newer in order to pick up a fix to GHC's change detection logic, as described in more detail in the above blog post. However, if you satisfy those requirements then this works exactly the way you'd expect: all of the incremental builds only have to build the diff since the last time boundary. Moreover, if CI caches the full build then developers can also run `nix build` locally and only have to build the diff, too. --- Lower required version … so that it works against the upstream PR I'll change the required version to an official release if the PR is merged. --- s/pkgs/pkg/g … as caught by @cdepillabout Co-authored-by: Dennis Gosnell <[email protected]> --- Skip the use of `tar` We can store the `dist` directory decompressed, which speeds up the dist export/import This potentially requires more disk space *but* by storing the files unpacked it may actually improve disk utilization in some cases if `auto-optimise-store` is enabled by permitting deduplication of `dist` files. --- Add an `installDist` phase … which is disabled by default The motivation for this is to bring the behavior of `enableSeparateDistOutput` more in line with the other options where it doesn't change *whether* or not something is exported, but rather *where* it is exported. Now `installDist` controls whether or not the `dist` directory is exported. Based on this discussion: https://github.com/NixOS/nixpkgs/pull/203499/files#r1034150076 --- Document `interval` argument … as suggested by @cdepillabout --- s/for use for/for use with/ … based on feedback from @MaxGabriel --- Move `installDistPhase` to `postPhases` There are two reasons for doing this: - We can get rid of the hack to remove the dist output from the outputs - We can ensure that any changes that happen in the install phase are correctly reflected in the `dist` export --- Disable dylib workaround for incremental build --- Improve correctness of `incremental` function Typically we don't want to just roll back the source code that is the input for the Haskell package because the dependencies for the package may have changed In other words, if you roll back the source code for the top-level package without also rolling back the Nix-supplied dependencies for that build then you run the risk of an unexpected build failure (due to an older version of the Haskell package being built against a newer version of the Nix-supplied dependencies). What you actually want to do is to roll back the entire repository (i.e. the Haskell source code and the supporting Nix code) to ensure that the Haskell source code and Nix code stay in sync. This more generalized rollback complicates the UX for the `incremental` function. I did my best to try to streamline the UX so that the user just needs to specify how to locate the matching (older) package after a rollback. --- Make date relative to revision (if possible) This way if you attempt to incrementally build an older revision then the full rebuild will be relative to the older revision instead of being relative to the present. --- Add `extraFetchGitArgs` option This in particular comes in handy if you want to specify `ref = "main";` to ensure that the older build comes from the `main` branch of your repository.
Incremental builds would be a game changer for every CI running Nix, saving time and resources. As discussed above, this PR does not add any more impurities that are not already there. I'm echoing Gabriella's request to please reconsider merging this. |
I wonder if this would be easier to support if it only applies when you already have a rev: builtins.fetchGit {
url = "some-url";
rev = "abb08192ed875ef73fa66029994aa2f6700befd0"
date = "1 day before";
} It does mean that The current PR uses ref to first obtain a rev, and then modify that to roll back time. builtins.fetchGit {
url = "some-url";
ref = "SOMEBRANCH"
date = "1 day before";
} I leaning toward accepting either as-is, or via restricting the behavior to when rev is provided. TimezonesAnother random question: is the timestamp specification sensitive to things like timezones and locales? If the someone's location impacted this, it would be much harder to consider the date to be a deterministic modifier. |
Hrm....
If we do this, we need to either ensure a consistent TZ or not allow some of the special forms (https://github.com/git/git/blob/master/date.c#L1197-L1204). "yesterday" is just an offset, but "tea" is a specific time of day most conducive to hot beverages, very location dependent. |
I'd also be okay with always requiring the |
No, such keywords should be forbidden in pure eval |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2024-08-21-nix-team-meeting-minutes-171/50950/1 |
What is the current status of this feature? From the 2024-08-21 nix team meeting minutes :
... which gives hope? |
This allows users to specify an absolute or relative date (basically, anything that git accepts as a date specification) when fetching a repository.
The motivation for this change is to enable support for incremental builds for Haskell packages for this Nixpkgs pull request:
NixOS/nixpkgs#204020
… inspired by this blog post:
https://harry.garrood.me/blog/easy-incremental-haskell-ci-builds-with-ghc-9.4/
Keep in mind that this new feature can power incremental builds for other package managers, too. There is not much that is Haskell-specific about this feature.
The basic idea is that instead of Nix doing a full build for a package, we split every build into two builds:
A full build at an older point in time
e.g. a daily or weekly time boundary
An incremental build relative to the last full build
This incremental build reuses the build products left over from the most recent full build.
In order to do this, though, we need a way to "snap" a package's
git
source input to an earlier point in time (e.g. a daily boundary or weekly boundary). This would allow multiple incremental builds to share the same full rebuild if they snap to the same time boundary.The two main approaches I considered were:
Approach 1 (this PR)
Patch Nix to add a
date
argument tobuiltins.fetchGit
Approach 2
Patch
nix-prefetch-git
to support a new--date
optionDisable the sandbox
Run
nix-prefetch-git
at evaluation time using import-from-derivation to fetch and rehash the repository at an older point in timeApproach 1 seemed the more desirable of the two.