/Library/Homebrew/dependency_collector.rb
Ruby | 188 lines | 150 code | 22 blank | 16 comment | 13 complexity | acf70d0a63460be11859cf45c00fe8f3 MD5 | raw file
- require 'dependency'
- require 'dependencies'
- require 'requirement'
- require 'requirements'
- require 'requirements/ld64_dependency'
- require 'set'
- ## A dependency is a formula that another formula needs to install.
- ## A requirement is something other than a formula that another formula
- ## needs to be present. This includes external language modules,
- ## command-line tools in the path, or any arbitrary predicate.
- ##
- ## The `depends_on` method in the formula DSL is used to declare
- ## dependencies and requirements.
- # This class is used by `depends_on` in the formula DSL to turn dependency
- # specifications into the proper kinds of dependencies and requirements.
- class DependencyCollector
- # Define the languages that we can handle as external dependencies.
- LANGUAGE_MODULES = Set[
- :chicken, :jruby, :lua, :node, :ocaml, :perl, :python, :rbx, :ruby
- ].freeze
- CACHE = {}
- attr_reader :deps, :requirements
- def initialize
- @deps = Dependencies.new
- @requirements = ComparableSet.new
- end
- def add(spec)
- case dep = fetch(spec)
- when Dependency
- @deps << dep
- when Requirement
- @requirements << dep
- end
- dep
- end
- def fetch(spec)
- CACHE.fetch(cache_key(spec)) { |key| CACHE[key] = build(spec) }
- end
- def cache_key(spec)
- if Resource === spec && spec.download_strategy == CurlDownloadStrategy
- File.extname(spec.url)
- else
- spec
- end
- end
- def build(spec)
- spec, tags = case spec
- when Hash then destructure_spec_hash(spec)
- else spec
- end
- parse_spec(spec, Array(tags))
- end
- private
- def destructure_spec_hash(spec)
- spec.each { |o| return o }
- end
- def parse_spec(spec, tags)
- case spec
- when String
- parse_string_spec(spec, tags)
- when Resource
- resource_dep(spec, tags)
- when Symbol
- parse_symbol_spec(spec, tags)
- when Requirement, Dependency
- spec
- when Class
- parse_class_spec(spec, tags)
- else
- raise TypeError, "Unsupported type #{spec.class} for #{spec.inspect}"
- end
- end
- def parse_string_spec(spec, tags)
- if tags.empty?
- Dependency.new(spec, tags)
- elsif (tag = tags.first) && LANGUAGE_MODULES.include?(tag)
- LanguageModuleDependency.new(tag, spec, tags[1])
- elsif HOMEBREW_TAP_FORMULA_REGEX === spec
- TapDependency.new(spec, tags)
- else
- Dependency.new(spec, tags)
- end
- end
- def parse_symbol_spec(spec, tags)
- case spec
- when :autoconf, :automake, :bsdmake, :libtool, :libltdl
- # Xcode no longer provides autotools or some other build tools
- autotools_dep(spec, tags)
- when :x11 then X11Dependency.new(spec.to_s, tags)
- when :cairo, :fontconfig, :freetype, :libpng, :pixman
- # We no longer use X11 proxy deps, but we support the symbols
- # for backwards compatibility.
- Dependency.new(spec.to_s, tags)
- when :xcode then XcodeDependency.new(tags)
- when :macos then MinimumMacOSRequirement.new(tags)
- when :mysql then MysqlDependency.new(tags)
- when :postgresql then PostgresqlDependency.new(tags)
- when :fortran then FortranDependency.new(tags)
- when :mpi then MPIDependency.new(*tags)
- when :tex then TeXDependency.new(tags)
- when :arch then ArchRequirement.new(tags)
- when :hg then MercurialDependency.new(tags)
- # python2 is deprecated
- when :python, :python2 then PythonDependency.new(tags)
- when :python3 then Python3Dependency.new(tags)
- # Tiger's ld is too old to properly link some software
- when :ld64 then LD64Dependency.new if MacOS.version < :leopard
- when :ant then ant_dep(spec, tags)
- when :clt # deprecated
- else
- raise ArgumentError, "Unsupported special dependency #{spec.inspect}"
- end
- end
- def parse_class_spec(spec, tags)
- if spec < Requirement
- spec.new(tags)
- else
- raise TypeError, "#{spec.inspect} is not a Requirement subclass"
- end
- end
- def autotools_dep(spec, tags)
- if spec == :libltdl
- spec = :libtool
- tags << :run
- end
- tags << :build unless tags.include? :run
- Dependency.new(spec.to_s, tags)
- end
- def ant_dep(spec, tags)
- if MacOS.version >= :mavericks
- tags << :build
- Dependency.new(spec.to_s, tags)
- end
- end
- def resource_dep(spec, tags)
- tags << :build
- strategy = spec.download_strategy
- case
- when strategy <= CurlDownloadStrategy
- parse_url_spec(spec.url, tags)
- when strategy <= GitDownloadStrategy
- GitDependency.new(tags)
- when strategy <= MercurialDownloadStrategy
- MercurialDependency.new(tags)
- when strategy <= FossilDownloadStrategy
- Dependency.new("fossil", tags)
- when strategy <= BazaarDownloadStrategy
- Dependency.new("bazaar", tags)
- when strategy <= CVSDownloadStrategy
- Dependency.new("cvs", tags) if MacOS.version >= :mavericks || !MacOS::Xcode.provides_cvs?
- when strategy < AbstractDownloadStrategy
- # allow unknown strategies to pass through
- else
- raise TypeError,
- "#{strategy.inspect} is not an AbstractDownloadStrategy subclass"
- end
- end
- def parse_url_spec(url, tags)
- case File.extname(url)
- when '.xz' then Dependency.new('xz', tags)
- when '.lz' then Dependency.new('lzip', tags)
- when '.rar' then Dependency.new('unrar', tags)
- when '.7z' then Dependency.new('p7zip', tags)
- end
- end
- end