stickler 0.1.1 → 2.0.0a
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.
- data/HISTORY.rdoc +5 -2
- data/Rakefile +31 -0
- data/examples/config.ru +9 -0
- data/examples/gemcutter_repo.ru +19 -0
- data/examples/index_repo.ru +15 -0
- data/examples/local_repo.ru +14 -0
- data/examples/mirror_repo.ru +16 -0
- data/examples/not_found.ru +8 -0
- data/lib/stickler/error.rb +3 -0
- data/lib/stickler/middleware/compression.rb +30 -0
- data/lib/stickler/middleware/gemcutter.rb +62 -0
- data/lib/stickler/middleware/helpers.rb +84 -0
- data/lib/stickler/middleware/index.rb +137 -0
- data/lib/stickler/middleware/local.rb +38 -0
- data/lib/stickler/middleware/mirror.rb +60 -0
- data/lib/stickler/middleware/not_found.rb +62 -0
- data/lib/stickler/middleware.rb +4 -0
- data/lib/stickler/repository/api.rb +167 -0
- data/lib/stickler/repository/index.rb +97 -0
- data/lib/stickler/repository/local.rb +251 -0
- data/lib/stickler/repository/mirror.rb +48 -0
- data/lib/stickler/repository/null.rb +58 -0
- data/lib/stickler/repository/remote.rb +235 -0
- data/lib/stickler/repository.rb +7 -499
- data/lib/stickler/spec_lite.rb +60 -14
- data/lib/stickler/version.rb +6 -6
- data/lib/stickler/web.rb +19 -0
- data/spec/data/gems/bar-1.0.0.gem +0 -0
- data/spec/data/gems/foo-1.0.0.gem +0 -0
- data/spec/data/specifications/bar-1.0.0.gemspec +31 -0
- data/spec/data/specifications/foo-1.0.0.gemspec +31 -0
- data/spec/middleware/common_gem_server_helpers.rb +67 -0
- data/spec/middleware/index_spec.rb +26 -0
- data/spec/middleware/legacy_gem_server_behavior.rb +33 -0
- data/spec/middleware/local_spec.rb +25 -0
- data/spec/middleware/modern_gem_server_behavior.rb +20 -0
- data/spec/middleware/not_found_spec.rb +25 -0
- data/spec/repository/api_behavior.rb +162 -0
- data/spec/repository/api_spec.rb +38 -0
- data/spec/repository/index_spec.rb +32 -0
- data/spec/repository/local_spec.rb +36 -0
- data/spec/repository/null_spec.rb +17 -0
- data/spec/repository/remote_spec.rb +49 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +15 -3
- data/spec/spec_lite_spec.rb +62 -0
- data/stickler.gemspec +60 -0
- data/views/index.erb +19 -0
- data/views/layout.erb +39 -0
- metadata +93 -63
- data/COPYING +0 -339
- data/bin/stickler +0 -58
- data/data/stickler.yml +0 -14
- data/gemspec.rb +0 -62
- data/lib/stickler/cli.rb +0 -302
- data/lib/stickler/configuration.rb +0 -74
- data/lib/stickler/console.rb +0 -72
- data/lib/stickler/paths.rb +0 -62
- data/lib/stickler/source.rb +0 -75
- data/lib/stickler/source_group.rb +0 -365
- data/lib/stickler.rb +0 -19
- data/spec/configuration_spec.rb +0 -68
- data/spec/paths_spec.rb +0 -25
- data/spec/repository_spec.rb +0 -55
- data/spec/version_spec.rb +0 -17
- data/tasks/announce.rake +0 -39
- data/tasks/config.rb +0 -107
- data/tasks/distribution.rake +0 -45
- data/tasks/documentation.rake +0 -31
- data/tasks/rspec.rake +0 -29
- data/tasks/rubyforge.rake +0 -51
- data/tasks/utils.rb +0 -80
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'stickler/repository'
|
2
|
+
require 'stickler/spec_lite'
|
3
|
+
|
4
|
+
module Stickler::Repository
|
5
|
+
#
|
6
|
+
# The API that all Stickler Repository classes MUST implement.
|
7
|
+
# This file is here to document the API
|
8
|
+
#
|
9
|
+
module Api
|
10
|
+
#
|
11
|
+
# :call-seq:
|
12
|
+
# repo.uri -> URI
|
13
|
+
#
|
14
|
+
# Return the URI of the repo
|
15
|
+
#
|
16
|
+
def uri
|
17
|
+
raise NotImplementedError, not_implemented_msg( :uri )
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# :call-seq:
|
22
|
+
# repo.gems_uri -> URI
|
23
|
+
#
|
24
|
+
# Return the URI to the location holding all the +.gem+ files.
|
25
|
+
#
|
26
|
+
#
|
27
|
+
def gems_uri
|
28
|
+
raise NotImplementedError, not_implemented_msg( :gems_uri )
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# :call-seq:
|
33
|
+
# repo.uri_for_gem( spec ) -> URI
|
34
|
+
#
|
35
|
+
# Given a SpecLite like object, return a URI that can be used
|
36
|
+
# to directly access the gem in the repository.
|
37
|
+
#
|
38
|
+
def uri_for_gem( spec )
|
39
|
+
raise NotImplementedError, not_implemented_msg( :uri_for_gem )
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# :call-seq:
|
44
|
+
# repo.search_for( spec ) -> Array
|
45
|
+
#
|
46
|
+
# +match+ MUST be an object that responds to +name+, +version+ and
|
47
|
+
# +platform+.
|
48
|
+
#
|
49
|
+
# The Array that is returned will be +empty?+ if no gems are found that
|
50
|
+
# match +match+.
|
51
|
+
#
|
52
|
+
# When one or matches is found, the Array will contain contain
|
53
|
+
# Stickler::SpecLite instances.
|
54
|
+
#
|
55
|
+
def search_for( spec )
|
56
|
+
raise NotImplementedError, not_implemented_msg( :search_for )
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# :call-seq:
|
61
|
+
# repo.push( path_to_gem_file ) -> Stickler::SpecLite
|
62
|
+
#
|
63
|
+
# Push, in the sense of the gem commandline command <tt>gem push</tt>.
|
64
|
+
# +path_to_gem_file+ must be a file system location to a .gem file
|
65
|
+
# that is then _pushed_ into the repository.
|
66
|
+
#
|
67
|
+
# The SpecLite returned can be used to retrieve the gem
|
68
|
+
# from the repo using the #get() method. A direct URI to the
|
69
|
+
# gem may be obtained using the #uri_for() method.
|
70
|
+
#
|
71
|
+
# If the gem pushed already exists, then a Stickler::Repository::Error is
|
72
|
+
# raised.
|
73
|
+
#
|
74
|
+
def push( path_to_gem_file )
|
75
|
+
raise NotImplementedError, not_implemented_msg( :push )
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# :call-seq:
|
80
|
+
# repo.delete( spec ) -> true|false
|
81
|
+
#
|
82
|
+
# Remove the gem matching the spec completely from the respository.
|
83
|
+
# Return +true+ if the gem was removed, +false+ otherwise
|
84
|
+
#
|
85
|
+
def delete( spec )
|
86
|
+
raise NotImplementedError, not_implemented_msg( :delete)
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# :call-seq:
|
91
|
+
# repo.yank( spec ) -> Stickler::SpecLite
|
92
|
+
#
|
93
|
+
# "yank" in the sense of
|
94
|
+
# http://update.gemcutter.org/2010/03/05/february-changelog.html.
|
95
|
+
# This means, remove the gem matching +spec+ from the index, so it will not
|
96
|
+
# be found when searching, but do not remove the gem physically from the
|
97
|
+
# server. It can still be downloaded directly.
|
98
|
+
#
|
99
|
+
# The SpecLite instance that is returned will have the information that may
|
100
|
+
# be used in the #get() or #uri_for_gem() methods to retrieve the actual
|
101
|
+
# gemfile.
|
102
|
+
#
|
103
|
+
# After a gem has been 'yanked' it MUST not longer be found via the
|
104
|
+
# #search_for() method, nor can it's specification be retrieved via the
|
105
|
+
# #uri_for_specification() method.
|
106
|
+
#
|
107
|
+
# If the gem described by spec does not exist, nil is returned.
|
108
|
+
#
|
109
|
+
def yank( spec )
|
110
|
+
raise NotImplementedError, not_implemented_msg( :yank )
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# :call-seq:
|
115
|
+
# repo.get( spec ) -> bytes
|
116
|
+
#
|
117
|
+
# Retrieve the gem matching the spec from the repository. The bytes
|
118
|
+
# returned MUST be something that would be acceptable to be written
|
119
|
+
# directly to disk as a .gem file.
|
120
|
+
#
|
121
|
+
# If the gem described by spec does not exist, nil is returned.
|
122
|
+
#
|
123
|
+
def get( spec )
|
124
|
+
raise NotImplementedError, not_implemented_msg( :get )
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# :call-seq:
|
129
|
+
# repo.open( spec ) -> reader
|
130
|
+
# repo.open( spec ) { |reader| block }
|
131
|
+
#
|
132
|
+
# Open the gem in a readonly manner, similar to that of File.open.
|
133
|
+
# the +reader+ object that is returned MUST respond to +read+,
|
134
|
+
# +close+ and +rewind+. These methods behave like their corresponding
|
135
|
+
# IO#read, IO#close and IO#rewind methods.
|
136
|
+
#
|
137
|
+
# If the gem described by spec does not exist, nil is returned.
|
138
|
+
# If the gem described by spec does not exist, the block is not called.
|
139
|
+
#
|
140
|
+
def open( spec, &block )
|
141
|
+
raise NotImplementedError, not_implemented_msg( :open )
|
142
|
+
end
|
143
|
+
|
144
|
+
# :stopdoc:
|
145
|
+
def self.api_methods
|
146
|
+
%w[
|
147
|
+
delete
|
148
|
+
gems_uri
|
149
|
+
get
|
150
|
+
open
|
151
|
+
push
|
152
|
+
search_for
|
153
|
+
uri
|
154
|
+
uri_for_gem
|
155
|
+
yank
|
156
|
+
]
|
157
|
+
end
|
158
|
+
# :startdoc:
|
159
|
+
|
160
|
+
private
|
161
|
+
# :stopdoc:
|
162
|
+
def not_implemented_msg( method )
|
163
|
+
"Please implement #{self.class.name}##{method}"
|
164
|
+
end
|
165
|
+
# :startdoc:
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'stickler/spec_lite'
|
2
|
+
require 'stickler/repository'
|
3
|
+
|
4
|
+
module Stickler::Repository
|
5
|
+
#
|
6
|
+
# A repository index is a container holding all the SpecLite elements
|
7
|
+
# in the repository. All the gem specs that this index holds are derived
|
8
|
+
# from actual files on the file system.
|
9
|
+
#
|
10
|
+
# It is modelled somewhat like a Gem::SourceIndex.
|
11
|
+
#
|
12
|
+
class Index
|
13
|
+
class Error < ::Stickler::Repository::Error; end
|
14
|
+
|
15
|
+
# The list of specs in the index
|
16
|
+
attr_reader :specs
|
17
|
+
|
18
|
+
# The directory the specs live
|
19
|
+
attr_reader :spec_dir
|
20
|
+
|
21
|
+
#
|
22
|
+
|
23
|
+
def initialize( spec_dir )
|
24
|
+
@specs = []
|
25
|
+
@spec_dir = spec_dir
|
26
|
+
load_specs
|
27
|
+
end
|
28
|
+
|
29
|
+
def specs
|
30
|
+
load_specs if reload_necessary?
|
31
|
+
return @specs
|
32
|
+
end
|
33
|
+
|
34
|
+
def latest_specs
|
35
|
+
latest = {}
|
36
|
+
specs.each do |s|
|
37
|
+
if old_spec = latest[s.name] then
|
38
|
+
if old_spec.version < s.version then
|
39
|
+
latest[s.name] = s
|
40
|
+
end
|
41
|
+
else
|
42
|
+
latest[s.name] = s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
latest.values
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_specs
|
49
|
+
load_specs_in_dir( self.spec_dir )
|
50
|
+
end
|
51
|
+
|
52
|
+
def reload_necessary?
|
53
|
+
return true
|
54
|
+
# return true unless @last_modified_time
|
55
|
+
# current_modified_time = File.stat( self.spec_dir ).mtime
|
56
|
+
# return (current_modified_time > @last_modified_time )
|
57
|
+
end
|
58
|
+
|
59
|
+
def last_modified_time
|
60
|
+
File.stat( self.spec_dir ).mtime
|
61
|
+
end
|
62
|
+
|
63
|
+
def spec_dir=( d )
|
64
|
+
raise Error, "#{d} is not a directory" unless File.directory?( d )
|
65
|
+
@spec_dir = d
|
66
|
+
@last_modified_time = File.stat( d ).mtime
|
67
|
+
end
|
68
|
+
|
69
|
+
def load_specs_in_dir( spec_dir )
|
70
|
+
return nil unless File.directory?( spec_dir )
|
71
|
+
@specs.clear
|
72
|
+
self.spec_dir = spec_dir
|
73
|
+
|
74
|
+
Dir.foreach( spec_dir ) do |entry|
|
75
|
+
next unless entry =~ /\.gemspec\Z/
|
76
|
+
add_spec_from_file( File.join( spec_dir, entry ) )
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_spec_from_file( path )
|
81
|
+
return nil unless File.exist?( path )
|
82
|
+
code = File.read( path )
|
83
|
+
full_spec = eval( code, binding, path )
|
84
|
+
raise Error, "File #{path} is not Gem::Specification in ruby format" unless full_spec.is_a?( Gem::Specification )
|
85
|
+
|
86
|
+
full_spec.untaint
|
87
|
+
spec = Stickler::SpecLite.new( full_spec.name, full_spec.version, full_spec.platform )
|
88
|
+
@specs << spec
|
89
|
+
end
|
90
|
+
|
91
|
+
def search( find_spec )
|
92
|
+
specs.select do |spec|
|
93
|
+
spec =~ find_spec
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'stickler/spec_lite'
|
2
|
+
require 'stickler/repository'
|
3
|
+
require 'stickler/repository/api'
|
4
|
+
require 'stickler/repository/index'
|
5
|
+
require 'addressable/uri'
|
6
|
+
require 'tempfile'
|
7
|
+
|
8
|
+
module Stickler::Repository
|
9
|
+
#
|
10
|
+
# A local repository of gems. It implements the Repository::Api
|
11
|
+
# and stores all the gems and specifications local to a root directory.
|
12
|
+
#
|
13
|
+
# It currently has two subdirectories:
|
14
|
+
#
|
15
|
+
# gems/ -> holding the .gem files
|
16
|
+
# specifications/ -> holding the .gemspec files
|
17
|
+
#
|
18
|
+
#
|
19
|
+
class Local
|
20
|
+
class Error < ::Stickler::Repository::Error; end
|
21
|
+
|
22
|
+
# the root directory of the repository
|
23
|
+
attr_reader :root_dir
|
24
|
+
|
25
|
+
# the directory containing the .gem files
|
26
|
+
attr_reader :gems_dir
|
27
|
+
|
28
|
+
# the directory containing the .gemspec files
|
29
|
+
attr_reader :specifications_dir
|
30
|
+
|
31
|
+
# a temporary directory for odds and ends
|
32
|
+
attr_reader :temp_dir
|
33
|
+
|
34
|
+
# the index of the repository
|
35
|
+
attr_reader :index
|
36
|
+
|
37
|
+
def initialize( root_dir )
|
38
|
+
@root_dir = File.expand_path( root_dir ) + File::SEPARATOR
|
39
|
+
@gems_dir = File.join( @root_dir, 'gems/' )
|
40
|
+
@specifications_dir = File.join( @root_dir, 'specifications/' )
|
41
|
+
@temp_dir = File.join( @root_dir, "tmp/" )
|
42
|
+
@index = ::Stickler::Repository::Index.new( @specifications_dir )
|
43
|
+
setup_dirs
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# See Api#uri
|
48
|
+
#
|
49
|
+
def uri
|
50
|
+
@uri ||= Addressable::URI.convert_path( root_dir )
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# See Api#gems_uri
|
55
|
+
#
|
56
|
+
def gems_uri
|
57
|
+
@gems_uri ||= Addressable::URI.convert_path( gems_dir )
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# See Api#uri_from_gem
|
62
|
+
#
|
63
|
+
def uri_for_gem( spec )
|
64
|
+
return nil unless gem_file_exist?( spec )
|
65
|
+
return self.gems_uri.join( spec.file_name )
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# A list of all the specs in the repo
|
70
|
+
#
|
71
|
+
def specs
|
72
|
+
@index.specs
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# A list of just the latests specs in the repo
|
77
|
+
#
|
78
|
+
def latest_specs
|
79
|
+
@index.latest_specs
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# The last time this index was modified
|
84
|
+
#
|
85
|
+
def last_modified_time
|
86
|
+
@index.last_modified_time
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# See Api#search_for
|
91
|
+
#
|
92
|
+
def search_for( spec )
|
93
|
+
return index.search( spec )
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# See Api#delete
|
98
|
+
#
|
99
|
+
def delete( spec )
|
100
|
+
uninstall( spec )
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# See Api#yank
|
105
|
+
#
|
106
|
+
def yank( spec )
|
107
|
+
uninstall_specification( spec ) if specification_file_exist?( spec )
|
108
|
+
return uri_for_gem( spec )
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
#
|
113
|
+
# :call-seq:
|
114
|
+
# repo.add( io ) -> Stickler::SpecLite
|
115
|
+
#
|
116
|
+
# A lower level version of #push. The item passed in is an IO like object
|
117
|
+
# that contains the binary stream that is a .gem file. IO must respond to
|
118
|
+
# #read and #rewind.
|
119
|
+
#
|
120
|
+
def add( io )
|
121
|
+
# spooling to a temp file because Gem::Format.from_io() closes the io
|
122
|
+
# stream it is sent. Why it does this, I do not know.
|
123
|
+
tempfile = Tempfile.new( "uploaded-gem.", temp_dir )
|
124
|
+
tempfile.write( io.read )
|
125
|
+
tempfile.rewind
|
126
|
+
|
127
|
+
format = Gem::Format.from_file_by_path( tempfile.path )
|
128
|
+
spec = Stickler::SpecLite.new( format.spec.name, format.spec.version, format.spec.platform )
|
129
|
+
specs = search_for( spec )
|
130
|
+
|
131
|
+
raise Error, "gem #{spec.full_name} already exists" unless specs.empty?
|
132
|
+
|
133
|
+
tempfile.rewind
|
134
|
+
return install( spec, tempfile )
|
135
|
+
ensure
|
136
|
+
tempfile.close!
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# See Api#push
|
141
|
+
#
|
142
|
+
def push( path )
|
143
|
+
spec = specification_from_gem_file( path )
|
144
|
+
result = nil
|
145
|
+
File.open( path ) do |io|
|
146
|
+
result = add( io )
|
147
|
+
end
|
148
|
+
return result
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
# See Api#get
|
153
|
+
#
|
154
|
+
def get( spec )
|
155
|
+
return IO.read( full_path_to_gem( spec ) ) if gem_file_exist?( spec )
|
156
|
+
return nil
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# See Api#open
|
161
|
+
#
|
162
|
+
def open( spec, &block )
|
163
|
+
return nil unless gem_file_exist?( spec )
|
164
|
+
path = full_path_to_gem( spec )
|
165
|
+
f = File.open( path, "rb" )
|
166
|
+
if block_given? then
|
167
|
+
begin
|
168
|
+
yield f
|
169
|
+
ensure
|
170
|
+
f.close
|
171
|
+
end
|
172
|
+
else
|
173
|
+
return f
|
174
|
+
end
|
175
|
+
return nil
|
176
|
+
end
|
177
|
+
|
178
|
+
def full_path_to_gem( spec )
|
179
|
+
File.join( gems_dir, spec.file_name )
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def setup_dirs
|
186
|
+
[ root_dir, specifications_dir, gems_dir, temp_dir ].each do |dir|
|
187
|
+
FileUtils.mkdir_p( dir ) unless File.directory?( dir )
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def full_path_to_specification( spec )
|
192
|
+
File.join( specifications_dir, spec.spec_file_name )
|
193
|
+
end
|
194
|
+
|
195
|
+
def install( spec, io )
|
196
|
+
install_gem( spec, io )
|
197
|
+
install_specification( spec )
|
198
|
+
end
|
199
|
+
|
200
|
+
def install_gem( spec, io )
|
201
|
+
File.open( full_path_to_gem( spec ) , "w+" ) do |of|
|
202
|
+
io.each do |str|
|
203
|
+
of.write( str )
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def install_specification( spec )
|
209
|
+
gemspec = specification_from_gem_file( full_path_to_gem( spec ) )
|
210
|
+
File.open( full_path_to_specification( spec ) , "w+" ) do |f|
|
211
|
+
f.write( gemspec.to_ruby )
|
212
|
+
end
|
213
|
+
return speclite_from_specification( gemspec )
|
214
|
+
end
|
215
|
+
|
216
|
+
def uninstall( spec )
|
217
|
+
uninstall_gem( spec )
|
218
|
+
uninstall_specification( spec )
|
219
|
+
end
|
220
|
+
|
221
|
+
def uninstall_gem( spec )
|
222
|
+
remove_file( full_path_to_gem( spec ) )
|
223
|
+
end
|
224
|
+
|
225
|
+
def uninstall_specification( spec )
|
226
|
+
remove_file( full_path_to_specification( spec ) )
|
227
|
+
end
|
228
|
+
|
229
|
+
def remove_file( path )
|
230
|
+
return false unless File.exist?( path )
|
231
|
+
return true if File.unlink( path ) > 0
|
232
|
+
end
|
233
|
+
|
234
|
+
def gem_file_exist?( spec )
|
235
|
+
File.exist?( full_path_to_gem( spec ) )
|
236
|
+
end
|
237
|
+
|
238
|
+
def specification_file_exist?( spec )
|
239
|
+
File.exist?( full_path_to_specification( spec ) )
|
240
|
+
end
|
241
|
+
|
242
|
+
def specification_from_gem_file( path )
|
243
|
+
format = Gem::Format.from_file_by_path( path )
|
244
|
+
return format.spec
|
245
|
+
end
|
246
|
+
|
247
|
+
def speclite_from_specification( spec )
|
248
|
+
Stickler::SpecLite.new( spec.name, spec.version.to_s, spec.platform )
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'stickler/repository'
|
2
|
+
require 'stickler/repository/remote'
|
3
|
+
require 'stickler/repository/local'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Stickler::Repository
|
7
|
+
#
|
8
|
+
# A Mirror mirrors gems in a Repository::Remote to a Repository::Local
|
9
|
+
# All of the Repository::Api methods are delegated to the Local instance
|
10
|
+
# and a new method #mirror() is added to pull gems from a Remote location
|
11
|
+
# and store in the Local instance
|
12
|
+
#
|
13
|
+
class Mirror
|
14
|
+
class Error < ::Stickler::Repository::Error ; end
|
15
|
+
|
16
|
+
extend Forwardable
|
17
|
+
|
18
|
+
def initialize( root_dir )
|
19
|
+
@root_dir = root_dir
|
20
|
+
@local_repo = ::Stickler::Repository::Local.new( @root_dir )
|
21
|
+
@remote_repos = {}
|
22
|
+
end
|
23
|
+
def_delegators :@local_repo, :uri, :gems_uri, :uri_for_gem, :search_for,
|
24
|
+
:push, :delete, :get, :open
|
25
|
+
|
26
|
+
#
|
27
|
+
# :call-seq:
|
28
|
+
# repo.mirror( spec, host = "rubygems.org" ) -> SpecLite
|
29
|
+
#
|
30
|
+
# Mirror the gem described by spec on the +host+. If no +host+
|
31
|
+
# is given, it is assumed to be http://rubygems.org/.
|
32
|
+
#
|
33
|
+
def mirror( host, spec )
|
34
|
+
specs = @local_repo.search_for( spec )
|
35
|
+
raise Error, "gem #{spec.full_name} already exists" unless specs.empty?
|
36
|
+
|
37
|
+
repo = remote_repo_for( host )
|
38
|
+
repo.open( spec ) do |io|
|
39
|
+
@local_repo.add( io )
|
40
|
+
end
|
41
|
+
return spec
|
42
|
+
end
|
43
|
+
|
44
|
+
def remote_repo_for( host )
|
45
|
+
@remote_repos[host] ||= ::Stickler::Repository::Remote.new( host )
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'stickler/repository'
|
2
|
+
|
3
|
+
module Stickler::Repository
|
4
|
+
#
|
5
|
+
# A null repository. It is in most respecs like a Repository::Local that has
|
6
|
+
# nothing in it.
|
7
|
+
#
|
8
|
+
# The response to +root_dir+ is set by default to be the class name, or
|
9
|
+
# whatever is passed to the initializer.
|
10
|
+
#
|
11
|
+
class Null
|
12
|
+
# the root directory of the repository, this is set in the constructor
|
13
|
+
attr_reader :root_dir
|
14
|
+
|
15
|
+
def initialize( root_dir = self.class.name )
|
16
|
+
@root_dir = root_dir
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty_string( junk = "" )
|
20
|
+
""
|
21
|
+
end
|
22
|
+
alias :uri :empty_string
|
23
|
+
alias :gems_uri :empty_string
|
24
|
+
|
25
|
+
def nilish( junk = nil, &block )
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
alias :push :nilish
|
29
|
+
alias :delete :nilish
|
30
|
+
alias :yank :nilish
|
31
|
+
alias :get :nilish
|
32
|
+
alias :open :nilish
|
33
|
+
alias :uri_for_gem :nilish
|
34
|
+
alias :full_path_to_gem :nilish
|
35
|
+
|
36
|
+
def last_modified_time
|
37
|
+
Time.now
|
38
|
+
end
|
39
|
+
|
40
|
+
def empty_array( junk = nil )
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
alias :specs :empty_array
|
44
|
+
alias :latest_specs :empty_array
|
45
|
+
alias :search_for :empty_array
|
46
|
+
|
47
|
+
def
|
48
|
+
|
49
|
+
def specs
|
50
|
+
Array.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def latest_specs
|
54
|
+
Array.new
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|