From 1b5ad2bc40918a5bbdce6a0aba78a03a0c523cb9 Mon Sep 17 00:00:00 2001 From: Tilo Date: Sun, 31 May 2026 18:27:09 +0200 Subject: [PATCH] Upgrade csvu to Zig 0.16 (#2) * Port source to Zig 0.16 * Declare Zig 0.16 toolchain * ci: add pr verification --- .gitattributes | 2 ++ .github/workflows/ci.yaml | 37 ++++++++++++++++++++++++ .github/workflows/release.yaml | 9 +++--- README.md | 2 +- build.zig | 11 +++++++ build.zig.zon | 2 +- src/csv.zig | 52 ++++++++++++++++------------------ src/main.zig | 12 ++++---- 8 files changed, 86 insertions(+), 41 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/workflows/ci.yaml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8984289 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.zig text eol=lf +*.zig.zon text eol=lf diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..01ae753 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,37 @@ +name: CI + +on: + pull_request: + branches: + - master + push: + branches: + - master + +permissions: + contents: read + +jobs: + verify: + name: Format, Test, Build + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Zig + uses: mlugg/setup-zig@v2 + with: + version: 0.16.0 + + - name: Check formatting + run: zig fmt --check . + + - name: Run tests + run: zig build test + + - name: Build + run: zig build + + - name: Build release mode + run: zig build -Doptimize=ReleaseSafe diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7f2e361..cb32655 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -51,20 +51,19 @@ jobs: - name: Install Zig uses: mlugg/setup-zig@v2 with: - version: 0.15.0 + version: 0.16.0 - name: Build for ${{ matrix.triple }} run: | - zig build-exe "${SRC}" \ + zig build \ -Dtarget=${{ matrix.triple }} \ - -O ReleaseSafe \ - -femit-bin="${BINARY_NAME}${{ matrix.ext }}" + -Doptimize=ReleaseSafe - name: Package binary run: | mkdir -p artifacts zip -j artifacts/"${BINARY_NAME}-${{ github.ref_name }}-${{ matrix.triple }}.zip" \ - "${BINARY_NAME}${{ matrix.ext }}" + "zig-out/bin/${BINARY_NAME}${{ matrix.ext }}" - name: Upload release asset uses: actions/upload-release-asset@v1 diff --git a/README.md b/README.md index 8df5824..e4501f5 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ The csvu is a dynamic CSV utility designed to streamline data handling. It effec Before getting started with csvu, ensure your runtime environment meets the following requirements: - **Programming Language:** Zig -- **Zig Version:** 0.14.0 or later +- **Zig Version:** 0.16.0 or later ### Installation diff --git a/build.zig b/build.zig index 25b6d48..7e5e47e 100644 --- a/build.zig +++ b/build.zig @@ -73,6 +73,16 @@ pub fn build(b: *std.Build) void { const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + const csv_unit_tests = b.addTest(.{ + .root_module = b.createModule(.{ + .root_source_file = b.path("src/csv.zig"), + .target = target, + .optimize = optimize, + }), + }); + + const run_csv_unit_tests = b.addRunArtifact(csv_unit_tests); + const exe_unit_tests = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), @@ -88,5 +98,6 @@ pub fn build(b: *std.Build) void { // running the unit tests. const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&run_lib_unit_tests.step); + test_step.dependOn(&run_csv_unit_tests.step); test_step.dependOn(&run_exe_unit_tests.step); } diff --git a/build.zig.zon b/build.zig.zon index 86b3b82..0a34b82 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -17,7 +17,7 @@ // This field is optional. // This is currently advisory only; Zig does not yet do anything // with this value. - //.minimum_zig_version = "0.11.0", + .minimum_zig_version = "0.16.0", // This field is optional. // Each dependency must either provide a `url` and `hash`, or a `path`. diff --git a/src/csv.zig b/src/csv.zig index a7a0706..918e39a 100644 --- a/src/csv.zig +++ b/src/csv.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const term = @import("term.zig"); const CsvError = error{ NoDelimiterFound, @@ -16,7 +15,7 @@ fn contains(arr: []const u8, target: u8) bool { } pub fn determineDelimiter(str: []const u8) !u8 { - var allocator = std.heap.GeneralPurposeAllocator(.{}){}; + var allocator = std.heap.DebugAllocator(.{}){}; defer _ = allocator.deinit(); const alloc = allocator.allocator(); @@ -88,22 +87,21 @@ const CsvFile = struct { } }; -pub fn printTable(file: CsvFile) !void { +pub fn printTable(io: std.Io, file: CsvFile) !void { var stdout_buf: [1024]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writer(&stdout_buf); + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &stdout_buf); var stdout = &stdout_writer.interface; defer { _ = stdout.flush() catch null; } - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + var gpa = std.heap.DebugAllocator(.{}){}; defer { _ = gpa.deinit(); } const alloc = gpa.allocator(); - const dimensions = try term.getTerminalDimensions(); const col_nums = file.header.items.len; const col_sizes = try alloc.alloc(usize, col_nums); defer alloc.free(col_sizes); @@ -120,8 +118,6 @@ pub fn printTable(file: CsvFile) !void { } } - _ = dimensions; - var complete_length = col_nums + 1; for (col_sizes) |col_size| { complete_length += col_size; @@ -152,7 +148,7 @@ pub fn printTable(file: CsvFile) !void { try stdout.print("\n", .{}); for (file.entries.items) |entry| { - var out_line = std.ArrayList(u8){}; + var out_line: std.ArrayList(u8) = .empty; defer out_line.deinit(alloc); try out_line.appendSlice(alloc, "|"); @@ -178,36 +174,35 @@ pub fn printTable(file: CsvFile) !void { try stdout.print("\n", .{}); } -pub fn loadFile(filepath: []const u8, alloc: std.mem.Allocator) !CsvFile { +pub fn loadFile(io: std.Io, filepath: []const u8, alloc: std.mem.Allocator) !CsvFile { var file_buf: [4096]u8 = undefined; - var file = try std.fs.cwd().openFile(filepath, .{ .mode = .read_write }); - defer file.close(); - var file_reader = file.reader(&file_buf); + var file = try std.Io.Dir.cwd().openFile(io, filepath, .{ .mode = .read_write }); + defer file.close(io); + var file_reader = file.readerStreaming(io, &file_buf); const in_stream = &file_reader.interface; var readHeader = false; var headerList: std.ArrayList([]const u8) = undefined; - var entries = std.ArrayList(std.ArrayList([]const u8)){}; - var lines = std.ArrayList([]const u8){}; + var entries: std.ArrayList(std.ArrayList([]const u8)) = .empty; + var lines: std.ArrayList([]const u8) = .empty; var delimiter: u8 = ' '; while (true) { - const line = in_stream.takeDelimiterExclusive('\n') catch |err| { - if (err == error.EndOfStream) { - break; - } - return err; + const line = in_stream.takeDelimiter('\n') catch |err| switch (err) { + error.ReadFailed => return file_reader.err.?, + else => return err, }; + if (line == null) break; if (delimiter == ' ') { - delimiter = try determineDelimiter(line); + delimiter = try determineDelimiter(line.?); } const del = delimiter; - var entr = std.ArrayList([]const u8){}; - var splitIt = std.mem.splitSequence(u8, line, &[_]u8{del}); + var entr: std.ArrayList([]const u8) = .empty; + var splitIt = std.mem.splitSequence(u8, line.?, &[_]u8{del}); while (splitIt.next()) |part| { const dest = try alloc.alloc(u8, part.len); @@ -232,12 +227,13 @@ pub fn loadFile(filepath: []const u8, alloc: std.mem.Allocator) !CsvFile { test "Determine delimiter" { const del = try determineDelimiter("this,is,a,test"); - std.testing.expect(del == ','); + try std.testing.expect(del == ','); const del2 = try determineDelimiter("th#is; is,a; test; with,many;symbols"); - std.testing.expect(del2 == ';'); + try std.testing.expect(del2 == ';'); - determineDelimiter("This does not have an delimiter") catch |err| { - try std.testing.expect(err == CsvError.NoDelimiterFound); - }; + try std.testing.expectError( + CsvError.NoDelimiterFound, + determineDelimiter("This does not have an delimiter"), + ); } diff --git a/src/main.zig b/src/main.zig index 499d7a2..648f8ba 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,16 +1,16 @@ const std = @import("std"); const csv = @import("csv.zig"); -pub fn main() !void { +pub fn main(init: std.process.Init) !void { var stdout_buf: [1024]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writer(&stdout_buf); + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &stdout_buf); var stdout = &stdout_writer.interface; - var allocator = std.heap.GeneralPurposeAllocator(.{}){}; + var allocator = std.heap.DebugAllocator(.{}){}; defer _ = allocator.deinit(); const alloc = allocator.allocator(); - var args = try std.process.ArgIterator.initWithAllocator(alloc); + var args = try init.minimal.args.iterateAllocator(alloc); defer args.deinit(); _ = args.next(); @@ -27,7 +27,7 @@ pub fn main() !void { return; } - var file = try csv.loadFile(filepath, alloc); + var file = try csv.loadFile(init.io, filepath, alloc); defer file.deinit(); const valid = file.isValid(); @@ -35,6 +35,6 @@ pub fn main() !void { _ = try stdout.flush(); - try csv.printTable(file); + try csv.printTable(init.io, file); _ = try stdout.flush(); }