geminabox 1.0.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 8afe3098cb80942ee57d596be27995cc09985c532a4f11e91652aad2794398a7
4
- data.tar.gz: d40b32a8f9975304805a35369ab3a55f80e7ad820b5c9a897d6870dd94a1b24a
2
+ SHA1:
3
+ metadata.gz: 58341b99ae23a2be5f634b571d4f2d95f7c3824b
4
+ data.tar.gz: d5dab4aa7155ca48994f6bac27902072f3fead85
5
5
  SHA512:
6
- metadata.gz: b2945ea3c84217cab2f84426d345a2171d48900ddcdec2df4632c197395c93936f51fee0540743cf2980d2b9e17818525eeeb73b3ff5202fee2a3392d9f44522
7
- data.tar.gz: 7636277b6475b3ddcd51e99dfe25a02ce426fdf12dd62940b9ada6639eecc1a9569e205116502faf41c0624c57b137dd92f0ad1c38a27e6f50e372ea949394aa
6
+ metadata.gz: 52a5d0c2190743b85fe4f588e80a0283725ca2e00f11216747cfc2f8e200eb0621789223e859804480ffe6e03b7f282e2fcfe3768d217e33fbd200ed5cb595b8
7
+ data.tar.gz: bf43c59a32f80f9ba739ed632a2529acf71f052f5842f4ce0fdc44210d6671a1fbb722c3a3bd1f98ec60c059c2a9c0238dbe1e4fe5d284c91fc8fbce6d7d85f1
data/README.md CHANGED
@@ -92,6 +92,24 @@ local systems SSL certificates.
92
92
 
93
93
  TemplateFaradayAdapter is provided as an example of an alternative HTTPAdapter.
94
94
 
95
+ ## Hooks
96
+
97
+ You can add a hook (anything callable) which will be called when a gem is
98
+ successfully received.
99
+
100
+ ```ruby
101
+ Geminabox.on_gem_received = Proc.new do |gem|
102
+ puts "Gem received: #{gem.spec.name} #{gem.spec.version}"
103
+ end
104
+ ```
105
+
106
+ Typically you might use this to push a notification to your team chat. Any
107
+ exceptions which occur within the hook is silently ignored, so please ensure they
108
+ are handled properly if this is not desirable.
109
+
110
+ Also, please note that this hook blocks `POST /upload` and `POST /api/v1/gems` APIs processing.
111
+ Hook authors are responsible to perform any action non-blocking/async to avoid HTTP timeout.
112
+
95
113
  ## Client Usage
96
114
 
97
115
  Since version 0.10, Geminabox supports the standard gemcutter push API:
@@ -104,6 +122,10 @@ You can also use the gem plugin:
104
122
 
105
123
  gem inabox pkg/my-awesome-gem-1.0.gem
106
124
 
125
+ And since version 1.2.0, Geminabox supports the standard gemcutter yank API:
126
+
127
+ gem yank my-awesome-gem -v 1.0 --host HOST
128
+
107
129
  Configure Gem in a box (interactive prompt to specify where to upload to):
108
130
 
109
131
  gem inabox -c
data/lib/geminabox.rb CHANGED
@@ -46,6 +46,7 @@ module Geminabox
46
46
  :gem_permissions,
47
47
  :allow_delete,
48
48
  :rubygems_proxy,
49
+ :rubygems_proxy_merge_strategy,
49
50
  :http_adapter,
50
51
  :lockfile,
51
52
  :retry_interval,
@@ -53,6 +54,7 @@ module Geminabox
53
54
  :ruby_gems_url,
54
55
  :bundler_ruby_gems_url,
55
56
  :allow_upload,
57
+ :on_gem_received
56
58
  )
57
59
 
58
60
  def set_defaults(defaults)
@@ -72,22 +74,24 @@ module Geminabox
72
74
  end
73
75
 
74
76
  set_defaults(
75
- data: File.join(File.dirname(__FILE__), *%w[.. data]),
76
- public_folder: File.join(File.dirname(__FILE__), *%w[.. public]),
77
- build_legacy: false,
78
- incremental_updates: true,
79
- views: File.join(File.dirname(__FILE__), *%w[.. views]),
80
- allow_replace: false,
81
- gem_permissions: 0644,
82
- rubygems_proxy: (ENV['RUBYGEMS_PROXY'] == 'true'),
83
- allow_delete: true,
84
- http_adapter: HttpClientAdapter.new,
85
- lockfile: '/tmp/geminabox.lockfile',
86
- retry_interval: 60,
87
- allow_remote_failure: false,
88
- ruby_gems_url: 'https://rubygems.org/',
89
- bundler_ruby_gems_url: 'https://bundler.rubygems.org/',
90
- allow_upload: true,
77
+ data: File.join(File.dirname(__FILE__), *%w[.. data]),
78
+ public_folder: File.join(File.dirname(__FILE__), *%w[.. public]),
79
+ build_legacy: false,
80
+ incremental_updates: true,
81
+ views: File.join(File.dirname(__FILE__), *%w[.. views]),
82
+ allow_replace: false,
83
+ gem_permissions: 0644,
84
+ rubygems_proxy: (ENV['RUBYGEMS_PROXY'] == 'true'),
85
+ rubygems_proxy_merge_strategy: ENV.fetch('RUBYGEMS_PROXY_MERGE_STRATEGY') { :local_gems_take_precedence_over_remote_gems }.to_sym,
86
+ allow_delete: true,
87
+ http_adapter: HttpClientAdapter.new,
88
+ lockfile: '/tmp/geminabox.lockfile',
89
+ retry_interval: 60,
90
+ allow_remote_failure: false,
91
+ ruby_gems_url: 'https://rubygems.org/',
92
+ bundler_ruby_gems_url: 'https://bundler.rubygems.org/',
93
+ allow_upload: true,
94
+ on_gem_received: nil
91
95
  )
92
96
 
93
97
  end
@@ -1,23 +1,38 @@
1
- module Geminabox
2
- class GemListMerge
3
- attr_accessor :list
4
-
5
- IGNORE_DEPENDENCIES = 0..-2
1
+ require "set"
6
2
 
7
- def self.from(*lists)
8
- lists.map{|list| new(list)}.inject(:merge)
3
+ module Geminabox
4
+ module GemListMerge
5
+ def self.merge(local_gem_list, remote_gem_list, strategy:)
6
+ strategy_for(strategy).merge(local_gem_list, remote_gem_list)
9
7
  end
10
8
 
11
- def initialize(list)
12
- @list = list
9
+ def self.strategy_for(strategy)
10
+ case strategy
11
+ when :local_gems_take_precedence_over_remote_gems
12
+ LocalGemsTakePrecedenceOverRemoteGems
13
+ when :combine_local_and_remote_gem_versions
14
+ CombineLocalAndRemoteGemVersions
15
+ else
16
+ raise ArgumentError, "Merge strategy must be :local_gems_take_precedence_over_remote_gems (default) or :merge_local_and_remote_gem_versions"
17
+ end
13
18
  end
14
19
 
15
- def merge(other)
16
- merged = (list + other.list)
17
- merged.uniq! {|val| val.values[IGNORE_DEPENDENCIES] }
18
- merged.sort_by! {|x| x.values[IGNORE_DEPENDENCIES] }
19
- merged
20
+ module LocalGemsTakePrecedenceOverRemoteGems
21
+ def self.merge(local_gem_list, remote_gem_list)
22
+ names = Set.new(local_gem_list.map { |gem| gem[:name] })
23
+ local_gem_list + remote_gem_list.reject { |gem| names.include? gem[:name] }
24
+ end
20
25
  end
21
26
 
27
+ module CombineLocalAndRemoteGemVersions
28
+ IGNORE_DEPENDENCIES = 0..-2
29
+
30
+ def self.merge(local_gem_list, remote_gem_list)
31
+ merged = local_gem_list + remote_gem_list
32
+ merged.uniq! {|val| val.values[IGNORE_DEPENDENCIES] }
33
+ merged.sort_by! {|x| x.values[IGNORE_DEPENDENCIES] }
34
+ merged
35
+ end
36
+ end
22
37
  end
23
38
  end
@@ -1,5 +1,6 @@
1
1
  require 'tempfile'
2
2
  require 'fileutils'
3
+ require 'rubygems/util'
3
4
 
4
5
  module Geminabox
5
6
  module Proxy
@@ -65,11 +66,11 @@ module Geminabox
65
66
  end
66
67
 
67
68
  def unpackage(content)
68
- Marshal.load(Gem.gunzip(content))
69
+ Marshal.load(Gem::Util.gunzip(content))
69
70
  end
70
71
 
71
72
  def package(content)
72
- Gem.gzip(Marshal.dump(content))
73
+ Gem::Util.gzip(Marshal.dump(content))
73
74
  end
74
75
 
75
76
  def merge_text_content
@@ -1,4 +1,5 @@
1
1
  require 'reentrant_flock'
2
+ require 'rubygems/util'
2
3
 
3
4
  module Geminabox
4
5
 
@@ -119,7 +120,7 @@ module Geminabox
119
120
  serialize_update do
120
121
  params[:force_rebuild] ||= 'true'
121
122
  unless %w(true false).include? params[:force_rebuild]
122
- error_response(400, "force_rebuild parameter must be either of true or false, but was #{params[:force_rebuild]}")
123
+ error_response(400, "force_rebuild parameter must be either of true or false")
123
124
  end
124
125
  force_rebuild = params[:force_rebuild] == 'true'
125
126
  self.class.reindex(force_rebuild)
@@ -130,6 +131,7 @@ module Geminabox
130
131
  get '/gems/:gemname' do
131
132
  gems = Hash[load_gems.by_name]
132
133
  @gem = gems[params[:gemname]]
134
+ @allow_delete = self.class.allow_delete?
133
135
  halt 404 unless @gem
134
136
  erb :gem
135
137
  end
@@ -147,6 +149,27 @@ module Geminabox
147
149
 
148
150
  end
149
151
 
152
+ delete '/api/v1/gems/yank' do
153
+ unless self.class.allow_delete?
154
+ error_response(403, 'Gem deletion is disabled')
155
+ end
156
+
157
+ halt 400 unless request.form_data?
158
+
159
+ serialize_update do
160
+ gems = load_gems.select { |gem| request['gem_name'] == gem.name and
161
+ request['version'] == gem.number.version }
162
+ halt 404, 'Gem not found' if gems.size == 0
163
+ gems.each do |gem|
164
+ gem_path = File.expand_path(File.join(Geminabox.data, 'gems',
165
+ "#{gem.gemfile_name}.gem"))
166
+ File.delete gem_path if File.exists? gem_path
167
+ end
168
+ self.class.reindex(:force_rebuild)
169
+ return 200, 'Yanked gem and reindexed'
170
+ end
171
+ end
172
+
150
173
  post '/upload' do
151
174
  unless self.class.allow_upload?
152
175
  error_response(403, 'Gem uploading is disabled')
@@ -197,6 +220,12 @@ module Geminabox
197
220
  error_response error.code, error.reason
198
221
  end
199
222
 
223
+ begin
224
+ Geminabox.on_gem_received.call(gem) if Geminabox.on_gem_received
225
+ rescue
226
+ # ignore errors which occur within the hook
227
+ end
228
+
200
229
  if api_request?
201
230
  "Gem #{gem.name} received and indexed."
202
231
  else
@@ -237,7 +266,7 @@ HTML
237
266
  def all_gems_with_duplicates
238
267
  specs_files_paths.map do |specs_file_path|
239
268
  if File.exist?(specs_file_path)
240
- Marshal.load(Gem.gunzip(Gem.read_binary(specs_file_path)))
269
+ Marshal.load(Gem::Util.gunzip(Gem.read_binary(specs_file_path)))
241
270
  else
242
271
  []
243
272
  end
@@ -283,7 +312,7 @@ HTML
283
312
  end
284
313
 
285
314
  def combined_gem_list
286
- GemListMerge.from(local_gem_list, remote_gem_list)
315
+ GemListMerge.merge(local_gem_list, remote_gem_list, strategy: Geminabox.rubygems_proxy_merge_strategy)
287
316
  end
288
317
 
289
318
  helpers do
@@ -305,7 +334,7 @@ HTML
305
334
  spec_file = File.join(Geminabox.data, "quick", "Marshal.#{Gem.marshal_version}", "#{filename.join("-")}.gemspec.rz")
306
335
  File::open(spec_file, 'r') do |unzipped_spec_file|
307
336
  unzipped_spec_file.binmode
308
- Marshal.load(Gem.inflate(unzipped_spec_file.read))
337
+ Marshal.load(Gem::Util.inflate(unzipped_spec_file.read))
309
338
  end if File.exist? spec_file
310
339
  end
311
340
 
@@ -1,3 +1,3 @@
1
1
  module Geminabox
2
- VERSION = '1.0.0' unless defined? VERSION
2
+ VERSION = '1.3.0' unless defined? VERSION
3
3
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geminabox
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Lea
8
8
  - Jack Foy
9
9
  - Rob Nichols
10
10
  - Naotoshi Seo
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-02-08 00:00:00.000000000 Z
14
+ date: 2021-03-18 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: sinatra
@@ -149,7 +149,7 @@ licenses:
149
149
  - MIT-LICENSE
150
150
  metadata:
151
151
  source_code_uri: https://github.com/geminabox/geminabox
152
- post_install_message:
152
+ post_install_message:
153
153
  rdoc_options:
154
154
  - "--main"
155
155
  - README.md
@@ -166,9 +166,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
166
  - !ruby/object:Gem::Version
167
167
  version: '0'
168
168
  requirements: []
169
- rubyforge_project:
170
- rubygems_version: 2.7.4
171
- signing_key:
169
+ rubyforge_project:
170
+ rubygems_version: 2.6.14
171
+ signing_key:
172
172
  specification_version: 4
173
173
  summary: Really simple rubygem hosting
174
174
  test_files: []