#!/usr/bin/env bash # Environnement de dev/test minimal pour Node.js/TypeScript, Shell, Docker, Python et Rust # Cible : Debian 11/12, Ubuntu 20.04/22.04/24.04 # Usage : bash setup_dev_env.sh # Idempotent : oui (réinstalle uniquement si absent) set -euo pipefail ### paramètres ################################################################# # Versions et options par défaut (LTS pour Node via nvm ; Rust via rustup stable) NVM_VERSION="v0.39.7" # version nvm NODE_DEFAULT="lts/*" # canal Node PY_PACKAGES=("pipx") # paquets Python APT PIPX_TOOLS=("black" "ruff" "pytest") # outils Python de base NPM_GLOBAL=("typescript" "ts-node" "eslint") # outils TS/JS de base SHELL_TOOLS=("vim" "dos2unix" "jq" "sed" "gawk" "grep" "tree" "rsync" "direnv" "bash-completion" "zip" "unzip") SYS_TOOLS=("build-essential" "coreutils" "gnupg" "ca-certificates" "lsb-release" "apt-transport-https" "software-properties-common") NET_TOOLS=("dnsutils" "traceroute" "whois" "iputils-ping" "iputils-tracepath" "net-tools" "iproute2" "curl" "wget") PROC_TOOLS=("htop" "iotop" "strace" "ltrace" "tcpdump" "nmap" "lsof" "psmisc" "procps" "dstat" "sysstat") SHELL_QUALITY=("shellcheck" "shfmt") # qualité shell minimale USER_NAME="${SUDO_USER:-${USER}}" WASM_PACK_VERSION="v0.13.1" # dernière version stable connue WASM_PACK_URL="https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-$(uname -s)-$(uname -m).tar.gz" ### fonctions utilitaires ###################################################### log() { printf "[setup] %s\n" "$*" ; } err() { printf "[setup:ERREUR] %s\n" "$*" >&2 ; } have() { command -v "$1" >/dev/null 2>&1 ; } require_root() { if [ "${EUID:-$(id -u)}" -ne 0 ]; then err "exécuter avec sudo ou en root" exit 1 fi } apt_install() { # installe si absent ; accepte une liste local to_install=() for pkg in "$@"; do dpkg -s "$pkg" >/dev/null 2>&1 || to_install+=("$pkg") done if [ "${#to_install[@]}" -gt 0 ]; then log "APT install : ${to_install[*]}" DEBIAN_FRONTEND=noninteractive apt-get install -y "${to_install[@]}" else log "APT install : rien à faire" fi } ### 0) prérequis système ####################################################### require_root log "mise à jour des index APT" apt-get update -y -qq log "installation des outils de base" apt_install git "${SYS_TOOLS[@]}" "${SHELL_TOOLS[@]}" "${NET_TOOLS[@]}" "${PROC_TOOLS[@]}" "${SHELL_QUALITY[@]}" ### 1) docker (moteur + compose plugin) ####################################### # dépôt officiel Docker (si non présent) if ! apt-cache policy | grep -qi "download.docker.com"; then log "ajout du dépôt Docker officiel" install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/$(. /etc/os-release && echo "$ID")/gpg \ | gpg --dearmor -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpg CODENAME="$(. /etc/os-release && echo "${VERSION_CODENAME:-$(lsb_release -cs)}")" echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(. /etc/os-release && echo "$ID") ${CODENAME} stable" \ > /etc/apt/sources.list.d/docker.list apt-get update -y -qq fi # installation moteur + plugins apt_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # exécution docker sans sudo if ! getent group docker >/dev/null; then log "création du groupe docker" groupadd docker fi if id -nG "$USER_NAME" | tr ' ' '\n' | grep -qx "docker"; then log "utilisateur ${USER_NAME} déjà dans le groupe docker" else log "ajout de ${USER_NAME} au groupe docker" usermod -aG docker "$USER_NAME" DOCKER_GROUP_HINT=1 fi # activation au démarrage systemctl enable docker >/dev/null 2>&1 || true systemctl start docker >/dev/null 2>&1 || true ### 2) node.js + typescript (via nvm, utilisateur non-root) ################### if ! sudo -u "$USER_NAME" bash -lc 'command -v nvm >/dev/null 2>&1'; then log "installation de nvm (${NVM_VERSION}) pour ${USER_NAME}" sudo -u "$USER_NAME" bash -lc "curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash" fi # charger nvm et installer Node LTS sudo -u "$USER_NAME" bash -lc ' export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm install '"${NODE_DEFAULT}"' nvm alias default '"${NODE_DEFAULT}"' npm config set fund false --location=global npm config set audit false --location=global ' # outils globaux TS/JS (minimaux) sudo -u "$USER_NAME" bash -lc ' export NVM_DIR="$HOME/.nvm" . "$NVM_DIR/nvm.sh" set -e for pkg in '"${NPM_GLOBAL[*]}"'; do if ! npm list -g --depth=0 "$pkg" >/dev/null 2>&1; then npm i -g "$pkg" fi done ' ### 3) python (interpréteur, venv, pipx + outils) ############################# apt_install python3 python3-venv python3-pip "${PY_PACKAGES[@]}" # s’assurer que pipx est sur le PATH utilisateur sudo -u "$USER_NAME" bash -lc ' python3 -m pipx ensurepath ' # installation d’outils Python via pipx for tool in "${PIPX_TOOLS[@]}"; do if ! sudo -u "$USER_NAME" bash -lc "pipx list | grep -qE ' ${tool}(\s|$)'"; then log "pipx : installation de ${tool}" sudo -u "$USER_NAME" bash -lc "pipx install ${tool}" else log "pipx : ${tool} déjà présent" fi done ### 4) rust (rustup + toolchain stable, utilisateur non-root) ################# if ! sudo -u "$USER_NAME" bash -lc 'command -v rustup >/dev/null 2>&1'; then log "installation de rustup (canal stable) pour ${USER_NAME}" sudo -u "$USER_NAME" bash -lc 'curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal' fi sudo -u "$USER_NAME" bash -lc ' source "$HOME/.cargo/env" rustup set profile minimal rustup toolchain install stable --component clippy rustfmt rustup default stable ' if ! sudo -u "$USER_NAME" bash -lc 'command -v wasm-pack >/dev/null 2>&1'; then log "installation de wasm-pack ${WASM_PACK_VERSION} pour ${USER_NAME}" sudo -u "$USER_NAME" bash -lc ' TMPDIR=$(mktemp -d) cd "$TMPDIR" curl -fsSL "'"${WASM_PACK_URL}"'" -o wasm-pack.tar.gz tar -xzf wasm-pack.tar.gz mkdir -p "$HOME/.cargo/bin" mv wasm-pack "$HOME/.cargo/bin/" cd / rm -rf "$TMPDIR" ' else log "wasm-pack déjà présent" fi ### 5) configuration direnv (sécurité) ######################################## # activer la charge automatique pour bash (zsh similaire si nécessaire) BASHRC="/home/${USER_NAME}/.bashrc" if ! grep -q 'direnv hook bash' "$BASHRC" 2>/dev/null; then log "activation de direnv dans .bashrc" echo 'eval "$(direnv hook bash)"' >> "$BASHRC" chown "$USER_NAME":"$USER_NAME" "$BASHRC" fi ### 6) vérifications et versions ############################################## log "vérification des versions essentielles" sudo -u "$USER_NAME" bash -lc ' set -e echo "git : $(git --version | awk "{print \$3}")" echo "node : $(node -v 2>/dev/null || echo absent)" echo "npm : $(npm -v 2>/dev/null || echo absent)" echo "tsc : $(tsc -v 2>/dev/null || echo absent)" echo "python3 : $(python3 --version | awk "{print \$2}")" echo "pipx : $(pipx --version 2>/dev/null || echo absent)" source "$HOME/.cargo/env" 2>/dev/null || true echo "rustc : $(rustc --version 2>/dev/null || echo absent)" echo "cargo : $(cargo --version 2>/dev/null || echo absent)" echo "wasm-pack : $(wasm-pack --version 2>/dev/null || echo absent)" ' echo "docker : $(docker --version 2>/dev/null || echo absent)" echo "compose : $(docker compose version 2>/dev/null || echo absent)" ### 7) post-install : information utilisateur ################################# if [ "${DOCKER_GROUP_HINT:-0}" -eq 1 ]; then log "remarque : une reconnexion de ${USER_NAME} est nécessaire pour utiliser docker sans sudo." fi log "installation terminée."