]> us-delaporte.pagekite.me Git - dotfiles.git/blob - bin/dot
Add dotbot for weird path link files
[dotfiles.git] / bin / dot
1 #!/bin/bash
2 ENVS="$HOME/envs" # Python environments - including required Ansible
3 ANSIBLE="$ENVS/ansible/bin/ansible-playbook" # Core command
4 TASKFILE="$HOME/backup/dot.$HOSTNAME.yaml" # Backup of localhost config
5 DOTFILES="$HOME/dotfiles" # Where to find dotfiles
6
7 LINKFILES="$DOTFILES/files" # Files to symlink
8 INSTALLS="$DOTFILES/install" # Install scripts
9 DOT="$HOME/.dot" # Touched files go here to track installs
10 REQS="$DOTFILES/reqs" # Python env requirements.txt files
11
12 mkdir -p "$DOT"
13
14 read -d '' HELP << EOF
15 dot - a (mostly) one script dotfiles manager
16
17 Copyright 2026 Edward Delaporte V
18 Licensed under AGPLv3 and later.
19
20 dot setup
21 install ansible CLI to $ANSIBLE
22
23 dot link FILE
24 updates ~/dot.HOSTNAME.yaml
25 to include a symlink from ~/dotfiles/files/FILE to ~/.FILE
26
27 dot check
28 check setup against ~/backup/dot.HOSTNAME.yaml
29
30 dot apply
31 apply config in ~/backup/dot.HOSTNAME.yaml
32
33 dot help FEATURE
34 setup - more information on setup
35 all - additional features
36 EOF
37
38 read -d '' SETUP_HELP << EOF
39 ## Setup
40
41 1. Install this file on your path
42 2. Clone your (or my) 'dotfiles' repository to ~/dotfiles
43 3. Run 'dot help' to get started.
44
45 EOF
46
47
48 read -d '' EXTRA_HELP << EOF
49
50 dot list
51 display the contents of $TASKFILE
52
53 dot install SCRIPT
54 updates ~/dot.HOSTNAME.yaml
55 to run ~/dotfiles/SCRIPT.sh if it has not yet been run
56 creates ~/dot/SCRIPT.installed after SCRIPT has been run
57
58 dot env ENV
59 create Python environment ~/envs/ENV based on ~/dotfiles/reqs/ENV.txt
60
61 EOF
62
63
64 if [ ! -n "$1" ] || [ "$1" == "help" ]; then
65 echo "$HELP"
66 fi
67 if [ "$1" == "help" ] && [ "$2" == "all" ]; then
68 echo ""
69 echo "$EXTRA_HELP"
70 echo ""
71 echo "$SETUP_HELP"
72 fi
73 if [ "$1" == "help" ] && [ "$2" == "setup" ]; then
74 echo ""
75 echo "$SETUP_HELP"
76 fi
77
78 # set -v
79 #
80
81
82 read -d '' EMPTY_TASKFILE << EOF
83 ---
84 - name: Set up dotfiles on $HOSTNAME
85 gather_facts: no
86 hosts: localhost
87 connection: local
88
89 tasks:
90 - name: Check on $TASKFILE
91 ansible.builtin.stat:
92 path: $TASKFILE
93 EOF
94
95 if [[ ! -f "$TASKFILE" ]]; then
96 echo "Creating empty $TASKFILE"
97 mkdir -p "$HOME/backup"
98 echo "$EMPTY_TASKFILE" >> $TASKFILE
99 fi
100
101 if [ "$1" == "list" ]; then
102 cat $TASKFILE
103 exit 0
104 fi
105
106 if [ "$1" == "setup" ]; then
107 if [[ ! -f "$ANSIBLE" ]]; then
108 mkdir -p "$ENVS"
109 echo "Setting up Ansible in ~/envs/ansible"
110 cd $HOME/envs; python3 -m venv ansible
111 $HOME/envs/ansible/bin/pip install ansible jinja2
112 fi
113 if [[ -f "$ANSIBLE" ]]; then
114 echo "[ ok ]: Ansible setup at $ANSIBLE"
115 fi
116 if [[ -f "$TASKFILE" ]]; then
117 echo "[ ok ]: dot config at $TASKFILE"
118 fi
119 fi
120
121 if [ "$1" == "reset" ]; then
122 read -n1 -p "Reset $TASKFILE? [y,N]" input
123 if [[ ! $input == "Y" && ! $input == "y" ]]; then
124 echo "Aborted by user"
125 exit 1
126 fi
127 echo "$EMPTY_TASKFILE" > $TASKFILE
128 echo ""
129 fi
130
131
132 if [ "$1" == "check" ]; then
133 $ANSIBLE $TASKFILE --check --diff
134 fi
135
136 if [ "$1" == "link" ]; then
137 if [ ! -n "$2" ]; then
138 echo "Can symlink: (from $LINKFILES)"
139 cd $LINKFILES
140 ls -p | grep -v /
141 exit 1
142 fi
143
144 read -d '' LINK_THIS_FILE << EOF
145
146 - name: symlink $2
147 ansible.builtin.file:
148 src: "$LINKFILES/$2"
149 dest: "$HOME/.$2"
150 state: "link"
151 EOF
152
153 if [[ "$2" == *"."* ]];then
154 # File already contains a dot
155 read -d '' LINK_THIS_FILE << EOF
156
157 - name: symlink $2
158 ansible.builtin.file:
159 src: "$LINKFILES/$2"
160 dest: "$HOME/$2"
161 state: "link"
162 EOF
163
164
165 fi
166
167 echo " $LINK_THIS_FILE" >> $TASKFILE
168 echo "$2 added to symlinks in $TASKFILE"
169 echo "Run 'dot apply' to create all configured symlinks"
170 fi
171
172 if [ "$1" == "apply" ]; then
173 if [[ ! -f "$TASKFILE" ]]; then
174 echo "$TASKFILE is missing. Run 'dot setup'"
175 exit 1
176 fi
177 $ANSIBLE -v $TASKFILE
178 fi
179
180 if [ "$1" == "install" ]; then
181 if [ ! -n "$2" ]; then
182 echo "Can install: (.sh scripts in $INSTALLS)"
183 cd $INSTALLS
184 ls -p | grep -v / | grep .sh
185 exit 1
186 fi
187 if [[ ! -f "$INSTALLS/$2.sh" ]]; then
188 echo "No such install script $INSTALLS/$2.sh"
189 echo "Run dot install with no params to list scripts."
190 exit 1
191 fi
192
193 mkdir -p $DOT
194 read -d '' RUN_INSTALL << EOF
195 - name: check $2
196 stat:
197 path: "$DOT/$2.installed"
198 register: $2_installed
199 - name: install $2
200 ansible.builtin.shell: |
201 "$INSTALLS/$2.sh" && touch "$DOT/$2.installed"
202 register: ret
203 failed_when: >
204 ("Error" in ret.stdout) or
205 ("Error" in ret.stderr) or
206 (ret.rc != 0)
207 when: not $2_installed.stat.exists
208 - name: verify $2 is installed
209 ansible.builtin.debug:
210 msg: "$2 is installed."
211 when: $2_installed.stat.exists
212 EOF
213 echo " $RUN_INSTALL" >> $TASKFILE
214 echo "Run 'dot apply' to run the install"
215 fi
216
217
218 if [ "$1" == "env" ]; then
219 if [ ! -n "$2" ]; then
220 echo "Can create: (.txt files in $REQS)"
221 cd $REQS
222 ls -p | grep -v / | grep .txt
223 exit 1
224 fi
225 if [[ ! -f "$REQS/$2.txt" ]]; then
226 echo "No such requirements file script $REQS/$2.txt"
227 echo "Run dot env with no params to list files."
228 exit 1
229 fi
230
231 read -d '' ADD_ENV << EOF
232 - name: check env $2
233 stat:
234 path: "$ENVS/$2"
235 register: $2_path
236 - name: add env $2
237 ansible.builtin.shell: |
238 cd $ENVS
239 python3 -m venv $2
240 $ENVS/$2/bin/python -m pip install -r $REQS/$2.txt
241 when: not $2_path.stat.exists
242 - name: verify env $2 exists
243 ansible.builtin.debug:
244 msg: "env $2 exists"
245 when: $2_path.stat.exists
246 EOF
247 echo " $ADD_ENV" >> $TASKFILE
248 echo "Run 'dot apply' to run the install"
249 fi
250