Commands¶
A profile provides several so called “commands” that you will use to create
links, set options, decrypt dotfiles and much more. They are called commands
because they behave similar to shell script commands and they won’t need to be
prepended with self
like every other class function needs to in python.
This document explains all those commands and gives examples on how to use
them. The commands are devided into "Basic Commands", "Helper Commands" and
"File manipulation commands".
Basic commands¶
cd(Path)¶
This command switches the directory like you are used to in UNIX. You can use relative paths or absolute paths and make use of environment variables or ‘~’ in the path. All links that will be created after you switched the directory will be linked relative to this directory.
Example:
# Switch to home directory
cd("~")
cd("$HOME")
# Switch to a subdirectory called "config"
cd("config")
# Using absolute paths
cd("/home/user")
link(*Dotfilenames, directory="", **Options)¶
This command takes a list of dotfile names and creates a symlink for
every single one of them in the current directory. It uses the same
name as the dotfile for the symlink as long you don’t specify another
one. This command lets you also set all options defined in the section
of the opt()
command. But unlike the opt()
command it also
accepts another option called directory
which lets you switch the
directory like cd()
. This is handy if you have to link a few
symlinks in different subdirectories of the same parent directory.
This command also accepts dynamicfiles instead of filenames.
Example:
# Find tmux.conf and create a link in the current directory
link("tmux.conf")
# Find pacman.conf and create a link in /etc
link("pacman.conf", directory="/etc")
# Find zsh_profile and create a link called .zprofile in the current directory
link("zsh_profile", name=".zprofile")
# Find polybarconfig and polybarlaunch.sh and create two links named according to the replace regex:
# polybarconfig -> config
# polybarlaunch.sh -> launch.sh
link("polybarconfig", "polybarlaunch.sh", replace_pattern="polybar(.+)", replace=r"\1")
# Find hosts and mkinitcpio.conf and create links in /etc
cd("/etc")
link("hosts", "mkinitcpio.conf")
# In combination with a dynamicfile (in this case using decrypt())
link(decrypt("id_rsa"), dircetory=".ssh")
opt(**Options)¶
There are several options that you can pass to functions like
link()
to control how links are set. The opt()
command will
apply those options permanently for all functions that support setting
options. This is a list of all options available:
- prefix: Every symlink name gets prepended with the provided prefix
- e.g.:
opt(prefix=".")
- e.g.:
- suffix: Same as prefix but appends to the symlink name. Note that
if the symlink name has an extension, the suffix will be inserted before
the extension.
- e.g.:
opt(suffix="somestring")
- e.g.:
- extension: Add or replace the extension of the symlink name
- e.g.:
opt(extension="ini")
- e.g.:
- owner: Sets the user and group owner of the symlink
- e.g.:
opt(owner="peter:users")
- e.g.:
- permission: Sets the permission of the target file (symlinks are
always 777)
- e.g.:
opt(permission=600)
- e.g.:
- replace_pattern: Specify a regular expression that will match what
you want to replace in the filename
- e.g.:
opt(replace_pattern="vim(.+)")
- e.g.:
- replace: Specify a string that replaces the
replace_pattern
- e.g.:
opt(replace=r"\1")
this will strip away any “vim” prefix of the symlinks name if used in combination with above example
- e.g.:
- name: Sets the name of the symlink. This can be a path as well.
- e.g.:
opt(name="config")
but usually used like thislink("polybarconfig", name=".config/polybar/config")
- e.g.:
- optional: If no correct version of a file is found and this is set
to True no error will be raised
- e.g.:
opt(optional=True)
- e.g.:
- secure: If set to True the symlink target will be chown to match the
owner of the symlink. Otherwise the target will be chown to the user that
started uberdot. Defaults to True.
- e.g.:
opt(secure=False)
- e.g.:
links(Pattern, encrypted=False, directory="", **Options)¶
This command works like link()
but instead of a list of filenames
it receives a regular expression. All dotfiles will be linked that
match this pattern (tags will be stripped away before matching). This
can be very handy because you don’t even have to edit your profile
when you add a new dotfile to your repository as long you use the same
naming pattern for those files. This command also has the advantage
that you don’t have to specify the replace_pattern
property if you
want to use replace
. The search pattern will be reused for this
purpose if replace_pattern
is not set. Another feature unique to
this command is that it supports the option encrypted
which will
decrypt every file that matches link, when set to True.
Example:
# Find the files gvimrc and vimrc and create the links called .gvimrc and .vimrc
links("g?vimrc", prefix=".")
# Find all files that match "rofi-*.rasi" and create links that strip away the "rofi-"
links("rofi-.+\.rasi", replace_pattern="rofi-(.+\.rasi)", replace=r"\1")
links("rofi-(.+\.rasi)", replace=r"\1") # Does the same as above
# Decrypt files on the fly
links("wifi-(.+).gpg", replace=r"\1", encrypted=True)
extlink(Path, directory="", **Options)¶
Creates a link to any file or directory by specifying a path. Relative
paths will be relatively to the directory the pofile is currently in.
The links name will be the same as the file or the directory if you don't
set another. Otherwise it behaves like the link()
command.
Example:
# Create a symlink from ~/.wallpapers/wallpaper.png to ~/owncloud/data/pictures/wallpaper.png
extlink("owncloud/data/pictures/wallpaper.png", directory=".wallpapers")
# Create a symlink from ~/Pictures to ~/owncloud/data/Camera/
extlink("~/owncloud/data/Camera", name="Pictures")
tags(*tags)¶
Takes a list of tags and adds all of them. A tag is just any string of characters (except for ‘%’) that you can choose as you like. It will be used to find alternate versions of a dotfile. Such a alternate version of a dotfile needs to be prefixed with the same tag plus a percent sign as a separator. The easiest way to explain this concept is with an example. Suppose you created a profile for your bash configuration:
from uberdot.profile import Profile
class Bash(Profile):
def generate(self):
link("bashrc", "inputrc", prefix=".")
This profile will search for the files bashrc
and inputrc
and
links them to .bashrc
and .inputrc
in your home directory. To
reuse this profile on different distributions you can now create
alternate versions of the files and name them like this:
- debian%bashrc
- debian%inputrc
- arch%bashrc
- arch%inputrc
Now you could create a profile for every device or distribution as you like and set the suitable tag.
from uberdot.profile import Profile
class Device1(Profile):
def generate(self):
tags("debian")
subprof("Bash")
from uberdot.profile import Profile
class Device2(Profile):
def generate(self):
tags("arch")
subprof("Bash")
So just install Device1 on devices that are running Debian and Device2 on devices that are running Arch Linux. The idea is that you create one “super” profile for every device and a profile for any program that you configure. By just setting the right tags that describe the device and adding the subprofiles for the programs that you want to configure you can basically setup any new device or variation of your configuration in a few minutes.
subprof(*profiles)¶
This command accepts a list of profilenames that will be executed as
subprofiles. A subprofile takes all properties (options, tags and the
current working directory) of its parent at the time this command is
called. It is considered good practice to call this directly at the
beginning of your profile but after the tags()
because usually you
don’t want to use the parents current working directory (which will
most likely change) but want to start in your home directory. A
subprofile is connected with it’s parent in that sense that it will be
updated/removed when the parent is updated/removed.
Example: This will search for the profiles Bash
, Vim
and
I3
and install them as subprofile of Main
. If no default
directory was set Main
starts in your home-directory. This means
Bash
and Vim
would also start in your home-directory, whereas
I3
would start at ~/.config/
.
class Main(Profile):
def generate(self):
subprof("Bash", "Vim")
cd(".config")
subprof("I3")
Helper commands¶
find(Dotfilename)¶
Search for a dotfile like link()
or other commands do. It returns the absolute
path to the dotfile. If no matching file is found, None
will be returned.
If more than one file is found, an error will be raised.
You can overwrite this function to change the searching behaviour of the entire
profile.
has_tag(tags)¶
Takes a tag and returns if it is set.
rmtags(*tags)¶
Takes a list of tags. Removes all of them if they are set.
default(*Optionnames)¶
This command accepts a list of options and sets them back to default.
If no option is provided it sets all options back to default. Tags are
handeled internally as an option that has list of tags, so you can
reset them with default()
as well.
Example:
# Set one option back to default
default("permission")
# Set multiple option back to default
default("optional", "owner", "prefix")
# Set all option (tags inclusive) back to default
default()
# Remove all tags (the default list of tags is empty)
default("tags")
File manipulation commands¶
decrypt(Dotfilename)¶
This command takes a single filename and searches for it like link()
. It
will decrypt it and return the decrypted file as a dynamicfile which then can
be used by link()
. If decryptPwd
is set in your configfile this will be
used for every decryption. Otherwise uberdot (or more precisely gnupg) will
ask you for the password. Because all dynamicfiles are regenerated every time a
profile gets executed, this command has the downside that it actually asks for
the decryption password even though nothing changed, so I highly recommend setting
decryptPwd
.
Example: This creates a DynamicFile called gitconfig
at
data/decrypted
. The DynamicFile contains the decrypted content of the
encrypted dotfile gitconfig
. Furthermore this creates a symlink in your
home directory called .gitconfig
which points to the DynamicFile.
link(decrypt("gitconfig"), prefix=".")
Example: To decrypt multiple files at once you could use python’s list
comprehension or use links()
with encrypted
setting. This will decrypt
key1
, key2
, key3
and key4
and link them to key1.pkk
,
key2.pkk
, key3.pkk
and key4.pkk
.
# using list comprehension
keyfiles = [decrypt(file) for file in ["key1", "key2", "key3", "key4"]]
link(keyfiles, suffix=".pkk")
# instead of decrypting every file by itself
link(decrypt("key1"), decrypt("key2"), decrypt("key3"), decrypt("key4"), suffix=".pkk")
# or use the links() command with encrypted option
links("key[1-4]", suffix=".pkk", encrypted=True)
merge(name, *Dotfilenames)¶
This command lets you merge multiple dotfiles into a one big dotfile. That is useful if you want to split a configuration file that doesn’t support source-operations (e.g. i3). It even works with tags, so the dotfile can be generated using alternate versions of the splittet files. The first parameter is the name that you give the new merged dotfile. All following parameters are dotfiles that will be searched for and merged in the order you provide. The command returns the merged dotfile as DynamicFile.
Example: This creates a DynamicFile called vimrc
at data/merged/
.
vimrc
contains the content of the dotfiles defaults.vim
,
keybindings.vim
and plugins.vim
. Furthermore this creates a symlink to
this DynamicFile in your home directory called .vimrc
.
link(merge("vimrc", ["defaults.vim", "keybindings.vim", "plugins.vim"]), prefix=".")
pipe(Dotfilename, shell_command)¶
This command lets you execute any shell command on a dotfile before linking it by piping its content into the specified shell command. It returns the result as a DynamicFile. This command also accepts a Dynamicfile instead of a filename.
Example: Think of a file text.txt
that only contains the numbers
one to twenty with each number on a separate line.
link(pipe("test.txt", "grep 2"))
This will create a link called test.txt
which only contains the numbers 2,
12 and 20.