Class: Chef::Provider::Package::Homebrew
- Inherits:
-
Chef::Provider::Package
- Object
- Chef::Provider
- Chef::Provider::Package
- Chef::Provider::Package::Homebrew
- Includes:
- Mixin::Homebrew
- Defined in:
- lib/chef/provider/package/homebrew.rb
Instance Attribute Summary
Attributes inherited from Chef::Provider
#action, #after_resource, #current_resource, #logger, #new_resource, #run_context
Instance Method Summary collapse
-
#available_version(i) ⇒ Object
Packages (formula) available to install should have a “stable” version, per the Homebrew project’s acceptable formula documentation, so we will rely on that being the case.
- #brew_cmd_output(*command, **options) ⇒ Object
-
#brew_info ⇒ Object
We implement a querying method that returns the JSON-as-Hash data for a formula per the Homebrew documentation.
- #candidate_version ⇒ Object
- #define_resource_requirements ⇒ Object
- #get_current_versions ⇒ Object
- #install_package(names, versions) ⇒ Object
-
#installed_version(i) ⇒ Object
Some packages (formula) are “keg only” and aren’t linked, because multiple versions installed can cause conflicts.
- #load_current_resource ⇒ Object
-
#package_info(package_name) ⇒ Hash
Return the package information given a package name or package alias.
-
#purge_package(names, versions) ⇒ Object
Homebrew doesn’t really have a notion of purging, do a “force remove”.
- #remove_package(names, versions) ⇒ Object
-
#upgrade_package(names, versions) ⇒ Object
upgrades are a bit harder in homebrew than other package formats.
Methods included from Mixin::Homebrew
#find_homebrew_uid, #find_homebrew_username, #homebrew_bin_path
Methods inherited from Chef::Provider::Package
#as_array, #check_resource_semantics!, #expand_options, #have_any_matching_version?, #initialize, #lock_package, #multipackage_api_adapter, #options, #package_locked, #prepare_for_installation, #preseed_package, #reconfig_package, #removing_package?, #target_version_already_installed?, #unlock_package, #version_compare, #version_equals?, #version_requirement_satisfied?
Methods included from Mixin::SubclassDirective
Methods inherited from Chef::Provider
action, action_description, action_descriptions, #action_nothing, #check_resource_semantics!, #cleanup_after_converge, #compile_and_converge_action, #converge_by, #converge_if_changed, #cookbook_name, #description, #events, include_resource_dsl?, include_resource_dsl_module, #initialize, #introduced, #load_after_resource, #node, #process_resource_requirements, provides, provides?, #recipe_name, #requirements, #resource_collection, #resource_updated?, #run_action, #set_updated_status, supports?, use, use_inline_resources, #validate_required_properties!, #whyrun_mode?, #whyrun_supported?
Methods included from Mixin::Provides
#provided_as, #provides, #provides?
Methods included from Mixin::DescendantsTracker
#descendants, descendants, direct_descendants, #direct_descendants, find_descendants_by_name, #find_descendants_by_name, #inherited, store_inherited
Methods included from Mixin::LazyModuleInclude
#descendants, #include, #included
Methods included from Mixin::PowershellOut
#powershell_out, #powershell_out!
Methods included from Mixin::WindowsArchitectureHelper
#assert_valid_windows_architecture!, #disable_wow64_file_redirection, #forced_32bit_override_required?, #is_i386_process_on_x86_64_windows?, #node_supports_windows_architecture?, #node_windows_architecture, #restore_wow64_file_redirection, #valid_windows_architecture?, #with_os_architecture, #wow64_architecture_override_required?, #wow64_directory
Methods included from DSL::Secret
#default_secret_config, #default_secret_service, #secret, #with_secret_config, #with_secret_service
Methods included from DSL::RenderHelpers
#render_json, #render_toml, #render_yaml
Methods included from DSL::ReaderHelpers
#parse_file, #parse_json, #parse_toml, #parse_yaml
Methods included from DSL::Powershell
Methods included from DSL::RegistryHelper
#registry_data_exists?, #registry_get_subkeys, #registry_get_values, #registry_has_subkeys?, #registry_key_exists?, #registry_value_exists?
Methods included from DSL::ChefVault
#chef_vault, #chef_vault_item, #chef_vault_item_for_environment
Methods included from DSL::DataQuery
#data_bag, #data_bag_item, #search, #tagged?
Methods included from EncryptedDataBagItem::CheckEncrypted
Methods included from DSL::PlatformIntrospection
#older_than_win_2012_or_8?, #platform?, #platform_family?, #value_for_platform, #value_for_platform_family
Methods included from DSL::Recipe
#exec, #have_resource_class_for?, #resource_class_for
Methods included from DSL::Definitions
add_definition, #evaluate_resource_definition, #has_resource_definition?
Methods included from DSL::Resources
add_resource_dsl, remove_resource_dsl
Methods included from DSL::Cheffish
Methods included from DSL::RebootPending
Methods included from DSL::IncludeRecipe
Methods included from Mixin::NotifyingBlock
#notifying_block, #subcontext_block
Methods included from DSL::DeclareResource
#build_resource, #declare_resource, #delete_resource, #delete_resource!, #edit_resource, #edit_resource!, #find_resource, #find_resource!, #resources, #with_run_context
Methods included from DSL::Compliance
#include_input, #include_profile, #include_waiver
Constructor Details
This class inherits a constructor from Chef::Provider::Package
Instance Method Details
#available_version(i) ⇒ Object
Packages (formula) available to install should have a “stable” version, per the Homebrew project’s acceptable formula documentation, so we will rely on that being the case. Older implementations of this provider in the homebrew cookbook would fall back to brew_info, but the schema has changed, and homebrew is a constantly rolling forward project.
github.com/Homebrew/homebrew/wiki/Acceptable-Formulae#stable-versions
180 181 182 183 184 185 186 187 |
# File 'lib/chef/provider/package/homebrew.rb', line 180 def available_version(i) p_data = package_info(i) # nothing is available return nil if p_data.empty? p_data["versions"]["stable"] end |
#brew_cmd_output(*command, **options) ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/chef/provider/package/homebrew.rb', line 189 def brew_cmd_output(*command, **) homebrew_uid = find_homebrew_uid(new_resource.respond_to?(:homebrew_user) && new_resource.homebrew_user) homebrew_user = Etc.getpwuid(homebrew_uid) logger.trace "Executing '#{homebrew_bin_path} #{command.join(" ")}' as user '#{homebrew_user.name}'" # allow the calling method to decide if the cmd should raise or not # brew_info uses this when querying out available package info since a bad # package name will raise and we want to surface a nil available package so that # the package provider can magically handle that shell_out_cmd = [:allow_failure] ? :shell_out : :shell_out! output = send(shell_out_cmd, homebrew_bin_path, *command, user: homebrew_uid, login: true, environment: { "HOME" => homebrew_user.dir, "RUBYOPT" => nil, "TMPDIR" => nil }) output.stdout.chomp end |
#brew_info ⇒ Object
We implement a querying method that returns the JSON-as-Hash data for a formula per the Homebrew documentation. Previous implementations of this provider in the homebrew cookbook performed a bit of magic with the load path to get this information, but that is not any more robust than using the command-line interface that returns the same thing.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/chef/provider/package/homebrew.rb', line 101 def brew_info @brew_info ||= begin command_array = ["info", "--json=v1"].concat package_name_array # convert the array of hashes into a hash where the key is the package name cmd_output = brew_cmd_output(command_array, allow_failure: true) if cmd_output.empty? # we had some kind of failure so we need to iterate through each package to find them package_name_array.each_with_object({}) do |package_name, hsh| cmd_output = brew_cmd_output("info", "--json=v1", package_name, allow_failure: true) if cmd_output.empty? hsh[package_name] = {} else json = Chef::JSONCompat.from_json(cmd_output).first hsh[json["name"]] = json end end else Hash[Chef::JSONCompat.from_json(cmd_output).collect { |pkg| [pkg["name"], pkg] }] end end end |
#candidate_version ⇒ Object
53 54 55 56 57 |
# File 'lib/chef/provider/package/homebrew.rb', line 53 def candidate_version package_name_array.map do |package_name| available_version(package_name) end end |
#define_resource_requirements ⇒ Object
44 45 46 47 48 49 50 51 |
# File 'lib/chef/provider/package/homebrew.rb', line 44 def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { !new_resource.environment } a. Chef::Exceptions::Package, "The environment property is not supported for package resources on this platform" end end |
#get_current_versions ⇒ Object
59 60 61 62 63 |
# File 'lib/chef/provider/package/homebrew.rb', line 59 def get_current_versions package_name_array.map do |package_name| installed_version(package_name) end end |
#install_package(names, versions) ⇒ Object
65 66 67 |
# File 'lib/chef/provider/package/homebrew.rb', line 65 def install_package(names, versions) brew_cmd_output("install", , names.compact) end |
#installed_version(i) ⇒ Object
Some packages (formula) are “keg only” and aren’t linked, because multiple versions installed can cause conflicts. We handle this by using the last installed version as the “current” (as in latest). Otherwise, we will use the version that brew thinks is linked as the current version.
153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/chef/provider/package/homebrew.rb', line 153 def installed_version(i) p_data = package_info(i) if p_data["keg_only"] if p_data["installed"].empty? nil else p_data["installed"].last["version"] end else p_data["linked_keg"] end end |
#load_current_resource ⇒ Object
35 36 37 38 39 40 41 42 |
# File 'lib/chef/provider/package/homebrew.rb', line 35 def load_current_resource @current_resource = Chef::Resource::HomebrewPackage.new(new_resource.name) current_resource.package_name(new_resource.package_name) current_resource.version(get_current_versions) logger.trace("#{new_resource} current package version(s): #{current_resource.version}") if current_resource.version current_resource end |
#package_info(package_name) ⇒ Hash
Return the package information given a package name or package alias
132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/chef/provider/package/homebrew.rb', line 132 def package_info(package_name) # return the package hash if it's in the brew info hash return brew_info[package_name] if brew_info[package_name] # check each item in the hash to see if we were passed an alias brew_info.each_value do |p| return p if p["full_name"] == package_name || p["aliases"].include?(package_name) end {} end |
#purge_package(names, versions) ⇒ Object
Homebrew doesn’t really have a notion of purging, do a “force remove”
87 88 89 |
# File 'lib/chef/provider/package/homebrew.rb', line 87 def purge_package(names, versions) brew_cmd_output("uninstall", "--force", , names.compact) end |
#remove_package(names, versions) ⇒ Object
82 83 84 |
# File 'lib/chef/provider/package/homebrew.rb', line 82 def remove_package(names, versions) brew_cmd_output("uninstall", , names.compact) end |
#upgrade_package(names, versions) ⇒ Object
upgrades are a bit harder in homebrew than other package formats. If you try to brew upgrade a package that isn’t installed it will fail so if a user specifies the action of upgrade we need to figure out which packages need to be installed and which packages can be upgrades. We do this by checking if brew_info has an entry via the installed_version helper.
74 75 76 77 78 79 80 |
# File 'lib/chef/provider/package/homebrew.rb', line 74 def upgrade_package(names, versions) upgrade_pkgs = names.filter_map { |x| x if installed_version(x) } install_pkgs = names.filter_map { |x| x unless installed_version(x) } brew_cmd_output("upgrade", , upgrade_pkgs) unless upgrade_pkgs.empty? brew_cmd_output("install", , install_pkgs) unless install_pkgs.empty? end |