summaryrefslogtreecommitdiff
path: root/lib/rubygems/dependency_resolver/installer_set.rb
blob: c39f77a005bbade20cdefd21d9c7c70a681f8cc7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
class Gem::DependencyResolver::InstallerSet

  ##
  # List of Gem::Specification objects that must always be installed.

  attr_reader :always_install

  ##
  # Only install gems in the always_install list

  attr_accessor :ignore_dependencies

  ##
  # Do not look in the installed set when finding specifications.  This is
  # used by the --install-dir option to `gem install`

  attr_accessor :ignore_installed

  def initialize domain
    @domain = domain

    @f = Gem::SpecFetcher.fetcher

    @all = Hash.new { |h,k| h[k] = [] }
    @always_install      = []
    @ignore_dependencies = false
    @ignore_installed    = false
    @loaded_remote_specs = []
    @specs               = {}
  end

  ##
  # Should local gems should be considered?

  def consider_local?
    @domain == :both or @domain == :local
  end

  ##
  # Should remote gems should be considered?

  def consider_remote?
    @domain == :both or @domain == :remote
  end

  ##
  # Returns an array of IndexSpecification objects matching DependencyRequest
  # +req+.

  def find_all req
    res = []

    dep  = req.dependency

    return res if @ignore_dependencies and
              @always_install.none? { |spec| dep.matches_spec? spec }

    name = dep.name

    dep.matching_specs.each do |gemspec|
      next if @always_install.include? gemspec

      res << Gem::DependencyResolver::InstalledSpecification.new(self, gemspec)
    end unless @ignore_installed

    if consider_local? then
      local_source = Gem::Source::Local.new

      if spec = local_source.find_gem(name, dep.requirement) then
        res << Gem::DependencyResolver::IndexSpecification.new(
          self, spec.name, spec.version, local_source, spec.platform)
      end
    end

    if consider_remote? then
      load_remote_specs dep

      @all[name].each do |remote_source, n|
        if dep.match? n then
          res << Gem::DependencyResolver::IndexSpecification.new(
            self, n.name, n.version, remote_source, n.platform)
        end
      end
    end

    res
  end

  def inspect # :nodoc:
    '#<%s domain: %s specs: %p>' % [ self.class, @domain, @specs.keys ]
  end

  ##
  # Loads remote prerelease specs if +dep+ is a prerelease dependency

  def load_remote_specs dep
    types = [:released]
    types << :prerelease if dep.prerelease?

    types.each do |type|
      next if @loaded_remote_specs.include? type
      @loaded_remote_specs << type

      list, = @f.available_specs type

      list.each do |uri, specs|
        specs.each do |n|
          @all[n.name] << [uri, n]
        end
      end
    end
  end

  ##
  # Called from IndexSpecification to get a true Specification
  # object.

  def load_spec name, ver, platform, source
    key = "#{name}-#{ver}-#{platform}"

    @specs.fetch key do
      tuple = Gem::NameTuple.new name, ver, platform

      @specs[key] = source.fetch_spec tuple
    end
  end

  ##
  # No prefetching needed since we load the whole index in initially.

  def prefetch(reqs)
  end

end