diff --git a/build-helpers/build-doom-emacs.sh b/build-helpers/build-doom-emacs.sh new file mode 100644 index 0000000..d2c3ad5 --- /dev/null +++ b/build-helpers/build-doom-emacs.sh @@ -0,0 +1,37 @@ +# -*- mode: sh; sh-shell: bash -*- + +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if [[ -z "$profileName" ]]; then + profileArgs=() +else + profileArgs=( + --set DOOMPROFILELOADFILE $doomProfile/loader/init.el + --set DOOMPROFILE "$profileName" + ) +fi +makeWrapper $emacsWithPackages/bin/emacs $out/bin/doom-emacs \ + "${profileArgs[@]}" \ + --set DOOMDIR $doomProfile/doomdir \ + --set-default DOOMLOCALDIR "$doomLocalDir" \ + --add-flags "--init-directory=$doomSource" +makeWrapper $doomSource/bin/doomscript $out/bin/doomscript \ + --set EMACS $emacsWithPackages/bin/emacs \ + --set-default DOOMLOCALDIR "$doomLocalDir" +makeWrapper $doomSource/bin/doom $out/bin/doom \ + --set EMACS $emacsWithPackages/bin/emacs \ + "${profileArgs[@]}" \ + --set DOOMDIR $doomProfile/doomdir \ + --set-default DOOMLOCALDIR "$doomLocalDir" diff --git a/build-helpers/build-doom-profile.sh b/build-helpers/build-doom-profile.sh new file mode 100644 index 0000000..d4cf9b2 --- /dev/null +++ b/build-helpers/build-doom-profile.sh @@ -0,0 +1,54 @@ +# -*- mode: sh; sh-shell: bash -*- + +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +mkdir $out $out/loader $out/doomdir $out/profile $out/straight +ln -s $doomDir/* $out/doomdir/ +# yasnippet logs an error at startup if snippets/ does not exist. +if ! [[ -e $out/doomdir/snippets ]]; then + mkdir $out/doomdir/snippets +fi +rm $out/doomdir/init.el +if [[ -z "$profileName" ]]; then + maybeSetProfileDir="(setq doom-profile-dir \"$out/profile\")" +else + maybeSetProfileDir="" +fi +substitute $initEl $out/doomdir/init.el \ + --subst-var maybeSetProfileDir \ + --subst-var profileName \ + --subst-var-by userInit "$doomDir/init.el" \ + --subst-var-by straightBaseDir $out +ln -sf $doomIntermediates/packages.el $out/doomdir/ +export DOOMDIR=$out/doomdir + +# DOOMLOCALDIR must be writable, Doom creates some subdirectories. +export DOOMLOCALDIR=$(mktemp -d) +if [[ -n "$profileName" ]]; then + export DOOMPROFILELOADFILE=$out/loader/init.el + $runtimeShell $doomSource/bin/doomscript $buildProfileLoader \ + ${noProfileHack:+-u} -n "$profileName" -b "$out" + + # With DOOMPROFILE set, doom-state-dir and friends are HOME-relative. + export HOME=$(mktemp -d) + export DOOMPROFILE="$profileName"; +fi +$runtimeShell $doomSource/bin/doomscript $buildProfile + +# Similar to audit-tmpdir.sh in nixpkgs. +if grep -q -F "$TMPDIR/" -r $out; then + echo "Doom profile contains a forbidden reference to $TMPDIR/" + exit 1 +fi diff --git a/build-helpers/build-emacs-with-doom.sh b/build-helpers/build-emacs-with-doom.sh new file mode 100644 index 0000000..f05940a --- /dev/null +++ b/build-helpers/build-emacs-with-doom.sh @@ -0,0 +1,28 @@ +# -*- mode: sh; sh-shell: bash -*- + +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +mkdir -p $out/bin +ln -s $emacs/bin/* $out/bin/ +rm $out/bin/emacs-* +ln -sf $doomEmacs/bin/doom-emacs $out/bin/emacs +ln -sf $doomEmacs/bin/{doom,doomscript} $out/bin/ + +mkdir -p $out/share +# Don't link everything: the systemd units would still refer to normal Emacs. +# This links the same stuff emacsWithPackages does. +for dir in applications icons info man; do + ln -s $emacs/share/$dir $out/share/$dir +done diff --git a/default.nix b/default.nix index 883eb8c..ed5b655 100644 --- a/default.nix +++ b/default.nix @@ -46,11 +46,12 @@ git, emacsPackagesFor, lib, - runCommand, runCommandLocal, runtimeShell, writeText, makeBinaryWrapper, + stdenv, + stdenvNoCC, }: let inherit (lib) optionalAttrs optionalString; @@ -304,107 +305,48 @@ let # - The path to the generated profile is included in the loader # - Generating the profile depends on the loader - # Force local build in case the user init.el does something weird. - doomProfile = runCommandLocal "doom-profile" - { - inherit doomDir doomIntermediates doomSource noProfileHack profileName runtimeShell; - buildProfileLoader = ./build-helpers/build-profile-loader; - buildProfile = ./build-helpers/build-profile; - initEl = ./init.el; - EMACS = lib.getExe emacsWithPackages; - # Enable this to troubleshoot failures at this step. - #DEBUG = "1"; - # Required to avoid Doom erroring out at startup. - nativeBuildInputs = [ git ]; - } '' - mkdir $out $out/loader $out/doomdir $out/profile $out/straight - ln -s $doomDir/* $out/doomdir/ - # yasnippet logs an error at startup if snippets/ does not exist. - if ! [[ -e $out/doomdir/snippets ]]; then - mkdir $out/doomdir/snippets - fi - rm $out/doomdir/init.el - if [[ -z "$profileName" ]]; then - maybeSetProfileDir="(setq doom-profile-dir \"$out/profile\")" - else - maybeSetProfileDir="" - fi - substitute $initEl $out/doomdir/init.el \ - --subst-var maybeSetProfileDir \ - --subst-var profileName \ - --subst-var-by userInit "$doomDir/init.el" \ - --subst-var-by straightBaseDir $out - ln -sf $doomIntermediates/packages.el $out/doomdir/ - export DOOMDIR=$out/doomdir + doomProfile = stdenvNoCC.mkDerivation { + name = "doom-profile"; + buildCommandPath = ./build-helpers/build-doom-profile.sh; - # DOOMLOCALDIR must be writable, Doom creates some subdirectories. - export DOOMLOCALDIR=$(mktemp -d) - if [[ -n "$profileName" ]]; then - export DOOMPROFILELOADFILE=$out/loader/init.el - $runtimeShell $doomSource/bin/doomscript $buildProfileLoader \ - ''${noProfileHack:+-u} -n "$profileName" -b "$out" + inherit doomDir doomIntermediates doomSource noProfileHack profileName runtimeShell; + buildProfileLoader = ./build-helpers/build-profile-loader; + buildProfile = ./build-helpers/build-profile; + initEl = ./init.el; + EMACS = lib.getExe emacsWithPackages; + # Enable this to troubleshoot failures at this step. + #DEBUG = "1"; - # With DOOMPROFILE set, doom-state-dir and friends are HOME-relative. - export HOME=$(mktemp -d) - export DOOMPROFILE="$profileName"; - fi - $runtimeShell $doomSource/bin/doomscript $buildProfile - - # Similar to audit-tmpdir.sh in nixpkgs. - if grep -q -F "$TMPDIR/" -r $out; then - echo "Doom profile contains a forbidden reference to $TMPDIR/" - exit 1 - fi - ''; + # Required to avoid Doom erroring out at startup. + nativeBuildInputs = [ git ]; + # Force local build in case the user init.el does something weird. + preferLocalBuild = true; + allowSubstitutes = false; + }; # Step 6: write wrappers to start the whole thing. - # Use runCommand, not runCommandLocal, because makeBinaryWrapper pulls in a compiler. - doomEmacs = runCommand "doom-emacs" { + # makeBinaryWrapper pulls in a compiler, so don't force this one local. + doomEmacs = stdenv.mkDerivation { + name = "doom-emacs"; + buildCommandPath = ./build-helpers/build-doom-emacs.sh; + # emacsWithPackages also accessed externally (for pushing to Cachix). inherit doomProfile doomLocalDir doomSource emacsWithPackages profileName; - nativeBuildInputs = [ makeBinaryWrapper ]; - } '' - if [[ -z "$profileName" ]]; then - profileArgs=() - else - profileArgs=( - --set DOOMPROFILELOADFILE $doomProfile/loader/init.el - --set DOOMPROFILE "$profileName" - ) - fi - makeWrapper $emacsWithPackages/bin/emacs $out/bin/doom-emacs \ - "''${profileArgs[@]}" \ - --set DOOMDIR $doomProfile/doomdir \ - --set-default DOOMLOCALDIR "$doomLocalDir" \ - --add-flags "--init-directory=$doomSource" - makeWrapper $doomSource/bin/doomscript $out/bin/doomscript \ - --set EMACS $emacsWithPackages/bin/emacs \ - --set-default DOOMLOCALDIR "$doomLocalDir" - makeWrapper $doomSource/bin/doom $out/bin/doom \ - --set EMACS $emacsWithPackages/bin/emacs \ - "''${profileArgs[@]}" \ - --set DOOMDIR $doomProfile/doomdir \ - --set-default DOOMLOCALDIR "$doomLocalDir" - ''; - emacsWithDoom = runCommand (lib.appendToName "with-doom" emacs).name { + nativeBuildInputs = [ makeBinaryWrapper ]; + }; + + emacsWithDoom = stdenvNoCC.mkDerivation { + inherit (lib.appendToName "with-doom" emacs) name; inherit (emacs) meta; inherit doomEmacs emacs; - } '' - mkdir -p $out/bin - ln -s $emacs/bin/* $out/bin/ - rm $out/bin/emacs-* - ln -sf $doomEmacs/bin/doom-emacs $out/bin/emacs - ln -sf $doomEmacs/bin/{doom,doomscript} $out/bin/ + buildCommandPath = ./build-helpers/build-emacs-with-doom.sh; - mkdir -p $out/share - # Don't link everything: the systemd units would still refer to normal Emacs. - # This links the same stuff emacsWithPackages does. - for dir in applications icons info man; do - ln -s $emacs/share/$dir $out/share/$dir - done - ''; + # Force local build as it's near-trivial. + preferLocalBuild = true; + allowSubstitutes = false; + }; in { inherit doomEmacs emacsWithDoom;