zig fetch: add --save flag

```
--save        Add the fetched package to build.zig.zon
--save=[name] Add the fetched package to build.zig.zon as name
```
This commit is contained in:
Andrew Kelley 2023-11-26 17:04:28 -07:00
parent a0c8d54823
commit 0c0b69891a
3 changed files with 347 additions and 111 deletions

View File

@ -61,7 +61,7 @@ String.
When this is provided, the package is found in a directory relative to the When this is provided, the package is found in a directory relative to the
build root. In this case the package's hash is irrelevant and therefore not build root. In this case the package's hash is irrelevant and therefore not
computed. computed. This field and `url` are mutually exclusive.
### `paths` ### `paths`

View File

@ -15,8 +15,7 @@
// Once all dependencies are fetched, `zig build` no longer requires // Once all dependencies are fetched, `zig build` no longer requires
// Internet connectivity. // Internet connectivity.
.dependencies = .{ .dependencies = .{
// A future version of Zig will provide a `zig add <url>` subcommand // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
// for easily adding dependencies.
//.example = .{ //.example = .{
// // When updating this field to a new URL, be sure to delete the corresponding // // When updating this field to a new URL, be sure to delete the corresponding
// // `hash`, otherwise you are communicating that you expect to find the old hash at // // `hash`, otherwise you are communicating that you expect to find the old hash at
@ -36,7 +35,7 @@
// //
// // When this is provided, the package is found in a directory relative to the // // When this is provided, the package is found in a directory relative to the
// // build root. In this case the package's hash is irrelevant and therefore not // // build root. In this case the package's hash is irrelevant and therefore not
// // computed. // // computed. This field and `url` are mutually exclusive.
// .path = "foo", // .path = "foo",
//}, //},
}, },
@ -57,5 +56,7 @@
//"build.zig", //"build.zig",
//"build.zig.zon", //"build.zig.zon",
//"src", //"src",
//"LICENSE",
//"README.md",
}, },
} }

View File

@ -1255,7 +1255,7 @@ fn buildOutputType(
override_lib_dir = args_iter.nextOrFatal(); override_lib_dir = args_iter.nextOrFatal();
} else if (mem.eql(u8, arg, "--debug-log")) { } else if (mem.eql(u8, arg, "--debug-log")) {
if (!build_options.enable_logging) { if (!build_options.enable_logging) {
std.log.warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}); warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
_ = args_iter.nextOrFatal(); _ = args_iter.nextOrFatal();
} else { } else {
try log_scopes.append(gpa, args_iter.nextOrFatal()); try log_scopes.append(gpa, args_iter.nextOrFatal());
@ -1279,7 +1279,7 @@ fn buildOutputType(
listen = .stdio; listen = .stdio;
} else if (mem.eql(u8, arg, "--debug-link-snapshot")) { } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {
if (!build_options.enable_link_snapshots) { if (!build_options.enable_link_snapshots) {
std.log.warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{}); warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{});
} else { } else {
enable_link_snapshots = true; enable_link_snapshots = true;
} }
@ -1558,7 +1558,7 @@ fn buildOutputType(
}; };
} else if (mem.eql(u8, arg, "--debug-compile-errors")) { } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
if (!crash_report.is_enabled) { if (!crash_report.is_enabled) {
std.log.warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{}); warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{});
} else { } else {
debug_compile_errors = true; debug_compile_errors = true;
} }
@ -1662,7 +1662,7 @@ fn buildOutputType(
}, },
.def, .unknown => { .def, .unknown => {
if (std.ascii.eqlIgnoreCase(".xml", std.fs.path.extension(arg))) { if (std.ascii.eqlIgnoreCase(".xml", std.fs.path.extension(arg))) {
std.log.warn("embedded manifest files must have the extension '.manifest'", .{}); warn("embedded manifest files must have the extension '.manifest'", .{});
} }
fatal("unrecognized file extension of parameter '{s}'", .{arg}); fatal("unrecognized file extension of parameter '{s}'", .{arg});
}, },
@ -2793,7 +2793,7 @@ fn buildOutputType(
continue; continue;
}, },
.only_compiler_rt => { .only_compiler_rt => {
std.log.warn("ignoring superfluous library '{s}': this dependency is fulfilled instead by compiler-rt which zig unconditionally provides", .{lib_name}); warn("ignoring superfluous library '{s}': this dependency is fulfilled instead by compiler-rt which zig unconditionally provides", .{lib_name});
continue; continue;
}, },
} }
@ -4851,7 +4851,6 @@ pub const usage_init =
; ;
pub fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { pub fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
_ = gpa;
{ {
var i: usize = 0; var i: usize = 0;
while (i < args.len) : (i += 1) { while (i < args.len) : (i += 1) {
@ -4868,58 +4867,24 @@ pub fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
} }
} }
} }
const self_exe_path = try introspect.findZigExePath(arena);
var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});
};
defer zig_lib_directory.handle.close();
const s = fs.path.sep_str; var templates = findTemplates(gpa, arena);
const template_sub_path = "init"; defer templates.deinit();
var template_dir = zig_lib_directory.handle.openDir(template_sub_path, .{}) catch |err| {
const path = zig_lib_directory.path orelse ".";
fatal("unable to open zig project template directory '{s}{s}{s}': {s}", .{
path, s, template_sub_path, @errorName(err),
});
};
defer template_dir.close();
const cwd_path = try process.getCwdAlloc(arena); const cwd_path = try process.getCwdAlloc(arena);
const cwd_basename = fs.path.basename(cwd_path); const cwd_basename = fs.path.basename(cwd_path);
const max_bytes = 10 * 1024 * 1024; const s = fs.path.sep_str;
const template_paths = [_][]const u8{ const template_paths = [_][]const u8{
"build.zig", Package.build_zig_basename,
"build.zig.zon", Package.Manifest.basename,
"src" ++ s ++ "main.zig", "src" ++ s ++ "main.zig",
"src" ++ s ++ "root.zig", "src" ++ s ++ "root.zig",
}; };
var ok_count: usize = 0; var ok_count: usize = 0;
for (template_paths) |template_path| { for (template_paths) |template_path| {
if (fs.path.dirname(template_path)) |dirname| { if (templates.write(arena, fs.cwd(), cwd_basename, template_path)) |_| {
fs.cwd().makePath(dirname) catch |err| {
fatal("unable to make path '{s}': {s}", .{ dirname, @errorName(err) });
};
}
const contents = template_dir.readFileAlloc(arena, template_path, max_bytes) catch |err| {
fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) });
};
var modified_contents = try std.ArrayList(u8).initCapacity(arena, contents.len);
for (contents) |c| {
if (c == '$') {
try modified_contents.appendSlice(cwd_basename);
} else {
try modified_contents.append(c);
}
}
if (fs.cwd().writeFile2(.{
.sub_path = template_path,
.data = modified_contents.items,
.flags = .{ .exclusive = true },
})) |_| {
std.log.info("created {s}", .{template_path}); std.log.info("created {s}", .{template_path});
ok_count += 1; ok_count += 1;
} else |err| switch (err) { } else |err| switch (err) {
@ -5057,14 +5022,14 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
try child_argv.appendSlice(args[i .. i + 2]); try child_argv.appendSlice(args[i .. i + 2]);
i += 1; i += 1;
if (!build_options.enable_logging) { if (!build_options.enable_logging) {
std.log.warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}); warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
} else { } else {
try log_scopes.append(gpa, args[i]); try log_scopes.append(gpa, args[i]);
} }
continue; continue;
} else if (mem.eql(u8, arg, "--debug-compile-errors")) { } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
if (!crash_report.is_enabled) { if (!crash_report.is_enabled) {
std.log.warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{}); warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{});
} else { } else {
debug_compile_errors = true; debug_compile_errors = true;
} }
@ -5113,44 +5078,11 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
defer if (cleanup_build_dir) |*dir| dir.close(); defer if (cleanup_build_dir) |*dir| dir.close();
const cwd_path = try process.getCwdAlloc(arena); const cwd_path = try process.getCwdAlloc(arena);
const build_zig_basename = if (build_file) |bf| fs.path.basename(bf) else Package.build_zig_basename; const build_root = try findBuildRoot(arena, .{
const build_root: Compilation.Directory = blk: { .cwd_path = cwd_path,
if (build_file) |bf| { .build_file = build_file,
if (fs.path.dirname(bf)) |dirname| {
const dir = fs.cwd().openDir(dirname, .{}) catch |err| {
fatal("unable to open directory to build file from argument 'build-file', '{s}': {s}", .{ dirname, @errorName(err) });
};
cleanup_build_dir = dir;
break :blk .{ .path = dirname, .handle = dir };
}
break :blk .{ .path = null, .handle = fs.cwd() };
}
// Search up parent directories until we find build.zig.
var dirname: []const u8 = cwd_path;
while (true) {
const joined_path = try fs.path.join(arena, &[_][]const u8{ dirname, build_zig_basename });
if (fs.cwd().access(joined_path, .{})) |_| {
const dir = fs.cwd().openDir(dirname, .{}) catch |err| {
fatal("unable to open directory while searching for build.zig file, '{s}': {s}", .{ dirname, @errorName(err) });
};
break :blk .{ .path = dirname, .handle = dir };
} else |err| switch (err) {
error.FileNotFound => {
dirname = fs.path.dirname(dirname) orelse {
std.log.info("{s}", .{
\\Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,
\\or see `zig --help` for more options.
}); });
fatal("No 'build.zig' file found, in the current directory or any parent directories.", .{}); child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;
};
continue;
},
else => |e| return e,
}
}
};
child_argv.items[argv_index_build_file] = build_root.path orelse cwd_path;
var global_cache_directory: Compilation.Directory = l: { var global_cache_directory: Compilation.Directory = l: {
const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena); const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
@ -5170,9 +5102,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
.path = local_cache_dir_path, .path = local_cache_dir_path,
}; };
} }
const cache_dir_path = try build_root.join(arena, &[_][]const u8{"zig-cache"}); const cache_dir_path = try build_root.directory.join(arena, &[_][]const u8{"zig-cache"});
break :l .{ break :l .{
.handle = try build_root.handle.makeOpenPath("zig-cache", .{}), .handle = try build_root.directory.handle.makeOpenPath("zig-cache", .{}),
.path = cache_dir_path, .path = cache_dir_path,
}; };
}; };
@ -5215,8 +5147,8 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
}; };
var build_mod: Package.Module = .{ var build_mod: Package.Module = .{
.root = .{ .root_dir = build_root }, .root = .{ .root_dir = build_root.directory },
.root_src_path = build_zig_basename, .root_src_path = build_root.build_zig_basename,
.fully_qualified_name = "root.@build", .fully_qualified_name = "root.@build",
}; };
if (build_options.only_core_functionality) { if (build_options.only_core_functionality) {
@ -6904,40 +6836,40 @@ const ClangSearchSanitizer = struct {
.I => { .I => {
if (m.I) return; if (m.I) return;
m.I = true; m.I = true;
if (m.isystem) std.log.warn(wtxt, .{ dir, "I", "isystem" }); if (m.isystem) warn(wtxt, .{ dir, "I", "isystem" });
if (m.idirafter) std.log.warn(wtxt, .{ dir, "I", "idirafter" }); if (m.idirafter) warn(wtxt, .{ dir, "I", "idirafter" });
if (m.iframework) std.log.warn(wtxt, .{ dir, "I", "iframework" }); if (m.iframework) warn(wtxt, .{ dir, "I", "iframework" });
}, },
.isystem => { .isystem => {
if (m.isystem) return; if (m.isystem) return;
m.isystem = true; m.isystem = true;
if (m.I) std.log.warn(wtxt, .{ dir, "isystem", "I" }); if (m.I) warn(wtxt, .{ dir, "isystem", "I" });
if (m.idirafter) std.log.warn(wtxt, .{ dir, "isystem", "idirafter" }); if (m.idirafter) warn(wtxt, .{ dir, "isystem", "idirafter" });
if (m.iframework) std.log.warn(wtxt, .{ dir, "isystem", "iframework" }); if (m.iframework) warn(wtxt, .{ dir, "isystem", "iframework" });
}, },
.iwithsysroot => { .iwithsysroot => {
if (m.iwithsysroot) return; if (m.iwithsysroot) return;
m.iwithsysroot = true; m.iwithsysroot = true;
if (m.iframeworkwithsysroot) std.log.warn(wtxt, .{ dir, "iwithsysroot", "iframeworkwithsysroot" }); if (m.iframeworkwithsysroot) warn(wtxt, .{ dir, "iwithsysroot", "iframeworkwithsysroot" });
}, },
.idirafter => { .idirafter => {
if (m.idirafter) return; if (m.idirafter) return;
m.idirafter = true; m.idirafter = true;
if (m.I) std.log.warn(wtxt, .{ dir, "idirafter", "I" }); if (m.I) warn(wtxt, .{ dir, "idirafter", "I" });
if (m.isystem) std.log.warn(wtxt, .{ dir, "idirafter", "isystem" }); if (m.isystem) warn(wtxt, .{ dir, "idirafter", "isystem" });
if (m.iframework) std.log.warn(wtxt, .{ dir, "idirafter", "iframework" }); if (m.iframework) warn(wtxt, .{ dir, "idirafter", "iframework" });
}, },
.iframework => { .iframework => {
if (m.iframework) return; if (m.iframework) return;
m.iframework = true; m.iframework = true;
if (m.I) std.log.warn(wtxt, .{ dir, "iframework", "I" }); if (m.I) warn(wtxt, .{ dir, "iframework", "I" });
if (m.isystem) std.log.warn(wtxt, .{ dir, "iframework", "isystem" }); if (m.isystem) warn(wtxt, .{ dir, "iframework", "isystem" });
if (m.idirafter) std.log.warn(wtxt, .{ dir, "iframework", "idirafter" }); if (m.idirafter) warn(wtxt, .{ dir, "iframework", "idirafter" });
}, },
.iframeworkwithsysroot => { .iframeworkwithsysroot => {
if (m.iframeworkwithsysroot) return; if (m.iframeworkwithsysroot) return;
m.iframeworkwithsysroot = true; m.iframeworkwithsysroot = true;
if (m.iwithsysroot) std.log.warn(wtxt, .{ dir, "iframeworkwithsysroot", "iwithsysroot" }); if (m.iwithsysroot) warn(wtxt, .{ dir, "iframeworkwithsysroot", "iwithsysroot" });
}, },
} }
try self.argv.append(arg); try self.argv.append(arg);
@ -7097,6 +7029,8 @@ pub const usage_fetch =
\\ -h, --help Print this help and exit \\ -h, --help Print this help and exit
\\ --global-cache-dir [path] Override path to global Zig cache directory \\ --global-cache-dir [path] Override path to global Zig cache directory
\\ --debug-hash Print verbose hash information to stdout \\ --debug-hash Print verbose hash information to stdout
\\ --save Add the fetched package to build.zig.zon
\\ --save=[name] Add the fetched package to build.zig.zon as name
\\ \\
; ;
@ -7111,6 +7045,7 @@ fn cmdFetch(
var opt_path_or_url: ?[]const u8 = null; var opt_path_or_url: ?[]const u8 = null;
var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena); var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
var debug_hash: bool = false; var debug_hash: bool = false;
var save: union(enum) { no, yes, name: []const u8 } = .no;
{ {
var i: usize = 0; var i: usize = 0;
@ -7125,10 +7060,12 @@ fn cmdFetch(
if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
i += 1; i += 1;
override_global_cache_dir = args[i]; override_global_cache_dir = args[i];
continue;
} else if (mem.eql(u8, arg, "--debug-hash")) { } else if (mem.eql(u8, arg, "--debug-hash")) {
debug_hash = true; debug_hash = true;
continue; } else if (mem.eql(u8, arg, "--save")) {
save = .yes;
} else if (mem.startsWith(u8, arg, "--save=")) {
save = .{ .name = arg["--save=".len..] };
} else { } else {
fatal("unrecognized parameter: '{s}'", .{arg}); fatal("unrecognized parameter: '{s}'", .{arg});
} }
@ -7214,7 +7151,97 @@ fn cmdFetch(
progress.done = true; progress.done = true;
progress.refresh(); progress.refresh();
const name = switch (save) {
.no => {
try io.getStdOut().writeAll(hex_digest ++ "\n"); try io.getStdOut().writeAll(hex_digest ++ "\n");
return cleanExit();
},
.yes => n: {
const fetched_manifest = fetch.manifest orelse
fatal("unable to determine name; fetched package has no build.zig.zon file", .{});
break :n fetched_manifest.name;
},
.name => |n| n,
};
const cwd_path = try process.getCwdAlloc(arena);
var build_root = try findBuildRoot(arena, .{
.cwd_path = cwd_path,
});
defer build_root.deinit();
// The name to use in case the manifest file needs to be created now.
const init_root_name = fs.path.basename(build_root.directory.path orelse cwd_path);
var manifest, var ast = try loadManifest(gpa, arena, .{
.root_name = init_root_name,
.dir = build_root.directory.handle,
.color = color,
});
defer {
manifest.deinit(gpa);
ast.deinit(gpa);
}
var fixups: Ast.Fixups = .{};
defer fixups.deinit(gpa);
const new_node_init = try std.fmt.allocPrint(arena,
\\.{{
\\ .url = "{}",
\\ .hash = "{}",
\\ }}
, .{
std.zig.fmtEscapes(path_or_url),
std.zig.fmtEscapes(&hex_digest),
});
const new_node_text = try std.fmt.allocPrint(arena, ".{} = {s},\n", .{
std.zig.fmtId(name), new_node_init,
});
const dependencies_init = try std.fmt.allocPrint(arena, ".{{\n {s} }}", .{
new_node_text,
});
const dependencies_text = try std.fmt.allocPrint(arena, ".dependencies = {s},\n", .{
dependencies_init,
});
if (manifest.dependencies.get(name)) |dep| {
if (dep.hash) |h| {
switch (dep.location) {
.url => |u| {
if (mem.eql(u8, h, &hex_digest) and mem.eql(u8, u, path_or_url)) {
std.log.info("existing dependency named '{s}' is up-to-date", .{name});
process.exit(0);
}
},
.path => {},
}
}
warn("overwriting existing dependency named '{s}'", .{name});
try fixups.replace_nodes_with_string.put(gpa, dep.node, new_node_init);
} else if (manifest.dependencies.count() > 0) {
// Add fixup for adding another dependency.
const deps = manifest.dependencies.values();
const last_dep_node = deps[deps.len - 1].node;
try fixups.append_string_after_node.put(gpa, last_dep_node, new_node_text);
} else if (manifest.dependencies_node != 0) {
// Add fixup for replacing the entire dependencies struct.
try fixups.replace_nodes_with_string.put(gpa, manifest.dependencies_node, dependencies_init);
} else {
// Add fixup for adding dependencies struct.
try fixups.append_string_after_node.put(gpa, manifest.version_node, dependencies_text);
}
var rendered = std.ArrayList(u8).init(gpa);
defer rendered.deinit();
try ast.renderToArrayList(&rendered, fixups);
build_root.directory.handle.writeFile(Package.Manifest.basename, rendered.items) catch |err| {
fatal("unable to write {s} file: {s}", .{ Package.Manifest.basename, @errorName(err) });
};
return cleanExit(); return cleanExit();
} }
@ -7279,3 +7306,211 @@ fn defaultWasmEntryName(exec_model: ?std.builtin.WasiExecModel) []const u8 {
} }
return "_start"; return "_start";
} }
const BuildRoot = struct {
directory: Cache.Directory,
build_zig_basename: []const u8,
cleanup_build_dir: ?fs.Dir,
fn deinit(br: *BuildRoot) void {
if (br.cleanup_build_dir) |*dir| dir.close();
br.* = undefined;
}
};
const FindBuildRootOptions = struct {
build_file: ?[]const u8 = null,
cwd_path: ?[]const u8 = null,
};
fn findBuildRoot(arena: Allocator, options: FindBuildRootOptions) !BuildRoot {
const cwd_path = options.cwd_path orelse try process.getCwdAlloc(arena);
const build_zig_basename = if (options.build_file) |bf|
fs.path.basename(bf)
else
Package.build_zig_basename;
if (options.build_file) |bf| {
if (fs.path.dirname(bf)) |dirname| {
const dir = fs.cwd().openDir(dirname, .{}) catch |err| {
fatal("unable to open directory to build file from argument 'build-file', '{s}': {s}", .{ dirname, @errorName(err) });
};
return .{
.build_zig_basename = build_zig_basename,
.directory = .{ .path = dirname, .handle = dir },
.cleanup_build_dir = dir,
};
}
return .{
.build_zig_basename = build_zig_basename,
.directory = .{ .path = null, .handle = fs.cwd() },
.cleanup_build_dir = null,
};
}
// Search up parent directories until we find build.zig.
var dirname: []const u8 = cwd_path;
while (true) {
const joined_path = try fs.path.join(arena, &[_][]const u8{ dirname, build_zig_basename });
if (fs.cwd().access(joined_path, .{})) |_| {
const dir = fs.cwd().openDir(dirname, .{}) catch |err| {
fatal("unable to open directory while searching for build.zig file, '{s}': {s}", .{ dirname, @errorName(err) });
};
return .{
.build_zig_basename = build_zig_basename,
.directory = .{
.path = dirname,
.handle = dir,
},
.cleanup_build_dir = dir,
};
} else |err| switch (err) {
error.FileNotFound => {
dirname = fs.path.dirname(dirname) orelse {
std.log.info("initialize {s} template file with 'zig init'", .{
Package.build_zig_basename,
});
std.log.info("see 'zig --help' for more options", .{});
fatal("no build.zig file found, in the current directory or any parent directories", .{});
};
continue;
},
else => |e| return e,
}
}
}
const LoadManifestOptions = struct {
root_name: []const u8,
dir: fs.Dir,
color: Color,
};
fn loadManifest(
gpa: Allocator,
arena: Allocator,
options: LoadManifestOptions,
) !struct { Package.Manifest, Ast } {
const manifest_bytes = while (true) {
break options.dir.readFileAllocOptions(
arena,
Package.Manifest.basename,
Package.Manifest.max_bytes,
null,
1,
0,
) catch |err| switch (err) {
error.FileNotFound => {
var templates = findTemplates(gpa, arena);
defer templates.deinit();
templates.write(arena, options.dir, options.root_name, Package.Manifest.basename) catch |e| {
fatal("unable to write {s}: {s}", .{
Package.Manifest.basename, @errorName(e),
});
};
continue;
},
else => |e| fatal("unable to load {s}: {s}", .{
Package.Manifest.basename, @errorName(e),
}),
};
};
var ast = try Ast.parse(gpa, manifest_bytes, .zon);
errdefer ast.deinit(gpa);
if (ast.errors.len > 0) {
try printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);
process.exit(2);
}
var manifest = try Package.Manifest.parse(gpa, ast, .{});
errdefer manifest.deinit(gpa);
if (manifest.errors.len > 0) {
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
try wip_errors.init(gpa);
defer wip_errors.deinit();
const src_path = try wip_errors.addString(Package.Manifest.basename);
try manifest.copyErrorsIntoBundle(ast, src_path, &wip_errors);
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(options.color));
process.exit(2);
}
return .{ manifest, ast };
}
const Templates = struct {
zig_lib_directory: Cache.Directory,
dir: fs.Dir,
buffer: std.ArrayList(u8),
fn deinit(templates: *Templates) void {
templates.zig_lib_directory.handle.close();
templates.dir.close();
templates.buffer.deinit();
templates.* = undefined;
}
fn write(
templates: *Templates,
arena: Allocator,
out_dir: fs.Dir,
root_name: []const u8,
template_path: []const u8,
) !void {
if (fs.path.dirname(template_path)) |dirname| {
out_dir.makePath(dirname) catch |err| {
fatal("unable to make path '{s}': {s}", .{ dirname, @errorName(err) });
};
}
const max_bytes = 10 * 1024 * 1024;
const contents = templates.dir.readFileAlloc(arena, template_path, max_bytes) catch |err| {
fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) });
};
templates.buffer.clearRetainingCapacity();
try templates.buffer.ensureUnusedCapacity(contents.len);
for (contents) |c| {
if (c == '$') {
try templates.buffer.appendSlice(root_name);
} else {
try templates.buffer.append(c);
}
}
return out_dir.writeFile2(.{
.sub_path = template_path,
.data = templates.buffer.items,
.flags = .{ .exclusive = true },
});
}
};
fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
const self_exe_path = introspect.findZigExePath(arena) catch |err| {
fatal("unable to find self exe path: {s}", .{@errorName(err)});
};
var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
};
const s = fs.path.sep_str;
const template_sub_path = "init";
const template_dir = zig_lib_directory.handle.openDir(template_sub_path, .{}) catch |err| {
const path = zig_lib_directory.path orelse ".";
fatal("unable to open zig project template directory '{s}{s}{s}': {s}", .{
path, s, template_sub_path, @errorName(err),
});
};
return .{
.zig_lib_directory = zig_lib_directory,
.dir = template_dir,
.buffer = std.ArrayList(u8).init(gpa),
};
}