-
Notifications
You must be signed in to change notification settings - Fork 1
Actions
DotR supports pre-deployment and post-deployment actions (hooks) that allow you to run shell commands before and after deploying packages. Actions are perfect for automating setup tasks like installing dependencies, reloading services, setting permissions, or running initialization scripts.
Actions are defined in your config.toml as part of package configuration:
-
pre_actions: Array of shell commands executed before deploying the package -
post_actions: Array of shell commands executed after deploying the package
Actions support full variable interpolation using the Tera template syntax, giving you access to all variables (environment, config, package, and user variables).
[packages.tmux]
src = "dotfiles/tmux"
dest = "~/.config/tmux"
# Reload tmux configuration after deployment
post_actions = [
"tmux source-file ~/.config/tmux/tmux.conf || echo 'Tmux not running'"
]When deploying a package, DotR executes actions in this order:
- Pre-actions (in order defined)
- Package deployment (copy files to destination)
- Post-actions (in order defined)
You can define multiple actions per package. They execute sequentially in the order defined:
[packages.nvim]
src = "dotfiles/nvim"
dest = "~/.config/nvim/"
pre_actions = [
"echo 'Preparing Neovim configuration...'",
"mkdir -p ~/.local/share/nvim/site/pack",
"mkdir -p ~/.cache/nvim"
]
post_actions = [
"echo 'Installing plugins...'",
"nvim --headless +PluginInstall +qall",
"echo 'Neovim setup complete!'"
]- If an action fails, DotR reports the error but continues with the deployment
- Use shell operators (
||,&&) for custom error handling - Actions run in a shell environment, so you have access to all shell features
post_actions = [
"command_that_might_fail || echo 'Command failed but continuing...'",
"critical_command && echo 'Success!' || exit 1"
]Actions support Tera template syntax for variable interpolation. All variables are available: environment, config, package, profile, and user variables.
[variables]
EDITOR = "nvim"
[packages.editor_config]
src = "dotfiles/editor"
dest = "~/.config/editor"
post_actions = [
"echo 'Configured editor: {{ EDITOR }}'",
"{{ EDITOR }} --version"
]Package variables are especially useful in actions:
[packages.nvim]
src = "dotfiles/nvim"
dest = "~/.config/nvim/"
[packages.nvim.variables]
PLUGIN_MANAGER = "lazy.nvim"
PLUGIN_DIR = "~/.local/share/nvim/lazy"
pre_actions = [
"echo 'Setting up {{ PLUGIN_MANAGER }}...'",
"mkdir -p {{ PLUGIN_DIR }}"
]
post_actions = [
"echo '{{ PLUGIN_MANAGER }} installation complete'"
]post_actions = [
"echo 'Deployed to {{ HOME }}/.config/app'",
"echo 'User: {{ USER }}'"
]Use Tera conditionals for platform-specific or environment-specific actions:
post_actions = [
"{% if USER == 'production' %}systemctl restart myservice{% endif %}",
"{% if HOME contains 'darwin' %}brew services restart app{% endif %}"
][packages.tmux]
src = "dotfiles/tmux"
dest = "~/.config/tmux"
pre_actions = [
"command -v tmux >/dev/null || brew install tmux"
][packages.i3]
src = "dotfiles/i3"
dest = "~/.config/i3"
post_actions = [
"i3-msg reload || echo 'i3 not running'"
][packages.scripts]
src = "dotfiles/scripts"
dest = "~/.local/bin"
post_actions = [
"chmod +x ~/.local/bin/*.sh"
][packages.nvim]
src = "dotfiles/nvim"
dest = "~/.config/nvim/"
[packages.nvim.variables]
PLUGIN_MANAGER = "lazy.nvim"
pre_actions = [
"echo 'Installing {{ PLUGIN_MANAGER }}...'",
"git clone https://github.com/folke/lazy.nvim ~/.local/share/nvim/lazy/lazy.nvim || echo 'Already installed'"
]
post_actions = [
"nvim --headless '+Lazy! sync' +qa",
"echo '{{ PLUGIN_MANAGER }} plugins synced'"
]pre_actions = [
"[ -f ~/.config/app/config ] && cp ~/.config/app/config ~/.config/app/config.pre-dotr || true"
]pre_actions = [
"mkdir -p ~/.cache/myapp",
"mkdir -p ~/.local/share/myapp/plugins",
"mkdir -p ~/.config/myapp/themes"
][packages.zsh]
src = "dotfiles/zsh"
dest = "~/.config/zsh"
post_actions = [
"zsh ~/.config/zsh/setup.sh",
"echo 'ZSH setup complete'"
][packages.shell]
src = "dotfiles/shell"
dest = "~/.config/shell"
post_actions = [
"{% if USER == 'root' %}echo 'Running as root, skipping user setup'{% else %}./setup-user.sh{% endif %}"
]post_actions = [
"cd ~/.config/app && ./build.sh && ./install.sh"
].uservariables.toml:
API_KEY = "secret-key-123"
DEPLOY_ENV = "production"config.toml:
post_actions = [
"echo 'Deploying to {{ DEPLOY_ENV }} environment'",
"export API_KEY='{{ API_KEY }}' && ./deploy.sh"
][packages.dev_env]
src = "dotfiles/dev"
dest = "~/.config/dev"
dependencies = ["f_bashrc", "d_nvim"]
[packages.dev_env.variables]
NODE_VERSION = "20"
PYTHON_VERSION = "3.11"
pre_actions = [
"echo 'Setting up development environment'",
"echo 'Node: {{ NODE_VERSION }}, Python: {{ PYTHON_VERSION }}'"
]
post_actions = [
"command -v nvm && nvm install {{ NODE_VERSION }} || echo 'NVM not found'",
"command -v pyenv && pyenv install {{ PYTHON_VERSION }} || echo 'pyenv not found'",
"echo 'Development environment ready!'"
]- Use pre-actions for setup: Create directories, check dependencies, backup files
- Use post-actions for configuration: Reload services, run initialization, install plugins
-
Handle errors gracefully: Use
||to provide fallbacks for commands that might fail - Use package variables: Store action-specific values in package variables for clarity
- Test actions independently: Ensure commands work before adding them to actions
- Keep actions simple: Break complex setups into scripts and call them from actions
- Use comments: Document why each action is needed
- Be idempotent: Actions should be safe to run multiple times
-
Check for prerequisites: Verify tools exist before using them (
command -v tool) -
Use verbose output: Add
echostatements to track what actions are doing
- Verify action syntax in
config.toml - Check that package is being deployed (
dotr deploy -p package_name) - Look for error messages in output
- Ensure variable is defined (use
dotr print-varsto check) - Check variable precedence (user > package > config > environment)
- Verify Tera syntax:
{{ VARIABLE }}not$VARIABLE
- Use full paths to executables:
/usr/bin/commandinstead ofcommand - Check that tools are installed before running actions
- Use
command -v toolto verify availability
- Use appropriate paths (user-writable locations)
- Add permission checks in pre-actions
- Consider using
sudowhere necessary (with caution)
Here's a complete example combining multiple features:
banner = true
[variables]
EDITOR = "nvim"
SHELL = "zsh"
[packages.shell_config]
src = "dotfiles/shell"
dest = "~/.config/shell"
post_actions = [
"echo 'Shell configured: {{ SHELL }}'",
"{{ SHELL }} -c 'echo Shell is working!'"
]
[packages.nvim]
src = "dotfiles/nvim"
dest = "~/.config/nvim/"
dependencies = ["shell_config"]
[packages.nvim.variables]
PLUGIN_MANAGER = "lazy.nvim"
THEME = "tokyonight"
pre_actions = [
"echo 'Setting up Neovim with {{ PLUGIN_MANAGER }}'",
"mkdir -p ~/.local/share/nvim/lazy",
"mkdir -p ~/.cache/nvim"
]
post_actions = [
"echo 'Installing plugins with {{ PLUGIN_MANAGER }}'",
"nvim --headless '+Lazy! sync' +qa || echo 'Plugin install failed'",
"echo 'Neovim configured with {{ THEME }} theme'"
]
[packages.tmux]
src = "dotfiles/tmux"
dest = "~/.config/tmux"
pre_actions = [
"command -v tmux >/dev/null || echo 'WARNING: tmux not installed'"
]
post_actions = [
"tmux source-file ~/.config/tmux/tmux.conf 2>/dev/null || echo 'tmux not running'"
]- Configuration Guide - Learn about package configuration
- Templating Guide - Learn about variable usage in templates
- Tera Documentation - Full template syntax reference