Class: Chef::Provider::Package::Homebrew
- Inherits:
-
Chef::Provider::Package
- Object
- Chef::Provider
- Chef::Provider::Package
- Chef::Provider::Package::Homebrew
- Includes:
- Mixin::HomebrewUser
- 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
- #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::HomebrewUser
#find_homebrew_uid, #find_homebrew_username, #homebrew_bin_path
Methods inherited from Chef::Provider::Package
#as_array, #check_resource_semantics!, #define_resource_requirements, #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, #define_resource_requirements, #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
172 173 174 175 176 177 178 179 |
# File 'lib/chef/provider/package/homebrew.rb', line 172 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
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/chef/provider/package/homebrew.rb', line 181 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 'brew #{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! # FIXME: this 1800 second default timeout should be deprecated output = send(shell_out_cmd, "brew", *command, timeout: 1800, user: homebrew_uid, 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.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/chef/provider/package/homebrew.rb', line 93 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
44 45 46 47 48 |
# File 'lib/chef/provider/package/homebrew.rb', line 44 def candidate_version package_name_array.map do |package_name| available_version(package_name) end end |
#get_current_versions ⇒ Object
50 51 52 53 54 |
# File 'lib/chef/provider/package/homebrew.rb', line 50 def get_current_versions package_name_array.map do |package_name| installed_version(package_name) end end |
#install_package(names, versions) ⇒ Object
56 57 58 |
# File 'lib/chef/provider/package/homebrew.rb', line 56 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.
145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/chef/provider/package/homebrew.rb', line 145 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
124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/chef/provider/package/homebrew.rb', line 124 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”
79 80 81 |
# File 'lib/chef/provider/package/homebrew.rb', line 79 def purge_package(names, versions) brew_cmd_output("uninstall", "--force", , names.compact) end |
#remove_package(names, versions) ⇒ Object
74 75 76 |
# File 'lib/chef/provider/package/homebrew.rb', line 74 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.
65 66 67 68 69 70 71 72 |
# File 'lib/chef/provider/package/homebrew.rb', line 65 def upgrade_package(names, versions) # @todo when we no longer support Ruby 2.6 this can be simplified to be a .filter_map upgrade_pkgs = names.select { |x| x if installed_version(x) }.compact install_pkgs = names.select { |x| x unless installed_version(x) }.compact brew_cmd_output("upgrade", , upgrade_pkgs) unless upgrade_pkgs.empty? brew_cmd_output("install", , install_pkgs) unless install_pkgs.empty? end |