about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lib/strings.nix20
-rw-r--r--pkgs/stdenv/generic/make-derivation.nix15
2 files changed, 33 insertions, 2 deletions
diff --git a/lib/strings.nix b/lib/strings.nix
index 4d7fa1e774d5..48420a367815 100644
--- a/lib/strings.nix
+++ b/lib/strings.nix
@@ -236,6 +236,26 @@ rec {
     in lenContent >= lenSuffix &&
        substring (lenContent - lenSuffix) lenContent content == suffix;
 
+  /* Determine whether a string contains the given infix
+
+    Type: hasInfix :: string -> string -> bool
+
+    Example:
+      hasInfix "bc" "abcd"
+      => true
+      hasInfix "ab" "abcd"
+      => true
+      hasInfix "cd" "abcd"
+      => true
+      hasInfix "foo" "abcd"
+      => false
+  */
+  hasInfix = infix: content:
+    let
+      drop = x: substring 1 (stringLength x) x;
+    in hasPrefix infix content
+      || content != "" && hasInfix infix (drop content);
+
   /* Convert a string to a list of characters (i.e. singleton strings).
      This allows you to, e.g., map a function over each character.  However,
      note that this will likely be horribly inefficient; Nix is not a
diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix
index 08a914787c35..5b1fd4b8d158 100644
--- a/pkgs/stdenv/generic/make-derivation.nix
+++ b/pkgs/stdenv/generic/make-derivation.nix
@@ -65,6 +65,8 @@ rec {
     , pos ? # position used in error messages and for meta.position
         (if attrs.meta.description or null != null
           then builtins.unsafeGetAttrPos "description" attrs.meta
+          else if attrs.version or null != null
+          then builtins.unsafeGetAttrPos "version" attrs
           else builtins.unsafeGetAttrPos "name" attrs)
     , separateDebugInfo ? false
     , outputs ? [ "out" ]
@@ -79,6 +81,15 @@ rec {
     , ... } @ attrs:
 
     let
+      # Check that the name is consistent with pname and version:
+      selfConsistent = (with attrs; attrs ? "name" ->
+        (lib.assertMsg (attrs ? "version" -> lib.strings.hasInfix version name)
+          "version ${version} does not appear in name ${name}" &&
+        lib.assertMsg (attrs ? "pname" -> lib.strings.hasInfix pname name)
+          "pname ${pname} does not appear in name ${name}"));
+
+      computedName = if name != "" then name else "${attrs.pname}-${attrs.version}";
+
       # TODO(@oxij, @Ericson2314): This is here to keep the old semantics, remove when
       # no package has `doCheck = true`.
       doCheck' = doCheck && stdenv.hostPlatform == stdenv.buildPlatform;
@@ -175,7 +186,7 @@ rec {
         // {
           # A hack to make `nix-env -qa` and `nix search` ignore broken packages.
           # TODO(@oxij): remove this assert when something like NixOS/nix#1771 gets merged into nix.
-          name = assert validity.handled && (separateDebugInfo -> stdenv.hostPlatform.isLinux); name + lib.optionalString
+          name = assert selfConsistent && validity.handled && (separateDebugInfo -> stdenv.hostPlatform.isLinux); computedName + lib.optionalString
             # Fixed-output derivations like source tarballs shouldn't get a host
             # suffix. But we have some weird ones with run-time deps that are
             # just used for their side-affects. Those might as well since the
@@ -287,7 +298,7 @@ rec {
       meta = {
           # `name` above includes cross-compilation cruft (and is under assert),
           # lets have a clean always accessible version here.
-          inherit name;
+          name = computedName;
 
           # If the packager hasn't specified `outputsToInstall`, choose a default,
           # which is the name of `p.bin or p.out or p`;