authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-09 12:12:37-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-09 12:12:37-04:00
log05f1ea33d2d2f4ffa2bb6686a6a938d1b7983074
tree4c756014c37eb0299914b155193b6b2ba04dc652
parent2ee67b7642cfeef36d8ebbc08080202b5b1d1958

ZIG_DEBUG_COLOR=1 overrides tty detection for runtime stack traces


3 files changed, 36 insertions(+), 18 deletions(-)

doc/docgen.zig+16-13
...@@ -689,7 +689,10 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {...@@ -689,7 +689,10 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
689fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {689fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
690 var code_progress_index: usize = 0;690 var code_progress_index: usize = 0;
691691
692 const builtin_code = try escapeHtml(allocator, try getBuiltinCode(allocator, zig_exe));692 var env_map = try os.getEnvMap(allocator);
693 try env_map.set("ZIG_DEBUG_COLOR", "1");
694
695 const builtin_code = try escapeHtml(allocator, try getBuiltinCode(allocator, &env_map, zig_exe));
693696
694 for (toc.nodes) |node| {697 for (toc.nodes) |node| {
695 switch (node) {698 switch (node) {
...@@ -778,12 +781,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -778,12 +781,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
778 try build_args.append("c");781 try build_args.append("c");
779 try out.print(" --library c");782 try out.print(" --library c");
780 }783 }
781 _ = exec(allocator, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");784 _ = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
782785
783 const run_args = [][]const u8{tmp_bin_file_name};786 const run_args = [][]const u8{tmp_bin_file_name};
784787
785 const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {788 const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {
786 const result = try os.ChildProcess.exec(allocator, run_args, null, null, max_doc_file_size);789 const result = try os.ChildProcess.exec(allocator, run_args, null, &env_map, max_doc_file_size);
787 switch (result.term) {790 switch (result.term) {
788 os.ChildProcess.Term.Exited => |exit_code| {791 os.ChildProcess.Term.Exited => |exit_code| {
789 if (exit_code == 0) {792 if (exit_code == 0) {
...@@ -799,7 +802,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -799,7 +802,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
799 }802 }
800 break :blk result;803 break :blk result;
801 } else blk: {804 } else blk: {
802 break :blk exec(allocator, run_args) catch return parseError(tokenizer, code.source_token, "example crashed");805 break :blk exec(allocator, &env_map, run_args) catch return parseError(tokenizer, code.source_token, "example crashed");
803 };806 };
804807
805 const escaped_stderr = try escapeHtml(allocator, result.stderr);808 const escaped_stderr = try escapeHtml(allocator, result.stderr);
...@@ -845,7 +848,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -845,7 +848,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
845 "msvc",848 "msvc",
846 });849 });
847 }850 }
848 const result = exec(allocator, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed");851 const result = exec(allocator, &env_map, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed");
849 const escaped_stderr = try escapeHtml(allocator, result.stderr);852 const escaped_stderr = try escapeHtml(allocator, result.stderr);
850 const escaped_stdout = try escapeHtml(allocator, result.stdout);853 const escaped_stdout = try escapeHtml(allocator, result.stdout);
851 try out.print("\n{}{}</code></pre>\n", escaped_stderr, escaped_stdout);854 try out.print("\n{}{}</code></pre>\n", escaped_stderr, escaped_stdout);
...@@ -877,7 +880,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -877,7 +880,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
877 try out.print(" --release-small");880 try out.print(" --release-small");
878 },881 },
879 }882 }
880 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);883 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);
881 switch (result.term) {884 switch (result.term) {
882 os.ChildProcess.Term.Exited => |exit_code| {885 os.ChildProcess.Term.Exited => |exit_code| {
883 if (exit_code == 0) {886 if (exit_code == 0) {
...@@ -923,7 +926,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -923,7 +926,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
923 builtin.Mode.ReleaseSmall => try test_args.append("--release-small"),926 builtin.Mode.ReleaseSmall => try test_args.append("--release-small"),
924 }927 }
925928
926 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);929 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);
927 switch (result.term) {930 switch (result.term) {
928 os.ChildProcess.Term.Exited => |exit_code| {931 os.ChildProcess.Term.Exited => |exit_code| {
929 if (exit_code == 0) {932 if (exit_code == 0) {
...@@ -1000,7 +1003,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1000,7 +1003,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1000 }1003 }
10011004
1002 if (maybe_error_match) |error_match| {1005 if (maybe_error_match) |error_match| {
1003 const result = try os.ChildProcess.exec(allocator, build_args.toSliceConst(), null, null, max_doc_file_size);1006 const result = try os.ChildProcess.exec(allocator, build_args.toSliceConst(), null, &env_map, max_doc_file_size);
1004 switch (result.term) {1007 switch (result.term) {
1005 os.ChildProcess.Term.Exited => |exit_code| {1008 os.ChildProcess.Term.Exited => |exit_code| {
1006 if (exit_code == 0) {1009 if (exit_code == 0) {
...@@ -1032,7 +1035,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1032,7 +1035,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1032 try out.print("</code></pre>\n");1035 try out.print("</code></pre>\n");
1033 }1036 }
1034 } else {1037 } else {
1035 _ = exec(allocator, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");1038 _ = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
1036 }1039 }
1037 if (!code.is_inline) {1040 if (!code.is_inline) {
1038 try out.print("</code></pre>\n");1041 try out.print("</code></pre>\n");
...@@ -1045,8 +1048,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1045,8 +1048,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1045 }1048 }
1046}1049}
10471050
1048fn exec(allocator: *mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {1051fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !os.ChildProcess.ExecResult {
1049 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);1052 const result = try os.ChildProcess.exec(allocator, args, null, env_map, max_doc_file_size);
1050 switch (result.term) {1053 switch (result.term) {
1051 os.ChildProcess.Term.Exited => |exit_code| {1054 os.ChildProcess.Term.Exited => |exit_code| {
1052 if (exit_code != 0) {1055 if (exit_code != 0) {
...@@ -1070,8 +1073,8 @@ fn exec(allocator: *mem.Allocator, args: []const []const u8) !os.ChildProcess.Ex...@@ -1070,8 +1073,8 @@ fn exec(allocator: *mem.Allocator, args: []const []const u8) !os.ChildProcess.Ex
1070 return result;1073 return result;
1071}1074}
10721075
1073fn getBuiltinCode(allocator: *mem.Allocator, zig_exe: []const u8) ![]const u8 {1076fn getBuiltinCode(allocator: *mem.Allocator, env_map: *std.BufMap, zig_exe: []const u8) ![]const u8 {
1074 const result = try exec(allocator, []const []const u8{1077 const result = try exec(allocator, env_map, []const []const u8{
1075 zig_exe,1078 zig_exe,
1076 "builtin",1079 "builtin",
1077 });1080 });
std/debug/index.zig+9-2
...@@ -10,6 +10,7 @@ const ArrayList = std.ArrayList;...@@ -10,6 +10,7 @@ const ArrayList = std.ArrayList;
10const builtin = @import("builtin");10const builtin = @import("builtin");
1111
12pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;12pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
13pub const failing_allocator = FailingAllocator.init(global_allocator, 0);
1314
14/// Tries to write to stderr, unbuffered, and ignores any error returned.15/// Tries to write to stderr, unbuffered, and ignores any error returned.
15/// Does not append a newline.16/// Does not append a newline.
...@@ -44,6 +45,12 @@ pub fn getSelfDebugInfo() !*ElfStackTrace {...@@ -44,6 +45,12 @@ pub fn getSelfDebugInfo() !*ElfStackTrace {
44 }45 }
45}46}
4647
48fn wantTtyColor() bool {
49 var bytes: [128]u8 = undefined;
50 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
51 return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
52}
53
47/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.54/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
48pub fn dumpCurrentStackTrace(start_addr: ?usize) void {55pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
49 const stderr = getStderrStream() catch return;56 const stderr = getStderrStream() catch return;
...@@ -51,7 +58,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -51,7 +58,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
51 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;58 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
52 return;59 return;
53 };60 };
54 writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, stderr_file.isTty(), start_addr) catch |err| {61 writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| {
55 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;62 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
56 return;63 return;
57 };64 };
...@@ -64,7 +71,7 @@ pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {...@@ -64,7 +71,7 @@ pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {
64 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;71 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
65 return;72 return;
66 };73 };
67 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, stderr_file.isTty()) catch |err| {74 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| {
68 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;75 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
69 return;76 return;
70 };77 };
std/os/index.zig+11-3
...@@ -544,8 +544,13 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {...@@ -544,8 +544,13 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {
544 return null;544 return null;
545}545}
546546
547pub const GetEnvVarOwnedError = error{
548 OutOfMemory,
549 EnvironmentVariableNotFound,
550};
551
547/// Caller must free returned memory.552/// Caller must free returned memory.
548pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) ![]u8 {553pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
549 if (is_windows) {554 if (is_windows) {
550 const key_with_null = try cstr.addNullByte(allocator, key);555 const key_with_null = try cstr.addNullByte(allocator, key);
551 defer allocator.free(key_with_null);556 defer allocator.free(key_with_null);
...@@ -554,14 +559,17 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) ![]u8 {...@@ -554,14 +559,17 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) ![]u8 {
554 errdefer allocator.free(buf);559 errdefer allocator.free(buf);
555560
556 while (true) {561 while (true) {
557 const windows_buf_len = try math.cast(windows.DWORD, buf.len);562 const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
558 const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);563 const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);
559564
560 if (result == 0) {565 if (result == 0) {
561 const err = windows.GetLastError();566 const err = windows.GetLastError();
562 return switch (err) {567 return switch (err) {
563 windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,568 windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
564 else => unexpectedErrorWindows(err),569 else => {
570 _ = unexpectedErrorWindows(err);
571 return error.EnvironmentVariableNotFound;
572 },
565 };573 };
566 }574 }
567575