TheKevJames / puppet-homebrew

homebrew (+brewcask! +taps!) package installer and provider
https://forge.puppet.com/thekevjames/homebrew
Apache License 2.0
18 stars 44 forks source link

Taps should install before all other homebrew-related resources #26

Closed zbentley closed 8 years ago

zbentley commented 8 years ago

If I install a Tap, it should be ordered by Puppet to install before anything of a normal "package" or "cask" type; otherwise, I regularly get into the situation where Puppet tries to install a package before the tap that provides it has been installed, which necessitates running Puppet again. In some of my larger provisioning operations (for lab workstations--dozens of custom taps for locally-hosted software), I have to run puppet 5 or 6 times to get everything green.

If "tap" were its own Puppet resource type, rather than a thin descendant of Package, it would be possible to do something like this in the provider code (or in site.pp, if you want it to be opt-in):

Homebrew::Tap <| |> -> Package <| |>
TheKevJames commented 8 years ago

I'm not quite sure on this one. Not all taps should come before all homebrew packages: assume some manifest installs fifty packages, twenty-five of which from one tap and twenty-five from another. In this case, clearly each group should begin installing based on only their own tap requirement; a failure to tap one of the resources should not prevent the other twenty-five from installing.

As for making it opt-in-able: maybe, though that will require somewhat of a refactor. I'll play with it a bit.

For now, I'd recommend setting your resource dependencies, eg.

package { 'neovim/neovim':
  ensure   => present,
  provider => tap,
} ->
package { 'neovim':
  ensure   => present,
  provider => homebrew,
}
zbentley commented 8 years ago

I agree with that proviso. I suggested that "all taps should come before all packages" since it is the (perhaps naïvely) easiest way to implement the desired functionality, but if there's some package-granular way of modeling "package X depends on tap Y" then that could be used to ensure that the ordering was . . . I'm not sure if "efficient" is the right word, but perhaps "as lazy as possible"?

However, if that granular modeling can not be achieved, it seems like fragility is preferable here. Say you have two taps, a and b, and two packages: c (which depends on tap a) and d (which depends on tap b). Say tap a succeeds its installation, but b does not. If you continue installing packages, you run the risk of installing a d package from a different tap (that's my understanding of how Homebrew handles name conflicts, and it may well be wrong--it may require explicit tap specification with the tap/package-name convention), which may introduce undesired behavior silently.

zbentley commented 8 years ago

An additional 100% subjective opinion: Puppet libs shouldn't be built for a partially-failing-apply case; they should be built for the successful-apply case, and should fail as sensibly as possible. That failure might entail bailing out of all subsequent package installs. For example, if yum fails to blow away its cache successfully at the beginning of manifest application, all packages fail (though that may have changed in recent releases; I'm testing yum-based packaging on a pretty old CentOS env).

TheKevJames commented 8 years ago

Marking this as wontfix as I think it's the job of the user to enforce relationship ordering rather than the library. See attached PR for the methods of achieving this; similar to your example, you should be able to use

Package <| provider == tap |> -> Package <| |>

to accomplish your goal.

zbentley commented 8 years ago

Sounds good, thanks!