From 4773d50419ac8f4bb3ad599b86e50f05e192ff3e Mon Sep 17 00:00:00 2001 From: Pablo Costas Date: Thu, 12 Mar 2020 17:36:33 +0100 Subject: [PATCH] Move `absolute_path/2` and `normalized_path` to `rebar_file_utils` As suggested in #2223, `make_absolute_path/2` and `make_normalized_path/2` should, instead of being exported in `rebar_dir`, be moved to `rebar_file_utils` and renamed (decided to simply remove the `make` from their names since in that module there is already a path related function called `canonical_path`). --- src/rebar_dir.erl | 42 +++------------------------------ src/rebar_file_utils.erl | 39 ++++++++++++++++++++++++++++++ test/rebar_file_utils_SUITE.erl | 35 +++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 39 deletions(-) diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl index 04d7a471..3e377966 100644 --- a/src/rebar_dir.erl +++ b/src/rebar_dir.erl @@ -191,42 +191,6 @@ processing_base_dir(State, Dir) -> AbsDir = filename:absname(Dir), AbsDir =:= rebar_state:get(State, base_dir). -%% @doc make a path absolute --spec make_absolute_path(file:filename()) -> file:filename(). -make_absolute_path(Path) -> - case filename:pathtype(Path) of - absolute -> - Path; - relative -> - {ok, Dir} = file:get_cwd(), - filename:join([Dir, Path]); - volumerelative -> - Volume = hd(filename:split(Path)), - {ok, Dir} = file:get_cwd(Volume), - filename:join([Dir, Path]) - end. - -%% @doc normalizing a path removes all of the `..' and the -%% `.' segments it may contain. --spec make_normalized_path(file:filename()) -> file:filename(). -make_normalized_path(Path) -> - AbsPath = make_absolute_path(Path), - Components = filename:split(AbsPath), - make_normalized_path(Components, []). - -%% @private drops path fragments for normalization --spec make_normalized_path([string()], [string()]) -> file:filename(). -make_normalized_path([], NormalizedPath) -> - filename:join(lists:reverse(NormalizedPath)); -make_normalized_path([H|T], NormalizedPath) -> - case H of - "." when NormalizedPath == [], T == [] -> make_normalized_path(T, ["."]); - "." -> make_normalized_path(T, NormalizedPath); - ".." when NormalizedPath == [] -> make_normalized_path(T, [".."]); - ".." when hd(NormalizedPath) =/= ".." -> make_normalized_path(T, tl(NormalizedPath)); - _ -> make_normalized_path(T, [H|NormalizedPath]) - end. - %% @doc take a source and a target path, and relativize the target path %% onto the source. %% @@ -239,8 +203,8 @@ make_normalized_path([H|T], NormalizedPath) -> %% ''' -spec make_relative_path(file:filename(), file:filename()) -> file:filename(). make_relative_path(Source, Target) -> - AbsSource = make_normalized_path(Source), - AbsTarget = make_normalized_path(Target), + AbsSource = rebar_file_utils:normalized_path(Source), + AbsTarget = rebar_file_utils:normalized_path(Target), do_make_relative_path(filename:split(AbsSource), filename:split(AbsTarget)). %% @private based on fragments of paths, replace the number of common @@ -301,7 +265,7 @@ raw_src_dirs(Type, Opts, Default) -> %% @private normalizes relative paths so that ./a/b/c/ => a/b/c normalize_relative_path(Path) -> - make_normalized_path(filename:split(Path), []). + rebar_file_utils:normalized_path(filename:split(Path), []). %% @doc returns all the source directories (`src_dirs' and %% `extra_src_dirs'). diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl index b2f34f03..5dc8aebc 100644 --- a/src/rebar_file_utils.erl +++ b/src/rebar_file_utils.erl @@ -43,6 +43,9 @@ touch/1, path_from_ancestor/2, canonical_path/1, + absolute_path/1, + normalized_path/1, + normalized_path/2, resolve_link/1, split_dirname/1, ensure_dir/1]). @@ -453,6 +456,42 @@ canonical_path([_|Acc], [".."|Rest]) -> canonical_path(Acc, Rest); canonical_path([], [".."|Rest]) -> canonical_path([], Rest); canonical_path(Acc, [Component|Rest]) -> canonical_path([Component|Acc], Rest). +%% @doc make a path absolute +-spec absolute_path(file:filename()) -> file:filename(). +absolute_path(Path) -> + case filename:pathtype(Path) of + absolute -> + Path; + relative -> + {ok, Dir} = file:get_cwd(), + filename:join([Dir, Path]); + volumerelative -> + Volume = hd(filename:split(Path)), + {ok, Dir} = file:get_cwd(Volume), + filename:join([Dir, Path]) + end. + +%% @doc normalizing a path removes all of the `..' and the +%% `.' segments it may contain. +-spec normalized_path(file:filename()) -> file:filename(). +normalized_path(Path) -> + AbsPath = absolute_path(Path), + Components = filename:split(AbsPath), + normalized_path(Components, []). + +%% @private drops path fragments for normalization +-spec normalized_path([string()], [string()]) -> file:filename(). +normalized_path([], NormalizedPath) -> + filename:join(lists:reverse(NormalizedPath)); +normalized_path([H|T], NormalizedPath) -> + case H of + "." when NormalizedPath == [], T == [] -> normalized_path(T, ["."]); + "." -> normalized_path(T, NormalizedPath); + ".." when NormalizedPath == [] -> normalized_path(T, [".."]); + ".." when hd(NormalizedPath) =/= ".." -> normalized_path(T, tl(NormalizedPath)); + _ -> normalized_path(T, [H|NormalizedPath]) + end. + %% @doc returns canonical target of path if path is a link, otherwise returns path -spec resolve_link(string()) -> string(). resolve_link(Path) -> diff --git a/test/rebar_file_utils_SUITE.erl b/test/rebar_file_utils_SUITE.erl index 4cc6a938..70fd5aab 100644 --- a/test/rebar_file_utils_SUITE.erl +++ b/test/rebar_file_utils_SUITE.erl @@ -15,6 +15,8 @@ reset_dir/1, path_from_ancestor/1, canonical_path/1, + absolute_path/1, + normalized_path/1, resolve_link/1, split_dirname/1, mv_warning_is_ignored/1, @@ -36,6 +38,8 @@ all() -> {group, mv}, path_from_ancestor, canonical_path, + absolute_path, + normalized_path, resolve_link, split_dirname, mv_warning_is_ignored]. @@ -144,6 +148,37 @@ canonical_path(_Config) -> ?assertEqual(filename:nativename(Root ++ "foo/bar"), rebar_file_utils:canonical_path("/foo/./bar")). +absolute_path(_Config) -> + %% We find the root so that the name works both on unix-likes and + %% with Windows. + Root = case os:type() of + {win32, _} -> filename:nativename(filename:absname("/")); % C:\, with proper drive + _ -> "/" + end, + ?assertEqual(filename:absname(Root), rebar_file_utils:absolute_path("/")), + ?assertEqual(Root ++ "foo", rebar_file_utils:absolute_path("/foo")), + % casoscon ../ o ./ + {ok, Cwd} = file:get_cwd(), + ?assertEqual(Cwd, rebar_file_utils:absolute_path("./")), + ?assertEqual(Cwd ++ "/foo", rebar_file_utils:absolute_path("./foo")), + ?assertEqual(Cwd ++ "/foo/bar", rebar_file_utils:absolute_path("foo/bar")). + +normalized_path(_Config) -> + %% We find the root so that the name works both on unix-likes and + %% with Windows. + Root = case os:type() of + {win32, _} -> filename:nativename(filename:absname("/")); % C:\, with proper drive + _ -> "/" + end, + ?assertEqual(filename:nativename(Root), rebar_file_utils:normalized_path("/")), + ?assertEqual("../..", rebar_file_utils:normalized_path("/../../..")), + ?assertEqual(Root ++ "foo", rebar_file_utils:normalized_path("/foo/bar/..")), + ?assertEqual(Root ++ "foo", rebar_file_utils:normalized_path("/foo/../foo")), + ?assertEqual(Root ++ "foo", rebar_file_utils:normalized_path("/foo/.")), + ?assertEqual(Root ++ "foo", rebar_file_utils:normalized_path("/foo/./.")), + ?assertEqual(filename:nativename(Root ++ "foo/bar"), + rebar_file_utils:normalized_path("/foo/./bar")). + resolve_link(_Config) -> TmpDir = rebar_file_utils:system_tmpdir( ["rebar_file_utils_SUITE", "resolve_link"]),