Skip to content
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

Use best-matching version #352

Open
mwean opened this issue Sep 11, 2018 · 40 comments · May be fixed by #1767
Open

Use best-matching version #352

mwean opened this issue Sep 11, 2018 · 40 comments · May be fixed by #1767
Labels

Comments

@mwean
Copy link
Contributor

mwean commented Sep 11, 2018

Steps to reproduce

$ asdf list ruby
> 2.3.1
  2.3.7
$ asdf local ruby 2.3

Expected behavior

Use version 2.3.7, since it is the highest version that matches the given value.

Actual behavior

version 2.3 is not installed for ruby

Environment

OS: macOS 10.13.6

asdf version: 0.5.1

Similar to #226, I'd love to be able to be less specific about versions and get the highest matching installed version. For something like postgres, I might just say 9 or 10, for ruby, I might use major and minor. I think this would make the tool a lot more useable.

If this sounds good, I could probably put together a PR, although I'm not sure how much overlap there will be in the logic for installing a highest-matching version.

@vic
Copy link
Contributor

vic commented Sep 11, 2018

Hm, currently asdf is very dumb about versions, they can actually be anything. I mean, not only semantic versions, but things like "system", "ref:master", even "foobar" is valid (I have things like "java intellij" or "android-tools brew" used with my asdf-link plugin)

My primary use for asdf is keeping a single .tool-versions in my projects and let any developer have the same exact versions for tools (compilers, etc). I'm using my .tool-versions file just like a Gem.lock or any-other-tool-locks-file to share the exact version to use on development, testing and production environments.

So I'd say implementing this would cause more problems (not allowing you to not be really sure what was the exact version you are using just by looking at the source code of your project).

I'd consider this issue as something not desirable. But if you really like to have the behaviour you want, you could easily do:

ln -s ~/.asdf/installs/ruby/2.3.7 ~/.asdf/installs/ruby/2.3

Yes, you'd have to update that symlink as you see fit. But again it's only on your development environment and not for all people in the world ^^.

@mwean
Copy link
Contributor Author

mwean commented Sep 11, 2018

My primary use for asdf is keeping a single .tool-versions in my projects and let any developer have the same exact versions for tools

That's definitely one of my use cases, but I also use it for side projects, scripts, etc. where I don't care about the exact version.

This change wouldn't impact any existing users. If you specify 2.3.7, it will use that exact version. If you just specify 2.3, it will find the best versions available. In my mind, it just adds more flexibility and doesn't take anything away.

@vic
Copy link
Contributor

vic commented Sep 11, 2018

Perhaps something better would be allowing some custom hooks for pre-post tool installation (so you can create the symlinks I mentioned, IIRC other people have asked for executing some commands like reshiming, or installing essential packages after tool installation. Can't remember right now if there's an issue for that).

Again, I guess I understand your use case (and yeah, for things like postgres, I think it'd make sense not to care about the minor version), but I'm still not convinced asdf should do anything of this kind by itself. If it did, you'd also have to have a way to ask asdf what it understands for 2.3 given your local installations. I'd certainly go for for creating the symlinks, either via a hook or a tiny script that just fixes the symlink for the tool.

Actually you could create a gist of such a script as a prove of concept, and it doesn't even have to be in asdf core, it can source all the asdf functions to get the list of installed versions and stuff, and just create the symlink.

I'd like to know what other people think on this matter. I'm just in favor of not adding unnecessary complexity (best code is deleted-or-never-written-code) and keeping asdf as agnostic as possible (keep in mind that every tool can have its own versioning semantics or none at all).

@mwean
Copy link
Contributor Author

mwean commented Sep 12, 2018

Yeah, I think hooks could support what I want to do. I can imagine post-install being useful for a bunch of things

@Stratus3D
Copy link
Member

Stratus3D commented Sep 17, 2018

#216 #226 are two issues related to this. I agree with @vic that this is the sort of thing that doesn't belong in asdf core. Every tool can have it's own versioning quirks. For example, the Erlang plugin has to deal with two version schemes since the way Erlang is versioned changed. There is also no guarantee to that tools will continue to use semantic versioning. In the future new version schemes could become popular. To do this properly we'd have to account for all of this, and handle every scenario correctly. In my experience just trying to sort semantic versions in Bash is hard enough to make me want to avoid this entirely in asdf core (we've even got stuff in the plugin guide about this).

Now there are other solutions to this problem that wouldn't necessarily require this to be implemented in asdf. As @vic said a simple script to create symlinks could achieve what you need. You could also create some sort of "resolver" Bash script that would actually generate the .tool-versions or set the appropriate env variables for your projects based on the state of the project and the tool versions you have installed. Another option is to figure out how to implement this behavior in asdf plugins, without having to make extensive changes to asdf core. Then plugins (like asdf-nodejs) could implement this best-matching version behavior, and others could not, without affecting core.

@fvictorio
Copy link

Another option is to figure out how to implement this behavior in asdf plugins, without having to make extensive changes to asdf core. Then plugins (like asdf-nodejs) could implement this best-matching version behavior, and others could not, without affecting core.

This would be great. Are there plans for doing it? I think it would be especially useful for people that come from nvm, where this is supported.

@vic
Copy link
Contributor

vic commented Jan 19, 2019

@mwean current branch has pre/post install hooks support (#434) . so you can try and use them to create symlinks as mentioned in previous comments.

@mwean
Copy link
Contributor Author

mwean commented Jan 19, 2019

Awesome! I'll give it a try

@azhi
Copy link

azhi commented Feb 20, 2019

Another option is to figure out how to implement this behavior in asdf plugins, without having to make extensive changes to asdf core. Then plugins (like asdf-nodejs) could implement this best-matching version behavior, and others could not, without affecting core.

This would be great. Are there plans for doing it? I think it would be especially useful for people that come from nvm, where this is supported.

+1 for the feature coming from rvm (ruby). It is even more unexpected when legacy_version_file is set to yes, and .ruby-version contains something like 2.6 which worked for rvm but is not working for asdf.

Pre/post install scripts won't fix the issue if no suitable version was installed beforehand. On the other hand, introducing fuzzy matching between version specified in .tool-versions and installed/used version can be unexpected for people who use .tool-versions only with specific versions. Perhaps it is worth adding additional config flag that allows plugins to use this fuzzy behaviour?

Great tool btw, it feels nice to drop rvm/kiex/nvm and use a single version manager 👍.

UPD: actually, right now plugins that support legacy_version_file can introduce some logic that will always pick latest available version when parsing version from legacy file. Downside would be the obligation to update your local version whenever newer patch version is released. @Stratus3D would you be interested in me trying to implement such logic for asdf-ruby?

@dboune
Copy link
Contributor

dboune commented Mar 14, 2019

New user of asdf, and enjoying it. I'd also be pleased to see this. I'd suggest that .tool-versions follow something like is commonly done for "Semantic Versioning" schemes to allow pinning to a specific version, or following minor / patch releases. Naturally it's up to the system owner to install a given version of a tool, but at least one chore can be reduced in a variety of cases.

Use Case

I have a number of small, non-public, nodejs projects that follow minor and patch releases along with an LTS release. They each have docker containers that already does the same. Before a production deploy, or during regular development, I will check the current LTS version, install it, and test. In these cases the specific version isn't terribly important, so long as it is an LTS version. It's very rare that I'd need to pin to a specific version. Using common semver syntax, for example, ^10.13.0 would be sufficient to follow along with the nodejs LTS releases.

Implementation

The semantic versioning "standard" doesn't specify the syntax, only the precedence rules which I would suggest honoring due to common use. For example, RubyGems and npm both have similar syntax, but differ in a few ways, so I don't suggest any particular syntax. Even a comparatively lightweight implementation like azhi references above would be convenient.

Edit: After reading Stratus3D's comment above, if this can be done in the individual plugins, that would be fantastic.

@bjeanes
Copy link

bjeanes commented Apr 2, 2020

Could this perhaps be something that plugins could opt in to doing. I wouldn't want to assume that every language has the same versioning semantics. However, the Ruby plugin could know that 2.5.3 is semantically OB for 2.5 and in the absence of more specific qualifier, is a better choice than 2.5.1.

In other words, the Ruby plugin is best positioned to decide whether it should add a 2.5 symlink to the highest 2.5.x version it is currently managing, because it is the most appropriate component to interpres the semantics of the versions. It would also know not to conflate jruby, REE, rubinius, truffleruby, etc versions.

  • asdf install ruby 2.5.1 - creates 2.5.1 install dir, 2.5 -> 2.5.1 symlink, maybe 2 -> 2.5[.1] symlink
  • asdf install ruby 2.5.3 - creates 2.5.3 install dir, updates 2.5 and possibly 2 symlink to point to it.

This would be consistent with chruby and perhaps others like RVM/rbenv, without opting in all languages to such behaviour.

@bjeanes
Copy link

bjeanes commented Apr 3, 2020

FWIW, I use a tactic like the following for a few langs to build my $HOME/.tool-versions so that by default it just picks the highest one available:

$ asdf list all ruby | 
	grep -vE 'truffle|rbx|ree|jruby|preview|-rc[0-9]|mruby|maglev|-dev' |
	sort -r |
	xargs echo ruby |
	tee -a ~/.tool-versions
ruby 2.7.0 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.7 2.5.6 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.4.9 2.4.8 2.4.7 2.4.6 2
.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 2.2.7 2.2.6 2.2.5 2
.2.4 2.2.3 2.2.2 2.2.10 2.2.1 2.2.0 2.1.9 2.1.8 2.1.7 2.1.6 2.1.5 2.1.4 2.1.3 2.1.2 2.1.10 2.1.1 2.1.0 2.0.0-p648 2.0.0-
p647 2.0.0-p645 2.0.0-p643 2.0.0-p598 2.0.0-p594 2.0.0-p576 2.0.0-p481 2.0.0-p451 2.0.0-p353 2.0.0-p247 2.0.0-p195 2.0.0
-p0 1.9.3-p551 1.9.3-p550 1.9.3-p547 1.9.3-p545 1.9.3-p484 1.9.3-p448 1.9.3-p429 1.9.3-p426 1.9.3-p392 1.9.3-p385 1.9.3-
p374 1.9.3-p362 1.9.3-p327 1.9.3-p286 1.9.3-p194 1.9.3-p125 1.9.3-p105 1.9.3-p0 1.9.2-p330 1.9.2-p326 1.9.2-p320 1.9.2-p
318 1.9.2-p290 1.9.2-p180 1.9.2-p136 1.9.2-p0 1.9.1-p431 1.9.1-p430 1.9.1-p429 1.9.1-p378 1.9.1-p376 1.9.1-p243 1.9.1-p1
29 1.9.1-p0 1.9.0-5 1.9.0-4 1.9.0-3 1.9.0-2 1.9.0-1 1.9.0-0 1.8.7-p72 1.8.7-p71 1.8.7-p375 1.8.7-p374 1.8.7-p373 1.8.7-p
371 1.8.7-p370 1.8.7-p358 1.8.7-p357 1.8.7-p352 1.8.7-p334 1.8.7-p330 1.8.7-p302 1.8.7-p301 1.8.7-p299 1.8.7-p249 1.8.7-
p248 1.8.7-p22 1.8.7-p174 1.8.7-p173 1.8.7-p17 1.8.7-p160 1.8.7 1.8.6-p420 1.8.6-p399 1.8.6-p398 1.8.6-p388 1.8.6-p383 1
.8.6-p369 1.8.6-p368 1.8.6-p36 1.8.6-p287 1.8.6-p286 1.8.6-p230 1.8.6-p114 1.8.6-p111 1.8.6-p110 1.8.6 1.8.5-p52 1.8.5-p
231 1.8.5-p115 1.8.5-p114 1.8.5-p113

@augustobmoura
Copy link
Member

augustobmoura commented Oct 5, 2020

Maybe plug asdf current into a plugin script (maybe bin/resolve-version?) then each plugin provides some version resolution of its own. I hit a similar problem in asdf-vm/asdf-nodejs#176 for implementing compatibility with nvm lts aliases, it will not work in current asdf because they have a / in the text and current asdf versions need to be acceptable directory names. With a custom resolve-query script I could just replace the / with a - and call it a day. Also implement node ranges and what not

@brandondrew
Copy link
Contributor

I'd like to propose a solution that

  1. is very simple
  2. gives the UX benefits that I think the OP is going for (and that I would prefer)
  3. does not require core or any plugins to know the versioning scheme used by a language
  4. does not require any changes to plugins
  5. does not require the user to create scripts or hooks

I think it's best expressed by an example interaction:

$ asdf local ruby 2.3
2 rubies matched '2.3'.  Do you want to use one of these?
  1)  2.3.1
  2)  2.3.7
  0)  Do not use either of these.

There's no need for a knowledge of semantic versioning in core (or anywhere else). It would simply show partial matches when there is no exact match to an interactive command. .tool-versions files would still be expected to contain exact matches. No symlinks would be needed.

@bjeanes
Copy link

bjeanes commented Feb 23, 2021

interesting proposal... when is this prompt displayed if you aren't explicitly choosing a version (for instance, you've cdd to another directory and just run ruby foo.rb. If it prompts then, that might break automation. If it prompts on cd it likely requires aliasing cd or extra shell-specific hooks.

If it is possible to do well given the above, it seems nice. I'd advocate we sort the version list with sort -rV, placing the best guess of the highest version at the top, so it's consistently in the 1 position (the most likely choice, I'd wager).

@jthegedus
Copy link
Contributor

I'd advocate we sort the version list with sort -rV

sort -V is not portable enough for asdf

@brandondrew proposal is interesting 🤔

@bjeanes
Copy link

bjeanes commented Apr 4, 2021

sort -V is not portable enough for asdf

Ah fair enough, though I think one could port the heuristic it uses fairly simply if the outcome was satisfactory.

@brandondrew proposal is interesting thinking

Agreed. Though is this a substring match or a prefix match? Some versions have a "type" prefix, such as ruby's jruby-<version>, rbx-<version>, etc. But I suppose, the MRI versions are still numbered and if somebody needed RBX or JRuby et al, they'd have to reflect that in their .tool-versions anyway

@brandondrew
Copy link
Contributor

@brandondrew proposal is interesting 🤔

@jthegedus Thanks!

@brandondrew
Copy link
Contributor

Agreed. Though is this a substring match or a prefix match? Some versions have a "type" prefix, such as ruby's jruby-<version>, rbx-<version>, etc. But I suppose, the MRI versions are still numbered and if somebody needed RBX or JRuby et al, they'd have to reflect that in their .tool-versions anyway

🤔 I'm not sure what is best... I was thinking of prefixes but may be the the things that match from the beginning can be prioritized and other substring matches can be below... or maybe substring matches only appear if no prefix matches are available? I guess it's open to experimentation...

@brandondrew
Copy link
Contributor

Honestly all the jruby and rbx stuff is clutter to me and I would love a setting to filter all of those out, as though using | grep -v 'rbx|jruby|etc' 🤭

@tobyhinloopen
Copy link

tobyhinloopen commented Jun 11, 2021

I was hoping I could define multiple compatible versions, like this:

node >=16.6.0, >=17.13.0, >=15.1.0

Basically like package.json's dependencies. I think you want to switch to the highest compatible version every time. Also, can ASDF please automatically install the best compatible version? I'm asking too much for an open source / free product maybe :)

@jthegedus
Copy link
Contributor

jthegedus commented Jun 12, 2021

Honestly all the jruby and rbx stuff is clutter to me and I would love a setting to filter all of those out, as though using | grep -v 'rbx|jruby|etc'

You can filter on most commands, eg:

asdf list all java adopt
# or
asdf list all java zulu

# another command
asdf current java

# another command
asdf latest nodejs
# with filter
asdf latest nodejs 14

@jthegedus
Copy link
Contributor

jthegedus commented Jun 12, 2021

I was hoping I could define multiple compatible versions, like this:

node >=16.6.0, >=17.13.0, >=15.1.0

Basically like package.json's dependencies. I think you want to switch to the highest compatible version every time. Also, can ASDF please automatically install the best compatible version? I'm asking too much for an open source / free product maybe :)

It's not that it's too much, it's just antithetical to the purpose of tools like asdf. This convenience of using the best matching version has the possiblity to introduce issues during development which this type of tool was specifically built to address.

So far, I think @brandondrew has proposed the soution that best aligns asdf goals with the underlying benefit the OP is after, though there may be other solutions available to us.

Using latest with global/local currently works (with some plugins, #633 adding universal support) but the filter as I mentioned above does not work:

# works (if the nodejs version is installed)
asdf local nodejs latest

# does not work
asdf local nodejs latest 14

If the filter worked that would somewhat help the situation (I think #633 introduces that). It would also probably make sense to just auto-install the version being added to .tool-versions instead of erroring.

Nonetheless, IMO the idea of using non-specific version in .tool-versions doesn't align with the goals of the tool.

I say all this as the OP of #226

@nealeu
Copy link

nealeu commented Oct 19, 2021

I've just come to asdf and found myself at this ticket having done:

$ asdf install nodejs latest:16
nodejs 16.11.1 is already installed
$ asdf local nodejs latest:16
version latest:16 is not installed for nodejs

From a CI and repeatable builds point of view, I can see a reason for enforcing an exact version.
From the point of view of having multiple projects across an organisation, or where team members may work on different projects for different organisations, I'd like some flexibility.

Perhaps the way to go would be to allow developer workstations to be lax, but CI to be exact. This is done well in the npm ecosystem via yarn.lock and package-lock.json, but could be done much more concisely here:

asdf install nodejs latest:16   # right now installs nodejs 16.11.1
asdf local nodejs latest:16 # succeeds by detecting that the current latest:16 is installed and updates .tool-versions

This would result in .tool-versions:

nodejs latest:16 16.11.1

And if using asdf in CI, then we should then be able to have

asdf install nodejs

and it'll install version 16.11.1

As a newbie, I wonder whether I'm missing something here?

Edit: And for the java projects I work on I really would not want to have multiple versions of each of Java 11 or Java 17 which starts getting rather bloated (although the total size of node_modules across various projects on my system has redefined the term bloat 😭 )

@stephanedaviet
Copy link

stephanedaviet commented Dec 20, 2021

After having read carefully the whole thread, it seems that there are some subtle differences between the needs of the different users here. To sum up what I have grasped so far:

  • The spirit behind ASDF is to ensure reproductible builds with exact version for each tool,
  • Those exact versions are expressed in .tool-versions, quite much as it's done by some package managers for dependencies of a project (package.json for npm/yarn, pom.xml for Maven, etc.),
  • This reproducibility is particularly useful in a continuous integration process (following the principle: the same causes produce the same effects),
  • On a developer workstation, the benefit of reproducibility should be balanced with other ones: space and speed. It can be acceptable to use a “best-matching” version of the tool, exempting to have to install a perfect match when an acceptable one is already available (gain in time for installation and space on disk),
  • Relying on semver to convey this notion of acceptable match (like it's done in nvm or jenv), isn't the way to go, as not every tool comply with the semantic versioning convention.

The example of npm/yarn and its package-lock.json is interesting and can be inspiring. Perhaps, ASDF can have some kind of convention to indicate the range of acceptable matches in the .tool-versions file and some fixed versions in a .tool-version.lock file that can be used for continuous integration (or other use aiming for reproducibility). We could imagine various way to describe the range of best-matches:

  • semantic version one: ~1.2.3, ^1.2.3, >=1.2.3 <1.3.0,
  • latest semantic: latest (let's go for that 😉 ),
  • Maven like syntax: [1.2.3,1.8.7),
  • natural ordering syntax: >=1.2.alpha-3,
  • regex: 1.2.[\d]+.

The benefits are obvious on the developer workstation, as already stated above. Moreover, it could bring quite easily to ASDF some missing (or tricky to achieve) features that can be found in other version managers (jenv for instance):

  • Use of an already provided system installation,
  • Auto-update of installed tool (linked to the latest, because it can be based on the update of the installed package brought by the system). This latest point is very useful when taking security patches into account.

Latest note, this lack of “best-matching version” is for me something that still brings my preference to other version managers over ASDF on my workstation (jenv and nvm in my case).

@augustobmoura
Copy link
Member

augustobmoura commented Dec 20, 2021

  • On a developer workstation, the benefit of reproducibility should be balanced with other ones: space and speed. It can be acceptable to use a “best-matching” version of the tool, exempting to have to install a perfect match when an acceptable one is already available (gain in time for installation and space on disk),

The reproducibility point still applies to workstations though (the classic "works on my machine" problem).

The example of npm/yarn and its package-lock.json is interesting and can be inspiring. Perhaps, ASDF can have some kind of convention to indicate the range of acceptable matches in the .tool-versions file and some fixed versions in a .tool-version.lock file that can be used for continuous integration (or other use aiming for reproducibility). We could imagine various way to describe the range of best-matches:

I mentioned the usage of .lock files on #523 (comment) some time ago.

I still prefer to have a custom hook for each tool. Semver works really well for node.js but not so much for other languages. There are also different tags in different stacks (latest, lts, nightly, etc). There are so much different aspects that I don't see asdf giving a good default for all of them.

I'm my opinion asdf in general is hardly a tool for CI/CD. We already have good ways of versioning environments (be it containers or platform-specific pipeline configuration), environments hardly need to switch tool versions between directories/contexts. I think we should focus primarily on developer experience and versatility. Being a universal tool versioning manager means just being flexible enough for all these different tools and use cases

@stephanedaviet
Copy link

stephanedaviet commented Dec 20, 2021

+1 for your mention on .lock files.

To make it short and simple, given two developers, one with NodeJS 16.9.1 on his workstation, the other with NodeJS 16.12.0, being able to get the same project working with a simple asdf local nodejs 16 is just super convenient. Yes, it brings some reproducibility risks, but it's greatly counterbalanced by the comfort it brings, the speed of the setup and the gain in space on the workstation.

OK, in my example, it's NodeJS and it's based on a semver logic, but my proposals try to give some lead on the different ways to comply with this need.

To be honest, not being able to do that is, according to me, a weakness of ASDF compared to other version managers.

I don't really see how it can be efficiently handle by plugins or hooks. Perhaps you can give me some helpful feedback of why I may be wrong and some acceptable compromises that I missed.

@augustobmoura
Copy link
Member

I don't really see how it can be efficiently handle by plugins or hooks. Perhaps you can give me some helpful feedback of why I may be wrong and some acceptable compromises that I missed.

You are not wrong, you can't be wrong in expressing your opinion. I was just adding something extra from my side.

I did mention the idea of a .lock file in the past (and I still see them helpful, for checksums and other metadata), but I'm not sure today if we should have dynamic ranges in the .tool-versions file. We can add tags/aliases to asdf install and other commands however. This is the direction that I think this thread is going.

Pinning on a version is not that hard. For example, if your project only works on node 16.x you can pin it to the latest version for that major version (16.13.1), and everyone will get the same version. So what are the benefits of having a dynamic version over a pinned version? I only see automatic updates for bug fixes and skipping some bits of commits when changing .tool-versions to a newer version. But even those are very easily fixable with just bumping the version on .tool-versions

@stephanedaviet
Copy link

stephanedaviet commented Feb 10, 2022

We can add tags/aliases to asdf install and other commands however. This is the direction that I think this thread is going.

Sorry for my misunderstanding, but I don't grasp your proposal here. What do you suggest by using tag or aliases and how it answers the concern I have explained?

So what are the benefits of having a dynamic version over a pinned version?

It's just something super handy when you get some developers with some slightly different minor/patch versions of the build/run tools on their workstations.

For instance, when you have some automatic security updates on your workstation, a new minor/patch version can be automatically installed. In the case where you will be able to use an already provided system installation (see the benefits in my first message), your build/run can suddenly stop working with the requirements of ASDF-VM.

I concede that when you install the exact version through ASDF-VM for each product you work on, you don't get this problem, but it can be very tedious and hog a lot of disk space with a lot of different but almost identical versions of the same tool.

It's precisely this concern that make me post at first (again, it's detailed in my last comment).

@iFreilicht
Copy link

Maybe one way to "easily" fix this would be to create symlinks to the latest version? I tried this as a workaround for compatibility with .nvmrc files, and it worked great!

So, whenever a version of something is installed, asdf could try to parse the version of that tool as a semver (17.8.0), and after installing it to .asdf/installs/<tool-name>/17.8.0, it also links to that directory with the symlinks .asdf/installs/<tool-name>/17.8 and .asdf/installs/<tool-name>/17. This would also work for something like CalVer.

This requires only an additional step after installing a tool, no change in logic during installation or shimming.

Using symlinks to manage tool versions is how the nix package manager handles things, too, and it seems quite elegant to me.

@mpql
Copy link

mpql commented Oct 23, 2023

To throw my own use case onto the pile, consider:

  • Python 3.10 is just releasing maintenance / security patches at this point.
  • I'm entering the project for an inherited codebase that specifically requires Python 3.10
  • I pinned latest:3.10 at a time when that resolved to 3.10.12
  • I've since upgraded my 3.10 to 3.10.13, and uninstalled 3.10.12

Desired behavior:

  • Specify e.g. asdf local python <version>, with version being something like one of:
    • 3.10
    • latest:3.10
    • ^3.10.12

Actual behavior:

  • asdf resolves python at the time of version pinning, python pinned at 3.10.12.
  • Trying to run python results in my environment unable to find it
  • Current workaround would require me to update every single .tool-versions file for every project where I may wish to run a specific minor point version of any patch.

I have to think far more use cases would benefit from more flexible version pinning, as opposed to necessarily experiencing dependency rot for want of an >= feature.

@Dogacel
Copy link

Dogacel commented Dec 26, 2023

This is a serious issue. I already have tons of different Java installations because this feature is lacking.

No preset version installed for command java
Please install a version by running one of the following:

asdf install java adoptopenjdk-11.0.11+9

or add one of the following versions in your config file at ...
java corretto-11.0.14.9.1
java corretto-11.0.15.9.1
java corretto-11.0.16.8.3
java corretto-11.0.16.9.1
java corretto-11.0.17.8.1
java corretto-17.0.4.9.1
java corretto-17.0.8.7.1
java corretto-8.292.10.1
java corretto-8.342.07.3
java openjdk-21
java temurin-17.0.7+7
make: *** [compile] Error 126

I work with many projects, and I don't mind the minor versions of those Java versions. I only do care about the major, i.e. 11, 17 etc. Not having this feature makes me want to disable this tool for multi-project workflows. I don't want to install a 6th version of java-11 into my machine.

@lilbobbytable
Copy link

@Dogacel just use rtx

@iFreilicht
Copy link

It's not called rtx anymore, but that is actually a pretty good suggestion. See mise.jdx.dev

@enebo
Copy link

enebo commented Jun 12, 2024

I am new to this tool and I am wondering how possible it would be to allow .tool_versions to accept a variable like:

Instead of:

java adoptopenjdk-8.0.412+8

This could perhaps be:

java adoptopenjdk-${MY_JAVA_8_VERSION}

Those of us which support dozens of libraries would then only have to update a single env when we update our Java runtimes. CI would need to define whatever variable we would define but that would also allow us to lock version for reproducibility without forcing all local dev envs to lock step update. As someone else has mentioned (for Java at least) minor patch releases tend to not be so important for Java.

@kennyp
Copy link
Contributor

kennyp commented Jun 12, 2024

You can do that by setting ASDF_JAVA_VERSION to the version you want instead of using .tool-versions

@enebo
Copy link

enebo commented Jun 13, 2024

@kennyp I support some number of projects using Java 8 and others using a more modern version so I guess I could do this with some hook via cd?

I was just thinking for Ruby and Java (two things I use) making .tool-versions eval the contents would allow people to:

  1. commit something which would not break other people who check things out (so long as they also maintain their own env)
  2. CI would still be consistent and reproducible at the cost of an extra env value
  3. for many projects we would still have to update when we get a new version but it will only be in a single place
  4. If you don't do this it works as it currently does so you opt in

So the idea is not best matching but it does feel like an alternative which would take most of the sting out of the need for this issue.

@mpql
Copy link

mpql commented Jun 13, 2024

@enebo You could use direnv or similar to achieve that cd-hook effect, but in order to both address the problems this issue is about, and stuff like your issue, I've switched to mise-en-place. It's generally faster, and far more intuitive. That link is a comparison to asdf; I highly recommend it.

P.S. mise also replaces direnv functionality, and it works great.

@bsalesc
Copy link

bsalesc commented Jul 20, 2024

Couldn't be start simple and check if matches a single version that starts with that input?

$ asdf list python
  2.7.18
  3.1.5
> 3.2.0
  3.2.1

In which I could asdf global python 2 and as I've 2.7.18 installed and it's the only one that starts with 2, then that's the version, if I want 3, I need to be more specific, asdf global python 3.1, asdf global python 3.2.0 or asdf global python 3.2.1

This way it could work easily for other plugins that don't have semantical versions.
asdf global java openjdk-18 matches openjdk-18.0.2.1 and it's the single one so will use that.

I was playing around to see if I could get something working and made a PR here

@ssbarnea
Copy link

ssbarnea commented Oct 3, 2024

The need for this is quite high and I reached a point where I really consider writing a script that can perform the action of updating tool versions. My primary need is for python, and I use multiple versions of python, but I do not want to get behind. New releases happen quite often, almost monthly, for each major python version.

PS. I have 7 python versions in my global .tool-versions, I don't want to have hire someone to keep the file update ;)

python 3.12.7 3.11.10 3.10.15 3.9.18 3.8.18 3.7.17 3.13-dev

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

Successfully merging a pull request may close this issue.