about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/expressions/builtins.xml11
-rw-r--r--src/libexpr/names.cc2
-rw-r--r--src/libexpr/names.hh2
-rw-r--r--src/libexpr/primops.cc21
-rw-r--r--tests/lang/eval-okay-splitversion.exp1
-rw-r--r--tests/lang/eval-okay-splitversion.nix1
6 files changed, 37 insertions, 1 deletions
diff --git a/doc/manual/expressions/builtins.xml b/doc/manual/expressions/builtins.xml
index 81770bcf6292..8a32ed8b5c99 100644
--- a/doc/manual/expressions/builtins.xml
+++ b/doc/manual/expressions/builtins.xml
@@ -126,6 +126,17 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
   </varlistentry>
 
 
+  <varlistentry><term><function>builtins.splitVersion</function>
+  <replaceable>s</replaceable></term>
+
+    <listitem><para>Split a string representing a version into its
+    components, by the same version splitting logic underlying the
+    version comparison in <link linkend="ssec-version-comparisons">
+    <command>nix-env -u</command></link>.</para></listitem>
+
+  </varlistentry>
+
+
   <varlistentry><term><function>builtins.concatLists</function>
   <replaceable>lists</replaceable></term>
 
diff --git a/src/libexpr/names.cc b/src/libexpr/names.cc
index 6d78d2116121..382088c78872 100644
--- a/src/libexpr/names.cc
+++ b/src/libexpr/names.cc
@@ -41,7 +41,7 @@ bool DrvName::matches(DrvName & n)
 }
 
 
-static string nextComponent(string::const_iterator & p,
+string nextComponent(string::const_iterator & p,
     const string::const_iterator end)
 {
     /* Skip any dots and dashes (component separators). */
diff --git a/src/libexpr/names.hh b/src/libexpr/names.hh
index 9667fc96fd0f..13c3093e77b0 100644
--- a/src/libexpr/names.hh
+++ b/src/libexpr/names.hh
@@ -24,6 +24,8 @@ private:
 
 typedef list<DrvName> DrvNames;
 
+string nextComponent(string::const_iterator & p,
+    const string::const_iterator end);
 int compareVersions(const string & v1, const string & v2);
 DrvNames drvNamesFromArgs(const Strings & opArgs);
 
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 466fd13e8698..ca97b2b28bb6 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1961,6 +1961,26 @@ static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * a
 }
 
 
+static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+    string version = state.forceStringNoCtx(*args[0], pos);
+    auto iter = version.cbegin();
+    Strings components;
+    while (iter != version.cend()) {
+        auto component = nextComponent(iter, version.cend());
+        if (component.empty())
+            break;
+        components.emplace_back(std::move(component));
+    }
+    state.mkList(v, components.size());
+    unsigned int n = 0;
+    for (auto & component : components) {
+        auto listElem = v.listElems()[n++] = state.allocValue();
+        mkString(*listElem, std::move(component));
+    }
+}
+
+
 /*************************************************************
  * Networking
  *************************************************************/
@@ -2196,6 +2216,7 @@ void EvalState::createBaseEnv()
     // Versions
     addPrimOp("__parseDrvName", 1, prim_parseDrvName);
     addPrimOp("__compareVersions", 2, prim_compareVersions);
+    addPrimOp("__splitVersion", 1, prim_splitVersion);
 
     // Derivations
     addPrimOp("derivationStrict", 1, prim_derivationStrict);
diff --git a/tests/lang/eval-okay-splitversion.exp b/tests/lang/eval-okay-splitversion.exp
new file mode 100644
index 000000000000..153ceb8186a0
--- /dev/null
+++ b/tests/lang/eval-okay-splitversion.exp
@@ -0,0 +1 @@
+[ "1" "2" "3" ]
diff --git a/tests/lang/eval-okay-splitversion.nix b/tests/lang/eval-okay-splitversion.nix
new file mode 100644
index 000000000000..9e5c99d2e7f6
--- /dev/null
+++ b/tests/lang/eval-okay-splitversion.nix
@@ -0,0 +1 @@
+builtins.splitVersion "1.2.3"