That's a good idea...
Instead of a list of tuples, it may make more sense to provide a dictionary.
dict(gcc='7.3.0', ruby='2.5.1p57', ...)
I don't think we want to deal with any compile options for packages at the generic level, though if someone wants to do that for the ports module I am ok with that later.
I would be fine with requiring that to be one package at a time for ports if they want to have parameters that aren't easy to designate together. Free BSD users have been GREAT contributors to my stuff in the past, but I wouldn't want to make that complicate the data entry for 99% of the other users out there.
So it sounds like it needs to accept three things:
a dict with versions, and some versions could be None, saying just whatever
a list of strings
Do to this effectively, I'd probably propose making a PackageList class that the provider can use to parse this, to avoid too much duplication between the package modules.
The code paths will need to become more complicated, adapting into loops. I am ok with it still saying "needs_install" and then storing the list of packages that actually need to be installed on the provider object so they don't have to be calculated again.
We don't need to have stuff like "needs_install_%s" % pkg_name as this would mess up the output in the app when returning too many actions.
Not sure if this is too "into the weeds" or not, so let me know.
I'm more than happy to take a first crack at this for probably apt and/or yum and let someone else apt dnf. I think my preferences may be a little specific. once that is done, it will be easy to add the apt-fast change.
Plus, we need to get this done anyway before moving on to pip.
Shouldn't be too bad...