-
Notifications
You must be signed in to change notification settings - Fork 146
Symlinking
- Linking table
- Combining directories
- Repos with no home directory
- Shallow symlinking
- Files outside your home directory
homeshick does not blindly symlink everything, instead it uses a carefully crafted linking strategy to achieve a high level of flexibility without resorting to configuration files.
The table below shows how homeshick decides what to do in different situations.
$HOME /castle |
directory | not directory |
---|---|---|
nonexistent | mkdir |
link |
symlink to castle | rm! && mkdir |
identical |
file/symlinked file | rm? && mkdir |
rm? && link |
directory | identical |
rm? && link |
directory (symlink) | identical |
rm? && link |
homeshick traverses through all resources (files, folders and symlinks),
that reside under the home/
folder of a castle in a depth-first manner.
Symlinks in the castle are not followed.
Conversely: if $HOME
contains a directory symlink that matches a normal
directory in the castle it will be followed.
The table is consulted for each resource that is encountered.
Files or directories that are not tracked by git are ignored and not traversed.
The columns directory and not directory represent the resource in the castle.
The rows represent what resource is found at the corresponding location in the actual $HOME
directory.
In the castle, directory is a simple directory (and not a symlink to a directory), while not directory is everything that is not the former (so: files, symlinked files, and symlinked directories).
The resources that can be encounter in the $HOME
directory are categorized as follows:
-
nonexistent means that the corresponding resource in the
$HOME
folder does not exist. - symlink to castle represents a symlink to the current resource
- file/symlinked file is a symlink to anything but the current resource
- directory is a regular directory
- directory (symlink) is a symlinked directory (but not to the castle)
The actions that can be taken always refer to the $HOME
directory. A &&
means that the second action is only executed if the first one was executed as well.
-
identical
: Do not do anything, resources are identical -
mkdir
: Create the directory -
link
: Create a symlink to the resource in the castle -
rm!
: Delete without prompting (this is only done for legacy directory symlinks) -
rm?
: Prompt whether the user wants to overwrite the resource
(--skip
answers "no" to this, while--force
does the opposite.--batch
selects the default, which is "no")
As you can see in the linking table,
every folder that is encountered in the castle is replicated in $HOME
.
This allows you to combine multiple castles into one directory structure.
Say you have two vim plugins in different castles:
- Castle 1:
home/.vim/bundle/vim-colors-solarized
- Castle 2:
home/.vim/bundle/vim-git
When homeshick symlinks castle 1, it will create the directory structure home/.vim/bundle/vim-colors-solarized
(and symlink whatever files are in that folder).
Upon encountering castle 2, homeshick sees the folders home/.vim/bundle/
and considers them identical
.
It then creates the directory vim-git
inside home/.vim/bundle/
and goes on with symlinking the vim-git
plugin files.
What do you do if you encounter a really cool repository that goes well with
your existing setup, but it has no home/
folder and needs to be linked to a
very specific place in your $HOME
folder?
Let's say you want to add vundle to your Vim configuration.
The documentation says it needs to be installed to ~/.vim/bundle/vundle
, but you are not
very interested in forking the repository solely for the purpose of changing the directory layout
so that all files are placed four directories deeper in home/.vim/bundle/vundle/
.
homeshick can solve this problem in two ways:
-
Add vundle as a submodule to your dotfiles. This is definitely the quick and easy way.
homeshick cd dotfiles git submodule add https://github.com/gmarik/vundle.git home/.vim/bundle/Vundle.vim
-
Clone vundle with homeshick and symlink to the repo from the appropriate folder in your dotfiles:
homeshick clone gmarik/vundle cd ~/.homesick/repos/dotfiles/home mkdir .vim/bundle cd .vim/bundle ln -s ../../../../vundle vundle # symlink to the location of the cloned vundle repository homeshick link dotfiles
We use a relative path for the symlink in case we log in with different username on other machines.
When running the link
command, homeshick will create a symlink at ~/.vim/bundle/vundle
pointing at the symlink we just created. This means there will be a symlinked directory at
~/.vim/bundle/vundle
, which contains the files of the cloned vundle repository
Note: You can see how homeshick decides what to do when encountering different symlink situations
by looking at the linking table.
The advantage of the second option is that you have more finegrained control over your repositories
and can manage each of them individually
(e.g. you want to refresh
your own dotfiles every week,
but you don't want to wait for all the submodules in your repository to refresh as well).
The downside of not using submodules is that you will need to add the additional repositories
with homeshick clone
on every machine.
However, you can use the automatic deployment script to avoid having
to do this manually.
Since homeshick traverses into the directories of your home/
folder,
it may encounter quite a lot of files that need symlinking.
In many scenarios this is desirable (e.g. when combining directories).
Some directories however may have a huge configuration setup with a lot of files.
Traversing and symlinking these files can take a little while and you may have no interest in
having fine-grained control over these directories.
You can use homeshick's linking strategy to your advantage in such cases and have homeshick create
a simple directory symlink in your $HOME
folder.
The not directory column in the linking table
also covers directory symlinks. When encountering a directory symlink,
homeshick will create a symlink in $HOME
, which points to the symlink in your Castle.
Therefore, all we need to do is to convert the directory in question into a symlink.
As an example, consider this directory structure:
dotfiles/
└─home/
└─.emacs/
├─snippets/
└─themes/
If we move .emacs
outside the home/
directory, we can still keep it in the repository
and create a symlink in its place like so:
dotfiles/
├─emacs/
│ └─snippets/
│ └─themes/
└─home/
└─.emacs ➞ ../emacs
When running homeshick link dotfiles
, homeshick will now not traverse into the .emacs
folder
in your castle. Instead it will create a symlink named .emacs
in your $HOME
,
which links to $HOME/.homesick/repos/dotfiles/home/.emacs
.
Although homeshick is specifically made for files in your $HOME
directory,
you can get homeshick to venture outside those borders.
Since homeshick follows directory symlinks in $HOME
, you can create one
that points to a different location on your machine.
Please note that managing files outside $HOME
is beyond homeshick's intended scope.
It is possible, but more often than not it is not the right tool for the job.
The strategy outlined below is more of a "hack" than a real pattern.
Consider a scenario where you might have a webapp you want to add to /var/www/tools
.
This is the structure of that app:
tools/
├─public/
│ ├─assets/
│ │ ├─js/
│ │ │ └─jquery.js
│ │ └─css/
│ │ └─bootstrap.css
│ └─index.htm
└─app/
└─controllers/
└─router.py
You will need to place a symlink somewhere inside your $HOME
that points at the intended
location for your webapp. We don't want to clutter $HOME
, so we place the symlink in the
.homesick
directory.
$HOME/
└─.homesick/
├─repos/
│ └─...
└─links/
└─tools ➞ /var/www/tools
The structure of the castle now needs to mimick the location of that symlink:
webapp/
└─home/
└─.homesick/
└─links/
└─tools/
├─public/
│ ├─assets/
│ │ └─...
│ └─index.htm
└─app/
└─...
When running homeshick link webapp
, homeshick will now traverse
into the directory structure of your castle, discover that the resource .homesick/links/tools
already exists, choose the identical
action (see the linking table),
follow the symlink you created, and go on with creating the public/
and app/
folders
in /var/www/tools
.
This method can of course be combined with the shallow symlinking method.
In such a case it would be better to point the symlink in the .homesick/links
directory at /var/www
(to avoid having to create symlinks for both public/
and app/
)
and use the following castle directory structure
webapp/
├─tools/
│ ├─public/
│ │ ├─assets/
│ │ │ └─...
│ │ └─index.htm
│ └─app/
│ └─...
└─home/
└─.homesick/
└─links/
└─var-www/
└─tools ➞ ../../../../tools
If you want the links/
folder to be under version control, you should place it adjacent to a castles home/
folder like this
webapp/
├─tools/
│ └─...
├─home/
│ └─.homesick/
│ └─repos/
│ └─webapp/
│ └─links/
│ └─var-www/
│ └─tools ➞ ../../../../../../tools
└─links/
└─var-www/ ➞ /var/www
This scenario is of course only useful if the destination of your webapp is the same on all the machines homeshick is deployed to. Deployment specific links (like /srv
instead of /var/www
on some installations) are only possible if you keep the symlinks outside of version control.