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
|
# File 'lib/gem_stasher.rb', line 23
def maintain_cache(builds)
sources = Set.new
required_gems = Set.new
existing_gems = Set.new
FileUtils.mkdir_p "#{@gempath}/gems"
@logger.info "Updating gem cache"
Dir["#{@gempath}/gems/*.gem"].each do |gempack|
begin
File.open(gempack) do |io|
Gem::Package.open(io, 'r', nil) do |gem|
spec = Bundler::LazySpecification.new(
gem.metadata.name,
gem.metadata.version,
gem.metadata.platform
)
existing_gems.add spec
end
end
rescue => e
@logger.warn "unable to read #{gempack}: #{e}"
File.delete gempack
end
end
builds.each do |build|
begin
gemfile = Bundler::Definition.build File.join(build, "Gemfile"),
File.join(build, "Gemfile.lock"), {}
gemfile.sources.each do |source|
next unless source.kind_of? Bundler::Source::Rubygems
source.remotes.each { |remote| sources.add remote }
end
gemfile.resolve.each do |spec|
required_gems.add Bundler::LazySpecification.new(
spec.name,
spec.version,
spec.platform
)
end
rescue => e
@logger.warn "unable to process #{build}: #{e}"
end
end
dead_gems = existing_gems - required_gems
missing_gems = required_gems - existing_gems
dead_gems.each do |spec|
@logger.info "- deleting dead #{spec.name} #{spec.version}"
filename = filename_for_spec spec
begin
File.delete "#{@gempath}/#{filename}"
rescue => e
@logger.warn "unable to delete #{filename}: #{e}"
end
end
if missing_gems.any?
sources.each do |uri|
fetcher = Bundler::Fetcher.new uri
names = missing_gems.map { |gem| gem.name }
specs = fetcher.specs names, uri
missing_gems.each do |gem|
found = specs.local_search gem
next unless found.any?
missing_gems.delete gem
spec, = found
filename = filename_for_spec spec
local_file_name = "#{@gempath}/#{filename}"
file_uri = uri.dup
file_uri.path = "#{uri.path}#{filename}"
@logger.info " - fetching #{spec.name} #{spec.version} from #{uri}"
io = File.open(local_file_name, "wb")
begin
fetch_file file_uri, io
rescue => e
File.delete io
warn "unable to download #{filename}: #{e}"
ensure
io.close
end
end
end
if missing_gems.any?
@logger.warn "unresolved dependencies:"
missing_gems.each do |spec|
@logger.warn " - #{spec}"
end
end
end
end
|