Current section
Files
Jump to
Current section
Files
lib/mix/tasks/kitto.install.ex
defmodule Mix.Tasks.Kitto.Install do
use Mix.Task
@shortdoc "Install community Widget/Job from a Github Gist"
@github_base_url "https://api.github.com/gists/"
@supported_languages ["JavaScript", "SCSS", "Markdown", "Elixir"]
@job_rexp ~r/\.exs$/
@lib_rexp ~r/\.ex$/
@moduledoc """
Installs community Widget/Job from a Github Gist
mix kitto.install --widget test_widget --gist JanStevens/0209a4a80cee782e5cdbe11a1e9bc393
mix kitto.install --gist 0209a4a80cee782e5cdbe11a1e9bc393
## Options
* `--widget` - specifies the widget name that will be used as directory name
in the widgets directory. By default we use the js filename as directory
* `--gist` - The gist to download from, specified as `Username/Gist` or `Gist`
"""
def run(args) do
{:ok, _started} = Application.ensure_all_started(:httpoison)
{opts, _parsed, _} = OptionParser.parse(args, strict: [widget: :string, gist: :string])
opts_map = Enum.into(opts, %{})
process(opts_map)
end
defp process(%{gist: gist, widget: widget}) do
files = gist |> String.split("/")
|> build_gist_url
|> download_gist
|> Map.get(:files)
|> Enum.map(&extract_file_properties/1)
|> Enum.filter(&supported_file_type?/1)
widget_dir = widget || find_widget_filename(files)
files
|> Enum.map(&(determine_file_location(&1, widget_dir)))
|> Enum.each(&write_file/1)
end
defp process(%{gist: gist}), do: process(%{gist: gist, widget: nil})
defp process(_) do
Mix.shell.error "Unsupported arguments"
end
defp write_file(file) do
Mix.Generator.create_directory(file.path)
Mix.Generator.create_file(Path.join(file.path, file.filename), file.content)
end
defp determine_file_location(_file, widget_name) when is_nil(widget_name) do
Mix.shell.error "Please specify a widget directory using the --widget flag"
Mix.raise "Installation failed"
end
defp determine_file_location(file = %{language: "Elixir", filename: filename}, _) do
file |> put_in([:path], (cond do
Regex.match?(@job_rexp, filename) -> "jobs"
Regex.match?(@lib_rexp, filename) -> "lib"
true -> Mix.shell.error "Found Elixir file #{filename} not ending in .ex or exs"
end))
end
# Other files all go into the widgets dir
defp determine_file_location(file, widget_name) do
put_in file, [:path], Path.join(["widgets", widget_name])
end
defp find_widget_filename(files) do
files
|> Enum.filter(&(&1.language == "JavaScript"))
|> List.first
|> extract_widget_dir
end
defp extract_widget_dir(%{filename: filename}) do
filename |> String.replace(~r/\.js$/, "")
end
defp extract_widget_dir(nil), do: nil
defp supported_file_type?(file), do: Enum.member?(@supported_languages, file.language)
defp extract_file_properties({_filename, file}), do: file
defp download_gist(url), do: url |> HTTPoison.get! |> process_response
defp build_gist_url([gist_url]), do: @github_base_url <> gist_url
defp build_gist_url([_ | gist_url]), do: build_gist_url(gist_url)
defp process_response(%HTTPoison.Response{status_code: 200, body: body}) do
body |> Poison.decode!(keys: :atoms)
end
defp process_response(%HTTPoison.Response{status_code: code, body: body}) do
decoded_body = body |> Poison.decode!(keys: :atoms)
Mix.shell.error "Could not fetch the gist from GitHub: " <>
"#{code}: #{decoded_body.message}"
Mix.raise "Installation failed"
end
end