Package: dfmpy
dfmSometimes pronounced "diff-em-py" and is a small play on words.  dfm is yet
another Dot-Files Manager, but with robust features that can essentially
"diff" the dotfiles actually installed versus the expected installed files.
Hence the "diff-em".dfm is not just another dotfiles manager, it supports multiple environments
based on hostname, system type, or a combination of the two.  It also ignores
files/directories based on user defined globs which can be particularly useful
if dfm has to traverse directories that have large I/O latencies (large
directory inodes, too many files to stat, or even just network mounted
directories, etc.).InstallationSince dfm isregistered on Pypi, you can install
dfm through standardpipmethods.# Install locally as a normal user:pip3install--user--force--upgradedfmpy# Or install globally, as the all powerful root, for all users of the system:sudopip3install--force--upgradedfmpyFor more installation details, seeINSTALLATION.md.Config FilesTo use dfm you must firstdfm initwhich will create two files config
files:${XDG_CONFIG_HOME}/dfm/config.ini${XDG_CONFIG_HOME}/dfm/ignore.globswhere${XDG_CONFIG_HOME}is usually~/.config.  dfm usesxdgenvpyto get a handle on the dfm config
directory.config.iniis the main config file that tells it, among other things, where to
find your dotfiles repository, where to install symlinks, and even how to manage
identical filenames for different systems.ignore.globsis a set of commonly ignored files and directories that one might
never want synced with their dotfiles repository.  For example, if you manage
your dotfiles repository with Git then you would never want the.gitdirectory
symlinked to your destination directory.  And vice versa, you should never add
SSH keys (~/.ssh/id_*) to your dotfiles repo.  The globs in this file tell
dfm to just skip over the files or directories.Usagedfm makes use of Python'sargparselibrary sub-command
feature.  This gives dfm multiple independent commands with their own set of
CLI arguments.File suffixesTo maintain dotfiles across multiple systems there needs to be a mechanism that
allows for all the files to have the same name when install but not collide when
they reside in the repository.  To get around this dfm makes use of the system's
hostname and system type appended to the file name.For example, developers may want a~/.vimrcin their home directory.  But in
the dotfiles repository we may want all vimrc files next to each other, i.e. in
the same directory.  dfm searches for a##marker in a file to determine if
the file has a system specific variant.  Suppose our dotfiles repo looks like
this:cd~/.files
tree
.|--.vimrc|--.vimrc##host1.Linux|--.vimrc##host2.Linux|--.vimrc##host2.Windows|--.vimrc##host3`--.vimrc##Windows0directories,6files.vimrcis the default vimrc file and will be the symlinked file if no other
system specific file exists..vimrc##host1.Linuxis a system specific file that will only be symlinked if
the hostname is "host1" and the system type is Linux..vimrc##host2.Linuxis a system specific file that will only be symlinked if
the hostname is "host2" and the system type is Linux..vimrc##host2.Windowsis a system specific file that will only be symlinked
if the hostname is "host2" and the system type is Windows..vimrc##host3is a system specific file that will only be symlinked if the
hostname is "host3"..vimrc##Windowsis a system specific file that will only be symlinked if the
system type is Windows.The hostname is determined by the return value fromsocket.gethostname(),
and the system type is determined by the return value fromplatform.system().Common argumentsdfm--help-vis the verbose flag, which can be used multiple times.  This flag controls
which log level gets printed.  The default log level is set to ERROR, which is
lowered to WARNING when one-vflag is set.  Multiple-vflags will lower
the log level even further.-iturns on interactive mode.  dfm strives to be as filesystem safe as
possible.  By default it will not attempt to overwrite files.  The interactive
flag tells dfm to ask for permission when it performs a potentially dangerous
operation.-fturns on force mode.  Again, dfm strives to be filesystem safe.  The
default commands will not overwrite files nor delete files without explicit user
direction.  While interactive mode can help with this, sometimes developers want
to just force an operation and live with the consequences.  Effectively, force
mode short circuits interactive mode and assumes the developers accepts the
operation that dfm is trying to perform (e.g. overwriting a file).Install dfmdfminit--helpCurrently, dfm requires initialization after installation.  We merely need to
run theinitcommand.pip3install--user--force--upgradedfmpy
dfminitSync your dotfilesdfmsync--helpOnce installed and initialized, dfm will utilize the${XDG_CONFIG_HOME}/dfm/config.iniconfig file when it needs to (re)sync your
dotfiles.  Per the defaultconfig.inifile, dfm assumes your dotfiles repo is
initially located at~/.local/share/dotfiles.  If this is not the case, you
need to modify yourconfig.iniaccordingly.dfmsync-fThe sync command will use thedfm/config.inifile to determine where the
dotfiles are installed and where the dotfiles repository is.  It will then
calculate a set of expected symlinks to files.  dfm uses this set to traverse
the installed dotfiles to determine what needs updating.The sync command will create new symlinks to the expected files in the dotfiles
repository.  However, being filesystem safe, the sync command will not unlink
existing symlinks, nor overwrite existing symlinks.  Either interactive or force
mode is required to make such changes.Adding individual filesdfmadd--helpSometimes developers want to add a single file to their dotfiles repository.
dfm has an option to add the file from their home directory directly into their
dotfiles repository, then automatically symlink so a system specific file.For example, let's say we needed to add our~/.vimrcfile to our dotfiles.
The$HOMEdirectory may look roughly like this:ls-al~
drwxr-xr-x22useruser4096Nov1011:47.
drwxr-xr-x3rootroot4096Apr252019..
...
drwxr-xr-x13useruser4096Jul904:54.cache
drwxr-xr-x30useruser4096Nov1011:47.config
drwx------6useruser4096Nov1011:47.local
-rw-------1useruser57Oct2319:13.vimrc
...We can simply add the~/.vimrcfile, and the developer's home directory will
look like this:dfmadd~/.vimrc
ls-al~
drwxr-xr-x22useruser4096Nov1011:47.
drwxr-xr-x3rootroot4096Apr252019..
...
drwxr-xr-x13useruser4096Jul904:54.cache
drwxr-xr-x30useruser4096Nov1011:47.config
drwx------6useruser4096Nov1011:47.local
lrwxrwxrwx1useruser28Nov1011:47.vimrc->/home/user/.files/.vimrc##hostname.Linux
...Under the hood, dfm is simply moving the file into the dotfiles repository with
the most restrictive system specific name.  Then it will create the symlink so
that~/.vimrcpoints to the repository file.Listing the installed (eg synced) filesdfmlist--helpdfm has a unique insight into your dotfiles.  It knows how to ignore certain
files, it knows what files should be symlinked to others, and it knows when
there is a discrepancy with the installed files versus the dotfiles repo.  As
such, simple Bashls -Rortreecommands will not print just the dotfiles
managed by dfm.dfm has alistcommand that prints only the files dfm manages, the files it
expects, and the files that might have broken symlinks.  The file listing also
adheres to dfm's log level conventions:broken symlinks(links to non-existent files) are logged at the CRITICAL
level.stale symlinks(links to the wrong files) are logged at the ERROR level.not installed symlinksare logged at the WARNING level.andproper symlinks(links to the correct files) are logged at the INFO
level.Additionally, the list command has a--treemode that changes the output into
a directory tree structure, rather than a strict list.