aboutsummaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-05-06 12:51:51 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-05-06 12:51:51 -0700
commit3791cd6781ce92478b8a17c8d56c5cf66d4ecfb0 (patch)
treecd1b0bef65345a8be9d0ace813cabe694d87c9c2 /src/main.zig
parent426e4c784cee76d3711bb17fb53ef062e3b0f072 (diff)
downloadzig-3791cd6781ce92478b8a17c8d56c5cf66d4ecfb0.tar.gz
zig-3791cd6781ce92478b8a17c8d56c5cf66d4ecfb0.zip
CLI: add 'run' command to the repl
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig275
1 files changed, 165 insertions, 110 deletions
diff --git a/src/main.zig b/src/main.zig
index a00e85163d..1e24571be1 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -488,18 +488,20 @@ fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 {
}
}
+const ArgMode = union(enum) {
+ build: std.builtin.OutputMode,
+ cc,
+ cpp,
+ translate_c,
+ zig_test,
+ run,
+};
+
fn buildOutputType(
gpa: *Allocator,
arena: *Allocator,
all_args: []const []const u8,
- arg_mode: union(enum) {
- build: std.builtin.OutputMode,
- cc,
- cpp,
- translate_c,
- zig_test,
- run,
- },
+ arg_mode: ArgMode,
) !void {
var color: Color = .auto;
var optimize_mode: std.builtin.Mode = .Debug;
@@ -1967,108 +1969,21 @@ fn buildOutputType(
.run, .zig_test => true,
else => false,
};
- if (run_or_test) run: {
- const exe_loc = emit_bin_loc orelse break :run;
- const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
- const exe_path = try fs.path.join(arena, &[_][]const u8{
- exe_directory.path orelse ".", exe_loc.basename,
- });
-
- var argv = std.ArrayList([]const u8).init(gpa);
- defer argv.deinit();
-
- if (test_exec_args.items.len == 0) {
- if (!std.Target.current.canExecBinariesOf(target_info.target)) {
- switch (arg_mode) {
- .zig_test => {
- warn("created {s} but skipping execution because it is non-native", .{exe_path});
- if (!watch) return cleanExit();
- break :run;
- },
- .run => fatal("unable to execute {s}: non-native", .{exe_path}),
- else => unreachable,
- }
- }
- // when testing pass the zig_exe_path to argv
- if (arg_mode == .zig_test)
- try argv.appendSlice(&[_][]const u8{
- exe_path, self_exe_path,
- })
- // when running just pass the current exe
- else
- try argv.appendSlice(&[_][]const u8{
- exe_path,
- });
- } else {
- for (test_exec_args.items) |arg| {
- if (arg) |a| {
- try argv.append(a);
- } else {
- try argv.appendSlice(&[_][]const u8{
- exe_path, self_exe_path,
- });
- }
- }
- }
- if (runtime_args_start) |i| {
- try argv.appendSlice(all_args[i..]);
- }
- // We do not execve for tests because if the test fails we want to print
- // the error message and invocation below.
- if (std.process.can_execv and arg_mode == .run and !watch) {
- // execv releases the locks; no need to destroy the Compilation here.
- const err = std.process.execv(gpa, argv.items);
- const cmd = try argvCmd(arena, argv.items);
- fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
- } else {
- const child = try std.ChildProcess.init(argv.items, gpa);
- defer child.deinit();
-
- child.stdin_behavior = .Inherit;
- child.stdout_behavior = .Inherit;
- child.stderr_behavior = .Inherit;
-
- if (!watch) {
- // Here we release all the locks associated with the Compilation so
- // that whatever this child process wants to do won't deadlock.
- comp.destroy();
- comp_destroyed = true;
- }
-
- const term = try child.spawnAndWait();
- switch (arg_mode) {
- .run => {
- switch (term) {
- .Exited => |code| {
- if (code == 0) {
- if (!watch) return cleanExit();
- } else {
- // TODO https://github.com/ziglang/zig/issues/6342
- process.exit(1);
- }
- },
- else => process.exit(1),
- }
- },
- .zig_test => {
- switch (term) {
- .Exited => |code| {
- if (code == 0) {
- if (!watch) return cleanExit();
- } else {
- const cmd = try argvCmd(arena, argv.items);
- fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });
- }
- },
- else => {
- const cmd = try argvCmd(arena, argv.items);
- fatal("the following test command crashed:\n{s}", .{cmd});
- },
- }
- },
- else => unreachable,
- }
- }
+ if (run_or_test) {
+ try runOrTest(
+ comp,
+ gpa,
+ arena,
+ emit_bin_loc,
+ test_exec_args.items,
+ self_exe_path,
+ arg_mode,
+ target_info.target,
+ watch,
+ &comp_destroyed,
+ all_args,
+ runtime_args_start,
+ );
}
const stdin = std.io.getStdIn().reader();
@@ -2096,6 +2011,21 @@ fn buildOutputType(
break;
} else if (mem.eql(u8, actual_line, "help")) {
try stderr.writeAll(repl_help);
+ } else if (mem.eql(u8, actual_line, "run")) {
+ try runOrTest(
+ comp,
+ gpa,
+ arena,
+ emit_bin_loc,
+ test_exec_args.items,
+ self_exe_path,
+ arg_mode,
+ target_info.target,
+ watch,
+ &comp_destroyed,
+ all_args,
+ runtime_args_start,
+ );
} else {
try stderr.print("unknown command: {s}\n", .{actual_line});
}
@@ -2105,6 +2035,131 @@ fn buildOutputType(
}
}
+fn runOrTest(
+ comp: *Compilation,
+ gpa: *Allocator,
+ arena: *Allocator,
+ emit_bin_loc: ?Compilation.EmitLoc,
+ test_exec_args: []const ?[]const u8,
+ self_exe_path: []const u8,
+ arg_mode: ArgMode,
+ target: std.Target,
+ watch: bool,
+ comp_destroyed: *bool,
+ all_args: []const []const u8,
+ runtime_args_start: ?usize,
+) !void {
+ const exe_loc = emit_bin_loc orelse return;
+ const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
+ const exe_path = try fs.path.join(arena, &[_][]const u8{
+ exe_directory.path orelse ".", exe_loc.basename,
+ });
+
+ var argv = std.ArrayList([]const u8).init(gpa);
+ defer argv.deinit();
+
+ if (test_exec_args.len == 0) {
+ if (!std.Target.current.canExecBinariesOf(target)) {
+ switch (arg_mode) {
+ .zig_test => {
+ warn("created {s} but skipping execution because it is non-native", .{exe_path});
+ if (!watch) return cleanExit();
+ return;
+ },
+ .run => fatal("unable to execute {s}: non-native", .{exe_path}),
+ else => unreachable,
+ }
+ }
+ // when testing pass the zig_exe_path to argv
+ if (arg_mode == .zig_test)
+ try argv.appendSlice(&[_][]const u8{
+ exe_path, self_exe_path,
+ })
+ // when running just pass the current exe
+ else
+ try argv.appendSlice(&[_][]const u8{
+ exe_path,
+ });
+ } else {
+ for (test_exec_args) |arg| {
+ if (arg) |a| {
+ try argv.append(a);
+ } else {
+ try argv.appendSlice(&[_][]const u8{
+ exe_path, self_exe_path,
+ });
+ }
+ }
+ }
+ if (runtime_args_start) |i| {
+ try argv.appendSlice(all_args[i..]);
+ }
+ // We do not execve for tests because if the test fails we want to print
+ // the error message and invocation below.
+ if (std.process.can_execv and arg_mode == .run and !watch) {
+ // execv releases the locks; no need to destroy the Compilation here.
+ const err = std.process.execv(gpa, argv.items);
+ const cmd = try argvCmd(arena, argv.items);
+ fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
+ } else {
+ const child = try std.ChildProcess.init(argv.items, gpa);
+ defer child.deinit();
+
+ child.stdin_behavior = .Inherit;
+ child.stdout_behavior = .Inherit;
+ child.stderr_behavior = .Inherit;
+
+ if (!watch) {
+ // Here we release all the locks associated with the Compilation so
+ // that whatever this child process wants to do won't deadlock.
+ comp.destroy();
+ comp_destroyed.* = true;
+ }
+
+ const term = try child.spawnAndWait();
+ switch (arg_mode) {
+ .run, .build => {
+ switch (term) {
+ .Exited => |code| {
+ if (code == 0) {
+ if (!watch) return cleanExit();
+ } else if (watch) {
+ warn("process exited with code {d}", .{code});
+ } else {
+ // TODO https://github.com/ziglang/zig/issues/6342
+ process.exit(1);
+ }
+ },
+ else => {
+ if (watch) {
+ warn("process aborted abnormally", .{});
+ } else {
+ process.exit(1);
+ }
+ },
+ }
+ },
+ .zig_test => {
+ switch (term) {
+ .Exited => |code| {
+ if (code == 0) {
+ if (!watch) return cleanExit();
+ } else {
+ const cmd = try argvCmd(arena, argv.items);
+ fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });
+ }
+ },
+ else => {
+ const cmd = try argvCmd(arena, argv.items);
+ fatal("the following test command crashed:\n{s}", .{cmd});
+ },
+ }
+ },
+ else => unreachable,
+ }
+ }
+}
+
const AfterUpdateHook = union(enum) {
none,
print: []const u8,