Skip to content

Commit eb41c69

Browse files
authored
fix: harden devcontainer shell tooling (#7)
## Summary - make the VS Code launcher exit cleanly on failure to avoid hanging container setups - align devcontainer provisioning helpers and add shared utilities/config scripts - standardize shellcheck configuration and annotate scripts for static analysis ## Testing - shellcheck code-dev-container.sh - shellcheck .devcontainer/scripts/*.sh
1 parent 6d28ab9 commit eb41c69

File tree

8 files changed

+228
-192
lines changed

8 files changed

+228
-192
lines changed

.devcontainer/devcontainer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"ghcr.io/devcontainers-extra/features/devcontainers-cli:1": {}
1515
},
1616
// "forwardPorts": [5000],
17+
"onCreateCommand": ".devcontainer/scripts/on-create.sh",
1718
"updateContentCommand": ".devcontainer/scripts/update-content.sh",
1819
"postCreateCommand": ".devcontainer/scripts/post-create.sh",
1920
"customizations": {
@@ -55,7 +56,8 @@
5556
"files.autoSaveWorkspaceFilesOnly": true,
5657
"terminal.integrated.cursorBlinking": true,
5758
"telemetry.editStats.enabled": false,
58-
"bashIde.explainshellEndpoint": "http://127.0.0.1:5000"
59+
"bashIde.explainshellEndpoint": "http://127.0.0.1:5000",
60+
"shellcheck.enableQuickFix": false
5961
}
6062
}
6163
},

.devcontainer/scripts/config.sh

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# shellcheck disable=SC2148
2+
3+
BASHRC="$HOME/.bashrc"
4+
ALIASES="$HOME/.bash_aliases"
5+
INPUTRC="$HOME/.inputrc"
6+
7+
log "Creating $ALIASES file..."
8+
cat <<'EOF' >"$ALIASES"
9+
alias ls="lsd --color auto"
10+
alias ll="lsd -alF --color auto"
11+
alias la="lsd -A --color auto"
12+
alias cat="bat --color auto --style plain"
13+
alias hx="hx --vsplit"
14+
alias helix=hx
15+
alias vim=hx
16+
EOF
17+
18+
log "Creating $INPUTRC file..."
19+
cat <<'EOF' >"$INPUTRC"
20+
$include /etc/inputrc
21+
22+
set blink-matching-paren on
23+
set colored-completion-prefix on
24+
set completion-ignore-case on
25+
set completion-map-case on
26+
set show-all-if-unmodified on
27+
set show-all-if-ambiguous on
28+
TAB: menu-complete
29+
"\e[Z": menu-complete-backward
30+
EOF
31+
32+
log "Creating $BASHRC..."
33+
cat <<'EOF' >"$BASHRC"
34+
case $- in
35+
*i*) ;;
36+
*) return;;
37+
esac
38+
39+
HISTCONTROL=ignoreboth
40+
shopt -s histappend
41+
HISTSIZE=-1
42+
HISTFILESIZE=-1
43+
HISTDUP="erase"
44+
HISTTIMEFORMAT="%FT%T "
45+
46+
shopt -s checkwinsize
47+
shopt -s globstar
48+
49+
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
50+
51+
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
52+
debian_chroot=$(cat /etc/debian_chroot)
53+
fi
54+
55+
case "$TERM" in
56+
xterm-color | *-256color) color_prompt=yes ;;
57+
esac
58+
59+
if [ -n "$force_color_prompt" ]; then
60+
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
61+
color_prompt=yes
62+
else
63+
color_prompt=
64+
fi
65+
fi
66+
67+
if [ "$color_prompt" = yes ]; then
68+
PS1='${debian_chroot:+($debian_chroot)}\[$(tput setaf 39)\]\u\[$(tput setaf 81)\]@\[$(tput setaf 77)\]\h \[$(tput setaf 226)\]\w \[$(tput sgr0)\]\n❯ '
69+
else
70+
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
71+
fi
72+
unset color_prompt force_color_prompt
73+
74+
case "$TERM" in
75+
xterm* | rxvt*)
76+
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
77+
;;
78+
*) ;;
79+
esac
80+
81+
if [ -x /usr/bin/dircolors ]; then
82+
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
83+
alias ls='ls --color=auto'
84+
fi
85+
86+
if [ -f ~/.bash_aliases ]; then
87+
. ~/.bash_aliases
88+
fi
89+
90+
if [ -f ~/.bash_env ]; then
91+
. ~/.bash_env
92+
fi
93+
94+
if ! shopt -oq posix; then
95+
if [ -f /usr/share/bash-completion/bash_completion ]; then
96+
. /usr/share/bash-completion/bash_completion
97+
elif [ -f /etc/bash_completion ]; then
98+
. /etc/bash_completion
99+
fi
100+
fi
101+
# bash theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
102+
__bash_prompt() {
103+
local userpart='`export XIT=$? \
104+
&& [ ! -z "${GITHUB_USER:-}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER:-} " || echo -n "\[\033[0;32m\]\u " \
105+
&& [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
106+
local gitbranch='`\
107+
if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
108+
export BRANCH="$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null)"; \
109+
if [ "${BRANCH:-}" != "" ]; then \
110+
echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH:-}" \
111+
&& if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \
112+
git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
113+
echo -n " \[\033[1;33m\]✗"; \
114+
fi \
115+
&& echo -n "\[\033[0;36m\]) "; \
116+
fi; \
117+
fi`'
118+
local lightblue='\[\033[1;34m\]'
119+
local removecolor='\[\033[0m\]'
120+
PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\n❯ "
121+
unset -f __bash_prompt
122+
}
123+
__bash_prompt
124+
export PROMPT_DIRTRIM=4
125+
126+
# Check if the terminal is xterm
127+
if [[ "$TERM" == "xterm" ]]; then
128+
# Function to set the terminal title to the current command
129+
preexec() {
130+
local cmd="${BASH_COMMAND}"
131+
echo -ne "\033]0;${USER}@${HOSTNAME}: ${cmd}\007"
132+
}
133+
134+
# Function to reset the terminal title to the shell type after the command is executed
135+
precmd() {
136+
echo -ne "\033]0;${USER}@${HOSTNAME}: ${SHELL}\007"
137+
}
138+
139+
# Trap DEBUG signal to call preexec before each command
140+
trap 'preexec' DEBUG
141+
142+
# Append to PROMPT_COMMAND to call precmd before displaying the prompt
143+
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND; }precmd"
144+
fi
145+
146+
source <(bat --completion bash)
147+
source <(fzf --bash)
148+
149+
FZF_COMPLETION_AUTO_COMMON_PREFIX=true
150+
FZF_COMPLETION_AUTO_COMMON_PREFIX_PART=true
151+
EOF

.devcontainer/scripts/on-create.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
# shellcheck source=.devcontainer/scripts/utils.sh
6+
source "${SCRIPTS_DIR}/utils.sh"
7+
# shellcheck source=.devcontainer/scripts/config.sh
8+
source "${SCRIPTS_DIR}/config.sh"
9+
10+
npm install --silent --quiet --location=global npm@latest

.devcontainer/scripts/post-create.sh

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
3+
#set -x
34

4-
log(){ printf '[post-create] %s\n' "$*"; }
5-
err(){ printf '[post-create][ERROR] %s\n' "$*"; }
6-
warn(){ printf '[post-create][WARN] %s\n' "$*"; }
5+
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
# shellcheck source=.devcontainer/scripts/utils.sh
7+
source "${SCRIPTS_DIR}/utils.sh"
78

89
log "This script is run after update-content.sh"
910

@@ -37,7 +38,8 @@ if command -v docker >/dev/null 2>&1; then
3738
-d "$EXPLAINSHELL_MONGODB_IMAGE"
3839

3940
log "Importing explainshell db dump in the background..."
40-
docker exec -t "$EXPLAINSHELL_MONGODB_CONTAINER" mongorestore --archive --gzip < "$work_location/dump.gz" &> "$work_location/$(date +%Y%m%dT%k%M%)-mongorestore.log" &
41+
docker exec -t "$EXPLAINSHELL_MONGODB_CONTAINER" mongorestore \
42+
--archive --gzip < "$work_location/dump.gz" &> "$work_location/$(date +%Y%m%dT%k%M%)-mongorestore.log" &
4143

4244
log "Starting explainshell container..."
4345
docker container run \

0 commit comments

Comments
 (0)