Skip to content

Add option to install from a local file #316

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

joshbax189
Copy link
Contributor

Rationale

  • I want to do eask install --local ./some/path.
  • But how do I get fresh changes from ./some/path, do I reinstall for every change?
  • No: Have Eask install whenever package-initialize is run!
  • But how does Eask know which packages to reinstall and from where?
  • Add local state

Changes
Adds --local option to eask install. All args are interpreted as paths in that case.

Adds a few functions that save data in .eask/ver/eask-state.el:

(eask-read-state-var 'local-packages) ;; alist of package-name to path
(eask-set-state-var 'local-packages '((foo . "./some/path")))
(eask--save-state)  ;; this is added to post-command-hook

Reinstalls saved 'local-packages whenever eask-pkg-init is called.

Notes

  • Might need to put the reinstall step somewhere other than eask-pkg-init if performance is bad
  • Haven't tested it a lot

TODOs

  • uninstall a local package
  • display local package source in eask list
  • test adding a file to a local package
  • test adding a dependency to a local package
  • add integration tests
  • update doco
    • cmd docs
    • hugo docs

@joshbax189 joshbax189 marked this pull request as draft April 3, 2025 00:52
await UTIL.e_call(
argv,
"core/install",
UTIL.def_flag(argv.local, "--local"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would probably need to add this to eask--option-switches too. :)

Edit: I saw you added it. Great! :)

Another issue is a naming conflict between this flag and the function eask-local-p. 😅 We might need to change this to something else. 🤔

@@ -345,6 +346,41 @@ and INHERIT-INPUT-METHOD see function `read-string' for more information."
(declare (indent 0) (debug t))
`(eask-with-buffer (erase-buffer) ,@body))

(defvar eask--state-alist '()
"Alist mapping symbols to values which will be persisted between sessions.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to set it as nil when '(). :)

@jcs090218
Copy link
Member

Maybe we should have a new command eask install-file [paths..] (name came from package-install-file).

I recommend we store eask--state-alist in Eask-file since eask-state.el can be lost after eask clean workspace. 🤔

How about?

(depends-on "foo-mode" :local "/path/to/foo-mode")

And handle local packages right before https://github.com/emacs-eask/cli/blob/master/lisp/_prepare.el#L1514.

@jcs090218
Copy link
Member

jcs090218 commented Apr 3, 2025

Could you check out #317? I hope it's what you're looking for! 😋

You can now install it with:

# directory
eask install-file /path/to/foo-mode
# .tar file
eask install-file /path/to/foo-mode.tar
# .el file
eask install-file /path/to/foo-mode.el

In Eask-file:

(depends-on "foo-mode" :file "/path/to/foo-mode")

Now it becomes the dependency to your project, then do eask install-deps.

@joshbax189
Copy link
Contributor Author

Haha this is a complex feature... because it's really 3 related features:

  • packages installed from a local file
  • packages that are reinstalled every run
  • packages that are installed but not saved in the eask file

I think we should use both #316 and #317, but should work out the naming of commands and options to present all these features to the user in the least confusing way.

I'll refer to these use cases below:

  • local install user installs from a file AND saves it in the eask file
    e.g. using a dependency in a git submodule or a using eask to manage ~/.emacs.d
  • local override user installs from a file but DOESN'T save it in the eask file
    e.g. testing changes to a dependency, or simultaneously working on packages
  • npm link when the user has an archive of local packages which can be installed by name

So, this PR enables local override (and perhaps npm link), but #317 enables local install -- both are useful features, but how do we organize them?

Local Install by Linking

First let's look at the "npm link" use case. I think this is optional to support. (We could implement it by using the save-state helpers in this commit to save links in the global eask folder). If we decided to make it, then it would make sense to redefine eask link to match. Then the other two use cases would look like

# in ./json-mode
eask link      # json-mode -> ./path/to/json-mode stored in ~/.eask/eask-state.el

# in ./foo-mode
# local install
# user manually add (depends-on json-mode) to Easkfile
eask install-deps   # fails to install json-mode
eask link add json-mode
eask install-deps   # succeeds, but is not required after link add

# local override
# no depends-on in Easkfile, link is temporary
eask link add json-mode

Note that there are no necessary changes to eask install in this case!

It might make sense to expose the "reinstalled every run" feature by having, say, eask install-file mean "install once, do not reinstall" and eask link add mean "reinstall every run".

Commands or Options

Now assume we are not using the "npm link" use case, and just consider the remaining two use cases. How should the commands and options be organized?

The most flexible choice is to use options for the eask install command. Then the user is free to use any combination of the options. The risk is that some combinations don't make sense, or that the meaning of different combinations is too confusing.

Here's how the use cases would look when using options:

  • local override eask install --source=local --temp ./path/to/json
  • local install eask install --source=local ./path/to/json
  • reinstall as an option eask install --source=local --reinstall ./path/to/json

New cases that are possible with these options:

  • eask install --temp ivy
  • eask install --reinstall ivy
  • eask install --source=github abo-abo/swiper generates a recipe in the Eask file

The other alternative (suggested in #317) is to use separate commands per install source. This is a good choice if we want to focus the functionality of the commands. For example, if we decide that a local install must always reinstall, it makes no sense to have --reinstall, and eask install-file will imply that feature.
We could write down the equivalent command/option versions

  • eask link-file ./path/to/json is eask install --source=local --temp ./path/to/json
    note: I added link-file so that install always means "change the Eask file"
  • eask install-file ./path/to/json is eask install --source=local ./path/to/json

If you think of commands like link-file and install-file as aliases for groups of options, then we just need to decide which options are sensible, which groups of options are valid, and what to call those groups.

Summary

I think these are the decisions:

  • should we implement the "npm link" use case at all? (this will affect the next decisions)
  • should --temp (don't save in Eask file) be a user option?
  • should --reinstall be a user option?
  • do we prefer eask install --source=file or eask install-file
  • are the extra features implied by new options worth supporting?

I hope you enjoyed my essay ;)

@jcs090218
Copy link
Member

jcs090218 commented Apr 3, 2025

Let's break this down a little. There are too many features at a time right now. 😬

Things to clarify:

  1. eask install-file installs packages temporarily, making it available only within the workspace. To make it a permanent dependency, you need to add it to your Eask-file, allowing installation via eask install-deps.
  2. eask install-file integrates with package.el, so the eask list command will function as expected.
  3. There is currently no reinstall except the command eask reinstall. We can use --force flag to eask install-file --force /path/to/foo-mode to force reinstall it.

It might make sense to expose the "reinstalled every run" feature by having, say, eask install-file mean "install once, do not reinstall" and eask link add mean "reinstall every run".

I'm confuse here. link is a command that creates a link to elpa directory and that's it. There is really no installation going on. You would need to use eask link delete to remove the link or eask clean workspace to remove entire .eask folder. 🤔

What I currently have in mind:

  • Install file temporarily (fresh): - eask install-file
  • Install file every run (fresh): - eask install-file --force
  • Install once (not fresh): - eask link add

Furthermore, you only need to change Eask-file when you want your users to install via eask install-deps.

(depends-on "foo-mode" :file "/path/to/foo-mode")  ; Force your users to install it so it cannot go wrong!

Not mentioning link now, I think it's can be a separate issue/PR. :)

@joshbax189
Copy link
Contributor Author

There are too many features at a time right now.

Fair enough, I'm trying to think of features we might want so that changes we make now don't block other possibilities.

It is definitely possible to just make "adds a file package" as a feature and "automatic reinstall" a later feature. This PR was mainly about showing that both are possible.

I'm confuse here. link is a command that creates a link to elpa directory and that's it. There is really no installation going on.

Again, I'm trying to think of how it should work. So I'm ignoring how commands work for now and thinking about how a user, looking only at the docs, will think that they work. Sorry for not clarifying that.

Install file every run (fresh): - eask install-file --force

This reads as though you are reinstalling the file just once? Or do you mean it will make Eask automatically install it every run?

What I currently have in mind

Putting on my "silly user" hat 🧢, I would ask these questions:

  • I can install a file temporarily and a file is just a package, so how can I install a package (from an archive) temporarily?
  • When I eask install package it helpfully adds a depends-on form, but how can I automatically add that for a file?
  • What does eask install --force do?

@jcs090218
Copy link
Member

jcs090218 commented Apr 3, 2025

This reads as though you are reinstalling the file just once? Or do you mean it will make Eask automatically install it every run?

Oops, I meant to install it just once. Use eask install-deps —force on every run.

I can install a file temporarily and a file is just a package, so how can I install a package (from an archive) temporarily?

What do you mean temporarily? 🤔 My definition in this context means you install it once but cannot install it with eask install-deps since it's not listed in the Eask-file.

Assuming we have the exact definition, you have these options:

  • eask install (from archive)
  • eask install-vc (directly from repo)

When I eask install package it helpfully adds a depends-on form, but how can I automatically add that for a file?

It does not. I hope I have this feature, but it's not easy to implement with my current implementation. 😅🥲 I can explain why, but this is currently out of scope.

What does eask install --force do?

It lets you overwrite installed packages (reinstall). If the package is not installed, just install it.

——-

No worries! I am trying to understand your needs. 😀👍

@jcs090218
Copy link
Member

This might not be exactly the same, but I wanted to let you know that global scope packages are now treated as system packages by default (via the package-directory-list variable). This change gives users greater control over which packages they want to use and reuse. :)

The commit changes is in e0732f2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants