asdf Version Manager

repository·master·Indexed 12 days ago

https://github.com/asdf-vm/asdf

A universal version manager that allows developers to manage multiple language runtimes through a single CLI using a plugin-based architecture. It provides a unified CLI for installing and switching runtime versions on a per-project basis using a .tool-versions file, and supports legacy configuration files like .nvmrc and .ruby-version.

Tokens
19.1K
Snippets
76
Records
116
Agent score
91%

What's inside asdf

  1. Overview of asdf version manager

    master

    asdf is a single CLI tool designed to manage multiple language runtime versions on a per-project basis. Instead of installing separate version managers for every language (like nvm for Node.js, pyenv for Python, or rbenv for Ruby), you use asdf and extend its functionality by installing language-specific plugins.

    Key features include:

    • Unified CLI: Consistent commands across all managed languages.
    • Project-specific configuration: Uses a .tool-versions file in your project directory to define required versions.
    • Automatic switching: Automatically switches the active runtime version as you navigate between directories.
    • Compatibility: Supports existing configuration files like .node-version, .nvmrc, and .ruby-version for easier migration.
    • Extensibility: A simple plugin system allows users to add support for any language or tool.
  2. Core features of asdf

    master

    asdf provides several key capabilities for managing development environments:

    • Plugins: A large ecosystem of existing runtimes and tools. You can add support for new tools via a plugin API.
    • One Config File: Use a .tool-versions file to manage all your tools, runtimes, and their versions in a single, sharable location.
    • Backwards Compatibility: asdf supports existing configuration files like .nvmrc, .node-version, and .ruby-version to facilitate smooth migrations.
    • Shell Support: Works with Bash, ZSH, Fish, and Elvish, including shell completions.
    • CI/CD Integration: Provides a GitHub Action to install and utilize your .tool-versions within GitHub Actions workflows.
  3. Explore asdf community projects

    master

    Beyond the core asdf repository, several community-driven projects exist to extend or support your workflow:

    • asdf-community: A collaborative project focused on the long-term maintenance of asdf plugins.
    • asdf dev container: A GitHub Dev Container implementation that supports asdf-managed tools, specifically designed for use in GitHub Codespaces.

    Note: These projects are not owned or maintained by the asdf core team. The core team is not responsible for their quality or security.

  4. Overview of asdf plugin scripts

    master

    asdf plugins are Git repositories containing executable scripts in a bin/ directory. These scripts are invoked by the asdf CLI to manage tool versions.

    Required Scripts:

    • bin/list-all: Lists all installable versions.
    • bin/download: Downloads source/binary to a specific location.
    • bin/install: Installs the tool to the target path.

    Recommended/Optional Scripts:

    • bin/latest-stable: Returns the latest stable version.
    • bin/help.overview: Provides a general description of the tool.
    • bin/help.deps: Lists OS-specific dependencies.
    • bin/help.config: Shows configuration info.
    • bin/help.links: Lists relevant URLs.
    • bin/list-bin-paths: Defines directories for shim creation.
    • bin/exec-env: Prepares the environment for running binaries.
    • bin/exec-path: Returns the executable path for a version.
    • bin/uninstall: Removes a specific version.
    • bin/list-legacy-filenames: Handles legacy version files (e.g., .ruby-version).
    • bin/parse-legacy-file: Custom parser for legacy files.
    • bin/post-plugin-add / bin/post-plugin-update: Hooks for plugin lifecycle.
    • bin/pre-plugin-remove: Hook before plugin removal.
  5. What is asdf and how does it work?

    master

    asdf is a tool version manager that uses a single configuration file, .tool-versions, to manage multiple runtimes and tools. Instead of using separate managers for every language (like nvm for Node or rbenv for Ruby), you use asdf with a plugin for each tool.

    Core Mechanism: Shims

    asdf works using shims. When you install a tool via an asdf plugin, the plugin creates shims for the tool's executables. When you run a command, the shim intercepts the call, checks the .tool-versions file in your current directory (or parent directories) to identify the required version, and then executes the correct version of that tool.

  6. Use Custom Shim Templates

    master

    By default, asdf uses a standard shim template for executables. However, if a plugin contains a file at shims/<executable_name>, asdf will use that specific file as the shim instead of the standard template.

    Warning: This is an advanced feature and should only be used if absolutely required (e.g., when an executable must also be valid source code, like in the Elixir plugin).

  7. Requirements for plugin extension commands

    master

    Because asdf 0.16.0+ is a Go binary that uses syscall.Exec to run extension commands, plugin developers must ensure their commands meet these requirements:

    1. Must have a shebang line: Scripts without a proper shebang (e.g., #!/bin/bash) will fail because they cannot be executed via syscall.Exec.
    2. Must be executable: The command files must have executable permissions set.
    3. Can be any language: Extension commands can now be binaries or scripts in any language (no longer restricted to Bash).
    4. Argument handling: Only the first argument after the plugin name is used to determine which extension command to run. Subsequent arguments are passed to that command.
  8. Understand `.tool-versions` version requirements

    master

    The .tool-versions file requires exact versions for every tool. To ensure deterministic and consistent environments across different machines and time, asdf forbids the following in .tool-versions files:

    • Version ranges (e.g., ^1.2.0)
    • Special values like latest (though latest may be used in CLI commands like asdf set <tool> latest)

    Think of .tool-versions as a lockfile (like package-lock.json or Gemfile.lock).

    Exception: The system value is permitted. Using system effectively disables asdf for that specific tool in that directory, allowing the version installed on your host OS to be used.

  9. Extend asdf behavior with Plugin Hooks

    master

    You can execute custom code by defining environment variables that follow specific naming patterns. These hooks can run before or after plugin installations, reshimming, updates, or command executions.

    Supported Hook Patterns

    PatternDescription
    pre_<plugin_name>_<command>Runs before a specific plugin command (e.g., pre_foo_bar).
    pre_asdf_download_<plugin_name>Runs before a plugin downloads something.
    {pre,post}_asdf_{install,reshim,uninstall}_<plugin_name>Runs around install/reshim/uninstall. $1 is the full version.
    {pre,post}_asdf_plugin_{add,update,remove,reshim}Runs around plugin management. $1 is the plugin name.
    {pre,post}_asdf_plugin_{add,update,remove}_<plugin_name>Runs around specific plugin management.

    Example

    To run a command before executing bar in a plugin named foo:

    pre_foo_bar = echo Executing with args: $@
  10. Understand the difference between asdf and package managers

    master

    It is important to distinguish asdf from system package managers:

    • asdf vs. Homebrew/NixOS: asdf is a tool version manager, not a package manager. It does not manage upstream dependencies or the entire dependency tree of a tool. It only manages the specific versions of the tools you explicitly install via plugins.
    • asdf vs. direnv: asdf does not manage environment variables. If you need to load/unload environment variables based on your directory, you should use direnv (or the asdf-direnv plugin).
  11. Implement internationalization (i18n) for the documentation

    master

    The documentation site uses VitePress's built-in i18n support. To add or manage locales, follow these two requirements:

    1. Configure Locales: Define the supported locales in docs/.vitepress/config.js. Each locale entry must include a label, lang, and references to its specific nav and sidebar configurations (imported from navbars.js and sidebars.js).
    2. Directory Structure: Markdown content for a locale must reside in a folder named exactly after the key used in the locales object in config.js. For example, if the locale key is pt-br, the files must be in docs/pt-br/.

    Example Directory Structure:

    docs
    ├─ README.md
    ├─ foo.md
    └─ pt-BR
       ├─ README.md
       └─ foo.md
    // docs/.vitepress/config.js
    export default defineConfig({
      locales: {
        root: {
          label: "English",
          lang: "en-US",
          themeConfig: {
            nav: navbars.en,
            sidebar: sidebars.en,
          },
        },
        "pt-br": {
          label: "Brazilian Portuguese",
          lang: "pr-br",
          themeConfig: {
            nav: navbars.pt_br,
            sidebar: sidebars.pt_br,
          },
        },
      },
    })
  12. How asdf shims work

    master

    asdf works by placing a shims directory (default ~/.asdf/shims) on your $PATH. This directory contains simple wrapper programs (shims) for every executable in your installed packages.

    When you run a command, the shim calls asdf exec, which:

    1. Determines the correct version (via .tool-versions or environment variables).
    2. Finds the final path to the executable.
    3. Sets up the environment (via the plugin's exec-env script).
    4. Executes the program.

    Important: Because shims use exec, they cannot be used to source shell scripts. If you need to source a script from an asdf-managed package, use asdf which or asdf where to find the actual path.

    # Get path to the main executable in the current version (for sourcing)
    source $(asdf which ${PLUGIN})/../script.sh
    
    # Get path to the package installation directory
    source $(asdf where ${PLUGIN})/bin/script.sh