Introducing zv: A blazing fast zig version manager / project starter

Introducing zv: A fast Zig version manager written in Rust :crab::high_voltage:

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 :rocket:

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

you should now be able to run zv or zig after installing a version zv use latest.
GitHub: GitHub - weezy20/zv: Blazing fast zig version manager & developer toolkit

Would love feedback from the Zig community! What features would you find most useful?

6 Likes

I think anyzig got it right.

13 Likes

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.

18 Likes

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.

Tigerbeetle does almost the same

Got it, thanks for pointing that out :folded_hands: — 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 :+1:

3 Likes

Having to install the complete Rust toolchain first before getting a Zig tool is a bit weird tbh :wink:

It’s a chicken-egg-problem of course but I prefer zvm’s installation shell-one-liner to pull a pre-compiled binary (see: GitHub - tristanisham/zvm: zvm (Zig Version Manager) lets you easily install/upgrade between different versions of Zig.).

From then on zvm can update itself.

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.

4 Likes

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).

1 Like

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)

11 Likes

That’s a pretty respectable take.

1 Like

Hey. Just updating here since you’d mentioned these two points:

zv is now able to bootstrap without a rust-toolchain using a one line install script for unix/linux and powershell.

zv also now comes with self update via zv update from v0.3.0 onwards.

zv is also available as a brew tap and npm using (npm i -g @weezy20/zv)

The manual setup, build steps are completely eliminated from the most widely used platform-os-arch combinations.

3 Likes

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:

If you use anyzig, then your list increases like this:

If you use OP’s project, the list increases like this:

  • Zig project maintainers
  • Rust project maintainers
  • Abhishek Shah (OP; newcomer in the Zig community)
  • addr2line crate maintainers
  • adler2 crate maintainers
  • aes crate maintainers
  • ahash crate maintainers
  • aho-corasick crate maintainers
  • anstream crate maintainers
  • anstyle crate maintainers
  • anstyle-parse crate maintainers
  • anstyle-query crate maintainers
  • atomic-waker crate maintainers
  • autocfg crate maintainers
  • backtrace crate maintainers
  • base64 crate maintainers
  • bitflags crate maintainers
  • block-buffer crate maintainers
  • bumpalo crate maintainers
  • bytes crate maintainers
  • bzip2 crate maintainers
  • cc crate maintainers
  • cfg-if crate maintainers
  • cfg_aliases crate maintainers
  • chrono crate maintainers
  • cipher crate maintainers
  • clap crate maintainers
  • clap_builder crate maintainers
  • clap_derive crate maintainers
  • clap_lex crate maintainers
  • color-eyre crate maintainers
  • color-spantrace crate maintainers
  • colorchoice crate maintainers
  • console crate maintainers
  • constant_time_eq crate maintainers
  • cpufeatures crate maintainers
  • crc crate maintainers
  • crc-catalog crate maintainers
  • crc32fast crate maintainers
  • crossbeam-deque crate maintainers
  • crossbeam-epoch crate maintainers
  • crossbeam-utils crate maintainers
  • crypto-common crate maintainers
  • cvt crate maintainers
  • deflate64 crate maintainers
  • deranged crate maintainers
  • dialoguer crate maintainers
  • digest crate maintainers
  • dirs crate maintainers
  • dirs-sys crate maintainers
  • displaydoc crate maintainers
  • dunce crate maintainers
  • either crate maintainers
  • equivalent crate maintainers
  • eyre crate maintainers
  • fastrand crate maintainers
  • filetime crate maintainers
  • find-msvc-tools crate maintainers
  • flate2 crate maintainers
  • fnv crate maintainers
  • form_urlencoded crate maintainers
  • fs_at crate maintainers
  • futures crate maintainers
  • futures-channel crate maintainers
  • futures-core crate maintainers
  • futures-executor crate maintainers
  • futures-io crate maintainers
  • futures-macro crate maintainers
  • futures-sink crate maintainers
  • futures-task crate maintainers
  • futures-util crate maintainers
  • generic-array crate maintainers
  • getrandom crate maintainers
  • gimli crate maintainers
  • h2 crate maintainers
  • hashbrown crate maintainers
  • heck crate maintainers
  • hmac crate maintainers
  • http crate maintainers
  • http-body crate maintainers
  • http-body-util crate maintainers
  • httparse crate maintainers
  • httpdate crate maintainers
  • hyper crate maintainers
  • hyper-rustls crate maintainers
  • hyper-util crate maintainers
  • iana-time-zone crate maintainers
  • icu_collections crate maintainers
  • icu_locale_core crate maintainers
  • icu_normalizer crate maintainers
  • icu_normalizer_data crate maintainers
  • icu_properties crate maintainers
  • icu_properties_data crate maintainers
  • icu_provider crate maintainers
  • idna crate maintainers
  • idna_adapter crate maintainers
  • indenter crate maintainers
  • indexmap crate maintainers
  • indicatif crate maintainers
  • inout crate maintainers
  • ipnet crate maintainers
  • iri-string crate maintainers
  • is-terminal crate maintainers
  • is_terminal_polyfill crate maintainers
  • itoa crate maintainers
  • jobserver crate maintainers
  • lazy_static crate maintainers
  • libbz2-rs-sys crate maintainers
  • libc crate maintainers
  • libz-rs-sys crate maintainers
  • linux-raw-sys crate maintainers
  • litemap crate maintainers
  • log crate maintainers
  • lzma-rust2 crate maintainers
  • lzma-sys crate maintainers
  • crate maintainers
  • matchers crate maintainers
  • memchr crate maintainers
  • minisign-verify crate maintainers
  • miniz_oxide crate maintainers
  • mio crate maintainers
  • nix crate maintainers
  • normpath crate maintainers
  • nu-ansi-term crate maintainers
  • num-conv crate maintainers
  • num-traits crate maintainers
  • number_prefix crate maintainers
  • object crate maintainers
  • once_cell crate maintainers
  • option-ext crate maintainers
  • owo-colors crate maintainers
  • pbkdf2 crate maintainers
  • percent-encoding crate maintainers
  • pin-project-lite crate maintainers
  • pin-utils crate maintainers
  • pkg-config crate maintainers
  • portable-atomic crate maintainers
  • potential_utf crate maintainers
  • powerfmt crate maintainers
  • ppmd-rust crate maintainers
  • ppv-lite86 crate maintainers
  • proc-macro2 crate maintainers
  • quick-xml crate maintainers
  • quote crate maintainers
  • rand crate maintainers
  • rand_chacha crate maintainers
  • rand_core crate maintainers
  • rayon crate maintainers
  • rayon-core crate maintainers
  • regex crate maintainers
  • regex-automata crate maintainers
  • regex-syntax crate maintainers
  • remove_dir_all crate maintainers
  • reqwest crate maintainers
  • ring crate maintainers
  • rustc-demangle crate maintainers
  • rustix crate maintainers
  • rustls crate maintainers
  • rustls-pki-types crate maintainers
  • rustls-webpki crate maintainers
  • ryu crate maintainers
  • same-file crate maintainers
  • self-replace crate maintainers
  • self_update crate maintainers
  • semver crate maintainers
  • serde crate maintainers
  • serde_core crate maintainers
  • serde_derive crate maintainers
  • serde_json crate maintainers
  • serde_spanned crate maintainers
  • serde_urlencoded crate maintainers
  • sha1 crate maintainers
  • sha2 crate maintainers
  • sharded-slab crate maintainers
  • shell-words crate maintainers
  • shlex crate maintainers
  • simd-adler32 crate maintainers
  • slab crate maintainers
  • smallvec crate maintainers
  • socket2 crate maintainers
  • stable_deref_trait crate maintainers
  • strsim crate maintainers
  • subtle crate maintainers
  • syn crate maintainers
  • sync_wrapper crate maintainers
  • synstructure crate maintainers
  • sysinfo crate maintainers
  • tar crate maintainers
  • target-lexicon crate maintainers
  • tempfile crate maintainers
  • thiserror crate maintainers
  • thiserror-impl crate maintainers
  • thread_local crate maintainers
  • time crate maintainers
  • time-core crate maintainers
  • tinystr crate maintainers
  • tokio crate maintainers
  • tokio-macros crate maintainers
  • tokio-rustls crate maintainers
  • tokio-util crate maintainers
  • toml crate maintainers
  • toml_datetime crate maintainers
  • toml_edit crate maintainers
  • toml_parser crate maintainers
  • toml_writer crate maintainers
  • tower crate maintainers
  • tower-http crate maintainers
  • tower-layer crate maintainers
  • tower-service crate maintainers
  • tracing crate maintainers
  • tracing-attributes crate maintainers
  • tracing-core crate maintainers
  • tracing-error crate maintainers
  • tracing-log crate maintainers
  • tracing-subscriber crate maintainers
  • try-lock crate maintainers
  • typenum crate maintainers
  • unicode-ident crate maintainers
  • unicode-width crate maintainers
  • unit-prefix crate maintainers
  • untrusted crate maintainers
  • url crate maintainers
  • urlencoding crate maintainers
  • utf8_iter crate maintainers
  • utf8parse crate maintainers
  • walkdir crate maintainers
  • want crate maintainers
  • webpki-roots crate maintainers
  • winnow crate maintainers
  • writeable crate maintainers
  • xattr crate maintainers
  • xz2 crate maintainers
  • yansi crate maintainers
  • yoke crate maintainers
  • yoke-derive crate maintainers
  • zerocopy crate maintainers
  • zerofrom crate maintainers
  • zerofrom-derive crate maintainers
  • zeroize crate maintainers
  • zeroize_derive crate maintainers
  • zerotrie crate maintainers
  • zerovec crate maintainers
  • zerovec-derive crate maintainers
  • zip crate maintainers
  • zlib-rs crate maintainers
  • zopfli crate maintainers
  • zstd crate maintainers
  • zstd-safe crate maintainers
  • zstd-sys crate maintainers

And reminder that we don’t only have to trust that a maintainer is not maliciously playing the long con, we also have to watch out for maintainers failing to follow basic security hygiene.

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.

31 Likes

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.

8 Likes

Petition to integrate the version manager into Zig :wink:

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’.

4 Likes

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.

1 Like

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.

10 Likes

Solid advice. Although zero dependency software is definitely harder to make, especially when using crypto, the learning experience definitely is worth it.

1 Like

zig has some crypto in std, funny that :stuck_out_tongue:

just poking fun at you for using rust

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.

1 Like