From b57611439f160c10987f55ee0d2043a201b91606 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Mon, 14 Oct 2024 20:55:45 -0700 Subject: [PATCH] PARTIAL update zig 0.10.0 -> 0.13.0 (Linux only) --- GitRepoStep.zig | 206 ------------------------------------------- build.zig | 136 ++++++++-------------------- src/clipboard.zig | 75 +++++----------- src/crypt.zig | 18 ++-- src/download.zig | 31 +++++-- src/main-linux.zig | 28 +++--- src/main-windows.zig | 2 +- zfetch_deps.zig | 1 - 8 files changed, 104 insertions(+), 393 deletions(-) delete mode 100644 GitRepoStep.zig delete mode 100644 zfetch_deps.zig diff --git a/GitRepoStep.zig b/GitRepoStep.zig deleted file mode 100644 index 1a83e2e..0000000 --- a/GitRepoStep.zig +++ /dev/null @@ -1,206 +0,0 @@ -//! Publish Date: 2021_10_17 -//! This file is hosted at github.com/marler8997/zig-build-repos and is meant to be copied -//! to projects that use it. -const std = @import("std"); -const GitRepoStep = @This(); - -pub const ShaCheck = enum { - none, - warn, - err, - - pub fn reportFail(self: ShaCheck, comptime fmt: []const u8, args: anytype) void { - switch (self) { - .none => unreachable, - .warn => std.log.warn(fmt, args), - .err => { - std.log.err(fmt, args); - std.os.exit(0xff); - }, - } - } -}; - -step: std.build.Step, -builder: *std.build.Builder, -url: []const u8, -name: []const u8, -branch: ?[]const u8 = null, -sha: []const u8, -path: []const u8 = null, -sha_check: ShaCheck = .warn, -fetch_enabled: bool, - -var cached_default_fetch_option: ?bool = null; -pub fn defaultFetchOption(b: *std.build.Builder) bool { - if (cached_default_fetch_option) |_| {} else { - cached_default_fetch_option = if (b.option(bool, "fetch", "automatically fetch network resources")) |o| o else false; - } - return cached_default_fetch_option.?; -} - -pub fn create(b: *std.build.Builder, opt: struct { - url: []const u8, - branch: ?[]const u8 = null, - sha: []const u8, - path: ?[]const u8 = null, - sha_check: ShaCheck = .warn, - fetch_enabled: ?bool = null, -}) *GitRepoStep { - var result = b.allocator.create(GitRepoStep) catch @panic("memory"); - const name = std.fs.path.basename(opt.url); - result.* = GitRepoStep{ - .step = std.build.Step.init(.custom, "clone a git repository", b.allocator, make), - .builder = b, - .url = opt.url, - .name = name, - .branch = opt.branch, - .sha = opt.sha, - .path = if (opt.path) |p| (b.allocator.dupe(u8, p) catch @panic("memory")) else (std.fs.path.resolve(b.allocator, &[_][]const u8{ - b.build_root, - "libs", - name, - })) catch @panic("memory"), - .sha_check = opt.sha_check, - .fetch_enabled = if (opt.fetch_enabled) |fe| fe else defaultFetchOption(b), - }; - return result; -} - -// TODO: this should be included in std.build, it helps find bugs in build files -fn hasDependency(step: *const std.build.Step, dep_candidate: *const std.build.Step) bool { - for (step.dependencies.items) |dep| { - // TODO: should probably use step.loop_flag to prevent infinite recursion - // when a circular reference is encountered, or maybe keep track of - // the steps encounterd with a hash set - if (dep == dep_candidate or hasDependency(dep, dep_candidate)) - return true; - } - return false; -} - -fn make(step: *std.build.Step) !void { - const self = @fieldParentPtr(GitRepoStep, "step", step); - - std.fs.accessAbsolute(self.path, std.fs.File.OpenFlags{ .read = true }) catch { - const branch_args = if (self.branch) |b| &[2][]const u8{ " -b ", b } else &[2][]const u8{ "", "" }; - if (!self.fetch_enabled) { - std.debug.print("Error: git repository '{s}' does not exist\n", .{self.path}); - std.debug.print(" Use -Dfetch to download it automatically, or run the following to clone it:\n", .{}); - std.debug.print(" git clone {s}{s}{s} {s} && git -C {3s} checkout {s} -b for_ziget\n", .{ self.url, branch_args[0], branch_args[1], self.path, self.sha }); - std.os.exit(1); - } - - { - var args = std.ArrayList([]const u8).init(self.builder.allocator); - defer args.deinit(); - try args.append("git"); - try args.append("clone"); - try args.append("--recurse-submodules"); - try args.append(self.url); - // TODO: clone it to a temporary location in case of failure - // also, remove that temporary location before running - try args.append(self.path); - if (self.branch) |branch| { - try args.append("-b"); - try args.append(branch); - } - try run(self.builder, args.items); - } - try run(self.builder, &[_][]const u8{ - "git", - "-C", - self.path, - "checkout", - self.sha, - "-b", - "fordep", - }); - }; - - try self.checkSha(); -} - -fn checkSha(self: GitRepoStep) !void { - if (self.sha_check == .none) - return; - - const result: union(enum) { failed: anyerror, output: []const u8 } = blk: { - const result = std.ChildProcess.exec(.{ - .allocator = self.builder.allocator, - .argv = &[_][]const u8{ - "git", - "-C", - self.path, - "rev-parse", - "HEAD", - }, - .cwd = self.builder.build_root, - .env_map = self.builder.env_map, - }) catch |e| break :blk .{ .failed = e }; - try std.io.getStdErr().writer().writeAll(result.stderr); - switch (result.term) { - .Exited => |code| { - if (code == 0) break :blk .{ .output = result.stdout }; - break :blk .{ .failed = error.GitProcessNonZeroExit }; - }, - .Signal => break :blk .{ .failed = error.GitProcessFailedWithSignal }, - .Stopped => break :blk .{ .failed = error.GitProcessWasStopped }, - .Unknown => break :blk .{ .failed = error.GitProcessFailed }, - } - }; - switch (result) { - .failed => |err| { - return self.sha_check.reportFail("failed to retreive sha for repository '{s}': {s}", .{ self.name, @errorName(err) }); - }, - .output => |output| { - if (!std.mem.eql(u8, std.mem.trimRight(u8, output, "\n\r"), self.sha)) { - return self.sha_check.reportFail("repository '{s}' sha does not match\nexpected: {s}\nactual : {s}\n", .{ self.name, self.sha, output }); - } - }, - } -} - -fn run(builder: *std.build.Builder, argv: []const []const u8) !void { - { - var msg = std.ArrayList(u8).init(builder.allocator); - defer msg.deinit(); - const writer = msg.writer(); - var prefix: []const u8 = ""; - for (argv) |arg| { - try writer.print("{s}\"{s}\"", .{ prefix, arg }); - prefix = " "; - } - std.log.info("[RUN] {s}", .{msg.items}); - } - - const child = try std.ChildProcess.init(argv, builder.allocator); - defer child.deinit(); - - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - child.cwd = builder.build_root; - child.env_map = builder.env_map; - - try child.spawn(); - const result = try child.wait(); - switch (result) { - .Exited => |code| if (code != 0) { - std.log.err("git clone failed with exit code {}", .{code}); - std.os.exit(0xff); - }, - else => { - std.log.err("git clone failed with: {}", .{result}); - std.os.exit(0xff); - }, - } -} - -// Get's the repository path and also verifies that the step requesting the path -// is dependent on this step. -pub fn getPath(self: *const GitRepoStep, who_wants_to_know: *const std.build.Step) []const u8 { - if (!hasDependency(who_wants_to_know, &self.step)) - @panic("a step called GitRepoStep.getPath but has not added it as a dependency"); - return self.path; -} diff --git a/build.zig b/build.zig index 5efafbc..1fb2d89 100644 --- a/build.zig +++ b/build.zig @@ -1,12 +1,6 @@ const std = @import("std"); -const GitRepoStep = @import("GitRepoStep.zig"); -pub fn build(b: *std.build.Builder) void { - const zfetch_repo = GitRepoStep.create(b, .{ - .url = "https://github.com/truemedian/zfetch", - // .branch = "0.1.10", // branch also takes tags. Tag 0.1.10 isn't quite new enough - .sha = "271cab5da4d12c8f08e67aa0cd5268da100e52f1", - }); +pub fn build(b: *std.Build) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options @@ -15,12 +9,12 @@ pub fn build(b: *std.build.Builder) void { // Standard release options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const uploadexe = switch (target.getOs().tag) { - .linux => b.addExecutable("clipboard-upload", "src/main-linux.zig"), - .windows => b.addExecutable("clipboard-upload", "src/main-windows.zig"), - else => std.os.exit(1), + const uploadexe = switch (target.result.os.tag) { + .linux => b.addExecutable(.{ .name = "clipboard-upload", .root_source_file = b.path("src/main-linux.zig"), .target = target }), + .windows => b.addExecutable(.{ .name = "clipboard-upload", .root_source_file = b.path("src/main-windows.zig"), .target = target }), + else => std.process.exit(1), }; const path = if (b.option(bool, "curl", "use external curl command") orelse false) @@ -30,19 +24,22 @@ pub fn build(b: *std.build.Builder) void { const enc_path = blk: { if (b.option(bool, "seperate-encryption", "use external encryption command") orelse false) { - const encryptionexe = b.addExecutable("encrypt", "src/encrypt.zig"); - encryptionexe.setTarget(target); - encryptionexe.setBuildMode(mode); - encryptionexe.install(); + const encryptionexe = b.addExecutable(.{ + .name = "encrypt", + .root_source_file = b.path("src/encrypt.zig"), + .target = target, + .optimize = optimize, + }); + b.getInstallStep().dependOn(&b.addInstallArtifact(encryptionexe, .{}).step); break :blk "config/external_encryption.zig"; } else { break :blk "config/sane_encryption.zig"; } }; - configureExe(uploadexe, b, target, mode, zfetch_repo, path, enc_path); + configureExe(uploadexe, b, target, optimize, path, enc_path); - const run_cmd = uploadexe.run(); + const run_cmd = b.addRunArtifact(uploadexe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); @@ -51,11 +48,11 @@ pub fn build(b: *std.build.Builder) void { const run_step = b.step("run", "Run the app (uplaods clipboard contents)"); run_step.dependOn(&run_cmd.step); - const downloadexe = b.addExecutable("clipboard-download", "src/download.zig"); + const downloadexe = b.addExecutable(.{ .name = "clipboard-download", .root_source_file = b.path("src/download.zig"), .target = target }); - configureExe(downloadexe, b, target, mode, zfetch_repo, path, enc_path); + configureExe(downloadexe, b, target, optimize, path, enc_path); - const run_download_cmd = downloadexe.run(); + const run_download_cmd = b.addRunArtifact(downloadexe); run_download_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_download_cmd.addArgs(args); @@ -65,10 +62,9 @@ pub fn build(b: *std.build.Builder) void { run_download_step.dependOn(&run_download_cmd.step); } -fn configureExe(exe: *std.build.LibExeObjStep, b: *std.build.Builder, target: std.zig.CrossTarget, mode: std.builtin.Mode, zfetch_repo: anytype, config_path: []const u8, enc_config_path: []const u8) void { - exe.setTarget(target); - exe.setBuildMode(mode); - if (target.getOs().tag == .linux) { +fn configureExe(exe: *std.Build.Step.Compile, b: *std.Build, target: std.Build.ResolvedTarget, mode: std.builtin.OptimizeMode, config_path: []const u8, enc_config_path: []const u8) void { + exe.root_module.optimize = mode; + if (target.result.os.tag == .linux) { exe.linkLibC(); // LibX11 1.7.2: https://gitlab.freedesktop.org/xorg/lib/libx11/-/archive/libX11-1.7.2/libx11-libX11-1.7.2.tar.gz // LibXfixes 5.0.3: https://gitlab.freedesktop.org/xorg/lib/libxfixes/-/archive/libXfixes-5.0.3/libxfixes-libXfixes-5.0.3.tar.gz @@ -76,93 +72,39 @@ fn configureExe(exe: *std.build.LibExeObjStep, b: *std.build.Builder, target: st // We can download the above by taking each url and processing in a // command e.g.: // curl | tar xz --wildcards '*.h' - exe.addIncludeDir("libx11-libX11-1.7.2/include"); - exe.addIncludeDir("libxfixes-libXfixes-5.0.3/include"); - exe.addIncludeDir("xorgproto-xorgproto-2021.5/include"); + exe.addIncludePath(b.path("libx11-libX11-1.7.2/include")); + exe.addIncludePath(b.path("libxfixes-libXfixes-5.0.3/include")); + exe.addIncludePath(b.path("xorgproto-xorgproto-2021.5/include")); // More than a little messy. We're grabbing libX11 and libXfixes from // the host, while using downloaded headers. This assumes debian // bullseye host, and also means you can't cross-compile from Windows. // TODO: Make this better + // const dependent_objects = .{ + // "/usr/lib/x86_64-linux-gnu/libX11.so.6", + // "/usr/lib/x86_64-linux-gnu/libXfixes.so.3", + // }; const dependent_objects = .{ "/usr/lib/x86_64-linux-gnu/libX11.so.6", - "/usr/lib/x86_64-linux-gnu/libXfixes.so.3", + "/nix/store/wd7b3f9sqgs0flgicx213iiyzjb4jxqm-libXfixes-6.0.1/lib/libXfixes.so.3", }; inline for (dependent_objects) |obj| - exe.addObjectFile(obj); + exe.addObjectFile(.{ .cwd_relative = obj }); + // exe.addObjectFile(b.path(obj)); } - if (target.getOs().tag == .windows) { + if (target.result.os.tag == .windows) { // woah...we don't actually need libc! exe.linkSystemLibrary("user32"); exe.linkSystemLibrary("kernel32"); exe.linkSystemLibrary("shell32"); } - const copy_deps = std.build.RunStep.create(b, "copy zfetch deps"); - copy_deps.addArgs(&[_][]const u8{ - "cp", - "zfetch_deps.zig", - "libs/zfetch/deps.zig", - }); - copy_deps.step.dependOn(&zfetch_repo.step); - // exe.step.dependOn(&zfetch_repo.step); - exe.step.dependOn(©_deps.step); + exe.root_module.addImport("config", b.createModule(.{ + .root_source_file = b.path(config_path), + })); + exe.root_module.addImport("encryptionconfig", b.createModule(.{ + .root_source_file = b.path(enc_config_path), + })); - // This import won't work unless we're already cloned. The way around - // this is to have a multi-stage build process, but that's a lot of work. - // Instead, I've copied the addPackage and tweaked it for the build prefix - // so we'll have to keep that in sync with upstream - // const zfetch = @import("libs/zfetch/build.zig"); - const zpkg = getZfetchPackage(b, "libs/zfetch") catch unreachable; - exe.addPackage(zpkg); - exe.addPackage(.{ - .name = "iguanaTLS", - .path = .{ .path = "libs/zfetch/libs/iguanaTLS/src/main.zig" }, - }); - - exe.addPackage(.{ - .name = "config", - .path = .{ .path = config_path }, - }); - exe.addPackage(.{ - .name = "encryptionconfig", - .path = .{ .path = enc_config_path }, - }); - - exe.install(); -} - -fn getDependency(comptime lib_prefix: []const u8, comptime name: []const u8, comptime root: []const u8) !std.build.Pkg { - const path = lib_prefix ++ "/libs/" ++ name ++ "/" ++ root; - - // We don't actually care if the dependency has been checked out, as - // GitRepoStep will handle that for us - // Make sure that the dependency has been checked out. - // std.fs.cwd().access(path, .{}) catch |err| switch (err) { - // error.FileNotFound => { - // std.log.err("zfetch: dependency '{s}' not checked out", .{name}); - // - // return err; - // }, - // else => return err, - // }; - - return std.build.Pkg{ - .name = name, - .path = .{ .path = path }, - }; -} -pub fn getZfetchPackage(b: *std.build.Builder, comptime lib_prefix: []const u8) !std.build.Pkg { - var dependencies = b.allocator.alloc(std.build.Pkg, 4) catch unreachable; - - dependencies[0] = try getDependency(lib_prefix, "iguanaTLS", "src/main.zig"); - dependencies[1] = try getDependency(lib_prefix, "network", "network.zig"); - dependencies[2] = try getDependency(lib_prefix, "uri", "uri.zig"); - dependencies[3] = try getDependency(lib_prefix, "hzzp", "src/main.zig"); - - return std.build.Pkg{ - .name = "zfetch", - .path = .{ .path = lib_prefix ++ "/src/main.zig" }, - .dependencies = dependencies, - }; + b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{}).step); } diff --git a/src/clipboard.zig b/src/clipboard.zig index 2558e32..48a1c04 100644 --- a/src/clipboard.zig +++ b/src/clipboard.zig @@ -1,6 +1,5 @@ const builtin = @import("builtin"); const std = @import("std"); -const zfetch = @import("zfetch"); const crypt = @import("crypt.zig"); const config = @import("config"); const encryptionconfig = @import("encryptionconfig"); @@ -13,7 +12,7 @@ const encryptionconfig = @import("encryptionconfig"); // iguanaTLS to support tls 1.3 // iguanaTLS to support something else, like ECDHE-ECDSA-CHACHA20-POLY1305 // In the meantime, I've allowed use of http, since we're encrypting anyway -const clipboard_url = "http://clippy.lerch.org/work2"; +const clipboard_url = "https://clippy.lerch.org/work2"; // const clipboard_url = "https://httpbin.org/post"; const Self = @This(); @@ -59,9 +58,8 @@ pub fn clipboardChanged(self: *Self, contents: []const u8) !void { defer aa.free(clip_contents); // Ugh - it's the encryption that Crowdstrike doesn't like.. :( - var buf: []u8 = try aa.alloc(u8, contents.len); + const buf: []u8 = try aa.dupe(u8, contents); defer aa.free(buf); - std.mem.copy(u8, buf, contents); const encrypted = encrypt(aa, self.key.*, buf) catch |e| { std.log.err("Could not encrypt clipboard contents: {}", .{e}); if (@errorReturnTrace()) |trace| { @@ -127,19 +125,20 @@ fn get(allocator: std.mem.Allocator) ![]const u8 { // @embedFile("/etc/ssl/certs/ca-certificates.crt"), // ).reader(); // const trust = try tls.x509.CertificateChain.from_pem(allocator, cert_reader); - try zfetch.init(); - defer zfetch.deinit(); - - var headers = zfetch.Headers.init(allocator); - defer headers.deinit(); // try headers.appendValue("Accept", "application/json"); // try headers.appendValue("Content-Type", "text/plain"); - var req = try zfetch.Request.init(allocator, clipboard_url, null); - defer req.deinit(); + var data = std.ArrayList(u8).init(allocator); + defer data.deinit(); + var client = std.http.Client{ .allocator = allocator }; + defer client.deinit(); - try req.do(.GET, headers, null); + const res = try client.fetch(.{ + .location = .{ .url = clipboard_url }, + .response_storage = .{ .dynamic = &data }, + }); + _ = res; // TODO: Check res.status // Printf debugging // const stdout = std.io.getStdOut().writer(); @@ -150,18 +149,6 @@ fn get(allocator: std.mem.Allocator) ![]const u8 { // } // try stdout.print("body:\n", .{}); // - const reader = req.reader(); - - var data = std.ArrayList(u8).init(allocator); - defer data.deinit(); - const data_writer = data.writer(); - var buf: [1024]u8 = undefined; - while (true) { - const read = try reader.read(&buf); - if (read == 0) break; - - try data_writer.writeAll(buf[0..read]); - } return data.toOwnedSlice(); } @@ -270,42 +257,20 @@ fn put(allocator: std.mem.Allocator, data: []const u8) !void { // @embedFile("/etc/ssl/certs/ca-certificates.crt"), // ).reader(); // const trust = try tls.x509.CertificateChain.from_pem(allocator, cert_reader); - try zfetch.init(); - defer zfetch.deinit(); + var client = std.http.Client{ .allocator = allocator }; + defer client.deinit(); - var headers = zfetch.Headers.init(allocator); - defer headers.deinit(); + const res = try client.fetch(.{ + .location = .{ .url = clipboard_url }, + .method = .PUT, + .payload = data, + }); + _ = res; // TODO: check status - // try headers.appendValue("Accept", "application/json"); - // try headers.appendValue("Content-Type", "text/plain"); - - var req = try zfetch.Request.init(allocator, clipboard_url, null); - defer req.deinit(); - - try req.do(.PUT, headers, data); - - // Printf debugging - // const stdout = std.io.getStdOut().writer(); - // try stdout.print("status: {d} {s}\n", .{ req.status.code, req.status.reason }); - // try stdout.print("headers:\n", .{}); - // for (req.headers.list.items) |header| { - // try stdout.print(" {s}: {s}\n", .{ header.name, header.value }); - // } - // try stdout.print("body:\n", .{}); - // - // const reader = req.reader(); - // - // var buf: [1024]u8 = undefined; - // while (true) { - // const read = try reader.read(&buf); - // if (read == 0) break; - // - // try stdout.writeAll(buf[0..read]); - // } } test "full integration" { - var allocator = std.testing.allocator; + const allocator = std.testing.allocator; var watcher = init(allocator); defer watcher.deinit(); try watcher.clipboardChanged("hello world"); diff --git a/src/crypt.zig b/src/crypt.zig index 33661fb..01237de 100644 --- a/src/crypt.zig +++ b/src/crypt.zig @@ -45,7 +45,7 @@ pub fn encryptWithKey(allocator: std.mem.Allocator, key: [key_size]u8, data: []u var encrypted = try std.ArrayList(u8).initCapacity(allocator, block_size * (total_blocks + 1)); defer encrypted.deinit(); while (current_block < total_blocks) { - in = @ptrCast(*[block_size]u8, data[(current_block * block_size)..(((current_block + 1) * block_size) - 1)]); + in = @ptrCast(data[(current_block * block_size)..(((current_block + 1) * block_size) - 1)]); ctx.encrypt(out[0..], in.*[0..]); encrypted.appendSliceAssumeCapacity(out[0..]); current_block += 1; @@ -56,7 +56,7 @@ pub fn encryptWithKey(allocator: std.mem.Allocator, key: [key_size]u8, data: []u // We can't just ptrcast into data as we are likely to run over the end // of the data memory. We'll declare a new input buffer var in_last: [block_size]u8 = undefined; - const padding: u8 = @intCast(u8, block_size - (data.len % block_size)); + const padding: u8 = @intCast(block_size - (data.len % block_size)); var inx: u8 = 0; for (data[(total_blocks * block_size)..]) |b| { in_last[inx] = b; @@ -99,14 +99,14 @@ pub fn decryptWithKey(allocator: std.mem.Allocator, key: [key_size]u8, data: []c var decrypted = try std.ArrayList(u8).initCapacity(allocator, block_size * (total_blocks - 1)); defer decrypted.deinit(); while (current_block < total_blocks - 1) { - in = @ptrCast(*const [block_size]u8, data[(current_block * block_size)..(((current_block + 1) * block_size) - 1)]); + in = @ptrCast(data[(current_block * block_size)..(((current_block + 1) * block_size) - 1)]); ctx.decrypt(out[0..], in.*[0..]); decrypted.appendSliceAssumeCapacity(out[0..]); current_block += 1; } // deal with final block, PKCS#7 padding - in = @ptrCast(*const [block_size]u8, data[(current_block * block_size)..(((current_block + 1) * block_size) - 1)]); + in = @ptrCast(data[(current_block * block_size)..(((current_block + 1) * block_size) - 1)]); ctx.decrypt(out[0..], in.*[0..]); // Assertion was triggering when data was plain text if (out[block_size - 1] > block_size) { @@ -131,7 +131,7 @@ test "correct size, even block" { const str = "0123456789ABCDEF"; var allocator = std.testing.allocator; var buf: [str.len]u8 = undefined; - var data = try std.fmt.bufPrint(&buf, str, .{}); + const data = try std.fmt.bufPrint(&buf, str, .{}); const encrypted = try encryptWithKey(allocator, test_key, data); defer allocator.free(encrypted); const size: usize = 32; @@ -142,7 +142,7 @@ test "round trip, even block" { const str = "0123456789ABCDEF"; var allocator = std.testing.allocator; var buf: [str.len]u8 = undefined; - var data = try std.fmt.bufPrint(&buf, str, .{}); + const data = try std.fmt.bufPrint(&buf, str, .{}); const encrypted = try encryptWithKey(allocator, test_key, data); defer allocator.free(encrypted); const decrypted = try decryptWithKey(allocator, test_key, encrypted); @@ -155,7 +155,7 @@ test "round trip, uneven block" { const str = "0123456789ABCDEFG"; var allocator = std.testing.allocator; var buf: [str.len]u8 = undefined; - var data = try std.fmt.bufPrint(&buf, str, .{}); + const data = try std.fmt.bufPrint(&buf, str, .{}); const encrypted = try encryptWithKey(allocator, test_key, data); defer allocator.free(encrypted); const decrypted = try decryptWithKey(allocator, test_key, encrypted); @@ -167,8 +167,8 @@ test "round trip, uneven block, using password" { const str = "0123456789ABCDEFG"; var allocator = std.testing.allocator; var buf: [str.len]u8 = undefined; - var data = try std.fmt.bufPrint(&buf, str, .{}); - var key = try keyFromPassword(allocator, "foo", ""); + const data = try std.fmt.bufPrint(&buf, str, .{}); + const key = try keyFromPassword(allocator, "foo", ""); defer allocator.free(key); const encrypted = try encryptWithKey(allocator, key.*, data); defer allocator.free(encrypted); diff --git a/src/download.zig b/src/download.zig index 54e21d9..3bb41ef 100644 --- a/src/download.zig +++ b/src/download.zig @@ -42,11 +42,9 @@ pub fn main() !u8 { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); - var args = std.process.args(); + var args = try std.process.argsWithAllocator(allocator); defer args.deinit(); - while (args.next(allocator)) |arg_or_err| { - const arg = try arg_or_err; - defer allocator.free(arg); + while (args.next()) |arg| { if (std.mem.eql(u8, arg, "-w")) { watch = true; break; @@ -101,7 +99,16 @@ fn addToClipboard(allocator: std.mem.Allocator, data: []const u8) !void { } } -fn execLinux(allocator: std.mem.Allocator, data: []const u8) !std.ChildProcess.ExecResult { +const Term = struct { + allocator: std.mem.Allocator, + stderr: []const u8, + term: std.process.Child.Term, + + pub fn deinit(self: *Term) void { + self.allocator.free(self.stderr); + } +}; +fn execLinux(allocator: std.mem.Allocator, data: []const u8) !Term { // we need to do this (maybe) because there is no real way to close stdin cleanly, which is what will // kill xclip. // @@ -114,15 +121,21 @@ fn execLinux(allocator: std.mem.Allocator, data: []const u8) !std.ChildProcess.E defer allocator.free(xclip_cmd); std.log.debug("cmd: {s}", .{xclip_cmd}); - return std.ChildProcess.exec(.{ - .allocator = allocator, - .argv = &[_][]const u8{ + var child = std.process.Child.init( + &[_][]const u8{ "/usr/bin/env", "sh", "-c", xclip_cmd, }, - }); + allocator, + ); + const term = try std.process.Child.spawnAndWait(&child); + return .{ + .term = term, + .allocator = allocator, + .stderr = if (child.stderr) |e| try e.readToEndAlloc(allocator, 10 * 1024 * 1024) else try allocator.dupe(u8, ""), + }; } fn execWindows(allocator: std.mem.Allocator, data: []const u8) !std.ChildProcess.ExecResult { diff --git a/src/main-linux.zig b/src/main-linux.zig index 78fbbe4..95ac34b 100644 --- a/src/main-linux.zig +++ b/src/main-linux.zig @@ -12,11 +12,9 @@ pub fn main() !u8 { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); - var args = std.process.args(); + var args = try std.process.argsWithAllocator(allocator); defer args.deinit(); - while (args.next(allocator)) |arg_or_err| { - const arg = try arg_or_err; - defer allocator.free(arg); + while (args.next()) |arg| { if (std.mem.eql(u8, arg, "-w")) { watch = true; break; @@ -29,15 +27,15 @@ pub fn main() !u8 { } fn clipboardAction(allocator: std.mem.Allocator, watch: bool, clip: *Clipboard) !void { - var display: *c.Display = c.XOpenDisplay(null).?; + const display: *c.Display = c.XOpenDisplay(null).?; defer _ = c.XCloseDisplay(display); const default_screen = c.XDefaultScreen(display); - var color = c.XBlackPixel(display, default_screen); - var window = c.XCreateSimpleWindow(display, c.XDefaultRootWindow(display), 0, 0, 1, 1, 0, color, color); + const color = c.XBlackPixel(display, default_screen); + const window = c.XCreateSimpleWindow(display, c.XDefaultRootWindow(display), 0, 0, 1, 1, 0, color, color); defer _ = c.XDestroyWindow(display, window); // Watch will not return if (watch) try watchClip(allocator, display, window, "CLIPBOARD", clip); - var result = (try printSelection(allocator, display, window, "CLIPBOARD", "UTF8_STRING", clip)) or + const result = (try printSelection(allocator, display, window, "CLIPBOARD", "UTF8_STRING", clip)) or (try printSelection(allocator, display, window, "CLIPBOARD", "STRING", clip)); if (!result) return error.ClipboardActionFailed; } @@ -46,7 +44,7 @@ fn watchClip(allocator: std.mem.Allocator, display: *c.Display, window: c.Window var event_base: c_int = undefined; var error_base: c_int = undefined; var event: c.XEvent = undefined; - var bufid = c.XInternAtom(display, bufname, c.False); + const bufid = c.XInternAtom(display, bufname, c.False); _ = c.XFixesQueryExtension(display, &event_base, &error_base); _ = c.XFixesSelectSelectionInput(display, c.XDefaultRootWindow(display), bufid, c.XFixesSetSelectionOwnerNotifyMask); @@ -74,10 +72,10 @@ fn printSelection( var ressize: c_ulong = undefined; var restail: c_ulong = undefined; var resbits: c_int = undefined; - var bufid = c.XInternAtom(display, bufname, c.False); + const bufid = c.XInternAtom(display, bufname, c.False); var fmtid = c.XInternAtom(display, fmtname, c.False); - var propid = c.XInternAtom(display, "XSEL_DATA", c.False); - var incrid = c.XInternAtom(display, "INCR", c.False); + const propid = c.XInternAtom(display, "XSEL_DATA", c.False); + const incrid = c.XInternAtom(display, "INCR", c.False); var event: c.XEvent = undefined; _ = c.XSelectInput(display, window, c.PropertyChangeMask); @@ -91,13 +89,13 @@ fn printSelection( _ = c.XGetWindowProperty(display, window, propid, 0, c.LONG_MAX / 4, c.True, c.AnyPropertyType, &fmtid, &resbits, &ressize, &restail, &result); defer _ = c.XFree(result); if (fmtid != incrid) - _ = async clip.clipboardChanged(std.mem.span(result)); // TODO: Ensure we don't start queueing these things up + _ = try clip.clipboardChanged(std.mem.span(result)); // TODO: Ensure we don't start queueing these things up if (fmtid == incrid) { ressize = 1; var arena_allocator = std.heap.ArenaAllocator.init(allocator); defer arena_allocator.deinit(); - var local_allocator = arena_allocator.allocator(); + const local_allocator = arena_allocator.allocator(); var buffer = std.ArrayList(u8).init(local_allocator); defer buffer.deinit(); while (ressize > 0) { @@ -110,7 +108,7 @@ fn printSelection( //defer _ = c.XFree(result); // Creates double free error, but not sure why try buffer.appendSlice(try std.fmt.allocPrint(local_allocator, "{s}", .{result})); } - _ = async clip.clipboardChanged(buffer.items); + _ = try clip.clipboardChanged(buffer.items); } return true; } else // request failed, e.g. owner can't convert to the target format diff --git a/src/main-windows.zig b/src/main-windows.zig index b1487ea..226fd2d 100644 --- a/src/main-windows.zig +++ b/src/main-windows.zig @@ -1191,7 +1191,7 @@ fn UpdateContents(hwnd: w.HWND) void { // Get a lock on the clipboard if (OpenClipboard(hwnd) > 0) { defer _ = CloseClipboard(); - var hglb = GetClipboardData(uFormat).?; + var hglb = GetClipboardData(uFormat) orelse return; const hnd = @intCast(isize, @ptrToInt(hglb)); var lpstr = GlobalLock(hnd).?; defer _ = GlobalUnlock(hnd); diff --git a/zfetch_deps.zig b/zfetch_deps.zig deleted file mode 100644 index 820efbd..0000000 --- a/zfetch_deps.zig +++ /dev/null @@ -1 +0,0 @@ -const use_submodules = 1;