jwiegley / use-package

A use-package declaration for simplifying your .emacs
https://jwiegley.github.io/use-package
GNU General Public License v3.0
4.41k stars 261 forks source link

Issue with using the `use-package-always-ensure` option #190

Closed kaushalmodi closed 6 years ago

kaushalmodi commented 9 years ago

Hi ,

I tried out the new option and set it to t.

But it gives me this error:

Eager macro-expansion failure: (error "Package defuns-' is unavailable") package-compute-transaction: Packagedefuns-' is unavailable

I have the below in my emacs init:

(defun prepend-path ( my-path )
  (setq load-path (cons (expand-file-name my-path) load-path)))

(prepend-path (concat user-emacs-directory "/elisp"))
;; ...
(package-initialize)
;; ...
(eval-when-compile
  (require 'use-package)
  (setq use-package-always-ensure t))
(use-package bind-key)
(use-package defuns)

The defuns.el is present in that elisp/ path.

But is looks like defuns is being tried to be installed by the package manager (even though it is available in the load-path) when this new option is t (or probably because :ensure is t).

kaushalmodi commented 6 years ago

some way to add tests for these things in use-package-tests.el that is independent from whether I do or don't use it in my own config?

Writing ert tests is on my long list of Emacs things to learn.. Aren't the ert tests run using emacs --batch? So they would automatically be agnostic to the user config.. Now I don't know the main part.. "How to write the above test in ert".

I believe, the same test as above can be replicated in ert.. I just don't know the syntax:

  1. Create a dummy "package" that has a provide.. make sure that that "package" couldn't ever be found on GNU Elpa (as we are running emacs --batch.. we can make it use just that archive).. and so I have that arbitrary name in my test.
  2. Then simply make use-package load that package with use-package-always-ensure set to t and :load-path set to the path where ert generated that dummy package.
  3. You can make that dummy package define a function that returns some constant.
  4. Make ert eval the above use-package form, run the fn from that package and compare the return value of that fn with the expected constant.
  5. Test passes if all of that is good.

With this bug, ert will see that "package not available" error in the "eval use-package" stage.

Sorry, but I wished I could have helped more..

npostavs commented 6 years ago

Create a dummy "package"

I think it would be simpler to do something like

(cl-letf* ((tried-to-install nil)
           ((symbol-function 'package-install)
            (lambda (pkg) (setq tried-to-install pkg))))
  (eval '(use-package foo :ensure t))
  (should (eq tried-to-install 'foo)))
kaushalmodi commented 6 years ago

@npostavs If I understand correctly, that test doesn't test this bug fix.. somewhere use-package-always-ensure must be set to t and :load-path must also be set.. and it should be checked that tried-to-install stays at nil, right?.. or may be I just need to bookmark this to revisit to understand it better.

npostavs commented 6 years ago

@kaushalmodi yeah, that was just a sketch to give the flavour, several tests would be necessary to hit all the relevant cases that you point out.

jwiegley commented 6 years ago

@npostavs Excellent! With your help I was able to make a decent test, which even uncovered yet another corner case when using :ensure with :load-path:

(ert-deftest use-package-test/:ensure ()
  (let ((use-package-always-ensure nil))
    (match-expansion
     (use-package foo :ensure t)
     `(progn
        (use-package-ensure-elpa 'foo 't 'nil :ensure)
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure t))
    (match-expansion
     (use-package foo :ensure t)
     `(progn
        (use-package-ensure-elpa 'foo 't 'nil :ensure)
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure nil))
    (match-expansion
     (use-package foo :ensure nil)
     `(progn
        (use-package-ensure-elpa 'foo 'nil 'nil :ensure)
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure t))
    (match-expansion
     (use-package foo :ensure nil)
     `(progn
        (use-package-ensure-elpa 'foo 'nil 'nil :ensure)
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure nil))
    (match-expansion
     (use-package foo :load-path "foo")
     `(progn
        (eval-and-compile
          (add-to-list 'load-path ,(pred stringp)))
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure t))
    (match-expansion
     (use-package foo :load-path "foo")
     `(progn
        (use-package-ensure-elpa 'foo 'nil 'nil :ensure)
        (eval-and-compile
          (add-to-list 'load-path ,(pred stringp)))
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure nil))
    (match-expansion
     (use-package foo :ensure nil :load-path "foo")
     `(progn
        (use-package-ensure-elpa 'foo 'nil 'nil :ensure)
        (eval-and-compile
          (add-to-list 'load-path ,(pred stringp)))
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure t))
    (match-expansion
     (use-package foo :ensure nil :load-path "foo")
     `(progn
        (use-package-ensure-elpa 'foo 'nil 'nil :ensure)
        (eval-and-compile
          (add-to-list 'load-path ,(pred stringp)))
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure nil))
    (match-expansion
     (use-package foo :ensure t :load-path "foo")
     `(progn
        (use-package-ensure-elpa 'foo 't 'nil :ensure)
        (eval-and-compile
          (add-to-list 'load-path ,(pred stringp)))
        (require 'foo nil 'nil))))

  (let ((use-package-always-ensure t))
    (match-expansion
     (use-package foo :ensure t :load-path "foo")
     `(progn
        (use-package-ensure-elpa 'foo 't 'nil :ensure)
        (eval-and-compile
          (add-to-list 'load-path ,(pred stringp)))
        (require 'foo nil 'nil))))

  (let (tried-to-install)
    (flet ((use-package-ensure-elpa
            (name ensure state context &optional no-refresh)
            (when ensure
              (setq tried-to-install name))))
      (eval '(use-package foo :ensure t))
      (should (eq tried-to-install 'foo)))))
npostavs commented 6 years ago
(flet ((use-package-ensure-elpa (name ensure state context &optional no-refresh)

Using (cl-flet (((symbol-function 'use-package-ensure-elpa) (lambda (name ... would be the non-deprecated way of doing that.

rprimus commented 6 years ago

Mon Jan 15 12:52:27 GMT 2018

Not sure if I should open another issue for this.

Recently spent some time recently cleaning up/modernising my init.d to use use-package.

Setting use-package-always-ensure t, I get the following errors:

Error (use-package): Failed to install dired-x: Package ‘dired-x-’ is unavailable
Error (use-package): Failed to install dired: Package ‘dired-’ is unavailable
Error (use-package): Failed to install uniquify: Package ‘uniquify-’ is unavailable
Error (use-package): Failed to install font-lock: Package ‘font-lock-’ is unavailable
Error (use-package): Failed to install em-smart: Package ‘em-smart-’ is unavailable

These errors can be silenced using :ensure nil, but raises the questions:

  1. What is a package?
  2. Can/Should internal features also be considered as packages?
  3. If not, should use-package be used to configure features?

(With use-package-always-ensure unset, no errors are generated.)

doolio commented 6 years ago

I get similar errors as reported by @rprimus above when running profile-dotemacs.el to profile my init file. In my case, it was the following packages:

Error (use-package): Failed to install cus-edit: Package ‘cus-edit-’ is unavailable
Error (use-package): Failed to install ediff-wind: Package ‘ediff-wind-’ is unavailable
Error (use-package): Failed to install frame: Package ‘frame-’ is unavailable
Error (use-package): Failed to install dired: Package ‘dired-’ is unavailable
Error (use-package): Failed to install dired-x: Package ‘dired-x-’ is unavailable
Error (use-package): Failed to install newcomment: Package ‘newcomment-’ is unavailable
Error (use-package): Failed to install isearch: Package ‘isearch-’ is unavailable
Error (use-package): Failed to install auto-insert: Package ‘auto-insert-’ is unavailable
Error (use-package): Failed to install org-agenda: Package ‘org-agenda-’ is unavailable

Are these examples of edge cases not detected by the above tests?

gety9 commented 9 months ago

Getting same error

Failed to install cus-edit: Package ‘cus-edit’ is unavailable