first working version

main
World's Tallest Ladder 2025-03-30 22:35:51 -07:00
parent 24cd1f0fa0
commit a81621cc99
Signed by: wtl
GPG Key ID: F0D4D5526213099D
10 changed files with 642 additions and 14 deletions

24
LICENSE
View File

@ -1,16 +1,16 @@
MIT No Attribution
Copyright <YEAR> <COPYRIGHT HOLDER>
Copyright 2025 World's Tallest Ladder
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,3 +1,46 @@
# webhost-setup
# Webhost Setup
Simple setup script using ansible for a generic webhost that installs initialization scripts and tools.
Simple setup script for a generic webhost that installs initialization scripts
and tools.
See the `playbook.yaml` file for what's installed as well as the other files for
the configuration that gets installed.
## Requirements
Host requires the following:
- ssh access
- [Cargo](https://github.com/rust-lang/cargo)
- [Composer](https://getcomposer.org/)
- [npm](https://www.npmjs.com/)
- [pip](https://pypi.org/project/pip/)
Optional requriements where configuration is installed for:
- [tmux](https://github.com/tmux/tmux/wiki)
- [vim](https://www.vim.org/)
- [zsh](https://www.zsh.org/)
An inventory file at `~/.config/ansible/hosts` with an entry for a host
`webhost`. This may be a group if you want to target multiple hosts.
Your machine requires the following:
- [ansible](https://www.redhat.com/en/ansible-collaborative)
- [zsh](https://www.zsh.org/)
Additionally, there are some ansible galaxy requirements you need toi install
first via:
```zsh
ansible-galaxy collection install -r requirements.yaml
```
## Run
Run via the following:
```zsh
./run.zsh
```

2
configurations/npmrc Normal file
View File

@ -0,0 +1,2 @@
cache=${HOME}/.npm/packages
prefix=${HOME}/.npm

12
configurations/tmux.conf Normal file
View File

@ -0,0 +1,12 @@
# Enable 256 colors
set -g default-terminal "tmux-256color"
# Tmux plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
# Powerline
source "$POWERLINE_TMUX"
# Set up tmux plugin manager
run '~/.tmux/plugins/tpm/tpm'

117
configurations/vimrc Normal file
View File

@ -0,0 +1,117 @@
" set encoding
set encoding=UTF-8
" Press F2 to switch between paste and nopaste mode
set pastetoggle=<F2>
" Helpful line# column# indicator
set ruler
" Enhance commendline autocomplete
set wildmenu
" Ignore case when searching...
set ignorecase
" ...except for when you specifically use capital letters
set smartcase
" Let VIM modify the terminal title
set title
" Autoindentation
set autoindent
set copyindent
" Show the matching brace
set showmatch
" Don't use swap files
set noswapfile
" Use backup files
set backupcopy=yes
" Use a visual bell rather than an audio one
set visualbell
" Don't use error bells
set noerrorbells
" Show a line on the line you're currently on
set cursorline
" No folding
set nofoldenable
" Syntax Highlighting
syntax on
filetype on
filetype plugin on
filetype indent on
" Highlight matches to search strings
set hlsearch
" Have j and k go up/down one visual line rather than actual line
nnoremap j gj
nnoremap k gk
" <leader>l toggles line numbers
nnoremap <leader>l :setlocal number!<CR>
" <leader>q toggles search highlighting
nnoremap <leader>q :nohlsearch<CR>
" <leader>s fix syntax
nnoremap <leader>s :syntax sync fromstart<CR>
" Ignore CSV files
au BufRead,BufNewFile *.csv match
" Colorscheme
colorscheme brogrammer
" indentation search
nnoremap <leader>j m':exec '/\%' . col(".") . 'c\S'<CR>``n
nnoremap <leader>k m':exec '?\%' . col(".") . 'c\S'<CR>``n
" Spellcheck
map <F5> :setlocal spell! spelllang=en_us<CR>
" vimdiff ignore empty lines
set diffopt+=iwhite
set diffexpr=MyDiff()
function MyDiff()
let opt = ""
if &diffopt =~ "icase"
let opt = opt . "-i "
endif
if &diffopt =~ "iwhite"
let opt = opt . "-w -B " " vim uses -b by default
endif
silent execute "!diff -a " . opt .
\ v:fname_in . " " . v:fname_new . " > " . v:fname_out
endfunction
" Do not wrap text
set textwidth=0
" highlight custom gitconfig files
au BufRead,BufNewFile */gitconfig setfiletype gitconfig
au BufRead,BufNewFile *.gitconfig setfiletype gitconfig
" highlight custom sshconfig files
au BufRead,BufNewFile */sshconfig setfiletype sshconfig
au BufRead,BufNewFile *.sshconfig setfiletype sshconfig
" Show max line from editorconfig
let g:EditorConfig_max_line_indicator = "line"
" Ale configration
let g:ale_fix_on_save = 1
let g:ale_linters = {
\ 'json': ['jq', 'jsonlint', 'spectral'],
\}
let g:ale_fixers = {
\ '*': ['remove_trailing_lines', 'trim_whitespace'],
\ 'css': ['prettier'],
\ 'html': ['prettier'],
\ 'javascript': ['eslint', 'prettier'],
\ 'json': ['prettier'],
\ 'markdown': ['prettier'],
\ 'php': ['php_cs_fixer', 'phpcbf'],
\ 'python': ['autopep8'],
\ 'scss': ['prettier'],
\ 'typescript': ['eslint', 'prettier'],
\ 'yaml': ['prettier'],
\}
let g:ale_completion_autoimport = 1
let g:ale_completion_enabled = 1
" go load all symbols in package
let g:ale_go_golangci_lint_package = 1
nnoremap <leader>f :ALEFix<CR>
" Powerline
set rtp+=$POWERLINE_VIM
set laststatus=2
set t_Co=256
set noshowmode
" Don't autoformat on save
let g:format_on_save = 0
let g:ale_fix_on_save = 0

2
configurations/zshenv Normal file
View File

@ -0,0 +1,2 @@
# UTF-8 Support
setopt COMBINING_CHARS

232
configurations/zshrc Normal file
View File

@ -0,0 +1,232 @@
###
# zsh setup
###
# Remove $HOME trailing slash
HOME="${HOME%/}"
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# In zsh, $path is an array with the values of $PATH, setting -U ensures it
# only contains unique entries
typeset -U path=("$path[@]")
# partial completion suggestions
zstyle ':completion:*' list-suffixes
zstyle ':completion:*' expand prefix suffix
# load bashcompinit for some old bash completions
autoload bashcompinit && bashcompinit
mkdir -p ~/.zfunc
fpath+=("$HOME/.zfunc")
# Enable advanced auto completion
if command -v brew >/dev/null 2>&1 && [ -n "$ZSH_VERSION" ]; then
# Brew install zsh to "insecure" directories, -i silently ignores the results
# of those security checks
autoload -Uz compinit && compinit -i
else
autoload -Uz compinit && compinit
fi
# enable vim mode
set -o vi
# Enable command correction
setopt CORRECT
setopt CORRECT_ALL
# Where should the history file be saved
HISTFILE=${ZDOTDIR:-$HOME}/.zsh_history
# Size of history file
SAVEHIST=5000
HISTSIZE=2000
# share history across multiple zsh sessions
setopt SHARE_HISTORY
# append to history
setopt APPEND_HISTORY
# adds commands as they are typed, not at shell exit
setopt INC_APPEND_HISTORY
# expire duplicates first
setopt HIST_EXPIRE_DUPS_FIRST
# do not store duplications
setopt HIST_IGNORE_DUPS
#ignore duplicates when searching
setopt HIST_FIND_NO_DUPS
# removes blank lines from history
setopt HIST_REDUCE_BLANKS
# Enable additional features in history
setopt EXTENDED_HISTORY
# Show `!!` command before executing
setopt HIST_VERIFY
# You may need to manually set your language environment
export LANG=en_US.UTF-8
###
# Path setup
###
# Local installations; add to front
path[1,0]="$HOME/.local/bin"
# Man files
if command -v man >/dev/null 2>&1; then
if ! [ "$MANPATH" ]; then
export MANPATH="$(manpath)"
fi
if ! echo $MANPATH | grep -q "$HOME/.local/share/man"; then
MANPATH="$HOME/.local/share/man:$MANPATH"
fi
fi
###
# Language setup
###
# Node
## npm packages
if command -v npm >/dev/null 2>&1 && [ -d "$HOME/.npm/bin" ] 2>&1; then
path+=("$HOME/.npm/bin")
fi
## n
if command -v n >/dev/null 2>&1; then
export N_PREFIX="$HOME/.n"
# add to start of path
path[1,0]=("$N_PREFIX/bin")
fi
# Python
alias python="python3"
alias pip="python -m pip"
export PYTHON_BASE="$(python -m site --user-base)"
export PYTHON_SITE="$(python -m site --user-site)"
path+=("$PYTHON_BASE/bin")
# update script to update all local pip packages
pip-update() {
pip --disable-pip-version-check list --user --outdated --format=json | \
python -c "import json, sys; print('\n'.join([x['name'] for x in json.load(sys.stdin)]))" | \
xargs -n1 pip install --user -U
}
# Rust / Cargo
if command -v cargo >/dev/null 2>&1; then
path+=("$HOME/.cargo/bin")
fi
# Composer / PHP
if command -v composer >/dev/null 2>&1; then
export COMPOSER_HOME="$HOME/.config/composer"
path+=("$COMPOSER_HOME/vendor/bin")
fi
if command -v php >/dev/null 2>&1; then
alias php="/usr/bin/env php -c $HOME/.config/php/php.ini"
fi
##
# User configuration
###
# Tmux
# Force it to believe the terminal supports 256 colors
if command -v tmux >/dev/null 2>&1; then
alias tmux="/usr/bin/env tmux -2"
fi
# make less more friendly for non-text input files, see lesspipe(1)
if command -v lesspipe >/dev/null 2>&1; then
eval "$(SHELL=/bin/sh lesspipe)"
fi
if command -v eza >/dev/null 2>&1; then
# Use lsd as ls alias
alias ls="eza --color=auto --icons --group-directories-first"
else
# enable color support of ls and also add handy aliases
if command -v dircolors >/dev/null 2>&1; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
fi
alias ls="ls --color=auto"
fi
# colored GCC warnings and errors
export GCC_COLORS="error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01"
# color for grep
alias grep="grep --color=auto"
# Powerline
export POWERLINE_PYTHON_BINDINGS="$PYTHON_SITE/powerline/bindings"
POWERLINE_VIM="$POWERLINE_PYTHON_BINDINGS/vim/"
POWERLINE_TMUX="$POWERLINE_PYTHON_BINDINGS/tmux/powerline.conf"
if ! [ -f "$POWERLINE_TMUX" ]; then
# Handle case where tmux config isn't installed
POWERLINE_TMUX="/tmp/powerline.conf"
touch "$POWERLINE_TMUX"
fi
if command -v powerline-daemon >/dev/null 2>&1; then
powerline-daemon -q
fi
# starship
if command -v starship >/dev/null 2>&1; then
eval "$(starship init zsh)"
fi
# Set editor
export EDITOR="$(which vim)"
# Editor alias
edit() {
$EDITOR "$@"
}
# clear caches
clear-caches() {
if command -v cargo >/dev/null 2>&1; then
if cargo install --list | grep 'cargo-cache' >/dev/null; then
cargo cache -a
fi
fi
if command -v go >/dev/null 2>&1; then
go clean -modcache
fi
if command -v composer >/dev/null 2>&1; then
composer clear-cache
fi
}
# Attach tmux when ssh session starts, exit when it exits
if command -v tmux >/dev/null 2>&1; then
if ([ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]) \
&& command -v tmux &> /dev/null \
&& [ -n "$PS1" ] \
&& [[ ! "$TERM" =~ screen ]] \
&& [[ ! "$TERM" =~ tmux ]] \
&& [ -z "$TMUX" ]; then
exec tmux new -A -s default && exit
fi
fi
# Set personal aliases, overriding those provided by oh-my-zsh libs,
# plugins, and themes. Aliases can be placed here, though oh-my-zsh
# users are encouraged to define aliases within the ZSH_CUSTOM folder.
# For a full list of active aliases, run `alias`.
## Get submodules to match latest committed commit in parent repo
alias fix-submodules="git submodule update --recursive -f"

197
playbook.yaml Normal file
View File

@ -0,0 +1,197 @@
# vi:syntax=yaml.ansible
---
- name: Environment Setup
hosts: webhost
gather_facts: true
become: false
tasks:
- name: Set variables
ansible.builtin.set_fact:
home: "{{ ansible_env.HOME | regex_replace('/$', '') }}"
composer_packages:
- friendsofphp/php-cs-fixer
- phpcompatibility/php-compatibility
- phpstan/phpstan
- psy/psysh
- rector/rector
- slevomat/coding-standard
- squizlabs/php_codesniffer
- vimeo/psalm
- name: Copy zshrc
ansible.builtin.copy:
dest: "{{ home }}/.zshrc"
src: configurations/zshrc
- name: Copy zshenv
ansible.builtin.copy:
dest: "{{ home }}/.zshenv"
src: configurations/zshenv
- name: Copy npmrc
ansible.builtin.copy:
dest: "{{ home }}/.npmrc"
src: configurations/npmrc
- name: Copy vimrc
ansible.builtin.copy:
dest: "{{ home }}/.vimrc"
src: configurations/vimrc
- name: Copy tmux.conf
ansible.builtin.copy:
dest: "{{ home }}/.tmux.conf"
src: configurations/tmux.conf
- name: Install npm tools
community.general.npm:
name: "{{ item }}"
global: true
loop:
- eslint
- prettier
- name: Update npm packages
community.general.npm:
global: true
state: latest
- name: Configure composer
# composer requires a modern amount of memory to update,
# so only run on systems with 2gb or more
when: ansible_memtotal_mb >= 2048
changed_when: false
community.general.composer:
arguments: "--no-interaction {{ item.key }} {{ item.value }}"
command: config
global_command: true
environment:
COMPOSER_HOME: "{{ home }}/.config/composer"
loop:
- key: allow-plugins.dealerdirect/phpcodesniffer-composer-installer
value: "true"
- key: minimum-stability
value: "stable"
- key: prefer-stable
value: "true"
- name: Install composer packages
# composer requires a modern amount of memory to update,
# so only run on systems with 2gb or more
when: ansible_memtotal_mb >= 2048
community.general.composer:
arguments: "--no-interaction --dev {{ composer_packages | join(' ') }}"
command: require
global_command: true
no_dev: false
optimize_autoloader: false
environment:
COMPOSER_HOME: "{{ home }}/.config/composer"
- name: Update composer packages
# composer requires a modern amount of memory to update,
# so only run on systems with 2gb or more
when: ansible_memtotal_mb >= 2048
community.general.composer:
arguments: --no-interaction
command: update
global_command: true
no_dev: false
optimize_autoloader: false
environment:
COMPOSER_HOME: "{{ home }}/.config/composer"
- name: Install pip packages
ansible.builtin.pip:
name:
- hyfetch
- powerline-gitstatus
- powerline-status
extra_args: --user
state: latest
- name: tmux plugins
ansible.builtin.git:
repo: https://github.com/{{ item.owner }}/{{ item.repo }}
dest: "{{ home }}/.tmux/plugins/{{ item.repo }}"
depth: 1
force: true # disregard local changes
loop:
- owner: tmux-plugins
repo: tmux-sensible
- owner: tmux-plugins
repo: tpm
- name: create vim directory
ansible.builtin.file:
path: "{{ home }}/.vim/pack/git-plugins/start"
state: directory
- name: vim plugins
ansible.builtin.git:
repo: https://github.com/{{ item.owner }}/{{ item.repo }}
dest: "{{ home }}/.vim/pack/git-plugins/start/{{ item.repo }}"
depth: 1
force: true # disregard local changes
loop:
- owner: adelarsq
repo: vim-matchit
- owner: cespare
repo: vim-toml
- owner: chrisbra
repo: csv.vim
- owner: dense-analysis
repo: ale
- owner: editorconfig
repo: editorconfig-vim
- owner: fatih
repo: vim-go
- owner: flazz
repo: vim-colorschemes
- owner: fpob
repo: nette.vim
- owner: idanarye
repo: vim-vebugger
- owner: imsnif
repo: kdl.vim
- owner: leafgarland
repo: typescript-vim
- owner: lumiliet
repo: vim-twig
- owner: martinda
repo: jenkinsfile-vim-syntax
- owner: mattn
repo: emmet-vim
- owner: pearofducks
repo: ansible-vim
- owner: plasticboy
repo: vim-markdown
- owner: quramy
repo: tsuquyomi
- owner: rust-lang
repo: rust.vim
- owner: ryanoasis
repo: vim-devicons
- owner: scrooloose
repo: nerdtree
- owner: shougo
repo: vimproc.vim
- owner: towolf
repo: vim-helm
- owner: tpope
repo: vim-fugitive
- owner: tpope
repo: vim-liquid
- owner: tpope
repo: vim-sensible
- name: symlink vim colors
ansible.builtin.file:
dest: "{{ home }}/.vim/colors"
src: "{{ home }}/.vim/pack/git-plugins/start/vim-colorschemes/colors"
state: link
- name: Install cargo packages
ansible.builtin.command:
cmd: "cargo install {{ item.package }}"
creates: "{{ home }}/.cargo/bin/{{ item.bin }}"
loop:
- package: cargo-update
bin: cargo-install-update
- package: eza
bin: eza
- package: ripgrep
bin: rg
- package: sd
bin: sd
- package: starship
bin: starship
- name: Update cargo packages
ansible.builtin.command:
cmd: cargo install-update --all
register: cargo_update
changed_when: cargo_update.stdout.find('No packages need updating.') == -1

14
requirements.yaml Normal file
View File

@ -0,0 +1,14 @@
# vi:syntax=yaml.ansible
#########
#
# Use ansible galaxy tools to use extensions to ansible
#
# Run this to install dependencies:
#
# ```sh
# ansible-galaxy collection install -r requirements.yaml
# ```
#
---
collections:
- community.general

9
run.zsh Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env zsh
local DIR="${0:a:h}"
ansible-playbook \
--ask-vault-pass \
--inventory-file "$HOME/.config/ansible/hosts" \
--limit "webhost" \
"$DIR/playbook.yaml"