diff --git a/CHANGELOG.md b/CHANGELOG.md index de8988d..78fb189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v1.0.4 + + * Update docs. + ## v1.0.3 * Correct License notice in README.md. diff --git a/README.md b/README.md index 35851c8..2a7d458 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,7 @@ During development, you can also depend on this repository directly: ```elixir def deps do [ - {:docker_availability, - github: "zacky1972/docker_availability", - branch: "main"} + {:docker_availability, github: "zacky1972/docker_availability", branch: "main"} ] end ``` @@ -34,6 +32,20 @@ Then fetch dependencies: mix deps.get ``` +## Which function should I use? + +| Need | Use | Result | +| --- | --- | --- | +| A simple yes/no answer | `DockerAvailability.available?/0` | `true` or `false` | +| The resolved Docker CLI path | `DockerAvailability.executable/0` | `{:ok, path}` or `{:error, :docker_not_found}` | +| Diagnostics, version information, or structured error handling | `DockerAvailability.check/0` | `{:ok, info}` or `{:error, reason}` | + +Use `available?/0` when a boolean is enough, for example when deciding whether to skip Docker-dependent work. + +Use `executable/0` when you only need to know whether the Docker CLI is installed and where it is located. This function does not check whether the Docker daemon is running or reachable. + +Use `check/0` when the caller needs diagnostic details, Docker client and server version information, or structured error handling. + ## Usage Use `available?/0` when you only need a boolean answer: @@ -46,6 +58,16 @@ else end ``` +Use `executable/0` when you only need to know whether the `docker` executable exists in `PATH`: + +```elixir +DockerAvailability.executable() +#=> {:ok, "/usr/bin/docker"} + +DockerAvailability.executable() +#=> {:error, :docker_not_found} +``` + Use `check/0` when you need diagnostic details: ```elixir @@ -68,16 +90,6 @@ case DockerAvailability.check() do end ``` -Use `executable/0` when you only need to know whether the `docker` executable exists in `PATH`: - -```elixir -DockerAvailability.executable() -#=> {:ok, "/usr/bin/docker"} - -DockerAvailability.executable() -#=> {:error, :docker_not_found} -``` - ## API ### `DockerAvailability.executable/0` @@ -86,40 +98,76 @@ Returns the path to the `docker` executable. It only checks the current process `PATH` by using `System.find_executable/1`. It does not check whether the Docker daemon is running. -Returns: +Return values: + +```elixir +{:ok, "/usr/bin/docker"} +{:error, :docker_not_found} +``` + +`{:ok, path}` means the executable was found. `path` is the resolved path returned by the current process environment. -- `{:ok, path}` when the executable is found -- `{:error, :docker_not_found}` when the executable is not available in `PATH` +`{:error, :docker_not_found}` means no `docker` executable was available in `PATH`. ### `DockerAvailability.available?/0` -Returns `true` when Docker is installed and usable by the current process. +Returns `true` when Docker is installed and usable by the current process. This is a convenience wrapper around `check/0`. -This is a convenience wrapper around `check/0`. It returns `false` for all error cases, including a missing executable, a failed Docker client command, or an unreachable Docker daemon. +Return values: -### `DockerAvailability.check/0` +```elixir +true +false +``` -Performs the full availability check. +It returns `false` for all error cases, including a missing executable, a failed Docker client command, or an unreachable Docker daemon. + +Use `check/0` instead when the caller needs to know why Docker is not available. + +### `DockerAvailability.check/0` -It verifies that: +Performs the full availability check. It verifies that: 1. the `docker` executable exists in `PATH` 2. the Docker client version can be queried 3. the Docker server version can be queried -Returns `{:ok, info}` when Docker is usable. The `info` map contains: +Returns `{:ok, info}` when Docker is usable: -- `:executable` - the resolved path to the Docker executable -- `:client_version` - the Docker client version reported by the executable -- `:server_version` - the Docker server version reported by the daemon +```elixir +{:ok, + %{ + executable: "/usr/bin/docker", + client_version: "24.0.0", + server_version: "24.0.0" + }} +``` + +The `info` map contains: + +| Field | Meaning | +| --- | --- | +| `:executable` | The resolved path to the Docker executable. | +| `:client_version` | The Docker client version reported by the executable. | +| `:server_version` | The Docker server version reported by the daemon. | + +The version fields are intended to be strings returned by Docker version commands. Returns one of the following errors: -- `{:error, :docker_not_found}` when `docker` is not found in `PATH` -- `{:error, {:docker_command_failed, status, output}}` when a Docker client command fails before daemon availability is established -- `{:error, {:docker_unavailable, status, output}}` when the Docker server version cannot be queried +```elixir +{:error, :docker_not_found} +{:error, {:docker_command_failed, status, output}} +{:error, {:docker_unavailable, status, output}} +``` + +| Error | Meaning | +| --- | --- | +| `:docker_not_found` | No `docker` executable could be found in `PATH`. | +| `{:docker_command_failed, status, output}` | The Docker executable was found, but a Docker command failed while retrieving client information. | +| `{:docker_unavailable, status, output}` | The Docker client exists, but the Docker server or daemon is stopped, unreachable, or inaccessible to the current user. | -`status` is the command exit status. `output` is the trimmed combined standard output and standard error from the Docker command. +`status` is the Docker command exit status. `output` is the trimmed combined standard output and standard error from the Docker command. ## What this library does not do @@ -187,12 +235,16 @@ Run the project checks: mix check ``` -Run the maintainer pre-commit checks: +`mix check` validates the project from a contributor-facing perspective. It runs dependency auditing, compilation with warnings treated as errors, formatting checks, static analysis, dependency-lock validation, spelling checks, and Dialyzer. + +Run the maintainer pre-commit checks before opening a pull request: ```sh mix precommit ``` +`mix precommit` runs the maintainer workflow, including formatting, static checks, and tests. Contributors should run this command before submitting changes when the full toolchain is available locally. + ## Documentation Generate documentation locally with: @@ -201,6 +253,8 @@ Generate documentation locally with: mix docs ``` +The README is the primary user-facing guide and is included in the generated documentation. Keep the README and module documentation in sync when changing public API behavior, examples, or error descriptions. + After the package is published, documentation should be available on HexDocs. ## Requirements @@ -212,6 +266,8 @@ After the package is published, documentation should be available on HexDocs. Copyright (c) 2026 University of Kitakyushu -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at . -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and limitations under the License. diff --git a/lib/docker_availability.ex b/lib/docker_availability.ex index 0089f1d..e8991bc 100644 --- a/lib/docker_availability.ex +++ b/lib/docker_availability.ex @@ -7,15 +7,64 @@ defmodule DockerAvailability do the `docker` command installed while the daemon is stopped, unreachable, or inaccessible to the current user. - `executable/0` only checks whether the `docker` executable can be found in - `PATH`. `check/0` performs the full availability check by running Docker - version commands and collecting the client and server versions. `available?/0` - is a boolean convenience wrapper around `check/0`. + ## Which function should I use? + + * Use `available?/0` when the caller only needs a boolean yes/no answer. + * Use `executable/0` when the caller needs to know whether the Docker CLI + is installed and where it is located. + * Use `check/0` when the caller needs diagnostics, version information, or + structured error handling. + + ## Return shapes + + `executable/0` returns either: + + {:ok, "/usr/bin/docker"} + {:error, :docker_not_found} + + `available?/0` returns either: + + true + false + + `check/0` returns either: + + {:ok, + %{ + executable: "/usr/bin/docker", + client_version: "24.0.0", + server_version: "24.0.0" + }} + + or one of these error tuples: + + {:error, :docker_not_found} + {:error, {:docker_command_failed, status, output}} + {:error, {:docker_unavailable, status, output}} + + ## Error reasons + + * `:docker_not_found` means no `docker` executable could be found in `PATH`. + * `{:docker_command_failed, status, output}` means the Docker executable was + found, but a Docker command failed while retrieving client information. + * `{:docker_unavailable, status, output}` means the Docker client exists, + but the Docker server or daemon is stopped, unreachable, or inaccessible + to the current user. + + `status` is the Docker command exit status. `output` is the trimmed combined + standard output and standard error from the Docker command. The functions in this module do not install Docker, start the Docker daemon, or modify Docker state. """ + @typedoc """ + Result returned by `check/0`. + + Successful results contain the resolved Docker executable path and the client + and server version values reported by Docker. Error results contain one of the + documented Docker availability reasons. + """ @type check_result :: {:ok, %{ @@ -25,6 +74,15 @@ defmodule DockerAvailability do }} | {:error, reason()} + @typedoc """ + Error reason returned by `check/0`. + + * `:docker_not_found` means no `docker` executable could be found in `PATH`. + * `{:docker_command_failed, status, output}` means a Docker command failed + while retrieving client information. + * `{:docker_unavailable, status, output}` means the Docker server or daemon + was not available to the current process. + """ @type reason :: :docker_not_found | {:docker_command_failed, non_neg_integer(), String.t()} @@ -36,9 +94,15 @@ defmodule DockerAvailability do This function searches for `docker` in the current process `PATH` by using `System.find_executable/1`. - Returns `{:ok, path}` when the executable is found. + Return values: + + {:ok, "/usr/bin/docker"} + {:error, :docker_not_found} + + `{:ok, path}` means the executable was found. `path` is the resolved path + returned by the current process environment. - Returns `{:error, :docker_not_found}` when the executable is not available in + `{:error, :docker_not_found}` means no `docker` executable was available in `PATH`. This function does not check whether the Docker daemon is running. Use @@ -57,6 +121,11 @@ defmodule DockerAvailability do This is a boolean convenience wrapper around `check/0`. + Return values: + + true + false + Returns `true` only when all of the following conditions are satisfied: * the `docker` executable is found in `PATH` @@ -81,23 +150,40 @@ defmodule DockerAvailability do executable with `executable/0`, then runs Docker version commands to obtain both the client and server versions. - Returns `{:ok, info}` when Docker is usable. The returned map contains: + Returns `{:ok, info}` when Docker is usable: + + {:ok, + %{ + executable: "/usr/bin/docker", + client_version: "24.0.0", + server_version: "24.0.0" + }} + + The returned map contains: * `:executable` - the resolved path to the Docker executable * `:client_version` - the Docker client version reported by the executable * `:server_version` - the Docker server version reported by the daemon + The version fields are intended to be strings returned by Docker version + commands. + Returns one of the following error tuples: - * `{:error, :docker_not_found}` when the `docker` executable cannot be found - in `PATH` - * `{:error, {:docker_command_failed, status, output}}` when a Docker client - command fails before daemon availability is established - * `{:error, {:docker_unavailable, status, output}}` when the Docker server - version cannot be queried, typically because the Docker daemon is stopped, - unreachable, or inaccessible to the current user + {:error, :docker_not_found} + {:error, {:docker_command_failed, status, output}} + {:error, {:docker_unavailable, status, output}} + + Error reasons: - `status` is the command exit status and `output` is the trimmed combined + * `:docker_not_found` means no `docker` executable could be found in `PATH`. + * `{:docker_command_failed, status, output}` means the Docker executable was + found, but a Docker command failed while retrieving client information. + * `{:docker_unavailable, status, output}` means the Docker client exists, + but the Docker server or daemon is stopped, unreachable, or inaccessible + to the current user. + + `status` is the Docker command exit status. `output` is the trimmed combined standard output and standard error from the Docker command. """ @spec check() :: check_result() @@ -105,12 +191,7 @@ defmodule DockerAvailability do with {:ok, docker} <- executable(), {:ok, client_version} <- docker_version(docker, "Client.Version"), {:ok, server_version} <- docker_version(docker, "Server.Version") do - {:ok, - %{ - executable: docker, - client_version: client_version, - server_version: server_version - }} + {:ok, %{executable: docker, client_version: client_version, server_version: server_version}} end end @@ -128,7 +209,6 @@ defmodule DockerAvailability do {:error, {:docker_command_failed, status, String.trim(output)}} end rescue - e in ErlangError -> - {:error, {:docker_command_failed, 127, Exception.message(e)}} + e in ErlangError -> {:error, {:docker_command_failed, 127, Exception.message(e)}} end end diff --git a/mix.exs b/mix.exs index 62f69b5..258a1b4 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule DockerAvailability.MixProject do use Mix.Project - @version "1.0.3" + @version "1.0.4" @source_url "https://github.com/zacky1972/docker_availability" def project do