@@ -15,42 +15,56 @@ 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
53+ prompt_ready = Base. Event ()
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)
65+ Base. reset (prompt_ready)
5266 REPL. activate (REPL. Precompile; interactive_utils= false )
53- notify (repl_init_done_event )
67+ notify (activate_done )
5468 end
5569 Base. errormonitor (t)
5670 end
@@ -83,14 +97,6 @@ function repl_workload()
8397 println("done")
8498 """
8599
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-
94100 tmphistfile = tempname ()
95101 write (tmphistfile, """
96102 # time: 2020-10-31 13:16:39 AWST
@@ -120,20 +126,16 @@ function repl_workload()
120126 Base. _fd (pts) == rawpts || Base. close_stdio (rawpts)
121127 end
122128 # Prepare a background process to copy output from `ptm` until `pts` is closed
123- output_copy = Base. BufferStream ()
124129 tee = @async try
125130 while ! eof (ptm)
126131 l = readavailable (ptm)
127132 write (debug_output, l)
128- write (output_copy, l)
129133 end
130- write (debug_output, " \n #### EOF ####\n " )
131134 catch ex
132135 if ! (ex isa Base. IOError && ex. code == Base. UV_EIO)
133136 rethrow () # ignore EIO on ptm after pts dies
134137 end
135138 finally
136- close (output_copy)
137139 close (ptm)
138140 end
139141 Base. errormonitor (tee)
@@ -159,46 +161,29 @@ function repl_workload()
159161 redirect_stderr (isopen (orig_stderr) ? orig_stderr : devnull )
160162 end
161163 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)
164+ # Wait for the first prompt, then for activate to complete
165+ wait (activate_done)
166+ # Send a newline to get the activated prompt
168167 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 ))
168+ # Wait for the new prompt to be ready
169+ wait (prompt_ready)
170+ Base. reset (prompt_ready)
173171
174- write (debug_output, " \n #### REPL STARTED ####\n " )
175172 # Input our script
176173 precompile_lines = split (repl_script:: String , ' \n ' ; keepempty= false )
177- curr = 0
178174 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
175+ # If the line ends with a CTRL_C, don't write an extra newline
176+ # CTRL_C cancels input but doesn't print a new prompt, so don't wait
177+ if endswith (l, CTRL_C)
178+ write (ptm, l)
179+ sleep (0.1 ) # Brief pause to let CTRL_C be processed
180+ else
181+ write (ptm, l, " \n " )
182+ # Wait for REPL to signal it's ready for next input
183+ wait (prompt_ready)
184+ Base. reset (prompt_ready)
198185 end
199- check_errors (strbuf)
200186 end
201- write (debug_output, " \n #### COMPLETED - Closing REPL ####\n " )
202187 write (ptm, " $CTRL_D " )
203188 wait (repltask)
204189 finally
@@ -208,7 +193,8 @@ function repl_workload()
208193 end
209194 wait (tee)
210195 end
211- write (debug_output, " \n #### FINISHED ####\n " )
196+ # Check for any unexpected errors in the output
197+ check_output ()
212198 nothing
213199end
214200
0 commit comments