b9dce11712
The `overrideScope` bound by `makeScope` (via special `callPackage`) took an override in the form `super: self { … }`. But this is dangerously close to the `self: super { … }` form used by *everything* else, even other definitions of `overrideScope`! Since that implementation did not even share any code either until I changed it recently in 3cf43547f4be03d1d6eb0bbfc557e2dbc13b4095, this inconsistency is almost certainly an oversight and not intentional. Unfortunately, just as the inconstency is hard to debug if one just assumes the conventional order, any sudden fix would break existing overrides in the same hard-to-debug way. So instead of changing the definition a new `overrideScope'` with the conventional order is added, and old `overrideScope` deprecated with a warning saying to use `overrideScope'` instead. That will hopefully get people to stop using `overrideScope`, freeing our hand to change or remove it in the future.
174 lines
5.6 KiB
Nix
174 lines
5.6 KiB
Nix
/*
|
|
|
|
# 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;
|
|
}
|