feat(git): deploy user-scope ~/.gitconfig from the repo template
Git never expands $VARS in its config, so gitconfig carries @USER@ and @EMAIL@ placeholders that install.sh fills from the deployed bashrc's USER/EMAIL exports. A differing ~/.gitconfig is kept as ~/.gitconfig.backup-<date>; an identical one is left alone. A repo's .git/config still overrides it. excludesfile uses ~ (git expands it, not $HOME). The rc files now override $USER, so the installer takes the login name from id -un for dscl and the code-server unit.
This commit is contained in:
@@ -90,3 +90,12 @@ Same branch. Prompt at start of Darwin block (MACOS_SHELL=bash|zsh env overrides
|
||||
- [x] install.sh: use_brew_bash_login_shell → set_login_shell <path>, called at end with chosen shell
|
||||
- [x] README + CLAUDE.md
|
||||
- [x] shellcheck/bash -n/zsh -n; runtime: theme in zsh (prompt render, timer, git bits), dtach-router sourced in zsh; harness both choices
|
||||
|
||||
## Feature — user-scope ~/.gitconfig from repo template, VIUSER/VIMAIL → USER/EMAIL (2026-10-06)
|
||||
- [x] rc files (bashrc-linux, bashrc-osx, zshrc-osx): `VIUSER`/`VIMAIL` → `USER`/`EMAIL`
|
||||
- [x] `gitconfig` template: git never expands `$VAR` → `@USER@`/`@EMAIL@` placeholders, `excludesfile = ~/.gitignore`
|
||||
- [x] install.sh `deploy_gitconfig`: values read from deployed bashrc, rendered → ~/.gitconfig, differing old one → ~/.gitconfig.backup-<date>
|
||||
- [x] install.sh: `$USER` → `$(id -un)` (dscl, code-server unit): rc now overrides USER with identity
|
||||
- [x] README + CLAUDE.md layout
|
||||
- [x] Verify: shellcheck, bash -n, render to temp HOME, `git config --file` reads values
|
||||
- [x] `git-delta` added to apt + brew lists (gitconfig pager = delta)
|
||||
|
||||
@@ -20,7 +20,8 @@ install.sh one-shot installer (OS auto-detected)
|
||||
vim/vimrc vim config (pathogen, molokai, syntastic, NERDTree)
|
||||
vim/autoload/ pathogen loader (committed)
|
||||
vim/colors/ molokai colorscheme (committed)
|
||||
bash/bashrc-{linux,osx} OS-detected bashrc
|
||||
bash/bashrc-{linux,osx} OS-detected bashrc (exports USER/EMAIL identity)
|
||||
gitconfig user-scope ~/.gitconfig template, @USER@/@EMAIL@ filled at install
|
||||
zsh/{zshrc-osx,bchanot.zsh-theme} macOS zsh option: oh-my-zsh zshrc + theme porting the bash prompt
|
||||
bin/{dt,dtach-router,claude-provider} CLI scripts deployed to ~/.local/bin
|
||||
etc/profile.d/disk-usage-warning.sh login-time low-disk warning → /etc/profile.d (Linux only)
|
||||
|
||||
@@ -27,6 +27,7 @@ curl -fsSL https://git.bchanot.fr/bchanot/config/raw/branch/master/remote-instal
|
||||
| `vim/vimrc` | Vim config: pathogen, molokai, syntastic (C with `-Wall -Werror -Wextra`), NERDTree, 42-style canonical class generators (`:ClassH`, `:ClassC`). |
|
||||
| `vim/autoload/` | `pathogen.vim` plugin loader (committed). |
|
||||
| `vim/colors/` | `molokai.vim` colorscheme (committed). |
|
||||
| `gitconfig` | Template of the user-scope `~/.gitconfig`. `@USER@` and `@EMAIL@` are filled at install with the `USER` and `EMAIL` exported by the bashrc (git never expands `$VARS` itself). |
|
||||
| `bash/bashrc-linux` | bashrc for desktop Linux (git-aware prompt + command timer). |
|
||||
| `bash/bashrc-osx` | bashrc for macOS: `bashrc-linux` adapted (Homebrew on `PATH`, BSD `ls -G`, bash 5 clock for the timer, `cc` without `systemd-run`). |
|
||||
| `zsh/zshrc-osx` | zshrc for macOS when zsh is chosen: oh-my-zsh + the same env, aliases and dtach menu as `bashrc-osx`. Loads `~/.zshrc.local` for machine-specific lines. |
|
||||
@@ -64,11 +65,11 @@ What it does:
|
||||
3. Moves any existing `~/.vim`, `~/.vimrc`, `~/.bashrc`, `~/.Sublivim` to `~/Oldconfig`.
|
||||
4. Clones the `syntastic` and `nerdtree` vim plugins into `~/.vim/bundle/`.
|
||||
5. Copies the tracked vim files into `~/.vim` and symlinks `~/.vimrc`.
|
||||
6. Picks the bashrc by OS: macOS → `bashrc-osx` (falls back to `bashrc-linux` if missing), everything else → `bashrc-linux`. Copies it to `~/.bashrc`.
|
||||
6. Picks the bashrc by OS: macOS → `bashrc-osx` (falls back to `bashrc-linux` if missing), everything else → `bashrc-linux`. Copies it to `~/.bashrc`. Then renders `gitconfig` into `~/.gitconfig` with that bashrc's `USER` / `EMAIL`. A different existing `~/.gitconfig` is saved as `~/.gitconfig.backup-<date>`; an identical one is left alone. It is the global level only: a repo's own `.git/config` still overrides it. `core.excludesfile` points at `~/.gitignore`, ignored by git when the file does not exist.
|
||||
7. Installs Python CLIs via `pipx` (`PyMuPDF` → `pymupdf`, `Markdown` → `markdown_py`) — skipped if `pipx` is absent.
|
||||
8. Copies the `bin/` scripts (`dt`, `dtach-router`, `claude-provider`) into `~/.local/bin`. The dtach session-resume menu ships in the deployed bashrc (both OSes), so every interactive shell offers it — including VS Code Remote-SSH terminals, which are non-login and never read `~/.profile`. The installer also strips any older dtach block left in `~/.profile` so a plain SSH login doesn't prompt twice.
|
||||
9. On Linux, installs `etc/profile.d/disk-usage-warning.sh` to `/etc/profile.d/` (needs `sudo`) so each login warns when `/` or `/home` cross 85% usage.
|
||||
10. On Linux, installs **code-server** (VS Code in the browser) via its vendor script — skipped if already present — and enables the `code-server@$USER` systemd service.
|
||||
10. On Linux, installs **code-server** (VS Code in the browser) via its vendor script — skipped if already present — and enables the `code-server@<login>` systemd service (login from `id -un`: the bashrc overrides `$USER`).
|
||||
11. On Linux, installs **`ubuntu-desktop-minimal`** (GDM + GNOME Shell, ~1.5 GB): the RDP remote login below hands out a GNOME session, which a bare server install does not have. Then sets up **RDP remote login** via `gnome-remote-desktop` (Wayland-native): installs the daemon + `openssl`, generates a self-signed TLS cert once, and prompts interactively for shared "gate" credentials (skipped when no terminal is attached, or already set). Disables `xrdp` if present; opens UFW port `3389` only when UFW is already active. Finally, when `lspci` sees an NVIDIA GPU, runs `ubuntu-drivers install` to put on the driver the distro recommends for the card (no version pinned; loads at the next reboot). Skipped on machines without an NVIDIA GPU.
|
||||
12. On Linux, installs the **`cloudpex`** NAS mount helper to `/usr/local/bin` via `cloudpex/install.sh`, which prompts for the NAS host, share name, SMB user, mount point and SMB version and writes them to `/etc/cloudpex.conf` (root, `0600`; an existing config is shown and kept unless you say `n`; skipped when no terminal is attached). Nothing is mounted, no password stored, see [`cloudpex/README.md`](cloudpex/README.md).
|
||||
13. On Linux, installs the **security baseline**, always, no prompt: **fail2ban** (+ `nftables`) with `etc/fail2ban/jail.d/local.conf` (sshd jail reading the journal, bans the offending IP on every port so the SSH port does not matter, 5 failures in 10 min → 1 h ban, loopback and private LAN ranges never banned); **unattended-upgrades** enabled through `etc/apt/apt.conf.d/20auto-upgrades`; and the **sshd drop-in** `etc/ssh/sshd_config.d/20-hardening.conf` (`PermitRootLogin no`, `MaxAuthTries 3`, `LoginGraceTime 20`), checked with `sshd -t` and removed again if sshd rejects it, then `reload ssh`. Authentication methods, port and user lists are left as they are.
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Template for the user-scope ~/.gitconfig, rendered by install.sh.
|
||||
# Git never expands $VARS: @USER@ and @EMAIL@ are replaced at install
|
||||
# time with the USER and EMAIL exported by the deployed bashrc.
|
||||
# A repo .git/config still overrides these values for that repo.
|
||||
[user]
|
||||
name = @USER@
|
||||
email = @EMAIL@
|
||||
[push]
|
||||
default = current
|
||||
[color]
|
||||
ui = auto
|
||||
[pull]
|
||||
rebase = true
|
||||
[core]
|
||||
editor = vim
|
||||
pager = delta
|
||||
excludesfile = ~/.gitignore
|
||||
[advice]
|
||||
detachedHead = false
|
||||
[merge]
|
||||
tool = vimdiff
|
||||
conflictStyle = zdiff3
|
||||
[pager]
|
||||
branch = false
|
||||
[url "git@salsa.debian.org:installer-team/"]
|
||||
pushInsteadOf = https://salsa.debian.org/installer-team/
|
||||
[interactive]
|
||||
diffFilter = delta --color-only
|
||||
[delta]
|
||||
navigate = true # use n and N to move between diff sections
|
||||
dark = true # or light = true, or omit for auto-detection
|
||||
+52
-4
@@ -364,7 +364,8 @@ set_login_shell() {
|
||||
if ! grep -qxF "$target" /etc/shells; then
|
||||
echo "$target" | sudo tee -a /etc/shells >/dev/null
|
||||
fi
|
||||
current="$(dscl . -read "/Users/$USER" UserShell | awk '{ print $2 }')"
|
||||
# id -un, not $USER: the deployed rc sets USER to the git/vim identity.
|
||||
current="$(dscl . -read "/Users/$(id -un)" UserShell | awk '{ print $2 }')"
|
||||
if [ "$current" = "$target" ]; then
|
||||
echo "Login shell already $target — skipping"
|
||||
return 0
|
||||
@@ -429,6 +430,50 @@ wire_bash_profile() {
|
||||
"$line" >> "$profile"
|
||||
}
|
||||
|
||||
# Value of `export NAME=value` ($1) in the rc file $2, quotes stripped. The last
|
||||
# match wins, as when the shell sources it. Empty when absent.
|
||||
rc_export_value() {
|
||||
sed -n "s/^export $1=//p" "$2" | tail -n 1 | tr -d "\"'"
|
||||
}
|
||||
|
||||
# Print the repo gitconfig template with @USER@ and @EMAIL@ replaced by $1 and
|
||||
# $2. Bash substitution, so the values need no sed escaping.
|
||||
render_gitconfig() {
|
||||
local name="$1" email="$2" line
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
line="${line//@USER@/$name}"
|
||||
line="${line//@EMAIL@/$email}"
|
||||
printf '%s\n' "$line"
|
||||
done < "$SCRIPT_DIR/gitconfig"
|
||||
}
|
||||
|
||||
# Install the user-scope ~/.gitconfig (a repo's own .git/config still wins).
|
||||
# The identity is read from the USER/EMAIL exports of the deployed rc ($1), so
|
||||
# git and the shell agree. A ~/.gitconfig that differs is kept as
|
||||
# ~/.gitconfig.backup-<date>, outside ~/Oldconfig which every run wipes.
|
||||
# Idempotent: an identical ~/.gitconfig is left alone.
|
||||
deploy_gitconfig() {
|
||||
local rc="$1" name email rendered backup
|
||||
name="$(rc_export_value USER "$rc")"
|
||||
email="$(rc_export_value EMAIL "$rc")"
|
||||
if [ -z "$name" ] || [ -z "$email" ]; then
|
||||
echo "USER/EMAIL not exported by $rc — skipping ~/.gitconfig" >&2
|
||||
return 0
|
||||
fi
|
||||
rendered="$(render_gitconfig "$name" "$email")"
|
||||
if printf '%s\n' "$rendered" | cmp -s - "$HOME/.gitconfig"; then
|
||||
echo "$HOME/.gitconfig already up to date — skipping"
|
||||
return 0
|
||||
fi
|
||||
if [ -e "$HOME/.gitconfig" ]; then
|
||||
backup="$HOME/.gitconfig.backup-$(date +%Y%m%d-%H%M%S)"
|
||||
echo "Saving the current ~/.gitconfig to $backup"
|
||||
mv "$HOME/.gitconfig" "$backup"
|
||||
fi
|
||||
echo "Deploying gitconfig to ~/.gitconfig ($name <$email>)"
|
||||
printf '%s\n' "$rendered" > "$HOME/.gitconfig"
|
||||
}
|
||||
|
||||
# What the Linux install sets up that this macOS run did not, and why.
|
||||
print_macos_gaps() {
|
||||
cat <<'EOF'
|
||||
@@ -463,8 +508,7 @@ if command -v apt-get >/dev/null 2>&1; then
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade -y
|
||||
|
||||
# Build + version control + C dev tooling (gitleaks backs the pre-commit hook).
|
||||
# Web stack: MariaDB + PHP modules for local WordPress/LAMP work; the php-* metapackages
|
||||
# Build + version control + C dev tooling (gitleaks backs the pre-commit hook). # Web stack: MariaDB + PHP modules for local WordPress/LAMP work; the php-* metapackages
|
||||
# follow the distro's PHP version instead of pinning php8.x-*.
|
||||
sudo apt-get install -y \
|
||||
vim git git-lfs git-filter-repo gitleaks gcc make pkg-config dkms valgrind shellcheck \
|
||||
@@ -483,7 +527,8 @@ if command -v apt-get >/dev/null 2>&1; then
|
||||
if ! command -v code-server >/dev/null 2>&1; then
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
fi
|
||||
sudo systemctl enable --now "code-server@$USER"
|
||||
# id -un, not $USER: the deployed bashrc sets USER to the git/vim identity.
|
||||
sudo systemctl enable --now "code-server@$(id -un)"
|
||||
|
||||
# GNOME desktop (GDM + Shell): the RDP remote login below needs a GNOME session
|
||||
# to hand out; a bare server install has none. Ubuntu-only metapackage.
|
||||
@@ -558,6 +603,9 @@ fi
|
||||
echo "Deploying $bashrc"
|
||||
cp "$SCRIPT_DIR/$bashrc" "$HOME/.bashrc"
|
||||
|
||||
# User-scope git config, identity taken from the bashrc just deployed.
|
||||
deploy_gitconfig "$SCRIPT_DIR/$bashrc"
|
||||
|
||||
# Python CLIs via pipx (run as the user, never sudo). Skipped if pipx is absent.
|
||||
if command -v pipx >/dev/null 2>&1; then
|
||||
echo "Installing pipx CLIs (PyMuPDF -> pymupdf, Markdown -> markdown_py)"
|
||||
|
||||
Reference in New Issue
Block a user