Class: Gel::Catalog::DependencyIndex

Inherits:
Object
  • Object
show all
Includes:
Common
Defined in:
lib/gel/catalog/dependency_index.rb

Constant Summary collapse

CACHE_TYPE =
"quick"
LIST_MAX =
40

Instance Method Summary collapse

Methods included from Common

#gem_info

Constructor Details

#initialize(catalog, *args) ⇒ DependencyIndex

Returns a new instance of DependencyIndex.



18
19
20
21
22
23
24
25
# File 'lib/gel/catalog/dependency_index.rb', line 18

def initialize(catalog, *args)
  super(*args)

  @catalog = catalog

  @active_gems = Set.new
  @pending_gems = Set.new
end

Instance Method Details

#force_refresh_including(gem_name) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/gel/catalog/dependency_index.rb', line 37

def force_refresh_including(gem_name)
  gems_to_refresh = []

  @monitor.synchronize do
    return if _info(gem_name) || @active_gems.include?(gem_name)

    gems_to_refresh << gem_name
    @pending_gems.delete gem_name

    while gems_to_refresh.size < LIST_MAX && @pending_gems.size > 0
      a_gem = @pending_gems.first
      @pending_gems.delete a_gem
      gems_to_refresh << a_gem
    end

    @active_gems.merge gems_to_refresh
  end

  refresh_some_gems gems_to_refresh
end

#prepare(gems) ⇒ Object



27
28
29
30
31
32
33
34
35
# File 'lib/gel/catalog/dependency_index.rb', line 27

def prepare(gems)
  @monitor.synchronize do
    @pending_gems.merge(gems)
  end
  force_refresh_including(gems.first)
  @monitor.synchronize do
    @refresh_cond.wait_until { gems.all? { |g| _info(g) } }
  end
end

#refresh_gem(gem_name, immediate = false) ⇒ Object



118
119
120
121
122
123
124
# File 'lib/gel/catalog/dependency_index.rb', line 118

def refresh_gem(gem_name, immediate = false)
  @monitor.synchronize do
    @pending_gems << gem_name unless _info(gem_name) || @active_gems.include?(gem_name)
  end

  force_refresh_including gem_name if immediate
end

#refresh_some_gems(gems) ⇒ Object



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
# File 'lib/gel/catalog/dependency_index.rb', line 58

def refresh_some_gems(gems)
  gem_list = gems.map { |g| CGI.escape(g) }.sort.join(",")
  @work_pool.queue(gem_list) do
    response =
      begin
        @catalog.send(:http_get, "api/v1/dependencies?gems=#{gem_list}")
      rescue Exception => ex
        @monitor.synchronize do
          @error = ex
          @refresh_cond.broadcast
        end
        next
      end

    new_info = {}
    gems.each { |g| new_info[g] = {} }

    new_dependencies = Set.new

    hashes = Marshal.load(response.body)
    hashes.each do |hash|
      v = hash[:number].to_s
      v += "-#{hash[:platform]}" unless hash[:platform] == "ruby"

      (new_info[hash[:name]] ||= {})[v] = {
        dependencies: hash[:dependencies].map { |name, versions| [name, versions.split(/,\s*/)] },
        ruby: lambda do
          # The disadvantage of trying to avoid this per-version
          # request is that when we do discover we need it, we need it
          # immediately. :/
          pinboard.file(uri("quick", "Marshal.4.8", "#{hash[:name]}-#{v}.gemspec.rz"), token: false, tail: false) do |f|
            data = Zlib::Inflate.inflate(f.read)
            # TODO: Extract the data we need without a full unmarshal
            Marshal.load(data).required_ruby_version
          end
        end,
      }
    end

    hashes.group_by { |h| h[:name] }.each do |_, group|
      versions = group.group_by { |h| h[:number] }
      latest = versions.keys.max_by { |v| Gel::Support::GemVersion.new(v) }
      new_dependencies.merge versions[latest].flat_map { |h| h[:dependencies].map(&:first) }.uniq
    end

    @monitor.synchronize do
      @gem_info.update new_info
      @active_gems.subtract new_info.keys

      @refresh_cond.broadcast

      new_dependencies.subtract @active_gems
      new_dependencies.subtract @gem_info.keys
      @pending_gems.merge new_dependencies
    end
  end

  @work_pool.start
end