rotint/deps/libxev/src/build/ScdocStep.zig
torque 7692cb4bc7
init
I will never get tired of vendoring dependencies. ha ha. It is possible
I am insane. I had to do a lot of pruning to get these not to be
ridiculous (especially the unicode data, which had nearly 1 million
lines of... stuff).
2024-08-09 19:26:32 -07:00

164 lines
5.1 KiB
Zig

const std = @import("std");
const mem = std.mem;
const fs = std.fs;
const Step = std.Build.Step;
const Build = std.Build;
/// ScdocStep generates man pages using scdoc(1).
///
/// It reads all the raw pages from src_path and writes them to out_path.
/// src_path is typically "docs/" relative to the build root and out_path is
/// the build cache.
///
/// The man pages can be installed by calling install() on the step.
const ScdocStep = @This();
step: Step,
builder: *Build,
/// path to read man page sources from, defaults to the "doc/" subdirectory
/// from the build.zig file. This must be an absolute path.
src_path: []const u8,
/// path where the generated man pages will be written (NOT installed). This
/// defaults to build cache root.
out_path: []const u8,
pub fn create(builder: *Build) *ScdocStep {
const self = builder.allocator.create(ScdocStep) catch unreachable;
self.* = init(builder);
return self;
}
pub fn init(builder: *Build) ScdocStep {
return ScdocStep{
.builder = builder,
.step = Step.init(.{
.id = .custom,
.name = "generate man pages",
.owner = builder,
.makeFn = make,
}),
.src_path = builder.pathFromRoot("docs/"),
.out_path = builder.cache_root.join(builder.allocator, &[_][]const u8{
"man",
}) catch unreachable,
};
}
fn make(step: *std.Build.Step, _: std.Progress.Node) !void {
const self: *ScdocStep = @fieldParentPtr("step", step);
// Create our cache path
// TODO(mitchellh): ideally this would be pure zig
{
const command = try std.fmt.allocPrint(
self.builder.allocator,
"rm -f {[path]s}/* && mkdir -p {[path]s}",
.{ .path = self.out_path },
);
_ = self.builder.run(&[_][]const u8{ "sh", "-c", command });
}
// Find all our man pages which are in our src path ending with ".scd".
var dir = try fs.openDirAbsolute(self.src_path, .{ .iterate = true });
defer dir.close();
var iter = dir.iterate();
while (try iter.next()) |*entry| {
// We only want "scd" files to generate.
if (!mem.eql(u8, fs.path.extension(entry.name), ".scd")) {
continue;
}
const src = try fs.path.join(
self.builder.allocator,
&[_][]const u8{ self.src_path, entry.name },
);
const dst = try fs.path.join(
self.builder.allocator,
&[_][]const u8{ self.out_path, entry.name[0..(entry.name.len - 4)] },
);
const command = try std.fmt.allocPrint(
self.builder.allocator,
"scdoc < {s} > {s}",
.{ src, dst },
);
_ = self.builder.run(&[_][]const u8{ "sh", "-c", command });
}
}
pub fn install(self: *ScdocStep) !void {
// Ensure that `zig build install` depends on our generation step first.
self.builder.getInstallStep().dependOn(&self.step);
// Then run our install step which looks at what we made out of our
// generation and moves it to the install prefix.
const install_step = InstallStep.create(self.builder, self);
self.builder.getInstallStep().dependOn(&install_step.step);
}
/// Install man pages, create using install() on ScdocStep.
const InstallStep = struct {
step: Step,
builder: *Build,
scdoc: *ScdocStep,
pub fn create(builder: *Build, scdoc: *ScdocStep) *InstallStep {
const self = builder.allocator.create(InstallStep) catch unreachable;
self.* = InstallStep.init(builder, scdoc);
self.step.dependOn(&scdoc.step);
return self;
}
fn init(builder: *Build, scdoc: *ScdocStep) InstallStep {
return InstallStep{
.builder = builder,
.step = Step.init(.{
.id = .custom,
.name = "install man pages",
.owner = builder,
.makeFn = InstallStep.make,
}),
.scdoc = scdoc,
};
}
fn make(step: *Step, progress: std.Progress.Node) !void {
const self: *InstallStep = @fieldParentPtr("step", step);
// Get our absolute output path
var path = self.scdoc.out_path;
if (!fs.path.isAbsolute(path)) {
path = self.builder.pathFromRoot(path);
}
// Find all our man pages which are in our src path ending with ".scd".
var dir = try fs.openDirAbsolute(path, .{ .iterate = true });
defer dir.close();
var iter = dir.iterate();
while (try iter.next()) |*entry| {
// We expect filenames to be "foo.3" and this gets us "3"
const section = entry.name[(entry.name.len - 1)..];
const src = try fs.path.join(
self.builder.allocator,
&[_][]const u8{ path, entry.name },
);
const output = try std.fmt.allocPrint(
self.builder.allocator,
"share/man/man{s}/{s}",
.{ section, entry.name },
);
const fileStep = self.builder.addInstallFile(
.{ .cwd_relative = src },
output,
);
try fileStep.step.make(progress);
}
}
};