source: trunk/src/compiler.erl @ 95

Revision 95, 4.2 KB checked in by dom, 2 years ago (diff)

Two improvements (and new start API): multiple directories watched, and slave started if no node given

Line 
1%%% Copyright (C) Dominic Williams
2%%% All rights reserved.
3%%% See file COPYING.
4
5-module (compiler).
6-export ([init/2]).
7-export ([init/3]).
8-export ([reset_includes/2]).
9
10init (Notify, Dirs) ->
11    init (Notify, Dirs, []).
12
13init (Notify, Dirs, Options) ->
14    Watchers = lists: foldl (fun watcher/2, [], Dirs),
15    Includes = [{i, D} || D <- Dirs],
16    State = {dict: new (), dict: new (), [], [], Includes ++ Options},
17    loop (Notify, Watchers, State).
18
19watcher (Dir, Acc) ->
20    Args = [Dir, notify_me ()],
21    Watcher = spawn_link (directory_watcher, init_recursive, Args),
22    [Watcher | Acc].
23   
24loop (Notify, Watchers, State) ->
25    receive
26        check ->
27            [W ! check || W <- Watchers],
28            {Modules, Includes, Binaries, Removed, Options} = State,
29            Received = receive_files (Modules, Includes),
30            {New_modules, New_includes} = Received,
31            New_options = reset_includes (New_includes, Options),
32            New_state = {New_modules, New_includes, Binaries,
33                         Removed, New_options},
34            Last_state =
35                if
36                    New_modules /= Modules ->
37                        compile (Notify, New_state);
38                    true ->
39                        New_state
40                end,
41            loop (Notify, Watchers, Last_state);
42        {Pid, stop} ->
43            Pid ! {self (), bye}
44    end.
45
46receive_files (Modules, Includes) ->
47%%          Includes = sets: from_list ([D || {i, D} <- Options]),
48    receive
49        {watcher, {{file, ".erl"}, File, Event}} ->
50            receive_files (dict: store (File, Event, Modules), Includes);
51        {watcher, {{file, ".hrl"}, File, Event}} ->
52            receive_files (Modules, dict: store (File, Event, Includes));
53        {watcher, _} ->
54            receive_files (Modules, Includes)
55    after 500 ->
56            {Modules, Includes}
57    end.
58
59compile (Notify, State) ->
60    {Modules, _, _, _, _} = State,
61    Notify (totals (Modules)),
62    Process = process_fun (Notify),
63    Processed = dict: fold (Process, State, Modules),
64    notify_end (Notify, Processed).
65
66reset_includes (Dict, Options) ->
67    dict: fold (fun reset_includes/3, Options, Dict).
68
69reset_includes (File, found, Options) ->
70    Is_include = fun ({i, _}) -> true; (_) -> false end,
71    {Includes, Other} = lists: partition (Is_include, Options),
72    Dirs = sets: from_list ([D || {i, D} <- Includes]),
73    Dir = filename: dirname (File),
74    New_dirs = sets: add_element (Dir, Dirs),
75    New_includes = [{i, D} || D <- sets: to_list (New_dirs)],
76    Other ++ New_includes;
77reset_includes (_, _, Options) ->
78    Options.
79
80process_fun (Notify) ->
81    fun (File, Event, Acc) when Event == found; Event == changed ->
82            {Modules, Includes, Binaries, Removed, Options} = Acc,
83            Result = modules: compile (File, Options),
84            notify_result (Result, Notify),
85            New_modules = dict: store (File, Result, Modules),
86            Notify (totals (New_modules)),
87            New_binaries = binaries (Result, Binaries),
88            {New_modules, Includes, New_binaries, Removed, Options};
89        (File, Event, Acc) when Event == lost ->
90            {Modules, Includes, Binaries, Removed, Options} = Acc,
91            New_modules = dict: erase (File, Modules),
92            New_removed = [modules: module_name (File) | Removed],
93            {New_modules, Includes, Binaries, New_removed, Options};
94        (_, _, Acc) ->
95            Acc
96    end.
97
98notify_me () ->
99    Self = self (),
100    fun (E) -> Self ! {watcher, E} end.
101           
102totals (Modules) ->
103    dict: fold (fun count/3, {0, 0, 0}, Modules).
104
105count (_, lost, Acc) ->
106    Acc;
107count (_, {ok, _, _, _}, {Total, Compiled, Successful}) ->
108    {Total + 1, Compiled + 1, Successful + 1};
109count (_, {error, _, _}, {Total, Compiled, Successful}) ->
110    {Total + 1, Compiled + 1, Successful};
111count (_, _, {Total, Compiled, Successful}) ->
112    {Total + 1, Compiled, Successful}.
113   
114notify_result ({ok, _, _, []}, _) ->
115    pass;
116notify_result ({ok, _, _, Warnings}, Notify) ->
117    Notify ({[], Warnings});
118notify_result ({error, Errors, Warnings},Notify) ->
119    Notify ({Errors, Warnings}).
120
121binaries ({ok, _, B, _}, Bs) ->
122    [B | Bs];
123binaries ({error, _, _}, Bs) ->
124    Bs.
125
126notify_end (Notify, State) ->
127    {Modules, _,  _, _, _} = State,
128    notify_end (Notify, totals (Modules), State).
129
130notify_end (Notify, {N, N, N}, {Modules, Includes, Binaries, Removed, Options}) ->
131    Notify ({{binaries, Binaries}, {removed, Removed}}),
132    {Modules, Includes, [], [], Options};
133notify_end (_, _, State) ->
134    State.
Note: See TracBrowser for help on using the repository browser.