Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/lib/internals/documenter.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ Documenter.user_host_upstream
Documenter.find_object
Documenter.xrefname
Documenter.crossref
Documenter.DocumenterBuildException
```
1 change: 1 addition & 0 deletions docs/src/lib/public.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ doctest
DocMeta
DocMeta.getdocmeta
DocMeta.setdocmeta!
Documenter.DocumenterError
```

## DocumenterTools
Expand Down
8 changes: 8 additions & 0 deletions src/Documenter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ abstract type Plugin end

abstract type Writer end

"""
abstract type DocumenterBuildException <: Exception

Internal abstract supertype for all the exceptions that get propagated to the user as
[`DocumenterError`](@ref)s.
"""
abstract type DocumenterBuildException <: Exception end

include("utilities/DOM.jl")
include("utilities/JSDependencies.jl")
include("utilities/MDFlatten.jl")
Expand Down
16 changes: 13 additions & 3 deletions src/builder_pipeline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,25 @@ function Selectors.runner(::Type{Builder.RenderDocument}, doc::Documenter.Docume
fatal_errors = filter(is_strict(doc), doc.internal.errors)
c = length(fatal_errors)
if c > 0
error("`makedocs` encountered $(c > 1 ? "errors" : "an error") ["
* join(Ref(":") .* string.(fatal_errors), ", ")
* "] -- terminating build before rendering.")
msg = string(
"`makedocs` encountered $(c > 1 ? "errors" : "an error") [",
join(Ref(":") .* string.(fatal_errors), ", "),
"] -- terminating build before rendering."
)
throw(DocCheckError(msg))
else
@info "RenderDocument: rendering document."
Documenter.render(doc)
end
end

struct DocCheckError <: DocumenterBuildException
msg::String
end
function Base.showerror(io::IO, e::DocCheckError)
println(io, "DocCheckError: $(e.msg)")
end

Selectors.runner(::Type{Builder.DocumentPipeline}, doc::Documenter.Document) = nothing

function is_doctest_only(doc, stepname)
Expand Down
66 changes: 57 additions & 9 deletions src/makedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,69 @@ Other formats can be enabled by using other addon-packages. For example, the
the original Markdown -> Markdown output. See the [Other Output Formats](@ref) for more
information.

# Errors

`makedocs` will throw a [`DocumenterError`](@ref) if it has a "controlled failure", e.g. due
document checks failing, or some other issue that is likely due to user configuration problems.
`makedocs` throwing something other than [`DocumenterError`](@ref) should, generally be considered
an error.

# See Also

A guide detailing how to document a package using Documenter's [`makedocs`](@ref) is provided
in the [setup guide in the manual](@ref Package-Guide).
"""
function makedocs(; debug = false, format = HTML(), kwargs...)
document = Documenter.Document(; format=format, kwargs...)
# Before starting the build pipeline, we empty out the subtype cache used by
# Selectors.dispatch. This is to make sure that we pick up any new selector stages that
# may have been added to the selector pipelines between makedocs calls.
empty!(Selectors.selector_subtypes)
cd(document.user.root) do; withenv(NO_KEY_ENV...) do
Selectors.dispatch(Builder.DocumentPipeline, document)
end end
debug ? document : nothing
exception = nothing
try
document = Documenter.Document(; format=format, kwargs...)
# Before starting the build pipeline, we empty out the subtype cache used by
# Selectors.dispatch. This is to make sure that we pick up any new selector stages that
# may have been added to the selector pipelines between makedocs calls.
empty!(Selectors.selector_subtypes)
cd(document.user.root) do
withenv(NO_KEY_ENV...) do
Selectors.dispatch(Builder.DocumentPipeline, document)
end
end
return debug ? document : nothing
catch e
if isa(e, DocumenterBuildException)
exc_error_log = IOBuffer()
showerror(exc_error_log, e, catch_backtrace())
@debug String(take!(exc_error_log))
exception = DocumenterError(:makedocs, (e, catch_backtrace()))
else
rethrow(e)
end
end
isnothing(exception) || throw(exception)
end

"""
struct DocumenterError <: Exception

Documenter throws this error when it fails in a "controlled" way (e.g. when docchecks or
doctests have failed).

!!! note

Documenter is not fully consistent about using this exception yet. So while Documenter
throwing a different error object should be considered a bug, it may still be indicating
a user error (rather than Documenter itself breaking in some way).
"""
struct DocumenterError <: Exception
fn::Symbol
exception::Union{Tuple{Any,Any},Nothing}
end

function Base.showerror(io::IO, e::DocumenterError)
println(io, "DocumenterError ($(e.fn)): Documenter build failed to complete.")
if !isnothing(e.exception)
println("Underlying exception:")
showerror(io, e.exception[1])
end
print(io, "Please check the error logs above as well.")
end

"""
Expand Down