Last active
March 17, 2026 20:16
-
-
Save agirault/048b17b0098a595f5487fdf93ba05b9f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -exo pipefail | |
| # Check for sudo | |
| if [[ $EUID -eq 0 ]]; then | |
| echo "This script must not be run as root" | |
| exit 1 | |
| fi | |
| # -- System variables -- # | |
| arch=$(dpkg --print-architecture) | |
| rel=$(. /etc/os-release && echo "$VERSION_CODENAME") | |
| # -- Add source repositories -- # | |
| # Dirs | |
| sudo mkdir -p -m 755 /etc/apt/keyrings | |
| sudo mkdir -p -m 755 /etc/apt/sources.list.d | |
| # Add apt source lists | |
| function setup_apt_list() { | |
| set -eu | |
| name=$1 | |
| repo=$2 | |
| rel_key_path=$3 | |
| rel_config=$4 | |
| source="/etc/apt/sources.list.d/$name.list" | |
| if [[ -f "$source" ]]; then return; fi | |
| gpg_path="/etc/apt/keyrings/$name.gpg" | |
| curl -fsSL "$repo/$rel_key_path" | sudo gpg --yes --dearmor -o "$gpg_path" | |
| sudo chmod go+r "$gh_gpg_path" | |
| echo "deb [arch="$arch" signed-by="$gpg_path"] $repo/$rel_config" | \ | |
| sudo tee "/etc/apt/sources.list.d/$name.list" > /dev/null | |
| } | |
| setup_apt_list "github-cli" "https://cli.github.com/packages" "githubcli-archive-keyring.gpg" " stable main" | |
| setup_apt_list "vscode" "https://packages.microsoft.com" "keys/microsoft.asc" "repos/code stable main" | |
| setup_apt_list "docker" "https://download.docker.com" "linux/ubuntu/gpg" "linux/ubuntu $rel stable" | |
| sudo apt-add-repository -n ppa:fish-shell/release-3 -y | |
| # Update sources | |
| sudo apt-get update | |
| # -- Install dependencies -- # | |
| # apt | |
| sudo apt-get install -y \ | |
| fish \ | |
| vim \ | |
| tldr ripgrep fd-find sd tree lsd duf \ | |
| wget curl unzip apt-transport-https openssh-server \ | |
| lshw pciutils iperf ncdu htop \ | |
| apt-rdepends \ | |
| git-gui git-delta tig gh \ | |
| build-essential libtool m4 automake \ | |
| ca-certificates gnupg gnupg2 pass pinentry-tty | |
| # snap | |
| sudo snap install glab | |
| # scripts | |
| curl -sSfL https://raw.githubusercontent.com/bootandy/dust/refs/heads/master/install.sh | bash | |
| curl -sSfL https://webinstall.dev/curlie | bash | |
| # -- Git config -- # | |
| if [[ ! -f "$HOME/.gitconfig" ]]; then | |
| # git config from https://gist.github.com/agirault/a69a7eb5862d479e68b92eef8840e5d9 | |
| wget https://gist.githubusercontent.com/agirault/a69a7eb5862d479e68b92eef8840e5d9/raw/.gitconfig -O $HOME/.gitconfig | |
| fi | |
| # Get or set git user name and email, storing them in variables | |
| fullname=$(git config --global user.name) || { read -p '[Git] Full Name: ' fullname && git config --global user.name "$fullname"; } | |
| email=$(git config --global user.email) || { read -p '[Git] Email: ' email && git config --global user.email "$email"; } | |
| # -- Shell -- # | |
| # Make fish default | |
| fish_path=$(which fish) | |
| if ! cat /etc/shells | grep $fish_path; then | |
| echo $fish_path | sudo tee -a /etc/shells | |
| fi | |
| sudo chsh -s $fish_path $USER | |
| # Configure Nerd Font | |
| if ! find /usr/share/fonts -name "*FiraCodeNerdFont*" | grep -q "."; then | |
| font_url="https://github.com/ryanoasis/nerd-fonts/releases/download/v3.4.0/FiraCode.zip" | |
| font_name=$(basename $font_url | cut -d. -f1) | |
| sudo wget -O /tmp/$font_name.zip "$font_url" | |
| sudo unzip -o /tmp/$font_name.zip -d "/usr/share/fonts/truetype/$font_name" | |
| sudo rm -rf /tmp/$font_name.zip | |
| fc-cache -f -v | |
| fi | |
| # Fisher (fish plugin manager) + Tide (fish prompt) | |
| fish -c "curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source \ | |
| && fisher install jorgebucaran/fisher IlanCosman/tide@v6 \ | |
| && tide configure --auto --style=Classic --prompt_colors='True color' --classic_prompt_color=Light --show_time='12-hour format' --classic_prompt_separators=Angled --powerline_prompt_heads=Sharp --powerline_prompt_tails=Slanted --powerline_prompt_style='Two lines, character and frame' --prompt_connection=Solid --powerline_right_prompt_frame=No --prompt_connection_andor_frame_color=Light --prompt_spacing=Sparse --icons='Many icons' --transient=No" | |
| # Prepare config dir | |
| fish_config_path="$HOME/.config/fish/conf.d" | |
| mkdir -p $fish_config_path | |
| # -- Docker config --# | |
| # Install if needed | |
| if ! command -v docker > /dev/null; then | |
| sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin | |
| fi | |
| if ! docker buildx version &> /dev/null ; then | |
| sudo apt-get install -y docker-buildx | |
| fi | |
| # Add user to docker group | |
| sudo groupadd docker || true | |
| sudo usermod -aG docker $USER | |
| newgrp docker << END | |
| docker run hello-world | |
| END | |
| # Install docker-credential-pass | |
| if ! command -v docker-credential-pass > /dev/null; then | |
| docker_creds_pass_version="v0.8.0" | |
| docker_creds_pass_url="https://github.com/docker/docker-credential-helpers/releases/download/$docker_creds_pass_version/docker-credential-pass-$docker_creds_pass_version.linux-$arch" | |
| docker_creds_pass_path="/usr/local/bin/docker-credential-pass" | |
| sudo wget "$docker_creds_pass_url" -O "$docker_creds_pass_path" | |
| sudo chown $USER "$docker_creds_pass_path" | |
| sudo chmod u+x "$docker_creds_pass_path" | |
| fi | |
| # Make docker use the docker-credential-pass | |
| docker_config_path="$HOME/.docker.config.json" | |
| docker_creds_config='"credsStore": "pass"' | |
| if [[ -f "$docker_config_path" ]]; then | |
| if ! grep -qF "$docker_creds_config" "$docker_config_path"; then | |
| # Append to config | |
| sed -i "0,/{/s|{|{\n\t$docker_creds_config,|" "$docker_config_path" | |
| fi | |
| else | |
| # Create config | |
| printf "{\n\t$docker_creds_config\n}\n" > "$docker_config_path" | |
| fi | |
| # Enable TTY pinentry when there is no display | |
| # https://superuser.com/questions/520980/how-to-force-gpg-to-use-console-mode-pinentry-to-prompt-for-passwords | |
| sudo update-alternatives --set pinentry $(which pinentry-tty) | |
| tty_comment="\n# Enable TTY pinentry for GPG password when there is no display\n" | |
| # fish | |
| fish_tty_cmd='set -gx GPG_TTY $(tty)' | |
| printf "${tty_comment}${fish_tty_cmd}\n" > "$fish_config_path/gpg_tty.fish" | |
| # bash | |
| bash_tty_cmd='export GPG_TTY=$(tty)' | |
| bash_config_path="$HOME/.bashrc" | |
| if ! grep -qF "$bash_tty_cmd" "$bash_config_path"; then | |
| printf "${tty_comment}${bash_tty_cmd}\n" >> "$bash_config_path" | |
| fi | |
| # Generate GPG key and add to pass | |
| gpgconf --kill gpg-agent | |
| export GPG_TTY=$(tty) # to make pipe work after gpg2 | |
| # Check if GPG key already exists | |
| gpg_id_regex='^\s*\K[[:alnum:]]+$' | |
| gpg_id=$(gpg2 --list-keys | grep -oP $gpg_id_regex) || true | |
| # If no GPG key exists, generate one using git user info | |
| if [[ -z "$gpg_id" ]]; then | |
| gpg2 --batch --generate-key <<EOF | |
| %echo Generating GPG key | |
| Key-Type: EDDSA | |
| Key-Curve: Ed25519 | |
| Subkey-Type: ECDH | |
| Subkey-Curve: Curve25519 | |
| Name-Real: $fullname | |
| Name-Email: $email | |
| Expire-Date: 0 | |
| %commit | |
| %echo done | |
| EOF | |
| gpg_id=$(gpg2 --list-keys | grep -oP $gpg_id_regex) | |
| fi | |
| pass init $gpg_id | |
| docker-credential-pass list >/dev/null # errors out if not setup properly | |
| # -- AI Agents -- # | |
| # Claude | |
| curl -fsSL https://claude.ai/install.sh | bash | |
| # -- Path -- # | |
| cuda_bin="/usr/local/cuda/bin" | |
| python_bin="\$HOME/.local/bin" | |
| expand_path_cmd="set -gx PATH $cuda_bin $python_bin \$PATH" | |
| printf "${expand_path_cmd}\n" > "$fish_config_path/cuda_path.fish" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Run with: