| ... | ... | @@ -46,6 +46,8 @@ since_event: FSEventStreamEventId, |
| 46 | 46 | |
| 47 | 47 | cwd_path: []const u8, |
| 48 | 48 | |
| 49 | must_reconfigure: bool, |
| 50 | |
| 49 | 51 | /// All of the symbols we pull from the `dlopen`ed CoreServices framework. If any of these symbols |
| 50 | 52 | /// is not present, `init` will close the framework and return an error. |
| 51 | 53 | const ResolvedSymbols = struct { |
| ... | ... | @@ -104,13 +106,15 @@ pub fn init(cwd_path: []const u8) error{ OpenFrameworkFailed, MissingCoreService |
| 104 | 106 | // to notice any changes which happened during said work. |
| 105 | 107 | .since_event = resolved_symbols.FSEventsGetCurrentEventId(), |
| 106 | 108 | .cwd_path = cwd_path, |
| 109 | .must_reconfigure = false, |
| 107 | 110 | }; |
| 108 | 111 | } |
| 109 | 112 | |
| 110 | 113 | pub fn deinit(fse: *FsEvents, gpa: Allocator, io: Io) void { |
| 114 | _ = io; |
| 111 | 115 | fse.waiting_semaphore.as_object().release(); |
| 112 | 116 | fse.dispatch_queue.as_object().release(); |
| 113 | | fse.core_services.close(io); |
| 117 | fse.core_services.close(); |
| 114 | 118 | |
| 115 | 119 | gpa.free(fse.watch_roots); |
| 116 | 120 | fse.watch_paths.deinit(gpa); |
| ... | ... | @@ -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 | 219 | if (fse.watch_roots.len == 0) @panic("nothing to watch"); |
| 216 | 220 | const gpa = maker.gpa; |
| 217 | 221 | |
| ... | ... | @@ -285,6 +289,7 @@ pub fn wait(fse: *FsEvents, maker: *Maker, timeout_ns: ?u64) error{ OutOfMemory, |
| 285 | 289 | const ns = timeout_ns orelse break :timeout .FOREVER; |
| 286 | 290 | break :timeout .time(.NOW, @intCast(ns)); |
| 287 | 291 | }); |
| 292 | if (fse.must_reconfigure) return error.MustReconfigure; |
| 288 | 293 | return switch (result) { |
| 289 | 294 | 0 => .dirty, |
| 290 | 295 | else => .timeout, |
| ... | ... | @@ -355,13 +360,23 @@ fn eventCallback( |
| 355 | 360 | false => { |
| 356 | 361 | if (fse.watch_paths.get(event_path)) |steps| { |
| 357 | 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 | 370 | if (std.fs.path.dirname(event_path)) |event_dirname| { |
| 361 | 371 | // Modifying '/foo/bar' triggers the watch on '/foo'. |
| 362 | 372 | if (fse.watch_paths.get(event_dirname)) |steps| { |
| 363 | 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 | 389 | const changed_path = std.fs.path.dirname(event_path) orelse event_path; |
| 375 | 390 | for (fse.watch_paths.keys(), fse.watch_paths.values()) |watching_path, steps| { |
| 376 | 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 | 404 | fse.since_event = rs.FSEventStreamGetLatestEventId(stream); |
| 385 | 405 | _ = fse.waiting_semaphore.signal(); |
| 386 | 406 | } |
| ... | ... | @@ -392,11 +412,11 @@ fn dirStartsWith(path: []const u8, prefix: []const u8) bool { |
| 392 | 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 | 416 | var any_dirty = false; |
| 397 | 417 | for (steps) |step_index| { |
| 398 | 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 | 421 | return any_dirty; |
| 402 | 422 | } |