-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
archive.build.ex
118 lines (96 loc) · 3.79 KB
/
archive.build.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
defmodule Mix.Tasks.Archive.Build do
use Mix.Task
@shortdoc "Archives this project into a .ez file"
@moduledoc """
Builds an archive according to the specification of the
[Erlang Archive Format](http://www.erlang.org/doc/man/code.html).
Archives are meant to contain small projects, usually installed
locally. Archives may be installed into a Mix environment by
running `mix archive.install`. Once installed, the archive is
available to all Mix projects. For this reason, the functionality
behind archives is limited. For instance, archives do not include
dependencies, as those would conflict with any dependency in a
Mix project after the archive is installed. In general, we recommend
the usage of archives to be limited for extensions of Mix, such
as custom SCMs, package managers, etc. For general scripts to be
installed into machines, please see `mix escript.build`.
The archive will be created in the current directory (which is
expected to be the project root), unless an argument `-o` is
provided with the file name.
By default, this command archives the current project but the `-i`
option can be used to archive any directory. For example,
`mix archive.build` with no options translates to:
mix archive.build -i _build/ENV/lib/APP -o APP-VERSION.ez
## Command line options
* `-o` - specifies output file name.
If there is a `mix.exs`, defaults to "APP-VERSION.ez".
* `-i` - specifies the input directory to archive.
If there is a `mix.exs`, defaults to the current application build.
* `--no-compile` - skips compilation.
Only applies when `mix.exs` is available.
"""
@switches [force: :boolean, compile: :boolean, output: :string, input: :string,
deps_check: :boolean, archives_check: :boolean, elixir_version_check: :boolean]
@spec run(OptionParser.argv) :: :ok
def run(args) do
{opts, _} = OptionParser.parse!(args, aliases: [o: :output, i: :input], strict: @switches)
project = Mix.Project.get
if project && Keyword.get(opts, :compile, true) do
Mix.Task.run :compile, args
end
source = cond do
input = opts[:input] ->
input
project ->
path = Mix.Project.app_path
if elixir = Mix.Project.config[:elixir] do
File.write Path.join(path, ".elixir"), elixir
else
File.rm Path.join(path, ".elixir")
end
path
true ->
Mix.raise "Cannot create archive without input directory, " <>
"please pass -i as an option"
end
project_config = Mix.Project.config
target = cond do
output = opts[:output] ->
output
project_config[:app] ->
Mix.Local.name_for(:archive, project_config)
true ->
Mix.raise "Cannot create archive without output file, " <>
"please pass -o as an option"
end
unless File.dir?(source) do
Mix.raise "Expected archive source #{inspect source} to be a directory"
end
create(source, target)
Mix.shell.info "Generated archive #{inspect target} with MIX_ENV=#{Mix.env}"
:ok
end
defp create(source, target) do
source_path = Path.expand(source)
target_path = Path.expand(target)
dir = Mix.Local.archive_name(target_path) |> String.to_charlist
{:ok, _} = :zip.create(String.to_charlist(target_path),
files_to_add(source_path, dir))
:ok
end
defp files_to_add(path, dir) do
File.cd! path, fn ->
evsn = Path.wildcard(".elixir")
ebin = Path.wildcard("ebin/*.{beam,app}")
priv = Path.wildcard("priv/**/*")
Enum.reduce evsn ++ ebin ++ priv, [], fn(f, acc) ->
case File.read(f) do
{:ok, bin} ->
[{Path.join(dir, f) |> String.to_charlist, bin} | acc]
{:error, _} ->
acc
end
end
end
end
end