Add support for tarball flake inputs
For example, $ nix flake info https://github.com/edolstra/dwarffs/archive/master.tar.gz Fixes #2929.
This commit is contained in:
parent
c39c2503f7
commit
1af7b94c1d
4 changed files with 110 additions and 1 deletions
|
@ -39,6 +39,10 @@ std::pair<Tree, std::shared_ptr<const Input>> Input::fetchTree(ref<Store> store)
|
||||||
if (input->narHash)
|
if (input->narHash)
|
||||||
assert(input->narHash == tree.narHash);
|
assert(input->narHash == tree.narHash);
|
||||||
|
|
||||||
|
if (narHash && narHash != input->narHash)
|
||||||
|
throw Error("NAR hash mismatch in input '%s', expected '%s', got '%s'",
|
||||||
|
to_string(), narHash->to_string(SRI), input->narHash->to_string(SRI));
|
||||||
|
|
||||||
return {std::move(tree), input};
|
return {std::move(tree), input};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct Tree
|
||||||
struct Input : std::enable_shared_from_this<Input>
|
struct Input : std::enable_shared_from_this<Input>
|
||||||
{
|
{
|
||||||
std::string type;
|
std::string type;
|
||||||
std::optional<Hash> narHash;
|
std::optional<Hash> narHash; // FIXME: implement
|
||||||
|
|
||||||
virtual ~Input() { }
|
virtual ~Input() { }
|
||||||
|
|
||||||
|
|
91
src/libstore/fetchers/tarball.cc
Normal file
91
src/libstore/fetchers/tarball.cc
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include "fetchers.hh"
|
||||||
|
#include "download.hh"
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "parse.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
namespace nix::fetchers {
|
||||||
|
|
||||||
|
struct TarballInput : Input
|
||||||
|
{
|
||||||
|
ParsedURL url;
|
||||||
|
std::optional<Hash> hash;
|
||||||
|
|
||||||
|
bool operator ==(const Input & other) const override
|
||||||
|
{
|
||||||
|
auto other2 = dynamic_cast<const TarballInput *>(&other);
|
||||||
|
return
|
||||||
|
other2
|
||||||
|
&& to_string() == other2->to_string()
|
||||||
|
&& hash == other2->hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isImmutable() const override
|
||||||
|
{
|
||||||
|
return (bool) hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const override
|
||||||
|
{
|
||||||
|
auto url2(url);
|
||||||
|
if (narHash)
|
||||||
|
url2.query.insert_or_assign("narHash", narHash->to_string(SRI));
|
||||||
|
return url2.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Tree, std::shared_ptr<const Input>> fetchTreeInternal(nix::ref<Store> store) const override
|
||||||
|
{
|
||||||
|
CachedDownloadRequest request(url.to_string());
|
||||||
|
request.unpack = true;
|
||||||
|
request.getLastModified = true;
|
||||||
|
request.name = "source";
|
||||||
|
|
||||||
|
auto res = getDownloader()->downloadCached(store, request);
|
||||||
|
|
||||||
|
auto input = std::make_shared<TarballInput>(*this);
|
||||||
|
|
||||||
|
auto storePath = store->parseStorePath(res.storePath);
|
||||||
|
|
||||||
|
input->narHash = store->queryPathInfo(storePath)->narHash;
|
||||||
|
|
||||||
|
return {
|
||||||
|
Tree {
|
||||||
|
.actualPath = res.path,
|
||||||
|
.storePath = std::move(storePath),
|
||||||
|
.lastModified = *res.lastModified
|
||||||
|
},
|
||||||
|
input
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TarballInputScheme : InputScheme
|
||||||
|
{
|
||||||
|
std::unique_ptr<Input> inputFromURL(const ParsedURL & url) override
|
||||||
|
{
|
||||||
|
if (url.scheme != "file" && url.scheme != "http" && url.scheme != "https") return nullptr;
|
||||||
|
|
||||||
|
if (!hasSuffix(url.path, ".zip")
|
||||||
|
&& !hasSuffix(url.path, ".tar")
|
||||||
|
&& !hasSuffix(url.path, ".tar.gz")
|
||||||
|
&& !hasSuffix(url.path, ".tar.xz")
|
||||||
|
&& !hasSuffix(url.path, ".tar.bz2"))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto input = std::make_unique<TarballInput>();
|
||||||
|
input->type = "tarball";
|
||||||
|
input->url = url;
|
||||||
|
|
||||||
|
auto narHash = url.query.find("narHash");
|
||||||
|
if (narHash != url.query.end()) {
|
||||||
|
// FIXME: require SRI hash.
|
||||||
|
input->narHash = Hash(narHash->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<TarballInputScheme>()); });
|
||||||
|
|
||||||
|
}
|
|
@ -573,3 +573,17 @@ nix flake info --flake-registry $registry --json hg+file://$flake5Dir
|
||||||
[[ $(nix flake info --flake-registry $registry --json hg+file://$flake5Dir | jq -e -r .revCount) = 1 ]]
|
[[ $(nix flake info --flake-registry $registry --json hg+file://$flake5Dir | jq -e -r .revCount) = 1 ]]
|
||||||
|
|
||||||
nix build -o $TEST_ROOT/result hg+file://$flake5Dir --no-registries --no-allow-dirty
|
nix build -o $TEST_ROOT/result hg+file://$flake5Dir --no-registries --no-allow-dirty
|
||||||
|
|
||||||
|
# Test tarball flakes
|
||||||
|
tar cfz $TEST_ROOT/flake.tar.gz -C $TEST_ROOT flake5
|
||||||
|
|
||||||
|
nix build -o $TEST_ROOT/result file://$TEST_ROOT/flake.tar.gz
|
||||||
|
|
||||||
|
# Building with a tarball URL containing a SRI hash should also work.
|
||||||
|
url=$(nix flake info --json file://$TEST_ROOT/flake.tar.gz | jq -r .url)
|
||||||
|
[[ $url =~ sha256- ]]
|
||||||
|
|
||||||
|
nix build -o $TEST_ROOT/result $url
|
||||||
|
|
||||||
|
# Building with an incorrect SRI hash should fail.
|
||||||
|
nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" 2>&1 | grep 'NAR hash mismatch'
|
||||||
|
|
Loading…
Reference in a new issue