1:- module(automake, [automake/0, 2 noautomake/0]). 3 4:- use_module(library(debug), [debug/3]). 5:- use_module(library(make), [make/0]). 6:- use_module(library(time), [alarm/3, remove_alarm/1]). 7 8:- use_foreign_library(foreign(watchdir4pl)). 9 10:- dynamic watches/2. 11 12automake :- 13 noautomake, 14 dir_monitor_init(Monitor), 15 add_new_source_files(Monitor), 16 thread_create(handle_file_changed(Monitor), _, [alias(automake)]). 17 18noautomake :- 19 retractall(watches(_, _)), 20 catch(thread_send_message(automake, done, [timeout(0)]), 21 error(existence_error(_ThreadOrMessageQueue, automake), _), 22 fail), !, 23 thread_join(automake, _). 24noautomake. 25 26handle_file_changed(Monitor) :- 27 dir_monitor_read(Monitor, Event, 0.5), !, 28 catch(handle_event(Event, Monitor), 29 Err, 30 debug(automake, "Error handling event ~w: ~w", [Event, Err])), 31 handle_file_changed(Monitor). 32handle_file_changed(Monitor) :- 33 thread_get_message(automake, _, [timeout(0)]), !, 34 dir_monitor_stop(Monitor). 35handle_file_changed(Monitor) :- 36 add_new_source_files(Monitor), 37 handle_file_changed(Monitor). 38 39:- dynamic make_alarm/1. 40 41handle_event(watchdir(modified, _, _), _) :- 42 maybe_cancel_make, 43 alarm(0.2, do_make, Alarm), 44 assertz(make_alarm(Alarm)). 45handle_event(Event, _) :- 46 debug(automake(debug), "Unknown event ~w", [Event]). 47 48do_make :- 49 retractall(make_alarm(_)), 50 catch(make, Err, 51 debug(automake, "Error making: ~w", [Err])). 52 53maybe_cancel_make :- 54 make_alarm(Alarm), !, 55 debug(automake(debug), "Cancelling alarm ~w", [Alarm]), 56 remove_alarm(Alarm), 57 retractall(make_alarm(Alarm)). 58maybe_cancel_make. 59 60add_new_source_files(Monitor) :- 61 forall(source_file(File), 62 ( maybe_add_watch(Monitor, File) )). 63 64maybe_add_watch(Monitor, Path) :- 65 watches(Path, _) 66 -> true 67 ; ( debug(automake, "Adding watch for ~w", [Path]), 68 exists_file(Path) 69 -> ( dir_monitor_add(Monitor, Path, W), 70 assertz(watches(Path, W)) ) 71 ; true )