Introducing zv: A fast Zig version manager written in Rust
Tired of juggling Zig versions? I built zv to make installing/switching between Zig toolchains effortless. Regardless of your platform.
Key features:
Project-aware versioning - Just add .zigversion to your repo and zv automatically uses the right version
Flexible version syntax - zv use 0.13.0 for stable, zv use master for latest dev, or zig +0.14.0 build to run commands with a specific version. This is made possible because I adopted rustupās proxy system for zv.
Smart cleanup - zv rm --except 0.13.0,master to free up space while keeping what you need
Multiple architectures - Your shell/platform is auto-detected.
Status: Alpha but stable! Iāve tested most core features and they work great and working great. ZLS support coming soon
Install via cargo: cargo install zv (latest 0.1.1)
Then run zv setup -d to preview changes (creates an env file & adds ZV_DIR/bin to PATH)
Then after youāve verified the changes run zv setup to install zv @ ZV_DIR/bin by default $HOME/.zv
finally uninstall the cargo binary: cargo uninstall zv
Nice to see a similar thing. I prefix the version with + following rustupās style. About the minimum_zig_version from build.zig/build.zig.zon it shouldnāt be too hard to implement it before 1.0.0. Thanks for the feedback!
Hi @zv2 , welcome to ziggit. The people in here and through out zig communities are generally pretty down to earth. We donāt care to be marketed to. Saying things like āBlazing Fastā are big red flags, especially when there is no accompanying benchmark data.
Instead, just be genuine, and direct. Just tell people what youāve worked on and some things you might be proud of about it.
I donāt say this as a reprimand, but as a kind word to help you assimilate to a new community.
It would be ideal to have something like ./zigw in the root of the repository (similar to ./gradlew). Just run ./zigw and donāt worry about version, mirrors, how it was downloaded or cached and never rely on garbage in your PATH.
Got it, thanks for pointing that out ā I should clarify that the āblazing fastā bit was meant tongue-in-cheek, since that phrase is often jokingly used with Rust projects. What it actually does is pretty straightforward: download + verification + extraction, using the best native Rust crates I could find for the ecosystem. Iāll keep it more direct going forward
Integration with homebrew, scoop, apk etc⦠would be even better than running a shell script which downloads an āuntrustedā binary of course, but thatās also a lot more hassle on the tool authorās side.
I feel you and thatās why this is alpha software. Iāve contemplated both one liner shell-scripts that would fetch some popular binaries generated via CI or integration with some package managers like scoop, choco, apt & pacman but this would come after I reach full feature compatibility (zv update & zls support).
Feel the same, and you know, software that builds software - like Zig - are high-value targets for supply chain attacks.
If I were to use a versioning system for a compiler (Iām personally not), then I want to understand it fully and it must be easy to see what has changed when the version manager is upgraded.
This is asking me to get confident with a surprisingly large amount non-Zig code for a Zig version manager, including a whopping 35 direct dependencies (a grand total of 116 crates were downloaded)
To put this in concrete terms, letās analyze one of the most important features that a programming language version manager brings to the table: how many different people do you have to trust?
If you only depend on Zig, then your supply chain only needs to trust these people:
Iām not arguing against dependencies in general. A compiler toolchain is a ārootā of the dependency tree, and so it is more vulnerable to supply chain attacks. Therefore, limiting the amount of trust required is one of the key features a version manager has to offer.
As a fun tidbit, I actually contributed a part of the anstyle crate, though it was for the roff renderer, so I doubt my code would play here (or if itās even used anymore)
EDIT:
I guess anstyle-roff is a separate but related create. Oh well.
From the list are missing crates.io maintainers, since dependencies donāt declare their own hash in Cargo.toml. Thereās Cargo.lock, so if you use the --locked (iirc) flag you do get hash validation, but normal builds will try to pull the latest compatible version automatically and you donāt have hashes for yet-unseen versions.
Petition to integrate the version manager into Zig
E.g.: the āfrontendā zig executable would just be a tiny shim with just enough code to download packages into the global zig cache and launch the actual compiler executable. The actual Zig toolchain would then be regular packages.
This would be the most minimal āchain of trustā.
Thanks for laying this out so clearly, Andrew, I completely get where youāre coming from. For a core piece of infrastructure, the number of people you have to trust matters, and that dependency list is indeed huge. From what Iāve seen the fact that this is non-zig software and comes with a huge dependency tree are the two most adverse criticisms that exist for zv.
The reality of building with Rust is that convenience often comes with a deep dependency tree. This is true for most rust based applications, including the main toolchain manager for rust itself (rustup) and many security critical applications like live blockchains/databases etc.
My approach was to accept that for general features (like the CLI, networking, async etc.) but be extremely strict about the core security logic. The part of the code that actually gives the āall clearā on a downloaded file is as narrow as it can be. It relies on just two key crates: sha2 from the well-respected RustCrypto project and jesdisct1/rust-minisign-verify to verify the downloaded artifacts from mirrors/ziglang.org & relies on two other crates to handle cross-platform tar.xz and zip extraction. So in essence, from mirror ā userās computer thereās a maximum of 3 crates that do the verification+extraction part. The rest of it has no bearing on the integrity of the zig that ends up on your machine.
But your point stands: this is all internal logic. From the outside, a user just sees the giant list & verification demands work on their part or as you said, trust. Itās a definite trade-off that you pay for convenience & that you canāt easily see where that trust is concentrated. Regardless, thanks for the valuable perspective.
I made zv, inspired by rustup, to replace the shell-scripts that I was using for managing my zig installations, PATH variables & I wanted cross-platform support and thatās how this came into being.
With a little bit of unsafe and ingenuity your other dependencies, if compromised, can indeed cause a lot of things to happen, including messing with how the binary is verified. And even without unsafe they could still just steal user data and cause a variety of problems (e.g. the CLI parser can decide to subprocess a shell and invoke rm on the userās home directory, which usually doesnāt require elevated privileges to succeed). Or, as another example, even if the compromised crate is unable to corrupt the executable verification process, it can simply swap the executable out for a compromised version after the original has been put into place.
That being said, in order to change the tone of the discussion a little and hopefully give you something of value, you are experiencing a first contact with a community and ecosystem that places a lot of emphasis on doing things from scratch, ideally not every time, but when thereās something to gain. In this case the argument (i.e. the main win by doing things from scratch) is about length of the chain of trust, but it varies depending on the domain. Sometimes itās about exploiting the capabilities of a given platform (e.g. writing native GUIs by interfacing directly with OS APIs vs using something like Electron), some other times it can be something else. Some other times thereās nothing particularly big to win and so maybe you do it anyway for the sake of learning, while some other times you just trust somebody else to put in the branpower for you (e.g. I use rockorager/zeit and I donāt see myself writing a datetime library anytime (hah pun) soon).
If you want to enjoy some of the best stuff the Zig community has to share, try your hand at doing something from scratch, maybe something that you have already made by using dependencies (might be zv or something else), and see if you end up learning something valuable.
I for example did this with my static site generator (talk) and definitely learned a lot.
Additionally, if you happen to leave near a zig day consider joining it once to see others attempt to do the same.
Lastly, just for clarity, you can totally do what I just described in Rust, you donāt need to use Zig at all, unless youāre feeling Zigcurious.
Solid advice. Although zero dependency software is definitely harder to make, especially when using crypto, the learning experience definitely is worth it.
Even with a strong ābatteries includedā std lib, I have seen this dependency explosion happen in multiple languages the moment a package manager gets added.
Personally Iād vote to remove Zigās package manager entirely before the same thing happens here, or hard limit dependency depth to 1 might be an interesting experiment/compromise. Similar to the āC header onlyā libs kicking around.
Otherwise I see a flood of CV enhancing small npm style packages heading this way, especially now that an LLM can trivially transpile such code.
At least until CRA and similar āknow your developerā source-code supply-chain securing measures kick in.