Selaa lähdekoodia

add help

pull/3/head
omarkj 10 vuotta sitten
vanhempi
commit
a1d030c964
54 muutettua tiedostoa jossa 1646 lisäystä ja 1308 poistoa
  1. +2
    -1
      .gitignore
  2. +14
    -3
      .travis.yml
  3. +11
    -8
      Makefile
  4. +22
    -21
      README.md
  5. +1
    -1
      bootstrap/bootstrap
  6. +0
    -3
      dialyzer_reference
  7. +93
    -0
      doc/guide.md
  8. +269
    -0
      doc/plugins.md
  9. +0
    -32
      ebin/rebar.app
  10. +9
    -11
      include/rebar.hrl
  11. +1
    -1
      priv/templates/gitignore.dtl
  12. +7
    -0
      priv/templates/otp_app.template
  13. +0
    -0
      priv/templates/otp_lib.template
  14. +29
    -0
      priv/templates/plugin.erl.dtl
  15. +7
    -0
      priv/templates/plugin.template
  16. +14
    -0
      priv/templates/plugin_README.md.dtl
  17. +16
    -23
      rebar.config
  18. +5
    -3
      src/rebar.app.src
  19. +61
    -62
      src/rebar3.erl
  20. +27
    -13
      src/rebar_app_discover.erl
  21. +32
    -29
      src/rebar_app_info.erl
  22. +17
    -51
      src/rebar_app_utils.erl
  23. +2
    -3
      src/rebar_config.erl
  24. +43
    -15
      src/rebar_core.erl
  25. +23
    -20
      src/rebar_erlc_compiler.erl
  26. +6
    -4
      src/rebar_fetch.erl
  27. +5
    -4
      src/rebar_packages.erl
  28. +27
    -1
      src/rebar_plugins.erl
  29. +0
    -165
      src/rebar_provider.erl
  30. +16
    -11
      src/rebar_prv_app_discovery.erl
  31. +44
    -0
      src/rebar_prv_clean.erl
  32. +110
    -9
      src/rebar_prv_common_test.erl
  33. +35
    -15
      src/rebar_prv_compile.erl
  34. +16
    -11
      src/rebar_prv_deps.erl
  35. +18
    -14
      src/rebar_prv_do.erl
  36. +20
    -23
      src/rebar_prv_erlydtl_compiler.erl
  37. +0
    -224
      src/rebar_prv_escripter.erl
  38. +35
    -15
      src/rebar_prv_help.erl
  39. +196
    -133
      src/rebar_prv_install_deps.erl
  40. +18
    -12
      src/rebar_prv_lock.erl
  41. +21
    -36
      src/rebar_prv_new.erl
  42. +16
    -11
      src/rebar_prv_packages.erl
  43. +26
    -14
      src/rebar_prv_release.erl
  44. +16
    -11
      src/rebar_prv_shell.erl
  45. +24
    -14
      src/rebar_prv_tar.erl
  46. +63
    -0
      src/rebar_prv_test_deps.erl
  47. +29
    -34
      src/rebar_prv_update.erl
  48. +55
    -0
      src/rebar_prv_upgrade.erl
  49. +16
    -11
      src/rebar_prv_version.erl
  50. +70
    -65
      src/rebar_state.erl
  51. +4
    -2
      src/rebar_templater.erl
  52. +22
    -26
      src/rebar_topo.erl
  53. +32
    -142
      src/rebar_utils.erl
  54. +1
    -1
      test/rebar_compile_SUITE.erl

+ 2
- 1
.gitignore Näytä tiedosto

@ -1,3 +1,4 @@
.depsolver_plt
*.beam *.beam
test/*_data test/*_data
logs logs
@ -14,4 +15,4 @@ rebar3
/.rebar /.rebar
rebar.lock rebar.lock
priv/templates/*.dtl.erl priv/templates/*.dtl.erl
ebin/rebar.app
ebin

+ 14
- 3
.travis.yml Näytä tiedosto

@ -1,10 +1,21 @@
language: erlang language: erlang
otp_release: otp_release:
- 17.0
- R16B02 - R16B02
- R16B01 - R16B01
- R15B01 - R15B01
- 17.0
script: "make travis"
script: make travis
branches: branches:
only: only:
- rebar3
- rebar3
before_deploy: "rm -rf !(rebar3)"
deploy:
on:
branch: rebar3
condition: $TRAVIS_OTP_RELEASE = R15B01
provider: s3
access_key_id: AKIAIKQB2JZYYNIWC72Q
secret_access_key:
secure: JoPSFeISsq7RbkgQLbz/DdLATgGhyuSjjIAwv0lZkhkHspmchArnt9hjDTxmkk8ApPcqDhp8iPEII6E8f2tltTA7djpxx8fO6a7DLyJnDe7QL4Qu1zSMmy91JmkapjDb8VqdAyvUmzAuCp91rfQPsgDiVQNrBSdCfy7LcTZyk3M=
bucket: "rebar3"
skip_cleanup: true

+ 11
- 8
Makefile Näytä tiedosto

@ -1,8 +1,10 @@
.PHONY: clean dialyzer_warnings xref_warnings deps test
.PHONY: clean xref_warnings deps test
REBAR=$(PWD)/rebar3 REBAR=$(PWD)/rebar3
RETEST=$(PWD)/deps/retest/retest RETEST=$(PWD)/deps/retest/retest
DEPS_PLT=$(CURDIR)/.depsolver_plt
all: all:
./bootstrap/bootstrap ./bootstrap/bootstrap
@ -11,23 +13,24 @@ clean:
@rm -f .rebarinfo @rm -f .rebarinfo
distclean: clean distclean: clean
@rm -f dialyzer_warnings
@rm -rf deps @rm -rf deps
debug: debug:
@./bootstrap/bootstrap debug @./bootstrap/bootstrap debug
check: debug xref dialyzer deps test
check: debug xref deps test
xref: xref:
@./rebar3 xref @./rebar3 xref
dialyzer: dialyzer_warnings
@diff -U0 dialyzer_reference dialyzer_warnings
$(DEPS_PLT):
@echo Building local erts plt at $(DEPS_PLT)
@echo
dialyzer --output_plt $(DEPS_PLT) --build_plt \
--apps erts kernel stdlib -r deps
dialyzer_warnings:
-@dialyzer -q -nn -n ebin -Wunmatched_returns -Werror_handling \
-Wrace_conditions > dialyzer_warnings
dialyzer: $(DEPS_PLT)
dialyzer --fullpath --plt $(DEPS_PLT) -Wno_opaque -Wrace_conditions -r ./ebin
binary: VSN = $(shell ./rebar3 -V) binary: VSN = $(shell ./rebar3 -V)
binary: clean all binary: clean all

+ 22
- 21
README.md Näytä tiedosto

@ -4,7 +4,7 @@ rebar
rebar is an Erlang build tool that makes it easy to compile and test Erlang rebar is an Erlang build tool that makes it easy to compile and test Erlang
applications, port drivers and releases. applications, port drivers and releases.
[![Build Status](https://secure.travis-ci.org/rebar/rebar.png?branch=master)](http://travis-ci.org/rebar/rebar)
[![Build Status](https://travis-ci.org/tsloughter/rebar.svg?branch=rebar3)](https://travis-ci.org/tsloughter/rebar)
rebar is a self-contained Erlang script, so it's easy to distribute or even rebar is a self-contained Erlang script, so it's easy to distribute or even
embed directly in a project. Where possible, rebar uses standard Erlang/OTP embed directly in a project. Where possible, rebar uses standard Erlang/OTP
@ -23,21 +23,24 @@ This is an experimental branch.
| Command | Description | | Command | Description |
|----------- |------------ | |----------- |------------ |
| compile | Build project | | compile | Build project |
| update | Update package index |
| clean | Remove project apps beam files |
| do | Higher-order provider to run multiple tasks in sequence |
| help | Print help for rebar or task |
| new | Create new rebar project from templates |
| pkgs | List available packages | | pkgs | List available packages |
| release | Build release of project |
| tar | Package release into tarball |
| shell | Run shell with project apps in path | | shell | Run shell with project apps in path |
| escriptize | Create escript from project |
| update | Update package index |
| upgrade | Fetch latest version of dep |
| version | Print current version of Erlang/OTP and rebar |
The following commands are still in the works. The following commands are still in the works.
| Command | Description | | Command | Description |
|----------- |------------ | |----------- |------------ |
| release | Build release of project |
| tar | Package release into tarball |
| new | |
| eunit | | | eunit | |
| ct | | | ct | |
| do | |
### Missing ### Missing
@ -69,8 +72,6 @@ Example:
-export([init/1, -export([init/1,
do/1]). do/1]).
-include("rebar.hrl").
-define(PROVIDER, something). -define(PROVIDER, something).
-define(DEPS, []). -define(DEPS, []).
@ -78,22 +79,22 @@ Example:
%% Public API %% Public API
%% =================================================================== %% ===================================================================
-spec init(rebar_config:config()) -> {ok, rebar_config:config()}.
-spec init(rebar_state:state()) -> {ok, rebar_state:state()}.
init(State) -> init(State) ->
State1 = rebar_config:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar something",
short_desc = "",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, rebar_provider:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar dummy"},
{short_desc, "dummy plugin."},
{desc, ""},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_config:config()) -> {ok, rebar_config:config()} | relx:error().
do(Config) ->
-spec do(rebar_state:state()) -> {ok, rebar_state:state()}.
do(State) ->
%% Do something %% Do something
{ok, Config}.
{ok, State}.
``` ```

+ 1
- 1
bootstrap/bootstrap Näytä tiedosto

@ -99,7 +99,7 @@ main(Args) ->
%% Add a helpful message %% Add a helpful message
io:format("Congratulations! You now have a self-contained script called" io:format("Congratulations! You now have a self-contained script called"
" \"rebar\" in\n"
" \"rebar3\" in\n"
"your current working directory. " "your current working directory. "
"Place this script anywhere in your path\n" "Place this script anywhere in your path\n"
"and you can use rebar to build OTP-compliant apps.\n"). "and you can use rebar to build OTP-compliant apps.\n").

+ 0
- 3
dialyzer_reference Näytä tiedosto

@ -1,3 +0,0 @@
rebar_eunit.erl:471: Call to missing or unexported function eunit_test:function_wrapper/2
rebar_utils.erl:197: Call to missing or unexported function escript:foldl/3

+ 93
- 0
doc/guide.md Näytä tiedosto

@ -0,0 +1,93 @@
## Why Rebar3?
Rebar was a great step forward for Erlang development but with time has proven to be fragile to change. Rebar3 builds on certain components of rebar which have benefited from years of community collaboration within a new core which is more extendable.
## Creating a New Project
```shell
$ rebar3 new rel myrelease
===> Writing apps/myrelease/src/myrelease_app.erl
===> Writing apps/myrelease/src/myrelease_sup.erl
===> Writing apps/myrelease/src/myrelease.app.src
===> Writing rebar.config
===> Writing relx.config
===> Writing config/sys.config
===> Writing config/vm.args
===> Writing .gitignore
===> Writing LICENSE
===> Writing README.md
```
## Working on an Existing Rebar3 Project
First, checkout the project and change directories to the project root.
```shell
$ git clone git://github.com/tsloughter/minansan.git
$ cd minansan
```
Now we can use rebar3 to fetch all dependencies and build both the dependencies and the project app or apps.
```shell
$ rebar3 compile
===> Fetching gproc
Cloning into '.tmp_dir109479658516'...
===> Fetching ranch
Cloning into '.tmp_dir725384773580'...
===> Fetching cowboy
Cloning into '.tmp_dir285325769000'...
===> Fetching cowlib
Cloning into '.tmp_dir924054839613'...
===> Compiling gproc
/home/tristan/Devel/minasan/_deps/gproc/src/gproc_dist.erl:23: Warning: behaviour gen_leader undefined
===> Compiling cowlib
===> Compiling ranch
===> Compiling cowboy
===> Compiling minasan
```
## Adding Dependencies
Dependencies are listed in `rebar.config` file under the `deps` key:
```erlang
{deps, [
{cowboy, ".*", {git, "git://github.com/ninenines/cowboy.git", {tag, "1.0.0"}}}
]}.
```
Then you'll most likely want to add the dependency to one of your project's application's `.app.src` file under applications.
## Rebar3 Conventions
Rebar3 is entirely based on building OTP applications and releases.
* Directories starting with underscores, e.g. `_deps`, are expected to not be checked in version control.
* Project apps you are working on exist under `apps/` or `lib/`, or is a single app project with `src/` in the root directory.
* `rebar.lock` and `rebar.config` go in the root of the project.
* Tests go in `tests/`.
## rebar.config vs rebar.lock
`rebar.lock` contains the exact reference id to a commit that was used to build the project. Committing this file allows you to specify a branch in `rebar.config` for a dependency and still have reproducable builds because if the `rebar.lock` file exists when a rebar3 project is being built the contents of deps in rebar.config are ignored.
## Checkout Dependencies
## Tests
Rebar3 has the concept of test dependencies. These dependencies will only be fetched when a rebar3 command that runs tests is run by the user.
```erlang
{test_deps, [
{meck, ".*", {git, "https://github.com/eproxus/meck.git", {tag, "0.8"}}}
]}.
```
```shell
$ rebar ct
===> Fetching meck
Cloning into '.tmp_dir772710363032'...
===> Compiling meck
===> Compiling minasan
```

+ 269
- 0
doc/plugins.md Näytä tiedosto

@ -0,0 +1,269 @@
#### TODO ####
- write a rebar3 template for plugin writing, make it easier on our poor souls
- rework the tutorial to use the rebar3 template for plugins
# Plugins #
Rebar3's system is based on the concept of *[providers](https://github.com/tsloughter/providers)*. A provider has three callbacks:
- `init(State) -> {ok, NewState}`, which helps set up the state required, state dependencies, etc.
- `do(State) -> {ok, NewState} | {error, String}`, which does the actual work.
- `format_error(Error, State) -> {String, NewState}`, which allows to print errors when they happen, and to filter out sensitive elements from the state.
A provider should also be an OTP Library application, which can be fetched as any other Erlang dependency, except for Rebar3 rather than your own system or application.
This document contains the following elements:
- [Using a Plugin](#using-a-plugin)
- [Reference](#reference)
- [Provider Interface](#provider-interface)
- [List of Possible Dependencies](#list-of-possible-dependencies)
- [Rebar State Manipulation](#rebar-state-manipulation)
- [Tutorial](#tutorial)
## Using a Plugin ##
## Reference ##
### Provider Interface ###
### List of Possible Dependencies ###
### Rebar State Manipulation ###
## Tutorial ##
### First version ###
In this tutorial, we'll show how to start from scratch, and get a basic plugin written. The plugin will be quite simple: it will look for instances of 'TODO:' lines in comments and report them as warnings. The final code for the plugin can be found on [bitbucket](https://bitbucket.org/ferd/rebar3-todo-plugin).
The first step is to create a new OTP Application that will contain the plugin:
→ git init
Initialized empty Git repository in /Users/ferd/code/self/rebar3-todo-plugin/.git/
→ mkdir src
→ touch src/provider_todo.erl src/provider_todo.app.src
Let's edit the app file to make sure the description is fine:
```erlang
{application, provider_todo, [
{description, "example rebar3 plubin"},
{vsn, "0.1.0"},
{registered, []},
{applications, [kernel, stdlib]},
{env, []}
]}.
```
Open up the `provider_todo.erl` file and make sure you have the following skeleton in place:
```erlang
-module(provider_todo).
-behaviour(provider).
-export([init/1, do/1, format_error/2]).
-include_lib("rebar3/include/rebar.hrl").
-define(PROVIDER, todo).
-define(DEPS, [app_discovery]).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Provider = providers:create([
{name, ?PROVIDER}, % The 'user friendly' name of the task
{module, ?MODULE}, % The module implementation of the task
{bare, true}, % The task can be run by the user, always true
{deps, ?DEPS}, % The list of dependencies
{example, "rebar $PLUGIN"}, % How to use the plugin
{opts, []} % list of options understood by the plugin
{short_desc, ""},
{desc, ""}
]),
{ok, rebar_state:add_provider(State, Provider)}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
```
This shows all the basic content needed. Note that we leave the `DEPS` macro to the value `app_discovery`, used to mean that the plugin should at least find the project's source code (excluding dependencies).
In this case, we need to change very little in `init/1`. Here's the new provider description:
```erlang
Provider = providers:create([
{name, ?PROVIDER}, % The 'user friendly' name of the task
{module, ?MODULE}, % The module implementation of the task
{bare, true}, % The task can be run by the user, always true
{deps, ?DEPS}, % The list of dependencies
{example, "rebar todo"}, % How to use the plugin
{opts, []}, % list of options understood by the plugin
{short_desc, "Reports TODOs in source code"},
{desc, "Scans top-level application source and find "
"instances of TODO: in commented out content "
"to report it to the user."}
]),
```
Instead, most of the work will need to be done directly in `do/1`. We'll use the `rebar_state` module to fetch all the applications we need. This can be done by calling the `project_apps/1` function, which returns the list of the project's top-level applications.
```erlang
do(State) ->
lists:foreach(fun check_todo_app/1, rebar_state:project_apps(State)),
{ok, State}.
```
This, on a high level, means that we'll check each top-level app one at a time (there may often be more than one top-level application when working with releases)
The rest is filler code specific to the plugin, in charge of reading each app path, go read code in there, and find instances of 'TODO:' in comments in the code:
```erlang
check_todo_app(App) ->
Path = filename:join(rebar_app_info:dir(App),"src"),
Mods = find_source_files(Path),
case lists:foldl(fun check_todo_mod/2, [], Mods) of
[] -> ok;
Instances -> display_todos(rebar_app_info:name(App), Instances)
end.
find_source_files(Path) ->
[filename:join(Path, Mod) || Mod <- filelib:wildcard("*.erl", Path)].
check_todo_mod(ModPath, Matches) ->
{ok, Bin} = file:read_file(ModPath),
case find_todo_lines(Bin) of
[] -> Matches;
Lines -> [{ModPath, Lines} | Matches]
end.
find_todo_lines(File) ->
case re:run(File, "%+.*(TODO:.*)", [{capture, all_but_first, binary}, global, caseless]) of
{match, DeepBins} -> lists:flatten(DeepBins);
nomatch -> []
end.
display_todos(_, []) -> ok;
display_todos(App, FileMatches) ->
io:format("Application ~s~n",[App]),
[begin
io:format("\t~s~n",[Mod]),
[io:format("\t ~s~n",[TODO]) || TODO <- TODOs]
end || {Mod, TODOs} <- FileMatches],
ok.
```
Just using `io:format/2` to output is going to be fine.
To test the plugin, push it to a source repository somewhere. Pick one of your projects, and add something to the rebar.config:
```erlang
{plugins, [
{provider_todo, ".*", {git, "git@bitbucket.org:ferd/rebar3-todo-plugin.git", {branch, "master"}}}
]}.
```
Then you can just call it directly:
```
→ rebar3 todo
===> Fetching provider_todo
Cloning into '.tmp_dir539136867963'...
===> Compiling provider_todo
Application merklet
/Users/ferd/code/self/merklet/src/merklet.erl
todo: consider endianness for absolute portability
```
Rebar3 will download and install the plugin, and figure out when to run it. Once compiled, it can be run at any time again.
### Optionally Search Deps ###
Let's extend things a bit. Maybe from time to time (when cutting a release), we'd like to make sure none of our dependencies contain 'TODO:'s either.
To do this, we'll need to go parse command line arguments a bit, and change our execution model. The `?DEPS` macro will now need to specify that the `todo` provider can only run *after* dependencies have been installed:
```erlang
-define(DEPS, [install_deps]).
```
We can add the option to the list we use to configure the provider in `init/1`:
```erlang
{opts, [ % list of options understood by the plugin
{deps, $d, "deps", undefined, "also run against dependencies"}
]},
```
Meaning that deps can be flagged in by using the option `-d` (or `--deps`), and if it's not defined, well, we get the default value `undefined`. The last element of the 4-tuple is documentation for the option.
And then we can implement the switch to figure out what to search:
```erlang
do(State) ->
Apps = case discovery_type(State) of
project -> rebar_state:project_apps(State);
deps -> rebar_state:project_apps(State) ++ rebar_state:src_deps(State)
end,
lists:foreach(fun check_todo_app/1, Apps),
{ok, State}.
[...]
discovery_type(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
case proplists:get_value(deps, Args) of
undefined -> project;
_ -> deps
end.
```
The `deps` option is found using `rebar_state:command_parsed_args(State)`, which will return a proplist of terms on the command-line after 'todo', and will take care of validating whether the flags are accepted or not. The rest can remain the same.
Push the new code for the plugin, and try it again on a project with dependencies:
```
→ rebar3 todo --deps
===> Fetching provider_todo
Cloning into '.tmp_dir846673888664'...
===> Compiling provider_todo
===> Fetching bootstrap
Cloning into '.tmp_dir57833696240'...
===> Fetching file_monitor
Cloning into '.tmp_dir403349997533'...
===> Fetching recon
Cloning into '.tmp_dir390854228780'...
[...]
Application dirmon
/Users/ferd/code/self/figsync/apps/dirmon/src/dirmon_tracker.erl
TODO: Peeranha should expose the UUID from a node.
Application meck
/Users/ferd/code/self/figsync/_deps/meck/src/meck_proc.erl
TODO: What to do here?
TODO: What to do here?
```
Rebar3 will now go pick dependencies before running the plugin on there.
you can also see that the help will be completed for you:
```
→ rebar3 help todo
Scans top-level application source and find instances of TODO: in commented out content to report it to the user.
Usage: rebar todo [-d]
-d, --deps also run against dependencies
```
That's it, the todo plugin is now complete! It's ready to ship and be included in other repositories.

+ 0
- 32
ebin/rebar.app Näytä tiedosto

@ -1,32 +0,0 @@
{application,rebar,
[{description,"Rebar: Erlang Build Tool"},
{vsn,"3.0.0"},
{modules,['LICENSE_dtl','README.md_dtl','app.erl_dtl',
gitignore_dtl,'mod.erl_dtl','otp_app.app.src_dtl',
'otp_lib.app.src_dtl','otp_lib.template_dtl',
'rebar.config_dtl',rebar3,rebar_app_discover,
rebar_app_info,rebar_app_utils,rebar_base_compiler,
rebar_config,rebar_core,rebar_erlc_compiler,
rebar_erlydtl_compiler,rebar_fetch,rebar_file_utils,
rebar_log,rebar_otp_app,rebar_packages,rebar_plugins,
rebar_provider,rebar_prv_app_discovery,
rebar_prv_compile,rebar_prv_deps,rebar_prv_do,
rebar_prv_escripter,rebar_prv_help,
rebar_prv_install_deps,rebar_prv_lock,rebar_prv_new,
rebar_prv_packages,rebar_prv_release,rebar_prv_shell,
rebar_prv_tar,rebar_prv_update,rebar_prv_version,
rebar_state,rebar_templater,rebar_topo,rebar_utils,
'relx.config_dtl','sup.erl_dtl','sys.config_dtl',
'vm.args_dtl']},
{registered,[]},
{applications,[kernel,stdlib,sasl,compiler,crypto,syntax_tools,
tools,erlware_commons,relx,inets]},
{env,[{log_level,warn},
{providers,[rebar_prv_escripter,rebar_prv_deps,
rebar_prv_do,rebar_prv_lock,
rebar_prv_install_deps,rebar_prv_packages,
rebar_erlydtl_compiler,rebar_prv_compile,
rebar_prv_app_discovery,rebar_prv_shell,
rebar_prv_tar,rebar_prv_new,rebar_prv_update,
rebar_prv_release,rebar_prv_version,
rebar_prv_help]}]}]}.

+ 9
- 11
include/rebar.hrl Näytä tiedosto

@ -13,16 +13,14 @@
-define(FMT(Str, Args), lists:flatten(io_lib:format(Str, Args))). -define(FMT(Str, Args), lists:flatten(io_lib:format(Str, Args))).
-record(provider, {name :: atom(), % The 'user friendly' name of the task
provider_impl :: atom(), % The implementation of the task, maybe fun or
bare :: boolean(), % Indicates whether a build config is needed
deps :: [atom()], % The list of dependencies
desc :: string(), % The description for the task
short_desc :: string(), % A one line short description of the task
example :: string(), % An example of the task usage
opts :: list()}). % The list of options that the task requires/understands
-define(DEFAULT_LIB_DIRS, ["apps", "libs", "."]).
-define(DEFAULT_DEPS_DIRS, ["deps"]).
-define(DEFAULT_LIB_DIRS, ["_checkouts", "apps", "libs", "."]).
-define(DEFAULT_DEPS_DIR, "_deps").
-define(DEFAULT_PLUGINS_DIR, "_plugins").
-define(DEFAULT_CONFIG_FILE, "rebar.config"). -define(DEFAULT_CONFIG_FILE, "rebar.config").
-define(LOCK_FILE, "rebar.lock"). -define(LOCK_FILE, "rebar.lock").
-ifdef(namespaced_types).
-type rebar_dict() :: dict:dict().
-else.
-type rebar_dict() :: dict().
-endif.

+ 1
- 1
priv/templates/gitignore.dtl Näytä tiedosto

@ -1,6 +1,6 @@
_*
.eunit .eunit
deps deps
priv
*.o *.o
*.beam *.beam
*.plt *.plt

+ 7
- 0
priv/templates/otp_app.template Näytä tiedosto

@ -0,0 +1,7 @@
{variables, []}.
{template, "app.erl", "src/{{appid}}_app.erl"}.
{template, "otp_app.app.src", "src/{{appid}}.app.src"}.
{template, "rebar.config", "rebar.config"}.
{template, "gitignore", ".gitignore"}.
{template, "LICENSE", "LICENSE"}.
{template, "README.md", "README.md"}.

priv/templates/otp_lib.template.dtl → priv/templates/otp_lib.template Näytä tiedosto


+ 29
- 0
priv/templates/plugin.erl.dtl Näytä tiedosto

@ -0,0 +1,29 @@
-module({{appid}}).
-behaviour(rebar_provider).
-export([init/1,
do/1]).
-define(PROVIDER, {{appid}}).
-define(DEPS, []).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
State1 = rebar_state:add_provider(State, rebar_provider:create([{name, ?PROVIDER},
{provider_impl, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar {{appid}}"},
{short_desc, "{{appid}} plugin."},
{desc, ""},
{opts, []}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
do(State) ->
{ok, State}.

+ 7
- 0
priv/templates/plugin.template Näytä tiedosto

@ -0,0 +1,7 @@
{variables, []}.
{template, "plugin.erl", "src/{{appid}}.erl"}.
{template, "otp_lib.app.src", "src/{{appid}}.app.src"}.
{template, "rebar.config", "rebar.config"}.
{template, "gitignore", ".gitignore"}.
{template, "LICENSE", "LICENSE"}.
{template, "plugin_README.md", "README.md"}.

+ 14
- 0
priv/templates/plugin_README.md.dtl Näytä tiedosto

@ -0,0 +1,14 @@
{{appid}}
=====
Rebar3 plugin
Build
-----
$ rebar3 compile
Use
---
$ rebar3 {{appid}}

+ 16
- 23
rebar.config Näytä tiedosto

@ -5,12 +5,19 @@
%% escript_incl_extra is for internal rebar-private use only. %% escript_incl_extra is for internal rebar-private use only.
%% Do not use outside rebar. Config interface is not stable. %% Do not use outside rebar. Config interface is not stable.
{escript_incl_extra, [{"priv/templates/*", "."}]}.
{escript_incl_extra, [{"priv/templates/*", "."}, {"rebar/include/*", "."}]}.
{escript_incl_apps, {escript_incl_apps,
[inets, getopt, erlydtl, erlware_commons, relx]}.
[inets, getopt, erlydtl, erlware_commons, relx, providers, rebar]}.
{escript_top_level_app, rebar}. {escript_top_level_app, rebar}.
{escript_name, rebar3}. {escript_name, rebar3}.
{erl_opts,
[{platform_define, "^[0-9]+", namespaced_types},
{platform_define, "^R1[4|5]", deprecated_crypto},
debug_info,
warnings_as_errors]}.
%% Types dict:dict() and digraph:digraph() have been introduced in Erlang 17. %% Types dict:dict() and digraph:digraph() have been introduced in Erlang 17.
%% At the same time, their counterparts dict() and digraph() are to be %% At the same time, their counterparts dict() and digraph() are to be
%% deprecated in Erlang 18. namespaced_types option is used to select proper %% deprecated in Erlang 18. namespaced_types option is used to select proper
@ -20,27 +27,13 @@
{platform_define, "^[0-9]+", namespaced_types} {platform_define, "^[0-9]+", namespaced_types}
]}. ]}.
{xref_checks, []}.
{xref_queries,
[{"(XC - UC) || (XU - X - B
- (\"escript\":\"foldl\"/\"3\")
- (\"eunit_test\":\"function_wrapper\"/\"2\")
- (\"abnfc\":\"file\"/\"2\")
- (\"erlydtl\":\"compile\"/\"3\")
- (\"lfe_comp\":\"file\"/\"2\")
- (\"neotoma\":\"file\"/\"2\")
- (\"protobuffs_compile\":\"scan_file\"/\"2\")
- (\"diameter_codegen\":\"from_dict\"/\"4\")
- (\"diameter_dict_util\":\"format_error\"/\"1\")
- (\"diameter_dict_util\":\"parse\"/\"2\"))",
[]}]}.
{first_files, [rebar_provider]}.
{deps, [{relx, "",
{git, "https://github.com/erlware/relx.git",
{branch, "master"}}},
{getopt, "", {git, "git@github.com:jcomellas/getopt.git", {branch, "master"}}}]}.
{deps, [{providers, "",
{git, "https://github.com/tsloughter/providers.git",
{branch, "format_error"}}},
{relx, "",
{git, "https://github.com/tsloughter/relx.git",
{branch, "format_error2"}}},
{getopt, "", {git, "https://github.com/jcomellas/getopt.git", {branch, "master"}}}]}.
{erlydtl_opts, [{doc_root, "priv/templates"}, {erlydtl_opts, [{doc_root, "priv/templates"},
{compiler_options, [report, return, debug_info]}]}. {compiler_options, [report, return, debug_info]}]}.

+ 5
- 3
src/rebar.app.src Näytä tiedosto

@ -21,22 +21,24 @@
{log_level, warn}, {log_level, warn},
%% any_dir processing modules %% any_dir processing modules
{providers, [rebar_prv_escripter,
{providers, [rebar_prv_clean,
rebar_prv_deps, rebar_prv_deps,
rebar_prv_do, rebar_prv_do,
rebar_prv_lock, rebar_prv_lock,
rebar_prv_install_deps, rebar_prv_install_deps,
rebar_prv_packages, rebar_prv_packages,
rebar_erlydtl_compiler,
rebar_prv_erlydtl_compiler,
rebar_prv_compile, rebar_prv_compile,
rebar_prv_app_discovery, rebar_prv_app_discovery,
rebar_prv_shell, rebar_prv_shell,
rebar_prv_tar, rebar_prv_tar,
rebar_prv_new, rebar_prv_new,
rebar_prv_update, rebar_prv_update,
rebar_prv_upgrade,
rebar_prv_release, rebar_prv_release,
rebar_prv_version, rebar_prv_version,
rebar_prv_common_test, rebar_prv_common_test,
rebar_prv_help]}
rebar_prv_help,
rebar_prv_test_deps]}
]} ]}
]}. ]}.

+ 61
- 62
src/rebar3.erl Näytä tiedosto

@ -28,15 +28,16 @@
-export([main/1, -export([main/1,
run/2, run/2,
option_spec_list/0,
global_option_spec_list/0,
init_config/0,
init_config1/1,
set_options/2,
parse_args/1, parse_args/1,
version/0, version/0,
log_level/1]).
log_level/0]).
-include("rebar.hrl"). -include("rebar.hrl").
-define(DEFAULT_JOBS, 3).
%% ==================================================================== %% ====================================================================
%% Public API %% Public API
%% ==================================================================== %% ====================================================================
@ -44,14 +45,21 @@
%% escript Entry point %% escript Entry point
main(Args) -> main(Args) ->
case catch(run(Args)) of case catch(run(Args)) of
ok ->
{ok, _State} ->
ok; ok;
rebar_abort -> rebar_abort ->
rebar_utils:delayed_halt(1); rebar_utils:delayed_halt(1);
{error, {Module, Reason}} ->
?ERROR(Module:format_error(Reason, []), []),
rebar_utils:delayed_halt(1);
{error, Error} ->
?ERROR(Error++"~n", []),
rebar_utils:delayed_halt(1);
Error -> Error ->
%% Nothing should percolate up from rebar_core; %% Nothing should percolate up from rebar_core;
%% Dump this error to console %% Dump this error to console
io:format("Uncaught error in rebar_core: ~p\n", [Error]),
?ERROR("Uncaught error in rebar_core. Run with DEBUG=1 to see stacktrace~n", []),
?DEBUG("Uncaught error: ~p~n", [Error]),
rebar_utils:delayed_halt(1) rebar_utils:delayed_halt(1)
end. end.
@ -59,7 +67,7 @@ main(Args) ->
run(BaseState, Command) -> run(BaseState, Command) ->
_ = application:load(rebar), _ = application:load(rebar),
BaseState1 = rebar_state:set(BaseState, task, Command), BaseState1 = rebar_state:set(BaseState, task, Command),
run_aux(BaseState1, []).
run_aux(BaseState1, [Command]).
%% ==================================================================== %% ====================================================================
%% Internal functions %% Internal functions
@ -67,24 +75,21 @@ run(BaseState, Command) ->
run(RawArgs) -> run(RawArgs) ->
ok = load_rebar_app(), ok = load_rebar_app(),
%% Parse out command line arguments -- what's left is a list of commands to
%% run -- and start running commands
Args = parse_args(RawArgs),
BaseConfig = init_config(Args),
{BaseConfig1, Args1} = set_options(BaseConfig, Args),
run_aux(BaseConfig1, Args1).
BaseConfig = init_config(),
{BaseConfig1, _Args1} = set_options(BaseConfig, {[], []}),
run_aux(BaseConfig1, RawArgs).
load_rebar_app() -> load_rebar_app() ->
%% Pre-load the rebar app so that we get default configuration %% Pre-load the rebar app so that we get default configuration
ok = application:load(rebar). ok = application:load(rebar).
init_config({Options, _NonOptArgs}) ->
init_config() ->
%% Initialize logging system %% Initialize logging system
Verbosity = log_level(Options),
Verbosity = log_level(),
ok = rebar_log:init(command_line, Verbosity), ok = rebar_log:init(command_line, Verbosity),
Config = case proplists:get_value(config, Options) of
undefined ->
Config = case os:getenv("REBAR_CONFIG") of
false ->
rebar_config:consult_file(?DEFAULT_CONFIG_FILE); rebar_config:consult_file(?DEFAULT_CONFIG_FILE);
ConfigFile -> ConfigFile ->
rebar_config:consult_file(ConfigFile) rebar_config:consult_file(ConfigFile)
@ -103,8 +108,8 @@ init_config({Options, _NonOptArgs}) ->
true -> true ->
?DEBUG("Load global config file ~p~n", ?DEBUG("Load global config file ~p~n",
[GlobalConfigFile]), [GlobalConfigFile]),
rebar_config:consult_file(GlobalConfigFile),
rebar_state:new(GlobalConfigFile, Config1);
GlobalConfig = rebar_state:new(rebar_config:consult_file(GlobalConfigFile)),
rebar_state:new(GlobalConfig, Config1);
false -> false ->
rebar_state:new(Config1) rebar_state:new(Config1)
end, end,
@ -123,7 +128,7 @@ init_config1(BaseConfig) ->
BaseConfig BaseConfig
end. end.
run_aux(State, Args) ->
run_aux(State, RawArgs) ->
%% Make sure crypto is running %% Make sure crypto is running
case crypto:start() of case crypto:start() of
ok -> ok; ok -> ok;
@ -136,28 +141,33 @@ run_aux(State, Args) ->
State1 = init_config1(State), State1 = init_config1(State),
code:add_pathsa([filename:join(rebar_utils:get_cwd(), "plugins")]),
%% Process each command, resetting any state between each one %% Process each command, resetting any state between each one
State2 = rebar_state:set(State1, base_dir, filename:absname(rebar_state:dir(State1))), State2 = rebar_state:set(State1, base_dir, filename:absname(rebar_state:dir(State1))),
{ok, Providers} = application:get_env(rebar, providers), {ok, Providers} = application:get_env(rebar, providers),
State3 = rebar_state:create_logic_providers(Providers, State2),
Task = rebar_state:get(State3, task, "help"),
rebar_core:process_command(rebar_state:command_args(State3, Args), list_to_atom(Task)),
ok.
{ok, PluginProviders, State3} = rebar_plugins:install(State2),
rebar_core:update_code_path(State3),
State4 = rebar_state:create_logic_providers(Providers++PluginProviders, State3),
{Task, Args} = parse_args(RawArgs),
rebar_core:process_command(rebar_state:command_args(State4, Args), list_to_atom(Task)).
%% %%
%% Parse command line arguments using getopt and also filtering out any %% Parse command line arguments using getopt and also filtering out any
%% key=value pairs. What's left is the list of commands to run %% key=value pairs. What's left is the list of commands to run
%% %%
parse_args(RawArgs) ->
%% Parse getopt options
OptSpecList = option_spec_list(),
case getopt:parse(OptSpecList, RawArgs) of
{ok, Args} ->;
Args;
{error, {Reason, Data}} ->
?ERROR("~s ~p~n~n", [Reason, Data]),
rebar_utils:delayed_halt(1)
end.
parse_args([]) ->
parse_args(["help"]);
parse_args([H | Rest]) when H =:= "-h"
; H =:= "--help" ->
parse_args(["help" | Rest]);
parse_args([H | Rest]) when H =:= "-v";
; H =:= "--version" ->
parse_args(["version" | Rest]);
parse_args([RawTask | RawRest]) ->
{RawTask, RawRest}.
set_options(State, {Options, NonOptArgs}) -> set_options(State, {Options, NonOptArgs}) ->
GlobalDefines = proplists:get_all_values(defines, Options), GlobalDefines = proplists:get_all_values(defines, Options),
@ -166,32 +176,26 @@ set_options(State, {Options, NonOptArgs}) ->
%% Set global variables based on getopt options %% Set global variables based on getopt options
State2 = set_global_flag(State1, Options, force), State2 = set_global_flag(State1, Options, force),
State3 = case proplists:get_value(jobs, Options, ?DEFAULT_JOBS) of
?DEFAULT_JOBS ->
State2;
Jobs ->
rebar_state:set(State2, jobs, Jobs)
end,
Task = proplists:get_value(task, Options, "help"), Task = proplists:get_value(task, Options, "help"),
{rebar_state:set(State3, task, Task), NonOptArgs}.
{rebar_state:set(State2, task, Task), NonOptArgs}.
%% %%
%% get log level based on getopt option %% get log level based on getopt option
%% %%
log_level(Options) ->
case proplists:get_bool(quiet, Options) of
true ->
rebar_log:error_level();
log_level() ->
case os:getenv("QUIET") of
false -> false ->
DefaultLevel = rebar_log:default_level(), DefaultLevel = rebar_log:default_level(),
case proplists:get_all_values(verbose, Options) of
[] ->
case os:getenv("DEBUG") of
false ->
DefaultLevel; DefaultLevel;
Verbosities ->
DefaultLevel + lists:last(Verbosities)
end
_ ->
DefaultLevel + 3
end;
_ ->
rebar_log:error_level()
end. end.
%% %%
@ -218,17 +222,12 @@ set_global_flag(State, Options, Flag) ->
%% %%
%% options accepted via getopt %% options accepted via getopt
%% %%
option_spec_list() ->
Jobs = ?DEFAULT_JOBS,
JobsHelp = io_lib:format(
"Number of concurrent workers a command may use. Default: ~B",
[Jobs]),
global_option_spec_list() ->
[ [
%% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg}
{help, $h, "help", undefined, "Print this help."},
{verbose, $v, "verbose", integer, "Verbosity level (-v, -vv)."},
{version, $V, "version", undefined, "Show version information."},
{jobs, $j, "jobs", integer, JobsHelp},
{config, $C, "config", string, "Rebar config file to use."},
{task, undefined, undefined, string, "Task to run."}
%% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg}
{help, $h, "help", undefined, "Print this help."},
%{verbose, $v, "verbose", integer, "Verbosity level (-v, -vv)."},
{version, $V, "version", undefined, "Show version information."},
%{config, $C, "config", string, "Rebar config file to use."},
{task, undefined, undefined, string, "Task to run."}
]. ].

+ 27
- 13
src/rebar_app_discover.erl Näytä tiedosto

@ -13,7 +13,8 @@ do(State, LibDirs) ->
Apps = find_apps(Dirs, all), Apps = find_apps(Dirs, all),
ProjectDeps = rebar_state:deps_names(State), ProjectDeps = rebar_state:deps_names(State),
lists:foldl(fun(AppInfo, StateAcc) -> lists:foldl(fun(AppInfo, StateAcc) ->
rebar_state:project_apps(StateAcc, rebar_app_info:deps(AppInfo, ProjectDeps))
ProjectDeps1 = lists:delete(rebar_app_info:name(AppInfo), ProjectDeps),
rebar_state:project_apps(StateAcc, rebar_app_info:deps(AppInfo, ProjectDeps1))
end, State, Apps). end, State, Apps).
-spec all_app_dirs(list(file:name())) -> list(file:name()). -spec all_app_dirs(list(file:name())) -> list(file:name()).
@ -47,14 +48,17 @@ app_dirs(LibDir) ->
find_unbuilt_apps(LibDirs) -> find_unbuilt_apps(LibDirs) ->
find_apps(LibDirs, invalid). find_apps(LibDirs, invalid).
-spec find_apps([file:filename_all()]) -> [rebar_app_info:t()].
find_apps(LibDirs) -> find_apps(LibDirs) ->
find_apps(LibDirs, valid). find_apps(LibDirs, valid).
-spec find_apps([file:filename_all()], valid | invalid | all) -> [rebar_app_info:t()].
find_apps(LibDirs, Validate) -> find_apps(LibDirs, Validate) ->
rebar_utils:filtermap(fun(AppDir) -> rebar_utils:filtermap(fun(AppDir) ->
find_app(AppDir, Validate) find_app(AppDir, Validate)
end, all_app_dirs(LibDirs)). end, all_app_dirs(LibDirs)).
-spec find_app(file:filename_all(), valid | invalid | all) -> {true, rebar_app_info:t()} | false.
find_app(AppDir, Validate) -> find_app(AppDir, Validate) ->
AppFile = filelib:wildcard(filename:join([AppDir, "ebin", "*.app"])), AppFile = filelib:wildcard(filename:join([AppDir, "ebin", "*.app"])),
AppSrcFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src"])), AppSrcFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src"])),
@ -104,12 +108,17 @@ find_app(AppDir, Validate) ->
app_dir(AppFile) -> app_dir(AppFile) ->
filename:join(rebar_utils:droplast(filename:split(filename:dirname(AppFile)))). filename:join(rebar_utils:droplast(filename:split(filename:dirname(AppFile)))).
-spec create_app_info(file:name(), file:name()) -> rebar_app_info:t() | error.
create_app_info(AppDir, AppFile) -> create_app_info(AppDir, AppFile) ->
case file:consult(AppFile) of case file:consult(AppFile) of
{ok, [{application, AppName, AppDetails}]} -> {ok, [{application, AppName, AppDetails}]} ->
AppVsn = proplists:get_value(vsn, AppDetails), AppVsn = proplists:get_value(vsn, AppDetails),
%AppDeps = proplists:get_value(applications, AppDetails, []),
C = rebar_config:consult(AppDir),
S = rebar_state:new(rebar_state:new(), C, AppDir),
AppDeps = rebar_state:deps_names(S),
AbsCwd = filename:absname(rebar_utils:get_cwd()), AbsCwd = filename:absname(rebar_utils:get_cwd()),
{ok, AppInfo} = rebar_app_info:new(AppName, AppVsn, AppDir),
{ok, AppInfo} = rebar_app_info:new(AppName, AppVsn, AppDir, AppDeps),
RebarConfig = filename:join(AppDir, "rebar.config"), RebarConfig = filename:join(AppDir, "rebar.config"),
AppState = case filelib:is_file(RebarConfig) of AppState = case filelib:is_file(RebarConfig) of
true -> true ->
@ -121,22 +130,28 @@ create_app_info(AppDir, AppFile) ->
AppState1 = rebar_state:set(AppState, base_dir, AbsCwd), AppState1 = rebar_state:set(AppState, base_dir, AbsCwd),
AppInfo1 = rebar_app_info:config( AppInfo1 = rebar_app_info:config(
rebar_app_info:app_details(AppInfo, AppDetails), AppState1), rebar_app_info:app_details(AppInfo, AppDetails), AppState1),
rebar_app_info:dir(AppInfo1, AppDir)
rebar_app_info:dir(AppInfo1, AppDir);
_ ->
error
end. end.
-spec validate_application_info(rebar_app_info:t()) -> boolean(). -spec validate_application_info(rebar_app_info:t()) -> boolean().
validate_application_info(AppInfo) -> validate_application_info(AppInfo) ->
EbinDir = rebar_app_info:ebin_dir(AppInfo), EbinDir = rebar_app_info:ebin_dir(AppInfo),
AppFile = rebar_app_info:app_file(AppInfo),
AppDetail = rebar_app_info:app_details(AppInfo),
case get_modules_list(AppFile, AppDetail) of
{ok, List} ->
has_all_beams(EbinDir, List);
_Error ->
false
case rebar_app_info:app_file(AppInfo) of
undefined ->
false;
AppFile ->
AppDetail = rebar_app_info:app_details(AppInfo),
case get_modules_list(AppFile, AppDetail) of
{ok, List} ->
has_all_beams(EbinDir, List);
_Error ->
false
end
end. end.
-spec get_modules_list(file:name(), proplists:proplist()) ->
-spec get_modules_list(file:filename_all(), proplists:proplist()) ->
{ok, list()} | {ok, list()} |
{warning, Reason::term()} | {warning, Reason::term()} |
{error, Reason::term()}. {error, Reason::term()}.
@ -148,8 +163,7 @@ get_modules_list(AppFile, AppDetail) ->
{ok, ModulesList} {ok, ModulesList}
end. end.
-spec has_all_beams(file:name(), list()) ->
ok | {error, Reason::term()}.
-spec has_all_beams(file:filename_all(), list()) -> boolean().
has_all_beams(EbinDir, [Module | ModuleList]) -> has_all_beams(EbinDir, [Module | ModuleList]) ->
BeamFile = filename:join([EbinDir, BeamFile = filename:join([EbinDir,
ec_cnv:to_list(Module) ++ ".beam"]), ec_cnv:to_list(Module) ++ ".beam"]),

+ 32
- 29
src/rebar_app_info.erl Näytä tiedosto

@ -1,7 +1,6 @@
-module(rebar_app_info). -module(rebar_app_info).
-export([new/0,
new/1,
-export([new/1,
new/2, new/2,
new/3, new/3,
new/4, new/4,
@ -21,6 +20,8 @@
ebin_dir/1, ebin_dir/1,
deps/1, deps/1,
deps/2, deps/2,
dep_level/1,
dep_level/2,
dir/1, dir/1,
dir/2, dir/2,
source/1, source/1,
@ -31,43 +32,40 @@
-export_type([t/0]). -export_type([t/0]).
-record(app_info_t, {name :: binary(), -record(app_info_t, {name :: binary(),
app_file_src :: file:name() | undefined,
app_file :: file:name(),
config :: rebar_config:config() | undefined,
original_vsn :: string(),
app_file_src :: file:filename_all() | undefined,
app_file :: file:filename_all() | undefined,
config :: rebar_state:t() | undefined,
original_vsn :: binary() | string() | undefined,
app_details=[] :: list(), app_details=[] :: list(),
deps=[] :: list(), deps=[] :: list(),
dep_level :: integer(),
dir :: file:name(), dir :: file:name(),
source :: string() | undefined,
source :: string() | tuple() | undefined,
valid :: boolean()}). valid :: boolean()}).
%%============================================================================ %%============================================================================
%% types %% types
%%============================================================================ %%============================================================================
-opaque t() :: record(app_info_t).
-type t() :: record(app_info_t).
%%============================================================================ %%============================================================================
%% API %% API
%% ============================================================================ %% ============================================================================
%% @doc Build a new, empty, app info value. This is not of a lot of use and you %% @doc Build a new, empty, app info value. This is not of a lot of use and you
%% probably wont be doing this much. %% probably wont be doing this much.
-spec new() -> {ok, t()}.
new() ->
{ok, #app_info_t{}}.
-spec new(atom() | binary() | string()) -> -spec new(atom() | binary() | string()) ->
{ok, t()}. {ok, t()}.
new(AppName) -> new(AppName) ->
{ok, #app_info_t{name=ec_cnv:to_binary(AppName)}}. {ok, #app_info_t{name=ec_cnv:to_binary(AppName)}}.
-spec new(atom() | binary() | string(), string()) ->
-spec new(atom() | binary() | string(), binary() | string()) ->
{ok, t()}. {ok, t()}.
new(AppName, Vsn) -> new(AppName, Vsn) ->
{ok, #app_info_t{name=ec_cnv:to_binary(AppName), {ok, #app_info_t{name=ec_cnv:to_binary(AppName),
original_vsn=Vsn}}. original_vsn=Vsn}}.
%% @doc build a complete version of the app info with all fields set. %% @doc build a complete version of the app info with all fields set.
-spec new(atom() | binary() | string(), string(), file:name()) ->
-spec new(atom() | binary() | string(), binary() | string(), file:name()) ->
{ok, t()}. {ok, t()}.
new(AppName, Vsn, Dir) -> new(AppName, Vsn, Dir) ->
{ok, #app_info_t{name=ec_cnv:to_binary(AppName), {ok, #app_info_t{name=ec_cnv:to_binary(AppName),
@ -75,7 +73,7 @@ new(AppName, Vsn, Dir) ->
dir=Dir}}. dir=Dir}}.
%% @doc build a complete version of the app info with all fields set. %% @doc build a complete version of the app info with all fields set.
-spec new(atom() | binary() | string(), string(), file:name(), list()) ->
-spec new(atom() | binary() | string(), binary() | string(), file:name(), list()) ->
{ok, t()}. {ok, t()}.
new(AppName, Vsn, Dir, Deps) -> new(AppName, Vsn, Dir, Deps) ->
{ok, #app_info_t{name=ec_cnv:to_binary(AppName), {ok, #app_info_t{name=ec_cnv:to_binary(AppName),
@ -84,17 +82,16 @@ new(AppName, Vsn, Dir, Deps) ->
deps=Deps}}. deps=Deps}}.
%% @doc discover a complete version of the app info with all fields set. %% @doc discover a complete version of the app info with all fields set.
-spec discover(file:name()) ->
{ok, t()}.
-spec discover(file:filename_all()) -> {ok, t()} | not_found.
discover(Dir) -> discover(Dir) ->
case rebar_app_discover:find_app(Dir, all) of case rebar_app_discover:find_app(Dir, all) of
{true, AppInfo} -> {true, AppInfo} ->
{ok, AppInfo}; {ok, AppInfo};
_ ->
false ->
not_found not_found
end. end.
-spec name(t()) -> atom().
-spec name(t()) -> binary().
name(#app_info_t{name=Name}) -> name(#app_info_t{name=Name}) ->
Name. Name.
@ -102,15 +99,15 @@ name(#app_info_t{name=Name}) ->
name(AppInfo=#app_info_t{}, AppName) -> name(AppInfo=#app_info_t{}, AppName) ->
AppInfo#app_info_t{name=ec_cnv:to_binary(AppName)}. AppInfo#app_info_t{name=ec_cnv:to_binary(AppName)}.
-spec config(t()) -> rebar_config:confg().
-spec config(t()) -> rebar_state:t().
config(#app_info_t{config=Config}) -> config(#app_info_t{config=Config}) ->
Config. Config.
-spec config(t(), rebar_config:confg()) -> t().
-spec config(t(), rebar_state:t()) -> t().
config(AppInfo=#app_info_t{}, Config) -> config(AppInfo=#app_info_t{}, Config) ->
AppInfo#app_info_t{config=Config}. AppInfo#app_info_t{config=Config}.
-spec app_file_src(t()) -> file:name().
-spec app_file_src(t()) -> file:filename_all() | undefined.
app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) -> app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) ->
AppFileSrc = filename:join([ec_cnv:to_list(Dir), "src", ec_cnv:to_list(Name)++".app.src"]), AppFileSrc = filename:join([ec_cnv:to_list(Dir), "src", ec_cnv:to_list(Name)++".app.src"]),
case filelib:is_file(AppFileSrc) of case filelib:is_file(AppFileSrc) of
@ -122,11 +119,11 @@ app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) ->
app_file_src(#app_info_t{app_file_src=AppFileSrc}) -> app_file_src(#app_info_t{app_file_src=AppFileSrc}) ->
ec_cnv:to_list(AppFileSrc). ec_cnv:to_list(AppFileSrc).
-spec app_file_src(t(), file:name()) -> t().
-spec app_file_src(t(), file:filename_all()) -> t().
app_file_src(AppInfo=#app_info_t{}, AppFileSrc) -> app_file_src(AppInfo=#app_info_t{}, AppFileSrc) ->
AppInfo#app_info_t{app_file_src=ec_cnv:to_list(AppFileSrc)}. AppInfo#app_info_t{app_file_src=ec_cnv:to_list(AppFileSrc)}.
-spec app_file(t()) -> file:name().
-spec app_file(t()) -> file:filename_all() | undefined.
app_file(#app_info_t{app_file=undefined, dir=Dir, name=Name}) -> app_file(#app_info_t{app_file=undefined, dir=Dir, name=Name}) ->
AppFile = filename:join([ec_cnv:to_list(Dir), "ebin", ec_cnv:to_list(Name)++".app"]), AppFile = filename:join([ec_cnv:to_list(Dir), "ebin", ec_cnv:to_list(Name)++".app"]),
case filelib:is_file(AppFile) of case filelib:is_file(AppFile) of
@ -138,9 +135,9 @@ app_file(#app_info_t{app_file=undefined, dir=Dir, name=Name}) ->
app_file(#app_info_t{app_file=AppFile}) -> app_file(#app_info_t{app_file=AppFile}) ->
AppFile. AppFile.
-spec app_file(t(), file:name()) -> t().
-spec app_file(t(), file:filename_all()) -> t().
app_file(AppInfo=#app_info_t{}, AppFile) -> app_file(AppInfo=#app_info_t{}, AppFile) ->
AppInfo#app_info_t{app_file=ec_cnv:to_list(AppFile)}.
AppInfo#app_info_t{app_file=AppFile}.
-spec app_details(t()) -> list(). -spec app_details(t()) -> list().
app_details(#app_info_t{app_details=AppDetails}) -> app_details(#app_info_t{app_details=AppDetails}) ->
@ -154,7 +151,7 @@ app_details(AppInfo=#app_info_t{}, AppDetails) ->
original_vsn(#app_info_t{original_vsn=Vsn}) -> original_vsn(#app_info_t{original_vsn=Vsn}) ->
Vsn. Vsn.
-spec original_vsn(t(), string()) -> string().
-spec original_vsn(t(), string()) -> t().
original_vsn(AppInfo=#app_info_t{}, Vsn) -> original_vsn(AppInfo=#app_info_t{}, Vsn) ->
AppInfo#app_info_t{original_vsn=Vsn}. AppInfo#app_info_t{original_vsn=Vsn}.
@ -166,6 +163,12 @@ deps(#app_info_t{deps=Deps}) ->
deps(AppInfo=#app_info_t{}, Deps) -> deps(AppInfo=#app_info_t{}, Deps) ->
AppInfo#app_info_t{deps=Deps}. AppInfo#app_info_t{deps=Deps}.
dep_level(AppInfo=#app_info_t{}, Level) ->
AppInfo#app_info_t{dep_level=Level}.
dep_level(#app_info_t{dep_level=Level}) ->
Level.
-spec dir(t()) -> file:name(). -spec dir(t()) -> file:name().
dir(#app_info_t{dir=Dir}) -> dir(#app_info_t{dir=Dir}) ->
Dir. Dir.
@ -178,11 +181,11 @@ dir(AppInfo=#app_info_t{}, Dir) ->
ebin_dir(#app_info_t{dir=Dir}) -> ebin_dir(#app_info_t{dir=Dir}) ->
filename:join(Dir, "ebin"). filename:join(Dir, "ebin").
-spec source(t(), string()) -> t().
-spec source(t(), string() | tuple()) -> t().
source(AppInfo=#app_info_t{}, Source) -> source(AppInfo=#app_info_t{}, Source) ->
AppInfo#app_info_t{source=Source}. AppInfo#app_info_t{source=Source}.
-spec source(t()) -> string().
-spec source(t()) -> string() | tuple().
source(#app_info_t{source=Source}) -> source(#app_info_t{source=Source}) ->
Source. Source.

+ 17
- 51
src/rebar_app_utils.erl Näytä tiedosto

@ -26,13 +26,14 @@
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
-module(rebar_app_utils). -module(rebar_app_utils).
-export([is_app_dir/0, is_app_dir/1,
-export([find/2,
find/3,
is_app_dir/0, is_app_dir/1,
is_app_src/1, is_app_src/1,
app_src_to_app/1, app_src_to_app/1,
app_name/2, app_name/2,
app_applications/2, app_applications/2,
app_vsn/2,
is_skipped_app/2]).
app_vsn/2]).
-export([load_app_file/2]). % TEMPORARY -export([load_app_file/2]). % TEMPORARY
@ -42,9 +43,22 @@
%% Public API %% Public API
%% =================================================================== %% ===================================================================
-spec find(binary(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
find(Name, Apps) ->
ec_lists:find(fun(App) -> rebar_app_info:name(App) =:= Name end, Apps).
-spec find(binary(), binary(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
find(Name, Vsn, Apps) ->
ec_lists:find(fun(App) ->
rebar_app_info:name(App) =:= Name
andalso rebar_app_info:original_vsn(App) =:= Vsn
end, Apps).
-spec is_app_dir() -> {true, file:name()} | false.
is_app_dir() -> is_app_dir() ->
is_app_dir(rebar_utils:get_cwd()). is_app_dir(rebar_utils:get_cwd()).
-spec is_app_dir(file:name()) -> {true, file:name()} | false.
is_app_dir(Dir) -> is_app_dir(Dir) ->
SrcDir = filename:join([Dir, "src"]), SrcDir = filename:join([Dir, "src"]),
AppSrc = filename:join([SrcDir, "*.app.src"]), AppSrc = filename:join([SrcDir, "*.app.src"]),
@ -109,30 +123,6 @@ app_vsn(Config, AppFile) ->
[AppFile, Reason]) [AppFile, Reason])
end. end.
is_skipped_app(Config, AppFile) ->
{Config1, ThisApp} = app_name(Config, AppFile),
%% Check for apps global parameter; this is a comma-delimited list
%% of apps on which we want to run commands
Skipped =
case get_apps(Config) of
undefined ->
%% No apps parameter specified, check the skip_apps list..
case get_skip_apps(Config) of
undefined ->
%% No skip_apps list, run everything..
false;
SkipApps ->
TargetApps = [list_to_atom(A) ||
A <- string:tokens(SkipApps, ",")],
is_skipped(ThisApp, TargetApps)
end;
Apps ->
%% run only selected apps
TargetApps = [list_to_atom(A) || A <- string:tokens(Apps, ",")],
is_selected(ThisApp, TargetApps)
end,
{Config1, Skipped}.
%% =================================================================== %% ===================================================================
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
@ -176,27 +166,3 @@ get_value(Key, AppInfo, AppFile) ->
Value -> Value ->
Value Value
end. end.
%% apps= for selecting apps
is_selected(ThisApp, TargetApps) ->
case lists:member(ThisApp, TargetApps) of
false ->
{true, ThisApp};
true ->
false
end.
%% skip_apps= for filtering apps
is_skipped(ThisApp, TargetApps) ->
case lists:member(ThisApp, TargetApps) of
false ->
false;
true ->
{true, ThisApp}
end.
get_apps(Config) ->
rebar_config:get_global(Config, apps, undefined).
get_skip_apps(Config) ->
rebar_config:get_global(Config, skip_apps, undefined).

+ 2
- 3
src/rebar_config.erl Näytä tiedosto

@ -35,11 +35,11 @@
%% Public API %% Public API
%% =================================================================== %% ===================================================================
-spec consult(file:name()) -> {ok, any()}.
-spec consult(file:name()) -> [any()].
consult(Dir) -> consult(Dir) ->
consult_file(filename:join(Dir, ?DEFAULT_CONFIG_FILE)). consult_file(filename:join(Dir, ?DEFAULT_CONFIG_FILE)).
-spec consult_file(file:name()) -> {ok, any()}.
-spec consult_file(file:name()) -> [any()].
consult_file(File) when is_binary(File) -> consult_file(File) when is_binary(File) ->
consult_file(binary_to_list(File)); consult_file(binary_to_list(File));
consult_file(File) -> consult_file(File) ->
@ -73,7 +73,6 @@ remove_script_ext(F) ->
try_consult(File) -> try_consult(File) ->
case file:consult(File) of case file:consult(File) of
{ok, Terms} -> {ok, Terms} ->
?DEBUG("Consult config file ~p~n", [File]),
Terms; Terms;
{error, enoent} -> {error, enoent} ->
[]; [];

+ 43
- 15
src/rebar_core.erl Näytä tiedosto

@ -26,33 +26,61 @@
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
-module(rebar_core). -module(rebar_core).
-export([process_command/2]).
-export([process_command/2
,update_code_path/1]).
-include("rebar.hrl"). -include("rebar.hrl").
-spec process_command(rebar_state:t(), atom()) -> {ok, rebar_state:t()} | {error, string()}.
process_command(State, Command) -> process_command(State, Command) ->
%% ? rebar_prv_install_deps:setup_env(State),
Providers = rebar_state:providers(State),
TargetProviders = providers:get_target_providers(Command, Providers),
case providers:get_provider(Command, Providers) of
not_found ->
{error, io_lib:format("Command ~p not found", [Command])};
CommandProvider ->
Opts = providers:opts(CommandProvider)++rebar3:global_option_spec_list(),
case Command of
do ->
do(TargetProviders, State);
_ ->
case getopt:parse(Opts, rebar_state:command_args(State)) of
{ok, Args} ->
State2 = rebar_state:command_parsed_args(State, Args),
do(TargetProviders, State2);
{error, {invalid_option, Option}} ->
{error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])}
end
end
end.
-spec do([atom()], rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do([], State) ->
{ok, State};
do([ProviderName | Rest], State) ->
Provider = providers:get_provider(ProviderName
,rebar_state:providers(State)),
case providers:do(Provider, State) of
{ok, State1} ->
do(Rest, State1);
{error, Error} ->
{error, Error}
end.
update_code_path(State) ->
true = rebar_utils:expand_code_path(), true = rebar_utils:expand_code_path(),
LibDirs = rebar_state:get(State, lib_dirs, ?DEFAULT_LIB_DIRS), LibDirs = rebar_state:get(State, lib_dirs, ?DEFAULT_LIB_DIRS),
DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIRS),
_UpdatedCodePaths = update_code_path([DepsDir | LibDirs]),
rebar_prv_install_deps:setup_env(State),
TargetProviders = rebar_provider:get_target_providers(Command, State),
DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR),
PluginsDir = rebar_state:get(State, plugins_dir, ?DEFAULT_PLUGINS_DIR),
_UpdatedCodePaths = update_code_path_([DepsDir, PluginsDir | LibDirs]).
lists:foldl(fun(TargetProvider, Conf) ->
Provider = rebar_provider:get_provider(TargetProvider
,rebar_state:providers(Conf)),
{ok, Conf1} = rebar_provider:do(Provider, Conf),
Conf1
end, State, TargetProviders).
%% =================================================================== %% ===================================================================
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
update_code_path([]) ->
no_change;
update_code_path(Paths) ->
update_code_path_(Paths) ->
LibPaths = expand_lib_dirs(Paths, rebar_utils:get_cwd(), []), LibPaths = expand_lib_dirs(Paths, rebar_utils:get_cwd(), []),
ok = code:add_pathsa(LibPaths), ok = code:add_pathsa(LibPaths),
%% track just the paths we added, so we can remove them without %% track just the paths we added, so we can remove them without

+ 23
- 20
src/rebar_erlc_compiler.erl Näytä tiedosto

@ -96,30 +96,30 @@ compile(Config, Dir) ->
rebar_base_compiler:run(Config, rebar_base_compiler:run(Config,
check_files(rebar_state:get( check_files(rebar_state:get(
Config, xrl_first_files, [])), Config, xrl_first_files, [])),
"src", ".xrl", "src", ".erl",
filename:join(Dir, "src"), ".xrl", filename:join(Dir, "src"), ".erl",
fun compile_xrl/3), fun compile_xrl/3),
rebar_base_compiler:run(Config, rebar_base_compiler:run(Config,
check_files(rebar_state:get( check_files(rebar_state:get(
Config, yrl_first_files, [])), Config, yrl_first_files, [])),
"src", ".yrl", "src", ".erl",
filename:join(Dir, "src"), ".yrl", filename:join(Dir, "src"), ".erl",
fun compile_yrl/3), fun compile_yrl/3),
rebar_base_compiler:run(Config, rebar_base_compiler:run(Config,
check_files(rebar_state:get( check_files(rebar_state:get(
Config, mib_first_files, [])), Config, mib_first_files, [])),
"mibs", ".mib", "priv/mibs", ".bin",
filename:join(Dir, "mibs"), ".mib", filename:join([Dir, "priv</span>", "mibs"]), ".bin",
fun compile_mib/3), fun compile_mib/3),
doterl_compile(Config, Dir). doterl_compile(Config, Dir).
-spec clean(rebar_state:t(), file:filename()) -> 'ok'. -spec clean(rebar_state:t(), file:filename()) -> 'ok'.
clean(Config, _AppFile) ->
MibFiles = rebar_utils:find_files("mibs", ?RE_PREFIX".*\\.mib\$"),
clean(Config, AppDir) ->
MibFiles = rebar_utils:find_files(filename:join(AppDir, "mibs"), ?RE_PREFIX".*\\.mib\$"),
MIBs = [filename:rootname(filename:basename(MIB)) || MIB <- MibFiles], MIBs = [filename:rootname(filename:basename(MIB)) || MIB <- MibFiles],
rebar_file_utils:delete_each( rebar_file_utils:delete_each(
[filename:join(["include",MIB++".hrl"]) || MIB <- MIBs]),
[filename:join([AppDir, "include",MIB++".hrl"]) || MIB <- MIBs]),
lists:foreach(fun(F) -> ok = rebar_file_utils:rm_rf(F) end, lists:foreach(fun(F) -> ok = rebar_file_utils:rm_rf(F) end,
["ebin/*.beam", "priv/mibs/*.bin"]),
[filename:join(AppDir, "ebin/*.beam"), filename:join(AppDir, "priv/mibs/*.bin")]),
YrlFiles = rebar_utils:find_files("src", ?RE_PREFIX".*\\.[x|y]rl\$"),
YrlFiles = rebar_utils:find_files(filename:join(AppDir, "src"), ?RE_PREFIX".*\\.[x|y]rl\$"),
rebar_file_utils:delete_each( rebar_file_utils:delete_each(
[ binary_to_list(iolist_to_binary(re:replace(F, "\\.[x|y]rl$", ".erl"))) [ binary_to_list(iolist_to_binary(re:replace(F, "\\.[x|y]rl$", ".erl")))
|| F <- YrlFiles ]), || F <- YrlFiles ]),
@ -131,9 +131,9 @@ clean(Config, _AppFile) ->
%% directory structure in ebin with .beam files within. As such, we want %% directory structure in ebin with .beam files within. As such, we want
%% to scan whatever is left in the ebin/ directory for sub-dirs which %% to scan whatever is left in the ebin/ directory for sub-dirs which
%% satisfy our criteria. %% satisfy our criteria.
BeamFiles = rebar_utils:find_files("ebin", ?RE_PREFIX".*\\.beam\$"),
BeamFiles = rebar_utils:find_files(filename:join(AppDir, "ebin"), ?RE_PREFIX".*\\.beam\$"),
rebar_file_utils:delete_each(BeamFiles), rebar_file_utils:delete_each(BeamFiles),
lists:foreach(fun(Dir) -> delete_dir(Dir, dirs(Dir)) end, dirs("ebin")),
lists:foreach(fun(Dir) -> delete_dir(Dir, dirs(Dir)) end, dirs(filename:join(AppDir, "ebin"))),
ok. ok.
%% =================================================================== %% ===================================================================
@ -241,14 +241,14 @@ test_compile_config_and_opts(Config, ErlOpts, Cmd) ->
%% *_first_files is questionable as the file would need to exist %% *_first_files is questionable as the file would need to exist
%% in all project directories for it to work. %% in all project directories for it to work.
OptsAtom = list_to_atom(Cmd ++ "_compile_opts"), OptsAtom = list_to_atom(Cmd ++ "_compile_opts"),
TestOpts = rebar_state:get_list(Config3, OptsAtom, []),
TestOpts = rebar_state:get(Config3, OptsAtom, []),
Opts0 = [{d, 'TEST'}] ++ Opts0 = [{d, 'TEST'}] ++
ErlOpts ++ TestOpts ++ TriqOpts ++ PropErOpts ++ EqcOpts, ErlOpts ++ TestOpts ++ TriqOpts ++ PropErOpts ++ EqcOpts,
Opts = [O || O <- Opts0, O =/= no_debug_info], Opts = [O || O <- Opts0, O =/= no_debug_info],
Config4 = rebar_state:set(Config3, erl_opts, Opts), Config4 = rebar_state:set(Config3, erl_opts, Opts),
FirstFilesAtom = list_to_atom(Cmd ++ "_first_files"), FirstFilesAtom = list_to_atom(Cmd ++ "_first_files"),
FirstErls = rebar_state:get_list(Config4, FirstFilesAtom, []),
FirstErls = rebar_state:get(Config4, FirstFilesAtom, []),
Config5 = rebar_state:set(Config4, erl_first_files, FirstErls), Config5 = rebar_state:set(Config4, erl_first_files, FirstErls),
{Config5, Opts}. {Config5, Opts}.
@ -274,7 +274,7 @@ define_if(Def, true) -> [{d, Def}];
define_if(_Def, false) -> []. define_if(_Def, false) -> [].
is_lib_avail(Config, DictKey, Mod, Hrl, Name) -> is_lib_avail(Config, DictKey, Mod, Hrl, Name) ->
case rebar_state:get_xconf(Config, DictKey, undefined) of
case rebar_state:get(Config, DictKey, undefined) of
undefined -> undefined ->
IsAvail = case code:lib_dir(Mod, include) of IsAvail = case code:lib_dir(Mod, include) of
{error, bad_name} -> {error, bad_name} ->
@ -282,17 +282,17 @@ is_lib_avail(Config, DictKey, Mod, Hrl, Name) ->
Dir -> Dir ->
filelib:is_regular(filename:join(Dir, Hrl)) filelib:is_regular(filename:join(Dir, Hrl))
end, end,
NewConfig = rebar_state:set_xconf(Config, DictKey, IsAvail),
NewConfig = rebar_state:set(Config, DictKey, IsAvail),
?DEBUG("~s availability: ~p\n", [Name, IsAvail]), ?DEBUG("~s availability: ~p\n", [Name, IsAvail]),
{NewConfig, IsAvail}; {NewConfig, IsAvail};
IsAvail -> IsAvail ->
{Config, IsAvail} {Config, IsAvail}
end. end.
-spec doterl_compile(rebar_state:t(), file:filename()) -> 'ok'.
doterl_compile(Config, Dir) ->
ErlOpts = rebar_utils:erl_opts(Config),
doterl_compile(Config, Dir, [], ErlOpts).
-spec doterl_compile(rebar_state:t(), file:filename()) -> ok.
doterl_compile(State, Dir) ->
ErlOpts = rebar_utils:erl_opts(State),
doterl_compile(State, Dir, [], ErlOpts).
doterl_compile(Config, Dir, MoreSources, ErlOpts) -> doterl_compile(Config, Dir, MoreSources, ErlOpts) ->
OutDir = filename:join(Dir, "ebin"), OutDir = filename:join(Dir, "ebin"),
@ -634,16 +634,19 @@ compile_yrl(Source, Target, Config) ->
-spec compile_xrl_yrl(rebar_state:t(), file:filename(), -spec compile_xrl_yrl(rebar_state:t(), file:filename(),
file:filename(), list(), module()) -> 'ok'. file:filename(), list(), module()) -> 'ok'.
compile_xrl_yrl(Config, Source, Target, Opts, Mod) -> compile_xrl_yrl(Config, Source, Target, Opts, Mod) ->
Dir = rebar_state:dir(Config),
Opts1 = [{includefile, filename:join(Dir, I)} || {includefile, I} <- Opts,
filename:pathtype(I) =:= relative],
case needs_compile(Source, Target, []) of case needs_compile(Source, Target, []) of
true -> true ->
case Mod:file(Source, Opts ++ [{return, true}]) of
case Mod:file(Source, Opts1 ++ [{return, true}]) of
{ok, _} -> {ok, _} ->
ok; ok;
{ok, _Mod, Ws} -> {ok, _Mod, Ws} ->
rebar_base_compiler:ok_tuple(Config, Source, Ws); rebar_base_compiler:ok_tuple(Config, Source, Ws);
{error, Es, Ws} -> {error, Es, Ws} ->
rebar_base_compiler:error_tuple(Config, Source, rebar_base_compiler:error_tuple(Config, Source,
Es, Ws, Opts)
Es, Ws, Opts1)
end; end;
false -> false ->
skipped skipped

+ 6
- 4
src/rebar_fetch.erl Näytä tiedosto

@ -49,14 +49,16 @@ lock_source(_AppDir, Source) ->
download_source(AppDir, Source) -> download_source(AppDir, Source) ->
TmpDir = ec_file:insecure_mkdtemp(), TmpDir = ec_file:insecure_mkdtemp(),
AppDir1 = ec_cnv:to_list(AppDir), AppDir1 = ec_cnv:to_list(AppDir),
ec_file:mkdir_p(AppDir1),
case download_source_tmp(TmpDir, Source) of case download_source_tmp(TmpDir, Source) of
{ok, _} -> {ok, _} ->
ec_file:mkdir_p(AppDir1),
ok = ec_file:copy(TmpDir, filename:absname(AppDir1), [recursive]); ok = ec_file:copy(TmpDir, filename:absname(AppDir1), [recursive]);
{tarball, File} -> {tarball, File} ->
ok = erl_tar:extract(File, [{cwd,
(filename:dirname(filename:absname(AppDir1)))}
,compressed])
ok = erl_tar:extract(File, [{cwd, TmpDir}
,compressed]),
BaseName = filename:basename(AppDir1),
[FromDir] = filelib:wildcard(filename:join(TmpDir, BaseName++"-*")),
ec_file:copy(FromDir, AppDir1, [recursive])
end. end.
download_source_tmp(TmpDir, {p4, Url}) -> download_source_tmp(TmpDir, {p4, Url}) ->

+ 5
- 4
src/rebar_packages.erl Näytä tiedosto

@ -4,7 +4,7 @@
-include("rebar.hrl"). -include("rebar.hrl").
-spec get_packages(rebar_state:t()) -> {list(), rlx_depsolver:t()}.
-spec get_packages(rebar_state:t()) -> {rebar_dict(), rlx_depsolver:t()}.
get_packages(State) -> get_packages(State) ->
RebarDir = rebar_state:get(State, global_rebar_dir, filename:join(os:getenv("HOME"), ".rebar")), RebarDir = rebar_state:get(State, global_rebar_dir, filename:join(os:getenv("HOME"), ".rebar")),
PackagesFile = filename:join(RebarDir, "packages"), PackagesFile = filename:join(RebarDir, "packages"),
@ -12,12 +12,13 @@ get_packages(State) ->
true -> true ->
try try
{ok, Binary} = file:read_file(PackagesFile), {ok, Binary} = file:read_file(PackagesFile),
binary_to_term(Binary)
{Dict, Graph} = binary_to_term(Binary),
{Dict, Graph}
catch catch
_:_ -> _:_ ->
?ERROR("Bad packages index, try to fix with `rebar update`~n", []), ?ERROR("Bad packages index, try to fix with `rebar update`~n", []),
{[], rlx_depsolver:new()}
{dict:new(), rlx_depsolver:new_graph()}
end; end;
false -> false ->
{[], rlx_depsolver:new()}
{dict:new(), rlx_depsolver:new_graph()}
end. end.

+ 27
- 1
src/rebar_plugins.erl Näytä tiedosto

@ -3,10 +3,36 @@
-module(rebar_plugins). -module(rebar_plugins).
-export([]).
-export([install/1]).
-include("rebar.hrl"). -include("rebar.hrl").
%% =================================================================== %% ===================================================================
%% Public API %% Public API
%% =================================================================== %% ===================================================================
install(State) ->
State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
Plugins = rebar_state:get(State1, plugins, []),
{ok, State2} = rebar_prv_install_deps:handle_deps(State1, Plugins),
Apps = rebar_state:get(State2, all_deps, []),
ToBuild = lists:dropwhile(fun rebar_app_info:valid/1, Apps),
lists:foreach(fun(AppInfo) ->
C = rebar_config:consult(rebar_app_info:dir(AppInfo)),
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)),
rebar_prv_compile:build(S, AppInfo)
end, ToBuild),
PluginProviders = plugin_providers(Plugins),
{ok, PluginProviders, rebar_state:set(State2, deps_dir, ?DEFAULT_DEPS_DIR)}.
plugin_providers(Plugins) ->
lists:map(fun({Plugin, _, _}) when is_atom(Plugin) ->
Plugin;
({Plugin, _}) when is_atom(Plugin) ->
Plugin;
(Plugin) when is_atom(Plugin) ->
Plugin
end, Plugins).

+ 0
- 165
src/rebar_provider.erl Näytä tiedosto

@ -1,165 +0,0 @@
-module(rebar_provider).
%% API
-export([new/2,
do/2,
impl/1,
get_provider/2,
get_target_providers/2,
help/1,
format/1]).
-export_type([t/0]).
-include("rebar.hrl").
%%%===================================================================
%%% Types
%%%===================================================================
-opaque t() :: record(provider).
-type provider_name() :: atom().
-ifdef(have_callback_support).
-callback init(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-callback do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-else.
%% In the case where R14 or lower is being used to compile the system
%% we need to export a behaviour info
-export([behaviour_info/1]).
-spec behaviour_info(atom()) -> [{atom(), arity()}] | undefined.
behaviour_info(callbacks) ->
[{init, 1},
{do, 1}];
behaviour_info(_) ->
undefined.
-endif.
%%%===================================================================
%%% API
%%%===================================================================
%% @doc create a new provider object from the specified module. The
%% module should implement the provider behaviour.
%%
%% @param ModuleName The module name.
%% @param State0 The current state of the system
-spec new(module(), rebar_state:t()) ->
{ok, rebar_state:t()}.
new(ModuleName, State0) when is_atom(ModuleName) ->
case code:which(ModuleName) of
non_existing ->
?ERROR("Module ~p does not exist.", [ModuleName]);
_ ->
ModuleName:init(State0)
end.
%% @doc Manipulate the state of the system, that new state
%%
%% @param Provider the provider object
%% @param State the current state of the system
-spec do(Provider::t(), rebar_state:t()) ->
{ok, rebar_state:t()}.
do(Provider, State) ->
{PreHooks, PostHooks} = rebar_state:hooks(State, Provider#provider.name),
{ok, State1} = run_hook_plugins(PreHooks, State),
{ok, State2} = (Provider#provider.provider_impl):do(State1),
run_hook_plugins(PostHooks, State2).
run_hook_plugins(Hooks, State) ->
State1 = lists:foldl(fun(Hook, StateAcc) ->
{ok, StateAcc1} = rebar_provider:do(Hook, StateAcc),
StateAcc1
end, State, Hooks),
{ok, State1}.
%%% @doc get the name of the module that implements the provider
%%% @param Provider the provider object
-spec impl(Provider::t()) -> module().
impl(Provider) ->
Provider#provider.name.
help(State) ->
Providers = rebar_state:providers(State),
Help = lists:sort([{ec_cnv:to_list(P#provider.name), P#provider.short_desc} || P <- Providers,
P#provider.bare =/= true]),
Longest = lists:max([length(X) || {X, _} <- Help]),
lists:foreach(fun({Name, ShortDesc}) ->
Length = length(Name),
Spacing = lists:duplicate(Longest - Length + 8, " "),
io:format("~s~s~s~n", [Name, Spacing, ShortDesc])
end, Help).
%% @doc print the provider module name
%%
%% @param T - The provider
%% @return An iolist describing the provider
-spec format(t()) -> iolist().
format(#provider{name=Name}) ->
atom_to_list(Name).
get_target_providers(Target, State) ->
Providers = rebar_state:providers(State),
TargetProviders = lists:filter(fun(#provider{name=T}) when T =:= Target->
true;
(#provider{name=T}) ->
false
end, Providers),
process_deps(TargetProviders, Providers).
-spec get_provider(provider_name(), [t()]) -> t().
get_provider(ProviderName, [Provider = #provider{name = ProviderName} | _]) ->
Provider;
get_provider(ProviderName, [_ | Rest]) ->
get_provider(ProviderName, Rest);
get_provider(_ProviderName, _) ->
[].
process_deps([], _Providers) ->
[];
process_deps(TargetProviders, Providers) ->
DepChain = lists:flatmap(fun(Provider) ->
{DC, _, _} = process_deps(Provider, Providers, []),
DC
end, TargetProviders),
['NONE' | Rest] =
reorder_providers(lists:flatten([{'NONE', P#provider.name} || P <- TargetProviders] ++ DepChain)),
Rest.
process_deps(Provider, Providers, Seen) ->
case lists:member(Provider, Seen) of
true ->
{[], Providers, Seen};
false ->
Deps = Provider#provider.deps,
DepList = lists:map(fun(Dep) ->
{Dep, Provider#provider.name}
end, Deps),
{NewDeps, _, NewSeen} =
lists:foldl(fun(Arg, Acc) ->
process_dep(Arg, Acc)
end,
{[], Providers, Seen}, Deps),
{[DepList | NewDeps], Providers, NewSeen}
end.
process_dep(ProviderName, {Deps, Providers, Seen}) ->
Provider = get_provider(ProviderName, Providers),
{NewDeps, _, NewSeen} = process_deps(Provider, Providers, [ProviderName | Seen]),
{[Deps | NewDeps], Providers, NewSeen}.
%% @doc Reorder the providers according to thier dependency set.
reorder_providers(OProviderList) ->
case rebar_topo:sort(OProviderList) of
{ok, ProviderList} ->
ProviderList;
{cycle, _} ->
?ERROR("There was a cycle in the provider list. Unable to complete build!", [])
end.

+ 16
- 11
src/rebar_prv_app_discovery.erl Näytä tiedosto

@ -3,10 +3,11 @@
-module(rebar_prv_app_discovery). -module(rebar_prv_app_discovery).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,18 +20,22 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = true,
deps = ?DEPS,
example = "",
short_desc = "",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, true},
{deps, ?DEPS},
{example, ""},
{short_desc, ""},
{desc, ""},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
LibDirs = rebar_state:get(State, lib_dirs, ?DEFAULT_LIB_DIRS), LibDirs = rebar_state:get(State, lib_dirs, ?DEFAULT_LIB_DIRS),
State1 = rebar_app_discover:do(State, LibDirs), State1 = rebar_app_discover:do(State, LibDirs),
{ok, State1}. {ok, State1}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.

+ 44
- 0
src/rebar_prv_clean.erl Näytä tiedosto

@ -0,0 +1,44 @@
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 et
-module(rebar_prv_clean).
-behaviour(provider).
-export([init/1,
do/1,
format_error/2]).
-include("rebar.hrl").
-define(PROVIDER, clean).
-define(DEPS, [app_discovery]).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar clean"},
{short_desc, "Remove compiled beam files from apps."},
{desc, ""},
{opts, []}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
ProjectApps = rebar_state:project_apps(State),
lists:foreach(fun(AppInfo) ->
?INFO("Cleaning out ~s...~n", [rebar_app_info:name(AppInfo)]),
rebar_erlc_compiler:clean(State, ec_cnv:to_list(rebar_app_info:dir(AppInfo)))
end, ProjectApps),
{ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.

+ 110
- 9
src/rebar_prv_common_test.erl Näytä tiedosto

@ -6,6 +6,7 @@
-behaviour(rebar_provider). -behaviour(rebar_provider).
-export([init/1, -export([init/1,
format_error/2,
do/1]). do/1]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,15 +20,15 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State,
#provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar ct",
short_desc = "Run Common Tests",
desc = "",
opts = []}),
Provider = providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{deps, ?DEPS},
{bare, false},
{example, "rebar ct"},
{short_desc, "Run Common Tests"},
{desc, ""},
{opts, ct_opts(State)}]),
State1 = rebar_state:add_provider(State, Provider),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
@ -36,6 +37,106 @@ do(State) ->
ct:run_test(Opts), ct:run_test(Opts),
{ok, State}. {ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
ct_opts(State) ->
DefaultTestDir = filename:join([rebar_state:dir(State), "test"]),
DefaultLogsDir = filename:join([rebar_state:dir(State), "logs"]),
[{dir, undefined, "dir", {string, DefaultTestDir}, help(dir)}, %% dir
{suite, undefined, "suite", string, help(suite)}, %% comma-seperated list
{group, undefined, "group", string, help(group)}, %% comma-seperated list
{testcase, undefined, "case", string, help(testcase)}, %% comma-seperated list
{spec, undefined, "spec", string, help(spec)}, %% comma-seperated list
{join_specs, undefined, "join_specs", boolean, help(join_specs)}, %% Boolean
{label, undefined, "label", string, help(label)}, %% String
{config, undefined, "config", string, help(config)}, %% comma-seperated list
{userconfig, undefined, "userconfig", string, help(userconfig)}, %% [{CallbackMod, CfgStrings}] | {CallbackMod, CfgStrings}
{allow_user_terms, undefined, "allow_user_terms", boolean, help(allow_user_terms)}, %% Bool
{logdir, undefined, "logdir", {string, DefaultLogsDir}, help(logdir)}, %% string
{logopts, undefined, "logopts", string, help(logopts)}, %% enum, no_nl | no_src
{verbosity, undefined, "verbosity", string, help(verbosity)}, %% Integer OR [{Category, VLevel}]
{silent_connections, undefined, "silent_connections", string,
help(silent_connections)}, % all OR %% comma-seperated list
{stylesheet, undefined, "stylesheet", string, help(stylesheet)}, %% file
{cover, undefined, "cover", string, help(cover)}, %% file
{cover_stop, undefined, "cover_stop", boolean, help(cover_stop)}, %% Boolean
{event_handler, undefined, "event_handler", string, help(event_handler)}, %% EH | [EH] WHERE EH atom() | {atom(), InitArgs} | {[atom()], InitArgs}
{include, undefined, "include", string, help(include)},
{abort_if_missing_suites, undefined, "abort_if_missing_suites", {boolean, true},
help(abort_if_missing_suites)}, %% boolean
{multiply_timetraps, undefined, "multiply_timetraps", integer,
help(multiply_timetraps)}, %% integer
{scale_timetraps, undefined, "scale_timetraps", boolean, help(scale_timetraps)}, %% Boolean
{create_priv_dir, undefined, "create_priv_dir", string, help(create_priv_dir)}, %% enum: auto_per_run | auto_per_tc | manual_per_tc
{repeat, undefined, "repeat", integer, help(repeat)}, %% integer
{duration, undefined, "duration", string, help(duration)}, % format: HHMMSS
{until, undefined, "until", string, help(until)}, %% format: YYMoMoDD[HHMMSS]
{force_stop, undefined, "force_stop", string, help(force_stop)}, % enum: skip_rest, bool
{basic_html, undefined, "basic_html", boolean, help(basic_html)}, %% Booloean
{ct_hooks, undefined, "ct_hooks", string, help(ct_hooks)} %% List: [CTHModule | {CTHModule, CTHInitArgs}] where CTHModule is atom CthInitArgs is term
].
help(dir) ->
"Test folder (default: test/)";
help(suite) ->
"List of test suites to run";
help(group) ->
"List of test groups to run";
help(testcase) ->
"List of test cases to run";
help(spec) ->
"List of test specs to run";
help(join_specs) ->
""; %% ??
help(label) ->
"Test label";
help(config) ->
"List of config files";
help(allow_user_terms) ->
""; %% ??
help(logdir) ->
"Log folder";
help(logopts) ->
""; %% ??
help(verbosity) ->
"Verbosity";
help(silent_connections) ->
""; %% ??
help(stylesheet) ->
"Stylesheet to use for test results";
help(cover) ->
"Cover file to use";
help(cover_stop) ->
""; %% ??
help(event_handler) ->
"Event handlers to attach to the runner";
help(include) ->
"Include folder";
help(abort_if_missing_suites) ->
"Abort if suites are missing";
help(multiply_timetraps) ->
""; %% ??
help(scale_timetraps) ->
""; %% ??
help(create_priv_dir) ->
""; %% ??
help(repeat) ->
"How often to repeat tests";
help(duration) ->
"Max runtime (format: HHMMSS)";
help(until) ->
"Run until (format: HHMMSS)";
help(force_stop) ->
"Force stop after time";
help(basic_html) ->
"Show basic HTML";
help(ct_hooks) ->
"";
help(userconfig) ->
"".
build_options(State) -> build_options(State) ->
Arguments = rebar_state:command_args(State), Arguments = rebar_state:command_args(State),
Opts = parse_args(Arguments, []), Opts = parse_args(Arguments, []),

+ 35
- 15
src/rebar_prv_compile.erl Näytä tiedosto

@ -1,9 +1,10 @@
-module(rebar_prv_compile). -module(rebar_prv_compile).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1, do/1,
format_error/2,
build/2]). build/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -11,34 +12,48 @@
-define(PROVIDER, compile). -define(PROVIDER, compile).
-define(DEPS, [lock]). -define(DEPS, [lock]).
-define(DEFAULT_JOBS, 3).
%% =================================================================== %% ===================================================================
%% Public API %% Public API
%% =================================================================== %% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar compile",
short_desc = "Compile apps .app.src and .erl files.",
desc = "",
opts = []}),
JobsHelp = io_lib:format(
"Number of concurrent workers the compiler may use. Default: ~B",
[?DEFAULT_JOBS]),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar compile"},
{short_desc, "Compile apps .app.src and .erl files."},
{desc, ""},
{opts, [
{jobs, $j, "jobs", integer, JobsHelp}
]}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
ProjectApps = rebar_state:project_apps(State),
Deps = rebar_state:get(State, deps_to_build, []),
{ok, State1} = handle_args(State),
ProjectApps = rebar_state:project_apps(State1),
Deps = rebar_state:get(State1, deps_to_build, []),
lists:foreach(fun(AppInfo) -> lists:foreach(fun(AppInfo) ->
C = rebar_config:consult(rebar_app_info:dir(AppInfo)),
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)),
AppDir = rebar_app_info:dir(AppInfo),
C = rebar_config:consult(AppDir),
S = rebar_state:new(State1, C, AppDir),
build(S, AppInfo) build(S, AppInfo)
end, Deps++ProjectApps), end, Deps++ProjectApps),
{ok, State}.
{ok, State1}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
build(State, AppInfo) -> build(State, AppInfo) ->
?INFO("Compiling ~s~n", [rebar_app_info:name(AppInfo)]), ?INFO("Compiling ~s~n", [rebar_app_info:name(AppInfo)]),
@ -49,3 +64,8 @@ build(State, AppInfo) ->
%% =================================================================== %% ===================================================================
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
handle_args(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
Jobs = proplists:get_value(jobs, Args, ?DEFAULT_JOBS),
{ok, rebar_state:set(State, jobs, Jobs)}.

+ 16
- 11
src/rebar_prv_deps.erl Näytä tiedosto

@ -1,9 +1,10 @@
-module(rebar_prv_deps). -module(rebar_prv_deps).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -12,20 +13,24 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = true,
deps = ?DEPS,
example = "rebar deps",
short_desc = "List dependencies",
desc = info("List dependencies"),
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, true},
{deps, ?DEPS},
{example, "rebar deps"},
{short_desc, "List dependencies"},
{desc, info("List dependencies")},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
{ok, State}. {ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
info(Description) -> info(Description) ->
io_lib:format("~s.~n" io_lib:format("~s.~n"
"~n" "~n"

+ 18
- 14
src/rebar_prv_do.erl Näytä tiedosto

@ -3,10 +3,11 @@
-module(rebar_prv_do). -module(rebar_prv_do).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,27 +20,30 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar3 do <task1>, <task2>, ...",
short_desc = "Higher order provider for running multiple tasks in a sequence.",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar3 do <task1>, <task2>, ..."},
{short_desc, "Higher order provider for running multiple tasks in a sequence."},
{desc, ""},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
Tasks = args_to_tasks(rebar_state:command_args(State)), Tasks = args_to_tasks(rebar_state:command_args(State)),
State1 = lists:foldl(fun(TaskArgs, StateAcc) ->
lists:foldl(fun(TaskArgs, {ok, StateAcc}) ->
[TaskStr | Args] = string:tokens(TaskArgs, " "), [TaskStr | Args] = string:tokens(TaskArgs, " "),
Task = list_to_atom(TaskStr), Task = list_to_atom(TaskStr),
StateAcc1 = rebar_state:set(StateAcc, task, Task), StateAcc1 = rebar_state:set(StateAcc, task, Task),
StateAcc2 = rebar_state:command_args(StateAcc1, Args), StateAcc2 = rebar_state:command_args(StateAcc1, Args),
rebar_core:process_command(StateAcc2, Task) rebar_core:process_command(StateAcc2, Task)
end, State, Tasks),
{ok, State1}.
end, {ok, State}, Tasks).
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
args_to_tasks(Args) -> args_to_tasks(Args) ->
[string:strip(T) || T <- string:tokens(string:join(Args, " "), ",")]. [string:strip(T) || T <- string:tokens(string:join(Args, " "), ",")].

src/rebar_erlydtl_compiler.erl → src/rebar_prv_erlydtl_compiler.erl Näytä tiedosto

@ -92,12 +92,13 @@
%% {doc_root, "templates"}, {module_ext, ""}, {source_ext, ".html"} %% {doc_root, "templates"}, {module_ext, ""}, {source_ext, ".html"}
%% ] %% ]
%% ]}. %% ]}.
-module(rebar_erlydtl_compiler).
-module(rebar_prv_erlydtl_compiler).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
%% for internal use only %% for internal use only
-export([info/2]). -export([info/2]).
@ -113,22 +114,23 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar erlydtl compile",
short_desc = "Compile erlydtl templates.",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar erlydtl compile"},
{short_desc, "Compile erlydtl templates."},
{desc, ""},
{opts, []}])),
{ok, State1}. {ok, State1}.
do(Config) -> do(Config) ->
MultiDtlOpts = erlydtl_opts(Config), MultiDtlOpts = erlydtl_opts(Config),
OrigPath = code:get_path(), OrigPath = code:get_path(),
true = code:add_path(rebar_utils:ebin_dir()),
%true = code:add_path(rebar_utils:ebin_dir()),
Result = lists:foldl(fun(DtlOpts, _) -> Result = lists:foldl(fun(DtlOpts, _) ->
file:make_dir(option(out_dir, DtlOpts)),
rebar_base_compiler:run(Config, [], rebar_base_compiler:run(Config, [],
option(doc_root, DtlOpts), option(doc_root, DtlOpts),
option(source_ext, DtlOpts), option(source_ext, DtlOpts),
@ -144,6 +146,10 @@ do(Config) ->
true = code:set_path(OrigPath), true = code:set_path(OrigPath),
{Result, Config}. {Result, Config}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
%% =================================================================== %% ===================================================================
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
@ -230,24 +236,15 @@ do_compile(Config, Source, Target, DtlOpts) ->
Opts = lists:ukeymerge(1, DtlOpts, Sorted), Opts = lists:ukeymerge(1, DtlOpts, Sorted),
?INFO("Compiling \"~s\" -> \"~s\" with options:~n ~s~n", ?INFO("Compiling \"~s\" -> \"~s\" with options:~n ~s~n",
[Source, Target, io_lib:format("~p", [Opts])]), [Source, Target, io_lib:format("~p", [Opts])]),
case erlydtl:compile(Source,
module_name(Target),
case erlydtl:compile_file(ec_cnv:to_list(Source),
list_to_atom(module_name(Target)),
Opts) of Opts) of
ok ->
ok;
{ok, _Mod} -> {ok, _Mod} ->
ok; ok;
{ok, _Mod, Ws} -> {ok, _Mod, Ws} ->
rebar_base_compiler:ok_tuple(Config, Source, Ws); rebar_base_compiler:ok_tuple(Config, Source, Ws);
{ok, _Mod, _Bin, Ws} ->
rebar_base_compiler:ok_tuple(Config, Source, Ws);
error -> error ->
rebar_base_compiler:error_tuple(Config, Source, [], [], Opts); rebar_base_compiler:error_tuple(Config, Source, [], [], Opts);
{error, {_File, _Msgs} = Error} ->
rebar_base_compiler:error_tuple(Config, Source, [Error], [], Opts);
{error, Msg} ->
Es = [{Source, [{erlydtl_parser, Msg}]}],
rebar_base_compiler:error_tuple(Config, Source, Es, [], Opts);
{error, Es, Ws} -> {error, Es, Ws} ->
rebar_base_compiler:error_tuple(Config, Source, Es, Ws, Opts) rebar_base_compiler:error_tuple(Config, Source, Es, Ws, Opts)
end. end.

+ 0
- 224
src/rebar_prv_escripter.erl Näytä tiedosto

@ -1,224 +0,0 @@
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 et
%% -------------------------------------------------------------------
%%
%% rebar: Erlang Build Tools
%%
%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
%%
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%%
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%%
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
%% -------------------------------------------------------------------
-module(rebar_prv_escripter).
-behaviour(rebar_provider).
-export([init/1,
do/1]).
-export([escriptize/2,
clean/2]).
%% for internal use only
-export([info/2]).
-include("rebar.hrl").
-include_lib("kernel/include/file.hrl").
-define(PROVIDER, escriptize).
-define(DEPS, [app_builder]).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar escriptize",
short_desc = "Build escript from project.",
desc = "",
opts = []}),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
do(Config) ->
AppName = rebar_state:get_local(Config, escript_top_level_app, undefined),
App = rebar_state:get_app(Config, AppName),
{ok, Config1} = escriptize(Config, rebar_app_info:app_file(App)),
{ok, Config1}.
escriptize(Config0, AppFile) ->
%% Extract the application name from the archive -- this is the default
%% name of the generated script
{Config, AppName} = rebar_app_utils:app_name(Config0, AppFile),
AppNameStr = atom_to_list(AppName),
%% Get the output filename for the escript -- this may include dirs
Filename = rebar_state:get_local(Config, escript_name, AppName),
ok = filelib:ensure_dir(Filename),
%% Look for a list of other applications (dependencies) to include
%% in the output file. We then use the .app files for each of these
%% to pull in all the .beam files.
InclBeams = get_app_beams(
rebar_state:get_local(Config, escript_incl_apps, []), []),
%% Look for a list of extra files to include in the output file.
%% For internal rebar-private use only. Do not use outside rebar.
InclExtra = get_extra(Config),
%% Construct the archive of everything in ebin/ dir -- put it on the
%% top-level of the zip file so that code loading works properly.
EbinPrefix = filename:join(AppNameStr, "ebin"),
EbinFiles = usort(load_files(EbinPrefix, "*", "ebin")),
ExtraFiles = usort(InclBeams ++ InclExtra),
Files = EbinFiles ++ ExtraFiles,
case zip:create("mem", Files, [memory]) of
{ok, {"mem", ZipBin}} ->
%% Archive was successfully created. Prefix that binary with our
%% header and write to our escript file
Shebang = rebar_state:get(Config, escript_shebang,
"#!/usr/bin/env escript\n"),
Comment = rebar_state:get(Config, escript_comment, "%%\n"),
DefaultEmuArgs = ?FMT("%%! -pa ~s/~s/ebin\n",
[AppNameStr, AppNameStr]),
EmuArgs = rebar_state:get(Config, escript_emu_args,
DefaultEmuArgs),
Script = iolist_to_binary([Shebang, Comment, EmuArgs, ZipBin]),
case file:write_file(Filename, Script) of
ok ->
ok;
{error, WriteError} ->
?ERROR("Failed to write ~p script: ~p\n",
[AppName, WriteError]),
?FAIL
end;
{error, ZipError} ->
?ERROR("Failed to construct ~p escript: ~p\n",
[AppName, ZipError]),
?FAIL
end,
%% Finally, update executable perms for our script
{ok, #file_info{mode = Mode}} = file:read_file_info(Filename),
ok = file:change_mode(Filename, Mode bor 8#00111),
{ok, Config}.
clean(Config0, AppFile) ->
%% Extract the application name from the archive -- this is the default
%% name of the generated script
{Config, AppName} = rebar_app_utils:app_name(Config0, AppFile),
%% Get the output filename for the escript -- this may include dirs
Filename = rebar_state:get_local(Config, escript_name, AppName),
rebar_file_utils:delete_each([Filename]),
{ok, Config}.
%% ===================================================================
%% Internal functions
%% ===================================================================
info(help, escriptize) ->
info_help("Generate escript archive");
info(help, clean) ->
info_help("Delete generated escript archive").
info_help(Description) ->
?CONSOLE(
"~s.~n"
"~n"
"Valid rebar.config options:~n"
" ~p~n"
" ~p~n"
" ~p~n"
" ~p~n"
" ~p~n",
[
Description,
{escript_name, "application"},
{escript_incl_apps, []},
{escript_shebang, "#!/usr/bin/env escript\n"},
{escript_comment, "%%\n"},
{escript_emu_args, "%%! -pa application/application/ebin\n"}
]).
get_app_beams([], Acc) ->
Acc;
get_app_beams([App | Rest], Acc) ->
case code:lib_dir(App, ebin) of
{error, bad_name} ->
?ABORT("Failed to get ebin/ directory for "
"~p escript_incl_apps.", [App]);
Path ->
Prefix = filename:join(atom_to_list(App), "ebin"),
Acc2 = load_files(Prefix, "*", Path),
get_app_beams(Rest, Acc2 ++ Acc)
end.
get_extra(Config) ->
Extra = rebar_state:get_local(Config, escript_incl_extra, []),
lists:foldl(fun({Wildcard, Dir}, Files) ->
load_files(Wildcard, Dir) ++ Files
end, [], Extra).
load_files(Wildcard, Dir) ->
load_files("", Wildcard, Dir).
load_files(Prefix, Wildcard, Dir) ->
[read_file(Prefix, Filename, Dir)
|| Filename <- filelib:wildcard(Wildcard, Dir)].
read_file(Prefix, Filename, Dir) ->
Filename1 = case Prefix of
"" ->
Filename;
_ ->
filename:join([Prefix, Filename])
end,
[dir_entries(filename:dirname(Filename1)),
{Filename1, file_contents(filename:join(Dir, Filename))}].
file_contents(Filename) ->
{ok, Bin} = file:read_file(Filename),
Bin.
%% Given a filename, return zip archive dir entries for each sub-dir.
%% Required to work around issues fixed in OTP-10071.
dir_entries(File) ->
Dirs = dirs(File),
[{Dir ++ "/", <<>>} || Dir <- Dirs].
%% Given "foo/bar/baz", return ["foo", "foo/bar", "foo/bar/baz"].
dirs(Dir) ->
dirs1(filename:split(Dir), "", []).
dirs1([], _, Acc) ->
lists:reverse(Acc);
dirs1([H|T], "", []) ->
dirs1(T, H, [H]);
dirs1([H|T], Last, Acc) ->
Dir = filename:join(Last, H),
dirs1(T, Dir, [Dir|Acc]).
usort(List) ->
lists:ukeysort(1, lists:flatten(List)).

+ 35
- 15
src/rebar_prv_help.erl Näytä tiedosto

@ -3,10 +3,11 @@
-module(rebar_prv_help). -module(rebar_prv_help).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,30 +20,49 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar help <task>",
short_desc = "Display a list of tasks or help for a given task or subtask.",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar help <task>"},
{short_desc, "Display a list of tasks or help for a given task or subtask."},
{desc, "Display a list of tasks or help for a given task or subtask."},
{opts, [
{help_task, undefined, undefined, string, "Task to print help for."}
]}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
help(State),
{ok, State}.
{Args, _} = rebar_state:command_parsed_args(State),
case proplists:get_value(help_task, Args, undefined) of
undefined ->
help(State),
{ok, State};
Name ->
Providers = rebar_state:providers(State),
case providers:get_provider(list_to_atom(Name), Providers) of
not_found ->
{error, io_lib:format("Unknown task ~s", [Name])};
Provider ->
providers:help(Provider),
{ok, State}
end
end.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
%% %%
%% print help/usage string %% print help/usage string
%% %%
help(State) -> help(State) ->
?CONSOLE("Rebar is a tool for working with Erlang projects.~n~n", []), ?CONSOLE("Rebar is a tool for working with Erlang projects.~n~n", []),
OptSpecList = rebar3:option_spec_list(),
OptSpecList = rebar3:global_option_spec_list(),
getopt:usage(OptSpecList, "rebar", "", []), getopt:usage(OptSpecList, "rebar", "", []),
?CONSOLE("~nSeveral tasks are available:~n", []), ?CONSOLE("~nSeveral tasks are available:~n", []),
rebar_provider:help(State),
providers:help(rebar_state:providers(State)),
?CONSOLE("~nRun 'rebar help <TASK>' for details.~n~n", []). ?CONSOLE("~nRun 'rebar help <TASK>' for details.~n~n", []).

+ 196
- 133
src/rebar_prv_install_deps.erl Näytä tiedosto

@ -26,14 +26,16 @@
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
-module(rebar_prv_install_deps). -module(rebar_prv_install_deps).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
-export([setup_env/1]).
-export([handle_deps/2,
handle_deps/3]).
%% for internal use only %% for internal use only
-export([get_deps_dir/1]). -export([get_deps_dir/1]).
@ -43,9 +45,9 @@
-define(DEPS, [app_discovery]). -define(DEPS, [app_discovery]).
-type src_dep() :: {atom(), string(), {atom(), string(), string()}}. -type src_dep() :: {atom(), string(), {atom(), string(), string()}}.
-type binary_dep() :: {atom(), binary()} | atom().
-type pkg_dep() :: {atom(), binary()} | atom().
-type dep() :: src_dep() | binary_dep().
-type dep() :: src_dep() | pkg_dep().
%% =================================================================== %% ===================================================================
%% Public API %% Public API
@ -53,174 +55,237 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = true,
deps = ?DEPS,
example = undefined,
short_desc = "Install dependencies",
desc = info("Install dependencies"),
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, true},
{deps, ?DEPS},
{example, undefined},
{short_desc, "Install dependencies"},
{desc, info("Install dependencies")},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
case rebar_state:get(State, locks, []) of
[] ->
handle_deps(State, ordsets:from_list(rebar_state:get(State, deps, [])));
Locks ->
handle_deps(State, ordsets:from_list(Locks))
ProjectApps = rebar_state:project_apps(State),
{ok, State1} = case rebar_state:get(State, locks, []) of
[] ->
handle_deps(State, rebar_state:get(State, deps, []));
Locks ->
handle_deps(State, Locks)
end,
Source = ProjectApps ++ rebar_state:src_apps(State1),
case rebar_topo:sort_apps(Source) of
{ok, Sort} ->
{ok, rebar_state:set(State1, deps_to_build, lists:dropwhile(fun rebar_app_info:valid/1, Sort -- ProjectApps))};
{error, Error} ->
{error, Error}
end. end.
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables
setup_env(State) ->
DepsDir = get_deps_dir(State),
%% include rebar's DepsDir in ERL_LIBS
Separator = case os:type() of
{win32, nt} ->
";";
_ ->
":"
end,
ERL_LIBS = case os:getenv("ERL_LIBS") of
false ->
{"ERL_LIBS", DepsDir};
PrevValue ->
{"ERL_LIBS", DepsDir ++ Separator ++ PrevValue}
end,
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS].
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
-spec get_deps_dir(rebar_state:t()) -> file:filename_all(). -spec get_deps_dir(rebar_state:t()) -> file:filename_all().
get_deps_dir(State) -> get_deps_dir(State) ->
BaseDir = rebar_state:get(State, base_dir, ""), BaseDir = rebar_state:get(State, base_dir, ""),
get_deps_dir(BaseDir, "deps").
DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR),
get_deps_dir(BaseDir, DepsDir).
-spec get_deps_dir(file:filename_all(), rebar_state:t()) -> file:filename_all().
-spec get_deps_dir(file:filename_all(), file:filename_all()) -> file:filename_all().
get_deps_dir(DepsDir, App) -> get_deps_dir(DepsDir, App) ->
filename:join(DepsDir, App). filename:join(DepsDir, App).
%% ===================================================================
%% Internal functions
%% ===================================================================
-spec handle_deps(rebar_state:t(), [dep()]) -> {ok, rebar_state:t()}. -spec handle_deps(rebar_state:t(), [dep()]) -> {ok, rebar_state:t()}.
handle_deps(State, []) ->
{ok, State};
handle_deps(State, Deps) -> handle_deps(State, Deps) ->
handle_deps(State, Deps, false).
-spec handle_deps(rebar_state:t(), [dep()], boolean() | {true, binary(), integer()})
-> {ok, rebar_state:t()}.
handle_deps(State, [], _) ->
{ok, State};
handle_deps(State, Deps, Update) ->
%% Read in package index and dep graph %% Read in package index and dep graph
{Packages, Graph} = rebar_packages:get_packages(State), {Packages, Graph} = rebar_packages:get_packages(State),
ProjectApps = rebar_state:project_apps(State),
%% Split source deps form binary deps, needed to keep backwards compatibility
%% Split source deps from pkg deps, needed to keep backwards compatibility
DepsDir = get_deps_dir(State), DepsDir = get_deps_dir(State),
{SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps),
State1 = rebar_state:src_deps(rebar_state:binary_deps(State, BinaryDeps),
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps),
State1 = rebar_state:src_deps(rebar_state:pkg_deps(State, PkgDeps),
SrcDeps), SrcDeps),
%% Fetch transitive src deps %% Fetch transitive src deps
State2 = update_src_deps(State1),
Solved = case rebar_state:binary_deps(State2) of
[] -> %% No binary deps
[];
BinaryDeps1 ->
%% Find binary deps needed
{ok, S} = rlx_depsolver:solve(Graph, BinaryDeps1),
%% Create app_info record for each binary dep
lists:map(fun({Name, Vsn}) ->
AppInfo = package_to_app(DepsDir
,Packages
,Name
,Vsn),
ok = maybe_fetch(AppInfo),
AppInfo
end, S)
State2 = update_src_deps(0, State1, Update),
Solved = case rebar_state:pkg_deps(State2) of
[] -> %% No pkg deps
[];
PkgDeps1 ->
%% Find pkg deps needed
{ok, S} = rlx_depsolver:solve(Graph, PkgDeps1),
%% Create app_info record for each pkg dep
[AppInfo || Pkg <- S,
AppInfo <- package_to_app(DepsDir
,Packages
,Pkg),
maybe_fetch(AppInfo, Update)]
end, end,
Source = ProjectApps ++ ordsets:to_list(rebar_state:src_deps(State2)),
AllDeps = ordsets:union([ordsets:to_list(rebar_state:src_deps(State2))
,ordsets:from_list(Solved)]),
AllDeps = lists:ukeymerge(2
,lists:ukeysort(2, rebar_state:src_apps(State2))
,lists:ukeysort(2, Solved)),
%% Sort all apps to build order %% Sort all apps to build order
State3 = rebar_state:set(State2, all_deps, AllDeps), State3 = rebar_state:set(State2, all_deps, AllDeps),
{ok, Sort} = rebar_topo:sort_apps(ordsets:to_list(Source)),
{ok, rebar_state:set(State3, deps_to_build, lists:dropwhile(fun is_valid/1, Sort -- ProjectApps))}.
{ok, State3}.
%% ===================================================================
%% Internal functions
%% ===================================================================
-spec is_valid(rebar_app_info:t()) -> boolean().
is_valid(App) ->
rebar_app_info:valid(App).
package_to_app(DepsDir, Packages, Pkg={_, Vsn}) ->
Name = ec_cnv:to_binary(rlx_depsolver:dep_pkg(Pkg)),
FmtVsn = iolist_to_binary(rlx_depsolver:format_version(Vsn)),
case dict:find({Name, FmtVsn}, Packages) of
error ->
[];
{ok, P} ->
PkgDeps = proplists:get_value(<<"deps">>, P, []),
Link = proplists:get_value(<<"link">>, P, ""),
{ok, AppInfo} = rebar_app_info:new(Name, FmtVsn),
AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps),
AppInfo2 = rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, Name)),
[rebar_app_info:source(AppInfo2, Link)]
end.
-spec package_to_app(file:name(), rlx_depsolver:t(), binary(), binary()) -> rebar_app_info:t().
package_to_app(DepsDir, Packages, Name, Vsn) ->
FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)),
-spec update_src_deps(integer(), rebar_state:t(), boolean()) -> rebar_state:t().
update_src_deps(Level, State, Update) ->
SrcDeps = rebar_state:src_deps(State),
case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, StateAcc}) ->
case Update of
{true, UpdateName, UpdateLevel} ->
handle_update(AppInfo
,UpdateName
,UpdateLevel
,SrcDepsAcc
,PkgDepsAcc
,Level
,StateAcc);
_ ->
maybe_fetch(AppInfo, false),
handle_dep(AppInfo
,SrcDepsAcc
,PkgDepsAcc
,Level
,StateAcc)
end
end, {[], rebar_state:pkg_deps(State), State}, SrcDeps) of
{[], NewPkgDeps, State1} ->
rebar_state:pkg_deps(State1, NewPkgDeps);
{NewSrcDeps, NewPkgDeps, State1} ->
State2 = rebar_state:pkg_deps(State1, NewPkgDeps),
State3 = rebar_state:src_deps(State2, NewSrcDeps),
update_src_deps(Level+1, State3, Update)
end.
{ok, P} = dict:find({Name, FmtVsn}, Packages),
PkgDeps = proplists:get_value(<<"deps">>, P),
Link = proplists:get_value(<<"link">>, P),
handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, Level, State) ->
Name = rebar_app_info:name(AppInfo),
Locks = rebar_state:get(State, locks, []),
{_, _, _, DepLevel} = lists:keyfind(Name, 1, Locks),
case UpdateLevel < DepLevel
orelse Name =:= UpdateName of
true ->
case maybe_fetch(AppInfo, true) of
true ->
handle_dep(AppInfo
,SrcDeps
,PkgDeps
,Level
,State);
{ok, AppInfo} = rebar_app_info:new(Name, FmtVsn),
AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps),
AppInfo2 =
rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, <<Name/binary, "-", FmtVsn/binary>>)),
rebar_app_info:source(AppInfo2, Link).
false ->
{SrcDeps, PkgDeps, State}
end;
false ->
{SrcDeps, PkgDeps, State}
end.
-spec update_src_deps(rebar_state:t()) -> rebat_state:t().
update_src_deps(State) ->
SrcDeps = rebar_state:src_deps(State),
handle_dep(AppInfo, SrcDeps, PkgDeps, Level, State) ->
DepsDir = get_deps_dir(State), DepsDir = get_deps_dir(State),
case lists:foldl(fun(AppInfo, {SrcDepsAcc, BinaryDepsAcc}) ->
ok = maybe_fetch(AppInfo),
{AppInfo1, NewSrcDeps, NewBinaryDeps} = handle_dep(DepsDir, AppInfo),
{ordsets:union(ordsets:add_element(AppInfo1, SrcDepsAcc), NewSrcDeps)
,NewBinaryDeps++BinaryDepsAcc}
end, {ordsets:new(), rebar_state:binary_deps(State)}, SrcDeps) of
{NewSrcDeps, NewBinaryDeps} when length(SrcDeps) =:= length(NewSrcDeps) ->
rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps);
{NewSrcDeps, NewBinaryDeps} ->
State1 = rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps),
update_src_deps(State1)
end.
{AppInfo1, NewSrcDeps, NewPkgDeps} =
handle_dep(DepsDir, AppInfo),
AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level),
{NewSrcDeps ++ SrcDeps
,NewPkgDeps++PkgDeps
,rebar_state:src_apps(State, AppInfo2)}.
-spec handle_dep(binary(), rebar_state:t()) -> {[rebar_app_info:t()], [binary_dep()]}.
-spec handle_dep(file:filename_all(), rebar_app_info:t()) ->
{rebar_app_info:t(), [rebar_app_info:t()], [pkg_dep()]}.
handle_dep(DepsDir, AppInfo) -> handle_dep(DepsDir, AppInfo) ->
C = rebar_config:consult(rebar_app_info:dir(AppInfo)), C = rebar_config:consult(rebar_app_info:dir(AppInfo)),
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)),
Deps = rebar_state:get(S, deps, []), Deps = rebar_state:get(S, deps, []),
AppInfo1 = rebar_app_info:deps(AppInfo, rebar_state:deps_names(S)), AppInfo1 = rebar_app_info:deps(AppInfo, rebar_state:deps_names(S)),
{SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps),
{AppInfo1, SrcDeps, BinaryDeps}.
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps),
{AppInfo1, SrcDeps, PkgDeps}.
-spec maybe_fetch(rebar_app_info:t()) -> ok.
maybe_fetch(AppInfo) ->
AppDir = rebar_app_info:dir(AppInfo),
case filelib:is_dir(AppDir) of
false ->
?INFO("Fetching ~s~n", [rebar_app_info:name(AppInfo)]),
Source = rebar_app_info:source(AppInfo),
rebar_fetch:download_source(AppDir, Source);
true ->
ok
-spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()}) -> boolean().
maybe_fetch(AppInfo, Update) ->
AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)),
Apps = rebar_app_discover:find_apps(["_checkouts"], all),
case rebar_app_utils:find(rebar_app_info:name(AppInfo), Apps) of
{ok, _} ->
%% Don't fetch dep if it exists in the _checkouts dir
false;
error ->
Exists = case rebar_app_utils:is_app_dir(filename:absname(AppDir)++"-*") of
{true, _} ->
true;
_ ->
case rebar_app_utils:is_app_dir(filename:absname(AppDir)) of
{true, _} ->
true;
_ ->
false
end
end,
case not Exists orelse Update of
true ->
?INFO("Fetching ~s~n", [rebar_app_info:name(AppInfo)]),
Source = rebar_app_info:source(AppInfo),
rebar_fetch:download_source(AppDir, Source),
true;
_ ->
false
end
end. end.
-spec parse_deps(binary(), [dep()]) -> {ordsets:ordset(rebar_app_info:t()), [binary_dep()]}.
-spec parse_deps(binary(), [dep()]) -> {[rebar_app_info:t()], [pkg_dep()]}.
parse_deps(DepsDir, Deps) -> parse_deps(DepsDir, Deps) ->
lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, BinaryDepsAcc}) ->
lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}) ->
{SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name) {SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name)
,ec_cnv:to_binary(Vsn)) | BinaryDepsAcc]};
(Name, {SrcDepsAcc, BinaryDepsAcc}) when is_atom(Name) ->
{SrcDepsAcc, [ec_cnv:to_binary(Name) | BinaryDepsAcc]};
({Name, Vsn, Source}, {SrcDepsAcc, BinaryDepsAcc}) when is_tuple (Source) ->
Dir = ec_cnv:to_list(get_deps_dir(DepsDir, Name)),
{ok, Dep} = case rebar_app_info:discover(Dir) of
{ok, App} ->
{ok, App};
not_found ->
rebar_app_info:new(Name, Vsn, Dir)
end,
Dep1 = rebar_app_info:source(Dep, Source),
{ordsets:add_element(Dep1, SrcDepsAcc), BinaryDepsAcc}
end, {ordsets:new(), []}, Deps).
-spec parse_goal(binary(), binary()) -> binary_dep().
,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]};
(Name, {SrcDepsAcc, PkgDepsAcc}) when is_atom(Name) ->
{SrcDepsAcc, [ec_cnv:to_binary(Name) | PkgDepsAcc]};
({Name, Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) ->
Dep = new_dep(DepsDir, Name, Vsn, Source),
{[Dep | SrcDepsAcc], PkgDepsAcc};
({Name, Vsn, Source, _Level}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) ->
Dep = new_dep(DepsDir, Name, Vsn, Source),
{[Dep | SrcDepsAcc], PkgDepsAcc}
end, {[], []}, Deps).
new_dep(DepsDir, Name, Vsn, Source) ->
Dir = ec_cnv:to_list(get_deps_dir(DepsDir, Name)),
{ok, Dep} = case rebar_app_info:discover(Dir) of
{ok, App} ->
{ok, App};
not_found ->
rebar_app_info:new(Name, Vsn, Dir)
end,
rebar_app_info:source(Dep, Source).
-spec parse_goal(binary(), binary()) -> pkg_dep().
parse_goal(Name, Constraint) -> parse_goal(Name, Constraint) ->
case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of
{match, [<<>>, Vsn]} -> {match, [<<>>, Vsn]} ->
@ -236,9 +301,7 @@ info(Description) ->
"~n" "~n"
"Valid rebar.config options:~n" "Valid rebar.config options:~n"
" ~p~n" " ~p~n"
" ~p~n"
"Valid command line options:~n"
" deps_dir=\"deps\" (override default or rebar.config deps_dir)~n",
" ~p~n",
[ [
Description, Description,
{deps_dir, "deps"}, {deps_dir, "deps"},

+ 18
- 12
src/rebar_prv_lock.erl Näytä tiedosto

@ -1,9 +1,10 @@
-module(rebar_prv_lock). -module(rebar_prv_lock).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -16,17 +17,17 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = true,
deps = ?DEPS,
example = "",
short_desc = "Locks dependencies.",
desc = info("Locks dependencies"),
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, true},
{deps, ?DEPS},
{example, ""},
{short_desc, "Locks dependencies."},
{desc, info("Locks dependencies")},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
case rebar_state:get(State, locks, []) of case rebar_state:get(State, locks, []) of
[] -> [] ->
@ -40,7 +41,8 @@ do(State) ->
Source when is_tuple(Source) -> Source when is_tuple(Source) ->
{rebar_app_info:name(Dep) {rebar_app_info:name(Dep)
,rebar_app_info:original_vsn(Dep) ,rebar_app_info:original_vsn(Dep)
,rebar_fetch:lock_source(Dir, Source)};
,rebar_fetch:lock_source(Dir, Source)
,rebar_app_info:dep_level(Dep)};
_Source -> _Source ->
{rebar_app_info:name(Dep) {rebar_app_info:name(Dep)
,rebar_app_info:original_vsn(Dep)} ,rebar_app_info:original_vsn(Dep)}
@ -53,5 +55,9 @@ do(State) ->
{ok, State} {ok, State}
end. end.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
info(_) -> info(_) ->
"". "".

+ 21
- 36
src/rebar_prv_new.erl Näytä tiedosto

@ -1,9 +1,10 @@
-module(rebar_prv_new). -module(rebar_prv_new).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -16,17 +17,17 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar new <template>",
short_desc = "Create new project from templates.",
desc = info(create),
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar new <template>"},
{short_desc, "Create new project from templates."},
{desc, info()},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
case rebar_state:command_args(State) of case rebar_state:command_args(State) of
[TemplateName] -> [TemplateName] ->
@ -41,33 +42,17 @@ do(State) ->
{ok, State} {ok, State}
end. end.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
%% =================================================================== %% ===================================================================
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
info(create) ->
io_lib:format(
"Create skel based on template and vars.~n"
"~n"
"Valid command line options:~n"
" template= [var=foo,...]~n", []);
info(create_app) ->
io_lib:format(
"Create simple app skel.~n"
"~n"
"Valid command line options:~n"
" [appid=myapp]~n", []);
info(create_lib) ->
io_lib:format(
"Create simple lib skel.~n"
"~n"
"Valid command line options:~n"
" [libid=mylib]~n", []);
info(create_node) ->
info() ->
io_lib:format( io_lib:format(
"Create simple node skel.~n"
"~n"
"Valid command line options:~n"
" [nodeid=mynode]~n", []);
info(list_templates) ->
io_lib:format("List available templates.~n", []).
"Create rebar project based on template and vars.~n"
"~n"
"Valid command line options:~n"
" template= [var=foo,...]~n", []).

+ 16
- 11
src/rebar_prv_packages.erl Näytä tiedosto

@ -1,9 +1,10 @@
-module(rebar_prv_packages). -module(rebar_prv_packages).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -12,22 +13,26 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar pkgs",
short_desc = "List available packages.",
desc = info("List available packages"),
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar pkgs"},
{short_desc, "List available packages."},
{desc, info("List available packages")},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
{Packages, _Graph} = rebar_packages:get_packages(State), {Packages, _Graph} = rebar_packages:get_packages(State),
print_packages(Packages), print_packages(Packages),
{ok, State}. {ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
print_packages(Packages) -> print_packages(Packages) ->
Keys = lists:keysort(1, dict:fetch_keys(Packages)), Keys = lists:keysort(1, dict:fetch_keys(Packages)),
Pkgs = merge(Keys), Pkgs = merge(Keys),

+ 26
- 14
src/rebar_prv_release.erl Näytä tiedosto

@ -3,10 +3,11 @@
-module(rebar_prv_release). -module(rebar_prv_release).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,17 +20,28 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar release",
short_desc = "Build release of project.",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar release"},
{short_desc, "Build release of project."},
{desc, ""},
{opts, relx:opt_spec_list()}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
do(Config) ->
relx:main("release"),
{ok, Config}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
Options = rebar_state:command_args(State),
AllOptions = string:join(["release" | Options], " "),
case rebar_state:get(State, relx, []) of
[] ->
relx:main(AllOptions);
Config ->
relx:main([{config, Config}], AllOptions)
end,
{ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.

+ 16
- 11
src/rebar_prv_shell.erl Näytä tiedosto

@ -28,10 +28,11 @@
-module(rebar_prv_shell). -module(rebar_prv_shell).
-author("Kresten Krab Thorup <krab@trifork.com>"). -author("Kresten Krab Thorup <krab@trifork.com>").
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -44,21 +45,25 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar shell",
short_desc = "Run shell with project apps and deps in path.",
desc = info(),
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar shell"},
{short_desc, "Run shell with project apps and deps in path."},
{desc, info()},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(Config) -> do(Config) ->
shell(), shell(),
{ok, Config}. {ok, Config}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
%% NOTE: %% NOTE:
%% this is an attempt to replicate `erl -pa ./ebin -pa deps/*/ebin`. it is %% this is an attempt to replicate `erl -pa ./ebin -pa deps/*/ebin`. it is
%% mostly successful but does stop and then restart the user io system to get %% mostly successful but does stop and then restart the user io system to get

+ 24
- 14
src/rebar_prv_tar.erl Näytä tiedosto

@ -3,10 +3,11 @@
-module(rebar_prv_tar). -module(rebar_prv_tar).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,17 +20,26 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar tar",
short_desc = "Tar archive of release built of project.",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar tar"},
{short_desc, "Tar archive of release built of project."},
{desc, ""},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
do(Config) ->
relx:main("release tar"),
{ok, Config}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
case rebar_state:get(State, relx, []) of
[] ->
relx:main(["release tar"]);
Config ->
relx:main([{config, Config}], ["release tar"])
end,
{ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.

+ 63
- 0
src/rebar_prv_test_deps.erl Näytä tiedosto

@ -0,0 +1,63 @@
-module(rebar_prv_test_deps).
-behaviour(provider).
-export([init/1,
do/1,
format_error/2]).
-include("rebar.hrl").
-define(PROVIDER, test_deps).
-define(DEPS, [install_deps]).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Providers = rebar_state:providers(State),
CompileProvider = providers:get_provider(compile, Providers),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, true},
{deps, ?DEPS},
{hooks, {[], [CompileProvider]}},
{example, undefined},
{short_desc, "Install dependencies needed only for testing."},
{desc, ""},
{opts, []}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
ProjectApps = rebar_state:project_apps(State),
TestDeps = rebar_state:get(State, test_deps, []),
Names = [ec_cnv:to_binary(element(1, Dep)) || Dep <- TestDeps],
ProjectApps1 = [rebar_app_info:deps(A, Names) || A <- ProjectApps],
{ok, State1} = rebar_prv_install_deps:handle_deps(State, TestDeps),
AllDeps = rebar_state:get(State1, all_deps, []),
case rebar_topo:sort_apps(ProjectApps1++AllDeps) of
{ok, Sort} ->
_ToBuild = lists:dropwhile(fun rebar_app_info:valid/1, Sort),
%% lists:foreach(fun(AppInfo) ->
%% AppDir = rebar_app_info:dir(AppInfo),
%% C = rebar_config:consult(AppDir),
%% S = rebar_state:new(State1, C, AppDir),
%% rebar_prv_compile:build(S, AppInfo)
%% end, ToBuild),
{ok, State1};
{error, Error} ->
{error, Error}
end.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
%% ===================================================================
%% Internal functions
%% ===================================================================

+ 29
- 34
src/rebar_prv_update.erl Näytä tiedosto

@ -3,10 +3,11 @@
-module(rebar_prv_update). -module(rebar_prv_update).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,41 +20,35 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar update cowboy",
short_desc = "Update package index or individual dependency.",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar update"},
{short_desc, "Update package index."},
{desc, ""},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
case rebar_state:command_args(State) of
[Name] ->
?ERROR("NOT IMPLEMENTED: Updating ~s~n", [Name]),
{ok, State};
[] ->
?INFO("Updating package index...~n", []),
Url = url(State),
%{ok, [Home]} = init:get_argument(home),
ec_file:mkdir_p(filename:join([os:getenv("HOME"), ".rebar"])),
PackagesFile = filename:join([os:getenv("HOME"), ".rebar", "packages"]),
{ok, RequestId} = httpc:request(get, {Url, []}, [], [{stream, PackagesFile}, {sync, false}]),
wait(RequestId, State)
end.
wait(RequestId, State) ->
receive
{http, {RequestId, saved_to_file}} ->
{ok, State}
after
500 ->
io:format("."),
wait(RequestId, State)
end.
?INFO("Updating package index...~n", []),
try
Url = url(State),
%{ok, [Home]} = init:get_argument(home),
ec_file:mkdir_p(filename:join([os:getenv("HOME"), ".rebar"])),
PackagesFile = filename:join([os:getenv("HOME"), ".rebar", "packages"]),
{ok, _RequestId} = httpc:request(get, {Url, []}, [], [{stream, PackagesFile}
,{sync, true}])
catch
_:_ ->
{error, io_lib:format("Failed to write package index.~n", [])}
end,
{ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
url(State) -> url(State) ->
SystemArch = erlang:system_info(system_architecture), SystemArch = erlang:system_info(system_architecture),

+ 55
- 0
src/rebar_prv_upgrade.erl Näytä tiedosto

@ -0,0 +1,55 @@
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 et
-module(rebar_prv_upgrade).
-behaviour(provider).
-export([init/1,
do/1,
format_error/2]).
-include("rebar.hrl").
-define(PROVIDER, upgrade).
-define(DEPS, [lock]).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
State1 =
rebar_state:add_provider(State,
providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar upgrade cowboy"},
{short_desc, "Upgrade dependency."},
{desc, ""},
{opts, [
{package, undefined, undefined, string, "Package to upgrade."}
]}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
Name = proplists:get_value(package, Args),
?INFO("Updating ~s~n", [Name]),
Locks = rebar_state:get(State, locks, []),
case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of
{_, _, _, Level} ->
Deps = rebar_state:get(State, deps),
Dep = lists:keyfind(list_to_atom(Name), 1, Deps),
rebar_prv_install_deps:handle_deps(State, [Dep], {true, ec_cnv:to_binary(Name), Level}),
{ok, State};
_ ->
{error, io_lib:format("No such dependency ~s~n", [Name])}
end.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.

+ 16
- 11
src/rebar_prv_version.erl Näytä tiedosto

@ -3,10 +3,11 @@
-module(rebar_prv_version). -module(rebar_prv_version).
-behaviour(rebar_provider).
-behaviour(provider).
-export([init/1, -export([init/1,
do/1]).
do/1,
format_error/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -19,18 +20,22 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) -> init(State) ->
State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER,
provider_impl = ?MODULE,
bare = false,
deps = ?DEPS,
example = "rebar version",
short_desc = "Print version for rebar and current Erlang.",
desc = "",
opts = []}),
State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar version"},
{short_desc, "Print version for rebar and current Erlang."},
{desc, ""},
{opts, []}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error().
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
rebar3:version(), rebar3:version(),
{ok, State}. {ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.

+ 70
- 65
src/rebar_state.erl Näytä tiedosto

@ -3,49 +3,39 @@
-export([new/0, new/1, new/2, new/3, -export([new/0, new/1, new/2, new/3,
get/2, get/3, set/3, get/2, get/3, set/3,
command_args/1, command_args/2, command_args/1, command_args/2,
command_parsed_args/1, command_parsed_args/2,
dir/1, dir/2, dir/1, dir/2,
set_skip_dir/2, is_skip_dir/2, reset_skip_dirs/1,
create_logic_providers/2, create_logic_providers/2,
project_apps/1, project_apps/2, project_apps/1, project_apps/2,
deps_names/1, deps_names/1,
binary_deps/1, binary_deps/2,
pkg_deps/1, pkg_deps/2,
src_deps/1, src_deps/2, src_deps/1, src_deps/2,
src_apps/1, src_apps/2,
prepend_hook/3, append_hook/3, hooks/2, prepend_hook/3, append_hook/3, hooks/2,
providers/1, providers/2, add_provider/2]). providers/1, providers/2, add_provider/2]).
-include("rebar.hrl"). -include("rebar.hrl").
-ifdef(namespaced_types).
%% dict:dict() exists starting from Erlang 17.
-type rebar_dict() :: dict:dict(term(), term()).
-else.
%% dict() has been obsoleted in Erlang 17 and deprecated in 18.
-type rebar_dict() :: dict().
-endif.
-record(state_t, {dir :: file:name(),
opts = [],
-record(state_t, {dir :: file:filename(),
opts = [] :: list(),
local_opts = [] :: list(),
config = new_globals() :: rebar_dict(),
command_args = [],
command_parsed_args = [],
envs = new_env() :: rebar_dict(),
command_args = [] :: list(),
src_deps = [],
src_apps = [],
pkg_deps = [] :: [rlx_depsolver:constraint()],
project_apps = [],
src_deps = ordsets:new() :: ordsets:ordset(rebar_app_info:t()),
binary_deps = [],
project_apps = ordsets:new() :: ordsets:ordset(rebar_app_info:t()),
providers = [],
hooks = [],
skip_dirs = new_skip_dirs() :: rebar_dict() }).
providers = []}).
-export_type([t/0]). -export_type([t/0]).
-opaque t() :: #state_t{}.
-type t() :: record(state_t).
-spec new() -> t(). -spec new() -> t().
new() -> new() ->
@ -64,9 +54,9 @@ new(ParentState=#state_t{}, Config) ->
-spec new(t(), list(), file:name()) -> t(). -spec new(t(), list(), file:name()) -> t().
new(ParentState, Config, Dir) -> new(ParentState, Config, Dir) ->
_Opts = ParentState#state_t.opts,
Opts = ParentState#state_t.opts,
LocalOpts = case rebar_config:consult_file(?LOCK_FILE) of LocalOpts = case rebar_config:consult_file(?LOCK_FILE) of
{ok, [D]} ->
[D] ->
[{locks, D} | Config]; [{locks, D} | Config];
_ -> _ ->
Config Config
@ -74,7 +64,7 @@ new(ParentState, Config, Dir) ->
ProviderModules = [], ProviderModules = [],
create_logic_providers(ProviderModules, ParentState#state_t{dir=Dir create_logic_providers(ProviderModules, ParentState#state_t{dir=Dir
,opts=LocalOpts}).
,opts=lists:umerge(LocalOpts, Opts)}).
get(State, Key) -> get(State, Key) ->
proplists:get_value(Key, State#state_t.opts). proplists:get_value(Key, State#state_t.opts).
@ -82,33 +72,23 @@ get(State, Key) ->
get(State, Key, Default) -> get(State, Key, Default) ->
proplists:get_value(Key, State#state_t.opts, Default). proplists:get_value(Key, State#state_t.opts, Default).
-spec set(t(), any(), any()) -> t().
set(State, Key, Value) -> set(State, Key, Value) ->
Opts = proplists:delete(Key, State#state_t.opts), Opts = proplists:delete(Key, State#state_t.opts),
State#state_t { opts = [{Key, Value} | Opts] }. State#state_t { opts = [{Key, Value} | Opts] }.
set_skip_dir(State, Dir) ->
OldSkipDirs = State#state_t.skip_dirs,
NewSkipDirs = case is_skip_dir(State, Dir) of
false ->
?DEBUG("Adding skip dir: ~s\n", [Dir]),
dict:store(Dir, true, OldSkipDirs);
true ->
OldSkipDirs
end,
State#state_t{skip_dirs = NewSkipDirs}.
is_skip_dir(State, Dir) ->
dict:is_key(Dir, State#state_t.skip_dirs).
reset_skip_dirs(State) ->
State#state_t{skip_dirs = new_skip_dirs()}.
command_args(#state_t{command_args=CmdArgs}) -> command_args(#state_t{command_args=CmdArgs}) ->
CmdArgs. CmdArgs.
command_args(State, CmdArgs) -> command_args(State, CmdArgs) ->
State#state_t{command_args=CmdArgs}. State#state_t{command_args=CmdArgs}.
command_parsed_args(#state_t{command_parsed_args=CmdArgs}) ->
CmdArgs.
command_parsed_args(State, CmdArgs) ->
State#state_t{command_parsed_args=CmdArgs}.
dir(#state_t{dir=Dir}) -> dir(#state_t{dir=Dir}) ->
Dir. Dir.
@ -123,13 +103,14 @@ deps_names(State) ->
ec_cnv:to_binary(Dep) ec_cnv:to_binary(Dep)
end, Deps). end, Deps).
binary_deps(#state_t{binary_deps=BinaryDeps}) ->
BinaryDeps.
-spec pkg_deps(t()) -> [rlx_depsolver:constraint()].
pkg_deps(#state_t{pkg_deps=PkgDeps}) ->
PkgDeps.
binary_deps(State=#state_t{binary_deps=BinaryDeps}, NewBinaryDeps) when is_list(BinaryDeps) ->
State#state_t{binary_deps=NewBinaryDeps};
binary_deps(State=#state_t{binary_deps=BinaryDeps}, BinaryDep) ->
State#state_t{binary_deps=[BinaryDep | BinaryDeps]}.
pkg_deps(State=#state_t{pkg_deps=PkgDeps}, NewPkgDeps) when is_list(PkgDeps) ->
State#state_t{pkg_deps=NewPkgDeps};
pkg_deps(State=#state_t{pkg_deps=PkgDeps}, PkgDep) ->
State#state_t{pkg_deps=[PkgDep | PkgDeps]}.
src_deps(#state_t{src_deps=SrcDeps}) -> src_deps(#state_t{src_deps=SrcDeps}) ->
SrcDeps. SrcDeps.
@ -137,7 +118,19 @@ src_deps(#state_t{src_deps=SrcDeps}) ->
src_deps(State=#state_t{src_deps=SrcDeps}, NewSrcDeps) when is_list(SrcDeps) -> src_deps(State=#state_t{src_deps=SrcDeps}, NewSrcDeps) when is_list(SrcDeps) ->
State#state_t{src_deps=NewSrcDeps}; State#state_t{src_deps=NewSrcDeps};
src_deps(State=#state_t{src_deps=SrcDeps}, SrcDep) -> src_deps(State=#state_t{src_deps=SrcDeps}, SrcDep) ->
State#state_t{src_deps=[SrcDep | SrcDeps]}.
Name = rebar_app_info:name(SrcDep),
NewSrcDeps = lists:keystore(Name, 2, SrcDeps, SrcDep),
State#state_t{src_deps=NewSrcDeps}.
src_apps(#state_t{src_apps=SrcApps}) ->
SrcApps.
src_apps(State=#state_t{src_apps=_SrcApps}, NewSrcApps) when is_list(NewSrcApps) ->
State#state_t{src_apps=NewSrcApps};
src_apps(State=#state_t{src_apps=SrcApps}, NewSrcApp) ->
Name = rebar_app_info:name(NewSrcApp),
NewSrcApps = lists:keystore(Name, 2, SrcApps, NewSrcApp),
State#state_t{src_apps=NewSrcApps}.
project_apps(#state_t{project_apps=Apps}) -> project_apps(#state_t{project_apps=Apps}) ->
Apps. Apps.
@ -153,32 +146,44 @@ providers(#state_t{providers=Providers}) ->
providers(State, NewProviders) -> providers(State, NewProviders) ->
State#state_t{providers=NewProviders}. State#state_t{providers=NewProviders}.
-spec add_provider(t(), providers:t()) -> t().
add_provider(State=#state_t{providers=Providers}, Provider) -> add_provider(State=#state_t{providers=Providers}, Provider) ->
State#state_t{providers=[Provider | Providers]}. State#state_t{providers=[Provider | Providers]}.
create_logic_providers(ProviderModules, State0) -> create_logic_providers(ProviderModules, State0) ->
lists:foldl(fun(ProviderMod, Acc) -> lists:foldl(fun(ProviderMod, Acc) ->
{ok, State1} = rebar_provider:new(ProviderMod, Acc),
State1
case providers:new(ProviderMod, Acc) of
{error, Reason} ->
?ERROR(Reason++"~n", []),
Acc;
{ok, State1} ->
State1
end
end, State0, ProviderModules). end, State0, ProviderModules).
prepend_hook(State=#state_t{hooks=Hooks}, Target, Hook) ->
{PreHooks, PostHooks} = proplists:get_value(Target, Hooks, {[], []}),
State#state_t{hooks=[{Target, {[Hook | PreHooks], PostHooks}} | proplists:delete(Target, Hooks)]}.
prepend_hook(State=#state_t{providers=Providers}, Target, Hook) ->
State#state_t{providers=add_hook(pre, Providers, Target, Hook)}.
append_hook(State=#state_t{hooks=Hooks}, Target, Hook) ->
{PreHooks, PostHooks} = proplists:get_value(Target, Hooks, {[], []}),
State#state_t{hooks=[{Target, {PreHooks, [Hook | PostHooks]}} | proplists:delete(Target, Hooks)]}.
append_hook(State=#state_t{providers=Providers}, Target, Hook) ->
State#state_t{providers=add_hook(post, Providers, Target, Hook)}.
hooks(#state_t{hooks=Hooks}, Target) ->
proplists:get_value(Target, Hooks, {[], []}).
-spec hooks(t(), atom()) -> {[providers:t()], [providers:t()]}.
hooks(_State=#state_t{providers=Providers}, Target) ->
Provider = providers:get_provider(Target, Providers),
providers:hooks(Provider).
%% =================================================================== %% ===================================================================
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
new_globals() -> dict:new().
new_env() -> dict:new().
new_skip_dirs() -> dict:new().
add_hook(Which, Providers, Target, Hook) ->
Provider = providers:get_provider(Target, Providers),
Hooks = providers:hooks(Provider),
NewHooks = add_hook(Which, Hooks, Hook),
NewProvider = providers:hooks(Provider, NewHooks),
[NewProvider | lists:delete(Provider, Providers)].
add_hook(pre, {PreHooks, PostHooks}, Hook) ->
{[Hook | PreHooks], PostHooks};
add_hook(post, {PreHooks, PostHooks}, Hook) ->
{PreHooks, [Hook | PostHooks]}.

+ 4
- 2
src/rebar_templater.erl Näytä tiedosto

@ -47,6 +47,8 @@ new(app, DirName, State) ->
create1(State, DirName, "otp_app"); create1(State, DirName, "otp_app");
new(lib, DirName, State) -> new(lib, DirName, State) ->
create1(State, DirName, "otp_lib"); create1(State, DirName, "otp_lib");
new(plugin, DirName, State) ->
create1(State, DirName, "plugin");
new(rel, DirName, State) -> new(rel, DirName, State) ->
create1(State, DirName, "otp_rel"). create1(State, DirName, "otp_rel").
@ -78,7 +80,7 @@ create(State) ->
resolve_variables([], Dict) -> resolve_variables([], Dict) ->
Dict; Dict;
resolve_variables([{Key, Value0} | Rest], Dict) when is_list(Value0) -> resolve_variables([{Key, Value0} | Rest], Dict) when is_list(Value0) ->
Value = render(list_to_binary(Value0), Dict),
Value = render(Value0, Dict),
resolve_variables(Rest, dict:store(Key, Value, Dict)); resolve_variables(Rest, dict:store(Key, Value, Dict));
resolve_variables([{Key, {list, Dicts}} | Rest], Dict) when is_list(Dicts) -> resolve_variables([{Key, {list, Dicts}} | Rest], Dict) when is_list(Dicts) ->
%% just un-tag it so erlydtl can use it %% just un-tag it so erlydtl can use it
@ -376,7 +378,7 @@ execute_template(Files, [{'case', Variable, Values, Instructions} | Rest], Templ
ExistingFiles); ExistingFiles);
execute_template(Files, [{template, Input, Output} | Rest], TemplateType, execute_template(Files, [{template, Input, Output} | Rest], TemplateType,
TemplateName, Context, Force, ExistingFiles) -> TemplateName, Context, Force, ExistingFiles) ->
InputName = filename:join(filename:dirname(TemplateName), Input),
_InputName = filename:join(filename:dirname(TemplateName), Input),
%File = load_file(Files, TemplateType, InputName), %File = load_file(Files, TemplateType, InputName),
OutputTemplateName = make_template_name("rebar_output_template", Output), OutputTemplateName = make_template_name("rebar_output_template", Output),
{ok, OutputTemplateName1} = erlydtl:compile_template(Output, OutputTemplateName, ?ERLYDTL_COMPILE_OPTS), {ok, OutputTemplateName1} = erlydtl:compile_template(Output, OutputTemplateName, ?ERLYDTL_COMPILE_OPTS),

+ 22
- 26
src/rebar_topo.erl Näytä tiedosto

@ -54,20 +54,18 @@
%% applications. This implies that you have already done the %% applications. This implies that you have already done the
%% constraint solve before you pass the list of apps here to be %% constraint solve before you pass the list of apps here to be
%% sorted. %% sorted.
-spec sort_apps([rebar_app_info:t()]) ->
{ok, [rebar_app_info:t()]} |
relx:error().
-spec sort_apps([rebar_app_info:t()]) -> {ok, [rebar_app_info:t()]} | {error, any()}.
sort_apps(Apps) -> sort_apps(Apps) ->
Pairs = apps_to_pairs(Apps), Pairs = apps_to_pairs(Apps),
case sort(Pairs) of case sort(Pairs) of
{ok, Names} -> {ok, Names} ->
{ok, names_to_apps(Names, Apps)}; {ok, names_to_apps(Names, Apps)};
E -> E ->
E
{error, E}
end. end.
%% @doc Do a topological sort on the list of pairs. %% @doc Do a topological sort on the list of pairs.
-spec sort([pair()]) -> {ok, [atom()]} | relx:error().
-spec sort([pair()]) -> {ok, [atom()]} | {error, any()}.
sort(Pairs) -> sort(Pairs) ->
iterate(Pairs, [], all(Pairs)). iterate(Pairs, [], all(Pairs)).
@ -78,9 +76,9 @@ format_error({cycle, Pairs}) ->
"before we can continue:\n", "before we can continue:\n",
case Pairs of case Pairs of
[{P1, P2}] -> [{P1, P2}] ->
[rebar_util:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1)];
[rebar_utils:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1)];
[{P1, P2} | Rest] -> [{P1, P2} | Rest] ->
[rebar_util:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1),
[rebar_utils:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1),
[["-> ", erlang:atom_to_list(PP2), " -> ", erlang:atom_to_list(PP1)] || {PP1, PP2} <- Rest]]; [["-> ", erlang:atom_to_list(PP2), " -> ", erlang:atom_to_list(PP1)] || {PP1, PP2} <- Rest]];
[] -> [] ->
[] []
@ -91,12 +89,12 @@ format_error({cycle, Pairs}) ->
%%==================================================================== %%====================================================================
-spec names_to_apps([atom()], [rebar_app_info:t()]) -> [rebar_app_info:t()]. -spec names_to_apps([atom()], [rebar_app_info:t()]) -> [rebar_app_info:t()].
names_to_apps(Names, Apps) -> names_to_apps(Names, Apps) ->
[element(2, App) || App <- [find_app_by_name(Name, Apps) || Name <- Names], App =/= error].
[element(2, App) || App <- [find_app_by_name(Name, Apps) || Name <- Names], App =/= error].
-spec find_app_by_name(atom(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error. -spec find_app_by_name(atom(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
find_app_by_name(Name, Apps) -> find_app_by_name(Name, Apps) ->
ec_lists:find(fun(App) -> ec_lists:find(fun(App) ->
rebar_app_info:name(App) =:= Name
ec_cnv:to_atom(rebar_app_info:name(App)) =:= ec_cnv:to_atom(Name)
end, Apps). end, Apps).
-spec apps_to_pairs([rebar_app_info:t()]) -> [pair()]. -spec apps_to_pairs([rebar_app_info:t()]) -> [pair()].
@ -105,20 +103,20 @@ apps_to_pairs(Apps) ->
-spec app_to_pairs(rebar_app_info:t()) -> [pair()]. -spec app_to_pairs(rebar_app_info:t()) -> [pair()].
app_to_pairs(App) -> app_to_pairs(App) ->
[{DepApp, rebar_app_info:name(App)} ||
[{ec_cnv:to_atom(DepApp), ec_cnv:to_atom(rebar_app_info:name(App))} ||
DepApp <- DepApp <-
rebar_app_info:deps(App)]. rebar_app_info:deps(App)].
%% @doc Iterate over the system. @private %% @doc Iterate over the system. @private
-spec iterate([pair()], [name()], [name()]) -> -spec iterate([pair()], [name()], [name()]) ->
{ok, [name()]} | relx:error().
{ok, [name()]} | {error, iolist()}.
iterate([], L, All) -> iterate([], L, All) ->
{ok, remove_duplicates(L ++ subtract(All, L))}; {ok, remove_duplicates(L ++ subtract(All, L))};
iterate(Pairs, L, All) -> iterate(Pairs, L, All) ->
case subtract(lhs(Pairs), rhs(Pairs)) of case subtract(lhs(Pairs), rhs(Pairs)) of
[] -> [] ->
?ERROR(format_error({cycle, Pairs}), []);
{error, format_error({cycle, Pairs})};
Lhs -> Lhs ->
iterate(remove_pairs(Lhs, Pairs), L ++ Lhs, All) iterate(remove_pairs(Lhs, Pairs), L ++ Lhs, All)
end. end.
@ -188,29 +186,27 @@ topo_2_test() ->
topo_pairs_cycle_test() -> topo_pairs_cycle_test() ->
Pairs = [{app2, app1}, {app1, app2}, {stdlib, app1}], Pairs = [{app2, app1}, {app1, app2}, {stdlib, app1}],
?assertMatch({error, {_, {cycle, [{app2, app1}, {app1, app2}]}}},
sort(Pairs)).
?assertMatch({error, _}, sort(Pairs)).
topo_apps_cycle_test() -> topo_apps_cycle_test() ->
{ok, App1} = rebar_app_info:new(app1, "0.1", "/no-dir", [app2], [stdlib]),
{ok, App2} = rebar_app_info:new(app2, "0.1", "/no-dir", [app1], []),
{ok, App1} = rebar_app_info:new(app1, "0.1", "/no-dir", [app2]),
{ok, App2} = rebar_app_info:new(app2, "0.1", "/no-dir", [app1]),
Apps = [App1, App2], Apps = [App1, App2],
?assertMatch({error, {_, {cycle, [{app2,app1},{app1,app2}]}}},
sort_apps(Apps)).
?assertMatch({error, _}, sort_apps(Apps)).
topo_apps_good_test() -> topo_apps_good_test() ->
Apps = [App || Apps = [App ||
{ok, App} <- {ok, App} <-
[rebar_app_info:new(app1, "0.1", "/no-dir", [app2, zapp1], [stdlib, kernel]),
rebar_app_info:new(app2, "0.1", "/no-dir", [app3], []),
rebar_app_info:new(app3, "0.1", "/no-dir", [kernel], []),
rebar_app_info:new(zapp1, "0.1", "/no-dir", [app2,app3,zapp2], []),
rebar_app_info:new(stdlib, "0.1", "/no-dir", [], []),
rebar_app_info:new(kernel, "0.1", "/no-dir", [], []),
rebar_app_info:new(zapp2, "0.1", "/no-dir", [], [])]],
[rebar_app_info:new(app1, "0.1", "/no-dir", [app2, zapp1]),
rebar_app_info:new(app2, "0.1", "/no-dir", [app3]),
rebar_app_info:new(app3, "0.1", "/no-dir", [kernel]),
rebar_app_info:new(zapp1, "0.1", "/no-dir", [app2,app3,zapp2]),
rebar_app_info:new(stdlib, "0.1", "/no-dir", []),
rebar_app_info:new(kernel, "0.1", "/no-dir", []),
rebar_app_info:new(zapp2, "0.1", "/no-dir", [])]],
{ok, Sorted} = sort_apps(Apps), {ok, Sorted} = sort_apps(Apps),
?assertMatch([stdlib, kernel, zapp2, ?assertMatch([stdlib, kernel, zapp2,
app3, app2, zapp1, app1], app3, app2, zapp1, app1],
[rebar_app_info:name(App) || App <- Sorted]).
[ec_cnv:to_atom(rebar_app_info:name(App)) || App <- Sorted]).
-endif. -endif.

+ 32
- 142
src/rebar_utils.erl Näytä tiedosto

@ -30,42 +30,27 @@
filtermap/2, filtermap/2,
get_cwd/0, get_cwd/0,
is_arch/1, is_arch/1,
get_arch/0,
wordsize/0,
sh/2, sh/2,
sh_send/3, sh_send/3,
abort/0,
abort/2,
escript_foldl/3,
find_files/2, find_files/2,
find_files/3, find_files/3,
now_str/0,
ensure_dir/1, ensure_dir/1,
beam_to_mod/1, beam_to_mod/1,
beams/1, beams/1,
erl_to_mod/1,
abort/0,
abort/2,
escript_foldl/3,
find_executable/1, find_executable/1,
prop_check/3,
expand_code_path/0, expand_code_path/0,
expand_env_variable/3,
vcs_vsn/3, vcs_vsn/3,
deprecated/3, deprecated/3,
deprecated/4, deprecated/4,
get_deprecated_global/4,
get_deprecated_global/5,
get_experimental_global/3,
get_experimental_local/3,
get_deprecated_list/4,
get_deprecated_list/5,
get_deprecated_local/4,
get_deprecated_local/5,
delayed_halt/1, delayed_halt/1,
erl_opts/1, erl_opts/1,
src_dirs/1, src_dirs/1,
ebin_dir/0, ebin_dir/0,
processing_base_dir/1, processing_base_dir/1,
processing_base_dir/2, processing_base_dir/2,
patch_env/2,
indent/1]). indent/1]).
%% for internal use only %% for internal use only
@ -177,11 +162,6 @@ find_files(Dir, Regex, Recursive) ->
filelib:fold_files(Dir, Regex, Recursive, filelib:fold_files(Dir, Regex, Recursive,
fun(F, Acc) -> [F | Acc] end, []). fun(F, Acc) -> [F | Acc] end, []).
now_str() ->
{{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(),
lists:flatten(io_lib:format("~4b/~2..0b/~2..0b ~2..0b:~2..0b:~2..0b",
[Year, Month, Day, Hour, Minute, Second])).
%% TODO: filelib:ensure_dir/1 corrected in R13B04. Remove when we drop %% TODO: filelib:ensure_dir/1 corrected in R13B04. Remove when we drop
%% support for OTP releases older than R13B04. %% support for OTP releases older than R13B04.
ensure_dir(Path) -> ensure_dir(Path) ->
@ -194,27 +174,6 @@ ensure_dir(Path) ->
Error Error
end. end.
-spec abort() -> no_return().
abort() ->
throw(rebar_abort).
-spec abort(string(), [term()]) -> no_return().
abort(String, Args) ->
?ERROR(String, Args),
abort().
%% TODO: Rename emulate_escript_foldl to escript_foldl and remove
%% this function when the time is right. escript:foldl/3 was an
%% undocumented exported fun and has been removed in R14.
escript_foldl(Fun, Acc, File) ->
{module, zip} = code:ensure_loaded(zip),
case erlang:function_exported(zip, foldl, 3) of
true ->
emulate_escript_foldl(Fun, Acc, File);
false ->
escript:foldl(Fun, Acc, File)
end.
find_executable(Name) -> find_executable(Name) ->
case os:find_executable(Name) of case os:find_executable(Name) of
false -> false; false -> false;
@ -222,10 +181,6 @@ find_executable(Name) ->
"\"" ++ filename:nativename(Path) ++ "\"" "\"" ++ filename:nativename(Path) ++ "\""
end. end.
%% Helper function for checking values and aborting when needed
prop_check(true, _, _) -> true;
prop_check(false, Msg, Args) -> ?ABORT(Msg, Args).
%% Convert all the entries in the code path to absolute paths. %% Convert all the entries in the code path to absolute paths.
expand_code_path() -> expand_code_path() ->
CodePath = lists:foldl(fun(Path, Acc) -> CodePath = lists:foldl(fun(Path, Acc) ->
@ -233,25 +188,6 @@ expand_code_path() ->
end, [], code:get_path()), end, [], code:get_path()),
code:set_path(lists:reverse(CodePath)). code:set_path(lists:reverse(CodePath)).
%%
%% Given env. variable FOO we want to expand all references to
%% it in InStr. References can have two forms: $FOO and ${FOO}
%% The end of form $FOO is delimited with whitespace or eol
%%
expand_env_variable(InStr, VarName, RawVarValue) ->
case string:chr(InStr, $$) of
0 ->
%% No variables to expand
InStr;
_ ->
ReOpts = [global, unicode, {return, list}],
VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", ReOpts),
%% Use a regex to match/replace:
%% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO}
RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]),
re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
end.
vcs_vsn(Config, Vsn, Dir) -> vcs_vsn(Config, Vsn, Dir) ->
Key = {Vsn, Dir}, Key = {Vsn, Dir},
Cache = rebar_state:get(Config, vsn_cache, dict:new()), Cache = rebar_state:get(Config, vsn_cache, dict:new()),
@ -265,33 +201,6 @@ vcs_vsn(Config, Vsn, Dir) ->
{Config, VsnString} {Config, VsnString}
end. end.
get_deprecated_global(Config, OldOpt, NewOpt, When) ->
get_deprecated_global(Config, OldOpt, NewOpt, undefined, When).
get_deprecated_global(Config, OldOpt, NewOpt, Default, When) ->
get_deprecated_3(fun rebar_state:get/3,
Config, OldOpt, NewOpt, Default, When).
get_experimental_global(Config, Opt, Default) ->
get_experimental_3(fun rebar_state:get/3, Config, Opt, Default).
get_experimental_local(Config, Opt, Default) ->
get_experimental_3(fun rebar_state:get/3, Config, Opt, Default).
get_deprecated_list(Config, OldOpt, NewOpt, When) ->
get_deprecated_list(Config, OldOpt, NewOpt, undefined, When).
get_deprecated_list(Config, OldOpt, NewOpt, Default, When) ->
get_deprecated_3(fun rebar_state:get_list/3,
Config, OldOpt, NewOpt, Default, When).
get_deprecated_local(Config, OldOpt, NewOpt, When) ->
get_deprecated_local(Config, OldOpt, NewOpt, undefined, When).
get_deprecated_local(Config, OldOpt, NewOpt, Default, When) ->
get_deprecated_3(fun rebar_state:get/3,
Config, OldOpt, NewOpt, Default, When).
deprecated(Old, New, Opts, When) when is_list(Opts) -> deprecated(Old, New, Opts, When) when is_list(Opts) ->
case lists:member(Old, Opts) of case lists:member(Old, Opts) of
true -> true ->
@ -337,7 +246,7 @@ delayed_halt(Code) ->
end. end.
%% @doc Return list of erl_opts %% @doc Return list of erl_opts
-spec erl_opts(rebar_state:config()) -> list().
-spec erl_opts(rebar_state:t()) -> list().
erl_opts(Config) -> erl_opts(Config) ->
RawErlOpts = filter_defines(rebar_state:get(Config, erl_opts, []), []), RawErlOpts = filter_defines(rebar_state:get(Config, erl_opts, []), []),
Defines = [{d, list_to_atom(D)} || Defines = [{d, list_to_atom(D)} ||
@ -367,25 +276,6 @@ processing_base_dir(State, Dir) ->
AbsDir = filename:absname(Dir), AbsDir = filename:absname(Dir),
AbsDir =:= rebar_state:get(State, base_dir). AbsDir =:= rebar_state:get(State, base_dir).
%% @doc Returns the list of environment variables including 'REBAR' which
%% points to the rebar executable used to execute the currently running
%% command. The environment is not modified if rebar was invoked
%% programmatically.
-spec patch_env(rebar_state:config(), [{string(), string()}])
-> [{string(), string()}].
patch_env(Config, []) ->
%% If we reached an empty list, the env did not contain the REBAR variable.
case rebar_state:get(Config, escript, "") of
"" -> % rebar was invoked programmatically
[];
Path ->
[{"REBAR", Path}]
end;
patch_env(_Config, [{"REBAR", _} | _]=All) ->
All;
patch_env(Config, [E | Rest]) ->
[E | patch_env(Config, Rest)].
%% ==================================================================== %% ====================================================================
%% Internal functions %% Internal functions
%% ==================================================================== %% ====================================================================
@ -426,30 +316,6 @@ otp_release1(Rel) ->
binary:bin_to_list(Vsn, {0, Size - 1}) binary:bin_to_list(Vsn, {0, Size - 1})
end. end.
get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) ->
case Get(Config, NewOpt, Default) of
Default ->
case Get(Config, OldOpt, Default) of
Default ->
Default;
Old ->
deprecated(OldOpt, NewOpt, When),
Old
end;
New ->
New
end.
get_experimental_3(Get, Config, Opt, Default) ->
Val = Get(Config, Opt, Default),
case Val of
Default ->
Default;
Val ->
?CONSOLE("NOTICE: Using experimental option '~p'~n", [Opt]),
Val
end.
%% We do the shell variable substitution ourselves on Windows and hope that the %% We do the shell variable substitution ourselves on Windows and hope that the
%% command doesn't use any other shell magic. %% command doesn't use any other shell magic.
patch_on_windows(Cmd, Env) -> patch_on_windows(Cmd, Env) ->
@ -466,6 +332,25 @@ patch_on_windows(Cmd, Env) ->
Cmd Cmd
end. end.
%%
%% Given env. variable FOO we want to expand all references to
%% it in InStr. References can have two forms: $FOO and ${FOO}
%% The end of form $FOO is delimited with whitespace or eol
%%
expand_env_variable(InStr, VarName, RawVarValue) ->
case string:chr(InStr, $$) of
0 ->
%% No variables to expand
InStr;
_ ->
ReOpts = [global, unicode, {return, list}],
VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", ReOpts),
%% Use a regex to match/replace:
%% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO}
RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]),
re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
end.
expand_sh_flag(return_on_error) -> expand_sh_flag(return_on_error) ->
{error_handler, {error_handler,
fun(_Command, Err) -> fun(_Command, Err) ->
@ -521,14 +406,19 @@ sh_loop(Port, Fun, Acc) ->
beam_to_mod(Filename) -> beam_to_mod(Filename) ->
list_to_atom(filename:basename(Filename, ".beam")). list_to_atom(filename:basename(Filename, ".beam")).
erl_to_mod(Filename) ->
list_to_atom(filename:rootname(filename:basename(Filename))).
beams(Dir) -> beams(Dir) ->
filelib:fold_files(Dir, ".*\.beam\$", true, filelib:fold_files(Dir, ".*\.beam\$", true,
fun(F, Acc) -> [F | Acc] end, []). fun(F, Acc) -> [F | Acc] end, []).
emulate_escript_foldl(Fun, Acc, File) ->
-spec abort() -> no_return().
abort() ->
throw(rebar_abort).
-spec abort(string(), [term()]) -> no_return().
abort(String, Args) ->
?ERROR(String, Args),
abort().
escript_foldl(Fun, Acc, File) ->
case escript:extract(File, [compile_source]) of case escript:extract(File, [compile_source]) of
{ok, [_Shebang, _Comment, _EmuArgs, Body]} -> {ok, [_Shebang, _Comment, _EmuArgs, Body]} ->
case Body of case Body of

+ 1
- 1
test/rebar_compile_SUITE.erl Näytä tiedosto

@ -25,7 +25,7 @@ init_per_testcase(_, Config) ->
DataDir = proplists:get_value(data_dir, Config), DataDir = proplists:get_value(data_dir, Config),
AppsDir = filename:join([DataDir, create_random_name("apps_dir1_")]), AppsDir = filename:join([DataDir, create_random_name("apps_dir1_")]),
ok = ec_file:mkdir_p(AppsDir), ok = ec_file:mkdir_p(AppsDir),
Verbosity = rebar3:log_level([]),
Verbosity = rebar3:log_level(),
rebar_log:init(command_line, Verbosity), rebar_log:init(command_line, Verbosity),
State = rebar_state:new(), State = rebar_state:new(),
[{apps, AppsDir}, {state, State} | Config]. [{apps, AppsDir}, {state, State} | Config].

Ladataan…
Peruuta
Tallenna