about summary refs log tree commit diff
path: root/nixpkgs/pkgs/build-support/emacs/wrapper.nix
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2019-01-07 02:18:36 +0000
committerAlyssa Ross <hi@alyssa.is>2019-01-07 02:18:47 +0000
commit36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2 (patch)
treeb3faaf573407b32aa645237a4d16b82778a39a92 /nixpkgs/pkgs/build-support/emacs/wrapper.nix
parent4e31070265257dc67d120c27e0f75c2344fdfa9a (diff)
parentabf060725d7614bd3b9f96764262dfbc2f9c2199 (diff)
downloadnixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.gz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.bz2
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.lz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.xz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.zst
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.zip
Add 'nixpkgs/' from commit 'abf060725d7614bd3b9f96764262dfbc2f9c2199'
git-subtree-dir: nixpkgs
git-subtree-mainline: 4e31070265257dc67d120c27e0f75c2344fdfa9a
git-subtree-split: abf060725d7614bd3b9f96764262dfbc2f9c2199
Diffstat (limited to 'nixpkgs/pkgs/build-support/emacs/wrapper.nix')
-rw-r--r--nixpkgs/pkgs/build-support/emacs/wrapper.nix173
1 files changed, 173 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/build-support/emacs/wrapper.nix b/nixpkgs/pkgs/build-support/emacs/wrapper.nix
new file mode 100644
index 000000000000..e161daffbd37
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/emacs/wrapper.nix
@@ -0,0 +1,173 @@
+/*
+
+# Usage
+
+`emacsWithPackages` takes a single argument: a function from a package
+set to a list of packages (the packages that will be available in
+Emacs). For example,
+```
+emacsWithPackages (epkgs: [ epkgs.evil epkgs.magit ])
+```
+All the packages in the list should come from the provided package
+set. It is possible to add any package to the list, but the provided
+set is guaranteed to have consistent dependencies and be built with
+the correct version of Emacs.
+
+# Overriding
+
+`emacsWithPackages` inherits the package set which contains it, so the
+correct way to override the provided package set is to override the
+set which contains `emacsWithPackages`. For example, to override
+`emacsPackagesNg.emacsWithPackages`,
+```
+let customEmacsPackages =
+      emacsPackagesNg.overrideScope' (self: super: {
+        # use a custom version of emacs
+        emacs = ...;
+        # use the unstable MELPA version of magit
+        magit = self.melpaPackages.magit;
+      });
+in customEmacsPackages.emacsWithPackages (epkgs: [ epkgs.evil epkgs.magit ])
+```
+
+*/
+
+{ lib, lndir, makeWrapper, runCommand, stdenv }: self:
+
+with lib; let inherit (self) emacs; in
+
+packagesFun: # packages explicitly requested by the user
+
+let
+  explicitRequires =
+    if lib.isFunction packagesFun
+      then packagesFun self
+    else packagesFun;
+in
+
+stdenv.mkDerivation {
+  name = (appendToName "with-packages" emacs).name;
+  nativeBuildInputs = [ emacs lndir makeWrapper ];
+  inherit emacs explicitRequires;
+
+  # Store all paths we want to add to emacs here, so that we only need to add
+  # one path to the load lists
+  deps = runCommand "emacs-packages-deps"
+   { inherit explicitRequires lndir emacs; }
+   ''
+     findInputsOld() {
+         local pkg="$1"; shift
+         local var="$1"; shift
+         local propagatedBuildInputsFiles=("$@")
+
+         # TODO(@Ericson2314): Restore using associative array once Darwin
+         # nix-shell doesn't use impure bash. This should replace the O(n)
+         # case with an O(1) hash map lookup, assuming bash is implemented
+         # well :D.
+         local varSlice="$var[*]"
+         # ''${..-} to hack around old bash empty array problem
+         case "''${!varSlice-}" in
+             *" $pkg "*) return 0 ;;
+         esac
+         unset -v varSlice
+
+         eval "$var"'+=("$pkg")'
+
+         if ! [ -e "$pkg" ]; then
+             echo "build input $pkg does not exist" >&2
+             exit 1
+         fi
+
+         local file
+         for file in "''${propagatedBuildInputsFiles[@]}"; do
+             file="$pkg/nix-support/$file"
+             [[ -f "$file" ]] || continue
+
+             local pkgNext
+             for pkgNext in $(< "$file"); do
+                 findInputsOld "$pkgNext" "$var" "''${propagatedBuildInputsFiles[@]}"
+             done
+         done
+     }
+     mkdir -p $out/bin
+     mkdir -p $out/share/emacs/site-lisp
+
+     local requires
+     for pkg in $explicitRequires; do
+       findInputsOld $pkg requires propagated-user-env-packages
+     done
+     # requires now holds all requested packages and their transitive dependencies
+
+     linkPath() {
+       local pkg=$1
+       local origin_path=$2
+       local dest_path=$3
+
+       # Add the path to the search path list, but only if it exists
+       if [[ -d "$pkg/$origin_path" ]]; then
+         $lndir/bin/lndir -silent "$pkg/$origin_path" "$out/$dest_path"
+       fi
+     }
+
+     linkEmacsPackage() {
+       linkPath "$1" "bin" "bin"
+       linkPath "$1" "share/emacs/site-lisp" "share/emacs/site-lisp"
+     }
+
+     # Iterate over the array of inputs (avoiding nix's own interpolation)
+     for pkg in "''${requires[@]}"; do
+       linkEmacsPackage $pkg
+     done
+
+     siteStart="$out/share/emacs/site-lisp/site-start.el"
+     siteStartByteCompiled="$siteStart"c
+
+     # A dependency may have brought the original siteStart, delete it and
+     # create our own
+     # Begin the new site-start.el by loading the original, which sets some
+     # NixOS-specific paths. Paths are searched in the reverse of the order
+     # they are specified in, so user and system profile paths are searched last.
+     rm -f $siteStart $siteStartByteCompiled
+     cat >"$siteStart" <<EOF
+(load-file "$emacs/share/emacs/site-lisp/site-start.el")
+(add-to-list 'load-path "$out/share/emacs/site-lisp")
+(add-to-list 'exec-path "$out/bin")
+EOF
+
+     # Byte-compiling improves start-up time only slightly, but costs nothing.
+     $emacs/bin/emacs --batch -f batch-byte-compile "$siteStart"
+  '';
+
+  phases = [ "installPhase" ];
+  installPhase = ''
+    mkdir -p "$out/bin"
+
+    # Wrap emacs and friends so they find our site-start.el before the original.
+    for prog in $emacs/bin/*; do # */
+      local progname=$(basename "$prog")
+      rm -f "$out/bin/$progname"
+      makeWrapper "$prog" "$out/bin/$progname" \
+        --suffix EMACSLOADPATH ":" "$deps/share/emacs/site-lisp:"
+    done
+
+    # Wrap MacOS app
+    # this has to pick up resources and metadata
+    # to recognize it as an "app"
+    if [ -d "$emacs/Applications/Emacs.app" ]; then
+      mkdir -p $out/Applications/Emacs.app/Contents/MacOS
+      cp -r $emacs/Applications/Emacs.app/Contents/Info.plist \
+            $emacs/Applications/Emacs.app/Contents/PkgInfo \
+            $emacs/Applications/Emacs.app/Contents/Resources \
+            $out/Applications/Emacs.app/Contents
+      makeWrapper $emacs/Applications/Emacs.app/Contents/MacOS/Emacs $out/Applications/Emacs.app/Contents/MacOS/Emacs \
+        --suffix EMACSLOADPATH ":" "$deps/share/emacs/site-lisp:"
+    fi
+
+    mkdir -p $out/share
+    # Link icons and desktop files into place
+    for dir in applications icons info man; do
+      ln -s $emacs/share/$dir $out/share/$dir
+    done
+  '';
+  inherit (emacs) meta;
+}