While Rust tools and applications can be managed by package managers like Homebrew, most can be installed with Cargo. However, we must then ask: how can we manage to keep track of those tools and applications and update them accordingly? Let’s talk about it.
Disclaimer Link to heading
The original title of this post used the word “binaries” instead of “tools and applications”, but since this post is meant to be a starting guide, I decided to use the latter.
After all, if you are reading this, you are likely used to using cargo install
to install tools like gfold
(shameless plug). I suspect many users would refer to most of what they have installed via Cargo to be “tools and applications”.
Thus, we’ll be referring to what we are managing as “tools and applications”.
One more thing before we continue: folks reading this may prefer using their system’s package manager or something all-encompassing, like topgrade. This guide is aimed at those using Cargo and meant to be flexible with multiple workflows. There is no one way to manage Rust tools and applications. Feel free to pick and choose what you like from this guide.
Choosing to Use the Locked Flag Link to heading
Let’s start by installing gfold
with cargo install
.
cargo install gfold
This is great and works well.
It does especially so for multi-platform use!
However, we can modify it a bit by using the --locked
flag.
What does the --locked
flag do?
“By default, the
Cargo.lock
file that is included with the package will be ignored. This means that Cargo will recompute which versions of dependencies to use, possibly using newer versions that have been released since the package was published. The--locked
flag can be used to force Cargo to use the packagedCargo.lock
file if it is available.”
Alright, so whether or not we use the flag is preferential. There are benefits and detriments to each approach, so let’s see what the docs have to say.
“This may be useful for ensuring reproducible builds, to use the exact same set of dependencies that were available when the package was published. It may also be useful if a newer version of a dependency is published that no longer builds on your system, or has other problems. The downside to using
--locked
is that you will not receive any fixes or updates to any dependency.”
Essentially, the --locked
flag ensures reproducible-ish builds by using the dependencies specified in Cargo.lock
(if found).
I prefer to use to --locked
flag despite missing out on potential bug fixes, performance improvements and security updates to dependencies.
This preference stems from my desire to have my experience using the tool or application to match that of the upstream developer’s experience and intentions, which translates to using the dependencies they tested with and included in hosted binaries (e.g. binaries on GitHub Release pages).
For the remainder of this post, I’ll use the --locked
flag, but as you are following along, please feel free to drop the flag wherever you’d like.
cargo install --locked gfold
One thing to keep in mind: we can mix and match which binaries we want installed with the flag. It does not have to be all or nothing! We’ll touch on how to do that later.
Ensuring Tools and Applications are Up to Date Link to heading
Now, you have gfold
installed, but we have a new problem: how do we make sure it is up to date?
We will use the excellent cargo-update to do so.
Let’s install it.
cargo install --locked cargo-update
This tool checks if an installed binary (via cargo install
) has a newer version available and will update it accordingly.
It also has the ability to update all installed binaries (via cargo install
) by using the -a/--all
as well as force install (i.e. re-install) selected binaries by using the -f/--force
flag.
We’ll want the former behavior in order to accomplish our overall goal.
Therefore, though we have only installed gfold
thus far, let’s update all potential tools and binaries installed.
cargo install-update -a
Before we continue to the next section, let’s say you want to ensure some dependencies are updated with respect to Cargo.lock
and others are not.
We can use another Cargo subcommand that comes with cargo-update
.
cargo install-update-config --enforce-lock <PACKAGE>
With the above command, we can toggle settings for how individual tools and applications are updated.
There are more tweaks you can perform and I recommend passing in the --help
flag to see what matches your preferences.
Creating a List of Installed Tools and Applications Link to heading
Some people like to maintain state of what their package managers have installed via files.
- For example, you can use Brewfiles, which are leveraged by
homebrew-bundle
to bundle non-Ruby dependencies for use with the Homebrew package manager. - Another example: you can execute
dnf repoquery --userinstalled --queryformat "%{NAME}" > packages.txt
on Fedora to display a list of user installed packages with the dnf package manager and redirect the output to a text file.
Similarly to the dnf
example, we will manage a crates.txt
file that contains out installed tools and applications.
When doing so, let’s use the multi-platform ripgrep instead of grep
for our Windows friends.
cargo install --locked ripgrep
Side note: For Windows and PowerShell users, I have been using
pwsh
on macOS in addition tozsh
throughout this post. I’ve tried to ensure multi-platform snippets and PowerShell-specific snippets work on your system, but I apologize for any inefficiencies or missed edge cases you may encounter.
Now, we can parse through the output of cargo install --list
in order to create a clean list of every installed tool and application by name.
cargo install --list | rg -o "^\S*\S" > crates.txt
Look below for the contents of my crates.txt
on the machine I’m writing this post on.
Yours will likely look different!
bat
bottom
cargo-audit
cargo-bloat
cargo-expand
cargo-fuzz
cargo-msrv
cargo-nextest
cargo-udeps
cargo-update
cargo-watch
cargo-whatfeatures
cross
exa
fd-find
ferris-fetch
gfold
git-cliff
kubie
nu
onefetch
procs
ripgrep
starship
tokei
tokio-console
toml2json
We can put this file somewhere safe, like a public or private GitHub repository, in order to share it across systems. Homelab users may consider using rsync or a similar tool to manage file sharing and data backup themselves. The possibilities are endless!
Let’s say we have a new system and want to install our Rust tools and applications from crates.txt
.
On macOS, Linux and similar systems, we can use xargs to install everything.
xargs cargo install --locked < crates.txt
On Windows and systems using PowerShell, we can do something roughly equivalent, though not quite the same.
$crates = Get-Content -Raw -Path .\crates.txt | Out-String
foreach($crate in $crates.split("`n")) { if ( $crate -ne "" ) { cargo install --locked $crate } }
We are also able to continually update our list by using the command we used to originally create the file. With that and the other snippets and tips laid out in this section, we can create, update, back up, install from scratch, and manage what we have installed on our system.
Automating Updates Link to heading
Finally, we can tie this all together with automation. There are a bunch of commands to remember, so adding shell functions or scripts could be a good idea to make our experience better.
For the following example, we are using a zsh
function, but transposing similar logic into your shell of choice should work on most popular platforms.
function update {
if [ "$(command -v rustup)" ]; then
rustup update
fi
if [ "$(command -v cargo)" ]; then
if [ ! -f $HOME/.cargo/bin/cargo-install-update ]; then
cargo install --locked cargo-update
fi
cargo install-update -a
cargo install --list | rg -o "^\S*\S" > $SOME_ABSOLUTE_PATH/crates.txt
fi
}
The above function checks if rustup is installed and updates your Rust toolchains, including Cargo, accordingly.
Then, it checks if Cargo is installed, installs cargo-update
if it has not been installed, updates all tools and applications installed with cargo install
, and then dumps the list of those same tools and applications into a crates.txt
file.
Whew.
There are a lot of possibilities here for advanced management here.
Perhaps, we could explore an opportunity to force updates with for all installed binaries (i.e. cargo install-update -a --force
) if the stable toolchain has been updated via rustup update
.
I say, get creative!
Update Away Link to heading
With this guide, tips and snippets, we are ready to manage our Rust tools and applications!
There are likely areas for improvement and optimizations that we could make here and there, but this guide is meant to get you started as well as to find and inspire methods that work best for you. Go forth and update away!