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`.
This commit is contained in:
magicquark
2025-10-01 02:49:45 +08:00
committed by Lin Jian
parent 4ae67070d1
commit 0749d7abed
2 changed files with 163 additions and 50 deletions
@@ -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'.")
@@ -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; [ ];
};
}
)