forked from cs50/sandbox
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cs50.sh
388 lines (353 loc) · 11.4 KB
/
cs50.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
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
#!/bin/bash
set -eo pipefail
# Install Python 3.7
# https://www.python.org/downloads/
# https://stackoverflow.com/a/44758621/5156190
apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential \
libbz2-dev \
libc6-dev \
libffi-dev `# For ctypes module` \
libgdbm-dev \
libncursesw5-dev \
libreadline-gplv2-dev \
libsqlite3-dev \
libssl-dev \
tk-dev \
wget \
zlib1g-dev && \
cd /tmp && \
wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tgz && \
tar xzf Python-3.7.6.tgz && \
rm -f Python-3.7.6.tgz && \
cd Python-3.7.6 && \
./configure && \
make && \
make install && \
cd .. && \
rm -rf Python-3.7.6 && \
pip3 install --upgrade pip
# Ubuntu-specific
apt-get update && \
apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
apt-file \
apt-transport-https \
apt-utils \
bash-completion \
bc \
bsdtar \
build-essential \
clang-8 \
cmake \
composer \
curl \
dnsutils \
dos2unix \
erlang \
exiftool \
expect `# For unbuffer` \
gdb \
gettext \
git \
golang \
haskell-platform \
imagemagick \
info \
libjpeg8-dev `For Pillow` \
lua5.3 \
luarocks \
man \
mysql-client \
nano \
ocaml \
octave \
perl \
php7.2-cli \
php7.2-curl \
php7.2-gmp \
php7.2-intl \
rpm \
ruby \
ruby-dev `# Avoid "can't find header files for ruby" for gem` \
s3cmd \
sqlite3 \
swi-prolog \
telnet \
tk-dev \
tree \
unzip \
valgrind \
vim \
zip
# Git-specific
# https://packagecloud.io/github/git-lfs/install
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash -e && \
DEBIAN_FRONTEND=noninteractive apt-get install -y git-lfs
# Install Java 13
# http://jdk.java.net/13/
cd /tmp && \
wget https://download.java.net/java/GA/jdk13.0.1/cec27d702aa74d5a8630c65ae61e4305/9/GPL/openjdk-13.0.1_linux-x64_bin.tar.gz && \
tar xzf openjdk-13.0.1_linux-x64_bin.tar.gz && \
rm -f openjdk-13.0.1_linux-x64_bin.tar.gz && \
mv jdk-13.0.1 /opt/ && \
mkdir -p /opt/bin && \
ln -s /opt/jdk-13.0.1/bin/* /opt/bin/ && \
chmod a+rx /opt/bin/*
# Lua-specific
# https://askubuntu.com/a/1035151
update-alternatives --install /usr/bin/lua lua-interpreter /usr/bin/lua5.3 130 --slave /usr/share/man/man1/lua.1.gz lua-manual /usr/share/man/man1/lua5.3.1.gz
update-alternatives --install /usr/bin/luac lua-compiler /usr/bin/luac5.3 130 --slave /usr/share/man/man1/luac.1.gz lua-compiler-manual /usr/share/man/man1/luac5.3.1.gz
# LÖVE-specific
# https://bitbucket.org/rude/love/downloads/
wget -P /tmp https://bitbucket.org/rude/love/downloads/love_0.10.2ppa1_amd64.deb && \
wget -P /tmp https://bitbucket.org/rude/love/downloads/liblove0_0.10.2ppa1_amd64.deb && \
(dpkg -i /tmp/love_0.10.2ppa1_amd64.deb /tmp/liblove0_0.10.2ppa1_amd64.deb || true) && \
DEBIAN_FRONTEND=noninteractive apt-get -f install -y && \
rm -f /tmp/love_0.10.2ppa1_amd64.deb /tmp/liblove0_0.10.2ppa1_amd64.deb
# Install Node.js 13.x
# https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions-enterprise-linux-fedora-and-snap-packages
# https://github.com/nodesource/distributions/blob/master/README.md#debinstall
curl -sL https://deb.nodesource.com/setup_13.x | bash - && \
DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs && \
npm install -g npm `# Upgrades npm to latest` && \
npm install -g grunt http-server nodemon
# Install Swift 5.1
cd /tmp && \
wget https://swift.org/builds/swift-5.1.3-release/ubuntu1804/swift-5.1.3-RELEASE/swift-5.1.3-RELEASE-ubuntu18.04.tar.gz && \
tar xzf swift-5.1.3-RELEASE-ubuntu18.04.tar.gz --strip-components=1 -C / && \
rm -f swift-5.1.3-RELEASE-ubuntu18.04.tar.gz && \
apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y libpython2.7
# Install CS50 packages
pip3 install \
check50 \
cs50 \
Flask \
Flask-Session \
style50 \
submit50
pip3 install \
awscli \
compare50 \
help50 \
matplotlib \
numpy \
pandas \
render50 \
submit50 \
virtualenv
# Install Heroku CLI
curl https://cli-assets.heroku.com/install.sh | sh
# Install fpm, asciidoctor
# https://github.com/asciidoctor/jekyll-asciidoc/issues/135#issuecomment-241948040
# https://github.com/asciidoctor/jekyll-asciidoc#development
gem install \
asciidoctor \
bundler \
fpm \
github-pages \
jekyll \
jekyll-asciidoc \
pygments.rb
# R-specific
# https://www.rstudio.com/products/rstudio/download-server/
mkdir -p /root/sandbox
echo "deb https://cloud.r-project.org/bin/linux/ubuntu bionic-cran35/" > /etc/apt/sources.list.d/cran.list && \
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9
apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y r-base && \
DEBIAN_FRONTEND=noninteractive apt-get install -y gdebi-core && \
wget -P /tmp https://download2.rstudio.org/rstudio-server-1.1.456-amd64.deb && \
DEBIAN_FRONTEND=noninteractive gdebi --non-interactive /tmp/rstudio-server-1.1.456-amd64.deb && \
rm -f /tmp/rstudio-server-1.1.456-amd64.deb && \
echo "server-app-armor-enabled=0" >> /etc/rstudio/rserver.conf && \
echo "www-frame-origin=any" >> /etc/rstudio/rserver.conf && \
echo "session-timeout-minutes=1" >> /etc/rstudio/rsession.conf
cat <<'EOF' > /etc/rstudio/login.html
<script>
window.onload = function() {
document.getElementById('username').value = 'ubuntu';
document.getElementById('password').value = 'crimson';
var p = document.querySelectorAll('#border p');
for (var i = 0; i < p.length; i++) {
p[i].style.display = 'none';
}
}
</script>
EOF
# CS50-specific
curl -s https://packagecloud.io/install/repositories/cs50/repo/script.deb.sh | bash -e && \
DEBIAN_FRONTEND=noninteractive apt-get install -y astyle libcs50 libcs50-java php-cs50
# Configure clang 8 last, else 7 takes priority
(update-alternatives --remove-all clang || true) && \
update-alternatives --install /usr/bin/clang clang $(which clang-8) 1
# Bash-specific
mkdir -p /root/.bashrcs
cat <<'EOF' > /root/.bashrcs/~cs50.sh
# File mode creation mask
if [ "$(id -u)" != "0" ]; then
umask 0077
fi
# PATH
export PATH=/opt/cs50/bin:"$HOME"/.local/bin:/opt/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Interactive shells
if [ "$PS1" ]; then
# Simplify prompt
export PS1='$ '
# Override HOME for cd if ~/sandbox exists
cd()
{
if [ -d "$HOME"/sandbox ]; then
HOME=~/sandbox command cd "$@"
else
command cd "$@"
fi
}
# Aliases
alias cp="cp -i"
alias gdb="gdb -q"
alias ls="ls --color=auto -F"
alias ll="ls -F -l"
alias mv="mv -i"
alias pip="pip3 --no-cache-dir"
alias pip3="pip3 --no-cache-dir"
alias python="python3"
alias rm="rm -i"
alias swift="swift 2> /dev/null" # https://github.com/cs50/sandbox/issues/26
# Environment variables
export CC="clang"
export CFLAGS="-fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow"
export CLASSPATH=".:/usr/share/java/cs50.jar"
export EDITOR=nano
export FLASK_APP=application.py
export FLASK_ENV=development
export LANG=C
export LANGUAGE=C.UTF-8
export LC_ALL=C.UTF-8
export LDLIBS="-lcrypt -lcs50 -lm"
export JAVA_HOME="/opt/jdk-12"
export PYTHONDONTWRITEBYTECODE="1"
export VALGRIND_OPTS="--memcheck:leak-check=full --memcheck:show-leak-kinds=all --memcheck:track-origins=yes"
# History
# https://www.shellhacks.com/tune-command-line-history-bash/
shopt -s histappend # Append Bash Commands to History File
export PROMPT_COMMAND='history -a' # Store Bash History Immediately
shopt -s cmdhist # Use one command per line
if [ "$(id -u)" == "0" ]; then
export HISTFILE=~/sandbox/.bash_history # Change the History File Name
fi
# make
make () {
local args=""
local invalid_args=0
for arg; do
case "$arg" in
(*.c) arg=${arg%.c}; invalid_args=1;;
esac
args="$args $arg"
done
if [ $invalid_args -eq 1 ]; then
echo "Did you mean 'make$args'?"
return 1
else
command make -B $*
fi
}
fi
# cmd
EOF
# /opt/cs50/bin
mkdir -p /opt/cs50/bin
cat <<'EOF' > /opt/cs50/bin/flask
#!/bin/bash
if [[ "$1" == "run" ]]; then
# Default options
host="--host=0.0.0.0"
port="--port=8080"
reload="--reload"
# Override default options
options=""
shift
while test ${#} -gt 0
do
if [[ "$1" =~ ^--host= || "$1" =~ ^-h[^\s]+ ]]; then
host="$1"
elif [[ "$1" == "-h" || "$1" == "--host" ]]; then
host="$1 $2"
shift
elif [[ "$1" =~ ^--port= || "$1" =~ ^-p[^\s]+ ]]; then
port="$1"
elif [[ "$1" == "-p" || "$1" == "--port" ]]; then
port="$1 $2"
shift
elif [[ "$1" =~ ^--(no-)?reload$ ]]; then
reload="$1"
elif [[ "$1" =~ ^--with(out)?-threads$ ]]; then
threads="$1"
else
options+=" $1"
fi
shift
done
# Kill any process listing on the specified port
# using regex to handle -pxxxx, -p xxxx, --port xxxx, --port=xxxx
fuser --kill -INT "${port//[^0-9]}/tcp" &> /dev/null
# Spawn flask
FLASK_APP="$FLASK_APP" FLASK_DEBUG="${FLASK_DEBUG:-0}" unbuffer /usr/local/bin/flask run $host $port $reload $threads $options | sed "s#\(.*http://\)[^:]\+\(:.\+\)#\1localhost\2#"
else
/usr/local/bin/flask "$@"
fi
EOF
cat <<'EOF' > /opt/cs50/bin/http-server
#!/bin/bash
# Default options
a="-a 0.0.0.0"
c="-c-1"
cors="--cors"
i="-i false"
port="-p 8080"
options="--no-dotfiles"
# Override default options
while test ${#} -gt 0
do
if [[ "$1" =~ ^-a$ ]]; then
a="$1 $2"
shift
shift
elif [[ "$1" =~ ^-c-?[0-9]+$ ]]; then
c="$1"
shift
elif [[ "$1" =~ ^--cors(=.*)?$ ]]; then
cors="$1"
shift
elif [[ "$1" =~ ^-i$ ]]; then
i="$1 $2"
shift
shift
elif [[ "$1" =~ ^-p[^\s]+ ]]; then
port="$1"
shift
elif [[ "$1" == "-p" ]]; then
port="$1 $2"
shift
shift
else
options+=" $1"
shift
fi
done
# Kill any process listing on the specified port
# using regex to handle -pxxxx, -p xxxx, --port xxxx, --port=xxxx
fuser --kill "${port//[^0-9]}/tcp" &> /dev/null
# Spawn http-server, retaining colorized output using expect's unbuffer
unbuffer "$(npm prefix -g)/bin/http-server" $a $c $cors $i $port $options | unbuffer -p sed "s#\(.*http://\)[^:]\+\(:.\+\)#\1localhost\2#" | uniq
EOF
chmod a+rx /opt/cs50/bin/*
# Ubuntu-specific
#useradd --home-dir /home/ubuntu --shell /bin/bash ubuntu && \
# umask 0077 && \
# mkdir -p /home/ubuntu && \
# chown -R ubuntu:ubuntu /home/ubuntu && \
# echo "ubuntu:crimson" | chpasswd