diff --git a/README.md b/README.md index a41cc38..3297e1e 100644 --- a/README.md +++ b/README.md @@ -228,8 +228,16 @@ This command will: ### Hooks -You can define `post_install` and `post_purge` hooks in your module's `init.lua` to run arbitrary commands after the module has been installed or purged. +You can define custom hooks in your module's `init.lua` file to run specific commands at different stages of the module's lifecycle. +#### Available Hooks + +- **`post_install`**: Runs after the specified packages have been installed via `brew`. +- **`post_purge`**: Runs after the specified packages have been removed via `brew`. +- **`post_link`**: Runs after configuration files have been linked. +- **`post_unlink`**: Runs after configuration files have been unlinked. + +#### Basic Hook Definition ```lua return { brew = { "gh" }, @@ -237,7 +245,9 @@ return { } ``` -You can also define multi-line hooks: +#### Multi-Line Hook Definition + +You can also define multi-line hooks using Lua's multi-line string syntax. ```lua return { diff --git a/dot.lua b/dot.lua index 7693d20..88493ac 100755 --- a/dot.lua +++ b/dot.lua @@ -370,11 +370,12 @@ end local function handle_config_symlink(config, module_dir, options) if not config.config then - return + return false end local configs = type(config.config) == "table" and config.config[1] and config.config or { config.config } local all_configs_linked = true + local config_changed = false for _, cfg in ipairs(configs) do local source = os.getenv "PWD" .. "/" .. module_dir:gsub("^./", "") .. "/" .. cfg.source:gsub("^./", "") @@ -387,6 +388,7 @@ local function handle_config_symlink(config, module_dir, options) local success, err = delete_path(output) if success then print_message("success", "config → removed " .. output) + config_changed = true else print_message("error", "config → " .. err) end @@ -404,13 +406,14 @@ local function handle_config_symlink(config, module_dir, options) local success, err = ensure_parent_directory(output) if not success then print_message("error", "config → " .. err) - return + return false end -- Copy source to output local success, err = copy_path(source, output) if success then print_message("success", "config → copied " .. source .. " to " .. output) + config_changed = true else print_message("error", "config → " .. err) end @@ -433,11 +436,11 @@ local function handle_config_symlink(config, module_dir, options) print_message("warning", "config → existing config backed up to " .. result) else print_message("error", "config → " .. result) - return + return false end else print_message("error", "config → file already exists at " .. output .. ". Use -f to force.") - return + return false end end @@ -445,7 +448,7 @@ local function handle_config_symlink(config, module_dir, options) local success, err = ensure_parent_directory(output) if not success then print_message("error", "config → " .. err) - return + return false end local cmd = string.format('ln -sf "%s" "%s"', source, output) @@ -454,6 +457,7 @@ local function handle_config_symlink(config, module_dir, options) print_message("error", "config → failed to create symlink: " .. error_output) else print_message("success", "config → symlink created for " .. output) + config_changed = true end end end @@ -466,6 +470,8 @@ local function handle_config_symlink(config, module_dir, options) elseif all_configs_linked and options.unlink_mode then print_message("success", "all configurations are unlinked") end + + return config_changed end -- Process each module by installing/uninstalling dependencies and managing symlinks @@ -490,7 +496,7 @@ local function process_module(module_name, options) local dependencies_changed = process_brew_dependencies(config, options.purge_mode) - handle_config_symlink(config, module_dir, options) + local config_changed = handle_config_symlink(config, module_dir, options) -- Run post_install or post_purge hooks if dependencies_changed or options.hooks_mode then @@ -501,6 +507,15 @@ local function process_module(module_name, options) end end + -- Run post_link or post_unlink hooks + if config_changed or options.hooks_mode then + if options.purge_mode and config.post_unlink then + run_hook(config.post_unlink, "post-unlink") + elseif not options.purge_mode and config.post_link then + run_hook(config.post_link, "post-link") + end + end + print "" -- Add a blank line between modules end diff --git a/spec/dot_spec.lua b/spec/dot_spec.lua index d3a0b56..b19d22d 100644 --- a/spec/dot_spec.lua +++ b/spec/dot_spec.lua @@ -411,6 +411,8 @@ return { }, post_install = "touch %s/.hooks_post_install_ran", post_purge = "touch %s/.hooks_post_purge_ran", + post_link = "touch %s/.hooks_post_link_ran", + post_unlink = "touch %s/.hooks_post_unlink_ran", } ]], home_dir, @@ -430,6 +432,11 @@ return { print("Checking for hook_install at:", hook_install) assert.is_true(path_exists(hook_install), "Post-install hook did not run") + -- Check if post_link hook ran + local hook_link = pl_path.join(home_dir, ".hooks_post_link_ran") + print("Checking for hook_link at:", hook_link) + assert.is_true(path_exists(hook_link), "Post-link hook did not run") + -- Run dot.lua with --purge option for 'dummy_app' assert.is_true(run_dot "--purge dummy_app") @@ -437,6 +444,11 @@ return { local hook_purge = pl_path.join(home_dir, ".hooks_post_purge_ran") print("Checking for hook_purge at:", hook_purge) assert.is_true(path_exists(hook_purge), "Post-purge hook did not run") + + -- Check if post_unlink hook ran + local hook_unlink = pl_path.join(home_dir, ".hooks_post_unlink_ran") + print("Checking for hook_unlink at:", hook_unlink) + assert.is_true(path_exists(hook_unlink), "Post-unlink hook did not run") end) it("should handle multiple configs in a module", function()