Skip to content

Actions

Utsob Roy edited this page Nov 21, 2025 · 2 revisions

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.

Overview

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).

Basic Example

[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'"
]

Action Execution

Execution Order

When deploying a package, DotR executes actions in this order:

  1. Pre-actions (in order defined)
  2. Package deployment (copy files to destination)
  3. Post-actions (in order defined)

Multiple Actions

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!'"
]

Error Handling

  • 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"
]

Variable Interpolation

Actions support Tera template syntax for variable interpolation. All variables are available: environment, config, package, profile, and user variables.

Basic Variable Usage

[variables]
EDITOR = "nvim"

[packages.editor_config]
src = "dotfiles/editor"
dest = "~/.config/editor"

post_actions = [
    "echo 'Configured editor: {{ EDITOR }}'",
    "{{ EDITOR }} --version"
]

Package Variables in Actions

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'"
]

Environment Variables

post_actions = [
    "echo 'Deployed to {{ HOME }}/.config/app'",
    "echo 'User: {{ USER }}'"
]

Conditional Actions

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 %}"
]

Common Use Cases

Installing Dependencies

[packages.tmux]
src = "dotfiles/tmux"
dest = "~/.config/tmux"

pre_actions = [
    "command -v tmux >/dev/null || brew install tmux"
]

Reloading Services

[packages.i3]
src = "dotfiles/i3"
dest = "~/.config/i3"

post_actions = [
    "i3-msg reload || echo 'i3 not running'"
]

Setting Permissions

[packages.scripts]
src = "dotfiles/scripts"
dest = "~/.local/bin"

post_actions = [
    "chmod +x ~/.local/bin/*.sh"
]

Initializing Applications

[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'"
]

Backing Up Before Deployment

pre_actions = [
    "[ -f ~/.config/app/config ] && cp ~/.config/app/config ~/.config/app/config.pre-dotr || true"
]

Creating Directory Structures

pre_actions = [
    "mkdir -p ~/.cache/myapp",
    "mkdir -p ~/.local/share/myapp/plugins",
    "mkdir -p ~/.config/myapp/themes"
]

Running Setup Scripts

[packages.zsh]
src = "dotfiles/zsh"
dest = "~/.config/zsh"

post_actions = [
    "zsh ~/.config/zsh/setup.sh",
    "echo 'ZSH setup complete'"
]

Advanced Examples

Platform-Specific Actions

[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 %}"
]

Chaining Multiple Commands

post_actions = [
    "cd ~/.config/app && ./build.sh && ./install.sh"
]

Using Variables from .uservariables.toml

.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"
]

Complex Setup with Dependencies

[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!'"
]

Best Practices

  1. Use pre-actions for setup: Create directories, check dependencies, backup files
  2. Use post-actions for configuration: Reload services, run initialization, install plugins
  3. Handle errors gracefully: Use || to provide fallbacks for commands that might fail
  4. Use package variables: Store action-specific values in package variables for clarity
  5. Test actions independently: Ensure commands work before adding them to actions
  6. Keep actions simple: Break complex setups into scripts and call them from actions
  7. Use comments: Document why each action is needed
  8. Be idempotent: Actions should be safe to run multiple times
  9. Check for prerequisites: Verify tools exist before using them (command -v tool)
  10. Use verbose output: Add echo statements to track what actions are doing

Troubleshooting

Actions Not Running

  • Verify action syntax in config.toml
  • Check that package is being deployed (dotr deploy -p package_name)
  • Look for error messages in output

Variable Not Interpolating

  • Ensure variable is defined (use dotr print-vars to check)
  • Check variable precedence (user > package > config > environment)
  • Verify Tera syntax: {{ VARIABLE }} not $VARIABLE

Command Not Found

  • Use full paths to executables: /usr/bin/command instead of command
  • Check that tools are installed before running actions
  • Use command -v tool to verify availability

Permission Errors

  • Use appropriate paths (user-writable locations)
  • Add permission checks in pre-actions
  • Consider using sudo where necessary (with caution)

Examples Repository

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'"
]

Further Reading