Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TimerOutput to analyze doc build times #2521

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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 Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ RegistryInstances = "2792f1a3-b283-48e8-9a74-f99dce5104f3"
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[compat]
Expand Down
3 changes: 3 additions & 0 deletions src/Documenter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ import Unicode
import Pkg
import RegistryInstances
import Git
import TimerOutputs
# Additional imported names
using Test: @testset, @test
using DocStringExtensions: SIGNATURES, EXPORTS
using Base64: base64decode

const TIMER = Ref(TimerOutputs.TimerOutput())
jkrumbiegel marked this conversation as resolved.
Show resolved Hide resolved

# Version number of Documenter itself
const DOCUMENTER_VERSION = let
project = joinpath(dirname(dirname(pathof(Documenter))), "Project.toml")
Expand Down
164 changes: 85 additions & 79 deletions src/builder_pipeline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,85 +72,87 @@
Selectors.strict(::Type{T}) where {T <: Builder.DocumentPipeline} = false

function Selectors.runner(::Type{Builder.SetupBuildDirectory}, doc::Documenter.Document)
@info "SetupBuildDirectory: setting up build directory."

# Frequently used fields.
build = doc.user.build
source = doc.user.source
workdir = doc.user.workdir

# The .user.source directory must exist.
isdir(source) || error("source directory '$(abspath(source))' is missing.")

# We create the .user.build directory.
# If .user.clean is set, we first clean the existing directory.
doc.user.clean && isdir(build) && rm(build; recursive = true)
isdir(build) || mkpath(build)

# We'll walk over all the files in the .user.source directory.
# The directory structure is copied over to .user.build. All files, with
# the exception of markdown files (identified by the extension) are copied
# over as well, since they're assumed to be images, data files etc.
# Markdown files, however, get added to the document and also stored into
# `mdpages`, to be used later.
mdpages = String[]
for (root, dirs, files) in walkdir(source)
for dir in dirs
d = normpath(joinpath(build, relpath(root, source), dir))
isdir(d) || mkdir(d)
end
for file in files
src = normpath(joinpath(root, file))
dst = normpath(joinpath(build, relpath(root, source), file))

if workdir == :build
# set working directory to be the same as `build`
wd = normpath(joinpath(build, relpath(root, source)))
elseif workdir isa Symbol
# Maybe allow `:src` and `:root` as well?
throw(ArgumentError("Unrecognized working directory option '$workdir'"))
else
wd = normpath(joinpath(doc.user.root, workdir))
TimerOutputs.@timeit Documenter.TIMER[] "SetupBuildDirectory" begin
@info "SetupBuildDirectory: setting up build directory."

# Frequently used fields.
build = doc.user.build
source = doc.user.source
workdir = doc.user.workdir

# The .user.source directory must exist.
isdir(source) || error("source directory '$(abspath(source))' is missing.")

# We create the .user.build directory.
# If .user.clean is set, we first clean the existing directory.
doc.user.clean && isdir(build) && rm(build; recursive = true)
isdir(build) || mkpath(build)

# We'll walk over all the files in the .user.source directory.
# The directory structure is copied over to .user.build. All files, with
# the exception of markdown files (identified by the extension) are copied
# over as well, since they're assumed to be images, data files etc.
# Markdown files, however, get added to the document and also stored into
# `mdpages`, to be used later.
mdpages = String[]
for (root, dirs, files) in walkdir(source)
for dir in dirs
d = normpath(joinpath(build, relpath(root, source), dir))
isdir(d) || mkdir(d)
end

if endswith(file, ".md")
push!(mdpages, Documenter.srcpath(source, root, file))
Documenter.addpage!(doc, src, dst, wd)
else
cp(src, dst; force = true)
for file in files
src = normpath(joinpath(root, file))
dst = normpath(joinpath(build, relpath(root, source), file))

if workdir == :build
# set working directory to be the same as `build`
wd = normpath(joinpath(build, relpath(root, source)))
elseif workdir isa Symbol

Check warning on line 110 in src/builder_pipeline.jl

View check run for this annotation

Codecov / codecov/patch

src/builder_pipeline.jl#L110

Added line #L110 was not covered by tests
# Maybe allow `:src` and `:root` as well?
throw(ArgumentError("Unrecognized working directory option '$workdir'"))

Check warning on line 112 in src/builder_pipeline.jl

View check run for this annotation

Codecov / codecov/patch

src/builder_pipeline.jl#L112

Added line #L112 was not covered by tests
else
wd = normpath(joinpath(doc.user.root, workdir))

Check warning on line 114 in src/builder_pipeline.jl

View check run for this annotation

Codecov / codecov/patch

src/builder_pipeline.jl#L114

Added line #L114 was not covered by tests
end

if endswith(file, ".md")
push!(mdpages, Documenter.srcpath(source, root, file))
Documenter.addpage!(doc, src, dst, wd)
else
cp(src, dst; force = true)
end
end
end
end

# If the user hasn't specified the page list, then we'll just default to a
# flat list of all the markdown files we found, sorted by the filesystem
# path (it will group them by subdirectory, among others).
userpages = isempty(doc.user.pages) ? sort(mdpages, lt=lt_page) : doc.user.pages
# If the user hasn't specified the page list, then we'll just default to a
# flat list of all the markdown files we found, sorted by the filesystem
# path (it will group them by subdirectory, among others).
userpages = isempty(doc.user.pages) ? sort(mdpages, lt=lt_page) : doc.user.pages

# Populating the .navtree and .navlist.
# We need the for loop because we can't assign to the fields of the immutable
# doc.internal.
for navnode in walk_navpages(userpages, nothing, doc)
push!(doc.internal.navtree, navnode)
end
# Populating the .navtree and .navlist.
# We need the for loop because we can't assign to the fields of the immutable
# doc.internal.
for navnode in walk_navpages(userpages, nothing, doc)
push!(doc.internal.navtree, navnode)
end

# Finally we populate the .next and .prev fields of the navnodes that point
# to actual pages.
local prev::Union{Documenter.NavNode, Nothing} = nothing
for navnode in doc.internal.navlist
navnode.prev = prev
if prev !== nothing
prev.next = navnode
# Finally we populate the .next and .prev fields of the navnodes that point
# to actual pages.
local prev::Union{Documenter.NavNode, Nothing} = nothing

Check warning on line 140 in src/builder_pipeline.jl

View check run for this annotation

Codecov / codecov/patch

src/builder_pipeline.jl#L140

Added line #L140 was not covered by tests
for navnode in doc.internal.navlist
navnode.prev = prev
if prev !== nothing
prev.next = navnode
end
prev = navnode

Check warning on line 146 in src/builder_pipeline.jl

View check run for this annotation

Codecov / codecov/patch

src/builder_pipeline.jl#L146

Added line #L146 was not covered by tests
end
prev = navnode
end

# If the user specified pagesonly, we will remove all the pages not in the navigation
# menu (.pages).
if doc.user.pagesonly
navlist_pages = getfield.(doc.internal.navlist, :page)
for page in keys(doc.blueprint.pages)
page ∈ navlist_pages || delete!(doc.blueprint.pages, page)
# If the user specified pagesonly, we will remove all the pages not in the navigation
# menu (.pages).
if doc.user.pagesonly
navlist_pages = getfield.(doc.internal.navlist, :page)
for page in keys(doc.blueprint.pages)
page ∈ navlist_pages || delete!(doc.blueprint.pages, page)
end

Check warning on line 155 in src/builder_pipeline.jl

View check run for this annotation

Codecov / codecov/patch

src/builder_pipeline.jl#L152-L155

Added lines #L152 - L155 were not covered by tests
end
end
end
Expand Down Expand Up @@ -206,7 +208,9 @@
function Selectors.runner(::Type{Builder.Doctest}, doc::Documenter.Document)
if doc.user.doctest in [:fix, :only, true]
@info "Doctest: running doctests."
_doctest(doc.blueprint, doc)
TimerOutputs.@timeit Documenter.TIMER[] "Doctest: running doctests." begin
_doctest(doc.blueprint, doc)
end
num_errors = length(doc.internal.errors)
if (doc.user.doctest === :only || is_strict(doc, :doctest)) && num_errors > 0
error("`makedocs` encountered $(num_errors > 1 ? "$(num_errors) doctest errors" : "a doctest error"). Terminating build")
Expand All @@ -219,22 +223,24 @@
function Selectors.runner(::Type{Builder.ExpandTemplates}, doc::Documenter.Document)
is_doctest_only(doc, "ExpandTemplates") && return
@info "ExpandTemplates: expanding markdown templates."
expand(doc)
TimerOutputs.@timeit Documenter.TIMER[] "ExpandTemplates: expanding markdown templates." expand(doc)
end

function Selectors.runner(::Type{Builder.CrossReferences}, doc::Documenter.Document)
is_doctest_only(doc, "CrossReferences") && return
@info "CrossReferences: building cross-references."
crossref(doc)
TimerOutputs.@timeit Documenter.TIMER[] "CrossReferences: building cross-references." crossref(doc)
end

function Selectors.runner(::Type{Builder.CheckDocument}, doc::Documenter.Document)
is_doctest_only(doc, "CheckDocument") && return
@info "CheckDocument: running document checks."
missingdocs(doc)
footnotes(doc)
linkcheck(doc)
githubcheck(doc)
TimerOutputs.@timeit Documenter.TIMER[] "CheckDocument: running document checks." begin
missingdocs(doc)
footnotes(doc)
linkcheck(doc)
githubcheck(doc)
end
end

function Selectors.runner(::Type{Builder.Populate}, doc::Documenter.Document)
Expand All @@ -255,7 +261,7 @@
* "] -- terminating build before rendering.")
else
@info "RenderDocument: rendering document."
Documenter.render(doc)
TimerOutputs.@timeit Documenter.TIMER[] "RenderDocument: rendering document." Documenter.render(doc)
end
end

Expand Down
Loading
Loading