authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-22 17:37:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-29 23:50:18-07:00
log27ae3b30add18fa1348c8e89cdace862e6b0bb09
tree487cd8a7407c099c84e335c13af2b48ec1cf7f0d
parent0c978ba957ad1d44f5a4952b2d6dce121a5b05e6

WIP: also move init subcommand to Maker process


2 files changed, 266 insertions(+), 264 deletions(-)

lib/compiler/Maker.zig+265-9
......@@ -170,8 +170,10 @@ pub fn main(init: process.Init.Minimal) !void {
170170 .random_seed = parseRandomSeed(seed_arg),
171171 };
172172
173 const cmd = stringToEnum(enum { fetch, build }, cmd_name) orelse fatal("bad command name: {q}", .{ cmd_name });
173 const cmd = stringToEnum(enum { init, fetch, build }, cmd_name) orelse
174 fatal("bad command name: {q}", .{ cmd_name });
174175 switch (cmd) {
176 .init => return cmdInit( gpa, &graph, args[arg_i..]),
175177 .fetch => return cmdFetch( gpa, &graph, args[arg_i..]),
176178 .build => {},
177179 }
......@@ -978,7 +980,7 @@ pub fn main(init: process.Init.Minimal) !void {
978980 }
979981
980982 const rand_int = randInt(io, u64);
981 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
983 const tmp_dir_sub_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
982984 const config_tmp_path: Path = .{
983985 .root_dir = dirs.local_cache,
984986 .sub_path = tmp_dir_sub_path,
......@@ -1033,7 +1035,7 @@ pub fn main(init: process.Init.Minimal) !void {
10331035 if (system_pkg_dir_path) |p| {
10341036 // In this mode, the system needs to provide these packages; they
10351037 // cannot be fetched by Zig.
1036 const s = fs.path.sep_str;
1038 const s = Dir.path.sep_str;
10371039 for (unlazy_set.keys()) |*hash| {
10381040 std.log.err("lazy dependency package not found: {s}" ++ s ++ "{s}", .{ p, hash.toSlice() });
10391041 }
......@@ -1100,7 +1102,7 @@ pub fn main(init: process.Init.Minimal) !void {
11001102 config_tmp_path, final_path, e,
11011103 });
11021104 };
1103 config_man.writeManifest() catch |err| warn("failed to write cache manifest: {t}", .{err});
1105 config_man.writeManifest() catch |err| log.warn("failed to write cache manifest: {t}", .{err});
11041106 break :cp .{ final_path, false };
11051107 }
11061108 };
......@@ -1549,7 +1551,7 @@ fn cmdFetch(
15491551 ast.deinit(gpa);
15501552 }
15511553
1552 var fixups: Ast.Render.Fixups = .{};
1554 var fixups: std.zig.Ast.Render.Fixups = .{};
15531555 defer fixups.deinit(gpa);
15541556
15551557 var saved_path_or_url = path_or_url;
......@@ -1630,7 +1632,7 @@ fn cmdFetch(
16301632 .{std.zig.fmtString(package_hash_slice)},
16311633 );
16321634
1633 warn("overwriting existing dependency named {q}", .{name});
1635 log.warn("overwriting existing dependency named {q}", .{name});
16341636 try fixups.replace_nodes_with_string.put(gpa, dep.location_node, location_replace);
16351637 if (dep.hash_node.unwrap()) |hash_node| {
16361638 try fixups.replace_nodes_with_string.put(gpa, hash_node, hash_replace);
......@@ -1692,10 +1694,129 @@ const usage_fetch =
16921694 \\
16931695;
16941696
1695fn cmdBuild() !void {
1697const usage_init =
1698 \\Usage: zig init
1699 \\
1700 \\ Initializes a `zig build` project in the current working
1701 \\ directory.
1702 \\
1703 \\Options:
1704 \\ -m, --minimal Use minimal init template
1705 \\ -h, --help Print this help and exit
1706 \\
1707 \\
1708;
1709
1710fn cmdInit(
1711 gpa: Allocator,
1712 graph: *Graph,
1713 args: []const []const u8
1714) !void {
1715 const arena = graph.arena;
1716 const io = graph.io;
1717
1718 var template: enum { example, minimal } = .example;
1719 {
1720 var i: usize = 0;
1721 while (i < args.len) : (i += 1) {
1722 const arg = args[i];
1723 if (mem.startsWith(u8, arg, "-")) {
1724 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
1725 template = .minimal;
1726 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
1727 try Io.File.stdout().writeStreamingAll(io, usage_init);
1728 return cleanExit(io);
1729 } else {
1730 fatal("unrecognized parameter: {q}", .{arg});
1731 }
1732 } else {
1733 fatal("unexpected extra parameter: {q}", .{arg});
1734 }
1735 }
1736 }
1737
1738 const cwd_path = try std.zig.getResolvedCwd(io, arena);
1739 const cwd_basename = Dir.path.basename(cwd_path);
1740 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
1741
1742 const rng: std.Random.IoSource = .{ .io = io };
1743 const fingerprint: Package.Fingerprint = .generate(rng.interface(), sanitized_root_name);
1744
1745 switch (template) {
1746 .example => {
1747 var templates = findTemplates(gpa, arena, io);
1748 defer templates.deinit(io);
1749
1750 const s = Dir.path.sep_str;
1751 const template_paths = [_][]const u8{
1752 Package.build_zig_basename,
1753 Package.Manifest.basename,
1754 "src" ++ s ++ "main.zig",
1755 "src" ++ s ++ "root.zig",
1756 };
1757 var ok_count: usize = 0;
1758
1759 for (template_paths) |template_path| {
1760 if (templates.write(arena, io, Io.Dir.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
1761 std.log.info("created {s}", .{template_path});
1762 ok_count += 1;
1763 } else |err| switch (err) {
1764 error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
1765 template_path,
1766 }),
1767 else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
1768 }
1769 }
16961770
1771 if (ok_count == template_paths.len) {
1772 std.log.info("see `zig build --help` for a menu of options", .{});
1773 }
1774 return cleanExit(io);
1775 },
1776 .minimal => {
1777 writeSimpleTemplateFile(io, Package.Manifest.basename,
1778 \\.{{
1779 \\ .name = .{s},
1780 \\ .version = "0.0.1",
1781 \\ .minimum_zig_version = "{s}",
1782 \\ .paths = .{{""}},
1783 \\ .fingerprint = 0x{x},
1784 \\}}
1785 \\
1786 , .{
1787 sanitized_root_name,
1788 builtin.zig_version_string,
1789 fingerprint.int(),
1790 }) catch |err| switch (err) {
1791 else => fatal("failed to create {q}: {t}", .{ Package.Manifest.basename, err }),
1792 error.PathAlreadyExists => fatal("refusing to overwrite {q}", .{Package.Manifest.basename}),
1793 };
1794 writeSimpleTemplateFile(io, Package.build_zig_basename,
1795 \\const std = @import("std");
1796 \\
1797 \\pub fn build(b: *std.Build) void {{
1798 \\ _ = b; // stub
1799 \\}}
1800 \\
1801 , .{}) catch |err| switch (err) {
1802 else => fatal("failed to create {q}: {t}", .{ Package.build_zig_basename, err }),
1803 // `build.zig` already existing is okay: the user has just used `zig init` to set up
1804 // their `build.zig.zon` *after* writing their `build.zig`. So this one isn't fatal.
1805 error.PathAlreadyExists => {
1806 std.log.info("successfully populated {q}, preserving existing {q}", .{
1807 Package.Manifest.basename, Package.build_zig_basename,
1808 });
1809 return cleanExit(io);
1810 },
1811 };
1812 std.log.info("successfully populated {q} and {q}", .{ Package.Manifest.basename, Package.build_zig_basename });
1813 return cleanExit(io);
1814 },
1815 }
16971816}
16981817
1818
1819
16991820fn markFailedStepsDirty(maker: *Maker) void {
17001821 const all_steps = maker.step_stack.keys();
17011822
......@@ -3234,7 +3355,7 @@ fn loadManifest(
32343355 \\
32353356 , .{
32363357 options.root_name,
3237 build_options.version,
3358 builtin.zig_version_string,
32383359 Package.Fingerprint.generate(rng.interface(), options.root_name).int(),
32393360 }) catch |e| {
32403361 fatal("unable to write {s}: {t}", .{ Package.Manifest.basename, e });
......@@ -3244,7 +3365,7 @@ fn loadManifest(
32443365 else => |e| fatal("unable to load {s}: {t}", .{ Package.Manifest.basename, e }),
32453366 };
32463367 };
3247 var ast = try Ast.parse(gpa, manifest_bytes, .zon);
3368 var ast = try std.zig.Ast.parse(gpa, manifest_bytes, .zon);
32483369 errdefer ast.deinit(gpa);
32493370
32503371 if (ast.errors.len > 0) {
......@@ -3272,3 +3393,138 @@ fn loadManifest(
32723393 return .{ manifest, ast };
32733394}
32743395
3396fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {
3397 var result: std.ArrayList(u8) = .empty;
3398 for (bytes, 0..) |byte, i| switch (byte) {
3399 '0'...'9' => {
3400 if (i == 0) try result.append(arena, '_');
3401 try result.append(arena, byte);
3402 },
3403 '_', 'a'...'z', 'A'...'Z' => try result.append(arena, byte),
3404 '-', '.', ' ' => try result.append(arena, '_'),
3405 else => continue,
3406 };
3407 if (!std.zig.isValidId(result.items)) return "foo";
3408 if (result.items.len > Package.Manifest.max_name_len)
3409 result.shrinkRetainingCapacity(Package.Manifest.max_name_len);
3410
3411 return result.toOwnedSlice(arena);
3412}
3413
3414test sanitizeExampleName {
3415 var arena_instance = std.heap.ArenaAllocator.init(std.testing.allocator);
3416 defer arena_instance.deinit();
3417 const arena = arena_instance.allocator();
3418
3419 try std.testing.expectEqualStrings("foo_bar", try sanitizeExampleName(arena, "foo bar+"));
3420 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, ""));
3421 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "!"));
3422 try std.testing.expectEqualStrings("a", try sanitizeExampleName(arena, "!a"));
3423 try std.testing.expectEqualStrings("a_b", try sanitizeExampleName(arena, "a.b!"));
3424 try std.testing.expectEqualStrings("_01234", try sanitizeExampleName(arena, "01234"));
3425 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "error"));
3426 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "test"));
3427 try std.testing.expectEqualStrings("tests", try sanitizeExampleName(arena, "tests"));
3428 try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project"));
3429}
3430
3431const Templates = struct {
3432 zig_lib_directory: Cache.Directory,
3433 dir: Io.Dir,
3434 buffer: std.array_list.Managed(u8),
3435
3436 fn deinit(templates: *Templates, io: Io) void {
3437 templates.zig_lib_directory.handle.close(io);
3438 templates.dir.close(io);
3439 templates.buffer.deinit();
3440 templates.* = undefined;
3441 }
3442
3443 fn write(
3444 templates: *Templates,
3445 arena: Allocator,
3446 io: Io,
3447 out_dir: Io.Dir,
3448 root_name: []const u8,
3449 template_path: []const u8,
3450 fingerprint: Package.Fingerprint,
3451 ) !void {
3452 if (Dir.path.dirname(template_path)) |dirname| {
3453 out_dir.createDirPath(io, dirname) catch |err| {
3454 fatal("unable to make path {q}: {t}", .{ dirname, err });
3455 };
3456 }
3457
3458 const max_bytes = 10 * 1024 * 1024;
3459 const contents = templates.dir.readFileAlloc(io, template_path, arena, .limited(max_bytes)) catch |err| {
3460 fatal("unable to read template file {q}: {t}", .{ template_path, err });
3461 };
3462 templates.buffer.clearRetainingCapacity();
3463 try templates.buffer.ensureUnusedCapacity(contents.len);
3464 var i: usize = 0;
3465 while (i < contents.len) {
3466 if (contents[i] == '_' or contents[i] == '.') {
3467 // Both '_' and '.' are allowed because depending on the context
3468 // one prefix will be valid, while the other might not.
3469 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {
3470 try templates.buffer.appendSlice(root_name);
3471 i += "_NAME".len;
3472 continue;
3473 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "FINGERPRINT")) {
3474 try templates.buffer.print("0x{x}", .{fingerprint.int()});
3475 i += "_FINGERPRINT".len;
3476 continue;
3477 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "ZIGVER")) {
3478 try templates.buffer.appendSlice(builtin.zig_version_string);
3479 i += "_ZIGVER".len;
3480 continue;
3481 }
3482 }
3483
3484 try templates.buffer.append(contents[i]);
3485 i += 1;
3486 }
3487
3488 return out_dir.writeFile(io, .{
3489 .sub_path = template_path,
3490 .data = templates.buffer.items,
3491 .flags = .{ .exclusive = true },
3492 });
3493 }
3494};
3495fn writeSimpleTemplateFile(io: Io, file_name: []const u8, comptime format: []const u8, args: anytype) !void {
3496 const f = try Io.Dir.cwd().createFile(io, file_name, .{ .exclusive = true });
3497 defer f.close(io);
3498 var buf: [4096]u8 = undefined;
3499 var fw = f.writer(io, &buf);
3500 try fw.interface.print(format, args);
3501 try fw.interface.flush();
3502}
3503
3504fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates {
3505 const cwd_path = std.zig.getResolvedCwd(io, arena) catch |err| {
3506 fatal("unable to get cwd: {t}", .{err});
3507 };
3508 const self_exe_path = process.executablePathAlloc(io, arena) catch |err| {
3509 fatal("unable to find self exe path: {t}", .{err});
3510 };
3511 var zig_lib_directory = std.zig.findZigLibDirFromSelfExe(arena, io, cwd_path, self_exe_path) catch |err| {
3512 fatal("unable to find zig installation directory {q}: {t}", .{ self_exe_path, err });
3513 };
3514
3515 const s = Dir.path.sep_str;
3516 const template_sub_path = "init";
3517 const template_dir = zig_lib_directory.handle.openDir(io, template_sub_path, .{}) catch |err| {
3518 const path = zig_lib_directory.path orelse ".";
3519 fatal("unable to open zig project template directory '{s}{s}{s}': {t}", .{
3520 path, s, template_sub_path, err,
3521 });
3522 };
3523
3524 return .{
3525 .zig_lib_directory = zig_lib_directory,
3526 .dir = template_dir,
3527 .buffer = std.array_list.Managed(u8).init(gpa),
3528 };
3529}
3530
src/main.zig+1-255
......@@ -353,7 +353,7 @@ fn mainArgs(
353353 dev.check(.ar_command);
354354 return process.exit(try llvmArMain(arena, args));
355355 },
356 .build, .fetch => {
356 .build, .fetch, .init => {
357357 return jitCmd(gpa, arena, io, args, environ_map, .{
358358 .cmd_name = "maker",
359359 .root_src_path = "Maker.zig",
......@@ -425,9 +425,6 @@ fn mainArgs(
425425 .prepend_global_cache_path = true,
426426 });
427427 },
428 .init => {
429 return cmdInit(gpa, arena, io, cmd_args);
430 },
431428 .targets => {
432429 dev.check(.targets_command);
433430 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
......@@ -4872,157 +4869,6 @@ pub fn translateC(
48724869 });
48734870}
48744871
4875const usage_init =
4876 \\Usage: zig init
4877 \\
4878 \\ Initializes a `zig build` project in the current working
4879 \\ directory.
4880 \\
4881 \\Options:
4882 \\ -m, --minimal Use minimal init template
4883 \\ -h, --help Print this help and exit
4884 \\
4885 \\
4886;
4887
4888fn cmdInit(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !void {
4889 dev.check(.init_command);
4890
4891 var template: enum { example, minimal } = .example;
4892 {
4893 var i: usize = 0;
4894 while (i < args.len) : (i += 1) {
4895 const arg = args[i];
4896 if (mem.startsWith(u8, arg, "-")) {
4897 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
4898 template = .minimal;
4899 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
4900 try Io.File.stdout().writeStreamingAll(io, usage_init);
4901 return cleanExit(io);
4902 } else {
4903 fatal("unrecognized parameter: {q}", .{arg});
4904 }
4905 } else {
4906 fatal("unexpected extra parameter: {q}", .{arg});
4907 }
4908 }
4909 }
4910
4911 const cwd_path = try std.zig.getResolvedCwd(io, arena);
4912 const cwd_basename = fs.path.basename(cwd_path);
4913 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
4914
4915 const rng: std.Random.IoSource = .{ .io = io };
4916 const fingerprint: Package.Fingerprint = .generate(rng.interface(), sanitized_root_name);
4917
4918 switch (template) {
4919 .example => {
4920 var templates = findTemplates(gpa, arena, io);
4921 defer templates.deinit(io);
4922
4923 const s = fs.path.sep_str;
4924 const template_paths = [_][]const u8{
4925 Package.build_zig_basename,
4926 Package.Manifest.basename,
4927 "src" ++ s ++ "main.zig",
4928 "src" ++ s ++ "root.zig",
4929 };
4930 var ok_count: usize = 0;
4931
4932 for (template_paths) |template_path| {
4933 if (templates.write(arena, io, Io.Dir.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
4934 std.log.info("created {s}", .{template_path});
4935 ok_count += 1;
4936 } else |err| switch (err) {
4937 error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
4938 template_path,
4939 }),
4940 else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
4941 }
4942 }
4943
4944 if (ok_count == template_paths.len) {
4945 std.log.info("see `zig build --help` for a menu of options", .{});
4946 }
4947 return cleanExit(io);
4948 },
4949 .minimal => {
4950 writeSimpleTemplateFile(io, Package.Manifest.basename,
4951 \\.{{
4952 \\ .name = .{s},
4953 \\ .version = "0.0.1",
4954 \\ .minimum_zig_version = "{s}",
4955 \\ .paths = .{{""}},
4956 \\ .fingerprint = 0x{x},
4957 \\}}
4958 \\
4959 , .{
4960 sanitized_root_name,
4961 build_options.version,
4962 fingerprint.int(),
4963 }) catch |err| switch (err) {
4964 else => fatal("failed to create {q}: {t}", .{ Package.Manifest.basename, err }),
4965 error.PathAlreadyExists => fatal("refusing to overwrite {q}", .{Package.Manifest.basename}),
4966 };
4967 writeSimpleTemplateFile(io, Package.build_zig_basename,
4968 \\const std = @import("std");
4969 \\
4970 \\pub fn build(b: *std.Build) void {{
4971 \\ _ = b; // stub
4972 \\}}
4973 \\
4974 , .{}) catch |err| switch (err) {
4975 else => fatal("failed to create {q}: {t}", .{ Package.build_zig_basename, err }),
4976 // `build.zig` already existing is okay: the user has just used `zig init` to set up
4977 // their `build.zig.zon` *after* writing their `build.zig`. So this one isn't fatal.
4978 error.PathAlreadyExists => {
4979 std.log.info("successfully populated {q}, preserving existing {q}", .{
4980 Package.Manifest.basename, Package.build_zig_basename,
4981 });
4982 return cleanExit(io);
4983 },
4984 };
4985 std.log.info("successfully populated {q} and {q}", .{ Package.Manifest.basename, Package.build_zig_basename });
4986 return cleanExit(io);
4987 },
4988 }
4989}
4990
4991fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {
4992 var result: std.ArrayList(u8) = .empty;
4993 for (bytes, 0..) |byte, i| switch (byte) {
4994 '0'...'9' => {
4995 if (i == 0) try result.append(arena, '_');
4996 try result.append(arena, byte);
4997 },
4998 '_', 'a'...'z', 'A'...'Z' => try result.append(arena, byte),
4999 '-', '.', ' ' => try result.append(arena, '_'),
5000 else => continue,
5001 };
5002 if (!std.zig.isValidId(result.items)) return "foo";
5003 if (result.items.len > Package.Manifest.max_name_len)
5004 result.shrinkRetainingCapacity(Package.Manifest.max_name_len);
5005
5006 return result.toOwnedSlice(arena);
5007}
5008
5009test sanitizeExampleName {
5010 var arena_instance = std.heap.ArenaAllocator.init(std.testing.allocator);
5011 defer arena_instance.deinit();
5012 const arena = arena_instance.allocator();
5013
5014 try std.testing.expectEqualStrings("foo_bar", try sanitizeExampleName(arena, "foo bar+"));
5015 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, ""));
5016 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "!"));
5017 try std.testing.expectEqualStrings("a", try sanitizeExampleName(arena, "!a"));
5018 try std.testing.expectEqualStrings("a_b", try sanitizeExampleName(arena, "a.b!"));
5019 try std.testing.expectEqualStrings("_01234", try sanitizeExampleName(arena, "01234"));
5020 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "error"));
5021 try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "test"));
5022 try std.testing.expectEqualStrings("tests", try sanitizeExampleName(arena, "tests"));
5023 try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project"));
5024}
5025
50264872const JitCmdOptions = struct {
50274873 cmd_name: []const u8,
50284874 root_src_path: []const u8,
......@@ -6152,106 +5998,6 @@ fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes {
61525998 fatal("unsupported rc includes type: {q}", .{arg});
61535999}
61546000
6155const Templates = struct {
6156 zig_lib_directory: Cache.Directory,
6157 dir: Io.Dir,
6158 buffer: std.array_list.Managed(u8),
6159
6160 fn deinit(templates: *Templates, io: Io) void {
6161 templates.zig_lib_directory.handle.close(io);
6162 templates.dir.close(io);
6163 templates.buffer.deinit();
6164 templates.* = undefined;
6165 }
6166
6167 fn write(
6168 templates: *Templates,
6169 arena: Allocator,
6170 io: Io,
6171 out_dir: Io.Dir,
6172 root_name: []const u8,
6173 template_path: []const u8,
6174 fingerprint: Package.Fingerprint,
6175 ) !void {
6176 if (fs.path.dirname(template_path)) |dirname| {
6177 out_dir.createDirPath(io, dirname) catch |err| {
6178 fatal("unable to make path {q}: {t}", .{ dirname, err });
6179 };
6180 }
6181
6182 const max_bytes = 10 * 1024 * 1024;
6183 const contents = templates.dir.readFileAlloc(io, template_path, arena, .limited(max_bytes)) catch |err| {
6184 fatal("unable to read template file {q}: {t}", .{ template_path, err });
6185 };
6186 templates.buffer.clearRetainingCapacity();
6187 try templates.buffer.ensureUnusedCapacity(contents.len);
6188 var i: usize = 0;
6189 while (i < contents.len) {
6190 if (contents[i] == '_' or contents[i] == '.') {
6191 // Both '_' and '.' are allowed because depending on the context
6192 // one prefix will be valid, while the other might not.
6193 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {
6194 try templates.buffer.appendSlice(root_name);
6195 i += "_NAME".len;
6196 continue;
6197 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "FINGERPRINT")) {
6198 try templates.buffer.print("0x{x}", .{fingerprint.int()});
6199 i += "_FINGERPRINT".len;
6200 continue;
6201 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "ZIGVER")) {
6202 try templates.buffer.appendSlice(build_options.version);
6203 i += "_ZIGVER".len;
6204 continue;
6205 }
6206 }
6207
6208 try templates.buffer.append(contents[i]);
6209 i += 1;
6210 }
6211
6212 return out_dir.writeFile(io, .{
6213 .sub_path = template_path,
6214 .data = templates.buffer.items,
6215 .flags = .{ .exclusive = true },
6216 });
6217 }
6218};
6219fn writeSimpleTemplateFile(io: Io, file_name: []const u8, comptime fmt: []const u8, args: anytype) !void {
6220 const f = try Io.Dir.cwd().createFile(io, file_name, .{ .exclusive = true });
6221 defer f.close(io);
6222 var buf: [4096]u8 = undefined;
6223 var fw = f.writer(io, &buf);
6224 try fw.interface.print(fmt, args);
6225 try fw.interface.flush();
6226}
6227
6228fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates {
6229 const cwd_path = std.zig.getResolvedCwd(io, arena) catch |err| {
6230 fatal("unable to get cwd: {t}", .{err});
6231 };
6232 const self_exe_path = process.executablePathAlloc(io, arena) catch |err| {
6233 fatal("unable to find self exe path: {t}", .{err});
6234 };
6235 var zig_lib_directory = std.zig.findZigLibDirFromSelfExe(arena, io, cwd_path, self_exe_path) catch |err| {
6236 fatal("unable to find zig installation directory {q}: {t}", .{ self_exe_path, err });
6237 };
6238
6239 const s = fs.path.sep_str;
6240 const template_sub_path = "init";
6241 const template_dir = zig_lib_directory.handle.openDir(io, template_sub_path, .{}) catch |err| {
6242 const path = zig_lib_directory.path orelse ".";
6243 fatal("unable to open zig project template directory '{s}{s}{s}': {t}", .{
6244 path, s, template_sub_path, err,
6245 });
6246 };
6247
6248 return .{
6249 .zig_lib_directory = zig_lib_directory,
6250 .dir = template_dir,
6251 .buffer = std.array_list.Managed(u8).init(gpa),
6252 };
6253}
6254
62556001fn parseOptimizeMode(s: []const u8) std.lang.OptimizeMode {
62566002 return stringToEnum(std.lang.OptimizeMode, s) orelse
62576003 fatal("unrecognized optimization mode: {q}", .{s});