From 34e20c164cd512c10af99803215e32889a6d965b Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Fri, 18 Feb 2022 16:56:35 +0100 Subject: [PATCH 1/3] libfetchers/path: set `lastModified` to path's mtime When importing e.g. a local `nixpkgs` in a flake to test a change like { inputs.nixpkgs.url = path:/home/ma27/Projects/nixpkgs; outputs = /* ... */ } then the input is missing a `lastModified`-field that's e.g. used in `nixpkgs.lib.nixosSystem`. Due to the missing `lastMoified`-field, the mtime is set to 19700101: result -> /nix/store/b7dg1lmmsill2rsgyv2w7b6cnmixkvc1-nixos-system-nixos-22.05.19700101.dirty With this change, the `path`-fetcher now sets a `lastModified` attribute to the `mtime` just like it's the case in the `tarball`-fetcher already. When building NixOS systems with `nixpkgs` being a `path`-input and this patch, the output-path now looks like this: result -> /nix/store/ld2qf9c1s98dxmiwcaq5vn9k5ylzrm1s-nixos-system-nixos-22.05.20220217.dirty --- src/libfetchers/path.cc | 15 ++++++++++++--- src/libutil/archive.cc | 19 +++++++++++++++---- src/libutil/archive.hh | 4 ++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index 59e228e97..2d5d7d58d 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -1,5 +1,7 @@ #include "fetchers.hh" #include "store-api.hh" +#include +#include "archive.hh" namespace nix::fetchers { @@ -80,8 +82,9 @@ struct PathInputScheme : InputScheme // nothing to do } - std::pair fetch(ref store, const Input & input) override + std::pair fetch(ref store, const Input & _input) override { + Input input(_input); std::string absPath; auto path = getStrAttr(input.attrs, "path"); @@ -111,9 +114,15 @@ struct PathInputScheme : InputScheme if (storePath) store->addTempRoot(*storePath); - if (!storePath || storePath->name() != "source" || !store->isValidPath(*storePath)) + time_t mtime = 0; + if (!storePath || storePath->name() != "source" || !store->isValidPath(*storePath)) { // FIXME: try to substitute storePath. - storePath = store->addToStore("source", absPath); + auto src = sinkToSource([&](Sink & sink) { + mtime = dumpPathAndGetMtime(absPath, sink, defaultPathFilter); + }); + storePath = store->addToStoreFromDump(*src, "source"); + } + input.attrs.insert_or_assign("lastModified", uint64_t(mtime)); return {std::move(*storePath), input}; } diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc index eda004756..30b471af5 100644 --- a/src/libutil/archive.cc +++ b/src/libutil/archive.cc @@ -64,11 +64,12 @@ static void dumpContents(const Path & path, off_t size, } -static void dump(const Path & path, Sink & sink, PathFilter & filter) +static time_t dump(const Path & path, Sink & sink, PathFilter & filter) { checkInterrupt(); auto st = lstat(path); + time_t result = st.st_mtime; sink << "("; @@ -103,7 +104,10 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter) for (auto & i : unhacked) if (filter(path + "/" + i.first)) { sink << "entry" << "(" << "name" << i.first << "node"; - dump(path + "/" + i.second, sink, filter); + auto tmp_mtime = dump(path + "/" + i.second, sink, filter); + if (tmp_mtime > result) { + result = tmp_mtime; + } sink << ")"; } } @@ -114,13 +118,20 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter) else throw Error("file '%1%' has an unsupported type", path); sink << ")"; + + return result; } -void dumpPath(const Path & path, Sink & sink, PathFilter & filter) +time_t dumpPathAndGetMtime(const Path & path, Sink & sink, PathFilter & filter) { sink << narVersionMagic1; - dump(path, sink, filter); + return dump(path, sink, filter); +} + +void dumpPath(const Path & path, Sink & sink, PathFilter & filter) +{ + dumpPathAndGetMtime(path, sink, filter); } diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh index fca351605..79ce08df0 100644 --- a/src/libutil/archive.hh +++ b/src/libutil/archive.hh @@ -48,6 +48,10 @@ namespace nix { void dumpPath(const Path & path, Sink & sink, PathFilter & filter = defaultPathFilter); +/* Same as `void dumpPath()`, but returns the last modified date of the path */ +time_t dumpPathAndGetMtime(const Path & path, Sink & sink, + PathFilter & filter = defaultPathFilter); + void dumpString(std::string_view s, Sink & sink); /* FIXME: fix this API, it sucks. */ From 244baff2c7bc287b83377f1ed807a861fc705dac Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Mon, 28 Feb 2022 11:56:50 +0100 Subject: [PATCH 2/3] libfetchers: remove obsolete filesystem #include --- src/libfetchers/path.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index 2d5d7d58d..f0ef97da5 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -1,6 +1,5 @@ #include "fetchers.hh" #include "store-api.hh" -#include #include "archive.hh" namespace nix::fetchers { From 975bade7f0adb0d122eabeeca6ad44bf1d1f4366 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 15 Mar 2022 12:55:32 +0100 Subject: [PATCH 3/3] Implement simple test for `path`-fetcher setting a correct `lastModifiedDate` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> --- tests/fetchPath.sh | 6 ++++++ tests/local.mk | 1 + 2 files changed, 7 insertions(+) create mode 100644 tests/fetchPath.sh diff --git a/tests/fetchPath.sh b/tests/fetchPath.sh new file mode 100644 index 000000000..0cfdf68cf --- /dev/null +++ b/tests/fetchPath.sh @@ -0,0 +1,6 @@ +source common.sh + +touch foo -t 222211111111 +# We only check whether 2222-11-1* **:**:** is the last modified date since +# `lastModified` is transformed into UTC in `builtins.fetchTarball`. +[[ "$(nix eval --impure --raw --expr "(builtins.fetchTree \"path://$PWD/foo\").lastModifiedDate")" =~ 2222111.* ]] diff --git a/tests/local.mk b/tests/local.mk index 8032fc38a..b69fb9391 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -21,6 +21,7 @@ nix_tests = \ tarball.sh \ fetchGit.sh \ fetchurl.sh \ + fetchPath.sh \ simple.sh \ referrers.sh \ optimise-store.sh \