mirror of
https://github.com/Tilo-K/csvu.git
synced 2026-07-03 11:43:02 +00:00
Upgrade csvu to Zig 0.16 (#2)
* Port source to Zig 0.16 * Declare Zig 0.16 toolchain * ci: add pr verification
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.zig text eol=lf
|
||||||
|
*.zig.zon text eol=lf
|
||||||
37
.github/workflows/ci.yaml
vendored
Normal file
37
.github/workflows/ci.yaml
vendored
Normal file
@@ -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
|
||||||
9
.github/workflows/release.yaml
vendored
9
.github/workflows/release.yaml
vendored
@@ -51,20 +51,19 @@ jobs:
|
|||||||
- name: Install Zig
|
- name: Install Zig
|
||||||
uses: mlugg/setup-zig@v2
|
uses: mlugg/setup-zig@v2
|
||||||
with:
|
with:
|
||||||
version: 0.15.0
|
version: 0.16.0
|
||||||
|
|
||||||
- name: Build for ${{ matrix.triple }}
|
- name: Build for ${{ matrix.triple }}
|
||||||
run: |
|
run: |
|
||||||
zig build-exe "${SRC}" \
|
zig build \
|
||||||
-Dtarget=${{ matrix.triple }} \
|
-Dtarget=${{ matrix.triple }} \
|
||||||
-O ReleaseSafe \
|
-Doptimize=ReleaseSafe
|
||||||
-femit-bin="${BINARY_NAME}${{ matrix.ext }}"
|
|
||||||
|
|
||||||
- name: Package binary
|
- name: Package binary
|
||||||
run: |
|
run: |
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
zip -j artifacts/"${BINARY_NAME}-${{ github.ref_name }}-${{ matrix.triple }}.zip" \
|
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
|
- name: Upload release asset
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
|
|||||||
@@ -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:
|
Before getting started with csvu, ensure your runtime environment meets the following requirements:
|
||||||
|
|
||||||
- **Programming Language:** Zig
|
- **Programming Language:** Zig
|
||||||
- **Zig Version:** 0.14.0 or later
|
- **Zig Version:** 0.16.0 or later
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
|
|||||||
11
build.zig
11
build.zig
@@ -73,6 +73,16 @@ pub fn build(b: *std.Build) void {
|
|||||||
|
|
||||||
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
|
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(.{
|
const exe_unit_tests = b.addTest(.{
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/main.zig"),
|
||||||
@@ -88,5 +98,6 @@ pub fn build(b: *std.Build) void {
|
|||||||
// running the unit tests.
|
// running the unit tests.
|
||||||
const test_step = b.step("test", "Run unit tests");
|
const test_step = b.step("test", "Run unit tests");
|
||||||
test_step.dependOn(&run_lib_unit_tests.step);
|
test_step.dependOn(&run_lib_unit_tests.step);
|
||||||
|
test_step.dependOn(&run_csv_unit_tests.step);
|
||||||
test_step.dependOn(&run_exe_unit_tests.step);
|
test_step.dependOn(&run_exe_unit_tests.step);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
// This field is optional.
|
// This field is optional.
|
||||||
// This is currently advisory only; Zig does not yet do anything
|
// This is currently advisory only; Zig does not yet do anything
|
||||||
// with this value.
|
// with this value.
|
||||||
//.minimum_zig_version = "0.11.0",
|
.minimum_zig_version = "0.16.0",
|
||||||
|
|
||||||
// This field is optional.
|
// This field is optional.
|
||||||
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
||||||
|
|||||||
52
src/csv.zig
52
src/csv.zig
@@ -1,5 +1,4 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const term = @import("term.zig");
|
|
||||||
|
|
||||||
const CsvError = error{
|
const CsvError = error{
|
||||||
NoDelimiterFound,
|
NoDelimiterFound,
|
||||||
@@ -16,7 +15,7 @@ fn contains(arr: []const u8, target: u8) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn determineDelimiter(str: []const u8) !u8 {
|
pub fn determineDelimiter(str: []const u8) !u8 {
|
||||||
var allocator = std.heap.GeneralPurposeAllocator(.{}){};
|
var allocator = std.heap.DebugAllocator(.{}){};
|
||||||
defer _ = allocator.deinit();
|
defer _ = allocator.deinit();
|
||||||
const alloc = allocator.allocator();
|
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_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;
|
var stdout = &stdout_writer.interface;
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
_ = stdout.flush() catch null;
|
_ = stdout.flush() catch null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.DebugAllocator(.{}){};
|
||||||
defer {
|
defer {
|
||||||
_ = gpa.deinit();
|
_ = gpa.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
const alloc = gpa.allocator();
|
const alloc = gpa.allocator();
|
||||||
const dimensions = try term.getTerminalDimensions();
|
|
||||||
const col_nums = file.header.items.len;
|
const col_nums = file.header.items.len;
|
||||||
const col_sizes = try alloc.alloc(usize, col_nums);
|
const col_sizes = try alloc.alloc(usize, col_nums);
|
||||||
defer alloc.free(col_sizes);
|
defer alloc.free(col_sizes);
|
||||||
@@ -120,8 +118,6 @@ pub fn printTable(file: CsvFile) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = dimensions;
|
|
||||||
|
|
||||||
var complete_length = col_nums + 1;
|
var complete_length = col_nums + 1;
|
||||||
for (col_sizes) |col_size| {
|
for (col_sizes) |col_size| {
|
||||||
complete_length += col_size;
|
complete_length += col_size;
|
||||||
@@ -152,7 +148,7 @@ pub fn printTable(file: CsvFile) !void {
|
|||||||
try stdout.print("\n", .{});
|
try stdout.print("\n", .{});
|
||||||
|
|
||||||
for (file.entries.items) |entry| {
|
for (file.entries.items) |entry| {
|
||||||
var out_line = std.ArrayList(u8){};
|
var out_line: std.ArrayList(u8) = .empty;
|
||||||
defer out_line.deinit(alloc);
|
defer out_line.deinit(alloc);
|
||||||
|
|
||||||
try out_line.appendSlice(alloc, "|");
|
try out_line.appendSlice(alloc, "|");
|
||||||
@@ -178,36 +174,35 @@ pub fn printTable(file: CsvFile) !void {
|
|||||||
try stdout.print("\n", .{});
|
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_buf: [4096]u8 = undefined;
|
||||||
|
|
||||||
var file = try std.fs.cwd().openFile(filepath, .{ .mode = .read_write });
|
var file = try std.Io.Dir.cwd().openFile(io, filepath, .{ .mode = .read_write });
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
var file_reader = file.reader(&file_buf);
|
var file_reader = file.readerStreaming(io, &file_buf);
|
||||||
const in_stream = &file_reader.interface;
|
const in_stream = &file_reader.interface;
|
||||||
|
|
||||||
var readHeader = false;
|
var readHeader = false;
|
||||||
var headerList: std.ArrayList([]const u8) = undefined;
|
var headerList: std.ArrayList([]const u8) = undefined;
|
||||||
var entries = std.ArrayList(std.ArrayList([]const u8)){};
|
var entries: std.ArrayList(std.ArrayList([]const u8)) = .empty;
|
||||||
var lines = std.ArrayList([]const u8){};
|
var lines: std.ArrayList([]const u8) = .empty;
|
||||||
|
|
||||||
var delimiter: u8 = ' ';
|
var delimiter: u8 = ' ';
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const line = in_stream.takeDelimiterExclusive('\n') catch |err| {
|
const line = in_stream.takeDelimiter('\n') catch |err| switch (err) {
|
||||||
if (err == error.EndOfStream) {
|
error.ReadFailed => return file_reader.err.?,
|
||||||
break;
|
else => return err,
|
||||||
}
|
|
||||||
return err;
|
|
||||||
};
|
};
|
||||||
|
if (line == null) break;
|
||||||
|
|
||||||
if (delimiter == ' ') {
|
if (delimiter == ' ') {
|
||||||
delimiter = try determineDelimiter(line);
|
delimiter = try determineDelimiter(line.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
const del = delimiter;
|
const del = delimiter;
|
||||||
var entr = std.ArrayList([]const u8){};
|
var entr: std.ArrayList([]const u8) = .empty;
|
||||||
var splitIt = std.mem.splitSequence(u8, line, &[_]u8{del});
|
var splitIt = std.mem.splitSequence(u8, line.?, &[_]u8{del});
|
||||||
|
|
||||||
while (splitIt.next()) |part| {
|
while (splitIt.next()) |part| {
|
||||||
const dest = try alloc.alloc(u8, part.len);
|
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" {
|
test "Determine delimiter" {
|
||||||
const del = try determineDelimiter("this,is,a,test");
|
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");
|
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.expectError(
|
||||||
try std.testing.expect(err == CsvError.NoDelimiterFound);
|
CsvError.NoDelimiterFound,
|
||||||
};
|
determineDelimiter("This does not have an delimiter"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/main.zig
12
src/main.zig
@@ -1,16 +1,16 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const csv = @import("csv.zig");
|
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_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 stdout = &stdout_writer.interface;
|
||||||
|
|
||||||
var allocator = std.heap.GeneralPurposeAllocator(.{}){};
|
var allocator = std.heap.DebugAllocator(.{}){};
|
||||||
defer _ = allocator.deinit();
|
defer _ = allocator.deinit();
|
||||||
const alloc = allocator.allocator();
|
const alloc = allocator.allocator();
|
||||||
|
|
||||||
var args = try std.process.ArgIterator.initWithAllocator(alloc);
|
var args = try init.minimal.args.iterateAllocator(alloc);
|
||||||
defer args.deinit();
|
defer args.deinit();
|
||||||
|
|
||||||
_ = args.next();
|
_ = args.next();
|
||||||
@@ -27,7 +27,7 @@ pub fn main() !void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var file = try csv.loadFile(filepath, alloc);
|
var file = try csv.loadFile(init.io, filepath, alloc);
|
||||||
defer file.deinit();
|
defer file.deinit();
|
||||||
|
|
||||||
const valid = file.isValid();
|
const valid = file.isValid();
|
||||||
@@ -35,6 +35,6 @@ pub fn main() !void {
|
|||||||
|
|
||||||
_ = try stdout.flush();
|
_ = try stdout.flush();
|
||||||
|
|
||||||
try csv.printTable(file);
|
try csv.printTable(init.io, file);
|
||||||
_ = try stdout.flush();
|
_ = try stdout.flush();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user