asdf icon indicating copy to clipboard operation
asdf copied to clipboard

[Feature Request] Separate "restrict to version X" and "install version X" functionalities

Open DerekTBrown opened this issue 1 year ago • 2 comments

Is your feature request related to a problem? Please describe

User Story

  • As a user, I want to be able to enforce that all sub-folders in a given repository use Python X.X.X, but I don't want to require users to install Python X.X.X when they run asdf install in the root of the repository: I only want installation to happen when users run asdf install in a project sub-folder.
  • This feature is critical for working in multi-langauge repositories: it prevents users from having to download a huge toolchain whenever they are working on a specific project.

Describe the proposed solution

Introduce two features:

  1. noinstall Following a version in a .tool-versions file, a user can add noinstall:
golangci-lint 1.59.1 noinstall

This line is functionally skipped when running asdf install

  1. inherit In place of a version in a .tool-versions file, a user can specify inherit:
golangci-lint inherit

Since this doesn't have the noinstall flag, the parent version would be installed.

Describe similar asdf features and why they are not sufficient

asdf doesn't have this functionality today.

Describe other workarounds you've considered

  • Creating separate linters that look at .tool-versions file. This is clumsy.

DerekTBrown avatar Jul 03 '24 16:07 DerekTBrown

asdf resolves tools in .tool-versions files by walking from the current working directory to the root /, using the closest definition as the requirement. Therefore, you can have .tool-versions files in the sub-directories and only require people to asdf install those when working in sub-directories.

We do this in this repo.

# .tool-versions
bats 1.8.2
shellcheck 0.9.0
shfmt 3.6.0
# docs/.tool-versions
nodejs 20.2.0

when in the repository root, asdf doesn't know about nodejs in the docs/ directory.

~/asdf $ asdf current
bats            1.8.2           ~/asdf/.tool-versions
nodejs          ______          No version is set. Run "asdf <global|shell|local> nodejs <version>"
shellcheck      0.9.0           ~/asdf/.tool-versions
shfmt           3.6.0           ~/asdf/.tool-versions

~/asdf $ cd docs

~/asdf/docs $ asdf current
bats            1.8.2           ~/asdf/.tool-versions
nodejs          20.2.0          ~/asdf/docs/.tool-versions
shellcheck      0.9.0           ~/asdf/.tool-versions
shfmt           3.6.0           ~/asdf/.tool-versions

~/asdf/docs $ cd ..

~/asdf $ asdf install
bats 1.8.2 is already installed
shellcheck 0.9.0 is already installed
shfmt 3.6.0 is already installed

# NOTE: nodejs is completely ignored since we are not in ~/asdf/docs/

Does this not do what you want?

jthegedus avatar Oct 07 '24 15:10 jthegedus

Does this not do what you want?

Not quite.

The purpose of the proposed feature is to make it easier to keep versions consistent (i.e. all sub .tool-versions use the same version of a given dependency) without actually enforcing that a given dependency is installed. Right now, you have to choose one or the other:

[Option 1] Specify version once in root .tool-version

✅ Makes it easy to keep versions consistent (just don't specify .tool-versions in sub-dirs). ❌ Python is installed, even in non-Python projects.

$ cat .tool-versions
python 3.12.3

$ cd ./non-python-project
$ cat .tool-versions
<empty>
$ asdf install
<installs python> 

[Option 2] Specify versions separately in sub-directory .tool-versions

✅ Python is only installed in projects which require Python in .tool-versions. ❌ Nothing keeps versions consistent. User must install linter to validate .tool-versions and perform codemods to keep versions up-to-date.

$ cat .tool-versions
<empty>

$ cd ./python-project-1
$ cat .tool-versions
python 3.12.3
$ asdf install
<installs python 3.12.3>

$ cd ../python-project-2
$ cat .tool-versions
python 3.12.7
$ asdf install
<installs python 3.12.7>

[Proposed] Specify version and installation separately

✅ Python is only installed in projects which require Python in .tool-versions. ✅ Makes it easy to keep versions consistent (.tool-versions merely need to specify inherit).

$ cat .tool-versions
python 3.12.3 noinstall

$ cd ./non-python-project
$ cat .tool-versions
<empty>
$ asdf install
<nothing installed>

$ cd ./python-project-1
$ cat .tool-versions
python inherit
$ asdf install
<installs python 3.12.3>

$ cd ../python-project-2
$ cat .tool-versions
python inherit
$ asdf install
<installs python 3.12.3>

DerekTBrown avatar Oct 16 '24 19:10 DerekTBrown

Sorry for the late reply here @DerekTBrown. I don't think we have a perfect solution for you. There are a couple things I think could work:

1. Symlink .tool-versions files

The issue you pointed out with your "Specify versions separately in sub-directory .tool-versions" option is that you'd have to manually update multiple .tool-versions files every time you updated a Python version. Symlinks would allow you to re-use the same .tool-versions file in multiple directories. The downside of course is you have to create links to one "global" .tool-versions for all your projects.

2. Use the system version in sub-directories

With your proposal you don't want versions defined in parent directories to be available in child directories. A workaround for this is to specify a python version of system in the .tool-versions file. This will tell asdf not to use the version from the parent directory, but rather use the version of Python on your system that was not installed via asdf. If you don't have a system-installed Python this will result in no version being available.

3. Organize by tools

If you have a bunch of projects that all need the same Python version put them in the same directory:

~/my-dev/python/
      project-1/
      project-2/

3. Write a script to keep your .tool-versions in sync

Writing a small shell script to find .tool-versions and update them manually. Probably not what you wanted to hear but something along these lines should work:

while IFS= read -r -d '' dir; do
	(cd "$dir" && asdf set python "$new_python_version")
done < <(find "$YOUR_DIR" -type f -name "*.tool-versions")

Inheritance of versions in parent directories has always been a core feature of asdf's version resolution mechanism. It's not something we are going to change. Hope the above suggestions help.

Stratus3D avatar Mar 17 '25 21:03 Stratus3D