| ... | @@ -46,6 +46,8 @@ since_event: FSEventStreamEventId, | ... | @@ -46,6 +46,8 @@ since_event: FSEventStreamEventId, |
| 46 | | 46 | |
| 47 | cwd_path: []const u8, | 47 | cwd_path: []const u8, |
| 48 | | 48 | |
| | 49 | must_reconfigure: bool, |
| | 50 | |
| 49 | /// All of the symbols we pull from the `dlopen`ed CoreServices framework. If any of these symbols | 51 | /// All of the symbols we pull from the `dlopen`ed CoreServices framework. If any of these symbols |
| 50 | /// is not present, `init` will close the framework and return an error. | 52 | /// is not present, `init` will close the framework and return an error. |
| 51 | const ResolvedSymbols = struct { | 53 | const ResolvedSymbols = struct { |
| ... | @@ -104,13 +106,15 @@ pub fn init(cwd_path: []const u8) error{ OpenFrameworkFailed, MissingCoreService | ... | @@ -104,13 +106,15 @@ pub fn init(cwd_path: []const u8) error{ OpenFrameworkFailed, MissingCoreService |
| 104 | // to notice any changes which happened during said work. | 106 | // to notice any changes which happened during said work. |
| 105 | .since_event = resolved_symbols.FSEventsGetCurrentEventId(), | 107 | .since_event = resolved_symbols.FSEventsGetCurrentEventId(), |
| 106 | .cwd_path = cwd_path, | 108 | .cwd_path = cwd_path, |
| | 109 | .must_reconfigure = false, |
| 107 | }; | 110 | }; |
| 108 | } | 111 | } |
| 109 | | 112 | |
| 110 | pub fn deinit(fse: *FsEvents, gpa: Allocator, io: Io) void { | 113 | pub fn deinit(fse: *FsEvents, gpa: Allocator, io: Io) void { |
| | 114 | _ = io; |
| 111 | fse.waiting_semaphore.as_object().release(); | 115 | fse.waiting_semaphore.as_object().release(); |
| 112 | fse.dispatch_queue.as_object().release(); | 116 | fse.dispatch_queue.as_object().release(); |
| 113 | fse.core_services.close(io); | 117 | fse.core_services.close(); |
| 114 | | 118 | |
| 115 | gpa.free(fse.watch_roots); | 119 | gpa.free(fse.watch_roots); |
| 116 | fse.watch_paths.deinit(gpa); | 120 | fse.watch_paths.deinit(gpa); |
| ... | @@ -211,7 +215,7 @@ pub fn setPaths(fse: *FsEvents, maker: *Maker, steps: []const std.Build.Configur | ... | @@ -211,7 +215,7 @@ pub fn setPaths(fse: *FsEvents, maker: *Maker, steps: []const std.Build.Configur |
| 211 | } | 215 | } |
| 212 | } | 216 | } |
| 213 | | 217 | |
| 214 | pub fn wait(fse: *FsEvents, maker: *Maker, timeout_ns: ?u64) error{ OutOfMemory, StartFailed }!Watch.WaitResult { | 218 | pub fn wait(fse: *FsEvents, maker: *Maker, timeout_ns: ?u64) error{ OutOfMemory, StartFailed, MustReconfigure }!Watch.WaitResult { |
| 215 | if (fse.watch_roots.len == 0) @panic("nothing to watch"); | 219 | if (fse.watch_roots.len == 0) @panic("nothing to watch"); |
| 216 | const gpa = maker.gpa; | 220 | const gpa = maker.gpa; |
| 217 | | 221 | |
| ... | @@ -285,6 +289,7 @@ pub fn wait(fse: *FsEvents, maker: *Maker, timeout_ns: ?u64) error{ OutOfMemory, | ... | @@ -285,6 +289,7 @@ pub fn wait(fse: *FsEvents, maker: *Maker, timeout_ns: ?u64) error{ OutOfMemory, |
| 285 | const ns = timeout_ns orelse break :timeout .FOREVER; | 289 | const ns = timeout_ns orelse break :timeout .FOREVER; |
| 286 | break :timeout .time(.NOW, @intCast(ns)); | 290 | break :timeout .time(.NOW, @intCast(ns)); |
| 287 | }); | 291 | }); |
| | 292 | if (fse.must_reconfigure) return error.MustReconfigure; |
| 288 | return switch (result) { | 293 | return switch (result) { |
| 289 | 0 => .dirty, | 294 | 0 => .dirty, |
| 290 | else => .timeout, | 295 | else => .timeout, |
| ... | @@ -355,13 +360,23 @@ fn eventCallback( | ... | @@ -355,13 +360,23 @@ fn eventCallback( |
| 355 | false => { | 360 | false => { |
| 356 | if (fse.watch_paths.get(event_path)) |steps| { | 361 | if (fse.watch_paths.get(event_path)) |steps| { |
| 357 | assert(steps.len > 0); | 362 | assert(steps.len > 0); |
| 358 | if (invalidateSteps(maker, steps)) any_dirty = true; | 363 | if (invalidateSteps(maker, steps) catch |err| switch (err) { |
| | 364 | error.MustReconfigure => { |
| | 365 | fse.must_reconfigure = true; |
| | 366 | break; |
| | 367 | }, |
| | 368 | }) any_dirty = true; |
| 359 | } | 369 | } |
| 360 | if (std.fs.path.dirname(event_path)) |event_dirname| { | 370 | if (std.fs.path.dirname(event_path)) |event_dirname| { |
| 361 | // Modifying '/foo/bar' triggers the watch on '/foo'. | 371 | // Modifying '/foo/bar' triggers the watch on '/foo'. |
| 362 | if (fse.watch_paths.get(event_dirname)) |steps| { | 372 | if (fse.watch_paths.get(event_dirname)) |steps| { |
| 363 | assert(steps.len > 0); | 373 | assert(steps.len > 0); |
| 364 | if (invalidateSteps(maker, steps)) any_dirty = true; | 374 | if (invalidateSteps(maker, steps) catch |err| switch (err) { |
| | 375 | error.MustReconfigure => { |
| | 376 | fse.must_reconfigure = true; |
| | 377 | break; |
| | 378 | }, |
| | 379 | }) any_dirty = true; |
| 365 | } | 380 | } |
| 366 | } | 381 | } |
| 367 | }, | 382 | }, |
| ... | @@ -374,13 +389,18 @@ fn eventCallback( | ... | @@ -374,13 +389,18 @@ fn eventCallback( |
| 374 | const changed_path = std.fs.path.dirname(event_path) orelse event_path; | 389 | const changed_path = std.fs.path.dirname(event_path) orelse event_path; |
| 375 | for (fse.watch_paths.keys(), fse.watch_paths.values()) |watching_path, steps| { | 390 | for (fse.watch_paths.keys(), fse.watch_paths.values()) |watching_path, steps| { |
| 376 | if (dirStartsWith(watching_path, changed_path)) { | 391 | if (dirStartsWith(watching_path, changed_path)) { |
| 377 | if (invalidateSteps(maker, steps)) any_dirty = true; | 392 | if (invalidateSteps(maker, steps) catch |err| switch (err) { |
| | 393 | error.MustReconfigure => { |
| | 394 | fse.must_reconfigure = true; |
| | 395 | break; |
| | 396 | }, |
| | 397 | }) any_dirty = true; |
| 378 | } | 398 | } |
| 379 | } | 399 | } |
| 380 | }, | 400 | }, |
| 381 | } | 401 | } |
| 382 | } | 402 | } |
| 383 | if (any_dirty) { | 403 | if (any_dirty or fse.must_reconfigure) { |
| 384 | fse.since_event = rs.FSEventStreamGetLatestEventId(stream); | 404 | fse.since_event = rs.FSEventStreamGetLatestEventId(stream); |
| 385 | _ = fse.waiting_semaphore.signal(); | 405 | _ = fse.waiting_semaphore.signal(); |
| 386 | } | 406 | } |
| ... | @@ -392,11 +412,11 @@ fn dirStartsWith(path: []const u8, prefix: []const u8) bool { | ... | @@ -392,11 +412,11 @@ fn dirStartsWith(path: []const u8, prefix: []const u8) bool { |
| 392 | return true; // `path` is `/foo/bar/...`, `prefix` is `/foo/bar` | 412 | return true; // `path` is `/foo/bar/...`, `prefix` is `/foo/bar` |
| 393 | } | 413 | } |
| 394 | | 414 | |
| 395 | fn invalidateSteps(maker: *Maker, steps: []const std.Build.Configuration.Step.Index) bool { | 415 | fn invalidateSteps(maker: *Maker, steps: []const std.Build.Configuration.Step.Index) !bool { |
| 396 | var any_dirty = false; | 416 | var any_dirty = false; |
| 397 | for (steps) |step_index| { | 417 | for (steps) |step_index| { |
| 398 | const step = maker.stepByIndex(step_index); | 418 | const step = maker.stepByIndex(step_index); |
| 399 | if (maker.invalidateResult(step)) any_dirty = true; | 419 | if (try maker.invalidateResult(step)) any_dirty = true; |
| 400 | } | 420 | } |
| 401 | return any_dirty; | 421 | return any_dirty; |
| 402 | } | 422 | } |