geminabox-jgraichen 0.12.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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