Skip to content

Commit a27f634

Browse files
committed
update zig to 0.15
- use new writer and reader interface - archiver streams content to foilz file directly (no need to alloc) also: - use defer more to close resources. - use std.Build.allocator in zig build script. - pass around a single arena. - replaced some helper functions in favour of doing it directly in place. (i.e shutil) - fmt really long lines
1 parent 3372daa commit a27f634

File tree

11 files changed

+166
-192
lines changed

11 files changed

+166
-192
lines changed

.github/workflows/burrito-xcomp-check.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
elixir-version: "1.18.3"
2121
- uses: goto-bus-stop/setup-zig@v2
2222
with:
23-
version: 0.14.1
23+
version: 0.15.1
2424
- name: Set up Homebrew
2525
if: matrix.host == 'macos-latest'
2626
id: set-up-homebrew

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ We support _targeting_ Windows (x86_64) from MacOS and Linux, we _do not_ offici
110110

111111
You must have the following installed and in your PATH:
112112

113-
* Zig (0.14.0) -- `zig`
113+
* Zig (0.15.1) -- `zig`
114114
* XZ -- `xz`
115115
* 7z -- `7z` (For Windows Targets)
116116

build.zig

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,71 +8,71 @@ const builtin = @import("builtin");
88

99
const log = std.log;
1010

11-
const Builder = std.Build;
1211
const CrossTarget = std.zig.CrossTarget;
1312
const Mode = std.builtin.Mode;
1413
const LibExeObjStep = std.build.LibExeObjStep;
1514

16-
var builder: *Builder = undefined;
17-
var wrapper_exe: *Builder.Step.Compile = undefined;
18-
19-
// Memory allocator
20-
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
21-
var allocator = arena.allocator();
22-
23-
pub fn build(b: *Builder) !void {
15+
pub fn build(b: *std.Build) !void {
2416
log.info("Zig is building an Elixir binary... ⚡", .{});
2517

26-
builder = b;
27-
2818
// Run build steps!
29-
_ = try run_archiver();
30-
_ = try build_wrapper();
19+
try run_archiver(b);
20+
try build_wrapper(b);
3121

3222
log.info("DONE 🚀", .{});
3323
}
3424

35-
pub fn run_archiver() !void {
25+
pub fn run_archiver(b: *std.Build) !void {
3626
log.info("Generating and compressing release payload... 📦", .{});
3727

38-
const release_path = try std.process.getEnvVarOwned(allocator, "__BURRITO_RELEASE_PATH");
39-
try foilz.pack_directory(release_path, "./payload.foilz");
28+
const release_path = try std.process.getEnvVarOwned(b.allocator, "__BURRITO_RELEASE_PATH");
29+
try foilz.pack_directory(b.allocator, release_path, "./payload.foilz");
4030

4131
if (builtin.os.tag == .windows) {
42-
_ = builder.run(&[_][]const u8{ "cmd", "/C", "xz -9ez --check=crc32 --stdout --keep payload.foilz > src/payload.foilz.xz" });
32+
_ = b.run(&[_][]const u8{
33+
"cmd",
34+
"/C",
35+
"xz -9ez --check=crc32 --stdout --keep payload.foilz > src/payload.foilz.xz",
36+
});
4337
} else {
44-
_ = builder.run(&[_][]const u8{ "/bin/sh", "-c", "xz -9ez --check=crc32 --stdout --keep payload.foilz > src/payload.foilz.xz" });
38+
_ = b.run(&[_][]const u8{
39+
"/bin/sh",
40+
"-c",
41+
"xz -9ez --check=crc32 --stdout --keep payload.foilz > src/payload.foilz.xz",
42+
});
4543
}
4644
}
4745

48-
pub fn build_wrapper() !void {
46+
pub fn build_wrapper(b: *std.Build) !void {
4947
log.info("Building wrapper and embedding payload... 🌯", .{});
5048

51-
const release_name = try std.process.getEnvVarOwned(allocator, "__BURRITO_RELEASE_NAME");
52-
const plugin_path = std.process.getEnvVarOwned(allocator, "__BURRITO_PLUGIN_PATH") catch null;
53-
const is_prod = std.process.getEnvVarOwned(allocator, "__BURRITO_IS_PROD") catch "1";
54-
const musl_runtime_path = std.process.getEnvVarOwned(allocator, "__BURRITO_MUSL_RUNTIME_PATH") catch "";
55-
var opt_level = std.builtin.Mode.Debug;
49+
const release_name = try std.process.getEnvVarOwned(b.allocator, "__BURRITO_RELEASE_NAME");
50+
const plugin_path = std.process.getEnvVarOwned(b.allocator, "__BURRITO_PLUGIN_PATH") catch null;
51+
const is_prod = std.process.getEnvVarOwned(b.allocator, "__BURRITO_IS_PROD") catch "1";
52+
const musl_runtime_path = std.process.getEnvVarOwned(b.allocator, "__BURRITO_MUSL_RUNTIME_PATH") catch "";
53+
var opt_level = std.builtin.OptimizeMode.Debug;
5654

5755
if (std.mem.eql(u8, is_prod, "1")) {
58-
opt_level = std.builtin.Mode.ReleaseSmall;
56+
opt_level = std.builtin.OptimizeMode.ReleaseSmall;
5957
}
6058

6159
var file = try std.fs.cwd().openFile("payload.foilz", .{});
6260
defer file.close();
6361
const uncompressed_size = try file.getEndPos();
64-
const target = builder.standardTargetOptions(.{});
62+
const target = b.standardTargetOptions(.{});
6563

66-
wrapper_exe = builder.addExecutable(.{
64+
const wrapper_exe = b.addExecutable(.{
6765
.name = release_name,
6866
// In this case the main source file is merely a path, however, in more
6967
// complicated build scripts, this could be a generated file.
70-
.root_source_file = builder.path("src/wrapper.zig"),
71-
.target = target,
72-
.optimize = opt_level,
68+
.root_module = b.createModule(.{
69+
.root_source_file = b.path("src/wrapper.zig"),
70+
.target = target,
71+
.optimize = opt_level,
72+
}),
7373
});
7474

75-
const exe_options = builder.addOptions();
75+
const exe_options = b.addOptions();
7676
wrapper_exe.root_module.addOptions("build_options", exe_options);
7777

7878
exe_options.addOption([]const u8, "RELEASE_NAME", release_name);
@@ -82,29 +82,29 @@ pub fn build_wrapper() !void {
8282
exe_options.addOption([]const u8, "MUSL_RUNTIME_PATH", musl_runtime_path);
8383

8484
if (target.result.os.tag == .windows) {
85-
wrapper_exe.addIncludePath(builder.path("src/"));
85+
wrapper_exe.addIncludePath(b.path("src/"));
8686
}
8787

8888
// Link standard C libary to the wrapper
8989
wrapper_exe.linkSystemLibrary("c");
9090

9191
if (plugin_path) |plugin| {
9292
log.info("Plugin found! {s} 🔌", .{plugin});
93-
const plug_mod = builder.addModule("burrito_plugin", .{
93+
const plug_mod = b.addModule("burrito_plugin", .{
9494
.root_source_file = .{ .cwd_relative = plugin },
9595
});
9696
wrapper_exe.root_module.addImport("burrito_plugin", plug_mod);
9797
} else {
98-
const plug_mod = builder.addModule("burrito_plugin", .{
99-
.root_source_file = builder.path("_dummy_plugin.zig"),
98+
const plug_mod = b.addModule("burrito_plugin", .{
99+
.root_source_file = b.path("_dummy_plugin.zig"),
100100
});
101101
wrapper_exe.root_module.addImport("burrito_plugin", plug_mod);
102102
}
103103

104-
wrapper_exe.addIncludePath(builder.path("src/xz"));
105-
wrapper_exe.addCSourceFile(.{ .file = builder.path("src/xz/xz_crc32.c") });
106-
wrapper_exe.addCSourceFile(.{ .file = builder.path("src/xz/xz_dec_lzma2.c") });
107-
wrapper_exe.addCSourceFile(.{ .file = builder.path("src/xz/xz_dec_stream.c") });
104+
wrapper_exe.addIncludePath(b.path("src/xz"));
105+
wrapper_exe.addCSourceFile(.{ .file = b.path("src/xz/xz_crc32.c") });
106+
wrapper_exe.addCSourceFile(.{ .file = b.path("src/xz/xz_dec_lzma2.c") });
107+
wrapper_exe.addCSourceFile(.{ .file = b.path("src/xz/xz_dec_stream.c") });
108108

109-
builder.installArtifact(wrapper_exe);
109+
b.installArtifact(wrapper_exe);
110110
}

lib/burrito.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ defmodule Burrito do
22
alias Burrito.Builder
33
alias Burrito.Builder.Log
44

5-
@zig_version_expected %Version{major: 0, minor: 14, patch: 1}
5+
@zig_version_expected %Version{major: 0, minor: 15, patch: 1}
66
@openssl_version %Version{major: 3, minor: 5, patch: 1}
77
@musl_version %Version{major: 1, minor: 2, patch: 5}
88

src/archiver.zig

Lines changed: 42 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
const builtin = @import("builtin");
3434
const std = @import("std");
3535

36+
const Allocator = std.mem.Allocator;
37+
const assert = std.debug.assert;
3638
const fs = std.fs;
3739
const log = std.log;
3840
const mem = std.mem;
@@ -44,22 +46,24 @@ const xz = @cImport(@cInclude("xz.h"));
4446
const MAGIC = "FOILZ";
4547
const MAX_READ_SIZE = 1000000000;
4648

47-
pub fn pack_directory(path: []const u8, archive_path: []const u8) anyerror!void {
48-
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
49-
defer arena.deinit();
50-
const allocator = arena.allocator();
51-
49+
pub fn pack_directory(arena: Allocator, path: []const u8, archive_path: []const u8) anyerror!void {
5250
// Open a file for the archive
53-
_ = try fs.cwd().createFile(archive_path, .{ .truncate = true });
54-
const arch_file = try fs.cwd().openFile(archive_path, .{ .mode = .read_write });
55-
const foilz_writer = fs.File.writer(arch_file);
51+
const arch_file = try fs.cwd().createFile(archive_path, .{ .truncate = true });
52+
defer arch_file.close();
53+
54+
var foilz_write_buf: [1024]u8 = undefined;
55+
var foilz_writer = arch_file.writer(&foilz_write_buf);
56+
const writer = &foilz_writer.interface;
5657

5758
var dir = try fs.openDirAbsolute(path, .{ .access_sub_paths = true, .iterate = true });
58-
var walker = try dir.walk(allocator);
59+
defer dir.close();
60+
61+
var walker = try dir.walk(arena);
62+
defer walker.deinit();
5963

6064
var count: u32 = 0;
6165

62-
try write_magic_number(&foilz_writer);
66+
try writer.writeAll(MAGIC);
6367

6468
while (try walker.next()) |entry| {
6569
if (entry.kind == .file) {
@@ -73,67 +77,44 @@ pub fn pack_directory(path: []const u8, archive_path: []const u8) anyerror!void
7377
const index = dest_buff[0..replacement_size];
7478
_ = mem.replace(u8, entry.path, needle, replacement, index);
7579

76-
// Read the entire contents of the file into a buffer
7780
const file = try entry.dir.openFile(entry.basename, .{});
7881
defer file.close();
7982

80-
// Allocate memory for the file
81-
var file_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
82-
defer file_arena.deinit();
83-
const file_allocator = file_arena.allocator();
83+
var read_buf: [1024]u8 = undefined;
84+
var file_reader = file.reader(&read_buf);
85+
const reader = &file_reader.interface;
8486

85-
// Read the file
86-
const file_buffer = try file.readToEndAlloc(file_allocator, MAX_READ_SIZE);
8787
const stat = try file.stat();
8888

8989
// Write file record to archive
90-
try write_file_record(&foilz_writer, index, file_buffer, stat.mode);
90+
const name = index;
91+
try writer.writeInt(u64, name.len, .little);
92+
try writer.writeAll(name);
93+
try writer.writeInt(u64, stat.size, .little);
94+
if (stat.size > 0) {
95+
assert(stat.size == try reader.streamRemaining(writer));
96+
}
97+
try writer.writeInt(usize, stat.mode, .little);
9198

92-
count = count + 1;
99+
count += 1;
93100

94101
direct_log("\rinfo: 🔍 Files Packed: {}", .{count});
95102
}
96103
}
97104
direct_log("\n", .{});
98105

99106
// Log success
100-
log.info("Archived {} files into payload! 📥", .{count});
101-
102-
// Clean up memory
103-
walker.deinit();
104-
105-
// Close the archive file
106-
try write_magic_number(&foilz_writer);
107-
108-
arch_file.close();
109-
}
110-
111-
pub fn write_magic_number(foilz_writer: *const fs.File.Writer) !void {
112-
_ = try foilz_writer.write(MAGIC);
113-
}
114107

115-
pub fn write_file_record(foilz_writer: *const fs.File.Writer, name: []const u8, data: []const u8, mode: usize) !void {
116-
_ = try foilz_writer.writeInt(u64, name.len, .little);
117-
_ = try foilz_writer.write(name);
118-
_ = try foilz_writer.writeInt(u64, data.len, .little);
119-
if (data.len > 0) {
120-
_ = try foilz_writer.write(data);
121-
}
122-
_ = try foilz_writer.writeInt(usize, mode, .little);
123-
}
108+
try writer.writeAll(MAGIC);
109+
try writer.flush();
124110

125-
pub fn validate_magic(first_bytes: []const u8) bool {
126-
return mem.eql(u8, first_bytes, MAGIC);
111+
log.info("Archived {} files into payload! 📥", .{count});
127112
}
128113

129-
pub fn unpack_files(data: []const u8, dest_path: []const u8, uncompressed_size: u64) !void {
114+
pub fn unpack_files(arena: Allocator, data: []const u8, dest_path: []const u8, uncompressed_size: u64) !void {
130115
// Decompress the data in the payload
131116

132-
var decompress_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
133-
defer decompress_arena.deinit();
134-
var allocator = decompress_arena.allocator();
135-
136-
var decompressed: []u8 = try allocator.alloc(u8, uncompressed_size);
117+
var decompressed: []u8 = try arena.alloc(u8, uncompressed_size);
137118

138119
var xz_buffer: xz.xz_buf = .{
139120
.in = data.ptr,
@@ -155,7 +136,7 @@ pub fn unpack_files(data: []const u8, dest_path: []const u8, uncompressed_size:
155136
}
156137

157138
// Validate the header of the payload
158-
if (!validate_magic(decompressed[0..5])) {
139+
if (!std.mem.eql(u8, MAGIC, decompressed[0..5])) {
159140
return error.BadHeader;
160141
}
161142

@@ -190,12 +171,12 @@ pub fn unpack_files(data: []const u8, dest_path: []const u8, uncompressed_size:
190171

191172
//////
192173
// Write the file
193-
const full_file_path = try fs.path.join(allocator, &[_][]const u8{ dest_path[0..], file_name });
174+
const full_file_path = try fs.path.join(arena, &[_][]const u8{ dest_path[0..], file_name });
194175

195176
//////
196177
// Create any directories needed
197178
const dir_name = fs.path.dirname(file_name);
198-
if (dir_name != null) try create_dirs(dest_path[0..], dir_name.?, allocator);
179+
if (dir_name != null) try create_dirs(dest_path[0..], dir_name.?, arena);
199180

200181
log.debug("Unpacked File: {s}", .{full_file_path});
201182

@@ -223,7 +204,7 @@ pub fn unpack_files(data: []const u8, dest_path: []const u8, uncompressed_size:
223204
log.debug("Unpacked {} files", .{file_count});
224205
}
225206

226-
fn create_dirs(dest_path: []const u8, sub_dir_names: []const u8, allocator: std.mem.Allocator) !void {
207+
fn create_dirs(dest_path: []const u8, sub_dir_names: []const u8, allocator: Allocator) !void {
227208
var iterator = try fs.path.componentIterator(sub_dir_names);
228209
var full_dir_path = try fs.path.join(allocator, &[_][]const u8{ dest_path, "" });
229210

@@ -244,8 +225,11 @@ fn create_dirs(dest_path: []const u8, sub_dir_names: []const u8, allocator: std.
244225

245226
// Adapted from `std.log`, but without forcing a newline
246227
fn direct_log(comptime message: []const u8, args: anytype) void {
247-
std.debug.lockStdErr();
248-
defer std.debug.unlockStdErr();
249-
const stderr = std.io.getStdErr().writer(); // Using the same IO as `std.log`
250-
nosuspend stderr.print(message, args) catch return;
228+
var buffer: [64]u8 = undefined;
229+
const stderr = std.debug.lockStderrWriter(&buffer);
230+
defer std.debug.unlockStderrWriter();
231+
nosuspend {
232+
stderr.print(message, args) catch return;
233+
stderr.flush() catch return;
234+
}
251235
}

src/erlang_launcher.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ pub fn launch(install_dir: []const u8, env_map: *EnvMap, meta: *const MetaStruct
9999
} else {
100100
const final_args = try std.mem.concat(allocator, []const u8, &.{ erlang_cli, args_trimmed });
101101

102-
log.debug("CLI List: {s}", .{final_args});
102+
log.debug("CLI List: {any}", .{final_args});
103103

104104
var erl_env_map = EnvMap.init(allocator);
105105
defer erl_env_map.deinit();

0 commit comments

Comments
 (0)