Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
509 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
""" | ||
Defines functions and constants managing the Kroki service the rest of the | ||
package uses to render diagrams. These services can be either local or remote. | ||
This module also enables management of a local service instance, provided | ||
[Docker](https://docker.com) and [Docker | ||
Compose](https://docs.docker.com/compose/) are available on the system. | ||
""" | ||
module Service | ||
|
||
using ..Documentation | ||
@setupDocstringMarkup() | ||
|
||
""" | ||
The default [`ENDPOINT`](@ref) to use, i.e. the [publicly hosted | ||
version](https://kroki.io). | ||
""" | ||
const DEFAULT_ENDPOINT = "https://kroki.io" | ||
|
||
""" | ||
A specialized `Exception` to include reporting instructions for specific types | ||
of errors that may occur while trying to execute `docker-compose`. | ||
""" | ||
struct DockerComposeExecutionError <: Exception | ||
message::String | ||
end | ||
Base.showerror(io::IO, error::DockerComposeExecutionError) = print( | ||
io, | ||
""" | ||
An error occurred while executing `docker-compose`. | ||
This may be caused by a change in its interface. If you believe this error to | ||
be caused by Kroki.jl itself instead of a configuration error on the system, | ||
please file an issue through https://github.com/bauglir/Kroki.jl/issues/new | ||
including the error message below and a description of when the error occurred. | ||
The reported error was: | ||
$(error.message) | ||
""", | ||
) | ||
|
||
"The currently active Kroki service endpoint being used." | ||
const ENDPOINT = Ref{String}("https://kroki.io") | ||
|
||
"Path to the Docker Compose definitions for running a local Kroki service." | ||
const SERVICE_DEFINITION_FILE = realpath("$(@__DIR__)/../../support/docker-services.yml") | ||
|
||
""" | ||
Helper function for executing Docker Compose commands. | ||
Returns captured stdout. | ||
Throws an `ErrorException` if Docker and/or Docker Compose aren't available. | ||
Throws a `DockerComposeExecutionError` if any other exception occurs during | ||
execution. | ||
""" | ||
function executeDockerCompose(cmd::Vector{String}) | ||
captured_stderr = IOBuffer() | ||
captured_stdout = IOBuffer() | ||
|
||
try | ||
run(pipeline( | ||
`docker-compose --file $(SERVICE_DEFINITION_FILE) --project-name krokijl $cmd`; | ||
stderr = captured_stderr, | ||
stdout = captured_stdout, | ||
)) | ||
catch exception | ||
exception isa Base.IOError && | ||
throw(ErrorException("Missing dependencies! Docker and/or Docker Compose do not appear to be available")) | ||
|
||
throw(DockerComposeExecutionError(String(take!(captured_stderr)))) | ||
end | ||
|
||
String(take!(captured_stdout)) | ||
end | ||
executeDockerCompose(cmd::String) = executeDockerCompose([cmd]) | ||
# The function should be called through indirection in cases where it needs to | ||
# be mocked out in tests | ||
const EXECUTE_DOCKER_COMPOSE = Ref{Any}(executeDockerCompose) | ||
|
||
""" | ||
Sets the [`ENDPOINT`](@ref) using a fallback mechanism if no `endpoint` is | ||
provided. | ||
The fallback mechanism checks for a `KROKI_ENDPOINT` environment variable | ||
specifying an endpoint (e.g. to be used across Julia instances). If this | ||
environment variable is also not present the [`DEFAULT_ENDPOINT`](@ref) is | ||
used. | ||
This can, for instance, be used in cases where a [privately hosted | ||
instance](https://docs.kroki.io/kroki/setup/install/) is available or when a | ||
local service has been [`start!`](@ref)ed. | ||
Returns the value that [`ENDPOINT`](@ref) got set to. | ||
# Examples | ||
- `setEndpoint!()` | ||
- `setEndpoint!("http://localhost:8000")` | ||
""" | ||
function setEndpoint!( | ||
endpoint::AbstractString = get(ENV, "KROKI_ENDPOINT", DEFAULT_ENDPOINT), | ||
) | ||
ENDPOINT[] != endpoint && @info "Setting Kroki service endpoint to $(endpoint)." | ||
ENDPOINT[] = String(endpoint) | ||
end | ||
|
||
""" | ||
Starts the Kroki service components on the local system, optionally, ensuring | ||
[`ENDPOINT`](@ref) points to them. | ||
Pass `false` to the function to prevent the [`ENDPOINT`](@ref) from being | ||
updated. The default behavior is to update. | ||
""" | ||
function start!(update_endpoint::Bool = true) | ||
@info "Starting Kroki service components." | ||
EXECUTE_DOCKER_COMPOSE[](["up", "--detach"]) | ||
update_endpoint && setEndpoint!("http://localhost:8000") | ||
return | ||
end | ||
|
||
""" | ||
Returns a `NamedTuple` where the keys are the names of the service components | ||
and the values their corresponding 'running' state. | ||
# Examples | ||
``` | ||
julia> status() | ||
(core = true, mermaid = false) | ||
``` | ||
""" | ||
function status() | ||
states_to_bool = Pair{String, Bool}["running" => true, "stopped" => false] | ||
|
||
services_by_state = map(states_to_bool) do (state, running)::Pair{String, Bool} | ||
services_with_state = | ||
EXECUTE_DOCKER_COMPOSE[](["ps", "--filter", "status=$state", "--services"]) | ||
|
||
service_symbols = Symbol.(split(services_with_state, '\n'; keepempty = false)) | ||
|
||
(; zip(service_symbols, Iterators.repeated(running))...) | ||
end | ||
|
||
merge(services_by_state...) | ||
end | ||
|
||
""" | ||
Stops any running Kroki service components ensuring [`ENDPOINT`](@ref) no | ||
longer points to the stopped service. | ||
Cleans up left-over containers by default. This behavior can be turned off by | ||
passing `false` to the function. | ||
""" | ||
function stop!(perform_cleanup::Bool = true) | ||
@info "Stopping Kroki service components." | ||
EXECUTE_DOCKER_COMPOSE[]("stop") | ||
perform_cleanup && EXECUTE_DOCKER_COMPOSE[](["rm", "--force"]) | ||
setEndpoint!() | ||
return | ||
end | ||
|
||
"Updates the Docker images for the individual Kroki service components." | ||
function update!() | ||
EXECUTE_DOCKER_COMPOSE[](["pull", "--quiet"]) | ||
return | ||
end | ||
|
||
# Ensure `ENDPOINT` has a valid value | ||
__init__() = setEndpoint!() | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
version: "3" | ||
services: | ||
core: | ||
image: yuzutech/kroki | ||
environment: | ||
- KROKI_BPMN_HOST=bpmn | ||
- KROKI_BLOCKDIAG_HOST=blockdiag | ||
- KROKI_MERMAID_HOST=mermaid | ||
# Enable inclusion of external PlantUML descriptions and Vega datasets | ||
- KROKI_SAFE_MODE=unsafe | ||
ports: | ||
- 8000:8000 | ||
blockdiag: | ||
image: yuzutech/kroki-blockdiag | ||
bpmn: | ||
image: yuzutech/kroki-bpmn | ||
mermaid: | ||
image: yuzutech/kroki-mermaid |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
[deps] | ||
SimpleMock = "a896ed2c-15a5-4479-b61d-a0e88e2a1d25" | ||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" |
Oops, something went wrong.