commit 9232cf030bd37566a62641e2cccc0fff2a24798e Author: Matthew Binning Date: Sat Mar 29 14:02:53 2025 -0700 init: Start dotfiles with a test container to verify installation. diff --git a/.config/aliasrc b/.config/aliasrc new file mode 100644 index 0000000..c31bc41 --- /dev/null +++ b/.config/aliasrc @@ -0,0 +1,18 @@ +#!/bin/sh + +# Typical verbosity and settings. +alias \ + mkd='mkdir -pv' \ + ffmepg='ffmpeg -hidebanner' + +# Colorize when possible. +alias \ + ls='ls -h -N -G --group-directories-first' \ + grep='grep --color=auto' + +# Shortenings +alias \ + d='docker' \ + h='history' \ + l='less' \ + s='sudo' diff --git a/.config/inputrc b/.config/inputrc new file mode 100644 index 0000000..5c96822 --- /dev/null +++ b/.config/inputrc @@ -0,0 +1,47 @@ +$include /etc/inputrc + +set colored-stats On +set completion-prefix-display-length 6 +set mark-symlinked-directories On + +set bell-style none +set completion-ignore-case off +set show-all-if-ambiguous on +set menu-complete-display-prefix on + +"\e[Z": menu-complete +"\e[A": history-search-backward +"\e[B": history-search-forward + +# "\eOd": backward-word +# "\eOc": forward-word +# +# # for linux console +# "\e[1~": beginning-of-line +# "\e[4~": end-of-line +# "\e[5~": beginning-of-history +# "\e[6~": end-of-history +# "\e[3~": delete-char +# "\e[2~": quoted-insert +# +# # for xterm +# "\eOH": beginning-of-line +# "\eOF": end-of-line + +set editing-mode vi +$if mode=vi + +set show-mode-in-prompt on +set vi-ins-mode-string \1\e\[6 q\2 +set vi-cmd-mode-string \1\e\[2 q\2 + +set keymap vi-command +Control-l: clear-screen +Control-a: beginning-of-line + +set keymap vi-insert +Control-l: clear-screen +Control-a: beginning-of-line +"\C-i": menu-complete + +$endif diff --git a/.containerignore b/.containerignore new file mode 100644 index 0000000..01cb1dc --- /dev/null +++ b/.containerignore @@ -0,0 +1,7 @@ +CHANGELOG.md +Containerfile +.containerignore +.dockerignore +.git +.gitignore +README.md diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..aec4966 --- /dev/null +++ b/.gitconfig @@ -0,0 +1,18 @@ +[user] + email = matthew@binning.dev + name = Matthew Binning +[diff] + tool = vimdiff +[difftool] + prompt = false +[difftool "sdiff"] + cmd = cmddiff $LOCAL $REMOTE +[merge] + tool = fugitive +[alias] + df = difftool + sdiff = difftool --ignore-submodules --tool=sdiff +[mergetool] + prompt = false +[mergetool "fugitive"] + cmd = vim -f -c \"Gvdiff\" \"$MERGED\" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be78379 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.cache +.config/shell/histfile +.config/sfeed/feeds +.config/sfeed/urls +.config/when/calendar +.*history +.local/share/nvim/site/pack/gitmodules/start/er.vim/* +.local/share/nvim/site/pack/gitmodules/start/indentLine/* +.local/share/nvim/site/pack/gitmodules/start/lspconfig/* +.local/share/nvim/site/pack/gitmodules/start/lspconfig/.* +.local/share/nvim/site/pack/gitmodules/start/todo.txt-vim/* +.kube/ diff --git a/.profile b/.profile new file mode 100644 index 0000000..c60808c --- /dev/null +++ b/.profile @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +# PS1='[\u@\h \W]\$ ' + +export XDG_CONFIG_HOME="$HOME/.config" +export XDG_DATA_HOME="$HOME/.local/share" +export XDG_CACHE_HOME="$HOME/.cache" + +export INPUTRC="${XDG_CONFIG_HOME:-$HOME/.config}/inputrc" +export ALIASRC="${XDG_CONFIG_HOME:-$HOME/.config}/aliasrc" + +if docker --version > /dev/null 2>&1; then + PS1="\[\033[38;5;34m\]\u@\h \W]\\$\[$(tput sgr0)\] " + export PS1 +else + PS1="\[\033[38;5;44m\]\u@\h \W]\\$\[$(tput sgr0)\] " + export PS1 +fi + +# Git should ask for a password through the command line. +unset GIT_ASKPASS +unset SSH_ASKPASS + +# shellcheck source=./.config/aliasrc +[ -f "$ALIASRC" ] && . ./"$ALIASRC" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7ce0d8b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +ARG BASE_REGISTRY=docker.io +ARG BASE_IMAGE=alpine +ARG BASE_TAG=latest +FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} AS base +RUN apk update && \ + apk upgrade && \ + apk add make + +FROM base as test +RUN adduser -D user +USER user +WORKDIR /home/user/dotfiles +COPY --chown=user ./ ./ +ENTRYPOINT [ "make" ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1eb4f3f --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +.POSIX: +.SUFFIXES: + +COLOR_BLUE:=\033[36m +COLOR_AUTO:=\033[0m +SRC=.config/aliasrc .config/inputrc .gitconfig .*profile +TGT=$(addprefix $$HOME/, $(SRC)) + +.PHONY: help ## Show this help menu. +help: + @printf 'make \n\nsubcommand:\n' + @awk -F '(: | ## )' '/^\.PHONY:.*?## .*$$/ {\ + printf("\t$(COLOR_BLUE)%s\t\t$(COLOR_AUTO)%s\n",$$2, $$3)\ + }' $(MAKEFILE_LIST) + +.PHONY: installcheck ## Check if the dotfiles are properly linked to home. +installcheck: + # Assert link sources match link destinations. + for link in $(SRC); do \ + dst_link=$$(stat -c "%N" ~/"$$link" | cut -d ' ' -f 3); \ + src_link="$$PWD/$$link"; \ + if [ ! "$$dst_link" = \'"$$src_link"\' ]; then \ + printf 'Destination link matches not the source link!\n'; \ + fi; \ + done + +# RFE: Use the single suffix inference rule to enhance iteration semantics +# to actual Makefile semantics. This could probably be done by suffixing source +# links with .ln. +.PHONY: install ## Actually symlink the dotfiles to home. +install: $(SRC) + mkdir -p $(dir $(TGT)) + for file in $(SRC); do $(RM) -r ~/$$file; ln -s $$PWD/$$file ~/$$file; done + +.PHONY: uninstallcheck ## Check if dotfiles' symlinks were properly removed. +uninstallcheck: + # Assert destination links were removed. + for link in $(TGT); do \ + [ ! -e ~/"$$link" ] || \ + printf '%s%s\n' "$$link" "survived teardown!"; \ + done + +.PHONY: uninstall ## Remove the symlinks to dotfiles. +uninstall: + $(RM) -r $(TGT) + for file in $(TGT); do if [ -e "$$file~" ]; then mv "$$file~" "$$file"; fi; done + +.PHONY: clean ## Purge cruft (not the dotfiles payload). +clean: + -docker rm check_dotfiles + -docker rmi dotfiles + +# ---------------------------------------------------------------------------- +# Make is not really a good system for this. +# It works with files, but this works with containers. +# Write a deployment for the test container? + +.PHONY: all ## lint -> build -> check +all: lint build check + +.PHONY: lint ## Lint the source repository. +lint: + docker run --rm \ + -u "$(shell id -u):$(shell id -g)" \ + -v "$(shell pwd):/mnt" \ + -w /mnt \ + mvdan/shfmt:latest -d -sr -i 4 .config/aliasrc .*profile + docker run --rm \ + -u "$(shell id -u):$(shell id -g)" \ + -v "$(shell pwd):/mnt" \ + -w /mnt \ + koalaman/shellcheck -x .config/aliasrc .*profile + +.PHONY: build ## Build a container to system-test the dotfiles. +build: + docker build --target test --tag dotfiles . + +.PHONY: check ## Check if (un)install works in the test container. +check: build + docker run --name="check_dotfiles" --tty -d --entrypoint sh dotfiles + docker exec check_dotfiles make install + docker exec check_dotfiles make installcheck + docker exec check_dotfiles make uninstall + docker exec check_dotfiles make uninstallcheck + docker stop check_dotfiles +# ---------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..64e7723 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# dotfiles + +This source repository contains configuration for common Unix systems. + +Influences include: + +- [Luke Smith's voidrice](https://github.com/lukesmithxyz/voidrice) +- [Whynothugo's dotfiles](https://git.sr.ht/~whynothugo/dotfiles) + +## Install + +This uses `make`. + +## Test + +To create a container, install the dotfiles there, check the installation, and then destroy the container, run: + +``` +make check +``` diff --git a/gitignore.template b/gitignore.template new file mode 100644 index 0000000..3cdc6bb --- /dev/null +++ b/gitignore.template @@ -0,0 +1,219 @@ +### Project specific +.gen/**/*_pb2*.py + +*_output.mpg +test-results.xml + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ +