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,40 @@
1
+ module Geminabox
2
+
3
+ class GemVersion
4
+ attr_accessor :name, :number, :platform
5
+
6
+ def initialize(name, number, platform)
7
+ @name = name
8
+ @number = number
9
+ @platform = platform
10
+ end
11
+
12
+ def ruby?
13
+ !!(platform =~ /ruby/i)
14
+ end
15
+
16
+ def version
17
+ Gem::Version.create(number)
18
+ end
19
+
20
+ def <=>(other)
21
+ sort = other.name <=> name
22
+ sort = version <=> other.version if sort.zero?
23
+ sort = (other.ruby? && !ruby?) ? 1 : -1 if sort.zero? && ruby? != other.ruby?
24
+ sort = other.platform <=> platform if sort.zero?
25
+
26
+ sort
27
+ end
28
+
29
+ def ==(other)
30
+ return false unless other.class == self.class
31
+ [name, number, platform] == [other.name, other.number, other.platform]
32
+ end
33
+
34
+ def gemfile_name
35
+ included_platform = ruby? ? nil : platform
36
+ [name, number, included_platform].compact.join('-')
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,65 @@
1
+ module Geminabox
2
+
3
+ # This class represents a sorted collection of Geminabox::GemVersion objects.
4
+ # It it used widely throughout the system for displaying and filtering gems.
5
+ class GemVersionCollection
6
+ include Enumerable
7
+
8
+ # Array of Geminabox::GemVersion objects, or an array of [name, version,
9
+ # platform] triples.
10
+ def initialize(initial_gems=[])
11
+ @gems = initial_gems.map{|object|
12
+ coerce_to_gem_version(object)
13
+ }.sort
14
+ end
15
+
16
+ # FIXME: Terminology makes no sense when the version are not all of the same
17
+ # name
18
+ def oldest
19
+ @gems.first
20
+ end
21
+
22
+ # FIXME: Terminology makes no sense when the version are not all of the same
23
+ # name
24
+ def newest
25
+ @gems.last
26
+ end
27
+
28
+ def size
29
+ @gems.size
30
+ end
31
+
32
+ def each(&block)
33
+ @gems.each(&block)
34
+ end
35
+
36
+ # The collection can contain gems of different names, this method groups them
37
+ # by name, and then sorts the different version of each name by version and
38
+ # platform.
39
+ #
40
+ # yields 'foo_gem', version_collection
41
+ def by_name(&block)
42
+ @grouped ||= @gems.group_by(&:name).map{|name, collection|
43
+ [name, Geminabox::GemVersionCollection.new(collection)]
44
+ }.sort_by{|name, collection|
45
+ name.downcase
46
+ }
47
+
48
+ if block_given?
49
+ @grouped.each(&block)
50
+ else
51
+ @grouped
52
+ end
53
+ end
54
+
55
+ private
56
+ def coerce_to_gem_version(object)
57
+ if object.is_a?(Geminabox::GemVersion)
58
+ object
59
+ else
60
+ Geminabox::GemVersion.new(*object)
61
+ end
62
+ end
63
+ end
64
+
65
+ end
@@ -0,0 +1,46 @@
1
+ require 'sinatra/base'
2
+
3
+ module Geminabox
4
+
5
+ class Hostess < Sinatra::Base
6
+ def serve
7
+ send_file(File.expand_path(File.join(Server.data, *request.path_info)), :type => response['Content-Type'])
8
+ end
9
+
10
+ %w[/specs.4.8.gz
11
+ /latest_specs.4.8.gz
12
+ /prerelease_specs.4.8.gz
13
+ ].each do |index|
14
+ get index do
15
+ content_type 'application/x-gzip'
16
+ serve
17
+ end
18
+ end
19
+
20
+ %w[/quick/Marshal.4.8/*.gemspec.rz
21
+ /yaml.Z
22
+ /Marshal.4.8.Z
23
+ ].each do |deflated_index|
24
+ get deflated_index do
25
+ content_type('application/x-deflate')
26
+ serve
27
+ end
28
+ end
29
+
30
+ %w[/yaml
31
+ /Marshal.4.8
32
+ /specs.4.8
33
+ /latest_specs.4.8
34
+ /prerelease_specs.4.8
35
+ ].each do |old_index|
36
+ get old_index do
37
+ serve
38
+ end
39
+ end
40
+
41
+ get "/gems/*.gem" do
42
+ serve
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,70 @@
1
+ module Geminabox
2
+
3
+ class IncomingGem
4
+ def initialize(gem_data, root_path = Geminabox.settings.data)
5
+ unless gem_data.respond_to? :read
6
+ raise ArgumentError, "Expected an instance of IO"
7
+ end
8
+
9
+ digest = Digest::SHA1.new
10
+ if RbConfig::CONFIG["MAJOR"].to_i <= 1 and RbConfig::CONFIG["MINOR"].to_i <= 8
11
+ @tempfile = Tempfile.new("gem")
12
+ else
13
+ @tempfile = Tempfile.new("gem", :encoding => 'binary')
14
+ end
15
+
16
+ while data = gem_data.read(1024**2)
17
+ @tempfile.write data
18
+ digest << data
19
+ end
20
+
21
+ @tempfile.close
22
+ @sha1 = digest.hexdigest
23
+
24
+ @root_path = root_path
25
+ end
26
+
27
+ def gem_data
28
+ File.open(@tempfile.path, "rb")
29
+ end
30
+
31
+ def valid?
32
+ spec && spec.name && spec.version
33
+ rescue Gem::Package::Error
34
+ false
35
+ end
36
+
37
+ def spec
38
+ @spec ||= extract_spec
39
+ end
40
+
41
+ def extract_spec
42
+ if Gem::Package.respond_to? :open
43
+ Gem::Package.open(gem_data, "r", nil) do |pkg|
44
+ return pkg.metadata
45
+ end
46
+ else
47
+ Gem::Package.new(@tempfile.path).spec
48
+ end
49
+ end
50
+
51
+ def name
52
+ @name ||= get_name
53
+ end
54
+
55
+ def get_name
56
+ filename = %W[#{spec.name} #{spec.version}]
57
+ filename.push(spec.platform) if spec.platform && spec.platform != "ruby"
58
+ filename.join("-") + ".gem"
59
+ end
60
+
61
+ def dest_filename
62
+ File.join(@root_path, "gems", name)
63
+ end
64
+
65
+ def hexdigest
66
+ @sha1
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,46 @@
1
+
2
+ # This module addresses Geminabox issue
3
+ # https://github.com/cwninja/geminabox/issues/70
4
+ #
5
+ # The underlying problem is rubygems issue
6
+ # https://github.com/rubygems/rubygems/issues/232, fixed by
7
+ # https://github.com/rubygems/rubygems/pull/364
8
+ #
9
+ # This library (and its call) should be deleted once that pull request is resolved.
10
+
11
+ require 'geminabox'
12
+ require 'rubygems/indexer'
13
+
14
+ module Geminabox::Indexer
15
+ def self.germane?
16
+ gem_version = Gem::Version.new(Gem::VERSION)
17
+ v1_8 = Gem::Version.new('1.8')
18
+ v1_8_25 = Gem::Version.new('1.8.25')
19
+
20
+ (gem_version >= v1_8) && (gem_version < v1_8_25)
21
+ end
22
+
23
+ def self.updated_gemspecs(indexer)
24
+ specs_mtime = File.stat(indexer.dest_specs_index).mtime
25
+ newest_mtime = Time.at 0
26
+
27
+ updated_gems = indexer.gem_file_list.select do |gem|
28
+ gem_mtime = File.stat(gem).mtime
29
+ newest_mtime = gem_mtime if gem_mtime > newest_mtime
30
+ gem_mtime >= specs_mtime
31
+ end
32
+
33
+ indexer.map_gems_to_specs updated_gems
34
+ end
35
+
36
+ def self.patch_rubygems_update_index_pre_1_8_25(indexer)
37
+ if germane?
38
+ specs = updated_gemspecs(indexer)
39
+
40
+ unless specs.empty?
41
+ Gem::Specification.dirs = []
42
+ Gem::Specification.add_specs(*specs)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Geminabox
3
+ module Proxy
4
+ def self.proxy_path(file)
5
+ File.join File.dirname(__FILE__), 'proxy', file
6
+ end
7
+
8
+ autoload :Hostess, proxy_path('hostess')
9
+ autoload :FileHandler, proxy_path('file_handler')
10
+ autoload :Splicer, proxy_path('splicer')
11
+ autoload :Copier, proxy_path('copier')
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+
2
+
3
+ module Geminabox
4
+ module Proxy
5
+ class Copier < FileHandler
6
+
7
+ def self.copy(file_name)
8
+ copier = new(file_name)
9
+ copier.get_file
10
+ copier
11
+ end
12
+
13
+ def get_file
14
+ return true if proxy_file_exists?
15
+ return copy_local if local_file_exists?
16
+ get_remote
17
+ end
18
+
19
+ def copy_local
20
+ FileUtils.cp local_path, proxy_path
21
+ end
22
+
23
+ def get_remote
24
+ File.open(proxy_path, 'w'){|f| f.write(remote_content)}
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,93 @@
1
+ require 'httpclient'
2
+ module Geminabox
3
+ module Proxy
4
+ class FileHandler
5
+
6
+ attr_reader :file_name
7
+
8
+ def initialize(file_name)
9
+ @file_name = file_name
10
+ ensure_destination_exists
11
+ end
12
+
13
+ def local_path
14
+ File.expand_path(file_name, root_path)
15
+ end
16
+
17
+ def root_path
18
+ Geminabox.data
19
+ end
20
+
21
+ def local_file_exists?
22
+ file_exists? local_path
23
+ end
24
+
25
+ def proxy_file_exists?
26
+ file_exists? proxy_path
27
+ end
28
+
29
+ def proxy_path
30
+ File.expand_path(file_name, proxy_folder_path)
31
+ end
32
+
33
+ def file_exists?(path)
34
+ File.exists? path
35
+ end
36
+
37
+ def proxy_folder_path
38
+ File.join(root_path, proxy_folder_name)
39
+ end
40
+
41
+ def proxy_folder_name
42
+ 'proxy'
43
+ end
44
+
45
+ def remote_content
46
+ HTTPClient.get_content(remote_url).force_encoding(encoding)
47
+ end
48
+
49
+ def remote_url
50
+ "http://rubygems.org/#{file_name}"
51
+ end
52
+
53
+ def local_content
54
+ File.read(local_path).force_encoding(encoding)
55
+ end
56
+
57
+ private
58
+ def encoding
59
+ "UTF-8"
60
+ end
61
+
62
+ def ensure_destination_exists
63
+ create_local_folder unless local_folder_exists?
64
+ create_proxy_folder unless proxy_folder_exists?
65
+ end
66
+
67
+ def proxy_file_folder
68
+ File.dirname proxy_path
69
+ end
70
+
71
+ def proxy_folder_exists?
72
+ Dir.exists?(proxy_file_folder)
73
+ end
74
+
75
+ def create_proxy_folder
76
+ FileUtils.mkdir_p(proxy_file_folder)
77
+ end
78
+
79
+ def local_file_folder
80
+ File.dirname local_path
81
+ end
82
+
83
+ def local_folder_exists?
84
+ Dir.exists?(local_file_folder)
85
+ end
86
+
87
+ def create_local_folder
88
+ FileUtils.mkdir_p(local_file_folder)
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,88 @@
1
+ require 'sinatra/base'
2
+ require 'net/http'
3
+
4
+ module Geminabox
5
+ module Proxy
6
+ class Hostess < Sinatra::Base
7
+ attr_accessor :file_handler
8
+
9
+ def serve
10
+ if file_handler
11
+ send_file file_handler.proxy_path
12
+ else
13
+ send_file(File.expand_path(File.join(Server.data, *request.path_info)), :type => response['Content-Type'])
14
+ end
15
+ end
16
+
17
+ %w[specs.4.8.gz
18
+ latest_specs.4.8.gz
19
+ prerelease_specs.4.8.gz
20
+ ].each do |index|
21
+ get "/#{index}" do
22
+ splice_file index
23
+ content_type 'application/x-gzip'
24
+ serve
25
+ end
26
+ end
27
+
28
+ %w[quick/Marshal.4.8/*.gemspec.rz
29
+ yaml.Z
30
+ Marshal.4.8.Z
31
+ ].each do |deflated_index|
32
+ get "/#{deflated_index}" do
33
+ copy_file request.path_info[1..-1]
34
+ content_type('application/x-deflate')
35
+ serve
36
+ end
37
+ end
38
+
39
+ %w[yaml
40
+ Marshal.4.8
41
+ specs.4.8
42
+ latest_specs.4.8
43
+ prerelease_specs.4.8
44
+ ].each do |old_index|
45
+ get "/#{old_index}" do
46
+ splice_file old_index
47
+ serve
48
+ end
49
+ end
50
+
51
+ get "/gems/*.gem" do
52
+ get_from_rubygems_if_not_local
53
+ serve
54
+ end
55
+
56
+ private
57
+ def get_from_rubygems_if_not_local
58
+
59
+ file = File.expand_path(File.join(Server.data, *request.path_info))
60
+
61
+ unless File.exists?(file)
62
+ net_http_class.start("production.cf.rubygems.org") do |http|
63
+ path = File.join(*request.path_info)
64
+ response = http.get(path)
65
+ GemStore.create(IncomingGem.new(StringIO.new(response.body)))
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ def net_http_class
72
+ return ::Net::HTTP if ENV['http_proxy'].empty?
73
+ proxy_uri = URI.parse(ENV['http_proxy'])
74
+ ::Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
75
+ end
76
+
77
+ def splice_file(file_name)
78
+ self.file_handler = Splicer.make(file_name)
79
+ end
80
+
81
+ def copy_file(file_name)
82
+ self.file_handler = Copier.copy(file_name)
83
+ end
84
+
85
+
86
+ end
87
+ end
88
+ end