diff --git a/rebar.config b/rebar.config index 5e00a59..7a0d428 100644 --- a/rebar.config +++ b/rebar.config @@ -13,7 +13,7 @@ {deps, [ nova, - enotify + fs ]}. {xref_checks, [ diff --git a/rebar.lock b/rebar.lock index 4f166bb..35c0ca0 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,32 +1,32 @@ {"1.2.0", [{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.18.0">>},1}, {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.19.0">>},2}, - {<<"enotify">>,{pkg,<<"enotify">>,<<"0.1.0">>},0}, {<<"erlydtl">>,{pkg,<<"erlydtl">>,<<"0.14.0">>},1}, + {<<"fs">>,{pkg,<<"fs">>,<<"11.4.1">>},0}, {<<"jhn_stdlib">>,{pkg,<<"jhn_stdlib">>,<<"5.11.2">>},1}, {<<"nova">>,{pkg,<<"nova">>,<<"0.15.3">>},0}, - {<<"ranch">>,{pkg,<<"ranch">>,<<"2.2.0">>},2}, + {<<"ranch">>,{pkg,<<"ranch">>,<<"2.2.1">>},2}, {<<"routing_tree">>,{pkg,<<"routing_tree">>,<<"1.0.11">>},1}, {<<"thoas">>,{pkg,<<"thoas">>,<<"1.2.1">>},1}]}. [ {pkg_hash,[ {<<"cowboy">>, <<"BFF388EB4D6356CB3F88C26E65B515976BF04B401B805D31550C3E60EBA8FE18">>}, {<<"cowlib">>, <<"C9D11C9D035472E27A740C9F327786C61ED209269B4BE0260D59D3EC07B8949F">>}, - {<<"enotify">>, <<"F6BF33AA7BC4789D953087E48C6ADBC6D9682B6D67E4BC353C2FDB96C5AC5595">>}, {<<"erlydtl">>, <<"964B2DC84F8C17ACFAA69C59BA129EF26AC45D2BA898C3C6AD9B5BDC8BA13CED">>}, + {<<"fs">>, <<"11FB3153BB2E1DE851B8263BB5698D526894853C73A525EBEB5E69108B2D25CD">>}, {<<"jhn_stdlib">>, <<"785074F3CA368EAA8E9AF1592BC19AE9EF1F7AF30B2CD6456A6083173A8F5CCB">>}, {<<"nova">>, <<"E5DB638900796822406947746110A48D48023B7F9345074522D6F59E9E13CF80">>}, - {<<"ranch">>, <<"25528F82BC8D7C6152C57666CA99EC716510FE0925CB188172F41CE93117B1B0">>}, + {<<"ranch">>, <<"FC2BB0E800EFBEAB8FF82EB325450B9C08653B14C3F69E8B09BBEA304973105D">>}, {<<"routing_tree">>, <<"72ACEF2095F0EC804F7AFD07EF781DDE5009425A1CA0A28F0706B1DB334A4812">>}, {<<"thoas">>, <<"19A25F31177A17E74004D4840F66D791D4298C5738790FA2CC73731EB911F195">>}]}, {pkg_hash_ext,[ {<<"cowboy">>, <<"62D0B26ABCF455054972B0DA242389C69D5982CE5914AFB8C344517F667B9600">>}, {<<"cowlib">>, <<"6DC66E3135B229193EA4DCB14294E79520C923D391315C9C962EF0B4BEA72356">>}, - {<<"enotify">>, <<"8E48DA763CE15BFD75CC857DDFE5011B03189D597F47BCDD8ACC6FBBE8E6B6F4">>}, {<<"erlydtl">>, <<"D80EC044CD8F58809C19D29AC5605BE09E955040911B644505E31E9DD8143431">>}, + {<<"fs">>, <<"DD00A61D89EAC01D16D3FC51D5B0EB5F0722EF8E3C1A3A547CD086957F3260A9">>}, {<<"jhn_stdlib">>, <<"2329CD16DEE46704AAB6184D09508E59DBA31C4D3255271DBB7D34D115ECA508">>}, {<<"nova">>, <<"95243B184DA37C6B40C15BD2B7531B520C35D9EFB85F8773134DB0A85B587F20">>}, - {<<"ranch">>, <<"FA0B99A1780C80218A4197A59EA8D3BDAE32FBFF7E88527D7D8A4787EFF4F8E7">>}, + {<<"ranch">>, <<"55F05CCE20EC2DA1D90DE5D5981AFB93DBFC01325FC7E933189AA5C62F037C24">>}, {<<"routing_tree">>, <<"85982C7AC502892C5179CD2A591331003BACD2D2A71723640BA7D23F45408E6E">>}, {<<"thoas">>, <<"E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A">>}]} ]. diff --git a/src/rebar3_nova.app.src b/src/rebar3_nova.app.src index 337a7b5..84597a0 100644 --- a/src/rebar3_nova.app.src +++ b/src/rebar3_nova.app.src @@ -7,7 +7,7 @@ stdlib, nova, routing_tree, - enotify + fs ]}, {env, []}, {modules, []}, diff --git a/src/rebar3_nova_serve.erl b/src/rebar3_nova_serve.erl index 07db2b8..c879769 100644 --- a/src/rebar3_nova_serve.erl +++ b/src/rebar3_nova_serve.erl @@ -13,7 +13,8 @@ -export([ auto/0, - flush/0 + flush/0, + watch_dirs/1 ]). -define(PROVIDER, serve). @@ -81,7 +82,7 @@ do(State) -> auto() -> receive - {ChangedFile, _Events} -> + {_Pid, {fs, file_event}, {ChangedFile, _Events}} -> Ext = filename:extension(unicode:characters_to_binary(ChangedFile)), IsValid = lists:any( fun(ValidExt) -> @@ -122,25 +123,34 @@ listen_on_project_apps(State) -> rebar_app_info:is_checkout(AppInfo) == true ], ProjectApps = rebar_state:project_apps(State), - lists:foreach( - fun(AppInfo) -> - SrcDir = filename:join(rebar_app_info:dir(AppInfo), "src"), - ViewsDir = filename:join(SrcDir, "views"), - CtrlDir = filename:join(SrcDir, "controllers"), - PrivDir = filename:join(rebar_app_info:dir(AppInfo), "priv"), - CSrcDir = filename:join(rebar_app_info:dir(AppInfo), "c_src"), - lists:foreach( - fun(Dir) -> - case filelib:is_dir(Dir) of - true -> enotify:start_link(Dir); - false -> ignore - end - end, - [SrcDir, ViewsDir, CtrlDir, PrivDir, CSrcDir] - ) - end, - ProjectApps ++ CheckoutDeps - ). + Dirs = [ + Dir + || AppInfo <- ProjectApps ++ CheckoutDeps, + Dir <- watch_dirs(rebar_app_info:dir(AppInfo)), + filelib:is_dir(Dir) + ], + lists:foreach(fun watch/1, lists:enumerate(Dirs)). + +watch_dirs(AppDir) -> + SrcDir = filename:join(AppDir, "src"), + [ + SrcDir, + filename:join(SrcDir, "views"), + filename:join(SrcDir, "controllers"), + filename:join(AppDir, "priv"), + filename:join(AppDir, "c_src") + ]. + +%% Each watched directory needs its own fs backend, and fs registers the +%% event manager under the name we hand it. +watch({N, Dir}) -> + Name = list_to_atom("nova_fs_" ++ integer_to_list(N)), + case fs:start_link(Name, Dir) of + {ok, _Pid} -> + fs:subscribe(Name); + {error, Reason} -> + rebar_api:warn("Not watching ~ts for changes: ~p", [Dir, Reason]) + end. remove_from_plugin_paths(State) -> PluginPaths = rebar_state:code_paths(State, all_plugin_deps), @@ -148,7 +158,7 @@ remove_from_plugin_paths(State) -> fun(Path) -> Name = filename:basename(Path, "/ebin"), not (list_to_atom(Name) =:= rebar_auto_plugin orelse - list_to_atom(Name) =:= enotify) + list_to_atom(Name) =:= fs) end, PluginPaths ), diff --git a/test/rebar3_nova_serve_SUITE.erl b/test/rebar3_nova_serve_SUITE.erl new file mode 100644 index 0000000..63e5799 --- /dev/null +++ b/test/rebar3_nova_serve_SUITE.erl @@ -0,0 +1,23 @@ +-module(rebar3_nova_serve_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). + +-export([all/0]). +-export([watch_dirs_covers_sources_and_views/1]). + +all() -> + [watch_dirs_covers_sources_and_views]. + +watch_dirs_covers_sources_and_views(_Config) -> + ?assertEqual( + [ + "/app/src", + "/app/src/views", + "/app/src/controllers", + "/app/priv", + "/app/c_src" + ], + rebar3_nova_serve:watch_dirs("/app") + ), + ok.