diff --git a/README.md b/README.md
index 0f5658f3..95c11d47 100644
--- a/README.md
+++ b/README.md
@@ -84,3 +84,9 @@ Check [`.github/workflows/deploy.yml`](.github/workflows/deploy.yml) and [`docs/
The result of that script is available at [https://juliacomputing.github.io/MultiDocumenter.jl/](https://juliacomputing.github.io/MultiDocumenter.jl/).
You can of course also just push the output artefact directly to S3 or some other hosting service.
+
+> **Warning**
+> MultiDocumenter sites can not be deployed on Windows right now, and the `make()` function will throw an error.
+> See [#70](https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70).
+>
+> It is still possible to develop and debug MultiDocumenter sites on Windows if the build script is run interactively (e.g. by `include`-ing it into a REPL session).
diff --git a/src/MultiDocumenter.jl b/src/MultiDocumenter.jl
index b1237155..f5d69232 100644
--- a/src/MultiDocumenter.jl
+++ b/src/MultiDocumenter.jl
@@ -140,7 +140,26 @@ function make(
canonical_domain::Union{AbstractString,Nothing} = nothing,
sitemap::Bool = false,
sitemap_filename::AbstractString = "sitemap.xml",
+ # This keyword is for internal test use only:
+ _override_windows_isinteractive_check::Bool = false,
)
+ if Sys.iswindows() && !isinteractive()
+ if _override_windows_isinteractive_check || isinteractive()
+ @warn """
+ Running a MultiDocumenter build interactively in Windows.
+ This should only be used for development and testing, as it will lead to partial
+ and broken builds. See https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70
+ """
+ else
+ msg = """
+ MultiDocumenter deployments are disabled on Windows due to difficulties
+ with handling symlinks in documentation sources.
+ You _can_ test this build locally by running it interactively (i.e. in the REPL).
+ See also: https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70
+ """
+ error(msg)
+ end
+ end
if isnothing(canonical_domain)
(sitemap === true) &&
throw(ArgumentError("When sitemap=true, canonical_domain must also be set"))
@@ -249,7 +268,8 @@ function maybe_clone(docs::Vector{MultiDocRef})
`$(git()) clone --depth 1 $(doc.giturl) --branch $(doc.branch) --single-branch --no-tags $(doc.upstream)`,
)
else
- git_dir, git_worktree = abspath(joinpath(doc.upstream, ".git")), abspath(doc.upstream)
+ git_dir, git_worktree =
+ abspath(joinpath(doc.upstream, ".git")), abspath(doc.upstream)
if !isdir(git_dir)
@warn "Unable to update existing clone at $(doc.upstream): .git/ directory missing"
continue
@@ -266,7 +286,8 @@ function maybe_clone(docs::Vector{MultiDocRef})
catch e
# We're only interested in catching `git` errors here
isa(e, ProcessFailedException) || rethrow()
- @error "Unable to update existing clone at $(doc.upstream)" exception = (e, catch_backtrace())
+ @error "Unable to update existing clone at $(doc.upstream)" exception =
+ (e, catch_backtrace())
end
end
end
diff --git a/src/documentertools/canonical_urls.jl b/src/documentertools/canonical_urls.jl
index ea9ca040..fae84d0c 100644
--- a/src/documentertools/canonical_urls.jl
+++ b/src/documentertools/canonical_urls.jl
@@ -101,7 +101,9 @@ function update_canonical_links(docs_directory::AbstractString; canonical::Abstr
# We'll skip all files. This includes files such as index.html, which in this
# directory will likely be the redirect. Also, links should be pointing to other
# versions, so we'll skip them too.
- if !isdir(path) || islink(path)
+ # Note: we need to check islink() first, because on windows, calling isdir() on a
+ # symlink can make it throw a permissions IOError.
+ if islink(path) || !isdir(path)
continue
end
# Preview directory is should contain other Documenter directories, so we just add
diff --git a/test/documentertools.jl b/test/documentertools.jl
index 3b44a85d..bb55b497 100644
--- a/test/documentertools.jl
+++ b/test/documentertools.jl
@@ -3,6 +3,8 @@ import MultiDocumenter: DocumenterTools
FIXTURES = joinpath(@__DIR__, "fixtures")
+normalize_newlines(s::AbstractString) = replace(s, "\r\n" => "\n")
+
@testset "walkdocs" begin
let fileinfos = DocumenterTools.FileInfo[]
rs = DocumenterTools.walkdocs(joinpath(FIXTURES, "pre")) do fileinfo
@@ -123,8 +125,8 @@ end
canonical = "https://example.org/this-is-test",
)
DocumenterTools.walkdocs(joinpath(FIXTURES, "post")) do fileinfo
- post = read(fileinfo.fullpath, String)
- changed = read(joinpath(out, fileinfo.relpath), String)
+ post = normalize_newlines(read(fileinfo.fullpath, String))
+ changed = normalize_newlines(read(joinpath(out, fileinfo.relpath), String))
if changed != post
@error "update_canonical_links: change and post not matching" out fileinfo
end
diff --git a/test/runtests.jl b/test/runtests.jl
index 5c3b8de9..cfdae536 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -84,6 +84,30 @@ docs = [
# giturl = "git@github.com:JuliaComputing/DataSets.jl.git",
),
]
+
+# We do not support deploying docs on Windows at the moment, and MultiDocumenter
+# should throw an error if it's being run on Windows (in a non-interactive session).
+# See also: https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70
+if Sys.iswindows() && !isinteractive()
+ @test_throws ErrorException MultiDocumenter.make(
+ outpath,
+ docs;
+ search_engine = MultiDocumenter.SearchConfig(
+ index_versions = ["stable", "dev"],
+ engine = MultiDocumenter.FlexSearch,
+ ),
+ custom_scripts = [
+ "foo/bar.js",
+ "https://foo.com/bar.js",
+ Docs.HTML("const foo = 'bar';"),
+ ],
+ rootpath = rootpath,
+ canonical_domain = "https://example.org/",
+ sitemap = true,
+ sitemap_filename = "sitemap-mydocs.xml",
+ )
+end
+
MultiDocumenter.make(
outpath,
docs;
@@ -100,6 +124,8 @@ MultiDocumenter.make(
canonical_domain = "https://example.org/",
sitemap = true,
sitemap_filename = "sitemap-mydocs.xml",
+ # The following keyword is not standard:
+ _override_windows_isinteractive_check = Sys.iswindows(),
)
@testset "MultiDocumenter.jl" begin
@@ -107,8 +133,16 @@ MultiDocumenter.make(
@testset "structure" begin
@test isdir(outpath, "inf")
@test !isdir(outpath, "inf", "previews")
- @test isdir(outpath, "inf", "stable")
- @test isfile(outpath, "inf", "stable", "index.html")
+ if Sys.iswindows()
+ # On Windows, symlinks are either kept as simple files, or are in fact
+ # symlinks, but then you would run into permission errors with isdir().
+ # So we need to have platform-specific test logic here.
+ path = joinpath(outpath, "inf", "stable")
+ @test islink(path) || isfile(path)
+ else
+ @test isdir(outpath, "inf", "stable")
+ @test isfile(outpath, "inf", "stable", "index.html")
+ end
@test read(joinpath(outpath, "inf", "index.html"), String) == """
@@ -122,8 +156,7 @@ MultiDocumenter.make(
@testset "custom scripts" begin
- index = read(joinpath(outpath, "inf", "stable", "index.html"), String)
-
+ index = read(joinpath(outpath, "inf", "v1.6.4", "index.html"), String)
@test occursin(
"""""",
index,
@@ -140,12 +173,36 @@ MultiDocumenter.make(
"""""",
index,
)
+
+ if !Sys.iswindows()
+ # Going through symlinks does not work on Windows
+ index = read(joinpath(outpath, "inf", "stable", "index.html"), String)
+ @test occursin(
+ """""",
+ index,
+ )
+ @test occursin(
+ """""",
+ index,
+ )
+ @test occursin(
+ """""",
+ index,
+ )
+ @test occursin(
+ """""",
+ index,
+ )
+ end
end
@testset "canonical URLs" begin
- index = read(joinpath(outpath, "inf", "stable", "index.html"), String)
- canonical_href = ""
- @test occursin(canonical_href, index)
+ # We can't traverse symlinks on Windows, so we ignore this case
+ if !Sys.iswindows()
+ index = read(joinpath(outpath, "inf", "stable", "index.html"), String)
+ canonical_href = ""
+ @test occursin(canonical_href, index)
+ end
index = read(joinpath(outpath, "inf", "v1.6.0", "index.html"), String)
canonical_href = ""
@@ -158,9 +215,17 @@ MultiDocumenter.make(
@test !isempty(store_content)
@test occursin("Infiltrator.jl", store_content)
@test occursin("@infiltrate", store_content)
- @test occursin("$(rootpath)inf/stable/", store_content)
- @test occursin("$(rootpath)inf/stable/", store_content)
- @test !occursin("/inf/dev/", store_content)
+ # We can't traverse symlinks on Windows, so stable/ things do not get
+ # written into the search index. Instead, it looks like we write dev/
+ if Sys.iswindows()
+ @test !occursin("$(rootpath)inf/stable/", store_content)
+ @test !occursin("$(rootpath)inf/stable/", store_content)
+ @test occursin("/inf/dev/", store_content)
+ else
+ @test occursin("$(rootpath)inf/stable/", store_content)
+ @test occursin("$(rootpath)inf/stable/", store_content)
+ @test !occursin("/inf/dev/", store_content)
+ end
end
@testset "sitemap" begin