1
0
Fork 0
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:
Leandro Reina 2025-01-21 14:40:27 +01:00
parent 40a3007b7c
commit 23c5219f81

View file

@ -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());
} }
} }