| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  | require "dependable" | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | # A dependency on another Homebrew formula. | 
					
						
							|  |  |  | class Dependency | 
					
						
							| 
									
										
										
										
											2017-06-26 07:30:28 +02:00
										 |  |  |   extend Forwardable | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |   include Dependable | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 19:47:19 +00:00
										 |  |  |   attr_reader :name, :tags, :env_proc, :option_names | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-19 21:46:20 +09:00
										 |  |  |   DEFAULT_ENV_PROC = proc {}.freeze | 
					
						
							| 
									
										
										
										
											2014-02-27 14:22:43 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 19:47:19 +00:00
										 |  |  |   def initialize(name, tags = [], env_proc = DEFAULT_ENV_PROC, option_names = [name]) | 
					
						
							| 
									
										
										
										
											2018-06-01 19:22:33 +01:00
										 |  |  |     raise ArgumentError, "Dependency must have a name!" unless name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-27 14:22:43 -06:00
										 |  |  |     @name = name | 
					
						
							| 
									
										
										
										
											2013-05-06 16:08:50 -05:00
										 |  |  |     @tags = tags | 
					
						
							| 
									
										
										
										
											2014-02-27 14:22:43 -06:00
										 |  |  |     @env_proc = env_proc | 
					
						
							| 
									
										
										
										
											2015-12-14 19:47:19 +00:00
										 |  |  |     @option_names = option_names | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def to_s | 
					
						
							|  |  |  |     name | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def ==(other) | 
					
						
							| 
									
										
										
										
											2014-11-21 16:08:37 -06:00
										 |  |  |     instance_of?(other.class) && name == other.name && tags == other.tags | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-09-23 18:13:48 +02:00
										 |  |  |   alias eql? == | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def hash | 
					
						
							| 
									
										
										
										
											2014-11-21 16:08:37 -06:00
										 |  |  |     name.hash ^ tags.hash | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def to_formula | 
					
						
							| 
									
										
										
										
											2014-08-11 17:48:30 -05:00
										 |  |  |     formula = Formulary.factory(name) | 
					
						
							|  |  |  |     formula.build = BuildOptions.new(options, formula.options) | 
					
						
							|  |  |  |     formula | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 07:30:28 +02:00
										 |  |  |   delegate installed?: :to_formula | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-27 14:22:43 -06:00
										 |  |  |   def satisfied?(inherited_options) | 
					
						
							|  |  |  |     installed? && missing_options(inherited_options).empty? | 
					
						
							| 
									
										
										
										
											2013-01-27 19:40:10 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-23 22:41:35 -05:00
										 |  |  |   def missing_options(inherited_options) | 
					
						
							| 
									
										
										
										
											2016-12-10 17:58:41 +00:00
										 |  |  |     formula = to_formula | 
					
						
							|  |  |  |     required = options | 
					
						
							|  |  |  |     required |= inherited_options | 
					
						
							|  |  |  |     required &= formula.options.to_a | 
					
						
							|  |  |  |     required -= Tab.for_formula(formula).used_options | 
					
						
							|  |  |  |     required | 
					
						
							| 
									
										
										
										
											2013-01-27 19:40:10 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-03 15:08:47 -05:00
										 |  |  |   def modify_build_environment | 
					
						
							| 
									
										
										
										
											2017-09-24 19:24:46 +01:00
										 |  |  |     env_proc&.call | 
					
						
							| 
									
										
										
										
											2013-06-03 15:08:47 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-07 20:36:13 -05:00
										 |  |  |   def inspect | 
					
						
							| 
									
										
										
										
											2014-07-01 15:07:06 -05:00
										 |  |  |     "#<#{self.class.name}: #{name.inspect} #{tags.inspect}>" | 
					
						
							| 
									
										
										
										
											2013-06-07 20:36:13 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-27 23:23:22 -05:00
										 |  |  |   # Define marshaling semantics because we cannot serialize @env_proc | 
					
						
							|  |  |  |   def _dump(*) | 
					
						
							|  |  |  |     Marshal.dump([name, tags]) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def self._load(marshaled) | 
					
						
							| 
									
										
										
										
											2017-10-07 00:31:28 +02:00
										 |  |  |     new(*Marshal.load(marshaled)) # rubocop:disable Security/MarshalLoad | 
					
						
							| 
									
										
										
										
											2013-09-27 23:23:22 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |   class << self | 
					
						
							|  |  |  |     # Expand the dependencies of dependent recursively, optionally yielding | 
					
						
							| 
									
										
										
										
											2018-10-18 21:42:43 -04:00
										 |  |  |     # `[dependent, dep]` pairs to allow callers to apply arbitrary filters to | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |     # the list. | 
					
						
							|  |  |  |     # The default filter, which is applied when a block is not given, omits | 
					
						
							|  |  |  |     # optionals and recommendeds based on what the dependent has asked for. | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     def expand(dependent, deps = dependent.deps, &block) | 
					
						
							| 
									
										
										
										
											2016-01-18 08:59:43 +00:00
										 |  |  |       # Keep track dependencies to avoid infinite cyclic dependency recursion. | 
					
						
							|  |  |  |       @expand_stack ||= [] | 
					
						
							|  |  |  |       @expand_stack.push dependent.name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 15:38:39 -05:00
										 |  |  |       expanded_deps = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       deps.each do |dep| | 
					
						
							| 
									
										
										
										
											2014-02-27 14:22:42 -06:00
										 |  |  |         next if dependent.name == dep.name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 15:41:18 +00:00
										 |  |  |         # we only care about one level of test dependencies. | 
					
						
							|  |  |  |         next if dep.test? && @expand_stack.length > 1
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-22 21:36:11 -05:00
										 |  |  |         case action(dependent, dep, &block) | 
					
						
							|  |  |  |         when :prune | 
					
						
							| 
									
										
										
										
											2014-02-13 15:38:39 -05:00
										 |  |  |           next | 
					
						
							| 
									
										
										
										
											2013-07-22 21:36:11 -05:00
										 |  |  |         when :skip | 
					
						
							| 
									
										
										
										
											2016-01-18 08:59:43 +00:00
										 |  |  |           next if @expand_stack.include? dep.name | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 15:38:39 -05:00
										 |  |  |           expanded_deps.concat(expand(dep.to_formula, &block)) | 
					
						
							| 
									
										
										
										
											2013-11-13 10:38:14 -06:00
										 |  |  |         when :keep_but_prune_recursive_deps | 
					
						
							| 
									
										
										
										
											2014-02-13 15:38:39 -05:00
										 |  |  |           expanded_deps << dep | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2016-01-18 08:59:43 +00:00
										 |  |  |           next if @expand_stack.include? dep.name | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 15:38:39 -05:00
										 |  |  |           expanded_deps.concat(expand(dep.to_formula, &block)) | 
					
						
							|  |  |  |           expanded_deps << dep | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2014-02-13 15:38:39 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-06-07 22:27:30 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-09 14:36:10 -06:00
										 |  |  |       merge_repeats(expanded_deps) | 
					
						
							| 
									
										
										
										
											2016-02-06 13:32:12 +08:00
										 |  |  |     ensure | 
					
						
							|  |  |  |       @expand_stack.pop | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     def action(dependent, dep, &_block) | 
					
						
							| 
									
										
										
										
											2013-07-22 21:36:11 -05:00
										 |  |  |       catch(:action) do | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |         if block_given? | 
					
						
							|  |  |  |           yield dependent, dep | 
					
						
							|  |  |  |         elsif dep.optional? || dep.recommended? | 
					
						
							| 
									
										
										
										
											2013-12-09 14:36:10 -06:00
										 |  |  |           prune unless dependent.build.with?(dep) | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-22 21:48:53 -05:00
										 |  |  |     # Prune a dependency and its dependencies recursively | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |     def prune | 
					
						
							| 
									
										
										
										
											2013-07-22 21:36:11 -05:00
										 |  |  |       throw(:action, :prune) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-22 21:48:53 -05:00
										 |  |  |     # Prune a single dependency but do not prune its dependencies | 
					
						
							| 
									
										
										
										
											2013-07-22 21:36:11 -05:00
										 |  |  |     def skip | 
					
						
							|  |  |  |       throw(:action, :skip) | 
					
						
							| 
									
										
										
										
											2013-05-10 23:45:05 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-07 22:27:30 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-13 10:38:14 -06:00
										 |  |  |     # Keep a dependency, but prune its dependencies | 
					
						
							|  |  |  |     def keep_but_prune_recursive_deps | 
					
						
							|  |  |  |       throw(:action, :keep_but_prune_recursive_deps) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 16:08:37 -06:00
										 |  |  |     def merge_repeats(all) | 
					
						
							| 
									
										
										
										
											2014-11-21 22:25:36 -06:00
										 |  |  |       grouped = all.group_by(&:name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       all.map(&:name).uniq.map do |name| | 
					
						
							|  |  |  |         deps = grouped.fetch(name) | 
					
						
							| 
									
										
										
										
											2014-11-21 16:08:37 -06:00
										 |  |  |         dep  = deps.first | 
					
						
							| 
									
										
										
										
											2015-12-15 10:50:38 +01:00
										 |  |  |         tags = merge_tags(deps) | 
					
						
							| 
									
										
										
										
											2015-12-14 19:47:19 +00:00
										 |  |  |         option_names = deps.flat_map(&:option_names).uniq | 
					
						
							|  |  |  |         dep.class.new(name, tags, dep.env_proc, option_names) | 
					
						
							| 
									
										
										
										
											2013-06-07 22:27:30 -05:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-12-15 10:50:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def merge_tags(deps) | 
					
						
							| 
									
										
										
										
											2018-03-08 09:46:53 +00:00
										 |  |  |       other_tags = deps.flat_map(&:option_tags).uniq | 
					
						
							|  |  |  |       other_tags << :test if deps.flat_map(&:tags).include?(:test) | 
					
						
							|  |  |  |       merge_necessity(deps) + merge_temporality(deps) + other_tags | 
					
						
							| 
									
										
										
										
											2015-12-15 10:50:38 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def merge_necessity(deps) | 
					
						
							|  |  |  |       # Cannot use `deps.any?(&:required?)` here due to its definition. | 
					
						
							|  |  |  |       if deps.any? { |dep| !dep.recommended? && !dep.optional? } | 
					
						
							|  |  |  |         [] # Means required dependency. | 
					
						
							|  |  |  |       elsif deps.any?(&:recommended?) | 
					
						
							|  |  |  |         [:recommended] | 
					
						
							|  |  |  |       else # deps.all?(&:optional?) | 
					
						
							|  |  |  |         [:optional] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def merge_temporality(deps) | 
					
						
							| 
									
										
										
										
											2018-03-19 10:11:08 +00:00
										 |  |  |       # Means both build and runtime dependency. | 
					
						
							|  |  |  |       return [] unless deps.all?(&:build?) | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-19 10:11:08 +00:00
										 |  |  |       [:build] | 
					
						
							| 
									
										
										
										
											2015-12-15 10:50:38 +01:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-01-26 20:05:39 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							| 
									
										
										
										
											2014-02-28 11:16:55 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TapDependency < Dependency | 
					
						
							| 
									
										
										
										
											2014-12-29 12:20:03 +00:00
										 |  |  |   attr_reader :tap | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 19:47:19 +00:00
										 |  |  |   def initialize(name, tags = [], env_proc = DEFAULT_ENV_PROC, option_names = [name.split("/").last]) | 
					
						
							| 
									
										
										
										
											2017-01-15 17:40:51 +00:00
										 |  |  |     @tap = Tap.fetch(name.rpartition("/").first) | 
					
						
							| 
									
										
										
										
											2015-12-14 19:47:19 +00:00
										 |  |  |     super(name, tags, env_proc, option_names) | 
					
						
							| 
									
										
										
										
											2014-02-28 11:16:55 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def installed? | 
					
						
							|  |  |  |     super | 
					
						
							|  |  |  |   rescue FormulaUnavailableError | 
					
						
							|  |  |  |     false | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |