Skip to content

Commit a495d20

Browse files
committed
zig init: allow the use of variables in templates like $root and $version
1 parent 1dda476 commit a495d20

File tree

4 files changed

+72
-26
lines changed

4 files changed

+72
-26
lines changed

lib/init/build.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ pub fn build(b: *std.Build) void {
4242
// Modules can depend on one another using the `std.Build.Module.addImport` function.
4343
// This is what allows Zig source code to use `@import("foo")` where 'foo' is not a
4444
// file path. In this case, we set up `exe_mod` to import `lib_mod`.
45-
exe_mod.addImport("$_lib", lib_mod);
45+
exe_mod.addImport("$root_lib", lib_mod);
4646

4747
// Now, we will create a static library based on the module we created above.
4848
// This creates a `std.Build.Step.Compile`, which is the build step responsible
4949
// for actually invoking the compiler.
5050
const lib = b.addLibrary(.{
5151
.linkage = .static,
52-
.name = "$",
52+
.name = "$root",
5353
.root_module = lib_mod,
5454
});
5555

@@ -61,7 +61,7 @@ pub fn build(b: *std.Build) void {
6161
// This creates another `std.Build.Step.Compile`, but this one builds an executable
6262
// rather than a static library.
6363
const exe = b.addExecutable(.{
64-
.name = "$",
64+
.name = "$root",
6565
.root_module = exe_mod,
6666
});
6767

lib/init/build.zig.zon

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77
// It is redundant to include "zig" in this name because it is already
88
// within the Zig package namespace.
9-
.name = "$",
9+
.name = "$root",
1010

1111
// This is a [Semantic Version](https://semver.org/).
1212
// In a future version of Zig it will be used for package deduplication.
@@ -15,7 +15,7 @@
1515
// This field is optional.
1616
// This is currently advisory only; Zig does not yet do anything
1717
// with this value.
18-
.minimum_zig_version = "*",
18+
.minimum_zig_version = "$version",
1919

2020
// This field is optional.
2121
// Each dependency must either provide a `url` and `hash`, or a `path`.

lib/init/src/main.zig

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! By convention, main.zig is where your main function lives in the case that
22
//! you are building an executable. If you are making a library, the convention
33
//! is to delete this file and start with root.zig instead.
4+
const std = @import("std");
5+
/// This imports the separate module containing `root.zig`. Take a look in `build.zig` for details.
6+
const lib = @import("$root_lib");
47

58
pub fn main() !void {
69
// Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
@@ -39,7 +42,3 @@ test "fuzz example" {
3942
try std.testing.fuzz(global.testOne, .{});
4043
}
4144

42-
const std = @import("std");
43-
44-
/// This imports the separate module containing `root.zig`. Take a look in `build.zig` for details.
45-
const lib = @import("$_lib");

src/main.zig

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4739,8 +4739,14 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
47394739
};
47404740
var ok_count: usize = 0;
47414741

4742+
// default replacements for templates
4743+
const replacements = &[_]Replacement{
4744+
.{ .variable = "$root", .replacement = cwd_basename },
4745+
.{ .variable = "$version", .replacement = build_options.version },
4746+
};
4747+
47424748
for (template_paths) |template_path| {
4743-
if (templates.write(arena, fs.cwd(), cwd_basename, template_path)) |_| {
4749+
if (templates.write(arena, fs.cwd(), template_path, replacements)) |_| {
47444750
std.log.info("created {s}", .{template_path});
47454751
ok_count += 1;
47464752
} else |err| switch (err) {
@@ -7427,7 +7433,12 @@ fn loadManifest(
74277433
var templates = findTemplates(gpa, arena);
74287434
defer templates.deinit();
74297435

7430-
templates.write(arena, options.dir, options.root_name, Package.Manifest.basename) catch |e| {
7436+
const replacements = &[_]Replacement{
7437+
.{ .variable = "$root", .replacement = options.root_name },
7438+
.{ .variable = "$version", .replacement = build_options.version },
7439+
};
7440+
7441+
templates.write(arena, options.dir, Package.Manifest.basename, replacements) catch |e| {
74317442
fatal("unable to write {s}: {s}", .{
74327443
Package.Manifest.basename, @errorName(e),
74337444
});
@@ -7467,6 +7478,19 @@ fn loadManifest(
74677478
return .{ manifest, ast };
74687479
}
74697480

7481+
/// replace variables for Zig templates
7482+
/// $root -> "project_name"
7483+
const Replacement = struct {
7484+
variable: []const u8,
7485+
replacement: []const u8,
7486+
7487+
pub inline fn check_variable(self: *@This()) !void {
7488+
if (self.variable.len < 2) {
7489+
return error.InvalidVariable;
7490+
}
7491+
}
7492+
};
7493+
74707494
const Templates = struct {
74717495
zig_lib_directory: Cache.Directory,
74727496
dir: fs.Dir,
@@ -7483,8 +7507,8 @@ const Templates = struct {
74837507
templates: *Templates,
74847508
arena: Allocator,
74857509
out_dir: fs.Dir,
7486-
root_name: []const u8,
74877510
template_path: []const u8,
7511+
replacements: ?[]const Replacement,
74887512
) !void {
74897513
if (fs.path.dirname(template_path)) |dirname| {
74907514
out_dir.makePath(dirname) catch |err| {
@@ -7500,24 +7524,47 @@ const Templates = struct {
75007524
templates.buffer.clearRetainingCapacity();
75017525
try templates.buffer.ensureUnusedCapacity(contents.len);
75027526

7503-
if (mem.eql(u8, template_path, Package.Manifest.basename)) {
7504-
for (contents) |c| {
7505-
if (c == '$') {
7506-
try templates.buffer.appendSlice(root_name);
7507-
} else if (c == '*') {
7508-
try templates.buffer.appendSlice(build_options.version);
7509-
} else {
7510-
try templates.buffer.append(c);
7511-
}
7512-
}
7513-
} else {
7514-
for (contents) |c| {
7515-
if (c == '$') {
7516-
try templates.buffer.appendSlice(root_name);
7527+
var iterator = mem.splitScalar(u8, contents, '\n');
7528+
7529+
// replace variables like $root and $version with the project name
7530+
// and zig compiler version respectively
7531+
while (iterator.next()) |line| {
7532+
7533+
var i: usize = 0;
7534+
while (i < line.len) : (i += 1) {
7535+
const c = line[i];
7536+
7537+
if (replacements) |replace_items| {
7538+
if (c == '$') {
7539+
var found: bool = false;
7540+
7541+
for (replace_items) |replacement| {
7542+
try replacement.check_variable();
7543+
7544+
if (line.len - i < replacement.variable.len) {
7545+
continue;
7546+
}
7547+
7548+
// found a match, break out
7549+
if (mem.eql(u8, replacement.variable, line[i .. i + replacement.variable.len])) {
7550+
try templates.buffer.appendSlice(replacement.replacement);
7551+
i += replacement.variable.len - 1;
7552+
found = true;
7553+
break;
7554+
}
7555+
}
7556+
7557+
if (!found) try templates.buffer.append(c);
7558+
} else {
7559+
// if we make it out here, no replacement was found, and we write out the literal '$'
7560+
try templates.buffer.append(c);
7561+
}
75177562
} else {
75187563
try templates.buffer.append(c);
75197564
}
75207565
}
7566+
7567+
try templates.buffer.append('\n');
75217568
}
75227569

75237570
return out_dir.writeFile(.{

0 commit comments

Comments
 (0)