Skip to content

fix(shim): make env PATH shims work#160

Merged
hendriknielaender merged 11 commits into
hendriknielaender:mainfrom
KercyDing:fix/setup-shims-and-docs
May 14, 2026
Merged

fix(shim): make env PATH shims work#160
hendriknielaender merged 11 commits into
hendriknielaender:mainfrom
KercyDing:fix/setup-shims-and-docs

Conversation

@KercyDing

@KercyDing KercyDing commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #157.
Closes #158.

This PR makes the zvm env setup actually work end to end. After users add the printed .zm/bin path to PATH, zig and zls now have real shims there instead of requiring manual symlinks or copies.

It also updates the README and website examples so they no longer point at the old zvm/bin path.

Main changes:

  • create zig / zls shims in $ZVM_HOME/bin on Unix
  • create zvm.exe, zig.exe, and zls.exe in %USERPROFILE%\.zm\bin on Windows
  • make the shim dispatch work with Windows .exe command names
  • keep the installer layout, zvm env, and docs aligned around .zm/bin
  • normalize single-root zip installs so Windows Zig archives end up in the layout the shim expects
  • add e2e coverage for shim creation

Verification

Verified manually on:

  • CachyOS
  • latest macOS
  • Windows 11

Checklist:

  • zig build test
  • zig build e2e
  • checked zvm env output
  • checked zig version through the shim
  • checked zls --version through the shim

KercyDing added 8 commits May 11, 2026 12:27
- keep using executablePath for shim resolution
- fix `zvm use <version>` failing with `NameTooLong` on macOS
- local testing showed 512 bytes was too small
- 1024 bytes was the smallest working buffer
- keep the existing limit on other platforms
- stop reusing the version-path scratch buffer during `use`
@KercyDing KercyDing changed the title fix: create Unix shims for env PATH fix(shim): make env PATH shims work May 11, 2026
@KercyDing

Copy link
Copy Markdown
Contributor Author

Cool, I went ahead with the .zm\bin migration for Windows as well.

While testing it locally, I noticed the Windows Zig zip was extracted one directory deeper than the shim expects, so I included that small extraction fix in this PR too. With that in place I can verify zvm i 0.16.0 and .zm\bin\zig.exe version end-to-end on Windows.

@KercyDing KercyDing marked this pull request as ready for review May 11, 2026 16:38
Copilot AI review requested due to automatic review settings May 11, 2026 16:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes end-to-end zvm env usability by ensuring zig / zls shims actually exist in the PATH directory that zvm env prints (i.e., $ZVM_HOME/.zm/bin), and aligns documentation/examples to the .zm/bin layout. It also adjusts Windows zip extraction to normalize “single-root-folder” archives into the directory structure the shim expects, and adds an e2e test to cover shim creation.

Changes:

  • Create/update zig/zls shims on zvm use (symlinks on Unix; copied .exe shims on Windows).
  • Teach shim dispatch to recognize Windows .exe names and build .exe tool paths.
  • Normalize zip extraction when the archive contains exactly one top-level directory; update docs/examples to use .zm/bin; add e2e coverage.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/core/alias.zig Ensures zvm use creates zig/zls shims in $ZVM_HOME/.zm/bin across platforms.
src/shim.zig Extends shim-name detection and tool path building for Windows .exe names; adds Windows exec path.
src/io/extract.zig Normalizes single-root zip archives so extracted layouts match what shims expect.
src/util/tool.zig Refactors directory copy path building (now using fixed-size stack buffers).
tests/e2e.zig Adds offline e2e test to assert shims are created after use.
README.md Updates PATH example to .zm/bin and simplifies “PATH not updated” guidance.
static/layouts/index.shtml Updates website PATH example to .zm/bin and clarifies it’s Unix-shell output.
install.ps1 Installs zvm.exe into .zm\\bin and creates zig.exe/zls.exe shims; updates PATH handling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/util/tool.zig
Comment on lines 83 to 96
var iterate = source.iterate();
while (try iterate.next(io)) |entry| {
const entry_name = entry.name;

// Build source sub path.
source_path_buffer.reset();
const source_sub_path = try source_path_buffer.set(
try std.fmt.bufPrint(source_path_buffer.slice(), "{s}/{s}", .{ source_dir, entry_name }),
);
var source_path_storage: [limits.limits.path_length_maximum]u8 = undefined;
const source_sub_path = try std.fmt.bufPrint(&source_path_storage, "{s}/{s}", .{ source_dir, entry_name });

// Build dest sub path.
dest_path_buffer.reset();
const dest_sub_path = try dest_path_buffer.set(
try std.fmt.bufPrint(dest_path_buffer.slice(), "{s}/{s}", .{ dest_dir, entry_name }),
);
var dest_path_storage: [limits.limits.path_length_maximum]u8 = undefined;
const dest_sub_path = try std.fmt.bufPrint(&dest_path_storage, "{s}/{s}", .{ dest_dir, entry_name });

switch (entry.kind) {
.directory => try copy_dir_static(io, source_sub_path, dest_sub_path, source_path_buffer, dest_path_buffer),
Comment thread src/shim.zig
Comment on lines 35 to +40
pub fn is_shim_name(program_basename: []const u8) bool {
return util_tool.eql_str(program_basename, "zig") or util_tool.eql_str(program_basename, "zls");
switch (builtin.os.tag) {
.windows => return util_tool.eql_str(program_basename, "zig") or
util_tool.eql_str(program_basename, "zig.exe") or
util_tool.eql_str(program_basename, "zls") or
util_tool.eql_str(program_basename, "zls.exe"),
Comment thread src/shim.zig
Comment on lines 60 to 62
assert(is_shim_name(program_name));
const tool_name = if (util_tool.eql_str(program_name, "zig") or util_tool.eql_str(program_name, "zig.exe")) "zig" else "zls";

Comment thread src/core/alias.zig Outdated
Comment on lines +193 to +199
var shim_path_storage: [self_path_buffer_len]u8 = undefined;
const shim_path = try std.fmt.bufPrint(&shim_path_storage, "{s}/{s}", .{ bin_dir, shim_name });

if (builtin.os.tag == .windows and std.ascii.eqlIgnoreCase(self_path, shim_path)) return;

std.Io.Dir.deleteFileAbsolute(ctx.io, shim_path) catch |err| switch (err) {
error.FileNotFound => {},
Comment thread src/io/extract.zig
var normalized_source_buffer: object_pools.PathBuffer = .{ .data = undefined, .used = 0 };
const copy_source = try normalize_archive_root(io, tmp_dir, tmp_path, &normalized_source_buffer);

// SAFETY: PathBuffer.data is initialized before first use via copy_dir_static
@KercyDing KercyDing marked this pull request as draft May 12, 2026 08:01
@KercyDing

Copy link
Copy Markdown
Contributor Author

I have found a more elegant way to solve the path_length problem.

@KercyDing KercyDing marked this pull request as ready for review May 12, 2026 09:55
@KercyDing

Copy link
Copy Markdown
Contributor Author

RFR now😘

@hendriknielaender hendriknielaender self-requested a review May 14, 2026 12:09

@hendriknielaender hendriknielaender left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, looks good to me 👍

@hendriknielaender hendriknielaender merged commit 68db55c into hendriknielaender:main May 14, 2026
8 checks passed
@KercyDing KercyDing deleted the fix/setup-shims-and-docs branch May 14, 2026 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

README and website show an old PATH zig / zls are not available after following zvm env

3 participants