@@ -15,42 +15,55 @@ finally
1515end
1616
1717function repl_workload ()
18- # these are intentionally triggered
18+ # Capture debug output to show if something goes wrong
19+ debug_output = IOBuffer ()
20+
21+ # Errors that are intentionally triggered by the script
1922 allowed_errors = [
2023 " BoundsError: attempt to access 0-element Vector{Any} at index [1]" ,
2124 " MethodError: no method matching f(::$Int , ::$Int )" ,
2225 " Padding of type" , # reinterpret docstring has ERROR examples
2326 ]
24- function check_errors (out)
25- str = String (out)
26- if occursin (" ERROR:" , str) && ! any (occursin (e, str) for e in allowed_errors)
27- @error " Unexpected error (Review REPL precompilation with debug_output on):\n $str " exception= (
28- Base. PrecompilableError (), Base. backtrace ())
29- exit (1 )
27+
28+ function check_output ()
29+ str = String (take! (copy (debug_output)))
30+ for line in eachline (IOBuffer (str))
31+ if occursin (" ERROR:" , line) && ! any (e -> occursin (e, line), allowed_errors)
32+ println (stderr , """
33+ ========================================================================
34+ ERROR: Unexpected error during REPL precompilation
35+ ========================================================================
36+ Debug output:
37+ ------------------------------------------------------------------------
38+ """ )
39+ println (stderr , str)
40+ println (stderr , " ========================================================================" )
41+ error (" REPL precompilation encountered unexpected error: $line " )
42+ end
3043 end
3144 end
32- # # Debugging options
33- # View the code sent to the repl by setting this to `stdout`
34- debug_output = devnull # or stdout
3545
3646 CTRL_C = ' \x 03'
3747 CTRL_D = ' \x 04'
3848 CTRL_R = ' \x 12'
3949 UP_ARROW = " \e [A"
4050 DOWN_ARROW = " \e [B"
4151
42- # This is notified as soon as the first prompt appears
43- repl_init_event = Base. Event ()
44- repl_init_done_event = Base. Event ()
52+ # Event that REPL notifies each time it's ready for input (autoreset so each wait blocks until next notify)
53+ prompt_ready = Base. Event (true )
54+ # Event to signal that REPL.activate has been called
55+ activate_done = Base. Event ()
4556
4657 atreplinit () do repl
47- # Main is closed so we can't evaluate in it, but atreplinit runs at
48- # a time that repl.mistate === nothing so REPL.activate fails. So do
49- # it async and wait for the first prompt to know its ready.
58+ # Set the prompt_ready_event on the repl - run_frontend will copy it to mistate
59+ if repl isa REPL. LineEditREPL
60+ repl. prompt_ready_event = prompt_ready
61+ end
62+ # Start async task to wait for first prompt then activate the module
5063 t = @async begin
51- wait (repl_init_event )
64+ wait (prompt_ready )
5265 REPL. activate (REPL. Precompile; interactive_utils= false )
53- notify (repl_init_done_event )
66+ notify (activate_done )
5467 end
5568 Base. errormonitor (t)
5669 end
@@ -83,14 +96,6 @@ function repl_workload()
8396 println("done")
8497 """
8598
86- JULIA_PROMPT = " julia> "
87- # The help text for `reinterpret` has example `julia>` prompts in it,
88- # so use the longer prompt to avoid desychronization.
89- ACTIVATED_JULIA_PROMPT = " (REPL.Precompile) julia> "
90- PKG_PROMPT = " pkg> "
91- SHELL_PROMPT = " shell> "
92- HELP_PROMPT = " help?> "
93-
9499 tmphistfile = tempname ()
95100 write (tmphistfile, """
96101 # time: 2020-10-31 13:16:39 AWST
@@ -120,20 +125,16 @@ function repl_workload()
120125 Base. _fd (pts) == rawpts || Base. close_stdio (rawpts)
121126 end
122127 # Prepare a background process to copy output from `ptm` until `pts` is closed
123- output_copy = Base. BufferStream ()
124128 tee = @async try
125129 while ! eof (ptm)
126130 l = readavailable (ptm)
127131 write (debug_output, l)
128- write (output_copy, l)
129132 end
130- write (debug_output, " \n #### EOF ####\n " )
131133 catch ex
132134 if ! (ex isa Base. IOError && ex. code == Base. UV_EIO)
133135 rethrow () # ignore EIO on ptm after pts dies
134136 end
135137 finally
136- close (output_copy)
137138 close (ptm)
138139 end
139140 Base. errormonitor (tee)
@@ -159,46 +160,27 @@ function repl_workload()
159160 redirect_stderr (isopen (orig_stderr) ? orig_stderr : devnull )
160161 end
161162 schedule (repltask)
162- # wait for the definitive prompt before start writing to the TTY
163- check_errors (readuntil (output_copy, JULIA_PROMPT, keep= true ))
164-
165- # Switch to the activated prompt
166- notify (repl_init_event)
167- wait (repl_init_done_event)
163+ # Wait for the first prompt, then for activate to complete
164+ wait (activate_done)
165+ # Send a newline to get the activated prompt
168166 write (ptm, " \n " )
169- # The prompt prints twice - once for the restatement of the input, once
170- # to indicate ready for the new prompt.
171- check_errors (readuntil (output_copy, ACTIVATED_JULIA_PROMPT, keep= true ))
172- check_errors (readuntil (output_copy, ACTIVATED_JULIA_PROMPT, keep= true ))
167+ # Wait for the new prompt to be ready
168+ wait (prompt_ready)
173169
174- write (debug_output, " \n #### REPL STARTED ####\n " )
175170 # Input our script
176171 precompile_lines = split (repl_script:: String , ' \n ' ; keepempty= false )
177- curr = 0
178172 for l in precompile_lines
179- sleep (0.01 ) # try to let a bit of output accumulate before reading again
180- curr += 1
181- # push our input
182- write (debug_output, " \n #### inputting statement: ####\n $(repr (l)) \n ####\n " )
183- # If the line ends with a CTRL_C, don't write an extra newline, which would
184- # cause a second empty prompt. Our code below expects one new prompt per
185- # input line and can race out of sync with the unexpected second line.
186- endswith (l, CTRL_C) ? write (ptm, l) : write (ptm, l, " \n " )
187- check_errors (readuntil (output_copy, " \n " ))
188- # wait for the next prompt-like to appear
189- check_errors (readuntil (output_copy, " \n " ))
190- strbuf = " "
191- while ! eof (output_copy)
192- strbuf *= String (readavailable (output_copy))
193- occursin (ACTIVATED_JULIA_PROMPT, strbuf) && break
194- occursin (PKG_PROMPT, strbuf) && break
195- occursin (SHELL_PROMPT, strbuf) && break
196- occursin (HELP_PROMPT, strbuf) && break
197- sleep (0.01 ) # try to let a bit of output accumulate before reading again
173+ # If the line ends with a CTRL_C, don't write an extra newline
174+ # CTRL_C cancels input but doesn't print a new prompt, so don't wait
175+ if endswith (l, CTRL_C)
176+ write (ptm, l)
177+ sleep (0.1 ) # Brief pause to let CTRL_C be processed
178+ else
179+ write (ptm, l, " \n " )
180+ # Wait for REPL to signal it's ready for next input
181+ wait (prompt_ready)
198182 end
199- check_errors (strbuf)
200183 end
201- write (debug_output, " \n #### COMPLETED - Closing REPL ####\n " )
202184 write (ptm, " $CTRL_D " )
203185 wait (repltask)
204186 finally
@@ -208,7 +190,9 @@ function repl_workload()
208190 end
209191 wait (tee)
210192 end
211- write (debug_output, " \n #### FINISHED ####\n " )
193+ # Check for any unexpected errors in the output
194+ check_output ()
195+ rm (tmphistfile, force= true )
212196 nothing
213197end
214198
0 commit comments