├── CHANGES ├── Makefile ├── LICENSE ├── yadm.spec ├── README.md ├── yadm.1 ├── yadm.md └── yadm /CHANGES: -------------------------------------------------------------------------------- 1 | 1.02 2 | * Handle permissions for `~/.gnupg/*gpg` 3 | 4 | 1.01 5 | * Set `status.showUntrackedFiles` to "no" 6 | 7 | 1.00 8 | * Initial public release 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: yadm.md 2 | 3 | yadm.md: yadm.1 4 | @groff -man -Tascii ./yadm.1 | col -bx | sed 's/^[A-Z]/## &/g' | sed '/yadm(1)/d' > yadm.md 5 | 6 | pdf: 7 | @groff -man -Tps ./yadm.1 > yadm.ps 8 | @open yadm.ps 9 | @sleep 1 10 | @rm yadm.ps 11 | 12 | man: 13 | groff -man -Tascii ./yadm.1 | less 14 | 15 | wide: 16 | man ./yadm.1 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | yadm - Yet Another Dotfiles Manager 2 | Copyright (C) 2015 Tim Byrne 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | -------------------------------------------------------------------------------- /yadm.spec: -------------------------------------------------------------------------------- 1 | Summary: Yet Another Dotfiles Manager 2 | Name: yadm 3 | Version: 1.02 4 | Release: 1 5 | URL: https://github.com/TheLocehiliosan/yadm 6 | License: GPL 7 | Group: Development/Tools 8 | Packager: Tim Byrne 9 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root 10 | Requires: bash 11 | Requires: git 12 | Source0: %{name}-%{version}.tar.gz 13 | BuildArch: noarch 14 | 15 | %description 16 | yadm is a dotfile management tool with 3 main features: Manages files across 17 | systems using a single Git repository. Provides a way to use alternate files on 18 | a specific OS or host. Supplies a method of encrypting confidential data so it 19 | can safely be stored in your repository. 20 | 21 | %prep 22 | %setup 23 | 24 | %build 25 | 26 | %install 27 | rm -rf ${RPM_BUILD_ROOT} 28 | mkdir -p ${RPM_BUILD_ROOT}%{_bindir} 29 | mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man1 30 | install -m 755 yadm ${RPM_BUILD_ROOT}%{_bindir} 31 | install -m 644 yadm.1 ${RPM_BUILD_ROOT}%{_mandir}/man1 32 | 33 | %clean 34 | rm -rf ${RPM_BUILD_ROOT} 35 | 36 | %files 37 | %defattr(-,root,root) 38 | %attr(755,root,root) %{_bindir}/yadm 39 | %attr(644,root,root) %{_mandir}/man1/* 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yadm - Yet Another Dotfiles Manager 2 | _A house that does not have one warm, comfy chair in it is soulless._—May Sarton 3 | 4 | When you live in a command line, configurations are a deeply personal thing. They are often crafted over years of experience, battles lost, lessons learned, advice followed, and ingenuity rewarded. When you are away from your own configurations, you are an orphaned refugee in unfamiliar and hostile surroundings. You feel clumsy and out of sorts. You are filled with a sense of longing to be back in a place you know. A place you built. A place where all the short-cuts have been worn bare by your own travels. A place you proudly call... `$HOME`. 5 | 6 | ## Introduction 7 | _Home is an invention on which no one has yet improved._—Ann Douglas 8 | 9 | As so many others, I started out with a repository of dotfiles and a few scripts to symbolically link them around my home directory. This quickly became inadequate and I looked for solutions elsewhere. I've used two excellent tools; [homeschick](https://github.com/andsens/homeshick), and [vcsh](https://github.com/RichiH/vcsh). These tools are great, and you should check them out to understand their strengths. However, I didn't find all of the features I personally wished for in a single tool. **yadm** was written with the following goals: 10 | 11 | - Use a single repository 12 | - Few dependencies 13 | - Ability to use alternate files based on OS or host 14 | - Ability to encrypt and track confidential files 15 | - Stay out of the way and let Git do what it's good at 16 | 17 | ## Installation 18 | _Seek home for rest, for home is best._—Thomas Tusser 19 | 20 | #### OSX 21 | 22 | **yadm** can be installed using [Homebrew](https://github.com/Homebrew/homebrew). 23 | 24 | brew tap TheLocehiliosan/yadm && brew install yadm 25 | 26 | #### Linux YUM/RPM 27 | 28 | wget https://bintray.com/thelocehiliosan/rpm/rpm -O bintray-thelocehiliosan-rpm.repo 29 | sudo mv bintray-thelocehiliosan-rpm.repo /etc/yum.repos.d/ 30 | sudo yum install yadm 31 | 32 | Or if not using yum, you can just directly download the RPM 33 | 34 | curl -fLO https://dl.bintray.com/thelocehiliosan/rpm/yadm-1.02-1.noarch.rpm 35 | sudo rpm -ivh yadm-1.02-1.noarch.rpm 36 | 37 | #### Other 38 | 39 | You *can* simply download the **yadm** script and put it into your `$PATH`. Something like this: 40 | 41 | curl -fLo /usr/local/bin/yadm https://github.com/TheLocehiliosan/yadm/raw/master/yadm && chmod a+x /usr/local/bin/yadm 42 | 43 | ## Getting Started 44 | _I would not change my blest estate for all the world calls good or great._—Isaac Watts 45 | 46 | If you know how to use Git, then you already know how to use **yadm**. 47 | See the [man page](yadm.md) for a comprehensive explanation of commands and options. 48 | 49 | 50 | #### If you don't currently have a repository 51 | Start out with an empty local repository 52 | 53 | yadm init 54 | yadm add 55 | yadm commit 56 | 57 | Eventually you will want to push the local repo to a remote. 58 | 59 | yadm remote add origin 60 | yadm push -u origin master 61 | 62 | #### If you have an existing remote repository 63 | This `clone` will attempt to merge your existing repository, but if it fails, it will do a reset instead and you'll have to decide best on how resolve the differences. 64 | 65 | 66 | yadm clone 67 | yadm status 68 | 69 | ## Strategies for alternate files on different systems 70 | _To feel at home, stay at home._—Clifton Fadiman 71 | 72 | Where possible, you should try to use the same file on every system. Here are a few examples: 73 | 74 | ### .vimrc 75 | 76 | let OS=substitute(system('uname -s'),"\n","","") 77 | if (OS == "Darwin") 78 | " do something that only makes sense on a Mac 79 | endif 80 | 81 | ### .tmux.conf 82 | 83 | # use reattach-to-user-namespace as the default command on OSX 84 | if-shell "test -f /usr/local/bin/reattach-to-user-namespace" 'set -g default-command "reattach-to-user-namespace -l bash"' 85 | 86 | ### .bash_profile 87 | 88 | system_type=$(uname -s) 89 | if [ "$system_type" = "Darwin" ]; then 90 | eval $(gdircolors $HOME/.dir_colors) 91 | else 92 | eval $(dircolors -b $HOME/.dir_colors) 93 | fi 94 | 95 | However, sometimes the type of file you are using doesn't allow for this type of logic. If a configuration can do an "include", you can include a specific alternate version using **yadm**. Consider these three files: 96 | 97 | ### .gitconfig 98 | 99 | #---- .gitconfig ----------------- 100 | [log] 101 | decorate = short 102 | abbrevCommit = true 103 | [include] 104 | path = .gitconfig.local 105 | 106 | #---- .gitconfig.local##Darwin --- 107 | [user] 108 | name = Tim Byrne 109 | email = tim@personal.email.org 110 | 111 | #---- .gitconfig.local##Linux ---- 112 | [user] 113 | name = Dr. Tim Byrne 114 | email = dr.byrne@work.email.com 115 | 116 | Configuring Git this way includes `.gitconfig.local` in the standard `.gitconfig`. **yadm** will automatically link the correct version based on the operation system. The bulk of your configurations can go in a single file, and you just put the exceptions in OS-specific files. 117 | 118 | Of course, you can use **yadm** to manage completely separate files for different systems as well. 119 | 120 | ### .signature 121 | 122 | #---- .signature## 123 | - Tim 124 | #---- .signature##Darwin.host1 125 | Sent from my MacBook 126 | - Tim 127 | #---- .signature##Linux.host2 128 | Sincerely, 129 | Dr. Tim Byrne 130 | 131 | **yadm** will link the appropriate version for the current host, or use the default `##` version. 132 | 133 | ## Example of managing SSH configurations 134 | _We shape our dwellings, and afterwards our dwellings shape us._—Winston Churchill 135 | 136 | Below is an example of how **yadm** can be used to manage SSH configurations. The example demonstrates **yadm** directly managing the `config` file, managing a host-specific `authorized_keys` file, and storing the private SSH key as part of its encrypted files. This example assumes a typical working SSH configuration exists, and walks through the steps to bring it under **yadm**'s management. 137 | 138 | yadm add ~/.ssh/config 139 | mv ~/.ssh/authorized_keys ~/.ssh/authorized_keys##Linux.myhost 140 | yadm add ~/.ssh/authorized_keys##Linux.myhost 141 | echo '.ssh/id_rsa' >> ~/.yadm/encrypt 142 | yadm add ~/.yadm/encrypt 143 | yadm encrypt 144 | 145 | ------ 146 | 147 | yadm status 148 | 149 | Changes to be committed: 150 | (use "git rm --cached ..." to unstage) 151 | 152 | new file: .ssh/authorized_keys##Linux.myhost 153 | new file: .ssh/config 154 | new file: .yadm/encrypt 155 | new file: .yadm/files.gpg 156 | 157 | ------ 158 | 159 | ls ~/.ssh 160 | 161 | authorized_keys -> ~/.ssh/authorized_keys##Linux.myhost 162 | authorized_keys##Linux.myhost 163 | config 164 | rsa_id 165 | 166 | 167 | First, the `config` file is simply added. This will cause the same `config` file to be used on other **yadm** managed hosts. The `authorized_keys` file needs to be host specific, so rename the file using the OS and hostname. After adding the renamed `authorized_keys##Linux.myhost`, **yadm** will automatically create the symlink for it. Last, the private key should be maintained in **yadm**'s encrypted files. Add a pattern to the `.yadm/encrypt` file which matches the private key. Then instruct **yadm** to encrypt all files matching the patterns found in `.yadm/encrypt`. Notice that the **yadm** repository is not tracking the private key directly, rather it tracks the collection of encrypted files `.yadm/files.gpg`. When these changes are brought onto another host, using the `yadm decrypt` command will extract the files stored. 168 | 169 | 170 | -------------------------------------------------------------------------------- /yadm.1: -------------------------------------------------------------------------------- 1 | ." vim: set spell so=8: 2 | .TH yadm 1 "12 August 2015" "1.02" 3 | .SH NAME 4 | yadm \- Yet Another Dotfiles Manager 5 | .SH SYNOPSIS 6 | .B yadm 7 | .I command 8 | .RI [ options ] 9 | 10 | .B yadm 11 | .I git-command-or-alias 12 | .RI [ options ] 13 | 14 | .B yadm 15 | init 16 | .RB [ -f ] 17 | .RB [ -w 18 | .IR directory ] 19 | 20 | .B yadm 21 | .RI clone " url 22 | .RB [ -f ] 23 | .RB [ -w 24 | .IR directory ] 25 | 26 | .B yadm 27 | .RI config " name 28 | .RI [ value ] 29 | 30 | .B yadm 31 | config 32 | .RB [ -e ] 33 | 34 | .B yadm 35 | list 36 | .RB [ -a ] 37 | 38 | .BR yadm " encrypt 39 | 40 | .BR yadm " decrypt 41 | .RB [ -l ] 42 | 43 | .BR yadm " alt 44 | 45 | .BR yadm " perms 46 | .SH DESCRIPTION 47 | .B yadm 48 | is a tool for managing a collection of files across multiple computers, 49 | using a shared Git repository. 50 | In addition, 51 | .B yadm 52 | provides a feature to select alternate versions of files 53 | based on the operation system or host name. 54 | Lastly, 55 | .B yadm 56 | supplies the ability to manage a subset of secure files, which are 57 | encrypted before they are included in the repository. 58 | .SH COMMANDS 59 | .TP 60 | .IR git-command " or " git-alias 61 | Any command not internally handled by 62 | .B yadm 63 | is passed through to 64 | .BR git (1). 65 | Git commands or aliases are invoked with the 66 | .B yadm 67 | managed repository. 68 | The working directory for git commands will be the configured 69 | .IR work-tree " (usually 70 | .IR $HOME ). 71 | 72 | Dotfiles are managed by using standard 73 | .B git 74 | commands; 75 | .IR add , 76 | .IR commit , 77 | .IR push , 78 | .IR pull , 79 | etc. 80 | 81 | .RI The " config 82 | command is not passed directly through. 83 | Instead use the 84 | .I gitconfig 85 | command (see below). 86 | .TP 87 | .B alt 88 | Create symbolic links for any managed files matching the naming rules describe in the ALTERNATES section. 89 | It is usually unnecessary to run this command, as 90 | .B yadm 91 | automatically processes alternates by default. 92 | This automatic behavior can be disabled by setting the configuration 93 | .I yadm.auto-alt 94 | to "false". 95 | .TP 96 | .BI clone " url 97 | Clone a remote repository for tracking dotfiles. 98 | After the contents of the remote repository have been fetched, a "merge" of 99 | .I origin/master 100 | is attempted. 101 | If there are conflicting files already present in the 102 | .IR work-tree , 103 | this merge will fail and instead a "reset" of 104 | .I origin/master 105 | will be done. 106 | It is up to the user to resolve these conflicts, 107 | but if the desired action is to have the contents in the repository overwrite the existing files, 108 | then a "hard reset" should accomplish that: 109 | 110 | .RS 111 | .RS 112 | yadm reset --hard origin/master 113 | .RE 114 | .RE 115 | .IP 116 | The repository is stored in 117 | .IR $HOME/.yadm/repo.git . 118 | By default, 119 | .I $HOME 120 | will be used as the 121 | .IR work-tree , 122 | but this can be overridden with the 123 | .BR -w " option. 124 | .B yadm 125 | can be forced to overwrite an existing repository by providing the 126 | .BR -f " option. 127 | .TP 128 | .B config 129 | This command manages configurations for 130 | .BR yadm . 131 | This command works exactly they way 132 | .BR git-config (1) 133 | does. 134 | See the CONFIGURATION section for more details. 135 | .TP 136 | .B decrypt 137 | Decrypt all files stored in 138 | .IR $HOME/.yadm/files.gpg . 139 | Files decrypted will be relative to the configured 140 | .IR work-tree " (usually 141 | .IR $HOME ). 142 | Using the 143 | .B -l 144 | option will list the files stored without extracting them. 145 | .TP 146 | .B encrypt 147 | Encrypt all files matching the patterns found in 148 | .IR $HOME/.yadm/encrypt . 149 | See the ENCRYPTION section for more details. 150 | .TP 151 | .B gitconfig 152 | Pass options to the 153 | .B git config 154 | command. Since 155 | .B yadm 156 | already uses the 157 | .I config 158 | command to manage its own configurations, 159 | this command is provided as a way to change configurations of the repository managed by 160 | .BR yadm . 161 | One useful case might be to configure the repository so untracked files are shown in status commands. 162 | .B yadm 163 | initially configures its repository so that untracked files are not shown. 164 | If you wish use the default git behavior (to show untracked files and directories), you can remove this configuration. 165 | 166 | .RS 167 | .RS 168 | yadm gitconfig --unset status.showUntrackedFiles 169 | .RE 170 | .RE 171 | .TP 172 | .B help 173 | Print a summary of 174 | .BR yadm " commands. 175 | .TP 176 | .B init 177 | Initialize a new, empty repository for tracking dotfiles. 178 | The repository is stored in 179 | .IR $HOME/.yadm/repo.git . 180 | By default, 181 | .I $HOME 182 | will be used as the 183 | .IR work-tree , 184 | but this can be overridden with the 185 | .BR -w " option. 186 | .B yadm 187 | can be forced to overwrite an existing repository by providing the 188 | .BR -f " option. 189 | .TP 190 | .B list 191 | Print a list of files managed by 192 | .BR yadm . 193 | .RB The " -a 194 | option will cause all managed files to be listed. 195 | Otherwise, the list will only include files from the current directory or below. 196 | .TP 197 | .B perms 198 | Update permissions as described in the PERMISSIONS section. 199 | It is usually unnecessary to run this command, as 200 | .B yadm 201 | automatically processes permissions by default. 202 | This automatic behavior can be disabled by setting the configuration 203 | .I yadm.auto-perms 204 | to "false". 205 | .TP 206 | .B version 207 | Print the version of 208 | .BR yadm . 209 | .SH CONFIGURATION 210 | .B yadm 211 | uses a configuration file named 212 | .IR $HOME/.yadm/config . 213 | This file uses the same format as 214 | .BR git-config (1). 215 | Also, you can control the contents of the configuration file 216 | via the 217 | .B yadm config 218 | command (which works exactly like 219 | .BR git-config ). 220 | For example, to disable alternates you can run the command: 221 | 222 | .RS 223 | yadm config yadm.auto-alt false 224 | .RE 225 | 226 | The following is the full list of supported configurations: 227 | .TP 228 | .B yadm.auto-alt 229 | Disable the automatic linking described in the section ALTERNATES. 230 | If disabled, you may still run 231 | .B yadm alt 232 | manually to create the alternate links. 233 | This feature is enabled by default. 234 | .TP 235 | .B yadm.auto-perms 236 | Disable the automatic permission changes described in the section PERMISSIONS. 237 | If disabled, you may still run 238 | .B yadm perms 239 | manually to update permissions. 240 | This feature is enabled by default. 241 | .TP 242 | .B yadm.ssh-perms 243 | Disable the permission changes to 244 | .IR $HOME/.ssh/* . 245 | This feature is enabled by default. 246 | .TP 247 | .B yadm.gpg-perms 248 | Disable the permission changes to 249 | .IR $HOME/.gnupg/* . 250 | This feature is enabled by default. 251 | .SH ALTERNATES 252 | When managing a set of files across different systems, it can be useful to have 253 | an automated way of choosing an alternate version of a file for a different 254 | operation system or simply for a different host. 255 | .B yadm 256 | implements a feature which will automatically create a symbolic link to 257 | the appropriate version of a file, as long as you follow a specific naming 258 | convention. 259 | .B yadm 260 | can detect files with names ending in: 261 | 262 | .RS 263 | .BR ##OS.HOSTNAME " or " ##OS " or " ## 264 | .RE 265 | 266 | If there are any files managed by 267 | .BR yadm \'s 268 | repository which match this naming convention, 269 | symbolic links will be created for the most appropriate version. 270 | This may best be demonstrated by example. Assume the following files are managed by 271 | .BR yadm \'s 272 | repository: 273 | 274 | - $HOME/path/example.txt## 275 | - $HOME/path/example.txt##Darwin 276 | - $HOME/path/example.txt##Darwin.host1 277 | - $HOME/path/example.txt##Darwin.host2 278 | - $HOME/path/example.txt##Linux 279 | - $HOME/path/example.txt##Linux.host1 280 | - $HOME/path/example.txt##Linux.host2 281 | 282 | If running on a Macbook named "host2", 283 | .B yadm 284 | will create a symbolic link which looks like this: 285 | 286 | .IR $HOME/path/example.txt " -> " $HOME/path/example.txt##Darwin.host2 287 | 288 | However, on another Mackbook named "host3", 289 | .B yadm 290 | will create a symbolic link which looks like this: 291 | 292 | .IR $HOME/path/example.txt " -> " $HOME/path/example.txt##Darwin 293 | 294 | Since the hostname doesn't match any of the managed files, the more generic version is chosen. 295 | 296 | If running on a Linux server named "host4", the link will be: 297 | 298 | .IR $HOME/path/example.txt " -> " $HOME/path/example.txt##Linux 299 | 300 | If running on a Solaris server, the link use the default "##" version: 301 | 302 | .IR $HOME/path/example.txt " -> " $HOME/path/example.txt## 303 | 304 | If no "##" version exists and no files match the current OS or HOSTNAME, then no link will be created. 305 | 306 | OS is determined by running 307 | .BR uname\ -s , 308 | and HOSTNAME by running 309 | .BR hostname\ -s . 310 | .B yadm 311 | will automatically create these links by default. This can be disabled using the 312 | .I yadm.auto-alt 313 | configuration. 314 | Even if disabled, links can be manually created by running 315 | .BR yadm\ alt . 316 | .SH ENCRYPTION 317 | It can be useful to manage confidential files, like SSH or GPG keys, across 318 | multiple systems. However, doing so would put plain text data into a Git 319 | repository, which often resides on a public system. 320 | .B yadm 321 | implements a feature which can make it easy to encrypt and decrypt a set of 322 | files so the encrypted version can be maintained in the Git repository. 323 | This feature will only work if the 324 | .BR gpg (1) 325 | command is available. 326 | 327 | To use this feature, a list of patterns must be created and saved as 328 | .IR $HOME/.yadm/encrypt . 329 | This list of patterns should be relative to the configured 330 | .IR work-tree " (usually 331 | .IR $HOME ). 332 | For example: 333 | 334 | .RS 335 | .ssh/*.key 336 | .gnupg/*.gpg 337 | .RE 338 | 339 | The 340 | .B yadm encrypt 341 | command will find all files matching the patterns, and prompt for a password. Once a 342 | password has confirmed, the matching files will be encrypted and saved as 343 | .IR $HOME/.yadm/files.gpg . 344 | The patterns and files.gpg should be added to the 345 | .B yadm 346 | repository so they are available across multiple systems. 347 | 348 | To decrypt these files later, or on another system run 349 | .BR yadm\ decrypt 350 | and provide the correct password. 351 | After files are decrypted, permissions are automatically updated as described 352 | in the PERMISSIONS section. 353 | 354 | .BR NOTE : 355 | It is recommended that you use a private repository when keeping confidential 356 | files, even though they are encrypted. 357 | .SH PERMISSIONS 358 | When files are checked out of a Git repository, their initial permissions are 359 | dependent upon the user's umask. This can result in confidential files with lax permissions. 360 | 361 | To prevent this, 362 | .B yadm 363 | will automatically update the permissions of confidential files. 364 | The "group" and "others" permissions will be removed from the following files: 365 | 366 | .RI - " $HOME/.yadm/files.gpg 367 | 368 | - All files matching patterns in 369 | .I $HOME/.yadm/encrypt 370 | 371 | - The SSH directory and files, 372 | .I .ssh/* 373 | 374 | - The GPG directory and files, 375 | .I .gnupg/* 376 | 377 | .B yadm 378 | will automatically update permissions by default. This can be disabled using the 379 | .I yadm.auto-perms 380 | configuration. 381 | Even if disabled, permissions can be manually updated by running 382 | .BR yadm\ perms . 383 | The SSH directory processing can be disabled using the 384 | .I yadm.ssh-perms 385 | configuration. 386 | .SH FILES 387 | .TP 388 | .I $HOME/.yadm/config 389 | Configuration file for 390 | .BR yadm . 391 | .TP 392 | .I $HOME/.yadm/repo.git 393 | Git repository used by 394 | .BR yadm . 395 | .TP 396 | .I $HOME/.yadm/encrypt 397 | List of globs used for encrypt/decrypt 398 | .TP 399 | .I $HOME/.yadm/files.gpg 400 | All files encrypted with 401 | .B yadm encrypt 402 | are stored in this file. 403 | .SH EXAMPLES 404 | .TP 405 | .B yadm init 406 | Create an empty repo for managing files 407 | .TP 408 | .B yadm add .bash_profile ; yadm commit 409 | Add 410 | .I .bash_profile 411 | to the Git index and create a new commit 412 | .TP 413 | .B yadm remote add origin 414 | Add a remote origin to an existing repository 415 | .TP 416 | .B yadm push -u origin master 417 | Initial push of master to origin 418 | .TP 419 | .B echo ".ssh/*.key" >> $HOME/.yadm/encrypt 420 | Add a new pattern to the list of encrypted files 421 | .TP 422 | .B yadm encrypt ; yadm add ~/.yadm/files.gpg ; yadm commit 423 | Commit a new set of encrypted files 424 | .SH REPORTING BUGS 425 | Report issues or create pull requests at GitHub: 426 | 427 | https://github.com/TheLocehiliosan/yadm 428 | .SH AUTHOR 429 | Tim Byrne 430 | .SH SEE ALSO 431 | 432 | .BR git (1), 433 | .BR gpg (1) 434 | 435 | Other management tools which inspired the creation of 436 | .BR yadm : 437 | 438 | .BR homeshick " 439 | 440 | .BR vcsh " 441 | -------------------------------------------------------------------------------- /yadm.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## NAME 5 | yadm - Yet Another Dotfiles Manager 6 | 7 | ## SYNOPSIS 8 | yadm command [options] 9 | 10 | yadm git-command-or-alias [options] 11 | 12 | yadm init [-f] [-w directory] 13 | 14 | yadm clone url [-f] [-w directory] 15 | 16 | yadm config name [value] 17 | 18 | yadm config [-e] 19 | 20 | yadm list [-a] 21 | 22 | yadm encrypt 23 | 24 | yadm decrypt [-l] 25 | 26 | yadm alt 27 | 28 | yadm perms 29 | 30 | ## DESCRIPTION 31 | yadm is a tool for managing a collection of files across multiple com- 32 | puters, using a shared Git repository. In addition, yadm provides a 33 | feature to select alternate versions of files based on the operation 34 | system or host name. Lastly, yadm supplies the ability to manage a 35 | subset of secure files, which are encrypted before they are included in 36 | the repository. 37 | 38 | ## COMMANDS 39 | git-command or git-alias 40 | Any command not internally handled by yadm is passed through to 41 | git(1). Git commands or aliases are invoked with the yadm man- 42 | aged repository. The working directory for git commands will be 43 | the configured work-tree (usually $HOME). 44 | 45 | Dotfiles are managed by using standard git commands; add, com- 46 | mit, push, pull, etc. 47 | 48 | The config command is not passed directly through. Instead use 49 | the gitconfig command (see below). 50 | 51 | alt Create symbolic links for any managed files matching the naming 52 | rules describe in the ALTERNATES section. It is usually unnec- 53 | essary to run this command, as yadm automatically processes 54 | alternates by default. This automatic behavior can be disabled 55 | by setting the configuration yadm.auto-alt to "false". 56 | 57 | clone url 58 | Clone a remote repository for tracking dotfiles. After the con- 59 | tents of the remote repository have been fetched, a "merge" of 60 | origin/master is attempted. If there are conflicting files 61 | already present in the work-tree, this merge will fail and 62 | instead a "reset" of origin/master will be done. It is up to 63 | the user to resolve these conflicts, but if the desired action 64 | is to have the contents in the repository overwrite the existing 65 | files, then a "hard reset" should accomplish that: 66 | 67 | yadm reset --hard origin/master 68 | 69 | The repository is stored in $HOME/.yadm/repo.git. By default, 70 | $HOME will be used as the work-tree, but this can be overridden 71 | with the -w option. yadm can be forced to overwrite an existing 72 | repository by providing the -f option. 73 | 74 | config This command manages configurations for yadm. This command 75 | works exactly they way git-config(1) does. See the CONFIGURA- 76 | TION section for more details. 77 | 78 | decrypt 79 | Decrypt all files stored in $HOME/.yadm/files.gpg. Files 80 | decrypted will be relative to the configured work-tree (usually 81 | $HOME). Using the -l option will list the files stored without 82 | extracting them. 83 | 84 | encrypt 85 | Encrypt all files matching the patterns found in 86 | $HOME/.yadm/encrypt. See the ENCRYPTION section for more 87 | details. 88 | 89 | gitconfig 90 | Pass options to the git config command. Since yadm already uses 91 | the config command to manage its own configurations, this com- 92 | mand is provided as a way to change configurations of the repos- 93 | itory managed by yadm. One useful case might be to configure 94 | the repository so untracked files are shown in status commands. 95 | yadm initially configures its repository so that untracked files 96 | are not shown. If you wish use the default git behavior (to 97 | show untracked files and directories), you can remove this con- 98 | figuration. 99 | 100 | yadm gitconfig --unset status.showUntrackedFiles 101 | 102 | help Print a summary of yadm commands. 103 | 104 | init Initialize a new, empty repository for tracking dotfiles. The 105 | repository is stored in $HOME/.yadm/repo.git. By default, $HOME 106 | will be used as the work-tree, but this can be overridden with 107 | the -w option. yadm can be forced to overwrite an existing 108 | repository by providing the -f option. 109 | 110 | list Print a list of files managed by yadm. The -a option will cause 111 | all managed files to be listed. Otherwise, the list will only 112 | include files from the current directory or below. 113 | 114 | perms Update permissions as described in the PERMISSIONS section. It 115 | is usually unnecessary to run this command, as yadm automati- 116 | cally processes permissions by default. This automatic behavior 117 | can be disabled by setting the configuration yadm.auto-perms to 118 | "false". 119 | 120 | version 121 | Print the version of yadm. 122 | 123 | ## CONFIGURATION 124 | yadm uses a configuration file named $HOME/.yadm/config. This file 125 | uses the same format as git-config(1). Also, you can control the con- 126 | tents of the configuration file via the yadm config command (which 127 | works exactly like git-config). For example, to disable alternates you 128 | can run the command: 129 | 130 | yadm config yadm.auto-alt false 131 | 132 | The following is the full list of supported configurations: 133 | 134 | yadm.auto-alt 135 | Disable the automatic linking described in the section ALTER- 136 | NATES. If disabled, you may still run yadm alt manually to cre- 137 | ate the alternate links. This feature is enabled by default. 138 | 139 | yadm.auto-perms 140 | Disable the automatic permission changes described in the sec- 141 | tion PERMISSIONS. If disabled, you may still run yadm perms 142 | manually to update permissions. This feature is enabled by 143 | default. 144 | 145 | yadm.ssh-perms 146 | Disable the permission changes to $HOME/.ssh/*. This feature is 147 | enabled by default. 148 | 149 | yadm.gpg-perms 150 | Disable the permission changes to $HOME/.gnupg/*. This feature 151 | is enabled by default. 152 | 153 | ## ALTERNATES 154 | When managing a set of files across different systems, it can be useful 155 | to have an automated way of choosing an alternate version of a file for 156 | a different operation system or simply for a different host. yadm 157 | implements a feature which will automatically create a symbolic link to 158 | the appropriate version of a file, as long as you follow a specific 159 | naming convention. yadm can detect files with names ending in: 160 | 161 | ##OS.HOSTNAME or ##OS or ## 162 | 163 | If there are any files managed by yadm's repository which match this 164 | naming convention, symbolic links will be created for the most appro- 165 | priate version. This may best be demonstrated by example. Assume the 166 | following files are managed by yadm's repository: 167 | 168 | - $HOME/path/example.txt## 169 | - $HOME/path/example.txt##Darwin 170 | - $HOME/path/example.txt##Darwin.host1 171 | - $HOME/path/example.txt##Darwin.host2 172 | - $HOME/path/example.txt##Linux 173 | - $HOME/path/example.txt##Linux.host1 174 | - $HOME/path/example.txt##Linux.host2 175 | 176 | If running on a Macbook named "host2", yadm will create a symbolic link 177 | which looks like this: 178 | 179 | $HOME/path/example.txt -> $HOME/path/example.txt##Darwin.host2 180 | 181 | However, on another Mackbook named "host3", yadm will create a symbolic 182 | link which looks like this: 183 | 184 | $HOME/path/example.txt -> $HOME/path/example.txt##Darwin 185 | 186 | Since the hostname doesn't match any of the managed files, the more 187 | generic version is chosen. 188 | 189 | If running on a Linux server named "host4", the link will be: 190 | 191 | $HOME/path/example.txt -> $HOME/path/example.txt##Linux 192 | 193 | If running on a Solaris server, the link use the default "##" version: 194 | 195 | $HOME/path/example.txt -> $HOME/path/example.txt## 196 | 197 | If no "##" version exists and no files match the current OS or HOST- 198 | NAME, then no link will be created. 199 | 200 | OS is determined by running uname -s, and HOSTNAME by running host- 201 | name -s. yadm will automatically create these links by default. This 202 | can be disabled using the yadm.auto-alt configuration. Even if dis- 203 | abled, links can be manually created by running yadm alt. 204 | 205 | ## ENCRYPTION 206 | It can be useful to manage confidential files, like SSH or GPG keys, 207 | across multiple systems. However, doing so would put plain text data 208 | into a Git repository, which often resides on a public system. yadm 209 | implements a feature which can make it easy to encrypt and decrypt a 210 | set of files so the encrypted version can be maintained in the Git 211 | repository. This feature will only work if the gpg(1) command is 212 | available. 213 | 214 | To use this feature, a list of patterns must be created and saved as 215 | $HOME/.yadm/encrypt. This list of patterns should be relative to the 216 | configured work-tree (usually $HOME). For example: 217 | 218 | .ssh/*.key 219 | .gnupg/*.gpg 220 | 221 | The yadm encrypt command will find all files matching the patterns, and 222 | prompt for a password. Once a password has confirmed, the matching 223 | files will be encrypted and saved as $HOME/.yadm/files.gpg. The pat- 224 | terns and files.gpg should be added to the yadm repository so they are 225 | available across multiple systems. 226 | 227 | To decrypt these files later, or on another system run yadm decrypt and 228 | provide the correct password. After files are decrypted, permissions 229 | are automatically updated as described in the PERMISSIONS section. 230 | 231 | NOTE: It is recommended that you use a private repository when keeping 232 | confidential files, even though they are encrypted. 233 | 234 | ## PERMISSIONS 235 | When files are checked out of a Git repository, their initial permis- 236 | sions are dependent upon the user's umask. This can result in confiden- 237 | tial files with lax permissions. 238 | 239 | To prevent this, yadm will automatically update the permissions of con- 240 | fidential files. The "group" and "others" permissions will be removed 241 | from the following files: 242 | 243 | - $HOME/.yadm/files.gpg 244 | 245 | - All files matching patterns in $HOME/.yadm/encrypt 246 | 247 | - The SSH directory and files, .ssh/* 248 | 249 | - The GPG directory and files, .gnupg/* 250 | 251 | yadm will automatically update permissions by default. This can be dis- 252 | abled using the yadm.auto-perms configuration. Even if disabled, per- 253 | missions can be manually updated by running yadm perms. The SSH direc- 254 | tory processing can be disabled using the yadm.ssh-perms configuration. 255 | 256 | ## FILES 257 | $HOME/.yadm/config 258 | Configuration file for yadm. 259 | 260 | $HOME/.yadm/repo.git 261 | Git repository used by yadm. 262 | 263 | $HOME/.yadm/encrypt 264 | List of globs used for encrypt/decrypt 265 | 266 | $HOME/.yadm/files.gpg 267 | All files encrypted with yadm encrypt are stored in this file. 268 | 269 | ## EXAMPLES 270 | yadm init 271 | Create an empty repo for managing files 272 | 273 | yadm add .bash_profile ; yadm commit 274 | Add .bash_profile to the Git index and create a new commit 275 | 276 | yadm remote add origin 277 | Add a remote origin to an existing repository 278 | 279 | yadm push -u origin master 280 | Initial push of master to origin 281 | 282 | echo .ssh/*.key >> $HOME/.yadm/encrypt 283 | Add a new pattern to the list of encrypted files 284 | 285 | yadm encrypt ; yadm add ~/.yadm/files.gpg ; yadm commit 286 | Commit a new set of encrypted files 287 | 288 | ## REPORTING BUGS 289 | Report issues or create pull requests at GitHub: 290 | 291 | https://github.com/TheLocehiliosan/yadm 292 | 293 | ## AUTHOR 294 | Tim Byrne 295 | 296 | ## SEE ALSO 297 | git(1), gpg(1) 298 | 299 | Other management tools which inspired the creation of yadm: 300 | 301 | homeshick 302 | 303 | vcsh 304 | 305 | 306 | 307 | -------------------------------------------------------------------------------- /yadm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # yadm - Yet Another Dotfiles Manager 4 | # Copyright (C) 2015 Tim Byrne 5 | 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3 of the License. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | VERSION=1.02 19 | 20 | YADM_WORK="$HOME" 21 | YADM_DIR="$HOME/.yadm" 22 | 23 | YADM_REPO="$YADM_DIR/repo.git" 24 | YADM_CONFIG="$YADM_DIR/config" 25 | YADM_ENCRYPT="$YADM_DIR/encrypt" 26 | YADM_ARCHIVE="$YADM_DIR/files.gpg" 27 | 28 | #; flag when something may have changes (which prompts auto actions to be performed) 29 | CHANGES_POSSIBLE=0 30 | 31 | #; use the yadm repo for all git operations 32 | export GIT_DIR="$YADM_REPO" 33 | 34 | function main() { 35 | 36 | require_git 37 | 38 | #; create the YADM_DIR if it doesn't exist yet 39 | [ -d "$YADM_DIR" ] || mkdir -p $YADM_DIR 40 | 41 | #; parse command line arguments 42 | internal_commands="^(alt|clean|clone|config|decrypt|encrypt|help|init|list|perms|version)$" 43 | if [ -z "$*" ] ; then 44 | #; no argumnts will result in help() 45 | help 46 | elif [ "$1" = "gitconfig" ] ; then 47 | #; 'config' is used for yadm, need to use 'gitcofnig' to pass through to git 48 | shift 49 | git_command config "$@" 50 | elif [[ "$1" =~ $internal_commands ]] ; then 51 | #; for internal commands, process all of the arguments 52 | YADM_COMMAND="$1" 53 | YADM_ARGS="" 54 | shift 55 | 56 | while [[ $# > 0 ]] ; do 57 | key="$1" 58 | case $key in 59 | -a) #; used by list() 60 | LIST_ALL="YES" 61 | ;; 62 | -d) #; used by all commands 63 | DEBUG="YES" 64 | ;; 65 | -f) #; used by init() and clone() 66 | FORCE="YES" 67 | ;; 68 | -l) #; used by decrypt() 69 | DO_LIST="YES" 70 | ;; 71 | -w) #; used by init() and clone() 72 | if [[ ! "$2" =~ ^/ ]] ; then 73 | error_out "You must specify a fully qualified work tree" 74 | fi 75 | YADM_WORK="$2" 76 | shift 77 | ;; 78 | *) #; any unhandled arguments 79 | if [ -z "$YADM_ARGS" ] ; then 80 | YADM_ARGS="$1" 81 | else 82 | YADM_ARGS+=" $1" 83 | fi 84 | ;; 85 | esac 86 | shift 87 | done 88 | [ ! -d $YADM_WORK ] && error_out "Work tree does not exist: [$YADM_WORK]" 89 | $YADM_COMMAND "$YADM_ARGS" 90 | else 91 | #; any other commands are simply passed through to git 92 | git_command "$@" 93 | fi 94 | 95 | #; process automatic events 96 | auto_alt 97 | auto_perms 98 | 99 | } 100 | 101 | #; ****** yadm Commands ****** 102 | 103 | function alt() { 104 | 105 | require_repo 106 | 107 | #; regex for matching "##SYSTEM.HOSTNAME.USER" 108 | match_system=$(uname -s) 109 | match_host=$(hostname -s) 110 | match_user=${USER} 111 | match="^(.+)##($match_system|$match_system.$match_host|$match_system.$match_host.$match_user|())$" 112 | 113 | #; process relative to YADM_WORK 114 | YADM_WORK=$(git config core.worktree) 115 | cd $YADM_WORK 116 | 117 | #; only be noisy if the "alt" command was run directly 118 | [ "$YADM_COMMAND" = "alt" ] && loud="YES" 119 | 120 | #; loop over all "tracked" files 121 | #; for every file which matches the above regex, create a symlink 122 | for tracked_file in $(git ls-files | sort); do 123 | tracked_file="$YADM_WORK/$tracked_file" 124 | if [ -e "$tracked_file" ] ; then 125 | if [[ $tracked_file =~ $match ]] ; then 126 | new_link="${BASH_REMATCH[1]}" 127 | debug "Linking $tracked_file to $new_link" 128 | [ -n "$loud" ] && echo "Linking $tracked_file to $new_link" 129 | ln -fs "$tracked_file" "$new_link" 130 | fi 131 | fi 132 | done 133 | 134 | } 135 | 136 | function clean() { 137 | 138 | error_out "\"git clean\" has been disabled for safety. You could end up removing all unmanaged files." 139 | 140 | } 141 | 142 | function clone() { 143 | 144 | #; clone will begin with a bare repo 145 | init 146 | 147 | #; add the specified remote, and configure the repo to track origin/master 148 | debug "Adding remote to new repo" 149 | git remote add origin "$1" 150 | debug "Configuring new repo to track origin/master" 151 | git config branch.master.remote origin 152 | git config branch.master.merge refs/heads/master 153 | 154 | #; fetch / merge (and possibly fallback to reset) 155 | debug "Doing an initial fetch of the origin" 156 | git fetch origin 157 | debug "Doing an initial merge of origin/master" 158 | git merge origin/master || { 159 | debug "Merge failed, doing a reset." 160 | git reset origin/master 161 | cat </dev/null)) 233 | fi 234 | done < "$YADM_ENCRYPT" 235 | 236 | #; encrypt all files which match the globs 237 | tar -cv ${GLOBS[@]} | gpg --yes -c --output "$YADM_ARCHIVE" 238 | if [ $? = 0 ]; then 239 | echo "Wrote new file: $YADM_ARCHIVE" 240 | else 241 | error_out "Unable to write $YADM_ARCHIVE" 242 | fi 243 | 244 | #; offer to add YADM_ARCHIVE if untracked 245 | archive_status=$(git status --porcelain -uall "$YADM_ARCHIVE" 2>/dev/null) 246 | archive_regex="^\?\?" 247 | if [[ $archive_status =~ $archive_regex ]] ; then 248 | echo "It appears that $YADM_ARCHIVE is not tracked by yadm's repository." 249 | echo "Would you like to add it now? (y/n)" 250 | read answer 251 | if [[ $answer =~ ^[yY]$ ]] ; then 252 | git add "$YADM_ARCHIVE" 253 | fi 254 | fi 255 | 256 | CHANGES_POSSIBLE=1 257 | 258 | } 259 | 260 | function git_command() { 261 | 262 | require_repo 263 | 264 | #; pass commands through to git 265 | git "$@" 266 | 267 | CHANGES_POSSIBLE=1 268 | 269 | } 270 | 271 | function help() { 272 | 273 | cat << EOF 274 | Usage: yadm [options...] 275 | 276 | Manage dotfiles maintained in a Git repository. Manage alternate files 277 | for specific systems or hosts. Encrypt/decrypt private files. 278 | 279 | Git Commands: 280 | Any Git command or alias can be used as a . It will operate 281 | on yadm's repository and files in the work tree (usually \$HOME). 282 | 283 | Commands: 284 | yadm init [-f] - Initialize an empty repository 285 | yadm clone [-f] - Clone an existing repository 286 | yadm config - Configure a setting 287 | yadm list [-a] - List tracked files 288 | yadm alt - Create links for alternates 289 | yadm encrypt - Encrypt files 290 | yadm decrypt [-l] - Decrypt files 291 | yadm perms - Fix perms for private files 292 | 293 | Files: 294 | \$HOME/.yadm/config - yadm's configuration file 295 | \$HOME/.yadm/repo.git - yadm's Git repository 296 | \$HOME/.yadm/encrypt - List of globs used for encrypt/decrypt 297 | \$HOME/.yadm/files.gpg - Encrypted data stored here 298 | 299 | Use "man yadm" for complete documentation. 300 | EOF 301 | 302 | exit 1 303 | 304 | } 305 | 306 | function init() { 307 | 308 | #; safety check, don't attempt to init when the repo is already present 309 | [ -d "$YADM_REPO" ] && [ -z "$FORCE" ] && \ 310 | error_out "Git repo already exist. [$YADM_REPO]\nUse '-f' if you want to force it to be overwritten." 311 | 312 | #; remove existing if forcing the init to happen anyway 313 | [ -d "$YADM_REPO" ] && { 314 | debug "Removing existing repo prior to init" 315 | rm -rf "$YADM_REPO" 316 | } 317 | 318 | #; init a new bare repo 319 | debug "Init new repo" 320 | git init --shared=0600 --bare "$YADM_REPO" 321 | configure_repo 322 | 323 | CHANGES_POSSIBLE=1 324 | 325 | } 326 | 327 | function list() { 328 | 329 | require_repo 330 | 331 | #; process relative to YADM_WORK when --all is specified 332 | if [ -n "$LIST_ALL" ] ; then 333 | YADM_WORK=$(git config core.worktree) 334 | cd $YADM_WORK 335 | fi 336 | 337 | #; list tracked files 338 | git ls-files 339 | 340 | } 341 | 342 | function perms() { 343 | 344 | #; TODO: prevent repeats in the files changed 345 | 346 | #; process relative to YADM_WORK 347 | YADM_WORK=$(git config core.worktree) 348 | cd $YADM_WORK 349 | 350 | GLOBS=() 351 | 352 | #; include the archive created by "encrypt" 353 | [ -f "$YADM_ARCHIVE" ] && GLOBS=("${GLOBS[@]}" "$YADM_ARCHIVE") 354 | 355 | #; include all .ssh files (unless disabled) 356 | if [[ $(config --bool yadm.ssh-perms) != "false" ]] ; then 357 | GLOBS=("${GLOBS[@]}" ".ssh" ".ssh/*") 358 | fi 359 | 360 | #; include all gpg files (unless disabled) 361 | if [[ $(config --bool yadm.gpg-perms) != "false" ]] ; then 362 | GLOBS=("${GLOBS[@]}" ".gnupg" ".gnupg/*") 363 | fi 364 | 365 | #; include globs found in YADM_ENCRYPT (if present) 366 | if [ -f "$YADM_ENCRYPT" ] ; then 367 | while IFS='' read -r glob || [ -n "$glob" ]; do 368 | if [[ ! $glob =~ ^# ]] ; then 369 | GLOBS=("${GLOBS[@]}" $(eval /bin/ls "$glob" 2>/dev/null)) 370 | fi 371 | done < "$YADM_ENCRYPT" 372 | fi 373 | 374 | #; remove group/other permissions from collected globs 375 | chmod -f go-rwx ${GLOBS[@]} >/dev/null 2>&1 376 | #; TODO: detect and report changing permissions in a portable way 377 | 378 | } 379 | 380 | function version() { 381 | 382 | echo "yadm $VERSION" 383 | exit 0 384 | 385 | } 386 | 387 | #; ****** Utility Functions ****** 388 | 389 | function configure_repo() { 390 | 391 | debug "Configuring new repo" 392 | 393 | #; change bare to false (there is a working directory) 394 | git config core.bare 'false' 395 | 396 | #; set the worktree for the yadm repo 397 | git config core.worktree "$YADM_WORK" 398 | 399 | #; by default, do not show untracked files and directories 400 | git config status.showUntrackedFiles no 401 | 402 | #; possibly used later to ensure we're working on the yadm repo 403 | git config yadm.managed 'true' 404 | 405 | } 406 | 407 | function debug() { 408 | 409 | [ -n "$DEBUG" ] && echo -e "DEBUG: $@" 410 | 411 | } 412 | 413 | function error_out() { 414 | 415 | echo -e "ERROR: $@" 416 | exit 1 417 | 418 | } 419 | 420 | #; ****** Auto Functions ****** 421 | 422 | function auto_alt() { 423 | 424 | #; process alternates if there are possible changes 425 | if [ "$CHANGES_POSSIBLE" = "1" ] ; then 426 | auto_alt=$(config --bool yadm.auto-alt) 427 | if [ "$auto_alt" != "false" ] ; then 428 | alt 429 | fi 430 | fi 431 | 432 | } 433 | 434 | function auto_perms() { 435 | 436 | #; process permissions if there are possible changes 437 | if [ "$CHANGES_POSSIBLE" = "1" ] ; then 438 | auto_perms=$(config --bool yadm.auto-perms) 439 | if [ "$auto_perms" != "false" ] ; then 440 | perms 441 | fi 442 | fi 443 | 444 | } 445 | 446 | #; ****** Prerequisites Functions ****** 447 | 448 | function require_archive() { 449 | [ -f "$YADM_ARCHIVE" ] || error_out "$YADM_ARCHIVE does not exist. did you forget to create it?" 450 | } 451 | function require_encrypt() { 452 | [ -f "$YADM_ENCRYPT" ] || error_out "$YADM_ENCRYPT does not exist. did you forget to create it?" 453 | } 454 | function require_git() { 455 | command -v git >/dev/null 2>&1 || \ 456 | error_out "This functionality requires Git to be installed, but the command git cannot be located." 457 | } 458 | function require_gpg() { 459 | command -v gpg >/dev/null 2>&1 || \ 460 | error_out "This functionality requires GPG to be installed, but the command gpg cannot be located." 461 | } 462 | function require_repo() { 463 | [ -d "$YADM_REPO" ] || error_out "Git repo does not exist. did you forget to run 'init' or 'clone'?" 464 | } 465 | 466 | main "$@" 467 | --------------------------------------------------------------------------------