diff --git a/lisp/_prepare.el b/lisp/_prepare.el index e73ffb00..d76a2cee 100644 --- a/lisp/_prepare.el +++ b/lisp/_prepare.el @@ -733,7 +733,7 @@ Argument BODY are forms for execution." ;; Handle `--force` flag. (when should-reinstall-p (package-delete (eask-package-desc pkg t) t)) ;; Install it. - (package-install-file (expand-file-name file))) + (eask-ignore-errors (package-install-file (expand-file-name file)))) "done ✓"))))) (defun eask-package-install (pkg) diff --git a/lisp/core/install-file.el b/lisp/core/install-file.el index f1846773..66b5c2f8 100644 --- a/lisp/core/install-file.el +++ b/lisp/core/install-file.el @@ -22,14 +22,39 @@ (eask-load "core/install") -(defun eask-install-file--guess-name (file) - "Guess the package name of the install FILE." - (file-name-sans-extension (file-name-nondirectory (directory-file-name file)))) +(defun eask-install-file--get-package-name (path) + "Get the package name from PATH, which is a file, directory or archive." + (cond + ((not (file-exists-p path)) + (eask-error "File does not exist %s" path)) + ((or (string-suffix-p ".tar" path) + (string-suffix-p ".tar.gz" path)) + ;; tar file + ;; Note this can throw strange errors if + ;; - there is no -pkg.el in the tar file + ;; - the tar file was built in a folder with a different name + ;; tar files created with eask package are fine + (require 'tar-mode) + (let ((pkg-desc (with-current-buffer (find-file (expand-file-name path)) + (eask-ignore-errors-silent (package-tar-file-info))))) + (unless pkg-desc + ;; package-dir-info will return nil if there is no -pkg.el and no .el files at path + (eask-error "No package in %s" path)) + (package-desc-name pkg-desc)) + ) + (t ;; .el file or directory + ;; Note package-dir-info doesn't work outside of dired mode! + (let ((pkg-desc (with-current-buffer (dired (expand-file-name path)) + (eask-ignore-errors-silent (package-dir-info))))) + (unless pkg-desc + ;; package-dir-info will return nil if there is no -pkg.el and no .el files at path + (eask-error "No package in %s" path)) + (package-desc-name pkg-desc))))) (defun eask-install-file--packages (files) "The file install packages with FILES." (let* ((deps (mapcar (lambda (file) - (list (eask-install-file--guess-name file) file)) + (list (eask-install-file--get-package-name file) file)) files)) (names (mapcar #'car deps)) (len (length deps)) @@ -52,7 +77,7 @@ ;; If package [files..] are specified, we try to install it (eask-install-file--packages files) ;; Otherwise, report error. - (eask-info "(No file packages have been intalled)") + (eask-info "(No file packages have been installed)") (eask-help "core/install-file"))) ;;; core/install-file.el ends here diff --git a/lisp/core/install-vc.el b/lisp/core/install-vc.el index 6d26519d..7eb54ebf 100644 --- a/lisp/core/install-vc.el +++ b/lisp/core/install-vc.el @@ -21,7 +21,10 @@ nil t)) (eask-load "core/install") -(eask-load "core/install-file") + +(defun eask-install-vc--guess-name (file) + "Guess the package name of the install FILE." + (file-name-sans-extension (file-name-nondirectory (directory-file-name file)))) (defun eask-install-vc--split-sepcs (specs) "Split the SPECS and return a list of specification." @@ -32,7 +35,7 @@ (cond ((ffap-url-p spec) (push (reverse current-spec) new-specs) ;; We're using the push, so the order is reversed. - (setq current-spec (list spec (eask-install-file--guess-name spec)))) + (setq current-spec (list spec (eask-install-vc--guess-name spec)))) (t (push spec current-spec)))) ;; Push thes rest of the specification. @@ -67,7 +70,7 @@ ;; If package [specs..] are specified, we try to install it (eask-install-vc--packages specs) ;; Otherwise, report error. - (eask-info "(No vc packages have been intalled)") + (eask-info "(No vc packages have been installed)") (eask-help "core/install-vc"))) ;;; core/install-vc.el ends here diff --git a/test/jest/install.test.js b/test/jest/install.test.js index ea2f2849..e9dc3450 100644 --- a/test/jest/install.test.js +++ b/test/jest/install.test.js @@ -53,11 +53,6 @@ describe("install and uninstall", () => { expect(stderr).not.toMatch(packageName); }); - it("installs file directly", async () => { - const { stderr } = await ctx.runEask("install-file ./mini.pkg.2"); - expect(stderr).toMatch("mini.pkg.2"); - }); - test.skip("installs vc directly", async () => { if ((await emacsVersion()) >= "29.1") { const { stderr } = await ctx.runEask( @@ -66,6 +61,52 @@ describe("install and uninstall", () => { expect(stderr).toMatch("msgu"); } }); + + describe("eask install-file", () => { + beforeAll(async () => { + await ctx.runEask("clean workspace"); + }); + + it("installs file directly", async () => { + const { stderr } = await ctx.runEask("install-file ./mini.pkg.2"); + expect(stderr).toMatch("mini.pkg.2"); + }); + + it("uses the correct package name", async () => { + const { stderr } = await ctx.runEask("install-file ./foo-mode"); + expect(stderr).toMatch("foo"); + }); + + it("can repeat installs", async () => { + await ctx.runEask("install-file ./foo-mode"); + }); + + it("reinstalls a package using --force", async () => { + const { stderr } = await ctx.runEask("install-file --force ./foo-mode"); + expect(stderr).toMatch("foo"); + }); + + it("installs a package with only an Eask file", async () => { + await ctx.runEask("install-file ./foo-no-pkg"); + }); + + it("errors when path is non-existing", async () => { + await expect(ctx.runEask("install-file ./foo")).rejects.toThrow(); + }); + + it("errors when path is an empty directory", async () => { + await expect(ctx.runEask("install-file ../empty")).rejects.toThrow(); + }); + + it("gets the package name from a tar file", async () => { + await ctx.runEask("install-file ./foo.tar.gz"); + }); + + it("can install tar files created with eask package", async () => { + // foo-0.0.1.tar is created by running eask package in ./foo-no-pkg + await ctx.runEask("install-file ./foo-0.0.1.tar"); + }); + }); }); describe("in an empty project", () => { diff --git a/test/jest/install/foo-0.0.1.tar b/test/jest/install/foo-0.0.1.tar new file mode 100644 index 00000000..70636069 Binary files /dev/null and b/test/jest/install/foo-0.0.1.tar differ diff --git a/test/jest/install/foo-mode/Eask b/test/jest/install/foo-mode/Eask new file mode 100644 index 00000000..dc2bc1d3 --- /dev/null +++ b/test/jest/install/foo-mode/Eask @@ -0,0 +1,14 @@ +(package "foo" + "0.0.1" + "") + +(website-url "") +(keywords ) + +(package-file "foo.el") + +(script "test" "echo \"Error: no test specified\" && exit 1") + +(source "gnu") + +(depends-on "emacs" "26.1") diff --git a/test/jest/install/foo-mode/foo-pkg.el b/test/jest/install/foo-mode/foo-pkg.el new file mode 100644 index 00000000..c7b3b1da --- /dev/null +++ b/test/jest/install/foo-mode/foo-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from foo.el -*- no-byte-compile: t -*- +(define-package "foo" "0.0.1" "foo" '((emacs "0")) :keywords '("test")) diff --git a/test/jest/install/foo-mode/foo.el b/test/jest/install/foo-mode/foo.el new file mode 100644 index 00000000..b9cafe63 --- /dev/null +++ b/test/jest/install/foo-mode/foo.el @@ -0,0 +1,38 @@ +;;; foo.el --- foo -*- lexical-binding: t -*- + +;; Author: none +;; Maintainer: none +;; Version: 0.0.1 +;; Package-Requires: (emacs) +;; Keywords: test + + +;; This file is not part of GNU Emacs + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + + +;;; Commentary: + +;; commentary + +;;; Code: + +(defun foo-message () + "docstring" + (interactive "P") + (message "Hello World!")) + +(provide 'foo) +;;; foo.el ends here diff --git a/test/jest/install/foo-no-pkg/Eask b/test/jest/install/foo-no-pkg/Eask new file mode 100644 index 00000000..dc2bc1d3 --- /dev/null +++ b/test/jest/install/foo-no-pkg/Eask @@ -0,0 +1,14 @@ +(package "foo" + "0.0.1" + "") + +(website-url "") +(keywords ) + +(package-file "foo.el") + +(script "test" "echo \"Error: no test specified\" && exit 1") + +(source "gnu") + +(depends-on "emacs" "26.1") diff --git a/test/jest/install/foo-no-pkg/foo.el b/test/jest/install/foo-no-pkg/foo.el new file mode 100644 index 00000000..b9cafe63 --- /dev/null +++ b/test/jest/install/foo-no-pkg/foo.el @@ -0,0 +1,38 @@ +;;; foo.el --- foo -*- lexical-binding: t -*- + +;; Author: none +;; Maintainer: none +;; Version: 0.0.1 +;; Package-Requires: (emacs) +;; Keywords: test + + +;; This file is not part of GNU Emacs + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + + +;;; Commentary: + +;; commentary + +;;; Code: + +(defun foo-message () + "docstring" + (interactive "P") + (message "Hello World!")) + +(provide 'foo) +;;; foo.el ends here diff --git a/test/jest/install/foo.tar.gz b/test/jest/install/foo.tar.gz new file mode 100644 index 00000000..26f21a0d Binary files /dev/null and b/test/jest/install/foo.tar.gz differ