geminabox-jgraichen 0.12.2.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.
@@ -0,0 +1,67 @@
1
+
2
+ module Geminabox
3
+ module Proxy
4
+ class Splicer < FileHandler
5
+
6
+ def self.make(file_name)
7
+ splicer = new(file_name)
8
+ splicer.create
9
+ splicer
10
+ end
11
+
12
+ def create
13
+ File.open(splice_path, 'w'){|f| f.write(new_content)}
14
+ end
15
+
16
+ def new_content
17
+ if local_file_exists?
18
+ merge_content
19
+ else
20
+ remote_content
21
+ end
22
+ end
23
+
24
+ def splice_path
25
+ proxy_path
26
+ end
27
+
28
+ def splice_folder_path
29
+ proxy_folder_path
30
+ end
31
+
32
+ def splice_file_exists?
33
+ file_exists? splice_path
34
+ end
35
+
36
+ def merge_content
37
+ if gzip?
38
+ merge_gziped_content
39
+ else
40
+ merge_text_content
41
+ end
42
+ end
43
+
44
+ def gzip?
45
+ /\.gz$/ =~ file_name
46
+ end
47
+
48
+ private
49
+ def merge_gziped_content
50
+ package(unpackage(local_content) | unpackage(remote_content))
51
+ end
52
+
53
+ def unpackage(content)
54
+ Marshal.load(Gem.gunzip(content))
55
+ end
56
+
57
+ def package(content)
58
+ Gem.gzip(Marshal.dump(content))
59
+ end
60
+
61
+ def merge_text_content
62
+ local_content.to_s + remote_content.to_s
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,27 @@
1
+ require 'httpclient'
2
+ require 'json'
3
+
4
+ module Geminabox
5
+ module RubygemsDependency
6
+
7
+ class << self
8
+
9
+ def for(*gems)
10
+
11
+ url = [
12
+ rubygems_uri,
13
+ '?gems=',
14
+ gems.map(&:to_s).join(',')
15
+ ].join
16
+ body = HTTPClient.get_content(url)
17
+ JSON.parse(body)
18
+ end
19
+
20
+ def rubygems_uri
21
+ "https://bundler.rubygems.org/api/v1/dependencies.json"
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,285 @@
1
+ module Geminabox
2
+
3
+ class Server < Sinatra::Base
4
+ enable :static, :methodoverride
5
+
6
+ def self.delegate_to_geminabox(*delegate_methods)
7
+ delegate_methods.each{|m| set m, Geminabox.send(m)}
8
+ end
9
+
10
+ delegate_to_geminabox(
11
+ :public_folder,
12
+ :data,
13
+ :build_legacy,
14
+ :incremental_updates,
15
+ :views,
16
+ :allow_replace,
17
+ :gem_permissions,
18
+ :allow_delete,
19
+ :rubygems_proxy
20
+ )
21
+
22
+ if Server.rubygems_proxy
23
+ use Proxy::Hostess
24
+ else
25
+ use Hostess
26
+ end
27
+
28
+ class << self
29
+ def disallow_replace?
30
+ ! allow_replace
31
+ end
32
+
33
+ def allow_delete?
34
+ allow_delete
35
+ end
36
+
37
+ def fixup_bundler_rubygems!
38
+ return if @post_reset_hook_applied
39
+ Gem.post_reset{ Gem::Specification.all = nil } if defined? Bundler and Gem.respond_to? :post_reset
40
+ @post_reset_hook_applied = true
41
+ end
42
+
43
+ def reindex(force_rebuild = false)
44
+ fixup_bundler_rubygems!
45
+ force_rebuild = true unless incremental_updates
46
+ if force_rebuild
47
+ indexer.generate_index
48
+ dependency_cache.flush
49
+ else
50
+ begin
51
+ require 'geminabox/indexer'
52
+ updated_gemspecs = Geminabox::Indexer.updated_gemspecs(indexer)
53
+ Geminabox::Indexer.patch_rubygems_update_index_pre_1_8_25(indexer)
54
+ indexer.update_index
55
+ updated_gemspecs.each { |gem| dependency_cache.flush_key(gem.name) }
56
+ rescue => e
57
+ puts "#{e.class}:#{e.message}"
58
+ puts e.backtrace.join("\n")
59
+ reindex(:force_rebuild)
60
+ end
61
+ end
62
+ end
63
+
64
+ def indexer
65
+ Gem::Indexer.new(data, :build_legacy => build_legacy)
66
+ end
67
+
68
+ def dependency_cache
69
+ @dependency_cache ||= Geminabox::DiskCache.new(File.join(data, "_cache"))
70
+ end
71
+ end
72
+
73
+
74
+
75
+ before do
76
+ headers 'X-Powered-By' => "geminabox #{Geminabox::VERSION}"
77
+ end
78
+
79
+ get '/' do
80
+ @gems = load_gems
81
+ @index_gems = index_gems(@gems)
82
+ erb :index
83
+ end
84
+
85
+ get '/atom.xml' do
86
+ @gems = load_gems
87
+ erb :atom, :layout => false
88
+ end
89
+
90
+ get '/api/v1/dependencies' do
91
+ query_gems.any? ? Marshal.dump(gem_list) : 200
92
+ end
93
+
94
+ get '/api/v1/dependencies.json' do
95
+ query_gems.any? ? gem_list.to_json : {}
96
+ end
97
+
98
+ get '/upload' do
99
+ erb :upload
100
+ end
101
+
102
+ get '/reindex' do
103
+ self.class.reindex(:force_rebuild)
104
+ redirect url("/")
105
+ end
106
+
107
+ get '/gems/:gemname' do
108
+ gems = Hash[load_gems.by_name]
109
+ @gem = gems[params[:gemname]]
110
+ halt 404 unless @gem
111
+ erb :gem
112
+ end
113
+
114
+ delete '/gems/*.gem' do
115
+ unless self.class.allow_delete?
116
+ error_response(403, 'Gem deletion is disabled - see https://github.com/cwninja/geminabox/issues/115')
117
+ end
118
+ File.delete file_path if File.exists? file_path
119
+ self.class.reindex(:force_rebuild)
120
+ redirect url("/")
121
+ end
122
+
123
+ post '/upload' do
124
+ unless params[:file] && params[:file][:filename] && (tmpfile = params[:file][:tempfile])
125
+ @error = "No file selected"
126
+ halt [400, erb(:upload)]
127
+ end
128
+ handle_incoming_gem(Geminabox::IncomingGem.new(tmpfile))
129
+ end
130
+
131
+ post '/api/v1/gems' do
132
+ begin
133
+ handle_incoming_gem(Geminabox::IncomingGem.new(request.body))
134
+ rescue Object => o
135
+ File.open "/tmp/debug.txt", "a" do |io|
136
+ io.puts o, o.backtrace
137
+ end
138
+ end
139
+ end
140
+
141
+ private
142
+
143
+ def handle_incoming_gem(gem)
144
+ begin
145
+ GemStore.create(gem, params[:overwrite])
146
+ rescue GemStoreError => error
147
+ error_response error.code, error.reason
148
+ end
149
+
150
+ if api_request?
151
+ "Gem #{gem.name} received and indexed."
152
+ else
153
+ redirect url("/")
154
+ end
155
+ end
156
+
157
+ def api_request?
158
+ request.accept.first != "text/html"
159
+ end
160
+
161
+ def error_response(code, message)
162
+ halt [code, message] if api_request?
163
+ html = <<HTML
164
+ <html>
165
+ <head><title>Error - #{code}</title></head>
166
+ <body>
167
+ <h1>Error - #{code}</h1>
168
+ <p>#{message}</p>
169
+ </body>
170
+ </html>
171
+ HTML
172
+ halt [code, html]
173
+ end
174
+
175
+ def file_path
176
+ File.expand_path(File.join(settings.data, *request.path_info))
177
+ end
178
+
179
+ def dependency_cache
180
+ self.class.dependency_cache
181
+ end
182
+
183
+ def all_gems
184
+ all_gems_with_duplicates.inject(:|)
185
+ end
186
+
187
+ def all_gems_with_duplicates
188
+ specs_files_paths.map do |specs_file_path|
189
+ if File.exists?(specs_file_path)
190
+ Marshal.load(Gem.gunzip(Gem.read_binary(specs_file_path)))
191
+ else
192
+ []
193
+ end
194
+ end
195
+ end
196
+
197
+ def specs_file_types
198
+ [:specs, :prerelease_specs]
199
+ end
200
+
201
+ def specs_files_paths
202
+ specs_file_types.map do |specs_file_type|
203
+ File.join(settings.data, spec_file_name(specs_file_type))
204
+ end
205
+ end
206
+
207
+ def spec_file_name(specs_file_type)
208
+ [specs_file_type, Gem.marshal_version, 'gz'].join('.')
209
+ end
210
+
211
+ def load_gems
212
+ @loaded_gems ||= Geminabox::GemVersionCollection.new(all_gems)
213
+ end
214
+
215
+ def index_gems(gems)
216
+ Set.new(gems.map{|gem| gem.name[0..0].downcase})
217
+ end
218
+
219
+ def gem_list
220
+ settings.rubygems_proxy ? combined_gem_list : local_gem_list
221
+ end
222
+
223
+ def query_gems
224
+ params[:gems].to_s.split(',')
225
+ end
226
+
227
+ def local_gem_list
228
+ query_gems.map{|query_gem| gem_dependencies(query_gem) }.flatten(1)
229
+ end
230
+
231
+ def remote_gem_list
232
+ RubygemsDependency.for(*query_gems)
233
+ end
234
+
235
+ def combined_gem_list
236
+ GemListMerge.from(local_gem_list, remote_gem_list)
237
+ end
238
+
239
+ helpers do
240
+ def spec_for(gem_name, version, platform = default_platform)
241
+ filename = [gem_name, version]
242
+ filename.push(platform) if platform != default_platform
243
+ spec_file = File.join(settings.data, "quick", "Marshal.#{Gem.marshal_version}", "#{filename.join("-")}.gemspec.rz")
244
+ Marshal.load(Gem.inflate(File.read(spec_file))) if File.exists? spec_file
245
+ end
246
+
247
+ def default_platform
248
+ 'ruby'
249
+ end
250
+
251
+ # Return a list of versions of gem 'gem_name' with the dependencies of each version.
252
+ def gem_dependencies(gem_name)
253
+ dependency_cache.marshal_cache(gem_name) do
254
+ load_gems.
255
+ select { |gem| gem_name == gem.name }.
256
+ map { |gem| [gem, spec_for(gem.name, gem.number, gem.platform)] }.
257
+ reject { |(_, spec)| spec.nil? }.
258
+ map do |(gem, spec)|
259
+ {
260
+ :name => gem.name,
261
+ :number => gem.number.version,
262
+ :platform => gem.platform,
263
+ :dependencies => runtime_dependencies(spec)
264
+ }
265
+ end
266
+ end
267
+ end
268
+
269
+
270
+
271
+ def runtime_dependencies(spec)
272
+ spec.
273
+ dependencies.
274
+ select { |dep| dep.type == :runtime }.
275
+ map { |dep| name_and_requirements_for(dep) }
276
+ end
277
+
278
+ def name_and_requirements_for(dep)
279
+ name = dep.name.kind_of?(Array) ? dep.name.first : dep.name
280
+ [name, dep.requirement.to_s]
281
+ end
282
+ end
283
+ end
284
+
285
+ end
@@ -0,0 +1,3 @@
1
+ module Geminabox
2
+ VERSION = '0.12.2.1' unless defined? VERSION
3
+ end
@@ -0,0 +1,60 @@
1
+ require 'uri'
2
+ require 'httpclient'
3
+
4
+ class GeminaboxClient
5
+ attr_reader :url, :http_client
6
+
7
+ def initialize(url)
8
+ extract_username_and_password_from_url!(url)
9
+ @http_client = HTTPClient.new
10
+ @http_client.set_auth(url_for(:upload), @username, @password) if @username or @password
11
+ @http_client.www_auth.basic_auth.challenge(url_for(:upload)) # Workaround: https://github.com/nahi/httpclient/issues/63
12
+ @http_client.ssl_config.ssl_version = nil # https://github.com/nahi/httpclient/pull/186
13
+ @http_client.send_timeout = 0
14
+ @http_client.receive_timeout = 0
15
+ end
16
+
17
+ def extract_username_and_password_from_url!(url)
18
+ uri = URI.parse(url.to_s)
19
+ @username, @password = uri.user, uri.password
20
+ uri.user = uri.password = nil
21
+ uri.path = uri.path + "/" unless uri.path.end_with?("/")
22
+ @url = uri.to_s
23
+ end
24
+
25
+ def url_for(path)
26
+ url + path.to_s
27
+ end
28
+
29
+ def push(gemfile, options = {})
30
+ response = http_client.post(url_for(:upload), { 'file' => File.open(gemfile, "rb"), 'overwrite' => !!options[:overwrite] }, { 'Accept' => 'text/plain' })
31
+
32
+ if response.status < 300
33
+ response.body
34
+ else
35
+ raise GeminaboxClient::Error, "Error (#{response.code} received)\n\n#{response.body}"
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ class GeminaboxClient::Error < RuntimeError
42
+ end
43
+
44
+ module GeminaboxClient::GemLocator
45
+ def find_gem(dir)
46
+ gemname = File.split(dir).last
47
+ glob_matcher = "{pkg/,}#{gemname}-*.gem"
48
+ latest_gem_for(gemname, Dir.glob(glob_matcher)) or raise Gem::CommandLineError, NO_GEM_PROVIDED_ERROR_MESSAGE
49
+ end
50
+
51
+ def latest_gem_for(gemname, files)
52
+ regexp_matcher = %r{(?:pkg/)#{gemname}-(#{Gem::Version::VERSION_PATTERN})\.gem}
53
+ sorter = lambda{|v| Gem::Version.new(regexp_matcher.match(v)[1]) }
54
+ files.grep(regexp_matcher).max_by(&sorter)
55
+ end
56
+
57
+ extend self
58
+
59
+ NO_GEM_PROVIDED_ERROR_MESSAGE = "Couldn't find a gem in pkg, please specify a gem name on the command line (e.g. gem inabox GEMNAME)"
60
+ end
@@ -0,0 +1,91 @@
1
+ require 'rubygems/command'
2
+
3
+ class Gem::Commands::InaboxCommand < Gem::Command
4
+ def description
5
+ 'Push a gem up to your GemInABox'
6
+ end
7
+
8
+ def arguments
9
+ "GEM built gem to push up"
10
+ end
11
+
12
+ def usage
13
+ "#{program_name} GEM"
14
+ end
15
+
16
+ def initialize
17
+ super 'inabox', description
18
+
19
+ add_option('-c', '--configure', "Configure GemInABox") do |value, options|
20
+ options[:configure] = true
21
+ end
22
+
23
+ add_option('-g', '--host HOST', "Host to upload to.") do |value, options|
24
+ options[:host] = value
25
+ end
26
+
27
+ add_option('-o', '--overwrite', "Overwrite Gem.") do |value, options|
28
+ options[:overwrite] = true
29
+ end
30
+ end
31
+
32
+ def last_minute_requires!
33
+ require 'yaml'
34
+ require File.expand_path("../../../geminabox_client.rb", __FILE__)
35
+ end
36
+
37
+ def execute
38
+ last_minute_requires!
39
+ return configure if options[:configure]
40
+ configure unless geminabox_host
41
+
42
+ if options[:args].size == 0
43
+ say "You didn't specify a gem, looking for one in . and in ./pkg/..."
44
+ gemfiles = [GeminaboxClient::GemLocator.find_gem(Dir.pwd)]
45
+ else
46
+ gemfiles = get_all_gem_names
47
+ end
48
+
49
+ send_gems(gemfiles)
50
+ end
51
+
52
+ def send_gems(gemfiles)
53
+ client = GeminaboxClient.new(geminabox_host)
54
+
55
+ gemfiles.each do |gemfile|
56
+ say "Pushing #{File.basename(gemfile)} to #{client.url}..."
57
+ begin
58
+ say client.push(gemfile, options)
59
+ rescue GeminaboxClient::Error => e
60
+ alert_error e.message
61
+ terminate_interaction(1)
62
+ end
63
+ end
64
+ end
65
+
66
+ def config_path
67
+ File.join(Gem.user_home, '.gem', 'geminabox')
68
+ end
69
+
70
+ def configure
71
+ say "Enter the root url for your personal geminabox instance (e.g. http://gems/)."
72
+ host = ask("Host:")
73
+ self.geminabox_host = host
74
+ end
75
+
76
+ def geminabox_host
77
+ @geminabox_host ||= options[:host] || Gem.configuration.load_file(config_path)[:host]
78
+ end
79
+
80
+ def geminabox_host=(host)
81
+ config = Gem.configuration.load_file(config_path).merge(:host => host)
82
+
83
+ dirname = File.dirname(config_path)
84
+ Dir.mkdir(dirname) unless File.exists?(dirname)
85
+
86
+ File.open(config_path, 'w') do |f|
87
+ f.write config.to_yaml
88
+ end
89
+ end
90
+
91
+ end