Skip to content

Instantly share code, notes, and snippets.

@joshday
Last active Jun 21, 2021
Embed
What would you like to do?
Modify Pluto.jl to run offline on the first run
# Edit Pluto (in place!) to run in an air-gapped environment
# Editing a package after it's installed is bad. But hey, this works.
# Before running this script, you can instantiate a new depot to avoid
# contaminating your main depot. Something like:
#
# push!(empty!(DEPOT_PATH), "my/new/depot/path")
# using Pkg
# Pkg.activate("my/project/path")
# Pkg.instantiate()
using Pluto, DelimitedFiles
pluto_root(args...) = abspath(joinpath(pathof(Pluto), "..", "..", args...))
function _replace(file, old_new::Pair)
old, new = old_new
sed = Sys.isapple() ? ["sed", "-i", ""] : ["sed", "-i"]
run(`$sed $("s|$old|$new|g") $file`)
end
frontend = pluto_root("frontend")
assets = pluto_root("frontend", "offline_assets")
mkpath(assets)
# find all lines that contain `jsdelivr`, the CDN that delivers assets to Pluto
lines = split(read(`grep -r "jsdelivr" $frontend`, String), '\n')
# place all CDN urls into `replaced_assets`
replaced_assets = []
for line in lines
match = findfirst(r"((?<=\")https:\/\/[^\"]*)|((?<=\()https:\/\/[^\)]*)", line)
if isnothing(match)
@warn "No match found for line: $line"
else
url = line[match]
push!(replaced_assets, url)
pluto_file = line[1:findfirst(':', line) - 1]
_replace(pluto_file, url => "/offline_assets/$(basename(url))")
end
end
writedlm(joinpath(@__DIR__, "assets.csv"), replaced_assets)
dir = pluto_root("frontend", "offline_assets")
for url in readlines(joinpath(@__DIR__, "assets.csv") )
@info "Downloading: $url"
file = touch(joinpath(dir, basename(url)))
download(url, file)
end
@joshday
Copy link
Author

joshday commented Jun 1, 2021

This script also saves assets.csv which tells you which assets were replaced.

@liu-leen
Copy link

liu-leen commented Jun 17, 2021

This script can't run in Pluto v0.14.7.
$)─> julia offline_pluto.jl ┌ Warning: No match found for line: ~/.julia/packages/Pluto/D9HrI/frontend/common/Binder.js: fetch(https://cdn.jsdelivr.net/gh/fonsp/pluto-usage-counter@1/binder-start.txt?skip_sw`).catch(() => {})
└ @ Main /software/offline_pluto.jl:34
┌ Warning: No match found for line:
/.julia/packages/Pluto/D9HrI/frontend/sw.js:const allowList = ["www.gstatic.com", "fonts.gstatic.com", "fonts.googleapis.com", "cdn.jsdelivr.net", "cdnjs.cloudflare.com", "unpkg.com"]
└ @ Main ~/software/offline_pluto.jl:34
┌ Warning: No match found for line: ~/.julia/packages/Pluto/D9HrI/frontend/components/CellOutput.js: path: (mode) => https://cdn.jsdelivr.net/npm/codemirror@5.60.0/mode/${mode}/${mode}.min.js,
└ @ Main ~/software/offline_pluto.jl:34
┌ Warning: No match found for line: ~/.julia/packages/Pluto/D9HrI/frontend/components/Editor.js: fetch(https://cdn.jsdelivr.net/gh/fonsp/pluto-usage-counter@1/article-view.txt?skip_sw).catch(() => {})
└ @ Main ~/software/offline_pluto.jl:34
┌ Warning: No match found for line:
└ @ Main ~/software/offline_pluto.jl:34
ERROR: LoadError: UndefVarError: here not defined
Stacktrace:
[1] top-level scope
@ ~/software/offline_pluto.jl:45
in expression starting at ~/software/offline_pluto.jl:45
`

Could you update?

@joshday
Copy link
Author

joshday commented Jun 21, 2021

I can't reproduce. What platform are you using?

@joshday
Copy link
Author

joshday commented Jun 21, 2021

Never mind...I copied and pasted this from a larger script and I missed a function definition. It's updated now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment