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 )