Skip to content

Commit 3ad634e

Browse files
committed
add LocalRemoteCard
1 parent f70a6e9 commit 3ad634e

File tree

14 files changed

+208
-7
lines changed

14 files changed

+208
-7
lines changed

src/DemoCards.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ include("compat.jl")
3535
include("types/card.jl")
3636
include("types/section.jl")
3737
include("types/page.jl")
38+
include("remote.jl")
3839

3940
include("utils.jl")
4041
include("show.jl")

src/generate.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ function makedemos(source::String, templates::Union{Dict, Nothing} = nothing;
150150
)
151151
end
152152
else
153+
# For themes that requires an index page
154+
# This will not generate a multi-level structure in the sidebar
153155
out_path = joinpath(relative_root, "index.md")
154156
end
155157

@@ -201,6 +203,9 @@ function makedemos(source::String, templates::Union{Dict, Nothing} = nothing;
201203
@info "Redirect page URL: redirect docs-edit-link for demos in \"$(source)\" directory."
202204
isnothing(templates) || push!(source_files, joinpath(page_root, "index.md"))
203205
foreach(source_files) do source_file
206+
# LocalRemoteCard is a virtual placeholder and does not exist here
207+
isfile(source_file) && return
208+
# only redirect to "real" files
204209
redirect_link(source_file, source, root, src, build, edit_branch)
205210
end
206211

@@ -249,14 +254,14 @@ function generate(page::DemoPage, templates)
249254
Mustache.render(page.template, items)
250255
end
251256

252-
function generate(cards::AbstractVector{<:AbstractDemoCard}, template; properties=Dict{String, Any}())
257+
function generate(cards::AbstractVector{<:Union{AbstractDemoCard, LocalRemoteCard}}, template; properties=Dict{String, Any}())
253258
# for those hidden cards, only generate the necessary assets and files, but don't add them into
254259
# the index.md page
255-
foreach(filter(x->x.hidden, cards)) do x
260+
foreach(filter(ishidden, cards)) do x
256261
generate(x, template; properties=properties)
257262
end
258263

259-
mapreduce(*, filter(x->!x.hidden, cards); init="") do x
264+
mapreduce(*, filter(x->!ishidden(x), cards); init="") do x
260265
generate(x, template; properties=properties)
261266
end
262267
end
@@ -326,7 +331,7 @@ function save_cover(path::String, sec::DemoSection)
326331
end
327332

328333
"""
329-
save_cover(path::String, card::AbstractDemoCard)
334+
save_cover(path::String, card)
330335
331336
process the cover image and save it.
332337
"""
@@ -361,7 +366,7 @@ function save_cover(path::String, card::AbstractDemoCard)
361366
end
362367
end
363368

364-
function get_covername(card::AbstractDemoCard)
369+
function get_covername(card)
365370
isnothing(card.cover) && return nothing
366371
is_remote_url(card.cover) && return card.cover
367372

src/preview.jl

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ function preview_demos(demo_path::String;
5555

5656
page_dir = generate_or_copy_pagedir(demo_path, build_dir)
5757
copy_assets_and_configs(page_dir, build_dir)
58+
rewrite_localremote_path(page_dir, build_dir)
5859

5960
cd(build_dir) do
6061
page = @suppress_err DemoPage(page_dir)
@@ -218,7 +219,12 @@ function copy_assets_and_configs(src_page_dir, dst_build_dir=pwd())
218219
config = JSON.parsefile(src_config_path)
219220
config_dir = dirname(dst_config_path)
220221
if haskey(config, "order")
221-
order = [x for x in config["order"] if x in readdir(config_dir)]
222+
files = readdir(config_dir)
223+
remote_files = keys(get(config, "remote", Dict()))
224+
order = filter(config["order"]) do x
225+
x in files || x in remote_files
226+
end
227+
222228
if isempty(order)
223229
delete!(config, "order")
224230
else
@@ -236,3 +242,28 @@ function copy_assets_and_configs(src_page_dir, dst_build_dir=pwd())
236242
end
237243
end
238244
end
245+
246+
function rewrite_localremote_path(page_dir, build_dir)
247+
# To support relpath for LocalRemoteCard, we have to
248+
# eagerly rewrite the relpath with abspath so that
249+
# later build can correctly find the remote filepath.
250+
# This only affects LocalRemoteCard with relpath.
251+
252+
page = @suppress_err DemoPage(page_dir)
253+
walkpage(page) do dir, card
254+
if card isa LocalRemoteCard
255+
# find out the corresponding config file, and rewrite the remote entry
256+
# with abspath
257+
build_carddir = joinpath(build_dir, basename(page_dir), relpath(dir, page_dir))
258+
src_config_path = joinpath(build_carddir, config_filename)
259+
260+
config = JSON.parsefile(src_config_path)
261+
config["remote"][card.name] = card.path
262+
263+
open(src_config_path, "w") do io
264+
JSON.print(io, config)
265+
end
266+
end
267+
end
268+
269+
end

src/remote.jl

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
abstract type AbstractRemotePath end
2+
3+
#####
4+
# LocalRemote
5+
#####
6+
struct LocalRemoteCard{T<:AbstractDemoCard} <: AbstractRemotePath
7+
name::String
8+
path::String
9+
item::T
10+
function LocalRemoteCard(name::String, path::String, item::T) where T<:AbstractDemoCard
11+
basename(name) == name || throw(ArgumentError("`name` should not be a path, instead it is: $name"))
12+
isfile(path) || throw(ArgumentError("file $path does not exist."))
13+
new{T}(name, path, item)
14+
end
15+
end
16+
17+
ishidden(card::LocalRemoteCard) = ishidden(card.item)
18+
19+
function Base.basename(card::LocalRemoteCard{T}) where T
20+
name, ext = splitext(card.name)
21+
if isempty(ext)
22+
if T <: MarkdownDemoCard
23+
ext = ".md"
24+
elseif T <: JuliaDemoCard
25+
ext = ".jl"
26+
else
27+
throw(ArgumentError("Unknown card type $T"))
28+
end
29+
end
30+
return name * ext
31+
end
32+
33+
function Base.show(io::IO, card::LocalRemoteCard)
34+
print(io, basename(card), " => ", card.path)
35+
end
36+
37+
function generate(card::LocalRemoteCard, template)
38+
with_tempcard(card) do tempcard
39+
generate(tempcard, template)
40+
end
41+
end
42+
function save_democards(card_dir::String, card::LocalRemoteCard; kwargs...)
43+
dst = joinpath(card_dir, basename(card))
44+
isfile(dst) && throw(ArgumentError("file $dst already exists."))
45+
46+
with_tempcard(card) do tempcard
47+
save_democards(card_dir, tempcard; kwargs...)
48+
end
49+
end
50+
51+
function save_cover(path::String, card::LocalRemoteCard)
52+
with_tempcard(card) do tempcard
53+
save_cover(path, tempcard)
54+
end
55+
end
56+
57+
# TODO: this file copy is not very necessary, and it get called many times
58+
function with_tempcard(f, card)
59+
mktempdir() do dir
60+
# copy and rename file so that generated files are correctly handled
61+
# For example:
62+
# "cardname" => "path/to/sourcefile.jl"
63+
# Later workflow uses "cardname.md" instead of "sourcefile.md"
64+
tmpfile = joinpath(dir, basename(card))
65+
cp(card.path, tmpfile)
66+
f(democard(tmpfile))
67+
end
68+
end

src/types/julia.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,5 @@ function make_badges(card::JuliaDemoCard; src, card_dir, nbviewer_root_url, proj
289289

290290
join(badges, " ")
291291
end
292+
293+
ishidden(x::JuliaDemoCard) = x.hidden

src/types/markdown.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,5 @@ function save_democards(card_dir::String,
133133
footer = credit ? markdown_footer : "\n"
134134
write(markdown_path, header, make_badges(card)*"\n\n", body, footer)
135135
end
136+
137+
ishidden(x::MarkdownDemoCard) = x.hidden

src/types/section.jl

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,15 @@ function DemoSection(root::String)::DemoSection
106106
# For files that `democard` fails to recognized, dummy
107107
# `UnmatchedCard` will be generated. Currently, we only
108108
# throw warnings for it.
109-
cards = map(democard, card_paths)
109+
cards = Union{AbstractDemoCard, LocalRemoteCard}[democard(x) for x in card_paths]
110110
unmatches = filter(cards) do x
111111
x isa UnmatchedCard
112112
end
113113
if !isempty(unmatches)
114114
msg = join(map(basename, unmatches), "\", \"")
115115
@warn "skip unmatched file: \"$msg\"" section_dir=root
116116
end
117+
117118
cards = filter!(cards) do x
118119
!(x isa UnmatchedCard)
119120
end
@@ -134,6 +135,20 @@ function DemoSection(root::String)::DemoSection
134135
subsections = map(DemoSection, ordered_paths)
135136
end
136137

138+
if haskey(config, "remote")
139+
remote_cards = LocalRemoteCard[]
140+
for (cardname, cardpath) in config["remote"]
141+
# if possible, store the abspath
142+
cardpath = isabspath(cardpath) ? cardpath : normpath(joinpath(root, cardpath))
143+
push!(remote_cards, LocalRemoteCard(cardname, cardpath, democard(cardpath)))
144+
end
145+
append!(cards, remote_cards)
146+
end
147+
148+
subsections = map(DemoSection, section_paths)
149+
section = DemoSection(root, cards, subsections, "", "")
150+
cards, subsections = sort_by_order(section, config)
151+
137152
title = load_config(section, "title"; config=config)
138153
description = load_config(section, "description"; config=config)
139154

@@ -146,6 +161,31 @@ function DemoSection(root::String)::DemoSection
146161
DemoSection(root, cards, subsections, title, description, properties)
147162
end
148163

164+
function sort_by_order(sec::DemoSection, config)
165+
cards = sec.cards
166+
subsections = sec.subsections
167+
168+
ordered_paths = load_config(sec, "order"; config=config)
169+
if !isempty(sec.cards)
170+
indices = map(ordered_paths) do ref
171+
findfirst(cards) do card
172+
basename(card) == ref
173+
end
174+
end
175+
cards = cards[indices]
176+
subsections = []
177+
else
178+
indices = map(ordered_paths) do ref
179+
findfirst(subsections) do sec
180+
basename(sec) == ref
181+
end
182+
end
183+
subsections = subsections[indices]
184+
cards = []
185+
end
186+
187+
return cards, subsections
188+
end
149189

150190
function load_config(sec::DemoSection, key; config=Dict())
151191
if isempty(config)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"remote": {
3+
"julia_card": "../../card/julia/title_1.jl",
4+
"markdown_card": "../../card/markdown/title_3.md"
5+
}
6+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# [Custom Title 2](@id custom_id_2)
2+
3+
This is the content
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"remote": {
3+
"julia_card.jl": "../../card/julia/title_1.jl",
4+
"markdown_card.md": "../../card/markdown/title_3.md"
5+
},
6+
"order": [
7+
"julia_card.jl",
8+
"markdown_card.md",
9+
"title_2.md"
10+
]
11+
}

0 commit comments

Comments
 (0)