Skip to content

Commit

Permalink
Add selector argument to makedocs. The selector argument decide
Browse files Browse the repository at this point in the history
the content, and order, of the version selector. The argument is
a vector, defaulting to ["stable", "v#.#", devurl] where the entries
expand according to:
 - "stable" will point to the latest release
 - "v#.#" expands to one doc per minor release
 - devurl maps to the development docs.
The following arguments are also valid to selector:
 - "v#" expands to one doc per major release
 - "v#.#.#" expands one doc per patch release
 - A string which directly maps to a folder
 - A pair, which will put p.first in the selector, and map it to p.second.
  • Loading branch information
fredrikekre committed Aug 20, 2018
1 parent 924d99b commit 5f04725
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 42 deletions.
45 changes: 32 additions & 13 deletions src/Documenter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ hide(root::AbstractString, children) = (true, nothing, root, map(hide, children)
make = <Function>,
devbranch = "master",
devurl = "dev",
selector = ["stable", "v#.#", devurl]
)
Converts markdown files generated by [`makedocs`](@ref) to HTML and pushes them to `repo`.
Expand Down Expand Up @@ -316,6 +317,16 @@ documentation. By default this value is set to `"master"`.
**`devurl`** the folder that in-development version of the docs will be deployed.
Defaults to `"dev"`.
**`selector`** determines content and order of the resulting version selector in
the generated html. The following entries are valied in the `selector` vector:
- `"stable"`: points to the latest released documentation.
- `"v#"`: expands to the latest documentation for each major release (i.e. `v1.1`, `v2.0`).
- `"v#.#"`: expands to the latest documentation for each minor release (i.e. `v1.0`, `v1.1`, `v2.0`).
- `"v#.#.#"`: expands to all released versions.
- A string which maps directly to an existing folder.
- A pair, e.g. `"first" => "second"`, which will put `"first"` in the selector, and point it
to the folder called `"second"`.
# See Also
The [Hosting Documentation](@ref) section of the manual provides a step-by-step guide to
Expand All @@ -339,6 +350,7 @@ function deploydocs(;

devbranch = "master",
devurl = "dev",
selector = ["stable", "v#.#", devurl]
)
# deprecation of latest kwarg (renamed to devbranch)
if latest !== nothing
Expand Down Expand Up @@ -443,7 +455,7 @@ function deploydocs(;
root, temp, repo;
branch=branch, dirname=dirname, target=target,
tag=travis_tag, key=documenter_key, sha=sha,
devurl = devurl,
devurl = devurl, selector = selector,
)
end
end
Expand All @@ -467,14 +479,11 @@ and also to the `stable` directory.
"""
function git_push(
root, temp, repo;
branch="gh-pages", dirname="", target="site", tag="", key="", sha="", devurl="dev"
branch="gh-pages", dirname="", target="site", tag="", key="", sha="", devurl="dev",
selector
)
dirname = isempty(dirname) ? temp : joinpath(temp, dirname)
isdir(dirname) || mkpath(dirname)
# Versioned docs directories.
devurl_dir = joinpath(dirname, devurl)
stable_dir = joinpath(dirname, "stable")
tagged_dir = joinpath(dirname, tag)

keyfile = abspath(joinpath(root, ".documenter"))
target_dir = abspath(target)
Expand Down Expand Up @@ -516,6 +525,7 @@ function git_push(

# Copy docs to `devurl`, or `stable`, `<release>`, and `<version>` directories.
if isempty(tag)
devurl_dir = joinpath(dirname, devurl)
gitrm_copy(target_dir, devurl_dir)
Writers.HTMLWriter.generate_siteinfo_file(devurl_dir, devurl)
# symlink "latest" to devurl to preserve links (remove in some future release)
Expand All @@ -529,20 +539,29 @@ function git_push(
else
@assert occursin(Base.VERSION_REGEX, tag) # checked in deploydocs
version = VersionNumber(tag)
# only push to stable if this is the latest stable release
# only symlink stable to latest release if this is the latest release
# which is not a prerelease
versions = filter!(x -> occursin(Base.VERSION_REGEX, x), readdir(dirname))
maxver = mapreduce(x -> VersionNumber(x), max, versions; init=v"0.0.0")
if version >= maxver && version.prerelease == () # don't deploy to stable for prereleases
gitrm_copy(target_dir, stable_dir)
Writers.HTMLWriter.generate_siteinfo_file(stable_dir, "stable")
if version >= maxver && version.prerelease == () && in("stable", selector)
cd(dirname) do; symlink(tag, "stable"); end
end
tagged_dir = joinpath(dirname, tag)
gitrm_copy(target_dir, tagged_dir)
Writers.HTMLWriter.generate_siteinfo_file(tagged_dir, tag)
end

# Create the versions.js file containing a list of all docs
# versions. This must always happen after the folder copying.
Writers.HTMLWriter.generate_version_file(dirname)
# Expand the users `selector` vector
entries, symlinks = Writers.HTMLWriter.expand_selector(dir, selector)

# Create the versions.js file containing a list of `entries`.
# This must always happen after the folder copying.
Writers.HTMLWriter.generate_version_file(dirname, entries)

# generate the symlinks
cd(dirname) do
foreach(kv -> symlink(kv.second, kv.first), symlinks)
end

# Add, commit, and push the docs to the remote.
run(`git add -A .`)
Expand Down
79 changes: 67 additions & 12 deletions src/Writers/HTMLWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -477,23 +477,78 @@ function render_topbar(ctx, navnode)
return div["#topbar"](span(page_title), a[".fa .fa-bars", :href => "#"])
end

function generate_version_file(dir::AbstractString)
all_folders = readdir(dir)
folders = []

for each in all_folders
occursin(Base.VERSION_REGEX, each) && push!(folders, each)
# expands the selector from the user
# and returns needed symlinks
function expand_selector(dir, selector)
available_folders = readdir(dir)
# returns "selector entry" => "underlying folder"
selector_entries = String[]
selector_symlinks = Pair{String,String}[]

# filter and sort release folders
vnum(x) = VersionNumber(x)
version_folders = [x for x in available_folders if occursin(Base.VERSION_REGEX, x)]
sort!(version_folders, lt = (x, y) -> vnum(x) < vnum(y), rev = true)
release_folders = filter(x -> (v = vnum(x); v.prerelease == () && v.build == ()), version_folders)
# pre_release_folders = filter(x -> (v = vnum(x); v.prerelease != () || v.build != ()), version_folders)
major_folders = unique(x -> vnum(x).major, release_folders)
minor_folders = unique(x -> (v = vnum(x); (v.major, v.minor)), release_folders)
patch_folders = unique(x -> (v = vnum(x); (v.major, v.minor, v.patch)), release_folders)

# populate output
for entry in selector
if entry == "v#" # one doc per major release
for x in major_folders
vstr = "v$(vnum(x).major).$(vnum(x).minor)"
push!(selector_entries, vstr)
push!(selector_symlinks, vstr => x)
end
elseif entry == "v#.#" # one doc per minor release
for x in minor_folders
vstr = "v$(vnum(x).major).$(vnum(x).minor)"
push!(selector_entries, vstr)
push!(selector_symlinks, vstr => x)
end
elseif entry == "v#.#.#" # one doc per patch release
for x in patch_folders
vstr = "v$(vnum(x).major).$(vnum(x).minor).$(vnum(x).patch)"
push!(selector_entries, vstr)
push!(selector_symlinks, vstr => x)
end
elseif entry == "stable"
push!(selector_entries, "stable")
push!(selector_symlinks, "stable" => first(release_folders))
elseif entry in available_folders
push!(selector_entries, entry) # no need to symlink
elseif entry isa Pair
k, v = entry
i = findfirst(==(v), available_folders)
if i === nothing
@info("no match for entry `$(repr(entry))` in selector.")
else
push!(selector_entries, k)
push!(selector_symlinks, k => v)
end
else
@info("no match for entry `$(repr(entry))` in selector.")
end
end
# sort tags by version number
sort!(folders, lt = (x, y) -> VersionNumber(x) < VersionNumber(y), rev = true)
unique!(selector_entries)

# include stable first, then dev
"dev" in all_folders && pushfirst!(folders, "dev")
"stable" in all_folders && pushfirst!(folders, "stable")
# generate remaining symlinks
foreach(x -> push!(selector_symlinks, "v$(vnum(x).major)" => x), major_folders)
foreach(x -> push!(selector_symlinks, "v$(vnum(x).major).$(vnum(x).minor)" => x), minor_folders)
foreach(x -> push!(selector_symlinks, "v$(vnum(x).major).$(vnum(x).minor).$(vnum(x).patch)" => x), patch_folders)
filter!(x -> x.first != x.second, unique!(selector_symlinks))

return selector_entries, selector_symlinks
end

# write version file
function generate_version_file(dir::AbstractString, selector_entries)
open(joinpath(dir, "versions.js"), "w") do buf
println(buf, "var DOC_VERSIONS = [")
for folder in folders
for folder in selector_entries
println(buf, " \"", folder, "\",")
end
println(buf, "];")
Expand Down
70 changes: 53 additions & 17 deletions test/htmlwriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,19 @@ module HTMLWriterTests

using Test

import Documenter.Writers.HTMLWriter: jsescape, generate_version_file
import Documenter.Writers.HTMLWriter: jsescape, generate_version_file, expand_selector

function verify_version_file(dir, entries)
file = joinpath(dir, "versions.js")
@test isfile(file)
content = read(file, String)
idx = 1
for entry in entries
i = findnext(entry, content, idx)
@test i !== nothing
idx = last(i)
end
end

@testset "HTMLWriter" begin
@test jsescape("abc123") == "abc123"
Expand All @@ -21,28 +33,52 @@ import Documenter.Writers.HTMLWriter: jsescape, generate_version_file
@test jsescape("policy to
 delete.") == "policy to\\u2028 delete."

mktempdir() do tmpdir
versions = ["stable", "dev", "v0.2.6", "v0.1.1", "v0.1.0"]
versions = ["stable", "dev",
"2.1.1", "v2.1.0", "v2.0.1", "v2.0.0",
"1.1.1", "v1.1.0", "v1.0.1", "v1.0.0",
"0.1.1", "v0.1.0"] # note no `v` on first ones
cd(tmpdir) do
mkdir("foobar")
for version in versions
mkdir(version)
end
end

generate_version_file(tmpdir)

versions_file = joinpath(tmpdir, "versions.js")
@test isfile(versions_file)
contents = String(read(versions_file))
@test !occursin("foobar", contents) # only specific directories end up in the versions file
# let's make sure they're in the right order -- they should be sorted in the output file
last = 0:0
for version in versions
this = findfirst(version, contents)
@test this !== nothing
@test first(last) < first(this)
last = this
end
# expanding selector
selector = ["stable", "v#.#", "dev"] # default to makedocs
entries, symlinks = expand_selector(tmpdir, selector)
@test entries == ["stable", "v2.1", "v2.0", "v1.1", "v1.0", "v0.1", "dev"]
@test symlinks == ["stable"=>"2.1.1", "v2.1"=>"2.1.1", "v2.0"=>"v2.0.1",
"v1.1"=>"1.1.1", "v1.0"=>"v1.0.1", "v0.1"=>"0.1.1",
"v2"=>"2.1.1", "v1"=>"1.1.1", "v0"=>"0.1.1", "v2.1.1"=>"2.1.1",
"v1.1.1"=>"1.1.1", "v0.1.1"=>"0.1.1"]
generate_version_file(tmpdir, entries)
verify_version_file(tmpdir, entries)

selector = ["v#"]
entries, symlinks = expand_selector(tmpdir, selector)
@test entries == ["v2.1", "v1.1", "v0.1"]
@test symlinks == ["v2.1"=>"2.1.1", "v1.1"=>"1.1.1", "v0.1"=>"0.1.1", "v2"=>"2.1.1",
"v1"=>"1.1.1", "v0"=>"0.1.1", "v2.0"=>"v2.0.1", "v1.0"=>"v1.0.1",
"v2.1.1"=>"2.1.1", "v1.1.1"=>"1.1.1", "v0.1.1"=>"0.1.1"]
generate_version_file(tmpdir, entries)
verify_version_file(tmpdir, entries)

selector = ["v#.#.#"]
entries, symlinks = expand_selector(tmpdir, selector)
@test entries == ["v2.1.1", "v2.1.0", "v2.0.1", "v2.0.0", "v1.1.1", "v1.1.0",
"v1.0.1", "v1.0.0", "v0.1.1", "v0.1.0"]
@test symlinks == ["v2.1.1"=>"2.1.1", "v1.1.1"=>"1.1.1", "v0.1.1"=>"0.1.1",
"v2"=>"2.1.1", "v1"=>"1.1.1", "v0"=>"0.1.1", "v2.1"=>"2.1.1",
"v2.0"=>"v2.0.1", "v1.1"=>"1.1.1", "v1.0"=>"v1.0.1", "v0.1"=>"0.1.1"]
generate_version_file(tmpdir, entries)
verify_version_file(tmpdir, entries)

selector = ["devel" => "dev", "foobar", "foo" => "bar"]
entries, symlinks = expand_selector(tmpdir, selector)
@test entries == ["devel"]
@test ("devel" => "dev") in symlinks
generate_version_file(tmpdir, entries)
verify_version_file(tmpdir, entries)
end
end

Expand Down

0 comments on commit 5f04725

Please sign in to comment.