stickler 0.1.1 → 2.0.0a

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/HISTORY.rdoc +5 -2
  2. data/Rakefile +31 -0
  3. data/examples/config.ru +9 -0
  4. data/examples/gemcutter_repo.ru +19 -0
  5. data/examples/index_repo.ru +15 -0
  6. data/examples/local_repo.ru +14 -0
  7. data/examples/mirror_repo.ru +16 -0
  8. data/examples/not_found.ru +8 -0
  9. data/lib/stickler/error.rb +3 -0
  10. data/lib/stickler/middleware/compression.rb +30 -0
  11. data/lib/stickler/middleware/gemcutter.rb +62 -0
  12. data/lib/stickler/middleware/helpers.rb +84 -0
  13. data/lib/stickler/middleware/index.rb +137 -0
  14. data/lib/stickler/middleware/local.rb +38 -0
  15. data/lib/stickler/middleware/mirror.rb +60 -0
  16. data/lib/stickler/middleware/not_found.rb +62 -0
  17. data/lib/stickler/middleware.rb +4 -0
  18. data/lib/stickler/repository/api.rb +167 -0
  19. data/lib/stickler/repository/index.rb +97 -0
  20. data/lib/stickler/repository/local.rb +251 -0
  21. data/lib/stickler/repository/mirror.rb +48 -0
  22. data/lib/stickler/repository/null.rb +58 -0
  23. data/lib/stickler/repository/remote.rb +235 -0
  24. data/lib/stickler/repository.rb +7 -499
  25. data/lib/stickler/spec_lite.rb +60 -14
  26. data/lib/stickler/version.rb +6 -6
  27. data/lib/stickler/web.rb +19 -0
  28. data/spec/data/gems/bar-1.0.0.gem +0 -0
  29. data/spec/data/gems/foo-1.0.0.gem +0 -0
  30. data/spec/data/specifications/bar-1.0.0.gemspec +31 -0
  31. data/spec/data/specifications/foo-1.0.0.gemspec +31 -0
  32. data/spec/middleware/common_gem_server_helpers.rb +67 -0
  33. data/spec/middleware/index_spec.rb +26 -0
  34. data/spec/middleware/legacy_gem_server_behavior.rb +33 -0
  35. data/spec/middleware/local_spec.rb +25 -0
  36. data/spec/middleware/modern_gem_server_behavior.rb +20 -0
  37. data/spec/middleware/not_found_spec.rb +25 -0
  38. data/spec/repository/api_behavior.rb +162 -0
  39. data/spec/repository/api_spec.rb +38 -0
  40. data/spec/repository/index_spec.rb +32 -0
  41. data/spec/repository/local_spec.rb +36 -0
  42. data/spec/repository/null_spec.rb +17 -0
  43. data/spec/repository/remote_spec.rb +49 -0
  44. data/spec/spec.opts +2 -0
  45. data/spec/spec_helper.rb +15 -3
  46. data/spec/spec_lite_spec.rb +62 -0
  47. data/stickler.gemspec +60 -0
  48. data/views/index.erb +19 -0
  49. data/views/layout.erb +39 -0
  50. metadata +93 -63
  51. data/COPYING +0 -339
  52. data/bin/stickler +0 -58
  53. data/data/stickler.yml +0 -14
  54. data/gemspec.rb +0 -62
  55. data/lib/stickler/cli.rb +0 -302
  56. data/lib/stickler/configuration.rb +0 -74
  57. data/lib/stickler/console.rb +0 -72
  58. data/lib/stickler/paths.rb +0 -62
  59. data/lib/stickler/source.rb +0 -75
  60. data/lib/stickler/source_group.rb +0 -365
  61. data/lib/stickler.rb +0 -19
  62. data/spec/configuration_spec.rb +0 -68
  63. data/spec/paths_spec.rb +0 -25
  64. data/spec/repository_spec.rb +0 -55
  65. data/spec/version_spec.rb +0 -17
  66. data/tasks/announce.rake +0 -39
  67. data/tasks/config.rb +0 -107
  68. data/tasks/distribution.rake +0 -45
  69. data/tasks/documentation.rake +0 -31
  70. data/tasks/rspec.rake +0 -29
  71. data/tasks/rubyforge.rake +0 -51
  72. data/tasks/utils.rb +0 -80
@@ -0,0 +1,235 @@
1
+ require 'resourceful'
2
+ require 'stickler/repository'
3
+ require 'stickler/repository/api'
4
+ require 'stringio'
5
+
6
+ module ::Stickler::Repository
7
+ #
8
+ # A Repository::Api implementation that retrieves all is data from an HTTP
9
+ # based remote location. It utilizes the Modern gem server api and the gem
10
+ # cutter api (push/yank/unyank). The legacy gem server api is not utilized.
11
+ #
12
+ class Remote
13
+ # the http client
14
+ attr_reader :http
15
+
16
+ def initialize( repo_uri )
17
+ @uri = Addressable::URI.parse( ensure_http( ensure_trailing_slash( repo_uri ) ) )
18
+ @http = Resourceful::HttpAccessor.new( :cache_manager => Resourceful::InMemoryCacheManager.new )
19
+ # :logger => Resourceful::StdOutLogger.new )
20
+ @specs_list = nil
21
+ end
22
+
23
+ #
24
+ # See Api#uri
25
+ def uri
26
+ @uri
27
+ end
28
+
29
+ #
30
+ # See Api#gems_uri
31
+ #
32
+ def gems_uri
33
+ @gems_uri ||= self.uri.join( "gems/" )
34
+ end
35
+
36
+ #
37
+ # See Api#uri_from_gem
38
+ #
39
+ def uri_for_gem( spec )
40
+ return nil unless remote_gem_file_exist?( spec )
41
+ return self.gems_uri.join( spec.file_name )
42
+ end
43
+
44
+ #
45
+ # The array of specs from upstream
46
+ #
47
+ def specs_list
48
+ Marshal.load( download_specs_list )
49
+ end
50
+
51
+ #
52
+ # See Api#search_for
53
+ #
54
+ def search_for( spec )
55
+ found = []
56
+ specs_list.each do |name, version, platform|
57
+ up_spec = Stickler::SpecLite.new( name, version, platform )
58
+ found << up_spec if spec =~ up_spec
59
+ end
60
+ return found
61
+ end
62
+
63
+ #
64
+ # See Api#get
65
+ #
66
+ def get( spec )
67
+ return download_gem( spec ) if remote_gem_file_exist?( spec )
68
+ return nil
69
+ end
70
+
71
+ #
72
+ # See Api#push
73
+ #
74
+ def push( path )
75
+ spec = speclite_from_gem_file( path )
76
+ raise Stickler::Repository::Error, "gem #{spec.full_name} already exists in remote repository" if remote_gem_file_exist?( spec )
77
+ begin
78
+ resp = push_resource.post( IO.read( path ) )
79
+ rescue Resourceful::UnsuccessfulHttpRequestError => e
80
+ msg = "Failure pushing #{path} to remote repository : response code => #{e.http_response.code}, response message => '#{e.http_response.body}'"
81
+ raise Stickler::Repository::Error, msg
82
+ end
83
+ return spec
84
+ end
85
+
86
+ #
87
+ # See Api#yank
88
+ #
89
+ def yank( spec )
90
+ return nil unless remote_gem_file_exist?( spec )
91
+ begin
92
+ form_data = Resourceful::UrlencodedFormData.new
93
+ form_data.add( "gem_name", spec.name )
94
+ form_data.add( "version", spec.version.to_s )
95
+ yank_resource.request( :delete, form_data.read, {'Content-Type' => form_data.content_type } )
96
+ return full_uri_to_gem( spec )
97
+ rescue Resourceful::UnsuccessfulHttpRequestError => e
98
+ raise Stickler::Repository::Error, "Failure yanking: #{e.inspect}"
99
+ end
100
+ end
101
+
102
+ #
103
+ # See Api#delete
104
+ #
105
+ def delete( spec )
106
+ return false unless remote_gem_file_exist?( spec )
107
+ begin
108
+ gem_resource( spec ).delete
109
+ return true
110
+ rescue Resourceful::UnsuccessfulHttpRequestError => e
111
+ return false
112
+ end
113
+ end
114
+
115
+ #
116
+ # See Api#open
117
+ #
118
+ def open( spec, &block )
119
+ return nil unless remote_gem_file_exist?( spec )
120
+ begin
121
+ data = download_resource( gem_resource( spec ) )
122
+ io = StringIO.new( data , "rb" )
123
+ if block_given? then
124
+ begin
125
+ yield io
126
+ ensure
127
+ io.close
128
+ end
129
+ else
130
+ return io
131
+ end
132
+ rescue Resourceful::UnsuccessfulHttpRequestError => e
133
+ return nil
134
+ end
135
+ nil
136
+ end
137
+
138
+ private
139
+
140
+ def ensure_trailing_slash( uri )
141
+ uri += '/' unless uri =~ %r{/\Z}
142
+ return uri
143
+ end
144
+
145
+ def ensure_http( uri )
146
+ uri = "http://#{uri}" unless uri =~ %r{\Ahttp(s)?://}
147
+ return uri
148
+ end
149
+
150
+ def full_uri_to_gem( spec )
151
+ gems_uri.join( spec.file_name )
152
+ end
153
+
154
+ def specs_list_uri
155
+ Addressable::URI.join( uri, "specs.#{Gem.marshal_version}.gz" )
156
+ end
157
+
158
+ def specs_list_resource
159
+ @specs_list_resource ||= @http.resource( specs_list_uri )
160
+ end
161
+
162
+ def push_uri
163
+ Addressable::URI.join( uri, "api/v1/gems" )
164
+ end
165
+
166
+ def push_resource
167
+ @push_resource ||= @http.resource( push_uri, { 'Content-Type', 'application/octet-stream' } )
168
+ end
169
+
170
+ def yank_uri
171
+ Addressable::URI.join( uri, "api/v1/gems/yank" )
172
+ end
173
+
174
+ def yank_resource
175
+ @yank_resource ||= @http.resource( yank_uri )
176
+ end
177
+
178
+ def gem_resource( spec )
179
+ @http.resource( full_uri_to_gem( spec ) )
180
+ end
181
+
182
+ def download_specs_list
183
+ download_gzipped_resource( specs_list_resource )
184
+ end
185
+
186
+ def download_gzipped_resource( resource )
187
+ Gem.gunzip( download_resource( resource ) )
188
+ end
189
+
190
+ def download_gem( spec )
191
+ download_uri( full_uri_to_gem( spec ) )
192
+ end
193
+
194
+ def download_uri( uri )
195
+ download_resource( http.resource( uri ) )
196
+ end
197
+
198
+ def download_resource( resource )
199
+ begin
200
+ resource.get.body
201
+ rescue Resourceful::UnsuccessfulHttpRequestError => e
202
+ return false
203
+ end
204
+ end
205
+
206
+ def remote_gem_file_exist?( spec )
207
+ gem_uri = full_uri_to_gem( spec )
208
+ remote_uri_exist?( gem_uri )
209
+ end
210
+
211
+ def remote_uri_exist?( uri )
212
+ begin
213
+ # FIXME: bug in Resourceful that uses cached HEAD responses
214
+ # to satisfy later GET requests.
215
+ rc = http.resource( uri ).head( 'Cache-Control' => 'no-store' ).successful?
216
+ return rc
217
+ rescue Resourceful::UnsuccessfulHttpRequestError => e
218
+ return false
219
+ end
220
+ end
221
+
222
+ def speclite_from_gem_file( path )
223
+ speclite_from_specification( specification_from_gem_file( path ) )
224
+ end
225
+
226
+ def specification_from_gem_file( path )
227
+ format = Gem::Format.from_file_by_path( path )
228
+ return format.spec
229
+ end
230
+
231
+ def speclite_from_specification( spec )
232
+ Stickler::SpecLite.new( spec.name, spec.version.to_s, spec.platform )
233
+ end
234
+ end
235
+ end