I have been using Linux since I was in my second year of undergraduate. My
experiments with the dotfiles (configuration files) also started at the same
time. For the uninformed, in Linux, it is common to configure a lot of settings
and configurations within dotfiles. Dotfiles are files in a Linux user's home
directory that begin with a dot or a full-stop character. This dot indicates to
the operating system that these files are used to store the settings of programs
like vim
or shells like bash
or fish
to name a few.
In the beginning, I was keeping a manual backup of my dotfiles by copying them to a folder from time to time. But the list soon started getting huge, that it became complicated for me to keep track of the changes. Then I moved to symlinks. I started symlinking all the dotfiles from my folder to their usual locations. This setup worked perfectly fine, but as my collection of dotfiles grew, It became very cumbersome for me to symlink every dotfile manually.
I also tried a few tools built for this particular purpose. Some of them are
vcsh
, mr
, and stow
. These tools work just fine, but I was not willing to
learn new tools just for maintaining my dotfiles. At last, I decided to write my
tool to solve this problem. This way, there will not be any external dependency,
and this tool will also become part of my dotfiles.
Design
The tool, in itself, is inspired by the UNIX tradition of keeping configuration files for the settings of the programs. This configuration system uses a JSON formatted dotfile.
Here is the source code for the configuration system. Let's have a look at the file structure of the repository.
|-- .backups
| |-- 08-01-2018-15:47
| |-- 08-01-2018-19:30
| |-- ......
|-- configure.py
|-- current_status
|-- dotfiles
| |-- dunst
| |-- gtk-3.0
| |-- i3
| |-- ......
|-- dotfiles.json
|-- LICENSE
|-- README.md
|-- .backups
| |-- 08-01-2018-15:47
| |-- 08-01-2018-19:30
| |-- ......
|-- configure.py
|-- current_status
|-- dotfiles
| |-- dunst
| |-- gtk-3.0
| |-- i3
| |-- ......
|-- dotfiles.json
|-- LICENSE
|-- README.md
During the initial setup, you need to edit the dotfiles.json
file to suit your
setup. A relevant section of the JSON file is given below.
{
"pre": [
{
"name": "cloning repository",
"command": "git",
"subcommand": "clone",
"argument": "https://github.com/yashhere/dotfiles.git"
}
],
"linking": [
{
"name": "bashrc",
"src": "dotfiles/.bashrc",
"dest": ".bashrc"
},
{
"name": "bash_profile",
"src": "dotfiles/.bash_profile",
"dest": ".bash_profile"
},
{
"name": "profile",
"src": "dotfiles/.profile",
"dest": ".profile"
},
{
"name": "i3",
"src": "dotfiles/i3",
"dest": ".config/i3"
}
]
}
{
"pre": [
{
"name": "cloning repository",
"command": "git",
"subcommand": "clone",
"argument": "https://github.com/yashhere/dotfiles.git"
}
],
"linking": [
{
"name": "bashrc",
"src": "dotfiles/.bashrc",
"dest": ".bashrc"
},
{
"name": "bash_profile",
"src": "dotfiles/.bash_profile",
"dest": ".bash_profile"
},
{
"name": "profile",
"src": "dotfiles/.profile",
"dest": ".profile"
},
{
"name": "i3",
"src": "dotfiles/i3",
"dest": ".config/i3"
}
]
}
As can be seen, the JSON file has an array variable linking
, which can be used
to set the paths for each configuration file and folder. The configure.py
script also requires a dotfiles
folder to be present in the current directory.
The folder can be created manually, or if it is already version controlled on
GitHub, then the script can clone it. For that, you can edit the pre
section
in the dotfiles.json
.
Your dotfiles and config folders go inside the dotfiles
folder. You need to
copy all your current configurations to this folder to get started.
So, how does the script know where a file or folder will be linked? Simple, you
need to edit the dotfiles.json
file and add source and destination locations.
For example, if you want to set up configurations of i3
to its original
location (which is, $HOME/.config/i3
), then you need to create a new JSON
object in the linking
array, like this.
{
"name": "i3",
"src": "dotfiles/i3",
"dest": ".config/i3"
}
{
"name": "i3",
"src": "dotfiles/i3",
"dest": ".config/i3"
}
Here the name
is used to identify the configuration file, the src
parameter
is the location of your config file/folder in the dotfiles directory, and the
dest
parameter is the final destination of the file/folder. Keen observers
would notice that I have not used $HOME
anywhere. It is understood that the
configuration will go to the current user's home directory. So the dest
is
relative to the user's home directory, and src
is relative to the directory
from which the configure.py
script is executed.
And you are done! Now, run configure.py
, and all your dotfiles and folders
will be symlinked to their correct place.
The current_status
file saves all the symlink locations that are being managed
by the script, for your easy reference and to debug any error.
Behind the Scenes
A lot to cool things happen behind the scenes. The script will check if any
previous symlink exists at the given dest
location. It removes any symlinks to
avoid redundancy. If the dest already has any dotfile or folder, then it backs
it up in the .backups
under today's date and time before replacing it with a
symlink to avoid any potential data loss.
I hope the article was useful. Cheers 😄