summaryrefslogtreecommitdiff
path: root/src/rebar_file_utils.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_file_utils.erl')
-rw-r--r--src/rebar_file_utils.erl29
1 files changed, 28 insertions, 1 deletions
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
%% ===================================================================