Current section
Files
Jump to
Current section
Files
image_pipe
mix.exs
mix.exs
defmodule ImagePipe.MixProject do
use Mix.Project
@version "0.1.0"
@source_url "https://github.com/hlindset/image_pipe"
@guide_groups [
"Getting started": [
"docs/index.md",
"docs/installation.md",
"../image_pipe_server/docs/server-getting-started.md",
"docs/phoenix-getting-started.md",
"docs/processing-in-elixir.md",
"docs/elixir-api.md",
"docs/building-server-urls.md"
],
"Requesting images": [
"docs/requesting-images.md",
"docs/processing.md",
"docs/processing/resize.md",
"docs/processing/crop.md",
"docs/processing/effects.md",
"docs/processing/watermark.md",
"docs/processing/output.md",
"docs/processing/request.md"
],
"Running ImagePipe": [
"../image_pipe_server/docs/server-deployment.md",
"docs/deployment.md",
"docs/sources.md",
"docs/serving-local-files.md",
"docs/serving-from-http.md",
"docs/serving-from-s3.md",
"docs/caching-processed-images.md",
"docs/serving-through-a-cdn.md",
"docs/signing-urls.md",
"docs/defining-presets.md",
"docs/enabling-detection.md",
"docs/processing-controls.md",
"docs/choosing-an-autoquality-target.md",
"docs/telemetry.md",
"docs/cookbook/opentelemetry-jaeger.md",
"docs/combined-usage.md",
"docs/fetching-from-the-server.md"
],
Concepts: [
"docs/processing-order.md",
"docs/caching-and-freshness.md",
"docs/streaming-failures.md",
"docs/urls.md",
"docs/presets.md",
"docs/content-aware-gravity.md",
"docs/source-network-policy.md",
"docs/tracing.md"
],
Extending: [
"docs/custom-sources.md",
"docs/custom-detectors.md",
"docs/storing-presets-in-a-database.md"
],
Reference: [
"docs/configuration.md",
"../image_pipe_server/docs/server-configuration.md",
"docs/shared-url-settings.md",
"docs/cache.md",
"docs/cdn-http-cache.md",
"docs/errors.md",
"docs/telemetry-events.md",
"docs/debug_headers.md"
],
Project: ["README.md", "CHANGELOG.md", "LICENSE.md"]
]
@guide_paths Enum.flat_map(@guide_groups, fn {_group, paths} -> paths end)
# Sidebar labels for pages whose H1 is too long for the sidebar.
@guide_titles %{
"docs/serving-from-http.md" => "Serving from an HTTP origin",
"docs/enabling-detection.md" => "Enabling detection",
"docs/choosing-an-autoquality-target.md" => "Choosing a quality target"
}
@internal_doc_references [
"ImagePipe.Error.tag/1",
"ImagePipe.Plug.Runner",
"ImagePipe.Response.Sender",
"ImagePipe.Security.verify/3",
"ImagePipe.Source.S3.Credentials.fetch/3",
"ImagePipe.Source.S3.Credentials.validate/1",
"ImagePipe.Source.S3.RefreshCache",
"ImagePipe.Telemetry.Trace.Capture"
]
# ExDoc resolves remote typespecs without consulting skip_code_autolink_to.
# These exact specs intentionally mention hidden runtime value types.
@internal_typespec_references [
"t:ImagePipe.Result.t/0"
]
def project do
[
app: :image_pipe,
version: @version,
description: description(),
package: package(),
elixir: "~> 1.18",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: extra_compilers(Mix.env()) ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
docs: [
main: "overview",
source_ref: "v#{@version}",
source_url: @source_url,
source_url_pattern: "#{@source_url}/blob/v#{@version}/image_pipe/%{path}#L%{line}",
skip_code_autolink_to: @internal_doc_references,
skip_undefined_reference_warnings_on: @internal_typespec_references,
assets: %{"docs/assets" => "docs/assets"},
extras:
Enum.map(@guide_paths, fn
"docs/index.md" -> {"docs/index.md", filename: "overview"}
path when is_map_key(@guide_titles, path) -> {path, title: @guide_titles[path]}
path -> path
end),
groups_for_extras: @guide_groups,
groups_for_modules: [
"Application API": [
ImagePipe,
ImagePipe.Config,
ImagePipe.Result,
ImagePipe.Plug,
ImagePipe.Plug.StreamAbortedError,
ImagePipe.ProcessingPool
],
Sources: [
ImagePipe.Source,
ImagePipe.Source.File,
ImagePipe.Source.HTTP,
ImagePipe.Source.S3
],
"Source adapter types": [
ImagePipe.Source.Resolved,
ImagePipe.Source.Response,
ImagePipe.Source.Origin,
ImagePipe.Source.CacheSettings,
ImagePipe.Source.CachePolicy,
ImagePipe.Source.CacheSemantics
],
"S3 credentials": [~r/ImagePipe\.Source\.S3\..*/],
Cache: [ImagePipe.Cache.FileSystem],
"Content detection": [
ImagePipe.Transform.Detector,
~r/ImagePipe\.Transform\.Detector\..*/
],
Telemetry: [ImagePipe.Telemetry, ~r/ImagePipe\.Telemetry\..*/]
]
],
test_coverage: [tool: ExCoveralls],
dialyzer: [
plt_core_path: "priv/plts",
plt_local_path: "priv/plts"
]
]
end
def application do
[
mod: {ImagePipe.Application, []},
extra_applications: [:logger]
]
end
def ex_dna_options do
[excluded_macros: [:alias]]
end
def cli do
[
preferred_envs: [
coveralls: :test,
"coveralls.html": :test,
"autoquality.bench": :test,
"autoquality.corpus": :test,
"autoquality.corpus.capture": :test,
"fixtures.gen_sources": :test,
"worktrees.clean": :test
]
]
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(:dev), do: ["lib"]
defp elixirc_paths(_env), do: ["lib"]
defp extra_compilers(:prod), do: []
defp extra_compilers(_env), do: [:boundary]
defp description do
"A Plug-based image optimization server with a declarative path API."
end
defp package do
[
files:
Enum.reject(@guide_paths, &String.starts_with?(&1, "../")) ++
[
"lib",
"priv/icc",
"docs/assets/demo-fiddle-desktop.png",
"mix.exs"
],
licenses: ["Apache-2.0"],
links: %{
"GitHub" => @source_url,
"Changelog" => "#{@source_url}/blob/main/image_pipe/CHANGELOG.md"
},
maintainers: ["Håvard Lindset"]
]
end
defp deps do
base = [
image_pipe_url_dep(),
{:plug, "~> 1.18"},
{:telemetry, "~> 1.0"},
# Opt-in OpenTelemetry export. Compile against the lightweight API only
# (optional: true, NO `only:` — the optional edge orders a host-provided
# opentelemetry_api before image_pipe so the compile guard activates). The
# SDK is the host's at runtime; we pull it only for our own tests.
{:opentelemetry_api, "~> 1.5", optional: true},
{:opentelemetry, "~> 1.7", only: :test},
{:nimble_options, "~> 1.1"},
{:image, "~> 0.72"},
{:ssimulacra2, "~> 0.1.0"},
{:vix, "~> 0.42"},
{:req, "~> 0.8.0-rc.0"},
{:stream_data, "~> 1.0", only: [:test, :dev]},
{:boundary, "~> 0.10", runtime: false},
{:excoveralls, ">= 0.0.0", only: [:test], runtime: false},
{:ex_doc, "~> 0.35", only: :dev, runtime: false},
{:makeup_syntect, "~> 0.1.4", only: :dev, runtime: false},
{:makeup_eex, "~> 2.0", only: :dev, runtime: false},
# makeup_syntect (docs) pins rustler_precompiled ~> 0.8.2, ssimulacra2 needs
# 0.9. The override only matters where makeup_syntect is present, but its
# `only:` applies to ssimulacra2's copy too, so it must cover those envs.
{:rustler_precompiled, "~> 0.9", only: [:dev, :test], override: true},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:ex_slop, "~> 0.4", only: [:dev, :test], runtime: false},
{:ex_dna, "~> 1.5", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
{:talan, "~> 1.0"},
{:bandit, "~> 1.5", only: [:dev, :test]}
]
# Real face detection needs `image_vision` AND its optional ONNX backend
# `ortex` (a Rust/ONNX runtime): `image_vision`'s `Image.FaceDetection` is
# compiled only when Ortex is configured (`if ImageVision.ortex_configured?()`),
# and the YuNet model (~340 KB) downloads on first use.
#
# The fiddle app owns real detection in its own deps. Here, the library pulls
# these only into the opt-in `:test` lane (`IMAGE_VISION=1`) for its own
# detector test (`IMAGE_VISION=1 mix test --only image_vision`).
ml_test_deps =
if System.get_env("IMAGE_VISION") in ["1", "true"] do
[
{:image_vision, "~> 0.4", only: :test},
{:ortex, "~> 0.1", only: :test}
]
else
[]
end
base ++ ml_test_deps
end
# Development and CI use the sibling project. Set IMAGE_PIPE_PUBLISH=1 when
# publishing: Hex packages cannot carry path deps, and the two packages are
# released in lockstep.
defp image_pipe_url_dep do
if System.get_env("IMAGE_PIPE_PUBLISH") in ["1", "true"] do
{:image_pipe_url, "== #{@version}"}
else
{:image_pipe_url, path: "../image_pipe_url"}
end
end
defp aliases do
[
"image_pipe.ex_dna": &run_ex_dna/1,
setup: ["deps.get"],
test: ["test"]
]
end
defp run_ex_dna(args) do
options = ex_dna_options()
excluded_macros =
Enum.flat_map(options[:excluded_macros], &["--exclude-macro", Atom.to_string(&1)])
Mix.Task.run("ex_dna", excluded_macros ++ args)
end
end