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    catch(thread_send_message(automake, done, [timeout(0)]),
   20          error(existence_error(message_queue, automake), _),
   21          fail), !,
   22    thread_join(automake, _).
   23noautomake.
   24
   25handle_file_changed(Monitor) :-
   26    dir_monitor_read(Monitor, Event, 0.5), !,
   27    catch(handle_event(Event, Monitor),
   28         Err,
   29         debug(automake, "Error handling event ~w: ~w", [Event, Err])),
   30    handle_file_changed(Monitor).
   31handle_file_changed(Monitor) :-
   32    thread_get_message(automake, _, [timeout(0)]), !,
   33    dir_monitor_stop(Monitor).
   34handle_file_changed(Monitor) :-
   35    add_new_source_files(Monitor),
   36    handle_file_changed(Monitor).
   37
   38:- dynamic make_alarm/1.   39
   40handle_event(watchdir(modified, _, _), _) :-
   41    maybe_cancel_make,
   42    alarm(0.2, do_make, Alarm),
   43    assertz(make_alarm(Alarm)).
   44handle_event(Event, _) :-
   45    debug(automake(debug), "Unknown event ~w", [Event]).
   46
   47% [TODO] Run hooks
   48do_make :-
   49    retractall(make_alarm(_)),
   50    make.
   51
   52maybe_cancel_make :-
   53    make_alarm(Alarm), !,
   54    debug(automake(debug), "Cancelling alarm ~w", [Alarm]),
   55    remove_alarm(Alarm),
   56    retractall(make_alarm(Alarm)).
   57maybe_cancel_make.
   58
   59add_new_source_files(Monitor) :-
   60    forall(source_file(File),
   61           ( maybe_add_watch(Monitor, File) )).
   62
   63maybe_add_watch(Monitor, Path) :-
   64    watches(Path, _)
   65    -> true
   66    ; ( debug(automake, "Adding watch for ~w", [Path]),
   67        exists_file(Path)
   68      -> ( dir_monitor_add(Monitor, Path, W),
   69           assertz(watches(Path, W)) )
   70      ; true )