Skip to content

Commit bb71a18

Browse files
committed
init: replace '--strip' with '--minimal'
This option never worked properly (it emitted wrongly-formatted code), and it doesn't seem particularly *useful* -- someone who's proficient enough with `std.Build` to not need explanations probably just wants to write their own thing. Meanwhile, the use case of writing your own `build.zig` was extremely poorly served, because `build.zig.zon` *needs* to be generated programmatically for a correct `fingerprint`, but the only ways to do that were to a) do it wrong and get an error, or b) get the full init template and delete the vast majority of it. Both of these were pretty clunky, and `-s` didn't really help. So, replace this flag with a new one, `--minimal`/`-m`, which uses a different template. This template is trivial enough that I opted to just hardcode it into the compiler for simplicity. The main job of `zig init -m` is to generate a correct `build.zig.zon` (if it is unable to do this, it exits with a fatal error). In addition, it will *attempt* to generate a tiny stub `build.zig`, with only an `std` import and an empty `pub fn build`. However, if `build.zig` already exists, it will avoid overwriting it, and doesn't even complain. This serves the use case of writing `build.zig` manually and *then* running `zig init -m` to generate an appropriate `build.zig.zon`.
1 parent d407c4e commit bb71a18

File tree

3 files changed

+102
-55
lines changed

3 files changed

+102
-55
lines changed

lib/init/build.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//! Use `zig init --strip` next time to generate a project without comments.
21
const std = @import("std");
32

43
// Although this function looks imperative, it does not perform the build

src/main.zig

Lines changed: 92 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4648,14 +4648,14 @@ const usage_init =
46484648
fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
46494649
dev.check(.init_command);
46504650

4651-
var strip = false;
4651+
var template: enum { example, minimal } = .example;
46524652
{
46534653
var i: usize = 0;
46544654
while (i < args.len) : (i += 1) {
46554655
const arg = args[i];
46564656
if (mem.startsWith(u8, arg, "-")) {
4657-
if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip")) {
4658-
strip = true;
4657+
if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
4658+
template = .minimal;
46594659
} else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
46604660
try fs.File.stdout().writeAll(usage_init);
46614661
return cleanExit();
@@ -4668,40 +4668,79 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
46684668
}
46694669
}
46704670

4671-
var templates = findTemplates(gpa, arena, strip);
4672-
defer templates.deinit();
4673-
46744671
const cwd_path = try introspect.getResolvedCwd(arena);
46754672
const cwd_basename = fs.path.basename(cwd_path);
46764673
const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
46774674

4678-
const s = fs.path.sep_str;
4679-
const template_paths = [_][]const u8{
4680-
Package.build_zig_basename,
4681-
Package.Manifest.basename,
4682-
"src" ++ s ++ "main.zig",
4683-
"src" ++ s ++ "root.zig",
4684-
};
4685-
var ok_count: usize = 0;
4686-
46874675
const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);
46884676

4689-
for (template_paths) |template_path| {
4690-
if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
4691-
std.log.info("created {s}", .{template_path});
4692-
ok_count += 1;
4693-
} else |err| switch (err) {
4694-
error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
4695-
template_path,
4696-
}),
4697-
else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
4698-
}
4699-
}
4677+
switch (template) {
4678+
.example => {
4679+
var templates = findTemplates(gpa, arena);
4680+
defer templates.deinit();
4681+
4682+
const s = fs.path.sep_str;
4683+
const template_paths = [_][]const u8{
4684+
Package.build_zig_basename,
4685+
Package.Manifest.basename,
4686+
"src" ++ s ++ "main.zig",
4687+
"src" ++ s ++ "root.zig",
4688+
};
4689+
var ok_count: usize = 0;
4690+
4691+
for (template_paths) |template_path| {
4692+
if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
4693+
std.log.info("created {s}", .{template_path});
4694+
ok_count += 1;
4695+
} else |err| switch (err) {
4696+
error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
4697+
template_path,
4698+
}),
4699+
else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
4700+
}
4701+
}
47004702

4701-
if (ok_count == template_paths.len) {
4702-
std.log.info("see `zig build --help` for a menu of options", .{});
4703+
if (ok_count == template_paths.len) {
4704+
std.log.info("see `zig build --help` for a menu of options", .{});
4705+
}
4706+
return cleanExit();
4707+
},
4708+
.minimal => {
4709+
writeSimpleTemplateFile(Package.Manifest.basename,
4710+
\\.{{
4711+
\\ .name = .{s},
4712+
\\ .version = "{s}",
4713+
\\ .paths = .{{""}},
4714+
\\ .fingerprint = 0x{x},
4715+
\\}}
4716+
\\
4717+
, .{
4718+
sanitized_root_name,
4719+
build_options.version,
4720+
fingerprint.int(),
4721+
}) catch |err| switch (err) {
4722+
else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }),
4723+
error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}),
4724+
};
4725+
writeSimpleTemplateFile(Package.build_zig_basename,
4726+
\\const std = @import("std");
4727+
\\pub fn build(b: *std.Build) void {{
4728+
\\ _ = b; // stub
4729+
\\}}
4730+
\\
4731+
, .{}) catch |err| switch (err) {
4732+
else => fatal("failed to create '{s}': {s}", .{ Package.build_zig_basename, @errorName(err) }),
4733+
// `build.zig` already existing is okay: the user has just used `zig init` to set up
4734+
// their `build.zig.zon` *after* writing their `build.zig`. So this one isn't fatal.
4735+
error.PathAlreadyExists => {
4736+
std.log.info("successfully populated '{s}', preserving existing '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
4737+
return cleanExit();
4738+
},
4739+
};
4740+
std.log.info("successfully populated '{s}' and '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
4741+
return cleanExit();
4742+
},
47034743
}
4704-
return cleanExit();
47054744
}
47064745

47074746
fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {
@@ -7229,13 +7268,20 @@ fn loadManifest(
72297268
0,
72307269
) catch |err| switch (err) {
72317270
error.FileNotFound => {
7232-
const fingerprint: Package.Fingerprint = .generate(options.root_name);
7233-
var templates = findTemplates(gpa, arena, true);
7234-
defer templates.deinit();
7235-
templates.write(arena, options.dir, options.root_name, Package.Manifest.basename, fingerprint) catch |e| {
7236-
fatal("unable to write {s}: {s}", .{
7237-
Package.Manifest.basename, @errorName(e),
7238-
});
7271+
writeSimpleTemplateFile(Package.Manifest.basename,
7272+
\\.{{
7273+
\\ .name = .{s},
7274+
\\ .version = "{s}",
7275+
\\ .paths = .{{""}},
7276+
\\ .fingerprint = 0x{x},
7277+
\\}}
7278+
\\
7279+
, .{
7280+
options.root_name,
7281+
build_options.version,
7282+
Package.Fingerprint.generate(options.root_name).int(),
7283+
}) catch |e| {
7284+
fatal("unable to write {s}: {s}", .{ Package.Manifest.basename, @errorName(e) });
72397285
};
72407286
continue;
72417287
},
@@ -7276,7 +7322,6 @@ const Templates = struct {
72767322
zig_lib_directory: Cache.Directory,
72777323
dir: fs.Dir,
72787324
buffer: std.ArrayList(u8),
7279-
strip: bool,
72807325

72817326
fn deinit(templates: *Templates) void {
72827327
templates.zig_lib_directory.handle.close();
@@ -7305,23 +7350,9 @@ const Templates = struct {
73057350
};
73067351
templates.buffer.clearRetainingCapacity();
73077352
try templates.buffer.ensureUnusedCapacity(contents.len);
7308-
var new_line = templates.strip;
73097353
var i: usize = 0;
73107354
while (i < contents.len) {
7311-
if (new_line) {
7312-
const trimmed = std.mem.trimLeft(u8, contents[i..], " ");
7313-
if (std.mem.startsWith(u8, trimmed, "//")) {
7314-
i += std.mem.indexOfScalar(u8, contents[i..], '\n') orelse break;
7315-
i += 1;
7316-
continue;
7317-
} else {
7318-
new_line = false;
7319-
}
7320-
}
7321-
7322-
if (templates.strip and contents[i] == '\n') {
7323-
new_line = true;
7324-
} else if (contents[i] == '_' or contents[i] == '.') {
7355+
if (contents[i] == '_' or contents[i] == '.') {
73257356
// Both '_' and '.' are allowed because depending on the context
73267357
// one prefix will be valid, while the other might not.
73277358
if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {
@@ -7350,8 +7381,16 @@ const Templates = struct {
73507381
});
73517382
}
73527383
};
7384+
fn writeSimpleTemplateFile(file_name: []const u8, comptime fmt: []const u8, args: anytype) !void {
7385+
const f = try fs.cwd().createFile(file_name, .{ .exclusive = true });
7386+
defer f.close();
7387+
var buf: [4096]u8 = undefined;
7388+
var fw = f.writer(&buf);
7389+
try fw.interface.print(fmt, args);
7390+
try fw.interface.flush();
7391+
}
73537392

7354-
fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {
7393+
fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
73557394
const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
73567395
fatal("unable to get cwd: {s}", .{@errorName(err)});
73577396
};
@@ -7375,7 +7414,6 @@ fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {
73757414
.zig_lib_directory = zig_lib_directory,
73767415
.dir = template_dir,
73777416
.buffer = std.ArrayList(u8).init(gpa),
7378-
.strip = strip,
73797417
};
73807418
}
73817419

test/tests.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,16 @@ pub fn addCliTests(b: *std.Build) *Step {
20162016
step.dependOn(&cleanup.step);
20172017
}
20182018

2019+
{
2020+
// Test `zig init -m`.
2021+
const tmp_path = b.makeTempPath();
2022+
const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init", "-m" });
2023+
init_exe.setCwd(.{ .cwd_relative = tmp_path });
2024+
init_exe.setName("zig init -m");
2025+
init_exe.expectStdOutEqual("");
2026+
init_exe.expectStdErrEqual("info: successfully populated 'build.zig.zon' and 'build.zig'\n");
2027+
}
2028+
20192029
// Test Godbolt API
20202030
if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
20212031
const tmp_path = b.makeTempPath();

0 commit comments

Comments
 (0)