FROM archlinux:latest # ── Build args: UID/GID matching for clean /workspace permissions ───────────── # Override at build: UID=$(id -u) GID=$(id -g) docker compose build # Or set in .env file ARG USER_UID=1000 ARG USER_GID=1000 # ── Rolling release: full system update first, always ───────────────────────── RUN pacman -Syu --noconfirm # ── Crown Jewel #1: pacman ──────────────────────────────────────────────────── RUN pacman -S --noconfirm --needed \ base-devel git curl wget unzip zip \ zsh tmux screen mosh \ zsh-syntax-highlighting zsh-autosuggestions zsh-history-substring-search \ zsh-completions \ neovim \ starship \ python python-pip python-pynvim \ perl \ pyright \ bash-language-server \ python-black ruff shellcheck shfmt \ python-pylint \ ripgrep fd bat eza fzf zoxide \ git-delta lazygit \ btop \ ttf-nerd-fonts-symbols ttf-jetbrains-mono-nerd \ man-db man-pages \ jq tree wget \ rsync \ imagemagick chafa jp2a \ go \ github-cli \ libnewt \ && pacman -Scc --noconfirm # ── Crown Jewel #2: AUR ─────────────────────────────────────────────────────── RUN useradd -m -s /bin/zsh -G wheel aurbuild && \ echo 'aurbuild ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/aurbuild RUN cd /tmp && \ git clone --depth=1 https://aur.archlinux.org/yay-bin.git && \ chown -R aurbuild:aurbuild yay-bin && \ cd yay-bin && \ sudo -u aurbuild makepkg -si --noconfirm && \ cd / && rm -rf /tmp/yay-bin RUN sudo -u aurbuild yay -S --noconfirm --needed \ eza \ wl-clipboard \ trash-cli \ tailscale \ && sudo -u aurbuild yay -Scc --noconfirm # ── Dev user with host-matching UID/GID ─────────────────────────────────────── # UID/GID match host so /workspace bind mount has clean permissions both sides RUN groupadd -g ${USER_GID} dev && \ useradd -m -s /bin/zsh -u ${USER_UID} -g ${USER_GID} -G wheel dev && \ echo 'dev ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/dev # ── Skeleton: bake dotfiles into /etc/skel-arch-dev/ ────────────────────────── COPY --chown=dev:dev dotfiles/ /etc/skel-arch-dev/ # ── Initial seed of /home/dev so plugin bake works at build time ────────────── RUN cp -an /etc/skel-arch-dev/. /home/dev/ && \ chown -R dev:dev /home/dev # ── nvm + LTS Node (as dev user) ────────────────────────────────────────────── # nvm install script writes to ~/.zshrc — we sandbox it then merge cleanly RUN sudo -u dev bash -c '\ export PROFILE=/dev/null && \ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash && \ export NVM_DIR="/home/dev/.nvm" && \ [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && \ nvm install --lts && \ nvm alias default node \ ' # Persist nvm install into the skel template so volume seeding includes it RUN cp -an /home/dev/.nvm /etc/skel-arch-dev/ && \ chown -R dev:dev /etc/skel-arch-dev/.nvm # ── Python tools ────────────────────────────────────────────────────────────── RUN pip install --break-system-packages pynvim httpx requests # ── Bake neovim plugins ─────────────────────────────────────────────────────── RUN sudo -u dev HOME=/home/dev XDG_DATA_HOME=/home/dev/.local/share \ nvim --headless +"Lazy! sync" +qa 2>/dev/null; exit 0 RUN sudo -u dev HOME=/home/dev XDG_DATA_HOME=/home/dev/.local/share \ nvim --headless \ +"TSUpdateSync python bash lua json yaml toml markdown vim vimdoc regex" \ +qa 2>/dev/null; exit 0 # Copy fully-baked /home/dev back into the skel template RUN cp -an /home/dev/.local /etc/skel-arch-dev/ && \ cp -an /home/dev/.cache /etc/skel-arch-dev/ 2>/dev/null || true && \ chown -R dev:dev /etc/skel-arch-dev # ── Cleanup AUR build user ──────────────────────────────────────────────────── RUN userdel -r aurbuild && rm -f /etc/sudoers.d/aurbuild # ── Entrypoint script ───────────────────────────────────────────────────────── COPY entrypoint.sh /usr/local/bin/arch-dev-entrypoint RUN chmod +x /usr/local/bin/arch-dev-entrypoint # ── Final permissions ───────────────────────────────────────────────────────── RUN chown -R dev:dev /home/dev USER dev WORKDIR /workspace ENTRYPOINT ["/usr/local/bin/arch-dev-entrypoint"] CMD ["/bin/zsh"]