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,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