-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmake.sh
135 lines (111 loc) · 4.61 KB
/
make.sh
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
#!/bin/bash
# `${1%.cpp}` extracts the file name (including path) by removing the `.cpp` suffix.
filename="${1%.cpp}"
# Definitions for colors
BLUE="\033[34m"
RED="\033[31m"
RESET="\033[0m"
# @brief: Outputs the provided string in blue.
# `\033[34m` sets the color to blue.
# `\033[0m` resets the text color to default.
blueOutput() {
echo -e "${BLUE}${1}${RESET}"
}
# @brief: Outputs the provided string in red.
# `\033[31m` sets the color to red.
# `\033[0m` resets the text color to default.
redOutput() {
echo -e "${RED}${1}${RESET}"
}
# @brief: Reads the default test case as `stdin` and redirects `stdout` to `${filename}.ans`.
# If `${filename}.in` exists, prompts the user to use it as the test case.
# The program output is saved to `${filename}.ans`.
tryUsingDefaultTestcase() {
if [[ -r ${filename}.in ]]; then # Checks if `${filename}.in` exists and is readable.
echo ""
blueOutput "[Info]:${RESET} Test case ${filename}.in detected."
echo "------> Use this test case as stdin? [Y/n]"
read -r operation
if [[ "$operation" != [Nn]* ]]; then # Proceed if the user input is not "N" or "n".
blueOutput "[Info]:${RESET} Using ${filename}.in as the test case."
"./${filename}.out" < "${filename}.in" > "${filename}.ans" # Executes the program with input redirection.
blueOutput "[Info]:${RESET} Output is shown below and saved as ${filename}.ans.\n"
cat "${filename}.ans"
blueOutput "\n[Hint]:${RESET} You can use \"diff ${filename}.ans <Standard Answer>\" to compare with the expected output."
fi
fi
}
# @brief: Removes old files if they exist.
# Deletes `${filename}.out`, `${filename}.ans`, and `${filename}.log`.
initCleanup() {
# Remove the old `${filename}.out` if it exists.
if [[ -f "${filename}.out" ]]; then
rm "${filename}.out"
fi
# Remove the old `${filename}.ans` if it exists.
if [[ -f "${filename}.ans" ]]; then
rm "${filename}.ans"
fi
# Remove the old `${filename}.log` if it exists.
if [[ -f "${filename}.log" ]]; then
rm "${filename}.log"
fi
}
# @brief: Removes empty files if they exist.
# Specifically checks `${filename}.ans` and `${filename}.log`.
cleanupEmptyFiles() {
# Check if the `.ans` file exists and is empty.
if [[ -f "${filename}.ans" && ! -s "${filename}.ans" ]]; then
rm "${filename}.ans"
fi
# Check if the `.log` file exists and is empty.
if [[ -f "${filename}.log" && ! -s "${filename}.log" ]]; then
rm "${filename}.log"
fi
}
# ---------- Function definitions complete ----------
initCleanup
# @brief: New a pipe named fake_tty
# `/dev/tty` is OK for most of the users. However, GitHub Actions doesn't have it.
# It will raise an error: `tee: /dev/tty: No such device or address`
# Given that, we should `tee` outputs to fake_tty, and `cat fake_tty` after
# compilation.
# Don't forget to `rm fake_tty` at last.
if [[ -e fake_tty ]]; then rm fake_tty; fi
mkfifo fake_tty
chmod +x fake_tty
# @brief: Compiles `${filename}.cpp` using `g++` with detailed warnings and debugging flags.
# --std=c++14 is the require of CCF - China Cheating-money Foundation
# c++14 for CSP-J/S, NOIp and NOI, etc.
# Outputs compilation details to the terminal and logs plain text to `${filename}.log`.
# If successful, the output executable is named `${filename}.out`.
g++ -g -Wall -Wextra -pedantic --std=c++14 -Og \
-Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wshift-overflow=2 \
-Wduplicated-cond -Wcast-qual -Wcast-align -Wnoexcept -Winline -Wdouble-promotion \
-fsanitize=undefined -fsanitize=address -fanalyzer \
-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC \
-fdiagnostics-color=always \
"$1" -o "${filename}.out" 2>&1 \
| tee fake_tty &
# @brief: Output `fake_tty` after compilation.
# The origin compile command was `tee /dev/tty` directly, it didn't work on
# GitHub Actions.
# We introduced `fake_tty` to resolve it.
# `wait` is because `tee fake_tty &` is asynchronous.
# Now it's time to output and clean it up.
#
# By the way, I hate the computer of GitHub Actions. It doesn't have `/dev/tty`.
./fake_tty >(sed "s/\x1B\[[0-9;]*[a-zA-Z]//g" > "${filename}.log")
wait
rm fake_tty
# Check if the output file was successfully created and is executable.
if [[ -x "${filename}.out" ]]; then
blueOutput "[Info]:${RESET} Compilation of $1 succeeded."
blueOutput "[Info]:${RESET} Executable file: ${filename}.out"
tryUsingDefaultTestcase
else
redOutput "[Error]: Compilation failed.\a"
blueOutput "[Info]:${RESET} Check '${filename}.log' for details."
fi
cleanupEmptyFiles
exit