From 4ae67070d1c974a558f4498a2a82a0c5aaad8ee2 Mon Sep 17 00:00:00 2001 From: magicquark <198001825+magicquark@users.noreply.github.com> Date: Sun, 28 Sep 2025 04:21:52 +0100 Subject: [PATCH 1/5] emacsPackages.cask: replace install with installBin --- .../emacs/elisp-packages/manual-packages/cask/package.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix index a344978ebf33..88c536062802 100644 --- a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix +++ b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix @@ -4,10 +4,10 @@ cl-generic, cl-lib, commander, - epl, f, fetchFromGitHub, + installShellFiles, git, melpaBuild, package-build, @@ -27,6 +27,8 @@ melpaBuild (finalAttrs: { hash = "sha256-91rJFsp2SLk/JY+v6G5JmXH5bg9QnT+qhI8ccNJlI4A="; }; + nativeBuildInputs = [ installShellFiles ]; + patches = [ # Uses LISPDIR substitution var ./0000-cask-lispdir.diff @@ -51,9 +53,8 @@ melpaBuild (finalAttrs: { substituteAllInPlace bin/cask ''; - # TODO: use installBin as soon as installBin arrives Master branch postInstall = '' - install -D -t $out/bin bin/cask + installBin bin/cask ''; meta = { From 0749d7abed040207dc6027c83f51b1a39ab309a7 Mon Sep 17 00:00:00 2001 From: magicquark <198001825+magicquark@users.noreply.github.com> Date: Sun, 28 Sep 2025 04:26:20 +0100 Subject: [PATCH 2/5] emacsPackages.cask: fix import error and use non-vendored dependencies - Fixes issue 445465. - Cask expects a local `package-build` directory to be present in the output, as it loads a custom version during bootstrap. See: https://github.com/cask/cask/blob/master/cask-bootstrap.el#L45 - The vendored version of `package-build` is then used to download from `melpa` and `elpa` the dependencies that `cask` requires. This is contrary to the philosophy of `nixpkgs` whereby the dependencies should be sourced from `nixpkgs` itself. - To avoid this, the bootstrap process has been patched to provide the required dependencies using `nixpkgs`. - Additionally, `cask-cli` has a function `upgrade-cask` that uses the `cask-bootstrap-dir` that its own bootstrap process creates. See https://github.com/cask/cask/blob/fd16ea95664b8f13c55b8608dea63942d431ca00/cask-cli.el#L131. As the bootstrap process has been modified to use dependencies from `nixpkgs`, `cask` can no longer update itself. Therefore, this function has been patched to make it effectively a noop. - The patch cannot be upstreamed as it is specific to the way that packages are integrated into `nixpkgs`. --- .../cask/0001-cask-bootstrap.diff | 85 ++++++++++++ .../manual-packages/cask/package.nix | 128 +++++++++++------- 2 files changed, 163 insertions(+), 50 deletions(-) create mode 100644 pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/0001-cask-bootstrap.diff diff --git a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/0001-cask-bootstrap.diff b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/0001-cask-bootstrap.diff new file mode 100644 index 000000000000..b6d0305f8ee1 --- /dev/null +++ b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/0001-cask-bootstrap.diff @@ -0,0 +1,85 @@ +diff --git a/cask-bootstrap.el b/cask-bootstrap.el +--- a/cask-bootstrap.el ++++ b/cask-bootstrap.el +@@ -27,41 +27,18 @@ + + ;;; Code: + +-(require 'package) ++;; Add nix store paths for dependencies to the load-path. ++(let ((paths '(@loadPaths@))) ++ (dolist (path paths) ++ (push path load-path))) + +-(defvar cask-directory) ++(let ((paths '(@nativeLoadPaths@))) ++ (dolist (path paths) ++ (push path native-comp-eln-load-path))) + +-(defconst cask-bootstrap-dir +- (expand-file-name +- (locate-user-emacs-file +- (format ".cask/%s.%s/bootstrap" emacs-major-version emacs-minor-version))) +- "Path to Cask bootstrap directory.") +- +-;; Restore several package- variables and `load-path` after let-scope. +-(let (package-alist +- package-archive-contents +- package--initialized +- (load-path (add-to-list +- 'load-path (expand-file-name "package-build" cask-directory))) +- (package-archives '(("gnu" . "https://elpa.gnu.org/packages/") +- ("melpa" . "https://melpa.org/packages/"))) +- (package-user-dir cask-bootstrap-dir) +- (deps '(s f commander git epl shut-up cl-lib cl-generic eieio ansi))) +- (package-initialize) +- (setq package-archive-contents nil) ;; force refresh, cask#573, cask#559 +- (unless (package-installed-p 'cl-lib) +- ;; package-build depends on cl-lib +- (unless package-archive-contents +- (package-refresh-contents)) +- (package-install 'cl-lib)) +- (require 'package-build) ++(let ((deps '(@depsMod@))) + (dolist (pkg deps) +- (unless (featurep pkg) +- (unless (package-installed-p pkg) +- (unless package-archive-contents +- (package-refresh-contents)) +- (package-install pkg)) +- (require pkg)))) ++ (require pkg))) + + (provide 'cask-bootstrap) + +diff --git a/cask-cli.el b/cask-cli.el +--- a/cask-cli.el ++++ b/cask-cli.el +@@ -129,25 +129,8 @@ already is installed, it will not be installed again." + (cask-install (cask-cli--bundle)))) + + (defun cask-cli/upgrade-cask () +- "Upgrade Cask itself and its dependencies. +- +-This command requires that Cask is installed using Git and that +-Git is available in `exec-path'." +- (unless (f-exists? (f-expand ".no-upgrade" cask-directory)) +- (unwind-protect +- (progn +- (epl-change-package-dir cask-bootstrap-dir) +- (epl-initialize) +- (epl-add-archive "gnu" "https://elpa.gnu.org/packages/") +- (epl-add-archive "melpa" "https://melpa.org/packages/") +- (epl-refresh) +- (epl-upgrade)) +- (epl-reset)) +- (require 'git) +- (let ((git-repo cask-directory)) +- (if (s-present? (git-run "status" "--porcelain")) +- (error "Cannot update Cask because of dirty tree") +- (git-pull))))) ++ "Disabled in Nixpkgs as this function requires that Cask is installed using Git." ++ (princ "Upgrade not available when installed via Nixpkgs.\n")) + + (defun cask-cli/exec (&rest _args) + "Execute ARGS with correct `exec-path' and `load-path'.") diff --git a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix index 88c536062802..cdf142086385 100644 --- a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix +++ b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix @@ -11,62 +11,90 @@ git, melpaBuild, package-build, + replaceVars, s, shut-up, }: +let + formatLoadPath = x: ''"${x}/share/emacs/site-lisp/elpa/${x.ename}-${x.melpaVersion or x.version}"''; + formatNativeLoadPath = x: ''"${x}/share/emacs/native-lisp"''; + getAllDependenciesOfPkg = + pkg: + let + direct = builtins.filter (x: x != null) (pkg.packageRequires or [ ]); + indirect = builtins.concatLists (map getAllDependenciesOfPkg direct); + in + lib.unique (direct ++ indirect); +in +melpaBuild ( + finalAttrs: + let + nixpkgDependencies = getAllDependenciesOfPkg finalAttrs.finalPackage; + loadPaths = builtins.concatStringsSep " " (map formatLoadPath nixpkgDependencies); + nativeLoadPaths = builtins.concatStringsSep " " (map formatNativeLoadPath nixpkgDependencies); + emacsBuiltinDeps = [ + "cl-lib" + "eieio" + ]; + depsMod = builtins.concatStringsSep " " ((map (x: x.ename) nixpkgDependencies) ++ emacsBuiltinDeps); + in + { + pname = "cask"; + version = "0.9.0"; -melpaBuild (finalAttrs: { - pname = "cask"; - version = "0.9.0"; + src = fetchFromGitHub { + name = "cask-source-${finalAttrs.version}"; + owner = "cask"; + repo = "cask"; + rev = "v${finalAttrs.version}"; + hash = "sha256-91rJFsp2SLk/JY+v6G5JmXH5bg9QnT+qhI8ccNJlI4A="; + }; - src = fetchFromGitHub { - name = "cask-source-${finalAttrs.version}"; - owner = "cask"; - repo = "cask"; - rev = "v${finalAttrs.version}"; - hash = "sha256-91rJFsp2SLk/JY+v6G5JmXH5bg9QnT+qhI8ccNJlI4A="; - }; + nativeBuildInputs = [ installShellFiles ]; - nativeBuildInputs = [ installShellFiles ]; + patches = [ + # Uses LISPDIR substitution var + ./0000-cask-lispdir.diff + # Use Nix provided dependencies instead of letting Cask bootstrap itself + (replaceVars ./0001-cask-bootstrap.diff { + inherit depsMod loadPaths nativeLoadPaths; + }) + ]; - patches = [ - # Uses LISPDIR substitution var - ./0000-cask-lispdir.diff - ]; + packageRequires = [ + ansi + cl-generic + cl-lib + commander + epl + f + git + package-build + s + shut-up + ]; - packageRequires = [ - ansi - cl-generic - cl-lib - commander - epl - f - git - package-build - s - shut-up - ]; - - # use melpaVersion so that it works for unstable releases too - postPatch = '' - lispdir=$out/share/emacs/site-lisp/elpa/cask-${finalAttrs.melpaVersion} \ - substituteAllInPlace bin/cask - ''; - - postInstall = '' - installBin bin/cask - ''; - - meta = { - homepage = "https://github.com/cask/cask"; - description = "Project management for Emacs"; - longDescription = '' - Cask is a project management tool for Emacs that helps automate the - package development cycle; development, dependencies, testing, building, - packaging and more. + # use melpaVersion so that it works for unstable releases too + postPatch = '' + lispdir=$out/share/emacs/site-lisp/elpa/cask-${finalAttrs.melpaVersion} \ + substituteAllInPlace bin/cask ''; - license = lib.licenses.gpl3Plus; - mainProgram = "cask"; - maintainers = with lib.maintainers; [ ]; - }; -}) + + postInstall = '' + installBin bin/cask + ''; + + meta = { + homepage = "https://github.com/cask/cask"; + description = "Project management for Emacs"; + longDescription = '' + Cask is a project management tool for Emacs that helps automate the + package development cycle; development, dependencies, testing, building, + packaging and more. + ''; + license = lib.licenses.gpl3Plus; + mainProgram = "cask"; + maintainers = with lib.maintainers; [ ]; + }; + } +) From 6d7351801cf49a5a065f5acd867188a9d9210b0f Mon Sep 17 00:00:00 2001 From: magicquark <198001825+magicquark@users.noreply.github.com> Date: Sun, 28 Sep 2025 04:23:14 +0100 Subject: [PATCH 3/5] emacsPackages.cask: 0.9.0 -> 0.9.1 Changelog: https://github.com/cask/cask/compare/v0.9.0...v0.9.1 --- .../emacs/elisp-packages/manual-packages/cask/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix index cdf142086385..5cc1b63a38ba 100644 --- a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix +++ b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix @@ -40,14 +40,14 @@ melpaBuild ( in { pname = "cask"; - version = "0.9.0"; + version = "0.9.1"; src = fetchFromGitHub { name = "cask-source-${finalAttrs.version}"; owner = "cask"; repo = "cask"; rev = "v${finalAttrs.version}"; - hash = "sha256-91rJFsp2SLk/JY+v6G5JmXH5bg9QnT+qhI8ccNJlI4A="; + hash = "sha256-/vinpQ51AuaTbXW4L4MnVonyfzTMvHUF4HViSPBKZxs="; }; nativeBuildInputs = [ installShellFiles ]; From be406552d6d46b5619eefe6f006b3647747e1a3c Mon Sep 17 00:00:00 2001 From: Lin Jian Date: Tue, 30 Sep 2025 18:30:43 +0800 Subject: [PATCH 4/5] emacsPackages.cask: improve patch substitution - use --replace-fail to fail fast - use shell variable melpaVersion to avoid a string interperation - use shell variable ename to be consistent with other code and to avoid hardcoding --- .../emacs/elisp-packages/manual-packages/cask/package.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix index 5cc1b63a38ba..27a93c3fb898 100644 --- a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix +++ b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix @@ -74,10 +74,10 @@ melpaBuild ( shut-up ]; - # use melpaVersion so that it works for unstable releases too postPatch = '' - lispdir=$out/share/emacs/site-lisp/elpa/cask-${finalAttrs.melpaVersion} \ - substituteAllInPlace bin/cask + # use melpaVersion so that it works for unstable releases too + substituteInPlace bin/cask \ + --replace-fail @lispdir@ $out/share/emacs/site-lisp/elpa/$ename-$melpaVersion ''; postInstall = '' From d9734a731a16f59f44877de378008e4f17ea7f98 Mon Sep 17 00:00:00 2001 From: Lin Jian Date: Tue, 30 Sep 2025 18:36:17 +0800 Subject: [PATCH 5/5] emacsPackages.cask: let cask use its own native compiled results --- .../manual-packages/cask/package.nix | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix index 27a93c3fb898..17b3cabb837d 100644 --- a/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix +++ b/pkgs/applications/editors/emacs/elisp-packages/manual-packages/cask/package.nix @@ -31,7 +31,9 @@ melpaBuild ( let nixpkgDependencies = getAllDependenciesOfPkg finalAttrs.finalPackage; loadPaths = builtins.concatStringsSep " " (map formatLoadPath nixpkgDependencies); - nativeLoadPaths = builtins.concatStringsSep " " (map formatNativeLoadPath nixpkgDependencies); + nativeLoadPaths = builtins.concatStringsSep " " ( + map formatNativeLoadPath (nixpkgDependencies ++ [ (placeholder "out") ]) + ); emacsBuiltinDeps = [ "cl-lib" "eieio" @@ -56,9 +58,7 @@ melpaBuild ( # Uses LISPDIR substitution var ./0000-cask-lispdir.diff # Use Nix provided dependencies instead of letting Cask bootstrap itself - (replaceVars ./0001-cask-bootstrap.diff { - inherit depsMod loadPaths nativeLoadPaths; - }) + ./0001-cask-bootstrap.diff ]; packageRequires = [ @@ -78,6 +78,12 @@ melpaBuild ( # use melpaVersion so that it works for unstable releases too substituteInPlace bin/cask \ --replace-fail @lispdir@ $out/share/emacs/site-lisp/elpa/$ename-$melpaVersion + + # using `replaceVars` results in wrong result of `placeholder "out"` + substituteInPlace cask-bootstrap.el \ + --replace-fail @depsMod@ '${depsMod}' \ + --replace-fail @loadPaths@ '${loadPaths}' \ + --replace-fail @nativeLoadPaths@ '${nativeLoadPaths}' ''; postInstall = ''