auser-poolparty 0.2.71 → 0.2.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. data/History.txt +3 -0
  2. data/Manifest.txt +38 -81
  3. data/PostInstall.txt +1 -1
  4. data/README.txt +1 -0
  5. data/lib/erlang/messenger/Makefile +15 -0
  6. data/lib/erlang/messenger/lib/eunit/Makefile +28 -0
  7. data/lib/erlang/messenger/lib/eunit/ebin/autoload.beam +0 -0
  8. data/lib/erlang/messenger/lib/eunit/ebin/code_monitor.beam +0 -0
  9. data/lib/erlang/messenger/lib/eunit/ebin/eunit.beam +0 -0
  10. data/lib/erlang/messenger/lib/eunit/ebin/eunit_autoexport.beam +0 -0
  11. data/lib/erlang/messenger/lib/eunit/ebin/eunit_data.beam +0 -0
  12. data/lib/erlang/messenger/lib/eunit/ebin/eunit_lib.beam +0 -0
  13. data/lib/erlang/messenger/lib/eunit/ebin/eunit_proc.beam +0 -0
  14. data/lib/erlang/messenger/lib/eunit/ebin/eunit_serial.beam +0 -0
  15. data/lib/erlang/messenger/lib/eunit/ebin/eunit_server.beam +0 -0
  16. data/lib/erlang/messenger/lib/eunit/ebin/eunit_striptests.beam +0 -0
  17. data/lib/erlang/messenger/lib/eunit/ebin/eunit_test.beam +0 -0
  18. data/lib/erlang/messenger/lib/eunit/ebin/eunit_tests.beam +0 -0
  19. data/lib/erlang/messenger/lib/eunit/ebin/eunit_tty.beam +0 -0
  20. data/lib/erlang/messenger/lib/eunit/ebin/file_monitor.beam +0 -0
  21. data/lib/erlang/messenger/lib/eunit/src/Makefile +46 -0
  22. data/lib/poolparty/dependency_resolutions/puppet.rb +1 -0
  23. data/lib/poolparty/modules/resourcing_dsl.rb +5 -5
  24. data/lib/poolparty/plugins/deploydirectory.rb +1 -1
  25. data/lib/poolparty/pool/resource.rb +12 -3
  26. data/lib/poolparty/spec/core/string.rb +8 -2
  27. data/lib/poolparty/spec/matchers/a_spec_extensions_base.rb +3 -1
  28. data/lib/poolparty/spec/matchers/have_deploydirectory.rb +11 -11
  29. data/lib/poolparty/spec/matchers/have_gempackage.rb +1 -1
  30. data/lib/poolparty/version.rb +1 -1
  31. data/lib/poolpartyspec.rb +1 -3
  32. data/poolparty.gemspec +44 -87
  33. data/spec/poolparty/plugins/deploydirectory_spec.rb +1 -0
  34. data/spec/poolparty/pool/resource_spec.rb +13 -0
  35. data/spec/poolparty/spec/core/string_spec.rb +57 -0
  36. data/website/index.html +2 -2
  37. metadata +43 -86
  38. data/lib/erlang/messenger/lib/eunit/.svn/all-wcprops +0 -53
  39. data/lib/erlang/messenger/lib/eunit/.svn/entries +0 -140
  40. data/lib/erlang/messenger/lib/eunit/.svn/format +0 -1
  41. data/lib/erlang/messenger/lib/eunit/.svn/prop-base/NOTES.svn-base +0 -5
  42. data/lib/erlang/messenger/lib/eunit/.svn/text-base/AUTHORS.svn-base +0 -2
  43. data/lib/erlang/messenger/lib/eunit/.svn/text-base/CHANGELOG.svn-base +0 -14
  44. data/lib/erlang/messenger/lib/eunit/.svn/text-base/COPYING.svn-base +0 -504
  45. data/lib/erlang/messenger/lib/eunit/.svn/text-base/NOTES.svn-base +0 -276
  46. data/lib/erlang/messenger/lib/eunit/.svn/text-base/README.svn-base +0 -3
  47. data/lib/erlang/messenger/lib/eunit/.svn/text-base/sys.config.svn-base +0 -9
  48. data/lib/erlang/messenger/lib/eunit/.svn/text-base/vsn.mk.svn-base +0 -1
  49. data/lib/erlang/messenger/lib/eunit/doc/.svn/all-wcprops +0 -59
  50. data/lib/erlang/messenger/lib/eunit/doc/.svn/entries +0 -142
  51. data/lib/erlang/messenger/lib/eunit/doc/.svn/format +0 -1
  52. data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/erlang.png.svn-base +0 -5
  53. data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/eunit.html.svn-base +0 -5
  54. data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/index.html.svn-base +0 -5
  55. data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/modules-frame.html.svn-base +0 -5
  56. data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/overview-summary.html.svn-base +0 -5
  57. data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/packages-frame.html.svn-base +0 -5
  58. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/edoc-info.svn-base +0 -3
  59. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/erlang.png.svn-base +0 -0
  60. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/eunit.html.svn-base +0 -172
  61. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/index.html.svn-base +0 -17
  62. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/modules-frame.html.svn-base +0 -12
  63. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/overview-summary.html.svn-base +0 -984
  64. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/overview.edoc.svn-base +0 -980
  65. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/packages-frame.html.svn-base +0 -11
  66. data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/stylesheet.css.svn-base +0 -55
  67. data/lib/erlang/messenger/lib/eunit/ebin/.svn/all-wcprops +0 -5
  68. data/lib/erlang/messenger/lib/eunit/ebin/.svn/dir-prop-base +0 -8
  69. data/lib/erlang/messenger/lib/eunit/ebin/.svn/entries +0 -28
  70. data/lib/erlang/messenger/lib/eunit/ebin/.svn/format +0 -1
  71. data/lib/erlang/messenger/lib/eunit/examples/.svn/all-wcprops +0 -23
  72. data/lib/erlang/messenger/lib/eunit/examples/.svn/entries +0 -66
  73. data/lib/erlang/messenger/lib/eunit/examples/.svn/format +0 -1
  74. data/lib/erlang/messenger/lib/eunit/examples/.svn/prop-base/eunit_examples.erl.svn-base +0 -5
  75. data/lib/erlang/messenger/lib/eunit/examples/.svn/prop-base/fib.erl.svn-base +0 -5
  76. data/lib/erlang/messenger/lib/eunit/examples/.svn/text-base/eunit_examples.erl.svn-base +0 -339
  77. data/lib/erlang/messenger/lib/eunit/examples/.svn/text-base/fib.erl.svn-base +0 -19
  78. data/lib/erlang/messenger/lib/eunit/examples/.svn/text-base/tests.txt.svn-base +0 -1
  79. data/lib/erlang/messenger/lib/eunit/include/.svn/all-wcprops +0 -11
  80. data/lib/erlang/messenger/lib/eunit/include/.svn/entries +0 -41
  81. data/lib/erlang/messenger/lib/eunit/include/.svn/format +0 -1
  82. data/lib/erlang/messenger/lib/eunit/include/.svn/prop-base/eunit.hrl.svn-base +0 -5
  83. data/lib/erlang/messenger/lib/eunit/include/.svn/text-base/eunit.hrl.svn-base +0 -313
  84. data/lib/erlang/messenger/lib/eunit/src/.svn/all-wcprops +0 -113
  85. data/lib/erlang/messenger/lib/eunit/src/.svn/entries +0 -259
  86. data/lib/erlang/messenger/lib/eunit/src/.svn/format +0 -1
  87. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/autoload.erl.svn-base +0 -5
  88. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/code_monitor.erl.svn-base +0 -5
  89. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit.erl.svn-base +0 -5
  90. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_autoexport.erl.svn-base +0 -5
  91. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_data.erl.svn-base +0 -5
  92. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_internal.hrl.svn-base +0 -5
  93. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_lib.erl.svn-base +0 -5
  94. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_proc.erl.svn-base +0 -5
  95. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_serial.erl.svn-base +0 -5
  96. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_server.erl.svn-base +0 -5
  97. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_striptests.erl.svn-base +0 -5
  98. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_test.erl.svn-base +0 -5
  99. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_tests.erl.svn-base +0 -5
  100. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_tty.erl.svn-base +0 -5
  101. data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/file_monitor.erl.svn-base +0 -5
  102. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/autoload.erl.svn-base +0 -388
  103. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/code_monitor.erl.svn-base +0 -243
  104. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit.app.src.svn-base +0 -21
  105. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit.appup.src.svn-base +0 -1
  106. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit.erl.svn-base +0 -196
  107. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_autoexport.erl.svn-base +0 -102
  108. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_data.erl.svn-base +0 -798
  109. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_internal.hrl.svn-base +0 -48
  110. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_lib.erl.svn-base +0 -682
  111. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_proc.erl.svn-base +0 -552
  112. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_serial.erl.svn-base +0 -157
  113. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_server.erl.svn-base +0 -340
  114. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_striptests.erl.svn-base +0 -64
  115. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_test.erl.svn-base +0 -334
  116. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_tests.erl.svn-base +0 -45
  117. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_tty.erl.svn-base +0 -272
  118. data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/file_monitor.erl.svn-base +0 -409
@@ -1,409 +0,0 @@
1
- %% This library is free software; you can redistribute it and/or modify
2
- %% it under the terms of the GNU Lesser General Public License as
3
- %% published by the Free Software Foundation; either version 2 of the
4
- %% License, or (at your option) any later version.
5
- %%
6
- %% This library is distributed in the hope that it will be useful, but
7
- %% WITHOUT ANY WARRANTY; without even the implied warranty of
8
- %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9
- %% Lesser General Public License for more details.
10
- %%
11
- %% You should have received a copy of the GNU Lesser General Public
12
- %% License along with this library; if not, write to the Free Software
13
- %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
14
- %% USA
15
- %%
16
- %% $Id$
17
- %%
18
- %% @private (for now)
19
- %% @author Richard Carlsson <richardc@it.uu.se>
20
- %% @copyright 2006 Richard Carlsson
21
- %% @doc Erlang file monitoring service
22
-
23
- %% The behaviour of this service is inspired by the open source FAM
24
- %% daemon [http://oss.sgi.com/projects/fam/].
25
-
26
- -module(file_monitor).
27
-
28
- -export([start/0, start/1, start/2, stop/0, stop/1, monitor_file/2,
29
- monitor_file/3, monitor_dir/2, monitor_dir/3, demonitor/1,
30
- demonitor/2]).
31
-
32
- -export([main/1]). %% private
33
-
34
- -include_lib("kernel/include/file.hrl").
35
-
36
- -define(POLL_TIME, 5000). % default; change with option poll_time
37
- -define(SERVER, file_monitor).
38
-
39
- %% NOTE: paths should be absolute, but this is not checked
40
-
41
- %% We don't change the paths, e.g. from relative to absolute, but we
42
- %% make sure that the path is a flat string and return it to the caller.
43
-
44
- monitor_file(Path, Pid) ->
45
- monitor_file(?SERVER, Path, Pid).
46
-
47
- monitor_file(Server, Path, Pid) ->
48
- monitor(Server, file, filename:flatten(Path), Pid).
49
-
50
- monitor_dir(Path, Pid) ->
51
- monitor_dir(?SERVER, Path, Pid).
52
-
53
- monitor_dir(Server, Path, Pid) ->
54
- monitor(Server, dir, filename:flatten(Path), Pid).
55
-
56
- monitor(Server, Type, Path, Pid) when is_pid(Pid) ->
57
- {ok, Ref} = command(Server, {monitor, {Type, Path}, Pid}),
58
- {ok, Path, Ref}.
59
-
60
- demonitor(Ref) ->
61
- demonitor(?SERVER, Ref).
62
-
63
- demonitor(Server, Ref) ->
64
- ok = command(Server, {demonitor, Ref}).
65
-
66
-
67
- command(Server, Cmd) ->
68
- ServerPid = ensure_started(Server),
69
- ServerPid ! {command, self(), Cmd},
70
- receive
71
- {ServerPid, Result} -> Result
72
- end.
73
-
74
-
75
- stop() ->
76
- stop(?SERVER).
77
-
78
- stop(Server) ->
79
- Server ! stop,
80
- ok.
81
-
82
- ensure_started(Name) when is_atom(Name) ->
83
- start(Name, []);
84
- ensure_started(Pid) when is_pid(Pid) ->
85
- Pid.
86
-
87
- start() ->
88
- start([]).
89
-
90
- start(Options) ->
91
- start(?SERVER, Options).
92
-
93
- start(Name, Options) ->
94
- case whereis(Name) of
95
- undefined ->
96
- Parent = self(),
97
- Pid = spawn(fun () -> server_init(Name, Parent, Options) end),
98
- receive
99
- {Pid, ok} -> Pid;
100
- {Pid, error} -> throw(no_server)
101
- end;
102
- Pid -> Pid
103
- end.
104
-
105
- -record(state, {name, time, dirs, files, clients, refs}).
106
-
107
- server_init(undefined = Name, Parent, Options) ->
108
- %% anonymous server
109
- server_init_1(Name, Parent, Options);
110
- server_init(Name, Parent, Options) ->
111
- case catch register(Name, self()) of
112
- true ->
113
- server_init_1(Name, Parent, Options);
114
- _ ->
115
- Parent ! {self(), error},
116
- exit(failed)
117
- end.
118
-
119
- server_init_1(Name, Parent, Options) ->
120
- Parent ! {self(), ok},
121
- server(set_timer(init_state(Name, Options))).
122
-
123
- init_state(Name, Options) ->
124
- Time = case proplists:get_value(poll_time, Options) of
125
- N when is_integer(N), N >= 100 -> N;
126
- _ -> ?POLL_TIME
127
- end,
128
- #state{name = Name,
129
- time = Time,
130
- dirs = dict:new(),
131
- files = dict:new(),
132
- clients = dict:new(),
133
- refs = dict:new()}.
134
-
135
- server(St) -> ?MODULE:main(St).
136
-
137
- %% @private
138
- main(St) ->
139
- receive
140
- {command, From, {monitor, Object, Pid}} when is_pid(Pid) ->
141
- {Ref, St1} = new_monitor(Object, Pid, St),
142
- server_reply(From, {ok, Ref}),
143
- server(add_client(Pid, St1));
144
- {command, From, {demonitor, Ref}} ->
145
- server_reply(From, ok),
146
- server(delete_monitor(Ref, St));
147
- stop ->
148
- exit(normal);
149
- time ->
150
- server(set_timer(poll(St)));
151
- {'DOWN', _Ref, process, Pid, _Info} ->
152
- server(purge_pid(Pid, del_client(Pid, St)));
153
- _ ->
154
- server(St)
155
- end.
156
-
157
- server_reply(To, Msg) ->
158
- To ! {self(), Msg}.
159
-
160
- set_timer(St) ->
161
- erlang:send_after(St#state.time, self(), time),
162
- St.
163
-
164
-
165
- %% client monitoring (once a client, always a client - until death)
166
-
167
- add_client(Pid, St) ->
168
- case dict:is_key(Pid, St#state.clients) of
169
- true ->
170
- St;
171
- false ->
172
- Ref = erlang:monitor(process, Pid),
173
- St#state{clients = dict:store(Pid, Ref, St#state.clients)}
174
- end.
175
-
176
- del_client(Pid, St) ->
177
- case dict:find(Pid, St#state.clients) of
178
- {ok, Ref} ->
179
- erlang:demonitor(Ref, [flush]),
180
- St#state{clients = dict:erase(Pid, St#state.clients)};
181
- error ->
182
- St
183
- end.
184
-
185
-
186
- -record(monitor, {pid, reference}).
187
-
188
- -record(entry, {info = undefined, files = [], monitors = sets:new()}).
189
-
190
- new_monitor(Object, Pid, St) ->
191
- Ref = make_ref(),
192
- Monitor = #monitor{pid = Pid, reference = Ref},
193
- new_monitor(Object, Monitor, Ref,
194
- St#state{refs = dict:store(Ref, {Pid, Object},
195
- St#state.refs)}).
196
-
197
- %% We must separate the namespaces for files and dirs, since we can't
198
- %% trust the users to keep them distinct; there may be simultaneous file
199
- %% and dir monitors for the same path.
200
-
201
- new_monitor({file, Path}, Monitor, Ref, St) ->
202
- {Ref, St#state{files = add_monitor(Path, Monitor, file,
203
- St#state.files)}};
204
- new_monitor({dir, Path}, Monitor, Ref, St) ->
205
- {Ref, St#state{dirs = add_monitor(Path, Monitor, dir,
206
- St#state.dirs)}}.
207
-
208
- %% Adding a new monitor forces an immediate poll of the file, such that
209
- %% previous monitors only see any real change, while the new monitor
210
- %% either gets {exists, ...} or {error, ...}.
211
-
212
- add_monitor(Path, Monitor, Type, Dict) ->
213
- Entry = case dict:find(Path, Dict) of
214
- {ok, OldEntry} -> poll_file(Path, OldEntry, Type);
215
- error -> new_entry(Path, Type)
216
- end,
217
- event(#entry{}, dummy_entry(Entry, Monitor), Type, Path),
218
- NewEntry = Entry#entry{monitors =
219
- sets:add_element(Monitor,
220
- Entry#entry.monitors)},
221
- dict:store(Path, NewEntry, Dict).
222
-
223
- dummy_entry(Entry, Monitor) ->
224
- Entry#entry{monitors = sets:add_element(Monitor, sets:new())}.
225
-
226
- new_entry(Path, Type) ->
227
- refresh_entry(Path, #entry{monitors = sets:new()}, Type).
228
-
229
- %% deleting a monitor by reference
230
-
231
- delete_monitor(Ref, St) ->
232
- case dict:find(Ref, St#state.refs) of
233
- {ok, {_Pid, Object}} ->
234
- St1 = St#state{refs = dict:erase(Ref, St#state.refs)},
235
- delete_monitor_1(Ref, Object, St1);
236
- error ->
237
- St
238
- end.
239
-
240
- delete_monitor_1(Ref, {file, Path}, St) ->
241
- St#state{files = delete_monitor_2(Path, Ref, St#state.files)};
242
- delete_monitor_1(Ref, {dir, Path}, St) ->
243
- St#state{dirs = delete_monitor_2(Path, Ref, St#state.dirs)}.
244
-
245
- delete_monitor_2(Path, Ref, Dict) ->
246
- case dict:find(Path, Dict) of
247
- {ok, Entry} ->
248
- purge_empty_sets(
249
- dict:store(Path, purge_monitor_ref(Ref, Entry), Dict));
250
- error ->
251
- Dict
252
- end.
253
-
254
- purge_monitor_ref(Ref, Entry) ->
255
- Entry#entry{monitors =
256
- sets:filter(fun (#monitor{reference = R})
257
- when R == Ref -> false;
258
- (_) -> true
259
- end,
260
- Entry#entry.monitors)}.
261
-
262
- %% purging monitors belonging to dead clients
263
-
264
- purge_pid(Pid, St) ->
265
- Files = dict:map(fun (_Path, Entry) ->
266
- purge_monitor_pid(Pid, Entry)
267
- end,
268
- St#state.files),
269
- Dirs = dict:map(fun (_Path, Entry) ->
270
- purge_monitor_pid(Pid, Entry)
271
- end,
272
- St#state.dirs),
273
- Refs = dict:filter(fun (_Ref, {P, _})
274
- when P == Pid -> false;
275
- (_, _) -> true
276
- end,
277
- St#state.refs),
278
- St#state{refs = Refs,
279
- files = purge_empty_sets(Files),
280
- dirs = purge_empty_sets(Dirs)}.
281
-
282
- purge_monitor_pid(Pid, Entry) ->
283
- Entry#entry{monitors =
284
- sets:filter(fun (#monitor{pid = P})
285
- when P == Pid -> false;
286
- (_) -> true
287
- end,
288
- Entry#entry.monitors)}.
289
-
290
- purge_empty_sets(Dict) ->
291
- dict:filter(fun (_Path, Entry) ->
292
- sets:size(Entry#entry.monitors) > 0
293
- end, Dict).
294
-
295
-
296
- %% generating events upon state changes
297
-
298
- %% Message formats:
299
- %% {exists, Path, Type, #file_info{}, Files}
300
- %% {changed, Path, Type, #file_info{}, Files}
301
- %% {error, Path, Type, Info}
302
- %%
303
- %% Type is dir or file. If Type is file, Files is always []. If Type is
304
- %% dir, Files is a list of {added, FileName} and {deleted, FileName},
305
- %% where FileName is relative to dir, without any path component.
306
- %%
307
- %% When a new monitor is installed for a path, an initial {exists,...}
308
- %% or {error,...} message will be sent to the monitor owner.
309
- %%
310
- %% Subsequent events will be either {changed,...} or {error,...}.
311
-
312
- event(#entry{info = Info}, #entry{info = Info}, _Type, _Path) ->
313
- %% no change in state
314
- ok;
315
- event(#entry{info = undefined}, #entry{info = NewInfo}=Entry,
316
- Type, Path)
317
- when not is_atom(NewInfo) ->
318
- %% file or directory exists, for a fresh monitor
319
- Files = [{added, F} || F <- Entry#entry.files],
320
- cast({exists, Path, Type, NewInfo, Files}, Entry#entry.monitors);
321
- event(_OldEntry, #entry{info = NewInfo}=Entry, Type, Path)
322
- when is_atom(NewInfo) ->
323
- %% file is not available
324
- cast({error, Path, Type, NewInfo}, Entry#entry.monitors);
325
- event(_OldEntry, Entry, file, Path) ->
326
- %% a normal file has changed
327
- cast({changed, Path, file, Entry#entry.info, []},
328
- Entry#entry.monitors);
329
- event(#entry{info = OldInfo}, #entry{info = NewInfo}=Entry, dir, Path)
330
- when is_atom(OldInfo) ->
331
- %% a directory has suddenly become available
332
- Files = [{added, F} || F <- Entry#entry.files],
333
- cast({changed, Path, dir, NewInfo, Files}, Entry#entry.monitors);
334
- event(OldEntry, #entry{info = NewInfo}=Entry, dir, Path) ->
335
- %% a directory has changed
336
- Files = diff_lists(Entry#entry.files, OldEntry#entry.files),
337
- cast({changed, Path, dir, NewInfo, Files}, Entry#entry.monitors).
338
-
339
-
340
- poll(St) ->
341
- St#state{files = dict:map(fun (Path, Entry) ->
342
- poll_file(Path, Entry, file)
343
- end,
344
- St#state.files),
345
- dirs = dict:map(fun (Path, Entry) ->
346
- poll_file(Path, Entry, dir)
347
- end,
348
- St#state.dirs)}.
349
-
350
- poll_file(Path, Entry, Type) ->
351
- NewEntry = refresh_entry(Path, Entry, Type),
352
- event(Entry, NewEntry, Type, Path),
353
- NewEntry.
354
-
355
- refresh_entry(Path, Entry, Type) ->
356
- Info = get_file_info(Path),
357
- Files = case Type of
358
- dir when not is_atom(Info) -> get_dir_files(Path);
359
- _ -> []
360
- end,
361
- Entry#entry{info = Info, files = Files}.
362
-
363
-
364
- %% We clear some fields of the file_info so that we only trigger on real
365
- %% changes; see the //kernel/file.erl manual and file.hrl for details.
366
-
367
- get_file_info(Path) ->
368
- case file:read_file_info(Path) of
369
- {ok, Info} ->
370
- Info#file_info{access = undefined,
371
- atime = undefined};
372
- {error, Error} ->
373
- Error % posix error code as atom
374
- end.
375
-
376
- %% Listing the members of a directory; note that it yields the empty
377
- %% list if it fails - this is not the place for error detection.
378
-
379
- get_dir_files(Path) ->
380
- case file:list_dir(Path) of
381
- {ok, Files} -> lists:sort(Files);
382
- {error, _} -> []
383
- end.
384
-
385
- %% both lists must be sorted for this diff to work
386
-
387
- diff_lists([F1 | Fs1], [F2 | _]=Fs2) when F1 < F2 ->
388
- [{added, F1} | diff_lists(Fs1, Fs2)];
389
- diff_lists([F1 | _]=Fs1, [F2 | Fs2]) when F1 > F2 ->
390
- [{deleted, F2} | diff_lists(Fs1, Fs2)];
391
- diff_lists([_ | Fs1], [_ | Fs2]) ->
392
- diff_lists(Fs1, Fs2);
393
- diff_lists([F | Fs1], Fs2) ->
394
- [{added, F} | diff_lists(Fs1, Fs2)];
395
- diff_lists(Fs1, [F | Fs2]) ->
396
- [{deleted, F} | diff_lists(Fs1, Fs2)];
397
- diff_lists([], []) ->
398
- [].
399
-
400
-
401
- %% Multicasting events to clients
402
-
403
- cast(Msg, Monitors) ->
404
- sets:fold(fun (#monitor{pid = Pid, reference = Ref}, Msg) ->
405
- %%erlang:display({file_monitor, Ref, Msg}),
406
- Pid ! {file_monitor, Ref, Msg},
407
- Msg % note that this is a fold, not a map
408
- end,
409
- Msg, Monitors).