add sourcehut input scheme
This commit is contained in:
parent
94992a9196
commit
72e8f94081
2 changed files with 122 additions and 1 deletions
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
namespace nix::fetchers {
|
namespace nix::fetchers {
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ struct DownloadUrl
|
||||||
Headers headers;
|
Headers headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A github or gitlab host
|
// A github, gitlab, or sourcehut host
|
||||||
const static std::string hostRegexS = "[a-zA-Z0-9.]*"; // FIXME: check
|
const static std::string hostRegexS = "[a-zA-Z0-9.]*"; // FIXME: check
|
||||||
std::regex hostRegex(hostRegexS, std::regex::ECMAScript);
|
std::regex hostRegex(hostRegexS, std::regex::ECMAScript);
|
||||||
|
|
||||||
|
@ -348,7 +349,95 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SourceHutInputScheme : GitArchiveInputScheme
|
||||||
|
{
|
||||||
|
std::string type() override { return "sourcehut"; }
|
||||||
|
|
||||||
|
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
||||||
|
{
|
||||||
|
// SourceHut supports both PAT and OAuth2. See
|
||||||
|
// https://man.sr.ht/meta.sr.ht/oauth.md
|
||||||
|
return std::pair<std::string, std::string>("Authorization", fmt("Bearer %s", token));
|
||||||
|
// Note: This currently serves no purpose, as this kind of authorization
|
||||||
|
// does not allow for downloading tarballs on sourcehut private repos.
|
||||||
|
// Once it is implemented, however, should work as expected.
|
||||||
|
}
|
||||||
|
|
||||||
|
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
||||||
|
{
|
||||||
|
// TODO: In the future, when the sourcehut graphql API is implemented for mercurial
|
||||||
|
// and with anonymous access, this method should use it instead.
|
||||||
|
|
||||||
|
auto ref = *input.getRef();
|
||||||
|
|
||||||
|
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
||||||
|
auto base_url = fmt("https://%s/%s/%s",
|
||||||
|
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"));
|
||||||
|
|
||||||
|
Headers headers = makeHeadersWithAuthTokens(host);
|
||||||
|
|
||||||
|
std::string ref_uri;
|
||||||
|
if (ref == "HEAD") {
|
||||||
|
auto file = store->toRealPath(
|
||||||
|
downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath);
|
||||||
|
std::ifstream is(file);
|
||||||
|
std::string line;
|
||||||
|
getline(is, line);
|
||||||
|
|
||||||
|
auto ref_index = line.find("ref: ");
|
||||||
|
if (ref_index == std::string::npos) {
|
||||||
|
throw BadURL("in '%d', couldn't resolve HEAD ref '%d'", input.to_string(), ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
ref_uri = line.substr(ref_index+5, line.length()-1);
|
||||||
|
} else
|
||||||
|
ref_uri = fmt("refs/heads/%s", ref);
|
||||||
|
|
||||||
|
auto file = store->toRealPath(
|
||||||
|
downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath);
|
||||||
|
std::ifstream is(file);
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::string id;
|
||||||
|
while(getline(is, line)) {
|
||||||
|
auto index = line.find(ref_uri);
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
id = line.substr(0, index-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(id.empty())
|
||||||
|
throw BadURL("in '%d', couldn't find ref '%d'", input.to_string(), ref);
|
||||||
|
|
||||||
|
auto rev = Hash::parseAny(id, htSHA1);
|
||||||
|
debug("HEAD revision for '%s' is %s", fmt("%s/%s", base_url, ref), rev.gitRev());
|
||||||
|
return rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadUrl getDownloadUrl(const Input & input) const override
|
||||||
|
{
|
||||||
|
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
||||||
|
auto url = fmt("https://%s/%s/%s/archive/%s.tar.gz",
|
||||||
|
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
|
||||||
|
input.getRev()->to_string(Base16, false));
|
||||||
|
|
||||||
|
Headers headers = makeHeadersWithAuthTokens(host);
|
||||||
|
return DownloadUrl { url, headers };
|
||||||
|
}
|
||||||
|
|
||||||
|
void clone(const Input & input, const Path & destDir) override
|
||||||
|
{
|
||||||
|
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
||||||
|
Input::fromURL(fmt("git+https://%s/%s/%s",
|
||||||
|
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
|
||||||
|
.applyOverrides(input.getRef(), input.getRev())
|
||||||
|
.clone(destDir);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static auto rGitHubInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); });
|
static auto rGitHubInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); });
|
||||||
static auto rGitLabInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); });
|
static auto rGitLabInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); });
|
||||||
|
static auto rSourceHutInputScheme = OnStartup([] { registerInputScheme(std::make_unique<SourceHutInputScheme>()); });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,38 @@ Currently the `type` attribute can be one of the following:
|
||||||
* `github:edolstra/dwarffs/unstable`
|
* `github:edolstra/dwarffs/unstable`
|
||||||
* `github:edolstra/dwarffs/d3f2baba8f425779026c6ec04021b2e927f61e31`
|
* `github:edolstra/dwarffs/d3f2baba8f425779026c6ec04021b2e927f61e31`
|
||||||
|
|
||||||
|
* `sourcehut`: Similar to `github`, is a more efficient way to fetch
|
||||||
|
SourceHut repositories. The following attributes are required:
|
||||||
|
|
||||||
|
* `owner`: The owner of the repository (including leading `~`).
|
||||||
|
|
||||||
|
* `repo`: The name of the repository.
|
||||||
|
|
||||||
|
Like `github`, these are downloaded as tarball archives.
|
||||||
|
|
||||||
|
The URL syntax for `sourcehut` flakes is:
|
||||||
|
|
||||||
|
`sourcehut:<owner>/<repo>(/<rev-or-ref>)?(\?<params>)?`
|
||||||
|
|
||||||
|
`<rev-or-ref>` works the same as `github`. Either a branch or tag name
|
||||||
|
(`ref`), or a commit hash (`rev`) can be specified.
|
||||||
|
|
||||||
|
Since SourceHut allows for self-hosting, you can specify `host` as
|
||||||
|
a parameter, to point to any instances other than `git.sr.ht`.
|
||||||
|
|
||||||
|
Currently, `ref` name resolution only works for Git repositories.
|
||||||
|
You can refer to Mercurial repositories by simply changing `host` to
|
||||||
|
`hg.sr.ht` (or any other Mercurial instance). With the caveat
|
||||||
|
that you must explicitly specify a commit hash (`rev`).
|
||||||
|
|
||||||
|
Some examples:
|
||||||
|
|
||||||
|
* `sourcehut:~misterio/nix-colors`
|
||||||
|
* `sourcehut:~misterio/nix-colors/main`
|
||||||
|
* `sourcehut:~misterio/nix-colors?host=git.example.org`
|
||||||
|
* `sourcehut:~misterio/nix-colors/182b4b8709b8ffe4e9774a4c5d6877bf6bb9a21c`
|
||||||
|
* `sourcehut:~misterio/nix-colors/21c1a380a6915d890d408e9f22203436a35bb2de?host=hg.sr.ht`
|
||||||
|
|
||||||
* `indirect`: Indirections through the flake registry. These have the
|
* `indirect`: Indirections through the flake registry. These have the
|
||||||
form
|
form
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue