rbx.cp 0.5.54__py3-none-any.whl → 0.5.56__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. rbx/box/checkers.py +11 -1
  2. rbx/box/cli.py +8 -0
  3. rbx/box/contest/schema.py +53 -4
  4. rbx/box/naming.py +20 -5
  5. rbx/box/packaging/boca/upload.py +247 -0
  6. rbx/box/packaging/main.py +13 -1
  7. rbx/box/solutions.py +12 -1
  8. rbx/box/tasks.py +4 -2
  9. rbx/box/testcase_extractors.py +3 -0
  10. rbx/box/ui/captured_log.py +13 -8
  11. rbx/box/ui/css/app.tcss +47 -8
  12. rbx/box/ui/main.py +5 -1
  13. rbx/box/ui/screens/__init__.py +0 -0
  14. rbx/box/ui/screens/build.py +6 -0
  15. rbx/box/ui/screens/command.py +35 -0
  16. rbx/box/ui/{run.py → screens/run.py} +10 -38
  17. rbx/box/ui/screens/run_explorer.py +5 -0
  18. rbx/box/ui/screens/test_explorer.py +100 -0
  19. rbx/box/ui/widgets/file_log.py +63 -0
  20. rbx/box/ui/widgets/rich_log_box.py +5 -0
  21. rbx/grading/judge/sandboxes/stupid_sandbox.py +5 -1
  22. rbx/grading/judge/sandboxes/timeit.py +2 -1
  23. rbx/resources/packagers/boca/interactive/c +15 -8
  24. rbx/resources/packagers/boca/interactive/cc +15 -8
  25. rbx/resources/packagers/boca/interactive/cpp +15 -9
  26. rbx/resources/packagers/boca/interactive/java +12 -5
  27. rbx/resources/packagers/boca/interactive/kt +12 -5
  28. rbx/resources/packagers/boca/interactive/py2 +15 -8
  29. rbx/resources/packagers/boca/interactive/py3 +14 -9
  30. rbx/resources/packagers/boca/run/c +2 -1
  31. rbx/resources/packagers/boca/run/cc +2 -1
  32. rbx/resources/packagers/boca/run/cpp +2 -1
  33. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.56.dist-info}/METADATA +7 -2
  34. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.56.dist-info}/RECORD +37 -29
  35. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.56.dist-info}/LICENSE +0 -0
  36. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.56.dist-info}/WHEEL +0 -0
  37. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.56.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+ from typing import List
3
+
4
+ from textual.app import ComposeResult
5
+ from textual.screen import Screen
6
+ from textual.widgets import Footer, Header
7
+
8
+ from rbx.box.ui.captured_log import LogDisplay
9
+
10
+
11
+ class CommandScreen(Screen):
12
+ BINDINGS = [('q', 'app.pop_screen', 'Back')]
13
+
14
+ def __init__(self, command: List[str]):
15
+ super().__init__()
16
+ self.command = command
17
+
18
+ def compose(self) -> ComposeResult:
19
+ yield Header()
20
+ yield Footer()
21
+ yield LogDisplay()
22
+
23
+ async def _run_command(self):
24
+ exitcode = await self.query_one(LogDisplay).capture(self.command)
25
+ if exitcode != 0:
26
+ self.query_one(LogDisplay).border_subtitle = f'Exit code: {exitcode}'
27
+ return
28
+
29
+ self.query_one(LogDisplay).border_subtitle = 'Finished'
30
+
31
+ async def on_mount(self):
32
+ self.query_one(LogDisplay).border_title = 'Command output'
33
+
34
+ # Fire and forget.
35
+ asyncio.create_task(self._run_command())
@@ -18,9 +18,10 @@ from rbx.box.solutions import (
18
18
  SolutionReportSkeleton,
19
19
  get_evals_formatted_time,
20
20
  get_testcase_markup_verdict,
21
- run_solutions,
22
21
  )
23
22
  from rbx.box.ui.captured_log import LogDisplay, LogDisplayState
23
+ from rbx.box.ui.screens.command import CommandScreen
24
+ from rbx.grading.steps import Evaluation
24
25
 
25
26
 
26
27
  def _build_solution_selection_label(sol: Solution) -> Text:
@@ -36,7 +37,7 @@ def _build_solution_selection_label(sol: Solution) -> Text:
36
37
  class SolutionReportScreen(Screen):
37
38
  skeleton: SolutionReportSkeleton
38
39
 
39
- BINDINGS = [('q', 'app.pop_screen', 'Quit')]
40
+ BINDINGS = [('q', 'app.pop_screen', 'Back')]
40
41
 
41
42
  def __init__(
42
43
  self,
@@ -86,7 +87,7 @@ class SolutionReportScreen(Screen):
86
87
  return i
87
88
  raise
88
89
 
89
- async def process(self, item: EvaluationItem):
90
+ async def process(self, item: EvaluationItem, eval: Evaluation):
90
91
  pkg = package.find_problem_package_or_die()
91
92
  sol_idx_in_skeleton = self._find_solution_index_in_skeleton(
92
93
  pkg.solutions[item.solution_index]
@@ -101,17 +102,19 @@ class SolutionReportScreen(Screen):
101
102
 
102
103
  table.update_cell_at(
103
104
  Coordinate(row=row_idx, column=2),
104
- get_testcase_markup_verdict(await item.eval()),
105
+ get_testcase_markup_verdict(eval),
105
106
  update_width=True,
106
107
  )
107
108
  table.update_cell_at(
108
109
  Coordinate(row=row_idx, column=3),
109
- get_evals_formatted_time([await item.eval()]),
110
+ get_evals_formatted_time([eval]),
110
111
  update_width=True,
111
112
  )
112
113
 
113
114
 
114
115
  class RunScreen(Screen):
116
+ BINDINGS = [('q', 'app.pop_screen', 'Back')]
117
+
115
118
  def compose(self) -> ComposeResult:
116
119
  yield Header()
117
120
  yield Footer()
@@ -141,7 +144,6 @@ class RunScreen(Screen):
141
144
  id='run-config',
142
145
  )
143
146
  yield Button('Run')
144
- yield LogDisplay()
145
147
 
146
148
  def on_mount(self):
147
149
  sols = self.query_one('#run-sols', SelectionList)
@@ -160,7 +162,6 @@ class RunScreen(Screen):
160
162
  async def on_button_pressed(self, _: Button.Pressed):
161
163
  await self.action_run()
162
164
 
163
- @textual.work(thread=True)
164
165
  async def _run_solutions(self, tracked_solutions: Set[str], check: bool):
165
166
  main_solution = package.get_main_solution()
166
167
  if check and main_solution is None:
@@ -169,36 +170,7 @@ class RunScreen(Screen):
169
170
  )
170
171
  check = False
171
172
 
172
- async def build():
173
- return await self.query_one(LogDisplay).capture(['rbx', 'build'])
174
-
175
- exitcode = self.app.call_from_thread(build)
176
-
177
- if exitcode != 0:
178
- textual.log(f'early quit: {exitcode}')
179
- return
180
-
181
- textual.log('build finished ok, running solutions')
182
-
183
- res = run_solutions(tracked_solutions=tracked_solutions, check=check)
184
-
185
- async def mount_report_widget() -> SolutionReportScreen:
186
- # log_display_state = self.query_one(LogDisplay).export()
187
- log_display_state = None
188
- await self.app.push_screen(
189
- screen := SolutionReportScreen(
190
- res.skeleton, log_display_state=log_display_state
191
- )
192
- )
193
- return screen
194
-
195
- new_screen = await mount_report_widget()
196
-
197
- async def process_item(item: EvaluationItem):
198
- await new_screen.process(item)
199
-
200
- for item in res.items:
201
- self.app.call_from_thread(process_item, item)
173
+ self.app.switch_screen(CommandScreen(['rbx', 'run']))
202
174
 
203
175
  async def action_run(self):
204
176
  sols = self.query_one('#run-sols', SelectionList)
@@ -207,4 +179,4 @@ class RunScreen(Screen):
207
179
  tracked_solutions = set(str(sol) for sol in sols.selected)
208
180
  check = 'check' in config.selected
209
181
 
210
- self._run_solutions(tracked_solutions, check)
182
+ await self._run_solutions(tracked_solutions, check)
@@ -0,0 +1,5 @@
1
+ from textual.screen import Screen
2
+
3
+
4
+ class RunExplorerScreen(Screen):
5
+ pass
@@ -0,0 +1,100 @@
1
+ from typing import List, Optional
2
+
3
+ from textual.app import ComposeResult
4
+ from textual.containers import Horizontal, Vertical
5
+ from textual.screen import Screen
6
+ from textual.widgets import Footer, Header, Label, ListItem, ListView, RichLog
7
+
8
+ from rbx.box.testcase_extractors import (
9
+ GenerationTestcaseEntry,
10
+ extract_generation_testcases_from_groups,
11
+ )
12
+ from rbx.box.ui.widgets.file_log import FileLog
13
+ from rbx.box.ui.widgets.rich_log_box import RichLogBox
14
+
15
+
16
+ class TestExplorerScreen(Screen):
17
+ BINDINGS = [
18
+ ('q', 'app.pop_screen', 'Quit'),
19
+ ('m', 'toggle_metadata', 'Toggle metadata'),
20
+ ]
21
+
22
+ def __init__(self):
23
+ super().__init__()
24
+ self._entries: List[GenerationTestcaseEntry] = []
25
+
26
+ def compose(self) -> ComposeResult:
27
+ yield Header()
28
+ yield Footer()
29
+ with Horizontal(id='test-explorer'):
30
+ with Vertical(id='test-list-container'):
31
+ yield ListView(id='test-list')
32
+ with Vertical(id='test-details'):
33
+ yield FileLog(id='test-input')
34
+ yield FileLog(id='test-output')
35
+ yield RichLogBox(id='test-metadata')
36
+
37
+ async def on_mount(self):
38
+ self.query_one('#test-list').border_title = 'Tests'
39
+ self.query_one('#test-input').border_title = 'Input'
40
+ self.query_one('#test-output').border_title = 'Output'
41
+
42
+ metadata = self.query_one('#test-metadata', RichLogBox)
43
+ metadata.display = False
44
+ metadata.border_title = 'Metadata'
45
+ metadata.wrap = True
46
+ metadata.markup = True
47
+ metadata.clear().write('No test selected')
48
+ await self._update_tests()
49
+
50
+ def action_toggle_metadata(self):
51
+ metadata = self.query_one('#test-metadata', RichLogBox)
52
+ metadata.display = not metadata.display
53
+
54
+ def _update_selected_test(self, index: Optional[int]):
55
+ input = self.query_one('#test-input', FileLog)
56
+ output = self.query_one('#test-output', FileLog)
57
+ metadata = self.query_one('#test-metadata', RichLog)
58
+
59
+ if index is None:
60
+ input.path = None
61
+ output.path = None
62
+ metadata.clear().write('No test selected')
63
+ return
64
+ entry = self._entries[index]
65
+ input.path = entry.metadata.copied_to.inputPath
66
+ output.path = entry.metadata.copied_to.outputPath
67
+
68
+ metadata.clear()
69
+ metadata.write(
70
+ f'[bold]{entry.group_entry.group}[/bold] / [bold]{entry.group_entry.index}[/bold]'
71
+ )
72
+ if entry.metadata.copied_from is not None:
73
+ metadata.write(
74
+ f'[bold]Copied from:[/bold] {entry.metadata.copied_from.inputPath}'
75
+ )
76
+ if entry.metadata.generator_call is not None:
77
+ metadata.write(f'[bold]Gen. call:[/bold] {entry.metadata.generator_call}')
78
+ if entry.metadata.generator_script is not None:
79
+ metadata.write(
80
+ f'[bold]Gen. script:[/bold] {entry.metadata.generator_script}'
81
+ )
82
+
83
+ async def _update_tests(self):
84
+ self.watch(
85
+ self.query_one('#test-list', ListView),
86
+ 'index',
87
+ self._update_selected_test,
88
+ )
89
+
90
+ self._entries = await extract_generation_testcases_from_groups()
91
+
92
+ test_names = [
93
+ f'{entry.group_entry.group}/{entry.group_entry.index}'
94
+ for entry in self._entries
95
+ ]
96
+
97
+ await self.query_one('#test-list', ListView).clear()
98
+ await self.query_one('#test-list', ListView).extend(
99
+ [ListItem(Label(name)) for name in test_names]
100
+ )
@@ -0,0 +1,63 @@
1
+ import pathlib
2
+ from typing import Optional
3
+
4
+ import aiofiles
5
+ from textual import work
6
+ from textual.app import ComposeResult
7
+ from textual.reactive import reactive
8
+ from textual.widget import Widget
9
+ from textual.widgets import Log
10
+
11
+ BATCH_SIZE = 1024
12
+
13
+
14
+ class FileLog(Widget, can_focus=False):
15
+ DEFAULT_CSS = """
16
+ FileLog {
17
+ border: solid $accent;
18
+ height: 1fr;
19
+ width: 1fr;
20
+ }
21
+ """
22
+
23
+ path: reactive[Optional[pathlib.Path]] = reactive(None)
24
+
25
+ def compose(self) -> ComposeResult:
26
+ yield Log()
27
+
28
+ def on_mount(self):
29
+ self.query_one(Log).auto_scroll = False
30
+ self.query_one(Log).can_focus = False
31
+
32
+ @work(exclusive=True)
33
+ async def _load_file(self, path: pathlib.Path):
34
+ log = self.query_one(Log)
35
+ log.clear()
36
+ path_str = str(path.relative_to(pathlib.Path.cwd()))
37
+ self.border_subtitle = f'{path_str} (loading...)'
38
+
39
+ async with aiofiles.open(path, 'r') as f:
40
+ batch = []
41
+ async for line in f:
42
+ batch.append(line)
43
+ if len(batch) >= BATCH_SIZE:
44
+ log.write(''.join(batch))
45
+ batch = []
46
+
47
+ if batch:
48
+ log.write(''.join(batch))
49
+
50
+ self.border_subtitle = path_str
51
+
52
+ async def watch_path(self, path: Optional[pathlib.Path]):
53
+ log = self.query_one(Log)
54
+ log.clear()
55
+
56
+ if path is None:
57
+ return
58
+
59
+ if not path.is_file():
60
+ self.query_one(Log).write(f'File {path} does not exist')
61
+ return
62
+
63
+ self._load_file(path)
@@ -0,0 +1,5 @@
1
+ from textual.widgets import RichLog
2
+
3
+
4
+ class RichLogBox(RichLog, can_focus=False):
5
+ pass
@@ -322,7 +322,11 @@ class StupidSandbox(SandboxBase):
322
322
  return self.translate_box_exitcode(self.returncode)
323
323
 
324
324
  def translate_box_exitcode(self, exitcode: int) -> bool:
325
- # SIGALRM can be safely ignored, just in case it leaks away.
325
+ # SIGALRM can be safely ignored, just in case it leaks away. SIGTERM also.
326
+ if self.log is None:
327
+ return False
328
+ if 'TE' in self.get_status_list():
329
+ return True
326
330
  return super().translate_box_exitcode(exitcode) or -exitcode == signal.SIGALRM
327
331
 
328
332
  def debug_message(self) -> Any:
@@ -109,7 +109,8 @@ def create_tee(files, mode, buffer_size=4096, prefix=''):
109
109
  else:
110
110
  # Parent -- Return a file object wrapper around the pipe to the
111
111
  # child.
112
- return os.fdopen(pipe_write, 'w', closefd=False)
112
+ # Preserve line buffering (buffering=1).
113
+ return os.fdopen(pipe_write, 'w', buffering=1, closefd=False)
113
114
 
114
115
 
115
116
  def parse_opts() -> Options:
@@ -140,14 +140,20 @@ ECINT=\$?
140
140
 
141
141
  rm -rf fifo.in fifo.out
142
142
 
143
- echo "interactor \$INTPID -> \$ECINT" >&2
144
- echo "solution \$SFPID -> \$ECSF" >&2
145
-
146
- echo "interactor exitcode \$ECINT" >&2
147
- echo "solution exitcode \$ECSF" >&2
143
+ echo "Ran solution as \$@" &>>stderr0
144
+ echo "interactor exitcode \$ECINT" &>>stderr0
145
+ echo "solution exitcode \$ECSF" &>>stderr0
146
+
147
+ RTE=0
148
+ if [[ \$ECSF -eq -13 ]]; then
149
+ RTE=0
150
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
151
+ echo "Found EOF RTE" &>>stderr0
152
+ RTE=1
153
+ fi
148
154
 
149
155
  ret=0
150
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
156
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
151
157
  echo "testlib exitcode \$ECINT" >stdout0
152
158
  ret=0
153
159
  elif [[ \$ECSF -ne 0 ]]; then
@@ -156,6 +162,7 @@ elif [[ \$ECINT -ne 0 ]]; then
156
162
  ret=9
157
163
  fi
158
164
 
165
+ echo "exitting from runit.sh with exit code \$ret" &>>stderr0
159
166
  exit \$ret
160
167
  EOF
161
168
 
@@ -198,8 +205,8 @@ fi
198
205
  ### END OF BOCA RUN COMMAND
199
206
 
200
207
  if [ $ret -gt 10 ]; then
201
- echo "execution error with code $ret" >&2
202
- ret=0
208
+ echo "> > > > > > > Nonzero return code - possible runtime error - I'M GUESSING IT IS RUNTIME ERROR < < < < < < < <"
209
+ ret=9
203
210
  fi
204
211
  if [ -f stdout0 ]; then
205
212
  cat stdout0
@@ -140,14 +140,20 @@ ECINT=\$?
140
140
 
141
141
  rm -rf fifo.in fifo.out
142
142
 
143
- echo "interactor \$INTPID -> \$ECINT" >&2
144
- echo "solution \$SFPID -> \$ECSF" >&2
145
-
146
- echo "interactor exitcode \$ECINT" >&2
147
- echo "solution exitcode \$ECSF" >&2
143
+ echo "Ran solution as \$@" &>>stderr0
144
+ echo "interactor exitcode \$ECINT" &>>stderr0
145
+ echo "solution exitcode \$ECSF" &>>stderr0
146
+
147
+ RTE=0
148
+ if [[ \$ECSF -eq -13 ]]; then
149
+ RTE=0
150
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
151
+ echo "Found EOF RTE" &>>stderr0
152
+ RTE=1
153
+ fi
148
154
 
149
155
  ret=0
150
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
156
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
151
157
  echo "testlib exitcode \$ECINT" >stdout0
152
158
  ret=0
153
159
  elif [[ \$ECSF -ne 0 ]]; then
@@ -156,6 +162,7 @@ elif [[ \$ECINT -ne 0 ]]; then
156
162
  ret=9
157
163
  fi
158
164
 
165
+ echo "exitting from runit.sh with exit code \$ret" &>>stderr0
159
166
  exit \$ret
160
167
  EOF
161
168
 
@@ -198,8 +205,8 @@ fi
198
205
  ### END OF BOCA RUN COMMAND
199
206
 
200
207
  if [ $ret -gt 10 ]; then
201
- echo "execution error with code $ret" >&2
202
- ret=0
208
+ echo "> > > > > > > Nonzero return code - possible runtime error - I'M GUESSING IT IS RUNTIME ERROR < < < < < < < <"
209
+ ret=9
203
210
  fi
204
211
  if [ -f stdout0 ]; then
205
212
  cat stdout0
@@ -140,14 +140,19 @@ ECINT=\$?
140
140
 
141
141
  rm -rf fifo.in fifo.out
142
142
 
143
- echo "interactor \$INTPID -> \$ECINT" >&2
144
- echo "solution \$SFPID -> \$ECSF" >&2
145
-
146
- echo "interactor exitcode \$ECINT" >&2
147
- echo "solution exitcode \$ECSF" >&2
148
-
143
+ echo "Ran solution as \$@" &>>stderr0
144
+ echo "interactor exitcode \$ECINT" &>>stderr0
145
+ echo "solution exitcode \$ECSF" &>>stderr0
146
+
147
+ RTE=0
148
+ if [[ \$ECSF -eq -13 ]]; then
149
+ RTE=0
150
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
151
+ echo "Found EOF RTE" &>>stderr0
152
+ RTE=1
153
+ fi
149
154
  ret=0
150
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
155
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
151
156
  echo "testlib exitcode \$ECINT" >stdout0
152
157
  ret=0
153
158
  elif [[ \$ECSF -ne 0 ]]; then
@@ -156,6 +161,7 @@ elif [[ \$ECINT -ne 0 ]]; then
156
161
  ret=9
157
162
  fi
158
163
 
164
+ echo "exitting from runit.sh with exit code \$ret" &>>stderr0
159
165
  exit \$ret
160
166
  EOF
161
167
 
@@ -198,8 +204,8 @@ fi
198
204
  ### END OF BOCA RUN COMMAND
199
205
 
200
206
  if [ $ret -gt 10 ]; then
201
- echo "execution error with code $ret" >&2
202
- ret=0
207
+ echo "> > > > > > > Nonzero return code - possible runtime error - I'M GUESSING IT IS RUNTIME ERROR < < < < < < < <"
208
+ ret=9
203
209
  fi
204
210
  if [ -f stdout0 ]; then
205
211
  cat stdout0
@@ -153,14 +153,20 @@ ECINT=\$?
153
153
 
154
154
  rm -rf fifo.in fifo.out
155
155
 
156
- echo "interactor \$INTPID -> \$ECINT" >&2
157
- echo "solution \$SFPID -> \$ECSF" >&2
156
+ echo "Ran solution as \$@" &>>stderr0
157
+ echo "interactor exitcode \$ECINT" &>>stderr0
158
+ echo "solution exitcode \$ECSF" &>>stderr0
158
159
 
159
- echo "interactor exitcode \$ECINT" >&2
160
- echo "solution exitcode \$ECSF" >&2
160
+ RTE=0
161
+ if [[ \$ECSF -eq -13 ]]; then
162
+ RTE=0
163
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
164
+ echo "Found EOF RTE" &>>stderr0
165
+ RTE=1
166
+ fi
161
167
 
162
168
  ret=0
163
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
169
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
164
170
  echo "testlib exitcode \$ECINT" >stdout0
165
171
  ret=0
166
172
  elif [[ \$ECSF -ne 0 ]]; then
@@ -169,6 +175,7 @@ elif [[ \$ECINT -ne 0 ]]; then
169
175
  ret=9
170
176
  fi
171
177
 
178
+ echo "exitting from runit.sh with exit code \$ret" &>>stderr0
172
179
  exit \$ret
173
180
  EOF
174
181
 
@@ -144,14 +144,20 @@ ECINT=\$?
144
144
 
145
145
  rm -rf fifo.in fifo.out
146
146
 
147
- echo "interactor \$INTPID -> \$ECINT" >&2
148
- echo "solution \$SFPID -> \$ECSF" >&2
147
+ echo "Ran solution as \$@" &>>stderr0
148
+ echo "interactor exitcode \$ECINT" &>>stderr0
149
+ echo "solution exitcode \$ECSF" &>>stderr0
149
150
 
150
- echo "interactor exitcode \$ECINT" >&2
151
- echo "solution exitcode \$ECSF" >&2
151
+ RTE=0
152
+ if [[ \$ECSF -eq -13 ]]; then
153
+ RTE=0
154
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
155
+ echo "Found EOF RTE" &>>stderr0
156
+ RTE=1
157
+ fi
152
158
 
153
159
  ret=0
154
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
160
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
155
161
  echo "testlib exitcode \$ECINT" >stdout0
156
162
  ret=0
157
163
  elif [[ \$ECSF -ne 0 ]]; then
@@ -160,6 +166,7 @@ elif [[ \$ECINT -ne 0 ]]; then
160
166
  ret=9
161
167
  fi
162
168
 
169
+ echo "exitting from runit.sh with exit code \$ret" &>>stderr0
163
170
  exit \$ret
164
171
  EOF
165
172
 
@@ -131,14 +131,20 @@ ECINT=\$?
131
131
 
132
132
  rm -rf fifo.in fifo.out
133
133
 
134
- echo "interactor \$INTPID -> \$ECINT" >&2
135
- echo "solution \$SFPID -> \$ECSF" >&2
136
-
137
- echo "interactor exitcode \$ECINT" >&2
138
- echo "solution exitcode \$ECSF" >&2
134
+ echo "Ran solution as \$@" &>>stderr0
135
+ echo "interactor exitcode \$ECINT" &>>stderr0
136
+ echo "solution exitcode \$ECSF" &>>stderr0
137
+
138
+ RTE=0
139
+ if [[ \$ECSF -eq -13 ]]; then
140
+ RTE=0
141
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
142
+ echo "Found EOF RTE" &>>stderr0
143
+ RTE=1
144
+ fi
139
145
 
140
146
  ret=0
141
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
147
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
142
148
  echo "testlib exitcode \$ECINT" >stdout0
143
149
  ret=0
144
150
  elif [[ \$ECSF -ne 0 ]]; then
@@ -147,6 +153,7 @@ elif [[ \$ECINT -ne 0 ]]; then
147
153
  ret=9
148
154
  fi
149
155
 
156
+ echo "exitting from runit.sh with exit code \$ret" &>>stderr0
150
157
  exit \$ret
151
158
  EOF
152
159
 
@@ -200,8 +207,8 @@ fi
200
207
  ### END OF BOCA RUN COMMAND
201
208
 
202
209
  if [ $ret -gt 10 ]; then
203
- echo "execution error with code $ret" >&2
204
- ret=0
210
+ echo "> > > > > > > Nonzero return code - possible runtime error - I'M GUESSING IT IS RUNTIME ERROR < < < < < < < <"
211
+ ret=9
205
212
  fi
206
213
  if [ -f stdout0 ]; then
207
214
  cat stdout0
@@ -115,8 +115,6 @@ cat <<EOF >runit.sh
115
115
  #!/bin/bash
116
116
  mkfifo fifo.in fifo.out
117
117
 
118
- echo "Running solution as \$@" >&2
119
-
120
118
  "\$@" >fifo.out <fifo.in 2>/dev/null &
121
119
  SFPID=\$!
122
120
 
@@ -131,14 +129,20 @@ ECINT=\$?
131
129
 
132
130
  rm -rf fifo.in fifo.out
133
131
 
134
- echo "interactor \$INTPID -> \$ECINT" >&2
135
- echo "solution \$SFPID -> \$ECSF" >&2
132
+ echo "Ran solution as \$@" &>>stderr0
133
+ echo "interactor exitcode \$ECINT" &>>stderr0
134
+ echo "solution exitcode \$ECSF" &>>stderr0
136
135
 
137
- echo "interactor exitcode \$ECINT" >&2
138
- echo "solution exitcode \$ECSF" >&2
136
+ RTE=0
137
+ if [[ \$ECSF -eq -13 ]]; then
138
+ RTE=0
139
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
140
+ echo "Found EOF RTE" &>>stderr0
141
+ RTE=1
142
+ fi
139
143
 
140
144
  ret=0
141
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
145
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
142
146
  echo "testlib exitcode \$ECINT" >stdout0
143
147
  ret=0
144
148
  elif [[ \$ECSF -ne 0 ]]; then
@@ -147,6 +151,7 @@ elif [[ \$ECINT -ne 0 ]]; then
147
151
  ret=9
148
152
  fi
149
153
 
154
+ echo "exitting from runit.sh with exit code \$ret" &>>stderr0
150
155
  exit \$ret
151
156
  EOF
152
157
 
@@ -200,8 +205,8 @@ fi
200
205
  ### END OF BOCA RUN COMMAND
201
206
 
202
207
  if [ $ret -gt 10 ]; then
203
- echo "execution error with code $ret" >&2
204
- ret=0
208
+ echo "> > > > > > > Nonzero return code - possible runtime error - I'M GUESSING IT IS RUNTIME ERROR < < < < < < < <"
209
+ ret=9
205
210
  fi
206
211
  if [ -f stdout0 ]; then
207
212
  cat stdout0
@@ -120,7 +120,8 @@ echo "Current directory is $cdir -- chrooting on it" >&2
120
120
  "$sf" -F10 -f$maxf -r$nruns -n1 -R$cdir -C. -U$bocau -G$bocag -ostdout0 -estderr0 -d$maxm -m$maxm -t$time -T$ttime -istdin0 ./run.exe
121
121
  ret=$?
122
122
  if [ $ret -gt 10 ]; then
123
- ret=0
123
+ echo "> > > > > > > Nonzero return code - possible runtime error - I'M GUESSING IT IS RUNTIME ERROR < < < < < < < <"
124
+ ret=9
124
125
  fi
125
126
  if [ -f stdout0 ]; then
126
127
  cat stdout0
@@ -120,7 +120,8 @@ echo "Current directory is $cdir -- chrooting on it" >&2
120
120
  "$sf" -F10 -f$maxf -r$nruns -n1 -R$cdir -C. -U$bocau -G$bocag -ostdout0 -estderr0 -d$maxm -m$maxm -t$time -T$ttime -istdin0 ./run.exe
121
121
  ret=$?
122
122
  if [ $ret -gt 10 ]; then
123
- ret=0
123
+ echo "> > > > > > > Nonzero return code - possible runtime error - I'M GUESSING IT IS RUNTIME ERROR < < < < < < < <"
124
+ ret=9
124
125
  fi
125
126
  if [ -f stdout0 ]; then
126
127
  cat stdout0