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