├── .gitignore ├── roles ├── media │ └── files │ │ ├── MakeMKV │ │ ├── settings.conf │ │ └── update.conf │ │ └── abcde.conf ├── tmux │ ├── vars │ │ ├── apt.yml │ │ ├── homebrew.yml │ │ ├── dnf5.yml │ │ └── main.yml │ ├── files │ │ └── tmuxp │ │ │ ├── main.yml │ │ │ ├── nb.yml │ │ │ └── dotfiles.yml │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── tmux.conf.j2 ├── zsh │ ├── files │ │ ├── zshenv │ │ └── rc.d │ │ │ ├── reload.zsh │ │ │ ├── fzf.zsh │ │ │ ├── atuin.zsh │ │ │ ├── show.zsh │ │ │ ├── gcsh.zsh │ │ │ └── prompt.zsh │ ├── handlers │ │ └── main.yml │ ├── templates │ │ └── zshrc │ │ │ ├── 50-parameters.zsh.j2 │ │ │ ├── 70-compinit.zsh.j2 │ │ │ ├── 90-evals.zsh.j2 │ │ │ ├── 40-zstyle.zsh.j2 │ │ │ ├── 80-sources.zsh.j2 │ │ │ ├── 60-setopt.zsh.j2 │ │ │ ├── 30-functions.zsh.j2 │ │ │ ├── 20-aliases.zsh.j2 │ │ │ ├── 00-PATHs.zsh.j2 │ │ │ └── 10-exports.zsh.j2 │ ├── vars │ │ └── main.yml │ ├── tasks │ │ ├── completions.yml │ │ ├── zshrc.yml │ │ └── main.yml │ └── defaults │ │ └── main.yml ├── dotfiles │ ├── files │ │ ├── home │ │ │ ├── .config │ │ │ │ ├── diceware │ │ │ │ │ └── diceware.ini │ │ │ │ ├── bat │ │ │ │ │ └── config │ │ │ │ ├── ghostty │ │ │ │ │ └── config │ │ │ │ ├── glow │ │ │ │ │ ├── glow.yml │ │ │ │ │ └── themes │ │ │ │ │ │ └── solarized-light.json │ │ │ │ ├── fzf │ │ │ │ │ └── config │ │ │ │ ├── atuin │ │ │ │ │ └── config.toml │ │ │ │ ├── beets │ │ │ │ │ └── config.yaml │ │ │ │ ├── starship.toml │ │ │ │ ├── eza │ │ │ │ │ ├── theme.yml │ │ │ │ │ └── themes │ │ │ │ │ │ ├── solarized-light.yml │ │ │ │ │ │ └── rose-pine-dawn.yml │ │ │ │ └── fastfetch │ │ │ │ │ └── config.jsonc │ │ │ └── .local │ │ │ │ ├── bin │ │ │ │ ├── numware │ │ │ │ ├── ics2json │ │ │ │ ├── youtube │ │ │ │ ├── pdf-compress │ │ │ │ ├── xdg_cleanup │ │ │ │ ├── ghpr │ │ │ │ ├── mk8sconf │ │ │ │ ├── id3renamer │ │ │ │ └── bmux │ │ │ │ └── share │ │ │ │ └── keychain │ │ │ │ └── init │ │ └── root │ │ │ ├── .bash_profile │ │ │ ├── .tmux.conf │ │ │ ├── .vimrc │ │ │ └── .bashrc │ ├── defaults │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── desktop │ ├── files │ │ └── icons │ │ │ ├── VLC.icns │ │ │ ├── Firefox.icns │ │ │ ├── PPSSPP.icns │ │ │ ├── Pocket.icns │ │ │ └── MusicBrainz Picard.icns │ ├── handlers │ │ └── main.yml │ ├── vars │ │ └── main.yml │ ├── defaults │ │ └── main.yml │ └── tasks │ │ ├── icons.yml │ │ ├── fonts │ │ ├── install.yml │ │ └── main.yml │ │ ├── logi.yml │ │ └── main.yml ├── docker │ ├── defaults │ │ └── main.yml │ ├── vars │ │ ├── homebrew.yml │ │ ├── dnf5.yml │ │ └── apt.yml │ ├── templates │ │ └── deb.repo.j2 │ └── tasks │ │ ├── install │ │ ├── dnf5.yml │ │ ├── homebrew.yml │ │ └── apt.yml │ │ └── main.yml ├── git │ ├── templates │ │ ├── allowed_signers.j2 │ │ └── gitconfig.j2 │ ├── handlers │ │ └── main.yml │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ ├── config.yml │ │ ├── install.yml │ │ ├── get_authorized_keys.yml │ │ ├── main.yml │ │ └── clone_repos.yml │ ├── vars │ │ └── main.yml │ └── files │ │ └── gitignore ├── onepassword │ ├── vars │ │ ├── homebrew.yml │ │ ├── main.yml │ │ ├── dnf5.yml │ │ └── apt.yml │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── install │ │ │ ├── homebrew.yml │ │ │ ├── dnf5.yml │ │ │ └── apt.yml │ │ ├── import.yml │ │ ├── main.yml │ │ └── auth.yml │ └── templates │ │ └── op.json.j2 ├── system │ ├── templates │ │ └── resolved.conf.j2 │ ├── vars │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── main.yml │ │ ├── dconf.yml │ │ ├── Darwin.yml │ │ └── Linux.yml │ └── defaults │ │ └── main.yml ├── vim │ ├── files │ │ ├── nvim │ │ │ ├── lua │ │ │ │ ├── options.lua │ │ │ │ ├── mappings.lua │ │ │ │ ├── configs │ │ │ │ │ ├── conform.lua │ │ │ │ │ ├── lspconfig.lua │ │ │ │ │ └── lazy.lua │ │ │ │ ├── plugins │ │ │ │ │ └── init.lua │ │ │ │ └── chadrc.lua │ │ │ ├── .stylua.toml │ │ │ ├── init.lua │ │ │ └── lazy-lock.json │ │ └── helix │ │ │ ├── config.toml │ │ │ └── themes │ │ │ ├── flexoki_light.toml │ │ │ └── solarized_light.toml │ ├── vars │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ ├── defaults │ │ └── main.yml │ └── templates │ │ └── vimrc.j2 ├── pkg_mgr │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── Darwin.yml │ │ ├── pkg_mgr │ │ │ ├── mas.yml │ │ │ ├── flatpak.yml │ │ │ ├── apt.yml │ │ │ ├── homebrew.yml │ │ │ └── dnf5.yml │ │ ├── main.yml │ │ └── Linux.yml │ └── defaults │ │ └── main.yml ├── cloud │ ├── defaults │ │ └── main.yml │ ├── vars │ │ └── main.yml │ ├── files │ │ └── k9s │ │ │ ├── k9s.config.yml │ │ │ └── skins │ │ │ ├── solarized-light.yml │ │ │ └── rosepine-dawn.yml │ └── tasks │ │ └── main.yml └── ssh │ ├── files │ └── op-ssh.bash │ ├── defaults │ └── main.yml │ ├── templates │ └── ssh_config.j2 │ ├── vars │ └── main.yml │ └── tasks │ └── main.yml ├── group_vars ├── Darwin │ ├── misc.yml │ └── pkg_mgr.yml ├── all │ ├── pkg_mgr.yml │ ├── ssh.yml │ ├── git.yml │ ├── dotfiles.yml │ └── system.yml ├── Linux_Mint.yml ├── Debian.yml ├── Ubuntu.yml └── Fedora.yml ├── _config.yml ├── host_vars ├── MacBookPro-m1.yml ├── memory-alpha.yml ├── MacBookAir-m4.yml └── mac06770.yml ├── requirements.txt ├── ansible.cfg ├── Makefile ├── inventory.py ├── templates └── host_vars.yml.j2 ├── play_init_onepassword.yml ├── TODO.md ├── play_all_roles.yml ├── play_bootstrap_ansible.yml ├── README.md └── install /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /roles/media/files/MakeMKV/settings.conf: -------------------------------------------------------------------------------- 1 | app_Key = "" 2 | app_UpdateEnable = '0' 3 | -------------------------------------------------------------------------------- /roles/tmux/vars/apt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | tmux_packages: 4 | - tmux 5 | - tmuxp 6 | -------------------------------------------------------------------------------- /roles/zsh/files/zshenv: -------------------------------------------------------------------------------- 1 | export ZDOTDIR=${XDG_CONFIG_HOME:-$HOME/.config}/zsh 2 | -------------------------------------------------------------------------------- /roles/tmux/vars/homebrew.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | tmux_packages: 4 | - tmux 5 | - tmuxp 6 | -------------------------------------------------------------------------------- /roles/tmux/vars/dnf5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | tmux_packages: 4 | - tmux 5 | - python3-tmuxp 6 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/diceware/diceware.ini: -------------------------------------------------------------------------------- 1 | [diceware] 2 | num = 5 3 | delimiter = "-" 4 | -------------------------------------------------------------------------------- /group_vars/Darwin/misc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | _bat_exec: "/opt/homebrew/bin/bat" 4 | tmux_clipboard: "pbcopy" 5 | -------------------------------------------------------------------------------- /roles/tmux/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | tmux_clipboard_defaults: 4 | Darwin: "pbcopy" 5 | Linux: "wl-copy" 6 | -------------------------------------------------------------------------------- /roles/media/files/MakeMKV/update.conf: -------------------------------------------------------------------------------- 1 | app_UpdateLastCheck = "17815" 2 | app_Key = "" 3 | app_UpdateEnable = "0" 4 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | exclude: 2 | - inventory 3 | - playbooks 4 | - roles 5 | remote_theme: just-the-docs/just-the-docs 6 | -------------------------------------------------------------------------------- /roles/desktop/files/icons/VLC.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyfrank/ansible/HEAD/roles/desktop/files/icons/VLC.icns -------------------------------------------------------------------------------- /roles/docker/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | docker_install_desktop_version: false 4 | docker_install_optional_packages: true 5 | -------------------------------------------------------------------------------- /roles/git/templates/allowed_signers.j2: -------------------------------------------------------------------------------- 1 | {{ global_email_address }} {{ git_signing_pub_key[0] }} {{ git_signing_pub_key[1] }} 2 | -------------------------------------------------------------------------------- /roles/onepassword/vars/homebrew.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | onepassword_packages: 4 | gui: "1password" 5 | cli: "1password-cli" 6 | -------------------------------------------------------------------------------- /roles/desktop/files/icons/Firefox.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyfrank/ansible/HEAD/roles/desktop/files/icons/Firefox.icns -------------------------------------------------------------------------------- /roles/desktop/files/icons/PPSSPP.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyfrank/ansible/HEAD/roles/desktop/files/icons/PPSSPP.icns -------------------------------------------------------------------------------- /roles/desktop/files/icons/Pocket.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyfrank/ansible/HEAD/roles/desktop/files/icons/Pocket.icns -------------------------------------------------------------------------------- /roles/docker/vars/homebrew.yml: -------------------------------------------------------------------------------- 1 | docker_pkgs: 2 | prereqs: [] 3 | packages: 4 | - docker 5 | - hadolint 6 | optional: [] 7 | -------------------------------------------------------------------------------- /roles/docker/vars/dnf5.yml: -------------------------------------------------------------------------------- 1 | docker_pkgs: 2 | packages: 3 | - podman 4 | - hadolint 5 | optional: 6 | - buildah 7 | - skopeo 8 | -------------------------------------------------------------------------------- /roles/system/templates/resolved.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | [Resolve] 4 | FallbackDNS={{ system_linux_dns_fallback | join(' ') }} 5 | -------------------------------------------------------------------------------- /roles/dotfiles/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dotfiles_to_delete: [] 4 | 5 | dotfiles_atuin: 6 | username: "" 7 | password: "" 8 | key: "" 9 | -------------------------------------------------------------------------------- /group_vars/all/pkg_mgr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | pkg_mgr_post_install_commands: 4 | - label: "Rebuild 'bat' cache" 5 | cmd: "{{ _bat_exec }} cache --build" 6 | -------------------------------------------------------------------------------- /roles/desktop/files/icons/MusicBrainz Picard.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyfrank/ansible/HEAD/roles/desktop/files/icons/MusicBrainz Picard.icns -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/bat/config: -------------------------------------------------------------------------------- 1 | --theme="Solarized-Light" 2 | --pager="less -R" 3 | --map-syntax .ignore:.gitignore 4 | --tabs 2 5 | --style plain 6 | -------------------------------------------------------------------------------- /roles/zsh/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Delete zshrc tempfile" 4 | ansible.builtin.file: 5 | state: absent 6 | path: "{{ zsh_temp_dir }}" 7 | -------------------------------------------------------------------------------- /roles/onepassword/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | onepassword_vault: "Private" 4 | onepassword_use_gui_integration: "{{ global_is_desktop_system | default(false) }}" 5 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/ghostty/config: -------------------------------------------------------------------------------- 1 | macos-titlebar-style = native 2 | theme = Builtin Solarized Light 3 | window-padding-y = 10,2 4 | window-theme = system 5 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lua/options.lua: -------------------------------------------------------------------------------- 1 | require "nvchad.options" 2 | 3 | -- add yours here! 4 | 5 | -- local o = vim.o 6 | -- o.cursorlineopt ='both' -- to enable cursorline! 7 | -------------------------------------------------------------------------------- /roles/desktop/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Restart macOS dock" 4 | ansible.builtin.command: 5 | cmd: "killall Dock" 6 | changed_when: false 7 | become: true 8 | -------------------------------------------------------------------------------- /roles/onepassword/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Delete 1Password template" 4 | ansible.builtin.file: 5 | path: "{{ onepassword_template }}" 6 | state: absent 7 | -------------------------------------------------------------------------------- /roles/onepassword/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | onepassword_template: "{{ ansible_facts['user_dir'] }}/op.json" 4 | onepassword_session_file: "{{ ansible_facts['user_dir'] }}/.op_session" 5 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/.stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 120 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferDouble" 6 | call_parentheses = "None" 7 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/50-parameters.zsh.j2: -------------------------------------------------------------------------------- 1 | WORDCHARS=${WORDCHARS//\/[&;]} # Don't consider these part of the word 2 | CORRECT_IGNORE_FILE='.*' # Skip correcting commands matching pattern 3 | KEYTIMEOUT=1 4 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/glow/glow.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/charmbracelet/glow/issues/713 2 | # style: ~/.config/glow/themes/solarized-light.json 3 | local: false 4 | mouse: true 5 | pager: true 6 | width: 100 7 | -------------------------------------------------------------------------------- /roles/git/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Stop ssh-agent" 4 | ansible.builtin.command: 5 | cmd: "ssh-agent -k" 6 | environment: 7 | SSH_AGENT_PID: "{{ git_ssh_auth_pid }}" 8 | changed_when: false 9 | -------------------------------------------------------------------------------- /roles/docker/templates/deb.repo.j2: -------------------------------------------------------------------------------- 1 | deb [arch={{ ansible_facts['architecture'] }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/{{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_release'] }} stable 2 | -------------------------------------------------------------------------------- /roles/pkg_mgr/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Start packagekit" 4 | ansible.builtin.systemd: 5 | name: "packagekit" 6 | state: "started" 7 | enabled: true 8 | become: true 9 | when: pkg_mgr_packagekit_enabled 10 | -------------------------------------------------------------------------------- /roles/cloud/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | cloud_packages: 4 | - google-cloud-sdk 5 | - kubectl 6 | - krew 7 | - k9s 8 | 9 | cloud_krew_plugins: 10 | - cert-manager 11 | - deprecations 12 | - get-all 13 | - neat 14 | - stern 15 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/numware: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Adds numbers to diceware. 5 | # Author: Brad Frank 6 | # Date: April 2024 7 | # Tested: 8 | # 9 | 10 | echo "$(diceware -n "$1")-$(pwgen -1Anr "$(echo {a..z})" "$1")" 11 | -------------------------------------------------------------------------------- /roles/ssh/files/op-ssh.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | vault="$(op vault list --format json 2>/dev/null \ 4 | | jq -r '.[]|.name' \ 5 | | grep -Eo '(Employee|Private)' 6 | )" 7 | 8 | op read "op://${vault}/$(uname -n)/${SSH_ASKPASS_KEY}" 2>/dev/null 9 | -------------------------------------------------------------------------------- /host_vars/MacBookPro-m1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | global_email_address: "bfrank@fastmail.com" 4 | global_is_desktop_system: true 5 | global_desktop_environment: "" 6 | global_homebrew_prefix: "/opt/homebrew" 7 | global_use_1password_ssh_agent: true 8 | cloud_packages: [] 9 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/70-compinit.zsh.j2: -------------------------------------------------------------------------------- 1 | autoload -Uz compinit bashcompinit zmv zcalc vcs_info edit-command-line run-help 2 | compinit -C && bashcompinit 3 | zle -N edit-command-line 4 | bindkey -M vicmd "^X" edit-command-line 5 | bindkey -M viins "^X" edit-command-line 6 | -------------------------------------------------------------------------------- /roles/dotfiles/files/root/.bash_profile: -------------------------------------------------------------------------------- 1 | #shellcheck disable=SC1090,SC1091,SC2148 2 | 3 | PATH=~/.local/bin:~/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin 4 | 5 | export PATH 6 | export VISUAL=vim 7 | export EDITOR=vim 8 | export CLICOLOR=1 9 | 10 | source ~/.bashrc 11 | -------------------------------------------------------------------------------- /roles/system/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | system_pkg_dconf: 4 | apt: "dconf-cli" 5 | dnf5: "dconf" 6 | 7 | system_macos_firewall_cmd: "/usr/libexec/ApplicationFirewall/socketfilterfw" 8 | system_macos_hidden_xattr: "0000000000000000400000000000000000000000000000000000000000000000" 9 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lua/mappings.lua: -------------------------------------------------------------------------------- 1 | require "nvchad.mappings" 2 | 3 | -- add yours here 4 | 5 | local map = vim.keymap.set 6 | 7 | map("n", ";", ":", { desc = "CMD enter command mode" }) 8 | map("i", "jk", "") 9 | 10 | -- map({ "n", "i", "v" }, "", " w ") 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ansible 2 | ansible-lint 3 | bcrypt 4 | cryptography>=35.0.0 5 | distro 6 | github3.py 7 | jmespath 8 | pexpect 9 | psutil 10 | pyobjc-framework-Cocoa; sys_platform == 'darwin' 11 | python-debian; sys_platform == 'linux' 12 | selinux; sys_platform == 'linux' 13 | xkcdpass 14 | -------------------------------------------------------------------------------- /roles/tmux/files/tmuxp/main.yml: -------------------------------------------------------------------------------- 1 | session_name: main 2 | windows: 3 | - window_name: infractl 4 | start_directory: ~/Development/Projects/infractl/main 5 | layout: even-horizontal 6 | panes: 7 | - shell_command: benv_activate && benv_sync && clear 8 | - shell_command: clear 9 | -------------------------------------------------------------------------------- /roles/cloud/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | cloud_krew_root: "{{ ansible_facts['user_dir'] }}/.local/share" 4 | cloud_krew_bin: "{{ global_homebrew_prefix }}/bin/kubectl krew" 5 | 6 | cloud_k9s_configs: 7 | Linux: "{{ ansible_facts['user_dir'] }}/.config/k9s" 8 | Darwin: "{{ ansible_facts['user_dir'] }}/Library/Application Support/k9s" 9 | -------------------------------------------------------------------------------- /roles/git/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | git_github_token: "" 4 | git_repos: [] 5 | git_ssh_authorized_keys_match: "[?contains(title,'{{ ansible_facts['user_id'] }}')&&!contains(title,'{{ ansible_facts['hostname'] }}')]" # "[*]" (match all) 6 | git_signing_pub_key: "{{ lookup('ansible.builtin.file', 'git_ssh_key_public') | split(' ') }}" 7 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | collections_path = ~/.config/ansible/collections 3 | fact_caching = community.general.yaml 4 | fact_caching_connection = ~/.cache/ansible 5 | force_color = true 6 | force_handlers = true 7 | inject_facts_as_vars = false 8 | inventory = inventory.py 9 | local_tmp = /tmp/.ansible 10 | remote_tmp = /tmp/.ansible 11 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/fzf/config: -------------------------------------------------------------------------------- 1 | --border='rounded' 2 | --color='border:#93a1a1,header:#586e75,info:#2aa198,gutter:#eee8d5,prompt:#586e75,pointer:#6c71c4,marker:#dc322f,spinner:#dc322f,fg:#839496,fg+:#586e75,bg:#fdf6e3,bg+:#eee8d5,hl:#839496,hl+:#586e75' 3 | --info='inline' 4 | --select-1 5 | --exit-0 6 | --reverse 7 | --height='~100%' 8 | -------------------------------------------------------------------------------- /roles/system/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Restart macOS dock" 4 | ansible.builtin.command: 5 | cmd: "killall Dock" 6 | changed_when: false 7 | become: true 8 | 9 | - name: "Regenerate Dracut" 10 | ansible.builtin.command: 11 | cmd: "dracut --regenerate-all --force" 12 | changed_when: false 13 | become: true 14 | -------------------------------------------------------------------------------- /roles/system/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Include system-specific tasks" 9 | ansible.builtin.include_tasks: 10 | file: "{{ ansible_facts['system'] }}.yml" 11 | tags: [always] 12 | -------------------------------------------------------------------------------- /roles/vim/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | vim_helix_package: 4 | apt: ["hx"] 5 | homebrew: ["helix"] 6 | dnf5: ["helix"] 7 | 8 | vim_neovim_package: 9 | apt: ["neovim", "python3-neovim"] 10 | homebrew: ["neovim"] 11 | dnf5: ["neovim", "python3-neovim"] 12 | 13 | vim_vim_package: 14 | apt: ["vim"] 15 | homebrew: ["vim"] 16 | dnf5: ["vim"] 17 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/Darwin.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Include Homebrew tasks" 4 | ansible.builtin.include_tasks: 5 | file: "pkg_mgr/homebrew.yml" 6 | tags: [taps, formulas, casks] 7 | 8 | - name: "Install Mac App Store apps" 9 | ansible.builtin.include_tasks: 10 | file: "pkg_mgr/mas.yml" 11 | when: pkg_mgr_gui['mas'] | length > 0 12 | tags: [mas] 13 | -------------------------------------------------------------------------------- /roles/system/tasks/dconf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Apply dconf settings" 4 | community.general.dconf: 5 | key: "{{ dconf_prefix }}/{{ dconf['key'] }}" 6 | value: "{{ dconf['value'] }}" 7 | loop: "{{ dconf_settings | dict2items }}" 8 | loop_control: 9 | label: "{{ dconf_prefix }}/{{ dconf['key'] }}" 10 | loop_var: "dconf" 11 | tags: [dconf] 12 | -------------------------------------------------------------------------------- /roles/desktop/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | desktop_fonts_dir_defaults: 4 | Linux: "{{ ansible_facts['user_dir'] }}/.local/share/fonts" 5 | Darwin: "{{ ansible_facts['user_dir'] }}/Library/Fonts" 6 | 7 | desktop_packages_defaults: 8 | Linux: [solaar] 9 | Darwin: [fileicon, bettermouse] 10 | 11 | desktop_fonts_github_user: "ryanoasis" 12 | desktop_fonts_github_repo: "nerd-fonts" 13 | -------------------------------------------------------------------------------- /host_vars/memory-alpha.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | global_homebrew_prefix: "/home/linuxbrew/.linuxbrew" 4 | global_email_address: "bradfrank@fastmail.com" 5 | global_is_desktop_system: False 6 | global_desktop_environment: "" 7 | global_use_1password_ssh_agent: true 8 | global_host_roles: 9 | - dotfiles 10 | - git 11 | - pkg_mgr 12 | - ssh 13 | - system 14 | - tmux 15 | - vim 16 | - zsh 17 | -------------------------------------------------------------------------------- /roles/pkg_mgr/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | pkg_mgr_current_desktop: "{{ global_desktop_environment | default('none') }}" 4 | pkg_mgr_desktop_present: "{{ global_is_desktop_system | default(false) }}" 5 | pkg_mgr_packagekit_enabled: true 6 | pkg_mgr_homebrew_bin_path: "{{ global_homebrew_prefix }}/bin" 7 | pkg_mgr_homebrew_casks_external: true 8 | pkg_mgr_homebrew_casks_install_options: ["no-quarantine"] 9 | -------------------------------------------------------------------------------- /roles/tmux/files/tmuxp/nb.yml: -------------------------------------------------------------------------------- 1 | session_name: nb 2 | start_directory: ~/Development/Scratch 3 | windows: 4 | - window_name: nb 5 | layout: main-vertical 6 | focus: true 7 | panes: 8 | - shell_command: clear && nb orm:ls --all --no-header --no-footer --no-indicator 9 | - shell_command: clear && nb orm:edit "Journal" 10 | focus: true 11 | - window_name: scratch 12 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lua/configs/conform.lua: -------------------------------------------------------------------------------- 1 | local options = { 2 | formatters_by_ft = { 3 | lua = { "stylua" }, 4 | -- css = { "prettier" }, 5 | -- html = { "prettier" }, 6 | }, 7 | 8 | -- format_on_save = { 9 | -- -- These options will be passed to conform.format() 10 | -- timeout_ms = 500, 11 | -- lsp_fallback = true, 12 | -- }, 13 | } 14 | 15 | return options 16 | -------------------------------------------------------------------------------- /host_vars/MacBookAir-m4.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ## GLOBAL 4 | 5 | global_homebrew_prefix: "/opt/homebrew" 6 | global_email_address: "bradfrank@fastmail.com" 7 | global_is_desktop_system: true 8 | global_desktop_environment: "" 9 | global_use_1password_ssh_agent: true 10 | global_host_roles: 11 | - desktop 12 | - dotfiles 13 | - git 14 | - pkg_mgr 15 | - ssh 16 | - system 17 | - tmux 18 | - vim 19 | - zsh 20 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/pkg_mgr/mas.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install mas formula" 4 | community.general.homebrew: 5 | name: "mas" 6 | state: present 7 | tags: [never, mas] 8 | 9 | - name: "Install apps via mas" 10 | environment: 11 | PATH: "/opt/homebrew/bin:{{ ansible_env['PATH'] }}" 12 | community.general.mas: 13 | id: "{{ pkg_mgr_gui['mas'] }}" 14 | upgrade_all: true 15 | tags: [mas] 16 | -------------------------------------------------------------------------------- /roles/dotfiles/files/root/.tmux.conf: -------------------------------------------------------------------------------- 1 | set -g status-interval 0 2 | set -g default-terminal "screen-256color" 3 | set -g default-command "${SHELL}" 4 | set -g mouse on 5 | set -g history-limit 10000 6 | set -g base-index 1 7 | set -g renumber-windows on 8 | set -g aggressive-resize on 9 | set -g allow-rename off 10 | bind 'y' set synchronize-panes 11 | bind 'h' select-layout even-vertical 12 | bind 'v' select-layout even-horizontal 13 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/atuin/config.toml: -------------------------------------------------------------------------------- 1 | enter_accept = true 2 | keymap_mode = "vim-insert" 3 | sync_address = "https://atuin.francopuccini.casa" 4 | show_preview = true 5 | stats.common_subcommands=["apt","brew","dnf","docker","git","ip","kubectl","nix","nmcli","npm","podman","systemctl","tmux"] 6 | stats.ignored_commands = ["cd","echo","ll","ls","lt","vim"] 7 | style = "full" 8 | sync.records = true 9 | workspaces = true 10 | -------------------------------------------------------------------------------- /roles/onepassword/tasks/install/homebrew.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install cli packages" 4 | community.general.homebrew: 5 | name: "{{ onepassword_packages['cli'] }}" 6 | state: present 7 | tags: [install] 8 | 9 | - name: "Install gui packages" 10 | community.general.homebrew: 11 | name: "{{ onepassword_packages['gui'] }}" 12 | state: present 13 | when: onepassword_use_gui_integration 14 | tags: [install] 15 | -------------------------------------------------------------------------------- /roles/docker/tasks/install/dnf5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install Podman" 4 | ansible.builtin.dnf: 5 | name: "{{ docker_pkgs['packages'] }}" 6 | state: present 7 | become: true 8 | tags: [docker, never] 9 | 10 | - name: "Install optional packages" 11 | ansible.builtin.dnf: 12 | name: "{{ docker_pkgs['optional'] }}" 13 | state: present 14 | become: true 15 | when: docker_install_optional_packages 16 | tags: [docker, never] 17 | -------------------------------------------------------------------------------- /roles/tmux/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | tmux_plugins_dir: "{{ ansible_facts['user_dir'] }}/.local/share" 4 | tmux_config_dir: "{{ ansible_facts['user_dir'] }}/.config/tmux" 5 | 6 | tmux_plugins: 7 | - name: "tmux-resurrect" 8 | repo: "https://github.com/tmux-plugins/tmux-resurrect.git" 9 | exec: "resurrect.tmux" 10 | - name: "tmux-continuum" 11 | repo: "https://github.com/tmux-plugins/tmux-continuum.git" 12 | exec: "continuum.tmux" 13 | -------------------------------------------------------------------------------- /roles/system/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | system_linux_current_desktop: "{{ global_desktop_environment | default('none') }}" 4 | system_linux_dconf: [] 5 | system_linux_dns_fallback: ["9.9.9.9", "1.1.1.1"] 6 | system_linux_enable_bluetooth_boot: true 7 | 8 | system_macos_defaults: [] 9 | system_macos_sleep_display: 15 10 | system_macos_sleep_computer: 30 11 | system_macos_firewall_enabled: true 12 | system_macos_unhide_user_library: true 13 | system_macos_unhide_volumes: true 14 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/90-evals.zsh.j2: -------------------------------------------------------------------------------- 1 | eval "$(batman --export-env)" 2 | eval "$(atuin init zsh)" 3 | {% if (ansible_facts['system'] == "Darwin") and not global_use_1password_ssh_agent %} 4 | eval "$(keychain --eval --ignore-missing --quiet --inherit any {{ ssh_keychain_keys | join(' ') }})" 5 | {% elif (ansible_facts['system'] == "Linux") and not global_use_1password_ssh_agent %} 6 | eval "$(keychain --eval --ignore-missing --quiet {{ ssh_keychain_keys | join(' ') }})" 7 | {% endif %} 8 | -------------------------------------------------------------------------------- /roles/ssh/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ssh_packages: "{{ ssh_packages_defaults[ansible_facts['system']] }}" 4 | ssh_manage_config: true 5 | ssh_harden_security: true 6 | 7 | ssh_keychain_keys: 8 | - id_ed25519 9 | - id_rsa 10 | 11 | ssh_keys: 12 | id_rsa: 13 | type: "rsa" 14 | passphrase: "" 15 | id_ed25519: 16 | type: "ed25519" 17 | passphrase: "" 18 | 19 | ssh_manage_host_keys: true 20 | ssh_host_keys: 21 | - "rsa" 22 | - "ed25519" 23 | - "ecdsa" 24 | -------------------------------------------------------------------------------- /roles/zsh/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | zsh_homebrew_prefix: "{{ global_homebrew_prefix | default('/opt/homebrew') }}" 4 | 5 | zsh_bin_search_paths: 6 | - "{{ ansible_facts['user_dir'] }}/.local/bin" 7 | - "{{ zsh_homebrew_prefix }}/bin" 8 | - "/usr/local/bin" 9 | - "/usr/bin" 10 | - "/bin" 11 | 12 | zsh_chmod_directories: 13 | - "{{ zsh_homebrew_prefix }}/share" 14 | - "{{ zsh_homebrew_prefix }}/share/zsh" 15 | - "{{ zsh_homebrew_prefix }}/share/zsh/site-functions" 16 | -------------------------------------------------------------------------------- /roles/zsh/files/rc.d/reload.zsh: -------------------------------------------------------------------------------- 1 | ZSH_AUTOLOAD="${HOME}/.local/share/zsh/autoload.zsh" 2 | 3 | reload() { 4 | print "rm -f ${HOME}/.config/zsh/.zcompdump" >> "$ZSH_AUTOLOAD" 5 | print "autoload -Uz compinit && compinit" >> "$ZSH_AUTOLOAD" 6 | if [[ -n $VIRTUAL_ENV ]]; then 7 | deactivate 8 | print "benv activate" >> "$ZSH_AUTOLOAD" 9 | fi 10 | exec zsh 11 | } 12 | 13 | if [[ -e "$ZSH_AUTOLOAD" ]]; then 14 | source "$ZSH_AUTOLOAD" 15 | rm -f "$ZSH_AUTOLOAD" 16 | fi 17 | -------------------------------------------------------------------------------- /roles/vim/files/helix/config.toml: -------------------------------------------------------------------------------- 1 | theme = "flexoki_light" 2 | 3 | [editor] 4 | bufferline = "multiple" 5 | cursorline = true 6 | rulers = [100] 7 | #clipboard-provider = "pasteboard" 8 | 9 | [editor.soft-wrap] 10 | enable = true 11 | 12 | [editor.cursor-shape] 13 | insert = "bar" 14 | normal = "block" 15 | select = "underline" 16 | 17 | [editor.indent-guides] 18 | character = "╎" 19 | render = true 20 | 21 | [editor.statusline] 22 | left = ["mode", "spinner", "version-control", "file-name"] 23 | -------------------------------------------------------------------------------- /roles/git/tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Ensure git config directory exists" 4 | ansible.builtin.file: 5 | path: "{{ git_config_dir }}" 6 | state: directory 7 | mode: "0744" 8 | 9 | - name: "Template gitconfig" 10 | ansible.builtin.template: 11 | src: "gitconfig.j2" 12 | dest: "{{ git_config_file }}" 13 | mode: "0640" 14 | 15 | - name: "Copy gitignore" 16 | ansible.builtin.copy: 17 | src: "gitignore" 18 | dest: "{{ git_ignore_file }}" 19 | mode: "0640" 20 | -------------------------------------------------------------------------------- /roles/tmux/files/tmuxp/dotfiles.yml: -------------------------------------------------------------------------------- 1 | session_name: dotfiles 2 | windows: 3 | - window_name: ansible 4 | start_directory: ~/Development/Projects/ansible/main 5 | layout: even-horizontal 6 | panes: 7 | - shell_command: benv_activate && benv_sync && clear 8 | - shell_command: clear 9 | - window_name: dotfiles 10 | start_directory: ~/Development/Projects/dotfiles/main 11 | layout: even-horizontal 12 | panes: 13 | - shell_command: clear 14 | - shell_command: clear 15 | -------------------------------------------------------------------------------- /roles/docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Include variables based on package manager" 9 | ansible.builtin.include_vars: 10 | file: "{{ ansible_facts['pkg_mgr'] }}.yml" 11 | tags: [docker] 12 | 13 | - name: "Include tasks based on package manager" 14 | ansible.builtin.include_tasks: 15 | file: "install/{{ ansible_facts['pkg_mgr'] }}.yml" 16 | tags: [docker] 17 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/pkg_mgr/flatpak.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install Flatpak" 4 | ansible.builtin.package: 5 | name: "flatpak" 6 | state: present 7 | become: true 8 | tags: [flatpak] 9 | 10 | - name: "Install Flathub remote" 11 | community.general.flatpak_remote: 12 | name: "flathub" 13 | flatpakrepo_url: "https://flathub.org/repo/flathub.flatpakrepo" 14 | tags: [flatpak] 15 | 16 | - name: "Install flatpaks" 17 | community.general.flatpak: 18 | name: "{{ pkg_mgr_gui['flatpak'] }}" 19 | tags: [flatpak] 20 | -------------------------------------------------------------------------------- /roles/onepassword/vars/dnf5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | onepassword_packages: 4 | gui: "1password" 5 | cli: "1password-cli" 6 | 7 | onepassword_linux_repo: 8 | name: "1Password" # Avoid name conflict with repo packaged with rpm: 1password.repo 9 | description: "1Password" 10 | baseurl: "https://downloads.1password.com/linux/rpm/stable/$basearch" 11 | gpgkey: "https://downloads.1password.com/linux/keys/1password.asc" 12 | gpgcheck: true 13 | skip_if_unavailable: true 14 | 15 | onepassword_repo_file: "/etc/yum.repos.d/1password.repo" 16 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Include per-system tasks" 9 | ansible.builtin.include_tasks: 10 | file: "{{ ansible_facts['system'] }}.yml" 11 | 12 | - name: "Post-install commands" 13 | ansible.builtin.command: 14 | cmd: "{{ item['cmd'] }}" 15 | loop: "{{ pkg_mgr_post_install_commands }}" 16 | loop_control: 17 | label: "{{ item['label'] }}" 18 | changed_when: true 19 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lua/plugins/init.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "stevearc/conform.nvim", 4 | -- event = 'BufWritePre', -- uncomment for format on save 5 | opts = require "configs.conform", 6 | }, 7 | { 8 | "neovim/nvim-lspconfig", 9 | config = function() 10 | require "configs.lspconfig" 11 | end, 12 | }, 13 | { 14 | "nvim-treesitter/nvim-treesitter", 15 | opts = { 16 | ensure_installed = { 17 | "vim", "lua", "vimdoc", "html", "css" 18 | }, 19 | }, 20 | }, 21 | { 22 | "folke/which-key.nvim" 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /roles/zsh/files/rc.d/fzf.zsh: -------------------------------------------------------------------------------- 1 | typeset -a __eza_opts=( 2 | "--almost-all" 3 | "--long" 4 | "--octal-permissions" 5 | "--group-directories-first" 6 | "--color=always" 7 | "--smart-group" 8 | "--no-permissions" 9 | "--no-filesize" 10 | "--time-style=relative" 11 | ) 12 | 13 | export FZF_DEFAULT_OPTS_FILE="${HOME}/.config/fzf/config" 14 | 15 | zstyle ':fzf-tab:*' switch-group '<' '>' 16 | zstyle ':fzf-tab:*' fzf-flags --height=~100% # resolves problem with single line results list 17 | zstyle ':fzf-tab:complete:cd:*' fzf-preview "eza ${(j' ')__eza_opts} $realpath" 18 | -------------------------------------------------------------------------------- /roles/zsh/files/rc.d/atuin.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | last-command() { 4 | atuin history last --cmd-only 5 | } 6 | 7 | copy-last-command() { 8 | local last_command 9 | if last_command="$(last-command)"; then 10 | print -P -- "Copied: %F{64}${last_command}%f" 11 | case "$(uname --kernel-name)" in 12 | Darwin) pbcopy <<< "$last_command" ;; 13 | Linux) wl-copy <<< "$last_command" ;; 14 | esac 15 | else 16 | print -P -- "%F{160}Could not copy previous command%f" 17 | fi 18 | } 19 | 20 | alias lc="last-command" 21 | alias clc="copy-last-command" 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: dots 2 | dots: 3 | ansible-playbook play_all_roles.yml --tags dots 4 | moredots: 5 | ansible-playbook play_all_roles.yml --tags dots,moredots 6 | tmux: 7 | ansible-playbook play_all_roles.yml --tags tmux --skip-tags become,install 8 | vim: 9 | ansible-playbook play_all_roles.yml --tags vim --skip-tags become,install 10 | zsh: 11 | ansible-playbook play_all_roles.yml --tags zsh --skip-tags become,install 12 | shellcheck: 13 | shellcheck --shell sh install 14 | lint: 15 | ansible-lint roles --exclude roles/*/files -q 16 | .PHONY: all dots moredots tmux vim zsh shellcheck lint 17 | -------------------------------------------------------------------------------- /roles/docker/vars/apt.yml: -------------------------------------------------------------------------------- 1 | docker_repo_url: "https://download.docker.com/linux/{{ ansible_facts['distribution'] | lower }}" 2 | 3 | docker_repo: 4 | name: docker 5 | uris: ["{{ docker_repo_url }}"] 6 | components: ["{{ ansible_facts['distribution_release'] }}"] 7 | suites: ["stable"] 8 | signed_by: "{{ docker_repo_url }}/gpg" 9 | 10 | docker_pkgs: 11 | prereqs: 12 | - "ca-certificates" 13 | - "curl" 14 | packages: 15 | - "docker-ce" 16 | - "docker-ce-cli" 17 | - "containerd.io" 18 | - "docker-buildx-plugin" 19 | - "docker-compose-plugin" 20 | optional: [] 21 | -------------------------------------------------------------------------------- /roles/ssh/templates/ssh_config.j2: -------------------------------------------------------------------------------- 1 | {% for host in ssh_config -%} 2 | Host {{ host['host'] }} 3 | {% filter indent(width=2, first=True) %} 4 | {% for config, value in host['args'].items() -%} 5 | {{ config }} {{ value }} 6 | {% endfor %} 7 | {% endfilter %} 8 | 9 | {% endfor %} 10 | Host * 11 | User {{ ansible_facts['user_id'] }} 12 | IdentitiesOnly yes 13 | CanonicalizeHostname yes 14 | ServerAliveCountMax 4 15 | ServerAliveInterval 15 16 | SetEnv TERM=xterm-256color # workaround for SSHing from Ghostty 17 | 18 | {% if global_use_1password_ssh_agent %} 19 | Include ~/.ssh/1Password/config 20 | {% endif %} 21 | -------------------------------------------------------------------------------- /roles/zsh/tasks/completions.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Generate completions" 4 | ansible.builtin.shell: 5 | cmd: "{{ item['command'] }} > {{ zsh_functions_dir }}/_{{ item['name'] }}" 6 | changed_when: false 7 | loop: "{{ zsh_completions }}" 8 | loop_control: 9 | label: "{{ item['name'] }}" 10 | 11 | - name: "Delete zcompdump" 12 | ansible.builtin.file: 13 | path: "{{ zsh_zcompdump }}" 14 | state: absent 15 | 16 | - name: "Generate zcompdump" 17 | ansible.builtin.shell: 18 | cmd: "autoload -Uz compinit && compinit" 19 | executable: "{{ zsh_bin }}" 20 | creates: "{{ zsh_zcompdump }}" 21 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lua/chadrc.lua: -------------------------------------------------------------------------------- 1 | -- This file needs to have same structure as nvconfig.lua 2 | -- https://github.com/NvChad/ui/blob/v3.0/lua/nvconfig.lua 3 | -- Please read that file to know all available options :( 4 | 5 | ---@type ChadrcConfig 6 | local M = {} 7 | 8 | M.base46 = { 9 | theme = "solarized_light", 10 | 11 | -- hl_override = { 12 | -- Comment = { italic = true }, 13 | -- ["@comment"] = { italic = true }, 14 | -- }, 15 | } 16 | 17 | -- M.nvdash = { load_on_startup = true } 18 | -- M.ui = { 19 | -- tabufline = { 20 | -- lazyload = false 21 | -- } 22 | --} 23 | 24 | return M 25 | -------------------------------------------------------------------------------- /roles/cloud/files/k9s/k9s.config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | k9s: 4 | skin: solarized-light 5 | refreshRate: 2 6 | maxConnRetry: 5 7 | enableMouse: false 8 | headless: false 9 | logoless: false 10 | crumbsless: false 11 | readOnly: false 12 | noIcons: false 13 | logger: 14 | tail: 100 15 | buffer: 5000 16 | sinceSeconds: 60 17 | fullScreenLogs: false 18 | textWrap: false 19 | showTime: false 20 | currentContext: default 21 | currentCluster: default 22 | clusters: {} 23 | thresholds: 24 | cpu: 25 | critical: 90 26 | warn: 70 27 | memory: 28 | critical: 90 29 | warn: 70 30 | -------------------------------------------------------------------------------- /inventory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import sys 5 | import platform 6 | import distro 7 | 8 | hostname = getattr(platform.uname(), "node") 9 | distribution = distro.id().capitalize() 10 | 11 | inventory = { 12 | "_meta": { 13 | "hostvars": { 14 | hostname: { 15 | "ansible_connection": "local" 16 | } 17 | } 18 | }, 19 | distribution: { 20 | "hosts": [hostname], 21 | } 22 | } 23 | 24 | if __name__ == "__main__": 25 | try: 26 | flag = sys.argv[1] 27 | except IndexError: 28 | sys.exit(1) 29 | 30 | print(json.dumps(inventory)) if flag == "--list" else print(json.dumps({})) 31 | -------------------------------------------------------------------------------- /group_vars/all/ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ssh_config: 4 | - host: "memory-alpha" 5 | args: 6 | HostName: "192.168.1.40" 7 | ForwardAgent: "yes" 8 | - host: "rsync.net" 9 | args: 10 | HostName: "de3481b.rsync.net" 11 | User: "root" 12 | 13 | ssh_keys: 14 | id_rsa: 15 | type: "rsa" 16 | passphrase: "{{ lookup('community.general.onepassword', ansible_facts['hostname'], 17 | section='SSH', field='id_rsa') }}" 18 | id_ed25519: 19 | type: "ed25519" 20 | passphrase: "{{ lookup('community.general.onepassword', ansible_facts['hostname'], 21 | section='SSH', field='id_ed25519') }}" 22 | -------------------------------------------------------------------------------- /roles/desktop/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | desktop_logi_app_install: false 4 | desktop_replacement_icons_dir: "icons" 5 | desktop_fonts_dir: "{{ desktop_fonts_dir_defaults[ansible_facts['system']] }}" 6 | desktop_packages: "{{ desktop_packages_defaults[ansible_facts['system']] }}" 7 | desktop_current_environment: "{{ global_desktop_environment | default('') }}" 8 | 9 | desktop_fonts_install: 10 | - "JetBrainsMono" 11 | - "SourceCodePro" 12 | 13 | desktop_fonts_current_version: "{{ 14 | ansible_facts['desktop_fonts_current_version'] | default('v0.0.0') 15 | }}" 16 | 17 | desktop_apps_paths: 18 | - "/Applications" 19 | - "{{ ansible_facts['user_dir'] }}/Applications" 20 | -------------------------------------------------------------------------------- /roles/desktop/tasks/icons.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Set app icons" 4 | vars: 5 | desktop_app: "{{ path }}/{{ app['path'] | splitext | first }}.app" 6 | ansible.builtin.command: 7 | cmd: "{{ global_homebrew_prefix }}/bin/fileicon set {{ desktop_app }} {{ app['src'] }}" 8 | register: cmd_fileicon_set 9 | changed_when: false 10 | failed_when: 11 | - "'you do not have read permissions' in cmd_fileicon_set['stderr']" 12 | - "'file not found or not a (readable) regular file' in cmd_fileicon_set['stderr']" 13 | loop: "{{ lookup('community.general.filetree', desktop_replacement_icons_dir + '/') }}" 14 | loop_control: 15 | label: "{{ desktop_app }}" 16 | loop_var: app 17 | tags: [icons] 18 | -------------------------------------------------------------------------------- /roles/desktop/tasks/fonts/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Download font {{ item }}" 4 | vars: 5 | url_prefix: "https://github.com/{{ desktop_fonts_github_user }}/{{ desktop_fonts_github_repo }}" 6 | ansible.builtin.get_url: 7 | url: "{{ url_prefix }}/releases/download/{{ desktop_fonts_latest_version }}/{{ item }}.zip" 8 | dest: "/tmp/{{ item }}.zip" 9 | mode: "0644" 10 | tags: [fonts] 11 | 12 | - name: "Extract Nerd Fonts" 13 | ansible.builtin.unarchive: 14 | src: "/tmp/{{ item }}.zip" 15 | dest: "{{ desktop_fonts_dir }}" 16 | tags: [fonts] 17 | 18 | - name: "Delete zip file" 19 | ansible.builtin.file: 20 | state: "absent" 21 | path: "/tmp/{{ item }}.zip" 22 | tags: [fonts] 23 | -------------------------------------------------------------------------------- /roles/docker/tasks/install/homebrew.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install Docker Desktop" 4 | community.general.homebrew_cask: 5 | name: "{{ docker_pkgs['packages'] }}" 6 | install_options: "{{ docker_homebrew_casks_install_options | default(omit) }}" 7 | when: docker_install_desktop_version 8 | tags: [docker, never] 9 | 10 | - name: "Install Docker Engine" 11 | community.general.homebrew: 12 | name: "{{ docker_pkgs['packages'] }}" 13 | when: not docker_install_desktop_version 14 | tags: [docker, never] 15 | 16 | - name: "Install optional packages" 17 | community.general.homebrew: 18 | name: "{{ docker_pkgs['optional'] }}" 19 | when: docker_install_optional_packages 20 | tags: [docker, never] 21 | -------------------------------------------------------------------------------- /group_vars/all/git.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | git_github_token: "{{ 4 | lookup('community.general.onepassword', 'GitHub Token', field='credential') 5 | }}" 6 | 7 | git_repos: 8 | - url: "ssh://git@github.com/bradleyfrank/dotfiles.git" 9 | - url: "ssh://git@github.com/bradleyfrank/ansible.git" 10 | - url: "ssh://git@github.com/bradleyfrank/home-servers.git" 11 | - url: "ssh://git@github.com/bradleyfrank/plexport.git" 12 | - url: "ssh://git@github.com/bradleyfrank/util-containers.git" 13 | - url: "ssh://git@github.com/bradleyfrank/cliday.git" 14 | branch: "gh-pages" 15 | 16 | git_signing_pub_key: "{{ 17 | lookup('community.general.onepassword', '7hepch5pzjetmlksffpnum2bzq', 18 | field='public key') | split(' ') 19 | }}" 20 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lua/configs/lspconfig.lua: -------------------------------------------------------------------------------- 1 | -- load defaults i.e lua_lsp 2 | require("nvchad.configs.lspconfig").defaults() 3 | 4 | local lspconfig = require "lspconfig" 5 | 6 | -- EXAMPLE 7 | local servers = { "html", "cssls" } 8 | local nvlsp = require "nvchad.configs.lspconfig" 9 | 10 | -- lsps with default config 11 | for _, lsp in ipairs(servers) do 12 | lspconfig[lsp].setup { 13 | on_attach = nvlsp.on_attach, 14 | on_init = nvlsp.on_init, 15 | capabilities = nvlsp.capabilities, 16 | } 17 | end 18 | 19 | -- configuring single server, example: typescript 20 | -- lspconfig.ts_ls.setup { 21 | -- on_attach = nvlsp.on_attach, 22 | -- on_init = nvlsp.on_init, 23 | -- capabilities = nvlsp.capabilities, 24 | -- } 25 | -------------------------------------------------------------------------------- /templates/host_vars.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ## GLOBAL 4 | 5 | global_homebrew_prefix: "{{ host_vars_globals['homebrew_prefix'][ansible_facts['system']] }}" 6 | global_email_address: "{{ host_vars_globals['email'] }}" 7 | global_is_desktop_system: {{ host_vars_globals['is_desktop'] }} 8 | global_desktop_environment: "{{ host_vars_globals['desktop_environment'] }}" 9 | global_use_1password_ssh_agent: {{ host_vars_globals['is_desktop'] }} 10 | global_host_roles: 11 | # - cloud 12 | {% if host_vars_globals['is_desktop'] %} 13 | - desktop 14 | {% else %} 15 | # - desktop 16 | {% endif %} 17 | # - docker 18 | - dotfiles 19 | - git 20 | # - media 21 | - pkg_mgr 22 | - ssh 23 | - system 24 | - tmux 25 | - vim 26 | - zsh 27 | 28 | ## ROLES 29 | 30 | -------------------------------------------------------------------------------- /roles/git/tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Add repository (dnf)" 4 | when: ansible_facts['pkg_mgr'] == "dnf5" 5 | become: true 6 | block: 7 | - name: "Install gpg keys (dnf)" 8 | ansible.builtin.rpm_key: 9 | key: "{{ git_github_ghcli_repo['dnf']['gpgkey'] }}" 10 | - name: "Add repository (dnf)" 11 | ansible.builtin.yum_repository: "{{ git_github_ghcli_repo['dnf'] }}" # noqa: args[module] 12 | 13 | - name: "Add repository (apt)" 14 | ansible.builtin.deb822_repository: "{{ git_github_ghcli_repo['apt'] }}" # noqa: args[module] 15 | become: true 16 | when: ansible_facts['pkg_mgr'] == "apt" 17 | 18 | - name: "Install git packages" 19 | ansible.builtin.package: 20 | name: "{{ git_packages }}" 21 | become: "{{ true if ansible_facts['system'] == 'Linux' else false }}" 22 | -------------------------------------------------------------------------------- /roles/git/tasks/get_authorized_keys.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Get list of existing Github SSH keys" 4 | ansible.builtin.uri: 5 | url: "{{ git_github_api['ssh_key_url'] }}" 6 | method: "GET" 7 | status_code: [200] 8 | headers: 9 | Authorization: "Bearer {{ git_github_token }}" 10 | Accept: "{{ git_github_api['headers_accept'] }}" 11 | X-GitHub-Api-Version: "{{ git_github_api['headers_version'] }}" 12 | register: git_ssh_keys 13 | 14 | - name: "Add matching public keys to `authorized_keys`" 15 | ansible.posix.authorized_key: 16 | user: "{{ ansible_facts['user_id'] }}" 17 | key: "{{ item['key'] }} {{ item['title'] }}" 18 | loop: "{{ git_ssh_keys['json'] | community.general.json_query(git_ssh_authorized_keys_match) }}" 19 | loop_control: 20 | label: "{{ item['title'] }}" 21 | -------------------------------------------------------------------------------- /play_init_onepassword.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install and authenticate to 1Password" 4 | hosts: all 5 | 6 | vars_prompt: 7 | - name: onepassword_signin_url 8 | prompt: "Enter the 1Password Signin URL" 9 | private: false 10 | confirm: true 11 | 12 | - name: onepassword_email_address 13 | prompt: "Enter the 1Password Email" 14 | private: false 15 | confirm: true 16 | 17 | - name: onepassword_secret_key 18 | prompt: "Enter the 1Password Secret Key" 19 | private: true 20 | confirm: true 21 | 22 | - name: onepassword_account_password 23 | prompt: "Enter the 1Password Account password" 24 | private: true 25 | confirm: true 26 | 27 | tasks: 28 | - name: "Import 1Password role" 29 | ansible.builtin.import_role: 30 | name: "onepassword" 31 | -------------------------------------------------------------------------------- /roles/onepassword/vars/apt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | onepassword_packages: 4 | gui: "1password" 5 | cli: "1password-cli" 6 | 7 | onepassword_arch_map: 8 | aarch64: "arm64" 9 | arm64: "arm64" 10 | x86_64: "amd64" 11 | amd64: "amd64" 12 | 13 | onepassword_arch: "{{ onepassword_arch_map[ansible_facts['architecture']] }}" 14 | 15 | onepassword_linux_repo: 16 | name: "1password" 17 | uris: "https://downloads.1password.com/linux/debian/{{ onepassword_arch }}" 18 | components: ["main"] 19 | suites: ["stable"] 20 | signed_by: "https://downloads.1password.com/linux/keys/1password.asc" 21 | enabled: true 22 | 23 | onepassword_repo_file: "/etc/apt/sources.list.d/1password.list" 24 | 25 | onepassword_debsig_url: "https://downloads.1password.com/linux/debian/debsig/1password.pol" 26 | onepassword_debsig_dir: "/etc/debsig/policies/AC2D62742012EA22" 27 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/ics2json: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import sys 5 | from ics import Calendar 6 | from pathlib import Path 7 | 8 | ics_file = sys.argv[1] 9 | json_file = ics_file.parent / f"{f.stem}.json" 10 | 11 | with open(ics_file, 'r', encoding='utf-8') as file: 12 | calendar = Calendar(file.read()) 13 | 14 | events_data = [] 15 | for event in calendar.events: 16 | event_dict = { 17 | "name": event.name, 18 | "begin": event.begin.isoformat() if event.begin else None, 19 | "end": event.end.isoformat() if event.end else None, 20 | "location": event.location, 21 | "description": event.description, 22 | "status": event.status, 23 | "uid": event.uid 24 | } 25 | events_data.append(event_dict) 26 | 27 | with open(json_file, 'w', encoding='utf-8') as out_file: 28 | json.dump(events_data, out_file, indent=2) 29 | -------------------------------------------------------------------------------- /roles/dotfiles/files/root/.vimrc: -------------------------------------------------------------------------------- 1 | hi colorcolumn ctermbg=LightMagenta guibg=LightMagenta 2 | hi Search ctermbg=DarkBlue ctermfg=White 3 | nnoremap :nohlsearch:echo 4 | set background=light 5 | set backspace=indent,eol,start 6 | set colorcolumn=100 7 | set cursorline 8 | set hlsearch incsearch 9 | set laststatus=2 10 | set linebreak 11 | set mouse=i 12 | set novisualbell noerrorbells 13 | set scrolloff=4 14 | set showmatch 15 | set tabstop=2 shiftwidth=2 expandtab smarttab autoindent 16 | set term=screen-256color 17 | set ttimeoutlen=10 18 | set updatetime=100 19 | syntax on 20 | 21 | " use hybrid line numbering by default with automatic toggling 22 | set number relativenumber 23 | augroup numbertoggle 24 | autocmd! 25 | autocmd BufEnter,FocusGained,InsertLeave * set relativenumber 26 | autocmd BufLeave,FocusLost,InsertEnter * set norelativenumber 27 | augroup END 28 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/40-zstyle.zsh.j2: -------------------------------------------------------------------------------- 1 | zstyle ':completion:*' completer _expand_alias _complete _ignored # Expand aliases with tab 2 | zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' # Case insensitive tab completion 3 | zstyle ':completion:*' list-suffixes true # Show ambiguous components for partial pathnames 4 | zstyle ':completion:*' rehash true # Auto find new executables in path 5 | zstyle ':completion:*' accept-exact '*(N)' 6 | zstyle ':completion:*' use-cache on # Speed up completions 7 | zstyle ':completion:*' cache-path "$HOME/.cache/zsh/.zcompcache" 8 | 9 | zstyle ':completion:*:*:*:*:corrections' format '%F{yellow}!- %d (errors: %e) -!%f' 10 | zstyle ':completion:*:*:*:*:descriptions' format '%F{blue}-- %D %d --%f' 11 | zstyle ':completion:*:*:*:*:messages' format ' %F{purple} -- %d --%f' 12 | zstyle ':completion:*:*:*:*:warnings' format ' %F{red}-- no matches found --%f' 13 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/80-sources.zsh.j2: -------------------------------------------------------------------------------- 1 | {% for plugin in zsh_plugins %} 2 | source $HOME/.local/share/{{ plugin['name'] }}/{{ plugin['source'] }} 3 | {% endfor %} 4 | {% if ansible_facts['distribution'] == "MacOSX" %} 5 | source {{ global_homebrew_prefix }}/opt/fzf/shell/completion.zsh 6 | source {{ global_homebrew_prefix }}/opt/fzf/shell/key-bindings.zsh 7 | source {{ global_homebrew_prefix }}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh 8 | {% elif ansible_facts['distribution'] == "Fedora" %} 9 | source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh 10 | source /usr/share/fzf/shell/key-bindings.zsh 11 | {% elif ansible_facts['os_family'] == "Debian" %} 12 | source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh 13 | source /usr/share/doc/fzf/examples/completion.zsh 14 | source /usr/share/doc/fzf/examples/key-bindings.zsh 15 | {% endif %} 16 | for zshrc in {{ zsh_rcd_dir }}/*; do source "$zshrc"; done 17 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | > [!IMPORTANT] 4 | > I have tried multiple different colorschemes now and I always come back to **Solarized Light**. If I get the itch to try again, I remind myself: do not waste your time! Keep what is working, and fix minor issues with the individual app's theme instead. 5 | 6 | > [!NOTE] 7 | > Packages `tmux` and `fzf` where too old in Ubuntu 22.04 repo 8 | 9 | 10 | - [ ] The command bar at the top of `tmux` is solarized dark instead of light 11 | - [ ] Remove unnecessary items from Neovim status bar 12 | - [ ] Make Neovim default to two spaces per tab 13 | - [ ] Make **atuin** setup dependent on `atuin status` 14 | - [ ] Fix `ffmpeg` packages for Fedora (specify repo) 15 | - [ ] Archive an existing host in 1Password if hostname exists 16 | - [ ] Refactor **dconf** package variables to be simplier 17 | - [ ] The **docker** role should use `dnf5` 18 | - [ ] Why are `lesshst` and `viminfo` being recreated even with env var set? 19 | -------------------------------------------------------------------------------- /roles/ssh/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ssh_packages_defaults: 4 | Darwin: 5 | - keychain 6 | - ssh-copy-id 7 | Linux: 8 | - keychain 9 | 10 | ssh_1password_agent_sock: 11 | Darwin: "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" 12 | Linux: "~/.1password/agent.sock" 13 | 14 | ssh_required_dirs: 15 | - "{{ ansible_facts['user_dir'] }}/.ssh" 16 | - "{{ ansible_facts['user_dir'] }}/.local/bin" 17 | 18 | ssh_hardening_overrides: 19 | Debian: 20 | sshd_path: /usr/sbin/sshd 21 | ssh_host_keys_dir: /etc/ssh 22 | sshd_service_name: ssh 23 | ssh_owner: root 24 | ssh_group: root 25 | ssh_host_keys_owner: root 26 | ssh_host_keys_group: root 27 | ssh_host_keys_mode: "0600" 28 | ssh_selinux_packages: 29 | - policycoreutils-python 30 | - checkpolicy 31 | ssh_kerberos_support: true 32 | ssh_pam_support: true 33 | sshd_moduli_file: /etc/ssh/moduli 34 | sshd_disable_crypto_policy: false 35 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/beets/config.yaml: -------------------------------------------------------------------------------- 1 | directory: ~/Music/Beets 2 | library: ~/Music/beets.db 3 | plugins: convert mbsync inline 4 | ignore_hidden: yes 5 | per_disc_numbering: yes 6 | ui: 7 | color: yes 8 | colors: 9 | action_description: darkgray 10 | text_highlight_minor: turquoise 11 | import: 12 | copy: yes 13 | from_scratch: yes 14 | musicbrainz: 15 | extra_tags: [year, catalognum, country, media, label] 16 | item_fields: 17 | disc_padded: u'%03i' % (disc) if disctotal > 99 else u'%02i' % (disc) 18 | track_padded: u'%03i' % (track) if tracktotal > 99 else u'%02i' % (track) 19 | paths: 20 | default: "%upper{${album}}/${disc_padded}x${track_padded}_${title}" 21 | singleton: "%upper{${album}}/${disc_padded}x${track_padded}_${title}" 22 | comp: "%upper{${album}}/${disc_padded}x${track_padded}_${title}" 23 | replace: 24 | '[^一-龠ぁ-ゔァ-ヴーa-zA-Z0-9々〆〤ヶ]+': _ 25 | convert: 26 | auto: yes 27 | dest: ~/Music/Archive 28 | never_convert_lossy_files: yes 29 | -------------------------------------------------------------------------------- /roles/onepassword/tasks/import.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Template 1Password json file for importing" 4 | vars: 5 | ed25519_passphrase: "{{ 6 | lookup('community.general.random_words', numwords=5, delimiter='-', case='capitalize') 7 | }}" 8 | rsa_passphrase: "{{ 9 | lookup('community.general.random_words', numwords=5, delimiter='-', case='capitalize') 10 | }}" 11 | ansible.builtin.template: 12 | src: "op.json.j2" 13 | dest: "{{ onepassword_template }}" 14 | mode: "0600" 15 | notify: "Delete 1Password template" 16 | 17 | - name: "Import secrets into 1Password" 18 | environment: 19 | PATH: "{{ ansible_facts['env']['PATH'] }}:{{ global_homebrew_prefix }}/bin" 20 | ansible.builtin.shell: 21 | # https://1password.community/discussion/comment/703328/#Comment_703328 22 | cmd: | 23 | . {{ onepassword_session_file }} 24 | op item create --template {{ onepassword_template }} --format json /dev/null 25 | changed_when: true 26 | -------------------------------------------------------------------------------- /roles/docker/tasks/install/apt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install Docker prereq packages" 4 | ansible.builtin.apt: 5 | name: "{{ docker_pkgs['prereqs'] }}" 6 | state: present 7 | install_recommends: true 8 | update_cache: true 9 | become: true 10 | tags: [docker, never] 11 | 12 | - name: "Add repositories" 13 | ansible.builtin.deb822_repository: "{{ docker_repos }}" # noqa: args[module] 14 | become: true 15 | tags: [docker, never] 16 | 17 | - name: "Install Docker packages" 18 | ansible.builtin.apt: 19 | name: "{{ docker_pkgs['packages'] }}" 20 | state: present 21 | install_recommends: true 22 | update_cache: true 23 | become: true 24 | tags: [docker, never] 25 | 26 | - name: "Install optional packages" 27 | ansible.builtin.apt: 28 | name: "{{ docker_pkgs['optional'] }}" 29 | state: present 30 | install_recommends: true 31 | update_cache: true 32 | become: true 33 | when: docker_install_optional_packages 34 | tags: [docker, never] 35 | -------------------------------------------------------------------------------- /roles/cloud/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Install packages via Homebrew" 9 | community.general.homebrew: 10 | name: "{{ cloud_packages }}" 11 | tags: [install] 12 | 13 | - name: "Install krew plugins" 14 | ansible.builtin.command: 15 | cmd: "{{ cloud_krew_bin }} install {{ item }}" 16 | loop: "{{ cloud_krew_plugins }}" 17 | register: cmd_krew_install 18 | changed_when: "'Installed plugin' in cmd_krew_install['stdout']" 19 | failed_when: "'does not exist in the plugin index' in cmd_krew_install['stdout']" 20 | when: "('krew' in cloud_packages) and (cloud_krew_plugins | length > 0)" 21 | tags: [moredots, krew] 22 | 23 | - name: "Copy k9s configs" 24 | ansible.builtin.copy: 25 | src: "k9s/" 26 | dest: "{{ cloud_k9s_configs[ansible_facts['system']] }}" 27 | mode: "0644" 28 | when: "'k9s' in cloud_packages" 29 | tags: [dots, k9s] 30 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/Linux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Enumerate services" 4 | ansible.builtin.service_facts: 5 | become: true 6 | tags: [apt, dnf] 7 | 8 | - name: "Stop packagekit" 9 | ansible.builtin.systemd: 10 | name: "packagekit.service" 11 | state: stopped 12 | enabled: false 13 | become: true 14 | notify: Start packagekit 15 | when: "'packagekit.service' in ansible_facts['services']" 16 | tags: [apt, dnf] 17 | 18 | - name: "Include OS package manager tasks" 19 | ansible.builtin.include_tasks: 20 | file: "pkg_mgr/{{ ansible_facts['pkg_mgr'] }}.yml" 21 | tags: [apt, dnf] 22 | 23 | - name: "Include Homebrew tasks" 24 | ansible.builtin.include_tasks: 25 | file: "pkg_mgr/homebrew.yml" 26 | when: (ansible_facts['architecture'] == 'x86_64') or (ansible_facts['architecture'] == 'amd64') 27 | tags: [formulas] 28 | 29 | - name: "Include Flakpak tasks" 30 | ansible.builtin.include_tasks: 31 | file: "pkg_mgr/flatpak.yml" 32 | when: pkg_mgr_desktop_present 33 | tags: [flatpak] 34 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/pkg_mgr/apt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Add repositories" 4 | ansible.builtin.deb822_repository: "{{ item }}" # noqa: args[module] 5 | loop: "{{ pkg_mgr_repos['base'] }}" 6 | loop_control: 7 | label: "{{ item['name'] }}" 8 | become: true 9 | 10 | - name: "Refresh packages" 11 | ansible.builtin.apt: 12 | name: "*" 13 | update_cache: true 14 | state: latest # noqa: package-latest 15 | become: true 16 | 17 | - name: "Install cli packages" 18 | ansible.builtin.apt: 19 | name: "{{ pkg_mgr_cli['base'] }}" 20 | state: present 21 | become: true 22 | 23 | - name: "Install gui packages" 24 | ansible.builtin.apt: 25 | name: "{{ pkg_mgr_gui['base'] | default([]) }}" 26 | state: present 27 | when: pkg_mgr_desktop_present 28 | become: true 29 | 30 | - name: "Install desktop packages" 31 | ansible.builtin.apt: 32 | name: "{{ pkg_mgr_gui[pkg_mgr_current_desktop] | default([]) }}" 33 | state: present 34 | become: true 35 | when: pkg_mgr_desktop_present 36 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/init.lua: -------------------------------------------------------------------------------- 1 | vim.g.base46_cache = vim.fn.stdpath "data" .. "/base46/" 2 | vim.g.mapleader = " " 3 | vim.g.is_bash = 1 4 | 5 | -- bootstrap lazy and all plugins 6 | local lazypath = vim.fn.stdpath "data" .. "/lazy/lazy.nvim" 7 | 8 | if not vim.uv.fs_stat(lazypath) then 9 | local repo = "https://github.com/folke/lazy.nvim.git" 10 | vim.fn.system { "git", "clone", "--filter=blob:none", repo, "--branch=stable", lazypath } 11 | end 12 | 13 | vim.opt.rtp:prepend(lazypath) 14 | 15 | local lazy_config = require "configs.lazy" 16 | 17 | -- load plugins 18 | require("lazy").setup({ 19 | { 20 | "NvChad/NvChad", 21 | lazy = false, 22 | branch = "v2.5", 23 | import = "nvchad.plugins", 24 | }, 25 | 26 | { import = "plugins" }, 27 | }, lazy_config) 28 | 29 | -- load theme 30 | dofile(vim.g.base46_cache .. "defaults") 31 | dofile(vim.g.base46_cache .. "statusline") 32 | 33 | require "options" 34 | require "nvchad.autocmds" 35 | 36 | vim.schedule(function() 37 | require "mappings" 38 | end) 39 | -------------------------------------------------------------------------------- /roles/dotfiles/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Create development folder structure" 9 | ansible.builtin.file: 10 | path: "{{ ansible_facts['user_dir'] }}/{{ item }}" 11 | state: directory 12 | mode: "0755" 13 | recurse: false 14 | loop: 15 | - "Development/Projects" 16 | - "Development/Notes" 17 | - "Development/Scratch" 18 | - "Development/Logs" 19 | - "Development/Build" 20 | tags: [dots] 21 | 22 | - name: "Remove dotfiles" 23 | ansible.builtin.file: 24 | path: "{{ ansible_facts['user_dir'] }}/{{ item }}" 25 | state: absent 26 | loop: "{{ dotfiles_to_remove }}" 27 | tags: [dots] 28 | 29 | - name: "Sync dotfiles to home directory" 30 | ansible.posix.synchronize: 31 | src: "home/" 32 | dest: "{{ ansible_facts['user_dir'] }}/" 33 | compress: false 34 | owner: false 35 | group: false 36 | tags: [dots] 37 | -------------------------------------------------------------------------------- /roles/onepassword/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Load package manager variables" 9 | ansible.builtin.include_vars: 10 | file: "{{ ansible_facts['pkg_mgr'] }}.yml" 11 | tags: [always] 12 | 13 | - name: "Include install tasks" 14 | ansible.builtin.include_tasks: 15 | file: "install/{{ ansible_facts['pkg_mgr'] }}.yml" 16 | tags: [install] 17 | 18 | - name: "Pause to enable 1Password CLI integration" 19 | ansible.builtin.pause: 20 | prompt: "Enable the 1Password CLI integration and hit [Enter]" 21 | when: onepassword_use_gui_integration 22 | tags: [auth] 23 | 24 | - name: "Authenticate 1Password-cli" 25 | ansible.builtin.include_tasks: 26 | file: "auth.yml" 27 | when: not onepassword_use_gui_integration 28 | tags: [auth] 29 | 30 | - name: "Include tasks to add host to 1Password" 31 | ansible.builtin.include_tasks: "import.yml" 32 | tags: [import] 33 | -------------------------------------------------------------------------------- /roles/zsh/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | zsh_packages: 4 | - atuin 5 | - zsh 6 | - zsh-autosuggestions 7 | - zsh-syntax-highlighting 8 | 9 | zsh_bin: "{{ lookup('ansible.builtin.first_found', files=['zsh'], paths=zsh_bin_search_paths) }}" 10 | 11 | zsh_dot_dir: "{{ ansible_facts['user_dir'] }}/.config/zsh" 12 | zsh_rcd_dir: "{{ zsh_dot_dir }}/rc.d" 13 | zsh_functions_dir: "{{ zsh_dot_dir }}/site-functions" 14 | zsh_plugins_dir: "{{ ansible_facts['user_dir'] }}/.local/share" 15 | 16 | zsh_rc: "{{ zsh_dot_dir }}/.zshrc" 17 | 18 | zsh_manage_zcompdump: true 19 | zsh_zcompdump: "{{ zsh_dot_dir }}/.zcompdump" 20 | 21 | zsh_supplemental_dirs: 22 | - "{{ zsh_plugins_dir }}" 23 | - "{{ zsh_functions_dir }}" 24 | - "{{ zsh_rcd_dir }}" 25 | 26 | zsh_completions: [] 27 | 28 | zsh_plugins: 29 | - name: "fzf-tab" 30 | repo: "https://github.com/Aloxaf/fzf-tab" 31 | source: "fzf-tab.plugin.zsh" 32 | - name: "zsh-vi-mode" 33 | repo: "https://github.com/jeffreytse/zsh-vi-mode.git" 34 | source: "zsh-vi-mode.plugin.zsh" 35 | -------------------------------------------------------------------------------- /roles/zsh/tasks/zshrc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Create ~/.zshenv which defines ZDOTDIR" 4 | ansible.builtin.copy: 5 | content: "export ZDOTDIR=${XDG_CONFIG_HOME:-$HOME/.config}/zsh" 6 | dest: "{{ ansible_facts['user_dir'] }}/.zshenv" 7 | mode: "0644" 8 | 9 | - name: "Create temp directory for templating" 10 | ansible.builtin.tempfile: 11 | state: directory 12 | register: zsh_temp_dir 13 | notify: "Delete zshrc tempfile" 14 | 15 | - name: "Apply zshrc templates" 16 | ansible.builtin.template: 17 | src: "{{ item }}" 18 | dest: "{{ zsh_temp_dir['path'] }}" 19 | mode: "0644" 20 | with_fileglob: 21 | - "templates/zshrc/*.zsh.j2" 22 | loop_control: 23 | label: "{{ item | basename }}" 24 | 25 | - name: "Build zshrc" 26 | ansible.builtin.assemble: 27 | src: "{{ zsh_temp_dir['path'] }}" 28 | dest: "{{ zsh_rc }}" 29 | delimiter: "\n" 30 | mode: "0644" 31 | 32 | - name: "Copy zshrc scripts" 33 | ansible.builtin.copy: 34 | src: "rc.d/" 35 | dest: "{{ zsh_rcd_dir }}" 36 | mode: "0644" 37 | -------------------------------------------------------------------------------- /roles/desktop/tasks/logi.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Check if Logi Options+ is installed" 4 | ansible.builtin.stat: 5 | path: "/Applications/logioptionsplus.app" 6 | register: stat_logioptionsplus_app 7 | tags: [install, logi] 8 | 9 | - name: "Download Logi Options+ installer" 10 | when: not stat_logioptionsplus_app['stat']['exists'] 11 | tags: [install, logi] 12 | block: 13 | - name: "Install Logi Options+" 14 | community.general.homebrew: 15 | name: "logi-options-plus" 16 | - name: "Find Logi installer" 17 | ansible.builtin.find: 18 | paths: "{{ global_homebrew_prefix }}/Caskroom/logi-options-plus" 19 | follow: true 20 | recurse: true 21 | patterns: "logioptionsplus_installer.app" 22 | file_type: "directory" 23 | register: find_logioptionsplus_installer 24 | - name: "Copy Logi installer" 25 | ansible.builtin.copy: 26 | src: "{{ find_logioptionsplus_installer['files'][0]['path'] }}" 27 | dest: "{{ ansible_facts['user_dir'] }}/Downloads" 28 | mode: "0755" 29 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/youtube: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # A youtube-dl wrapper to making downloading music and video easier. 5 | # Author: Brad Frank 6 | # Date: Jan 2022 7 | # Tested: GNU bash, version 5.1.12(1)-release (x86_64-apple-darwin21.1.0) 8 | # Requires: yt-dlp 9 | # 10 | 11 | music() { 12 | case $(uname -s) in 13 | Darwin) 14 | yt-dlp --format bestaudio --extract-audio --audio-format mp3 \ 15 | --postprocessor-args "-strict experimental" "$1" ;; 16 | Linux) 17 | yt-dlp --format bestaudio --extract-audio --audio-format mp3 "$1" ;; 18 | esac 19 | } 20 | 21 | video() { 22 | yt-dlp \ 23 | --format "bestvideo+bestaudio[ext=m4a]/bestvideo+bestaudio/best" \ 24 | --merge-output-format mp4 \ 25 | -o "%(title)s.%(ext)s" "$1" 26 | } 27 | 28 | while getopts ':hm:v:' flag; do 29 | case "$flag" in 30 | h) echo "Usage: youtube [-m(usic) | -v(ideo) ]" ; exit 0 ;; 31 | m) music "$OPTARG" ;; 32 | v) video "$OPTARG" ;; 33 | *) echo "Invalid argument." >&2 ; exit 1 ;; 34 | esac 35 | done 36 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lua/configs/lazy.lua: -------------------------------------------------------------------------------- 1 | return { 2 | defaults = { lazy = true }, 3 | install = { colorscheme = { "nvchad" } }, 4 | 5 | ui = { 6 | icons = { 7 | ft = "", 8 | lazy = "󰂠 ", 9 | loaded = "", 10 | not_loaded = "", 11 | }, 12 | }, 13 | 14 | performance = { 15 | rtp = { 16 | disabled_plugins = { 17 | "2html_plugin", 18 | "tohtml", 19 | "getscript", 20 | "getscriptPlugin", 21 | "gzip", 22 | "logipat", 23 | "netrw", 24 | "netrwPlugin", 25 | "netrwSettings", 26 | "netrwFileHandlers", 27 | "matchit", 28 | "tar", 29 | "tarPlugin", 30 | "rrhelper", 31 | "spellfile_plugin", 32 | "vimball", 33 | "vimballPlugin", 34 | "zip", 35 | "zipPlugin", 36 | "tutor", 37 | "rplugin", 38 | "syntax", 39 | "synmenu", 40 | "optwin", 41 | "compiler", 42 | "bugreport", 43 | "ftplugin", 44 | }, 45 | }, 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/60-setopt.zsh.j2: -------------------------------------------------------------------------------- 1 | setopt appendhistory # Immediately append history instead of overwriting 2 | setopt auto_pushd # Push directories onto stack 3 | setopt autocd # Change directory without `cd` 4 | setopt correct # Auto correct mistakes 5 | setopt extended_history # Save each commands beginning timestamp and the duration 6 | setopt extendedglob # Extended globbing. Allows using regular expressions with * 7 | setopt globdots # Show hidden files in completion 8 | setopt hist_verify # Confirm commands from history expansion 9 | setopt inc_append_history_time # Time taken by the command is recorded correctly in the history file 10 | setopt nobeep # No beep 11 | setopt nocaseglob # Case insensitive globbing 12 | setopt numericglobsort # Sort filenames numerically when it makes sense 13 | setopt pushd_ignore_dups # Ignore duplices in the directory stack 14 | setopt rcexpandparam # Array expension with parameters 15 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/pdf-compress: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Provides a wrapper around ghostscript to compress PDF files. 5 | # Author: Brad Frank 6 | # Date: Nov 2020 7 | # Tested: GNU bash, version 5.0.18(1)-release (x86_64-apple-darwin19.6.0) 8 | # Requires: ghostscript 9 | # 10 | 11 | usage() { 12 | echo "Usage: pdf-compress -h | [-c ] -f " 13 | } 14 | 15 | main() { 16 | local OPTIND compression input; compression="ebook" 17 | 18 | while getopts ':hc:f:' flag; do 19 | case "$flag" in 20 | h) usage; exit 0 ;; 21 | c) compression="$OPTARG" ;; 22 | f) input="$OPTARG" ;; 23 | :) echo "Must supply an argument to -$OPTARG." >&2; usage >&2; exit 1 ;; 24 | \?) echo "Invalid option: $OPTARG" >&2; usage >&2; exit 1 ;; 25 | esac 26 | done 27 | 28 | gs \ 29 | -sDEVICE=pdfwrite \ 30 | -dCompatibilityLevel=1.4 \ 31 | -dPDFSETTINGS=/"$compression" \ 32 | -dNOPAUSE \ 33 | -dQUIET \ 34 | -dBATCH \ 35 | -sOutputFile="${input%.*}.${compression}.pdf" \ 36 | "$input" 37 | } 38 | 39 | main "$@" 40 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/pkg_mgr/homebrew.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install Homebrew taps" 4 | environment: 5 | PATH: "{{ pkg_mgr_homebrew_bin_path }}:{{ ansible_facts['env']['PATH'] }}" 6 | community.general.homebrew_tap: 7 | name: "{{ pkg_mgr_repos['taps'] | default([]) }}" 8 | tags: [never, taps] 9 | 10 | - name: "Install Homebrew formulas" 11 | environment: 12 | PATH: "{{ pkg_mgr_homebrew_bin_path }}:{{ ansible_facts['env']['PATH'] }}" 13 | community.general.homebrew: 14 | name: "{{ pkg_mgr_cli['formulas'] | default([]) }}" 15 | force_formula: true 16 | upgrade_all: true 17 | when: "'formulas' in pkg_mgr_cli" 18 | tags: [never, formulas] 19 | 20 | - name: "Install Homebrew casks" 21 | environment: 22 | PATH: "{{ pkg_mgr_homebrew_bin_path }}:{{ ansible_facts['env']['PATH'] }}" 23 | community.general.homebrew_cask: 24 | name: "{{ pkg_mgr_gui['casks'] | default([]) }}" 25 | accept_external_apps: "{{ pkg_mgr_homebrew_casks_external }}" 26 | install_options: "{{ pkg_mgr_homebrew_casks_install_options }}" 27 | upgrade_all: true 28 | when: "'casks' in pkg_mgr_gui" 29 | tags: [never, casks] 30 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/xdg_cleanup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pathlib import PosixPath 4 | 5 | home = PosixPath.home() 6 | 7 | dotfiles = [ 8 | ".zshrc", 9 | ".zsh_history", 10 | ".vimrc", 11 | ".cargo", 12 | ".docker", 13 | ".go", 14 | ".minikube", 15 | ".nb", 16 | ".nbrc", 17 | ".sqlite_history", 18 | ".terminfo", 19 | ".w3m", 20 | ".vim" 21 | ] 22 | 23 | def _unlink(file): 24 | try: 25 | current_file.unlink() 26 | print(f"{file} deleted successfully") 27 | except PermissionError: 28 | print(f"{file} permission denied, check file permissions") 29 | 30 | def _rmdir(file): 31 | for root, dirs, files in current_file.walk(top_down=False): 32 | for name in files: 33 | (root / name).unlink() 34 | for name in dirs: 35 | (root / name).rmdir() 36 | current_file.rmdir() 37 | print(f"{file} deleted successfully") 38 | 39 | for file in dotfiles: 40 | current_file = (home / file) 41 | if current_file.is_file(): 42 | _unlink(current_file) 43 | elif current_file.is_dir(): 44 | _rmdir(current_file) 45 | else: 46 | print(f"{file} not found, nothing to delete") 47 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/ghpr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Searches for open PRs within the last 90 days given a list of users. 5 | # Author: Brad Frank 6 | # Date: Jan 2022, Oct 2023 7 | # Tested: GNU bash, version 5.2.15(1)-release (aarch64-apple-darwin22.1.0) 8 | # Requires: gh, jq 9 | # 10 | 11 | # input: comma separated list of GitHub usernames 12 | members="$(while read -rd, username; do printf "author:%s " "$username"; done <<< "$1")" 13 | 14 | gh api -X GET search/issues \ 15 | -f q="${members} is:open draft:false created:>$(date -d "90 days ago" +%Y-%m-%d)" \ 16 | | jq -jr 'def cls: { 17 | "black": "\u001b[30m", 18 | "yellow": "\u001b[33m", 19 | "blue": "\u001b[34m", 20 | "green": "\u001b[32m", 21 | "bold": "\u001b[1m", 22 | "reset": "\u001b[0m", 23 | }; .items[] | "\n" + 24 | cls.blue + cls.bold + .title + cls.reset + "\n" + 25 | cls.green + cls.bold + ">> " + cls.reset + "Created on: ", cls.yellow + (.created_at|fromdate|strftime("%Y-%m-%d")) + cls.reset + "\n" + 26 | cls.green + cls.bold + ">> " + cls.reset + "Created by: ", cls.green + .user.login + cls.reset + "\n" + 27 | cls.green + cls.bold + ">> " + cls.reset + .pull_request.html_url + "\n\n"' 28 | -------------------------------------------------------------------------------- /roles/pkg_mgr/tasks/pkg_mgr/dnf5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install gpg keys" 4 | ansible.builtin.rpm_key: 5 | key: "{{ item['gpgkey'] }}" 6 | state: present 7 | loop: "{{ pkg_mgr_repos['base'] }}" 8 | loop_control: 9 | label: "{{ item['name'] }}" 10 | become: true 11 | 12 | - name: "Add repositories" 13 | ansible.builtin.yum_repository: "{{ item }}" # noqa: args[module] 14 | loop: "{{ pkg_mgr_repos['base'] }}" 15 | loop_control: 16 | label: "{{ item['name'] }}" 17 | become: true 18 | 19 | - name: "Refresh packages" 20 | ansible.builtin.dnf5: 21 | name: "*" 22 | update_cache: true 23 | state: latest # noqa: package-latest 24 | become: true 25 | 26 | - name: "Install cli packages" 27 | ansible.builtin.dnf5: 28 | name: "{{ pkg_mgr_cli['base'] }}" 29 | state: present 30 | become: true 31 | 32 | - name: "Install gui packages" 33 | ansible.builtin.dnf5: 34 | name: "{{ pkg_mgr_gui['base'] | default([]) }}" 35 | state: present 36 | when: pkg_mgr_desktop_present 37 | become: true 38 | 39 | - name: "Install desktop packages" 40 | ansible.builtin.dnf5: 41 | name: "{{ pkg_mgr_gui[pkg_mgr_current_desktop] | default([]) }}" 42 | state: present 43 | when: pkg_mgr_desktop_present 44 | become: true 45 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/30-functions.zsh.j2: -------------------------------------------------------------------------------- 1 | # for quickly moving around the zsh dir stack 2 | cdf() { cd $(dirs -lp | fzf --no-multi) ; } 3 | 4 | # serve a website with jekyll 5 | jekyll() { 6 | docker run \ 7 | --rm \ 8 | --volume="${1:-$PWD}:/srv/jekyll" \ 9 | --publish "${2:-4000}:4000" \ 10 | jekyll/jekyll jekyll serve 11 | } 12 | 13 | # archive a directory and names the file for the directory 14 | tardir() { tar -czf "${1%/}".tar.gz "$1" ; } 15 | 16 | # cd directly to the root of a git repo 17 | gtop() { cd $(git rev-parse --show-toplevel | xargs realpath --relative-to .) ; } 18 | 19 | # (re-)start a tmux session 20 | mux() { 21 | [[ "$TERM_PROGRAM" == "ghostty" ]] && export TERM=xterm-256color 22 | tmux new-session -As main 23 | } 24 | 25 | # makes a diceword password suffixed with a number the same length and the number of words 26 | numware() { echo "$(diceware -n "${1:-5}")-$(random "${1:-5}")" ; } 27 | 28 | # create a random number by restricting 'pwgen' to numbers [by removing alphabetical characters] 29 | random() { pwgen -1 --no-capitalize --numerals --remove-chars "$(echo {a..z})" "${1:-5}" ; } 30 | 31 | # rebind atuin after zsh-vi-mode loads 32 | zvm_after_init() { 33 | bindkey -M viins '^R' atuin-search 34 | bindkey -M vicmd '^R' atuin-search 35 | } 36 | -------------------------------------------------------------------------------- /roles/tmux/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Include per-distro variables" 9 | ansible.builtin.include_vars: 10 | file: "{{ ansible_facts['pkg_mgr'] }}.yml" 11 | tags: [install] 12 | 13 | - name: "Install tmux packages" 14 | ansible.builtin.package: 15 | name: "{{ tmux_packages }}" 16 | become: "{{ true if ansible_facts['system'] == 'Linux' else false }}" 17 | tags: [install] 18 | 19 | - name: "Ensure tmux config path exists" 20 | ansible.builtin.file: 21 | path: "{{ tmux_config_dir }}" 22 | mode: "0755" 23 | state: directory 24 | tags: [dots] 25 | 26 | - name: "Template tmux config" 27 | ansible.builtin.template: 28 | src: "tmux.conf.j2" 29 | dest: "{{ tmux_config_dir }}/{{ item }}.conf" 30 | mode: "0755" 31 | loop: [tmux, popup] 32 | tags: [dots] 33 | 34 | - name: "Install tmux plugins" 35 | ansible.builtin.git: 36 | repo: "{{ item['repo'] }}" 37 | dest: "{{ tmux_plugins_dir }}/{{ item['name'] }}" 38 | depth: 1 39 | version: "{{ item['version'] | default(omit) }}" 40 | loop: "{{ tmux_plugins }}" 41 | loop_control: 42 | label: "{{ item['name'] }}" 43 | tags: [moredots] 44 | -------------------------------------------------------------------------------- /roles/git/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Import package install tasks" 9 | ansible.builtin.import_tasks: 10 | file: "install.yml" 11 | tags: [install] 12 | 13 | - name: "Import config tasks" 14 | ansible.builtin.import_tasks: 15 | file: "config.yml" 16 | tags: [dots, gitconfig] 17 | 18 | - name: "Import authorized keys tasks" 19 | ansible.builtin.import_tasks: 20 | file: "get_authorized_keys.yml" 21 | tags: [moredots, authorized_keys] 22 | 23 | - name: "Register SSH key with Github" 24 | community.general.github_key: 25 | name: "{{ git_ssh_key_name }}" 26 | pubkey: "{{ lookup('ansible.builtin.file', git_ssh_key_public) }}" 27 | state: "present" 28 | token: "{{ git_github_token }}" 29 | when: not global_use_1password_ssh_agent 30 | tags: [never, ssh_keys] 31 | 32 | - name: "Create allowed_signers file" 33 | ansible.builtin.template: 34 | src: "allowed_signers.j2" 35 | dest: "{{ git_signing_allowed_signers }}" 36 | mode: "0644" 37 | tags: [moredots, gitconfig] 38 | 39 | - name: "Import repo cloning tasks" 40 | ansible.builtin.import_tasks: 41 | file: "clone_repos.yml" 42 | tags: [git_repos] 43 | -------------------------------------------------------------------------------- /play_all_roles.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Run all the things" 4 | hosts: all 5 | tasks: 6 | - ansible.builtin.import_role: 7 | name: "cloud" 8 | tags: [cloud] 9 | 10 | - ansible.builtin.import_role: 11 | name: "desktop" 12 | tags: [desktop] 13 | 14 | - ansible.builtin.import_role: 15 | name: "docker" 16 | tags: [docker] 17 | 18 | - ansible.builtin.import_role: 19 | name: "dotfiles" 20 | tags: [dotfiles] 21 | 22 | - ansible.builtin.import_role: 23 | name: "git" 24 | tags: [git] 25 | 26 | - ansible.builtin.import_role: 27 | name: "media" 28 | tags: [media] 29 | 30 | - ansible.builtin.import_role: 31 | name: "onepassword" 32 | tags: [onepassword] 33 | 34 | - ansible.builtin.import_role: 35 | name: "pkg_mgr" 36 | tags: [pkg_mgr] 37 | 38 | - ansible.builtin.import_role: 39 | name: "ssh" 40 | tags: [ssh] 41 | 42 | - ansible.builtin.import_role: 43 | name: "system" 44 | tags: [system] 45 | 46 | - ansible.builtin.import_role: 47 | name: "tmux" 48 | tags: [tmux] 49 | 50 | - ansible.builtin.import_role: 51 | name: "vim" 52 | tags: [vim] 53 | 54 | - ansible.builtin.import_role: 55 | name: "zsh" 56 | tags: [zsh] 57 | -------------------------------------------------------------------------------- /roles/onepassword/tasks/install/dnf5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install gpg keys" 4 | ansible.builtin.rpm_key: 5 | key: "{{ onepassword_linux_repo['gpgkey'] }}" 6 | state: "present" 7 | become: true 8 | tags: [repos] 9 | 10 | - name: "Install repository" 11 | ansible.builtin.yum_repository: "{{ onepassword_linux_repo }}" # noqa: args[module] 12 | become: true 13 | tags: [repos] 14 | 15 | - name: "Update dnf cache" 16 | ansible.builtin.dnf5: 17 | update_cache: true 18 | become: true 19 | tags: [repos] 20 | 21 | - name: "Install cli packages" 22 | ansible.builtin.dnf5: 23 | name: "{{ onepassword_packages['cli'] }}" 24 | state: present 25 | become: true 26 | tags: [install] 27 | 28 | - name: "Install gui packages" 29 | ansible.builtin.dnf5: 30 | name: "{{ onepassword_packages['gui'] }}" 31 | state: present 32 | become: true 33 | when: onepassword_use_gui_integration 34 | tags: [install] 35 | 36 | - name: "Remove repo installed by package" 37 | ansible.builtin.file: 38 | path: "{{ onepassword_repo_file }}" 39 | state: absent 40 | become: true 41 | tags: [repos] 42 | 43 | - name: "Symlink official repo to avoid custom repo being overwritten" 44 | ansible.builtin.file: 45 | src: "/etc/yum.repos.d/{{ onepassword_linux_repo['name'] }}.repo" 46 | dest: "{{ onepassword_repo_file }}" 47 | state: link 48 | become: true 49 | tags: [repos] 50 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/20-aliases.zsh.j2: -------------------------------------------------------------------------------- 1 | alias ls='ls --color=auto --classify -l --almost-all --group-directories-first --human-readable' 2 | alias lz='eza --color always --classify --long --all --group-directories-first --no-quotes' 3 | alias lk='lz --sort type' 4 | alias ll='lz --octal-permissions' 5 | alias lt='lz --tree' 6 | alias lT='lz --sort time' 7 | alias lS='lz --sort size' 8 | 9 | unalias run-help &> /dev/null || true 10 | alias help='run-help' # help topics path set via $HELPDIR 11 | 12 | {% if ansible_facts['os_family'] == "Debian" %} 13 | alias bat='batcat' 14 | {% endif %} 15 | alias cp='cp -i' 16 | alias dig='dig +noall +answer' 17 | alias dirdiff='git diff --no-index' 18 | alias e='aunpack' 19 | alias ff='fastfetch' 20 | alias isodate='date --iso-8601=seconds' 21 | alias man='batman' 22 | alias mp='multipass' 23 | alias psync='rsync -a --info=progress2' 24 | alias pubip='dig myip.opendns.com @resolver1.opendns.com -1' 25 | alias sc='shellcheck' 26 | alias scp='rsync -va' 27 | alias timestamp='date +%F_%T | tr -d ":-" | tr "_" "-"' 28 | alias vi='vim' 29 | alias vim='nvim' 30 | alias wget='wget --hsts-file="${HOME}/.local/share/wget-hsts"' 31 | {% if ansible_facts['system'] == "Linux" %} 32 | alias iowatch='watch -n 1 iostat -xy --human 1 1' 33 | alias ipa='ip -c a' 34 | alias lsblk='lsblk -o "NAME,FSTYPE,SIZE,UUID,MOUNTPOINT"' 35 | alias lsports='lsof -i -P -n' 36 | alias proc='ps -e --forest -o pid,ppid,user,time,cmd' 37 | {% endif %} 38 | -------------------------------------------------------------------------------- /roles/git/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | git_packages: 4 | - git 5 | - git-lfs 6 | - gh 7 | 8 | git_repos_path: "{{ ansible_facts['user_dir'] }}/Development/Projects" 9 | 10 | git_ssh_auth_sock: "" 11 | git_ssh_auth_pid: "" 12 | 13 | git_config_dir: "{{ ansible_facts['user_dir'] }}/.config/git" 14 | git_config_file: "{{ git_config_dir }}/config" 15 | git_ignore_file: "{{ git_config_dir }}/ignore" 16 | 17 | git_signing_allowed_signers: "{{ ansible_facts['user_dir'] }}/.ssh/allowed_signers" 18 | 19 | git_ssh_key_name: "{{ ansible_facts['user_id'] }}@{{ ansible_facts['hostname'] }}" 20 | git_ssh_key_private: "{{ ansible_facts['user_dir'] }}/.ssh/id_ed25519" 21 | git_ssh_key_public: "{{ git_ssh_key_private }}.pub" 22 | 23 | git_github_api: 24 | ssh_key_url: "https://api.github.com/user/keys" 25 | signing_key_url: "https://api.github.com/user/ssh_signing_keys" 26 | headers_accept: "application/vnd.github+json" 27 | headers_version: "2022-11-28" 28 | 29 | git_github_ghcli_repo: 30 | dnf: 31 | name: "gh-cli" 32 | description: "packages for the GitHub CLI" 33 | baseurl: "https://cli.github.com/packages/rpm" 34 | gpgkey: "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x23F3D4EA75716059" 35 | apt: 36 | name: "gh-cli" 37 | uris: ["https://cli.github.com/packages"] 38 | components: ["main"] 39 | suites: ["stable"] 40 | enabled: true 41 | signed_by: "https://cli.github.com/packages/githubcli-archive-keyring.gpg" 42 | -------------------------------------------------------------------------------- /roles/desktop/tasks/fonts/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Get latest release version of Nerd Fonts" 4 | community.general.github_release: 5 | user: "{{ desktop_fonts_github_user }}" 6 | repo: "{{ desktop_fonts_github_repo }}" 7 | action: latest_release 8 | register: desktop_fonts_latest_release 9 | tags: [install, fonts] 10 | 11 | - name: "Install newer fonts" 12 | vars: 13 | desktop_fonts_latest_version: "{{ desktop_fonts_latest_release['tag'] }}" 14 | when: "desktop_fonts_current_version is version(desktop_fonts_latest_version, '<')" 15 | tags: [install, fonts] 16 | block: 17 | - name: "Ensure fonts directory exists" 18 | ansible.builtin.file: 19 | path: "{{ desktop_fonts_dir }}" 20 | state: directory 21 | mode: "0755" 22 | - name: "Include font install tasks" 23 | ansible.builtin.include_tasks: 24 | file: "fonts/install.yml" 25 | loop: "{{ desktop_fonts_install }}" 26 | - name: "Set latest version" 27 | ansible.builtin.set_fact: 28 | desktop_fonts_current_version: "{{ desktop_fonts_latest_version }}" 29 | cacheable: true 30 | 31 | - name: "Symlink lcdfilter conf for better fonts" 32 | ansible.builtin.file: 33 | src: "/usr/share/fontconfig/conf.avail/11-lcdfilter-default.conf" 34 | dest: "/etc/fonts/conf.d/11-lcdfilter-default.conf" 35 | owner: "root" 36 | group: "root" 37 | state: link 38 | become: true 39 | when: ansible_facts['distribution'] == "Fedora" 40 | tags: [fonts] 41 | -------------------------------------------------------------------------------- /play_bootstrap_ansible.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Bootstrap Ansible requirements" 4 | hosts: all 5 | 6 | vars: 7 | galaxy_collections: 8 | - name: "ansible.posix" 9 | - name: "community.crypto" 10 | - name: "community.general" 11 | - name: "devsec.hardening" 12 | _xdg_session_type: "{{ ansible_facts['env']['XDG_SESSION_TYPE'] | default('tty') }}" 13 | _xdg_desktop: "{{ ansible_facts['env']['XDG_CURRENT_DESKTOP'] | default('') }}" 14 | _distro: "{{ ansible_facts['distribution'] }}" 15 | host_vars_yml: "host_vars/{{ ansible_facts['hostname'] }}.yml" 16 | host_vars_globals: 17 | homebrew_prefix: 18 | Linux: "/home/linuxbrew/.linuxbrew" 19 | Darwin: "/opt/homebrew" 20 | email: "{{ ansible_facts['user_id'] }}@{{ ansible_facts['hostname'] }}" 21 | is_desktop: "{{ _xdg_session_type != 'tty' or _distro == 'MacOSX' }}" 22 | desktop_environment: "{{ _xdg_desktop | lower }}" 23 | 24 | tasks: 25 | - name: "Install Ansible Galaxy requirements" 26 | community.general.ansible_galaxy_install: 27 | name: "{{ item['name'] }}" 28 | type: "{{ item['type'] | default('collection') }}" 29 | force: true 30 | loop: "{{ galaxy_collections }}" 31 | tags: [collections] 32 | 33 | - name: "Template host_vars file" 34 | ansible.builtin.template: 35 | backup: true 36 | src: "host_vars.yml.j2" 37 | dest: "{{ host_vars_yml }}" 38 | mode: "0644" 39 | tags: [host_vars] 40 | -------------------------------------------------------------------------------- /group_vars/all/dotfiles.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dotfiles_atuin: 4 | username: "{{ lookup('community.general.onepassword', 'Atuin', field='username') }}" 5 | password: "{{ lookup('community.general.onepassword', 'Atuin', field='password') }}" 6 | key: "{{ lookup('community.general.onepassword', 'Atuin', field='key') }}" 7 | 8 | dotfiles_to_remove: 9 | - ".abcde.conf" # moved to 'media' role (temp unused) 10 | - ".ansible" # moved to `~/.config/` 11 | - ".bundle" # moved to `~/.config`, `~/.cache`, `~/.local/share` 12 | - ".cargo" # no longer needed 13 | - ".diceware.ini" # moved to `~/.config/` 14 | - ".dir_colors" # no longer needed with eza 15 | - ".gitconfig" # moved to `~/.config/` 16 | - ".gitconfig.d" # no longer needed 17 | - ".gitignore" # moved to `~/.config/` 18 | - ".lesshst" # moved to `~/.config/` 19 | - ".MakeMKV" # moved to 'media' role (temp unused) 20 | - ".minikube" # no longer needed 21 | - ".npm" # moved to `~/.config`, `~/.cache`, `~/.local/run` 22 | - ".python_history" # moved to `~/.config/` 23 | - ".sqlite_history" # no longer needed 24 | - ".terminfo" # moved to `~/.local/share/` 25 | - ".vim" # moved to `~/.config/` 26 | - ".viminfo" # moved to `~/.config/` 27 | - ".vimrc" # moved to `~/.config/` 28 | - ".zcompdump" # moved to `~/.config/` 29 | - ".zsh" # moved to `~/.config/` 30 | - ".zsh_history" # moved to `~/.config/` 31 | - ".zsh_sessions" # only used for macOS Terminal 32 | - ".zshrc" # moved to `~/.config/` 33 | - ".zshrc.d" # moved to `~/.config/` 34 | -------------------------------------------------------------------------------- /roles/vim/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Install vim packages" 9 | ansible.builtin.package: 10 | name: "{{ vim_packages }}" 11 | become: "{{ true if ansible_facts['system'] == 'Linux' else false }}" 12 | tags: [install] 13 | 14 | - name: "Create config directories" 15 | ansible.builtin.file: 16 | path: "{{ item }}" 17 | state: directory 18 | mode: "0755" 19 | loop: 20 | - "{{ vim_rcd }}" 21 | - "{{ vim_neovim_rcd }}" 22 | - "{{ vim_helix_rcd }}" 23 | - "{{ vim_extensions_dir }}" 24 | tags: [dots] 25 | 26 | - name: "Copy Helix config files" 27 | ansible.builtin.copy: 28 | src: "helix/" 29 | dest: "{{ vim_helix_rcd }}/" 30 | mode: "0644" 31 | tags: [dots] 32 | 33 | - name: "Copy Neovim config files" 34 | ansible.builtin.copy: 35 | src: "nvim/" 36 | dest: "{{ vim_neovim_rcd }}/" 37 | mode: "0644" 38 | tags: [dots] 39 | 40 | - name: "Template vimrc" 41 | ansible.builtin.template: 42 | src: "vimrc.j2" 43 | dest: "{{ vim_rc }}" 44 | mode: "0644" 45 | tags: [dots] 46 | 47 | - name: "Install Vim extensions" 48 | ansible.builtin.git: 49 | repo: "{{ item['repo'] }}" 50 | dest: "{{ vim_extensions_dir }}/{{ item['name'] }}" 51 | depth: "1" 52 | version: "{{ item['version'] | default(omit) }}" 53 | loop: "{{ vim_extensions }}" 54 | loop_control: 55 | label: "{{ item['name'] }}" 56 | tags: [moredots] 57 | -------------------------------------------------------------------------------- /roles/desktop/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Install desktop utilities" 9 | ansible.builtin.package: 10 | name: "{{ desktop_packages }}" 11 | state: present 12 | become: "{{ true if ansible_facts['system'] == 'Linux' else false }}" 13 | tags: [install, fonts, icons] 14 | 15 | - name: "Reset macOS dock" 16 | community.general.osx_defaults: 17 | domain: com.apple.dock 18 | key: "persistent-apps" 19 | type: "array" 20 | value: [] 21 | notify: Restart macOS dock 22 | when: ansible_facts['system'] == "Darwin" 23 | tags: [never] 24 | 25 | - name: "Reset Gnome dock" 26 | community.general.dconf: 27 | key: "/org/gnome/shell/favorites" 28 | value: "['org.gnome.Nautilus.desktop']" 29 | when: "'gnome' in desktop_current_environment" 30 | tags: [never] 31 | 32 | - name: "Include font tasks" 33 | ansible.builtin.include_tasks: 34 | file: "fonts/main.yml" 35 | tags: [fonts] 36 | 37 | - name: "Include Logitech tasks" 38 | ansible.builtin.include_tasks: 39 | file: "logi.yml" 40 | when: (ansible_facts['system'] == "Darwin") and (desktop_logi_app_install) 41 | tags: [logitech] 42 | 43 | - name: "Include icon tasks" 44 | ansible.builtin.include_tasks: 45 | file: "icons.yml" 46 | loop: "{{ desktop_apps_paths }}" 47 | loop_control: 48 | label: "{{ path }}" 49 | loop_var: path 50 | when: ansible_facts['system'] == "Darwin" 51 | tags: [icons] 52 | -------------------------------------------------------------------------------- /host_vars/mac06770.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | global_email_address: "bfrank@oreilly.com" 4 | global_is_desktop_system: true 5 | global_desktop_environment: "" 6 | global_homebrew_prefix: "/opt/homebrew" 7 | global_onepassword_vault: "Employee" 8 | global_use_1password_ssh_agent: true 9 | global_host_roles: 10 | - cloud 11 | - desktop 12 | - dotfiles 13 | - git 14 | - pkg_mgr 15 | - ssh 16 | - system 17 | - tmux 18 | - vim 19 | - zsh 20 | 21 | desktop_app_paths: 22 | - "/Applications" 23 | - "{{ ansible_facts['user_dir'] }}/Applications/Chrome Apps.localized" 24 | 25 | git_clone_repos: 26 | - url: "git@github.com:bradleyfrank/ansible.git" 27 | - url: "git@github.com:bradleyfrank/notes-etc.git" 28 | - url: "git@github.com:bradleyfrank/util-containers.git" 29 | - url: "git@github.com:bradleyfrank/cliday.git" 30 | 31 | infractl_token: "{{ lookup('community.general.onepassword', 'Infractl Token', field='credential') }}" 32 | 33 | pkg_mgr_gui: 34 | casks: 35 | - 1password 36 | - 1password-cli 37 | - ghostty 38 | - google-cloud-sdk 39 | - itsycal 40 | - keepingyouawake 41 | - maccy 42 | - multipass 43 | - netnewswire 44 | - numi 45 | - pearcleaner 46 | - vlc 47 | - zoom 48 | mas: [] 49 | 50 | ssh_manage_config: false 51 | 52 | zsh_completions: 53 | - name: "kubectl" 54 | command: "kubectl completion zsh" 55 | - name: "stern" 56 | command: "kubectl stern --completion=zsh" 57 | - name: "k9s" 58 | command: "k9s completion zsh" 59 | 60 | system_macos_sleep_display: -1 61 | system_macos_sleep_computer: -1 62 | -------------------------------------------------------------------------------- /roles/onepassword/tasks/install/apt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Install 1Password repository" 4 | ansible.builtin.deb822_repository: "{{ onepassword_linux_repo }}" # noqa: args[module] 5 | become: true 6 | tags: [repos] 7 | 8 | - name: "Create debsig-verify policy directory" 9 | ansible.builtin.file: 10 | path: "{{ onepassword_debsig_dir }}" 11 | state: directory 12 | mode: "0644" 13 | become: true 14 | tags: [repos] 15 | 16 | - name: "Add debsign-verify policy" 17 | ansible.builtin.get_url: 18 | url: "{{ onepassword_debsig_url }}" 19 | dest: "{{ onepassword_debsig_dir }}/1password.pol" 20 | mode: "0644" 21 | become: true 22 | tags: [repos] 23 | 24 | - name: "Update apt cache" 25 | ansible.builtin.apt: 26 | update_cache: true 27 | become: true 28 | tags: [repos] 29 | 30 | - name: "Install 1Password cli package" 31 | ansible.builtin.apt: 32 | name: "{{ onepassword_packages['cli'] }}" 33 | state: present 34 | autoclean: true 35 | autoremove: true 36 | install_recommends: true 37 | become: true 38 | tags: [install] 39 | 40 | - name: "Install 1Password gui package" 41 | ansible.builtin.apt: 42 | name: "{{ onepassword_packages['gui'] }}" 43 | state: present 44 | autoclean: true 45 | autoremove: true 46 | install_recommends: true 47 | become: true 48 | when: onepassword_use_gui_integration 49 | tags: [install] 50 | 51 | - name: "Remove repo installed by package" 52 | ansible.builtin.file: 53 | path: "{{ onepassword_repo_file }}" 54 | state: absent 55 | become: true 56 | tags: [repos] 57 | -------------------------------------------------------------------------------- /roles/onepassword/tasks/auth.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Add account to 1Password-cli" 4 | vars: 5 | address: "--address {{ onepassword_signin_url }}" 6 | email: "--email {{ onepassword_email_address }}" 7 | secret_key: "--secret-key {{ onepassword_secret_key }}" 8 | ansible.builtin.expect: 9 | command: "op account add {{ address }} {{ email }} {{ secret_key }}" 10 | responses: 11 | Enter the password: "{{ onepassword_account_password }}" 12 | 13 | - name: "Confirm account is present" 14 | ansible.builtin.command: 15 | cmd: "op account list --format json" 16 | register: cmd_op_account_list 17 | changed_when: (cmd_op_account_list['stdout'] | from_json)[0]['user_uuid'] 18 | failed_when: not (cmd_op_account_list['stdout'] | from_json)[0]['user_uuid'] 19 | 20 | - name: "Generate session token" 21 | ansible.builtin.expect: 22 | command: "op signin --raw" 23 | responses: 24 | Enter the password: "{{ onepassword_account_password }}" 25 | register: cmd_op_session_token 26 | 27 | - name: "Generate shell command to set envars" 28 | vars: 29 | # Split output because the first line is the 'Enter password' prompt. 30 | onepassword_session_token: "{{ cmd_op_session_token['stdout'] | split('\n') | last }}" 31 | ansible.builtin.command: 32 | cmd: "op signin --session {{ onepassword_session_token }} --force" 33 | changed_when: true 34 | register: cmd_op_signin 35 | 36 | - name: "Save shell command to file for sourcing" 37 | ansible.builtin.copy: 38 | content: "{{ cmd_op_signin['stdout'] | default('') }}" 39 | dest: "{{ onepassword_session_file }}" 40 | mode: "0400" 41 | -------------------------------------------------------------------------------- /roles/vim/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | vim_helix_rcd: "{{ ansible_facts['user_dir'] }}/.config/helix" 4 | vim_neovim_rcd: "{{ ansible_facts['user_dir'] }}/.config/nvim" 5 | 6 | vim_packages: "{{ 7 | vim_vim_package[ansible_facts['pkg_mgr']] + 8 | vim_neovim_package[ansible_facts['pkg_mgr']] + 9 | vim_helix_package[ansible_facts['pkg_mgr']] 10 | }}" 11 | 12 | vim_rcd: "{{ ansible_facts['user_dir'] }}/.config/vim" 13 | vim_rc: "{{ vim_rcd }}/vimrc" 14 | vim_extensions_dir: "{{ vim_rcd }}/pack/default/start" 15 | 16 | vim_extensions: 17 | - name: "vim-airline" 18 | repo: "https://github.com/vim-airline/vim-airline.git" 19 | - name: "vim-airline-themes" 20 | repo: "https://github.com/vim-airline/vim-airline-themes.git" 21 | - name: "vim-gitgutter" 22 | repo: "https://github.com/airblade/vim-gitgutter.git" 23 | version: "main" 24 | - name: "vim-indent-guides" 25 | repo: "https://github.com/preservim/vim-indent-guides.git" 26 | - name: "vim-solarized8" 27 | repo: "https://github.com/lifepillar/vim-solarized8.git" 28 | - name: "vim-terraform" 29 | repo: "https://github.com/hashivim/vim-terraform.git" 30 | - name: "vim-jinja2-syntax" 31 | repo: "https://github.com/Glench/Vim-Jinja2-Syntax.git" 32 | - name: "fzf.vim" 33 | repo: "https://github.com/junegunn/fzf.vim.git" 34 | - name: "vim-fugitive" 35 | repo: "https://github.com/tpope/vim-fugitive.git" 36 | - name: "vim-css-color" 37 | repo: "https://github.com/ap/vim-css-color.git" 38 | - name: "vim-markdown" 39 | repo: "https://github.com/preservim/vim-markdown.git" 40 | - name: "vim-peekaboo" 41 | repo: "https://github.com/junegunn/vim-peekaboo.git" 42 | -------------------------------------------------------------------------------- /group_vars/Linux_Mint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | _bat_exec: "/usr/bin/batcat" 4 | 5 | tmux_clipboard: "xsel --clipboard --input" 6 | 7 | pkg_mgr_repos: 8 | base: 9 | - name: "charm" 10 | uris: ["https://repo.charm.sh/apt"] 11 | components: ["*"] 12 | suites: ["*"] 13 | enabled: true 14 | signed_by: "https://apt.fury.io/charmcli/gpg.key" 15 | 16 | pkg_mgr_cli: 17 | base: 18 | - apt-file 19 | - asciinema 20 | - atool 21 | - bash-completion 22 | - bat 23 | - bcal 24 | - diceware 25 | - dictd 26 | - duf 27 | - fastfetch 28 | - fd-find 29 | - ffmpeg 30 | - figlet 31 | - freeze 32 | - fwupd 33 | - fzf 34 | - ghostscript 35 | - glow # available from LTS Ubuntu repos as of 26.04 36 | - htop 37 | - httpie 38 | - iftop 39 | - inxi 40 | - jq 41 | - keychain 42 | - libmp4-info-perl 43 | - libvirt-clients 44 | - mkvtoolnix 45 | - msmtp 46 | - mtr 47 | - nmap 48 | - p7zip-* 49 | - par 50 | - perf-tools-unstable 51 | - pdfgrep 52 | - pwgen 53 | - python3 54 | - python3-dev 55 | - python3-pip 56 | - ripgrep 57 | - shellcheck 58 | - strace 59 | - tidy 60 | - tlp 61 | - trurl 62 | - toilet 63 | - tree 64 | - virtualenv 65 | - wget 66 | - xz-utils 67 | - yt-dlp 68 | formulas: 69 | - argc 70 | - atuin 71 | - bat-extras 72 | - dua-cli 73 | - eza 74 | - fclones 75 | - qsv 76 | - yq 77 | 78 | pkg_mgr_gui: 79 | common: 80 | - 1password 81 | - keepassxc 82 | - libreoffice 83 | - picard 84 | - vlc 85 | cinnamon: 86 | - celluloid 87 | - mpv 88 | - transmission-gtk 89 | -------------------------------------------------------------------------------- /roles/system/tasks/Darwin.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Set macOS default settings" 4 | community.general.osx_defaults: 5 | domain: "{{ item['domain'] }}" 6 | key: "{{ item['key'] }}" 7 | type: "{{ item['type'] }}" 8 | value: "{{ item['value'] }}" 9 | loop: "{{ system_macos_defaults }}" 10 | loop_control: 11 | label: "{{ item['name'] }}" 12 | notify: Restart macOS dock 13 | tags: [mac_defaults] 14 | 15 | - name: "Put display to sleep after X minutes" 16 | ansible.builtin.command: 17 | cmd: "pmset displaysleep {{ system_macos_sleep_display }}" 18 | changed_when: false 19 | become: true 20 | when: system_macos_sleep_display >= 0 21 | tags: [sleep, become] 22 | 23 | - name: "Put computer to sleep after X minutes" 24 | ansible.builtin.command: 25 | cmd: "pmset sleep {{ system_macos_sleep_computer }}" 26 | changed_when: false 27 | become: true 28 | when: system_macos_sleep_computer >= 0 29 | tags: [sleep, become] 30 | 31 | - name: "Enable firewall" 32 | ansible.builtin.command: 33 | cmd: "{{ system_macos_firewall_cmd }} --setglobalstate on" 34 | changed_when: true 35 | become: true 36 | when: system_macos_firewall_enabled 37 | tags: [firewall, become] 38 | 39 | - name: "Unhide ~/Library" 40 | ansible.builtin.shell: 41 | cmd: | 42 | chflags nohidden ~/Library 43 | xattr -d com.apple.FinderInfo ~/Library || true # xattr not idempotent 44 | changed_when: true 45 | when: system_macos_unhide_user_library 46 | tags: [dir_flags] 47 | 48 | - name: "Unhide /Volumes" 49 | ansible.builtin.command: 50 | cmd: "chflags nohidden /Volumes" 51 | changed_when: true 52 | become: true 53 | when: system_macos_unhide_volumes 54 | tags: [dir_flags, become] 55 | -------------------------------------------------------------------------------- /roles/media/files/abcde.conf: -------------------------------------------------------------------------------- 1 | ACTIONS=default,embedalbumart 2 | CDDBCOPYLOCAL=y 3 | CDDBLOCALDIR="$HOME/.cddb" 4 | CDDBLOCALRECURSIVE=y 5 | CDDBMETHOD=musicbrainz 6 | CDDBUSELOCAL=y 7 | CDDISCID=cd-discid 8 | CDPARANOIA=cdparanoia 9 | CDPARANOIAOPTS="--never-skip=40" 10 | CDROMREADERSYNTAX=cdparanoia 11 | EJECTCD=y 12 | EXTRAVERBOSE=1 13 | LOWDISK=y 14 | MAXPROCS=2 15 | OUTPUTTYPE="ogg,mp3,flac,m4a" 16 | PADTRACKS=y 17 | 18 | OUTPUTDIR="$HOME/Music/abcde" 19 | ONETRACKOUTPUTFORMAT='${OUTPUT}/${ARTISTFILE}/${ALBUMFILE}/${ALBUMFILE}' 20 | VAONETRACKOUTPUTFORMAT='${OUTPUT}/Various/${ALBUMFILE}/${ALBUMFILE}' 21 | OUTPUTFORMAT='${OUTPUT}/${ARTISTFILE}/${ALBUMFILE}/${TRACKNUM}.${TRACKFILE}' 22 | VAOUTPUTFORMAT='${OUTPUT}/Various/${ALBUMFILE}/${TRACKNUM}.${TRACKFILE}' 23 | 24 | OGGENCODERSYNTAX=oggenc # Specify encoder for Ogg Vorbis 25 | MP3ENCODERSYNTAX=lame # Specify encoder for MP3 26 | FLACENCODERSYNTAX=flac # Specify encoder for FLAC 27 | AACENCODERSYNTAX=fdkaac # Specify encoder for AAC 28 | 29 | OGGENC=oggenc # Path to Ogg Vorbis encoder 30 | LAME=lame # Path to MP3 encoder 31 | FLAC=flac # Path to FLAC encoder 32 | FDKAAC=fdkaac # Path to the AAC encoder 33 | FFMPEG=ffmpeg # Path to FFmpeg (AC3 via FFmpeg) 34 | 35 | OGGENCOPTS='-q 6' # Options for Ogg Vorbis 36 | LAMEOPTS='-V 2' # Options for MP3 37 | FLACOPTS='-s -e -V -8' # Options for FLAC 38 | FDKAACENCOPTS='-p 2 -m 5 -a 1' # Options for fdkaac 39 | 40 | mungefilename () 41 | { 42 | echo "$@" | sed -e 's/^\.*//' -e 's/ /_/g' | tr -d ":><|*/\"'?[:cntrl:]" 43 | } 44 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/mk8sconf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @meta describe Generate or add entries to kubeconfig for GKE 4 | # @meta author Brad Frank 5 | # @meta require-tools fzf 6 | # @meta combine-shorts 7 | 8 | 9 | # @option -p --projects*, 10 | # @flag -a --append 11 | main() { 12 | local project projectId temp_cluster_list 13 | 14 | temp_cluster_list="$(mktemp)" 15 | KUBECONFIG="${KUBECONFIG:-"${HOME}/.kube/config"}" 16 | 17 | if [[ -z $argc_projects ]]; then 18 | argc_projects="$(gcloud projects list \ 19 | --sort-by 'projectId' \ 20 | --filter 'projectId !~ "^(sys|quickstart|test|gam)-.*" AND lifecycleState=ACTIVE' \ 21 | --format 'value[separator=";"](projectId,name)' \ 22 | | awk -F ';' '{print $1" ("$2")"}' \ 23 | | fzf --multi 24 | )" 25 | fi 26 | 27 | if [[ -e $KUBECONFIG ]]; then 28 | cp "$KUBECONFIG" "${KUBECONFIG}.$(date --iso-8601=seconds | tr -d ':-')" 29 | fi 30 | 31 | if [[ -z $argc_append ]]; then 32 | rm -f "$KUBECONFIG" 33 | fi 34 | 35 | while read -r project; do 36 | projectId="$(awk -F ' ' '{print $1}' <<< "$project")" 37 | gcloud container clusters list \ 38 | --project "$projectId" \ 39 | --format="value[separator=' '](name,zone)" \ 40 | | sed "s/^/${projectId} /g" \ 41 | | awk '{print "("$1") " $2" "$1" "$3}' >> "$temp_cluster_list" 42 | done <<< "$argc_projects" 43 | 44 | while read -r cluster; do 45 | gcloud container clusters get-credentials "$(awk '{print $2}' <<< "$cluster")" \ 46 | --project "$(awk '{print $3}' <<< "$cluster")" \ 47 | --region "$(awk '{print $4}' <<< "$cluster")" 48 | done < <(fzf --multi --with-nth 2,1 < "$temp_cluster_list") 49 | 50 | rm "$temp_cluster_list" 51 | } 52 | 53 | eval "$(argc --argc-eval "$0" "$@")" 54 | -------------------------------------------------------------------------------- /roles/system/tasks/Linux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Add DNS fallback" 4 | become: true 5 | tags: [dns, become] 6 | when: system_linux_dns_fallback | length > 0 7 | block: 8 | - name: "Ensure 'resolved' conf directory exists" 9 | ansible.builtin.file: 10 | path: "/etc/systemd/resolved.conf.d" 11 | mode: "0755" 12 | state: "directory" 13 | - name: "Add DNS fallback for systemd-resolved" 14 | ansible.builtin.template: 15 | src: "resolved.conf.j2" 16 | dest: "/etc/systemd/resolved.conf.d/fallback_dns.conf" 17 | mode: "0644" 18 | 19 | - name: "Apply dconf settings" 20 | become: true 21 | tags: [dconf, become] 22 | when: "'gnome' in system_linux_current_desktop" 23 | block: 24 | - name: "Install dconf package" 25 | ansible.builtin.package: 26 | name: "{{ system_pkg_dconf[ansible_facts['pkg_mgr']] }}" 27 | - name: "Load dconf tasks" 28 | vars: 29 | dconf_prefix: "{{ item['path'] }}" 30 | dconf_settings: "{{ item['keys'] }}" 31 | ansible.builtin.include_tasks: 32 | file: "dconf.yml" 33 | loop: "{{ system_linux_dconf }}" 34 | loop_control: 35 | label: "{{ dconf_prefix }}" 36 | 37 | - name: "Set Yaru light theme (Ubuntu)" 38 | community.general.dconf: 39 | key: "/org/gnome/desktop/interface" 40 | value: "'Yaru-light'" 41 | become: true 42 | when: ansible_facts['distribution'] == "Ubuntu" 43 | tags: [dconf, become] 44 | 45 | - name: "Enable bluetooth at boot" 46 | ansible.builtin.lineinfile: 47 | mode: "0644" 48 | path: "/etc/dracut.conf.d/ble.conf" 49 | line: "add_dracutmodules+=' bluetooth '" 50 | state: present 51 | become: true 52 | notify: Regenerate Dracut 53 | when: ansible_facts['distribution'] == "Fedora" # Remove as of Ubuntu 25.10 54 | tags: [never, bluetooth] 55 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/id3renamer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sanitize() { 4 | echo "$1" | sed 's/[^[:alnum:]]/_/g' | sed 's/\(\-\)\1/\1/g' 5 | } 6 | 7 | 8 | declare -A ALBUMS_SCANNED 9 | declare BASE_DIR; BASE_DIR="${HOME}/Music/TaggedMusic" 10 | 11 | mkdir "$BASE_DIR" 12 | 13 | 14 | while read -r file; do 15 | [[ -d "$file" ]] && continue 16 | 17 | tags="$(ffprobe -loglevel fatal -show_entries format_tags -of json "$file")" 18 | id3="$(jq '.format.tags' <<< "$tags")" 19 | 20 | [[ "$id3" == "null" ]] && exit 1 21 | 22 | id3_album_raw="$(jq -r '.album' <<< "$id3")" 23 | id3_album="$(sanitize "$id3_album_raw")" 24 | 25 | id3_title_raw="$(jq -r '.title' <<< "$id3")" 26 | id3_title="$(sanitize "$id3_title_raw")" 27 | 28 | id3_discs="$(jq -jr '.disc' <<< "$id3")" 29 | id3_tracks="$(jq -jr '.track' <<< "$id3")" 30 | 31 | id3_totdiscs="$(cut -d/ -f2 <<< "$id3_discs")" 32 | id3_tottracks="$(cut -d/ -f2 <<< "$id3_tracks")" 33 | id3_curdisc="$(cut -d/ -f1 <<< "$id3_discs")" 34 | id3_curtrack="$(cut -d/ -f1 <<< "$id3_tracks")" 35 | 36 | filename="${file##*/}" 37 | extension="${filename##*.}" 38 | 39 | rep_filename="$(printf \ 40 | "%0${#id3_totdiscs}dx%0${#id3_tottracks}d.%s.%s\n" \ 41 | "$id3_curdisc" "$id3_curtrack" "$id3_title" "$extension" 42 | )" 43 | 44 | printf "Processing... %s :: Disc %s :: Track %s\n" "$id3_album_raw" "$id3_discs" "$id3_tracks" 45 | 46 | [[ ! -d "$id3_album" ]] && mkdir "$id3_album" 47 | cp "$file" "${id3_album}/${rep_filename}" 48 | ALBUMS_SCANNED["$id3_album"]="" 49 | done <<< "$(find ./ -maxdepth 1 -type f -printf '%P\n' | sort -n)" 50 | 51 | 52 | for album in "${!ALBUMS_SCANNED[@]}"; do 53 | if [[ ! -d "${BASE_DIR}/${album}" ]]; then 54 | mv "${PWD}/${album}" "${BASE_DIR}/${album}" 55 | else 56 | printf "\nSkipped moving directory '%s'" "$album" 57 | fi 58 | done 59 | -------------------------------------------------------------------------------- /roles/git/templates/gitconfig.j2: -------------------------------------------------------------------------------- 1 | [alias] 2 | co = checkout 3 | graph = log --oneline --decorate --graph --all 4 | history = log --full-history -- 5 | last = log -1 HEAD --stat 6 | ll = log --oneline 7 | s = switch 8 | sb = status -sb 9 | search = !git rev-list --all | xargs git grep -F 10 | showtag = !git --no-pager tag -l --sort=v:refname | tail -n -1 11 | std = stash drop 12 | stp = stash pop 13 | tags = tag -l --sort=v:refname 14 | unstage = reset HEAD -- 15 | upstream = !git branch --show-current | xargs -I{} git branch --set-upstream-to origin/{} {} 16 | wtl = worktree list 17 | [branch] 18 | sort = -committerdate 19 | [commit] 20 | gpgsign = true 21 | verbose = true 22 | [core] 23 | excludesfile = {{ ansible_facts['user_dir'] }}/.config/git/ignore 24 | editor = vim 25 | {% if ansible_facts['system'] == 'Darwin' %} 26 | fsmonitor = true 27 | {% endif %} 28 | untrackedCache = true 29 | [diff] 30 | algorithm = histogram 31 | [gpg] 32 | format = ssh 33 | [gpg "ssh"] 34 | allowedSignersFile = {{ git_signing_allowed_signers }} 35 | [help] 36 | autocorrect = 20 37 | [init] 38 | defaultBranch = main 39 | [merge] 40 | {% if (ansible_facts['distribution'] == 'Ubuntu') and 41 | (ansible_facts['distribution_version'] | int < 24) %} 42 | conflictstyle = diff3 43 | {% else %} 44 | conflictstyle = zdiff3 45 | {% endif %} 46 | [pull] 47 | rebase = true 48 | [push] 49 | default = current 50 | [rebase] 51 | autoStash = true 52 | [rerere] 53 | enabled = true 54 | [status] 55 | showUntrackedfiles = all 56 | {% if ansible_facts['hostname'] == "mac06770" %} 57 | [url "https://{{ infractl_token }}@github.com"] 58 | insteadOf = https://github.com 59 | {% endif %} 60 | [user] 61 | name = {{ ansible_facts['user_gecos'] }} 62 | email = {{ global_email_address }} 63 | signingkey = {{ git_signing_pub_key[0] }} {{ git_signing_pub_key[1] }} 64 | -------------------------------------------------------------------------------- /roles/zsh/files/rc.d/show.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # 4 | # 5 | # Author: Brad Frank 6 | # Date: March 2024 7 | # Tested: zsh 5.9 (arm-apple-darwin22.1.0) 8 | # Requires: bat, jq 9 | # 10 | 11 | show() { 12 | local arg opt_help opt_pager no_pager \ 13 | whence_type whence_word orig_path real_path disp_path charset_regex 14 | local -a bat 15 | 16 | charset_regex="[0-9A-Za-z_:\-]+" 17 | 18 | zparseopts -D -E -- \ 19 | h=opt_help -help=opt_help \ 20 | p=opt_pager -no-pager=opt_pager \ 21 | 22 | [[ -n $opt_help ]] && { _show_usage; return 0; } 23 | [[ -n $opt_pager ]] && bat=("bat" "--paging=never") || bat=("bat" "--paging=always") 24 | [[ -z "$1" ]] && arg="$(fzf --no-multi -0 -1)" || arg="$1" 25 | 26 | whence_word="$(whence -w "$arg")" 27 | whence_type="${${(s/ /)whence_word}[2]}" 28 | 29 | case "$whence_type" in 30 | "alias") 31 | whence -f "$arg" | bat --pager=never --language=sh 32 | ;; 33 | "builtin") 34 | run-help "$arg" 35 | ;; 36 | "command") 37 | orig_path="$(whence "$arg")" 38 | real_path="$(realpath -- "$orig_path")" 39 | disp_path="%F{64}${real_path}%f" 40 | [[ "$orig_path" != "$real_path" ]] && disp_path="%F{136}${orig_path}%f  %F{64}${real_path}%f" 41 | source =(file --brief --mime "$real_path" | grep -Eo "charset=${charset_regex}" | sort -u) 42 | [[ "$charset" == "binary" ]] && print -P -- "$disp_path" || "${bat[@]}" "$real_path" 43 | ;; 44 | "function") 45 | whence -f "$arg" | "${bat[@]}" --language=sh 46 | ;; 47 | "hashed") 48 | print -P -- "$whence_word" 49 | ;; 50 | "reserved") 51 | print -P -- "$whence_word" 52 | ;; 53 | "none") 54 | case "${arg:t:e}" in 55 | "md") PAGER="${bat[@]}" glow "$arg" ;; 56 | "json") jq -C < "$arg" | "${bat[@]}" ;; 57 | *) "${bat[@]}" "$arg" ;; 58 | esac 59 | ;; 60 | esac 61 | } 62 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/share/keychain/init: -------------------------------------------------------------------------------- 1 | export KEYCHAIN_DIR="${HOME}/.local/share/keychain" 2 | 3 | _keychain_load_agent() { 4 | if [[ -s "${KEYCHAIN_DIR}/agent" ]]; then 5 | source "${KEYCHAIN_DIR}/agent" >/dev/null 6 | else 7 | killall ssh-agent >/dev/null 2>&1 8 | _keychain_eval_ssh_agent 9 | fi 10 | } 11 | 12 | 13 | _keychain_eval_ssh_agent() { 14 | eval "$(ssh-agent -s | tee "${KEYCHAIN_DIR}/agent")" >/dev/null 15 | } 16 | 17 | 18 | _keychain_ssh_add() { 19 | if SSH_ASKPASS_KEY="$1" SSH_ASKPASS_REQUIRE=force SSH_ASKPASS=op-ssh \ 20 | ssh-add "$2" >/dev/null 2>&1 21 | then 22 | echo $'\uf43d' " \e[32mIdentity added: ${key}\e[0m" 23 | else 24 | echo $'\uf43d' " \e[31mError adding identity: ${key}\e[0m" 25 | fi 26 | } 27 | 28 | 29 | _keychain_init() { 30 | local key ssh_key_file ssh_key_hash_file ssh_key_hash ssh_agent_fingerprints 31 | local -a keys; keys=("$@") 32 | 33 | ssh_agent_fingerprints="$(ssh-add -l | awk '{print $2}' | tr '\n' ' ')" 34 | 35 | for key in "${keys[@]}"; do 36 | if [[ -f "$key" ]]; then 37 | ssh_key_file="$key" 38 | elif [[ -f "${HOME}/.ssh/${key}" ]]; then 39 | ssh_key_file="${HOME}/.ssh/${key}" 40 | else 41 | echo $'\uf43d' " \e[31mIdentity skipped: ${key}\e[0m" 42 | continue 43 | fi 44 | 45 | ssh_key_hash_file="${KEYCHAIN_DIR}/$(tr '/' '_' <<< "$ssh_key_file")" 46 | 47 | if [[ -s "$ssh_key_hash_file" ]]; then 48 | ssh_key_hash="$(<"$ssh_key_hash_file")" 49 | else 50 | ssh_key_hash="$(ssh-keygen -lf "$ssh_key_file" | awk '{print $2}' | tee "${ssh_key_hash_file}")" 51 | fi 52 | 53 | if [[ "$ssh_agent_fingerprints" != *"$ssh_key_hash"* ]]; then 54 | _keychain_ssh_add "$key" "$ssh_key_file" 55 | fi 56 | done 57 | } 58 | 59 | 60 | if pgrep ssh-agent >/dev/null 2>&1; then 61 | _keychain_load_agent 62 | else 63 | _keychain_eval_ssh_agent 64 | fi 65 | 66 | _keychain_init "$@" 67 | -------------------------------------------------------------------------------- /roles/dotfiles/files/root/.bashrc: -------------------------------------------------------------------------------- 1 | #shellcheck disable=SC1090,SC1091,SC2148 2 | 3 | # If not running interactively, don't do anything 4 | [[ -z "$PS1" ]] && return 5 | 6 | # Source global definitions 7 | [[ -f /etc/bashrc ]] && source /etc/bashrc 8 | 9 | # don't put duplicate lines in the history. See bash(1) for more options 10 | # ... or force ignoredups and ignorespace 11 | HISTCONTROL=ignoredups:ignorespace 12 | 13 | # append to the history file, don't overwrite it 14 | shopt -s histappend 15 | 16 | # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) 17 | HISTSIZE=1000 18 | HISTFILESIZE=2000 19 | 20 | # check the window size after each command and, if necessary, 21 | # update the values of LINES and COLUMNS. 22 | shopt -s checkwinsize 23 | 24 | # make less more friendly for non-text input files, see lesspipe(1) 25 | [[ -x /usr/bin/lesspipe ]] && eval "$(SHELL=/bin/sh lesspipe)" 26 | 27 | # enable color support of ls and also add handy aliases 28 | if [[ -x /usr/bin/dircolors ]]; then 29 | if [[ -r ~/.dircolors ]]; then eval "$(dircolors -b ~/.dircolors)"; else eval "$(dircolors -b)"; fi 30 | alias ls='ls --color=auto' 31 | alias dir='dir --color=auto' 32 | alias vdir='vdir --color=auto' 33 | alias grep='grep --color=auto' 34 | alias fgrep='fgrep --color=auto' 35 | alias egrep='egrep --color=auto' 36 | fi 37 | 38 | # some more ls aliases 39 | alias ll='ls -alF' 40 | alias la='ls -A' 41 | alias l='ls -CF' 42 | alias rm='rm -i' 43 | alias cp='cp -i' 44 | alias mv='mv -i' 45 | 46 | [[ -f ~/.bash_aliases ]] && source ~/.bash_aliases 47 | 48 | # enable programmable completion features (you don't need to enable 49 | # this, if it's already enabled in /etc/bash.bashrc and /etc/profile 50 | # sources /etc/bash.bashrc). 51 | if [[ -f /etc/bash_completion ]] && ! shopt -oq posix; then 52 | source /etc/bash_completion 53 | fi 54 | 55 | bind "set mark-symlinked-directories on" 56 | bind "set visible-stats on" 57 | 58 | PS1="[\[\e[38;5;166m\]\u\[\e[0;0m\]@\[\e[38;5;33m\]\h\[\e[0;0m\]:\[\e[38;5;160m\]\W\[\e[0;0m\]]# " 59 | -------------------------------------------------------------------------------- /roles/onepassword/templates/op.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "title": "{{ ansible_facts['hostname'] }}", 3 | "category": "SERVER", 4 | "sections": [ 5 | { 6 | "id": "ssh_keys", 7 | "label": "SSH" 8 | }, 9 | { 10 | "id": "admin_console", 11 | "label": "Admin Console" 12 | } 13 | ], 14 | "fields": [ 15 | { 16 | "id": "notesPlain", 17 | "type": "STRING", 18 | "purpose": "NOTES", 19 | "label": "notesPlain", 20 | "value": "" 21 | }, 22 | { 23 | "id": "username", 24 | "type": "STRING", 25 | "label": "username", 26 | "value": "{{ ansible_facts['user_id'] }}" 27 | }, 28 | { 29 | "id": "password", 30 | "type": "CONCEALED", 31 | "label": "password", 32 | "value": "" 33 | }, 34 | { 35 | "id": "SSH_id_rsa", 36 | "section": { 37 | "id": "ssh_keys", 38 | "label": "SSH" 39 | }, 40 | "type": "CONCEALED", 41 | "label": "id_rsa", 42 | "value": "{{ rsa_passphrase }}" 43 | }, 44 | { 45 | "id": "SSH_id_ed25519", 46 | "section": { 47 | "id": "ssh_keys", 48 | "label": "SSH" 49 | }, 50 | "type": "CONCEALED", 51 | "label": "id_ed25519", 52 | "value": "{{ ed25519_passphrase }}" 53 | }, 54 | { 55 | "id": "admin_console_url", 56 | "section": { 57 | "id": "admin_console", 58 | "label": "Admin Console" 59 | }, 60 | "type": "STRING", 61 | "label": "admin console URL", 62 | "value": "{{ ansible_facts['default_ipv4']['address'] }}" 63 | }, 64 | { 65 | "id": "admin_console_username", 66 | "section": { 67 | "id": "admin_console", 68 | "label": "Admin Console" 69 | }, 70 | "type": "STRING", 71 | "label": "admin console username", 72 | "value": "root" 73 | }, 74 | { 75 | "id": "admin_console_password", 76 | "section": { 77 | "id": "admin_console", 78 | "label": "Admin Console" 79 | }, 80 | "type": "CONCEALED", 81 | "label": "console password", 82 | "value": "" 83 | } 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /group_vars/Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | _bat_exec: "/usr/bin/batcat" 4 | 5 | tmux_clipboard: "wl-copy" 6 | 7 | pkg_mgr_repos: 8 | base: 9 | - name: "charm" 10 | uris: ["https://repo.charm.sh/apt"] 11 | components: ["*"] 12 | suites: ["*"] 13 | enabled: true 14 | signed_by: "https://apt.fury.io/charmcli/gpg.key" 15 | - name: "backports" 16 | uris: "http://deb.debian.org/debian" 17 | components: ["main"] 18 | suites: ["{{ ansible_facts['distribution_release'] }}-backports"] 19 | enabled: true 20 | signed_by: "/usr/share/keyrings/debian-archive-keyring.gpg" 21 | 22 | pkg_mgr_cli: 23 | base: 24 | - apt-file 25 | - asciinema 26 | - atool 27 | - atuin 28 | - bash-completion 29 | - bat 30 | - bcal 31 | - diceware 32 | - dictd 33 | - duf 34 | - eza 35 | - fastfetch 36 | - fd-find 37 | - ffmpeg 38 | - figlet 39 | - freeze 40 | - fwupd 41 | - fzf 42 | - ghostscript 43 | - glow # 'charm' repo 44 | - htop 45 | - httpie 46 | - iftop 47 | - inxi 48 | - jq 49 | - keychain 50 | - libmp4-info-perl 51 | - libvirt-clients 52 | - mkvtoolnix 53 | - msmtp 54 | - mtr 55 | - nmap 56 | - p7zip-* 57 | - par 58 | - perf-tools-unstable 59 | - pdfgrep 60 | - pwgen 61 | - python3 62 | - python3-dev 63 | - python3-pip 64 | - ripgrep 65 | - shellcheck 66 | - strace 67 | - tidy 68 | - tlp 69 | - trurl 70 | - toilet 71 | - tree 72 | - virtualenv 73 | - wget 74 | - xz-utils 75 | - yt-dlp 76 | formulas: 77 | - argc 78 | - bat-extras 79 | - dua-cli 80 | - fclones 81 | - qsv 82 | - yq 83 | 84 | pkg_mgr_gui: 85 | common: 86 | - 1password 87 | - keepassxc 88 | - libreoffice 89 | - picard 90 | - vlc 91 | gnome: 92 | - celluloid 93 | - gnome-characters 94 | - gnome-connections 95 | - gnome-shell-extensions-gpaste 96 | - gpaste* 97 | - gthumb 98 | - mpv 99 | - transmission-gtk 100 | kde: 101 | - transmission-qt 102 | -------------------------------------------------------------------------------- /group_vars/Darwin/pkg_mgr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | pkg_mgr_cli: 4 | formulas: 5 | - argc 6 | - asciinema 7 | - atuin 8 | - atool 9 | - bash 10 | - bash-completion@2 11 | - bat 12 | - bat-extras 13 | - bcal 14 | - cabextract 15 | - coreutils 16 | - diceware 17 | - dict 18 | - dua-cli 19 | - duf 20 | - dust 21 | - eye-d3 22 | - eza 23 | - fastfetch 24 | - fclones 25 | - fd 26 | - ffmpeg 27 | - findutils 28 | - fzf 29 | - fx 30 | - gawk 31 | - gh 32 | - ghostscript 33 | - git 34 | - git-absorb 35 | - glow 36 | - gnu-sed 37 | - gnu-tar 38 | - gnu-which 39 | - grep 40 | - gzip 41 | - httpie 42 | - iftop 43 | - jq 44 | - jo 45 | - kpcli 46 | - lame 47 | - less 48 | - markdown 49 | - moreutils 50 | - mtr 51 | - nmap 52 | - ocrmypdf 53 | - p7zip 54 | - par 55 | - pdfgrep 56 | - pwgen 57 | - qpdf 58 | - qsv 59 | - rdfind 60 | - rename 61 | - ripgrep 62 | - rpm2cpio 63 | - rsync 64 | - shellcheck 65 | - shellharden 66 | - shfmt 67 | - tidy-html5 68 | - tree 69 | - trippy 70 | - trurl 71 | - watch 72 | - wget 73 | - yamllint 74 | - yt-dlp 75 | 76 | pkg_mgr_gui: 77 | casks: 78 | - expressions 79 | - fantastical 80 | - firefox 81 | - ghostty 82 | - iina 83 | - jordanbaird-ice 84 | - keepassxc 85 | - keepingyouawake 86 | - libreoffice 87 | - maccy 88 | - multipass 89 | - mullvad-vpn 90 | - musicbrainz-picard 91 | - netnewswire 92 | - notesnook 93 | - numi 94 | - pearcleaner 95 | - plexamp 96 | - ppsspp 97 | - signal 98 | - sony-ps-remote-play 99 | - spotify 100 | - transmission 101 | - transmit 102 | - utm 103 | - vlc 104 | - zoom 105 | mas: 106 | - 1320666476 # Wipr Safari extension 107 | - 1555925018 # Genki Arcade 108 | - 1569813296 # 1Password Safari extension 109 | - 1591303229 # Vinegar Safari extension 110 | - 1622835804 # Kagi Safari extension 111 | -------------------------------------------------------------------------------- /group_vars/all/system.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | system_linux_dconf: 4 | - path: "/org/gnome" 5 | keys: 6 | calendar/follow-night-light: "false" 7 | clock-show-weekday: "true" 8 | shell/disable-user-extensions: "false" 9 | system/location/enabled: "true" 10 | night-light-enabled: "true" 11 | night-light-schedule-automatic: "true" 12 | - path: "/org/gnome/nautilus" 13 | keys: 14 | list-view/default-zoom-level: "'small'" 15 | list-view/use-tree-view: "true" 16 | preferences/default-folder-viewer: "'list-view'" 17 | preferences/search-filter-time-type: "'last_modified'" 18 | preferences/show-create-link: "true" 19 | preferences/show-delete-permanently: "true" 20 | window-state/maximized: "true" 21 | - path: "/org/gnome/desktop" 22 | keys: 23 | datetime/automatic-timezone: "true" 24 | input-sources/xkb-options: "['ctrl:nocaps']" 25 | interface/accent-color: "'teal'" 26 | interface/clock-format: "'12h'" 27 | interface/clock-show-date: "true" 28 | interface/clock-show-seconds: "false" 29 | interface/clock-show-weekday: "true" 30 | interface/enable-animations: "false" 31 | interface/show-battery-percentage: "true" 32 | media-handling/autorun-never: "true" 33 | media-handling/autorun-x-content-ignore: "[\ 34 | 'x-content/audio-cdda', 35 | 'x-content/video-dvd', 36 | 'x-content/audio-player', 37 | 'x-content/image-dcf', 38 | 'x-content/unix-software']" 39 | peripherals/mouse/natural-scroll: "false" 40 | peripherals/touchpad/tap-to-click: "true" 41 | peripherals/touchpad/two-finger-scrolling-enabled: "true" 42 | privacy/remove-old-temp-files: "true" 43 | privacy/remove-old-trash-files: "true" 44 | - path: "/org/gnome/Ptyxis" 45 | keys: 46 | audible-bell: "false" 47 | default-profile-uuid: "'d67886b4db0b2d949cf15b6e683a0a9a'" 48 | interface-style: "'light'" 49 | profile-uuids: "['d67886b4db0b2d949cf15b6e683a0a9a']" 50 | use-system-font: "true" 51 | Profiles/d67886b4db0b2d949cf15b6e683a0a9a/label: "'Brads-Profile'" 52 | Profiles/d67886b4db0b2d949cf15b6e683a0a9a/palette: "'solarized'" 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!CAUTION] 2 | > This repository is archived, pending deletion. Please see https://codeberg.org/bradfrank/dotfiles for further updates. 3 | 4 | # Brad's Bootstrapping & dotfiles Manager 5 | 6 | ## Overview 7 | 8 | Ansible playbooks and roles for bootstrapping macOS and Linux workstations, and managing dotfiles. The playbooks are designed with _no assumed prior knowledge of the system_, and are meant to be run on a newly installed system. 9 | 10 | Because these playbooks are meant to be run locally instead of over SSH, the inventory is dynamic, such that the current host is assigned to groups based on Linux distro, or simply `Darwin` for macOS. 11 | 12 | ## Running the Playbooks 13 | 14 | 1. On macOS, authenticate to the App Store (required if using `mas`) 15 | 2. Clone the repository locally 16 | 3. `cd` into the git repo and run `sh install` 17 | 18 | > [!TIP] 19 | > Run `sh install -h` to show available script flags 20 | 21 | ### Setup Workflow 22 | 23 | 1. **Bootstrap the OS:** the `install` script installs necessary packages to setup and run Ansible; this includes e.g. Homebrew, Python, and Git. _This script requires `sudo` access on Linux only._ 24 | 25 | 2. **Bootstrap Ansible**: this playbook installs the necessary Ansible collections, and creates a host YAML file that is pre-filled with global variables (used as default values in roles). 26 | 27 | 3. **Initialize 1Password**: the user is prompted for 1Password credentials, Ansible authenticates with the option of using the GUI or just the CLI version. A new entry is created for the host machine under the category `SERVER`. 28 | 29 | 4. **System bootstrap**: runs the `play_all_roles` playbook which includes all roles and tasks, specifically `all,never` to target tasks where idompotence isn't desireable (e.g. completely resetting a dock). 30 | 31 | > [!NOTE] 32 | > Upon completion, a full reboot is recommended for a clean shell. 33 | 34 | ## Managing Dotfiles 35 | 36 | Run the playbook `play_dots`. Tasks that fall under dotfile management are tagged with `dots`. Add the tag `moredots` to include additional tasks that are complimentary to dotfile management. 37 | 38 | > [!TIP] 39 | > A Makefile is provided to use frequently used playbook settings; e.g. `make dots` 40 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/starship.toml: -------------------------------------------------------------------------------- 1 | '$schema' = 'https://starship.rs/config-schema.json' 2 | 3 | format = """ 4 | [\\[](bold fg:base01)\ 5 | $hostname\ 6 | $python\ 7 | $directory\ 8 | $git_branch\ 9 | $git_status\ 10 | [\\]](bold fg:base01)\n \ 11 | 󱞪 $status\ 12 | $character\ 13 | """ 14 | 15 | add_newline = true 16 | palette = 'solarized_light' 17 | 18 | [palettes.solarized_light] 19 | base01 = '#586e75' 20 | base2 = '#eee8d5' 21 | blue = '#268bd2' 22 | cyan = '#2aa198' 23 | magenta = '#d33682' 24 | orange = '#cb4b16' 25 | red = '#dc322f' 26 | violet = '#6c71c4' 27 | yellow = '#b58900' 28 | 29 | [character] 30 | success_symbol = '[%](fg:green)' 31 | error_symbol = '[%](fg:red)' 32 | 33 | [directory] 34 | format = '[](fg:base2)[$path]($style)[](fg:base2)' 35 | repo_root_format = """ 36 | [](fg:base2)\ 37 | [$before_root_path]($before_repo_root_style)\ 38 | [$repo_root]($repo_root_style)\ 39 | [$path](bg:base2 fg:base01)\ 40 | [](fg:base2) \ 41 | """ 42 | before_repo_root_style = 'bg:base2 fg:blue' 43 | repo_root_style = 'bg:base2 fg:blue' 44 | style = 'bg:base2 fg:blue' 45 | truncation_length = 0 46 | truncation_symbol = '' 47 | 48 | [directory.substitutions] 49 | '~/Development' = '~/Dev' 50 | 51 | [git_branch] 52 | format = '[](fg:base2)[$branch]($style)[](fg:base2)' 53 | style = 'bg:base2 fg:green' 54 | 55 | [git_status] 56 | disabled = false 57 | style = 'bg:base2 fg:yellow' 58 | format = """ 59 | ( [](fg:base2)\ 60 | [$conflicted$deleted$modified$renamed$staged$stashed$untracked]($style)\ 61 | [](fg:base2))\ 62 | """ 63 | conflicted = 'C' 64 | deleted = 'D' 65 | modified = 'M' 66 | renamed = 'R' 67 | staged = 'S' 68 | stashed = '\$' 69 | untracked = 'U' 70 | 71 | [hostname] 72 | disabled = false 73 | format = '[](fg:base2)[$hostname]($style)[](fg:base2) ' 74 | style = 'bg:base2 fg:magenta' 75 | ssh_only = true 76 | 77 | [python] 78 | style = 'bg:base2 fg:cyan' 79 | format = '[](fg:base2)[$version]($style)[](fg:base2) ' 80 | disabled = false 81 | detect_files = [] 82 | detect_extensions = [] 83 | version_format = '${major}.${minor}' 84 | 85 | [status] 86 | disabled = false 87 | format = '[\[$status\]]($style)' 88 | success_symbol = '+' # required to show return code "0" 89 | success_style = 'fg:green' 90 | failure_style = 'fg:red' 91 | -------------------------------------------------------------------------------- /group_vars/Ubuntu.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | _bat_exec: "/usr/bin/batcat" 4 | 5 | tmux_clipboard: "wl-copy" 6 | 7 | pkg_mgr_repos: 8 | base: 9 | - name: "charm" 10 | uris: ["https://repo.charm.sh/apt"] 11 | components: ["*"] 12 | suites: ["*"] 13 | enabled: true 14 | signed_by: "https://apt.fury.io/charmcli/gpg.key" 15 | - name: "githubcli" 16 | uris: ["https://cli.github.com/packages"] 17 | components: ["main"] 18 | suites: ["stable"] 19 | enabled: true 20 | signed_by: "https://cli.github.com/packages/githubcli-archive-keyring.gpg" 21 | 22 | pkg_mgr_cli: 23 | base: 24 | - apt-file 25 | - asciinema 26 | - atool 27 | - atuin 28 | - bash-completion 29 | - bat 30 | - bcal 31 | - diceware 32 | - dictd 33 | - duf 34 | - eza 35 | - fastfetch 36 | - fd-find 37 | - ffmpeg 38 | - figlet 39 | - freeze 40 | - fwupd 41 | - fzf 42 | - gh # comes from 'githubcli' repo 43 | - ghostscript 44 | - glow # available from LTS Ubuntu repos as of 26.04 45 | - htop 46 | - httpie 47 | - iftop 48 | - inxi 49 | - jq 50 | - keychain 51 | - libmp4-info-perl 52 | - libvirt-clients 53 | - mkvtoolnix 54 | - msmtp 55 | - mtr 56 | - nmap 57 | - p7zip-* 58 | - par 59 | - perf-tools-unstable 60 | - pdfgrep 61 | - pwgen 62 | - python3 63 | - python3-dev 64 | - python3-pip 65 | - ripgrep 66 | - shellcheck 67 | - strace 68 | - tidy 69 | - tlp 70 | - trurl 71 | - toilet 72 | - tree 73 | - virtualenv 74 | - wget 75 | - xz-utils 76 | - yt-dlp 77 | formulas: 78 | - argc 79 | - bat-extras 80 | - dua-cli 81 | - fclones 82 | - qsv 83 | - yq 84 | 85 | pkg_mgr_gui: 86 | common: 87 | - 1password 88 | - keepassxc 89 | - libreoffice 90 | - picard 91 | - vlc 92 | gnome: 93 | - celluloid 94 | - gnome-characters 95 | - gnome-connections 96 | - gnome-shell-extensions-gpaste 97 | - gpaste* 98 | - gthumb 99 | - mpv 100 | - transmission-gtk 101 | kde: 102 | - transmission-qt 103 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/00-PATHs.zsh.j2: -------------------------------------------------------------------------------- 1 | PATH="${HOME}/.local/bin:/opt/bin" 2 | PATH="${PATH}:${HOME}/.local/share/krew/bin" 3 | PATH="${PATH}:{{ global_homebrew_prefix }}/bin:{{ global_homebrew_prefix }}/sbin" 4 | {% if ansible_facts['distribution'] == "MacOSX" %} 5 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/coreutils/libexec/gnubin" 6 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/gnu-tar/libexec/gnubin" 7 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/grep/libexec/gnubin" 8 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/gnu-sed/libexec/gnubin" 9 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/gsed/libexec/gnubin" 10 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/gawk/libexec/gnubin" 11 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/findutils/libexec/gnubin" 12 | PATH="${PATH}:{{ global_homebrew_prefix }}/opt/gnu-which/libexec/gnubin" 13 | {% endif %} 14 | {% if ansible_facts['distribution'] == "Ubuntu" %} 15 | PATH="${PATH}:/snap/bin" 16 | {% endif %} 17 | PATH="${PATH}:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin" 18 | 19 | MANPATH="${HOME}/.local/share/man" 20 | {% if ansible_facts['distribution'] == "MacOSX" %} 21 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/coreutils/libexec/gnuman" 22 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/gnu-tar/libexec/gnuman" 23 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/grep/libexec/gnuman" 24 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/gnu-sed/libexec/gnuman" 25 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/gsed/libexec/gnuman" 26 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/gawk/libexec/gnuman" 27 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/findutils/libexec/gnuman" 28 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/opt/gnu-which/libexec/gnuman" 29 | MANPATH="${MANPATH}:{{ global_homebrew_prefix }}/share/man" 30 | {% endif %} 31 | MANPATH="${MANPATH}:/usr/local/share/man:/usr/share/man" 32 | 33 | INFOPATH={{ global_homebrew_prefix }}/share/info:"${INFOPATH:-}" 34 | {% if ansible_facts['distribution'] == "Fedora" %} 35 | HELPDIR=/usr/share/zsh/{{ zsh_current_version }}/help 36 | {% elif ansible_facts['distribution'] == "MacOSX" %} 37 | HELPDIR={{ global_homebrew_prefix }}/Cellar/zsh/{{ zsh_current_version }}/share/zsh/help 38 | {% endif %} 39 | 40 | export PATH 41 | export MANPATH 42 | export INFOPATH 43 | export HELPDIR 44 | -------------------------------------------------------------------------------- /roles/git/tasks/clone_repos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Check SSH agent socket" 4 | ansible.builtin.stat: 5 | path: "{{ git_ssh_auth_sock }}" 6 | register: stat_ssh_auth_sock 7 | 8 | - name: "Manual ssh-agent setup" 9 | when: not stat_ssh_auth_sock['stat']['exists'] 10 | notify: "Stop ssh-agent" 11 | block: 12 | - name: "Start ssh-agent" 13 | ansible.builtin.shell: 14 | cmd: | 15 | eval $(ssh-agent -s) > /dev/null 16 | echo "{\"SSH_AUTH_SOCK\":\"$SSH_AUTH_SOCK\",\"SSH_AGENT_PID\":\"$SSH_AGENT_PID\"}" 17 | register: cmd_eval 18 | changed_when: true 19 | - name: "Add key to ssh-agent" 20 | environment: "{{ cmd_eval['stdout'] }}" 21 | ansible.builtin.expect: 22 | command: "ssh-add {{ git_ssh_key_private }}" 23 | responses: 24 | passphrase: "{{ ssh_keys['id_ed25519']['passphrase'] | default('') }}" 25 | - name: "Set ssh-agent socket" 26 | ansible.builtin.set_fact: 27 | git_ssh_auth_sock: "{{ cmd_eval['stdout'] | from_json | json_query('SSH_AUTH_SOCK') }}" 28 | git_ssh_auth_pid: "{{ cmd_eval['stdout'] | from_json | json_query('SSH_AGENT_PID') }}" 29 | 30 | - name: "Build repository metadata" 31 | vars: 32 | git_repo_name: "{{ item['url'] | basename | split('.') | first }}" 33 | ansible.builtin.set_fact: 34 | git_repos_metadata: "{{ git_repos_metadata | default([]) + [ { 35 | 'name': git_repo_name, 36 | 'dirname': git_repos_path ~ git_repo_name), 37 | 'branch': item['branch'] | default('main'), 38 | 'url': item['url'] 39 | } ] }}" 40 | loop: "{{ git_repos }}" 41 | loop_control: 42 | label: "{{ git_repo_name }}" 43 | 44 | - name: "Create repository directories" 45 | ansible.builtin.file: 46 | path: "{{ item['dirname'] }}" 47 | state: directory 48 | mode: "0755" 49 | loop: "{{ git_repos_metadata }}" 50 | loop_control: 51 | label: "{{ item['name'] }}" 52 | 53 | - name: "Clone repositories" 54 | ansible.builtin.git: 55 | repo: "{{ item['url'] }}" 56 | version: "{{ item['branch'] }}" 57 | dest: "{{ item['dirname'] }}/{{ item['branch'] }}" 58 | key_file: "{{ git_ssh_key_private }}" 59 | ssh_opts: "-o 'IdentityAgent={{ git_ssh_auth_sock }}'" 60 | update: false 61 | accept_hostkey: true 62 | loop: "{{ git_repos_metadata }}" 63 | loop_control: 64 | label: "{{ item['name'] }}" 65 | -------------------------------------------------------------------------------- /roles/zsh/templates/zshrc/10-exports.zsh.j2: -------------------------------------------------------------------------------- 1 | # shell-related variables 2 | export EDITOR=nvim 3 | export VISUAL=nvim 4 | export DIRSTACKSIZE=10 # Max directories in auto_pushd stack 5 | 6 | # application configs 7 | export DOCKER_CLI_HINTS=false 8 | export GH_PAGER=glow 9 | # https://github.com/charmbracelet/glow/issues/713 10 | export GLOW_STYLE="${HOME}/.config/glow/themes/solarized-light.json" 11 | export LESS="-R --mouse" 12 | 13 | # ssh settings 14 | {% if (ansible_facts['system'] == "Darwin") and global_use_1password_ssh_agent %} 15 | export SSH_AUTH_SOCK="${HOME}/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" 16 | {% elif (ansible_facts['system'] == "Linux") and global_use_1password_ssh_agent %} 17 | export SSH_AUTH_SOCK="${HOME}/.1password/agent.sock" 18 | {% endif %} 19 | 20 | # Homebrew settings 21 | export HOMEBREW_CELLAR={{ global_homebrew_prefix }}/Cellar 22 | export HOMEBREW_NO_AUTO_UPDATE=1 23 | export HOMEBREW_NO_EMOJI=1 24 | export HOMEBREW_NO_ENV_HINTS=1 25 | export HOMEBREW_NO_INSTALL_CLEANUP=1 26 | export HOMEBREW_NO_INSTALL_UPGRADE=1 27 | export HOMEBREW_PREFIX={{ global_homebrew_prefix }} 28 | export HOMEBREW_REPOSITORY={{ global_homebrew_prefix }}/Homebrew 29 | 30 | # application XDG configs 31 | export ANSIBLE_HOME="${HOME}/.config/ansible" 32 | export BUNDLE_USER_CACHE="${HOME}/.cache/bundle" 33 | export BUNDLE_USER_CONFIG="${HOME}/.config/bundle" 34 | export BUNDLE_USER_PLUGIN="${HOME}/.local/share/bundle" 35 | export CARGO_HOME="${HOME}/.local/share/cargo" 36 | export DOCKER_CONFIG="${HOME}/.config/docker" 37 | export EZA_CONFIG_DIR="${HOME}/.config/eza" 38 | export GLOW_CONFIG_HOME="${HOME}/.config/glow" 39 | export GOPATH="${HOME}/.local/share/go" 40 | export HISTFILE="${HOME}/.cache/zsh/history" 41 | export KREW_ROOT="${HOME}/.local/share/krew" 42 | export MINIKUBE_HOME="${HOME}/.local/share/minikube" 43 | export NPM_CONFIG_PREFIX="${HOME}/.local" 44 | export NPM_CONFIG_CACHE="${HOME}/.cache/npm" 45 | export NPM_CONFIG_INIT_MODULE="${HOME}/.config/npm/config/npm-init.js" 46 | export NPM_CONFIG_TMP="${HOME}/.local/run/npm" 47 | export NPM_CONFIG_USERCONFIG="${HOME}/.config/npm/npmrc" 48 | export NVM_DIR="${HOME}/.local/share/nvm" 49 | export PYTHON_HISTORY="${HOME}/.config/python/history" 50 | export TERMINFO="${HOME}/.local/share/terminfo" 51 | export TERMINFO_DIRS="${HOME}/.local/share/terminfo:/usr/share/terminfo" 52 | export SQLITE_HISTORY="${HOME}/.cache/sqlite_history" 53 | export W3M_DIR="${HOME}/.local/share/w3m" 54 | -------------------------------------------------------------------------------- /roles/ssh/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Install ssh packages" 9 | ansible.builtin.package: 10 | name: "{{ ssh_packages }}" 11 | become: "{{ true if ansible_facts['system'] == 'Linux' else false }}" 12 | tags: [install] 13 | 14 | - name: "Ensure required directories are present" 15 | ansible.builtin.file: 16 | mode: "0755" 17 | path: "{{ item }}" 18 | state: directory 19 | loop: "{{ ssh_required_dirs }}" 20 | tags: [dots] 21 | 22 | - name: "Set proper permissions on ~/.ssh/authorized_keys" 23 | ansible.builtin.file: 24 | mode: "0600" 25 | path: "{{ ansible_facts['user_dir'] }}/.ssh/authorized_keys" 26 | state: touch 27 | tags: [dots] 28 | 29 | - name: "Create SSH keys" 30 | community.crypto.openssh_keypair: 31 | comment: "{{ ansible_facts['user_id'] }}@{{ ansible_facts['hostname'] }}" 32 | passphrase: "{{ item['value']['passphrase'] }}" 33 | path: "{{ ansible_facts['user_dir'] }}/.ssh/{{ item['key'] }}" 34 | size: 4096 35 | type: "{{ item['value']['type'] }}" 36 | loop: "{{ ssh_keys | dict2items }}" 37 | loop_control: 38 | label: "{{ item['key'] }}" 39 | tags: [ssh_keys] 40 | 41 | - name: "Template SSH config" 42 | ansible.builtin.template: 43 | src: "ssh_config.j2" 44 | dest: "{{ ansible_facts['user_dir'] }}/.ssh/config" 45 | mode: "0644" 46 | when: ssh_manage_config 47 | tags: [dots] 48 | 49 | - name: "Copy SSH agent script" 50 | ansible.builtin.copy: 51 | src: "op-ssh.bash" 52 | dest: "{{ ansible_facts['user_dir'] }}/.local/bin/op-ssh" 53 | mode: "0755" 54 | tags: [dots] 55 | 56 | - name: "Create host keys" 57 | community.crypto.openssh_keypair: 58 | path: "/etc/ssh/ssh_host_{{ item }}_key" 59 | type: "{{ item }}" 60 | loop: "{{ ssh_host_keys }}" 61 | loop_control: 62 | label: "{{ item }}" 63 | become: true 64 | when: (ansible_facts['system'] == "Linux") and (ssh_manage_host_keys) 65 | tags: [never] 66 | 67 | - name: "Set SSH hardening vars for Linux Mint" 68 | ansible.builtin.set_fact: 69 | os_vars: "{{ ssh_hardening['Debian'] }}" 70 | when: (ansible_facts['distribution'] in ["Linux_Mint", "LMDE"]) 71 | tags: [never, hardening] 72 | 73 | - name: "Include SSH hardening role" 74 | ansible.builtin.include_role: 75 | name: devsec.hardening.ssh_hardening 76 | tags: [never, hardening] 77 | when: (ansible_facts['system'] == "Linux") and (ssh_harden_security) 78 | -------------------------------------------------------------------------------- /roles/vim/files/nvim/lazy-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "LuaSnip": { "branch": "master", "commit": "c9b9a22904c97d0eb69ccb9bab76037838326817" }, 3 | "NvChad": { "branch": "v2.5", "commit": "46b15ef1b9d10a83ab7df26b14f474d15c01e770" }, 4 | "base46": { "branch": "v3.0", "commit": "c17bd9b562c111253139a0abe2c74dc15df0ab92" }, 5 | "cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" }, 6 | "cmp-nvim-lsp": { "branch": "main", "commit": "a8912b88ce488f411177fc8aed358b04dc246d7b" }, 7 | "cmp-nvim-lua": { "branch": "main", "commit": "f12408bdb54c39c23e67cab726264c10db33ada8" }, 8 | "cmp-path": { "branch": "main", "commit": "c6635aae33a50d6010bf1aa756ac2398a2d54c32" }, 9 | "cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" }, 10 | "conform.nvim": { "branch": "master", "commit": "eebc724d12c5579d733d1f801386e0ceb909d001" }, 11 | "friendly-snippets": { "branch": "main", "commit": "efff286dd74c22f731cdec26a70b46e5b203c619" }, 12 | "gitsigns.nvim": { "branch": "main", "commit": "17ab794b6fce6fce768430ebc925347e349e1d60" }, 13 | "indent-blankline.nvim": { "branch": "master", "commit": "005b56001b2cb30bfa61b7986bc50657816ba4ba" }, 14 | "lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" }, 15 | "mason.nvim": { "branch": "main", "commit": "fc98833b6da5de5a9c5b1446ac541577059555be" }, 16 | "menu": { "branch": "main", "commit": "ce1d8b5fc980edc388cd0da0884cacea25dcc6c5" }, 17 | "minty": { "branch": "main", "commit": "aafc9e8e0afe6bf57580858a2849578d8d8db9e0" }, 18 | "nvim-autopairs": { "branch": "master", "commit": "2a406cdd8c373ae7fe378a9e062a5424472bd8d8" }, 19 | "nvim-cmp": { "branch": "main", "commit": "059e89495b3ec09395262f16b1ad441a38081d04" }, 20 | "nvim-lspconfig": { "branch": "master", "commit": "4ea9083b6d3dff4ddc6da17c51334c3255b7eba5" }, 21 | "nvim-tree.lua": { "branch": "master", "commit": "5bea2b37523a31288e0fcab42f3be5c1bd4516bb" }, 22 | "nvim-treesitter": { "branch": "master", "commit": "0e21ee8df6235511c02bab4a5b391d18e165a58d" }, 23 | "nvim-web-devicons": { "branch": "master", "commit": "c90dee4e930ab9f49fa6d77f289bff335b49e972" }, 24 | "plenary.nvim": { "branch": "master", "commit": "857c5ac632080dba10aae49dba902ce3abf91b35" }, 25 | "telescope.nvim": { "branch": "master", "commit": "a4ed82509cecc56df1c7138920a1aeaf246c0ac5" }, 26 | "ui": { "branch": "v3.0", "commit": "2fe0652081a5fe358db041633fca3efd39d215c7" }, 27 | "volt": { "branch": "main", "commit": "c45d5f48da8e802e608b5c6da471ca4d84276dfb" }, 28 | "which-key.nvim": { "branch": "main", "commit": "370ec46f710e058c9c1646273e6b225acf47cbed" } 29 | } 30 | -------------------------------------------------------------------------------- /roles/cloud/files/k9s/skins/solarized-light.yml: -------------------------------------------------------------------------------- 1 | # Styles... 2 | foreground: &foreground "#657b83" 3 | background: &background "#fdf6e3" 4 | current_line: ¤t_line "#eee8d5" 5 | selection: &selection "#eee8d5" 6 | comment: &comment "#93a1a1" 7 | cyan: &cyan "#2aa198" 8 | green: &green "#859900" 9 | yellow: &yellow "#b58900" 10 | orange: &orange "#cb4b16" 11 | magenta: &magenta "#d33682" 12 | blue: &blue "#268bd2" 13 | red: &red "#dc322f" 14 | 15 | # Skin... 16 | k9s: 17 | body: 18 | fgColor: *foreground 19 | bgColor: *background 20 | logoColor: *blue 21 | prompt: 22 | fgColor: *foreground 23 | bgColor: *background 24 | suggestColor: *orange 25 | info: 26 | fgColor: *magenta 27 | sectionColor: *foreground 28 | dialog: 29 | fgColor: *foreground 30 | bgColor: *background 31 | buttonFgColor: *foreground 32 | buttonBgColor: *magenta 33 | buttonFocusFgColor: white 34 | buttonFocusBgColor: *cyan 35 | labelFgColor: *orange 36 | fieldFgColor: *foreground 37 | frame: 38 | border: 39 | fgColor: *selection 40 | focusColor: *foreground 41 | menu: 42 | fgColor: *foreground 43 | keyColor: *magenta 44 | numKeyColor: *magenta 45 | crumbs: 46 | fgColor: white 47 | bgColor: *cyan 48 | activeColor: *yellow 49 | status: 50 | newColor: *cyan 51 | modifyColor: *blue 52 | addColor: *green 53 | errorColor: *red 54 | highlightColor: *orange 55 | killColor: *comment 56 | completedColor: *comment 57 | title: 58 | fgColor: *foreground 59 | bgColor: *background 60 | highlightColor: *blue 61 | counterColor: *magenta 62 | filterColor: *magenta 63 | views: 64 | charts: 65 | bgColor: default 66 | defaultDialColors: 67 | - *blue 68 | - *red 69 | defaultChartColors: 70 | - *blue 71 | - *red 72 | table: 73 | fgColor: *foreground 74 | bgColor: *background 75 | cursorFgColor: white 76 | cursorBgColor: *background 77 | markColor: darkgoldenrod 78 | header: 79 | fgColor: *foreground 80 | bgColor: *background 81 | sorterColor: *cyan 82 | xray: 83 | fgColor: *foreground 84 | bgColor: *background 85 | cursorColor: *current_line 86 | graphicColor: *blue 87 | showIcons: false 88 | yaml: 89 | keyColor: *magenta 90 | colonColor: *blue 91 | valueColor: *foreground 92 | logs: 93 | fgColor: *foreground 94 | bgColor: *background 95 | indicator: 96 | fgColor: *foreground 97 | bgColor: *selection 98 | toggleOnColor: *magenta 99 | toggleOffColor: *blue 100 | -------------------------------------------------------------------------------- /roles/zsh/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Skip role if not in host_vars" 4 | ansible.builtin.meta: end_role 5 | when: role_name not in global_host_roles 6 | tags: [always] 7 | 8 | - name: "Install zsh packages" 9 | ansible.builtin.package: 10 | name: "{{ zsh_packages }}" 11 | become: "{{ true if ansible_facts['system'] == 'Linux' else false }}" 12 | tags: [install] 13 | 14 | - name: "Get current Zsh version" 15 | ansible.builtin.command: 16 | cmd: "{{ zsh_bin }} --version" 17 | register: cmd_zsh_version 18 | changed_when: false 19 | tags: [dots, zshrc] 20 | 21 | - name: "Set current Zsh version" 22 | ansible.builtin.set_fact: 23 | zsh_current_version: "{{ (cmd_zsh_version['stdout'] | split)[1] }}" 24 | tags: [dots, zshrc] 25 | 26 | - name: "Ensure supplemental Zsh directories exist" 27 | ansible.builtin.file: 28 | path: "{{ item }}" 29 | state: "directory" 30 | mode: "0744" 31 | loop: "{{ zsh_supplemental_dirs }}" 32 | tags: [moredots] 33 | 34 | - name: "Check if Zsh is an available shell" 35 | ansible.builtin.find: 36 | contains: "{{ zsh_bin }}" 37 | read_whole_file: true 38 | path: "/etc" 39 | patterns: "^shells$" 40 | use_regex: true 41 | register: find_zsh_etc_shells 42 | 43 | - name: "Add Homebrew Zsh to available shells" 44 | ansible.builtin.lineinfile: 45 | path: "/etc/shells" 46 | line: "{{ zsh_bin }}" 47 | become: true 48 | when: find_zsh_etc_shells['matched'] == 0 49 | 50 | - name: "Fix Homebrew Zsh folder permissions" 51 | ansible.builtin.file: 52 | path: "{{ item }}" 53 | mode: "0755" 54 | loop: "{{ zsh_chmod_directories }}" 55 | when: ansible_facts['system'] == "Darwin" 56 | 57 | - name: "Set Zsh as default shell" 58 | ansible.builtin.user: 59 | name: "{{ ansible_facts['user_id'] }}" 60 | shell: "{{ zsh_bin }}" 61 | become: true 62 | when: ansible_facts['user_shell'] != zsh_bin 63 | 64 | - name: "Install Zsh plugins" 65 | ansible.builtin.git: 66 | repo: "{{ item['repo'] }}" 67 | dest: "{{ zsh_plugins_dir }}/{{ item['name'] }}" 68 | depth: 1 69 | version: "{{ item['version'] | default(omit) }}" 70 | loop: "{{ zsh_plugins }}" 71 | loop_control: 72 | label: "{{ item['name'] }}" 73 | tags: [moredots] 74 | 75 | - name: "Build zshrc" 76 | ansible.builtin.import_tasks: 77 | file: "zshrc.yml" 78 | tags: [dots, zshrc] 79 | 80 | - name: "Refresh Zsh completions" 81 | ansible.builtin.import_tasks: 82 | file: "completions.yml" 83 | tags: [dots, completions] 84 | 85 | - name: "Setup Atuin sync" 86 | ansible.builtin.expect: 87 | command: "atuin login -u {{ dotfiles_atuin['username'] }}" 88 | responses: 89 | Please enter password: "{{ dotfiles_atuin['password'] }}" 90 | Please enter encryption key: "{{ dotfiles_atuin['key'] }}" 91 | tags: [never, atuin] 92 | -------------------------------------------------------------------------------- /roles/zsh/files/rc.d/gcsh.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # 4 | # Functions for making gcloud easier to use. 5 | # Author: Brad Frank 6 | # Date: Feb 2022 7 | # Tested: zsh 5.8 (x86_64-apple-darwin19.6.0) 8 | # Requires: gcloud, fzf 9 | # 10 | 11 | _fzf_g() { fzf --select-1 --exit-0 --ansi -i --height=50% --reverse --inline-info --border rounded "$@"; } 12 | 13 | _gc_project() { 14 | gcloud projects list --format="value(name,projectId)" | grep "${1:-}" \ 15 | | _fzf_g --no-multi --delimiter '\t' --with-nth 1 | awk '{print $2}' 16 | } 17 | 18 | _save_and_exec() { 19 | local cmd; cmd="$(tr -s ' ' <<< "$1")" 20 | fc -R =(echo "$cmd") 21 | eval "$cmd" 22 | } 23 | 24 | alias gpu='gcloud config unset project' 25 | 26 | 27 | # [gpl] list gcloud projects; usage: gpl [-c|--columns ] [-f|--filter ] 28 | gpl() { 29 | local columns filter default_columns default_filter 30 | default_columns="name,projectId,projectNumber" 31 | default_filter="projectId !~ \"^(sys|quickstart|test|gam)-.*\"" 32 | zparseopts -E -D -- c:=columns -columns:=columns f:=filter -filter:=filter 33 | gcloud projects list \ 34 | --sort-by="name" \ 35 | --format="value(${columns:-${default_columns}})" \ 36 | --filter="${filter:-${default_filter}}" \ 37 | | column -ts $'\t' 38 | } 39 | 40 | 41 | # [gkube] generate kubectl credentials 42 | gkube() { 43 | local project cluster 44 | mv "$HOME"/.kube/config "$HOME"/.kube/config."$(date --iso-8601=seconds | tr -d ':-')" 45 | 46 | while read -r project; do 47 | while read -r cluster; do 48 | [[ -z "$cluster" ]] && continue 49 | _save_and_exec "gcloud container clusters get-credentials \ 50 | $(awk '{print $2}' <<< "$cluster") \ 51 | --region=$(awk '{print $1}' <<< "$cluster") \ 52 | --project $project" 53 | done < <(gcloud container clusters list \ 54 | --project "$project" \ 55 | --format="value[separator=' '](zone,name)" \ 56 | | _fzf_g --multi --delimiter ' ' --with-nth 2) 57 | done < <(gpl --columns="projectId" | _fzf_g --multi) 58 | } 59 | 60 | 61 | # [gssh] allows you to ssh into a GCS instance; usage: gssh [-p|--project] 62 | gssh() { 63 | local project _project 64 | zparseopts -E -D -- p:=project -project:=project 65 | _project="$(_gc_project "${project[2]}")" 66 | ssh "$(gcloud --project "$_project" compute instances list \ 67 | --format="value[separator=' '](name,networkInterfaces[0].networkIP)" \ 68 | | _fzf_g --no-multi --delimiter " " --with-nth 1 \ 69 | | awk '{print $2}' 70 | )" 71 | } 72 | 73 | 74 | # [ghelp] show this help message 75 | ghelp() { 76 | echo "helper aliases and functions for gcloud SDK" 77 | echo 78 | grep -E '^# \[.+\]' "${(%):-%x}" 79 | } 80 | -------------------------------------------------------------------------------- /roles/cloud/files/k9s/skins/rosepine-dawn.yml: -------------------------------------------------------------------------------- 1 | k9s: 2 | body: 3 | fgColor: '#575279' 4 | bgColor: '#faf4ed' 5 | logoColor: '#907aa9' 6 | prompt: 7 | fgColor: '#575279' 8 | bgColor: '#fffaf3' 9 | suggestColor: '#56949f' 10 | help: 11 | fgColor: '#575279' 12 | bgColor: '#faf4ed' 13 | sectionColor: '#286983' 14 | keyColor: '#56949f' 15 | numKeyColor: '#d7827e' 16 | frame: 17 | title: 18 | fgColor: '#286983' 19 | bgColor: '#faf4ed' 20 | highlightColor: '#907aa9' 21 | counterColor: '#ea9d34' 22 | filterColor: '#286983' 23 | border: 24 | fgColor: '#907aa9' 25 | focusColor: '#56949f' 26 | menu: 27 | fgColor: '#575279' 28 | keyColor: '#56949f' 29 | numKeyColor: '#d7827e' 30 | crumbs: 31 | fgColor: '#faf4ed' 32 | bgColor: '#907aa9' 33 | activeColor: '#d7827e' 34 | status: 35 | newColor: '#56949f' 36 | modifyColor: '#56949f' 37 | addColor: '#286983' 38 | pendingColor: '#b4637a' 39 | errorColor: '#b4637a' 40 | highlightColor: '#d7827e' 41 | killColor: '#907aa9' 42 | completedColor: '#797593' 43 | info: 44 | fgColor: '#b4637a' 45 | sectionColor: '#575279' 46 | views: 47 | table: 48 | fgColor: '#575279' 49 | bgColor: '#faf4ed' 50 | cursorFgColor: '#fffaf3' 51 | cursorBgColor: '#faf4ed' 52 | markColor: '#907aa9' 53 | header: 54 | fgColor: '#ea9d34' 55 | bgColor: '#faf4ed' 56 | sorterColor: '#d7827e' 57 | xray: 58 | fgColor: '#575279' 59 | bgColor: '#faf4ed' 60 | cursorColor: '#cecacd' 61 | cursorTextColor: '#faf4ed' 62 | graphicColor: '#907aa9' 63 | charts: 64 | bgColor: '#faf4ed' 65 | chartBgColor: '#faf4ed' 66 | dialBgColor: '#faf4ed' 67 | defaultDialColors: 68 | - '#286983' 69 | - '#b4637a' 70 | defaultChartColors: 71 | - '#286983' 72 | - '#b4637a' 73 | resourceColors: 74 | cpu: 75 | - '#907aa9' 76 | - '#56949f' 77 | mem: 78 | - '#ea9d34' 79 | - '#b4637a' 80 | yaml: 81 | keyColor: '#56949f' 82 | valueColor: '#575279' 83 | colonColor: '#797593' 84 | logs: 85 | fgColor: '#575279' 86 | bgColor: '#faf4ed' 87 | indicator: 88 | fgColor: '#56949f' 89 | bgColor: '#faf4ed' 90 | toggleOnColor: '#286983' 91 | toggleOffColor: '#797593' 92 | dialog: 93 | fgColor: '#ea9d34' 94 | bgColor: '#9893a5' 95 | buttonFgColor: '#faf4ed' 96 | buttonBgColor: '#575279' 97 | buttonFocusFgColor: '#faf4ed' 98 | buttonFocusBgColor: '#907aa9' 99 | labelFgColor: '#d7827e' 100 | fieldFgColor: '#575279' 101 | -------------------------------------------------------------------------------- /roles/vim/templates/vimrc.j2: -------------------------------------------------------------------------------- 1 | " keymappings 2 | set ttimeoutlen=10 3 | set pastetoggle= 4 | let g:mapleader = ',' 5 | map :Lexplore 6 | nnoremap b :Buffers 7 | nnoremap d :put =strftime('## %F') 8 | nnoremap f :RG 9 | nnoremap i :IndentGuidesToggle 10 | nnoremap s :set spell! 11 | nnoremap t :let _s="[ ] #TODO"put=_s 12 | nnoremap u :source ~/.config/vim/vimrc 13 | nnoremap w :let _s=@/:%s/\s\+$//e:let @/=_s " rm trailing whitespace 14 | nnoremap :nohlsearch 15 | nnoremap H :bp 16 | nnoremap L :bn 17 | 18 | 19 | " layout/format/style 20 | let g:indent_guides_auto_colors = 0 21 | let g:indent_guides_enable_on_vim_startup = 0 22 | let g:netrw_browse_split = 4 23 | let g:netrw_winsize = 30 24 | let g:vim_markdown_folding_disabled = 1 25 | set colorcolumn=100 26 | set conceallevel=0 27 | set cursorline 28 | set foldmethod=syntax 29 | set hlsearch 30 | set incsearch 31 | set linebreak 32 | set number 33 | set showmatch 34 | 35 | 36 | " tabs as spaces 37 | set autoindent 38 | set expandtab 39 | set shiftwidth=2 40 | set smarttab 41 | set softtabstop=2 42 | set tabstop=2 43 | 44 | 45 | " functionality 46 | set backspace=indent,eol,start 47 | {% if 'MacOSX' in ansible_facts['distribution'] -%} 48 | set clipboard=unnamed 49 | set rtp+={{ global_homebrew_prefix }}/opt/fzf 50 | {% elif 'Ubuntu' in ansible_facts['distribution'] -%} 51 | set rtp+=/usr/share/doc/fzf/examples/ 52 | {% endif -%} 53 | set laststatus=2 54 | set mouse=a 55 | set noerrorbells 56 | set novisualbell 57 | set scrolloff=4 58 | set updatetime=100 59 | if exists('$TMUX') 60 | set ttymouse=xterm2 61 | endif 62 | 63 | 64 | " airline config 65 | let g:airline#extensions#fzf#enabled = 1 66 | let g:airline#extensions#tabline#buffer_nr_show = 1 67 | let g:airline#extensions#tabline#buffers_label = '' 68 | let g:airline#extensions#tabline#enabled = 1 69 | let g:airline#extensions#tabline#fnamemod = ':t' 70 | let g:airline_inactive_collapse=1 71 | let g:airline_section_b = '' 72 | let g:airline_section_y = '' 73 | let g:airline_section_z = '%3p%% %3l/%L:%3v' 74 | let g:airline_skip_empty_sections = 1 75 | let g:airline_solarized_dark_inactive_background = 1 76 | let g:airline_solarized_enable_command_color = 1 77 | let g:airline_solarized_normal_green = 1 78 | let g:airline_stl_path_style = 'short' 79 | let g:airline_theme = 'solarized' 80 | 81 | " cursor settings 82 | " 0 = blinking block 83 | " 1 = blinking block (default) 84 | " 2 = steady block 85 | " 3 = blinking underline 86 | " 4 = steady underline 87 | " 5 = blinking bar (xterm) 88 | " 6 = steady bar (xterm) 89 | let &t_SI = "\e[6 q" " insert mode 90 | let &t_EI = "\e[2 q" " normal mode 91 | 92 | 93 | " colorscheme/syntax 94 | let g:is_bash = 1 95 | let g:is_posix = 1 96 | syntax on 97 | set termguicolors 98 | set background=light 99 | colorscheme solarized8 100 | highlight Normal guibg=NONE 101 | highlight IndentGuidesOdd guifg=NONE guibg=Cornsilk1 102 | highlight IndentGuidesEven guifg=NONE guibg=NONE 103 | 104 | 105 | " macros and functions 106 | function! s:twoTab() 107 | set ts=4 sts=4 noet | retab! | set ts=2 sts=2 et | retab! 108 | endfunction 109 | -------------------------------------------------------------------------------- /roles/vim/files/helix/themes/flexoki_light.toml: -------------------------------------------------------------------------------- 1 | # Based on Flexoki: https://stephango.com/flexoki 2 | 3 | "ui.background" = { bg = "bg" } 4 | "ui.cursor" = { fg = "tx", bg = "tx-3" } 5 | "ui.cursor.primary" = { fg = "bg", bg = "tx" } 6 | "ui.cursor.match" = { modifiers = ["bold"] } 7 | "ui.linenr" = "tx-3" 8 | "ui.linenr.selected" = "tx" 9 | "ui.selection" = { bg = "ui-2" } 10 | "ui.statusline" = { fg = "tx", bg = "bg-2" } 11 | "ui.statusline.normal" = { fg = "bg", bg = "bl" } 12 | "ui.statusline.insert" = { fg = "bg", bg = "or" } 13 | "ui.statusline.select" = { fg = "bg", bg = "ma" } 14 | "ui.cursorline" = { bg = "bg-2" } 15 | "ui.popup" = { fg = "tx", bg = "bg-2" } 16 | "ui.window" = "tx" 17 | "ui.help" = { fg = "tx", bg = "bg" } 18 | "ui.text" = "tx" 19 | "ui.text.focus" = { bg = "bg-2", fg = "tx" } 20 | "ui.text.info" = "tx" 21 | "ui.virtual.whitespace" = "bg-2" 22 | "ui.virtual.ruler" = { bg = "bg-2" } 23 | "ui.virtual.inlay-hint" = { fg = "tx-3", bg = "bg" } 24 | "ui.virtual.jump-label" = { bg = "bg-2", modifiers = ["bold"]} 25 | "ui.menu" = { fg = "tx", bg = "bg" } 26 | "ui.menu.selected" = { bg = "ui", fg = "tx" } 27 | "ui.debug" = { fg = "or", bg = "bg" } 28 | "ui.highlight.frameline" = { bg = "ye" } 29 | "ui.bufferline" = { fg = "tx-2", bg = "bg-2"} 30 | "ui.bufferline.active" = { fg = "ye", bg = "bg-2" } 31 | "diagnostic.hint" = { underline = { color = "bl", style = "curl" } } 32 | "diagnostic.info" = { underline = { color = "bl", style = "curl" } } 33 | "diagnostic.warning" = { underline = { color = "ye", style = "curl" } } 34 | "diagnostic.error" = { underline = { color = "re", style = "curl" } } 35 | "diagnostic.unnecessary" = { modifiers = ["dim"] } 36 | "diagnostic.deprecated" = { modifiers = ["crossed_out"] } 37 | "hint" = { fg = "bl", modifiers = ["bold"] } 38 | "info" = { fg = "ye", modifiers = ["bold"] } 39 | "warning" = { fg = "or", modifiers = ["bold"] } 40 | "error" = { fg = "re", modifiers = ["bold"] } 41 | "attribute" = "ye" 42 | "type" = "ye" 43 | "constructor" = "gr" 44 | "constant" = "pu" 45 | "constant.builtin" = "ye" 46 | "string" = "cy" 47 | "string.regexp" = "or" 48 | "string.special" = "ye" 49 | "comment" = "tx-3" 50 | "variable" = "tx" 51 | "variable.builtin" = "ma" 52 | "variable.other" = "bl" 53 | "punctuation" = "tx-2" 54 | "keyword" = "gr" 55 | "keyword.control" = "re" 56 | "keyword.control.conditional" = "gr" 57 | "keyword.control.import" = "ye" 58 | "keyword.control.return" = "gr" 59 | "keyword.function" = "gr" 60 | "keyword.storage.type" = "bl" 61 | "keyword.storage.modifier" = "bl" 62 | "operator" = "tx-2" 63 | "function" = "or" 64 | "tag" = "bl" 65 | "namespace" = "re" 66 | "markup.heading" = "or" 67 | "markup.list" = "ye" 68 | "markup.bold" = { fg = "or", modifiers = ["bold"] } 69 | "markup.italic" = { fg = "or", modifiers = ["italic"] } 70 | "markup.strikethrough" = { modifiers = ["crossed_out"] } 71 | "markup.raw.block" = "or" 72 | "markup.link.url" = "bl" 73 | "markup.link.text" = "ye" 74 | "markup.link.label" = "gr" 75 | "markup.quote" = "ye" 76 | "markup.raw" = "bl" 77 | "diff.plus" = "gr" 78 | "diff.minus" = "re" 79 | "diff.delta" = "ye" 80 | 81 | [palette] 82 | tx = "#100F0F" 83 | tx-2 = "#6F6E69" 84 | tx-3 = "#B7B5AC" 85 | ui-3 = "#CECDC3" 86 | ui-2 = "#DAD8CE" 87 | ui = "#E6E4D9" 88 | bg-2 = "#F2F0E5" 89 | bg = "#FFFCF0" 90 | 91 | 92 | re = "#AF3029" 93 | or = "#BC5215" 94 | ye = "#AD8301" 95 | gr = "#66800B" 96 | cy = "#24837B" 97 | bl = "#205EA6" 98 | pu = "#5E409D" 99 | ma = "#A02F6F" 100 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/eza/theme.yml: -------------------------------------------------------------------------------- 1 | colourful: true 2 | 3 | filekinds: 4 | normal: {foreground: "#586e75"} 5 | directory: {foreground: "#268bd2"} 6 | symlink: {foreground: "#2aa198"} 7 | pipe: {foreground: "#657b83"} 8 | block_device: {foreground: "#dc322f"} 9 | char_device: {foreground: "#dc322f"} 10 | socket: {foreground: "#93a1a1"} 11 | special: {foreground: "#6c71c4"} 12 | executable: {foreground: "#859900"} 13 | mount_point: {foreground: "#cb4b16"} 14 | 15 | perms: 16 | user_read: {foreground: "#586e75"} 17 | user_write: {foreground: "#b58900"} 18 | user_execute_file: {foreground: "#859900"} 19 | user_execute_other: {foreground: "#859900"} 20 | group_read: {foreground: "#586e75"} 21 | group_write: {foreground: "#b58900"} 22 | group_execute: {foreground: "#859900"} 23 | other_read: {foreground: "#657b83"} 24 | other_write: {foreground: "#b58900"} 25 | other_execute: {foreground: "#859900"} 26 | special_user_file: {foreground: "#6c71c4"} 27 | special_other: {foreground: "#657b83"} 28 | attribute: {foreground: "#657b83"} 29 | 30 | size: 31 | major: {foreground: "#657b83"} 32 | minor: {foreground: "#2aa198"} 33 | number_byte: {foreground: "#586e75"} 34 | number_kilo: {foreground: "#586e75"} 35 | number_mega: {foreground: "#268bd2"} 36 | number_giga: {foreground: "#6c71c4"} 37 | number_huge: {foreground: "#6c71c4"} 38 | unit_byte: {foreground: "#657b83"} 39 | unit_kilo: {foreground: "#268bd2"} 40 | unit_mega: {foreground: "#6c71c4"} 41 | unit_giga: {foreground: "#6c71c4"} 42 | unit_huge: {foreground: "#cb4b16"} 43 | 44 | users: 45 | user_you: {foreground: "#586e75"} 46 | user_root: {foreground: "#dc322f"} 47 | user_other: {foreground: "#6c71c4"} 48 | group_yours: {foreground: "#586e75"} 49 | group_other: {foreground: "#657b83"} 50 | group_root: {foreground: "#dc322f"} 51 | 52 | links: 53 | normal: {foreground: "#2aa198"} 54 | multi_link_file: {foreground: "#cb4b16"} 55 | 56 | git: 57 | new: {foreground: "#859900"} 58 | modified: {foreground: "#b58900"} 59 | deleted: {foreground: "#dc322f"} 60 | renamed: {foreground: "#2aa198"} 61 | typechange: {foreground: "#6c71c4"} 62 | ignored: {foreground: "#657b83"} 63 | conflicted: {foreground: "#d33682"} 64 | 65 | git_repo: 66 | branch_main: {foreground: "#586e75"} 67 | branch_other: {foreground: "#6c71c4"} 68 | git_clean: {foreground: "#859900"} 69 | git_dirty: {foreground: "#dc322f"} 70 | 71 | security_context: 72 | colon: {foreground: "#657b83"} 73 | user: {foreground: "#586e75"} 74 | role: {foreground: "#6c71c4"} 75 | typ: {foreground: "#93a1a1"} 76 | range: {foreground: "#6c71c4"} 77 | 78 | file_type: 79 | image: {foreground: "#b58900"} 80 | video: {foreground: "#dc322f"} 81 | music: {foreground: "#859900"} 82 | lossless: {foreground: "#2aa198"} 83 | crypto: {foreground: "#657b83"} 84 | document: {foreground: "#586e75"} 85 | compressed: {foreground: "#6c71c4"} 86 | temp: {foreground: "#d33682"} 87 | compiled: {foreground: "#268bd2"} 88 | build: {foreground: "#657b83"} 89 | source: {foreground: "#268bd2"} 90 | 91 | punctuation: {foreground: "#657b83"} 92 | date: {foreground: "#b58900"} 93 | inode: {foreground: "#657b83"} 94 | blocks: {foreground: "#878580"} 95 | header: {foreground: "#586e75"} 96 | octal: {foreground: "#2aa198"} 97 | flags: {foreground: "#6c71c4"} 98 | 99 | symlink_path: {foreground: "#2aa198"} 100 | control_char: {foreground: "#268bd2"} 101 | broken_symlink: {foreground: "#dc322f"} 102 | broken_path_overlay: {foreground: "#657b83"} 103 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/eza/themes/solarized-light.yml: -------------------------------------------------------------------------------- 1 | colourful: true 2 | 3 | filekinds: 4 | normal: {foreground: "#586e75"} 5 | directory: {foreground: "#268bd2"} 6 | symlink: {foreground: "#2aa198"} 7 | pipe: {foreground: "#657b83"} 8 | block_device: {foreground: "#dc322f"} 9 | char_device: {foreground: "#dc322f"} 10 | socket: {foreground: "#93a1a1"} 11 | special: {foreground: "#6c71c4"} 12 | executable: {foreground: "#859900"} 13 | mount_point: {foreground: "#cb4b16"} 14 | 15 | perms: 16 | user_read: {foreground: "#586e75"} 17 | user_write: {foreground: "#b58900"} 18 | user_execute_file: {foreground: "#859900"} 19 | user_execute_other: {foreground: "#859900"} 20 | group_read: {foreground: "#586e75"} 21 | group_write: {foreground: "#b58900"} 22 | group_execute: {foreground: "#859900"} 23 | other_read: {foreground: "#657b83"} 24 | other_write: {foreground: "#b58900"} 25 | other_execute: {foreground: "#859900"} 26 | special_user_file: {foreground: "#6c71c4"} 27 | special_other: {foreground: "#657b83"} 28 | attribute: {foreground: "#657b83"} 29 | 30 | size: 31 | major: {foreground: "#657b83"} 32 | minor: {foreground: "#2aa198"} 33 | number_byte: {foreground: "#586e75"} 34 | number_kilo: {foreground: "#586e75"} 35 | number_mega: {foreground: "#268bd2"} 36 | number_giga: {foreground: "#6c71c4"} 37 | number_huge: {foreground: "#6c71c4"} 38 | unit_byte: {foreground: "#657b83"} 39 | unit_kilo: {foreground: "#268bd2"} 40 | unit_mega: {foreground: "#6c71c4"} 41 | unit_giga: {foreground: "#6c71c4"} 42 | unit_huge: {foreground: "#cb4b16"} 43 | 44 | users: 45 | user_you: {foreground: "#586e75"} 46 | user_root: {foreground: "#dc322f"} 47 | user_other: {foreground: "#6c71c4"} 48 | group_yours: {foreground: "#586e75"} 49 | group_other: {foreground: "#657b83"} 50 | group_root: {foreground: "#dc322f"} 51 | 52 | links: 53 | normal: {foreground: "#2aa198"} 54 | multi_link_file: {foreground: "#cb4b16"} 55 | 56 | git: 57 | new: {foreground: "#859900"} 58 | modified: {foreground: "#b58900"} 59 | deleted: {foreground: "#dc322f"} 60 | renamed: {foreground: "#2aa198"} 61 | typechange: {foreground: "#6c71c4"} 62 | ignored: {foreground: "#657b83"} 63 | conflicted: {foreground: "#d33682"} 64 | 65 | git_repo: 66 | branch_main: {foreground: "#586e75"} 67 | branch_other: {foreground: "#6c71c4"} 68 | git_clean: {foreground: "#859900"} 69 | git_dirty: {foreground: "#dc322f"} 70 | 71 | security_context: 72 | colon: {foreground: "#657b83"} 73 | user: {foreground: "#586e75"} 74 | role: {foreground: "#6c71c4"} 75 | typ: {foreground: "#93a1a1"} 76 | range: {foreground: "#6c71c4"} 77 | 78 | file_type: 79 | image: {foreground: "#b58900"} 80 | video: {foreground: "#dc322f"} 81 | music: {foreground: "#859900"} 82 | lossless: {foreground: "#2aa198"} 83 | crypto: {foreground: "#657b83"} 84 | document: {foreground: "#586e75"} 85 | compressed: {foreground: "#6c71c4"} 86 | temp: {foreground: "#d33682"} 87 | compiled: {foreground: "#268bd2"} 88 | build: {foreground: "#657b83"} 89 | source: {foreground: "#268bd2"} 90 | 91 | punctuation: {foreground: "#657b83"} 92 | date: {foreground: "#b58900"} 93 | inode: {foreground: "#657b83"} 94 | blocks: {foreground: "#878580"} 95 | header: {foreground: "#586e75"} 96 | octal: {foreground: "#2aa198"} 97 | flags: {foreground: "#6c71c4"} 98 | 99 | symlink_path: {foreground: "#2aa198"} 100 | control_char: {foreground: "#268bd2"} 101 | broken_symlink: {foreground: "#dc322f"} 102 | broken_path_overlay: {foreground: "#657b83"} 103 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.local/bin/bmux: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @meta describe Utility scripts for tmux 4 | # @meta author Brad Frank 5 | # @meta require-tools tmux,fzf 6 | # @meta combine-shorts 7 | 8 | 9 | _get_window_name() { 10 | local cwd base_cwd username branch_name repo_name 11 | 12 | cwd="$1" 13 | base_cwd="$(basename "$cwd")" 14 | repo_name="$base_cwd" 15 | username="$(id --user --name)" 16 | 17 | pushd "$cwd" &> /dev/null || exit 1 18 | 19 | if branch_name="$(git branch --show-current 2>/dev/null)"; then 20 | [[ "$base_cwd" == "$branch_name" ]] && repo_name="$(basename "$(dirname "$cwd")")" 21 | echo "${repo_name} (${branch_name})" 22 | elif [[ "$base_cwd" == "$username" ]]; then 23 | echo "~${username}" 24 | else 25 | echo "$base_cwd" 26 | fi 27 | 28 | popd &> /dev/null || exit 1 29 | } 30 | 31 | 32 | _get_project_dir() { 33 | find "${HOME}/Development/Projects" -mindepth 2 -maxdepth 2 -type d \ 34 | | fzf-tmux -p --reverse --no-multi --delimiter / --with-nth -2,-1 \ 35 | --preview="eza --color always --classify --no-user --no-permissions --long --all --git {} --" 36 | } 37 | 38 | 39 | _select_session() { 40 | tmux list-session -F "#{session_name}" \ 41 | | fzf-tmux --no-multi -p --preview="tmux list-windows -t {} -F '#{window_name}' --" 42 | } 43 | 44 | 45 | # @cmd Rename window with Git branch info 46 | # @arg dir! 47 | rename() { 48 | tmux rename-window "$(_get_window_name "$argc_dir")" 49 | } 50 | 51 | 52 | # @cmd Open a project in a new window or session 53 | # @arg directory Project directory 54 | # @option -c --command Command to run in new window 55 | # @flag -s --new-session Open the window in a new session 56 | open() { 57 | local window_name session_name 58 | 59 | [[ -z "$argc_directory" ]] && argc_directory="$(_get_project_dir)" 60 | [[ -z "$argc_directory" ]] && exit 0 61 | 62 | window_name="$(_get_window_name "$argc_directory")" 63 | 64 | if [[ -n $argc_new_session ]]; then 65 | session_name="$(awk '{print $1}' <<< "$window_name")" 66 | if tmux has-session -t "$session_name" 2>/dev/null; then 67 | tmux new-window -n "$window_name" -c "$argc_directory" -d 68 | else 69 | tmux new-session -s "$session_name" -n "$window_name" -c "$argc_directory" -d 70 | fi 71 | else 72 | session_name="$(tmux display-message -p "#S")" 73 | tmux new-window -n "$window_name" -c "$argc_directory" -d 74 | fi 75 | 76 | tmux switch-client -t "${session_name}:${window_name}" 77 | if [[ -n "$argc_command" ]]; then 78 | tmux send-keys -t "${session_name}:${window_name}" "$argc_command" Enter 79 | fi 80 | } 81 | 82 | 83 | # @cmd Save pane output to file 84 | # @option -o --output Output file 85 | dump() { 86 | local window_name session_name output_dir output_temp 87 | 88 | session_name="$(tmux display-message -p "#{session_name}")" 89 | output_temp="$(mktemp)" 90 | 91 | if [[ -z $argc_output ]]; then 92 | argc_output="${HOME}/Development/Logs/$(tmux display-message -p \ 93 | 'tmux-%Y-%b-%d-%H%M-#{session_name}.log' | tr -cd '[:print:]')" 94 | fi 95 | 96 | output_dir="$(dirname "$argc_output")" 97 | 98 | mkdir --parents "$(dirname "$argc_output")" 99 | tmux capture-pane -S - 100 | tmux save-buffer "$output_temp" 101 | cat -s "$output_temp" > "$argc_output" 102 | rm "$output_temp" 103 | 104 | window_name="$(_get_window_name "$output_dir")" 105 | tmux new-window -n "${window_name}" -c "$output_dir" -d 106 | tmux switch-client -t "${session_name}:${window_name}" 107 | tmux send-keys -t "${session_name}:${window_name}" "vim ${argc_output}; clear" Enter 108 | } 109 | 110 | 111 | # @cmd Save session (tmux-resurrect) 112 | save() { 113 | "${HOME}/.local/share/tmux-resurrect/scripts/save.sh" 114 | } 115 | 116 | 117 | eval "$(argc --argc-eval "$0" "$@")" 118 | -------------------------------------------------------------------------------- /group_vars/Fedora.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | _bat_exec: "/usr/bin/bat" 4 | _rpmfusion: 5 | gpgkey: "https://rpmfusion.org/keys?action=AttachFile&do=get&target" 6 | metalink: "https://mirrors.rpmfusion.org/metalink?arch=$basearch&repo" 7 | 8 | tmux_clipboard: "wl-copy" 9 | 10 | pkg_mgr_repos: 11 | base: 12 | - name: "rpmfusion-free" 13 | description: "RPM Fusion for Fedora - Free" 14 | metalink: "{{ _rpmfusion['metalink'] }}=free-fedora-$releasever" 15 | gpgkey: "{{ _rpmfusion['gpgkey'] }}=RPM-GPG-KEY-rpmfusion-free-fedora-2020" 16 | - name: "rpmfusion-free-updates" 17 | description: "RPM Fusion for Fedora - Free - Updates" 18 | metalink: "{{ _rpmfusion['metalink'] }}=free-fedora-updates-released-$releasever" 19 | gpgkey: "{{ _rpmfusion['gpgkey'] }}=RPM-GPG-KEY-rpmfusion-free-fedora-2020" 20 | - name: "rpmfusion-nonfree" 21 | description: "RPM Fusion for Fedora - Nonfree" 22 | metalink: "{{ _rpmfusion['metalink'] }}=nonfree-fedora-$releasever" 23 | gpgkey: "{{ _rpmfusion['gpgkey'] }}=RPM-GPG-KEY-rpmfusion-nonfree-fedora-2020" 24 | - name: "rpmfusion-nonfree-updates" 25 | description: "RPM Fusion for Fedora - Nonfree - Updates" 26 | metalink: "{{ _rpmfusion['metalink'] }}=nonfree-fedora-updates-released-$releasever" 27 | gpgkey: "{{ _rpmfusion['gpgkey'] }}=RPM-GPG-KEY-rpmfusion-nonfree-fedora-2020" 28 | 29 | pkg_mgr_cli: 30 | base: 31 | - asciinema 32 | - atool 33 | - atuin 34 | - bash-completion 35 | - bat 36 | - bcal 37 | - diceware 38 | - dictd 39 | - dnf-plugin-system-upgrade 40 | - dnf-utils 41 | - dua-cli 42 | - duf 43 | - fastfetch 44 | - fd-find 45 | - fdkaac 46 | - figlet 47 | - fwupd 48 | - fzf 49 | - gcc-c++ 50 | - gh 51 | - ghostscript 52 | - glow 53 | - gron 54 | - htop 55 | - httpie 56 | - iftop 57 | - inxi 58 | - jq 59 | - jo 60 | - lame 61 | - keychain 62 | - libmp4v2 63 | - libvirt-client 64 | - mkvtoolnix 65 | - moreutils 66 | - msmtp 67 | - mtr 68 | - nmap 69 | - ocrmypdf 70 | - p7zip 71 | - p7zip-plugins 72 | - par 73 | - perf 74 | - pdfgrep 75 | - pwgen 76 | - python3 77 | - python3-devel 78 | - rdfind 79 | - ripgrep 80 | - ruby 81 | - ShellCheck 82 | - strace 83 | - tidy 84 | - tlp 85 | - toilet 86 | - tree 87 | - trurl 88 | - virtualenv 89 | - wget 90 | - xz 91 | - yt-dlp 92 | formulas: 93 | - argc 94 | - bat-extras 95 | - eza # https://github.com/eza-community/eza/issues/1456 96 | - fclones 97 | - lazygit 98 | - yq 99 | 100 | pkg_mgr_gui: 101 | base: 102 | - 1password 103 | - foliate 104 | - keepassxc 105 | - libreoffice 106 | - mediawriter 107 | - metadata-cleaner 108 | - papers 109 | - picard 110 | - wildcard # regex testing 111 | - vlc 112 | flatpak: 113 | - app.drey.EarTag # ID3 tagging 114 | - app.drey.Warp # airdrop 115 | - com.github.huluti.Curtail # image compresser 116 | - com.github.junrrein.PDFSlicer 117 | - com.github.liferooter.textpieces # filter and manipulate text/code 118 | - com.plexamp.Plexamp 119 | - com.spotify.Client 120 | - io.github.diegoivan.pdf_metadata_editor # Paper Clip - pdf metadata editor 121 | - io.github.seadve.Kooha # screen recorder 122 | - io.gitlab.news_flash.NewsFlash # rss reader 123 | - org.gnome.gitlab.somas.Apostrophe # markdown editor 124 | - org.ppsspp.PPSSPP 125 | - org.signal.Signal 126 | - tv.plex.PlexDesktop 127 | - us.zoom.Zoom 128 | gnome: 129 | - celluloid # mpv frontend 130 | - gnome-characters # emoji picker 131 | - gnome-connections # vnc viewer 132 | - gnome-shell-extension-gpaste 133 | - gpaste* 134 | - gthumb # image viewer and editor 135 | - libgnome-keyring 136 | - mpv # video player 137 | - transmission-gtk 138 | kde: 139 | - transmission-qt 140 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/eza/themes/rose-pine-dawn.yml: -------------------------------------------------------------------------------- 1 | colourful: true 2 | 3 | # Colors are in format of: 4 | # color/paletteRef (Description) #color code 5 | 6 | # Gold (Terminal Yellow) #ea9d34 7 | # Love (Terminal Red) #b4637a 8 | # Rose (Terminal Cyan) #d7827e 9 | # Base (Primary Background) #faf4ed 10 | # Iris (Terminal Magenta) #907aa9 11 | # Foam (Terminal Blue) #56949f 12 | # Pine (Terminal Green) #286983 13 | # Text (High contrast foreground) #575279 14 | # Muted (Low Contrast Foreground) #9893a5 15 | # Subtle (Medium Contrast Foreground) #797593 16 | # Highlight Low (Low contrast highlight) #f4ede8 17 | # Highlight Med (Medium Contrast Highlight) #dfdad9 18 | # Highlight High (High Contrast Highlight) #cecacd 19 | 20 | filekinds: 21 | normal: {foreground: "#575279"} 22 | directory: {foreground: "#56949f"} 23 | symlink: {foreground: "#cecacd"} 24 | pipe: {foreground: "#797593"} 25 | block_device: {foreground: "#d7827e"} 26 | char_device: {foreground: "#ea9d34"} 27 | socket: {foreground: "#f4ede8"} 28 | special: {foreground: "#907aa9"} 29 | executable: {foreground: "#907aa9"} 30 | mount_point: {foreground: "#dfdad9"} 31 | 32 | perms: 33 | user_read: {foreground: "#797593"} 34 | user_write: {foreground: "#d7827e"} 35 | user_execute_file: {foreground: "#907aa9"} 36 | user_execute_other: {foreground: "#907aa9"} 37 | group_read: {foreground: "#797593"} 38 | group_write: {foreground: "#d7827e"} 39 | group_execute: {foreground: "#907aa9"} 40 | other_read: {foreground: "#797593"} 41 | other_write: {foreground: "#d7827e"} 42 | other_execute: {foreground: "#907aa9"} 43 | special_user_file: {foreground: "#907aa9"} 44 | special_other: {foreground: "#d7827e"} 45 | attribute: {foreground: "#797593"} 46 | 47 | size: 48 | major: {foreground: "#797593"} 49 | minor: {foreground: "#56949f"} 50 | number_byte: {foreground: "#797593"} 51 | number_kilo: {foreground: "#cecacd"} 52 | number_mega: {foreground: "#286983"} 53 | number_giga: {foreground: "#907aa9"} 54 | number_huge: {foreground: "#907aa9"} 55 | unit_byte: {foreground: "#797593"} 56 | unit_kilo: {foreground: "#286983"} 57 | unit_mega: {foreground: "#907aa9"} 58 | unit_giga: {foreground: "#907aa9"} 59 | unit_huge: {foreground: "#56949f"} 60 | 61 | users: 62 | user_you: {foreground: "#ea9d34"} 63 | user_root: {foreground: "#b4637a"} 64 | user_other: {foreground: "#907aa9"} 65 | group_yours: {foreground: "#cecacd"} 66 | group_other: {foreground: "#9893a5"} 67 | group_root: {foreground: "#b4637a"} 68 | 69 | links: 70 | normal: {foreground: "#56949f"} 71 | multi_link_file: {foreground: "#286983"} 72 | 73 | git: 74 | new: {foreground: "#56949f"} 75 | modified: {foreground: "#ea9d34"} 76 | deleted: {foreground: "#b4637a"} 77 | renamed: {foreground: "#286983"} 78 | typechange: {foreground: "#907aa9"} 79 | ignored: {foreground: "#9893a5"} 80 | conflicted: {foreground: "#d7827e"} 81 | 82 | git_repo: 83 | branch_main: {foreground: "#797593"} 84 | branch_other: {foreground: "#907aa9"} 85 | git_clean: {foreground: "#56949f"} 86 | git_dirty: {foreground: "#b4637a"} 87 | 88 | security_context: 89 | colon: {foreground: "#797593"} 90 | user: {foreground: "#56949f"} 91 | role: {foreground: "#907aa9"} 92 | typ: {foreground: "#9893a5"} 93 | range: {foreground: "#907aa9"} 94 | 95 | file_type: 96 | image: {foreground: "#ea9d34"} 97 | video: {foreground: "#b4637a"} 98 | music: {foreground: "#56949f"} 99 | lossless: {foreground: "#9893a5"} 100 | crypto: {foreground: "#dfdad9"} 101 | document: {foreground: "#797593"} 102 | compressed: {foreground: "#907aa9"} 103 | temp: {foreground: "#d7827e"} 104 | compiled: {foreground: "#286983"} 105 | build: {foreground: "#9893a5"} 106 | source: {foreground: "#d7827e"} 107 | 108 | punctuation: {foreground: "#cecacd"} 109 | date: {foreground: "#286983"} 110 | inode: {foreground: "#797593"} 111 | blocks: {foreground: "#9893a5"} 112 | header: {foreground: "#797593"} 113 | octal: {foreground: "#56949f"} 114 | flags: {foreground: "#907aa9"} 115 | 116 | symlink_path: {foreground: "#56949f"} 117 | control_char: {foreground: "#286983"} 118 | broken_symlink: {foreground: "#b4637a"} 119 | broken_path_overlay: {foreground: "#cecacd"} 120 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/glow/themes/solarized-light.json: -------------------------------------------------------------------------------- 1 | { 2 | "document": { 3 | "block_prefix": "\n", 4 | "block_suffix": "\n", 5 | "color": "#657b83", 6 | "margin": 2 7 | }, 8 | "block_quote": { 9 | "indent": 1, 10 | "indent_token": "│ " 11 | }, 12 | "paragraph": {}, 13 | "list": { 14 | "level_indent": 2 15 | }, 16 | "heading": { 17 | "block_suffix": "\n", 18 | "color": "#268bd2", 19 | "bold": true 20 | }, 21 | "h1": { 22 | "prefix": " ", 23 | "suffix": " ", 24 | "color": "#b58900", 25 | "background_color": "#eee8d5", 26 | "bold": true 27 | }, 28 | "h2": { 29 | "prefix": "## " 30 | }, 31 | "h3": { 32 | "prefix": "### " 33 | }, 34 | "h4": { 35 | "prefix": "#### " 36 | }, 37 | "h5": { 38 | "prefix": "##### " 39 | }, 40 | "h6": { 41 | "prefix": "###### ", 42 | "bold": false 43 | }, 44 | "text": {}, 45 | "strikethrough": { 46 | "crossed_out": true 47 | }, 48 | "emph": { 49 | "italic": true 50 | }, 51 | "strong": { 52 | "bold": true 53 | }, 54 | "hr": { 55 | "color": "#586e75", 56 | "format": "\n--------\n" 57 | }, 58 | "item": { 59 | "block_prefix": "• " 60 | }, 61 | "enumeration": { 62 | "block_prefix": ". " 63 | }, 64 | "task": { 65 | "ticked": "[✓] ", 66 | "unticked": "[ ] " 67 | }, 68 | "link": { 69 | "color": "#2aa198", 70 | "underline": true 71 | }, 72 | "link_text": { 73 | "color": "#268bd2", 74 | "bold": true 75 | }, 76 | "image": { 77 | "color": "#d33682", 78 | "underline": true 79 | }, 80 | "image_text": { 81 | "color": "#586e75", 82 | "format": "Image: {{.text}} →" 83 | }, 84 | "code": { 85 | "prefix": " ", 86 | "suffix": " ", 87 | "color": "#dc322f", 88 | "background_color": "#eee8d5" 89 | }, 90 | "code_block": { 91 | "color": "#586e75", 92 | "margin": 2, 93 | "chroma": { 94 | "text": { 95 | "color": "#657b83" 96 | }, 97 | "error": { 98 | "color": "#fdf6e3", 99 | "background_color": "#dc322f" 100 | }, 101 | "comment": { 102 | "color": "#93a1a1" 103 | }, 104 | "comment_preproc": { 105 | "color": "#cb4b16" 106 | }, 107 | "keyword": { 108 | "color": "#268bd2" 109 | }, 110 | "keyword_reserved": { 111 | "color": "#d33682" 112 | }, 113 | "keyword_namespace": { 114 | "color": "#6c71c4" 115 | }, 116 | "keyword_type": { 117 | "color": "#859900" 118 | }, 119 | "operator": { 120 | "color": "#dc322f" 121 | }, 122 | "punctuation": { 123 | "color": "#cb4b16" 124 | }, 125 | "name_builtin": { 126 | "color": "#268bd2" 127 | }, 128 | "name_tag": { 129 | "color": "#6c71c4" 130 | }, 131 | "name_attribute": { 132 | "color": "#859900" 133 | }, 134 | "name_class": { 135 | "color": "#657b83", 136 | "underline": true, 137 | "bold": true 138 | }, 139 | "name_constant": { 140 | "color": "#6c71c4" 141 | }, 142 | "name_decorator": { 143 | "color": "#b58900" 144 | }, 145 | "name_function": { 146 | "color": "#859900" 147 | }, 148 | "literal_number": { 149 | "color": "#2aa198" 150 | }, 151 | "literal_string": { 152 | "color": "#cb4b16" 153 | }, 154 | "literal_string_escape": { 155 | "color": "#2aa198" 156 | }, 157 | "generic_deleted": { 158 | "color": "#dc322f" 159 | }, 160 | "generic_emph": { 161 | "italic": true 162 | }, 163 | "generic_inserted": { 164 | "color": "#859900" 165 | }, 166 | "generic_strong": { 167 | "bold": true 168 | }, 169 | "generic_subheading": { 170 | "color": "#586e75" 171 | }, 172 | "background": { 173 | "background_color": "#fdf6e3" 174 | } 175 | } 176 | }, 177 | "table": {}, 178 | "definition_list": {}, 179 | "definition_term": {}, 180 | "definition_description": { 181 | "block_prefix": "\n🠶 " 182 | }, 183 | "html_block": {}, 184 | "html_span": {} 185 | } 186 | -------------------------------------------------------------------------------- /roles/tmux/templates/tmux.conf.j2: -------------------------------------------------------------------------------- 1 | ##### THEME SETTINGS ##### 2 | 3 | # unicode "pill" design (default,highlighted,zoom) 4 | set -s @cap_l_df "#[fg=#eee8d5,bg=default]#[default]" 5 | set -s @cap_r_df "#[fg=#eee8d5,bg=default]#[default]" 6 | set -s @cap_l_hi "#[fg=#268bd2,bg=default]#[default]" 7 | set -s @cap_r_hi "#[fg=#268bd2,bg=default]#[default]" 8 | set -s @cap_l_zm "#[fg=#d33682,bg=default]#[default]" 9 | set -s @cap_r_zm "#[fg=#d33682,bg=default]#[default]" 10 | 11 | # pane border (default,sync,zoom) 12 | set -s @pane_df "fg=#eee8d5,bg=default" 13 | set -s @pane_hi "fg=#073642,bg=default" 14 | set -s @pane_sy "fg=#2aa198,bg=default" 15 | set -s @pane_zm "fg=#dc322f,bg=default" 16 | 17 | # window tab names (default,highlighted) 18 | set -s @window_df "#[fg=#268bd2,bg=#eee8d5,bold]#I: #W#[default]" 19 | set -s @window_hi "#[fg=#fdf6e3,bg=#268bd2,bold]#I: #W#[default]" 20 | 21 | # status-right info (defaults) 22 | set -s @session_df "#[fg=#6c71c4,bg=#eee8d5,bold]#{session_name}#[default]" 23 | set -s @host_df "#[fg=#d33682,bg=#eee8d5,bold]#{host_short}#[default]" 24 | 25 | 26 | ##### PANE SETTINGS ##### 27 | 28 | set -g pane-active-border-style "#{?window_zoomed_flag,#{@pane_zm},#{?pane_synchronized,#{@pane_sy},#{@pane_hi}}}" 29 | set -g pane-border-format "#{?window_zoomed_flag,#[#{@pane_zm}] ZOOM #[default],}" 30 | set -g pane-border-indicators "off" 31 | set -g pane-border-style "bg=default,#{?pane_synchronized,#{@pane_sy},#{@pane_df}}" 32 | set -gF pane-border-status "top" 33 | set -gF pane-border-lines "double" 34 | 35 | 36 | ##### WINDOW SETTINGS ##### 37 | 38 | set -g window-status-activity-style "" 39 | set -g window-status-style "" 40 | set -g window-status-current-style "" 41 | set -gF window-status-format "#{@cap_l_df}#{@window_df}#{@cap_r_df}" 42 | set -gF window-status-current-format "#{@cap_l_hi}#{@window_hi}#{@cap_r_hi}" 43 | 44 | 45 | ##### STATUS LINE SETTINGS ##### 46 | 47 | set -g message-style "bg=black,fg=default" 48 | set -g mode-style "bg=white,fg=black" 49 | set -g status "on" 50 | set -g status-justify "left" 51 | set -g status-left " " 52 | set -g status-style "bg=default" 53 | set -gF status-right "#{@cap_l_df}#{@session_df}#{@cap_r_df} #{@cap_l_df}#{@host_df}#{@cap_r_df} " 54 | set -gF status-position "top" 55 | 56 | 57 | ##### GENERAL SETTINGS ##### 58 | 59 | set -g aggressive-resize "off" 60 | set -g allow-passthrough "on" 61 | set -g allow-rename "on" 62 | set -g automatic-rename-format "#{b:pane_current_path}" 63 | set -g base-index 1 64 | set -g default-command "${SHELL}" 65 | set -g default-terminal "tmux-256color" 66 | set -g detach-on-destroy "off" 67 | set -g history-limit "10000" 68 | set -g monitor-activity "off" 69 | set -g mouse "on" 70 | set -g renumber-windows "on" 71 | set -g status-interval 1 72 | set -g terminal-overrides "xterm-*:Tc,gnome*:Tc" 73 | 74 | 75 | ##### COPY MODE SETTINGS ##### 76 | 77 | bind -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe {{ tmux_clipboard }} 78 | bind -T copy-mode-vi WheelDownPane send -N2 -X scroll-down # fix scrolling speed 79 | bind -T copy-mode-vi WheelUpPane send -N2 -X scroll-up # fix scrolling speed 80 | 81 | bind '+' resize-pane -Z 82 | bind '%' split-window -h -c "#{pane_current_path}" 83 | bind '"' split-window -c "#{pane_current_path}" 84 | bind 'C' new-window -c "#{pane_current_path}" 85 | bind 'c' new-window -c "~/" 86 | bind 'D' run-shell -b "bmux dump" 87 | bind 'r' run-shell -b "bmux rename #{pane_current_path}" 88 | bind 'u' source-file "~/.config/tmux/{{ item }}.conf" 89 | bind 'y' set synchronize-panes 90 | {% if item == "tmux" %} 91 | bind 'I' command-prompt -p "New session: " "new-session -A -s '%%'" 92 | bind 'M' choose-tree -Zs "move-window -t %%" 93 | bind 'm' choose-tree -Z "move-pane -t %%" 94 | bind 'O' run-shell -b "bmux open" 95 | bind 'N' display-popup -E -w 90% -h 90% -b rounded -S "fg=color234" "tmux -L notes -f ~/.config/tmux/popup.conf new-session -As notes -c ~/Development/Scratch" 96 | bind 'P' display-popup -E -w 55% -h 100% -b rounded -S "fg=color234" "tmux -L popup -f ~/.config/tmux/popup.conf new-session -As popup -c ~/Development/Scratch" 97 | {% endif %} 98 | 99 | {% for plugin in tmux_plugins %} 100 | run-shell {{ ansible_facts['user_dir'] }}/.local/share/{{ plugin['name'] }}/{{ plugin['exec'] }} 101 | {% endfor %} 102 | -------------------------------------------------------------------------------- /roles/dotfiles/files/home/.config/fastfetch/config.jsonc: -------------------------------------------------------------------------------- 1 | // Load with --load-config examples/2.jsonc 2 | // Note that you must replace the image path to an existing image to display it. 3 | 4 | { 5 | "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", 6 | // "logo": { 7 | // "type": "iterm", 8 | // "source": "/Users/carter/Desktop/apple1.png", 9 | // "width": 28, 10 | // "height": 12 11 | // }, 12 | "display": { 13 | "separator": " " 14 | }, 15 | "modules": [ 16 | { 17 | "type": "custom", // HardwareStart 18 | "format": "┌─────────── \u001b[1mHardware Information\u001b[0m ───────────┐" // `\u001b` is `\033`, or `\e` 19 | }, 20 | { 21 | "type": "host", 22 | "key": " 󰌢" 23 | }, 24 | { 25 | "type": "cpu", 26 | "key": " 󰻠" 27 | }, 28 | { 29 | "type": "gpu", 30 | "key": " 󰍛" 31 | }, 32 | { 33 | "type": "disk", 34 | "key": " " 35 | }, 36 | { 37 | "type": "memory", 38 | "key": " 󰑭" 39 | }, 40 | { 41 | "type": "swap", 42 | "key": " 󰓡" 43 | }, 44 | { 45 | "type": "display", 46 | "key": " 󰍹" 47 | }, 48 | { 49 | "type": "brightness", 50 | "key": " 󰃞" 51 | }, 52 | { 53 | "type": "battery", 54 | "key": " " 55 | }, 56 | { 57 | "type": "poweradapter", 58 | "key": " " 59 | }, 60 | { 61 | "type": "bluetooth", 62 | "key": " " 63 | }, 64 | { 65 | "type": "sound", 66 | "key": " " 67 | }, 68 | { 69 | "type": "gamepad", 70 | "key": " " 71 | }, 72 | { 73 | "type": "custom", // SoftwareStart 74 | "format": "├─────────── \u001b[1mSoftware Information\u001b[0m ───────────┤" 75 | }, 76 | { 77 | "type": "title", 78 | "key": " ", 79 | "format": "{1}@{2}" 80 | }, 81 | { 82 | "type": "os", 83 | "key": " " // Just get your distro's logo off nerdfonts.com 84 | }, 85 | { 86 | "type": "kernel", 87 | "key": " ", 88 | "format": "{1} {2}" 89 | }, 90 | { 91 | "type": "lm", 92 | "key": " 󰧨" 93 | }, 94 | { 95 | "type": "de", 96 | "key": " " 97 | }, 98 | { 99 | "type": "wm", 100 | "key": " " 101 | }, 102 | { 103 | "type": "shell", 104 | "key": " " 105 | }, 106 | { 107 | "type": "terminal", 108 | "key": " " 109 | }, 110 | { 111 | "type": "terminalfont", 112 | "key": " " 113 | }, 114 | { 115 | "type": "theme", 116 | "key": " 󰉼" 117 | }, 118 | { 119 | "type": "icons", 120 | "key": " 󰀻" 121 | }, 122 | { 123 | "type": "wallpaper", 124 | "key": " 󰸉" 125 | }, 126 | { 127 | "type": "packages", 128 | "key": " 󰏖" 129 | }, 130 | { 131 | "type": "uptime", 132 | "key": " 󰅐" 133 | }, 134 | { 135 | "type": "media", 136 | "key": " 󰝚" 137 | }, 138 | { 139 | "type": "localip", 140 | "key": " 󰩟", 141 | "compact": true 142 | }, 143 | { 144 | "type": "publicip", 145 | "key": " 󰩠" 146 | }, 147 | { 148 | "type": "wifi", 149 | "key": " ", 150 | "format": "{4}" // ssid 151 | }, 152 | { 153 | "type": "locale", 154 | "key": " " 155 | }, 156 | { 157 | "type": "custom", // InformationEnd 158 | "format": "└────────────────────────────────────────────┘" 159 | }, 160 | { 161 | "type": "colors", 162 | "paddingLeft": 2, 163 | "symbol": "circle" 164 | } 165 | ] 166 | } 167 | -------------------------------------------------------------------------------- /roles/vim/files/helix/themes/solarized_light.toml: -------------------------------------------------------------------------------- 1 | "attribute" = { fg = "violet" } 2 | "keyword" = { fg = "green" } 3 | "keyword.directive" = { fg = "orange" } 4 | "namespace" = { fg = "violet" } 5 | "operator" = { fg = "green" } 6 | "special" = { fg = "orange" } 7 | "variable.builtin" = { fg = "cyan", modifiers = ["bold"] } 8 | "variable.function" = { fg = "blue" } 9 | "type" = { fg = "yellow" } 10 | "type.builtin" = { fg = "yellow", modifiers = ["bold"] } 11 | "constructor" = { fg = "blue" } 12 | "function" = { fg = "blue" } 13 | "function.macro" = { fg = "magenta" } 14 | "function.builtin" = { fg = "blue", modifiers = ["bold"] } 15 | "function.special" = { fg = "magenta" } 16 | "comment" = { fg = "base01" } 17 | "string" = { fg = "cyan" } 18 | "constant" = { fg = "cyan" } 19 | "constant.builtin" = { fg = "cyan", modifiers = ["bold"] } 20 | "constant.character.escape" = { fg = "red", modifiers = ["bold"] } 21 | "label" = { fg = "green" } 22 | "module" = { fg = "violet" } 23 | "tag" = { fg = "magenta" } 24 | 25 | # TODO 26 | "markup.heading" = "blue" 27 | "markup.list" = "red" 28 | "markup.bold" = { fg = "yellow", modifiers = ["bold"] } 29 | "markup.italic" = { fg = "magenta", modifiers = ["italic"] } 30 | "markup.strikethrough" = { modifiers = ["crossed_out"] } 31 | "markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } 32 | "markup.link.text" = "red" 33 | "markup.quote" = "cyan" 34 | "markup.raw" = "green" 35 | 36 | "diff.plus" = { fg = "green" } 37 | "diff.delta" = { fg = "orange" } 38 | "diff.minus" = { fg = "red" } 39 | 40 | # 背景 41 | # background 42 | "ui.background" = { bg = "base03" } 43 | 44 | "ui.virtual.whitespace" = { fg = "base01" } 45 | "ui.virtual.inlay-hint" = { fg = "base01", modifiers = ["italic"] } 46 | "ui.virtual.jump-label" = { fg = "red", modifiers = ["bold"] } 47 | 48 | # 行号栏 49 | # line number column 50 | "ui.linenr" = { fg = "base0", bg = "base02" } 51 | # 当前行号栏 52 | # current line number column 53 | "ui.linenr.selected" = { fg = "blue", modifiers = ["bold"] } 54 | # cursorline 55 | "ui.cursorline" = { bg = "base0" } 56 | 57 | # 状态栏 58 | # status bar 59 | "ui.statusline" = { fg = "base03", bg = "base0" } 60 | "ui.statusline.normal" = { bg = "blue" } 61 | "ui.statusline.insert" = { bg = "green" } 62 | "ui.statusline.select" = { bg = "yellow" } 63 | 64 | # 非活动状态栏 65 | # inactive status bar 66 | "ui.statusline.inactive" = { fg = "base1", bg = "base01" } 67 | 68 | # 补全窗口, preview窗口 69 | # Completion window, preview window 70 | "ui.popup" = { bg = "base02" } 71 | # 影响 补全选中 cmd弹出信息选中 72 | # Affect completion selection, cmd pop-up information selection 73 | "ui.menu.selected" = { fg = "base02", bg = "base2"} 74 | "ui.menu" = { fg = "base0", bg = "base02" } 75 | # ?? 76 | "ui.window" = { fg = "base3" } 77 | # 命令行 补全的帮助信息 78 | # Command line completion help information 79 | "ui.help" = { modifiers = ["reversed"] } 80 | 81 | # 快捷键窗口 82 | # Shortcut window 83 | "ui.popup.info" = { bg = "base1" } 84 | # 快捷键字体 85 | # Shortcut font 86 | "ui.text.info" = {fg = "base02", modifiers = ["bold"]} 87 | 88 | # 普通ui的字体样式 89 | # Normal ui font style 90 | "ui.text" = { fg = "base1" } 91 | # 影响 picker列表选中, 快捷键帮助窗口文本 92 | # Affects picker list selection, shortcut key help window text 93 | "ui.text.focus" = { fg = "blue", modifiers = ["bold"]} 94 | 95 | # 主光标/selection 96 | # main cursor/selection 97 | "ui.cursor.primary" = { fg = "base03", bg = "base1" } 98 | "ui.cursor.select" = { fg = "base02", bg = "cyan" } 99 | 100 | "ui.cursorline.primary" = { bg = "base02" } 101 | "ui.cursorline.secondary" = { bg = "base025" } 102 | 103 | "ui.selection" = { bg = "base0175" } 104 | "ui.selection.primary" = { bg = "base015" } 105 | 106 | "ui.virtual.indent-guide" = { fg = "base02" } 107 | "ui.virtual.ruler" = { bg = "base02" } 108 | 109 | # normal模式的光标 110 | # normal mode cursor 111 | "ui.cursor" = {fg = "base02", bg = "cyan"} 112 | "ui.cursor.insert" = {fg = "base03", bg = "base3"} 113 | # 当前光标匹配的标点符号 114 | # The punctuation character matched by the current cursor 115 | "ui.cursor.match" = { fg = "base02", bg = "base015" } 116 | 117 | "warning" = { fg = "orange", modifiers= ["bold", "underlined"] } 118 | "error" = { fg = "red", modifiers= ["bold", "underlined"] } 119 | "info" = { fg = "blue", modifiers= ["bold", "underlined"] } 120 | "hint" = { fg = "base01", modifiers= ["bold", "underlined"] } 121 | 122 | "diagnostic.warning" = { underline = { style = "curl", color = "orange" } } 123 | "diagnostic.error" = { underline = { style = "curl", color = "red" } } 124 | "diagnostic.info" = { underline = { style = "curl", color = "blue" } } 125 | "diagnostic.hint" = { underline = { style = "curl", color = "base01" } } 126 | "diagnostic.unnecessary" = { modifiers = ["dim"] } 127 | "diagnostic.deprecated" = { modifiers = ["crossed_out"] } 128 | 129 | 130 | [palette] 131 | red = '#dc322f' 132 | green = '#859900' 133 | yellow = '#b58900' 134 | blue = '#268bd2' 135 | magenta = '#d33682' 136 | cyan = '#2aa198' 137 | orange = '#cb4b16' 138 | violet = '#6c71c4' 139 | 140 | # 深色 越来越深 141 | # dark getting darker 142 | base0 = '#657b83' 143 | base1 = '#586e75' 144 | base2 = '#073642' 145 | base3 = '#002b36' 146 | 147 | # 浅色 越來越浅 148 | # Lighter and lighter 149 | base00 = '#839496' 150 | base01 = '#93a1a1' 151 | base015 = '#c5c8bd' 152 | base0175 = '#dddbcc' 153 | base02 = '#eee8d5' 154 | base025 = '#f5eedb' 155 | base03 = '#fdf6e3' 156 | -------------------------------------------------------------------------------- /install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # shellcheck disable=SC1090,SC1091,SC2155 3 | 4 | set -o errexit 5 | 6 | EXTRA_VARS="" 7 | HOMEBREW_INSTALL_SCRIPT="https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh" 8 | SYSTEM_HOSTNAME="$(uname -n | sed 's|.local||g')" 9 | SYSTEM_TYPE="$(uname -s)" 10 | PATH="/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/local/bin:${PATH}"; export PATH 11 | 12 | usage() { 13 | echo "install: system and Ansible bootstrap script" 14 | echo 15 | echo "USAGE: sh install [OPTIONS]" 16 | echo 17 | echo "OPTIONS:" 18 | echo " -h Show help and exit" 19 | echo " -r Resume an interrupted Ansible run" 20 | echo " -w Skip Homebrew install on Linux (noop for macOS)" 21 | echo 22 | } 23 | 24 | 25 | # ------------------------------------- 26 | # Bootstrap functions 27 | # ------------------------------------- 28 | 29 | install_homebrew() { 30 | case "$ID" in 31 | fedora) sudo dnf install -y procps-ng file @development-tools python3-libdnf5 ;; 32 | debian|ubuntu|linuxmint) sudo apt-get install -y build-essential procps file ;; 33 | macos) sudo softwareupdate --install-rosetta ;; 34 | esac 35 | NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL $HOMEBREW_INSTALL_SCRIPT)" 36 | } 37 | 38 | 39 | bootstrap_mac() { 40 | pgrep caffeinate >/dev/null || (caffeinate -d -i -m -u &) 41 | sudo scutil --set HostName "$SYSTEM_HOSTNAME" 42 | ID=macos install_homebrew 43 | brew install python3 44 | } 45 | 46 | 47 | bootstrap_linux() { 48 | if sudo systemctl is-active packagekit.service --quiet; then 49 | sudo systemctl stop packagekit 50 | fi 51 | 52 | sudo hostnamectl set-hostname "$SYSTEM_HOSTNAME" 53 | . /etc/os-release 54 | 55 | case "$ID" in 56 | fedora) 57 | sudo dnf clean all 58 | sudo dnf makecache 59 | sudo dnf install -y python3 python3-devel python3-pip python3-wheel gcc 60 | ;; 61 | debian|ubuntu|linuxmint) 62 | sudo apt-get clean 63 | sudo apt-get update 64 | sudo apt-get install -y python3 python3-pip python3-venv lsb-release rsync curl 65 | ;; 66 | *) exit 1 ;; 67 | esac 68 | 69 | case $(uname -m) in (aarch*|arm*) 70 | SKIP_HOMEBREW_LINUX=1 ;; # https://github.com/Homebrew/brew/issues/19208 71 | esac 72 | 73 | if [ -z "$SKIP_HOMEBREW_LINUX" ]; then 74 | install_homebrew 75 | fi 76 | } 77 | 78 | 79 | # ------------------------------------- 80 | # Main functions 81 | # ------------------------------------- 82 | 83 | main_setup_venv() { 84 | export PATH="$(python3 -m site --user-base)/bin:${PATH}" 85 | export ANSIBLE_PYTHON_INTERPRETER="venv/bin/python3" 86 | export ANSIBLE_HOME="${HOME}/.config/ansible" 87 | 88 | git pull 89 | 90 | if [ ! -d venv ]; then 91 | python3 -m venv venv --system-site-packages # required for selinux libs on Fedora 92 | fi 93 | 94 | . venv/bin/activate 95 | pip install --no-cache-dir --requirement requirements.txt 96 | } 97 | 98 | 99 | main_build_host_vars() { 100 | HOST_VARS="host_vars/${SYSTEM_HOSTNAME}.yml" 101 | 102 | if [ ! -s "$HOST_VARS" ]; then 103 | ansible-playbook play_bootstrap_ansible.yml 104 | # reminder: these grep flags are BSD-compatible 105 | grep "^(#|-|$)" roles/*/defaults/main.yml \ 106 | --invert-match \ 107 | --no-filename \ 108 | --extended-regexp \ 109 | --color=never \ 110 | | sed "s/^/# /g" >> "${HOST_VARS}" 111 | vi "$HOST_VARS" 112 | fi 113 | } 114 | 115 | 116 | main_initialize_onepassword() { 117 | if op account list >/dev/null 2>&1; then 118 | # 1Password is installed and callable but the cli needs to re-auth 119 | # due to the session token having a 30min TTL 120 | if [ -z "$XDG_CURRENT_DESKTOP" ] && [ "$SYSTEM_TYPE" = "Linux" ]; then 121 | op signin --session "$(op signin --raw)" > "${HOME}/.op_session" 122 | fi 123 | else 124 | # setting extra-vars bypasses vars_prompt in the playbook which are 125 | # not used when enabling the 1Password CLI integration from the GUI 126 | if [ -n "$XDG_CURRENT_DESKTOP" ] || [ "$SYSTEM_TYPE" = "Darwin" ]; then 127 | EXTRA_VARS="${EXTRA_VARS} onepassword_signin_url=''" 128 | EXTRA_VARS="${EXTRA_VARS} onepassword_email_address=''" 129 | EXTRA_VARS="${EXTRA_VARS} onepassword_secret_key=''" 130 | EXTRA_VARS="${EXTRA_VARS} onepassword_account_password=''" 131 | fi 132 | ansible-playbook play_init_onepassword.yml --ask-become-pass --extra-vars "$EXTRA_VARS" 133 | fi 134 | } 135 | 136 | 137 | main_play_all_roles() { 138 | . "${HOME}/.op_session" 139 | rm -f "${HOME}/.op_session" 140 | ansible-playbook play_all_roles.yml --ask-become-pass --tags "all,never" 141 | } 142 | 143 | 144 | # ------------------------------------- 145 | # Main script 146 | # ------------------------------------- 147 | 148 | while getopts "hrw" opt; do 149 | case "$opt" in 150 | h) usage; exit 0 ;; 151 | r) SKIP_BOOTSTRAP=1 ;; 152 | w) SKIP_HOMEBREW_LINUX=1 ;; 153 | *) usage; exit 1 ;; 154 | esac 155 | done 156 | 157 | if [ -z "$SKIP_BOOTSTRAP" ]; then 158 | printf "Enter hostname [%s]: " "$SYSTEM_HOSTNAME" 159 | read -r read_system_hostname 160 | SYSTEM_HOSTNAME="${read_system_hostname:-${SYSTEM_HOSTNAME}}" 161 | 162 | case $SYSTEM_TYPE in 163 | Darwin) bootstrap_mac ;; 164 | Linux) bootstrap_linux ;; 165 | *) exit 1 ;; 166 | esac 167 | fi 168 | 169 | if [ ! -e "${HOME}/.config/ansible" ]; then 170 | mkdir "${HOME}/.config/ansible" 171 | fi 172 | 173 | main_setup_venv 174 | main_build_host_vars 175 | main_initialize_onepassword 176 | main_play_all_roles 177 | -------------------------------------------------------------------------------- /roles/zsh/files/rc.d/prompt.zsh: -------------------------------------------------------------------------------- 1 | precmd() { 2 | local _rc=$? prompt_color 3 | local -a prompt_order 4 | local -A prompt_segments git_info 5 | local -r reset="%b%f%k" \ 6 | bold="%B" \ 7 | fg_red="%F{1}" \ 8 | fg_green="%F{2}" \ 9 | fg_yellow="%F{3}" \ 10 | fg_blue="%F{4}" \ 11 | fg_magenta="%F{5}" \ 12 | fg_cyan="%F{6}" \ 13 | fg_white="%F{7}" \ 14 | fg_base03="%F{8}" \ 15 | fg_orange="%F{9}" \ 16 | fg_base01="%F{10}" \ 17 | fg_violet="%F{13}" \ 18 | bg_white="%K{7}" 19 | local -r segment_left="${fg_white}${reset}${bg_white}" \ 20 | segment_right="${reset}${fg_white}${reset}" 21 | 22 | prompt_order=( 23 | newline 24 | lbrak 25 | host 26 | venv 27 | cwd 28 | git_branch 29 | git_status 30 | git_stash 31 | git_action 32 | rbrak 33 | newline 34 | prompt 35 | ) 36 | 37 | prompt_segments=( 38 | [lbrak]="${bold}${fg_base03}[${reset}" 39 | [host]="" 40 | [venv]="" 41 | [cwd]="" 42 | [git_branch]="" 43 | [git_status]="" 44 | [git_stash]="" 45 | [git_action]="" 46 | [rbrak]="${bold}${fg_base03}]${reset}" 47 | [newline]=$'\n' 48 | [prompt]="" 49 | ) 50 | 51 | vcs_info 52 | 53 | if [[ -z $TMUX ]]; then 54 | prompt_segments[host]="${segment_left}${fg_magenta}%m${segment_right} " 55 | fi 56 | 57 | if [[ -n $VIRTUAL_ENV ]]; then 58 | prompt_segments[venv]+="${segment_left}" 59 | prompt_segments[venv]+="${fg_cyan}$(python --version | grep -Po '\d+\.\d+')" 60 | prompt_segments[venv]+="${segment_right} " 61 | fi 62 | 63 | if [[ -z $vcs_info_msg_0_ ]]; then 64 | prompt_segments[cwd]="${segment_left}${fg_blue}%1~${segment_right}" 65 | else 66 | while IFS='=' read -r key value; do 67 | git_info[$key]=$value 68 | done <<< $vcs_info_msg_0_ 69 | 70 | # 71 | # cwd 72 | # 73 | # If the repo name matches the repo branch, this is a worktree; use the directory above the 74 | # git root directory as the project name. Otherwise it's not a worktree, so use the git root 75 | # directory as the project name. 76 | # 77 | if [[ "${git_info[repo]}" == "${git_info[branch]}" ]]; then 78 | prompt_segments[cwd]+="${segment_left}" 79 | prompt_segments[cwd]+="${fg_violet}${"$(git rev-parse --show-toplevel)":h:t}${reset}" 80 | prompt_segments[cwd]+="${segment_right}" 81 | else 82 | prompt_segments[cwd]+="${segment_left}" 83 | prompt_segments[cwd]+="${fg_violet}${"$(git rev-parse --show-toplevel)":t}${reset}" 84 | prompt_segments[cwd]+="${segment_right}" 85 | fi 86 | 87 | # 88 | # git_branch 89 | # 90 | # If the CWD is at least one directory below the repository root (i.e. not in the root 91 | # itself), break the PWD into an array, and reassemble it using just the first character 92 | # of each directory (i.e. Fish style). 93 | # 94 | prompt_segments[git_branch]+=" " 95 | prompt_segments[git_branch]+="${segment_left}" 96 | prompt_segments[git_branch]+="${fg_green}${git_info[branch]}" 97 | 98 | if [[ "${git_info[subdir]}" != "." ]]; then 99 | local i subdirs numdirs subpath="" 100 | subdirs=( ${(@s:/:)git_info[subdir]} ) 101 | numdirs=$(( ${#subdirs} - 1 )) # compensate for the leading slash 102 | if [[ $numdirs -ge 1 ]]; then 103 | for i in {1..${numdirs}}; do 104 | subpath+="/${subdirs[i][1]}" 105 | done 106 | fi 107 | prompt_segments[git_branch]+="${fg_base01}${subpath}/${subdirs[-1]}" 108 | fi 109 | 110 | prompt_segments[git_branch]+="${segment_right}" 111 | 112 | # 113 | # git_status 114 | # 115 | if [[ -n ${git_info[staged]} || -n ${git_info[unstaged]} ]]; then 116 | prompt_segments[git_status]+=" " 117 | prompt_segments[git_status]+="${segment_left}" 118 | prompt_segments[git_status]+="${fg_yellow}${git_info[staged]}" 119 | prompt_segments[git_status]+="${fg_yellow}${git_info[unstaged]}" 120 | prompt_segments[git_status]+="${segment_right}" 121 | fi 122 | 123 | # 124 | # git_stash 125 | # 126 | git_info[stash_count]="$(git rev-list --walk-reflogs --ignore-missing --count refs/stash)" 127 | if (( git_info[stash_count] > 0 )); then 128 | prompt_segments[git_stash]+=" " 129 | prompt_segments[git_stash]+="${segment_left}" 130 | prompt_segments[git_stash]+="${fg_yellow}\$^${git_info[stash_count]}" 131 | prompt_segments[git_stash]+="${segment_right}" 132 | fi 133 | 134 | # 135 | # git_action 136 | # 137 | if [[ -n ${git_info[action]} ]]; then 138 | prompt_segments[git_action]+=" " 139 | prompt_segments[git_action]+="${segment_left}" 140 | prompt_segments[git_action]+="${fg_red}${git_info[action]:u}" 141 | prompt_segments[git_action]+="${segment_right}" 142 | fi 143 | fi 144 | 145 | case "$_rc" in 146 | 0) prompt_color="${fg_green}" ;; 147 | 1) prompt_color="${fg_red}" ;; 148 | *) prompt_color="${fg_magenta}" ;; 149 | esac 150 | 151 | prompt_segments[prompt]=" 󱞪 ${bold}${prompt_color}[${_rc}]%#${reset} " 152 | 153 | PROMPT="" 154 | for segment in "${prompt_order[@]}"; do 155 | PROMPT+="${prompt_segments[${segment}]}" 156 | done 157 | } 158 | 159 | zstyle ':vcs_info:*' enable git 160 | zstyle ':vcs_info:git*' check-for-changes true 161 | zstyle ':vcs_info:git*' formats \ 162 | $'branch=%b\nrepo=%r\nsubdir=%S\nstaged=%c\nunstaged=%u' 163 | zstyle ':vcs_info:git*' actionformats \ 164 | $'branch=%b\nrepo=%r\nsubdir=%S\nstaged=%c\nunstaged=%u\naction=%a' 165 | -------------------------------------------------------------------------------- /roles/git/files/gitignore: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # Custom 3 | # ----------------------------------------------------------------------------- 4 | 5 | .cache 6 | .dccache 7 | ve 8 | venv 9 | 10 | # ============================================================================= 11 | # macOS.gitignore 12 | # ----------------------------------------------------------------------------- 13 | 14 | # General 15 | .DS_Store 16 | .AppleDouble 17 | .LSOverride 18 | 19 | # Icon must end with two \r 20 | Icon 21 | 22 | # Thumbnails 23 | ._* 24 | 25 | # Files that might appear in the root of a volume 26 | .DocumentRevisions-V100 27 | .fseventsd 28 | .Spotlight-V100 29 | .TemporaryItems 30 | .Trashes 31 | .VolumeIcon.icns 32 | .com.apple.timemachine.donotpresent 33 | 34 | # Directories potentially created on remote AFP share 35 | .AppleDB 36 | .AppleDesktop 37 | Network Trash Folder 38 | Temporary Items 39 | .apdisk 40 | 41 | 42 | # ============================================================================= 43 | # Linux.gitignore 44 | # ----------------------------------------------------------------------------- 45 | 46 | *~ 47 | 48 | # temporary files which can be created if a process still has a handle open of a deleted file 49 | .fuse_hidden* 50 | 51 | # KDE directory preferences 52 | .directory 53 | 54 | # Linux trash folder which might appear on any partition or disk 55 | .Trash-* 56 | 57 | # .nfs files are created when an open file is removed but is still being accessed 58 | .nfs* 59 | 60 | 61 | # ============================================================================= 62 | # VirtualEnv.gitignore 63 | # ----------------------------------------------------------------------------- 64 | 65 | .Python 66 | pyvenv.cfg 67 | .venv 68 | pip-selfcheck.json 69 | 70 | 71 | # ============================================================================= 72 | # Python.gitignore 73 | # ----------------------------------------------------------------------------- 74 | 75 | # Byte-compiled / optimized / DLL files 76 | __pycache__/ 77 | *.py[cod] 78 | *$py.class 79 | 80 | # C extensions 81 | *.so 82 | 83 | # Distribution / packaging 84 | .Python 85 | build/ 86 | develop-eggs/ 87 | dist/ 88 | downloads/ 89 | eggs/ 90 | .eggs/ 91 | lib/ 92 | lib64/ 93 | parts/ 94 | sdist/ 95 | var/ 96 | wheels/ 97 | share/python-wheels/ 98 | *.egg-info/ 99 | .installed.cfg 100 | *.egg 101 | MANIFEST 102 | 103 | # PyInstaller 104 | # Usually these files are written by a python script from a template 105 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 106 | *.manifest 107 | *.spec 108 | 109 | # Installer logs 110 | pip-log.txt 111 | pip-delete-this-directory.txt 112 | 113 | # Unit test / coverage reports 114 | htmlcov/ 115 | .tox/ 116 | .nox/ 117 | .coverage 118 | .coverage.* 119 | .cache 120 | nosetests.xml 121 | coverage.xml 122 | *.cover 123 | *.py,cover 124 | .hypothesis/ 125 | .pytest_cache/ 126 | cover/ 127 | 128 | # Translations 129 | *.mo 130 | *.pot 131 | 132 | # Django stuff: 133 | *.log 134 | local_settings.py 135 | db.sqlite3 136 | db.sqlite3-journal 137 | 138 | # Flask stuff: 139 | instance/ 140 | .webassets-cache 141 | 142 | # Scrapy stuff: 143 | .scrapy 144 | 145 | # Sphinx documentation 146 | docs/_build/ 147 | 148 | # PyBuilder 149 | .pybuilder/ 150 | target/ 151 | 152 | # Jupyter Notebook 153 | .ipynb_checkpoints 154 | 155 | # IPython 156 | profile_default/ 157 | ipython_config.py 158 | 159 | # pyenv 160 | # For a library or package, you might want to ignore these files since the code is 161 | # intended to run in multiple environments; otherwise, check them in: 162 | # .python-version 163 | 164 | # pipenv 165 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 166 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 167 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 168 | # install all needed dependencies. 169 | #Pipfile.lock 170 | 171 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 172 | __pypackages__/ 173 | 174 | # Celery stuff 175 | celerybeat-schedule 176 | celerybeat.pid 177 | 178 | # SageMath parsed files 179 | *.sage.py 180 | 181 | # Environments 182 | .env 183 | .venv 184 | env/ 185 | venv/ 186 | ENV/ 187 | env.bak/ 188 | venv.bak/ 189 | 190 | # Spyder project settings 191 | .spyderproject 192 | .spyproject 193 | 194 | # Rope project settings 195 | .ropeproject 196 | 197 | # mkdocs documentation 198 | /site 199 | 200 | # mypy 201 | .mypy_cache/ 202 | .dmypy.json 203 | dmypy.json 204 | 205 | # Pyre type checker 206 | .pyre/ 207 | 208 | # pytype static type analyzer 209 | .pytype/ 210 | 211 | # Cython debug symbols 212 | cython_debug/ 213 | 214 | 215 | # ============================================================================= 216 | # Vim.gitignore 217 | # ----------------------------------------------------------------------------- 218 | 219 | # Swap 220 | [._]*.s[a-v][a-z] 221 | !*.svg # comment out if you don't need vector files 222 | [._]*.sw[a-p] 223 | [._]s[a-rt-v][a-z] 224 | [._]ss[a-gi-z] 225 | [._]sw[a-p] 226 | 227 | # Session 228 | Session.vim 229 | Sessionx.vim 230 | 231 | # Temporary 232 | .netrwhist 233 | *~ 234 | # Auto-generated tag files 235 | tags 236 | # Persistent undo 237 | [._]*.un~ 238 | 239 | 240 | # ============================================================================= 241 | # VisualStudioCode.gitignore 242 | # ----------------------------------------------------------------------------- 243 | 244 | .vscode* 245 | *.code-workspace 246 | 247 | # Local History for Visual Studio Code 248 | .history/ 249 | 250 | 251 | # ============================================================================= 252 | # Ansible.gitignore 253 | # ----------------------------------------------------------------------------- 254 | 255 | *.retry 256 | 257 | 258 | # ============================================================================= 259 | # Backup.gitignore 260 | # ----------------------------------------------------------------------------- 261 | 262 | *.bak 263 | *.gho 264 | *.ori 265 | *.orig 266 | *.tmp 267 | 268 | 269 | # ============================================================================= 270 | # Vagrant.gitignore 271 | # ----------------------------------------------------------------------------- 272 | 273 | # General 274 | .vagrant/ 275 | 276 | # Log files (if you are creating logs in debug mode, uncomment this) 277 | # *.log 278 | --------------------------------------------------------------------------------