Skip to content

Commit 0685e03

Browse files
author
José Valim
committed
Document and list aliases on help --names
1 parent 5e42900 commit 0685e03

File tree

6 files changed

+182
-17
lines changed

6 files changed

+182
-17
lines changed

lib/mix/lib/mix.ex

Lines changed: 142 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,148 @@
11
defmodule Mix do
2-
@moduledoc """
3-
Mix is a build tool that provides tasks for creating, compiling and
4-
testing Elixir projects. Mix is inspired by the Leiningen
5-
build tool for Clojure and was written by one of its contributors.
2+
@moduledoc ~S"""
3+
Mix is a build tool that provides tasks for creating, compiling,
4+
testing Elixir projects, as well as handle dependencies, and more.
65
7-
This module works as a facade for accessing the most common functionality
8-
in Elixir, such as the shell and the current project configuration.
6+
## Mix.Project
97
10-
For getting started with Elixir, checkout out the guide available on
11-
[Elixir's website](http://elixir-lang.org).
8+
The foundation of Mix is a project. A project can be defined by
9+
by using the `Mix.Project` in a module, usually place in a file
10+
named `mix.exs`:
11+
12+
defmodule MyApp.Mixfile do
13+
def project do
14+
[app: :my_app,
15+
version: "1.0.0"]
16+
end
17+
end
18+
19+
The `project/0` function is where the project information is defined
20+
and it allows developers to configure many tasks.
21+
22+
After the project above is defined, there are many tasks one can
23+
run directly from the command line:
24+
25+
* `mix compile` - compiles the current project
26+
* `mix test` - runs tests for the given project
27+
* `mix run` - runs a particular command inside the project
28+
29+
Each task has its own options and sometimes specific configuration
30+
to be defined in the `project/0` function. You can use `mix help`
31+
to list all available tasks and `mix help NAME` to show help for
32+
a particular task.
33+
34+
The best way to get started with your first project is by calling
35+
`mix new my_project` from the command line.
36+
37+
## Mix.Task
38+
39+
Tasks are what make Mix extensible.
40+
41+
Any project can extend Mix behaviour by adding their own tasks. For
42+
example, you can add the task below inside your project and it will
43+
be available to everyone that uses your project:
44+
45+
defmodule Mix.Tasks.Hello do
46+
use Mix.Task
47+
48+
def run(_) do
49+
Mix.shell.info "hello"
50+
end
51+
end
52+
53+
Now they can invoke it with `mix run hello`.
54+
55+
## Dependencies
56+
57+
Another important feature in Mix is that it is able to manage your
58+
dependencies and integrates nicely with [the Hex package manager](http://hex.pm).
59+
60+
In order to use dependencies, you just need to add a `:deps` key
61+
to your project configuration. We often extract the dependencies
62+
listing to its own functions:
63+
64+
defmodule MyApp.Mixfile do
65+
def project do
66+
[app: :my_app,
67+
version: "1.0.0",
68+
deps: deps]
69+
end
70+
71+
defp deps do
72+
[{:ecto, "~> 0.3.0"},
73+
{:plug, github: "elixir-lang/plug"}]
74+
end
75+
end
76+
77+
You can run `mix help deps` to learn more about dependencies in Mix.
78+
79+
## Environments
80+
81+
Mix provides environments.
82+
83+
Environments allow developers to prepare and organize their project
84+
specific to different scenarios. By default, Mix provides three
85+
environments:
86+
87+
* `:dev` - the default environment
88+
* `:test` - the environment `mix test` runs on
89+
* `:prod` - the environment your dependencies runs on
90+
91+
The environment can be changed via the command line by setting
92+
the `MIX_ENV` environment variable, for example:
93+
94+
$ MIX_ENV=prod mix run server.exs
95+
96+
## Aliases
97+
98+
Aliases are shortcut or tasks specific to the current project.
99+
100+
In the `Mix.Task` section, we have defined a task that would be
101+
available to everyone using our project as a dependency. What if
102+
we wanted the task to only be available for our project? Just
103+
define an alias:
104+
105+
defmodule MyApp.Mixfile do
106+
def project do
107+
[app: :my_app,
108+
version: "1.0.0",
109+
aliases: aliases]
110+
end
111+
112+
defp aliases do
113+
[c: "compile",
114+
hello: &hello/1]
115+
end
116+
117+
defp hello(_) do
118+
Mix.shell.info "Hello world"
119+
end
120+
end
121+
122+
In the example above, we have defined two aliases. One is `mix c`
123+
which is a shortcut for `mix compile`. The other is named
124+
`mix hello`, which is the equivalent to the `Mix.Tasks.Hello`
125+
we have defined in the `Mix.Task` section.
126+
127+
Aliases may also be a list, specifying multiple tasks to run
128+
at once:
129+
130+
[all: [&hello/1, "deps.get --only #{Mix.env}", "compile"]]
131+
132+
In the example above, we have defined an alias named `mix all`,
133+
that prints hello, then fetches dependencies specific to the
134+
current environment and compiles it.
135+
136+
Finally, aliases can also be use to augment existing tasks.
137+
Let's suppose you want to augment `mix clean` to clean another
138+
directory Mix does not know about:
139+
140+
[clean: ["clean", &clean_extra/1]]
141+
142+
Where `&clean_extra/1` would be a function in your `mix.exs`
143+
with extra clean up logic.
144+
145+
Note aliases do not show up on `mix help`.
12146
"""
13147

14148
use Application

lib/mix/lib/mix/project.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule Mix.Project do
2121
even without a project.
2222
2323
In case the developer needs a project or wants to access a special
24-
function in the project, he/she can call `Mix.Project.get!/0`
24+
function in the project, the developer can call `Mix.Project.get!/0`
2525
which fails with `Mix.NoProjectError` in case a project is not
2626
defined.
2727
"""

lib/mix/lib/mix/task.ex

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ defmodule Mix.Task do
1313
use Mix.Task
1414
1515
def run(_) do
16-
IO.puts "hello"
16+
Mix.shell.info "hello"
1717
end
1818
end
1919
@@ -194,11 +194,15 @@ defmodule Mix.Task do
194194
If the task was not yet invoked, it runs the task and
195195
returns the result.
196196
197-
If the task was already invoked, it does not run the task
198-
again and simply aborts with `:noop`.
197+
If there is an alias with the same name, the alias
198+
will be invoked instead of a task.
199199
200-
It may raise an exception if the task was not found
201-
or it is invalid. Check `get!/1` for more information.
200+
If the task or alias were already invoked, it does not
201+
run them again and simply aborts with `:noop`.
202+
203+
It may raise an exception if the an alias or a task can't
204+
be found or the task is invalid. Check `get!/1` for more
205+
information.
202206
"""
203207
@spec run(task_name, [any]) :: any
204208
def run(task, args \\ []) when is_binary(task) or is_atom(task) do

lib/mix/lib/mix/tasks/help.ex

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ defmodule Mix.Tasks.Help do
99
## Arguments
1010
1111
mix help - prints all tasks and their shortdoc
12-
mix help --names - prints all task names
1312
mix help TASK - prints full docs for the given task
13+
mix help --names - prints all task names and aliases
14+
(useful for autocompleting)
1415
1516
## Colors
1617
@@ -58,8 +59,17 @@ defmodule Mix.Tasks.Help do
5859
end
5960

6061
def run(["--names"]) do
61-
for module <- Enum.sort(Mix.Task.load_all()) do
62-
Mix.shell.info "#{Mix.Task.task_name(module)}"
62+
tasks =
63+
Mix.Task.load_all()
64+
|> Enum.map(&Mix.Task.task_name/1)
65+
66+
aliases =
67+
Mix.Project.config[:aliases]
68+
|> Dict.keys
69+
|> Enum.map(&Atom.to_string/1)
70+
71+
for info <- Enum.sort(aliases ++ tasks) do
72+
Mix.shell.info info
6373
end
6474
end
6575

lib/mix/test/mix/aliases_test.exs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ defmodule Mix.AliasesTest do
88
[aliases: [h: "hello",
99
p: &inspect/1,
1010
compile: "hello",
11+
help: ["help", "hello"],
1112
"nested.h": [&Mix.shell.info(inspect(&1)), "h foo bar"]]]
1213
end
1314
end
@@ -44,4 +45,9 @@ defmodule Mix.AliasesTest do
4445
assert Mix.Task.run("compile", []) == "Hello, World!"
4546
assert Mix.Task.run("compile", []) == :noop
4647
end
48+
49+
test "run alias override with recursion" do
50+
assert Mix.Task.run("help", []) == "Hello, World!"
51+
assert_received {:mix_shell, :info, ["mix test" <> _]}
52+
end
4753
end

lib/mix/test/mix/tasks/help_test.exs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,21 @@ defmodule Mix.Tasks.HelpTest do
2424
end
2525
end
2626

27+
28+
defmodule Aliases do
29+
def project do
30+
[aliases: [h: "hello", c: "compile"]]
31+
end
32+
end
33+
2734
test "help --names" do
35+
Mix.Project.push Aliases
36+
2837
in_fixture "no_mixfile", fn ->
2938
Mix.Tasks.Help.run ["--names"]
39+
assert_received {:mix_shell, :info, ["c"]}
3040
assert_received {:mix_shell, :info, ["compile"]}
41+
assert_received {:mix_shell, :info, ["h"]}
3142
assert_received {:mix_shell, :info, ["help"]}
3243
assert_received {:mix_shell, :info, ["escriptize"]}
3344
end

0 commit comments

Comments
 (0)