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 selector argument to deploydocs #813

Merged
merged 1 commit into from
Aug 26, 2018
Merged
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
62 changes: 41 additions & 21 deletions src/Documenter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ hide(root::AbstractString, children) = (true, nothing, root, map(hide, children)
make = <Function>,
devbranch = "master",
devurl = "dev",
versions = ["stable" => "v^", "v#.#", devurl => devurl]
)

Converts markdown files generated by [`makedocs`](@ref) to HTML and pushes them to `repo`.
Expand Down Expand Up @@ -315,6 +316,20 @@ 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"`.

**`versions`** determines content and order of the resulting version selector in
the generated html. The following entries are valied in the `versions` vector:
- `"v#"`: includes links to the latest documentation for each major release cycle
(i.e. `v2.0`, `v1.1`).
- `"v#.#"`: includes links to the latest documentation for each minor release cycle
(i.e. `v2.0`, `v1.1`, `v1.0`, `v0.1`).
- `"v#.#.#"`: includes links to all released versions.
- `"v^"`: includes a link to the docs for the maximum version
(i.e. a link `vX.Y` pointing to `vX.Y.Z` for highest `X`, `Y`, `Z`, respectively).
- A pair, e.g. `"first" => "second"`, which will put `"first"` in the selector,
and generate a url from which `"second"` can be accessed.
The second argument can be `"v^"`, to point to the maximum version docs
(as in e.g. `"stable" => "v^"`).

# See Also

The [Hosting Documentation](@ref) section of the manual provides a step-by-step guide to
Expand All @@ -338,6 +353,7 @@ function deploydocs(;

devbranch = "master",
devurl = "dev",
versions = ["stable" => "v^", "v#.#", devurl => devurl]
)
# deprecation of latest kwarg (renamed to devbranch)
if latest !== nothing
Expand Down Expand Up @@ -442,7 +458,7 @@ function deploydocs(;
root, temp, repo;
branch=branch, dirname=dirname, target=target,
tag=travis_tag, key=documenter_key, sha=sha,
devurl = devurl,
devurl = devurl, versions = versions,
)
end
end
Expand All @@ -461,19 +477,15 @@ end

Handles pushing changes to the remote documentation branch.
When `tag` is empty the docs are deployed to the `devurl` directory,
and when building docs for a tag they are deployed to a `vX.Y.Z` directory,
and also to the `stable` directory.
and when building docs for a tag they are deployed to a `vX.Y.Z` 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",
versions
)
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 @@ -515,6 +527,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 @@ -523,25 +536,25 @@ function git_push(
@warn(string("creating symlink from `latest` to `$(devurl)` for backwards ",
"compatibility with old links. In future Documenter versions this symlink ",
"will not be created. Please update any links that point to `latest`."))
cd(dirname) do; symlink(devurl, "latest"); end
cd(dirname) do; rm_and_add_symlink(devurl, "latest"); end
end
else
@assert occursin(Base.VERSION_REGEX, tag) # checked in deploydocs
version = VersionNumber(tag)
# only push to stable if this is the latest stable release
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")
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 `versions` vector
entries, symlinks = Writers.HTMLWriter.expand_versions(dirname, versions)

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

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

# Add, commit, and push the docs to the remote.
run(`git add -A .`)
Expand All @@ -559,6 +572,13 @@ function git_push(
end
end

function rm_and_add_symlink(target, link)
# If `link` is an old symlink, remove it,
# if `link` is something else we let symlink throw.
islink(link) && rm(link)
symlink(target, link)
end

"""
gitrm_copy(src, dst)

Expand Down
90 changes: 77 additions & 13 deletions src/Writers/HTMLWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -477,23 +477,87 @@ 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)
# expand the versions argument from the user
# and return entries and needed symlinks
function expand_versions(dir, versions)
# output: entries and symlinks
entries = String[]
symlinks = Pair{String,String}[]

# read folders and filter out symlinks
available_folders = readdir(dir)
cd(() -> filter!(!islink, available_folders), dir)

# 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 = filter!(x -> (v = vnum(x); v.major != 0),
unique(x -> (v = vnum(x); v.major), release_folders))
minor_folders = filter!(x -> (v = vnum(x); !(v.major == 0 && v.minor == 0)),
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)

filter!(x -> vnum(x) !== 0, major_folders)

# populate output
for entry in versions
if entry == "v#" # one doc per major release
for x in major_folders
vstr = "v$(vnum(x).major).$(vnum(x).minor)"
push!(entries, vstr)
push!(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!(entries, vstr)
push!(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!(entries, vstr)
push!(symlinks, vstr => x)
end
elseif entry == "v^" || (entry isa Pair && entry.second == "v^")
if !isempty(release_folders)
x = first(release_folders)
vstr = isa(entry, Pair) ? entry.first : "v$(vnum(x).major).$(vnum(x).minor)"
push!(entries, vstr)
push!(symlinks, vstr => x)
end
elseif entry isa Pair
k, v = entry
i = findfirst(==(v), available_folders)
if i === nothing
@info("no match for `versions` entry `$(repr(entry))`")
else
push!(entries, k)
push!(symlinks, k => v)
end
else
@info("no match for `versions` entry `$(repr(entry))`")
end
end
# sort tags by version number
sort!(folders, lt = (x, y) -> VersionNumber(x) < VersionNumber(y), rev = true)
unique!(entries) # remove any duplicates

# 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!(symlinks, "v$(vnum(x).major)" => x), major_folders)
foreach(x -> push!(symlinks, "v$(vnum(x).major).$(vnum(x).minor)" => x), minor_folders)
foreach(x -> push!(symlinks, "v$(vnum(x).major).$(vnum(x).minor).$(vnum(x).patch)" => x), patch_folders)
filter!(x -> x.first != x.second, unique!(symlinks))

return entries, symlinks
end

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

using Test

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

function verify_version_file(versionfile, entries)
@test isfile(versionfile)
content = read(versionfile, 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 +32,54 @@ 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"]
versionfile = joinpath(tmpdir, "versions.js")
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 versions
versions = ["stable" => "v^", "v#.#", "dev" => "dev"] # default to makedocs
entries, symlinks = expand_versions(tmpdir, versions)
@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", "v2.1.1"=>"2.1.1",
"v1.1.1"=>"1.1.1", "v0.1.1"=>"0.1.1"]
generate_version_file(versionfile, entries)
verify_version_file(versionfile, entries)

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

versions = ["v#.#.#"]
entries, symlinks = expand_versions(tmpdir, versions)
@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", "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(versionfile, entries)
verify_version_file(versionfile, entries)

versions = ["v^", "devel" => "dev", "foobar", "foo" => "bar"]
entries, symlinks = expand_versions(tmpdir, versions)
@test entries == ["v2.1", "devel"]
@test ("v2.1" => "2.1.1") in symlinks
@test ("devel" => "dev") in symlinks
generate_version_file(versionfile, entries)
verify_version_file(versionfile, entries)
end
end

Expand Down