diff --git a/apps/emqx_utils/src/emqx_utils_fs.erl b/apps/emqx_utils/src/emqx_utils_fs.erl index 6d1bfe831..5c8b5ded0 100644 --- a/apps/emqx_utils/src/emqx_utils_fs.erl +++ b/apps/emqx_utils/src/emqx_utils_fs.erl @@ -20,6 +20,7 @@ -export([traverse_dir/3]). -export([read_info/1]). +-export([find_relpath/2]). -export([canonicalize/1]). -type fileinfo() :: #file_info{}. @@ -62,6 +63,28 @@ traverse_dir(FoldFun, Acc, AbsPath, {error, Reason}) -> read_info(AbsPath) -> file:read_link_info(AbsPath, [{time, posix}, raw]). +-spec find_relpath(file:name(), file:name()) -> + file:name(). +find_relpath(Path, RelativeTo) -> + case + filename:pathtype(Path) =:= filename:pathtype(RelativeTo) andalso + drop_path_prefix(filename:split(Path), filename:split(RelativeTo)) + of + false -> + Path; + [] -> + "."; + RelativePath -> + filename:join(RelativePath) + end. + +drop_path_prefix([Name | T1], [Name | T2]) -> + drop_path_prefix(T1, T2); +drop_path_prefix(Path, []) -> + Path; +drop_path_prefix(_Path, _To) -> + false. + %% @doc Canonicalize a file path. %% Removes stray slashes and converts to a string. -spec canonicalize(file:name()) -> diff --git a/apps/emqx_utils/test/emqx_utils_fs_SUITE.erl b/apps/emqx_utils/test/emqx_utils_fs_SUITE.erl index 2a36f6902..704d0af24 100644 --- a/apps/emqx_utils/test/emqx_utils_fs_SUITE.erl +++ b/apps/emqx_utils/test/emqx_utils_fs_SUITE.erl @@ -143,6 +143,44 @@ t_canonicalize_non_utf8(_) -> emqx_utils_fs:canonicalize(<<128, 128, 128>>) ). +%% + +t_find_relpath(_) -> + ?assertEqual( + "d1/1", + emqx_utils_fs:find_relpath("/usr/local/nonempty/d1/1", "/usr/local/nonempty") + ). + +t_find_relpath_same(_) -> + ?assertEqual( + ".", + emqx_utils_fs:find_relpath("/usr/local/bin", "/usr/local/bin/") + ), + ?assertEqual( + ".", + emqx_utils_fs:find_relpath("/usr/local/bin/.", "/usr/local/bin") + ). + +t_find_relpath_no_prefix(_) -> + ?assertEqual( + "/usr/lib/erlang/lib", + emqx_utils_fs:find_relpath("/usr/lib/erlang/lib", "/usr/local/bin") + ). + +t_find_relpath_both_relative(_) -> + ?assertEqual( + "1/2/3", + emqx_utils_fs:find_relpath("local/nonempty/1/2/3", "local/nonempty") + ). + +t_find_relpath_different_types(_) -> + ?assertEqual( + "local/nonempty/1/2/3", + emqx_utils_fs:find_relpath("local/nonempty/1/2/3", "/usr/local/nonempty") + ). + +%% + chmod_file(File, Mode) -> {ok, FileInfo} = file:read_file_info(File), ok = file:write_file_info(File, FileInfo#file_info{mode = Mode}).