diff options
Diffstat (limited to 'src/libutil/url-name.cc')
-rw-r--r-- | src/libutil/url-name.cc | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/libutil/url-name.cc b/src/libutil/url-name.cc new file mode 100644 index 000000000..6ef58c80a --- /dev/null +++ b/src/libutil/url-name.cc @@ -0,0 +1,59 @@ +#include <iostream> +#include <regex> + +#include "url-name.hh" + +namespace nix { + +static std::string const attributeNamePattern("[a-z0-9_-]+"); +static std::regex const lastAttributeRegex("(?:" + attributeNamePattern + "\\.)*(?!default)(" + attributeNamePattern +")(\\^.*)?"); +static std::string const pathSegmentPattern("[a-zA-Z0-9_-]+"); +static std::regex const lastPathSegmentRegex(".*/(" + pathSegmentPattern +")"); +static std::regex const secondPathSegmentRegex("(?:" + pathSegmentPattern + ")/(" + pathSegmentPattern +")(?:/.*)?"); +static std::regex const gitProviderRegex("github|gitlab|sourcehut"); +static std::regex const gitSchemeRegex("git($|\\+.*)"); +static std::regex const defaultOutputRegex(".*\\.default($|\\^.*)"); + +std::optional<std::string> getNameFromURL(ParsedURL const & url) +{ + std::smatch match; + + /* If there is a dir= argument, use its value */ + if (url.query.count("dir") > 0) { + return url.query.at("dir"); + } + + /* If the fragment isn't a "default" and contains two attribute elements, use the last one */ + if (std::regex_match(url.fragment, match, lastAttributeRegex)) { + return match.str(1); + } + + /* If this is a github/gitlab/sourcehut flake, use the repo name */ + if ( + std::regex_match(url.scheme, gitProviderRegex) + && std::regex_match(url.path, match, secondPathSegmentRegex) + ) { + return match.str(1); + } + + /* If it is a regular git flake, use the directory name */ + if ( + std::regex_match(url.scheme, gitSchemeRegex) + && std::regex_match(url.path, match, lastPathSegmentRegex) + ) { + return match.str(1); + } + + /* If everything failed but there is a non-default fragment, use it in full */ + if (!url.fragment.empty() && !std::regex_match(url.fragment, defaultOutputRegex)) + return url.fragment; + + /* If there is no fragment, take the last element of the path */ + if (std::regex_match(url.path, match, lastPathSegmentRegex)) + return match.str(1); + + /* If even that didn't work, the URL does not contain enough info to determine a useful name */ + return {}; +} + +} |