mirror of
https://github.com/NixOS/nix
synced 2025-06-25 19:01:16 +02:00
(Part of the) code review
This commit is contained in:
parent
40a3007b7c
commit
23c5219f81
1 changed files with 29 additions and 28 deletions
|
@ -14,10 +14,12 @@ namespace fs = std::filesystem;
|
||||||
namespace nix {
|
namespace nix {
|
||||||
namespace lfs {
|
namespace lfs {
|
||||||
|
|
||||||
// git-lfs metadata about a file
|
/**
|
||||||
struct Md
|
* git-lfs pointer
|
||||||
|
* @see https://github.com/git-lfs/git-lfs/blob/2ef4108/docs/spec.md
|
||||||
|
*/
|
||||||
|
struct Pointer
|
||||||
{
|
{
|
||||||
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
|
||||||
|
@ -41,7 +43,7 @@ struct Fetch
|
||||||
const std::string & pointerFilePath,
|
const std::string & pointerFilePath,
|
||||||
StringSink & sink,
|
StringSink & sink,
|
||||||
std::function<void(uint64_t)> sizeCallback) const;
|
std::function<void(uint64_t)> sizeCallback) const;
|
||||||
std::vector<nlohmann::json> fetchUrls(const std::vector<Md> & metadatas) const;
|
std::vector<nlohmann::json> fetchUrls(const std::vector<Pointer> & pointers) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// if authHeader is "", downloadToSink assumes no auth is expected
|
// if authHeader is "", downloadToSink assumes no auth is expected
|
||||||
|
@ -79,15 +81,15 @@ std::string getLfsApiToken(const ParsedURL & url)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (output.empty())
|
if (output.empty())
|
||||||
throw std::runtime_error(
|
throw Error(
|
||||||
"git-lfs-authenticate: no output (cmd: ssh " + *url.authority + " git-lfs-authenticate " + url.path
|
"git-lfs-authenticate: no output (cmd: ssh " + *url.authority + " git-lfs-authenticate " + url.path
|
||||||
+ " download)");
|
+ " 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"))
|
||||||
throw std::runtime_error("no header in git-lfs-authenticate response");
|
throw Error("no header in git-lfs-authenticate response");
|
||||||
if (!query_resp["header"].contains("Authorization"))
|
if (!query_resp["header"].contains("Authorization"))
|
||||||
throw std::runtime_error("no Authorization in git-lfs-authenticate response");
|
throw Error("no Authorization in git-lfs-authenticate response");
|
||||||
|
|
||||||
std::string res = query_resp["header"]["Authorization"].get<std::string>();
|
std::string res = query_resp["header"]["Authorization"].get<std::string>();
|
||||||
|
|
||||||
|
@ -122,7 +124,7 @@ std::string getLfsEndpointUrl(git_repository * repo)
|
||||||
return std::string(url_c_str);
|
return std::string(url_c_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Md> parseLfsMetadata(const std::string & content, const std::string & filename)
|
std::optional<Pointer> parseLfsPointer(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
|
||||||
//
|
//
|
||||||
|
@ -175,7 +177,7 @@ std::optional<Md> parseLfsMetadata(const std::string & content, const std::strin
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_optional(Md{filename, oid, std::stoul(size)});
|
return std::make_optional(Pointer{oid, std::stoul(size)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Fetch::Fetch(git_repository * repo, git_oid rev)
|
Fetch::Fetch(git_repository * repo, git_oid rev)
|
||||||
|
@ -200,15 +202,15 @@ bool Fetch::shouldFetch(const std::string & path) const
|
||||||
return attr != nullptr && !std::string(attr).compare("lfs");
|
return attr != nullptr && !std::string(attr).compare("lfs");
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json mdToPayload(const std::vector<Md> & items)
|
nlohmann::json pointerToPayload(const std::vector<Pointer> & items)
|
||||||
{
|
{
|
||||||
nlohmann::json jArray = nlohmann::json::array();
|
nlohmann::json jArray = nlohmann::json::array();
|
||||||
for (const auto & md : items)
|
for (const auto & pointer : items)
|
||||||
jArray.push_back({{"oid", md.oid}, {"size", md.size}});
|
jArray.push_back({{"oid", pointer.oid}, {"size", pointer.size}});
|
||||||
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<Pointer> & pointers) const
|
||||||
{
|
{
|
||||||
ParsedURL httpUrl(url);
|
ParsedURL httpUrl(url);
|
||||||
httpUrl.scheme = url.scheme == "ssh" ? "https" : url.scheme;
|
httpUrl.scheme = url.scheme == "ssh" ? "https" : url.scheme;
|
||||||
|
@ -220,7 +222,7 @@ std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Md> & metadatas)
|
||||||
headers.push_back({"Content-Type", "application/vnd.git-lfs+json"});
|
headers.push_back({"Content-Type", "application/vnd.git-lfs+json"});
|
||||||
headers.push_back({"Accept", "application/vnd.git-lfs+json"});
|
headers.push_back({"Accept", "application/vnd.git-lfs+json"});
|
||||||
request.headers = headers;
|
request.headers = headers;
|
||||||
nlohmann::json oidList = mdToPayload(metadatas);
|
nlohmann::json oidList = pointerToPayload(pointers);
|
||||||
nlohmann::json data = {{"operation", "download"}};
|
nlohmann::json data = {{"operation", "download"}};
|
||||||
data["objects"] = oidList;
|
data["objects"] = oidList;
|
||||||
request.data = data.dump();
|
request.data = data.dump();
|
||||||
|
@ -238,13 +240,12 @@ std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Md> & metadatas)
|
||||||
if (resp.contains("objects"))
|
if (resp.contains("objects"))
|
||||||
objects.insert(objects.end(), resp["objects"].begin(), resp["objects"].end());
|
objects.insert(objects.end(), resp["objects"].begin(), resp["objects"].end());
|
||||||
else
|
else
|
||||||
throw std::runtime_error("response does not contain 'objects'");
|
throw Error("response does not contain 'objects'");
|
||||||
|
|
||||||
return objects;
|
return objects;
|
||||||
} catch (const nlohmann::json::parse_error & e) {
|
} catch (const nlohmann::json::parse_error & e) {
|
||||||
std::stringstream ss;
|
printMsg(lvlTalkative, "Full response: '%1%'", responseString);
|
||||||
ss << "response did not parse as json: " << responseString;
|
throw Error("response did not parse as json: %s", e.what());
|
||||||
throw std::runtime_error(ss.str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,8 +265,8 @@ void Fetch::fetch(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto md = parseLfsMetadata(std::string(content), std::string(pointerFilePath));
|
const auto pointer = parseLfsPointer(std::string(content), std::string(pointerFilePath));
|
||||||
if (md == std::nullopt) {
|
if (pointer == std::nullopt) {
|
||||||
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);
|
||||||
sizeCallback(content.length());
|
sizeCallback(content.length());
|
||||||
|
@ -275,7 +276,7 @@ void Fetch::fetch(
|
||||||
|
|
||||||
Path cacheDir = getCacheDir() + "/git-lfs";
|
Path cacheDir = getCacheDir() + "/git-lfs";
|
||||||
std::string key =
|
std::string key =
|
||||||
hashString(HashAlgorithm::SHA256, pointerFilePath).to_string(HashFormat::Base16, false) + "/" + md->oid;
|
hashString(HashAlgorithm::SHA256, pointerFilePath).to_string(HashFormat::Base16, false) + "/" + pointer->oid;
|
||||||
Path cachePath = cacheDir + "/" + key;
|
Path cachePath = cacheDir + "/" + key;
|
||||||
if (pathExists(cachePath)) {
|
if (pathExists(cachePath)) {
|
||||||
debug("using cache entry %s -> %s", key, cachePath);
|
debug("using cache entry %s -> %s", key, cachePath);
|
||||||
|
@ -292,9 +293,9 @@ void Fetch::fetch(
|
||||||
}
|
}
|
||||||
debug("did not find cache entry for %s", key);
|
debug("did not find cache entry for %s", key);
|
||||||
|
|
||||||
std::vector<Md> vMds;
|
std::vector<Pointer> pointers;
|
||||||
vMds.push_back(md.value());
|
pointers.push_back(pointer.value());
|
||||||
const auto objUrls = fetchUrls(vMds);
|
const auto objUrls = fetchUrls(pointers);
|
||||||
|
|
||||||
const auto obj = objUrls[0];
|
const auto obj = objUrls[0];
|
||||||
try {
|
try {
|
||||||
|
@ -320,7 +321,7 @@ void Fetch::fetch(
|
||||||
} catch (const nlohmann::json::out_of_range & e) {
|
} catch (const nlohmann::json::out_of_range & e) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "bad json from /info/lfs/objects/batch: " << obj << " " << e.what();
|
ss << "bad json from /info/lfs/objects/batch: " << obj << " " << e.what();
|
||||||
throw std::runtime_error(ss.str());
|
throw Error(ss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue