chocolatey-community / chocolatey-hooks

Chocolatey Community managed repository for hook packages.
https://docs.chocolatey.org/en-us/features/hook
Apache License 2.0
1 stars 7 forks source link

How to use hooks? #6

Open teknowledgist opened 1 year ago

teknowledgist commented 1 year ago

Maybe I'm just ignorant or not keeping up on changes that I should be, but I haven't seen any information on how to use hooks. As the initial "definer" of an early issue, I'm curious how they work so I can try them out. That particular issue was closed and locked before I could ask why the hook solution was better than folding the function in as a choco.exe switch, but regardless, I don't know how to use a hook.

Are there examples or documentation for how to use/call hooks? All I can find is this documentation page advocating for extending Chocolatey with hooks, but nothing for "regular users".

Thanks.

gep13 commented 1 year ago

Let me see if I can help to explain...

A hook is a specifically named PowerShell script, that lives (by default) within the C:\ProgramData\chocolatey\hooks folder. Depending on the name of this file, either before (pre) or after (post) the install/beforemodify/uninstall phase of a Chocolatey operation, this PowerShell script (hook) will be executed, for either a specifically named package, or for all packages.

These PowerShell scripts (hooks) can be placed in the above mentioned location either manually, or by installing a hook package.

A hook package is a specifically named Chocolatey package (specifically a package that ends with .hook). This type of package includes nothing but a collection of hook scripts, and when installed, Chocolatey will do the work of extracting the hook scripts to the above mentioned location. An example of a hook package can be found on the Chocolatey Community Repository. Hook packages are similar in function to a .template or .extension package, where Chocolatey has specific handling for where these packages are installed to.

If we take a closer look at the contents of this hook package, you will see that it contains the following two files:

Based on what we said before, these scripts will be executed before (pre) and after (post) the normal Chocolatey install operation, for all Chocolatey packages. If you look inside the contents of these scripts, you will see that they are attempting to prevent the creation/placement of a shortcut on the users desktop by taking a snapshot of the shortcuts that exist before the installation of a Chocolatey package, and then comparing this to the contents of the desktop after the installation has completed.

So, once this package is installed, any subsequent Chocolatey operations (say for example the installation of another package), will make use of the newly installed (or available), hook scripts.

Why are we suggesting that this work is done this way? Simply put, there are lots of ways during the installation of a Chocolatey package that a desktop shortcut might find its way to your desktop. For example:

So, bottom line, there is no sure fire way that we will catch all of the possible edge cases for how/when a shortcut might appear on your desktop.

As a compromise, we have implemented the hook functionality within Chocolatey that provides the end-user of Chocolatey with the power to write their own scripts (or consume hook packages that are contributed by the community) to do the work that they are looking for.

Trying to put this type of work directly into choco.exe would never cover all the potential ways that folks would want this type of functionality to work, so we opted to extend Chocolatey in a way that would mean that an end-user can do whatever is required for their specific needs.

Just to be clear here, hook scripts (and therefore hook packages) are not constrained to only caring about desktop shortcuts. You can create a hook script that literally does anything that is required for you, or your team, or the wider Chocolatey community, during the normal operation of Chocolatey commands.

So, to recap, to take advantage of hooks, and specifically, a hook that aims to prevent the creation of desktop shortcuts, simply do one of the following:

or

choco install cleanup-desktop-shortcuts.hook --pre 

Then, when you install another package, say for example, windirstat, the desktop shortcut that would normally have been created after the package was installed, will no longer be present.

We recently did a Chocolatey Product Spotlight live stream where we show hook scripts in action. If you wanted to check this out, you can watch it back here:

https://chocolatey.org/events/chocolatey-spotlight-2022-november

If the above helps you to understand hook scripts and hook package better, and you think that there are improvements that can be made to our documentation, I would encourage you to create an issue here:

https://github.com/chocolatey/docs/issues

and ideally, if possible, create a pull request to suggest the required modifications. All of our open source documentation for Chocolatey CLI is on GitHub, and anyone can contribute to it.

If you are unclear about how to contribute to GitHub, and specifically the Chocolatey documentation on GitHub, I did a short series of videos that walk you through exactly how to do this. You can find this playlist here:

https://www.youtube.com/watch?v=MEYjsdZZ5_M&list=PL84yg23i9GBjLbj44FipAIChz98_drwij

pauby commented 1 year ago

I've pinned this issue as I think it's useful for everybody to see. It also highlights a hole in our docs.

teknowledgist commented 1 year ago

@gep13 Thank you for that write-up; It helps a lot.

One key piece of it that I was unclear on and, unfortunately, is not the answer I was hoping for is that hooks are generic and indiscriminate. They run before or after every package install with no ability for the user to selectively apply them (short of installing and uninstalling pre/post package install). That is not necessarily a bad thing, and I see a logical reason and can imagine the potential usefulness to offer the hook feature in Chocolatey. I will be interested in seeing what hook packages get developed.

However, for the purposes of the desktop shortcut question, I feel like it swings too far too the other side. Installing users still do not have individual control over this one (rather annoying) aspect of application installation.

gep13 commented 1 year ago

A hook package can be created that targets a specific package, you use the packageId in the name of the file. Also, you can pass the --skip-hooks option during the operation that is being performed.

gep13 commented 1 year ago

@teknowledgist said... However, for the purposes of the desktop shortcut question, I feel like it swings too far too the other side. Installing users still do not have individual control over this one (rather annoying) aspect of application installation.

Can you perhaps elaborate on this point a little bit?

teknowledgist commented 1 year ago

@gep13 Actually, I think you resolved it.

There are two types of application packages:

  1. Packages for which users can control desktop icons either because the installer has the option or because the maintainer has graciously coded the option.
  2. Packages for which the user cannot control the creation of desktop icons. These are the packages of concern here.

My issue was that with the desktop shortcuts hooks, users still didn't have control over 2 but in the other direction. The hooks do prevent desktop icons from appearing after an install or update, but the user doesn't have granular control. All desktop icons created on installation are removed (or so I thought).

The --skip-hooks option -- that isn't in the documentation on hooks or your explanation above -- does give per-package granular control, so I think you/Chocolatey are "off the hook". 😄 That said, I can imagine someone in the future asking how to skip some hooks and not others.

I'm not convinced that desktop icon prevention/removal couldn't have been adequately managed from within Chocolatey, but I can accept the hooks solution.

Thanks.

TheCakeIsNaOH commented 1 year ago

All desktop icons created on installation are removed (or so I thought).

For the cleanup-desktop-shortcuts.hook hook package, that is correct. All desktop icons/shortcuts created during while running all chocolateyinstall.ps1 scripts are removed. Desktop icons/shortcuts that are preexisting or are added outside Chocolatey package installations should be kept.

The hooks do prevent desktop icons from appearing after an install or update, but the user doesn't have granular control.

So you are saying that you would like a way to configure the hook script via a whitelist/blacklist to keep/remove desktop icons from specific package IDs, instead of removing icons from all package IDs?

This makes sense to me, and is something I would like to add. Once https://github.com/chocolatey/choco/issues/2854 is released (or another mechanism for configuring hooks is decided on), then support for configuring which package IDs have icons removed could be added.

For example, this could be a semicolon separated list of package IDs, and the cleanup-desktop-shortcuts.hook would no-op on those package IDs, and so not remove any icons created.

Would you be able to create an issue for this, with any wants/needs/suggestions for what this configuration would look like?

teknowledgist commented 1 year ago

The hook solution with the --skip-hooks switch is granular at the package level.

If you look at my description of the original issue, I wanted to be able to have sub-package granular control. Some packages deposit multiple icons, and my dream as a user/administrator was to be able to remove (or leave) only the icons I wanted.

A whitelist/blacklist to "lock" the hook on/off for packages isn't a bad idea, but does require some planning and keeping track of another file somewhere whereas the --skip-hooks (and my imagined, ideal switch) would be on-the-moment solutions. For the purposes of desktop icons, it would allow for a Choco upgrade all to be more granular with regard to which applications get to place/keep icons on the desktop. Otherwise, I imagine upgrades would have to be split into the --skip-hooks set and the "all hooks" set.

The brings me back to my assumption that someone at some point is going to want to apply hook "A" to some packages but not hook "B", and unless the hooks are written to affect only specific packages, it wont' be possible (unless --skip-hooks allows for listing the hooks to skip -- idea?).

I still haven't had a chance to play with the hooks, so I don't know when I will be able to create an intelligent issue or documentation, but I will keep both in mind.

gep13 commented 1 year ago

@teknowledgist said... A whitelist/blacklist to "lock" the hook on/off for packages isn't a bad idea, but does require some planning and keeping track of another file somewhere whereas the --skip-hooks (and my imagined, ideal switch) would be on-the-moment solutions.

The file that @TheCakeIsNaOH was referring to here is the chocolatey.config file, which would be updated via the normal choco config command, i.e. you would do something like choco config set --name="hook-alldesktopshortcutfrom" --value-"windirstat;vlc". This configuration value would then be read with the hook script, and shortcuts would be allowed from those packages. So it wouldn't be a separate file that would have to be maintained, it would be within the normal Chocolatey configuration.

@teknowledgist said... If you look at my description of the original issue, I wanted to be able to have sub-package granular control. Some packages deposit multiple icons, and my dream as a user/administrator was to be able to remove (or leave) only the icons I wanted.

This is perhaps where the benefit of moving this work into a hook package starts to come into play. For example, it would be possible to add an almost "interactive" mode to desktop shortcut cleanup to the hook package. In the final part of the hook execution, rather than simply deleting all the shortcuts that were created, it could prompt and say "these are the shortcuts that were just created, what do you want to do, keep or remove". Having that sort of functionality directly in choco.exe would likely not make sense, but confined within a hook package, which it tailored to the specific action that is being executed, it is more than possible. This interactive mode could again be enabled/disabled via a configuration value in the chocolatey.config file, so that folks can get the sort of functionality that they want.

teknowledgist commented 1 year ago

@gep13 Very good. Thanks.

I can see why you might want to push that interactive stuff onto optional hooks, but have you considered allowing Chocolatey to pass parameters to specific hooks? Imagine, for example:

choco install mypackage --hookset @{cleanup-desktop-shortcuts=@{regex='^sidekick'}; aNoisyHook=@{sound='quack'}; dummyHook=$false}

If the cleanup-desktop-shortcuts hook had an optional regex parameter to match shortcut names to remove (defaulting to .*), and a fictional "aNoisyHook" had an optional sound parameter, and a "dummyHook" shouldn't be run for this package this time. That would give a lot of power to hook developers who might want to offer granularity without interaction and users who might want in-the-moment options.

Just my $.02.