summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFred Hebert <mononcqc@ferd.ca>2015-09-25 17:46:03 -0400
committerFred Hebert <mononcqc@ferd.ca>2015-09-25 17:46:03 -0400
commit509c7afec67a980e73efb61c53efd87a53e7e14e (patch)
tree0fdf2991408531cb475ea05cddc17d90632c9b39 /src
parent4d76a556e20665e0d3f77910635586613036fa4e (diff)
parentae275c6396545defc80a765a6b835d01f4c76599 (diff)
Merge pull request #800 from talentdeficit/extract_path_utils
extract `retarget_path/2', `relative_path/2' and `reduce_path/1' and add tests
Diffstat (limited to 'src')
-rw-r--r--src/rebar_dir.erl29
-rw-r--r--src/rebar_file_utils.erl29
2 files changed, 56 insertions, 2 deletions
diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl
index 7220d89..364e197 100644
--- a/src/rebar_dir.erl
+++ b/src/rebar_dir.erl
@@ -23,7 +23,8 @@
make_relative_path/2,
src_dirs/1, src_dirs/2,
extra_src_dirs/1, extra_src_dirs/2,
- all_src_dirs/1, all_src_dirs/3]).
+ all_src_dirs/1, all_src_dirs/3,
+ retarget_path/2]).
-include("rebar.hrl").
@@ -160,3 +161,29 @@ all_src_dirs(Opts) -> all_src_dirs(Opts, [], []).
list(file:filename_all()).
all_src_dirs(Opts, SrcDefault, ExtraDefault) ->
src_dirs(Opts, SrcDefault) ++ extra_src_dirs(Opts, ExtraDefault).
+
+%% given a path if that path is an ancestor of an app dir return the path relative to that
+%% apps outdir. if the path is not an ancestor to any app dirs but is an ancestor of the
+%% project root return the path relative to the project base_dir. if it is not an ancestor
+%% of either return it unmodified
+-spec retarget_path(rebar_state:t(), string()) -> string().
+
+retarget_path(State, Path) ->
+ ProjectApps = rebar_state:project_apps(State),
+ retarget_path(State, Path, ProjectApps).
+
+%% not relative to any apps in project, check to see it's relative to
+%% project root
+retarget_path(State, Path, []) ->
+ case rebar_file_utils:path_from_ancestor(rebar_file_utils:canonical_path(Path), rebar_state:dir(State)) of
+ {ok, NewPath} -> filename:join([base_dir(State), NewPath]);
+ %% not relative to project root, don't modify
+ {error, badparent} -> Path
+ end;
+%% relative to current app, retarget to the same dir relative to
+%% the app's out_dir
+retarget_path(State, Path, [App|Rest]) ->
+ case rebar_file_utils:path_from_ancestor(rebar_file_utils:canonical_path(Path), rebar_app_info:dir(App)) of
+ {ok, NewPath} -> filename:join([rebar_app_info:out_dir(App), NewPath]);
+ {error, badparent} -> retarget_path(State, Path, Rest)
+ end.
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index 732d83f..ea1a6a2 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -37,7 +37,9 @@
system_tmpdir/0,
system_tmpdir/1,
reset_dir/1,
- touch/1]).
+ touch/1,
+ path_from_ancestor/2,
+ canonical_path/1]).
-include("rebar.hrl").
@@ -244,6 +246,31 @@ touch(Path) ->
ok = file:write_file_info(Path, A#file_info{mtime = calendar:local_time(),
atime = calendar:local_time()}).
+%% for a given path return the path relative to a base directory
+-spec path_from_ancestor(string(), string()) -> {ok, string()} | {error, badparent}.
+
+path_from_ancestor(Target, To) ->
+ path_from_ancestor_(filename:split(canonical_path(Target)),
+ filename:split(canonical_path(To))).
+
+path_from_ancestor_([Part|Target], [Part|To]) -> path_from_ancestor_(Target, To);
+path_from_ancestor_([], []) -> {ok, ""};
+path_from_ancestor_(Target, []) -> {ok, filename:join(Target)};
+path_from_ancestor_(_, _) -> {error, badparent}.
+
+
+%% reduce a filepath by removing all incidences of `.' and `..'
+-spec canonical_path(string()) -> string().
+
+canonical_path(Dir) -> canonical_path([], filename:split(filename:absname(Dir))).
+
+canonical_path([], []) -> filename:nativename("/");
+canonical_path(Acc, []) -> filename:join(lists:reverse(Acc));
+canonical_path(Acc, ["."|Rest]) -> canonical_path(Acc, Rest);
+canonical_path([_|Acc], [".."|Rest]) -> canonical_path(Acc, Rest);
+canonical_path([], [".."|Rest]) -> canonical_path([], Rest);
+canonical_path(Acc, [Component|Rest]) -> canonical_path([Component|Acc], Rest).
+
%% ===================================================================
%% Internal functions
%% ===================================================================