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).
164 lines
5.1 KiB
Zig
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);
|
|
}
|
|
}
|
|
};
|