| author | |
| committer | |
| log | 716b4489be09bc34ac5470658722924460d36a5d |
| tree | 2da6dcad7747358a0df9c08580b7474076749b21 |
| parent | e60adb97d06f85adef7a0e2a2f320e04d0dce052 |
16 files changed, 350 insertions(+), 398 deletions(-)
lib/compiler/build_runner.zig+64-60| ... | ... | @@ -378,13 +378,16 @@ pub fn main() !void { |
| 378 | 378 | |
| 379 | 379 | validateSystemLibraryOptions(builder); |
| 380 | 380 | |
| 381 | const stdout_writer = io.getStdOut().writer(); | |
| 381 | var stdout_writer: std.io.BufferedWriter = .{ | |
| 382 | .buffer = &stdout_buffer, | |
| 383 | .unbuffered_writer = std.io.getStdOut().writer(), | |
| 384 | }; | |
| 382 | 385 | |
| 383 | 386 | if (help_menu) |
| 384 | return usage(builder, stdout_writer); | |
| 387 | return usage(builder, &stdout_writer); | |
| 385 | 388 | |
| 386 | 389 | if (steps_menu) |
| 387 | return steps(builder, stdout_writer); | |
| 390 | return steps(builder, &stdout_writer); | |
| 388 | 391 | |
| 389 | 392 | var run: Run = .{ |
| 390 | 393 | .max_rss = max_rss, |
| ... | ... | @@ -696,24 +699,23 @@ fn runStepNames( |
| 696 | 699 | const ttyconf = run.ttyconf; |
| 697 | 700 | |
| 698 | 701 | if (run.summary != .none) { |
| 699 | std.debug.lockStdErr(); | |
| 702 | var bw = std.debug.lockStdErr2(); | |
| 700 | 703 | defer std.debug.unlockStdErr(); |
| 701 | const stderr = run.stderr; | |
| 702 | 704 | |
| 703 | 705 | const total_count = success_count + failure_count + pending_count + skipped_count; |
| 704 | ttyconf.setColor(stderr, .cyan) catch {}; | |
| 705 | stderr.writeAll("Build Summary:") catch {}; | |
| 706 | ttyconf.setColor(stderr, .reset) catch {}; | |
| 707 | stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; | |
| 708 | if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {}; | |
| 709 | if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {}; | |
| 706 | ttyconf.setColor(&bw, .cyan) catch {}; | |
| 707 | bw.writeAll("Build Summary:") catch {}; | |
| 708 | ttyconf.setColor(&bw, .reset) catch {}; | |
| 709 | bw.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; | |
| 710 | if (skipped_count > 0) bw.print("; {d} skipped", .{skipped_count}) catch {}; | |
| 711 | if (failure_count > 0) bw.print("; {d} failed", .{failure_count}) catch {}; | |
| 710 | 712 | |
| 711 | if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; | |
| 712 | if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {}; | |
| 713 | if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {}; | |
| 714 | if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {}; | |
| 713 | if (test_count > 0) bw.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; | |
| 714 | if (test_skip_count > 0) bw.print("; {d} skipped", .{test_skip_count}) catch {}; | |
| 715 | if (test_fail_count > 0) bw.print("; {d} failed", .{test_fail_count}) catch {}; | |
| 716 | if (test_leak_count > 0) bw.print("; {d} leaked", .{test_leak_count}) catch {}; | |
| 715 | 717 | |
| 716 | stderr.writeAll("\n") catch {}; | |
| 718 | bw.writeAll("\n") catch {}; | |
| 717 | 719 | |
| 718 | 720 | // Print a fancy tree with build results. |
| 719 | 721 | var step_stack_copy = try step_stack.clone(gpa); |
| ... | ... | @@ -722,7 +724,7 @@ fn runStepNames( |
| 722 | 724 | var print_node: PrintNode = .{ .parent = null }; |
| 723 | 725 | if (step_names.len == 0) { |
| 724 | 726 | print_node.last = true; |
| 725 | printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 727 | printTreeStep(b, b.default_step, run, &bw, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 726 | 728 | } else { |
| 727 | 729 | const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: { |
| 728 | 730 | var i: usize = step_names.len; |
| ... | ... | @@ -741,7 +743,7 @@ fn runStepNames( |
| 741 | 743 | for (step_names, 0..) |step_name, i| { |
| 742 | 744 | const tls = b.top_level_steps.get(step_name).?; |
| 743 | 745 | print_node.last = i + 1 == last_index; |
| 744 | printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 746 | printTreeStep(b, &tls.step, run, &bw, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 745 | 747 | } |
| 746 | 748 | } |
| 747 | 749 | } |
| ... | ... | @@ -775,7 +777,7 @@ const PrintNode = struct { |
| 775 | 777 | last: bool = false, |
| 776 | 778 | }; |
| 777 | 779 | |
| 778 | fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void { | |
| 780 | fn printPrefix(node: *PrintNode, stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Config) !void { | |
| 779 | 781 | const parent = node.parent orelse return; |
| 780 | 782 | if (parent.parent == null) return; |
| 781 | 783 | try printPrefix(parent, stderr, ttyconf); |
| ... | ... | @@ -789,7 +791,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void |
| 789 | 791 | } |
| 790 | 792 | } |
| 791 | 793 | |
| 792 | fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void { | |
| 794 | fn printChildNodePrefix(stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Config) !void { | |
| 793 | 795 | try stderr.writeAll(switch (ttyconf) { |
| 794 | 796 | .no_color, .windows_api => "+- ", |
| 795 | 797 | .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─ |
| ... | ... | @@ -798,7 +800,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void { |
| 798 | 800 | |
| 799 | 801 | fn printStepStatus( |
| 800 | 802 | s: *Step, |
| 801 | stderr: File, | |
| 803 | stderr: *std.io.BufferedWriter, | |
| 802 | 804 | ttyconf: std.io.tty.Config, |
| 803 | 805 | run: *const Run, |
| 804 | 806 | ) !void { |
| ... | ... | @@ -820,10 +822,10 @@ fn printStepStatus( |
| 820 | 822 | try stderr.writeAll(" cached"); |
| 821 | 823 | } else if (s.test_results.test_count > 0) { |
| 822 | 824 | const pass_count = s.test_results.passCount(); |
| 823 | try stderr.writer().print(" {d} passed", .{pass_count}); | |
| 825 | try stderr.print(" {d} passed", .{pass_count}); | |
| 824 | 826 | if (s.test_results.skip_count > 0) { |
| 825 | 827 | try ttyconf.setColor(stderr, .yellow); |
| 826 | try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count}); | |
| 828 | try stderr.print(" {d} skipped", .{s.test_results.skip_count}); | |
| 827 | 829 | } |
| 828 | 830 | } else { |
| 829 | 831 | try stderr.writeAll(" success"); |
| ... | ... | @@ -832,15 +834,15 @@ fn printStepStatus( |
| 832 | 834 | if (s.result_duration_ns) |ns| { |
| 833 | 835 | try ttyconf.setColor(stderr, .dim); |
| 834 | 836 | if (ns >= std.time.ns_per_min) { |
| 835 | try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min}); | |
| 837 | try stderr.print(" {d}m", .{ns / std.time.ns_per_min}); | |
| 836 | 838 | } else if (ns >= std.time.ns_per_s) { |
| 837 | try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s}); | |
| 839 | try stderr.print(" {d}s", .{ns / std.time.ns_per_s}); | |
| 838 | 840 | } else if (ns >= std.time.ns_per_ms) { |
| 839 | try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms}); | |
| 841 | try stderr.print(" {d}ms", .{ns / std.time.ns_per_ms}); | |
| 840 | 842 | } else if (ns >= std.time.ns_per_us) { |
| 841 | try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us}); | |
| 843 | try stderr.print(" {d}us", .{ns / std.time.ns_per_us}); | |
| 842 | 844 | } else { |
| 843 | try stderr.writer().print(" {d}ns", .{ns}); | |
| 845 | try stderr.print(" {d}ns", .{ns}); | |
| 844 | 846 | } |
| 845 | 847 | try ttyconf.setColor(stderr, .reset); |
| 846 | 848 | } |
| ... | ... | @@ -848,13 +850,13 @@ fn printStepStatus( |
| 848 | 850 | const rss = s.result_peak_rss; |
| 849 | 851 | try ttyconf.setColor(stderr, .dim); |
| 850 | 852 | if (rss >= 1000_000_000) { |
| 851 | try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000}); | |
| 853 | try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000}); | |
| 852 | 854 | } else if (rss >= 1000_000) { |
| 853 | try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000}); | |
| 855 | try stderr.print(" MaxRSS:{d}M", .{rss / 1000_000}); | |
| 854 | 856 | } else if (rss >= 1000) { |
| 855 | try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000}); | |
| 857 | try stderr.print(" MaxRSS:{d}K", .{rss / 1000}); | |
| 856 | 858 | } else { |
| 857 | try stderr.writer().print(" MaxRSS:{d}B", .{rss}); | |
| 859 | try stderr.print(" MaxRSS:{d}B", .{rss}); | |
| 858 | 860 | } |
| 859 | 861 | try ttyconf.setColor(stderr, .reset); |
| 860 | 862 | } |
| ... | ... | @@ -866,7 +868,7 @@ fn printStepStatus( |
| 866 | 868 | if (skip == .skipped_oom) { |
| 867 | 869 | try stderr.writeAll(" (not enough memory)"); |
| 868 | 870 | try ttyconf.setColor(stderr, .dim); |
| 869 | try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); | |
| 871 | try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); | |
| 870 | 872 | try ttyconf.setColor(stderr, .yellow); |
| 871 | 873 | } |
| 872 | 874 | try stderr.writeAll("\n"); |
| ... | ... | @@ -878,23 +880,23 @@ fn printStepStatus( |
| 878 | 880 | |
| 879 | 881 | fn printStepFailure( |
| 880 | 882 | s: *Step, |
| 881 | stderr: File, | |
| 883 | stderr: *std.io.BufferedWriter, | |
| 882 | 884 | ttyconf: std.io.tty.Config, |
| 883 | 885 | ) !void { |
| 884 | 886 | if (s.result_error_bundle.errorMessageCount() > 0) { |
| 885 | 887 | try ttyconf.setColor(stderr, .red); |
| 886 | try stderr.writer().print(" {d} errors\n", .{ | |
| 888 | try stderr.print(" {d} errors\n", .{ | |
| 887 | 889 | s.result_error_bundle.errorMessageCount(), |
| 888 | 890 | }); |
| 889 | 891 | try ttyconf.setColor(stderr, .reset); |
| 890 | 892 | } else if (!s.test_results.isSuccess()) { |
| 891 | try stderr.writer().print(" {d}/{d} passed", .{ | |
| 893 | try stderr.print(" {d}/{d} passed", .{ | |
| 892 | 894 | s.test_results.passCount(), s.test_results.test_count, |
| 893 | 895 | }); |
| 894 | 896 | if (s.test_results.fail_count > 0) { |
| 895 | 897 | try stderr.writeAll(", "); |
| 896 | 898 | try ttyconf.setColor(stderr, .red); |
| 897 | try stderr.writer().print("{d} failed", .{ | |
| 899 | try stderr.print("{d} failed", .{ | |
| 898 | 900 | s.test_results.fail_count, |
| 899 | 901 | }); |
| 900 | 902 | try ttyconf.setColor(stderr, .reset); |
| ... | ... | @@ -902,7 +904,7 @@ fn printStepFailure( |
| 902 | 904 | if (s.test_results.skip_count > 0) { |
| 903 | 905 | try stderr.writeAll(", "); |
| 904 | 906 | try ttyconf.setColor(stderr, .yellow); |
| 905 | try stderr.writer().print("{d} skipped", .{ | |
| 907 | try stderr.print("{d} skipped", .{ | |
| 906 | 908 | s.test_results.skip_count, |
| 907 | 909 | }); |
| 908 | 910 | try ttyconf.setColor(stderr, .reset); |
| ... | ... | @@ -910,7 +912,7 @@ fn printStepFailure( |
| 910 | 912 | if (s.test_results.leak_count > 0) { |
| 911 | 913 | try stderr.writeAll(", "); |
| 912 | 914 | try ttyconf.setColor(stderr, .red); |
| 913 | try stderr.writer().print("{d} leaked", .{ | |
| 915 | try stderr.print("{d} leaked", .{ | |
| 914 | 916 | s.test_results.leak_count, |
| 915 | 917 | }); |
| 916 | 918 | try ttyconf.setColor(stderr, .reset); |
| ... | ... | @@ -932,7 +934,7 @@ fn printTreeStep( |
| 932 | 934 | b: *std.Build, |
| 933 | 935 | s: *Step, |
| 934 | 936 | run: *const Run, |
| 935 | stderr: File, | |
| 937 | stderr: *std.io.BufferedWriter, | |
| 936 | 938 | ttyconf: std.io.tty.Config, |
| 937 | 939 | parent_node: *PrintNode, |
| 938 | 940 | step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void), |
| ... | ... | @@ -992,7 +994,7 @@ fn printTreeStep( |
| 992 | 994 | if (s.dependencies.items.len == 0) { |
| 993 | 995 | try stderr.writeAll(" (reused)\n"); |
| 994 | 996 | } else { |
| 995 | try stderr.writer().print(" (+{d} more reused dependencies)\n", .{ | |
| 997 | try stderr.print(" (+{d} more reused dependencies)\n", .{ | |
| 996 | 998 | s.dependencies.items.len, |
| 997 | 999 | }); |
| 998 | 1000 | } |
| ... | ... | @@ -1129,11 +1131,11 @@ fn workerMakeOneStep( |
| 1129 | 1131 | const show_stderr = s.result_stderr.len > 0; |
| 1130 | 1132 | |
| 1131 | 1133 | if (show_error_msgs or show_compile_errors or show_stderr) { |
| 1132 | std.debug.lockStdErr(); | |
| 1134 | var bw = std.debug.lockStdErr2(); | |
| 1133 | 1135 | defer std.debug.unlockStdErr(); |
| 1134 | 1136 | |
| 1135 | 1137 | const gpa = b.allocator; |
| 1136 | printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, run.stderr, run.prominent_compile_errors) catch {}; | |
| 1138 | printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, &bw, run.prominent_compile_errors) catch {}; | |
| 1137 | 1139 | } |
| 1138 | 1140 | |
| 1139 | 1141 | handle_result: { |
| ... | ... | @@ -1190,7 +1192,7 @@ pub fn printErrorMessages( |
| 1190 | 1192 | gpa: Allocator, |
| 1191 | 1193 | failing_step: *Step, |
| 1192 | 1194 | options: std.zig.ErrorBundle.RenderOptions, |
| 1193 | stderr: File, | |
| 1195 | stderr: *std.io.BufferedWriter, | |
| 1194 | 1196 | prominent_compile_errors: bool, |
| 1195 | 1197 | ) !void { |
| 1196 | 1198 | // Provide context for where these error messages are coming from by |
| ... | ... | @@ -1209,7 +1211,7 @@ pub fn printErrorMessages( |
| 1209 | 1211 | var indent: usize = 0; |
| 1210 | 1212 | while (step_stack.pop()) |s| : (indent += 1) { |
| 1211 | 1213 | if (indent > 0) { |
| 1212 | try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3); | |
| 1214 | try stderr.splatByteAll(' ', (indent - 1) * 3); | |
| 1213 | 1215 | try printChildNodePrefix(stderr, ttyconf); |
| 1214 | 1216 | } |
| 1215 | 1217 | |
| ... | ... | @@ -1231,7 +1233,7 @@ pub fn printErrorMessages( |
| 1231 | 1233 | } |
| 1232 | 1234 | |
| 1233 | 1235 | if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) { |
| 1234 | try failing_step.result_error_bundle.renderToWriter(options, stderr.writer()); | |
| 1236 | try failing_step.result_error_bundle.renderToWriter(options, stderr); | |
| 1235 | 1237 | } |
| 1236 | 1238 | |
| 1237 | 1239 | for (failing_step.result_error_msgs.items) |msg| { |
| ... | ... | @@ -1243,27 +1245,29 @@ pub fn printErrorMessages( |
| 1243 | 1245 | } |
| 1244 | 1246 | } |
| 1245 | 1247 | |
| 1246 | fn steps(builder: *std.Build, out_stream: anytype) !void { | |
| 1248 | fn steps(builder: *std.Build, bw: *std.io.BufferedWriter) !void { | |
| 1247 | 1249 | const allocator = builder.allocator; |
| 1248 | 1250 | for (builder.top_level_steps.values()) |top_level_step| { |
| 1249 | 1251 | const name = if (&top_level_step.step == builder.default_step) |
| 1250 | 1252 | try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name}) |
| 1251 | 1253 | else |
| 1252 | 1254 | top_level_step.step.name; |
| 1253 | try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description }); | |
| 1255 | try bw.print(" {s:<28} {s}\n", .{ name, top_level_step.description }); | |
| 1254 | 1256 | } |
| 1255 | 1257 | } |
| 1256 | 1258 | |
| 1257 | fn usage(b: *std.Build, out_stream: anytype) !void { | |
| 1258 | try out_stream.print( | |
| 1259 | var stdout_buffer: [256]u8 = undefined; | |
| 1260 | ||
| 1261 | fn usage(b: *std.Build, bw: *std.io.BufferedWriter) !void { | |
| 1262 | try bw.print( | |
| 1259 | 1263 | \\Usage: {s} build [steps] [options] |
| 1260 | 1264 | \\ |
| 1261 | 1265 | \\Steps: |
| 1262 | 1266 | \\ |
| 1263 | 1267 | , .{b.graph.zig_exe}); |
| 1264 | try steps(b, out_stream); | |
| 1268 | try steps(b, bw); | |
| 1265 | 1269 | |
| 1266 | try out_stream.writeAll( | |
| 1270 | try bw.writeAll( | |
| 1267 | 1271 | \\ |
| 1268 | 1272 | \\General Options: |
| 1269 | 1273 | \\ -p, --prefix [path] Where to install files (default: zig-out) |
| ... | ... | @@ -1319,25 +1323,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void { |
| 1319 | 1323 | |
| 1320 | 1324 | const arena = b.allocator; |
| 1321 | 1325 | if (b.available_options_list.items.len == 0) { |
| 1322 | try out_stream.print(" (none)\n", .{}); | |
| 1326 | try bw.print(" (none)\n", .{}); | |
| 1323 | 1327 | } else { |
| 1324 | 1328 | for (b.available_options_list.items) |option| { |
| 1325 | 1329 | const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{ |
| 1326 | 1330 | option.name, |
| 1327 | 1331 | @tagName(option.type_id), |
| 1328 | 1332 | }); |
| 1329 | try out_stream.print("{s:<30} {s}\n", .{ name, option.description }); | |
| 1333 | try bw.print("{s:<30} {s}\n", .{ name, option.description }); | |
| 1330 | 1334 | if (option.enum_options) |enum_options| { |
| 1331 | 1335 | const padding = " " ** 33; |
| 1332 | try out_stream.writeAll(padding ++ "Supported Values:\n"); | |
| 1336 | try bw.writeAll(padding ++ "Supported Values:\n"); | |
| 1333 | 1337 | for (enum_options) |enum_option| { |
| 1334 | try out_stream.print(padding ++ " {s}\n", .{enum_option}); | |
| 1338 | try bw.print(padding ++ " {s}\n", .{enum_option}); | |
| 1335 | 1339 | } |
| 1336 | 1340 | } |
| 1337 | 1341 | } |
| 1338 | 1342 | } |
| 1339 | 1343 | |
| 1340 | try out_stream.writeAll( | |
| 1344 | try bw.writeAll( | |
| 1341 | 1345 | \\ |
| 1342 | 1346 | \\System Integration Options: |
| 1343 | 1347 | \\ --search-prefix [path] Add a path to look for binaries, libraries, headers |
| ... | ... | @@ -1352,7 +1356,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void { |
| 1352 | 1356 | \\ |
| 1353 | 1357 | ); |
| 1354 | 1358 | if (b.graph.system_library_options.entries.len == 0) { |
| 1355 | try out_stream.writeAll(" (none) -\n"); | |
| 1359 | try bw.writeAll(" (none) -\n"); | |
| 1356 | 1360 | } else { |
| 1357 | 1361 | for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { |
| 1358 | 1362 | const status = switch (v) { |
| ... | ... | @@ -1360,11 +1364,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void { |
| 1360 | 1364 | .declared_disabled => "no", |
| 1361 | 1365 | .user_enabled, .user_disabled => unreachable, // already emitted error |
| 1362 | 1366 | }; |
| 1363 | try out_stream.print(" {s:<43} {s}\n", .{ k, status }); | |
| 1367 | try bw.print(" {s:<43} {s}\n", .{ k, status }); | |
| 1364 | 1368 | } |
| 1365 | 1369 | } |
| 1366 | 1370 | |
| 1367 | try out_stream.writeAll( | |
| 1371 | try bw.writeAll( | |
| 1368 | 1372 | \\ |
| 1369 | 1373 | \\Advanced Options: |
| 1370 | 1374 | \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error |
lib/std/Build/Fuzz.zig+4-6| ... | ... | @@ -112,7 +112,6 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog |
| 112 | 112 | |
| 113 | 113 | fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void { |
| 114 | 114 | const gpa = run.step.owner.allocator; |
| 115 | const stderr = std.io.getStdErr(); | |
| 116 | 115 | |
| 117 | 116 | const compile = run.producer.?; |
| 118 | 117 | const prog_node = parent_prog_node.start(compile.step.name, 0); |
| ... | ... | @@ -125,9 +124,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, par |
| 125 | 124 | const show_stderr = compile.step.result_stderr.len > 0; |
| 126 | 125 | |
| 127 | 126 | if (show_error_msgs or show_compile_errors or show_stderr) { |
| 128 | std.debug.lockStdErr(); | |
| 127 | var bw = std.debug.lockStdErr2(); | |
| 129 | 128 | defer std.debug.unlockStdErr(); |
| 130 | build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, stderr, false) catch {}; | |
| 129 | build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, &bw, false) catch {}; | |
| 131 | 130 | } |
| 132 | 131 | |
| 133 | 132 | const rebuilt_bin_path = result catch |err| switch (err) { |
| ... | ... | @@ -152,10 +151,9 @@ fn fuzzWorkerRun( |
| 152 | 151 | |
| 153 | 152 | run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) { |
| 154 | 153 | error.MakeFailed => { |
| 155 | const stderr = std.io.getStdErr(); | |
| 156 | std.debug.lockStdErr(); | |
| 154 | var bw = std.debug.lockStdErr2(); | |
| 157 | 155 | defer std.debug.unlockStdErr(); |
| 158 | build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, stderr, false) catch {}; | |
| 156 | build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, &bw, false) catch {}; | |
| 159 | 157 | return; |
| 160 | 158 | }, |
| 161 | 159 | else => { |
lib/std/Build/Step/CheckObject.zig+9-8| ... | ... | @@ -1393,7 +1393,8 @@ const MachODumper = struct { |
| 1393 | 1393 | }, |
| 1394 | 1394 | macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => { |
| 1395 | 1395 | name_buf.clearRetainingCapacity(); |
| 1396 | try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32)); | |
| 1396 | if (true) @panic("TODO fix this"); | |
| 1397 | //try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32)); | |
| 1397 | 1398 | try name_buf.append(0); |
| 1398 | 1399 | }, |
| 1399 | 1400 | macho.BIND_OPCODE_SET_ADDEND_SLEB => { |
| ... | ... | @@ -2430,10 +2431,11 @@ const WasmDumper = struct { |
| 2430 | 2431 | return error.UnsupportedWasmVersion; |
| 2431 | 2432 | } |
| 2432 | 2433 | |
| 2433 | var output = std.ArrayList(u8).init(gpa); | |
| 2434 | var output: std.io.AllocatingWriter = undefined; | |
| 2435 | const bw = output.init(gpa); | |
| 2434 | 2436 | defer output.deinit(); |
| 2435 | parseAndDumpInner(step, check, bytes, &fbs, &output) catch |err| switch (err) { | |
| 2436 | error.EndOfStream => try output.appendSlice("\n<UnexpectedEndOfStream>"), | |
| 2437 | parseAndDumpInner(step, check, bytes, &fbs, bw) catch |err| switch (err) { | |
| 2438 | error.EndOfStream => try bw.writeAll("\n<UnexpectedEndOfStream>"), | |
| 2437 | 2439 | else => |e| return e, |
| 2438 | 2440 | }; |
| 2439 | 2441 | return output.toOwnedSlice(); |
| ... | ... | @@ -2443,11 +2445,10 @@ const WasmDumper = struct { |
| 2443 | 2445 | step: *Step, |
| 2444 | 2446 | check: Check, |
| 2445 | 2447 | bytes: []const u8, |
| 2446 | fbs: *std.io.FixedBufferStream([]const u8), | |
| 2447 | output: *std.ArrayList(u8), | |
| 2448 | fbs: *std.io.FixedBufferStream, | |
| 2449 | bw: *std.io.BufferedWriter, | |
| 2448 | 2450 | ) !void { |
| 2449 | 2451 | const reader = fbs.reader(); |
| 2450 | const writer = output.writer(); | |
| 2451 | 2452 | |
| 2452 | 2453 | switch (check.kind) { |
| 2453 | 2454 | .headers => { |
| ... | ... | @@ -2457,7 +2458,7 @@ const WasmDumper = struct { |
| 2457 | 2458 | }; |
| 2458 | 2459 | |
| 2459 | 2460 | const section_length = try std.leb.readUleb128(u32, reader); |
| 2460 | try parseAndDumpSection(step, section, bytes[fbs.pos..][0..section_length], writer); | |
| 2461 | try parseAndDumpSection(step, section, bytes[fbs.pos..][0..section_length], bw); | |
| 2461 | 2462 | fbs.pos += section_length; |
| 2462 | 2463 | } else |_| {} // reached end of stream |
| 2463 | 2464 | }, |
lib/std/Build/Step/Compile.zig+6-6| ... | ... | @@ -2040,17 +2040,17 @@ fn checkCompileErrors(compile: *Compile) !void { |
| 2040 | 2040 | .exact => |expect_lines| { |
| 2041 | 2041 | for (expect_lines) |expect_line| { |
| 2042 | 2042 | const actual_line = actual_line_it.next() orelse { |
| 2043 | try expected_generated.appendSlice(expect_line); | |
| 2044 | try expected_generated.append('\n'); | |
| 2043 | try expected_generated.appendSlice(arena, expect_line); | |
| 2044 | try expected_generated.append(arena, '\n'); | |
| 2045 | 2045 | continue; |
| 2046 | 2046 | }; |
| 2047 | 2047 | if (matchCompileError(actual_line, expect_line)) { |
| 2048 | try expected_generated.appendSlice(actual_line); | |
| 2049 | try expected_generated.append('\n'); | |
| 2048 | try expected_generated.appendSlice(arena, actual_line); | |
| 2049 | try expected_generated.append(arena, '\n'); | |
| 2050 | 2050 | continue; |
| 2051 | 2051 | } |
| 2052 | try expected_generated.appendSlice(expect_line); | |
| 2053 | try expected_generated.append('\n'); | |
| 2052 | try expected_generated.appendSlice(arena, expect_line); | |
| 2053 | try expected_generated.append(arena, '\n'); | |
| 2054 | 2054 | } |
| 2055 | 2055 | |
| 2056 | 2056 | if (mem.eql(u8, expected_generated.items, actual_errors)) return; |
lib/std/Build/Step/ConfigHeader.zig+5-5| ... | ... | @@ -599,14 +599,14 @@ fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) ! |
| 599 | 599 | try output.appendSlice(if (b) " 1\n" else " 0\n"); |
| 600 | 600 | }, |
| 601 | 601 | .int => |i| { |
| 602 | try output.writer().print("%define {s} {d}\n", .{ name, i }); | |
| 602 | try output.print("%define {s} {d}\n", .{ name, i }); | |
| 603 | 603 | }, |
| 604 | 604 | .ident => |ident| { |
| 605 | try output.writer().print("%define {s} {s}\n", .{ name, ident }); | |
| 605 | try output.print("%define {s} {s}\n", .{ name, ident }); | |
| 606 | 606 | }, |
| 607 | 607 | .string => |string| { |
| 608 | 608 | // TODO: use nasm-specific escaping instead of zig string literals |
| 609 | try output.writer().print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) }); | |
| 609 | try output.print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) }); | |
| 610 | 610 | }, |
| 611 | 611 | } |
| 612 | 612 | } |
| ... | ... | @@ -707,7 +707,7 @@ fn expand_variables_cmake( |
| 707 | 707 | try result.append(if (b) '1' else '0'); |
| 708 | 708 | }, |
| 709 | 709 | .int => |i| { |
| 710 | try result.writer().print("{d}", .{i}); | |
| 710 | try result.print("{d}", .{i}); | |
| 711 | 711 | }, |
| 712 | 712 | .ident, .string => |s| { |
| 713 | 713 | try result.appendSlice(s); |
| ... | ... | @@ -764,7 +764,7 @@ fn expand_variables_cmake( |
| 764 | 764 | try result.append(if (b) '1' else '0'); |
| 765 | 765 | }, |
| 766 | 766 | .int => |i| { |
| 767 | try result.writer().print("{d}", .{i}); | |
| 767 | try result.print("{d}", .{i}); | |
| 768 | 768 | }, |
| 769 | 769 | .ident, .string => |s| { |
| 770 | 770 | try result.appendSlice(s); |
lib/std/Uri.zig+4-3| ... | ... | @@ -445,13 +445,14 @@ test remove_dot_segments { |
| 445 | 445 | |
| 446 | 446 | /// 5.2.3. Merge Paths |
| 447 | 447 | fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component { |
| 448 | var aux = std.io.fixedBufferStream(aux_buf.*); | |
| 448 | var aux: std.io.BufferedWriter = undefined; | |
| 449 | aux.initFixed(aux_buf.*); | |
| 449 | 450 | if (!base.isEmpty()) { |
| 450 | try aux.writer().print("{path}", .{base}); | |
| 451 | aux.print("{fpath}", .{base}) catch |err| return @errorCast(err); | |
| 451 | 452 | aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse |
| 452 | 453 | return remove_dot_segments(new); |
| 453 | 454 | } |
| 454 | try aux.writer().print("/{s}", .{new}); | |
| 455 | aux.print("/{s}", .{new}) catch |err| return @errorCast(err); | |
| 455 | 456 | const merged_path = remove_dot_segments(aux.getWritten()); |
| 456 | 457 | aux_buf.* = aux_buf.*[merged_path.percent_encoded.len..]; |
| 457 | 458 | return merged_path; |
lib/std/array_list.zig+15-1| ... | ... | @@ -338,6 +338,12 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty |
| 338 | 338 | @memcpy(self.items[old_len..][0..items.len], items); |
| 339 | 339 | } |
| 340 | 340 | |
| 341 | pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { | |
| 342 | var unmanaged = self.moveToUnmanaged(); | |
| 343 | try unmanaged.print(self.allocator, fmt, args); | |
| 344 | self.* = unmanaged.toManaged(self.allocator); | |
| 345 | } | |
| 346 | ||
| 341 | 347 | /// Append a value to the list `n` times. |
| 342 | 348 | /// Allocates more memory as necessary. |
| 343 | 349 | /// Invalidates element pointers if additional memory is needed. |
| ... | ... | @@ -902,7 +908,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 902 | 908 | var aw: std.io.AllocatingWriter = undefined; |
| 903 | 909 | const bw = aw.fromArrayList(gpa, self); |
| 904 | 910 | defer self.* = aw.toArrayList(); |
| 905 | bw.print(fmt, args) catch return error.OutOfMemory; | |
| 911 | return @errorCast(bw.print(fmt, args)); | |
| 912 | } | |
| 913 | ||
| 914 | pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void { | |
| 915 | comptime assert(T == u8); | |
| 916 | var bw: std.io.BufferedWriter = undefined; | |
| 917 | bw.initFixed(self.unusedCapacitySlice()); | |
| 918 | bw.print(fmt, args) catch unreachable; | |
| 919 | self.items.len += bw.end; | |
| 906 | 920 | } |
| 907 | 921 | |
| 908 | 922 | /// Append a value to the list `n` times. |
lib/std/http/Server.zig+64-14| ... | ... | @@ -421,9 +421,9 @@ pub const Request = struct { |
| 421 | 421 | try request.server.connection.stream.writeAll(h.items); |
| 422 | 422 | return; |
| 423 | 423 | } |
| 424 | h.fixedWriter().print("{s} {d} {s}\r\n", .{ | |
| 424 | h.printAssumeCapacity("{s} {d} {s}\r\n", .{ | |
| 425 | 425 | @tagName(options.version), @intFromEnum(options.status), phrase, |
| 426 | }) catch unreachable; | |
| 426 | }); | |
| 427 | 427 | |
| 428 | 428 | switch (options.version) { |
| 429 | 429 | .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"), |
| ... | ... | @@ -434,7 +434,7 @@ pub const Request = struct { |
| 434 | 434 | .none => {}, |
| 435 | 435 | .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"), |
| 436 | 436 | } else { |
| 437 | h.fixedWriter().print("content-length: {d}\r\n", .{content.len}) catch unreachable; | |
| 437 | h.printAssumeCapacity("content-length: {d}\r\n", .{content.len}); | |
| 438 | 438 | } |
| 439 | 439 | |
| 440 | 440 | var chunk_header_buffer: [18]u8 = undefined; |
| ... | ... | @@ -573,9 +573,9 @@ pub const Request = struct { |
| 573 | 573 | h.appendSliceAssumeCapacity("content-length: 0\r\n\r\n"); |
| 574 | 574 | break :eb true; |
| 575 | 575 | } else eb: { |
| 576 | h.fixedWriter().print("{s} {d} {s}\r\n", .{ | |
| 576 | h.printAssumeCapacity("{s} {d} {s}\r\n", .{ | |
| 577 | 577 | @tagName(o.version), @intFromEnum(o.status), phrase, |
| 578 | }) catch unreachable; | |
| 578 | }); | |
| 579 | 579 | |
| 580 | 580 | switch (o.version) { |
| 581 | 581 | .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"), |
| ... | ... | @@ -586,7 +586,7 @@ pub const Request = struct { |
| 586 | 586 | .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"), |
| 587 | 587 | .none => {}, |
| 588 | 588 | } else if (options.content_length) |len| { |
| 589 | h.fixedWriter().print("content-length: {d}\r\n", .{len}) catch unreachable; | |
| 589 | h.printAssumeCapacity("content-length: {d}\r\n", .{len}); | |
| 590 | 590 | } else { |
| 591 | 591 | h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"); |
| 592 | 592 | } |
| ... | ... | @@ -889,12 +889,34 @@ pub const Response = struct { |
| 889 | 889 | /// when the end of stream occurs by calling `end`. |
| 890 | 890 | pub fn write(r: *Response, bytes: []const u8) WriteError!usize { |
| 891 | 891 | switch (r.transfer_encoding) { |
| 892 | .content_length, .none => return write_cl(r, bytes), | |
| 893 | .chunked => return write_chunked(r, bytes), | |
| 892 | .content_length, .none => return @errorCast(cl_writeSplat(r, &.{bytes}, 1)), | |
| 893 | .chunked => return @errorCast(chunked_writeSplat(r, &.{bytes}, 1)), | |
| 894 | 894 | } |
| 895 | 895 | } |
| 896 | 896 | |
| 897 | fn write_cl(context: *const anyopaque, bytes: []const u8) WriteError!usize { | |
| 897 | fn cl_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | |
| 898 | _ = splat; | |
| 899 | return cl_write(context, data[0]); // TODO: try to send all the data | |
| 900 | } | |
| 901 | ||
| 902 | fn cl_writeFile( | |
| 903 | context: *anyopaque, | |
| 904 | file: std.fs.File, | |
| 905 | offset: u64, | |
| 906 | len: std.io.Writer.VTable.FileLen, | |
| 907 | headers_and_trailers: []const []const u8, | |
| 908 | headers_len: usize, | |
| 909 | ) anyerror!usize { | |
| 910 | _ = context; | |
| 911 | _ = file; | |
| 912 | _ = offset; | |
| 913 | _ = len; | |
| 914 | _ = headers_and_trailers; | |
| 915 | _ = headers_len; | |
| 916 | return error.Unimplemented; | |
| 917 | } | |
| 918 | ||
| 919 | fn cl_write(context: *anyopaque, bytes: []const u8) WriteError!usize { | |
| 898 | 920 | const r: *Response = @constCast(@alignCast(@ptrCast(context))); |
| 899 | 921 | |
| 900 | 922 | var trash: u64 = std.math.maxInt(u64); |
| ... | ... | @@ -944,7 +966,29 @@ pub const Response = struct { |
| 944 | 966 | return bytes.len; |
| 945 | 967 | } |
| 946 | 968 | |
| 947 | fn write_chunked(context: *const anyopaque, bytes: []const u8) WriteError!usize { | |
| 969 | fn chunked_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | |
| 970 | _ = splat; | |
| 971 | return chunked_write(context, data[0]); // TODO: try to send all the data | |
| 972 | } | |
| 973 | ||
| 974 | fn chunked_writeFile( | |
| 975 | context: *anyopaque, | |
| 976 | file: std.fs.File, | |
| 977 | offset: u64, | |
| 978 | len: std.io.Writer.VTable.FileLen, | |
| 979 | headers_and_trailers: []const []const u8, | |
| 980 | headers_len: usize, | |
| 981 | ) anyerror!usize { | |
| 982 | _ = context; | |
| 983 | _ = file; | |
| 984 | _ = offset; | |
| 985 | _ = len; | |
| 986 | _ = headers_and_trailers; | |
| 987 | _ = headers_len; | |
| 988 | return error.Unimplemented; | |
| 989 | } | |
| 990 | ||
| 991 | fn chunked_write(context: *anyopaque, bytes: []const u8) WriteError!usize { | |
| 948 | 992 | const r: *Response = @constCast(@alignCast(@ptrCast(context))); |
| 949 | 993 | assert(r.transfer_encoding == .chunked); |
| 950 | 994 | |
| ... | ... | @@ -1115,11 +1159,17 @@ pub const Response = struct { |
| 1115 | 1159 | r.chunk_len = 0; |
| 1116 | 1160 | } |
| 1117 | 1161 | |
| 1118 | pub fn writer(r: *Response) std.io.AnyWriter { | |
| 1162 | pub fn writer(r: *Response) std.io.Writer { | |
| 1119 | 1163 | return .{ |
| 1120 | .writeFn = switch (r.transfer_encoding) { | |
| 1121 | .none, .content_length => write_cl, | |
| 1122 | .chunked => write_chunked, | |
| 1164 | .vtable = switch (r.transfer_encoding) { | |
| 1165 | .none, .content_length => &.{ | |
| 1166 | .writeSplat = cl_writeSplat, | |
| 1167 | .writeFile = cl_writeFile, | |
| 1168 | }, | |
| 1169 | .chunked => &.{ | |
| 1170 | .writeSplat = chunked_writeSplat, | |
| 1171 | .writeFile = chunked_writeFile, | |
| 1172 | }, | |
| 1123 | 1173 | }, |
| 1124 | 1174 | .context = r, |
| 1125 | 1175 | }; |
lib/std/io.zig-13| ... | ... | @@ -123,19 +123,6 @@ pub fn GenericReader( |
| 123 | 123 | return @errorCast(self.any().readAllAlloc(allocator, max_size)); |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | pub inline fn readUntilDelimiterArrayList( | |
| 127 | self: Self, | |
| 128 | array_list: *std.ArrayList(u8), | |
| 129 | delimiter: u8, | |
| 130 | max_size: usize, | |
| 131 | ) (NoEofError || Allocator.Error || error{StreamTooLong})!void { | |
| 132 | return @errorCast(self.any().readUntilDelimiterArrayList( | |
| 133 | array_list, | |
| 134 | delimiter, | |
| 135 | max_size, | |
| 136 | )); | |
| 137 | } | |
| 138 | ||
| 139 | 126 | pub inline fn readUntilDelimiterAlloc( |
| 140 | 127 | self: Self, |
| 141 | 128 | allocator: Allocator, |
lib/std/io/AllocatingWriter.zig+2| ... | ... | @@ -17,6 +17,8 @@ const assert = std.debug.assert; |
| 17 | 17 | /// returning a slice that includes both. |
| 18 | 18 | written: []u8, |
| 19 | 19 | allocator: std.mem.Allocator, |
| 20 | /// When using this API, it is not necessary to call | |
| 21 | /// `std.io.BufferedWriter.flush`. | |
| 20 | 22 | buffered_writer: std.io.BufferedWriter, |
| 21 | 23 | |
| 22 | 24 | const vtable: std.io.Writer.VTable = .{ |
lib/std/io/BufferedWriter.zig+3-3| ... | ... | @@ -33,7 +33,7 @@ pub fn writer(bw: *BufferedWriter) Writer { |
| 33 | 33 | return .{ |
| 34 | 34 | .context = bw, |
| 35 | 35 | .vtable = &.{ |
| 36 | .write = passthru_writeSplat, | |
| 36 | .writeSplat = passthru_writeSplat, | |
| 37 | 37 | .writeFile = passthru_writeFile, |
| 38 | 38 | }, |
| 39 | 39 | }; |
| ... | ... | @@ -1003,7 +1003,7 @@ pub fn printFloat( |
| 1003 | 1003 | 'x' => { |
| 1004 | 1004 | var sub_bw: BufferedWriter = undefined; |
| 1005 | 1005 | sub_bw.initFixed(&buf); |
| 1006 | sub_bw.printFloatHexadecimal(value, options) catch unreachable; | |
| 1006 | sub_bw.printFloatHexadecimal(value, options.precision) catch unreachable; | |
| 1007 | 1007 | return alignBufferOptions(bw, sub_bw.getWritten(), options); |
| 1008 | 1008 | }, |
| 1009 | 1009 | else => invalidFmtError(fmt, value), |
| ... | ... | @@ -1103,7 +1103,7 @@ pub fn printFloatHexadecimal(bw: *BufferedWriter, value: anytype, opt_precision: |
| 1103 | 1103 | // Add trailing zeros if explicitly requested. |
| 1104 | 1104 | if (opt_precision) |precision| if (precision > 0) { |
| 1105 | 1105 | if (precision > trimmed.len) |
| 1106 | try bw.writeByteNTimes('0', precision - trimmed.len); | |
| 1106 | try bw.splatByteAll('0', precision - trimmed.len); | |
| 1107 | 1107 | }; |
| 1108 | 1108 | try bw.writeAll("p"); |
| 1109 | 1109 | try printIntOptions(bw, exponent - exponent_bias, 10, .lower, .{}); |
lib/std/io/Reader.zig+4-98| ... | ... | @@ -93,108 +93,14 @@ pub fn readAllAlloc(self: Self, allocator: mem.Allocator, max_size: usize) anyer |
| 93 | 93 | return try array_list.toOwnedSlice(); |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | /// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead. | |
| 97 | /// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found. | |
| 98 | /// Does not include the delimiter in the result. | |
| 99 | /// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the | |
| 100 | /// `std.ArrayList` is populated with `max_size` bytes from the stream. | |
| 101 | pub fn readUntilDelimiterArrayList( | |
| 102 | self: Self, | |
| 103 | array_list: *std.ArrayList(u8), | |
| 104 | delimiter: u8, | |
| 105 | max_size: usize, | |
| 106 | ) anyerror!void { | |
| 107 | array_list.shrinkRetainingCapacity(0); | |
| 108 | try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size); | |
| 109 | } | |
| 110 | ||
| 111 | /// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead. | |
| 112 | /// Allocates enough memory to read until `delimiter`. If the allocated | |
| 113 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. | |
| 114 | /// Caller owns returned memory. | |
| 115 | /// If this function returns an error, the contents from the stream read so far are lost. | |
| 116 | pub fn readUntilDelimiterAlloc( | |
| 117 | self: Self, | |
| 118 | allocator: mem.Allocator, | |
| 119 | delimiter: u8, | |
| 120 | max_size: usize, | |
| 121 | ) anyerror![]u8 { | |
| 122 | var array_list = std.ArrayList(u8).init(allocator); | |
| 123 | defer array_list.deinit(); | |
| 124 | try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size); | |
| 125 | return try array_list.toOwnedSlice(); | |
| 126 | } | |
| 127 | ||
| 128 | /// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead. | |
| 129 | /// Reads from the stream until specified byte is found. If the buffer is not | |
| 130 | /// large enough to hold the entire contents, `error.StreamTooLong` is returned. | |
| 131 | /// If end-of-stream is found, `error.EndOfStream` is returned. | |
| 132 | /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The | |
| 133 | /// delimiter byte is written to the output buffer but is not included | |
| 134 | /// in the returned slice. | |
| 135 | pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) anyerror![]u8 { | |
| 136 | var fbs = std.io.fixedBufferStream(buf); | |
| 137 | try self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len); | |
| 138 | const output = fbs.getWritten(); | |
| 139 | buf[output.len] = delimiter; // emulating old behaviour | |
| 140 | return output; | |
| 141 | } | |
| 142 | ||
| 143 | /// Deprecated: use `streamUntilDelimiter` with ArrayList's (or any other's) writer instead. | |
| 144 | /// Allocates enough memory to read until `delimiter` or end-of-stream. | |
| 145 | /// If the allocated memory would be greater than `max_size`, returns | |
| 146 | /// `error.StreamTooLong`. If end-of-stream is found, returns the rest | |
| 147 | /// of the stream. If this function is called again after that, returns | |
| 148 | /// null. | |
| 149 | /// Caller owns returned memory. | |
| 150 | /// If this function returns an error, the contents from the stream read so far are lost. | |
| 151 | pub fn readUntilDelimiterOrEofAlloc( | |
| 152 | self: Self, | |
| 153 | allocator: mem.Allocator, | |
| 154 | delimiter: u8, | |
| 155 | max_size: usize, | |
| 156 | ) anyerror!?[]u8 { | |
| 157 | var array_list = std.ArrayList(u8).init(allocator); | |
| 158 | defer array_list.deinit(); | |
| 159 | self.streamUntilDelimiter(array_list.writer(), delimiter, max_size) catch |err| switch (err) { | |
| 160 | error.EndOfStream => if (array_list.items.len == 0) { | |
| 161 | return null; | |
| 162 | }, | |
| 163 | else => |e| return e, | |
| 164 | }; | |
| 165 | return try array_list.toOwnedSlice(); | |
| 166 | } | |
| 167 | ||
| 168 | /// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead. | |
| 169 | /// Reads from the stream until specified byte is found. If the buffer is not | |
| 170 | /// large enough to hold the entire contents, `error.StreamTooLong` is returned. | |
| 171 | /// If end-of-stream is found, returns the rest of the stream. If this | |
| 172 | /// function is called again after that, returns null. | |
| 173 | /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The | |
| 174 | /// delimiter byte is written to the output buffer but is not included | |
| 175 | /// in the returned slice. | |
| 176 | pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) anyerror!?[]u8 { | |
| 177 | var fbs = std.io.fixedBufferStream(buf); | |
| 178 | self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len) catch |err| switch (err) { | |
| 179 | error.EndOfStream => if (fbs.getWritten().len == 0) { | |
| 180 | return null; | |
| 181 | }, | |
| 182 | ||
| 183 | else => |e| return e, | |
| 184 | }; | |
| 185 | const output = fbs.getWritten(); | |
| 186 | buf[output.len] = delimiter; // emulating old behaviour | |
| 187 | return output; | |
| 188 | } | |
| 189 | ||
| 190 | /// Appends to the `writer` contents by reading from the stream until `delimiter` is found. | |
| 96 | /// Appends to `bw` contents by reading from the stream until `delimiter` is found. | |
| 191 | 97 | /// Does not write the delimiter itself. |
| 192 | 98 | /// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`, |
| 193 | 99 | /// returns `error.StreamTooLong` and finishes appending. |
| 194 | 100 | /// If `optional_max_size` is null, appending is unbounded. |
| 195 | 101 | pub fn streamUntilDelimiter( |
| 196 | 102 | self: Self, |
| 197 | writer: anytype, | |
| 103 | bw: *std.io.BufferedWriter, | |
| 198 | 104 | delimiter: u8, |
| 199 | 105 | optional_max_size: ?usize, |
| 200 | 106 | ) anyerror!void { |
| ... | ... | @@ -202,14 +108,14 @@ pub fn streamUntilDelimiter( |
| 202 | 108 | for (0..max_size) |_| { |
| 203 | 109 | const byte: u8 = try self.readByte(); |
| 204 | 110 | if (byte == delimiter) return; |
| 205 | try writer.writeByte(byte); | |
| 111 | try bw.writeByte(byte); | |
| 206 | 112 | } |
| 207 | 113 | return error.StreamTooLong; |
| 208 | 114 | } else { |
| 209 | 115 | while (true) { |
| 210 | 116 | const byte: u8 = try self.readByte(); |
| 211 | 117 | if (byte == delimiter) return; |
| 212 | try writer.writeByte(byte); | |
| 118 | try bw.writeByte(byte); | |
| 213 | 119 | } |
| 214 | 120 | // Can not throw `error.StreamTooLong` since there are no boundary. |
| 215 | 121 | } |
lib/std/tar/writer.zig+156-167| ... | ... | @@ -2,187 +2,176 @@ const std = @import("std"); |
| 2 | 2 | const assert = std.debug.assert; |
| 3 | 3 | const testing = std.testing; |
| 4 | 4 | |
| 5 | /// Creates tar Writer which will write tar content to the `underlying_writer`. | |
| 6 | /// Use setRoot to nest all following entries under single root. If file don't | |
| 7 | /// fit into posix header (name+prefix: 100+155 bytes) gnu extented header will | |
| 8 | /// be used for long names. Options enables setting file premission mode and | |
| 9 | /// mtime. Default is to use current time for mtime and 0o664 for file mode. | |
| 10 | pub fn writer(underlying_writer: anytype) Writer(@TypeOf(underlying_writer)) { | |
| 11 | return .{ .underlying_writer = underlying_writer }; | |
| 12 | } | |
| 13 | ||
| 14 | pub fn Writer(comptime WriterType: type) type { | |
| 15 | return struct { | |
| 16 | const block_size = @sizeOf(Header); | |
| 17 | const empty_block: [block_size]u8 = [_]u8{0} ** block_size; | |
| 18 | ||
| 19 | /// Options for writing file/dir/link. If left empty 0o664 is used for | |
| 20 | /// file mode and current time for mtime. | |
| 21 | pub const Options = struct { | |
| 22 | /// File system permission mode. | |
| 23 | mode: u32 = 0, | |
| 24 | /// File system modification time. | |
| 25 | mtime: u64 = 0, | |
| 26 | }; | |
| 27 | const Self = @This(); | |
| 5 | pub const Writer = struct { | |
| 6 | const block_size = @sizeOf(Header); | |
| 7 | const empty_block: [block_size]u8 = [_]u8{0} ** block_size; | |
| 8 | ||
| 9 | /// Options for writing file/dir/link. If left empty 0o664 is used for | |
| 10 | /// file mode and current time for mtime. | |
| 11 | pub const Options = struct { | |
| 12 | /// File system permission mode. | |
| 13 | mode: u32 = 0, | |
| 14 | /// File system modification time. | |
| 15 | mtime: u64 = 0, | |
| 16 | }; | |
| 17 | const Self = @This(); | |
| 28 | 18 | |
| 29 | underlying_writer: WriterType, | |
| 30 | prefix: []const u8 = "", | |
| 31 | mtime_now: u64 = 0, | |
| 19 | underlying_writer: *std.io.BufferedWriter, | |
| 20 | prefix: []const u8 = "", | |
| 21 | mtime_now: u64 = 0, | |
| 32 | 22 | |
| 33 | /// Sets prefix for all other write* method paths. | |
| 34 | pub fn setRoot(self: *Self, root: []const u8) !void { | |
| 35 | if (root.len > 0) | |
| 36 | try self.writeDir(root, .{}); | |
| 23 | /// Sets prefix for all other write* method paths. | |
| 24 | pub fn setRoot(self: *Self, root: []const u8) !void { | |
| 25 | if (root.len > 0) | |
| 26 | try self.writeDir(root, .{}); | |
| 37 | 27 | |
| 38 | self.prefix = root; | |
| 39 | } | |
| 28 | self.prefix = root; | |
| 29 | } | |
| 40 | 30 | |
| 41 | /// Writes directory. | |
| 42 | pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void { | |
| 43 | try self.writeHeader(.directory, sub_path, "", 0, opt); | |
| 44 | } | |
| 31 | /// Writes directory. | |
| 32 | pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void { | |
| 33 | try self.writeHeader(.directory, sub_path, "", 0, opt); | |
| 34 | } | |
| 45 | 35 | |
| 46 | /// Writes file system file. | |
| 47 | pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void { | |
| 48 | const stat = try file.stat(); | |
| 49 | const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 36 | /// Writes file system file. | |
| 37 | pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void { | |
| 38 | const stat = try file.stat(); | |
| 39 | const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 50 | 40 | |
| 51 | var header = Header{}; | |
| 52 | try self.setPath(&header, sub_path); | |
| 53 | try header.setSize(stat.size); | |
| 54 | try header.setMtime(mtime); | |
| 55 | try header.write(self.underlying_writer); | |
| 41 | var header = Header{}; | |
| 42 | try self.setPath(&header, sub_path); | |
| 43 | try header.setSize(stat.size); | |
| 44 | try header.setMtime(mtime); | |
| 45 | try header.write(self.underlying_writer); | |
| 56 | 46 | |
| 57 | try self.underlying_writer.writeFile(file); | |
| 58 | try self.writePadding(stat.size); | |
| 59 | } | |
| 47 | try self.underlying_writer.writeFileAll(file, .{ .len = .init(stat.size) }); | |
| 48 | try self.writePadding(stat.size); | |
| 49 | } | |
| 60 | 50 | |
| 61 | /// Writes file reading file content from `reader`. Number of bytes in | |
| 62 | /// reader must be equal to `size`. | |
| 63 | pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void { | |
| 64 | try self.writeHeader(.regular, sub_path, "", @intCast(size), opt); | |
| 51 | /// Writes file reading file content from `reader`. Number of bytes in | |
| 52 | /// reader must be equal to `size`. | |
| 53 | pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void { | |
| 54 | try self.writeHeader(.regular, sub_path, "", @intCast(size), opt); | |
| 65 | 55 | |
| 66 | var counting_reader = std.io.countingReader(reader); | |
| 67 | var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); | |
| 68 | try fifo.pump(counting_reader.reader(), self.underlying_writer); | |
| 69 | if (counting_reader.bytes_read != size) return error.WrongReaderSize; | |
| 70 | try self.writePadding(size); | |
| 71 | } | |
| 56 | var counting_reader = std.io.countingReader(reader); | |
| 57 | var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); | |
| 58 | try fifo.pump(counting_reader.reader(), self.underlying_writer); | |
| 59 | if (counting_reader.bytes_read != size) return error.WrongReaderSize; | |
| 60 | try self.writePadding(size); | |
| 61 | } | |
| 72 | 62 | |
| 73 | /// Writes file using bytes buffer `content` for size and file content. | |
| 74 | pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void { | |
| 75 | try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt); | |
| 76 | try self.underlying_writer.writeAll(content); | |
| 77 | try self.writePadding(content.len); | |
| 78 | } | |
| 63 | /// Writes file using bytes buffer `content` for size and file content. | |
| 64 | pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void { | |
| 65 | try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt); | |
| 66 | try self.underlying_writer.writeAll(content); | |
| 67 | try self.writePadding(content.len); | |
| 68 | } | |
| 79 | 69 | |
| 80 | /// Writes symlink. | |
| 81 | pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void { | |
| 82 | try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt); | |
| 83 | } | |
| 70 | /// Writes symlink. | |
| 71 | pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void { | |
| 72 | try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt); | |
| 73 | } | |
| 84 | 74 | |
| 85 | /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and | |
| 86 | /// default for entry mode . | |
| 87 | pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void { | |
| 88 | switch (entry.kind) { | |
| 89 | .directory => { | |
| 90 | try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); | |
| 91 | }, | |
| 92 | .file => { | |
| 93 | var file = try entry.dir.openFile(entry.basename, .{}); | |
| 94 | defer file.close(); | |
| 95 | try self.writeFile(entry.path, file); | |
| 96 | }, | |
| 97 | .sym_link => { | |
| 98 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 99 | const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); | |
| 100 | try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); | |
| 101 | }, | |
| 102 | else => { | |
| 103 | return error.UnsupportedWalkerEntryKind; | |
| 104 | }, | |
| 105 | } | |
| 75 | /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and | |
| 76 | /// default for entry mode . | |
| 77 | pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void { | |
| 78 | switch (entry.kind) { | |
| 79 | .directory => { | |
| 80 | try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); | |
| 81 | }, | |
| 82 | .file => { | |
| 83 | var file = try entry.dir.openFile(entry.basename, .{}); | |
| 84 | defer file.close(); | |
| 85 | try self.writeFile(entry.path, file); | |
| 86 | }, | |
| 87 | .sym_link => { | |
| 88 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 89 | const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); | |
| 90 | try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); | |
| 91 | }, | |
| 92 | else => { | |
| 93 | return error.UnsupportedWalkerEntryKind; | |
| 94 | }, | |
| 106 | 95 | } |
| 96 | } | |
| 107 | 97 | |
| 108 | fn writeHeader( | |
| 109 | self: *Self, | |
| 110 | typeflag: Header.FileType, | |
| 111 | sub_path: []const u8, | |
| 112 | link_name: []const u8, | |
| 113 | size: u64, | |
| 114 | opt: Options, | |
| 115 | ) !void { | |
| 116 | var header = Header.init(typeflag); | |
| 117 | try self.setPath(&header, sub_path); | |
| 118 | try header.setSize(size); | |
| 119 | try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow()); | |
| 120 | if (opt.mode != 0) | |
| 121 | try header.setMode(opt.mode); | |
| 122 | if (typeflag == .symbolic_link) | |
| 123 | header.setLinkname(link_name) catch |err| switch (err) { | |
| 124 | error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}), | |
| 125 | else => return err, | |
| 126 | }; | |
| 127 | try header.write(self.underlying_writer); | |
| 128 | } | |
| 98 | fn writeHeader( | |
| 99 | self: *Self, | |
| 100 | typeflag: Header.FileType, | |
| 101 | sub_path: []const u8, | |
| 102 | link_name: []const u8, | |
| 103 | size: u64, | |
| 104 | opt: Options, | |
| 105 | ) !void { | |
| 106 | var header = Header.init(typeflag); | |
| 107 | try self.setPath(&header, sub_path); | |
| 108 | try header.setSize(size); | |
| 109 | try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow()); | |
| 110 | if (opt.mode != 0) | |
| 111 | try header.setMode(opt.mode); | |
| 112 | if (typeflag == .symbolic_link) | |
| 113 | header.setLinkname(link_name) catch |err| switch (err) { | |
| 114 | error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}), | |
| 115 | else => return err, | |
| 116 | }; | |
| 117 | try header.write(self.underlying_writer); | |
| 118 | } | |
| 129 | 119 | |
| 130 | fn mtimeNow(self: *Self) u64 { | |
| 131 | if (self.mtime_now == 0) | |
| 132 | self.mtime_now = @intCast(std.time.timestamp()); | |
| 133 | return self.mtime_now; | |
| 134 | } | |
| 120 | fn mtimeNow(self: *Self) u64 { | |
| 121 | if (self.mtime_now == 0) | |
| 122 | self.mtime_now = @intCast(std.time.timestamp()); | |
| 123 | return self.mtime_now; | |
| 124 | } | |
| 135 | 125 | |
| 136 | fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { | |
| 137 | const stat = try entry.dir.statFile(entry.basename); | |
| 138 | return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 139 | } | |
| 126 | fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { | |
| 127 | const stat = try entry.dir.statFile(entry.basename); | |
| 128 | return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 129 | } | |
| 140 | 130 | |
| 141 | /// Writes path in posix header, if don't fit (in name+prefix; 100+155 | |
| 142 | /// bytes) writes it in gnu extended header. | |
| 143 | fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void { | |
| 144 | header.setPath(self.prefix, sub_path) catch |err| switch (err) { | |
| 145 | error.NameTooLong => { | |
| 146 | // write extended header | |
| 147 | const buffers: []const []const u8 = if (self.prefix.len == 0) | |
| 148 | &.{sub_path} | |
| 149 | else | |
| 150 | &.{ self.prefix, "/", sub_path }; | |
| 151 | try self.writeExtendedHeader(.gnu_long_name, buffers); | |
| 152 | }, | |
| 153 | else => return err, | |
| 154 | }; | |
| 155 | } | |
| 131 | /// Writes path in posix header, if don't fit (in name+prefix; 100+155 | |
| 132 | /// bytes) writes it in gnu extended header. | |
| 133 | fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void { | |
| 134 | header.setPath(self.prefix, sub_path) catch |err| switch (err) { | |
| 135 | error.NameTooLong => { | |
| 136 | // write extended header | |
| 137 | const buffers: []const []const u8 = if (self.prefix.len == 0) | |
| 138 | &.{sub_path} | |
| 139 | else | |
| 140 | &.{ self.prefix, "/", sub_path }; | |
| 141 | try self.writeExtendedHeader(.gnu_long_name, buffers); | |
| 142 | }, | |
| 143 | else => return err, | |
| 144 | }; | |
| 145 | } | |
| 156 | 146 | |
| 157 | /// Writes gnu extended header: gnu_long_name or gnu_long_link. | |
| 158 | fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void { | |
| 159 | var len: usize = 0; | |
| 160 | for (buffers) |buf| | |
| 161 | len += buf.len; | |
| 162 | ||
| 163 | var header = Header.init(typeflag); | |
| 164 | try header.setSize(len); | |
| 165 | try header.write(self.underlying_writer); | |
| 166 | for (buffers) |buf| | |
| 167 | try self.underlying_writer.writeAll(buf); | |
| 168 | try self.writePadding(len); | |
| 169 | } | |
| 147 | /// Writes gnu extended header: gnu_long_name or gnu_long_link. | |
| 148 | fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void { | |
| 149 | var len: usize = 0; | |
| 150 | for (buffers) |buf| | |
| 151 | len += buf.len; | |
| 152 | ||
| 153 | var header = Header.init(typeflag); | |
| 154 | try header.setSize(len); | |
| 155 | try header.write(self.underlying_writer); | |
| 156 | for (buffers) |buf| | |
| 157 | try self.underlying_writer.writeAll(buf); | |
| 158 | try self.writePadding(len); | |
| 159 | } | |
| 170 | 160 | |
| 171 | fn writePadding(self: *Self, bytes: u64) !void { | |
| 172 | const pos: usize = @intCast(bytes % block_size); | |
| 173 | if (pos == 0) return; | |
| 174 | try self.underlying_writer.writeAll(empty_block[pos..]); | |
| 175 | } | |
| 161 | fn writePadding(self: *Self, bytes: u64) !void { | |
| 162 | const pos: usize = @intCast(bytes % block_size); | |
| 163 | if (pos == 0) return; | |
| 164 | try self.underlying_writer.writeAll(empty_block[pos..]); | |
| 165 | } | |
| 176 | 166 | |
| 177 | /// Tar should finish with two zero blocks, but 'reasonable system must | |
| 178 | /// not assume that such a block exists when reading an archive' (from | |
| 179 | /// reference). In practice it is safe to skip this finish. | |
| 180 | pub fn finish(self: *Self) !void { | |
| 181 | try self.underlying_writer.writeAll(&empty_block); | |
| 182 | try self.underlying_writer.writeAll(&empty_block); | |
| 183 | } | |
| 184 | }; | |
| 185 | } | |
| 167 | /// Tar should finish with two zero blocks, but 'reasonable system must | |
| 168 | /// not assume that such a block exists when reading an archive' (from | |
| 169 | /// reference). In practice it is safe to skip this finish. | |
| 170 | pub fn finish(self: *Self) !void { | |
| 171 | try self.underlying_writer.writeAll(&empty_block); | |
| 172 | try self.underlying_writer.writeAll(&empty_block); | |
| 173 | } | |
| 174 | }; | |
| 186 | 175 | |
| 187 | 176 | /// A struct that is exactly 512 bytes and matches tar file format. This is |
| 188 | 177 | /// intended to be used for outputting tar files; for parsing there is |
| ... | ... | @@ -431,14 +420,14 @@ test "write files" { |
| 431 | 420 | { |
| 432 | 421 | const root = "root"; |
| 433 | 422 | |
| 434 | var output = std.ArrayList(u8).init(testing.allocator); | |
| 423 | var output: std.io.AllocatingWriter = undefined; | |
| 424 | var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) }; | |
| 435 | 425 | defer output.deinit(); |
| 436 | var wrt = writer(output.writer()); | |
| 437 | 426 | try wrt.setRoot(root); |
| 438 | 427 | for (files) |file| |
| 439 | 428 | try wrt.writeFileBytes(file.path, file.content, .{}); |
| 440 | 429 | |
| 441 | var input = std.io.fixedBufferStream(output.items); | |
| 430 | var input: std.io.FixedBufferStream = .{ .buffer = output.getWritten() }; | |
| 442 | 431 | var iter = std.tar.iterator( |
| 443 | 432 | input.reader(), |
| 444 | 433 | .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer }, |
| ... | ... | @@ -467,15 +456,15 @@ test "write files" { |
| 467 | 456 | } |
| 468 | 457 | // without root |
| 469 | 458 | { |
| 470 | var output = std.ArrayList(u8).init(testing.allocator); | |
| 459 | var output: std.io.AllocatingWriter = undefined; | |
| 460 | var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) }; | |
| 471 | 461 | defer output.deinit(); |
| 472 | var wrt = writer(output.writer()); | |
| 473 | 462 | for (files) |file| { |
| 474 | 463 | var content = std.io.fixedBufferStream(file.content); |
| 475 | 464 | try wrt.writeFileStream(file.path, file.content.len, content.reader(), .{}); |
| 476 | 465 | } |
| 477 | 466 | |
| 478 | var input = std.io.fixedBufferStream(output.items); | |
| 467 | var input: std.io.FixedBufferStream = .{ .buffer = output.getWritten() }; | |
| 479 | 468 | var iter = std.tar.iterator( |
| 480 | 469 | input.reader(), |
| 481 | 470 | .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer }, |
lib/std/zig.zig+4-4| ... | ... | @@ -635,7 +635,7 @@ pub fn parseTargetQueryOrReportFatalError( |
| 635 | 635 | var help_text = std.ArrayList(u8).init(allocator); |
| 636 | 636 | defer help_text.deinit(); |
| 637 | 637 | for (diags.arch.?.allCpuModels()) |cpu| { |
| 638 | help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help; | |
| 638 | help_text.print(" {s}\n", .{cpu.name}) catch break :help; | |
| 639 | 639 | } |
| 640 | 640 | std.log.info("available CPUs for architecture '{s}':\n{s}", .{ |
| 641 | 641 | @tagName(diags.arch.?), help_text.items, |
| ... | ... | @@ -648,7 +648,7 @@ pub fn parseTargetQueryOrReportFatalError( |
| 648 | 648 | var help_text = std.ArrayList(u8).init(allocator); |
| 649 | 649 | defer help_text.deinit(); |
| 650 | 650 | for (diags.arch.?.allFeaturesList()) |feature| { |
| 651 | help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help; | |
| 651 | help_text.print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help; | |
| 652 | 652 | } |
| 653 | 653 | std.log.info("available CPU features for architecture '{s}':\n{s}", .{ |
| 654 | 654 | @tagName(diags.arch.?), help_text.items, |
| ... | ... | @@ -661,7 +661,7 @@ pub fn parseTargetQueryOrReportFatalError( |
| 661 | 661 | var help_text = std.ArrayList(u8).init(allocator); |
| 662 | 662 | defer help_text.deinit(); |
| 663 | 663 | inline for (@typeInfo(std.Target.ObjectFormat).@"enum".fields) |field| { |
| 664 | help_text.writer().print(" {s}\n", .{field.name}) catch break :help; | |
| 664 | help_text.print(" {s}\n", .{field.name}) catch break :help; | |
| 665 | 665 | } |
| 666 | 666 | std.log.info("available object formats:\n{s}", .{help_text.items}); |
| 667 | 667 | } |
| ... | ... | @@ -672,7 +672,7 @@ pub fn parseTargetQueryOrReportFatalError( |
| 672 | 672 | var help_text = std.ArrayList(u8).init(allocator); |
| 673 | 673 | defer help_text.deinit(); |
| 674 | 674 | inline for (@typeInfo(std.Target.Cpu.Arch).@"enum".fields) |field| { |
| 675 | help_text.writer().print(" {s}\n", .{field.name}) catch break :help; | |
| 675 | help_text.print(" {s}\n", .{field.name}) catch break :help; | |
| 676 | 676 | } |
| 677 | 677 | std.log.info("available architectures:\n{s} native\n", .{help_text.items}); |
| 678 | 678 | } |
lib/std/zig/ErrorBundle.zig+8-8| ... | ... | @@ -194,11 +194,11 @@ fn renderErrorMessageToWriter( |
| 194 | 194 | ) anyerror!void { |
| 195 | 195 | const ttyconf = options.ttyconf; |
| 196 | 196 | var counting_writer: std.io.CountingWriter = .{ .child_writer = bw.writer() }; |
| 197 | const counting_bw = counting_writer.unbufferedWriter(); | |
| 197 | var counting_bw = counting_writer.unbufferedWriter(); | |
| 198 | 198 | const err_msg = eb.getErrorMessage(err_msg_index); |
| 199 | 199 | if (err_msg.src_loc != .none) { |
| 200 | 200 | const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc)); |
| 201 | try counting_bw.writeByteNTimes(' ', indent); | |
| 201 | try counting_bw.splatByteAll(' ', indent); | |
| 202 | 202 | try ttyconf.setColor(bw, .bold); |
| 203 | 203 | try counting_bw.print("{s}:{d}:{d}: ", .{ |
| 204 | 204 | eb.nullTerminatedString(src.data.src_path), |
| ... | ... | @@ -210,7 +210,7 @@ fn renderErrorMessageToWriter( |
| 210 | 210 | try counting_bw.writeAll(": "); |
| 211 | 211 | // This is the length of the part before the error message: |
| 212 | 212 | // e.g. "file.zig:4:5: error: " |
| 213 | const prefix_len: usize = @intCast(counting_bw.context.bytes_written); | |
| 213 | const prefix_len: usize = @intCast(counting_writer.bytes_written); | |
| 214 | 214 | try ttyconf.setColor(bw, .reset); |
| 215 | 215 | try ttyconf.setColor(bw, .bold); |
| 216 | 216 | if (err_msg.count == 1) { |
| ... | ... | @@ -233,11 +233,11 @@ fn renderErrorMessageToWriter( |
| 233 | 233 | const before_caret = src.data.span_main - src.data.span_start; |
| 234 | 234 | // -1 since span.main includes the caret |
| 235 | 235 | const after_caret = src.data.span_end -| src.data.span_main -| 1; |
| 236 | try bw.writeByteNTimes(' ', src.data.column - before_caret); | |
| 236 | try bw.splatByteAll(' ', src.data.column - before_caret); | |
| 237 | 237 | try ttyconf.setColor(bw, .green); |
| 238 | try bw.writeByteNTimes('~', before_caret); | |
| 238 | try bw.splatByteAll('~', before_caret); | |
| 239 | 239 | try bw.writeByte('^'); |
| 240 | try bw.writeByteNTimes('~', after_caret); | |
| 240 | try bw.splatByteAll('~', after_caret); | |
| 241 | 241 | try bw.writeByte('\n'); |
| 242 | 242 | try ttyconf.setColor(bw, .reset); |
| 243 | 243 | } |
| ... | ... | @@ -277,7 +277,7 @@ fn renderErrorMessageToWriter( |
| 277 | 277 | } |
| 278 | 278 | } else { |
| 279 | 279 | try ttyconf.setColor(bw, color); |
| 280 | try bw.writeByteNTimes(' ', indent); | |
| 280 | try bw.splatByteAll(' ', indent); | |
| 281 | 281 | try bw.writeAll(kind); |
| 282 | 282 | try bw.writeAll(": "); |
| 283 | 283 | try ttyconf.setColor(bw, .reset); |
| ... | ... | @@ -306,7 +306,7 @@ fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter, |
| 306 | 306 | try bw.writeAll(line); |
| 307 | 307 | if (lines.index == null) break; |
| 308 | 308 | try bw.writeByte('\n'); |
| 309 | try bw.writeByteNTimes(' ', indent); | |
| 309 | try bw.splatByteAll(' ', indent); | |
| 310 | 310 | } |
| 311 | 311 | } |
| 312 | 312 |
lib/std/zig/LibCInstallation.zig+2-2| ... | ... | @@ -370,7 +370,7 @@ fn findNativeIncludeDirWindows( |
| 370 | 370 | |
| 371 | 371 | for (installs) |install| { |
| 372 | 372 | result_buf.shrinkAndFree(0); |
| 373 | try result_buf.writer().print("{s}\\Include\\{s}\\ucrt", .{ install.path, install.version }); | |
| 373 | try result_buf.print("{s}\\Include\\{s}\\ucrt", .{ install.path, install.version }); | |
| 374 | 374 | |
| 375 | 375 | var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) { |
| 376 | 376 | error.FileNotFound, |
| ... | ... | @@ -417,7 +417,7 @@ fn findNativeCrtDirWindows( |
| 417 | 417 | |
| 418 | 418 | for (installs) |install| { |
| 419 | 419 | result_buf.shrinkAndFree(0); |
| 420 | try result_buf.writer().print("{s}\\Lib\\{s}\\ucrt\\{s}", .{ install.path, install.version, arch_sub_dir }); | |
| 420 | try result_buf.print("{s}\\Lib\\{s}\\ucrt\\{s}", .{ install.path, install.version, arch_sub_dir }); | |
| 421 | 421 | |
| 422 | 422 | var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) { |
| 423 | 423 | error.FileNotFound, |