You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 line
5.7 KiB

  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. -module(rebar_prv_path).
  4. -behaviour(provider).
  5. -export([init/1,
  6. do/1,
  7. format_error/1]).
  8. -include("rebar.hrl").
  9. -define(PROVIDER, path).
  10. -define(DEPS, [app_discovery]).
  11. %% ===================================================================
  12. %% Public API
  13. %% ===================================================================
  14. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
  15. init(State) ->
  16. State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
  17. {module, ?MODULE},
  18. {bare, true},
  19. {deps, ?DEPS},
  20. {example, "rebar3 path"},
  21. {short_desc, "Print paths to build dirs in current profile."},
  22. {desc, "Print paths to build dirs in current profile."},
  23. {opts, eunit_opts(State)}])),
  24. {ok, State1}.
  25. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  26. do(State) ->
  27. {RawOpts, _} = rebar_state:command_parsed_args(State),
  28. %% retrieve apps to filter by for other args
  29. Apps = filter_apps(RawOpts, State),
  30. %% remove apps and separator opts from options
  31. Paths = lists:filter(fun({app, _}) -> false; ({separator, _}) -> false; (_) -> true end, RawOpts),
  32. %% if no paths requested in opts print the base_dir instead
  33. P = case Paths of [] -> [{ebin, true}]; _ -> Paths end,
  34. case paths(P, Apps, State, []) of
  35. ok -> {ok, State};
  36. {error, Error} -> {error, Error}
  37. end.
  38. -spec format_error(any()) -> iolist().
  39. format_error(Reason) ->
  40. io_lib:format("~p", [Reason]).
  41. filter_apps(RawOpts, State) ->
  42. RawApps = proplists:get_all_values(app, RawOpts),
  43. Apps = lists:foldl(fun(String, Acc) -> string:tokens(String, ",") ++ Acc end, [], RawApps),
  44. case Apps of
  45. [] ->
  46. ProjectDeps = project_deps(State),
  47. ProjectApps = rebar_state:project_apps(State),
  48. lists:map(fun(A) -> binary_to_list(rebar_app_info:name(A)) end, ProjectApps) ++ ProjectDeps;
  49. _ -> Apps
  50. end.
  51. paths([], _, State, Acc) -> print_paths_if_exist(lists:reverse(Acc), State);
  52. paths([{base, true}|Rest], Apps, State, Acc) ->
  53. paths(Rest, Apps, State, [base_dir(State)|Acc]);
  54. paths([{bin, true}|Rest], Apps, State, Acc) ->
  55. paths(Rest, Apps, State, [bin_dir(State)|Acc]);
  56. paths([{ebin, true}|Rest], Apps, State, Acc) ->
  57. paths(Rest, Apps, State, ebin_dirs(Apps, State) ++ Acc);
  58. paths([{lib, true}|Rest], Apps, State, Acc) ->
  59. paths(Rest, Apps, State, [lib_dir(State)|Acc]);
  60. paths([{priv, true}|Rest], Apps, State, Acc) ->
  61. paths(Rest, Apps, State, priv_dirs(Apps, State) ++ Acc);
  62. paths([{src, true}|Rest], Apps, State, Acc) ->
  63. paths(Rest, Apps, State, src_dirs(Apps, State) ++ Acc);
  64. paths([{rel, true}|Rest], Apps, State, Acc) ->
  65. paths(Rest, Apps, State, [rel_dir(State)|Acc]).
  66. base_dir(State) -> io_lib:format("~s", [rebar_dir:base_dir(State)]).
  67. bin_dir(State) -> io_lib:format("~s/bin", [rebar_dir:base_dir(State)]).
  68. lib_dir(State) -> io_lib:format("~s/lib", [rebar_dir:base_dir(State)]).
  69. rel_dir(State) -> io_lib:format("~s/rel", [rebar_dir:base_dir(State)]).
  70. ebin_dirs(Apps, State) ->
  71. lists:map(fun(App) -> io_lib:format("~s/lib/~s/ebin", [rebar_dir:base_dir(State), App]) end, Apps).
  72. priv_dirs(Apps, State) ->
  73. lists:map(fun(App) -> io_lib:format("~s/lib/~s/priv", [rebar_dir:base_dir(State), App]) end, Apps).
  74. src_dirs(Apps, State) ->
  75. lists:map(fun(App) -> io_lib:format("~s/lib/~s/src", [rebar_dir:base_dir(State), App]) end, Apps).
  76. print_paths_if_exist(Paths, State) ->
  77. {RawOpts, _} = rebar_state:command_parsed_args(State),
  78. Sep = proplists:get_value(separator, RawOpts, " "),
  79. RealPaths = lists:filter(fun(P) -> ec_file:is_dir(P) end, Paths),
  80. io:format("~s", [string:join(RealPaths, Sep)]).
  81. project_deps(State) ->
  82. Profiles = rebar_state:current_profiles(State),
  83. List = lists:foldl(fun(Profile, Acc) -> rebar_state:get(State, {deps, Profile}, []) ++ Acc end, [], Profiles),
  84. Deps = [normalize(Name) || {Name, _} <- List],
  85. lists:usort(Deps).
  86. normalize(AppName) when is_list(AppName) -> AppName;
  87. normalize(AppName) when is_atom(AppName) -> atom_to_list(AppName);
  88. normalize(AppName) when is_binary(AppName) -> binary_to_list(AppName).
  89. eunit_opts(_State) ->
  90. [{app, undefined, "app", string, help(app)},
  91. {base, undefined, "base", boolean, help(base)},
  92. {bin, undefined, "bin", boolean, help(bin)},
  93. {ebin, undefined, "ebin", boolean, help(ebin)},
  94. {lib, undefined, "lib", boolean, help(lib)},
  95. {priv, undefined, "priv", boolean, help(priv)},
  96. {separator, $s, "separator", string, help(separator)},
  97. {src, undefined, "src", boolean, help(src)},
  98. {rel, undefined, "rel", boolean, help(rel)}].
  99. help(app) -> "Comma seperated list of applications to return paths for.";
  100. help(base) -> "Return the `base' path of the current profile.";
  101. help(bin) -> "Return the `bin' path of the current profile.";
  102. help(ebin) -> "Return all `ebin' paths of the current profile's applications.";
  103. help(lib) -> "Return the `lib' path of the current profile.";
  104. help(priv) -> "Return the `priv' path of the current profile's applications.";
  105. help(separator) -> "In case of multiple return paths, the separator character to use to join them.";
  106. help(src) -> "Return the `src' path of the current profile's applications.";
  107. help(rel) -> "Return the `rel' path of the current profile.".