summaryrefslogtreecommitdiff
path: root/lib/bundler/index.rb
blob: d92035f86f63d6e2039d39519fa53c3a72df5120 (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
module Bundler
  class Index
    def self.build
      i = new
      yield i
      i
    end

    def self.installed_gems
      build do |idx|
        idx.use bundler_gems
        idx.use system_gems
      end
    end

    def self.bundler_gems
      Source::BundlerGems.new.specs
    end

    def self.system_gems
      Source::SystemGems.new.specs
    end

    def self.cached_gems
      build do |idx|
        idx.use application_cached_gems
        idx.use system_cached_gems
      end
    end

    def self.application_cached_gems
      path = "#{Bundler.root}/vendor/cache"
      if File.directory?(path)
        from_cached_specs(path)
      end
    end

    def self.system_cached_gems
      from_cached_specs("#{Bundler.bundle_path}/cache")
    end

    def self.from_cached_specs(path)
      Source::GemCache.new("path" => path).specs
    end

    def initialize
      @cache = {}
      @specs = Hash.new { |h,k| h[k] = [] }
    end

    def initialize_copy(o)
      super
      @cache = {}
      @specs = Hash.new { |h,k| h[k] = [] }
      merge!(o)
    end

    def empty?
      each { return false }
      true
    end

    def search(query)
      case query
      when Gem::Specification, RemoteSpecification then search_by_spec(query)
      when String then @specs[query]
      else search_by_dependency(query)
      end
    end

    def sources
      @specs.values.map do |specs|
        specs.map{|s| s.source.class }
      end.flatten.uniq
    end

    alias [] search

    def <<(spec)
      arr = @specs[spec.name]

      arr.delete_if do |s|
        s.version == spec.version && s.platform == spec.platform
      end

      arr << spec
      spec
    end

    def each(&blk)
      @specs.values.each do |specs|
        specs.each(&blk)
      end
    end

    def use(other)
      return unless other
      other.each do |s|
        next if search_by_spec(s).any?
        @specs[s.name] << s
      end
      self
    end

  private

    def search_by_spec(spec)
      @specs[spec.name].select { |s| s.version == spec.version && s.platform == spec.platform }
    end

    def search_by_dependency(dependency)
      @cache[dependency.hash] ||= begin
        specs = @specs[dependency.name]

        wants_prerelease = dependency.requirement.prerelease?
        only_prerelease  = specs.all? {|spec| spec.version.prerelease? }
        found = specs.select { |spec| dependency =~ spec }

        unless wants_prerelease || only_prerelease
          found.reject! { |spec| spec.version.prerelease? }
        end

        found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
      end
    end

  end
end