Skip to content

Commit 275d1f5

Browse files
author
José Valim
committed
Straight up and unify impls of clean, deps.clean and deps.unlock
1 parent e6420c8 commit 275d1f5

File tree

5 files changed

+115
-95
lines changed

5 files changed

+115
-95
lines changed

lib/mix/lib/mix/tasks/clean.ex

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,37 @@ defmodule Mix.Tasks.Clean do
77
@moduledoc """
88
Delete generated application files.
99
10-
This command deletes all build artifacts for the current application
11-
across all environments. Dependencies are only cleaned if the
12-
`--all` option is given.
13-
14-
## Command line options
15-
16-
* `--all` - clean everything, including builds and dependencies
10+
This command deletes all build artifacts for the current project
11+
Dependencies' build files are cleaned if the `--deps` option is given.
1712
13+
By default this task works accross all environments, unless `--only`
14+
is given.
1815
"""
1916

17+
@switches [deps: :boolean, only: :string]
18+
2019
def run(args) do
2120
Mix.Project.get!
2221
loadpaths!
2322

24-
{opts, _, _} = OptionParser.parse(args)
23+
{opts, _, _} = OptionParser.parse(args, switches: @switches)
2524

2625
_ = for compiler <- Mix.Tasks.Compile.compilers(),
2726
module = Mix.Task.get("compile.#{compiler}"),
2827
function_exported?(module, :clean, 0),
2928
do: module.clean
3029

31-
if opts[:all] do
32-
Mix.Task.run("deps.clean", args)
33-
Mix.Project.build_path
34-
|> Path.dirname
35-
|> File.rm_rf
30+
build = Mix.Project.build_path
31+
|> Path.dirname
32+
|> Path.join("#{opts[:only] || :*}")
33+
34+
if opts[:deps] do
35+
build
36+
|> Path.wildcard
37+
|> Enum.each(&File.rm_rf/1)
3638
else
37-
config = Mix.Project.config
38-
Mix.Project.build_path(config)
39-
|> Path.dirname
40-
|> Path.join("*/lib/#{config[:app]}")
39+
build
40+
|> Path.join("lib/#{Mix.Project.config[:app]}")
4141
|> Path.wildcard
4242
|> Enum.each(&File.rm_rf/1)
4343
end

lib/mix/lib/mix/tasks/deps.clean.ex

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,52 +6,66 @@ defmodule Mix.Tasks.Deps.Clean do
66
@moduledoc """
77
Remove the given dependencies' files.
88
9-
Since this is a destructive action, cleaning of all dependencies
10-
can only happen by passing the `--all` command line option. It
11-
also works accross all environments, unless `--only` is given.
9+
Since this is a destructive action, cleaning of dependencies
10+
can only happen by passing arguments/options:
1211
13-
Clean does not unlock the dependencies, unless `--unlock` is given.
14-
The `--unused` flag removes unused the dependencies.
12+
* `dep1, dep2` - the name of dependency to be removed
13+
* `--all` - removes all dependencies
14+
* `--unused` - removes only unused dependencies (no longer mentioned
15+
in the `mix.exs` file)
16+
17+
By default this task works accross all environments, unless `--only`
18+
is given.
1519
"""
20+
1621
@switches [unlock: :boolean, all: :boolean, only: :string, unused: :boolean]
1722

1823
def run(args) do
1924
Mix.Project.get!
20-
{opts, args, _} = OptionParser.parse(args, switches: @switches)
25+
{opts, apps, _} = OptionParser.parse(args, switches: @switches)
26+
27+
build = Mix.Project.build_path
28+
|> Path.dirname
29+
|> Path.join("#{opts[:only] || :*}/lib")
30+
deps = Mix.Project.deps_path
2131

2232
cond do
2333
opts[:all] ->
24-
# Clean all deps by default unless --only is given
25-
clean_opts = if only = opts[:only], do: [env: :"#{only}"], else: []
26-
apps = Mix.Dep.loaded(clean_opts) |> Enum.map(&(&1.app))
27-
do_clean apps, opts
34+
checked_deps(build, deps) |> do_clean(build, deps)
2835
opts[:unused] ->
29-
Mix.Dep.loaded([]) |> Enum.map(&(&1.app)) |> unused_apps |> do_clean opts
30-
args != [] ->
31-
do_clean args, opts
36+
checked_deps(build, deps) |> filter_loaded(opts) |> do_clean(build, deps)
37+
apps != [] ->
38+
do_clean(apps, build, deps)
3239
true ->
3340
Mix.raise "mix deps.clean expects dependencies as arguments or " <>
3441
"a flag indicating which dependencies to clean " <>
3542
"The --all option will clean all dependencies while"
3643
"the --unused option cleans unused dependencies."
3744
end
45+
46+
if opts[:unlock] do
47+
Mix.Task.run "deps.unlock", args
48+
end
3849
end
3950

40-
defp unused_apps(loaded_apps) do
41-
case File.ls(Mix.Project.deps_path) do
42-
{:ok, deps} ->
43-
Enum.reject deps,
44-
fn(x) -> not File.dir?(x) and Enum.member?(loaded_apps, String.to_atom(x)) end
45-
{_, _} -> []
51+
defp checked_deps(build, deps) do
52+
for root <- [deps, build],
53+
path <- Path.wildcard(Path.join(root, "*")),
54+
File.dir?(path) do
55+
Path.basename(path)
4656
end
57+
|> Enum.uniq()
58+
|> List.delete(to_string(Mix.Project.config[:app]))
4759
end
4860

49-
defp do_clean(apps, opts) do
61+
defp filter_loaded(apps, opts) do
62+
load_opts = if only = opts[:only], do: [env: :"#{only}"], else: []
63+
load_deps = Mix.Dep.loaded(load_opts) |> Enum.map(&Atom.to_string(&1.app))
64+
Enum.reject(apps, &(&1 in load_deps))
65+
end
66+
67+
defp do_clean(apps, build, deps) do
5068
shell = Mix.shell
51-
build = Mix.Project.build_path
52-
|> Path.dirname
53-
|> Path.join("#{opts[:only] || :*}/lib")
54-
deps = Mix.Project.deps_path
5569

5670
Enum.each apps, fn(app) ->
5771
shell.info "* Cleaning #{app}"
@@ -65,9 +79,5 @@ defmodule Mix.Tasks.Deps.Clean do
6579
|> Path.join(to_string(app))
6680
|> File.rm_rf!
6781
end
68-
69-
if opts[:unlock] do
70-
Mix.Task.run "deps.unlock", apps
71-
end
7282
end
7383
end

lib/mix/lib/mix/tasks/deps.unlock.ex

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,43 @@ defmodule Mix.Tasks.Deps.Unlock do
66
@moduledoc """
77
Unlock the given dependencies.
88
9-
Since this is a destructive action, unlocking of all dependencies
10-
can only happen by passing the `--all` command line option.
9+
Since this is a destructive action, unlocking of dependencies
10+
can only happen by passing arguments/options:
11+
12+
* `dep1, dep2` - the name of dependency to be unlocked
13+
* `--all` - unlcks all dependencies
14+
* `--unused` - unlocks only unused dependencies (no longer mentioned
15+
in the `mix.exs` file)
16+
1117
"""
1218

19+
@switches [all: :boolean, unused: :boolean]
20+
1321
def run(args) do
1422
Mix.Project.get!
15-
{opts, args, _} = OptionParser.parse(args, switches: [all: :boolean])
23+
{opts, apps, _} = OptionParser.parse(args, switches: @switches)
1624

1725
cond do
1826
opts[:all] ->
1927
Mix.Dep.Lock.write([])
20-
args != [] ->
28+
opts[:unused] ->
29+
apps = Mix.Dep.loaded([]) |> Enum.map(& &1.app)
30+
Mix.Dep.Lock.read() |> Map.take(apps) |> Mix.Dep.Lock.write()
31+
32+
apps != [] ->
2133
lock =
22-
Enum.reduce args, Mix.Dep.Lock.read, fn(arg, lock) ->
23-
if is_binary(arg), do: arg = String.to_atom(arg)
24-
Map.delete(lock, arg)
34+
Enum.reduce apps, Mix.Dep.Lock.read, fn(app, lock) ->
35+
Map.delete(lock, String.to_atom(app))
2536
end
26-
2737
Mix.Dep.Lock.write(lock)
38+
2839
true ->
2940
Mix.raise "mix deps.unlock expects dependencies as arguments or " <>
30-
"the --all option to unlock all dependencies"
41+
"the --all option to unlock all dependencies"
3142
end
3243
end
44+
45+
defp unlock(apps) do
46+
47+
end
3348
end

lib/mix/test/mix/tasks/clean_test.exs

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,37 +21,30 @@ defmodule Mix.Tasks.CleanTest do
2121
:ok
2222
end
2323

24-
test "removes the build application" do
24+
test "cleans the application build" do
2525
in_fixture "deps_status", fn ->
26-
Mix.Tasks.Compile.run ["--no-deps"]
27-
assert File.exists?("_build/dev/lib/sample")
26+
File.mkdir_p! "_build/dev/lib/sample"
27+
File.mkdir_p! "_build/test/lib/sample"
28+
File.mkdir_p! "_build/dev/lib/ok"
2829

2930
Mix.Tasks.Clean.run []
3031
refute File.exists?("_build/dev/lib/sample")
32+
refute File.exists?("_build/test/lib/sample")
33+
assert File.exists?("_build/dev/lib/ok")
3134
end
3235
end
3336

34-
test "cleans deps" do
37+
test "cleans dependencies build" do
3538
in_fixture "deps_status", fn ->
36-
assert File.exists?("_build/dev/lib/ok")
37-
Mix.Tasks.Clean.run ["--all"]
39+
File.mkdir_p! "_build/dev/lib/ok"
40+
File.mkdir_p! "_build/test/lib/ok"
3841

42+
Mix.Tasks.Clean.run ["--deps", "--only", "dev"]
3943
refute File.exists?("_build/dev")
40-
assert_received {:mix_shell, :info, ["* Cleaning ok"]}
41-
42-
# Assert we don't choke on unfetched deps
43-
assert_received {:mix_shell, :info, ["* Cleaning unknown"]}
44-
end
45-
end
46-
47-
test "cleans all deps and builds" do
48-
in_fixture "deps_status", fn ->
49-
assert File.exists?("_build/dev/lib/ok")
50-
Mix.Tasks.Clean.run ["--all"]
44+
assert File.exists?("_build/test")
5145

52-
refute File.exists?("_build")
53-
assert_received {:mix_shell, :info, ["* Cleaning ok"]}
54-
assert_received {:mix_shell, :info, ["* Cleaning unknown"]}
46+
Mix.Tasks.Clean.run ["--deps"]
47+
refute File.exists?("_build/test")
5548
end
5649
end
5750
end

lib/mix/test/mix/tasks/deps_test.exs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ defmodule Mix.Tasks.DepsTest do
183183
end
184184
end
185185

186+
test "unlocks unused deps" do
187+
Mix.Project.push DepsApp
188+
in_fixture "no_mixfile", fn ->
189+
Mix.Dep.Lock.write %{whatever: "abcdef", ok: "abcdef"}
190+
assert Mix.Dep.Lock.read == %{whatever: "abcdef", ok: "abcdef"}
191+
Mix.Tasks.Deps.Unlock.run ["--unused"]
192+
assert Mix.Dep.Lock.read == %{ok: "abcdef"}
193+
end
194+
end
195+
186196
test "unlocks specific deps" do
187197
Mix.Project.push DepsApp
188198
in_fixture "no_mixfile", fn ->
@@ -531,12 +541,13 @@ defmodule Mix.Tasks.DepsTest do
531541
end
532542
end
533543

534-
test "clean all deps" do
544+
test "cleans dependencies" do
535545
Mix.Project.push CleanDepsApp
536546

537547
in_fixture "deps_status", fn ->
538-
File.mkdir_p!("deps/git_repo")
548+
File.mkdir_p!("_build/dev/lib/raw_sample")
539549
File.mkdir_p!("_build/dev/lib/git_repo")
550+
File.mkdir_p!("_build/test/lib/git_repo")
540551

541552
message = "mix deps.clean expects dependencies as arguments or " <>
542553
"a flag indicating which dependencies to clean " <>
@@ -547,16 +558,23 @@ defmodule Mix.Tasks.DepsTest do
547558
Mix.Tasks.Deps.Clean.run []
548559
end
549560

561+
Mix.Tasks.Deps.Clean.run ["--only", "dev", "--all"]
562+
refute File.exists?("_build/dev/lib/git_repo")
563+
assert File.exists?("_build/test/lib/git_repo")
564+
assert File.exists?("_build/dev/lib/raw_sample")
565+
550566
Mix.Tasks.Deps.Clean.run ["--all"]
551567
refute File.exists?("_build/dev/lib/git_repo")
552-
refute File.exists?("deps/git_repo")
568+
refute File.exists?("_build/test/lib/git_repo")
569+
assert File.exists?("_build/dev/lib/raw_sample")
553570
end
554571
end
555572

556-
test "clean unused" do
573+
test "cleans unused dependencies" do
557574
Mix.Project.push CleanDepsApp
558575

559576
in_fixture "deps_status", fn ->
577+
File.mkdir_p!("_build/dev/lib/raw_sample")
560578
File.mkdir_p!("deps/git_repo")
561579
File.mkdir_p!("_build/dev/lib/git_repo")
562580
File.mkdir_p!("deps/git_repo_unused")
@@ -567,23 +585,7 @@ defmodule Mix.Tasks.DepsTest do
567585
assert File.exists?("_build/dev/lib/git_repo")
568586
refute File.exists?("deps/git_repo_unused")
569587
refute File.exists?("_build/dev/lib/git_repo_unused")
570-
end
571-
end
572-
573-
test "cleans dependencies" do
574-
Mix.Project.push CleanDepsApp
575-
576-
in_fixture "deps_status", fn ->
577-
File.mkdir_p!("_build/dev/lib/git_repo")
578-
File.mkdir_p!("_build/test/lib/git_repo")
579-
580-
Mix.Tasks.Deps.Clean.run ["--only", "dev", "--all"]
581-
refute File.exists?("_build/dev/lib/git_repo")
582-
assert File.exists?("_build/test/lib/git_repo")
583-
584-
Mix.Tasks.Deps.Clean.run ["--all"]
585-
refute File.exists?("_build/dev/lib/git_repo")
586-
refute File.exists?("_build/test/lib/git_repo")
588+
assert File.exists?("_build/dev/lib/raw_sample")
587589
end
588590
end
589591
end

0 commit comments

Comments
 (0)