rubyforge 1.0.4 → 2.0.0

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/lib/rubyforge.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  #! /usr/bin/env ruby -w
2
2
 
3
+ require 'json'
3
4
  require 'enumerator'
4
5
  require 'fileutils'
5
6
  require 'yaml'
@@ -8,14 +9,15 @@ require 'rubyforge/client'
8
9
 
9
10
  $TESTING = false unless defined? $TESTING
10
11
 
12
+ $DEBUG=false
13
+
11
14
  class RubyForge
12
15
 
13
16
  # :stopdoc:
14
- VERSION = '1.0.4'
17
+ VERSION = '2.0.0'
15
18
  HOME = ENV["HOME"] || ENV["HOMEPATH"] || File::expand_path("~")
16
19
  RUBYFORGE_D = File::join HOME, ".rubyforge"
17
20
  CONFIG_F = File::join RUBYFORGE_D, "user-config.yml"
18
- COOKIE_F = File::join RUBYFORGE_D, "cookie.dat"
19
21
 
20
22
  # We must use __FILE__ instead of DATA because this is now a library
21
23
  # and DATA is relative to $0, not __FILE__.
@@ -36,6 +38,10 @@ class RubyForge
36
38
  @client = nil
37
39
  @uri = nil
38
40
  end
41
+
42
+ # These are no-ops now, but we'll keep them here for backwards compatibility
43
+ def login ; end
44
+ def logout ; end
39
45
 
40
46
  def configure opts = {}
41
47
  user_path = CONFIG_F
@@ -56,7 +62,6 @@ class RubyForge
56
62
 
57
63
  raise "no <username>" unless @userconfig["username"]
58
64
  raise "no <password>" unless @userconfig["password"]
59
- raise "no <cookie_jar>" unless @userconfig["cookie_jar"]
60
65
 
61
66
  self
62
67
  end
@@ -65,10 +70,6 @@ class RubyForge
65
70
  @userconfig['force']
66
71
  end
67
72
 
68
- def cookie_store
69
- client.cookie_store
70
- end
71
-
72
73
  def uri
73
74
  @uri ||= URI.parse @userconfig['uri']
74
75
  end
@@ -82,7 +83,6 @@ class RubyForge
82
83
  open(CONFIG_F, "w") { |f|
83
84
  f.write YAML.dump(config)
84
85
  }
85
- FileUtils::touch COOKIE_F
86
86
  edit = (ENV["EDITOR"] || ENV["EDIT"] || "vi") + " '#{CONFIG_F}'"
87
87
  system edit or puts "edit '#{CONFIG_F}'"
88
88
  end
@@ -99,18 +99,21 @@ class RubyForge
99
99
  %w(group package processor release).each do |type|
100
100
  @autoconfig["#{type}_ids"].clear if @autoconfig["#{type}_ids"]
101
101
  end
102
+
103
+ json = get_via_rest_api "/users/#{username}/groups.js"
102
104
 
103
- puts "Getting #{username}"
104
- html = URI.parse("http://rubyforge.org/users/#{username}/index.html").read
105
-
106
- projects = html.scan(%r%/projects/([^/]+)/%).flatten
107
-
105
+ projects = json.collect {|group| group['group']['unix_group_name'] }
108
106
  puts "Fetching #{projects.size} projects"
109
107
  projects.each do |project|
110
- next if project == "support"
111
108
  scrape_project(project)
112
109
  end
113
110
  end
111
+
112
+ def get_via_rest_api(path)
113
+ url = "#{@userconfig['uri']}#{path}"
114
+ puts "Hitting REST API: #{url}" if $DEBUG
115
+ JSON.parse(client.get_content(url, {}, {}, @userconfig))
116
+ end
114
117
 
115
118
  def scrape_project(project)
116
119
  data = {
@@ -120,45 +123,30 @@ class RubyForge
120
123
  "release_ids" => Hash.new { |h,k| h[k] = {} },
121
124
  }
122
125
 
123
- puts "Updating #{project}"
124
-
125
126
  unless data["group_ids"].has_key? project then
126
- html = URI.parse("http://rubyforge.org/projects/#{project}/index.html").read
127
- group_id = html[%r/(memberlist.php|frs|tracker|mail)\/?\?group_id=\d+/][%r/\d+/].to_i
128
-
127
+ json = get_via_rest_api "/groups/#{project}.js"
128
+ group_id = json["group"]["group_id"].to_i
129
129
  data["group_ids"][project] = group_id
130
130
  end
131
131
 
132
- group_id = data["group_ids"][project]
133
-
134
- html = URI.parse("http://rubyforge.org/frs/?group_id=#{group_id}").read
135
-
136
- package = nil
137
- html.scan(/<h3>[^<]+|release_id=\d+">[^>]+|filemodule_id=\d+/).each do |s|
138
- case s
139
- when /<h3>([^<]+)/ then
140
- package = $1.strip
141
- when /release_id=(\d+)">([^<]+)/ then
142
- data["release_ids"][package][$2] = $1.to_i
143
- when /filemodule_id=(\d+)/ then
144
- data["package_ids"][package] = $1.to_i
132
+ # Get project's packages
133
+ json = get_via_rest_api "/groups/#{project}/packages.js"
134
+ json.each do |package|
135
+ data["package_ids"][package["package"]["name"]] = package["package"]["package_id"]
136
+ # Get releases for this package
137
+ json = get_via_rest_api "/packages/#{package["package"]["package_id"]}/releases.js"
138
+ json.each do |release|
139
+ data["release_ids"][package["package"]["name"]][release["name"]] = release["release_id"]
145
140
  end
146
141
  end
147
142
 
148
- if not data['release_ids'][package].empty? and
149
- (@autoconfig['processor_ids'].nil? or
150
- @autoconfig['processor_ids'].empty?) then
151
- puts "Fetching processor ids"
152
-
153
- login
154
-
155
- html = client.get_content "http://rubyforge.org/frs/admin/qrs.php?package=&group_id=#{group_id}"
156
-
157
- html =~ /<select name="processor_id">(.*?)<\/select>/m
158
- processors = $1
159
- processors.scan(/<option value="(\d{4})">([^<]+)/) do
160
- data["processor_ids"][$2] = $1.to_i
161
- end if processors
143
+ # Get processor ids
144
+ if @autoconfig['processor_ids'].nil? || @autoconfig['processor_ids'].empty?
145
+ puts "Fetching processor ids" if $DEBUG
146
+ json = get_via_rest_api "/processors.js"
147
+ json.each do |processor|
148
+ data["processor_ids"][processor["processor"]["name"]] = processor["processor"]["processor_id"]
149
+ end
162
150
  end
163
151
 
164
152
  data.each do |key, val|
@@ -169,51 +157,16 @@ class RubyForge
169
157
  save_autoconfig
170
158
  end
171
159
 
172
- def logout
173
- cookie_store.clear "rubyforge.org"
174
- end
175
-
176
- def login
177
- return if(!force and cookie_store['rubyforge.org']['session_ser']) rescue false
178
-
179
- page = self.uri + "/account/login.php"
180
- page.scheme = 'https'
181
- page = URI.parse page.to_s # set SSL port correctly
182
-
183
- username = @userconfig["username"]
184
- password = @userconfig["password"]
185
-
186
- form = {
187
- "return_to" => "",
188
- "form_loginname" => username,
189
- "form_pw" => password,
190
- "login" => "Login"
191
- }
192
-
193
- response = run page, form
194
-
195
- re = %r/personal\s+page/iom
196
- unless response =~ re
197
- warn("%s:%d: warning: potentially failed login using %s" %
198
- [__FILE__, __LINE__, username]) unless $TESTING
199
- end
200
-
201
- response
202
- end
203
-
204
160
  def create_package(group_id, package_name)
205
- page = "/frs/admin/index.php"
161
+ page = "/groups/#{group_id}/packages"
206
162
 
207
163
  group_id = lookup "group", group_id
208
164
  is_private = @userconfig["is_private"]
209
165
  is_public = is_private ? 0 : 1
210
166
 
211
167
  form = {
212
- "func" => "add_package",
213
- "group_id" => group_id,
214
- "package_name" => package_name,
215
- "is_public" => is_public,
216
- "submit" => "Create This Package",
168
+ "package[name]" => package_name,
169
+ "package[is_public]" => is_public
217
170
  }
218
171
 
219
172
  run page, form
@@ -226,102 +179,61 @@ class RubyForge
226
179
  # Posts news item to +group_id+ (can be name) with +subject+ and +body+
227
180
 
228
181
  def post_news(group_id, subject, body)
229
- page = "/news/submit.php"
230
- group_id = lookup "group", group_id
231
-
182
+ # TODO - what was the post_changes parameter for?
232
183
  form = {
233
- "group_id" => group_id,
234
- "post_changes" => "y",
235
- "summary" => subject,
236
- "details" => body,
237
- "submit" => "Submit",
184
+ "news_byte[summary]" => subject,
185
+ "news_byte[details]" => body
238
186
  }
239
-
240
- run page, form
187
+ group_id = lookup "group", group_id
188
+ url = "/groups/#{group_id}/news_bytes"
189
+ run url, form
241
190
  end
242
191
 
243
192
  def delete_package(group_id, package_id)
244
- page = "/frs/admin/index.php"
245
-
246
193
  group_id = lookup "group", group_id
247
194
  package_id = lookup "package", package_id
248
-
249
- form = {
250
- "func" => "delete_package",
251
- "group_id" => group_id,
252
- "package_id" => package_id,
253
- "sure" => "1",
254
- "really_sure" => "1",
255
- "submit" => "Delete",
256
- }
257
-
258
195
  package_name = @autoconfig["package_ids"].invert[package_id]
259
196
  @autoconfig["package_ids"].delete package_name
260
197
  @autoconfig["release_ids"].delete package_name
261
198
  save_autoconfig
262
-
263
- run page, form
199
+ url = "/packages/#{package_id}"
200
+ run url, {"_method" => "delete"}
264
201
  end
265
202
 
266
203
  def add_release(group_id, package_id, release_name, *files)
267
- userfile = files.shift
268
- page = "/frs/admin/qrs.php"
269
-
270
204
  group_id = lookup "group", group_id
271
205
  package_id = lookup "package", package_id
272
- userfile = open userfile, 'rb'
273
206
  release_date = @userconfig["release_date"]
274
- type_id = @userconfig["type_id"]
275
- processor_id = @userconfig["processor_id"]
276
207
  release_notes = @userconfig["release_notes"]
277
208
  release_changes = @userconfig["release_changes"]
278
209
  preformatted = @userconfig["preformatted"]
279
-
280
210
  release_date ||= Time.now.strftime("%Y-%m-%d %H:%M")
281
-
282
- type_id ||= userfile.path[%r|\.[^\./]+$|]
283
- type_id = (lookup "type", type_id rescue lookup "type", ".oth")
284
-
285
- processor_id ||= "Any"
286
- processor_id = lookup "processor", processor_id
287
-
288
211
  release_notes = IO::read(release_notes) if
289
212
  test(?e, release_notes) if release_notes
290
-
291
213
  release_changes = IO::read(release_changes) if
292
214
  test(?e, release_changes) if release_changes
293
-
294
215
  preformatted = preformatted ? 1 : 0
295
216
 
296
217
  form = {
297
- "group_id" => group_id,
298
- "package_id" => package_id,
299
- "release_name" => release_name,
300
- "release_date" => release_date,
301
- "type_id" => type_id,
302
- "processor_id" => processor_id,
303
- "release_notes" => release_notes,
304
- "release_changes" => release_changes,
305
- "preformatted" => preformatted,
306
- "userfile" => userfile,
307
- "submit" => "Release File"
218
+ "release[name]" => release_name,
219
+ "release[release_date]" => release_date,
220
+ "release[notes]" => release_notes,
221
+ "release[changes]" => release_changes,
222
+ "release[preformatted]" => preformatted,
308
223
  }
309
224
 
310
- boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
311
- boundary = "multipart/form-data; boundary=___#{ boundary }___"
312
-
313
- html = run(page, form, 'content-type' => boundary)
314
- raise "Invalid package_id #{package_id}" if html[/Invalid package_id/]
315
- raise "You have already released this version." if html[/That filename already exists in this project/]
316
-
317
- release_id = html[/release_id=\d+/][/\d+/].to_i rescue nil
318
-
225
+ url = "/packages/#{package_id}/releases"
226
+ json = run url, form
227
+
228
+ release_id = JSON.parse(json)["release_id"].to_i rescue nil
319
229
  unless release_id then
320
- puts html if $DEBUG
321
- raise "Couldn't get release_id, upload failed\?"
230
+ puts json if $DEBUG
231
+ raise "Couldn't get release_id, upload failed?"
322
232
  end
323
233
 
324
- puts "RELEASE ID = #{release_id}" if $DEBUG
234
+ # FIXME
235
+ #raise "Invalid package_id #{package_id}" if html[/Invalid package_id/]
236
+ #raise "You have already released this version." if html[/That filename already exists in this project/]
325
237
 
326
238
  files.each do |file|
327
239
  add_file(group_id, package_id, release_id, file)
@@ -346,35 +258,29 @@ class RubyForge
346
258
  # add_file(1024, 1242, "0.8.0", "traits-0.8.0.gem")
347
259
 
348
260
  def add_file(group_name, package_name, release_name, userfile)
349
- page = '/frs/admin/editrelease.php'
350
261
  type_id = @userconfig["type_id"]
351
262
  group_id = lookup "group", group_name
352
263
  package_id = lookup "package", package_name
353
264
  release_id = (Integer === release_name) ? release_name : lookup("release", package_name)[release_name]
354
- processor_id = @userconfig["processor_id"]
355
-
356
- page = "/frs/admin/editrelease.php?group_id=#{group_id}&release_id=#{release_id}&package_id=#{package_id}"
265
+ url = "/releases/#{release_id}/files.js"
357
266
 
358
267
  userfile = open userfile, 'rb'
359
268
 
360
269
  type_id ||= userfile.path[%r|\.[^\./]+$|]
361
270
  type_id = (lookup "type", type_id rescue lookup "type", ".oth")
362
271
 
272
+ processor_id = @userconfig["processor_id"]
363
273
  processor_id ||= "Any"
364
274
  processor_id = lookup "processor", processor_id
365
275
 
366
276
  form = {
367
- "step2" => 1,
368
- "type_id" => type_id,
369
- "processor_id" => processor_id,
370
- "userfile" => userfile,
371
- "submit" => "Add This File"
372
- }
373
-
374
- boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
375
- boundary = "multipart/form-data; boundary=___#{ boundary }___"
277
+ "file[filename]" => File.basename(userfile.path),
278
+ "file[processor_id]" => processor_id,
279
+ "file[type_id]" => type_id,
280
+ "contents" => userfile.read
281
+ }
376
282
 
377
- run page, form, 'content-type' => boundary
283
+ run url, form
378
284
  end
379
285
 
380
286
  def client
@@ -382,29 +288,16 @@ class RubyForge
382
288
 
383
289
  @client = RubyForge::Client::new ENV["HTTP_PROXY"]
384
290
  @client.debug_dev = STDERR if ENV["RUBYFORGE_DEBUG"] || ENV["DEBUG"] || $DEBUG
385
- @client.cookie_store = @userconfig["cookie_jar"]
386
291
 
387
292
  @client
388
293
  end
389
294
 
390
295
  def run(page, form, extheader={}) # :nodoc:
391
296
  uri = self.uri + page
392
- if $DEBUG then
393
- puts "client.post_content #{uri.inspect}, #{form.inspect}, #{extheader.inspect}"
394
- end
395
-
396
- response = client.post_content uri, form, extheader
397
-
398
- client.save_cookie_store
399
-
400
- if $DEBUG then
401
- response.sub!(/\A.*end tabGenerator -->/m, '')
402
- response.gsub!(/\t/, ' ')
403
- response.gsub!(/\n{3,}/, "\n\n")
404
- puts response
405
- end
406
-
407
- return response
297
+ puts "client.post_content #{uri.inspect}, #{form.inspect}, #{extheader.inspect}" if $DEBUG
298
+ response = client.post_content uri, form, extheader, @userconfig
299
+ puts response if $DEBUG
300
+ response
408
301
  end
409
302
 
410
303
  def lookup(type, val) # :nodoc:
@@ -421,11 +314,11 @@ __END__
421
314
  #
422
315
  # base rubyforge uri - store in #{ CONFIG_F }
423
316
  #
424
- uri : http://rubyforge.org
317
+ uri : http://api.rubyforge.org
425
318
  #
426
319
  # this must be your username
427
320
  #
428
- username : username
321
+ username : tom
429
322
  #
430
323
  # this must be your password
431
324
  #
@@ -433,7 +326,6 @@ __END__
433
326
  #
434
327
  # defaults for some values
435
328
  #
436
- cookie_jar : #{ COOKIE_F }
437
329
  is_private : false
438
330
  # AUTOCONFIG:
439
331
  rubyforge :
@@ -442,6 +334,7 @@ __END__
442
334
  #
443
335
  group_ids :
444
336
  codeforpeople : 1024
337
+ support : 5
445
338
  #
446
339
  # map your package names to their rubyforge ids
447
340
  #