Skip to content

Commit

Permalink
Allow letting the docs build to fail with servedocs() (#176)
Browse files Browse the repository at this point in the history
Previously `servedocs()` would exit whenever the docs failed to build, and it
can be annoying to always restart it on errors. Now when building the docs fails
a special status will be set on the `SimpleWatcher` which will get
`serve_file()` to return a custom error page (which will be reloaded
automatically when the docs build again).
  • Loading branch information
JamesWrigley authored Apr 9, 2024
1 parent 262aa6a commit e6997ed
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 21 deletions.
64 changes: 44 additions & 20 deletions src/server.jl
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,11 @@ function serve_file(
ret_code = 200
fs_path, case = get_fs_path(req.target)

if case == :not_found_without_404
html_404 = pagehtml(title = "404 Not Found") do io
write(io, """
# Fast paths to execute if building documentation isn't currently failing
if fw.status != :documenter_jl_error
if case == :not_found_without_404
html_404 = pagehtml(title = "404 Not Found") do io
write(io, """
<div style="width: 100%; max-width: 500px; margin: auto">
<h1 style="margin-top: 2em">404 Not Found</h1>
<p>
Expand All @@ -366,26 +368,48 @@ function serve_file(
</p>
</div>
"""
)
)
end
return HTTP.Response(404, html_404)
elseif case == :not_found_with_404
ret_code = 404
elseif case == :dir_without_index
index_page = get_dir_list(fs_path)
return HTTP.Response(200, index_page)
end
return HTTP.Response(404, html_404)
elseif case == :not_found_with_404
ret_code = 404
elseif case == :dir_without_index
index_page = get_dir_list(fs_path)
return HTTP.Response(200, index_page)
end

#
# In what follows, fs_path points to a file
# :dir_with_index
# :file
# :not_found_with_404
# --> html-like: try to inject reload-script
# --> other: just get the browser to show it
#
ext = lstrip(last(splitext(fs_path)), '.') |> string
content = read(fs_path, String)
ext = nothing
content = nothing

# If building the documentation is failing we return a special error page,
# otherwise we just read the file from disk.
if fw.status == :documenter_jl_error
ret_code = 500
ext = "html"
content = pagehtml(title = "Documenter.jl error") do io
write(io, """
<div style="width: 100%; max-width: 500px; margin: auto">
<h1 style="margin-top: 2em">Error building docs</h1>
<p>
An error occurred when rebuilding the documentation, please check the <code>servedocs()</code> output.
</p>
</div>
"""
)
end
else
#
# In what follows, fs_path points to a file
# :dir_with_index
# :file
# :not_found_with_404
# --> html-like: try to inject reload-script
# --> other: just get the browser to show it
#
ext = lstrip(last(splitext(fs_path)), '.') |> string
content = read(fs_path, String)
end

# build the response with appropriate mime type (this is inspired from Mux
# https://github.com/JuliaWeb/Mux.jl/blob/master/src/examples/files.jl)
Expand Down
9 changes: 8 additions & 1 deletion src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ function servedocs_callback!(
end

# Run a Documenter pass
Main.include(abspath(path2makejl))
try
Main.include(abspath(path2makejl))
dw.status = :runnable
catch ex
# If there was an error, record it so that an error is displayed to the user
dw.status = :documenter_jl_error
end

file_changed_callback(fp)
return
end
Expand Down
16 changes: 16 additions & 0 deletions test/server.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,22 @@ tasks that you will try to start.
@test !sentinel1.io.io.writable
@test !sentinel2.io.io.writable

# Mimic an error when building documentation with Documenter.jl. When this
# happens servedocs_callback!() will set the watcher status to
# :documenter_jl_error.
fw.status = :documenter_jl_error

# Now any requests should give us the custom error page
response = HTTP.get("http://localhost:$port/"; status_exception=false)
body_str = String(response.body)
@test response.status == 500
@test occursin("error occurred when rebuilding", body_str)
# And they should include the browser reload script so they automatically
# reload when the docs build again.
@test occursin(LS.BROWSER_RELOAD_SCRIPT, body_str)
# Reset the watcher status for the rest of the tests
fw.status = :runnable

# if we remove the files, it shall stop following it
rm("tmp.html")
rm("css", recursive=true)
Expand Down
10 changes: 10 additions & 0 deletions test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@
@test length(dw.watchedfiles) == 2
@test readmake() == 4

# Modify make.jl to force an error
write(makejl, "error()")
LS.servedocs_callback!(dw, joinpath("docs", "src", "index.md"), makejl, def...)
@test dw.status == :documenter_jl_error

# Fixing the error should reset the status
write(makejl, "42")
LS.servedocs_callback!(dw, joinpath("docs", "src", "index.md"), makejl, def...)
@test dw.status == :runnable

cd(bk)
end

Expand Down

0 comments on commit e6997ed

Please sign in to comment.