How to easily deploy your dotfiles to any machine

Here I’ll show my way of dynamically deploying your dotfiles on any machine you happen to land on and leaving no trace when you’re done.

The problem

Everyone knows the pain of cloning, scp-ing or any other method of getting your dotfiles on the machine at hand, then symlinking, copying over and eventually having to clean up all the files when done.

The solution

My method involves downloading (with curl, but you can get creative here) the dotfiles into random-named temp files, using mostly environment variables to point to them and creating a cleanup hook for the shell.

The advantages of such a solution are many:

  • If the source is git, for example, then just link to the raw version’s address of your config file and have it updated on every push and re-spawn of the shell.

  • Physical files mean you are not limited to one specific configuration method - do whatever your software requires you to.

  • Clean up is being done automatically.

The code

A complete script can be downloaded from my repository. To load it you’d be executing something like this on the machine:

source <(curl -sS https://xicod.github.io/b)

(This specific url is just a symlink to the script mentioned above)

Let’s go over the interesting parts of the script:

function createTempFileFromUrl {
	local t=$(mktemp --tmpdir bash.tmp.XXXXXXXXXX) \
		&& tmp_files+=($t) \
		&& curl -sSf "$1" >$t
}

This basically creates an empty, random-named file, usually in /tmp, but that depends on your system.

Then, the file is being added to the array that will be later used by the cleanup routine.

And finally, the config is being downloaded into it.

function trap_tempConfFilesDelete {
	for f in "${tmp_files[@]}"; do
		command rm $f
	done
}
trap "trap_tempConfFilesDelete" EXIT

This is the cleanup routine that is called when the process receives the EXIT signal. The process in this case is the shell, so when you close it or log out, it will be called.

: \
&& createTempFileFromUrl ${dt_repo_dl_prefix}/vimrc \
&& export VIMINIT="source ${tmp_files[-1]}" \
&& createTempFileFromUrl ${dt_repo_dl_prefix}/tigrc \
&& export TIGRC_USER=${tmp_files[-1]} \
&& source <(curl -sSf ${dt_repo_dl_prefix}/dt-env-common.sh)

This is the actual code that calls the download method and sets the config files to be active via environment variables.

${tmp_files[-1]} is the syntax to access last entry in an array.

In my setup, a vim, tig and generic bash code are loaded. Environment variables are preferable, because they leave no trace on the system, but if your program needs to have the file in a specific location, then you should do something like:

ln -sf ${tmp_files[-1]} ~/.myrcfile

And that’s it. In that shell, whenever you use vim, for example, it will have your vimrc loaded.

When you close that shell, all the files mentioned in the tmp_files array are removed.

Words of caution

  • Be very careful with the files you download off the internet and load into your shell. This can pose a very serious security risk so be sure the source is properly controlled and limited for modifications. Also prefer https over http.

  • In some cases, the clean up function isn’t called, like in an event of a reboot or dropped connection and such. This shouldn’t pose much of a risk as the files are only current user readable, but they’ll be left hanging around in /tmp, which is again not a huge issue as /tmp should be routinely cleared up anyway.

Feel free to drop me a mail if you have any thoughts or ideas.