| ... | @@ -60,6 +60,8 @@ web_server: ?*AvoidableWebServer, | ... | @@ -60,6 +60,8 @@ web_server: ?*AvoidableWebServer, |
| 60 | /// Allocated into `gpa`. | 60 | /// Allocated into `gpa`. |
| 61 | memory_blocked_steps: std.ArrayList(Configuration.Step.Index), | 61 | memory_blocked_steps: std.ArrayList(Configuration.Step.Index), |
| 62 | /// Allocated into `gpa`. | 62 | /// Allocated into `gpa`. |
| | 63 | initial_steps: std.array_hash_map.Auto(Configuration.Step.Index, void), |
| | 64 | /// Allocated into `gpa`. |
| 63 | step_stack: std.array_hash_map.Auto(Configuration.Step.Index, void), | 65 | step_stack: std.array_hash_map.Auto(Configuration.Step.Index, void), |
| 64 | pkg_config: PkgConfig, | 66 | pkg_config: PkgConfig, |
| 65 | | 67 | |
| ... | @@ -762,6 +764,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -762,6 +764,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 762 | .protocol_server = protocol_server, | 764 | .protocol_server = protocol_server, |
| 763 | .protocol_server_mutex = .init, | 765 | .protocol_server_mutex = .init, |
| 764 | .memory_blocked_steps = .empty, | 766 | .memory_blocked_steps = .empty, |
| | 767 | .initial_steps = .empty, |
| 765 | .step_stack = .empty, | 768 | .step_stack = .empty, |
| 766 | .pkg_config = .{ .debug = debug_pkg_config }, | 769 | .pkg_config = .{ .debug = debug_pkg_config }, |
| 767 | | 770 | |
| ... | @@ -776,6 +779,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -776,6 +779,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 776 | }; | 779 | }; |
| 777 | defer { | 780 | defer { |
| 778 | maker.memory_blocked_steps.deinit(gpa); | 781 | maker.memory_blocked_steps.deinit(gpa); |
| | 782 | maker.initial_steps.deinit(gpa); |
| 779 | maker.step_stack.deinit(gpa); | 783 | maker.step_stack.deinit(gpa); |
| 780 | } | 784 | } |
| 781 | | 785 | |
| ... | @@ -809,6 +813,41 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -809,6 +813,41 @@ pub fn main(init: process.Init.Minimal) !void { |
| 809 | cleanExit(io, &scanned_config); | 813 | cleanExit(io, &scanned_config); |
| 810 | process.exit(0); | 814 | process.exit(0); |
| 811 | }, | 815 | }, |
| | 816 | .bsp_build_steps => { |
| | 817 | // Cancel existing file watching |
| | 818 | select.cancelDiscard(); |
| | 819 | in_debounce = false; |
| | 820 | |
| | 821 | const body = try s.in.takeStruct(Client.Message.BuildSteps, .little); |
| | 822 | const steps = try s.in.readSliceEndianAlloc(gpa, Configuration.Step.Index, body.step_count, .little); |
| | 823 | defer gpa.free(steps); |
| | 824 | if (body.flags.watch and !Watch.have_impl) fatal("file watching is unavailable", .{}); |
| | 825 | |
| | 826 | try select.concurrent(.message, Server.receiveMessage, .{s}); |
| | 827 | |
| | 828 | maker.watch = body.flags.watch; |
| | 829 | maker.prepare(steps) catch |err| switch (err) { |
| | 830 | error.DependencyLoopDetected, error.InsufficientMemory => { |
| | 831 | // TODO handle DependencyLoopDetected as error.FailedButCacheIntact |
| | 832 | // and handle InsufficientMemory as error.AlreadyReported |
| | 833 | _ = io.lockStderr(&.{}, graph.stderr_mode) catch {}; |
| | 834 | process.exit(1); |
| | 835 | }, |
| | 836 | else => |e| return e, |
| | 837 | }; |
| | 838 | |
| | 839 | try maker.makeSteps(main_progress_node, null); |
| | 840 | |
| | 841 | if (body.flags.watch) { |
| | 842 | if (!Watch.have_impl) unreachable; |
| | 843 | if (w == null) w = try .init(&maker); |
| | 844 | |
| | 845 | try w.?.update(maker.step_stack.keys()); |
| | 846 | try select.concurrent(.fs_event, Watch.wait, .{ &w.?, if (in_debounce) .{ .ms = debounce_interval_ms } else .none }); |
| | 847 | } |
| | 848 | |
| | 849 | continue :loop try select.await(); |
| | 850 | }, |
| 812 | else => fatal("unsupported message: {t}", .{header.tag}), | 851 | else => fatal("unsupported message: {t}", .{header.tag}), |
| 813 | } | 852 | } |
| 814 | }, | 853 | }, |
| ... | @@ -818,7 +857,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -818,7 +857,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 818 | .timeout => { | 857 | .timeout => { |
| 819 | assert(in_debounce); | 858 | assert(in_debounce); |
| 820 | markFailedStepsDirty(&maker); | 859 | markFailedStepsDirty(&maker); |
| 821 | if (true) @panic("TODO run steps that were previous specified over the build system protocol"); | 860 | try maker.makeSteps(main_progress_node, null); |
| 822 | in_debounce = false; | 861 | in_debounce = false; |
| 823 | }, | 862 | }, |
| 824 | .dirty => in_debounce = true, | 863 | .dirty => in_debounce = true, |
| ... | @@ -830,7 +869,10 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -830,7 +869,10 @@ pub fn main(init: process.Init.Minimal) !void { |
| 830 | } | 869 | } |
| 831 | } | 870 | } |
| 832 | | 871 | |
| 833 | maker.prepare(step_names.items) catch |err| switch (err) { | 872 | const initial_steps = try maker.resolveTopLevelSteps(step_names.items); |
| | 873 | defer gpa.free(initial_steps); |
| | 874 | |
| | 875 | maker.prepare(initial_steps) catch |err| switch (err) { |
| 834 | error.DependencyLoopDetected, error.InsufficientMemory => { | 876 | error.DependencyLoopDetected, error.InsufficientMemory => { |
| 835 | // TODO handle DependencyLoopDetected as error.FailedButCacheIntact | 877 | // TODO handle DependencyLoopDetected as error.FailedButCacheIntact |
| 836 | // and handle InsufficientMemory as error.AlreadyReported | 878 | // and handle InsufficientMemory as error.AlreadyReported |
| ... | @@ -857,7 +899,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -857,7 +899,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 857 | }) { | 899 | }) { |
| 858 | if (web_server) |ws| ws.startBuild(); | 900 | if (web_server) |ws| ws.startBuild(); |
| 859 | | 901 | |
| 860 | try maker.makeStepNames(step_names.items, main_progress_node, fuzz); | 902 | try maker.makeSteps(main_progress_node, fuzz); |
| 861 | | 903 | |
| 862 | if (web_server) |ws| { | 904 | if (web_server) |ws| { |
| 863 | if (fuzz) |mode| if (mode != .forever) fatal( | 905 | if (fuzz) |mode| if (mode != .forever) fatal( |
| ... | @@ -2104,11 +2146,37 @@ pub fn stepByIndex(maker: *const Maker, i: Configuration.Step.Index) *Step { | ... | @@ -2104,11 +2146,37 @@ pub fn stepByIndex(maker: *const Maker, i: Configuration.Step.Index) *Step { |
| 2104 | return &maker.steps[@backingInt(i)]; | 2146 | return &maker.steps[@backingInt(i)]; |
| 2105 | } | 2147 | } |
| 2106 | | 2148 | |
| 2107 | fn prepare(maker: *Maker, step_names: []const []const u8) !void { | 2149 | fn resolveTopLevelSteps(maker: *Maker, step_names: []const []const u8) ![]const Configuration.Step.Index { |
| | 2150 | const gpa = maker.gpa; |
| | 2151 | const c = &maker.scanned_config.configuration; |
| | 2152 | |
| | 2153 | if (step_names.len == 0) { |
| | 2154 | return try gpa.dupe(Configuration.Step.Index, &.{c.default_step}); |
| | 2155 | } |
| | 2156 | |
| | 2157 | var result: std.array_hash_map.Auto(Configuration.Step.Index, void) = .empty; |
| | 2158 | defer result.deinit(gpa); |
| | 2159 | |
| | 2160 | try result.ensureTotalCapacity(gpa, step_names.len); |
| | 2161 | |
| | 2162 | for (0..step_names.len) |i| { |
| | 2163 | const step_name = step_names[step_names.len - i - 1]; |
| | 2164 | const s = maker.scanned_config.top_level_steps.get(step_name) orelse { |
| | 2165 | log.info("to list available steps: zig build -l", .{}); |
| | 2166 | fatal("no such step: {s}", .{step_name}); |
| | 2167 | }; |
| | 2168 | result.putAssumeCapacity(s, {}); |
| | 2169 | } |
| | 2170 | |
| | 2171 | return try gpa.dupe(Configuration.Step.Index, result.keys()); |
| | 2172 | } |
| | 2173 | |
| | 2174 | fn prepare(maker: *Maker, step_indices: []const Configuration.Step.Index) !void { |
| 2108 | const gpa = maker.gpa; | 2175 | const gpa = maker.gpa; |
| 2109 | const graph = maker.graph; | 2176 | const graph = maker.graph; |
| 2110 | const arena = graph.arena; | 2177 | const arena = graph.arena; |
| 2111 | const seed: u32 = graph.random_seed; | 2178 | const seed: u32 = graph.random_seed; |
| | 2179 | const initial_steps = &maker.initial_steps; |
| 2112 | const step_stack = &maker.step_stack; | 2180 | const step_stack = &maker.step_stack; |
| 2113 | const c = &maker.scanned_config.configuration; | 2181 | const c = &maker.scanned_config.configuration; |
| 2114 | | 2182 | |
| ... | @@ -2117,18 +2185,15 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { | ... | @@ -2117,18 +2185,15 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { |
| 2117 | step.* = .{ .extended = .init(step_index.ptr(c).flags(c).tag) }; | 2185 | step.* = .{ .extended = .init(step_index.ptr(c).flags(c).tag) }; |
| 2118 | } | 2186 | } |
| 2119 | | 2187 | |
| 2120 | if (step_names.len == 0) { | 2188 | try initial_steps.ensureUnusedCapacity(gpa, step_indices.len); |
| 2121 | try step_stack.put(gpa, c.default_step, {}); | 2189 | try step_stack.ensureUnusedCapacity(gpa, step_indices.len); |
| 2122 | } else { | 2190 | |
| 2123 | try step_stack.ensureUnusedCapacity(gpa, step_names.len); | 2191 | initial_steps.clearRetainingCapacity(); |
| 2124 | for (0..step_names.len) |i| { | 2192 | step_stack.clearRetainingCapacity(); |
| 2125 | const step_name = step_names[step_names.len - i - 1]; | 2193 | |
| 2126 | const s = maker.scanned_config.top_level_steps.get(step_name) orelse { | 2194 | for (step_indices) |step| { |
| 2127 | log.info("to list available steps: zig build -l", .{}); | 2195 | initial_steps.putAssumeCapacity(step, {}); |
| 2128 | fatal("no such step: {s}", .{step_name}); | 2196 | step_stack.putAssumeCapacity(step, {}); |
| 2129 | }; | | |
| 2130 | step_stack.putAssumeCapacity(s, {}); | | |
| 2131 | } | | |
| 2132 | } | 2197 | } |
| 2133 | | 2198 | |
| 2134 | const starting_steps = try arena.dupe(Configuration.Step.Index, step_stack.keys()); | 2199 | const starting_steps = try arena.dupe(Configuration.Step.Index, step_stack.keys()); |
| ... | @@ -2177,9 +2242,8 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { | ... | @@ -2177,9 +2242,8 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { |
| 2177 | } | 2242 | } |
| 2178 | } | 2243 | } |
| 2179 | | 2244 | |
| 2180 | fn makeStepNames( | 2245 | fn makeSteps( |
| 2181 | maker: *Maker, | 2246 | maker: *Maker, |
| 2182 | step_names: []const []const u8, | | |
| 2183 | parent_progress_node: std.Progress.Node, | 2247 | parent_progress_node: std.Progress.Node, |
| 2184 | fuzz: ?Fuzz.Mode, | 2248 | fuzz: ?Fuzz.Mode, |
| 2185 | ) !void { | 2249 | ) !void { |
| ... | @@ -2367,7 +2431,7 @@ fn makeStepNames( | ... | @@ -2367,7 +2431,7 @@ fn makeStepNames( |
| 2367 | defer step_stack_copy.deinit(gpa); | 2431 | defer step_stack_copy.deinit(gpa); |
| 2368 | | 2432 | |
| 2369 | var print_node: PrintNode = .{ .parent = null }; | 2433 | var print_node: PrintNode = .{ .parent = null }; |
| 2370 | if (step_names.len == 0) { | 2434 | if (maker.initial_steps.count() == 0) { |
| 2371 | print_node.last = true; | 2435 | print_node.last = true; |
| 2372 | printTreeStep(maker, c.default_step, t, &print_node, &step_stack_copy) catch |err| switch (err) { | 2436 | printTreeStep(maker, c.default_step, t, &print_node, &step_stack_copy) catch |err| switch (err) { |
| 2373 | error.Canceled => |e| return e, | 2437 | error.Canceled => |e| return e, |
| ... | @@ -2375,10 +2439,10 @@ fn makeStepNames( | ... | @@ -2375,10 +2439,10 @@ fn makeStepNames( |
| 2375 | }; | 2439 | }; |
| 2376 | } else { | 2440 | } else { |
| 2377 | const last_index = if (maker.summary == .all) top_level_steps.count() else blk: { | 2441 | const last_index = if (maker.summary == .all) top_level_steps.count() else blk: { |
| 2378 | var i: usize = step_names.len; | 2442 | var i: usize = maker.initial_steps.count(); |
| 2379 | while (i > 0) { | 2443 | while (i > 0) { |
| 2380 | i -= 1; | 2444 | i -= 1; |
| 2381 | const step_index = top_level_steps.get(step_names[i]).?; | 2445 | const step_index = maker.initial_steps.keys()[i]; |
| 2382 | const step = maker.stepByIndex(step_index); | 2446 | const step = maker.stepByIndex(step_index); |
| 2383 | const found = switch (maker.summary) { | 2447 | const found = switch (maker.summary) { |
| 2384 | .all, .line, .none => unreachable, | 2448 | .all, .line, .none => unreachable, |
| ... | @@ -2389,8 +2453,7 @@ fn makeStepNames( | ... | @@ -2389,8 +2453,7 @@ fn makeStepNames( |
| 2389 | } | 2453 | } |
| 2390 | break :blk top_level_steps.count(); | 2454 | break :blk top_level_steps.count(); |
| 2391 | }; | 2455 | }; |
| 2392 | for (step_names, 0..) |step_name, i| { | 2456 | for (maker.initial_steps.keys(), 0..) |step_index, i| { |
| 2393 | const step_index = top_level_steps.get(step_name).?; | | |
| 2394 | print_node.last = i + 1 == last_index; | 2457 | print_node.last = i + 1 == last_index; |
| 2395 | printTreeStep(maker, step_index, t, &print_node, &step_stack_copy) catch |err| switch (err) { | 2458 | printTreeStep(maker, step_index, t, &print_node, &step_stack_copy) catch |err| switch (err) { |
| 2396 | error.Canceled => |e| return e, | 2459 | error.Canceled => |e| return e, |
| ... | @@ -2401,7 +2464,7 @@ fn makeStepNames( | ... | @@ -2401,7 +2464,7 @@ fn makeStepNames( |
| 2401 | w.writeByte('\n') catch {}; | 2464 | w.writeByte('\n') catch {}; |
| 2402 | } | 2465 | } |
| 2403 | | 2466 | |
| 2404 | if (maker.watch or maker.web_server != null) return; | 2467 | if (maker.watch or maker.web_server != null or maker.protocol_server != null) return; |
| 2405 | | 2468 | |
| 2406 | const code: u8 = code: { | 2469 | const code: u8 = code: { |
| 2407 | if (failure_count == 0) break :code 0; // success | 2470 | if (failure_count == 0) break :code 0; // success |