├── .gitignore ├── .gitmodules ├── README.md ├── home ├── .bashrc ├── .common.sh ├── .config │ ├── autostart │ │ ├── keyboard-repeat.desktop │ │ └── pyupdatesd.desktop │ ├── fish │ │ ├── config.fish │ │ ├── functions │ │ │ ├── grep.fish │ │ │ ├── ll.fish │ │ │ ├── ls.fish │ │ │ ├── ping.fish │ │ │ ├── refish.fish │ │ │ ├── socks.fish │ │ │ ├── title.fish │ │ │ └── vi.fish │ │ └── virtual.fish │ ├── pulse │ │ └── daemon.conf │ └── sublime-text-3 │ │ └── Installed Packages │ │ ├── Better CoffeeScript.sublime-package │ │ └── Package Control.sublime-package ├── .editorconfig ├── .gitconfig ├── .ssh │ └── config ├── .tmux.conf ├── .vim │ └── syntax │ │ └── nginx.vim ├── .vimrc ├── .zshrc └── bin │ ├── REST │ ├── SimpleHTTPServer │ ├── backup-check │ ├── datename │ ├── dbvault │ ├── dfm │ ├── docker-enter │ ├── fedora-setup │ ├── flatten-linked │ ├── flv2avi │ ├── git-branch-check │ ├── gosh │ ├── grkill │ ├── gsync │ ├── gu │ ├── h264ify │ ├── id-codec │ ├── id3set │ ├── ipwatch │ ├── json-pretty │ ├── keyboard-repeat │ ├── ksplit │ ├── kupdatesd │ ├── luksvault │ ├── make-it-rain │ ├── mb-brightness │ ├── mednafen-zenity │ ├── metacity-test │ ├── mp3rename │ ├── nextcloud-dav │ ├── onetime │ ├── podwrap │ ├── pyupdatesd │ ├── pywhich │ ├── renew-certs.py │ ├── rmbackup │ ├── rre │ ├── sayto │ ├── script.go │ ├── stall │ ├── sync-pics │ ├── to-photoblog │ ├── udptoss │ ├── video2gif │ └── window-notify ├── make-submodules.py ├── misc ├── .gtkrc-2.0 ├── cron │ ├── crontab.caskir │ ├── mc-backup.py │ └── mcclient.py ├── kioskrc └── powertop.service └── setup /.gitignore: -------------------------------------------------------------------------------- 1 | backup/ 2 | .last-updated 3 | __pycache__ 4 | *.pyc 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "home/.vim/bundle/Vundle.vim"] 2 | path = home/.vim/bundle/Vundle.vim 3 | url = https://github.com/gmarik/Vundle.vim 4 | [submodule "home/.vim/bundle/nerdtree"] 5 | path = home/.vim/bundle/nerdtree 6 | url = https://github.com/scrooloose/nerdtree 7 | [submodule "home/.vim/bundle/vim-nerdtree-tabs"] 8 | path = home/.vim/bundle/vim-nerdtree-tabs 9 | url = https://github.com/jistr/vim-nerdtree-tabs 10 | [submodule "home/.vim/bundle/vim-airline"] 11 | path = home/.vim/bundle/vim-airline 12 | url = https://github.com/bling/vim-airline 13 | [submodule "home/.vim/bundle/tagbar"] 14 | path = home/.vim/bundle/tagbar 15 | url = https://github.com/majutsushi/tagbar 16 | [submodule "home/.vim/bundle/molokai"] 17 | path = home/.vim/bundle/molokai 18 | url = https://github.com/tomasr/molokai 19 | [submodule "home/.vim/bundle/ctrlp.vim"] 20 | path = home/.vim/bundle/ctrlp.vim 21 | url = https://github.com/kien/ctrlp.vim 22 | [submodule "home/.vim/bundle/vim-coffee-script"] 23 | path = home/.vim/bundle/vim-coffee-script 24 | url = https://github.com/kchmck/vim-coffee-script 25 | [submodule "home/.vim/bundle/vim-markdown"] 26 | path = home/.vim/bundle/vim-markdown 27 | url = https://github.com/tpope/vim-markdown 28 | [submodule "home/.vim/bundle/editorconfig-vim"] 29 | path = home/.vim/bundle/editorconfig-vim 30 | url = https://github.com/editorconfig/editorconfig-vim 31 | [submodule "zsh/zgen"] 32 | path = zsh/zgen 33 | url = https://github.com/tarjoilija/zgen 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kirsle's Dotfiles 2 | 3 | This repo is for my own personal use for syncing my Unix config files and 4 | scripts between my various devices. Feel free to look around and learn from 5 | my config scripts. 6 | 7 | # Setup 8 | 9 | ```bash 10 | ~$ git clone git@github.com:kirsle/.dotfiles 11 | ~$ ./.dotfiles/setup 12 | ``` 13 | 14 | # Dotfiles Manager (dfm) 15 | 16 | The dotfiles repo is managed by a `dfm` command, which gets installed into 17 | `~/bin` automatically. (The `.dotfiles/setup` script is just an easy alias 18 | to this command). 19 | 20 | See `dfm --help` for documentation. Briefly: 21 | 22 | * `dfm setup` creates symlinks to all the files in `./home` into `$HOME`. 23 | * `dfm update` does a `git pull` and installs any new dotfiles. 24 | * `dfm check-update` reminds you every 15 days to run `dfm update` (but 25 | doesn't remind you more than once per 24 hours). 26 | 27 | In case one of the target files already exists (and is not a symlink), it is 28 | copied into `.dotfiles/backup` before being deleted and relinked. 29 | 30 | The commands take optional arguments: 31 | 32 | * `dfm setup --force`: forcefully re-link all dotfiles, deleting any links 33 | that already exist. 34 | * `dfm setup --copy`: tell it not to use symlinks but instead make normal 35 | file copies into `$HOME`. 36 | * `dfm check-update --force`: always show the update reminder. 37 | 38 | The `.dotfiles/setup` script passes all options along to `dfm`, so you can 39 | do `.dotfiles/setup --copy` for example. 40 | 41 | # Layout 42 | 43 | * `./setup` 44 | 45 | Installation script for the dotfiles. Creates symlinks for everything in 46 | `./home` into `$HOME`. 47 | 48 | This will **not** delete existing files, such as `~/.bashrc`. Use the 49 | `--install` option to make it do so. 50 | 51 | * `./home` 52 | 53 | Everything in this folder will be symlinked to from your `$HOME` folder. 54 | -------------------------------------------------------------------------------- /home/.bashrc: -------------------------------------------------------------------------------- 1 | # .bashrc 2 | 3 | # Kirsle's Global BashRC 4 | # Updated 2018-09-05 5 | 6 | # Source global definitions 7 | if [ -f /etc/bashrc ]; then 8 | . /etc/bashrc 9 | fi 10 | 11 | platform="unknown" 12 | unamestr=`uname` 13 | if [[ "$unamestr" == "Linux" ]]; then 14 | platform="linux" 15 | elif [[ "$unamestr" == "Darwin" ]]; then 16 | platform="darwin" 17 | fi 18 | 19 | # PATH settings. 20 | export PATH="/usr/sbin:/sbin:/usr/bin:/bin:$HOME/bin:$HOME/go/bin:$HOME/go/.ext/bin" 21 | if [[ $platform == "darwin" ]]; then 22 | # Prefer /usr/local/bin because homebrew 23 | export PATH="/usr/local/bin:$PATH" 24 | 25 | # Enable colors and set a similar color scheme as Linux (see `man ls`) 26 | export CLICOLOR=1 27 | export LSCOLORS="ExGxcxdxcxegedabagecec" 28 | else 29 | export PATH="$PATH:/usr/local/bin:/usr/local/sbin" 30 | fi 31 | 32 | # Perlbrew 33 | export PERLBREW_ROOT="/opt/perl5" 34 | if [ -f /opt/perl5/etc/bashrc ]; then 35 | source /opt/perl5/etc/bashrc 36 | fi 37 | 38 | # Virtualenv settings. Prefer Python 3 for new environments. 39 | export WORKON_HOME=~/.virtualenvs 40 | unset VIRTUAL_ENV_DISABLE_PROMPT 41 | command -v python3 >/dev/null 2>&1 && export VIRTUALENV_PYTHON=`command -v python3` 42 | if [ -f /usr/bin/virtualenvwrapper.sh ]; then 43 | source /usr/bin/virtualenvwrapper.sh 44 | elif [ -f /usr/share/virtualenvwrapper/virtualenvwrapper.sh ]; then 45 | source /usr/share/virtualenvwrapper/virtualenvwrapper.sh 46 | fi 47 | 48 | # Go 49 | export GOPATH="$HOME/go/.ext:$HOME/go" 50 | 51 | # Colors! 52 | BLACK='\e[0;30m' 53 | NAVY='\e[0;34m' 54 | GREEN='\e[0;32m' 55 | TEAL='\e[0;36m' 56 | MAROON='\e[0;31m' 57 | PURPLE='\e[0;35m' 58 | BROWN='\e[0;33m' 59 | SILVER='\e[0;37m' 60 | GRAY='\e[30m' 61 | BLUE='\e[34m' 62 | BRIGHTGREEN='\e[32m' 63 | BRIGHTTEAL='\e[36m' 64 | RED='\e[31m' 65 | MAGENTA='\e[35m' 66 | YELLOW='\e[33m' 67 | WHITE='\e[37m' 68 | BOLD='\e[1m' 69 | NC='\e[0m' # No Color 70 | 71 | # Some 256-colors colors 72 | LBLUE="\e[38;5;39m" 73 | PINK="\e[38;5;213m" 74 | LIME="\e[38;5;10m" 75 | CYAN="\e[38;5;14m" 76 | 77 | function showcolors() { 78 | echo -e "$BLACK BLACK $NAVY NAVY $GREEN GREEN $TEAL TEAL" 79 | echo -e "$MAROON MAROON $PURPLE PURPLE $BROWN BROWN $SILVER SILVER" 80 | echo -e "$GRAY GRAY $BLUE BLUE $LIME LIME $CYAN CYAN $RED RED" 81 | echo -e "$MAGENTA MAGENTA $YELLOW YELLOW $WHITE WHITE$NC" 82 | } 83 | 84 | # Normalize the terminal. 85 | ENLIGHTENED=0 86 | if [ "$TERM" = 'xterm' ] || [ "$TERM" = 'xterm-256color' ] || [ "$TERM" = 'linux' ]; then 87 | ENLIGHTENED=1 88 | elif [ "$TERM" = 'screen' ] || [ "$TERM" = 'screen-256color' ]; then 89 | ENLIGHTENED=1 90 | elif [ "$TERM" = 'cygwin' ]; then 91 | ENLIGHTENED=1 92 | fi 93 | 94 | # Custom bash prompt. 95 | git_branch() { 96 | branch=`git branch 2> /dev/null | sed -e '/^[^*]/d' | perl -pe 's/^\*\s+//g'` 97 | if [ "$branch" != '' ]; then 98 | echo -n " ($branch)" 99 | fi 100 | } 101 | if [ "$ENLIGHTENED" = '1' ]; then 102 | export PS1="\[$LBLUE\][\[$PINK\]\u\[$LBLUE\]@\[$PINK\]\h \[$LIME\]\W\[$CYAN\]\$(git_branch)\[$LBLUE\]\[$LBLUE\]]\\$ \[$NC\]" 103 | fi 104 | 105 | # For non-Fedora environments be sure the PROMPT_COMMAND sets the title bar. 106 | export PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"' 107 | 108 | # ___ ____ _ _ ____ ____ __ __ 109 | # / __)( ___)( \( )( ___)( _ \ /__\ ( ) 110 | # ( (_-. )__) ) ( )__) ) / /(__)\ )(__ 111 | # \___/(____)(_)\_)(____)(_)\_)(__)(__)(____) 112 | # -==General Bash Aliases and Functions==- 113 | 114 | alias vi='vim' 115 | 116 | # reload .bashrc 117 | alias rebash='. ~/.bashrc' 118 | 119 | # a DOS-like title command 120 | function title { 121 | PROMPT_COMMAND="echo -en \"\033]0;$1\007\"" 122 | } 123 | 124 | # Custom git command that overrides $PATH settings 125 | function git { 126 | if [ -x "/usr/local/bin/git" ]; then 127 | /usr/local/bin/git $@ 128 | elif [ -x "/opt/git/bin/git" ]; then 129 | /opt/git/bin/git $@ 130 | elif [ -x "/usr/bin/git" ]; then 131 | /usr/bin/git $@ 132 | else 133 | echo "git isn't installed" 134 | fi 135 | } 136 | 137 | # Case-insensitive searching. 138 | shopt -s nocaseglob 139 | 140 | # Save history correctly when using multiple terminals. 141 | # Don't save duplicate lines or blank lines. 142 | export HISTCONTROL="ignoreboth" 143 | export HISTSIZE=1000 144 | shopt -s histappend 145 | 146 | export EDITOR="/usr/bin/vim" 147 | 148 | # Color grepping! Highlight grep expression in red text. 149 | export GREP_COLOR=31 150 | alias grep='grep --exclude=min.js --color=auto' 151 | 152 | # Show proc name with pgrepping. 153 | alias pg='ps aux | grep' 154 | alias pgrep='pgrep -l' 155 | 156 | # Allow ASCII color codes to work in less/more. 157 | alias less='less -r' 158 | alias more='less -r' # less is more 159 | 160 | # ls aliases (Fedora defaults but here for portability) 161 | if [[ $platform == "darwin" ]]; then 162 | alias ll='ls -hl' 163 | else 164 | alias ls='ls --color=auto' 165 | alias ll='ls --color=auto -hl' 166 | fi 167 | 168 | # More aliases! 169 | alias ping='ping -c 10' 170 | 171 | # Shortcuts to graphical programs. 172 | alias firefox='nohup firefox 2>/dev/null' 173 | alias gedit='nohup gedit 2>/dev/null' 174 | 175 | # Lazy cd commands. 176 | alias ...='cd ../..' 177 | alias ..='cd ..' 178 | alias ~='cd ~' 179 | alias cd..='cd ..' 180 | alias cd...='cd ../..' 181 | 182 | # Lazy id commands 183 | alias me='whoami' 184 | alias i='whoami' 185 | 186 | # Typos 187 | alias iv='vi' 188 | 189 | # Make cp and mv ask before replacing an existing file. 190 | alias cp='cp -i' 191 | alias mv='mv -i' 192 | 193 | # 256 Color Terminal! Make sure a .xterm256 file exists in $HOME to enable. 194 | if [ -e ".xterm256" ]; then 195 | [ "$TERM" = 'xterm' ] && TERM=xterm-256color 196 | [ "$TERM" = 'screen' ] && TERM=screen-256color 197 | [ "$TERM" = 'rxvt-unicode' ] && TERM=rxvt-unicode-256color 198 | 199 | if [ ! -z "$TERMCAP" ] && [ "$TERM" = "screen-256color" ]; then 200 | TERMCAP=$(echo $TERMCAP | sed -e 's/Co#8/Co#256/g') 201 | export TERMCAP 202 | fi 203 | fi 204 | 205 | # Source local system-specific config. 206 | if [ -f ~/.localbashrc ]; then 207 | . ~/.localbashrc 208 | fi 209 | 210 | ### 211 | # Import common functions (bash/zsh) 212 | ### 213 | 214 | . ~/.common.sh 215 | . "$HOME/.cargo/env" 216 | -------------------------------------------------------------------------------- /home/.common.sh: -------------------------------------------------------------------------------- 1 | ### 2 | # Common shell functions/aliases between bash and zsh. 3 | ### 4 | 5 | # Notify to update the dotfiles. 6 | dfm check-update 7 | 8 | ################################################################################ 9 | ## Functions 10 | ################################################################################ 11 | 12 | # Poor Man's ngrok. https://www.kirsle.net/blog/entry/poor-mans-ngrok 13 | tunup() { 14 | port=${1:-5000} 15 | echo "Forwarding kirsle.net:5000 to local port $port" 16 | ssh -R 5000:127.0.0.1:$port kirsle 17 | } 18 | 19 | # Recursively traverse directory tree for git repositories, run git command 20 | # e.g. 21 | # rgit status 22 | # rgit diff 23 | # 24 | # Credit: 25 | # http://chr4.org/blog/2014/09/10/gittree-bash-slash-zsh-function-to-run-git-commands-recursively/ 26 | rgit() { 27 | if [ $# -lt 1 ]; then 28 | echo "Usage: rgit " 29 | return 1 30 | fi 31 | 32 | for gitdir in $(find . -type d -name .git); do 33 | # Display repository name in bold orange text. 34 | repo=$(dirname $gitdir) 35 | echo -e "\e[1;38;5;208m$repo\e[0m" 36 | 37 | # Run git command in the repository's directory 38 | cd $repo && git $@ 39 | ret=$? 40 | 41 | # Return to calling directory (ignore output) 42 | cd - >/dev/null 43 | 44 | # Abort if cd or git command fails 45 | if [ $ret -ne 0 ]; then 46 | return 1 47 | fi 48 | 49 | echo 50 | done 51 | } 52 | 53 | # Push and pull my KeePass DB from remote storage. 54 | pw-push() { 55 | rsync -av ~/.config/pwdb/kirsle.kdbx kirsle:/mnt/volume/pwdb/ 56 | } 57 | pw-pull() { 58 | rsync -av kirsle:/mnt/volume/pwdb/kirsle.kdbx ~/.config/pwdb/ 59 | } 60 | 61 | # Generate a random UUID4 string. 62 | uuid4() { 63 | python -c "import uuid; print(str(uuid.uuid4()))" 64 | } 65 | -------------------------------------------------------------------------------- /home/.config/autostart/keyboard-repeat.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Version=0.9.4 4 | Type=Application 5 | Name=keyboard-repeat 6 | Comment=Sets my keyboard repeat setting in GNOME. 7 | Icon=/usr/share/icons/Adwaita/32x32/devices/input-keyboard.png 8 | Exec=keyboard-repeat 9 | OnlyShowIn=GNOME 10 | StartupNotify=false 11 | Terminal=false 12 | Hidden=false 13 | 14 | Name[en_US]=keyboard-repeat 15 | Comment[en_US]=Sets my keyboard repeat setting in GNOME. 16 | -------------------------------------------------------------------------------- /home/.config/autostart/pyupdatesd.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Version=0.9.4 4 | Type=Application 5 | Name=pyupdatesd 6 | Comment=Yum Updates Daemon 7 | Icon=/usr/share/icons/gnome/32x32/status/software-update-available.png 8 | Exec=pyupdatesd 9 | OnlyShowIn=XFCE;MATE; 10 | StartupNotify=false 11 | Terminal=false 12 | Hidden=false 13 | 14 | X-MATE-Autostart-enabled=true 15 | Name[en_US]=pyupdatesd: Yum Updates Daemon 16 | Comment[en_US]=Notifies about available software updates. 17 | -------------------------------------------------------------------------------- /home/.config/fish/config.fish: -------------------------------------------------------------------------------- 1 | # config.fish 2 | 3 | # Kirsle's config.fish 4 | # Updated: 2014-03-03 5 | 6 | function fish_greeting 7 | echo -s (set_color FF9900) "-== " (fish --version ^&1) " ==-" (set_color normal) 8 | echo -s (set_color FFFF00) " Date: " (set_color FFFFFF) (date) (set_color normal) 9 | echo -s (set_color FFFF00) "Uptime: " (set_color FFFFFF) (uptime) (set_color normal) 10 | end 11 | 12 | # Normalize the $PATH. 13 | set -gx PATH /usr/sbin /sbin /usr/bin /bin /usr/local/sbin /usr/local/bin $HOME/bin $HOME/go/bin $HOME/android/sdk/platform-tools 14 | 15 | set -gx EDITOR /usr/bin/vim 16 | 17 | # 256 colors 18 | if test $TERM = "xterm" 19 | set -x TERM "xterm-256color" 20 | end 21 | 22 | # VirtualEnv 23 | set -g VIRTUALFISH_HOME $HOME/.virtualenvs 24 | set -g VIRTUALFISH_COMPAT_ALIASES 25 | . ~/.config/fish/virtual.fish 26 | 27 | # Git repo branches 28 | function git_branch 29 | git branch 2>/dev/null | grep -v '^[^*]' | perl -pe 's/^\*\s+//g' 30 | end 31 | 32 | # Shell prompt 33 | function base_prompt 34 | # VirtualEnv prefix 35 | if set -q VIRTUAL_ENV 36 | echo -n -s (set_color FF9900) "(" (basename "$VIRTUAL_ENV") ")" (set_color normal) 37 | end 38 | 39 | set_color --bold 0099FF 40 | echo -n "[" 41 | set_color FF99FF 42 | echo -n (whoami) 43 | set_color 0099FF 44 | echo -n "@" 45 | set_color FF99FF 46 | echo -n (hostname) 47 | echo -n " " 48 | set_color 00FF00 49 | echo -n (prompt_pwd) 50 | 51 | # git branch 52 | set branch (git_branch) 53 | if test -n "$branch" 54 | set_color 00FFFF 55 | echo -n " ($branch)" 56 | end 57 | 58 | set_color 0099FF 59 | echo -n "]\$ " 60 | set_color normal 61 | end 62 | function fish_prompt 63 | echo -n (base_prompt) 64 | end 65 | 66 | # Title bar 67 | function fish_title 68 | if set -q FISH_CUSTOM_TITLE 69 | echo -n $FISH_CUSTOM_TITLE 70 | else 71 | echo -n -s (whoami) "@" (hostname) ":" (prompt_pwd) 72 | end 73 | end 74 | 75 | # `sudo !!` compat for fish shell 76 | function sudo 77 | if test "$argv" = !! 78 | eval command sudo $history[1] 79 | else 80 | command sudo $argv 81 | end 82 | end 83 | 84 | # Source local system-specific config. 85 | if test -e ~/.local.fish 86 | . ~/.local.fish 87 | end 88 | 89 | -------------------------------------------------------------------------------- /home/.config/fish/functions/grep.fish: -------------------------------------------------------------------------------- 1 | # Color grepping! 2 | set -gx GREP_COLOR 31 3 | function grep 4 | /bin/grep --exclude=min.js --color=auto $argv 5 | end 6 | 7 | -------------------------------------------------------------------------------- /home/.config/fish/functions/ll.fish: -------------------------------------------------------------------------------- 1 | # ls aliases. Fedora defaults, but here for compatibility 2 | function ll 3 | /bin/ls -hl --color=auto $argv 4 | end 5 | -------------------------------------------------------------------------------- /home/.config/fish/functions/ls.fish: -------------------------------------------------------------------------------- 1 | # ls aliases. Fedora defaults, but here for compatibility 2 | function ls 3 | /bin/ls --color=auto $argv 4 | end 5 | 6 | -------------------------------------------------------------------------------- /home/.config/fish/functions/ping.fish: -------------------------------------------------------------------------------- 1 | function ping 2 | /bin/ping -c 10 $argv 3 | end 4 | -------------------------------------------------------------------------------- /home/.config/fish/functions/refish.fish: -------------------------------------------------------------------------------- 1 | # refish = reload the fish config 2 | function refish 3 | . ~/.config/fish/config.fish 4 | end 5 | -------------------------------------------------------------------------------- /home/.config/fish/functions/socks.fish: -------------------------------------------------------------------------------- 1 | # socks tunnel in background 2 | function socks 3 | /usr/bin/ssh -f -N -D 8080 kirsle@kirsle.net 4 | end 5 | -------------------------------------------------------------------------------- /home/.config/fish/functions/title.fish: -------------------------------------------------------------------------------- 1 | # A DOS-like title command 2 | function title 3 | set -gx FISH_CUSTOM_TITLE "$argv" 4 | end 5 | -------------------------------------------------------------------------------- /home/.config/fish/functions/vi.fish: -------------------------------------------------------------------------------- 1 | # Use vim when I type vi 2 | function vi 3 | /usr/bin/vim $argv 4 | end 5 | 6 | -------------------------------------------------------------------------------- /home/.config/fish/virtual.fish: -------------------------------------------------------------------------------- 1 | # VirtualFish 2 | # A Virtualenv wrapper for the Fish Shell based on Doug Hellman's virtualenvwrapper 3 | 4 | if not set -q VIRTUALFISH_HOME 5 | set -g VIRTUALFISH_HOME $HOME/.virtualenvs 6 | end 7 | 8 | if set -q VIRTUALFISH_COMPAT_ALIASES 9 | function workon 10 | if not set -q argv[1] 11 | vf ls 12 | else 13 | vf activate $argv[1] 14 | end 15 | end 16 | function deactivate 17 | vf deactivate 18 | end 19 | function mktmpenv 20 | vf tmp $argv 21 | end 22 | function mkvirtualenv 23 | # Check if the first argument is an option to virtualenv 24 | # if it is then the the last argument must be the DEST_DIR. 25 | set -l idx 1 26 | switch $argv[1] 27 | case '-*' 28 | set idx -1 29 | end 30 | 31 | # Extract the DEST_DIR and remove it from $argv 32 | set -l env_name $argv[$idx] 33 | set -e argv[$idx] 34 | 35 | vf new $argv $env_name 36 | end 37 | function rmvirtualenv 38 | vf rm $argv 39 | end 40 | function add2virtualenv 41 | __vf_addpath $argv 42 | end 43 | function cdvirtualenv 44 | vf cd $argv 45 | end 46 | function cdsitepackages 47 | vf cdpackages $argv 48 | end 49 | end 50 | 51 | function vf --description "VirtualFish: fish plugin to manage virtualenvs" 52 | # copy all but the first argument to $scargs 53 | set -l sc $argv[1] 54 | set -l funcname "__vf_$sc" 55 | set -l scargs 56 | 57 | if test (count $argv) -gt 1 58 | set scargs $argv[2..-1] 59 | end 60 | 61 | if functions -q $funcname 62 | eval $funcname $scargs 63 | else 64 | echo "The subcommand $sc is not defined" 65 | end 66 | end 67 | 68 | function __vf_activate --description "Activate a virtualenv" 69 | # check arguments 70 | if [ (count $argv) -lt 1 ] 71 | echo "You need to specify a virtualenv." 72 | return 1 73 | end 74 | if not [ -d $VIRTUALFISH_HOME/$argv[1] ] 75 | echo "The virtualenv $argv[1] does not exist." 76 | echo "You can create it with mkvirtualenv." 77 | return 2 78 | end 79 | 80 | #Check if a different env is being used 81 | if set -q VIRTUAL_ENV 82 | vf deactivate 83 | end 84 | 85 | emit virtualenv_will_activate 86 | emit virtualenv_will_activate:$argv[1] 87 | 88 | set -gx VIRTUAL_ENV $VIRTUALFISH_HOME/$argv[1] 89 | set -g _VF_EXTRA_PATH $VIRTUAL_ENV/bin 90 | set -gx PATH $_VF_EXTRA_PATH $PATH 91 | 92 | # hide PYTHONHOME 93 | if set -q PYTHONHOME 94 | set -g _VF_OLD_PYTHONHOME $PYTHONHOME 95 | set -e PYTHONHOME 96 | end 97 | 98 | emit virtualenv_did_activate 99 | emit virtualenv_did_activate:(basename $VIRTUAL_ENV) 100 | end 101 | 102 | function __vf_deactivate --description "Deactivate the currently-activated virtualenv" 103 | 104 | emit virtualenv_will_deactivate 105 | emit virtualenv_will_deactivate:(basename $VIRTUAL_ENV) 106 | 107 | # find elements to remove from PATH 108 | set to_remove 109 | for i in (seq (count $PATH)) 110 | if contains $PATH[$i] $_VF_EXTRA_PATH 111 | set to_remove $to_remove $i 112 | end 113 | end 114 | 115 | # remove them 116 | for i in $to_remove 117 | set -e PATH[$i] 118 | end 119 | 120 | # restore PYTHONHOME 121 | if set -q _VF_OLD_PYTHONHOME 122 | set -gx PYTHONHOME $_VF_OLD_PYTHONHOME 123 | set -e _VF_OLD_PYTHONHOME 124 | end 125 | 126 | emit virtualenv_did_deactivate 127 | emit virtualenv_did_deactivate:(basename $VIRTUAL_ENV) 128 | 129 | set -e VIRTUAL_ENV 130 | end 131 | 132 | function __vf_new --description "Create a new virtualenv" 133 | emit virtualenv_will_create 134 | set envname $argv[-1] 135 | set -e argv[-1] 136 | virtualenv $argv $VIRTUALFISH_HOME/$envname 137 | set vestatus $status 138 | if begin; [ $vestatus -eq 0 ]; and [ -d $VIRTUALFISH_HOME/$envname ]; end 139 | vf activate $envname 140 | emit virtualenv_did_create 141 | emit virtualenv_did_create:(basename $VIRTUAL_ENV) 142 | else 143 | echo "Error: The virtualenv wasn't created properly." 144 | echo "virtualenv returned status $vestatus." 145 | return 1 146 | end 147 | end 148 | 149 | function __vf_rm --description "Delete a virtualenv" 150 | if not [ (count $argv) -eq 1 ] 151 | echo "You need to specify exactly one virtualenv." 152 | return 1 153 | end 154 | if begin; set -q VIRTUAL_ENV; and [ $argv[1] = (basename $VIRTUAL_ENV) ]; end 155 | echo "You can't delete a virtualenv you're currently using." 156 | return 1 157 | end 158 | echo "Removing $VIRTUALFISH_HOME/$argv[1]" 159 | rm -rf $VIRTUALFISH_HOME/$argv[1] 160 | end 161 | 162 | function __vf_ls --description "List all of the available virtualenvs" 163 | pushd $VIRTUALFISH_HOME 164 | for i in */bin/python 165 | echo $i 166 | end | sed "s|/bin/python||" 167 | popd 168 | end 169 | 170 | function __vf_cd --description "Change directory to currently-activated virtualenv" 171 | if set -q VIRTUAL_ENV 172 | cd $VIRTUAL_ENV 173 | else 174 | echo "Cannot locate an active virtualenv." 175 | end 176 | end 177 | 178 | function __vf_cdpackages --description "Change to the site-packages directory of the active virtualenv" 179 | vf cd 180 | cd lib/python*/site-packages 181 | end 182 | 183 | 184 | function __vf_connect --description "Connect this virtualenv to the current directory" 185 | if set -q VIRTUAL_ENV 186 | basename $VIRTUAL_ENV > $VIRTUALFISH_ACTIVATION_FILE 187 | else 188 | echo "No virtualenv is active." 189 | end 190 | end 191 | 192 | function __vf_tmp --description "Create a temporary virtualenv that will be removed when deactivated" 193 | set -l env_name (printf "%s%.4x" "tempenv-" (random) (random) (random)) 194 | set -g VF_TEMPORARY_ENV 195 | 196 | # Use will_deactivate here so that $VIRTUAL_ENV is available. 197 | function __vf_tmp_remove --on-event virtualenv_will_deactivate:$env_name 198 | echo "Removing $VIRTUAL_ENV" 199 | rm -rf $VIRTUAL_ENV 200 | set -e VF_TEMPORARY_ENV 201 | end 202 | 203 | # Ensure that the virtualenv gets deleted even if we close the shell w/o 204 | # explicitly deactivating. 205 | function __vfsupport_remove_temp_env_on_exit --on-process %self 206 | if set -q VF_TEMPORARY_ENV 207 | vf deactivate # the deactivate handler will take care of removing it 208 | end 209 | end 210 | 211 | vf new $argv $env_name 212 | end 213 | 214 | function __vf_addpath --description "Adds a path to sys.path in this virtualenv" 215 | if set -q VIRTUAL_ENV 216 | set -l site_packages (eval "$VIRTUAL_ENV/bin/python -c 'import distutils; print(distutils.sysconfig.get_python_lib())'") 217 | set -l path_file $site_packages/_virtualenv_path_extensions.pth 218 | 219 | set -l remove 0 220 | if test $argv[1] = "-d" 221 | set remove 1 222 | set -e argv[1] 223 | end 224 | 225 | if not test -f $path_file 226 | echo "import sys; sys.__plen = len(sys.path)" > $path_file 227 | echo "import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)" >> $path_file 228 | end 229 | 230 | for pydir in $argv 231 | set -l absolute_path (eval "$VIRTUAL_ENV/bin/python -c 'import os,sys; sys.stdout.write(os.path.abspath(\"$pydir\")+\"\n\")'") 232 | if not test $pydir = $absolute_path 233 | echo "Warning: Converting \"$pydir\" to \"$absolute_path\"" 1>&2 234 | end 235 | 236 | if test $remove -eq 1 237 | sed -i.tmp "\:^$absolute_path\$: d" "$path_file" 238 | else 239 | sed -i.tmp '1 a\ 240 | '"$absolute_path"' 241 | ' "$path_file" 242 | end 243 | rm -f "$path_file.tmp" 244 | end 245 | return 0 246 | else 247 | echo "No virtualenv is active." 248 | end 249 | end 250 | 251 | ################ 252 | # Autocomplete 253 | # Based on https://github.com/zmalltalker/fish-nuggets/blob/master/completions/git.fish 254 | begin 255 | function __vfcompletion_needs_command 256 | set cmd (commandline -opc) 257 | if test (count $cmd) -eq 1 -a $cmd[1] = 'vf' 258 | return 0 259 | end 260 | return 1 261 | end 262 | 263 | function __vfcompletion_using_command 264 | set cmd (commandline -opc) 265 | if test (count $cmd) -gt 1 266 | if test $argv[1] = $cmd[2] 267 | return 0 268 | end 269 | end 270 | return 1 271 | end 272 | 273 | # add completion for subcommands 274 | for sc in (functions -a | sed -n '/__vf_/{s///g;p;}') 275 | set -l helptext (functions "__vf_$sc" | head -n 1 | sed -E "s|.*'(.*)'.*|\1|") 276 | complete -x -c vf -n '__vfcompletion_needs_command' -a $sc -d $helptext 277 | end 278 | 279 | complete -x -c vf -n '__vfcompletion_using_command activate' -a "(vf ls)" 280 | complete -x -c vf -n '__vfcompletion_using_command rm' -a "(vf ls)" 281 | if set -q VIRTUALFISH_COMPAT_ALIASES 282 | complete -x -c workon -a "(vf ls)" 283 | complete -x -c rmvirtualenv -a "(vf ls)" 284 | end 285 | end 286 | 287 | -------------------------------------------------------------------------------- /home/.config/pulse/daemon.conf: -------------------------------------------------------------------------------- 1 | # My PulseAudio setting overrides. 2 | # https://wiki.archlinux.org/index.php/PulseAudio 3 | # 4 | # Run these commands when changing this config: 5 | # $ pulseaudio -k 6 | # $ pulseaudio --start 7 | 8 | # Stop per-application volume from adjusting when the Master volume is 9 | # adjusted. 10 | flat-volumes = no 11 | 12 | # vim:ft=conf 13 | -------------------------------------------------------------------------------- /home/.config/sublime-text-3/Installed Packages/Better CoffeeScript.sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirsle/.dotfiles/8d6864519bb012be834c889bfa9dc3766239bc48/home/.config/sublime-text-3/Installed Packages/Better CoffeeScript.sublime-package -------------------------------------------------------------------------------- /home/.config/sublime-text-3/Installed Packages/Package Control.sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirsle/.dotfiles/8d6864519bb012be834c889bfa9dc3766239bc48/home/.config/sublime-text-3/Installed Packages/Package Control.sublime-package -------------------------------------------------------------------------------- /home/.editorconfig: -------------------------------------------------------------------------------- 1 | # Top-most EditorConfig file 2 | root = true 3 | 4 | # Common settings for all files. I don't specify indent type here, because 5 | # some EditorConfig implementations (notably Atom) will cause default settings 6 | # and behaviors (like tab type auto-detection) to be overridden. 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | # Python 14 | [*.py] 15 | indent_style = space 16 | indent_size = 4 17 | 18 | # YAML and Markdown 19 | [*.{yml,yaml,md}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | # CoffeeScript 24 | [*.coffee] 25 | indent_style = space 26 | indent_size = 2 27 | 28 | # format:dosini 29 | -------------------------------------------------------------------------------- /home/.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | name = Noah Petherbridge 3 | email = root@kirsle.net 4 | 5 | [alias] 6 | ci = commit 7 | co = checkout 8 | br = branch 9 | st = status 10 | 11 | [core] 12 | editor = vim 13 | 14 | [color] 15 | ui = true 16 | diff = true 17 | pager = true 18 | status = auto 19 | branch = auto 20 | 21 | [push] 22 | default = simple 23 | -------------------------------------------------------------------------------- /home/.ssh/config: -------------------------------------------------------------------------------- 1 | Host * 2 | ForwardAgent no 3 | ForwardX11 no 4 | ForwardX11Trusted yes 5 | Port 22 6 | Protocol 2 7 | ServerAliveInterval 60 8 | ServerAliveCountMax 30 9 | 10 | # All hosts here prohibit password based logins, so don't get any ideas. ;) 11 | 12 | Host socks 13 | HostName kirsle.net 14 | User kirsle 15 | PasswordAuthentication no 16 | DynamicForward 8080 17 | 18 | Host kirsle 19 | HostName kirsle.net 20 | User kirsle 21 | PasswordAuthentication no 22 | 23 | Host caskir 24 | HostName caskir.com 25 | User kirsle 26 | PasswordAuthentication no 27 | ForwardAgent yes 28 | 29 | Host mtgit git.mtsvc.net 30 | HostName git.mtsvc.net 31 | User git 32 | ControlMaster auto 33 | ControlPath /tmp/ssh_mux_%h_%p_%r 34 | ControlPersist 30s 35 | 36 | Host omega 37 | HostName omega.mtsvc.net 38 | User npetherbridge 39 | ForwardAgent yes 40 | -------------------------------------------------------------------------------- /home/.tmux.conf: -------------------------------------------------------------------------------- 1 | # tmux config 2 | 3 | # UTF-8 -- options seem not supported anymore? 4 | #set -g utf8 5 | #set-window-option -g utf8 on 6 | 7 | # 256 Colors 8 | set -g default-terminal "screen-256color" 9 | 10 | # Set scrollback history 11 | set -g history-limit 10000 12 | 13 | # remap prefix to Ctrl-A 14 | set -g prefix C-a 15 | unbind C-b 16 | bind C-a send-prefix 17 | 18 | # Reload the config file 19 | unbind r 20 | bind r source-file ~/.tmux.conf \; display "Reloaded!" 21 | 22 | # Quick pane cycling, Ctrl-A+A 23 | unbind ^A 24 | bind ^A select-pane -t :.+ 25 | 26 | # Set window and pane index to start at 1 instead of 0 27 | set-option -g base-index 1 28 | setw -g pane-base-index 1 29 | 30 | # Use PREFIX | to split horizontally and PREFIX - for vertical 31 | bind | split-window -h 32 | bind - split-window -v 33 | 34 | # Make the current window the first window 35 | bind T swap-window -t 1 36 | 37 | # Resize panes using vim-style direction keys 38 | bind h resize-pane -L 5 39 | bind j resize-pane -D 5 40 | bind k resize-pane -U 5 41 | bind l resize-pane -R 5 42 | 43 | # Mouse controls 44 | set -g mouse on 45 | 46 | # Toggle mouse mode on with ^A-m 47 | bind m \ 48 | set -g mouse on \;\ 49 | display "Mouse: ON" 50 | 51 | # Toggle mouse mode off with ^A-M 52 | bind M \ 53 | set -g mouse off \;\ 54 | display "Mouse: OFF" 55 | 56 | # Status bar customization 57 | #set -g status-utf8 on 58 | set -g status-bg black 59 | set -g status-fg white 60 | set -g status-interval 5 61 | set -g status-left-length 90 62 | set -g status-right-length 60 63 | set -g status-left "#[fg=green]#(whoami)#[fg=white]@#[fg=blue]#(hostname -s)" 64 | set -g status-justify left 65 | set -g status-right "#[fg=cyan]#S #[fg=white]%a %d %b %R" 66 | 67 | -------------------------------------------------------------------------------- /home/.vimrc: -------------------------------------------------------------------------------- 1 | " vimrc, http://sh.kirsle.net/ 2 | 3 | " https://www.mail-archive.com/fish-users@lists.sourceforge.net/msg01425.html 4 | if $SHELL =~ 'bin/fish' 5 | set shell=/bin/bash 6 | endif 7 | 8 | set encoding=utf8 " Unicode support 9 | set nocompatible " use vim defaults 10 | set background=dark " my terminal has a black background 11 | set tabstop=4 " number of spaces for tab character 12 | set softtabstop=4 " insert/delete 4 spaces when hitting a tab/backspace 13 | set shiftwidth=4 " number of spaces to auto-indent 14 | set shiftround " round indent to multiple of 'shiftwidth' 15 | set scrolloff=3 " keep 3 lines when scrolling 16 | set smartindent " smart auto-indenting (recognizes C-like code) 17 | set showmatch " hilite the matching brace when we type the closing brace 18 | set nohls " don't highlight search matches 19 | set incsearch " incremental search (search while you type) 20 | set ignorecase " case-insensitive search 21 | set showcmd " display incomplete commands 22 | set ttyfast " smoother changes 23 | set autowrite " automatic saving when quitting and switching buffer 24 | set autoread " automatic read when file is modified from outside 25 | set modeline " process modelines in files 26 | set number " show line numbers 27 | set relativenumber " and make line numbers relative to current line 28 | syntax on " syntax highlighting 29 | 30 | " Leader Key 31 | map 32 | 33 | " When vimrc is edited, reload it. 34 | autocmd! BufWritePost .vimrc source ~/.vimrc 35 | 36 | " Enable filetype plugin 37 | filetype plugin on 38 | filetype indent on 39 | 40 | " Mouse support that keeps the fast scroll wheel speed. 41 | set mouse=a 42 | set ttymouse=xterm2 43 | map 12j 44 | map 12k 45 | map 46 | imap 12j 47 | imap 12k 48 | imap 49 | 50 | " Make movement make sense across wrapped lines. 51 | nnoremap j gj 52 | nnoremap k gk 53 | imap gk 54 | imap gj 55 | map gk 56 | map gj 57 | 58 | " Tell Vim to remember things when we exit: 59 | " '10 : marks will be remembered for up to 10 previously edited files 60 | " "100 : will save up to 100 lines for each register 61 | " :20 : up to 20 lines of command-line history remembered 62 | " % : saves and restores the buffer list 63 | " n... : where to save the viminfo files 64 | set viminfo='10,\"100,:20,%,n~/.viminfo' 65 | 66 | " Restore the cursor position. 67 | function! ResCur() 68 | if line("'\"") <= line("$") 69 | normal! g`" 70 | return 1 71 | endif 72 | endfunction 73 | augroup resCur 74 | autocmd! 75 | autocmd BufWinEnter * call ResCur() 76 | augroup END 77 | 78 | " make tab in v mode indent code 79 | vmap >gv 80 | vmap I 84 | nmap ^i 85 | 86 | " change the bash title so the filename is first in the title bar 87 | let &titlestring = expand("%:t") . " - vim on " . hostname() 88 | if &term == "screen" 89 | set t_ts=k 90 | set t_fs=\ 91 | endif 92 | if &term == "screen" || &term == "xterm" || &term == "xterm-256color" 93 | set title 94 | endif 95 | 96 | " custom file extensions 97 | au BufNewFile,BufRead *.gohtml set filetype=html 98 | 99 | " Tab Navigation 100 | nnoremap [t :tabprevious 101 | nnoremap ]t :tabnext 102 | nnoremap [T :tabfirst 103 | nnoremap ]T :tablast 104 | 105 | " Buffer Navigation 106 | nnoremap [b :bprev 107 | nnoremap ]b :bnext 108 | nnoremap [B :bfirst 109 | nnoremap ]B :blast 110 | 111 | """""""""""""""""""""""" 112 | """ General coding stuff 113 | """""""""""""""""""""""" 114 | 115 | " git commit messages 116 | autocmd Filetype gitcommit setlocal spell textwidth=72 117 | 118 | " reStructuredText 119 | autocmd FileType rst set tabstop=3 softtabstop=3 shiftwidth=3 expandtab 120 | 121 | " nginx config 122 | autocmd BufRead,BufNewFile /etc/nginx/*,/usr/local/nginx/conf/* if &ft == '' | setfiletype nginx | endif 123 | 124 | " Make sure the syntax is always right, even when in the middle of 125 | " a huge javascript inside an html file. 126 | autocmd BufEnter * :syntax sync fromstart 127 | 128 | " Map F12 to sync the syntax too. 129 | noremap :syntax sync fromstart 130 | inoremap :syntax sync fromstart 131 | 132 | " Markdown syntax 133 | autocmd BufRead,BufNewFile *.md set ft=markdown 134 | 135 | " Show tab characters 136 | set list listchars=tab:\|\ ,trail:-,extends:>,precedes:<,nbsp:x 137 | highlight SpecialKey ctermfg=darkgrey guifg=darkgrey 138 | 139 | " Show a divider line at the 80 column mark 140 | if v:version > 702 141 | set colorcolumn=80,120 142 | highlight ColorColumn ctermbg=darkgrey guibg=darkgrey 143 | endif 144 | 145 | """""""""""""" 146 | """ Perl stuff 147 | """""""""""""" 148 | 149 | " check perl code with :make 150 | autocmd FileType perl set makeprg=perl\ -c\ %\ $* 151 | autocmd FileType perl set errorformat=%f:%l%m 152 | 153 | " syntax highlight pod documentation correctly 154 | let perl_include_pod = 1 155 | 156 | " syntax color complex things like @{${"foo"}} 157 | let perl_extended_vars = 1 158 | 159 | """"""""""""""" 160 | """ vim plugins 161 | """"""""""""""" 162 | 163 | " My vim plugins. https://github.com/gmarik/Vundle.vim 164 | filetype off 165 | 166 | " Set the runtime path to include Vundle and initialize 167 | set rtp+=~/.vim/bundle/Vundle.vim 168 | call vundle#begin() 169 | 170 | " let Vundle manage Vundle, required 171 | Plugin 'gmarik/Vundle.vim' 172 | 173 | " Layout Plugins 174 | Plugin 'scrooloose/nerdtree' 175 | Plugin 'jistr/vim-nerdtree-tabs' 176 | Plugin 'bling/vim-airline' 177 | Plugin 'majutsushi/tagbar' 178 | Plugin 'tomasr/molokai' 179 | 180 | " Editor Enhancements 181 | Plugin 'kien/ctrlp.vim' 182 | 183 | " Languages 184 | Plugin 'kchmck/vim-coffee-script' 185 | Plugin 'tpope/vim-markdown' 186 | 187 | call vundle#end() " required 188 | filetype plugin indent on " required 189 | 190 | " Brief help: 191 | " :PluginList 192 | " :PluginInstall - installs plugins; append '!' to update or :PluginUpdate 193 | " :PluginSearch foo - searches for foo; append '!' to refresh local cache 194 | " :PluginClean - confirms removal of unused plugins; append '!' 195 | " to auto-approve removal 196 | " 197 | " See :h vundle for more details 198 | 199 | """"""""""""""""""""""""" 200 | """ Plugin Configurations 201 | """"""""""""""""""""""""" 202 | 203 | colorscheme molokai 204 | 205 | "---------- 206 | " NERD Tree 207 | "---------- 208 | 209 | " Auto-open the NERDTree, but focus the original file's panel 210 | autocmd VimEnter * NERDTree 211 | autocmd VimEnter * wincmd p 212 | 213 | " The same, but for when you open vim w/o a specific file 214 | autocmd StdinReadPre * let s:std_in=1 215 | autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif 216 | 217 | " map Space-d to show/hide the NERDTree 218 | nmap d :NERDTreeToggle 219 | 220 | " close VIM if the only window left open is the NERDTree 221 | autocmd BufEnter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif 222 | 223 | " NERD Tree Tabs 224 | map n NERDTreeTabsToggle 225 | 226 | "-------- 227 | " Airline 228 | "-------- 229 | 230 | " Sexier tab bar 231 | let g:airline#extensions#tabline#enabled = 1 232 | let g:airline#extensions#tabline#buffer_idx_mode = 1 233 | let g:airline#extensions#tabline#tab_nr_mode = 1 234 | nmap 1 AirlineSelectTab1 235 | nmap 2 AirlineSelectTab2 236 | nmap 3 AirlineSelectTab3 237 | nmap 4 AirlineSelectTab4 238 | nmap 5 AirlineSelectTab5 239 | nmap 6 AirlineSelectTab6 240 | nmap 7 AirlineSelectTab7 241 | nmap 8 AirlineSelectTab8 242 | nmap 9 AirlineSelectTab9 243 | 244 | "-------- 245 | " Tag bar 246 | "-------- 247 | 248 | " F8 to show/hide the tag bar 249 | nmap :TagbarToggle 250 | 251 | "------ 252 | " CtrlP 253 | "------ 254 | 255 | let g:ctrlp_map = '' 256 | let g:ctrlp_cmd = 'CtrlP' 257 | 258 | "----- 259 | " Misc 260 | "----- 261 | 262 | autocmd BufNewFile,BufReadPost *.md set filetype=markdown 263 | -------------------------------------------------------------------------------- /home/.zshrc: -------------------------------------------------------------------------------- 1 | ### 2 | # .zshrc 3 | # 4 | # Kirsle's Global ZSH Configuration 5 | ### 6 | 7 | export LANG=en_US.UTF-8 # Unicode 8 | setopt prompt_subst # Allow for dynamic prompts 9 | autoload -U colors && colors # Get color aliases 10 | autoload -U compinit && compinit # Better tab completion 11 | export HISTSIZE=2000 # History settings 12 | export HISTFILE="$HOME/.history" 13 | export SAVEHIST=$HISTSIZE 14 | setopt hist_ignore_all_dups 15 | setopt hist_ignore_space 16 | setopt inc_append_history 17 | setopt nobeep 18 | 19 | # Enable 256 colors in my terminal 20 | [[ "$TERM" == "xterm" ]] && export TERM=xterm-256color 21 | 22 | # CLI colors under OS X for `ls` 23 | if [[ `uname` == "Darwin" ]]; then 24 | # Enable colors and set a similar scheme as on Linux (see `man ls`) 25 | export CLICOLOR=1 26 | export LSCOLORS="ExGxcxdxcxegedabagecec" 27 | fi 28 | 29 | # Normalize the PATH. Under Linux prefer /usr/bin over local paths, 30 | # but on MacOS allow /usr/local and ~/bin to override system paths, 31 | # for Homebrew. 32 | CORE_PATH="/usr/sbin:/sbin:/usr/bin:/bin" 33 | USR_PATH="/usr/local/sbin:/usr/local/bin:${HOME}/bin:${HOME}/go/bin:${HOME}/go/.ext/bin:${HOME}/.cargo/bin:${HOME}/android/sdk/platform-tools" 34 | if [[ `uname` == "Linux" ]] then export PATH="${CORE_PATH}:${USR_PATH}" 35 | else export PATH="${USR_PATH}:${CORE_PATH}" 36 | fi 37 | 38 | # Vim as the favorite editor. 39 | export EDITOR="/usr/bin/vim" 40 | 41 | # Python settings. 42 | ## Prefer Python3 for new environments created by virtualenvwrapper. 43 | export WORKON_HOME=~/.virtualenvs 44 | command -v python3 >/dev/null 2>&1 && export VIRTUALENV_PYTHON=`command -v python3` 45 | 46 | # Go settings. 47 | ## Separate the GOPATH into external (.ext) and main, to keep my projects 48 | ## apart from everyone else's. `go get` installs into the first directory 49 | ## of $GOPATH so third party packages end up there. 50 | export GOPATH="$HOME/go/.ext:$HOME/go" 51 | 52 | # JavaScript settings. 53 | ## Store globally installed npm packages (e.g. `npm install -g babel-cli`) 54 | ## in my ~/.npm-global-pkg directory, and add it to my $PATH. 55 | if [[ ! -f "${HOME}/.npmrc" ]]; then 56 | echo "prefix = ${HOME}/.npm-global-pkg" > $HOME/.npmrc 57 | fi 58 | export NPM_PACKAGES="${HOME}/.npm-global-pkg" 59 | export NODE_PATH="${NPM_PACKAGES}/lib/node_modules:${NODE_PATH}" 60 | export PATH="${NPM_PACKAGES}/bin:$PATH" 61 | 62 | # Java settings. 63 | ## Make ~/java available on the CLASSPATH. 64 | export CLASSPATH="$CLASSPATH:${HOME}/java" 65 | 66 | # Reload zshrc 67 | alias rezsh="source ${HOME}/.zshrc" 68 | 69 | # Allow overriding hostname in the prompt from a local config 70 | export PROMPT_HOSTNAME="%m" 71 | 72 | # Source local (system specific) configurations 73 | if [[ -f "${HOME}/.zshrc-local" ]]; then 74 | source "${HOME}/.zshrc-local" 75 | fi 76 | 77 | ### 78 | # Base shell prompt. 79 | ### 80 | 81 | # I slowly build the prompt up over multiple places and store it in 82 | # in $base_prompt, so I can modify it before exporting it (for example, 83 | # so the git branch appears before the % at the end of the prompt). 84 | 85 | # For the color palette, see: http://www.pixelbeat.org/docs/terminal_colours/ 86 | # Use light shades of blue and pink. 87 | local blue="%F{39}" 88 | local pink="%F{213}" 89 | local orange="%F{208}" 90 | local lime="%F{46}" 91 | local cyan="%F{51}" 92 | local base_prompt="%{$blue%}[%{$pink%}%n%{$blue%}@%{$pink%}${PROMPT_HOSTNAME} %{$lime%}%1~" 93 | 94 | ### 95 | # Include git branch in the prompt 96 | ### 97 | 98 | git_branch() { 99 | local res=`git branch 2>/dev/null | grep -v '^[^*]' | perl -pe 's/^\*\s+//g'` 100 | if [[ "$res" != "" ]]; then 101 | local res=" ($res)" 102 | fi 103 | echo $res 104 | } 105 | 106 | local git_prompt='%{$cyan%}$(git_branch)%{$reset_color%}' 107 | local base_prompt="${base_prompt}${git_prompt}" 108 | 109 | # End the base prompt 110 | local base_prompt="${base_prompt}%{$blue%}]%# %{%f%}" 111 | 112 | ### 113 | # Set terminal titles automatically 114 | ### 115 | 116 | # allow resetting the terminal title like in DOS 117 | function title { 118 | export PROMPT_DOS_TITLE="$1" 119 | } 120 | 121 | precmd() { 122 | if [ "$PROMPT_DOS_TITLE" != "" ]; then 123 | print -Pn "\e]0;${PROMPT_DOS_TITLE}\a" 124 | else 125 | print -Pn "\e]0;%n@${PROMPT_HOSTNAME}:%~\a" 126 | fi 127 | } 128 | 129 | ############################################################################### 130 | # Aliases and things # 131 | ############################################################################### 132 | 133 | alias vi="vim" 134 | alias grep="grep --exclude=min.js --color=auto" 135 | alias ll="ls -l" 136 | alias tojson="python -m json.tool" # JSON pretty print 137 | 138 | if [[ `uname` == 'Linux' ]] then 139 | alias ls="ls --color=auto" 140 | fi 141 | 142 | # `h` is a shortcut for `history 1` (show all history) or `history 1 | grep` 143 | # example: `h ls` will do `history 1 | grep ls` 144 | h() { 145 | if [ -z "$*" ]; then 146 | history 1; 147 | else 148 | history 1 | egrep "$@"; 149 | fi 150 | } 151 | 152 | ############################################################################### 153 | # zsh plugins # 154 | ############################################################################### 155 | 156 | # Load zgen (plugin manager) 157 | source "${HOME}/.dotfiles/zsh/zgen/zgen.zsh" 158 | 159 | # Initialize zgen plugins 160 | if ! zgen saved; then 161 | echo "Creating a zgen save" 162 | 163 | # Load plugins 164 | zgen oh-my-zsh plugins/virtualenv 165 | zgen oh-my-zsh plugins/virtualenvwrapper 166 | zgen load zsh-users/zsh-syntax-highlighting 167 | 168 | # Save all to the init script 169 | zgen save 170 | fi 171 | 172 | ### 173 | # Configure plugin: virtualenvwrapper 174 | ### 175 | 176 | # Virtualenv prompt. The dynamic part (name of the virtualenv) needs to 177 | # recompute each time so we separate it out into a single-quoted variable. 178 | # See: http://stackoverflow.com/questions/11877551/zsh-not-re-computing-my-shell-prompt 179 | export ZSH_THEME_VIRTUALENV_PREFIX="(" 180 | export ZSH_THEME_VIRTUALENV_SUFFIX=")" 181 | local virtualenv_prompt='%{$orange%}$(virtualenv_prompt_info)%{$reset_color%}' 182 | local base_prompt="${virtualenv_prompt}${base_prompt}" 183 | 184 | # Trigger any virtualenvs to auto-activate in the current working directory, 185 | # in case we just opened a new terminal inside a project. 186 | command -v workon_cwd >/dev/null && workon_cwd 187 | 188 | ### 189 | # Configure plugin: zsh-syntax-highlighting 190 | ### 191 | 192 | typeset -A ZSH_HIGHLIGHT_STYLES 193 | 194 | # I like blue instead of green as the base color for most things. 195 | # 39 = light blue, 27 = darker blue 196 | ZSH_HIGHLIGHT_STYLES[alias]=fg=39 197 | ZSH_HIGHLIGHT_STYLES[suffix-alias]=fg=39,underline 198 | ZSH_HIGHLIGHT_STYLES[builtin]=fg=39 199 | ZSH_HIGHLIGHT_STYLES[function]=fg=39 200 | ZSH_HIGHLIGHT_STYLES[command]=fg=39 201 | ZSH_HIGHLIGHT_STYLES[precommand]=fg=39,underline 202 | ZSH_HIGHLIGHT_STYLES[hashed-command]=fg=39 203 | ZSH_HIGHLIGHT_STYLES[globbing]=fg=green 204 | 205 | # Highlight command line flags too. 206 | ZSH_HIGHLIGHT_STYLES[single-hyphen-option]=fg=27 207 | ZSH_HIGHLIGHT_STYLES[double-hyphen-option]=fg=27 208 | 209 | # Finalize and export the prompt 210 | export PROMPT=$base_prompt 211 | 212 | ### 213 | # Import common functions (bash/zsh) 214 | ### 215 | 216 | . ~/.common.sh 217 | 218 | -------------------------------------------------------------------------------- /home/bin/REST: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function 4 | 5 | """REST: Simple command line interface to testing RESTful services. 6 | 7 | usage: REST [-h] [--cookie COOKIE] [--header HEADER] [--data DATA] 8 | {GET,POST,PUT,PATCH,DELETE} url 9 | 10 | REST API Tester 11 | 12 | positional arguments: 13 | {GET,POST,PUT,PATCH,DELETE} 14 | The HTTP method to use 15 | url The URL to request 16 | 17 | optional arguments: 18 | -h, --help show this help message and exit 19 | --cookie COOKIE, -c COOKIE 20 | Specify an HTTP cookie value in NAME=VALUE format. 21 | --header HEADER, -H HEADER 22 | Add custom HTTP request headers in 'Name: Value' 23 | format. 24 | --data DATA, -d DATA JSON data to be sent with the request. 25 | 26 | Examples: 27 | REST GET http://localhost/v1/resource/item 28 | REST POST http://localhost/v1/resource -d '{"hello": "world"}' 29 | """ 30 | 31 | import argparse 32 | import requests 33 | import json 34 | 35 | def main(): 36 | parser = argparse.ArgumentParser(description="REST API Tester") 37 | parser.add_argument( 38 | "--cookie", "-c", 39 | action="append", 40 | help="Specify an HTTP cookie value in NAME=VALUE format.", 41 | ) 42 | parser.add_argument( 43 | "--header", "-H", 44 | action="append", 45 | help="Add custom HTTP request headers in 'Name: Value' format.", 46 | ) 47 | parser.add_argument( 48 | "--data", "-d", 49 | default=None, 50 | help="JSON data to be sent with the request.", 51 | ) 52 | parser.add_argument( 53 | "--insecure", "-k", 54 | action="store_true", 55 | help="Don't validate SSL certificates.", 56 | ) 57 | parser.add_argument( 58 | "method", 59 | help="The HTTP method to use", 60 | choices=["GET", "POST", "PUT", "PATCH", "DELETE"], 61 | ) 62 | parser.add_argument( 63 | "url", 64 | help="The URL to request", 65 | ) 66 | args = parser.parse_args() 67 | 68 | # Convert cookie/header params. 69 | if args.header: 70 | args.header = strings_to_dict(args.header, ":") 71 | if args.cookie: 72 | args.cookie = strings_to_dict(args.cookie, "=") 73 | 74 | do_http(args) 75 | 76 | 77 | def do_http(args): 78 | result = None 79 | 80 | headers = { 81 | "Content-Type": "application/json", 82 | } 83 | if args.header: 84 | headers.update(args.header) 85 | 86 | ssl_opts = {} 87 | if args.insecure: 88 | ssl_opts.update(verify=False) 89 | 90 | result = getattr(requests, args.method.lower())( 91 | args.url, 92 | headers=headers, 93 | cookies=args.cookie, 94 | data=args.data, 95 | **ssl_opts 96 | ) 97 | 98 | print(args.method, args.url, result.status_code) 99 | 100 | # JSON response? 101 | try: 102 | parsed = result.json 103 | print(json.dumps(parsed, 104 | sort_keys=True, 105 | indent=4, 106 | separators=(',', ': '), 107 | )) 108 | except: 109 | print(result.text) 110 | 111 | 112 | def strings_to_dict(strings, separator): 113 | """Turn a list of key/value pairs into a dictionary.""" 114 | result = dict() 115 | for item in strings: 116 | k, v = item.split(separator) 117 | k = k.strip() 118 | v = v.strip() 119 | result[k] = v 120 | return result 121 | 122 | if __name__ == "__main__": 123 | main() 124 | -------------------------------------------------------------------------------- /home/bin/SimpleHTTPServer: -------------------------------------------------------------------------------- 1 | ///bin/true && exec /usr/bin/env script.go "$0" "$@" 2 | // vim:set ft=go: 3 | package main 4 | 5 | // SimpleHTTPServer is a simple Go static file server, similar to the Python 6 | // module of the same name, but which supports high concurrency and all the 7 | // other niceties that you get from Go out of the box. 8 | // 9 | // It runs via my `gosh` wrapper for treating simple Go programs as shell 10 | // scripts. See my `gosh` script, or just remove the shebang line at the top 11 | // of this file to `go build` your own version. 12 | 13 | import ( 14 | "encoding/base64" 15 | "flag" 16 | "fmt" 17 | "log" 18 | "net/http" 19 | "regexp" 20 | "strings" 21 | ) 22 | 23 | // Regular expression for the user:passwd format for HTTP Basic Auth (-auth) 24 | var HTTPAuthRegexp = regexp.MustCompile(`^([A-Za-z0-9_]+?):(.+?)$`) 25 | 26 | // If using HTTP Basic Auth, the username and password. 27 | var HTTPAuthUsername string 28 | var HTTPAuthPassword string 29 | 30 | // LogMiddleware logs all HTTP requests. 31 | func LogMiddleware(next http.Handler) http.Handler { 32 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 33 | // Using HTTP Basic Auth? 34 | if len(HTTPAuthUsername) > 0 { 35 | if !checkAuth(w, r) { 36 | w.Header().Set("WWW-Authenticate", `Basic realm="SimpleHTTPServer"`) 37 | w.WriteHeader(401) 38 | w.Write([]byte("401 Unauthorized\n")) 39 | return 40 | } 41 | } 42 | 43 | res := &ResponseWriter{w, 200} 44 | next.ServeHTTP(res, r) 45 | log.Printf("%s %d %s %s\n", 46 | r.RemoteAddr, 47 | res.Status, 48 | r.Method, 49 | r.RequestURI, 50 | ) 51 | }) 52 | } 53 | 54 | // checkAuth handles HTTP Basic Auth checking. 55 | func checkAuth(w http.ResponseWriter, r *http.Request) bool { 56 | s := strings.SplitN(r.Header.Get("Authorization"), " ", 2) 57 | if len(s) != 2 { 58 | return false 59 | } 60 | 61 | b, err := base64.StdEncoding.DecodeString(s[1]) 62 | if err != nil { 63 | return false 64 | } 65 | 66 | pair := strings.SplitN(string(b), ":", 2) 67 | if len(pair) != 2 { 68 | return false 69 | } 70 | 71 | return pair[0] == HTTPAuthUsername && pair[1] == HTTPAuthPassword 72 | } 73 | 74 | // ResponseWriter is my own wrapper around http.ResponseWriter that lets me 75 | // capture its status code, for logging purposes. 76 | type ResponseWriter struct { 77 | http.ResponseWriter 78 | Status int 79 | } 80 | 81 | // WriteHeader wraps http.WriteHeader to also capture the status code. 82 | func (w *ResponseWriter) WriteHeader(code int) { 83 | w.ResponseWriter.WriteHeader(code) 84 | w.Status = code 85 | } 86 | 87 | func main() { 88 | // Command line flag: the port number to listen on. 89 | host := flag.String("host", "0.0.0.0", "The host address to listen on.") 90 | port := flag.Int("port", 8000, "The port number to listen on.") 91 | auth := flag.String("auth", "", "Use HTTP Basic Authentication. The "+ 92 | "auth string should be in `user:passwd` format.") 93 | flag.Parse() 94 | 95 | // If using HTTP authentication... 96 | if len(*auth) > 0 { 97 | m := HTTPAuthRegexp.FindStringSubmatch(*auth) 98 | if len(m) == 0 { 99 | log.Panicf("The -auth parameter must be in user:passwd format.") 100 | } 101 | HTTPAuthUsername = m[1] 102 | HTTPAuthPassword = m[2] 103 | } 104 | 105 | fmt.Printf("Serving at http://%s:%d/\n", *host, *port) 106 | err := http.ListenAndServe( 107 | fmt.Sprintf("%s:%d", *host, *port), 108 | LogMiddleware(http.FileServer(http.Dir("."))), 109 | ) 110 | panic(err) 111 | } 112 | -------------------------------------------------------------------------------- /home/bin/backup-check: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """backup-check: Periodically compare checksums of backups in multiple 4 | locations. It's mainly to do a weekly check of all my backup locations and 5 | identify bit rot before it's too late. 6 | 7 | Install via `crontab -e`: 8 | 0 2 * * 0 /home/kirsle/bin/backup-check 9 | 10 | --Kirsle 11 | http://sh.kirsle.net/ 12 | """ 13 | 14 | import codecs 15 | import os.path 16 | import subprocess 17 | 18 | # Directories to compare with each other. 19 | DIRECTORIES = [ 20 | "/mnt/Midnight/Images/Organized", 21 | "/run/media/kirsle/Cyro/Pictures/Organized", 22 | "/run/media/kirsle/Obelisk/Redundant/Images/Organized", 23 | "/home/kirsle/Dropbox/Photos/Organized", 24 | ] 25 | ERROR_OUT = "/home/noah/Desktop/Checksum Error.txt" 26 | 27 | def main(): 28 | # First available disk becomes the common denominator. 29 | master = None 30 | for disk in DIRECTORIES: 31 | if os.path.isdir(disk): 32 | if master is None: 33 | print("Master disk chosen as:", disk) 34 | master = disk 35 | 36 | if disk != master: 37 | # Do the comparison. 38 | print("Compare {} <=> {}".format(master, disk)) 39 | out = subprocess.check_output(["diff", "-aqr", master, disk]) 40 | if len(out): 41 | # Problem! 42 | error(out) 43 | break 44 | 45 | def error(out): 46 | """Error, panic!""" 47 | fh = codecs.open(ERROR_OUT, "w", "utf-8") 48 | fh.write(out.decode("utf-8")) 49 | fh.close() 50 | 51 | if __name__ == "__main__": 52 | main() 53 | -------------------------------------------------------------------------------- /home/bin/datename: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # datename - Automatically rename a large group of files to have dates in their 4 | # names. 5 | # 6 | # This script is for renaming many files (e.g. files downloaded from a digital 7 | # camera) to have dates as their file names, e.g. from 2009-12-25_001.jpg to 8 | # 2009-12-25_058.jpg 9 | # 10 | # Usage: datename [options] 11 | # See `datename -?` for more help. 12 | # 13 | # --Kirsle 14 | # http://sh.kirsle.net/ 15 | 16 | use strict; 17 | use warnings; 18 | use Getopt::Long; 19 | use File::Copy; 20 | our $version = "1.0 Feb 23 2009"; 21 | 22 | unless (@ARGV) { 23 | print "Usage: datename [options] [files]\n" 24 | . "Try `datename -?` for help.\n"; 25 | exit(1); 26 | } 27 | 28 | our %c = ( 29 | r => "\e[31m", 30 | g => "\e[32m", 31 | c => "\e[34m", 32 | o => "\e[0m", 33 | ); 34 | 35 | ############################## 36 | # Collect Options # 37 | ############################## 38 | 39 | my @lt = localtime(time()); 40 | my $today = join("-", 41 | sprintf("%04d", ($lt[5] + 1900)), 42 | sprintf("%02d", ($lt[4] + 1)), 43 | sprintf("%02d", ($lt[3])), 44 | ); 45 | my $o = { 46 | help => 0, 47 | format => undef, 48 | date => undef, 49 | start => 1, 50 | force => 0, 51 | backup => "./datename-backup", 52 | nobackup => 0, 53 | mono => 0, 54 | }; 55 | GetOptions ( 56 | 'help|h|?' => \$o->{help}, 57 | 'format|f=s' => \$o->{format}, 58 | 'date|d=s' => \$o->{date}, 59 | 'start|s=i' => \$o->{start}, 60 | 'backup|b=s' => \$o->{backup}, 61 | 'nobackup' => \$o->{nobackup}, 62 | 'force' => \$o->{force}, 63 | 'monotone|mono|m' => \$o->{mono}, 64 | ); 65 | if ($o->{help}) { 66 | &help(); 67 | } 68 | if ($o->{mono}) { 69 | foreach my $key (keys %c) { 70 | $c{$key} = ''; 71 | } 72 | } 73 | 74 | ############################## 75 | # Ask for Parameters # 76 | ############################## 77 | $| = 1; 78 | print "$c{r}DateName$c{o} version $c{g}$version$c{o}\n\n"; 79 | 80 | unless ($o->{nobackup}) { 81 | print "Initializing backup directory... "; 82 | if (!-d $o->{backup}) { 83 | system("mkdir", "-p", $o->{backup}); 84 | if (!-d $o->{backup}) { 85 | die "Can't create backup directory: $!"; 86 | } 87 | } 88 | print "Done!\n\n"; 89 | } 90 | 91 | if (!defined $o->{format}) { 92 | print "$c{c}1: Enter the format for the file names to follow. This should\n" 93 | . " contain the sequences `yyyy`, `mm`, `dd`, and at least one\n" 94 | . " `n`. For example if the format is `yyyy-mm-dd_nnn`, the\n" 95 | . " and the date is 2009-02-23, the first file will be named\n" 96 | . " 2009-02-23_001.jpg, the second 2009-02-23_002.jpg, and\n" 97 | . " so-on. The default is yyyy-mm-dd_nnn. You can simply hit\n" 98 | . " return here if you want to keep the default.$c{o}\n\n"; 99 | 100 | while (1) { 101 | my $format = &prompt("Enter the date format, or blank for " 102 | . "", "yyyy-mm-dd_nnn"); 103 | 104 | # Validate the format. 105 | if ($format !~ /yyyy/ || $format !~ /mm/ || $format !~ /dd/ 106 | || $format !~ /n+/) { 107 | print "\n$c{r}You've entered an invalid date format. " 108 | . "Try again.$c{o}\n\n"; 109 | } 110 | else { 111 | # Good. 112 | $o->{format} = $format; 113 | last; 114 | } 115 | } 116 | } 117 | if (!defined $o->{date}) { 118 | print "\n$c{c}2: Enter the date that you want these files to be renamed\n" 119 | . " after. Enter the date in the format of yyyy-mm-dd.\n" 120 | . " Today's date is $c{g}$today$c{c}.$c{o}\n\n"; 121 | 122 | while (1) { 123 | my $date = &prompt("Enter the date to rename the files after, " 124 | . "or <$today>", $today); 125 | 126 | # Validate the date. 127 | if ($date !~ /^(\d\d\d\d)\-(\d\d)\-(\d\d)$/) { 128 | print "\n$c{r}You've entered an invalid date. The date\n" 129 | . "must be in yyyy-mm-dd format.$c{o}\n\n"; 130 | } 131 | else { 132 | # Good. 133 | $o->{date} = $date; 134 | last; 135 | } 136 | } 137 | } 138 | if (1) { 139 | print "\n$c{c}3: Your files will be renamed beginning with the number " 140 | . $c{g} . $o->{start} . "$c{c}.$c{o}\n\n"; 141 | 142 | my $answer = &prompt("Okay to begin at the number $o->{start}? " 143 | . " [y/n] ", 144 | "y", 145 | qw(y yes n no)); 146 | if ($answer =~ /^n/i) { 147 | while (1) { 148 | my $start = &prompt("What number do you want to " 149 | . "start at, or <1>", 1); 150 | if ($start !~ /^\d+$/) { 151 | print "\n$c{r}Invalid answer.$c{o}\n\n"; 152 | } 153 | else { 154 | $o->{start} = $start; 155 | last; 156 | } 157 | } 158 | } 159 | } 160 | 161 | ############################## 162 | # Summarize What's Going On # 163 | ############################## 164 | 165 | my @files = &getFileList(); 166 | my $numFiles = scalar(@files); 167 | my ($nss) = ($o->{format} =~ /(n+)/i); 168 | our $ns = length $nss; 169 | our ($year,$mon,$day) = ($o->{date} =~ /^(\d\d\d\d)\-(\d\d)\-(\d\d)$/); 170 | if (1) { 171 | my $backuptext = "Your files will be backed up to $o->{backup}."; 172 | if ($o->{nobackup}) { 173 | $backuptext = "Your files will *NOT* be backed up."; 174 | } 175 | my $first = &datename($o->{start}); 176 | my $last = &datename($o->{start} + $numFiles); 177 | print "\n" . $c{c} 178 | . ("=" x 70) . "$c{o}\n" 179 | . "$c{g}Summary of Operations:$c{o}\n\n" 180 | . "$c{c}Your $numFiles files are going to be renamed in the format\n" 181 | . "'$o->{format}' using the date '$o->{date}', beginning with\n" 182 | . "the number $o->{start}. They will be renamed from\n" 183 | . "$first to $last.\n\n" 184 | . "$backuptext$c{o}\n\n"; 185 | 186 | my $proceed = &prompt("Okay to proceed? [y/n] ", "n", 187 | qw(y yes n no)); 188 | unless ($proceed =~ /^y/i) { 189 | print "\nAborting procedure!\n"; 190 | exit(0); 191 | } 192 | } 193 | 194 | ############################## 195 | # Main Operation # 196 | ############################## 197 | 198 | my $int = $o->{start}; 199 | foreach my $file (@files) { 200 | next unless -f $file; 201 | my ($ext) = ($file =~ /\.([A-Za-z0-9]+?)$/i); 202 | $ext = "jpg" unless defined $ext; 203 | print "$c{c}Looking at file $file$c{o}\n"; 204 | unless ($o->{nobackup}) { 205 | my $backup = $file; 206 | my $bi = 1; 207 | while (-f "$o->{backup}/$backup") { 208 | $backup = "[$bi] $file"; 209 | $bi++; 210 | } 211 | print " Backing it up as $o->{backup}/$backup... "; 212 | copy ($file, "$o->{backup}/$backup"); 213 | if (-f "$o->{backup}/$backup") { 214 | print "Done!\n"; 215 | } 216 | else { 217 | die "$c{r}Error: couldn't back it up: $!$c{o}"; 218 | } 219 | } 220 | 221 | my $newName = &datename($int) . "." . lc($ext); 222 | $int++; 223 | print " Renaming file to $newName" 224 | . ($o->{force} ? " (forced)" : "") 225 | . "... "; 226 | if (-f $newName && !$o->{force}) { 227 | print "Warning: File already exists!$c{r}\n"; 228 | my $continue = &prompt( 229 | " The file $newName already exists. Overwrite? " 230 | . "[y/n] ", "n", qw(y yes n no)); 231 | 232 | if ($continue !~ /^y/i) { 233 | print " Skipping rename of $file!$c{o}\n"; 234 | next; 235 | } 236 | 237 | print " Renaming file to $newName (forced)... $c{o}"; 238 | } 239 | 240 | # Rename it. 241 | rename ($file, $newName); 242 | print "$c{g}Done!$c{o}\n"; 243 | } 244 | 245 | print "\n" 246 | . "$c{g}Procedure completed. Backups were saved to $o->{backup}.$c{o}\n"; 247 | exit(0); 248 | 249 | sub datename { 250 | my $i = shift; 251 | 252 | my $format = $o->{format}; 253 | $format =~ s/yyyy/$year/ig; 254 | $format =~ s/mm/$mon/ig; 255 | $format =~ s/dd/$day/ig; 256 | my $sprint = sprintf("%0${ns}d", $i); 257 | $format =~ s/n+/$sprint/ig; 258 | return $format; 259 | } 260 | 261 | sub getFileList { 262 | if (@ARGV) { 263 | return (@ARGV); 264 | } 265 | my @return = (); 266 | opendir (DIR, "."); 267 | foreach my $f (sort(grep(/^\./, readdir(DIR)))) { 268 | if (-f $f) { 269 | push (@return, $f); 270 | } 271 | } 272 | closedir (DIR); 273 | return (@return); 274 | } 275 | 276 | sub prompt { 277 | my $question = shift; 278 | my $default = shift; 279 | my @accept = (); 280 | 281 | my $asking = 1; 282 | while ($asking) { 283 | print "$question "; 284 | chomp (my $answer = ); 285 | 286 | if (defined $answer && length $answer) { 287 | if (@accept) { 288 | foreach my $a (@accept) { 289 | if ($answer eq $a) { 290 | return $a; 291 | } 292 | } 293 | print "Invalid answer.\n"; 294 | } 295 | else { 296 | return $answer; 297 | } 298 | } 299 | else { 300 | if (@accept) { 301 | print "INvalid answer.\n"; 302 | } 303 | else { 304 | return $default; 305 | } 306 | } 307 | } 308 | } 309 | 310 | sub help { 311 | print < 319 | 320 | OPTIONS 321 | 322 | The following options can be provided at the command line, or will be 323 | prompted for during operation. 324 | 325 | --format, -f 326 | 327 | Provide the date format. Should contain yyyy, mm, dd, and a 328 | sequence of at least one n. Ex: yyyy-mm-dd_nnn 329 | 330 | --date, -d 331 | 332 | Provide the date. Should be in yyyy-mm-dd format, e.g. 333 | 2009-02-23 334 | 335 | --start, -s 336 | 337 | Enter the iteration number to begin renaming files at. By 338 | default it is 1. 339 | 340 | The following options will modify the default behavior of the program: 341 | 342 | --backup, -b 343 | 344 | Specify the directory you want the files backed up into. 345 | Default is ./datename-backup 346 | This folder will try to be created if it doesn't exist. 347 | 348 | --nobackup 349 | 350 | Do not back up files (I don't recommend this option). 351 | 352 | --force 353 | 354 | Force rename all files (do not prompt the user if the file 355 | already exists). 356 | 357 | EXAMPLES 358 | 359 | ; Specify all the prompt questions on the command line and rename 360 | ; JPG and PNG images only. 361 | datename -f "yyyy-mm-dd_nnn" -d "2009-02-23" -s 100 *.jpg *.png 362 | 363 | ; Rename JPG, BMP, and GIF, will be prompted for the other options 364 | datename *.jpg *.bmp *.gif 365 | 366 | ; Rename everything 367 | datename * 368 | 369 | AUTHOR 370 | 371 | Casey Kirsle 372 | http://www.kirsle.net/ 373 | EOF 374 | exit(1); 375 | } 376 | -------------------------------------------------------------------------------- /home/bin/dbvault: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """dbvault: Dropbox Encrypted Folders 4 | 5 | This script makes it easy to set up, mount and unmount encrypted folders for use 6 | in Dropbox. It depends on fuse-encfs in Linux. 7 | 8 | To initialize it in a new Dropbox installation: 9 | 10 | $ dbvault init 11 | 12 | To mount later: 13 | 14 | $ dbvault mount 15 | 16 | And unmount: 17 | 18 | $ dbvault umount 19 | 20 | --Kirsle 21 | """ 22 | 23 | from __future__ import print_function 24 | import sys 25 | import os 26 | import os.path 27 | import subprocess 28 | 29 | # Relevant paths. 30 | # home = $HOME 31 | # dropbox = $HOME/Dropbox (your Dropbox folder) 32 | # encrypted = $HOME/Dropbox/.vault (your encrypted folder inside Dropbox) 33 | # mount = $HOME/Dropbox Vault (mount point when accessing folder; OUTSIDE of Dropbox root!) 34 | home = os.environ["HOME"] 35 | dropbox = os.path.join(home, "Dropbox") 36 | encrypted = os.path.join(dropbox, ".vault") 37 | mount = os.path.join(home, "Dropbox Vault") 38 | 39 | # Test for enc-fs. 40 | if subprocess.call("which encfs >/dev/null 2>&1", shell=True) != 0: 41 | print("You require fuse-encfs to use this script.") 42 | sys.exit(1) 43 | 44 | if len(sys.argv) == 1: 45 | print("Usage: dbvault ") 46 | print("") 47 | print("To set up for the first time (and create ~/Dropbox/.vault):") 48 | print(" $ dbvault init") 49 | print("") 50 | print("To mount the encrypted folder (to ~/Dropbox Vault):") 51 | print(" $ dbvault mount") 52 | print("") 53 | print("To unmount the folder when you're done:") 54 | print(" $ dbvault umount") 55 | print("") 56 | print("The paths used by this script:") 57 | print("* Your home directory: ", home) 58 | print("* Your Dropbox folder: ", dropbox) 59 | print("* Your encrypted folder inside Dropbox:", encrypted) 60 | print("* Your mount point OUTSIDE Dropbox: ", mount) 61 | sys.exit(1) 62 | 63 | def die(message): 64 | print(message) 65 | sys.exit(1) 66 | 67 | def mkdir(): 68 | if os.path.isdir(mount): 69 | die("Can't create mount point {}: already exists!".format(mount)) 70 | os.mkdir(mount) 71 | 72 | def rmdir(): 73 | if not os.path.isdir(mount): 74 | die("Can't remove mount point {}: doesn't exist!".format(mount)) 75 | os.rmdir(mount) 76 | 77 | action = sys.argv[1] 78 | if action == "init": 79 | # Initialization. 80 | if not os.path.isdir(dropbox): 81 | die("Couldn't find your Dropbox folder. Is it at {}?".format(dropbox)) 82 | 83 | # Already initialized? 84 | if os.path.isdir(encrypted): 85 | die("Encrypted folder '{}' already exists. dbvault appears to already be initialized.".format(encrypted)) 86 | 87 | print("Initializing encrypted folder. I will now run `encfs` to create the folder.") 88 | print("I recommend that you pick the strongest encryption you think you'll need.") 89 | mkdir() 90 | subprocess.call(["encfs", encrypted, mount]) 91 | 92 | elif action == "mount": 93 | mkdir() 94 | result = subprocess.call(["encfs", encrypted, mount]) 95 | if result != 0: 96 | print("An error happened when trying to mount the filesystem.") 97 | print("The mount point will be removed.") 98 | rmdir() 99 | 100 | elif action in ["umount", "unmount"]: 101 | subprocess.call(["fusermount", "-u", mount]) 102 | rmdir() 103 | 104 | else: 105 | die("Unknown action: {}".format(action)) 106 | 107 | # vim:expandtab 108 | -------------------------------------------------------------------------------- /home/bin/dfm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | =head1 NAME 4 | 5 | dfm: Dotfiles Manager. 6 | 7 | =head1 DESCRIPTION 8 | 9 | This is a custom script to help me manage my dotfiles. The C script 10 | acts as an alias to C. 11 | 12 | This is written in Perl for maximum compatibility; the old C script that 13 | this replaces was written in Python, and for the servers I work with I had to 14 | make it simultaneously support Python 2.6, 2.7 and 3.x; Perl is simpler and 15 | more universal. 16 | 17 | =head1 USAGE 18 | 19 | dfm [options...] 20 | 21 | =cut 22 | 23 | use strict; 24 | use warnings; 25 | 26 | use Cwd qw(getcwd abs_path); 27 | use Data::Dumper; 28 | use File::Copy; 29 | use File::Spec; 30 | use FindBin; 31 | use Getopt::Long; 32 | 33 | # Our home folder and the root to the .dotfiles repo. 34 | our $HOME = $ENV{HOME} || $ENV{USERPROFILE} || getcwd(); 35 | our $DOTFILES = abs_path("$FindBin::RealBin/../.."); 36 | our $BACKUP = "$DOTFILES/backup"; 37 | 38 | # Threshhold at which to start notifying about possible updates. 39 | our $UPDATE_FILE = "$DOTFILES/.last-updated"; 40 | our $UPDATE_THRESHHOLD = 60*60*24*15; 41 | 42 | =head1 OPTIONS 43 | 44 | =over 4 45 | 46 | =item --noop 47 | 48 | Don't make any changes to the filesystem; just go through the motions. 49 | 50 | =item --copy 51 | 52 | Use file copies instead of symlinks, in case your host platform doesn't support 53 | symlinks. 54 | 55 | In C<--copy> mode, any existing symlinks to a dotfile will be deleted and 56 | replaced with a normal file copy. 57 | 58 | =item --force 59 | 60 | Force certain subcommands to do as much work as possible. 61 | 62 | In C<--force> mode, all existing symlinks to a dotfile will be deleted and 63 | re-linked (or copied if used with C<--copy>). 64 | 65 | When used with C, it always tells you the update notification 66 | including how many days since you've last updated. 67 | 68 | =item --help 69 | 70 | Shows this help documentation. 71 | 72 | =back 73 | 74 | =cut 75 | 76 | # Global command line arguments. 77 | our $noop = 0; 78 | our $copy = 0; 79 | our $force = 0; 80 | 81 | # Process command line arguments. 82 | sub flags { 83 | # Command line flags. 84 | my $help = 0; 85 | GetOptions( 86 | "force" => \$force, 87 | "noop" => \$noop, 88 | "copy" => \$copy, 89 | "help|?" => \$help, 90 | ); 91 | 92 | if ($help) { 93 | exec("perldoc", $0); 94 | } 95 | } 96 | 97 | sub main { 98 | flags(); 99 | if (scalar @ARGV == 0) { 100 | die "Usage: dfm [args...]\n"; 101 | } 102 | 103 | # Handle commands. 104 | my $command = lc(shift @ARGV); 105 | 106 | if ($command eq "setup") { 107 | setup(); 108 | if (fork() == 0) { 109 | open(STDOUT, '>', File::Spec->devnull()); 110 | open(STDERR, '>', File::Spec->devnull()); 111 | print "[`dfm vim` finished]\n"; 112 | vim(); 113 | } 114 | } elsif ($command eq "vim") { 115 | vim(); 116 | } elsif ($command eq "check-update") { 117 | checkUpdate(); 118 | } elsif ($command eq "update") { 119 | update(); 120 | } else { 121 | die "Invalid command. See `dfm --help`.\n"; 122 | } 123 | 124 | return; 125 | } 126 | 127 | =head1 COMMANDS 128 | 129 | =over 4 130 | 131 | =item C 132 | 133 | Sets up and installs the dotfiles. 134 | 135 | All files under the C<.dotfiles/home> directory are symlinked into their 136 | respective paths in C<$HOME>. 137 | 138 | If a file already exists in C<$HOME> and is not a link, the original file is 139 | copied into C<.dotfiles/backup> and then deleted and replaced with a link. 140 | 141 | Files that are already links are not modified, unless the C<--force> command 142 | line flag is used. Then links will be removed and relinked. 143 | 144 | At the end, this also calls C in the background to handle Vim plugins. 145 | 146 | =cut 147 | 148 | sub setup { 149 | crawl("$DOTFILES/home"); 150 | 151 | # Log the time we last ran this. 152 | updated(time()); 153 | } 154 | 155 | =item C 156 | 157 | Sets up my Vim plugins. 158 | 159 | I use Git submodules for my Vim plugins, and these take several seconds to 160 | download when setting up my dotfiles for the first time. 161 | 162 | Calling C will also call C (in the background) at the end, 163 | so that most of the dotfiles get linked immediately and then the Vim ones 164 | follow shortly after, without making me wait for the submodules to download. 165 | 166 | =cut 167 | 168 | sub vim { 169 | # Initialize the git submodules to pull down our Vim plugins. 170 | print "Initializing git submodules...\n"; 171 | chdir($DOTFILES); 172 | system("git submodule update --init"); 173 | chdir($HOME); 174 | print "Submodules updated!\n\n"; 175 | 176 | # And re-run `dfm setup` to install the vim dotfiles. 177 | setup(); 178 | } 179 | 180 | =item C 181 | 182 | Check if the dotfiles haven't been updated in a while. 183 | 184 | This is intended to be called from your C<.bashrc> to notify that updates 185 | may be available, when the dotfiles were last updated greater than 15 days ago. 186 | 187 | If the last-update threshhold is greater than 15 days, it prints a message like: 188 | 189 | It has been 15 days since you've updated your dotfiles (`dfm update`) 190 | 191 | Otherwise it doesn't print anything. Use C<--force> to force it to print. 192 | 193 | It only notifies about updates one time per day (by modifying the time stamp 194 | on the C<.last-updated> file). 195 | 196 | =cut 197 | 198 | sub checkUpdate { 199 | my $time = updated(); 200 | 201 | my ($mtime) = (stat($UPDATE_FILE))[9]; 202 | my $delta = time() - $time; 203 | my $days = int($delta / (60*60*24)); 204 | 205 | # Need to notify? If the last-updated time is >15 days and the file 206 | # itself was last modified more than 24h ago. 207 | my $notify = (time() - $time > $UPDATE_THRESHHOLD) && (time() - $mtime > 60*60*24); 208 | 209 | if ($force || $notify) { 210 | print "It has been $days days since you've updated your dotfiles (" . 211 | "`dfm update`)\n"; 212 | } 213 | 214 | system("touch", $UPDATE_FILE); 215 | exit 0; 216 | } 217 | 218 | =item C 219 | 220 | Update the dotfiles. 221 | 222 | This will go into the git repo and do a C and re-link any new files. 223 | 224 | =cut 225 | 226 | sub update { 227 | chdir($DOTFILES); 228 | system("git stash; git pull; git stash pop"); 229 | setup(); 230 | } 231 | 232 | =back 233 | 234 | =cut 235 | 236 | sub crawl { 237 | my ($directory) = @_; 238 | 239 | opendir(my $dh, $directory); 240 | foreach my $file (readdir($dh)) { 241 | next if $file =~ /^\.+$/; # Skip . and .. 242 | 243 | # Get the absolute path to this file in the dotfiles repo and its 244 | # destination relative to $HOME. 245 | my $source = "$directory/$file"; 246 | my $target = $source; 247 | $target =~ s{^$DOTFILES/home}{$HOME}g; 248 | my $backup = $source; 249 | $backup =~ s{^$DOTFILES/home}{$BACKUP}g; 250 | 251 | # If the source is a directory, make sure it exists relative to $HOME. 252 | if (-d $source) { 253 | if (!-d $target) { 254 | print "Create directory: $target\n"; 255 | mkdir($target) unless $noop; 256 | } 257 | if (!-d $backup) { 258 | mkdir($backup) unless $noop; 259 | } 260 | 261 | # Recursively descend into the directory. 262 | crawl($source); 263 | next; 264 | } 265 | 266 | # Besides directories we only care about normal files. 267 | next unless -f $source; 268 | 269 | # Existing non-link targets should be backed up. 270 | if (-f $target && !-l $target) { 271 | print "Back up existing file to: $backup\n"; 272 | if (!-d $BACKUP) { 273 | mkdir($BACKUP) unless $noop; 274 | } 275 | copy($target, $backup) unless $noop; 276 | unlink($target) unless $noop; 277 | } 278 | 279 | # If in `copy` or `force` mode, delete any existing symlink. 280 | if (-l $target && ($copy || $force)) { 281 | my $link = readlink($target); 282 | my $label = $copy ? "copy" : "force"; 283 | print "[--$label] Delete existing link (was $target -> $link)\n"; 284 | unlink($target) unless $noop; 285 | } 286 | 287 | # Already linked? 288 | if (-l $target || ($copy && -f $target)) { 289 | my $link = readlink($target); 290 | if ($link ne $source) { 291 | print "Removing old link; wrong target (was $target -> $link)\n"; 292 | unlink($target) unless $noop; 293 | } else { 294 | # Already linked! 295 | next; 296 | } 297 | } 298 | 299 | # Link it. 300 | print "Link: $target\n"; 301 | if ($copy) { 302 | copy($source, $target) unless $noop; 303 | } else { 304 | symlink($source, $target) unless $noop; 305 | } 306 | 307 | # Fix permissions. 308 | if ($source =~ m{.ssh/config$}) { 309 | print "Fix permissions: .ssh/config\n"; 310 | chmod 0600, $target unless $noop; 311 | } 312 | } 313 | } 314 | 315 | # Get or set the 'last updated' time. 316 | sub updated { 317 | my ($setting) = @_; 318 | 319 | if ($setting) { 320 | open(my $fh, ">", $UPDATE_FILE); 321 | print {$fh} Dumper({ time => $setting }); 322 | close($fh); 323 | return $setting; 324 | } 325 | 326 | if (-f $UPDATE_FILE) { 327 | my $data = do $UPDATE_FILE; 328 | return $data->{time} || 0; 329 | } 330 | 331 | return 0; 332 | } 333 | 334 | main() unless caller; 335 | 336 | =head1 AUTHOR 337 | 338 | Noah Petherbridge, L 339 | 340 | =cut 341 | -------------------------------------------------------------------------------- /home/bin/docker-enter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # docker-enter: Get inside a docker container, using nsenter. 4 | # 5 | # Usage: docker-enter 6 | # 7 | # See also: 8 | # https://jpetazzo.github.io/2014/03/23/lxc-attach-nsinit-nsenter-docker-0-9/ 9 | # 10 | # --Kirsle 11 | # http://sh.kirsle.net/ 12 | 13 | use strict; 14 | use warnings; 15 | 16 | if (scalar(@ARGV) != 1) { 17 | die "Usage: $0 \n"; 18 | } 19 | 20 | my $container_id = shift(@ARGV); 21 | 22 | # Get the process ID. 23 | chomp(my $pid = `docker inspect --format '{{.State.Pid}}' $container_id`); 24 | die "Couldn't get process ID for that container!\n" unless $pid; 25 | 26 | # Enter the docker container. 27 | exec("nsenter --target $pid --mount --uts --ipc --net --pid"); 28 | -------------------------------------------------------------------------------- /home/bin/fedora-setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Installs my favorite programs on a new Fedora system. 5 | 6 | Most things are generally safe enough to install on any Fedora system, but there 7 | are command line flags for some of the possibly dangerous options: 8 | 9 | --xfce 10 | This installs MATE components on an Xfce desktop. Normally the Xfce 11 | desktop would be automatically detected, but if not, provide this 12 | option. 13 | 14 | --plymouth, -p 15 | Install and configure my favorite Plymouth theme (solar). This option 16 | must be explicitly passed in because changing the Plymouth theme might 17 | not always be desired. 18 | 19 | --wl 20 | Install the Broadcom wireless drivers (akmod-wl). Only do this on 21 | systems that need the `wl` driver. 22 | 23 | --dry-run 24 | Do not actually change any packages on the system. 25 | 26 | Fonts: 27 | - Microsoft core fonts 28 | - Emoji fonts 29 | 30 | Apps: 31 | - Firefox, Thunderbird 32 | - The GIMP 33 | - Banshee 34 | - MATE Desktop counterparts to my favorite old GNOME apps (--xfce only): 35 | - Eye of MATE (Image viewer, fork of Eye of GNOME) 36 | - Engrampa (archive manager, fork of file-roller) 37 | - Pluma (text editor, fork of gedit) 38 | - Atril (PDF viewer, fork of evince) 39 | 40 | Dev stuff: 41 | - zsh 42 | - python-virtualenvwrapper 43 | - git 44 | - golang 45 | - pyflakes 46 | - nodejs, npm 47 | 48 | Filesystems: 49 | - fuse-encfs 50 | - fuse-exfat 51 | - gvfs-mtp 52 | 53 | Misc: 54 | - Video codecs 55 | - h264 support for Firefox HTML5 videos 56 | - VLC Media Player 57 | 58 | Themes: 59 | - Bluecurve Cursor Theme 60 | - Solar Plymouth Theme 61 | 62 | --Kirsle 63 | http://sh.kirsle.net/ 64 | """ 65 | 66 | import argparse 67 | import hashlib 68 | import os 69 | import subprocess 70 | 71 | class Application(object): 72 | def __init__(self, args): 73 | self.to_install = [] 74 | 75 | # Detect desktop environments. 76 | desktop = os.environ.get("XDG_CURRENT_DESKTOP", "").upper() 77 | self.xfce = args.xfce or desktop == "XFCE" 78 | 79 | # More args. 80 | self.noop = args.dry_run 81 | self.plymouth = args.plymouth 82 | self.wl = args.wl 83 | 84 | # Using custom configs? 85 | self.custom = self.xfce or self.plymouth or self.wl 86 | 87 | def main(self): 88 | """Main entry point of the app.""" 89 | 90 | # Update first. 91 | self.shell("sudo dnf -y update") 92 | 93 | # The latest RPM Fusion. 94 | if not self.test("rpm -q rpmfusion-free-release"): 95 | self.shell("sudo dnf install --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm") 96 | 97 | # Microsoft core fonts and Emoji support. 98 | if not self.test("rpm -q msttcore-fonts"): 99 | # The fonts aren't signed, so verify their checksum. 100 | self.shell("wget -O /tmp/msttcore-fonts.rpm https://rpm.kirsle.net/any/rpm/msttcore-fonts-2.0-3.noarch.rpm") 101 | expect_sum = "a20ecca993827d10bb51118a0cfdf8a1e65f161a78361bee865a138ca5a4f43f" 102 | if not self.noop and self.sha256sum("/tmp/msttcore-fonts.rpm") != expect_sum: 103 | print("!!! WARNING !!!") 104 | print("The SHA256 hash of msttcore-fonts doesn't match what I expected!") 105 | print("Expected: {}".format(expect_sum)) 106 | print(" Got: {}".format(self.sha256sum("/tmp/msttcore-fonts.rpm"))) 107 | input("Press any key to continue. . .") 108 | else: 109 | self.shell("sudo dnf install /tmp/msttcore-fonts.rpm") 110 | 111 | if os.path.isfile("/tmp/msttcore-fonts.rpm"): 112 | os.unlink("/tmp/msttcore-fonts.rpm") 113 | self.install("gdouros-symbola-fonts") 114 | 115 | # My favorite desktop apps. 116 | self.install( 117 | "firefox", 118 | "thunderbird", 119 | "gimp", 120 | "libreoffice", 121 | ) 122 | 123 | # Ones that I mainly want on the Xfce desktop (MATE apps) 124 | if self.xfce: 125 | self.install( 126 | "pluma", # gedit (Text Editor) 127 | "atril", # evince (Document Viewer) 128 | "engrampa", # file-roller (Archive Manager) 129 | "eom", # eog (Picture Viewer) 130 | "tumbler", # thumbnailer for Thunar file browser 131 | "ffmpegthumbnailer", # video thumbnail support 132 | ) 133 | 134 | # Development stuff. 135 | self.install( 136 | "ctags", 137 | "git", 138 | "golang", 139 | "nodejs", 140 | "npm", 141 | "zsh", 142 | ) 143 | 144 | # Filesystems 145 | self.install("fuse-encfs", "fuse-exfat", "gvfs-mtp") 146 | 147 | # Codecs and plugins and Firefox h264 video support 148 | self.install("gstreamer1-libav", "gstreamer1-vaapi", 149 | "gstreamer1-plugins-good", "gstreamer1-plugins-ugly", 150 | "gstreamer1-plugins-good-extras", "gstreamer1-plugins-bad-free", 151 | "gstreamer1-plugins-bad-freeworld", "vlc") 152 | 153 | self.commit() 154 | 155 | print("\nSuccess! Everything has been set up and configured.") 156 | if self.custom: 157 | print("\nThe following custom software groups were included:\n") 158 | if self.xfce: 159 | print("\tThe XFCE set (MATE desktop utilities for XFCE)") 160 | if self.plymouth: 161 | print("\tThe Solar Plymouth theme") 162 | if self.wl: 163 | print("\tThe Broadcom proprietary WiFi driver") 164 | 165 | def install(self, *rpm): 166 | """Name an rpm I wanna install. Checks if it's already installed first, 167 | then adds it to the self.to_install list.""" 168 | for item in rpm: 169 | if not self.test("rpm -q {}".format(item)): 170 | print("* To install: {}".format(item)) 171 | self.to_install.append(item) 172 | 173 | def commit(self): 174 | """Install the pending RPMs.""" 175 | if len(self.to_install) > 0: 176 | print("Installing...") 177 | self.shell("sudo dnf -y install {}".format(" ".join(self.to_install))) 178 | self.to_install = [] 179 | 180 | def shell(self, cmd): 181 | print("EXECUTE: {}".format(cmd)) 182 | if self.noop: 183 | return 184 | 185 | subprocess.call(cmd, shell=True) 186 | 187 | def test(self, command): 188 | """Test if a command exits successfully.""" 189 | if self.noop: 190 | return False 191 | 192 | try: 193 | subprocess.check_call("{} >/dev/null 2>&1".format(command), shell=True) 194 | return True 195 | except subprocess.CalledProcessError: 196 | return False 197 | 198 | def sha256sum(self, file): 199 | """Get the SHA256 checksum of a file.""" 200 | m = hashlib.sha256() 201 | with open(file, 'rb') as fh: 202 | m.update(fh.read()) 203 | return m.hexdigest() 204 | 205 | if __name__ == "__main__": 206 | parser = argparse.ArgumentParser(description="Noah's Fedora Setup Script") 207 | parser.add_argument("--xfce", "-x", 208 | help="Assume the Xfce desktop environment and install useful MATE " 209 | "utilities (pluma, atril, eom, engrampa)", 210 | action="store_true", 211 | ) 212 | parser.add_argument("--plymouth", "-p", 213 | help="Install and configure the Solar plymouth theme (only if the " 214 | "theme is not presently installed)", 215 | action="store_true", 216 | ) 217 | parser.add_argument("--wl", 218 | help="Install the Broadcom `wl` WiFi driver (akmod-wl)", 219 | action="store_true", 220 | ) 221 | parser.add_argument("--dry-run", 222 | help="Do not actually modify any packages on the system.", 223 | action="store_true", 224 | ) 225 | app = Application(args=parser.parse_args()) 226 | app.main() 227 | -------------------------------------------------------------------------------- /home/bin/flatten-linked: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # flatten-linked - Create symlinks to every file in a directory, recursively, 4 | # creating the links in the current working directory. 5 | # 6 | # If you have iTunes or similar managing your music and it organizes them in a 7 | # large folder structure (Band Name/Album Name/Song Name.mp3) you can run this 8 | # script on your iTunes folder and it will create links to every file in the 9 | # current folder. So you'll end up with a single folder "containing" all your 10 | # songs, when really they're all links to their real locations. 11 | # 12 | # But with this you can import your iTunes collection into XMMS or another 13 | # primitive media player very easily, by only importing one folder - the one 14 | # full of links. 15 | # 16 | # --Kirsle 17 | # http://sh.kirsle.net/ 18 | 19 | unless (@ARGV) { 20 | print "Usage: flatten-linked \n" 21 | . "Creates symlinks to all files in current directory\n"; 22 | exit(1); 23 | } 24 | 25 | foreach (@ARGV) { 26 | &crawl($_); 27 | } 28 | closedir (DIR); 29 | 30 | sub crawl { 31 | my $dir = shift; 32 | print "Crawling into directory $dir"; 33 | opendir (DIR, $dir) or die "Can't open dir $dir: $!"; 34 | foreach my $file (sort(grep(!/^\./, readdir(DIR)))) { 35 | if (-d "$dir/$file") { 36 | &crawl("$dir/$file"); 37 | } 38 | elsif (-f "$dir/$file") { 39 | print "Linking $dir/$file as ./$file\n"; 40 | system("ln", "-s", "$dir/$file", "./$file"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /home/bin/flv2avi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # flv2avi - Convert FLV video to AVI (divx or xvid codec). 4 | # 5 | # This script was not written by Kirsle, it was found on the net somewhere. 6 | # 7 | # Usage: flv2avi [-divx|-xvid] list_of_flv_files 8 | # 9 | # --Kirsle 10 | # http://sh.kirsle.net/ 11 | 12 | if [ -z "$1" ]; then 13 | echo "Usage: $0 {-divx|-xvid} list_of_flv_files" 14 | exit 1 15 | fi 16 | 17 | # video encoding bit rate 18 | V_BITRATE=1000 19 | 20 | while [ "$1" ]; do 21 | case "$1" in 22 | -divx) 23 | MENC_OPTS="-ovc lavc -lavcopts \ 24 | vcodec=mpeg4:vbitrate=$V_BITRATE:mbd=2:v4mv:autoaspect" 25 | ;; 26 | -xvid) 27 | MENC_OPTS="-ovc xvid -xvidencopts bitrate=$V_BITRATE:autoaspect" 28 | ;; 29 | *) 30 | if file "$1" | grep -q "Macromedia Flash Video"; then 31 | mencoder "$1" $MENC_OPTS -vf pp=lb -oac mp3lame \ 32 | -lameopts fast:preset=standard -o \ 33 | "`basename $1 .flv`.avi" 34 | else 35 | echo "$1 is not Flash Video. Skipping" 36 | fi 37 | ;; 38 | esac 39 | shift 40 | done 41 | 42 | -------------------------------------------------------------------------------- /home/bin/git-branch-check: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # git-branch-check: Compare your local git branches with the remote. 4 | # 5 | # Usage: git-branch-check [remote] 6 | # 7 | # Default remote name is "origin", provide [remote] to change that. 8 | # 9 | # --Kirsle 10 | # https://www.kirsle.net/ 11 | 12 | from __future__ import print_function 13 | 14 | import sys 15 | import subprocess 16 | 17 | remote = "origin" 18 | if len(sys.argv) >= 2: 19 | remote = sys.argv[1] 20 | 21 | local_branch = set() 22 | remote_branch = set() 23 | 24 | subprocess.call(["git", "remote", "update", remote, "--prune"]) 25 | 26 | data = subprocess.check_output(["git", "branch", "-a"]).decode() 27 | for line in data.split("\n"): 28 | # Remove the currently active branch indicator and extra spaces. 29 | line = line.strip("*").strip() 30 | if not len(line): continue 31 | 32 | # Remote branch? 33 | if line.startswith("remotes/{}/".format(remote)): 34 | line = line.replace("remotes/{}/".format(remote), "") 35 | remote_branch.add(line) 36 | elif line.startswith("remotes/"): 37 | # A different remote? 38 | pass 39 | else: 40 | local_branch.add(line) 41 | 42 | # Show comparisons. 43 | print("Local branches that are not on the remote:") 44 | for branch in sorted(local_branch): 45 | if not branch in remote_branch: 46 | print("*", branch) 47 | 48 | # vim:expandtab 49 | -------------------------------------------------------------------------------- /home/bin/gosh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """gosh: use Golang as a shell scripting language. 4 | 5 | This is written in Python so that I don't have to commit any binaries to my 6 | dotfiles repo, and my Go shell scripts can also remain in source form. 7 | 8 | Usage: write a Go program with this shebang comment on top immediately before 9 | the `package main` statement: 10 | 11 | #!/usr/bin/env gosh 12 | package main 13 | 14 | And make it executable and run it like any shell script. 15 | """ 16 | 17 | import codecs 18 | import os 19 | import subprocess 20 | import sys 21 | import tempfile 22 | 23 | def main(): 24 | if len(sys.argv) == 1: 25 | die("Usage: gosh ") 26 | 27 | # Get the Go source file from the command line. 28 | source = sys.argv[1] 29 | argv = sys.argv[2:] 30 | if not os.path.isfile(source): 31 | die("{}: not a file".format(source)) 32 | 33 | # Make a temp file that lacks the shebang line of the input file. 34 | with codecs.open(source, "r", "utf-8") as fh: 35 | # Get the shebang off and sanity check it. 36 | shebang = fh.readline() 37 | if not "gosh" in shebang: 38 | die("{}: doesn't appear to be a Go script".format(source)) 39 | 40 | # Write it to a temp file, sans shebang. 41 | temp = tempfile.NamedTemporaryFile(delete=False, suffix=".go") 42 | temp.write(fh.read().strip().encode()) 43 | temp.close() 44 | 45 | # Call it. 46 | subprocess.call(["go", "run", temp.name] + argv) 47 | 48 | # Clean up. 49 | os.unlink(temp.name) 50 | 51 | def die(message): 52 | print(message) 53 | sys.exit(1) 54 | 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /home/bin/grkill: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # grkill - Kill command and grep all in one! 4 | # Usage: grkill [options] "grep string" 5 | # 6 | # Does a `ps aux | grep STRING` and for each PID found, runs a `kill` command 7 | # passing any other options verbatim. For example, `grkill -9 application.py` 8 | # would kill any process with "application.py" in its command line. 9 | # 10 | # --Kirsle 11 | # http://sh.kirsle.net/ 12 | 13 | from sys import argv, exit 14 | import re 15 | import subprocess 16 | 17 | def main(): 18 | if len(argv) < 2: 19 | print "Usage: {} [options] ".format(argv[0]) 20 | exit(1) 21 | 22 | # Separate the search string from other options. 23 | options = argv[1:] 24 | grep = options.pop() 25 | 26 | # Do a `ps aux | grep` 27 | try: 28 | ps = subprocess.check_output( 29 | "ps aux | grep {} | grep -v grep | grep -v grkill".format(grep), 30 | shell=True 31 | ) 32 | except: 33 | print "No processes found." 34 | exit(1) 35 | 36 | for line in ps.split("\n"): 37 | if not line.strip(): 38 | continue 39 | pid = re.split(r'\s+', line)[1] 40 | 41 | # And kill it. 42 | subprocess.call("kill {opts} {pid}".format( 43 | opts=" ".join(options), 44 | pid=pid, 45 | ), shell=True) 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /home/bin/gsync: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # gsync - Graphically run the `sync` command to flush the write buffers to 4 | # flash drives and things in Linux. 5 | # 6 | # If you want to make sure data is written to a flash drive without having to 7 | # unmount it, sync is the command to run. This just adds libnotify popups 8 | # about it. 9 | 10 | use strict; 11 | use warnings; 12 | 13 | # Icon to use 14 | my $icon = "/usr/share/icons/gnome/32x32/actions/stock_refresh.png"; 15 | 16 | # Start 17 | system("notify-send", 18 | "--icon" => $icon, 19 | "Syncing removable media..."); 20 | my $now = time(); 21 | system("sync"); 22 | my $elapsed = time() - $now; 23 | system("notify-send", 24 | "--icon" => $icon, 25 | "Sync completed in $elapsed second" . ($elapsed == 1 ? '' : 's') . "!"); 26 | -------------------------------------------------------------------------------- /home/bin/gu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Set my local git e-mail on a per-repo basis to my work vs. home address. 4 | # 5 | # Usage: `gu work` or `gu home` (or shortcuts: `gu w` and `gu h`) 6 | 7 | if (scalar @ARGV == 0) { 8 | die "Usage: gu work || gu home || gu w || gu h\n"; 9 | } 10 | 11 | my $env = shift(@ARGV); 12 | my $email = ''; 13 | 14 | if ($env =~ /^w/i) { 15 | $email = 'noah@with.in'; 16 | } 17 | elsif ($env =~ /^n/i) { 18 | system(qw(git config user.name), 'Noah'); 19 | $email = 'noah@nonshy.com'; 20 | } 21 | elsif ($env =~ /^h/i) { 22 | $email = 'root@kirsle.net'; 23 | } 24 | else { 25 | die "Invalid environment option, should be w[ork] or h[ome]\n"; 26 | } 27 | 28 | if (!-d "./.git") { 29 | die "You don't appear to be inside a git repository.\n"; 30 | } 31 | 32 | system(qw(git config user.email), $email); 33 | print "E-mail updated as $email for this repository.\n"; 34 | -------------------------------------------------------------------------------- /home/bin/h264ify: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """h264ify - Upgrade my videos to h.264/AAC for Chromecast. 4 | 5 | With Google Chrome, you can Chromecast any movie file from your PC by dragging 6 | the movie into a Chrome window, and then cast the tab to your Chromecast. 7 | 8 | However this only works if the video is encoded with H.264 for video and 9 | AAC for audio. Other video files will instead "download" in Chrome instead of 10 | play inside the tab. 11 | 12 | This script takes input video file names (without a `.mp4` extension), and 13 | encodes them into a file of the same name but with a `.mp4` extension. 14 | 15 | Usage: h264ify