Runs a tool's availability and version check.
Two things here are deliberate and easy to get wrong:
Exit status is ignored when a version was found. A surprising number of
tools exit non-zero for --version, or print it to stderr. If the output
contains a version, the tool is present and the check succeeds; the exit
status only matters when nothing could be parsed.
Nothing is executed unless the executable exists. System.find_executable/1
is consulted first, so a missing tool costs a PATH scan rather than a
process spawn — which matters when a check sits on a request path behind a
cache that has just expired.
Summary
Functions
A human-readable explanation of a result, including the install hint.
Extracts a version string from command output.
Checks one tool, without consulting or populating any cache.
Types
@type result() :: {:ok, String.t() | :unknown} | {:error, :not_found | {:version_mismatch, String.t(), String.t()} | {:unparseable_version, String.t()} | {:exec_failed, term()}}
The outcome of checking one tool.
{:ok, version}— present, and satisfying the requirement if one was declared{:ok, :unknown}— present, but no version could be parsed and none was required{:error, :not_found}— not onPATH{:error, {:version_mismatch, found, requirement}}— present but too old{:error, {:unparseable_version, output}}— present, a version was required, none found{:error, {:exec_failed, reason}}— the executable exists but could not be run
Functions
@spec explain(CliDeps.Tool.t(), result()) :: String.t()
A human-readable explanation of a result, including the install hint.
Written for whoever has to fix it, which is usually not the person who wrote the declaration.
@spec extract_version(CliDeps.Tool.t(), String.t()) :: String.t() | nil
Extracts a version string from command output.
Returns a value Version.parse/1 accepts, padding a two-part version such
as 7.1 to 7.1.0 — tools print both forms and Version requires three.
@spec run(CliDeps.Tool.t()) :: result()
Checks one tool, without consulting or populating any cache.