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 substituting in fetchGit #25

Merged
merged 4 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/libexpr/primops/fetchTree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,20 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
if (evalSettings.pureEval && !expectedHash)
throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who);

// try to substitute if we can
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't actually necessary, but eventually we may want to support fetchGit

if (settings.useSubstitutes && expectedHash) {
auto substitutableStorePath = fetchers::trySubstitute(state.store,
unpack ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat, *expectedHash, name);
if (substitutableStorePath) {
auto substitutablePath = state.store->toRealPath(*substitutableStorePath);
if (state.allowedPaths)
state.allowedPaths->insert(substitutablePath);

mkString(v, substitutablePath, PathSet({substitutablePath}));
return;
}
}

auto storePath =
unpack
? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).storePath
Expand Down
18 changes: 18 additions & 0 deletions src/libfetchers/fetchers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,22 @@ std::pair<Tree, std::shared_ptr<const Input>> Input::fetchTree(ref<Store> store)
return {std::move(tree), input};
}

std::optional<StorePath> trySubstitute(ref<Store> store, FileIngestionMethod ingestionMethod,
Hash hash, std::string_view name)
{
auto substitutablePath = store->makeFixedOutputPath(ingestionMethod, hash, name);

try {
store->ensurePath(substitutablePath);

debug("using substituted path '%s'", store->printStorePath(substitutablePath));

return substitutablePath;
} catch (Error & e) {
debug("substitution of path '%s' failed: %s", store->printStorePath(substitutablePath), e.what());
}

return std::nullopt;
}

}
3 changes: 3 additions & 0 deletions src/libfetchers/fetchers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,7 @@ Tree downloadTarball(
const std::string & name,
bool immutable);

std::optional<StorePath> trySubstitute(ref<Store> store, FileIngestionMethod ingestionMethod,
Hash hash, std::string_view name);

}
20 changes: 19 additions & 1 deletion src/libfetchers/git.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ struct GitInput : Input

auto ingestionMethod = treeHash ? FileIngestionMethod::Git : FileIngestionMethod::Recursive;

// try to substitute
if (settings.useSubstitutes && treeHash && !submodules) {
auto storePath = fetchers::trySubstitute(store, ingestionMethod, *treeHash, name);
if (storePath) {
return {
Tree {
.actualPath = store->toRealPath(*storePath),
.storePath = std::move(*storePath),
.info = TreeInfo {
.revCount = std::nullopt,
.lastModified = 0,
},
},
input
};
}
}

std::string cacheType = "git";
if (shallow) cacheType += "-shallow";
if (submodules) cacheType += "-submodules";
Expand Down Expand Up @@ -385,7 +403,7 @@ struct GitInput : Input
unpackTarfile(*source, tmpDir);
}

auto storePath = store->addToStore(name, tmpDir, FileIngestionMethod::Recursive, ingestionMethod == FileIngestionMethod::Git ? htSHA1 : htSHA256, filter);
auto storePath = store->addToStore(name, tmpDir, ingestionMethod, ingestionMethod == FileIngestionMethod::Git ? htSHA1 : htSHA256, filter);

// verify treeHash is what we actually obtained in the nix store
if (input->treeHash) {
Expand Down
9 changes: 7 additions & 2 deletions tests/git.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
source common.sh

clearStore
clearCache

try () {
hash=$(nix hash-git --base16 --type sha1 $TEST_ROOT/hash-path)
Expand Down Expand Up @@ -40,8 +41,6 @@ test "$hash3" = "sha256:1i2x80840igikhbyy7nqf08ymx3a6n83x1fzyrxvddf0sdl5nqvp"
if [[ -n $(type -p git) ]]; then
repo=$TEST_ROOT/git

export _NIX_FORCE_HTTP=1

rm -rf $repo $TEST_HOME/.cache/nix

git init $repo
Expand All @@ -64,6 +63,12 @@ if [[ -n $(type -p git) ]]; then

# Submodules cause error.
(! nix eval --raw "(builtins.fetchTree { type = \"git\"; url = file://$repo; treeHash = \"$treeHash\"; submodules = true; }).outPath")

# Check that we can substitute it from other places.
nix copy --to file://$cacheDir $path
nix-store --delete $path
path2=$(nix eval --raw "(builtins.fetchTree { type = \"git\"; url = file:///no-such-repo; treeHash = \"$treeHash\"; }).outPath" --substituters file://$cacheDir --option substitute true)
[ $path2 = $path ]
else
echo "Git not installed; skipping Git tests"
fi