Cover image for Pixi Global: Declarative Tool Installation

Pixi Global: Declarative Tool Installation

Julian Hofer
Written by Julian Hofer 2 months ago

TL;DR: Think Homebrew, but cross-platform and easy to share with collaborators.

During my Physics bachelor's, I started using Fedora Linux as my daily driver. Most tutorials recommended installing applications via the command line, so I quickly adopted that practice. On Linux, package managers handle both system libraries and user applications, which seems convenient—until you accidentally remove the wrong package and break your entire system.

For non-Linux systems, there are other alternatives such as homebrew, scoop, or pipx. Each of them has its own strengths and weaknesses:

  • Homebrew works very well on macOS and also has Linux support. However, it doesn't always offer older versions of packages, doesn't support Windows, and installs packages into a single global environment.
  • Scoop is fine for Windows but doesn't support macOS or Linux.
  • pipx works well on macOS, Linux and Windows. However, PyPI primarily hosts Python packages, so most non-Python tools are not available there.

With pixi, we are trying to address these shortcomings with a single tool! Pixi is very fast (written in Rust), does not require administrative privileges, and supports all major operating systems. With the subcommand pixi global, you can install a wide variety of packages globally on your system without worrying about breaking anything.

Unless you specify otherwise, pixi global will download your requested packages from conda-forge. Here are a few tools that are available in the conda-forge distribution:

  • Languages such as Python, R, NodeJS, Rust, Go, and C/C++ compilers
  • Developer tools such as ripgrep, gh, starship and nushell
  • Text editors such as helix, neovim, and nano
  • Other package managers such as pipx, micromamba, and more

Let's Get Started with the New Pixi Global

Running the following command installs rattler-build on your system.

pixi global install rattler-build

Every action is recorded in a manifest file in TOML format. This makes it easy to share your setup with other people.

Running pixi global edit opens the manifest in your editor.

version = 1
 
[envs.rattler-build]
channels = ["conda-forge"]
dependencies = { rattler-build = "*" }
exposed = { rattler-build = "rattler-build" }

You can check out the docs or run pixi info to locate the manifest on your system. Then, share the manifest with your colleague and ask her to:

  1. Place your manifest in the location given by pixi info.
  2. Run pixi global sync.

Voilà! She now has rattler-build set up on her system.

Note

By running command line instructions to modify the manifest, pixi global combines the simplicity of imperative commands with the predictability of declarative specifications. However, you can also directly edit the manifest and run pixi global sync to synchronize changes. This allows for seamless integration with version control systems like git and automation tools like ansible.

Adding Dependencies

What's great about pixi global is that, by default, it isolates each package in its own environment, exposing only the necessary entry points. This means you don't have to worry about removing a package and accidentally breaking seemingly unrelated packages. This behavior is quite similar to that of pipx.

However, there are times when you may want multiple dependencies in the same environment. For instance, the keyring package allows you to access the system keyring service from Python. If you want to use the Google Cloud backend, you'll need the keyrings.google-artifactregistry-auth package to be present in the same environment.

Let's install both packages by running the following command:

pixi global install keyring --with keyrings.google-artifactregistry-auth

This is how the relevant part of the manifest then looks like:

[envs.keyring]
channels = ["conda-forge"]
dependencies = { keyring = "*", "keyrings.google-artifactregistry-auth" = "*" }
exposed = { keyring = "keyring" }

As you can see, only keyring has been exposed. Even if the keyrings.google-artifactregistry-auth would contain entry points, --with wouldn't expose any of them.

Global Environments

Instead of recreating a conda-like workflow with pixi, we typically recommend giving pixi projects a try first. However, for quick experimentation, it is very useful to have a global environment at your disposal.

Let's say we want to install jupyter and ipython, with the common dependencies numpy and matplotlib.

pixi global install jupyter ipython --environment science --with numpy --with matplotlib

This will create an environment called science with the aforementioned packages in it.

Running the command adds the following to the manifest:

[envs.science]
channels = ["conda-forge"]
dependencies = { jupyter = "*", ipython = "*", numpy = "*", matplotlib = "*" }
exposed = { jupyter = "jupyter", ipython = "ipython", ipython3 = "ipython3" }

We can now access both numpy and matplotlib when using ipython or jupyter.

Install Multiple Versions of a Package

It is quite common to try your code with multiple versions of your language toolchain. The problem is that even though the versions differ between packages, they often still contain entry points of the same name. We can avoid that by installing them in different environments and exposing them under different names.

By passing --expose, we can not only specify which entry points to expose but also under which name to expose them.

pixi global install python=3.10 --environment python3-10 --expose python3.10=python
pixi global install python=3.11 --environment python3-11 --expose python3.11=python

After running the commands above, we have python3.10 and python3.11 available on our system.

Adding Missing Software

At prefix, we really like the conda-forge channel. If possible, our advice is to add missing packages there — it is fully open source and anyone can contribute recipes to the community!

However, sometimes that is not feasible, and for that reason, you can also easily make your own package channels with your bespoke packages and share them with your friends or team members.

Coincidentally, we at prefix.dev offer hosting for public and private conda channels. Even private channels are free while we are still in the beta phase.

Let's see how we can take advantage of this with pixi global.

pixi global install tealdeer --channel https://prefix.dev/rust-forge

tealdeer (tldr) is now installed from the rust-forge channel on prefix.dev. To understand how the magic happens, you can check out the channel sources on Github wolfv/rust-forge.

Outlook

pixi global is very useful as is, but people have already identified a couple of potential features to add. Adding support for PyPI packages is an obvious next step. We are also considering adding a lock file.

If you like what you read here, we encourage you to give pixi global a try. Also, please tell us about your favorite CLI tools. If you are missing some of them on conda-forge, we are happy to help you get them on conda-forge. You can join our Discord and have a chat about your workflow or open issues on GitHub.