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