summaryrefslogtreecommitdiff
path: root/lib/rubygems/source/local.rb
blob: a320ff1c66ac0d8993255da626a91f09bcecaa46 (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
# frozen_string_literal: false
##
# The local source finds gems in the current directory for fulfilling
# dependencies.

class Gem::Source::Local < Gem::Source

  def initialize # :nodoc:
    @specs   = nil
    @api_uri = nil
    @uri     = nil
  end

  ##
  # Local sorts before Gem::Source and after Gem::Source::Installed

  def <=> other
    case other
    when Gem::Source::Installed,
         Gem::Source::Lock then
      -1
    when Gem::Source::Local then
      0
    when Gem::Source then
      1
    else
      nil
    end
  end

  def inspect # :nodoc:
    keys = @specs ? @specs.keys.sort : 'NOT LOADED'
    "#<%s specs: %p>" % [self.class, keys]
  end

  def load_specs type # :nodoc:
    names = []

    @specs = {}

    Dir["*.gem"].each do |file|
      begin
        pkg = Gem::Package.new(file)
      rescue SystemCallError, Gem::Package::FormatError
        # ignore
      else
        tup = pkg.spec.name_tuple
        @specs[tup] = [File.expand_path(file), pkg]

        case type
        when :released
          unless pkg.spec.version.prerelease?
            names << pkg.spec.name_tuple
          end
        when :prerelease
          if pkg.spec.version.prerelease?
            names << pkg.spec.name_tuple
          end
        when :latest
          tup = pkg.spec.name_tuple

          cur = names.find { |x| x.name == tup.name }
          if !cur
            names << tup
          elsif cur.version < tup.version
            names.delete cur
            names << tup
          end
        else
          names << pkg.spec.name_tuple
        end
      end
    end

    names
  end

  def find_gem gem_name, version = Gem::Requirement.default, # :nodoc:
               prerelease = false
    load_specs :complete

    found = []

    @specs.each do |n, data|
      if n.name == gem_name
        s = data[1].spec

        if version.satisfied_by?(s.version)
          if prerelease
            found << s
          elsif !s.version.prerelease?
            found << s
          end
        end
      end
    end

    found.max_by { |s| s.version }
  end

  def fetch_spec name # :nodoc:
    load_specs :complete

    if data = @specs[name]
      data.last.spec
    else
      raise Gem::Exception, "Unable to find spec for #{name.inspect}"
    end
  end

  def download spec, cache_dir = nil # :nodoc:
    load_specs :complete

    @specs.each do |name, data|
      return data[0] if data[1].spec == spec
    end

    raise Gem::Exception, "Unable to find file for '#{spec.full_name}'"
  end

  def pretty_print q # :nodoc:
    q.group 2, '[Local gems:', ']' do
      q.breakable
      q.seplist @specs.keys do |v|
        q.text v.full_name
      end
    end
  end

end