-
Notifications
You must be signed in to change notification settings - Fork 13
/
dotfiles
executable file
·205 lines (183 loc) · 5.29 KB
/
dotfiles
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/bin/sh
# vim: fdm=marker
#
# dotfiles - track dotfiles in git directly from your home directory
#
# Copyright (c) 2017-2019 by Eli Schwartz <[email protected]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
[ -f "${XDG_CONFIG_HOME:-$HOME/.config}"/dotfiles.conf ] && . "${XDG_CONFIG_HOME:-$HOME/.config}"/dotfiles.conf
usage() {
cat <<- _EOF_
Usage: dotfiles [-h|--help] <COMMAND>
Thin wrapper around git to version dotfiles. Most commands are passed
straight through to git with a custom GIT_DIR to store dotfiles metadata
outside of the top-level home directory.
OPTIONS
-h, --help Show this usage message
CUSTOM COMMANDS
init Init a bare git repository and set it up as an
empty dotfiles repository
clone Clone an existing dotfiles repository and integrate
it with \$HOME. If existing files clash with repository
files, they must be manually resolved.
ignore Add new strings to gitignore, or edit the gitignore
directly, without using ~/.gitignore
readme Edit the repository README.md without using ~/README.md
_EOF_
}
error() {
local mesg="${1:-An unknown error occurred.}"
printf "==> ERROR: %s\nAborting...\n" "$mesg" 1>&2
exit 1
}
sparse_tree() {
cat <<- _EOF_
/*
!README.md
!LICENSE
!.gitattributes
!.gitignore
_EOF_
}
# gitignore {{{
base_gitignore() {
cat <<- _EOF_
# XDG user dirs
Desktop/
Documents/
Downloads/
Music/
Pictures/
Public/
Templates/
Videos/
# Security
.gnupg/*
!.gnupg/*.conf
.ssh/
# Common caches
.adobe/
.atom/
.*cache/
.gem/
.macromedia/
.node-gyp/
.npm/
.cargo/
.thumbnails/
.wget-hsts
.v8flags*
# Misc commonly generated files
.bash_history
.zsh_history
.bazaar/
.dbus/
.dropbox/
.ICEauthority
.lesshst
.python_history
.sqlite_history
.psql_history
.subversion/
.wine/
.Xauthority
.xsession-errors
# Misc junk files
*~
*.bak
*.log
*.swp
*.tmp
# Automatically appended
_EOF_
}
# }}}
# Init {{{
init_setup() {
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}"
echo "dotfiles_dir=$dotfiles_dir" > "${XDG_CONFIG_HOME:-$HOME/.config}"/dotfiles.conf
sparse_tree > "$dotfiles_dir"/info/sparse-checkout
git --git-dir "$dotfiles_dir" config --local core.bare false
git --git-dir "$dotfiles_dir" config --local core.worktree ~
git --git-dir "$dotfiles_dir" config --local core.sparseCheckout true
git --git-dir "$dotfiles_dir" config --local status.showUntrackedFiles no
}
init() {
if ! dotfiles_dir="$("$readlink" -m "${1:-.}")"; then
error "failed to resolve directory '$1'"
fi
git init --bare "$dotfiles_dir" || error "failed to init repository in '$1'"
init_setup
base_gitignore > "$dotfiles_dir"/info/exclude
}
clone() {
if ! dotfiles_dir="$("$readlink" -m "${2:-dotfiles}")"; then
error "failed to resolve directory '$2'"
fi
git clone --bare "$1" "$dotfiles_dir" || error "failed to clone '$1'"
init_setup
# If there is no .gitignore yet, this will just clobber some comments
git --git-dir "$dotfiles_dir" show HEAD:.gitignore > "$dotfiles_dir"/info/exclude 2>/dev/null
git --git-dir "$dotfiles_dir" show HEAD:.gitattributes > "$dotfiles_dir"/info/attributes 2>/dev/null
git --git-dir "$dotfiles_dir" checkout
}
# }}}
edit_info() {
local infofile="$dotfiles_dir/info/$1" dotfile="$2"; shift 2
if [ $# -eq 0 ]; then
${EDITOR:-vim} "$infofile"
else
printf '%s\n' "$@" >> "$infofile"
fi
git --git-dir="$dotfiles_dir" update-index --add --cacheinfo 10064,$(git --git-dir="$dotfiles_dir" hash-object -w "$infofile"),"$dotfile"
git --git-dir "$dotfiles_dir" checkout --quiet
}
readme() {
local readme_file="$(mktemp -dt dotfiles.XXXXXX)/README.md"
git --git-dir="$dotfiles_dir" show :README.md > "$readme_file"
${EDITOR:-vim} "$readme_file"
git --git-dir="$dotfiles_dir" update-index --add --cacheinfo 10064,$(git --git-dir="$dotfiles_dir" hash-object -w "$readme_file"),README.md
rm -r "${readme_file%README.md}"
git --git-dir "$dotfiles_dir" checkout --quiet
}
# Main
# prefer GNU-prefixed readlink for macOS
readlink=$(command -v greadlink || command -v readlink)
if [ -n "$1" ]; then
# POSIX shift complains if there is nothing to pop.
dot_cmd="$1"
shift
fi
case $dot_cmd in
-h|--help|help)
usage
exit
;;
init|clone)
$dot_cmd "$@"
;;
ignore)
edit_info exclude .gitignore "$@"
;;
attributes)
edit_info attributes .gitattributes "$@"
;;
readme)
$dot_cmd
;;
*)
git --git-dir="$dotfiles_dir" $dot_cmd "$@"
esac