@@ -24,13 +24,18 @@ mutable struct File
24
24
options = _parsed_options (options)
25
25
_, _, file_frontmatter = raw_text_chunks (path)
26
26
merged_options = _extract_relevant_options (file_frontmatter, options)
27
- exeflags, env = _exeflags_and_env (merged_options)
27
+ exeflags, env, quarto_env = _exeflags_and_env (merged_options)
28
28
timeout = _extract_timeout (merged_options)
29
29
30
-
31
30
exe, _exeflags = _julia_exe (exeflags)
32
- worker =
33
- cd (() -> Malt. Worker (; exe, exeflags = _exeflags, env), dirname (path))
31
+ worker = cd (
32
+ () -> Malt. Worker (;
33
+ exe,
34
+ exeflags = _exeflags,
35
+ env = vcat (env, quarto_env),
36
+ ),
37
+ dirname (path),
38
+ )
34
39
file = new (
35
40
worker,
36
41
path,
@@ -104,7 +109,7 @@ function _julia_exe(exeflags)
104
109
end
105
110
106
111
function _extract_timeout (merged_options)
107
- daemon = merged_options[" format" ][" execute" ][" daemon" ]
112
+ daemon = something ( merged_options[" format" ][" execute" ][" daemon" ], true )
108
113
if daemon === true
109
114
300.0 # match quarto's default timeout of 300 seconds
110
115
elseif daemon === false
@@ -149,6 +154,13 @@ function _exeflags_and_env(options)
149
154
# if exeflags already contains '--color=no', the 'no' will prevail
150
155
pushfirst! (exeflags, " --color=yes" )
151
156
157
+ # Several QUARTO_* environment variables are passed to the worker process
158
+ # via the `env` field rather than via real environment variables. Capture
159
+ # these and pass them to the worker process separate from `env` since that
160
+ # is used by the worker status printout and we don't want these extra ones
161
+ # that the user has not set themselves to show up there.
162
+ quarto_env = Base. byteenv (options[" env" ])
163
+
152
164
# Ensure that coverage settings are passed to the worker so that worker
153
165
# code is tracked correctly during tests.
154
166
# Based on https://github.com/JuliaLang/julia/blob/eed18bdf706b7aab15b12f3ba0588e8fafcd4930/base/util.jl#L216-L229.
@@ -171,7 +183,7 @@ function _exeflags_and_env(options)
171
183
end
172
184
end
173
185
174
- return exeflags, env
186
+ return exeflags, env, quarto_env
175
187
end
176
188
177
189
struct Server
@@ -205,22 +217,40 @@ function init!(file::File, options::Dict)
205
217
end
206
218
207
219
function refresh! (file:: File , options:: Dict )
208
- exeflags, env = _exeflags_and_env (options)
220
+ exeflags, env, quarto_env = _exeflags_and_env (options)
209
221
if exeflags != file. exeflags || env != file. env || ! Malt. isrunning (file. worker) # the worker might have been killed on another task
210
222
Malt. stop (file. worker)
211
223
exe, _exeflags = _julia_exe (exeflags)
212
- file. worker =
213
- cd (() -> Malt. Worker (; exe, exeflags = _exeflags, env), dirname (file. path))
224
+ file. worker = cd (
225
+ () -> Malt. Worker (; exe, exeflags = _exeflags, env = vcat (env, quarto_env)),
226
+ dirname (file. path),
227
+ )
214
228
file. exe = exe
215
229
file. exeflags = exeflags
216
230
file. env = env
217
231
file. source_code_hash = hash (VERSION )
218
232
file. output_chunks = []
219
233
init! (file, options)
220
234
end
235
+ refresh_quarto_env_vars! (file, quarto_env)
221
236
remote_eval_fetch_channeled (file. worker, :(refresh! ($ (options)); revise_hook ()))
222
237
end
223
238
239
+ # Environment variables provided by Quarto may change between `quarto render`
240
+ # calls. To update them correctly in the worker process, we need to refresh
241
+ # them before each run.
242
+ function refresh_quarto_env_vars! (file:: File , quarto_env)
243
+ if ! isempty (quarto_env)
244
+ remote_eval_fetch_channeled (file. worker, quote
245
+ for each in $ quarto_env
246
+ k, v = Base. splitenv (each)
247
+ ENV [k] = v
248
+ end
249
+ end )
250
+ end
251
+ return nothing
252
+ end
253
+
224
254
function _cache_file (f:: File , source_code_hash)
225
255
path = joinpath (dirname (f. path), " .cache" )
226
256
hs = string (hash (f. worker. manifest_file, source_code_hash); base = 62 )
@@ -441,9 +471,11 @@ function _extract_relevant_options(file_frontmatter::Dict, options::Dict)
441
471
daemon = daemon_default,
442
472
params = params_default,
443
473
cache = cache_default,
474
+ env = Dict {String,Any} (),
444
475
)
445
476
else
446
477
format = get (D, options, " format" )
478
+ env = get (D, options, " env" )
447
479
execute = get (D, format, " execute" )
448
480
fig_width = get (execute, " fig-width" , fig_width_default)
449
481
fig_height = get (execute, " fig-height" , fig_height_default)
@@ -481,6 +513,7 @@ function _extract_relevant_options(file_frontmatter::Dict, options::Dict)
481
513
daemon,
482
514
params = params_merged,
483
515
cache,
516
+ env,
484
517
)
485
518
end
486
519
end
@@ -497,6 +530,7 @@ function _options_template(;
497
530
daemon,
498
531
params,
499
532
cache,
533
+ env,
500
534
)
501
535
D = Dict{String,Any}
502
536
return D (
@@ -515,6 +549,7 @@ function _options_template(;
515
549
" metadata" => D (" julia" => julia),
516
550
),
517
551
" params" => D (params),
552
+ " env" => env,
518
553
)
519
554
end
520
555
@@ -1466,7 +1501,7 @@ function run!(
1466
1501
chunk_callback = (i, n, c) -> nothing ,
1467
1502
)
1468
1503
try
1469
- borrow_file! (server, path; optionally_create = true ) do file
1504
+ borrow_file! (server, path; options, optionally_create = true ) do file
1470
1505
if file. timeout_timer != = nothing
1471
1506
close (file. timeout_timer)
1472
1507
file. timeout_timer = nothing
@@ -1606,7 +1641,7 @@ function borrow_file!(
1606
1641
get (server. workers, apath, nothing )
1607
1642
end
1608
1643
if file != = current_file
1609
- return borrow_file! (f, server, apath; optionally_create)
1644
+ return borrow_file! (f, server, apath; options, optionally_create)
1610
1645
else
1611
1646
return f (file)
1612
1647
end
0 commit comments