mirror of
https://github.com/NixOS/nix
synced 2025-06-30 03:23:16 +02:00
Fix format
This commit is contained in:
parent
79d41062d0
commit
70ffcc83d7
2 changed files with 307 additions and 287 deletions
|
@ -110,7 +110,6 @@ TEST_F(GitUtilsTest, sink_hardlink)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace lfs {
|
namespace lfs {
|
||||||
|
|
||||||
TEST_F(GitUtilsTest, parseGitRemoteUrl)
|
TEST_F(GitUtilsTest, parseGitRemoteUrl)
|
||||||
|
@ -196,7 +195,8 @@ TEST_F(GitUtilsTest, parseGitRemoteUrl)
|
||||||
EXPECT_EQ(result.path, "");
|
EXPECT_EQ(result.path, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TEST_F(GitUtilsTest, gitUrlToHttp) {
|
TEST_F(GitUtilsTest, gitUrlToHttp)
|
||||||
|
{
|
||||||
{
|
{
|
||||||
const GitUrl url = parseGitUrl("git@github.com:user/repo.git");
|
const GitUrl url = parseGitUrl("git@github.com:user/repo.git");
|
||||||
EXPECT_EQ(url.toHttp(), "https://github.com/user/repo.git");
|
EXPECT_EQ(url.toHttp(), "https://github.com/user/repo.git");
|
||||||
|
@ -219,7 +219,8 @@ TEST_F(GitUtilsTest, gitUrlToHttp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(GitUtilsTest, gitUrlToSsh) {
|
TEST_F(GitUtilsTest, gitUrlToSsh)
|
||||||
|
{
|
||||||
{
|
{
|
||||||
const GitUrl url = parseGitUrl("https://example.com/user/repo.git");
|
const GitUrl url = parseGitUrl("https://example.com/user/repo.git");
|
||||||
const auto [host, path] = url.toSsh();
|
const auto [host, path] = url.toSsh();
|
||||||
|
@ -234,9 +235,11 @@ TEST_F(GitUtilsTest, gitUrlToSsh) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FetchAttributeTest : public ::testing::Test {
|
class FetchAttributeTest : public ::testing::Test
|
||||||
|
{
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override
|
||||||
|
{
|
||||||
// test literal (non-wildcard) matches too
|
// test literal (non-wildcard) matches too
|
||||||
std::string content1 = "litfile filter=lfs diff=lfs merge=lfs -text";
|
std::string content1 = "litfile filter=lfs diff=lfs merge=lfs -text";
|
||||||
auto rules1 = parseGitAttrFile(content1);
|
auto rules1 = parseGitAttrFile(content1);
|
||||||
|
@ -251,23 +254,25 @@ protected:
|
||||||
Fetch fetch2;
|
Fetch fetch2;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(FetchAttributeTest, ExactMatch) {
|
TEST_F(FetchAttributeTest, ExactMatch)
|
||||||
|
{
|
||||||
EXPECT_TRUE(fetch1.hasAttribute("litfile", "filter", "lfs"));
|
EXPECT_TRUE(fetch1.hasAttribute("litfile", "filter", "lfs"));
|
||||||
EXPECT_FALSE(fetch1.hasAttribute("other", "filter", "lfs"));
|
EXPECT_FALSE(fetch1.hasAttribute("other", "filter", "lfs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FetchAttributeTest, WildcardMatch) {
|
TEST_F(FetchAttributeTest, WildcardMatch)
|
||||||
|
{
|
||||||
EXPECT_TRUE(fetch2.hasAttribute("match.wildcard", "filter", "lfs"));
|
EXPECT_TRUE(fetch2.hasAttribute("match.wildcard", "filter", "lfs"));
|
||||||
EXPECT_FALSE(fetch2.hasAttribute("nomatch.otherext", "filter", "lfs"));
|
EXPECT_FALSE(fetch2.hasAttribute("nomatch.otherext", "filter", "lfs"));
|
||||||
EXPECT_FALSE(fetch2.hasAttribute("nomatch.wildcard.extra", "filter", "lfs"));
|
EXPECT_FALSE(fetch2.hasAttribute("nomatch.wildcard.extra", "filter", "lfs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FetchAttributeTest, EmptyPath) {
|
TEST_F(FetchAttributeTest, EmptyPath)
|
||||||
|
{
|
||||||
EXPECT_FALSE(fetch1.hasAttribute("", "filter", "lfs"));
|
EXPECT_FALSE(fetch1.hasAttribute("", "filter", "lfs"));
|
||||||
EXPECT_FALSE(fetch2.hasAttribute("", "filter", "lfs"));
|
EXPECT_FALSE(fetch2.hasAttribute("", "filter", "lfs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace lfs
|
} // namespace lfs
|
||||||
|
|
||||||
} // namespace nix
|
} // namespace nix
|
||||||
|
|
|
@ -16,25 +16,28 @@
|
||||||
#include "processes.hh"
|
#include "processes.hh"
|
||||||
#include "url.hh"
|
#include "url.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
namespace lfs {
|
namespace lfs {
|
||||||
|
|
||||||
// see Fetch::rules
|
// see Fetch::rules
|
||||||
struct AttrRule {
|
struct AttrRule
|
||||||
|
{
|
||||||
std::string pattern;
|
std::string pattern;
|
||||||
std::unordered_map<std::string, std::string> attributes;
|
std::unordered_map<std::string, std::string> attributes;
|
||||||
git_pathspec * pathspec = nullptr;
|
git_pathspec * pathspec = nullptr;
|
||||||
|
|
||||||
AttrRule() = default;
|
AttrRule() = default;
|
||||||
|
|
||||||
explicit AttrRule(std::string pat) : pattern(std::move(pat)) {
|
explicit AttrRule(std::string pat)
|
||||||
|
: pattern(std::move(pat))
|
||||||
|
{
|
||||||
initPathspec();
|
initPathspec();
|
||||||
}
|
}
|
||||||
|
|
||||||
~AttrRule() {
|
~AttrRule()
|
||||||
|
{
|
||||||
if (pathspec) {
|
if (pathspec) {
|
||||||
git_pathspec_free(pathspec);
|
git_pathspec_free(pathspec);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +53,8 @@ struct AttrRule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initPathspec() {
|
void initPathspec()
|
||||||
|
{
|
||||||
git_strarray patterns = {0};
|
git_strarray patterns = {0};
|
||||||
const char * pattern_str = pattern.c_str();
|
const char * pattern_str = pattern.c_str();
|
||||||
patterns.strings = const_cast<char **>(&pattern_str);
|
patterns.strings = const_cast<char **>(&pattern_str);
|
||||||
|
@ -63,43 +67,44 @@ struct AttrRule {
|
||||||
};
|
};
|
||||||
|
|
||||||
// git-lfs metadata about a file
|
// git-lfs metadata about a file
|
||||||
struct Md {
|
struct Md
|
||||||
|
{
|
||||||
std::string path; // fs path relative to repo root, no ./ prefix
|
std::string path; // fs path relative to repo root, no ./ prefix
|
||||||
std::string oid; // git-lfs managed object id. you give this to the lfs server
|
std::string oid; // git-lfs managed object id. you give this to the lfs server
|
||||||
// for downloads
|
// for downloads
|
||||||
size_t size; // in bytes
|
size_t size; // in bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GitUrl {
|
struct GitUrl
|
||||||
|
{
|
||||||
std::string protocol;
|
std::string protocol;
|
||||||
std::string user;
|
std::string user;
|
||||||
std::string host;
|
std::string host;
|
||||||
std::string port;
|
std::string port;
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
std::string toHttp() const {
|
std::string toHttp() const
|
||||||
|
{
|
||||||
if (protocol.empty() || host.empty()) {
|
if (protocol.empty() || host.empty()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
std::string prefix = ((protocol == "ssh") ? "https" : protocol) + "://";
|
std::string prefix = ((protocol == "ssh") ? "https" : protocol) + "://";
|
||||||
return prefix + host +
|
return prefix + host + (port.empty() ? "" : ":" + port) + "/" + path;
|
||||||
(port.empty() ? "" : ":" + port) + "/" + path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [host, path]
|
// [host, path]
|
||||||
std::pair<std::string, std::string> toSsh() const {
|
std::pair<std::string, std::string> toSsh() const
|
||||||
|
{
|
||||||
if (host.empty()) {
|
if (host.empty()) {
|
||||||
return {"", ""};
|
return {"", ""};
|
||||||
}
|
}
|
||||||
std::string userPart = user.empty() ? "" : user + "@";
|
std::string userPart = user.empty() ? "" : user + "@";
|
||||||
return {
|
return {userPart + host, path};
|
||||||
userPart + host,
|
|
||||||
path
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Fetch {
|
struct Fetch
|
||||||
|
{
|
||||||
// only true after init()
|
// only true after init()
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
|
|
||||||
|
@ -121,15 +126,15 @@ struct Fetch {
|
||||||
std::vector<nlohmann::json> fetchUrls(const std::vector<Md> & metadatas) const;
|
std::vector<nlohmann::json> fetchUrls(const std::vector<Md> & metadatas) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static size_t writeCallback(void * contents, size_t size, size_t nmemb, std::string * s)
|
||||||
static size_t writeCallback(void *contents, size_t size, size_t nmemb,
|
{
|
||||||
std::string *s) {
|
|
||||||
size_t newLength = size * nmemb;
|
size_t newLength = size * nmemb;
|
||||||
s->append((char *) contents, newLength);
|
s->append((char *) contents, newLength);
|
||||||
return newLength;
|
return newLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SinkCallbackData {
|
struct SinkCallbackData
|
||||||
|
{
|
||||||
Sink * sink;
|
Sink * sink;
|
||||||
std::string_view sha256Expected;
|
std::string_view sha256Expected;
|
||||||
HashSink hashSink;
|
HashSink hashSink;
|
||||||
|
@ -138,10 +143,12 @@ struct SinkCallbackData {
|
||||||
: sink(sink)
|
: sink(sink)
|
||||||
, sha256Expected(sha256)
|
, sha256Expected(sha256)
|
||||||
, hashSink(HashAlgorithm::SHA256)
|
, hashSink(HashAlgorithm::SHA256)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t sinkWriteCallback(void *contents, size_t size, size_t nmemb, SinkCallbackData *data) {
|
static size_t sinkWriteCallback(void * contents, size_t size, size_t nmemb, SinkCallbackData * data)
|
||||||
|
{
|
||||||
size_t totalSize = size * nmemb;
|
size_t totalSize = size * nmemb;
|
||||||
data->hashSink({(char *) contents, totalSize});
|
data->hashSink({(char *) contents, totalSize});
|
||||||
(*data->sink)({(char *) contents, totalSize});
|
(*data->sink)({(char *) contents, totalSize});
|
||||||
|
@ -149,7 +156,9 @@ static size_t sinkWriteCallback(void *contents, size_t size, size_t nmemb, SinkC
|
||||||
}
|
}
|
||||||
|
|
||||||
// if authHeader is "", downloadToSink assumes to auth is expected
|
// if authHeader is "", downloadToSink assumes to auth is expected
|
||||||
void downloadToSink(const std::string &url, const std::string &authHeader, Sink &sink, std::string_view sha256Expected) {
|
void downloadToSink(
|
||||||
|
const std::string & url, const std::string & authHeader, Sink & sink, std::string_view sha256Expected)
|
||||||
|
{
|
||||||
CURL * curl;
|
CURL * curl;
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
|
|
||||||
|
@ -177,15 +186,17 @@ void downloadToSink(const std::string &url, const std::string &authHeader, Sink
|
||||||
|
|
||||||
const auto sha256Actual = data.hashSink.finish().first.to_string(HashFormat::Base16, false);
|
const auto sha256Actual = data.hashSink.finish().first.to_string(HashFormat::Base16, false);
|
||||||
if (sha256Actual != data.sha256Expected) {
|
if (sha256Actual != data.sha256Expected) {
|
||||||
throw std::runtime_error("sha256 mismatch: while fetching " + url + ": expected " + std::string(data.sha256Expected) + " but got " + sha256Actual);
|
throw std::runtime_error(
|
||||||
|
"sha256 mismatch: while fetching " + url + ": expected " + std::string(data.sha256Expected) + " but got "
|
||||||
|
+ sha256Actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getLfsApiToken(const GitUrl & u)
|
||||||
std::string getLfsApiToken(const GitUrl& u) {
|
{
|
||||||
const auto [maybeUserAndHost, path] = u.toSsh();
|
const auto [maybeUserAndHost, path] = u.toSsh();
|
||||||
auto [status, output] = runProgram(RunOptions{
|
auto [status, output] = runProgram(RunOptions{
|
||||||
.program = "ssh",
|
.program = "ssh",
|
||||||
|
@ -193,7 +204,9 @@ std::string getLfsApiToken(const GitUrl& u) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (output.empty())
|
if (output.empty())
|
||||||
throw std::runtime_error("git-lfs-authenticate: no output (cmd: ssh " + maybeUserAndHost + " git-lfs-authenticate " + path + " download)");
|
throw std::runtime_error(
|
||||||
|
"git-lfs-authenticate: no output (cmd: ssh " + maybeUserAndHost + " git-lfs-authenticate " + path
|
||||||
|
+ " download)");
|
||||||
|
|
||||||
nlohmann::json query_resp = nlohmann::json::parse(output);
|
nlohmann::json query_resp = nlohmann::json::parse(output);
|
||||||
if (!query_resp.contains("header"))
|
if (!query_resp.contains("header"))
|
||||||
|
@ -206,7 +219,8 @@ std::string getLfsApiToken(const GitUrl& u) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getLfsEndpointUrl(git_repository *repo) {
|
std::string getLfsEndpointUrl(git_repository * repo)
|
||||||
|
{
|
||||||
int err;
|
int err;
|
||||||
git_remote * remote = NULL;
|
git_remote * remote = NULL;
|
||||||
err = git_remote_lookup(&remote, repo, "origin");
|
err = git_remote_lookup(&remote, repo, "origin");
|
||||||
|
@ -222,7 +236,8 @@ std::string getLfsEndpointUrl(git_repository *repo) {
|
||||||
return std::string(url_c_str);
|
return std::string(url_c_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string git_attr_value_to_string(git_attr_value_t value) {
|
std::string git_attr_value_to_string(git_attr_value_t value)
|
||||||
|
{
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case GIT_ATTR_VALUE_UNSPECIFIED:
|
case GIT_ATTR_VALUE_UNSPECIFIED:
|
||||||
return "GIT_ATTR_VALUE_UNSPECIFIED";
|
return "GIT_ATTR_VALUE_UNSPECIFIED";
|
||||||
|
@ -237,8 +252,8 @@ std::string git_attr_value_to_string(git_attr_value_t value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<Md> parseLfsMetadata(const std::string & content, const std::string & filename)
|
||||||
std::optional<Md> parseLfsMetadata(const std::string &content, const std::string &filename) {
|
{
|
||||||
// https://github.com/git-lfs/git-lfs/blob/2ef4108/docs/spec.md
|
// https://github.com/git-lfs/git-lfs/blob/2ef4108/docs/spec.md
|
||||||
//
|
//
|
||||||
// example git-lfs pointer file:
|
// example git-lfs pointer file:
|
||||||
|
@ -293,19 +308,18 @@ std::optional<Md> parseLfsMetadata(const std::string &content, const std::string
|
||||||
return std::make_optional(Md{filename, oid, std::stoul(size)});
|
return std::make_optional(Md{filename, oid, std::stoul(size)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// there's already a ParseURL here
|
||||||
// there's already a ParseURL here https://github.com/b-camacho/nix/blob/ef6fa54e05cd4134ec41b0d64c1a16db46237f83/src/libutil/url.cc#L13
|
// https://github.com/b-camacho/nix/blob/ef6fa54e05cd4134ec41b0d64c1a16db46237f83/src/libutil/url.cc#L13 but that does
|
||||||
// but that does not handle git's custom scp-like syntax
|
// not handle git's custom scp-like syntax
|
||||||
GitUrl parseGitUrl(const std::string& url) {
|
GitUrl parseGitUrl(const std::string & url)
|
||||||
|
{
|
||||||
GitUrl result;
|
GitUrl result;
|
||||||
|
|
||||||
// regular protocols
|
// regular protocols
|
||||||
const std::regex r_url(
|
const std::regex r_url(R"(^(ssh|git|https?|ftps?)://(?:([^@]+)@)?([^:/]+)(?::(\d+))?/(.*))");
|
||||||
R"(^(ssh|git|https?|ftps?)://(?:([^@]+)@)?([^:/]+)(?::(\d+))?/(.*))");
|
|
||||||
|
|
||||||
// "alternative scp-like syntax" https://git-scm.com/docs/git-fetch#_git_urls
|
// "alternative scp-like syntax" https://git-scm.com/docs/git-fetch#_git_urls
|
||||||
const std::regex r_scp_like_url(
|
const std::regex r_scp_like_url(R"(^(?:([^@]+)@)?([^:/]+):(/?.*))");
|
||||||
R"(^(?:([^@]+)@)?([^:/]+):(/?.*))");
|
|
||||||
|
|
||||||
std::smatch matches;
|
std::smatch matches;
|
||||||
if (std::regex_match(url, matches, r_url)) {
|
if (std::regex_match(url, matches, r_url)) {
|
||||||
|
@ -314,8 +328,7 @@ GitUrl parseGitUrl(const std::string& url) {
|
||||||
result.host = matches[3].str();
|
result.host = matches[3].str();
|
||||||
result.port = matches[4].str();
|
result.port = matches[4].str();
|
||||||
result.path = matches[5].str();
|
result.path = matches[5].str();
|
||||||
}
|
} else if (std::regex_match(url, matches, r_scp_like_url)) {
|
||||||
else if (std::regex_match(url, matches, r_scp_like_url)) {
|
|
||||||
result.protocol = "ssh";
|
result.protocol = "ssh";
|
||||||
|
|
||||||
result.user = matches[1].str();
|
result.user = matches[1].str();
|
||||||
|
@ -355,7 +368,8 @@ std::vector<AttrRule> parseGitAttrFile(const std::string& content)
|
||||||
if (git_pathspec_new(&rule.pathspec, &patterns) != 0) {
|
if (git_pathspec_new(&rule.pathspec, &patterns) != 0) {
|
||||||
auto error = git_error_last();
|
auto error = git_error_last();
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "git_pathspec_new parsing '" << line << "': " << (error ? error->message : "unknown error") << std::endl;
|
ss << "git_pathspec_new parsing '" << line << "': " << (error ? error->message : "unknown error")
|
||||||
|
<< std::endl;
|
||||||
warn(ss.str());
|
warn(ss.str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -396,7 +410,8 @@ std::vector<AttrRule> parseGitAttrFile(const std::string& content)
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fetch::init(git_repository* repo, const std::string& gitattributesContent) {
|
void Fetch::init(git_repository * repo, const std::string & gitattributesContent)
|
||||||
|
{
|
||||||
const auto remoteUrl = lfs::getLfsEndpointUrl(repo);
|
const auto remoteUrl = lfs::getLfsEndpointUrl(repo);
|
||||||
|
|
||||||
this->gitUrl = parseGitUrl(remoteUrl);
|
this->gitUrl = parseGitUrl(remoteUrl);
|
||||||
|
@ -407,15 +422,13 @@ void Fetch::init(git_repository* repo, const std::string& gitattributesContent)
|
||||||
this->ready = true;
|
this->ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Fetch::hasAttribute(const std::string & path, const std::string & attrName, const std::string & attrValue) const
|
bool Fetch::hasAttribute(const std::string & path, const std::string & attrName, const std::string & attrValue) const
|
||||||
{
|
{
|
||||||
for (auto it = rules.rbegin(); it != rules.rend(); ++it) {
|
for (auto it = rules.rbegin(); it != rules.rend(); ++it) {
|
||||||
int match = git_pathspec_matches_path(
|
int match = git_pathspec_matches_path(
|
||||||
it->pathspec,
|
it->pathspec,
|
||||||
0, // no flags
|
0, // no flags
|
||||||
path.c_str()
|
path.c_str());
|
||||||
);
|
|
||||||
|
|
||||||
if (match > 0) {
|
if (match > 0) {
|
||||||
auto attr = it->attributes.find(attrName);
|
auto attr = it->attributes.find(attrName);
|
||||||
|
@ -428,7 +441,8 @@ bool Fetch::hasAttribute(const std::string& path, const std::string& attrName, c
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json mdToPayload(const std::vector<Md> &items) {
|
nlohmann::json mdToPayload(const std::vector<Md> & items)
|
||||||
|
{
|
||||||
nlohmann::json jArray = nlohmann::json::array();
|
nlohmann::json jArray = nlohmann::json::array();
|
||||||
for (const auto & md : items) {
|
for (const auto & md : items) {
|
||||||
jArray.push_back({{"oid", md.oid}, {"size", md.size}});
|
jArray.push_back({{"oid", md.oid}, {"size", md.size}});
|
||||||
|
@ -436,8 +450,8 @@ nlohmann::json mdToPayload(const std::vector<Md> &items) {
|
||||||
return jArray;
|
return jArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Md> & metadatas) const
|
||||||
std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Md> &metadatas) const {
|
{
|
||||||
nlohmann::json oidList = mdToPayload(metadatas);
|
nlohmann::json oidList = mdToPayload(metadatas);
|
||||||
nlohmann::json data = {
|
nlohmann::json data = {
|
||||||
{"operation", "download"},
|
{"operation", "download"},
|
||||||
|
@ -461,8 +475,7 @@ std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Md> &metadatas) c
|
||||||
headers = curl_slist_append(headers, authHeader.c_str());
|
headers = curl_slist_append(headers, authHeader.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
headers =
|
headers = curl_slist_append(headers, "Content-Type: application/vnd.git-lfs+json");
|
||||||
curl_slist_append(headers, "Content-Type: application/vnd.git-lfs+json");
|
|
||||||
headers = curl_slist_append(headers, "Accept: application/vnd.git-lfs+json");
|
headers = curl_slist_append(headers, "Accept: application/vnd.git-lfs+json");
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||||
|
@ -487,8 +500,7 @@ std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Md> &metadatas) c
|
||||||
try {
|
try {
|
||||||
auto resp = nlohmann::json::parse(responseString);
|
auto resp = nlohmann::json::parse(responseString);
|
||||||
if (resp.contains("objects")) {
|
if (resp.contains("objects")) {
|
||||||
objects.insert(objects.end(), resp["objects"].begin(),
|
objects.insert(objects.end(), resp["objects"].begin(), resp["objects"].end());
|
||||||
resp["objects"].end());
|
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("response does not contain 'objects'");
|
throw std::runtime_error("response does not contain 'objects'");
|
||||||
}
|
}
|
||||||
|
@ -498,11 +510,11 @@ std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Md> &metadatas) c
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "response did not parse as json: " << responseString;
|
ss << "response did not parse as json: " << responseString;
|
||||||
throw std::runtime_error(ss.str());
|
throw std::runtime_error(ss.str());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fetch::fetch(const git_blob* pointerBlob, const std::string& pointerFilePath, Sink& sink) const {
|
void Fetch::fetch(const git_blob * pointerBlob, const std::string & pointerFilePath, Sink & sink) const
|
||||||
|
{
|
||||||
constexpr size_t chunkSize = 128 * 1024; // 128 KiB
|
constexpr size_t chunkSize = 128 * 1024; // 128 KiB
|
||||||
auto size = git_blob_rawsize(pointerBlob);
|
auto size = git_blob_rawsize(pointerBlob);
|
||||||
|
|
||||||
|
@ -510,7 +522,8 @@ void Fetch::fetch(const git_blob* pointerBlob, const std::string& pointerFilePat
|
||||||
debug("Skip git-lfs, pointer file too large");
|
debug("Skip git-lfs, pointer file too large");
|
||||||
warn("Encountered a file that should have been a pointer, but wasn't: %s", pointerFilePath);
|
warn("Encountered a file that should have been a pointer, but wasn't: %s", pointerFilePath);
|
||||||
for (size_t offset = 0; offset < size; offset += chunkSize) {
|
for (size_t offset = 0; offset < size; offset += chunkSize) {
|
||||||
sink(std::string((const char *) git_blob_rawcontent(pointerBlob) + offset, std::min(chunkSize, size - offset)));
|
sink(std::string(
|
||||||
|
(const char *) git_blob_rawcontent(pointerBlob) + offset, std::min(chunkSize, size - offset)));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -521,7 +534,8 @@ void Fetch::fetch(const git_blob* pointerBlob, const std::string& pointerFilePat
|
||||||
debug("Skip git-lfs, invalid pointer file");
|
debug("Skip git-lfs, invalid pointer file");
|
||||||
warn("Encountered a file that should have been a pointer, but wasn't: %s", pointerFilePath);
|
warn("Encountered a file that should have been a pointer, but wasn't: %s", pointerFilePath);
|
||||||
for (size_t offset = 0; offset < size; offset += chunkSize) {
|
for (size_t offset = 0; offset < size; offset += chunkSize) {
|
||||||
sink(std::string((const char *) git_blob_rawcontent(pointerBlob) + offset, std::min(chunkSize, size - offset)));
|
sink(std::string(
|
||||||
|
(const char *) git_blob_rawcontent(pointerBlob) + offset, std::min(chunkSize, size - offset)));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -535,7 +549,8 @@ void Fetch::fetch(const git_blob* pointerBlob, const std::string& pointerFilePat
|
||||||
std::string oid = obj.at("oid");
|
std::string oid = obj.at("oid");
|
||||||
std::string ourl = obj.at("actions").at("download").at("href");
|
std::string ourl = obj.at("actions").at("download").at("href");
|
||||||
std::string authHeader = "";
|
std::string authHeader = "";
|
||||||
if (obj.at("actions").at("download").contains("header") && obj.at("actions").at("download").at("header").contains("Authorization")) {
|
if (obj.at("actions").at("download").contains("header")
|
||||||
|
&& obj.at("actions").at("download").at("header").contains("Authorization")) {
|
||||||
authHeader = obj["actions"]["download"]["header"]["Authorization"];
|
authHeader = obj["actions"]["download"]["header"]["Authorization"];
|
||||||
}
|
}
|
||||||
// oid is also the sha256
|
// oid is also the sha256
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue