|
|
@ -1,3 +1,4 @@ |
|
|
|
%%% @doc utility functions for directory and path handling of all kind. |
|
|
|
-module(rebar_dir). |
|
|
|
|
|
|
|
-export([base_dir/1, |
|
|
@ -29,10 +30,14 @@ |
|
|
|
|
|
|
|
-include("rebar.hrl"). |
|
|
|
|
|
|
|
%% @doc returns the directory root for build artifacts |
|
|
|
%% for the current profile, such as `_build/default/'. |
|
|
|
-spec base_dir(rebar_state:t()) -> file:filename_all(). |
|
|
|
base_dir(State) -> |
|
|
|
profile_dir(rebar_state:opts(State), rebar_state:current_profiles(State)). |
|
|
|
|
|
|
|
%% @doc returns the directory root for build artifacts for a given set |
|
|
|
%% of profiles. |
|
|
|
-spec profile_dir(rebar_dict(), [atom()]) -> file:filename_all(). |
|
|
|
profile_dir(Opts, Profiles) -> |
|
|
|
{BaseDir, ProfilesStrings} = case [ec_cnv:to_list(P) || P <- Profiles] of |
|
|
@ -46,25 +51,36 @@ profile_dir(Opts, Profiles) -> |
|
|
|
ProfilesDir = string:join(ProfilesStrings, "+"), |
|
|
|
filename:join(BaseDir, ProfilesDir). |
|
|
|
|
|
|
|
%% @doc returns the directory where dependencies should be placed |
|
|
|
%% given the current profile. |
|
|
|
-spec deps_dir(rebar_state:t()) -> file:filename_all(). |
|
|
|
deps_dir(State) -> |
|
|
|
filename:join(base_dir(State), rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR)). |
|
|
|
|
|
|
|
%% @doc returns the directory where a dependency should be placed |
|
|
|
%% given the current profile, based on its app name. Expects to be passed |
|
|
|
%% the result of `deps_dir/1' as a first argument. |
|
|
|
-spec deps_dir(file:filename_all(), file:filename_all()) -> file:filename_all(). |
|
|
|
deps_dir(DepsDir, App) -> |
|
|
|
filename:join(DepsDir, App). |
|
|
|
|
|
|
|
%% @doc returns the absolute path for the project root (by default, |
|
|
|
%% the current working directory for the currently running escript). |
|
|
|
root_dir(State) -> |
|
|
|
filename:absname(rebar_state:get(State, root_dir, ?DEFAULT_ROOT_DIR)). |
|
|
|
|
|
|
|
%% @doc returns the expected location of the `_checkouts' directory. |
|
|
|
-spec checkouts_dir(rebar_state:t()) -> file:filename_all(). |
|
|
|
checkouts_dir(State) -> |
|
|
|
filename:join(root_dir(State), rebar_state:get(State, checkouts_dir, ?DEFAULT_CHECKOUTS_DIR)). |
|
|
|
|
|
|
|
%% @doc returns the expected location of a given app in the checkouts |
|
|
|
%% directory for the project. |
|
|
|
-spec checkouts_dir(rebar_state:t(), file:filename_all()) -> file:filename_all(). |
|
|
|
checkouts_dir(State, App) -> |
|
|
|
filename:join(checkouts_dir(State), App). |
|
|
|
|
|
|
|
%% @doc Returns the directory where plugins are located. |
|
|
|
-spec plugins_dir(rebar_state:t()) -> file:filename_all(). |
|
|
|
plugins_dir(State) -> |
|
|
|
case lists:member(global, rebar_state:current_profiles(State)) of |
|
|
@ -74,33 +90,50 @@ plugins_dir(State) -> |
|
|
|
filename:join(base_dir(State), rebar_state:get(State, plugins_dir, ?DEFAULT_PLUGINS_DIR)) |
|
|
|
end. |
|
|
|
|
|
|
|
%% @doc returns the list of relative path where the project applications can |
|
|
|
%% be located. |
|
|
|
-spec lib_dirs(rebar_state:t()) -> file:filename_all(). |
|
|
|
lib_dirs(State) -> |
|
|
|
rebar_state:get(State, project_app_dirs, ?DEFAULT_PROJECT_APP_DIRS). |
|
|
|
|
|
|
|
%% @doc returns the user's home directory. |
|
|
|
-spec home_dir() -> file:filename_all(). |
|
|
|
home_dir() -> |
|
|
|
{ok, [[Home]]} = init:get_argument(home), |
|
|
|
Home. |
|
|
|
|
|
|
|
%% @doc returns the directory where the global configuration files for rebar3 |
|
|
|
%% may be stored. |
|
|
|
-spec global_config_dir(rebar_state:t()) -> file:filename_all(). |
|
|
|
global_config_dir(State) -> |
|
|
|
Home = home_dir(), |
|
|
|
rebar_state:get(State, global_rebar_dir, filename:join([Home, ".config", "rebar3"])). |
|
|
|
|
|
|
|
%% @doc returns the path of the global rebar.config file |
|
|
|
-spec global_config(rebar_state:t()) -> file:filename_all(). |
|
|
|
global_config(State) -> |
|
|
|
filename:join(global_config_dir(State), "rebar.config"). |
|
|
|
|
|
|
|
%% @doc returns the default path of the global rebar.config file |
|
|
|
-spec global_config() -> file:filename_all(). |
|
|
|
global_config() -> |
|
|
|
Home = home_dir(), |
|
|
|
filename:join([Home, ".config", "rebar3", "rebar.config"]). |
|
|
|
|
|
|
|
%% @doc returns the location for the global cache directory |
|
|
|
-spec global_cache_dir(rebar_dict()) -> file:filename_all(). |
|
|
|
global_cache_dir(Opts) -> |
|
|
|
Home = home_dir(), |
|
|
|
rebar_opts:get(Opts, global_rebar_dir, filename:join([Home, ".cache", "rebar3"])). |
|
|
|
|
|
|
|
%% @doc appends the cache directory to the path passed to this function. |
|
|
|
-spec local_cache_dir(file:filename_all()) -> file:filename_all(). |
|
|
|
local_cache_dir(Dir) -> |
|
|
|
filename:join(Dir, ".rebar3"). |
|
|
|
|
|
|
|
%% @doc returns the current working directory, with some specific |
|
|
|
%% conversions and handling done to be cross-platform compatible. |
|
|
|
-spec get_cwd() -> file:filename_all(). |
|
|
|
get_cwd() -> |
|
|
|
{ok, Dir} = file:get_cwd(), |
|
|
|
%% On windows cwd may return capital letter for drive, |
|
|
@ -109,9 +142,14 @@ get_cwd() -> |
|
|
|
%% cwd as soon as it possible. |
|
|
|
filename:join([Dir]). |
|
|
|
|
|
|
|
%% @doc returns the file location for the global template |
|
|
|
%% configuration variables file. |
|
|
|
-spec template_globals(rebar_state:t()) -> file:filename_all(). |
|
|
|
template_globals(State) -> |
|
|
|
filename:join([global_config_dir(State), "templates", "globals"]). |
|
|
|
|
|
|
|
%% @doc returns the location for the global template directory |
|
|
|
-spec template_dir(rebar_state:t()) -> file:filename_all(). |
|
|
|
template_dir(State) -> |
|
|
|
filename:join([global_config_dir(State), "templates"]). |
|
|
|
|
|
|
@ -129,6 +167,8 @@ 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 -> |
|
|
@ -142,11 +182,16 @@ make_absolute_path(Path) -> |
|
|
|
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) -> |
|
|
@ -181,37 +226,42 @@ do_make_relative_path(Source, Target) -> |
|
|
|
Base = lists:duplicate(max(length(Target) - 1, 0), ".."), |
|
|
|
filename:join(Base ++ Source). |
|
|
|
|
|
|
|
%%%----------------------------------------------------------------- |
|
|
|
%%% 'src_dirs' and 'extra_src_dirs' can be configured with options |
|
|
|
%%% @doc |
|
|
|
%%% `src_dirs' and `extra_src_dirs' can be configured with options |
|
|
|
%%% like this: |
|
|
|
%%% |
|
|
|
%%% ``` |
|
|
|
%%% {src_dirs,[{"foo",[{recursive,false}]}]} |
|
|
|
%%% {extra_src_dirs,[{"bar",[recursive]}]} (equivalent to {recursive,true}) |
|
|
|
%%% |
|
|
|
%%% src_dirs/1,2 and extra_src_dirs/1,2 return only the list of |
|
|
|
%%% directories for the 'src_dirs' and 'extra_src_dirs' options |
|
|
|
%%% respectively, while src_dirs_opts/2 return the options list for |
|
|
|
%%% the given directory, no matter if it is configured as 'src_dirs' or |
|
|
|
%%% 'extra_src_dirs'. |
|
|
|
%%% |
|
|
|
%%% ''' |
|
|
|
%%% `src_dirs/1,2' and `extra_src_dirs/1,2' return only the list of |
|
|
|
%%% directories for the `src_dirs' and `extra_src_dirs' options |
|
|
|
%%% respectively, while `src_dirs_opts/2' returns the options list for |
|
|
|
%%% the given directory, no matter if it is configured as `src_dirs' or |
|
|
|
%%% `extra_src_dirs'. |
|
|
|
-spec src_dirs(rebar_dict()) -> list(file:filename_all()). |
|
|
|
src_dirs(Opts) -> src_dirs(Opts, []). |
|
|
|
|
|
|
|
%% @doc same as `src_dirs/1', but allows to pass in a list of default options. |
|
|
|
-spec src_dirs(rebar_dict(), list(file:filename_all())) -> list(file:filename_all()). |
|
|
|
src_dirs(Opts, Default) -> |
|
|
|
src_dirs(src_dirs, Opts, Default). |
|
|
|
|
|
|
|
%% @doc same as `src_dirs/1', but for the `extra_src_dirs' options |
|
|
|
-spec extra_src_dirs(rebar_dict()) -> list(file:filename_all()). |
|
|
|
extra_src_dirs(Opts) -> extra_src_dirs(Opts, []). |
|
|
|
|
|
|
|
%% @doc same as `src_dirs/2', but for the `extra_src_dirs' options |
|
|
|
-spec extra_src_dirs(rebar_dict(), list(file:filename_all())) -> list(file:filename_all()). |
|
|
|
extra_src_dirs(Opts, Default) -> |
|
|
|
src_dirs(extra_src_dirs, Opts, Default). |
|
|
|
|
|
|
|
%% @private agnostic version of src_dirs and extra_src_dirs. |
|
|
|
src_dirs(Type, Opts, Default) -> |
|
|
|
lists:usort([case D0 of {D,_} -> D; _ -> D0 end || |
|
|
|
D0 <- raw_src_dirs(Type,Opts,Default)]). |
|
|
|
|
|
|
|
%% @private extracts the un-formatted src_dirs or extra_src_dirs |
|
|
|
%% options as configured. |
|
|
|
raw_src_dirs(Type, Opts, Default) -> |
|
|
|
ErlOpts = rebar_opts:erl_opts(Opts), |
|
|
|
Vs = proplists:get_all_values(Type, ErlOpts), |
|
|
@ -220,19 +270,23 @@ raw_src_dirs(Type, Opts, Default) -> |
|
|
|
Dirs -> Dirs |
|
|
|
end. |
|
|
|
|
|
|
|
%% @doc returns all the source directories (`src_dirs' and |
|
|
|
%% `extra_src_dirs'). |
|
|
|
-spec all_src_dirs(rebar_dict()) -> list(file:filename_all()). |
|
|
|
all_src_dirs(Opts) -> all_src_dirs(Opts, [], []). |
|
|
|
|
|
|
|
%% @doc returns all the source directories (`src_dirs' and |
|
|
|
%% `extra_src_dirs') while being able to configure defaults for both. |
|
|
|
-spec all_src_dirs(rebar_dict(), list(file:filename_all()), list(file:filename_all())) -> |
|
|
|
list(file:filename_all()). |
|
|
|
all_src_dirs(Opts, SrcDefault, ExtraDefault) -> |
|
|
|
lists:usort(src_dirs(Opts, SrcDefault) ++ extra_src_dirs(Opts, ExtraDefault)). |
|
|
|
|
|
|
|
%%%----------------------------------------------------------------- |
|
|
|
%%% @doc |
|
|
|
%%% Return the list of options for the given src directory |
|
|
|
%%% If the same option is given multiple times for a directory in the |
|
|
|
%%% config, the priority order is: first occurence of 'src_dirs' |
|
|
|
%%% followed by first occurence of 'extra_src_dirs'. |
|
|
|
%%% config, the priority order is: first occurence of `src_dirs' |
|
|
|
%%% followed by first occurence of `extra_src_dirs'. |
|
|
|
-spec src_dir_opts(rebar_dict(), file:filename_all()) -> [{atom(),term()}]. |
|
|
|
src_dir_opts(Opts, Dir) -> |
|
|
|
RawSrcDirs = raw_src_dirs(src_dirs, Opts, []), |
|
|
@ -241,7 +295,7 @@ src_dir_opts(Opts, Dir) -> |
|
|
|
D==Dir], |
|
|
|
lists:ukeysort(1,proplists:unfold(lists:append(AllOpts))). |
|
|
|
|
|
|
|
%%%----------------------------------------------------------------- |
|
|
|
%%% @doc |
|
|
|
%%% Return the value of the 'recursive' option for the given directory. |
|
|
|
%%% If not given, the value of 'recursive' in the 'erlc_compiler' |
|
|
|
%%% options is used, and finally the default is 'true'. |
|
|
@ -254,16 +308,17 @@ recursive(Opts, Dir) -> |
|
|
|
R = proplists:get_value(recursive, DirOpts, Default), |
|
|
|
R. |
|
|
|
|
|
|
|
%% 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 |
|
|
|
%% @doc 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). |
|
|
|
|
|
|
|
%% @private worker for retarget_path/2 |
|
|
|
%% @end |
|
|
|
%% not relative to any apps in project, check to see it's relative to |
|
|
|
%% project root |
|
|
|
retarget_path(State, Path, []) -> |
|
|
|