source: trunk/src/directory_watcher.erl @ 81

Revision 81, 3.5 KB checked in by dom, 3 years ago (diff)

Refactoring.

Line 
1%%% Copyright (C) Dominic Williams
2%%% All rights reserved.
3%%% See file COPYING.
4
5-module (directory_watcher).
6-export ([init/2]).
7-export ([init_recursive/2]).
8-include_lib ("kernel/include/file.hrl").
9
10init (Directory, F) ->
11    D = filename: absname (Directory),
12    check (D, F, dict: new ()).
13
14init_recursive (Directory, F) ->
15    D = filename: absname (Directory),
16    Self = self (),
17    Watcher = spawn_link (?MODULE, init, [D, send (Self)]),
18    loop_recursive (D, F, [Watcher]).
19
20check (Directory, F, State) ->
21    New_state = list_dir (Directory, F),
22    compare (F, State, New_state),
23    loop (Directory, F, New_state).
24
25list_dir (Directory, F) ->
26    list_dir (Directory, F, file: list_dir (Directory)).
27
28list_dir (Directory, _, {ok, Filenames}) ->
29    Paths = [filename: join (Directory, F) || F <- Filenames],
30    read_state (Paths);
31list_dir (Directory, F, Error) ->
32    F ({directory, Directory, Error}),
33    dict: new ().
34
35read_state (Filenames) ->
36    lists: foldl (fun read_state/2, dict: new (), Filenames).
37
38read_state (File_name, State) ->
39    case file: read_file_info (File_name) of
40        {ok, Info} ->
41            Value = value (Info#file_info.type, File_name),
42            dict: store (File_name, Value, State);
43        _ ->
44            State
45    end.
46
47value (regular, Filename) ->
48    {ok, Content} = file: read_file (Filename),
49    {regular, erlang: md5 (Content)};
50value (directory, _) ->
51    directory.
52
53loop (Directory, F, Filenames) ->
54    receive
55        check ->
56            check (Directory, F, Filenames);
57        stop ->
58            F (bye)
59    end.
60
61loop_recursive (Directory, F, Watchers) ->
62    receive
63        {?MODULE, _, {directory, Dir, found}=Event} ->
64            Self = self (),
65            Watcher = spawn_link (?MODULE, init, [Dir, send (Self)]),
66            F (Event),
67            loop_recursive (Directory, F, [Watcher | Watchers]);
68        {?MODULE, Watcher, {directory, _, {error, _}}} ->
69            Watcher ! stop,
70            loop_recursive (Directory, F, Watchers -- [Watcher]);
71        {?MODULE, _, bye} ->
72            loop_recursive (Directory, F, Watchers);
73        {?MODULE, _, Event} ->
74            F (Event),
75            loop_recursive (Directory, F, Watchers);
76        check ->
77            lists: foreach (fun (P) -> P ! check end, Watchers),
78            loop_recursive (Directory, F, Watchers);
79        stop ->
80            F (bye)
81    end.
82
83compare (F, Original, Modified) ->
84    Compared = adlib: compare_dict (Modified, Original),
85    dict: fold (fun notify_new/3, F, dict: fetch (new, Compared)),
86    dict: fold (fun notify_lost/3, F, dict: fetch (lost, Compared)),
87    dict: fold (fun notify_changed/3, F, dict: fetch (changed, Compared)),
88    done.
89   
90notify_new (File_name, _, Fun) ->
91    report_found (Fun, File_name),
92    Fun.
93
94report_found (F, Filename) ->
95    F ({type (Filename), Filename, found}).
96
97notify_lost (File_name, Value, Fun) ->
98    report_lost (Fun, {File_name, Value}),
99    Fun.
100
101report_lost (F, {Filename, directory}) ->
102    F ({directory, Filename, lost});
103report_lost (F, {Filename, {regular, _}}) ->
104    F ({{file, filename: extension (Filename)}, Filename, lost}).
105
106notify_changed (File_name, {{regular, _}, {regular, _}}, Fun) ->
107    report_changed (Fun, File_name),
108    Fun;
109notify_changed (File_name, {_, Original}, Fun) ->
110    report_lost (Fun, {File_name, Original}),
111    report_found (Fun, File_name),
112    Fun.
113
114report_changed (F, Filename) ->
115    F ({type (Filename), Filename, changed}).
116   
117type (Path) ->
118    type (file: read_file_info (Path), Path).
119
120type ({ok, #file_info{type=directory}}, _) ->
121    directory;
122type ({ok, #file_info{type=regular}}, Path) ->
123    {file, filename: extension (Path)}.
124
125send (Pid) ->
126    fun (Event) ->
127            Pid ! {?MODULE, self (), Event}
128    end.
129
Note: See TracBrowser for help on using the repository browser.