gemstash 1.0.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +13 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +139 -0
  6. data/Rakefile +35 -0
  7. data/bin/console +14 -0
  8. data/bin/gemstash +3 -0
  9. data/bin/setup +5 -0
  10. data/docs/config.md +136 -0
  11. data/docs/debug.md +24 -0
  12. data/docs/deploy.md +30 -0
  13. data/docs/mirror.md +30 -0
  14. data/docs/multiple_sources.md +68 -0
  15. data/docs/private_gems.md +140 -0
  16. data/docs/reference.md +308 -0
  17. data/exe/gemstash +3 -0
  18. data/gemstash.gemspec +47 -0
  19. data/gemstash.png +0 -0
  20. data/lib/gemstash.rb +26 -0
  21. data/lib/gemstash/authorization.rb +87 -0
  22. data/lib/gemstash/cache.rb +79 -0
  23. data/lib/gemstash/cli.rb +71 -0
  24. data/lib/gemstash/cli/authorize.rb +69 -0
  25. data/lib/gemstash/cli/base.rb +46 -0
  26. data/lib/gemstash/cli/setup.rb +173 -0
  27. data/lib/gemstash/cli/start.rb +52 -0
  28. data/lib/gemstash/cli/status.rb +21 -0
  29. data/lib/gemstash/cli/stop.rb +21 -0
  30. data/lib/gemstash/config.ru +13 -0
  31. data/lib/gemstash/configuration.rb +41 -0
  32. data/lib/gemstash/db.rb +15 -0
  33. data/lib/gemstash/db/authorization.rb +20 -0
  34. data/lib/gemstash/db/dependency.rb +50 -0
  35. data/lib/gemstash/db/rubygem.rb +14 -0
  36. data/lib/gemstash/db/version.rb +51 -0
  37. data/lib/gemstash/dependencies.rb +93 -0
  38. data/lib/gemstash/env.rb +150 -0
  39. data/lib/gemstash/gem_fetcher.rb +50 -0
  40. data/lib/gemstash/gem_pusher.rb +125 -0
  41. data/lib/gemstash/gem_source.rb +37 -0
  42. data/lib/gemstash/gem_source/dependency_caching.rb +40 -0
  43. data/lib/gemstash/gem_source/private_source.rb +139 -0
  44. data/lib/gemstash/gem_source/rack_middleware.rb +22 -0
  45. data/lib/gemstash/gem_source/upstream_source.rb +183 -0
  46. data/lib/gemstash/gem_unyanker.rb +61 -0
  47. data/lib/gemstash/gem_yanker.rb +61 -0
  48. data/lib/gemstash/http_client.rb +77 -0
  49. data/lib/gemstash/logging.rb +93 -0
  50. data/lib/gemstash/migrations/01_gem_dependencies.rb +41 -0
  51. data/lib/gemstash/migrations/02_authorizations.rb +12 -0
  52. data/lib/gemstash/puma.rb +6 -0
  53. data/lib/gemstash/rack_env_rewriter.rb +66 -0
  54. data/lib/gemstash/specs_builder.rb +93 -0
  55. data/lib/gemstash/storage.rb +207 -0
  56. data/lib/gemstash/upstream.rb +65 -0
  57. data/lib/gemstash/version.rb +4 -0
  58. data/lib/gemstash/web.rb +97 -0
  59. metadata +306 -0
@@ -0,0 +1,207 @@
1
+ require "gemstash"
2
+ require "digest"
3
+ require "pathname"
4
+ require "fileutils"
5
+ require "yaml"
6
+
7
+ module Gemstash
8
+ #:nodoc:
9
+ class Storage
10
+ extend Gemstash::Env::Helper
11
+ VERSION = 1
12
+
13
+ # If the storage engine detects something that was stored with a newer
14
+ # version of the storage engine, this error will be thrown.
15
+ class VersionTooNew < StandardError
16
+ end
17
+
18
+ def initialize(folder, root: true)
19
+ check_engine if root
20
+ @folder = folder
21
+ FileUtils.mkpath(@folder) unless Dir.exist?(@folder)
22
+ end
23
+
24
+ def resource(id)
25
+ Resource.new(@folder, id)
26
+ end
27
+
28
+ def for(child)
29
+ Storage.new(File.join(@folder, child), root: false)
30
+ end
31
+
32
+ def self.for(name)
33
+ new(gemstash_env.base_file(name))
34
+ end
35
+
36
+ def self.metadata
37
+ file = gemstash_env.base_file("metadata.yml")
38
+
39
+ unless File.exist?(file)
40
+ File.write(file, { storage_version: Gemstash::Storage::VERSION,
41
+ gemstash_version: Gemstash::VERSION }.to_yaml)
42
+ end
43
+
44
+ YAML.load_file(file)
45
+ end
46
+
47
+ private
48
+
49
+ def check_engine
50
+ version = Gemstash::Storage.metadata[:storage_version]
51
+ return if version <= Gemstash::Storage::VERSION
52
+ raise Gemstash::Storage::VersionTooNew, "Storage engine is out of date: #{version}"
53
+ end
54
+
55
+ def path_valid?(path)
56
+ return false if path.nil?
57
+ return false unless File.writable?(path)
58
+ true
59
+ end
60
+ end
61
+
62
+ #:nodoc:
63
+ class Resource
64
+ include Gemstash::Logging
65
+ attr_reader :name, :folder
66
+ def initialize(folder, name)
67
+ @base_path = folder
68
+ @name = name
69
+ # Avoid odd characters in paths, in case of issues with the file system
70
+ safe_name = sanitize(@name)
71
+ # Use a trie structure to avoid file system limits causing too many files in 1 folder
72
+ # Downcase to avoid issues with case insensitive file systems
73
+ trie_parents = safe_name[0...3].downcase.split("")
74
+ # The digest is included in case the name differs only by case
75
+ # Some file systems are case insensitive, so such collisions will be a problem
76
+ digest = Digest::MD5.hexdigest(@name)
77
+ child_folder = "#{safe_name}-#{digest}"
78
+ @folder = File.join(@base_path, *trie_parents, child_folder)
79
+ end
80
+
81
+ def exist?(key = nil)
82
+ if key
83
+ File.exist?(properties_filename) && File.exist?(content_filename(key))
84
+ else
85
+ File.exist?(properties_filename) && content?
86
+ end
87
+ end
88
+
89
+ def save(content, properties = nil)
90
+ content.each do |key, value|
91
+ save_content(key, value)
92
+ end
93
+
94
+ update_properties(properties)
95
+ self
96
+ end
97
+
98
+ def content(key)
99
+ @content[key]
100
+ end
101
+
102
+ def properties
103
+ @properties || {}
104
+ end
105
+
106
+ def update_properties(props)
107
+ load_properties
108
+ save_properties(properties.merge(props || {}))
109
+ self
110
+ end
111
+
112
+ def load(key)
113
+ raise "Resource #{@name} has no content to load" unless exist?(key)
114
+ load_properties
115
+ @content ||= {}
116
+ @content[key] = read_file(content_filename(key))
117
+ self
118
+ end
119
+
120
+ def delete(key)
121
+ return self unless exist?(key)
122
+
123
+ begin
124
+ File.delete(content_filename(key))
125
+ rescue => e
126
+ log_error "Failed to delete stored content at #{content_filename(key)}", e, level: :warn
127
+ end
128
+
129
+ begin
130
+ File.delete(properties_filename) unless content?
131
+ rescue => e
132
+ log_error "Failed to delete stored properties at #{properties_filename}", e, level: :warn
133
+ end
134
+
135
+ return self
136
+ ensure
137
+ reset
138
+ end
139
+
140
+ private
141
+
142
+ def load_properties
143
+ return unless File.exist?(properties_filename)
144
+ @properties = YAML.load_file(properties_filename)
145
+ check_version
146
+ end
147
+
148
+ def check_version
149
+ version = @properties[:gemstash_storage_version]
150
+ return if version <= Gemstash::Storage::VERSION
151
+ reset
152
+ raise Gemstash::Storage::VersionTooNew, "Resource was stored with a newer storage: #{version}"
153
+ end
154
+
155
+ def reset
156
+ @content = nil
157
+ @properties = nil
158
+ end
159
+
160
+ def content?
161
+ return false unless Dir.exist?(@folder)
162
+ entries = Dir.entries(@folder).reject {|file| file =~ /\A\.\.?\z/ }
163
+ !entries.empty? && entries != %w(properties.yaml)
164
+ end
165
+
166
+ def sanitize(name)
167
+ name.gsub(/[^a-zA-Z0-9_]/, "_")
168
+ end
169
+
170
+ def save_content(key, content)
171
+ store(content_filename(key), content)
172
+ @content ||= {}
173
+ @content[key] = content
174
+ end
175
+
176
+ def save_properties(props)
177
+ props ||= {}
178
+ props = { gemstash_storage_version: Gemstash::Storage::VERSION }.merge(props)
179
+ store(properties_filename, props.to_yaml)
180
+ @properties = props
181
+ end
182
+
183
+ def store(filename, content)
184
+ FileUtils.mkpath(@folder) unless Dir.exist?(@folder)
185
+ save_file(filename) { content }
186
+ end
187
+
188
+ def save_file(filename)
189
+ content = yield
190
+ File.open(filename, "wb") {|f| f.write(content) }
191
+ end
192
+
193
+ def read_file(filename)
194
+ File.open(filename, "rb", &:read)
195
+ end
196
+
197
+ def content_filename(key)
198
+ name = sanitize(key.to_s)
199
+ raise "Invalid content key #{key.inspect}" if name.empty?
200
+ File.join(@folder, name)
201
+ end
202
+
203
+ def properties_filename
204
+ File.join(@folder, "properties.yaml")
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,65 @@
1
+ require "digest"
2
+
3
+ module Gemstash
4
+ #:nodoc:
5
+ class Upstream
6
+ extend Forwardable
7
+
8
+ attr_reader :user_agent
9
+
10
+ def_delegators :@uri, :scheme, :host, :user, :password, :to_s
11
+
12
+ def initialize(upstream, user_agent: nil)
13
+ @uri = URI(URI.decode(upstream.to_s))
14
+ @user_agent = user_agent
15
+ raise "URL '#{@uri}' is not valid!" unless @uri.to_s =~ URI.regexp
16
+ end
17
+
18
+ def url(path = nil, params = nil)
19
+ base = to_s
20
+
21
+ unless path.to_s.empty?
22
+ base = "#{base}/" unless base.end_with?("/")
23
+ path = path[1..-1] if path.to_s.start_with?("/")
24
+ end
25
+
26
+ params = "?#{params}" if !params.nil? && !params.empty?
27
+ "#{base}#{path}#{params}"
28
+ end
29
+
30
+ def auth?
31
+ !user.to_s.empty? && !password.to_s.empty?
32
+ end
33
+
34
+ # Utilized as the parent directory for cached gems
35
+ def host_id
36
+ @host_id ||= "#{host}_#{hash}"
37
+ end
38
+
39
+ private
40
+
41
+ def hash
42
+ Digest::MD5.hexdigest(to_s)
43
+ end
44
+
45
+ #:nodoc:
46
+ class GemName
47
+ def initialize(upstream, gem_name)
48
+ @upstream = upstream
49
+ @id = gem_name
50
+ end
51
+
52
+ def to_s
53
+ name
54
+ end
55
+
56
+ def id
57
+ @id
58
+ end
59
+
60
+ def name
61
+ @name ||= @id.gsub(/\.gem(spec\.rz)?$/i, "")
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,4 @@
1
+ #:nodoc:
2
+ module Gemstash
3
+ VERSION = "1.0.0.pre.1"
4
+ end
@@ -0,0 +1,97 @@
1
+ require "sinatra/base"
2
+ require "json"
3
+ require "gemstash"
4
+
5
+ module Gemstash
6
+ #:nodoc:
7
+ class Web < Sinatra::Base
8
+ def initialize(gemstash_env: nil, http_client_builder: nil)
9
+ @gemstash_env = gemstash_env || Gemstash::Env.new
10
+ @http_client_builder = http_client_builder || Gemstash::HTTPClient
11
+ Gemstash::Env.current = @gemstash_env
12
+ super()
13
+ end
14
+
15
+ before do
16
+ Gemstash::Env.current = @gemstash_env
17
+ @gem_source = env["gemstash.gem_source"].new(self)
18
+ end
19
+
20
+ def http_client_for(server_url)
21
+ @http_client_builder.for(server_url)
22
+ end
23
+
24
+ not_found do
25
+ status 404
26
+ body JSON.dump("error" => "Not found", "code" => 404)
27
+ end
28
+
29
+ get "/" do
30
+ @gem_source.serve_root
31
+ end
32
+
33
+ get "/api/v1/dependencies" do
34
+ @gem_source.serve_dependencies
35
+ end
36
+
37
+ get "/api/v1/dependencies.json" do
38
+ @gem_source.serve_dependencies_json
39
+ end
40
+
41
+ post "/api/v1/gems" do
42
+ @gem_source.serve_add_gem
43
+ end
44
+
45
+ delete "/api/v1/gems/yank" do
46
+ @gem_source.serve_yank
47
+ end
48
+
49
+ put "/api/v1/gems/unyank" do
50
+ @gem_source.serve_unyank
51
+ end
52
+
53
+ post "/api/v1/add_spec.json" do
54
+ @gem_source.serve_add_spec_json
55
+ end
56
+
57
+ post "/api/v1/remove_spec.json" do
58
+ @gem_source.serve_remove_spec_json
59
+ end
60
+
61
+ get "/names" do
62
+ @gem_source.serve_names
63
+ end
64
+
65
+ get "/versions" do
66
+ @gem_source.serve_versions
67
+ end
68
+
69
+ get "/info/:name" do
70
+ @gem_source.serve_info(params[:name])
71
+ end
72
+
73
+ get "/quick/Marshal.4.8/:id" do
74
+ @gem_source.serve_marshal(params[:id])
75
+ end
76
+
77
+ get "/fetch/actual/gem/:id" do
78
+ @gem_source.serve_actual_gem(params[:id])
79
+ end
80
+
81
+ get "/gems/:id" do
82
+ @gem_source.serve_gem(params[:id])
83
+ end
84
+
85
+ get "/latest_specs.4.8.gz" do
86
+ @gem_source.serve_latest_specs
87
+ end
88
+
89
+ get "/specs.4.8.gz" do
90
+ @gem_source.serve_specs
91
+ end
92
+
93
+ get "/prerelease_specs.4.8.gz" do
94
+ @gem_source.serve_prerelease_specs
95
+ end
96
+ end
97
+ end
metadata ADDED
@@ -0,0 +1,306 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gemstash
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre.1
5
+ platform: ruby
6
+ authors:
7
+ - Andre Arko
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dalli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: lru_redux
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: puma
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.14'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.14'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sequel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.26'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.26'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sinatra
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: thor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.19'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.19'
97
+ - !ruby/object:Gem::Dependency
98
+ name: faraday
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.9'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.9'
111
+ - !ruby/object:Gem::Dependency
112
+ name: faraday_middleware
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.10'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.10'
125
+ - !ruby/object:Gem::Dependency
126
+ name: sqlite3
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.3'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.3'
139
+ - !ruby/object:Gem::Dependency
140
+ name: bundler
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.10'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.10'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rack-test
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.6'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.6'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rake
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '10.0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '10.0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rspec
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '3.3'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '3.3'
195
+ - !ruby/object:Gem::Dependency
196
+ name: rubocop
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '0.34'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '0.34'
209
+ description: Gemstash acts as a local RubyGems server, caching copies of gems from
210
+ RubyGems.org automatically, and eventually letting you push your own private gems
211
+ as well.
212
+ email:
213
+ - andre@arko.net
214
+ executables:
215
+ - gemstash
216
+ extensions: []
217
+ extra_rdoc_files: []
218
+ files:
219
+ - ".gitignore"
220
+ - ".rspec"
221
+ - ".rubocop-bundler.yml"
222
+ - ".rubocop-relax.yml"
223
+ - ".rubocop.yml"
224
+ - ".travis.yml"
225
+ - CODE_OF_CONDUCT.md
226
+ - Gemfile
227
+ - LICENSE.txt
228
+ - README.md
229
+ - Rakefile
230
+ - bin/console
231
+ - bin/gemstash
232
+ - bin/setup
233
+ - docs/config.md
234
+ - docs/debug.md
235
+ - docs/deploy.md
236
+ - docs/mirror.md
237
+ - docs/multiple_sources.md
238
+ - docs/private_gems.md
239
+ - docs/reference.md
240
+ - exe/gemstash
241
+ - gemstash.gemspec
242
+ - gemstash.png
243
+ - lib/gemstash.rb
244
+ - lib/gemstash/authorization.rb
245
+ - lib/gemstash/cache.rb
246
+ - lib/gemstash/cli.rb
247
+ - lib/gemstash/cli/authorize.rb
248
+ - lib/gemstash/cli/base.rb
249
+ - lib/gemstash/cli/setup.rb
250
+ - lib/gemstash/cli/start.rb
251
+ - lib/gemstash/cli/status.rb
252
+ - lib/gemstash/cli/stop.rb
253
+ - lib/gemstash/config.ru
254
+ - lib/gemstash/configuration.rb
255
+ - lib/gemstash/db.rb
256
+ - lib/gemstash/db/authorization.rb
257
+ - lib/gemstash/db/dependency.rb
258
+ - lib/gemstash/db/rubygem.rb
259
+ - lib/gemstash/db/version.rb
260
+ - lib/gemstash/dependencies.rb
261
+ - lib/gemstash/env.rb
262
+ - lib/gemstash/gem_fetcher.rb
263
+ - lib/gemstash/gem_pusher.rb
264
+ - lib/gemstash/gem_source.rb
265
+ - lib/gemstash/gem_source/dependency_caching.rb
266
+ - lib/gemstash/gem_source/private_source.rb
267
+ - lib/gemstash/gem_source/rack_middleware.rb
268
+ - lib/gemstash/gem_source/upstream_source.rb
269
+ - lib/gemstash/gem_unyanker.rb
270
+ - lib/gemstash/gem_yanker.rb
271
+ - lib/gemstash/http_client.rb
272
+ - lib/gemstash/logging.rb
273
+ - lib/gemstash/migrations/01_gem_dependencies.rb
274
+ - lib/gemstash/migrations/02_authorizations.rb
275
+ - lib/gemstash/puma.rb
276
+ - lib/gemstash/rack_env_rewriter.rb
277
+ - lib/gemstash/specs_builder.rb
278
+ - lib/gemstash/storage.rb
279
+ - lib/gemstash/upstream.rb
280
+ - lib/gemstash/version.rb
281
+ - lib/gemstash/web.rb
282
+ homepage: https://github.com/bundler/gemstash
283
+ licenses:
284
+ - MIT
285
+ metadata: {}
286
+ post_install_message:
287
+ rdoc_options: []
288
+ require_paths:
289
+ - lib
290
+ required_ruby_version: !ruby/object:Gem::Requirement
291
+ requirements:
292
+ - - ">="
293
+ - !ruby/object:Gem::Version
294
+ version: '0'
295
+ required_rubygems_version: !ruby/object:Gem::Requirement
296
+ requirements:
297
+ - - ">"
298
+ - !ruby/object:Gem::Version
299
+ version: 1.3.1
300
+ requirements: []
301
+ rubyforge_project:
302
+ rubygems_version: 2.4.8
303
+ signing_key:
304
+ specification_version: 4
305
+ summary: A place to stash gems you'll need
306
+ test_files: []