defmodule Webp do
@moduledoc """
Webp is a installer and runner for [Webp].
## Profiles
You can define multiple configuration profiles. By default, there is a
profile called `:default` which you can configure its args, current
directory and environment:
config :webp,
default: [
location: Path.expand("../priv/static/images/", __DIR__),
destination: Path.expand("../priv/static/images/", __DIR__)
]
## Webp configuration
There are two global configurations for the `webp` application:
* `:path` - the path to the webp executable.
Once you find the location of the executable, you can store it in a
`MIX_WEBP_PATH` environment variable, which you can then read in
your configuration file:
config :webp, path: System.get_env("MIX_WEBP_PATH")
"""
use Application
require Logger
@doc false
def start(_, _) do
Supervisor.start_link([], strategy: :one_for_one)
end
@doc """
Returns the configuration for the given profile.
Returns nil if the profile does not exist.
"""
def config_for!(profile) when is_atom(profile) do
Application.get_env(:webp, profile) ||
raise ArgumentError, """
unknown webp profile. Make sure the profile named #{inspect(profile)} is defined in your config files, such as:
config :webp,
#{profile}: [
location: Path.expand("../assets", __DIR__),
destination: Path.expand("../priv/static/images/", __DIR__)
]
"""
end
@doc false
def script_path() do
Path.join(:code.priv_dir(:webp), "webp.bash")
end
defp cmd(command, args, opts) do
System.cmd(command, args, opts)
end
@doc """
Runs the given command with `args`.
The given args will be appended to the configured args.
The task output will be streamed directly to stdio. It
returns the status of the underlying call.
"""
def run(profile, extra_args) when is_atom(profile) and is_list(extra_args) do
config = config_for!(profile)
location = config[:location] || []
destination = config[:destination] || nil
quality = config[:quality] || 80
if location == [] and extra_args == [] do
raise "no arguments passed to webp"
end
opts = [
cd: config[:location] || File.cwd!(),
env: config[:env] || %{},
into: IO.stream(:stdio, :line),
stderr_to_stdout: true
]
args = [location] ++ extra_args
glob = location <> "/*"
files = Path.wildcard(glob)
for source <- files do
path = bin_path()
valid_extension =
Path.extname(source) in Application.get_env(:webp, :image_extensions, [
".png",
".jpg",
".jpeg"
])
case valid_extension do
true ->
extname = Path.extname(source)
filename = Path.basename(source, extname)
destination = config[:destination] || Path.basename(source, extname)
params = ["-quiet", "#{source}", "-o", "#{destination}.webp"]
path =
if "--watch" in args do
[script_path() | path]
else
path
end
path
|> cmd(params, opts)
|> elem(1)
false ->
:error
end
end
end
@doc """
Returns the path to the executable.
The executable may not be available if it was not yet installed.
"""
def bin_path do
Application.get_env(:webp, :path, "/usr/bin/cwebp")
end
@doc """
Convert Source to Destination `args`.
"""
def convert(source, params \\ []) do
opts = [
cd: params[:location] || File.cwd!(),
env: params[:env] || %{},
into: IO.stream(:stdio, :line),
stderr_to_stdout: true
]
path = bin_path()
unless File.exists?(path) do
raise "#{} Not Found please set path to the cwebp location"
end
valid_extension =
Path.extname(source) in Application.get_env(:webp, :image_extensions, [
".png",
".jpg",
".jpeg"
])
case valid_extension do
true ->
extname = Path.extname(source)
filename = Path.basename(source, extname)
destination = params[:destination] || Path.basename(source, extname)
params = ["-quiet", "#{source}", "-o", "#{destination}.webp"]
path
|> cmd(params, opts)
|> elem(1)
false ->
:error
end
end
@doc """
Convert Source to Destination if cwebp exists.
"""
def install_and_run(profile, args) do
unless File.exists?(bin_path()) do
raise "#{} Not Found please set path to the cwebp location"
end
run(profile, args)
end
end