defmodule VFS.MixProject do use Mix.Project @version "0.1.0" @source_url "https://github.com/ivarvong/vfs" # `coveralls` only exists in :test; without this, a bare `mix check` # from the default dev env dies at the last gate step. def cli do [preferred_envs: [check: :test, coveralls: :test, "coveralls.html": :test]] end def project do [ app: :vfs, version: @version, elixir: "~> 1.16", elixirc_paths: elixirc_paths(Mix.env()), consolidate_protocols: consolidate_protocols?(), start_permanent: Mix.env() == :prod, deps: deps(), aliases: aliases(), test_coverage: [tool: ExCoveralls], dialyzer: [ plt_add_apps: [:ex_unit, :stream_data, :mix], plt_core_path: "priv/plts", plt_local_path: "priv/plts", flags: [ :error_handling, :unknown, :unmatched_returns, :extra_return, :missing_return ] ], package: package(), description: description(), docs: docs(), name: "VFS", source_url: @source_url ] end # Consolidate protocols everywhere except :test (the suite defines its own # VFS.Mountable impls), unless VFS_CONSOLIDATE_PROTOCOLS overrides it — CI sets # it to prove release-style consolidation doesn't break protocol dispatch. defp consolidate_protocols? do case System.get_env("VFS_CONSOLIDATE_PROTOCOLS") do "true" -> true "false" -> false _ -> Mix.env() != :test end end # `dev/` holds maintainer-only Mix tasks (vfs.audit, vfs.mutate); it is # compiled in dev/test but never shipped (see package `files:`), so consumers # don't get internal tooling injected into their projects. defp elixirc_paths(:dev), do: ["lib", "dev"] defp elixirc_paths(:test), do: ["lib", "test/support", "dev"] defp elixirc_paths(_), do: ["lib"] defp deps do [ {:telemetry, "~> 1.3"}, {:stream_data, "~> 1.1", only: [:dev, :test]}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:excoveralls, "~> 0.18", only: :test}, {:ex_doc, "~> 0.34", only: :dev, runtime: false}, {:benchee, "~> 1.3", only: [:dev, :test], runtime: false}, # Test-only: real exgit for the integration test set. Validates that # VFS.Mountable actually fits a non-trivial real-world backend (lazy # partial-clone, content-addressed objects, network transports). The # defimpl ships in test/support/ for now; production version moves # into :exgit once the protocol shape is stable. {:exgit, github: "ivarvong/exgit", only: :test} ] end defp aliases do [ setup: ["deps.get", "dialyzer --plt", &install_pre_commit_hook/1], check: [ "format --check-formatted", "compile --warnings-as-errors --force", "credo", "dialyzer", "coveralls --raise" ] ] end # CLAUDE.md promises `mix setup` wires the local pre-commit gate. defp install_pre_commit_hook(_args) do hook = ".git/hooks/pre-commit" if File.dir?(Path.dirname(hook)) do File.write!(hook, "#!/bin/sh\nexec mix check\n") File.chmod!(hook, 0o755) Mix.shell().info("Installed #{hook} (runs mix check)") end end defp description do "Protocol-based virtual filesystem for the Elixir AI tools stack — pluggable backends, " <> "state threading, lazy reads, and a tiny core surface." end defp package do [ licenses: ["MIT"], links: %{"GitHub" => @source_url}, files: ~w(lib mix.exs README.md SPEC.md CHANGELOG.md LICENSE .formatter.exs) ] end defp docs do [ main: "readme", source_ref: "v#{@version}", extras: ["README.md", "SPEC.md", "CHANGELOG.md"], # Docs build in :dev, where dev/ (maintainer-only Mix tasks) is # compiled; without the filter those tasks leak into hexdocs. filter_modules: ~r/^Elixir\.VFS(\.|$)/, groups_for_modules: [ Core: [VFS, VFS.Mountable, VFS.Stat, VFS.Path, VFS.Error], "Backends & helpers": [VFS.Memory, VFS.Skeleton, VFS.Default, VFS.StreamOptions] ] ] end end