diff --git a/.woodpecker.yml b/.woodpecker.yml index 0dfa225..849f6f1 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -9,27 +9,27 @@ clone: recursive: false pipeline: lint: - image: git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1 commands: - ./tools/fmt-check.sh test: - image: git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1 commands: - zig build test sdl2: - image: git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1 commands: - zig build -Ddriver=sdl2 x11: - image: git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1 commands: - zig build -Ddriver=x11 aarch64: - image: git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1 commands: - zig build -Ddriver=fbev -Dtarget=aarch64-linux-musl -Doptimize=ReleaseSafe -Dstrip - sha256sum zig-out/bin/nd zig-out/bin/ngui playground: - image: git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1 commands: - zig build guiplay btcrpc lndhc diff --git a/README.md b/README.md index 9a26726..f427ed2 100644 --- a/README.md +++ b/README.md @@ -61,17 +61,17 @@ to make a new image and switch the CI to use it, first modify the [ci-containerfile](tools/ci-containerfile) and produce the image locally: podman build --rm -t ndg-ci -f ./tools/ci-containerfile \ - --build-arg ZIGURL=https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz + --build-arg ZIGURL=https://ziglang.org/download/0.12.0/zig-linux-x86_64-0.12.0.tar.xz then tag it with the target URL, for example: - podman tag localhost/ndg-ci git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + podman tag localhost/ndg-ci git.qcode.ch/nakamochi/ci-zig0.12.0:v1 generate an [access token](https://git.qcode.ch/user/settings/applications), login to the container registry and push the image to remote: podman login git.qcode.ch - podman push git.qcode.ch/nakamochi/ci-zig0.11.0:v2 + podman push git.qcode.ch/nakamochi/ci-zig0.12.0:v1 the image will be available at https://git.qcode.ch/nakamochi/-/packages/ diff --git a/build.zig b/build.zig index 92a8e28..ac00456 100644 --- a/build.zig +++ b/build.zig @@ -11,18 +11,16 @@ pub fn build(b: *std.Build) void { const inver = b.option([]const u8, "version", "semantic version of the build; must match git tag when available"); const buildopts = b.addOptions(); + const buildopts_mod = buildopts.createModule(); buildopts.addOption(DriverTarget, "driver", drv); const semver_step = VersionStep.create(b, buildopts, inver); buildopts.step.dependOn(semver_step); // network interface (nif) standalone library used by the daemon and tests. - const libnif_dep = b.anonymousDependency("lib/nif", @import("lib/nif/build.zig"), .{ - .target = target, - .optimize = optimize, - }); + const libnif_dep = b.lazyDependency("nif", .{ .target = target, .optimize = optimize }) orelse return; const libnif = libnif_dep.artifact("nif"); // ini file format parser - const libini = b.addModule("ini", .{ .source_file = .{ .path = "lib/ini/src/ini.zig" } }); + const libini_dep = b.lazyDependency("ini", .{ .target = target, .optimize = optimize }) orelse return; const common_cflags = .{ "-Wall", @@ -35,16 +33,16 @@ pub fn build(b: *std.Build) void { // gui build const ngui = b.addExecutable(.{ .name = "ngui", - .root_source_file = .{ .path = "src/ngui.zig" }, + .root_source_file = b.path("src/ngui.zig"), .target = target, .optimize = optimize, .link_libc = true, + .strip = strip, }); ngui.pie = true; - ngui.strip = strip; - ngui.addOptions("build_options", buildopts); - ngui.addIncludePath(.{ .path = "lib" }); - ngui.addIncludePath(.{ .path = "src/ui/c" }); + ngui.root_module.addImport("build_options", buildopts_mod); + ngui.addIncludePath(b.path("lib")); + ngui.addIncludePath(b.path("src/ui/c")); const lvgl_flags = .{ "-std=c11", @@ -52,7 +50,7 @@ pub fn build(b: *std.Build) void { "-Wformat", "-Wformat-security", } ++ common_cflags; - ngui.addCSourceFiles(lvgl_generic_src, &lvgl_flags); + ngui.addCSourceFiles(.{ .files = lvgl_generic_src, .flags = &lvgl_flags }); const ngui_cflags = .{ "-std=c11", @@ -60,39 +58,46 @@ pub fn build(b: *std.Build) void { "-Wunused-parameter", "-Werror", } ++ common_cflags; - ngui.addCSourceFiles(&.{ - "src/ui/c/ui.c", - "src/ui/c/lv_font_courierprimecode_14.c", - "src/ui/c/lv_font_courierprimecode_16.c", - "src/ui/c/lv_font_courierprimecode_24.c", - }, &ngui_cflags); - - ngui.defineCMacroRaw(b.fmt("NM_DISP_HOR={}", .{disp_horiz})); - ngui.defineCMacroRaw(b.fmt("NM_DISP_VER={}", .{disp_vert})); - ngui.defineCMacro("LV_CONF_INCLUDE_SIMPLE", null); + ngui.addCSourceFiles(.{ + .root = b.path("src/ui/c"), + .files = &.{ + "ui.c", + "lv_font_courierprimecode_14.c", + "lv_font_courierprimecode_16.c", + "lv_font_courierprimecode_24.c", + }, + .flags = &ngui_cflags, + }); + + ngui.root_module.addCMacro("NM_DISP_HOR", b.fmt("{d}", .{disp_horiz})); + ngui.root_module.addCMacro("NM_DISP_VER", b.fmt("{d}", .{disp_vert})); + ngui.defineCMacro("LV_CONF_INCLUDE_SIMPLE", "1"); ngui.defineCMacro("LV_LOG_LEVEL", lvgl_loglevel.text()); ngui.defineCMacro("LV_TICK_CUSTOM", "1"); ngui.defineCMacro("LV_TICK_CUSTOM_INCLUDE", "\"lv_custom_tick.h\""); ngui.defineCMacro("LV_TICK_CUSTOM_SYS_TIME_EXPR", "(nm_get_curr_tick())"); switch (drv) { .sdl2 => { - ngui.addCSourceFiles(lvgl_sdl2_src, &lvgl_flags); - ngui.addCSourceFile(.{ .file = .{ .path = "src/ui/c/drv_sdl2.c" }, .flags = &ngui_cflags }); + ngui.addCSourceFiles(.{ .files = lvgl_sdl2_src, .flags = &lvgl_flags }); + ngui.addCSourceFile(.{ .file = b.path("src/ui/c/drv_sdl2.c"), .flags = &ngui_cflags }); ngui.defineCMacro("USE_SDL", "1"); ngui.linkSystemLibrary("SDL2"); }, .x11 => { - ngui.addCSourceFiles(lvgl_x11_src, &lvgl_flags); - ngui.addCSourceFiles(&.{ - "src/ui/c/drv_x11.c", - "src/ui/c/mouse_cursor_icon.c", - }, &ngui_cflags); + ngui.addCSourceFiles(.{ .files = lvgl_x11_src, .flags = &lvgl_flags }); + ngui.addCSourceFiles(.{ + .files = &.{ + "src/ui/c/drv_x11.c", + "src/ui/c/mouse_cursor_icon.c", + }, + .flags = &ngui_cflags, + }); ngui.defineCMacro("USE_X11", "1"); ngui.linkSystemLibrary("X11"); }, .fbev => { - ngui.addCSourceFiles(lvgl_fbev_src, &lvgl_flags); - ngui.addCSourceFile(.{ .file = .{ .path = "src/ui/c/drv_fbev.c" }, .flags = &ngui_cflags }); + ngui.addCSourceFiles(.{ .files = lvgl_fbev_src, .flags = &lvgl_flags }); + ngui.addCSourceFile(.{ .file = b.path("src/ui/c/drv_fbev.c"), .flags = &ngui_cflags }); ngui.defineCMacro("USE_FBDEV", "1"); ngui.defineCMacro("USE_EVDEV", "1"); }, @@ -104,15 +109,15 @@ pub fn build(b: *std.Build) void { // daemon build const nd = b.addExecutable(.{ .name = "nd", - .root_source_file = .{ .path = "src/nd.zig" }, + .root_source_file = b.path("src/nd.zig"), .target = target, .optimize = optimize, + .strip = strip, }); nd.pie = true; - nd.strip = strip; - nd.addOptions("build_options", buildopts); - nd.addModule("nif", libnif_dep.module("nif")); - nd.addModule("ini", libini); + nd.root_module.addImport("build_options", buildopts_mod); + nd.root_module.addImport("nif", libnif_dep.module("nif")); + nd.root_module.addImport("ini", libini_dep.module("ini")); nd.linkLibrary(libnif); const nd_build_step = b.step("nd", "build nd (nakamochi daemon)"); @@ -121,15 +126,15 @@ pub fn build(b: *std.Build) void { // automated tests { const tests = b.addTest(.{ - .root_source_file = .{ .path = "src/test.zig" }, + .root_source_file = b.path("src/test.zig"), .target = target, .optimize = optimize, .link_libc = true, .filter = b.option([]const u8, "test-filter", "run tests matching the filter"), }); - tests.addOptions("build_options", buildopts); - tests.addModule("nif", libnif_dep.module("nif")); - tests.addModule("ini", libini); + tests.root_module.addImport("build_options", buildopts_mod); + tests.root_module.addImport("nif", libnif_dep.module("nif")); + tests.root_module.addImport("ini", libini_dep.module("ini")); tests.linkLibrary(libnif); const run_tests = b.addRunArtifact(tests); @@ -141,11 +146,11 @@ pub fn build(b: *std.Build) void { { const guiplay = b.addExecutable(.{ .name = "guiplay", - .root_source_file = .{ .path = "src/test/guiplay.zig" }, + .root_source_file = b.path("src/test/guiplay.zig"), .target = target, .optimize = optimize, }); - guiplay.addModule("comm", b.createModule(.{ .source_file = .{ .path = "src/comm.zig" } })); + guiplay.root_module.addImport("comm", b.createModule(.{ .root_source_file = b.path("src/comm.zig") })); const guiplay_build_step = b.step("guiplay", "build GUI playground"); guiplay_build_step.dependOn(&b.addInstallArtifact(guiplay, .{}).step); @@ -156,12 +161,12 @@ pub fn build(b: *std.Build) void { { const btcrpc = b.addExecutable(.{ .name = "btcrpc", - .root_source_file = .{ .path = "src/test/btcrpc.zig" }, + .root_source_file = b.path("src/test/btcrpc.zig"), .target = target, .optimize = optimize, + .strip = strip, }); - btcrpc.strip = strip; - btcrpc.addModule("bitcoindrpc", b.createModule(.{ .source_file = .{ .path = "src/bitcoindrpc.zig" } })); + btcrpc.root_module.addImport("bitcoindrpc", b.createModule(.{ .root_source_file = b.path("src/bitcoindrpc.zig") })); const btcrpc_build_step = b.step("btcrpc", "bitcoind RPC client playground"); btcrpc_build_step.dependOn(&b.addInstallArtifact(btcrpc, .{}).step); @@ -171,12 +176,12 @@ pub fn build(b: *std.Build) void { { const lndhc = b.addExecutable(.{ .name = "lndhc", - .root_source_file = .{ .path = "src/test/lndhc.zig" }, + .root_source_file = b.path("src/test/lndhc.zig"), .target = target, .optimize = optimize, + .strip = strip, }); - lndhc.strip = strip; - lndhc.addModule("lightning", b.createModule(.{ .source_file = .{ .path = "src/lightning.zig" } })); + lndhc.root_module.addImport("lightning", b.createModule(.{ .root_source_file = b.path("src/lightning.zig") })); const lndhc_build_step = b.step("lndhc", "lnd HTTP API client playground"); lndhc_build_step.dependOn(&b.addInstallArtifact(lndhc, .{}).step); @@ -423,7 +428,7 @@ const VersionStep = struct { } fn make(step: *std.Build.Step, _: *std.Progress.Node) anyerror!void { - const self = @fieldParentPtr(VersionStep, "step", step); + const self: *@This() = @fieldParentPtr("step", step); const semver = try self.eval(); std.log.info("build version: {any}", .{semver}); self.buildopts.addOption(std.SemanticVersion, "semver", semver); @@ -460,7 +465,7 @@ const VersionStep = struct { const matchTag = self.b.fmt("{s}*.*.*", .{prefix}); const cmd = [_][]const u8{ git, "-C", self.b.pathFromRoot("."), "describe", "--match", matchTag, "--tags", "--abbrev=8" }; var code: u8 = undefined; - const git_describe = self.b.execAllowFail(&cmd, &code, .Ignore) catch return null; + const git_describe = self.b.runAllowFail(&cmd, &code, .Ignore) catch return null; const repotag = std.mem.trim(u8, git_describe, " \n\r")[prefix.len..]; return std.SemanticVersion.parse(repotag) catch |err| ret: { std.log.err("unparsable git tag semver '{s}': {any}", .{ repotag, err }); diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..326febc --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,17 @@ +.{ + .name = "ndg", + .version = "0.8.1", + .dependencies = .{ + .nif = .{ + .path = "lib/nif", + }, + .ini = .{ + .path = "lib/ini", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/lib/ini/build.zig.zon b/lib/ini/build.zig.zon new file mode 100644 index 0000000..8ff2aeb --- /dev/null +++ b/lib/ini/build.zig.zon @@ -0,0 +1,10 @@ +.{ + .name = "libini", + .version = "0.0.0", + .dependencies = .{}, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/lib/nif/build.zig b/lib/nif/build.zig index 6a32113..307afdb 100644 --- a/lib/nif/build.zig +++ b/lib/nif/build.zig @@ -1,30 +1,33 @@ const std = @import("std"); pub fn build(b: *std.Build) void { - _ = b.addModule("nif", .{ .source_file = .{ .path = "nif.zig" } }); + _ = b.addModule("nif", .{ .root_source_file = b.path("nif.zig") }); const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const lib = b.addStaticLibrary(.{ .name = "nif", - .root_source_file = .{ .path = "nif.zig" }, + .root_source_file = b.path("nif.zig"), .target = target, .optimize = optimize, .link_libc = true, }); lib.defineCMacro("CONFIG_CTRL_IFACE", null); lib.defineCMacro("CONFIG_CTRL_IFACE_UNIX", null); - lib.addIncludePath(.{ .path = "wpa_supplicant" }); - lib.addCSourceFiles(&.{ - "wpa_supplicant/wpa_ctrl.c", - "wpa_supplicant/os_unix.c", - }, &.{ - "-Wall", - "-Wextra", - "-Wshadow", - "-Wundef", - "-Wunused-parameter", - "-Werror", + lib.addIncludePath(b.path("wpa_supplicant")); + lib.addCSourceFiles(.{ + .files = &.{ + "wpa_supplicant/wpa_ctrl.c", + "wpa_supplicant/os_unix.c", + }, + .flags = &.{ + "-Wall", + "-Wextra", + "-Wshadow", + "-Wundef", + "-Wunused-parameter", + "-Werror", + }, }); b.installArtifact(lib); } diff --git a/lib/nif/build.zig.zon b/lib/nif/build.zig.zon new file mode 100644 index 0000000..9b4af6d --- /dev/null +++ b/lib/nif/build.zig.zon @@ -0,0 +1,10 @@ +.{ + .name = "libnif", + .version = "0.0.1", + .dependencies = .{}, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/lib/nif/nif.zig b/lib/nif/nif.zig index e9c6556..c13bef7 100644 --- a/lib/nif/nif.zig +++ b/lib/nif/nif.zig @@ -1,7 +1,7 @@ const std = @import("std"); const mem = std.mem; const net = std.net; -const os = std.os; +const posix = std.posix; pub const wpa = @import("wpa.zig"); @@ -12,11 +12,11 @@ const ifaddrs = extern struct { next: ?*ifaddrs, name: [*:0]const u8, flags: c_uint, // see IFF_xxx SIOCGIFFLAGS in netdevice(7) - addr: ?*std.os.sockaddr, - netmask: ?*std.os.sockaddr, + addr: ?*std.posix.sockaddr, + netmask: ?*std.posix.sockaddr, ifu: extern union { - broad: *os.sockaddr, // flags & IFF_BROADCAST - dst: *os.sockaddr, // flags & IFF_POINTOPOINT + broad: *posix.sockaddr, // flags & IFF_BROADCAST + dst: *posix.sockaddr, // flags & IFF_POINTOPOINT }, data: ?*anyopaque, }; @@ -37,8 +37,8 @@ pub fn pubAddresses(allocator: mem.Allocator, ifname: ?[]const u8) ![]net.Addres var list = std.ArrayList(net.Address).init(allocator); var it: ?*ifaddrs = res; while (it) |ifa| : (it = ifa.next) { - const sa: *os.sockaddr = ifa.addr orelse continue; - if (sa.family != os.AF.INET and sa.family != os.AF.INET6) { + const sa: *posix.sockaddr = ifa.addr orelse continue; + if (sa.family != posix.AF.INET and sa.family != posix.AF.INET6) { // not an IP address continue; } @@ -47,7 +47,7 @@ pub fn pubAddresses(allocator: mem.Allocator, ifname: ?[]const u8) ![]net.Addres continue; } const ipaddr = net.Address.initPosix(@alignCast(sa)); // initPosix makes a copy - if (ipaddr.any.family == os.AF.INET6 and ipaddr.in6.sa.scope_id > 0) { + if (ipaddr.any.family == posix.AF.INET6 and ipaddr.in6.sa.scope_id > 0) { // want only global, with 0 scope // non-zero scopes make sense for link-local addr only. continue; diff --git a/src/bitcoindrpc.zig b/src/bitcoindrpc.zig index d937aa2..ed1fb03 100644 --- a/src/bitcoindrpc.zig +++ b/src/bitcoindrpc.zig @@ -2,7 +2,7 @@ const std = @import("std"); const ArenaAllocator = std.heap.ArenaAllocator; -const Atomic = std.atomic.Atomic; +const Atomic = std.atomic.Value; const base64enc = std.base64.standard.Encoder; const types = @import("types.zig"); @@ -13,7 +13,7 @@ pub const Client = struct { addr: []const u8 = "127.0.0.1", port: u16 = 8332, - // each request gets a new ID with a value of reqid.fetchAdd(1, .Monotonic) + // each request gets a new ID with a value of reqid.fetchAdd(1, .monotonic) reqid: Atomic(u64) = Atomic(u64).init(1), pub const Method = enum { @@ -153,7 +153,7 @@ pub const Client = struct { /// callers own returned value. fn formatreq(self: *Client, comptime m: Method, args: MethodArgs(m)) ![]const u8 { const req = RpcRequest(m){ - .id = self.reqid.fetchAdd(1, .Monotonic), + .id = self.reqid.fetchAdd(1, .monotonic), .method = @tagName(m), .params = args, }; @@ -183,7 +183,7 @@ pub const Client = struct { defer file.close(); const cookie = try file.readToEndAlloc(self.allocator, 1024); defer self.allocator.free(cookie); - var auth = try self.allocator.alloc(u8, base64enc.calcSize(cookie.len)); + const auth = try self.allocator.alloc(u8, base64enc.calcSize(cookie.len)); return base64enc.encode(auth, cookie); } diff --git a/src/comm.zig b/src/comm.zig index ecaece4..c949d51 100644 --- a/src/comm.zig +++ b/src/comm.zig @@ -56,15 +56,15 @@ pub const MessageTag = enum(u16) { ping = 0x01, pong = 0x02, poweroff = 0x03, - wifi_connect = 0x04, - network_report = 0x05, - get_network_report = 0x06, + // nd -> ngui: reports poweroff progress + poweroff_progress = 0x09, // ngui -> nd: screen timeout, no user activity; no reply standby = 0x07, // ngui -> nd: resume screen due to user touch; no reply wakeup = 0x08, - // nd -> ngui: reports poweroff progress - poweroff_progress = 0x09, + wifi_connect = 0x04, + network_report = 0x05, + get_network_report = 0x06, // nd -> ngui: bitcoin core daemon status report onchain_report = 0x0a, // nd -> ngui: lnd status and stats report @@ -103,12 +103,12 @@ pub const Message = union(MessageTag) { ping: void, pong: void, poweroff: void, + poweroff_progress: PoweroffProgress, standby: void, wakeup: void, wifi_connect: WifiConnect, network_report: NetworkReport, get_network_report: GetNetworkReport, - poweroff_progress: PoweroffProgress, onchain_report: OnchainReport, lightning_report: LightningReport, lightning_error: LightningError, @@ -294,8 +294,8 @@ pub const ParsedMessage = struct { /// callers must deallocate resources with ParsedMessage.deinit when done. pub fn read(allocator: mem.Allocator, reader: anytype) !ParsedMessage { // alternative is @intToEnum(reader.ReadIntLittle(u16)) but it may panic. - const tag = try reader.readEnum(MessageTag, .Little); - const len = try reader.readIntLittle(u64); + const tag = try reader.readEnum(MessageTag, .little); + const len = try reader.readInt(u64, .little); if (len == 0) { return switch (tag) { .lightning_get_ctrlconn => .{ .value = .lightning_get_ctrlconn }, @@ -318,7 +318,7 @@ pub fn read(allocator: mem.Allocator, reader: anytype) !ParsedMessage { .wakeup, => unreachable, // handled above inline else => |t| { - var bytes = try allocator.alloc(u8, len); + const bytes = try allocator.alloc(u8, len); defer allocator.free(bytes); try reader.readNoEof(bytes); @@ -370,8 +370,8 @@ pub fn write(allocator: mem.Allocator, writer: anytype, msg: Message) !void { return Error.CommWriteTooLarge; } - try writer.writeIntLittle(u16, @intFromEnum(msg)); - try writer.writeIntLittle(u64, data.items.len); + try writer.writeInt(u16, @intFromEnum(msg), .little); + try writer.writeInt(u64, data.items.len, .little); try writer.writeAll(data.items); } @@ -401,8 +401,8 @@ test "read" { var buf = std.ArrayList(u8).init(t.allocator); defer buf.deinit(); - try buf.writer().writeIntLittle(u16, @intFromEnum(msg)); - try buf.writer().writeIntLittle(u64, data.items.len); + try buf.writer().writeInt(u16, @intFromEnum(msg), .little); + try buf.writer().writeInt(u64, data.items.len, .little); try buf.writer().writeAll(data.items); var bs = std.io.fixedBufferStream(buf.items); @@ -424,8 +424,8 @@ test "write" { const payload = "{\"ssid\":\"wlan\",\"password\":\"secret\"}"; var js = std.ArrayList(u8).init(t.allocator); defer js.deinit(); - try js.writer().writeIntLittle(u16, @intFromEnum(msg)); - try js.writer().writeIntLittle(u64, payload.len); + try js.writer().writeInt(u16, @intFromEnum(msg), .little); + try js.writer().writeInt(u64, payload.len, .little); try js.appendSlice(payload); try t.expectEqualStrings(js.items, buf.items); @@ -442,8 +442,8 @@ test "write enum" { const payload = "\"edge\""; var js = std.ArrayList(u8).init(t.allocator); defer js.deinit(); - try js.writer().writeIntLittle(u16, @intFromEnum(msg)); - try js.writer().writeIntLittle(u64, payload.len); + try js.writer().writeInt(u16, @intFromEnum(msg), .little); + try js.writer().writeInt(u64, payload.len, .little); try js.appendSlice(payload); try t.expectEqualStrings(js.items, buf.items); diff --git a/src/lightning/LndConf.zig b/src/lightning/LndConf.zig index 7e2a254..3d62d9b 100644 --- a/src/lightning/LndConf.zig +++ b/src/lightning/LndConf.zig @@ -36,7 +36,7 @@ pub const Section = struct { const vdup = try self.alloc.dupe(u8, value); errdefer self.alloc.free(vdup); - var res = try self.props.getOrPut(try self.alloc.dupe(u8, key)); + const res = try self.props.getOrPut(try self.alloc.dupe(u8, key)); if (!res.found_existing) { res.value_ptr.* = .{ .str = vdup }; return; @@ -180,7 +180,7 @@ pub fn appendDefaultSection(self: *LndConf) !*Section { /// the section name ascii is converted to lower case. pub fn appendSection(self: *LndConf, name: []const u8) !*Section { const alloc = self.arena.allocator(); - var low_name = try std.ascii.allocLowerString(alloc, name); + const low_name = try std.ascii.allocLowerString(alloc, name); try self.sections.append(.{ .name = low_name, .props = std.StringArrayHashMap(PropValue).init(alloc), diff --git a/src/lightning/lndhttp.zig b/src/lightning/lndhttp.zig index 656c0c3..f08c7c0 100644 --- a/src/lightning/lndhttp.zig +++ b/src/lightning/lndhttp.zig @@ -143,22 +143,29 @@ pub const Client = struct { pub fn call(self: *Client, comptime apimethod: ApiMethod, args: MethodArgs(apimethod)) !Result(apimethod) { const formatted = try self.formatreq(apimethod, args); defer formatted.deinit(); + + var headersbuf: [8 * 1024]u8 = undefined; const reqinfo = formatted.value; - const opt = std.http.Client.Options{ .handle_redirects = false }; // no redirects in REST API - var req = try self.httpClient.request(reqinfo.httpmethod, reqinfo.url, reqinfo.headers, opt); + const opt = std.http.Client.RequestOptions{ + .redirect_behavior = .not_allowed, // no redirects in REST API + .headers = reqinfo.stdheaders, + .privileged_headers = reqinfo.xheaders, + .server_header_buffer = &headersbuf, + }; + var req = try self.httpClient.open(reqinfo.httpmethod, reqinfo.url, opt); defer req.deinit(); if (reqinfo.payload) |p| { req.transfer_encoding = .{ .content_length = p.len }; } - try req.start(); + try req.send(); if (reqinfo.payload) |p| { - req.writer().writeAll(p) catch return Error.LndPayloadWriteFail; + req.writeAll(p) catch return Error.LndPayloadWriteFail; try req.finish(); } try req.wait(); if (req.response.status.class() != .success) { - // a structured error reporting in lnd is in a less than desirable state. + // a structured error reporting in lnd is unclear: // https://github.com/lightningnetwork/lnd/issues/5586 // TODO: return a more detailed error when the upstream improves. return Error.LndHttpBadStatusCode; @@ -181,8 +188,9 @@ pub const Client = struct { const HttpReqInfo = struct { httpmethod: std.http.Method, url: std.Uri, - headers: std.http.Headers, - payload: ?[]const u8, + stdheaders: std.http.Client.Request.Headers = .{}, // overridable standard headers + xheaders: []const std.http.Header = &.{}, // any extra headers + payload: ?[]const u8 = null, }; fn formatreq(self: Client, comptime apimethod: ApiMethod, args: MethodArgs(apimethod)) !types.Deinitable(HttpReqInfo) { @@ -194,12 +202,10 @@ pub const Client = struct { .genseed, .walletstatus => |m| .{ .httpmethod = .GET, .url = try std.Uri.parse(try std.fmt.allocPrint(arena, "{s}/{s}", .{ self.apibase, m.apipath() })), - .headers = std.http.Headers{ .allocator = arena }, - .payload = null, }, .initwallet => |m| blk: { const payload = p: { - var params: struct { + const params: struct { wallet_password: []const u8, // base64 cipher_seed_mnemonic: []const []const u8, aezeed_passphrase: ?[]const u8 = null, // base64 @@ -215,13 +221,12 @@ pub const Client = struct { break :blk .{ .httpmethod = .POST, .url = try std.Uri.parse(try std.fmt.allocPrint(arena, "{s}/{s}", .{ self.apibase, m.apipath() })), - .headers = std.http.Headers{ .allocator = arena }, .payload = payload, }; }, .unlockwallet => |m| blk: { const payload = p: { - var params: struct { + const params: struct { wallet_password: []const u8, // base64 } = .{ .wallet_password = try base64EncodeAlloc(arena, args.unlock_password), @@ -233,20 +238,19 @@ pub const Client = struct { break :blk .{ .httpmethod = .POST, .url = try std.Uri.parse(try std.fmt.allocPrint(arena, "{s}/{s}", .{ self.apibase, m.apipath() })), - .headers = std.http.Headers{ .allocator = arena }, .payload = payload, }; }, .feereport, .getinfo, .getnetworkinfo, .pendingchannels, .walletbalance => |m| .{ .httpmethod = .GET, .url = try std.Uri.parse(try std.fmt.allocPrint(arena, "{s}/{s}", .{ self.apibase, m.apipath() })), - .headers = blk: { + .xheaders = blk: { if (self.macaroon.readonly == null) { return Error.LndHttpMissingMacaroon; } - var h = std.http.Headers{ .allocator = arena }; - try h.append(authHeaderName, self.macaroon.readonly.?); - break :blk h; + var h = std.ArrayList(std.http.Header).init(arena); + try h.append(.{ .name = authHeaderName, .value = self.macaroon.readonly.? }); + break :blk try h.toOwnedSlice(); }, .payload = null, }, @@ -270,13 +274,13 @@ pub const Client = struct { } break :blk try std.Uri.parse(buf.items); // uri point to the original buf }, - .headers = blk: { + .xheaders = blk: { if (self.macaroon.readonly == null) { return Error.LndHttpMissingMacaroon; } - var h = std.http.Headers{ .allocator = arena }; - try h.append(authHeaderName, self.macaroon.readonly.?); - break :blk h; + var h = std.ArrayList(std.http.Header).init(arena); + try h.append(.{ .name = authHeaderName, .value = self.macaroon.readonly.? }); + break :blk try h.toOwnedSlice(); }, .payload = null, }, @@ -299,7 +303,7 @@ pub const Client = struct { } fn base64EncodeAlloc(gpa: std.mem.Allocator, v: []const u8) ![]const u8 { - var buf = try gpa.alloc(u8, base64enc.calcSize(v.len)); + const buf = try gpa.alloc(u8, base64enc.calcSize(v.len)); return base64enc.encode(buf, v); // always returns a slice of buf.len } }; diff --git a/src/nd.zig b/src/nd.zig index 2fa573f..abf4d56 100644 --- a/src/nd.zig +++ b/src/nd.zig @@ -1,7 +1,6 @@ const buildopts = @import("build_options"); const std = @import("std"); -const os = std.os; -const sys = os.system; +const posix = std.posix; const time = std.time; const Address = std.net.Address; @@ -137,7 +136,7 @@ fn sighandler(sig: c_int) callconv(.C) void { return; } switch (sig) { - os.SIG.INT, os.SIG.TERM => sigquit.set(), + posix.SIG.INT, posix.SIG.TERM => sigquit.set(), else => {}, } } @@ -220,13 +219,13 @@ pub fn main() !void { try nd.start(); // graceful shutdown; see sigaction(2) - const sa = os.Sigaction{ + const sa = posix.Sigaction{ .handler = .{ .handler = sighandler }, - .mask = os.empty_sigset, + .mask = posix.empty_sigset, .flags = 0, }; - try os.sigaction(os.SIG.INT, &sa, null); - try os.sigaction(os.SIG.TERM, &sa, null); + try posix.sigaction(posix.SIG.INT, &sa, null); + try posix.sigaction(posix.SIG.TERM, &sa, null); sigquit.wait(); logger.info("sigquit: terminating ...", .{}); diff --git a/src/nd/Config.zig b/src/nd/Config.zig index bf00d2a..ba6f319 100644 --- a/src/nd/Config.zig +++ b/src/nd/Config.zig @@ -145,7 +145,7 @@ fn inferStaticData(allocator: std.mem.Allocator) !StaticData { } fn inferLndTorHostname(allocator: std.mem.Allocator) ![]const u8 { - var raw = try std.fs.cwd().readFileAlloc(allocator, TOR_DATA_DIR ++ "/lnd/hostname", 1024); + const raw = try std.fs.cwd().readFileAlloc(allocator, TOR_DATA_DIR ++ "/lnd/hostname", 1024); const hostname = std.mem.trim(u8, raw, &std.ascii.whitespace); logger.info("inferred lnd tor hostname: [{s}]", .{hostname}); return hostname; @@ -156,7 +156,7 @@ fn inferBitcoindRpcPass(allocator: std.mem.Allocator) ![]const u8 { // the password was placed on a separate comment line, preceding another comment // line containing "rpcauth.py". // TODO: get rid of the hack; do something more robust - var conf = try std.fs.cwd().readFileAlloc(allocator, BITCOIND_CONFIG_PATH, 1024 * 1024); + const conf = try std.fs.cwd().readFileAlloc(allocator, BITCOIND_CONFIG_PATH, 1024 * 1024); var it = std.mem.tokenizeScalar(u8, conf, '\n'); var next_is_pass = false; while (it.next()) |line| { @@ -346,7 +346,7 @@ fn genSysupdatesCronScript(self: Config) !void { /// /// the caller must serialize this function calls. fn runSysupdates(allocator: std.mem.Allocator, scriptpath: []const u8) !void { - const res = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = &.{scriptpath} }); + const res = try std.ChildProcess.run(.{ .allocator = allocator, .argv = &.{scriptpath} }); defer { allocator.free(res.stdout); allocator.free(res.stderr); @@ -383,7 +383,7 @@ pub fn lndConnectWaitMacaroonFile(self: Config, allocator: std.mem.Allocator, ty defer allocator.free(macaroon); const base64enc = std.base64.url_safe_no_pad.Encoder; - var buf = try allocator.alloc(u8, base64enc.calcSize(macaroon.len)); + const buf = try allocator.alloc(u8, base64enc.calcSize(macaroon.len)); defer allocator.free(buf); const macaroon_b64 = base64enc.encode(buf, macaroon); const port: u16 = switch (typ) { @@ -599,7 +599,7 @@ test "ndconfig: switch sysupdates with .run=true" { const tt = @import("../test.zig"); // no arena deinit here: expecting Config to auto-deinit. - var conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); + const conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); conf_arena.* = std.heap.ArenaAllocator.init(std.testing.allocator); var tmp = try tt.TempDir.create(); defer tmp.cleanup(); @@ -644,7 +644,7 @@ test "ndconfig: genLndConfig" { const tt = @import("../test.zig"); // Config auto-deinits the arena. - var conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); + const conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); conf_arena.* = std.heap.ArenaAllocator.init(std.testing.allocator); var tmp = try tt.TempDir.create(); defer tmp.cleanup(); @@ -695,7 +695,7 @@ test "ndconfig: mutate LndConf" { const tt = @import("../test.zig"); // Config auto-deinits the arena. - var conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); + const conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); conf_arena.* = std.heap.ArenaAllocator.init(t.allocator); var tmp = try tt.TempDir.create(); defer tmp.cleanup(); @@ -737,7 +737,7 @@ test "ndconfig: screen lock" { const tt = @import("../test.zig"); // Config auto-deinits the arena. - var conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); + const conf_arena = try std.testing.allocator.create(std.heap.ArenaAllocator); conf_arena.* = std.heap.ArenaAllocator.init(t.allocator); var tmp = try tt.TempDir.create(); defer tmp.cleanup(); diff --git a/src/nd/Daemon.zig b/src/nd/Daemon.zig index 6bf16c0..7e32982 100644 --- a/src/nd/Daemon.zig +++ b/src/nd/Daemon.zig @@ -548,7 +548,9 @@ fn unlockScreen(self: *Daemon, pincode: []const u8) !void { defer self.allocator.free(pindup); // TODO: slow down self.conf.verifySlockPin(pindup) catch |err| { - logger.err("verifySlockPin: {!}", .{err}); + if (!builtin.is_test) { // logging err makes some tests fail + logger.err("verifySlockPin: {!}", .{err}); + } const errmsg: comm.Message = .{ .screen_unlock_result = .{ .ok = false, .err = if (err == error.IncorrectSlockPin) "incorrect pin code" else "unlock failed", @@ -562,7 +564,7 @@ fn unlockScreen(self: *Daemon, pincode: []const u8) !void { /// sends poweroff progress to uiwriter in comm.Message.PoweroffProgress format. fn sendPoweroffReport(self: *Daemon) !void { - var svstat = try self.allocator.alloc(comm.Message.PoweroffProgress.Service, self.services.list.len); + const svstat = try self.allocator.alloc(comm.Message.PoweroffProgress.Service, self.services.list.len); defer self.allocator.free(svstat); for (self.services.list, svstat) |*sv, *stat| { stat.* = .{ @@ -962,7 +964,7 @@ fn processLndReportError(self: *Daemon, err: anyerror) !void { error.FileNotFound, // tls cert file missing, not re-generated by lnd yet => return comm.write(self.allocator, self.uiwriter, msg_starting), // old tls cert, refused by our http client - std.http.Client.ConnectUnproxiedError.TlsInitializationFailed => { + std.http.Client.ConnectTcpError.TlsInitializationFailed => { try self.resetLndTlsUnguarded(); return error.LndReportRetryLater; }, @@ -1006,7 +1008,7 @@ fn sendLightningPairingConn(self: *Daemon) !void { defer self.allocator.free(tor_rpc); const tor_http = try self.conf.lndConnectWaitMacaroonFile(self.allocator, .tor_http); defer self.allocator.free(tor_http); - var conn: comm.Message.LightningCtrlConn = &.{ + const conn: comm.Message.LightningCtrlConn = &.{ .{ .url = tor_rpc, .typ = .lnd_rpc, .perm = .admin }, .{ .url = tor_http, .typ = .lnd_http, .perm = .admin }, }; @@ -1257,7 +1259,7 @@ fn setNodenameInternal(self: *Daemon, newname: []const u8) !void { /// replaces whitespace with space literal and ignores ascii control chars. /// caller owns returned value. fn allocSanitizeNodename(allocator: std.mem.Allocator, name: []const u8) ![]const u8 { - if (name.len == 0 or try std.unicode.utf8CountCodepoints(name) > std.os.HOST_NAME_MAX) { + if (name.len == 0 or try std.unicode.utf8CountCodepoints(name) > std.posix.HOST_NAME_MAX) { return error.InvalidNodenameLength; } var sanitized = try std.ArrayList(u8).initCapacity(allocator, name.len); @@ -1448,7 +1450,7 @@ test "daemon: screen unlock" { fn dummyTestConfig() !Config { const talloc = std.testing.allocator; - var arena = try talloc.create(std.heap.ArenaAllocator); + const arena = try talloc.create(std.heap.ArenaAllocator); arena.* = std.heap.ArenaAllocator.init(talloc); return Config{ .arena = arena, diff --git a/src/nd/network.zig b/src/nd/network.zig index 610d315..d669afc 100644 --- a/src/nd/network.zig +++ b/src/nd/network.zig @@ -86,7 +86,7 @@ pub fn sendReport(gpa: mem.Allocator, wpa_ctrl: *types.WpaControl, w: anytype) ! }; // fetch available wifi networks from scan results using WPA ctrl - var wifi_networks: ?types.StringList = if (queryWifiScanResults(arena, wpa_ctrl)) |v| v else |err| blk: { + const wifi_networks: ?types.StringList = if (queryWifiScanResults(arena, wpa_ctrl)) |v| v else |err| blk: { logger.err("queryWifiScanResults: {any}", .{err}); break :blk null; }; diff --git a/src/ngui.zig b/src/ngui.zig index bf6db69..2f72f3b 100644 --- a/src/ngui.zig +++ b/src/ngui.zig @@ -1,6 +1,6 @@ const buildopts = @import("build_options"); const std = @import("std"); -const os = std.os; +const posix = std.posix; const time = std.time; const comm = @import("comm.zig"); @@ -291,7 +291,7 @@ fn commThreadLoopCycle() !void { fn uiThreadLoop() void { while (true) { ui_mutex.lock(); - var till_next_ms = lvgl.loopCycle(); // UI loop + const till_next_ms = lvgl.loopCycle(); // UI loop const do_state = state; ui_mutex.unlock(); @@ -391,7 +391,7 @@ fn sighandler(sig: c_int) callconv(.C) void { return; } switch (sig) { - os.SIG.INT, os.SIG.TERM => sigquit.set(), + posix.SIG.INT, posix.SIG.TERM => sigquit.set(), else => {}, } } @@ -440,13 +440,13 @@ pub fn main() anyerror!void { } // set up a sigterm handler for clean exit. - const sa = os.Sigaction{ + const sa = posix.Sigaction{ .handler = .{ .handler = sighandler }, - .mask = os.empty_sigset, + .mask = posix.empty_sigset, .flags = 0, }; - try os.sigaction(os.SIG.INT, &sa, null); - try os.sigaction(os.SIG.TERM, &sa, null); + try posix.sigaction(posix.SIG.INT, &sa, null); + try posix.sigaction(posix.SIG.TERM, &sa, null); sigquit.wait(); logger.info("sigquit: terminating ...", .{}); diff --git a/src/sys/sysimpl.zig b/src/sys/sysimpl.zig index 137a6ab..be38d25 100644 --- a/src/sys/sysimpl.zig +++ b/src/sys/sysimpl.zig @@ -5,8 +5,8 @@ const types = @import("../types.zig"); /// caller owns memory; must dealloc using `allocator`. pub fn hostname(allocator: std.mem.Allocator) ![]const u8 { - var buf: [std.os.HOST_NAME_MAX]u8 = undefined; - const name = try std.os.gethostname(&buf); + var buf: [std.posix.HOST_NAME_MAX]u8 = undefined; + const name = try std.posix.gethostname(&buf); return allocator.dupe(u8, name); } @@ -40,8 +40,8 @@ pub fn setHostname(allocator: std.mem.Allocator, name: []const u8) !void { const newname = sanitized.items; // need not continue if current name matches the new one. - var buf: [std.os.HOST_NAME_MAX]u8 = undefined; - const currname = try std.os.gethostname(&buf); + var buf: [std.posix.HOST_NAME_MAX]u8 = undefined; + const currname = try std.posix.gethostname(&buf); if (std.mem.eql(u8, currname, newname)) { return; } diff --git a/src/test.zig b/src/test.zig index 5fa23e8..4cc583b 100644 --- a/src/test.zig +++ b/src/test.zig @@ -37,7 +37,7 @@ pub fn initGlobal() void { fn initGlobalFn() void { global_gpa_state = std.heap.GeneralPurposeAllocator(.{}){}; global_gpa = global_gpa_state.allocator(); - var pipe = types.IoPipe.create() catch |err| { + const pipe = types.IoPipe.create() catch |err| { std.debug.panic("IoPipe.create: {any}", .{err}); }; comm.initPipe(global_gpa, pipe); @@ -118,7 +118,7 @@ pub const TestChildProcess = struct { argv: []const []const u8, pub fn init(argv: []const []const u8, allocator: std.mem.Allocator) TestChildProcess { - var adup = allocator.alloc([]u8, argv.len) catch unreachable; + const adup = allocator.alloc([]u8, argv.len) catch unreachable; for (argv, adup) |v, *dup| { dup.* = allocator.dupe(u8, v) catch unreachable; } @@ -242,7 +242,7 @@ pub fn expectDeepEqual(expected: anytype, actual: @TypeOf(expected)) !void { .Slice => { switch (@typeInfo(p.child)) { .Pointer, .Struct, .Optional, .Union => { - var err: ?anyerror = blk: { + const err: ?anyerror = blk: { if (expected.len != actual.len) { std.debug.print("expected.len = {d}, actual.len = {d}\n", .{ expected.len, actual.len }); break :blk error.ExpectDeepEqual; @@ -331,6 +331,7 @@ test { _ = @import("ngui.zig"); _ = @import("lightning.zig"); _ = @import("sys.zig"); + _ = @import("xfmt.zig"); std.testing.refAllDecls(@This()); } diff --git a/src/test/guiplay.zig b/src/test/guiplay.zig index c0734c3..db6f807 100644 --- a/src/test/guiplay.zig +++ b/src/test/guiplay.zig @@ -1,6 +1,6 @@ const std = @import("std"); const time = std.time; -const os = std.os; +const posix = std.posix; const comm = @import("comm"); const types = @import("../types.zig"); @@ -12,9 +12,9 @@ var ngui_proc: std.ChildProcess = undefined; var sigquit: std.Thread.ResetEvent = .{}; fn sighandler(sig: c_int) callconv(.C) void { - logger.info("received signal {} (TERM={} INT={})", .{ sig, os.SIG.TERM, os.SIG.INT }); + logger.info("received signal {} (TERM={} INT={})", .{ sig, posix.SIG.TERM, posix.SIG.INT }); switch (sig) { - os.SIG.INT, os.SIG.TERM => sigquit.set(), + posix.SIG.INT, posix.SIG.TERM => sigquit.set(), else => {}, } } @@ -79,7 +79,7 @@ fn parseArgs(gpa: std.mem.Allocator) !Flags { /// global vars for comm read/write threads var state: struct { mu: std.Thread.Mutex = .{}, - nodename: types.BufTrimString(std.os.HOST_NAME_MAX) = .{}, + nodename: types.BufTrimString(std.posix.HOST_NAME_MAX) = .{}, slock_pincode: ?[]const u8 = null, // disabled when null settings_sent: bool = false, @@ -114,7 +114,7 @@ fn commReadThread(gpa: std.mem.Allocator, r: anytype, w: anytype) void { }, .poweroff => { logger.info("sending poweroff status1", .{}); - var s1: comm.Message.PoweroffProgress = .{ .services = &.{ + const s1: comm.Message.PoweroffProgress = .{ .services = &.{ .{ .name = "lnd", .stopped = false, .err = null }, .{ .name = "bitcoind", .stopped = false, .err = null }, } }; @@ -122,7 +122,7 @@ fn commReadThread(gpa: std.mem.Allocator, r: anytype, w: anytype) void { time.sleep(2 * time.ns_per_s); logger.info("sending poweroff status2", .{}); - var s2: comm.Message.PoweroffProgress = .{ .services = &.{ + const s2: comm.Message.PoweroffProgress = .{ .services = &.{ .{ .name = "lnd", .stopped = true, .err = null }, .{ .name = "bitcoind", .stopped = false, .err = null }, } }; @@ -130,7 +130,7 @@ fn commReadThread(gpa: std.mem.Allocator, r: anytype, w: anytype) void { time.sleep(3 * time.ns_per_s); logger.info("sending poweroff status3", .{}); - var s3: comm.Message.PoweroffProgress = .{ .services = &.{ + const s3: comm.Message.PoweroffProgress = .{ .services = &.{ .{ .name = "lnd", .stopped = true, .err = null }, .{ .name = "bitcoind", .stopped = true, .err = null }, } }; @@ -149,7 +149,7 @@ fn commReadThread(gpa: std.mem.Allocator, r: anytype, w: anytype) void { time.sleep(3 * time.ns_per_s); }, .lightning_get_ctrlconn => { - var conn: comm.Message.LightningCtrlConn = &.{ + const conn: comm.Message.LightningCtrlConn = &.{ .{ .url = "lndconnect://adfkjhadwaepoijsadflkjtrpoijawokjafulkjsadfkjhgjfdskjszd.onion:10009?macaroon=Adasjsadkfljhfjhasdpiuhfiuhawfffoihgpoiadsfjharpoiuhfdsgpoihafdsgpoiheafoiuhasdfhisdufhiuhfewiuhfiuhrfl6prrx", .typ = .lnd_rpc, .perm = .admin }, .{ .url = "lndconnect://adfkjhadwaepoijsadflkjtrpoijawokjafulkjsadfkjhgjfdskjszd.onion:10010?macaroon=Adasjsadkfljhfjhasdpiuhfiuhawfffoihgpoiadsfjharpoiuhfdsgpoihafdsgpoiheafoiuhasdfhisdufhiuhfewiuhfiuhrfl6prrx", .typ = .lnd_http, .perm = .admin }, }; @@ -374,13 +374,13 @@ pub fn main() !void { const th2 = try std.Thread.spawn(.{}, commWriteThread, .{ gpa, uiwriter }); th2.detach(); - const sa = os.Sigaction{ + const sa = posix.Sigaction{ .handler = .{ .handler = sighandler }, - .mask = os.empty_sigset, + .mask = posix.empty_sigset, .flags = 0, }; - try os.sigaction(os.SIG.INT, &sa, null); - try os.sigaction(os.SIG.TERM, &sa, null); + try posix.sigaction(posix.SIG.INT, &sa, null); + try posix.sigaction(posix.SIG.TERM, &sa, null); sigquit.wait(); logger.info("killing ngui", .{}); diff --git a/src/types.zig b/src/types.zig index 689567a..d83676f 100644 --- a/src/types.zig +++ b/src/types.zig @@ -40,8 +40,8 @@ pub const IoPipe = struct { w: std.fs.File, /// a pipe must be close'ed when done. - pub fn create() std.os.PipeError!IoPipe { - const fds = try std.os.pipe(); + pub fn create() std.posix.PipeError!IoPipe { + const fds = try std.posix.pipe(); return .{ .r = std.fs.File{ .handle = fds[0] }, .w = std.fs.File{ .handle = fds[1] }, @@ -138,7 +138,7 @@ pub fn Deinitable(comptime T: type) type { const Self = @This(); pub fn init(allocator: std.mem.Allocator) !Self { - var res = Self{ + const res = Self{ .arena = try allocator.create(std.heap.ArenaAllocator), .value = undefined, }; diff --git a/src/ui/drv.zig b/src/ui/drv.zig index bd94f63..18c3fb4 100644 --- a/src/ui/drv.zig +++ b/src/ui/drv.zig @@ -46,9 +46,9 @@ pub usingnamespace switch (buildopts.driver) { } }, .fbev => struct { - extern "c" fn nm_open_evdev_nonblock() std.os.fd_t; - extern "c" fn nm_close_evdev(fd: std.os.fd_t) void; - extern "c" fn nm_consume_input_events(fd: std.os.fd_t) bool; + extern "c" fn nm_open_evdev_nonblock() std.posix.fd_t; + extern "c" fn nm_close_evdev(fd: std.posix.fd_t) void; + extern "c" fn nm_consume_input_events(fd: std.posix.fd_t) bool; pub fn InputWatcher() !EvdevWatcher { const fd = nm_open_evdev_nonblock(); @@ -59,7 +59,7 @@ pub usingnamespace switch (buildopts.driver) { } pub const EvdevWatcher = struct { - evdev_fd: std.os.fd_t, + evdev_fd: std.posix.fd_t, pub fn consume(self: @This()) bool { return nm_consume_input_events(self.evdev_fd); diff --git a/src/ui/lightning.zig b/src/ui/lightning.zig index d178118..778931d 100644 --- a/src/ui/lightning.zig +++ b/src/ui/lightning.zig @@ -99,7 +99,7 @@ var tab: struct { } = null, fn initSetup(self: *@This(), topwin: lvgl.Window) !void { - var arena = try self.allocator.create(std.heap.ArenaAllocator); + const arena = try self.allocator.create(std.heap.ArenaAllocator); arena.* = std.heap.ArenaAllocator.init(tab.allocator); self.seed_setup = .{ .arena = arena, .topwin = topwin }; } diff --git a/src/ui/lvgl.zig b/src/ui/lvgl.zig index 059a163..3283415 100644 --- a/src/ui/lvgl.zig +++ b/src/ui/lvgl.zig @@ -719,7 +719,7 @@ pub const Label = struct { /// the text value is copied into a heap-allocated alloc. pub fn new(parent: anytype, text: ?[*:0]const u8, opt: Opt) !Label { - var lv_label = lv_label_create(parent.lvobj) orelse return error.OutOfMemory; + const lv_label = lv_label_create(parent.lvobj) orelse return error.OutOfMemory; if (text) |s| { lv_label_set_text(lv_label, s); } @@ -757,7 +757,7 @@ pub const Label = struct { /// formats a new label text and passes it on to `setText`. /// the buffer can be dropped once the function returns. pub fn setTextFmt(self: Label, buf: []u8, comptime format: []const u8, args: anytype) !void { - var s = try std.fmt.bufPrintZ(buf, format, args); + const s = try std.fmt.bufPrintZ(buf, format, args); self.setText(s); } diff --git a/src/ui/settings.zig b/src/ui/settings.zig index 53f3932..f646057 100644 --- a/src/ui/settings.zig +++ b/src/ui/settings.zig @@ -75,7 +75,7 @@ var tab: struct { var state: struct { // node name nodename_change_inprogress: bool = false, - curr_nodename: types.BufTrimString(std.os.HOST_NAME_MAX) = .{}, + curr_nodename: types.BufTrimString(std.posix.HOST_NAME_MAX) = .{}, // screenlock slock_pin_input1: ?[]const u8 = null, // verified against a second time input // sysupdates channel @@ -111,7 +111,7 @@ pub fn initNodenamePanel(cont: lvgl.Container) !lvgl.Card { right.setPad(0, .column, .{}); tab.nodename.textarea = try lvgl.TextArea.new(right, .{ - .maxlen = std.os.HOST_NAME_MAX, + .maxlen = std.posix.HOST_NAME_MAX, .oneline = true, }); tab.nodename.textarea.setWidth(lvgl.sizePercent(100)); diff --git a/src/xfmt.zig b/src/xfmt.zig index 0460f86..db7af22 100644 --- a/src/xfmt.zig +++ b/src/xfmt.zig @@ -41,12 +41,11 @@ fn formatUnix(sec: u64, comptime fmt: []const u8, opts: std.fmt.FormatOptions, w } fn formatMetricI(value: i64, comptime fmt: []const u8, opts: std.fmt.FormatOptions, w: anytype) !void { - const uval: u64 = std.math.absCast(value); + const uval: u64 = @abs(value); const base: u64 = 1000; if (uval < base) { return std.fmt.formatIntValue(value, fmt, opts, w); } - if (value < 0) { try w.writeByte('-'); } @@ -64,8 +63,60 @@ fn formatMetricU(value: u64, comptime fmt: []const u8, opts: std.fmt.FormatOptio const mags_si = " kMGTPEZY"; const log2 = std.math.log2(value); const m = @min(log2 / comptime std.math.log2(base), mags_si.len - 1); - const newval = lossyCast(f64, value) / std.math.pow(f64, lossyCast(f64, base), lossyCast(f64, m)); const suffix = mags_si[m]; - try std.fmt.formatFloatDecimal(newval, opts, w); + const newval: f64 = lossyCast(f64, value) / std.math.pow(f64, lossyCast(f64, base), lossyCast(f64, m)); + try std.fmt.formatType(newval, "d", opts, w, 0); try w.writeByte(suffix); } + +test "unix" { + const t = std.testing; + var buf: [1024]u8 = undefined; + var fbs = std.io.fixedBufferStream(&buf); + try std.fmt.format(fbs.writer(), "{}", .{unix(1136239445)}); + try t.expectEqualStrings("2006-01-02 22:04:05 UTC", fbs.getWritten()); +} + +test "imetric" { + const t = std.testing; + var buf: [1024]u8 = undefined; + var fbs = std.io.fixedBufferStream(&buf); + + const table: []const struct { val: i64, str: []const u8 } = &.{ + .{ .val = 0, .str = "0" }, + .{ .val = -13, .str = "-13" }, + .{ .val = 1000, .str = "1k" }, + .{ .val = -1234, .str = "-1.234k" }, + .{ .val = 12340, .str = "12.34k" }, + .{ .val = -123400, .str = "-123.4k" }, + .{ .val = 1234000, .str = "1.234M" }, + .{ .val = -1234000000, .str = "-1.234G" }, + }; + for (table) |item| { + fbs.reset(); + try std.fmt.format(fbs.writer(), "{}", .{imetric(item.val)}); + try t.expectEqualStrings(item.str, fbs.getWritten()); + } +} + +test "umetric" { + const t = std.testing; + var buf: [1024]u8 = undefined; + var fbs = std.io.fixedBufferStream(&buf); + + const table: []const struct { val: u64, str: []const u8 } = &.{ + .{ .val = 0, .str = "0" }, + .{ .val = 13, .str = "13" }, + .{ .val = 1000, .str = "1k" }, + .{ .val = 1234, .str = "1.234k" }, + .{ .val = 12340, .str = "12.34k" }, + .{ .val = 123400, .str = "123.4k" }, + .{ .val = 1234000, .str = "1.234M" }, + .{ .val = 1234000000, .str = "1.234G" }, + }; + for (table) |item| { + fbs.reset(); + try std.fmt.format(fbs.writer(), "{}", .{umetric(item.val)}); + try t.expectEqualStrings(item.str, fbs.getWritten()); + } +} diff --git a/tools/ci-containerfile b/tools/ci-containerfile index 021587d..0b94896 100644 --- a/tools/ci-containerfile +++ b/tools/ci-containerfile @@ -1,9 +1,9 @@ # ci container file for compiling and testing zig projects. # requires a ZIGURL build arg. for instance: -# podman build --rm -t ci-zig0.11.0 -f ci-containerfile \ -# --build-arg ZIGURL=https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz +# podman build --rm -t ci-zig0.12.0 -f ci-containerfile \ +# --build-arg ZIGURL=https://ziglang.org/download/0.12.0/zig-linux-x86_64-0.12.0.tar.xz -FROM alpine:3.18.3 +FROM alpine:3.18.6 ARG ZIGURL RUN apk add --no-cache git curl xz libc-dev sdl2-dev clang16-extra-tools && \