Forecastle.Appup.Source (forecastle v1.0.0)

Copy Markdown View Source

Reads and rewrites the appup source named by the :appup project key.

Appup source is arbitrary Elixir evaluated for its value. This module rewrites only a pure literal whose value is determined by its AST. Computed source, structs, and bitstrings that require runtime truncation are refused. Literal aliases, lists, maps, tuples, binaries and uninterpolated ~c/~C sigils are accepted.

New entries are inserted as text so comments, formatting and existing entries remain unchanged. The result is parsed again and must equal the intended merged term before it can be written.

Summary

Types

The kind of appup source being written, which selects its header.

The result of reading a source file.

t()

A pure-literal source file and what is needed to rewrite it.

Functions

Creates an appup source exclusively.

Returns a compact line diff suitable for terminal output.

Renders one from-version entry with its generated comments.

Inserts entries into the upgrade and downgrade lists of a literal source.

Reads an appup source file.

Renders a complete appup source for an application with no source file.

Atomically replaces a literal source with merged text.

Converts a literal AST to its term.

Types

kind()

@type kind() :: :project | {:dependency, atom(), binary()}

The kind of appup source being written, which selects its header.

:project is the file named by the :appup key, compiled by the :appup compiler. {:dependency, app, vsn} is rel/appups/<app>-<from>-<to>.exs, which Forecastle.Appup.Dep places into an assembled release.

read()

@type read() ::
  :absent | {:literal, t()} | {:computed, binary()} | {:malformed, binary()}

The result of reading a source file.

:absent means no file exists and {:literal, t()} can be merged into. The other two are refusals, carrying the reason to report.

t()

@type t() :: %{path: binary(), source: binary(), ast: Macro.t(), term: tuple()}

A pure-literal source file and what is needed to rewrite it.

Functions

create(path, text)

@spec create(binary(), binary()) :: :ok | {:error, binary()}

Creates an appup source exclusively.

Returns an error if the path already exists or cannot be written, preventing a concurrent edit from being replaced.

diff(old, new)

@spec diff(binary(), binary()) :: [binary()]

Returns a compact line diff suitable for terminal output.

Changed lines use + and - prefixes. Unchanged context uses two spaces, with omitted regions marked by ....

entry_text(entry)

@spec entry_text(Forecastle.Appup.Draft.entry()) :: binary()

Renders one from-version entry with its generated comments.

The generator uses the same text for source updates and manual-merge output.

merge(literal, additions)

@spec merge(t(), [{:up | :down, Forecastle.Appup.Draft.entry()}]) ::
  {:ok, binary()} | {:error, binary()}

Inserts entries into the upgrade and downgrade lists of a literal source.

A direction may be omitted when it already has a matching entry. The function preserves all other source text and verifies the merged term.

read(path)

@spec read(binary()) :: read()

Reads an appup source file.

Returns :absent, a literal source that can be merged, or a computed or malformed source with a reason for refusing it.

render(tag, up, dn, kind)

@spec render(
  binary(),
  Forecastle.Appup.Draft.entry(),
  Forecastle.Appup.Draft.entry(),
  kind()
) ::
  {:ok, binary()} | {:error, binary()}

Renders a complete appup source for an application with no source file.

The header says whether the file is for the project or a dependency, and what the draft cannot decide.

replace(literal, text)

@spec replace(t(), binary()) :: :ok | {:error, binary()}

Atomically replaces a literal source with merged text.

The function refuses a file that changed after it was read. It writes a staging file beside the resolved target, preserves the file mode, and renames the completed file into place. Symlink chains are followed to the source file.

to_term(list)

@spec to_term(Macro.t()) :: {:ok, term()} | :error

Converts a literal AST to its term.

Returns :error when evaluating the AST requires computation.