-
Notifications
You must be signed in to change notification settings - Fork 1
391 lines (335 loc) · 14.6 KB
/
code-execution.yml
File metadata and controls
391 lines (335 loc) · 14.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
name: ACC-IDE Code Judge
on:
workflow_dispatch:
inputs:
# 从App接收要评测的代码
source_code:
description: 'The source code to be judged'
required: true
# 从App接收标准输入
std_input:
description: 'Standard input for the code'
required: false
default: ''
# 从App接收预期输出
expected_output:
description: 'Expected output for comparison'
required: false
default: ''
# App传来的语言类型,用于选择编译器
language:
description: 'The programming language (cpp, python, java)'
required: true
default: 'cpp'
jobs:
build-and-run:
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- name: Checkout repository
uses: actions/checkout@v4
# 根据语言,将接收到的代码和输入写入文件
- name: Prepare execution files
run: |
set +e
mkdir -p results || true
export LC_ALL=C.UTF-8 || true
export LANG=C.UTF-8 || true
echo -e "${{ github.event.inputs.std_input }}" > input.txt || true
echo -e "${{ github.event.inputs.expected_output }}" > expected.txt || true
if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then
echo "EXPECTED_EMPTY=true" >> $GITHUB_ENV || true
echo "预期输出为空,设置 EXPECTED_EMPTY=true" || true
else
echo "EXPECTED_EMPTY=false" >> $GITHUB_ENV || true
echo "预期输出不为空,设置 EXPECTED_EMPTY=false" || true
fi
echo "=== Expected Output Content ===" || true
cat expected.txt || true
echo "===============================" || true
if [ "${{ github.event.inputs.language }}" = "java" ]; then
SOURCE_FILE="Main.java"
elif [ "${{ github.event.inputs.language }}" = "python" ] || [ "${{ github.event.inputs.language }}" = "py" ]; then
SOURCE_FILE="main.py"
else
SOURCE_FILE="main.${{ github.event.inputs.language }}"
fi
# 使用 base64 解码确保源代码中的空格和特殊字符被正确保留
# 首先将源代码写入临时文件,然后检查并确保文件格式正确
echo "${{ github.event.inputs.source_code }}" > source_code_temp.txt || true
echo "=== Source Code (Before Processing) ===" || true
cat source_code_temp.txt || true
echo "=====================================" || true
# 修复可能的空格问题,将连续的 << 后面的空格保留
sed -i 's/<< *;/<< " ";/g' source_code_temp.txt || true
sed -i 's/<< *)/<< " ")/g' source_code_temp.txt || true
sed -i 's/<< *,/<< " ",/g' source_code_temp.txt || true
sed -i 's/<< *$/<< " "/g' source_code_temp.txt || true
sed -i 's/<< *\]/<< " "]/g' source_code_temp.txt || true
sed -i 's/<< *}/<< " "}/g' source_code_temp.txt || true
sed -i 's/<< *>/<< " ">/g' source_code_temp.txt || true
# 处理 >> 运算符周围的空格
sed -i 's/>> *;/>> " ";/g' source_code_temp.txt || true
sed -i 's/>> *)/>> " ")/g' source_code_temp.txt || true
sed -i 's/>> *,/>> " ",/g' source_code_temp.txt || true
sed -i 's/>> *$/>> " "/g' source_code_temp.txt || true
sed -i 's/>> *\]/>> " "]/g' source_code_temp.txt || true
sed -i 's/>> *}/>> " "}/g' source_code_temp.txt || true
sed -i 's/>> *>/>> " ">/g' source_code_temp.txt || true
# 修复Python语法错误:__main__ 需要引号
sed -i 's/__main__:/"__main__":/g' source_code_temp.txt || true
echo "=== Source Code (After Processing) ===" || true
cat source_code_temp.txt || true
echo "====================================" || true
cat source_code_temp.txt > $SOURCE_FILE || true
# 确保源代码文件是 UTF-8 编码
echo "=== Converting to UTF-8 ===" || true
iconv -f ISO-8859-1 -t UTF-8 $SOURCE_FILE -o $SOURCE_FILE.utf8 || true
mv $SOURCE_FILE.utf8 $SOURCE_FILE || true
echo "=========================" || true
echo "SOURCE_FILE=$SOURCE_FILE" >> $GITHUB_ENV || true
echo "=== Final Source Code ===" || true
cat $SOURCE_FILE || true
echo "========================" || true
echo "=== File Encoding ===" || true
file -i $SOURCE_FILE || true
echo "====================" || true
- name: Compile C++ Code
if: github.event.inputs.language == 'cpp'
id: compile_cpp
run: |
set +e
g++ --version || true
mkdir -p ./results || true
g++ main.cpp -o main_exec -O2 -std=c++17 -Wall -Wextra -fdiagnostics-color=always > ./results/compile.log 2>&1
COMPILE_RESULT=$?
echo "=== Compilation Log ===" || true
cat ./results/compile.log || true
echo "=======================" || true
if [ $COMPILE_RESULT -ne 0 ]; then
echo "Compilation failed with exit code: $COMPILE_RESULT" || true
echo '{"status": "CE", "message": "Compilation Error", "execution_time": 0}' > ./results/result.json || true
echo "JUDGE_STATUS=CE" >> $GITHUB_ENV || true
else
echo "Compilation successful" || true
fi
- name: Run and Judge C++ Code
if: success() && env.JUDGE_STATUS != 'CE' && github.event.inputs.language == 'cpp'
run: |
set +e
# 检查预期输出是否为空
if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then
EXPECTED_EMPTY=true
else
EXPECTED_EMPTY=false
fi
# 计时脚本
cat > time_wrapper.sh << 'EOF'
#!/bin/bash
start_time=$(date +%s%N)
"$@"
exit_code=$?
end_time=$(date +%s%N)
execution_time=$((($end_time - $start_time) / 1000000))
echo $execution_time > execution_time.txt
exit $exit_code
EOF
chmod +x time_wrapper.sh
# TLE: 2 seconds, MLE: 256 MB
timeout 2s ./time_wrapper.sh ./main_exec < input.txt > ./results/actual.txt 2> ./results/stderr.log || true
EXIT_CODE=$?
# 获取执行时间
EXECUTION_TIME=0
if [ -f execution_time.txt ]; then
EXECUTION_TIME=$(cat execution_time.txt)
fi
if [ $EXIT_CODE -eq 124 ]; then
STATUS="TLE"
MESSAGE="Time Limit Exceeded"
elif [ $EXIT_CODE -ne 0 ]; then
STATUS="RE"
MESSAGE="Runtime Error (Exit Code: $EXIT_CODE)"
else
# 检查预期是否为空,空则"RS"(Run Successful)
if [ "$EXPECTED_EMPTY" = "true" ]; then
STATUS="RS"
MESSAGE="Run Successful"
else
# 使用 diff 命令比较输出。
# -i 忽略大小写, -w 忽略所有空格, -B 忽略空行
diff -i -w -B ./results/actual.txt expected.txt > /dev/null
DIFF_RESULT=$?
if [ $DIFF_RESULT -ne 0 ]; then
STATUS="WA"
MESSAGE="Wrong Answer"
echo "=== Expected Output ===" > ./results/diff.txt
cat expected.txt >> ./results/diff.txt
echo -e "\n=== Actual Output ===" >> ./results/diff.txt
cat ./results/actual.txt >> ./results/diff.txt
else
STATUS="AC"
MESSAGE="Accepted"
fi
fi
fi
echo "{\"status\": \"$STATUS\", \"message\": \"$MESSAGE\", \"execution_time\": $EXECUTION_TIME}" > ./results/result.json
# 输出调试信息
echo "=== DEBUG INFO (C++) ===" || true
echo "Input:" || true
cat input.txt || true
echo -e "\nExpected Output:" || true
cat expected.txt || true
echo -e "\nActual Output:" || true
cat ./results/actual.txt || true
echo -e "\nStatus: $STATUS (EXPECTED_EMPTY=$EXPECTED_EMPTY)" || true
echo "===========================" || true
- name: Run Python Code
if: github.event.inputs.language == 'python' || github.event.inputs.language == 'py'
run: |
set +e
mkdir -p ./results || true
if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then
EXPECTED_EMPTY=true
else
EXPECTED_EMPTY=false
fi
cat > time_wrapper.sh << 'EOF'
#!/bin/bash
start_time=$(date +%s%N)
"$@"
exit_code=$?
end_time=$(date +%s%N)
execution_time=$((($end_time - $start_time) / 1000000))
echo $execution_time > execution_time.txt
exit $exit_code
EOF
chmod +x time_wrapper.sh
timeout 2s ./time_wrapper.sh python3 main.py < input.txt > ./results/actual.txt 2> ./results/stderr.log || true
EXIT_CODE=$?
EXECUTION_TIME=0
if [ -f execution_time.txt ]; then
EXECUTION_TIME=$(cat execution_time.txt)
fi
if [ $EXIT_CODE -eq 124 ]; then
STATUS="TLE"
MESSAGE="Time Limit Exceeded"
elif [ $EXIT_CODE -ne 0 ]; then
STATUS="RE"
MESSAGE="Runtime Error (Exit Code: $EXIT_CODE)"
else
if [ "$EXPECTED_EMPTY" = "true" ]; then
STATUS="RS"
MESSAGE="Run Successful"
else
diff -i -w -B ./results/actual.txt expected.txt > /dev/null
DIFF_RESULT=$?
if [ $DIFF_RESULT -ne 0 ]; then
STATUS="WA"
MESSAGE="Wrong Answer"
echo "=== Expected Output ===" > ./results/diff.txt
cat expected.txt >> ./results/diff.txt
echo -e "\n=== Actual Output ===" >> ./results/diff.txt
cat ./results/actual.txt >> ./results/diff.txt
else
STATUS="AC"
MESSAGE="Accepted"
fi
fi
fi
echo "{\"status\": \"$STATUS\", \"message\": \"$MESSAGE\", \"execution_time\": $EXECUTION_TIME}" > ./results/result.json
echo "=== DEBUG INFO (Python) ===" || true
echo "Input:" || true
cat input.txt || true
echo -e "\nExpected Output:" || true
cat expected.txt || true
echo -e "\nActual Output:" || true
cat ./results/actual.txt || true
echo -e "\nStatus: $STATUS (EXPECTED_EMPTY=$EXPECTED_EMPTY)" || true
echo "===========================" || true
- name: Compile Java Code
if: github.event.inputs.language == 'java'
id: compile_java
run: |
set +e
javac Main.java -d . &> ./results/compile.log || true
COMPILE_RESULT=$?
echo "=== Compilation Log ===" || true
cat ./results/compile.log || true
echo "=======================" || true
if [ $COMPILE_RESULT -ne 0 ]; then
echo "Compilation failed with exit code: $COMPILE_RESULT" || true
echo '{"status": "CE", "message": "Compilation Error", "execution_time": 0}' > ./results/result.json || true
echo "JUDGE_STATUS=CE" >> $GITHUB_ENV || true
else
echo "Compilation successful" || true
fi
- name: Run Java Code
if: success() && env.JUDGE_STATUS != 'CE' && github.event.inputs.language == 'java'
run: |
set +e
if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then
EXPECTED_EMPTY=true
else
EXPECTED_EMPTY=false
fi
cat > time_wrapper.sh << 'EOF'
#!/bin/bash
start_time=$(date +%s%N)
"$@"
exit_code=$?
end_time=$(date +%s%N)
execution_time=$((($end_time - $start_time) / 1000000))
echo $execution_time > execution_time.txt
exit $exit_code
EOF
chmod +x time_wrapper.sh
timeout 2s ./time_wrapper.sh java Main < input.txt > ./results/actual.txt 2> ./results/stderr.log || true
EXIT_CODE=$?
EXECUTION_TIME=0
if [ -f execution_time.txt ]; then
EXECUTION_TIME=$(cat execution_time.txt)
fi
if [ $EXIT_CODE -eq 124 ]; then
STATUS="TLE"
MESSAGE="Time Limit Exceeded"
elif [ $EXIT_CODE -ne 0 ]; then
STATUS="RE"
MESSAGE="Runtime Error (Exit Code: $EXIT_CODE)"
else
if [ "$EXPECTED_EMPTY" = "true" ]; then
STATUS="RS"
MESSAGE="Run Successful"
else
diff -i -w -B ./results/actual.txt expected.txt > /dev/null
DIFF_RESULT=$?
if [ $DIFF_RESULT -ne 0 ]; then
STATUS="WA"
MESSAGE="Wrong Answer"
echo "=== Expected Output ===" > ./results/diff.txt
cat expected.txt >> ./results/diff.txt
echo -e "\n=== Actual Output ===" >> ./results/diff.txt
cat ./results/actual.txt >> ./results/diff.txt
else
STATUS="AC"
MESSAGE="Accepted"
fi
fi
fi
echo "{\"status\": \"$STATUS\", \"message\": \"$MESSAGE\", \"execution_time\": $EXECUTION_TIME}" > ./results/result.json
echo "=== DEBUG INFO (Java) ===" || true
echo "Input:" || true
cat input.txt || true
echo -e "\nExpected Output:" || true
cat expected.txt || true
echo -e "\nActual Output:" || true
cat ./results/actual.txt || true
echo -e "\nStatus: $STATUS (EXPECTED_EMPTY=$EXPECTED_EMPTY)" || true
echo "===========================" || true
# 上传结果文件
- name: Upload judgment result
uses: actions/upload-artifact@v4
continue-on-error: true
with:
name: judge-result
path: ./results/
if-no-files-found: warn