Something went wrong. Try again.
A Zig client for the Paperless-ngx REST API, with streaming uploads, task waiting and a command-line tool.
Something went wrong. Try again.
zig-paperless build.zig
6.6 kB · 155 lines
Zig
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
const std = @import("std");
pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{});
// Instantiated with the same options zig-http and zig-mime use, so that // the zig-uri they each bring and the one named here resolve to one // module rather than three that merely look alike. const deps = .{ .target = target, .optimize = optimize }; const http_dep = b.dependency("http", deps); const mime_dep = b.dependency("zig_mime", deps); const uri_dep = b.dependency("uri", deps);
const mod = b.addModule("paperless", .{ .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "http", .module = http_dep.module("http") }, .{ .name = "http_io", .module = http_dep.module("http_io") }, .{ .name = "mime", .module = mime_dep.module("mime") }, .{ .name = "uri", .module = uri_dep.module("uri") }, }, });
// A command-line tool, which is both useful on its own and the worked // example of the library. const exe = b.addExecutable(.{ .name = "zig-paperless", .root_module = b.createModule(.{ .root_source_file = b.path("tools/main.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "paperless", .module = mod }, }, }), }); b.installArtifact(exe);
const run = b.addRunArtifact(exe); run.addPassthruArgs(); const run_step = b.step("run", "Run the command-line tool"); run_step.dependOn(&run.step);
const test_step = b.step("test", "Run tests"); // The tool is compiled with the tests, since nothing else in a test run // would notice it had stopped compiling. test_step.dependOn(&exe.step);
// `use_llvm` because the self-hosted backend emits no coverage // instrumentation, which leaves kcov reporting nothing. const unit_tests = b.addTest(.{ .name = "paperless-test", .root_module = mod, .use_llvm = true, }); test_step.dependOn(&b.addRunArtifact(unit_tests).step);
// The client against a fake Paperless on a loopback socket: requests as // the server sees them, and responses as the client reads them. const client_tests = b.addTest(.{ .name = "paperless-client-test", .root_module = b.createModule(.{ .root_source_file = b.path("tests/client.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "paperless", .module = mod }, .{ .name = "http", .module = http_dep.module("http") }, .{ .name = "http_io", .module = http_dep.module("http_io") }, }, }), .use_llvm = true, }); test_step.dependOn(&b.addRunArtifact(client_tests).step);
// Against a real server, when one is named in the environment; skipped // when not. `nix flake check` points it at a Paperless-ngx in a virtual // machine, and by hand it is // PAPERLESS_URL=http://... PAPERLESS_TOKEN=... zig build live-test const live_tests = b.addTest(.{ .name = "paperless-live-test", .root_module = b.createModule(.{ .root_source_file = b.path("tests/live.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "paperless", .module = mod }, }, }), .use_llvm = true, }); const run_live_tests = b.addRunArtifact(live_tests); // What it tests is outside the build, so a cached pass says nothing. run_live_tests.has_side_effects = true; const live_step = b.step("live-test", "Run the tests that need a real Paperless-ngx server"); live_step.dependOn(&run_live_tests.step); // Compiled with everything else, so that it cannot stop compiling // unnoticed between the runs that have a server to point it at. test_step.dependOn(&live_tests.step); // And installed, for the virtual machine test, which runs it against a // server that does not exist until the machine has booted. // Under `libexec` rather than `bin`, since it is not a program anybody // installing the package wants on their PATH. const install_live_tests = b.addInstallArtifact(live_tests, .{ .dest_dir = .{ .override = .{ .custom = "libexec" } }, }); b.getInstallStep().dependOn(&install_live_tests.step);
const library = b.addLibrary(.{ .name = "paperless", .root_module = mod }); const install_docs = b.addInstallDirectory(.{ .source_dir = library.getEmittedDocs(), .install_dir = .prefix, .install_subdir = "docs", }); const docs_step = b.step("docs", "Build the API documentation into zig-out/docs"); docs_step.dependOn(&install_docs.step);
const docs_port = b.option(u16, "docs-port", "Port for `zig build docs-serve` (default 8000)") orelse 8000; const docs_server = b.addExecutable(.{ .name = "docs-server", .root_module = b.createModule(.{ .root_source_file = b.path("tools/docs_server.zig"), // Always the machine running the build, never whatever -Dtarget // the library is being built for. .target = b.graph.host, .optimize = .Debug, }), }); const run_docs_server = b.addRunArtifact(docs_server); run_docs_server.step.dependOn(&install_docs.step); run_docs_server.addDirectoryArg(library.getEmittedDocs()); run_docs_server.addArg(b.fmt("{d}", .{docs_port})); // It runs until interrupted, so its output has to reach the terminal // rather than being captured by the build runner. run_docs_server.stdio = .inherit; const docs_serve_step = b.step("docs-serve", "Serve the API documentation over HTTP"); docs_serve_step.dependOn(&run_docs_server.step);
// Compile everything without running anything. const check_step = b.step("check", "Build everything, including what no other step builds"); check_step.dependOn(&exe.step); check_step.dependOn(&unit_tests.step); check_step.dependOn(&client_tests.step); check_step.dependOn(&live_tests.step); check_step.dependOn(&docs_server.step); test_step.dependOn(&b.addRunArtifact( b.addTest(.{ .root_module = docs_server.root_module }), ).step);}