Split the parseFlakeRefWithFragment function

Was starting to be very complex and hard to follow.
Now the different cases should be easier to understand.
This commit is contained in:
Théophane Hufschmitt 2023-04-20 06:51:47 +02:00
parent 50e61f579c
commit e8113747e1

View file

@ -69,36 +69,27 @@ std::optional<FlakeRef> maybeParseFlakeRef(
} }
} }
std::pair<FlakeRef, std::string> parseFlakeRefWithFragment( std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
const std::string & url, const std::string & url,
const std::optional<Path> & baseDir, const std::optional<Path> & baseDir,
bool allowMissing, bool allowMissing,
bool isFlake) bool isFlake)
{ {
using namespace fetchers;
static std::regex flakeRegex(
"((" + flakeIdRegexS + ")(?:/(?:" + refAndOrRevRegex + "))?)"
+ "(?:#(" + queryRegex + "))?",
std::regex::ECMAScript);
std::smatch match;
auto parsePathFlakeRef = [&]() {
std::string path = url; std::string path = url;
std::string fragment = ""; std::string fragment = "";
std::map<std::string, std::string> query = {}; std::map<std::string, std::string> query;
auto pathEnd = url.find_first_of("#?"); auto pathEnd = url.find_first_of("#?");
auto fragmentStart = pathEnd; auto fragmentStart = pathEnd;
if (pathEnd != std::string::npos && url[pathEnd] == '?') if (pathEnd != std::string::npos && url[pathEnd] == '?') {
fragmentStart = url.find("#"); fragmentStart = url.find("#");
}
if (pathEnd != std::string::npos) { if (pathEnd != std::string::npos) {
path = url.substr(0, pathEnd); path = url.substr(0, pathEnd);
} }
if (fragmentStart != std::string::npos) { if (fragmentStart != std::string::npos) {
fragment = percentDecode(url.substr(fragmentStart+1)); fragment = percentDecode(url.substr(fragmentStart+1));
} }
if (fragmentStart != std::string::npos && pathEnd != std::string::npos) { if (pathEnd != std::string::npos && fragmentStart != std::string::npos) {
query = decodeQuery(url.substr(pathEnd+1, fragmentStart)); query = decodeQuery(url.substr(pathEnd+1, fragmentStart));
} }
@ -165,7 +156,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
parsedURL.query.insert_or_assign("shallow", "1"); parsedURL.query.insert_or_assign("shallow", "1");
return std::make_pair( return std::make_pair(
FlakeRef(Input::fromURL(parsedURL, isFlake), getOr(parsedURL.query, "dir", "")), FlakeRef(fetchers::Input::fromURL(parsedURL), getOr(parsedURL.query, "dir", "")),
fragment); fragment);
} }
@ -184,11 +175,23 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
attrs.insert_or_assign("type", "path"); attrs.insert_or_assign("type", "path");
attrs.insert_or_assign("path", path); attrs.insert_or_assign("path", path);
return std::make_pair(FlakeRef(Input::fromAttrs(std::move(attrs)), ""), fragment); return std::make_pair(FlakeRef(fetchers::Input::fromAttrs(std::move(attrs)), ""), fragment);
}; };
/* Check if 'url' is a flake ID. This is an abbreviated syntax for
/* Check if 'url' is a flake ID. This is an abbreviated syntax for
'flake:<flake-id>?ref=<ref>&rev=<rev>'. */ 'flake:<flake-id>?ref=<ref>&rev=<rev>'. */
std::optional<std::pair<FlakeRef, std::string>> parseFlakeIdRef(
const std::string & url,
bool isFlake
)
{
std::smatch match;
static std::regex flakeRegex(
"((" + flakeIdRegexS + ")(?:/(?:" + refAndOrRevRegex + "))?)"
+ "(?:#(" + queryRegex + "))?",
std::regex::ECMAScript);
if (std::regex_match(url, match, flakeRegex)) { if (std::regex_match(url, match, flakeRegex)) {
auto parsedURL = ParsedURL{ auto parsedURL = ParsedURL{
@ -200,25 +203,53 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
}; };
return std::make_pair( return std::make_pair(
FlakeRef(Input::fromURL(parsedURL), ""), FlakeRef(fetchers::Input::fromURL(parsedURL, isFlake), ""),
percentDecode(match.str(6))); percentDecode(match.str(6)));
} }
else { return {};
}
std::optional<std::pair<FlakeRef, std::string>> parseURLFlakeRef(
const std::string & url,
const std::optional<Path> & baseDir,
bool isFlake
)
{
ParsedURL parsedURL;
try { try {
auto parsedURL = parseURL(url); parsedURL = parseURL(url);
} catch (BadURL &) {
return std::nullopt;
}
std::string fragment; std::string fragment;
std::swap(fragment, parsedURL.fragment); std::swap(fragment, parsedURL.fragment);
auto input = Input::fromURL(parsedURL, isFlake); auto input = fetchers::Input::fromURL(parsedURL, isFlake);
input.parent = baseDir; input.parent = baseDir;
return std::make_pair( return std::make_pair(
FlakeRef(std::move(input), getOr(parsedURL.query, "dir", "")), FlakeRef(std::move(input), getOr(parsedURL.query, "dir", "")),
fragment); fragment);
} catch (BadURL &) { }
return parsePathFlakeRef();
} std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
const std::string & url,
const std::optional<Path> & baseDir,
bool allowMissing,
bool isFlake)
{
using namespace fetchers;
std::smatch match;
if (auto res = parseFlakeIdRef(url, isFlake)) {
return *res;
} else if (auto res = parseURLFlakeRef(url, baseDir, isFlake)) {
return *res;
} else {
return parsePathFlakeRefWithFragment(url, baseDir, allowMissing, isFlake);
} }
} }