Skip to content

Commit 97be9bb

Browse files
authored
Merge pull request #26 from clojerl/compile-files-first-option
Adapt plugin to be able to compile Clojerl with it
2 parents 4478b82 + 6d37278 commit 97be9bb

File tree

5 files changed

+98
-90
lines changed

5 files changed

+98
-90
lines changed

src/rebar3_clojerl.erl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ init(State) ->
77
Commands = [ fun rebar3_clojerl_prv_compile:init/1
88
, fun rebar3_clojerl_prv_test:init/1
99
, fun rebar3_clojerl_prv_repl:init/1
10-
, fun rebar3_clojerl_prv_release:init/1
1110
],
1211
FoldFun = fun(F, {ok, StateAcc}) -> F(StateAcc) end,
1312
lists:foldl(FoldFun, {ok, State}, Commands).

src/rebar3_clojerl_prv_compile.erl

Lines changed: 74 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
-define(PROVIDER, compile).
88
-define(NAMESPACE, clojerl).
9-
-define(DEPS, [{default, compile}]).
9+
-define(DEPS, [{default, lock}]).
1010

1111
-type config() :: #{ ebin_dir => file:name()
1212
, protocols_dir => file:name()
@@ -34,17 +34,29 @@ init(State) ->
3434

3535
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
3636
do(State) ->
37-
DepsPaths = rebar_state:code_paths(State, all_deps),
38-
ok = code:add_pathsa(DepsPaths),
39-
ok = rebar3_clojerl_utils:ensure_clojerl(State),
37+
DepsPaths = rebar_state:code_paths(State, all_deps),
38+
ok = code:add_pathsa(DepsPaths),
4039

41-
AllApps = rebar3_clojerl_utils:all_apps(State),
42-
Apps = rebar3_clojerl_utils:filter_app(AllApps, ?CLOJERL),
43-
Config = #{protocols_dir => protocols_dir(State)},
40+
ProjectApps = rebar_state:project_apps(State),
41+
Deps = rebar_state:all_deps(State),
4442

45-
restore_duplicates(AllApps),
46-
[compile(AppInfo, Config) || AppInfo <- Apps],
47-
backup_duplicates(AllApps, Config),
43+
AppsPaths = [rebar_app_info:ebin_dir(AppInfo) || AppInfo <- ProjectApps],
44+
ok = code:add_pathsa(AppsPaths),
45+
46+
ok = rebar3_clojerl_utils:ensure_clojerl(),
47+
48+
Apps0 = Deps ++ ProjectApps,
49+
Config = #{protocols_dir => protocols_dir(State)},
50+
51+
%% More than one application might modify existing protocols, so we
52+
%% restore the original backed-up protocol modules before compiling.
53+
try
54+
restore_duplicates(DepsPaths),
55+
Apps1 = maybe_compile_clojerl(Apps0, Config),
56+
[compile(AppInfo, Config) || AppInfo <- Apps1]
57+
after
58+
backup_duplicates(DepsPaths, Config)
59+
end,
4860

4961
{ok, State}.
5062

@@ -64,13 +76,23 @@ protocols_dir(State) ->
6476
rebar_api:debug("Protocols dir: ~s", [ProtoDir]),
6577
ProtoDir.
6678

79+
-spec maybe_compile_clojerl([rebar_app_info:t()], config()) ->
80+
[rebar_app_info:t()].
81+
maybe_compile_clojerl(Apps, Config) ->
82+
case rebar3_clojerl_utils:find_app(Apps, ?CLOJERL) of
83+
notfound -> Apps;
84+
{ok, ClojerlApp} ->
85+
compile(ClojerlApp, Config),
86+
Apps -- [ClojerlApp]
87+
end.
88+
6789
-spec backup_duplicates([rebar_app_info:t()], config()) -> ok.
68-
backup_duplicates(Apps, Config) ->
90+
backup_duplicates(DepsDirs, Config) ->
6991
ProtoDir = maps:get(protocols_dir, Config),
7092
BeamFilepaths = rebar_utils:find_files(ProtoDir, ".beam$"),
7193
BeamFilenames = [filename:basename(F) || F <- BeamFilepaths],
7294

73-
Dirs = [rebar_app_info:ebin_dir(App) || App <- Apps] -- [ProtoDir],
95+
Dirs = DepsDirs -- [ProtoDir],
7496
rebar_api:debug("Finding duplicates for:~n~p~nin~n~p", [BeamFilenames, Dirs]),
7597
Deleted = [backup_duplicates_from_dir(BeamFilenames, Dir) || Dir <- Dirs],
7698

@@ -89,9 +111,8 @@ backup_duplicates_from_dir(BeamFilenames, Dir) ->
89111
],
90112
{Dir, Filepaths}.
91113

92-
-spec restore_duplicates([rebar_app_info:t()]) -> ok.
93-
restore_duplicates(Apps) ->
94-
Dirs = [rebar_app_info:ebin_dir(App) || App <- Apps],
114+
-spec restore_duplicates([file:name()]) -> ok.
115+
restore_duplicates(Dirs) ->
95116
[ begin
96117
DestPath = filename:rootname(Path),
97118
ok = file:rename(Path, DestPath),
@@ -132,15 +153,18 @@ update_app_file({Dir, Filepaths}) ->
132153
compile(AppInfo, Config0) ->
133154
Graph = load_graph(AppInfo),
134155
Config1 = Config0#{graph => Graph},
135-
try find_files_to_compile(AppInfo, Config1) of
156+
try find_files_to_compile(AppInfo) of
136157
[] ->
137158
false;
138159
SrcFiles ->
139160
rebar_api:info("Clojerl Compiling ~s", [rebar_app_info:name(AppInfo)]),
140-
EbinDir = rebar_app_info:ebin_dir(AppInfo),
161+
rebar_api:debug("Files to compile: ~p", [SrcFiles]),
162+
EbinDir = rebar_app_info:ebin_dir(AppInfo),
163+
ProtoDir = list_to_binary(maps:get(protocols_dir, Config1)),
141164
Config2 = Config1#{ebin_dir => EbinDir},
142165
[ compile_clje(Src, Config2#{src_dir => SrcDir})
143-
|| {SrcDir, Src} <- SrcFiles
166+
|| {SrcDir, Src} <- SrcFiles,
167+
should_compile_file(Src, SrcDir, EbinDir, ProtoDir, Graph)
144168
],
145169
store_graph(AppInfo, Graph),
146170
true
@@ -150,7 +174,7 @@ compile(AppInfo, Config0) ->
150174

151175
-spec compile_clje(file:name(), config()) -> ok.
152176
compile_clje(Src, Config) ->
153-
rebar_api:debug("Compiling ~s...", [Src]),
177+
io:format("%%% Compiling ~s...~n", [Src]),
154178

155179
SrcDir = list_to_binary(maps:get(src_dir, Config)),
156180
EbinDir = list_to_binary(maps:get(ebin_dir, Config)),
@@ -163,8 +187,9 @@ compile_clje(Src, Config) ->
163187
},
164188
try
165189
ok = 'clojerl.Var':push_bindings(Bindings),
166-
Targets = clj_compiler:compile_file(list_to_binary(Src)),
167-
update_graph(remove_src_dir(Src, SrcDir), Targets, Graph)
190+
FullSrc = filename:join(SrcDir, Src),
191+
Targets = clj_compiler:compile_file(FullSrc),
192+
update_graph(Src, Targets, Graph)
168193
catch
169194
_:Reason ->
170195
Stacktrace = erlang:get_stacktrace(),
@@ -227,34 +252,29 @@ cljinfo_file(AppInfo) ->
227252
%% =============================================================================
228253
%% Find files to compile
229254

230-
-spec find_files_to_compile(rebar_app_info:t(), config()) ->
231-
[{file:name(), file:name()}].
232-
find_files_to_compile(AppInfo, Config) ->
233-
Graph = maps:get(graph, Config),
234-
ProtoDir = maps:get(protocols_dir, Config),
255+
-spec find_files_to_compile(rebar_app_info:t()) -> [{file:name(), file:name()}].
256+
find_files_to_compile(AppInfo) ->
235257
OutDir = rebar_app_info:out_dir(AppInfo),
236-
EbinDir = rebar_app_info:ebin_dir(AppInfo),
237258
CljeSrcDirs = rebar_app_info:get(AppInfo, clje_src_dirs, ?DEFAULT_SRC_DIRS),
259+
CljeFirst = clje_compile_first(AppInfo),
260+
CljeExclude = rebar_app_info:get(AppInfo, clje_exclude, []),
238261

239262
SrcDirPaths = [filename:join(OutDir, Dir) || Dir <- CljeSrcDirs],
240263
ok = code:add_pathsa(SrcDirPaths),
241-
Fun = fun(SrcDir) ->
242-
find_files_to_compile(SrcDir, EbinDir, ProtoDir, Graph)
243-
end,
244264

245-
lists:flatmap(Fun, SrcDirPaths).
265+
AllFiles = lists:flatmap(fun find_files/1, SrcDirPaths),
266+
SortFun = fun({_, X}, {_, Y}) ->
267+
maps:get(X, CljeFirst, -1) > maps:get(Y, CljeFirst, -1)
268+
end,
269+
[ X
270+
|| {_, Src} = X <- lists:sort(SortFun, AllFiles),
271+
not lists:member(Src, CljeExclude)
272+
].
246273

247-
-spec find_files_to_compile( file:name()
248-
, file:name()
249-
, file:name()
250-
, digraph:graph()
251-
) -> [{file:name(), file:name()}].
252-
find_files_to_compile(SrcDir, EbinDirs, ProtoDir, Graph) ->
274+
-spec find_files(file:name()) -> [{file:name(), file:name()}].
275+
find_files(SrcDir) ->
253276
SrcFiles = rebar_utils:find_files(SrcDir, ".clj[ce]"),
254-
[ {SrcDir, Source}
255-
|| Source <- SrcFiles,
256-
should_compile_file(Source, SrcDir, EbinDirs, ProtoDir, Graph)
257-
].
277+
[{SrcDir, remove_src_dir(Source, SrcDir)} || Source <- SrcFiles].
258278

259279
-spec should_compile_file( file:name()
260280
, file:name()
@@ -265,12 +285,12 @@ find_files_to_compile(SrcDir, EbinDirs, ProtoDir, Graph) ->
265285
should_compile_file(Src, SrcDir, EbinDir, ProtoDir, Graph) ->
266286
%% Check if the target file is either in the ebin directory or the
267287
%% protocols directory.
288+
FullSrc = filename:join(SrcDir, Src),
268289
Fun = fun(Target) ->
269-
should_compile(filename:join(ProtoDir, Target), Src) andalso
270-
should_compile(filename:join(EbinDir, Target), Src)
290+
should_compile(filename:join(ProtoDir, Target), FullSrc) andalso
291+
should_compile(filename:join(EbinDir, Target), FullSrc)
271292
end,
272-
SrcFilename = remove_src_dir(Src, SrcDir),
273-
case digraph:out_neighbours(Graph, SrcFilename) of
293+
case digraph:out_neighbours(Graph, Src) of
274294
[] -> true;
275295
Targets -> lists:any(Fun, Targets)
276296
end.
@@ -283,3 +303,12 @@ should_compile(Target, Source) ->
283303
-spec remove_src_dir(file:name(), file:name()) -> file:name().
284304
remove_src_dir(Src, SrcDir) ->
285305
re:replace(Src, ["^", SrcDir, "/"], "", [global, {return, list}]).
306+
307+
-spec clje_compile_first(rebar_app_info:t()) -> #{list() => non_neg_integer()}.
308+
clje_compile_first(AppInfo) ->
309+
CljeFirst = rebar_app_info:get(AppInfo, clje_compile_first, []),
310+
Fun = fun (X, {Acc, N}) ->
311+
{Acc#{X => N}, N - 1}
312+
end,
313+
{Positions, _} = lists:foldl(Fun, {#{}, length(CljeFirst)}, CljeFirst),
314+
Positions.

src/rebar3_clojerl_prv_release.erl

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/rebar3_clojerl_prv_test.erl

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,20 @@ init(State) ->
3232

3333
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
3434
do(State) ->
35+
rebar_api:info("Running Clojerl tests...", []),
36+
3537
{Opts, _} = rebar_state:command_parsed_args(State),
3638
ok = rebar3_clojerl_utils:maybe_set_sname(Opts),
3739

3840
DepsPaths = rebar_state:code_paths(State, all_deps),
3941
ok = code:add_pathsa(DepsPaths),
40-
ok = rebar3_clojerl_utils:ensure_clojerl(State),
4142

4243
Apps = rebar_state:project_apps(State),
44+
AppsPaths = [rebar_app_info:ebin_dir(AppInfo) || AppInfo <- Apps],
45+
ok = code:add_pathsa(AppsPaths),
46+
47+
%% Ensure clojerl after adding all code pahts
48+
ok = rebar3_clojerl_utils:ensure_clojerl(),
4349

4450
try
4551
[test(AppInfo, Opts) || AppInfo <- Apps]
@@ -69,7 +75,7 @@ test(AppInfo, Opts) ->
6975
NsOpt = proplists:get_value(ns, Opts, undefined),
7076
VarOpt = proplists:get_value(var, Opts, undefined),
7177

72-
NsSymbols = case NsOpt of
78+
NsSyms0 = case NsOpt of
7379
undefined -> lists:flatmap(fun find_tests/1, TestDirs);
7480
NsOpt -> [clj_rt:symbol(list_to_binary(NsOpt))]
7581
end,
@@ -80,7 +86,7 @@ test(AppInfo, Opts) ->
8086
'clojure.core':use([clj_rt:symbol(<<"clojure.core">>)]),
8187

8288
%% TODO: maybe change this to a compilation of the file
83-
'clojure.core':require(NsSymbols),
89+
'clojure.core':require(NsSyms0),
8490

8591
Var = case {NsOpt, VarOpt} of
8692
{undefined, _} -> undefined;
@@ -92,11 +98,14 @@ test(AppInfo, Opts) ->
9298
'clojure.core':'find-var'(VarSymbol)
9399
end,
94100

95-
rebar_api:debug("Test namespaces: ~p", [clj_rt:str(NsSymbols)]),
96-
97101
case Var of
98-
undefined -> 'clojure.test':'run-tests'(NsSymbols);
99-
_ -> 'clojure.test':'test-var'(Var)
102+
undefined ->
103+
NsSyms1 = [X || X <- NsSyms0, 'clojure.core':'find-ns'(X) =/= undefined],
104+
rebar_api:debug("Test namespaces: ~s", [clj_rt:str(NsSyms1)]),
105+
'clojure.test':'run-tests'(NsSyms1);
106+
_ ->
107+
rebar_api:debug("Test var: ~s", [clj_rt:str(Var)]),
108+
'clojure.test':'test-var'(Var)
100109
end,
101110
ok.
102111

src/rebar3_clojerl_utils.erl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
-include("rebar3_clojerl.hrl").
44

5-
-export([ ensure_clojerl/1
5+
-export([ ensure_clojerl/0
66
, all_apps/1
77
, find_app/2
88
, filter_app/2
@@ -11,13 +11,13 @@
1111

1212
-type opts() :: [{atom(), any()}].
1313

14-
-spec ensure_clojerl(rebar_state:t()) -> ok.
15-
ensure_clojerl(State) ->
16-
case find_app(all_apps(State), ?CLOJERL) of
17-
notfound ->
18-
rebar_api:abort("Clojerl was not found as a dependency", []);
19-
{ok, _} ->
20-
ok = clojerl:start()
14+
-spec ensure_clojerl() -> ok.
15+
ensure_clojerl() ->
16+
case code:ensure_loaded(clojerl) of
17+
{module, clojerl} ->
18+
ok = clojerl:start();
19+
{error, Reason} ->
20+
rebar_api:abort("Application Clojerl could not be started: ~p", [Reason])
2121
end.
2222

2323
-spec all_apps(rebar_state:t()) -> [rebar_app_info:t()].

0 commit comments

Comments
 (0)