Skip to content

Commit

Permalink
Add mix utility to update SVGs from github
Browse files Browse the repository at this point in the history
  • Loading branch information
greven committed Jan 3, 2022
1 parent 4aa62f6 commit 8b890e3
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 1 deletion.
7 changes: 7 additions & 0 deletions config/config.exs
@@ -0,0 +1,7 @@
import Config

config :heroicons,
version: "1.0.3",
another: [
args: ["--version"]
]
84 changes: 84 additions & 0 deletions lib/heroicons.ex
Expand Up @@ -17,6 +17,11 @@ defmodule Heroicons do
Heroicons are designed by [Steve Schoger](https://twitter.com/steveschoger)
"""

# https://github.com/tailwindlabs/heroicons/releases
@latest_version "1.0.3"

require Logger

defmodule Outline do
@moduledoc """
Outline style icons drawn with a stroke, packaged as Phoenix Components.
Expand All @@ -36,4 +41,83 @@ defmodule Heroicons do

use Heroicons.Generator, icon_dir: "solid/"
end

@doc false
# Latest known version at the time of publishing.
def latest_version, do: @latest_version

@doc """
Returns the configured Sass version.
"""
def configured_version do
Application.get_env(:heroicons, :version, latest_version())
end

@doc false
def svgs_path, do: :code.priv_dir(:heroicons)

def update do
version = configured_version()
tmp_dir = Path.join(System.tmp_dir!(), "heroicons-elixir")
File.rm_rf!(tmp_dir)
File.mkdir_p!(tmp_dir)

url = "https://github.com/tailwindlabs/heroicons/archive/refs/tags/v#{version}.zip"
archive = fetch_body!(url)

case unpack_archive(".zip", archive, tmp_dir) do
:ok -> :ok
other -> raise "couldn't unpack archive: #{inspect(other)}"
end

File.cp_r!(Path.join([tmp_dir, "heroicons-#{version}", "optimized"]), svgs_path())
end

defp fetch_body!(url) do
url = String.to_charlist(url)
Logger.debug("Downloading heroicons from #{url}")

{:ok, _} = Application.ensure_all_started(:inets)
{:ok, _} = Application.ensure_all_started(:ssl)

# https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets
cacertfile = CAStore.file_path() |> String.to_charlist()

http_options = [
autoredirect: false,
ssl: [
verify: :verify_peer,
cacertfile: cacertfile,
depth: 2,
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
]

case :httpc.request(:get, {url, []}, http_options, []) do
{:ok, {{_, 302, _}, headers, _}} ->
{'location', download} = List.keyfind(headers, 'location', 0)
options = [body_format: :binary]

case :httpc.request(:get, {download, []}, http_options, options) do
{:ok, {{_, 200, _}, _, body}} ->
body

other ->
raise "couldn't fetch #{download}: #{inspect(other)}"
end

other ->
raise "couldn't fetch #{url}: #{inspect(other)}"
end
end

defp unpack_archive(".zip", zip, cwd) do
with {:ok, _} <- :zip.unzip(zip, cwd: to_charlist(cwd)), do: :ok
end

defp unpack_archive(_, tar, cwd) do
:erl_tar.extract({:binary, tar}, [:compressed, cwd: to_charlist(cwd)])
end
end
31 changes: 31 additions & 0 deletions lib/mix/tasks/heroicons.ex
@@ -0,0 +1,31 @@
defmodule Mix.Tasks.Heroicons do
@moduledoc """
Invokes heroicons mix utilities.
Usage:
$ mix heroicons
"""

@shortdoc "Invokes heroicons mix utilities"

use Mix.Task

@impl true
def run(args) do
{_opts, args} = OptionParser.parse!(args, strict: [])

case args do
[] -> help()
_ -> Mix.raise("Invalid arguments, expected: mix heroicons")
end
end

defp help() do
Mix.Task.run("app.start")
Mix.shell().info("Heroicons v#{Application.spec(:heroicons, :vsn)}")
Mix.shell().info("Include Heroicons as SVG-strings in your Elixir/Phoenix project!")
Mix.shell().info("\nAvailable tasks:\n")
Mix.Tasks.Help.run(["--search", "heroicons."])
end
end
24 changes: 24 additions & 0 deletions lib/mix/tasks/heroicons.update.ex
@@ -0,0 +1,24 @@
defmodule Mix.Tasks.Heroicons.Update do
@moduledoc """
Update heroicons.
By default, it downloads the latest version but you
can configure it in your config files, such as:
config :heroicons, :version, "#{Heroicons.latest_version()}"
"""

@shortdoc "Update heroicons assets"

use Mix.Task

@impl true
def run(args) do
{_opts, args} = OptionParser.parse!(args, strict: [])

case args do
[] -> Heroicons.update()
_ -> Mix.raise("Invalid arguments, expected: mix heroicons.update")
end
end
end
4 changes: 3 additions & 1 deletion mix.exs
Expand Up @@ -12,6 +12,7 @@ defmodule HeroiconsElixir.MixProject do
source_url: "https://github.com/mveytsman/heroicons_elixir",
description: "Include Heroicons as SVG-strings in your Elixir/Phoenix project!",
docs: docs(),
xref: [exclude: [:httpc, :public_key]],
package: package()
]
end
Expand All @@ -28,7 +29,8 @@ defmodule HeroiconsElixir.MixProject do
[
{:phoenix_html, "~> 2.14 or ~> 3.0"},
{:phoenix_live_view, ">= 0.16.0", optional: true},
{:ex_doc, "~> 0.23", only: :dev, runtime: false}
{:ex_doc, "~> 0.23", only: :dev, runtime: false},
{:castore, ">= 0.0.0"}
]
end

Expand Down
1 change: 1 addition & 0 deletions mix.lock
@@ -1,4 +1,5 @@
%{
"castore": {:hex, :castore, "0.1.14", "3f6d7c7c1574c402fef29559d3f1a7389ba3524bc6a090a5e9e6abc3af65dcca", [:mix], [], "hexpm", "b34af542eadb727e6c8b37fdf73e18b2e02eb483a4ea0b52fd500bc23f052b7b"},
"earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"},
"ex_doc": {:hex, :ex_doc, "0.23.0", "a069bc9b0bf8efe323ecde8c0d62afc13d308b1fa3d228b65bca5cf8703a529d", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "f5e2c4702468b2fd11b10d39416ddadd2fcdd173ba2a0285ebd92c39827a5a16"},
"floki": {:hex, :floki, "0.30.0", "22ebbe681a5d3777cdd830ca091b1b806d33c3449c26312eadca7f7be685c0c8", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "a9e128a4ca9bb71f11affa315b6768a9ad326d5996ff1e92acf1d7a01a10076a"},
Expand Down

0 comments on commit 8b890e3

Please sign in to comment.