-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #139 from liveview-native/bc-gen-mix-tasks
generator mix tasks
- Loading branch information
Showing
13 changed files
with
423 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
defmodule Mix.LiveViewNative.Context do | ||
defstruct context_app: nil, | ||
base_module: nil, | ||
web_module: nil, | ||
native_module: nil, | ||
module_suffix: nil, | ||
format: nil, | ||
opts: [] | ||
|
||
def build(args, caller) do | ||
{parsed_opts, parsed, _} = parse_opts(args, caller.switches()) | ||
[format | opts] = caller.validate_args!(parsed) | ||
|
||
format = atomize(format) | ||
|
||
ctx_app = parsed_opts[:context_app] || Mix.Phoenix.context_app() | ||
base_module = Module.concat([Mix.Phoenix.context_base(ctx_app)]) | ||
native_module = Module.concat([inspect(base_module) <> "Native"]) | ||
web_module = Mix.Phoenix.web_module(base_module) | ||
|
||
%__MODULE__{ | ||
context_app: ctx_app, | ||
base_module: base_module, | ||
native_module: native_module, | ||
web_module: web_module, | ||
module_suffix: get_module_suffix(format), | ||
format: format, | ||
opts: opts | ||
} | ||
end | ||
|
||
defp atomize(atom) when is_atom(atom), do: atom | ||
defp atomize(string) when is_binary(string), | ||
do: String.to_atom(string) | ||
|
||
defp get_module_suffix(nil), do: nil | ||
defp get_module_suffix(format), | ||
do: LiveViewNative.fetch_plugin!(format).module_suffix | ||
|
||
def valid_format?(format) do | ||
LiveViewNative.fetch_plugin(format) | ||
|> case do | ||
{:ok, _plugin} -> true | ||
:error -> false | ||
end | ||
end | ||
|
||
def apps(format) do | ||
plugin_otp_app_name = | ||
format | ||
|> LiveViewNative.fetch_plugin!() | ||
|> Map.get(:__struct__) | ||
|> Application.get_application() | ||
|
||
[".", plugin_otp_app_name, :live_view_native] | ||
end | ||
|
||
def prompt_for_conflicts(generator_files) do | ||
file_paths = | ||
Enum.flat_map(generator_files, fn | ||
{:new_eex, _, _path} -> [] | ||
{_kind, _, path} -> [path] | ||
end) | ||
|
||
case Enum.filter(file_paths, &File.exists?(&1)) do | ||
[] -> :ok | ||
conflicts -> | ||
Mix.shell().info""" | ||
The following files conflict with new files to be generated: | ||
#{Enum.map_join(conflicts, "\n", &" * #{&1}")} | ||
""" | ||
unless Mix.shell().yes?("Proceed with interactive overwrite?") do | ||
System.halt() | ||
end | ||
end | ||
end | ||
|
||
defp parse_opts(args, switches) do | ||
{opts, parsed, invalid} = OptionParser.parse(args, switches: switches) | ||
|
||
merged_opts = put_context_app(opts, opts[:context_app]) | ||
|
||
{merged_opts, parsed, invalid} | ||
end | ||
|
||
defp put_context_app(opts, nil), do: opts | ||
|
||
defp put_context_app(opts, string) do | ||
Keyword.put(opts, :context_app, String.to_atom(string)) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
defmodule Mix.Tasks.Lvn.Gen do | ||
alias Mix.LiveViewNative.Context | ||
|
||
def run(args) do | ||
context = Context.build(args, __MODULE__) | ||
|
||
files = files_to_be_generated(context) | ||
|
||
Context.prompt_for_conflicts(files) | ||
|
||
copy_new_files(context, files) | ||
end | ||
|
||
def switches, do: [ | ||
context_app: :string, | ||
web: :string | ||
] | ||
|
||
def validate_args!([]), do: [nil] | ||
def validate_args!(_args) do | ||
Mix.raise(""" | ||
mix lvn.gen does not take any arguments, only the following switches: | ||
--context-app | ||
--web | ||
""") | ||
end | ||
|
||
defp files_to_be_generated(context) do | ||
path = Mix.Phoenix.context_app_path(context.context_app, "lib") | ||
file = Phoenix.Naming.underscore(context.native_module) <> ".ex" | ||
|
||
[{:eex, "app_name_native.ex", Path.join(path, file)}] | ||
end | ||
|
||
defp copy_new_files(%Context{} = context, files) do | ||
binding = [ | ||
context: context, | ||
assigns: %{ | ||
gettext: true, | ||
formats: formats(), | ||
layouts: layouts(context.web_module) | ||
} | ||
] | ||
|
||
Mix.Phoenix.copy_from([".", :live_view_native], "priv/templates/lvn.gen", binding, files) | ||
|
||
context | ||
end | ||
|
||
defp formats do | ||
LiveViewNative.available_formats() | ||
end | ||
|
||
defp layouts(web_module) do | ||
Enum.map(formats(), fn(format) -> | ||
format_module = | ||
format | ||
|> LiveViewNative.fetch_plugin!() | ||
|> Map.fetch!(:module_suffix) | ||
|
||
{format, {Module.concat([web_module, Layouts, format_module]), :app}} | ||
end) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
defmodule Mix.Tasks.Lvn.Gen.Layout do | ||
alias Mix.LiveViewNative.Context | ||
|
||
def run(args) do | ||
context = Context.build(args, __MODULE__) | ||
|
||
files = files_to_be_generated(context) | ||
|
||
Context.prompt_for_conflicts(files) | ||
|
||
copy_new_files(context, files) | ||
end | ||
|
||
def switches, do: [ | ||
context_app: :string, | ||
web: :string | ||
] | ||
|
||
def validate_args!([]) do | ||
formats = | ||
LiveViewNative.available_formats() | ||
|> Enum.map(&("* #{&1}")) | ||
|> Enum.join("\n") | ||
|
||
Mix.raise(""" | ||
You must pass a valid format. Available formats: | ||
#{formats} | ||
""") | ||
end | ||
|
||
def validate_args!([format | _] = args) do | ||
cond do | ||
not Context.valid_format?(format) -> | ||
formats = | ||
LiveViewNative.available_formats() | ||
|> Enum.map(&("* #{&1}")) | ||
|> Enum.join("\n") | ||
|
||
Mix.raise(""" | ||
#{format} is an unregistered format. | ||
Available formats: | ||
#{formats} | ||
Please see the documentation for how to register new LiveView Native plugins | ||
""") | ||
|
||
true -> | ||
args | ||
end | ||
end | ||
|
||
defp files_to_be_generated(%Context{format: format, context_app: context_app}) do | ||
web_prefix = Mix.Phoenix.web_path(context_app) | ||
|
||
components_path = Path.join(web_prefix, "components") | ||
layouts_path = Path.join(components_path, "layouts_#{format}") | ||
|
||
[ | ||
{:eex, "layout.ex", Path.join(components_path, "layouts.#{format}.ex")}, | ||
{:eex, "app.neex", Path.join(layouts_path, "app.#{format}.neex")}, | ||
{:eex, "root.neex", Path.join(layouts_path, "root.#{format}.neex")} | ||
] | ||
end | ||
|
||
defp copy_new_files(%Context{} = context, files) do | ||
binding = [ | ||
context: context, | ||
assigns: %{ | ||
gettext: true | ||
} | ||
] | ||
|
||
apps = Context.apps(context.format) | ||
|
||
Mix.Phoenix.copy_from(apps, "priv/templates/lvn.gen.layout", binding, files) | ||
|
||
context | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<%%= @inner_content %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
defmodule <%= context.web_module %>.Layouts.<%= context.module_suffix %> do | ||
use <%= context.native_module %>, [:layout, format: <%= inspect context.format %>] | ||
|
||
embed_templates "layouts_<%= context.format %>/*" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<.csrf_token /> | ||
<Style url={~p"/assets/app.<%= context.format %>"} /> | ||
<%%= @inner_content %> |
Oops, something went wrong.