Current section
Files
Jump to
Current section
Files
lib/mix/tasks/firebird.target.clean.ex
defmodule Mix.Tasks.Firebird.Target.Clean do
@moduledoc """
Clean WASM build artifacts produced by the Firebird compiler.
Removes compiled `.wat`, `.wasm`, source map, and manifest files
from the output directory. Optionally removes the entire output
directory.
## Usage
# Clean default output directory (_build/wasm)
mix firebird.target.clean
# Clean a specific output directory
mix firebird.target.clean --output priv/wasm
# Remove the entire output directory
mix firebird.target.clean --all
# Dry run โ show what would be deleted
mix firebird.target.clean --dry-run
# Clean only specific artifact types
mix firebird.target.clean --wat # only .wat files
mix firebird.target.clean --wasm # only .wasm files
mix firebird.target.clean --manifests # only manifests
## What Gets Cleaned
- `.wat` files (WebAssembly Text Format)
- `.wasm` files (WebAssembly binary)
- `.source_map.json` files (source maps)
- `firebird_manifest.json` (compilation manifest)
- `firebird_target.manifest` (incremental build manifest)
- `firebird_content_hashes.manifest` (content hash cache)
"""
use Mix.Task
@shortdoc "Clean WASM compilation artifacts"
@switches [
output: :string,
all: :boolean,
dry_run: :boolean,
wat: :boolean,
wasm: :boolean,
manifests: :boolean,
quiet: :boolean
]
@aliases [
o: :output,
q: :quiet
]
@impl Mix.Task
def run(args) do
{opts, _rest, _invalid} = OptionParser.parse(args, switches: @switches, aliases: @aliases)
output_dir = Keyword.get(opts, :output, default_output_dir())
remove_all = Keyword.get(opts, :all, false)
dry_run = Keyword.get(opts, :dry_run, false)
quiet = Keyword.get(opts, :quiet, false)
# Determine which artifact types to clean
wat_only = Keyword.get(opts, :wat, false)
wasm_only = Keyword.get(opts, :wasm, false)
manifests_only = Keyword.get(opts, :manifests, false)
# If no specific type is selected, clean all
clean_all_types = not wat_only and not wasm_only and not manifests_only
unless quiet do
if dry_run do
Mix.shell().info("๐งน Firebird WASM Clean โ Dry Run")
else
Mix.shell().info("๐งน Firebird WASM Clean")
end
Mix.shell().info("")
end
if remove_all do
clean_entire_directory(output_dir, dry_run, quiet)
else
files_removed =
clean_artifacts(
output_dir,
%{
wat: clean_all_types or wat_only,
wasm: clean_all_types or wasm_only,
manifests: clean_all_types or manifests_only
},
dry_run,
quiet
)
# Also clean the Mix compiler manifest
if clean_all_types or manifests_only do
clean_compiler_manifests(dry_run, quiet)
end
unless quiet do
if dry_run do
Mix.shell().info("")
Mix.shell().info(" Would remove #{files_removed} file(s)")
else
Mix.shell().info("")
Mix.shell().info(" Removed #{files_removed} file(s)")
end
end
end
:ok
end
@doc """
Clean artifacts from the output directory.
Returns the number of files removed (or that would be removed in dry-run mode).
"""
@spec clean_artifacts(String.t(), map(), boolean(), boolean()) :: non_neg_integer()
def clean_artifacts(output_dir, types, dry_run \\ false, quiet \\ false) do
unless File.dir?(output_dir) do
unless quiet do
Mix.shell().info(" #{output_dir}/ does not exist โ nothing to clean")
end
0
else
patterns = build_patterns(output_dir, types)
files =
patterns
|> Enum.flat_map(&Path.wildcard/1)
|> Enum.uniq()
|> Enum.sort()
Enum.each(files, fn file ->
unless quiet do
action = if dry_run, do: "Would remove", else: "Removing"
Mix.shell().info(" #{action}: #{Path.relative_to_cwd(file)}")
end
unless dry_run do
File.rm(file)
end
end)
length(files)
end
end
@doc """
Remove the entire output directory.
"""
@spec clean_entire_directory(String.t(), boolean(), boolean()) :: :ok
def clean_entire_directory(output_dir, dry_run \\ false, quiet \\ false) do
if File.dir?(output_dir) do
unless quiet do
action = if dry_run, do: "Would remove", else: "Removing"
Mix.shell().info(" #{action} entire directory: #{output_dir}/")
end
unless dry_run do
File.rm_rf!(output_dir)
end
# Also clean compiler manifests
clean_compiler_manifests(dry_run, quiet)
else
unless quiet do
Mix.shell().info(" #{output_dir}/ does not exist โ nothing to clean")
end
end
:ok
end
@doc """
Clean Mix compiler manifests related to Firebird WASM compilation.
"""
@spec clean_compiler_manifests(boolean(), boolean()) :: :ok
def clean_compiler_manifests(dry_run \\ false, quiet \\ false) do
manifest_files = [
manifest_path("firebird_wasm.manifest"),
manifest_path("firebird_target.manifest"),
manifest_path("firebird_content_hashes.manifest")
]
Enum.each(manifest_files, fn path ->
if path && File.exists?(path) do
unless quiet do
action = if dry_run, do: "Would remove", else: "Removing"
Mix.shell().info(" #{action}: #{Path.relative_to_cwd(path)}")
end
unless dry_run do
File.rm(path)
end
end
end)
:ok
end
# Private
defp build_patterns(output_dir, types) do
patterns = []
patterns =
if types.wat do
patterns ++ [Path.join(output_dir, "*.wat")]
else
patterns
end
patterns =
if types.wasm do
patterns ++ [Path.join(output_dir, "*.wasm")]
else
patterns
end
patterns =
if types.manifests do
patterns ++
[
Path.join(output_dir, "firebird_manifest.json"),
Path.join(output_dir, "*.source_map.json")
]
else
patterns
end
patterns
end
defp default_output_dir do
config = Firebird.Target.Config.from_mix_project()
config.output_dir
rescue
_ -> "_build/wasm"
end
defp manifest_path(filename) do
Path.join(Mix.Project.manifest_path(), filename)
rescue
_ -> nil
end
end