aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/experimental-features.cc10
-rw-r--r--src/libutil/experimental-features.hh4
-rw-r--r--src/libutil/git.cc25
-rw-r--r--src/libutil/git.hh40
-rw-r--r--src/libutil/json-utils.hh21
-rw-r--r--src/libutil/tests/git.cc33
-rw-r--r--src/libutil/tests/tests.cc20
-rw-r--r--src/libutil/util.cc1
-rw-r--r--src/libutil/util.hh24
9 files changed, 167 insertions, 11 deletions
diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc
index df37edf57..315de64a4 100644
--- a/src/libutil/experimental-features.cc
+++ b/src/libutil/experimental-features.cc
@@ -35,7 +35,9 @@ const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::str
std::string_view showExperimentalFeature(const ExperimentalFeature feature)
{
- return stringifiedXpFeatures.at(feature);
+ const auto ret = get(stringifiedXpFeatures, feature);
+ assert(ret);
+ return *ret;
}
std::set<ExperimentalFeature> parseFeatures(const std::set<std::string> & rawFeatures)
@@ -58,11 +60,13 @@ std::ostream & operator <<(std::ostream & str, const ExperimentalFeature & featu
return str << showExperimentalFeature(feature);
}
-void to_json(nlohmann::json& j, const ExperimentalFeature& feature) {
+void to_json(nlohmann::json & j, const ExperimentalFeature & feature)
+{
j = showExperimentalFeature(feature);
}
-void from_json(const nlohmann::json& j, ExperimentalFeature& feature) {
+void from_json(const nlohmann::json & j, ExperimentalFeature & feature)
+{
const std::string input = j;
const auto parsed = parseExperimentalFeature(input);
diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh
index a6d080094..57512830c 100644
--- a/src/libutil/experimental-features.hh
+++ b/src/libutil/experimental-features.hh
@@ -55,7 +55,7 @@ public:
* Semi-magic conversion to and from json.
* See the nlohmann/json readme for more details.
*/
-void to_json(nlohmann::json&, const ExperimentalFeature&);
-void from_json(const nlohmann::json&, ExperimentalFeature&);
+void to_json(nlohmann::json &, const ExperimentalFeature &);
+void from_json(const nlohmann::json &, ExperimentalFeature &);
}
diff --git a/src/libutil/git.cc b/src/libutil/git.cc
new file mode 100644
index 000000000..f35c2fdb7
--- /dev/null
+++ b/src/libutil/git.cc
@@ -0,0 +1,25 @@
+#include "git.hh"
+
+#include <regex>
+
+namespace nix {
+namespace git {
+
+std::optional<LsRemoteRefLine> parseLsRemoteLine(std::string_view line)
+{
+ const static std::regex line_regex("^(ref: *)?([^\\s]+)(?:\\t+(.*))?$");
+ std::match_results<std::string_view::const_iterator> match;
+ if (!std::regex_match(line.cbegin(), line.cend(), match, line_regex))
+ return std::nullopt;
+
+ return LsRemoteRefLine {
+ .kind = match[1].length() == 0
+ ? LsRemoteRefLine::Kind::Object
+ : LsRemoteRefLine::Kind::Symbolic,
+ .target = match[2],
+ .reference = match[3].length() == 0 ? std::nullopt : std::optional<std::string>{ match[3] }
+ };
+}
+
+}
+}
diff --git a/src/libutil/git.hh b/src/libutil/git.hh
new file mode 100644
index 000000000..cb13ef0e5
--- /dev/null
+++ b/src/libutil/git.hh
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <optional>
+
+namespace nix {
+
+namespace git {
+
+// A line from the output of `git ls-remote --symref`.
+//
+// These can be of two kinds:
+//
+// - Symbolic references of the form
+//
+// ref: {target} {reference}
+//
+// where {target} is itself a reference and {reference} is optional
+//
+// - Object references of the form
+//
+// {target} {reference}
+//
+// where {target} is a commit id and {reference} is mandatory
+struct LsRemoteRefLine {
+ enum struct Kind {
+ Symbolic,
+ Object
+ };
+ Kind kind;
+ std::string target;
+ std::optional<std::string> reference;
+};
+
+std::optional<LsRemoteRefLine> parseLsRemoteLine(std::string_view line);
+
+}
+
+}
diff --git a/src/libutil/json-utils.hh b/src/libutil/json-utils.hh
new file mode 100644
index 000000000..b8a031227
--- /dev/null
+++ b/src/libutil/json-utils.hh
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+
+namespace nix {
+
+const nlohmann::json * get(const nlohmann::json & map, const std::string & key)
+{
+ auto i = map.find(key);
+ if (i == map.end()) return nullptr;
+ return &*i;
+}
+
+nlohmann::json * get(nlohmann::json & map, const std::string & key)
+{
+ auto i = map.find(key);
+ if (i == map.end()) return nullptr;
+ return &*i;
+}
+
+}
diff --git a/src/libutil/tests/git.cc b/src/libutil/tests/git.cc
new file mode 100644
index 000000000..5b5715fc2
--- /dev/null
+++ b/src/libutil/tests/git.cc
@@ -0,0 +1,33 @@
+#include "git.hh"
+#include <gtest/gtest.h>
+
+namespace nix {
+
+ TEST(GitLsRemote, parseSymrefLineWithReference) {
+ auto line = "ref: refs/head/main HEAD";
+ auto res = git::parseLsRemoteLine(line);
+ ASSERT_TRUE(res.has_value());
+ ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic);
+ ASSERT_EQ(res->target, "refs/head/main");
+ ASSERT_EQ(res->reference, "HEAD");
+ }
+
+ TEST(GitLsRemote, parseSymrefLineWithNoReference) {
+ auto line = "ref: refs/head/main";
+ auto res = git::parseLsRemoteLine(line);
+ ASSERT_TRUE(res.has_value());
+ ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic);
+ ASSERT_EQ(res->target, "refs/head/main");
+ ASSERT_EQ(res->reference, std::nullopt);
+ }
+
+ TEST(GitLsRemote, parseObjectRefLine) {
+ auto line = "abc123 refs/head/main";
+ auto res = git::parseLsRemoteLine(line);
+ ASSERT_TRUE(res.has_value());
+ ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Object);
+ ASSERT_EQ(res->target, "abc123");
+ ASSERT_EQ(res->reference, "refs/head/main");
+ }
+}
+
diff --git a/src/libutil/tests/tests.cc b/src/libutil/tests/tests.cc
index 92972ed14..6e325db98 100644
--- a/src/libutil/tests/tests.cc
+++ b/src/libutil/tests/tests.cc
@@ -548,7 +548,7 @@ namespace nix {
TEST(get, emptyContainer) {
StringMap s = { };
- auto expected = std::nullopt;
+ auto expected = nullptr;
ASSERT_EQ(get(s, "one"), expected);
}
@@ -559,7 +559,23 @@ namespace nix {
s["two"] = "er";
auto expected = "yi";
- ASSERT_EQ(get(s, "one"), expected);
+ ASSERT_EQ(*get(s, "one"), expected);
+ }
+
+ TEST(getOr, emptyContainer) {
+ StringMap s = { };
+ auto expected = "yi";
+
+ ASSERT_EQ(getOr(s, "one", "yi"), expected);
+ }
+
+ TEST(getOr, getFromContainer) {
+ StringMap s;
+ s["one"] = "yi";
+ s["two"] = "er";
+ auto expected = "yi";
+
+ ASSERT_EQ(getOr(s, "one", "nope"), expected);
}
/* ----------------------------------------------------------------------------
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index b49c1e466..d4d78329d 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -1588,7 +1588,6 @@ std::string stripIndentation(std::string_view s)
//////////////////////////////////////////////////////////////////////
-
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index a1d0e0e6b..09ccfa591 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -543,13 +543,31 @@ std::string stripIndentation(std::string_view s);
/* Get a value for the specified key from an associate container. */
template <class T>
-std::optional<typename T::mapped_type> get(const T & map, const typename T::key_type & key)
+const typename T::mapped_type * get(const T & map, const typename T::key_type & key)
{
auto i = map.find(key);
- if (i == map.end()) return {};
- return std::optional<typename T::mapped_type>(i->second);
+ if (i == map.end()) return nullptr;
+ return &i->second;
}
+template <class T>
+typename T::mapped_type * get(T & map, const typename T::key_type & key)
+{
+ auto i = map.find(key);
+ if (i == map.end()) return nullptr;
+ return &i->second;
+}
+
+/* Get a value for the specified key from an associate container, or a default value if the key isn't present. */
+template <class T>
+const typename T::mapped_type & getOr(T & map,
+ const typename T::key_type & key,
+ const typename T::mapped_type & defaultValue)
+{
+ auto i = map.find(key);
+ if (i == map.end()) return defaultValue;
+ return i->second;
+}
/* Remove and return the first item from a container. */
template <class T>