Skip to content

Commit 0897baf

Browse files
committed
refactor: migrate entire codebase to Zig 0.16.0 I/O API
Upgrade zvm to compile against Zig 0.16.0, which introduces a fundamental I/O revolution — every filesystem and network operation now requires an explicit io: std.Io parameter threaded through the call chain. Key API migrations in this commit: - main() signature: pub fn main() void → pub fn main(init: std.process.Init) !void using init.gpa, init.io, init.environ_map, init.minimal.args - File/Dir operations: std.fs.cwd() → std.Io.Dir.cwd() with io param - File close: file.close() → file.close(io) - Dir close: dir.close() → dir.close(io) - Dir iteration: iter.next() → iter.next(io) - Dir rename: dir.rename(old, new) → dir.rename(old, dir, new, io) - Symlink: std.posix.symlink() → std.Io.Dir.symLinkAbsolute(io, ...) - File reading: reader.allocRemaining() → reader.interface.allocRemaining() - Subprocess: std.process.Child.run() → std.process.run(alloc, io, opts) - Spawn: std.process.Child.init/spawn/wait → std.process.spawn/wait - Timestamps: std.time.timestamp() → Io.Clock.Timestamp.now(io, .real) - Latency: std.time.Instant → Io.Timestamp.now(io, .awake) + durationTo() - Zip extract: std.zip.extract(cwd, io, reader, opts) → extract(cwd, reader, opts) - Term fields: .Exited/.Signal → .exited/.signal (lowercase) - CLI args: argsWithAllocator → Args.Iterator.initAllocator - Env vars: getEnvVarOwned → environ_map.get() - Build: build_options.minimum_zig_version bumped to 0.14.0 Architecture: io and environ_map stored in ZVM struct to minimize signature changes across command handlers — all commands access zvm.io and zvm.environ_map as needed. Verified: binary compiles and passes basic smoke tests (help, version, ls)
1 parent 9181d07 commit 0897baf

23 files changed

Lines changed: 320 additions & 305 deletions

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: Setup Zig
1919
uses: mlugg/setup-zig@v2
2020
with:
21-
version: '0.15.2'
21+
version: '0.16.0'
2222

2323
- name: Build
2424
run: zig build -Doptimize=ReleaseSafe -Dtarget=aarch64-linux-gnu
@@ -39,7 +39,7 @@ jobs:
3939
- name: Setup Zig
4040
uses: mlugg/setup-zig@v2
4141
with:
42-
version: '0.15.2'
42+
version: '0.16.0'
4343

4444
- name: Check formatting
4545
run: zig fmt --check src/

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
- name: Setup Zig
4949
uses: mlugg/setup-zig@v2
5050
with:
51-
version: '0.15.2'
51+
version: '0.16.0'
5252

5353
- name: Build
5454
run: |

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ export PATH="$HOME/.zvm/bin:$PATH"
7070

7171
```bash
7272
# Install a Zig version
73-
zvm install 0.15.2
73+
zvm install 0.16.0
7474

7575
# Install latest nightly build
7676
zvm install master
7777

7878
# Install with ZLS (Zig Language Server)
79-
zvm install --zls 0.15.2
79+
zvm install --zls 0.16.0
8080

8181
# Switch to a different version
8282
zvm use 0.14.0
@@ -221,7 +221,7 @@ eval "$(zvm completion bash)"
221221
~/.zvm/
222222
├── bin → symlink/junction to the active version directory
223223
├── .active → marker file tracking the active version name
224-
├── 0.15.2/ → Zig 0.15.2 installation
224+
├── 0.16.0/ → Zig 0.16.0 installation
225225
│ └── zig → Zig compiler binary
226226
├── 0.14.0/ → Zig 0.14.0 installation
227227
│ └── zig

build.zig

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ pub fn build(b: *std.Build) void {
1212
"version",
1313
"Semantic version (e.g. 0.2.0). In CI, pass the git tag. Locally defaults to git describe or \"0.0.1\".",
1414
) orelse blk: {
15-
const tag = std.process.Child.run(.{
16-
.allocator = b.allocator,
15+
const tag = std.process.run(b.allocator, b.graph.io, .{
1716
.argv = &.{ "git", "describe", "--tags", "--abbrev=0" },
1817
}) catch break :blk "0.0.1";
1918
switch (tag.term) {
20-
.Exited => |code| if (code != 0) break :blk "0.0.1",
19+
.exited => |code| if (code != 0) break :blk "0.0.1",
2120
else => break :blk "0.0.1",
2221
}
2322
const trimmed = std.mem.trim(u8, tag.stdout, " \n\r");
@@ -26,8 +25,7 @@ pub fn build(b: *std.Build) void {
2625
};
2726

2827
const git_commit = blk: {
29-
const result = std.process.Child.run(.{
30-
.allocator = b.allocator,
28+
const result = std.process.run(b.allocator, b.graph.io, .{
3129
.argv = &.{ "git", "rev-parse", "--short", "HEAD" },
3230
}) catch break :blk "unknown";
3331
break :blk std.mem.trim(u8, result.stdout, " \n\r");

build.zig.zon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
.fingerprint = 0xec41f7019ea1800d, // Changing this has security and trust implications.
2626
// Tracks the earliest Zig version that the package considers to be a
2727
// supported use case.
28-
.minimum_zig_version = "0.15.1",
28+
.minimum_zig_version = "0.16.0",
2929
// This field is optional.
3030
// Each dependency must either provide a `url` and `hash`, or a `path`.
3131
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.

src/archive.zig

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,56 @@
11
//! Archive extraction for .tar.xz and .zip files.
2-
//! Uses the `tar` CLI for .tar.xz (stdlib xz has compile issues in Zig 0.15.2)
2+
//! Uses the `tar` CLI for .tar.xz (stdlib xz has compile issues in Zig 0.16.0)
33
//! and std.zip for .zip archives.
44

55
const std = @import("std");
66
const builtin = @import("builtin");
77

88
/// Extract a .tar.xz archive using the system `tar` command.
9-
/// This is the primary extraction method on Unix platforms.
10-
pub fn extractTarXz(allocator: std.mem.Allocator, archive_path: []const u8, output_dir: []const u8) !void {
11-
const result = try std.process.Child.run(.{
12-
.allocator = allocator,
9+
pub fn extractTarXz(allocator: std.mem.Allocator, io: std.Io, archive_path: []const u8, output_dir: []const u8) !void {
10+
const result = try std.process.run(allocator, io, .{
1311
.argv = &.{ "tar", "-xf", archive_path, "-C", output_dir },
1412
});
1513
defer allocator.free(result.stdout);
1614
defer allocator.free(result.stderr);
1715

18-
if (result.term != .Exited or result.term.Exited != 0) {
16+
if (result.term != .exited or result.term.exited != 0) {
1917
return error.ExtractionFailed;
2018
}
2119
}
2220

2321
/// Extract a .zip archive using Zig's stdlib zip implementation.
24-
pub fn extractZip(allocator: std.mem.Allocator, archive_path: []const u8, output_dir: []const u8) !void {
22+
pub fn extractZip(allocator: std.mem.Allocator, io: std.Io, archive_path: []const u8, output_dir: []const u8) !void {
2523
_ = output_dir;
26-
const file = try std.fs.cwd().openFile(archive_path, .{});
27-
defer file.close();
24+
const file = try std.Io.Dir.cwd().openFile(io, archive_path, .{});
25+
defer file.close(io);
2826

2927
var reader_buf: [8192]u8 = undefined;
30-
var reader = file.reader(&reader_buf);
28+
var reader = file.reader(io, &reader_buf);
3129

3230
var diagnostics: std.zip.Diagnostics = .{ .allocator = allocator };
3331
defer diagnostics.deinit();
3432

35-
try std.zip.extract(std.fs.cwd(), &reader, .{
33+
try std.zip.extract(std.Io.Dir.cwd(), &reader, .{
3634
.diagnostics = &diagnostics,
3735
});
3836
}
3937

4038
/// Extract an archive based on its file extension.
4139
/// Supports: .tar.xz, .zip, .tar
42-
pub fn extractArchive(allocator: std.mem.Allocator, archive_path: []const u8, output_dir: []const u8) !void {
40+
pub fn extractArchive(allocator: std.mem.Allocator, io: std.Io, archive_path: []const u8, output_dir: []const u8) !void {
4341
if (std.mem.endsWith(u8, archive_path, ".tar.xz")) {
44-
try extractTarXz(allocator, archive_path, output_dir);
42+
try extractTarXz(allocator, io, archive_path, output_dir);
4543
} else if (std.mem.endsWith(u8, archive_path, ".zip")) {
46-
try extractZip(allocator, archive_path, output_dir);
44+
try extractZip(allocator, io, archive_path, output_dir);
4745
} else if (std.mem.endsWith(u8, archive_path, ".tar")) {
4846
// Plain tar using CLI
49-
const result = try std.process.Child.run(.{
50-
.allocator = allocator,
47+
const result = try std.process.run(allocator, io, .{
5148
.argv = &.{ "tar", "-xf", archive_path, "-C", output_dir },
5249
});
5350
defer allocator.free(result.stdout);
5451
defer allocator.free(result.stderr);
5552

56-
if (result.term != .Exited or result.term.Exited != 0) {
53+
if (result.term != .exited or result.term.exited != 0) {
5754
return error.ExtractionFailed;
5855
}
5956
} else {

src/clean.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ pub fn run(
1717

1818
const extensions = [_][]const u8{ ".zip", ".xz", ".tar", ".tar.xz" };
1919

20-
var dir = try std.fs.cwd().openDir(zvm.base_dir, .{ .iterate = true });
21-
defer dir.close();
20+
var dir = try std.Io.Dir.cwd().openDir(zvm.io, zvm.base_dir, .{ .iterate = true });
21+
defer dir.close(zvm.io);
2222

2323
var count: usize = 0;
2424
var iter = dir.iterate();
25-
while (try iter.next()) |entry| {
25+
while (try iter.next(zvm.io)) |entry| {
2626
if (entry.kind != .file) continue;
2727
for (extensions) |ext| {
2828
if (std.mem.endsWith(u8, entry.name, ext)) {
29-
dir.deleteFile(entry.name) catch continue;
29+
dir.deleteFile(zvm.io, entry.name) catch continue;
3030
count += 1;
3131
break;
3232
}

src/cli.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ const command_aliases = std.StaticStringMap(Command).initComptime(.{
121121
.{ "-v", .version },
122122
});
123123

124-
pub fn parse(allocator: std.mem.Allocator) !struct { global: GlobalFlags, cmd: ParsedCommand } {
125-
var args = try std.process.argsWithAllocator(allocator);
124+
pub fn parse(allocator: std.mem.Allocator, args_data: std.process.Args) !struct { global: GlobalFlags, cmd: ParsedCommand } {
125+
var args = std.process.Args.Iterator.initAllocator(args_data, allocator) catch return error.OutOfMemory;
126126
defer args.deinit();
127127

128128
// Skip program name

src/crypto.zig

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ fn hexEncode(digest: *const [Sha256.digest_length]u8, buf: *[hex_len]u8) []const
2020
/// Compute SHA256 hash of a file and return as hex-encoded string.
2121
/// Reads the entire file into memory (up to 500MB).
2222
/// Caller owns returned memory.
23-
pub fn computeFileSha256(allocator: std.mem.Allocator, path: []const u8) ![]const u8 {
24-
const file = try std.fs.cwd().openFile(path, .{});
25-
defer file.close();
23+
pub fn computeFileSha256(allocator: std.mem.Allocator, io: std.Io, path: []const u8) ![]const u8 {
24+
const file = try std.Io.Dir.cwd().openFile(io, path, .{});
25+
defer file.close(io);
2626

27-
const content = try file.readToEndAlloc(allocator, 500 * 1024 * 1024);
27+
var read_buf: [16384]u8 = undefined;
28+
var reader = file.reader(io, &read_buf);
29+
const content = try reader.interface.allocRemaining(allocator, .limited(500 * 1024 * 1024));
2830
defer allocator.free(content);
2931

3032
var hasher = Sha256.init(.{});
@@ -40,11 +42,13 @@ pub fn computeFileSha256(allocator: std.mem.Allocator, path: []const u8) ![]cons
4042

4143
/// Verify that a file's SHA256 hash matches the expected hex-encoded checksum.
4244
/// Returns true if they match, false otherwise.
43-
pub fn verifyFileSha256(path: []const u8, expected_hex: []const u8) !bool {
44-
const file = try std.fs.cwd().openFile(path, .{});
45-
defer file.close();
45+
pub fn verifyFileSha256(io: std.Io, path: []const u8, expected_hex: []const u8) !bool {
46+
const file = try std.Io.Dir.cwd().openFile(io, path, .{});
47+
defer file.close(io);
4648

47-
const content = try file.readToEndAlloc(std.heap.page_allocator, 500 * 1024 * 1024);
49+
var read_buf: [16384]u8 = undefined;
50+
var reader = file.reader(io, &read_buf);
51+
const content = try reader.interface.allocRemaining(std.heap.page_allocator, .limited(500 * 1024 * 1024));
4852
defer std.heap.page_allocator.free(content);
4953

5054
var hasher = Sha256.init(.{});

0 commit comments

Comments
 (0)