rubyforge 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/rubyforge CHANGED
@@ -1,477 +1,220 @@
1
1
  #! /usr/bin/env ruby
2
- $VERBOSE = nil
3
- #
4
- # add local lib dir to load path - http-access2 is included here for
5
- # convenience.
6
- #
7
- $:.unshift(File::join(File::dirname(File::dirname(__FILE__)), "lib"))
8
- #
9
- # load gems/libs
10
- #
11
- %w( getoptlong enumerator http-access2 yaml fileutils ).each do |l|
12
- begin require "rubygems"; require_gem l; rescue LoadError; require l end
13
- end
14
- #
15
- # hack to fix http-access2 cookie selection bug
16
- #
17
- module WebAgent::CookieUtils
18
- def domain_match(host, domain)
19
- case domain
20
- when /\d+\.\d+\.\d+\.\d+/
21
- return (host == domain)
22
- when '.'
23
- return true
24
- when /^\./
25
- #return tail_match?(domain, host)
26
- return tail_match?(host, domain)
27
- else
28
- return (host == domain)
29
- end
30
- end
31
- end
32
- #
33
- # defaults
34
- #
35
- PROGRAM = File::basename $0
36
- HOME = ENV["HOME"] || ENV["HOMEPATH"] || File::expand_path("~")
37
- RUBYFORGE_D = File::join HOME, ".rubyforge"
38
- CONFIG_F = File::join RUBYFORGE_D, "config.yml"
39
- COOKIE_F = File::join RUBYFORGE_D, "cookie.dat"
40
- #
41
- # usage
42
- #
43
- USAGE = <<-txt
44
- SYNOPSIS
45
-
46
- #{ PROGRAM } [options]* mode [mode_args]*
47
-
48
- DESCRIPTION
49
-
50
- simplistic script which automates a limited set of rubyforge operations
51
-
52
- MODES
53
-
54
- setup()
55
- initializes your .rubyforge directory. you need to run this first before
56
- doing anything else.
57
-
58
- example :
59
- #{ PROGRAM } setup
60
-
61
- login()
62
- sends username and password from config.yml (or --username/--password
63
- options) and stores login cookie in cookie.dat. this is required for
64
- subsquent operations work.
65
-
66
- example :
67
- #{ PROGRAM } login
68
- #{ PROGRAM } login --username zaphod --password 42
69
-
70
- create_package(group_id, package_name)
71
- creates the named package under the specified group.
72
-
73
- example :
74
- #{ PROGRAM } create_package 1024 traits
75
- #{ PROGRAM } login && #{ PROGRAM } create_package codeforpeople.com traits
76
-
77
- notes :
78
- in order to use group_ids by name, rather than number, you must edit the
79
- rubyforge[group_ids] translation table in your config.yml.
80
-
81
- add_release(group_id, package_id, release_name, userfile)
82
- release a file as release_name under the specified group_id and
83
- package_id.
84
-
85
- example :
86
- #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.gem
87
- #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.tgz
88
- #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem
89
- #{ PROGRAM } login && #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem
90
-
91
- notes :
92
- in order to use group_ids and package_ids by name, rather than number,
93
- you must edit the rubyforge[group_ids] and rubyforge[package_ids]
94
- translation tables in your config.yml.
95
-
96
- delete_package(group_id, package_name)
97
- deletes a package and all it's files.
98
-
99
- example :
100
- #{ PROGRAM } delete_package codeforpeople.com traits
101
- #{ PROGRAM } delete_package 1024 traits
102
-
103
- NOTES
104
-
105
- - you can determine the group_id and package_id of projects and packages by
106
-
107
- login ->
108
- my page tab ->
109
- select a project link from 'my projects' ->
110
- files tab ->
111
- admin link (not the admin tab!) ->
112
-
113
- now you'll be at page listing your packages in this project.
114
- near the bottom you'll see links to 'add a release' or 'edit a
115
- release' - hover over the url and you'll notice the query
116
- string, which looks something like
117
-
118
- ?package_id=1242&group_id=1024
119
-
120
- and that's what you need to know
121
-
122
- - don't forget to login! logging in will store a cookie in your
123
- .rubyforge directory which expires after a time. always run the login
124
- command before any operation that requires authentication, such as
125
- uploading a package.
126
-
127
- TODO
128
-
129
- - scrape rubyforge to auto-configure group_id and package_ids.
130
-
131
- - objectify the script. it's procedural butchery attm.
132
-
133
- - add error checking. this requires screen scraping to see of an operation
134
- succeeded since 200 is returned from rubyforge even for failed operations
135
- and only the html text reveals the status.
136
-
137
- - add more functionality.
138
-
139
- OPTIONS
140
-
141
- global :
142
- --help , -h
143
- this message
144
- --config , -c
145
- specify a config file (default #{ CONFIG_F })
146
- --username , -u
147
- specify username, taken from config otherwise
148
- --password , -p
149
- specify password, taken from config otherwise
150
- --cookie_jar , -C
151
- specify cookie storage file (default #{ COOKIE_F })
152
-
153
- add_release :
154
- --is_private , -P
155
- if true, release is not public
156
- --release_date , -r
157
- specify time of release (default 'now')
158
- --type_id , -t
159
- specify filetype code (default determined by ext)
160
- --processor_id , -o
161
- specify processor (default 'Any')
162
- --release_notes , -n
163
- specify release notes as string or file
164
- --release_changes , -a
165
- specify release changes as string or file
166
- --preformatted , -f
167
- specify whether release_notes/changes are preformatted
168
-
169
- txt
170
- USAGE.gsub! %r|^#{ USAGE[%r/^\s*/] }|, ''
171
- #
172
- # config
173
- #
174
- CONFIG = <<-yml
175
- #
176
- # base rubyforge uri - store in #{ CONFIG_F }
177
- #
178
- uri : http://rubyforge.org
179
- #
180
- # this must be your username
181
- #
182
- username : username
183
- #
184
- # this must be your password
185
- #
186
- password : password
187
- #
188
- # defaults for some values
189
- #
190
- defaults :
191
- cookie_jar : #{ COOKIE_F }
192
- is_private : false
193
- #
194
- # server side rubyforge configuration
195
- #
196
- rubyforge :
197
- #
198
- # map your package names to their rubyforge ids
199
- #
200
- package_ids :
201
- traits : 1241
202
- #
203
- # map your group names to their rubyforge ids
204
- #
205
- group_ids :
206
- codeforpeople.com : 1024
207
- #
208
- # mapping file exts to rubyforge ids
209
- #
210
- type_ids :
211
- .deb : 1000
212
- .rpm : 2000
213
- .zip : 3000
214
- .bz2 : 3100
215
- .gz : 3110
216
- .src.zip : 5000
217
- .src.bz2 : 5010
218
- .src.tar.bz2 : 5010
219
- .src.gz : 5020
220
- .src.tar.gz : 5020
221
- .src.rpm : 5100
222
- .src : 5900
223
- .jpg : 8000
224
- .txt : 8100
225
- .text : 8100
226
- .htm : 8200
227
- .html : 8200
228
- .pdf : 8300
229
- .oth : 9999
230
- .ebuild : 1300
231
- .exe : 1100
232
- .dmg : 1200
233
- .tar.gz : 5000
234
- .tgz : 5000
235
- .gem : 1400
236
- .pgp : 8150
237
- .sig : 8150
238
- #
239
- # map processor names to rubyforge ids
240
- #
241
- processor_ids :
242
- i386 : 1000
243
- IA64 : 6000
244
- Alpha : 7000
245
- Any : 8000
246
- PPC : 2000
247
- MIPS : 3000
248
- Sparc : 4000
249
- UltraSparc : 5000
250
- Other : 9999
251
- yml
252
- CONFIG.gsub! %r|^#{ CONFIG[%r/^\s*/] }|, ''
253
- #
254
- # load mode, global opts, and config
255
- #
256
- mode = ARGV.shift
257
-
258
- opts = GetoptLong::new(
259
- [ "--help" , "-h" , GetoptLong::REQUIRED_ARGUMENT ] ,
260
- [ "--config" , "-c" , GetoptLong::REQUIRED_ARGUMENT ] ,
261
- [ "--username" , "-u" , GetoptLong::REQUIRED_ARGUMENT ] ,
262
- [ "--password" , "-p" , GetoptLong::REQUIRED_ARGUMENT ] ,
263
- [ "--cookie_jar" , "-C" , GetoptLong::REQUIRED_ARGUMENT ] ,
264
-
265
- [ "--is_private", "-P", GetoptLong::REQUIRED_ARGUMENT ],
266
-
267
- [ "--release_date" , "-r" , GetoptLong::REQUIRED_ARGUMENT ] ,
268
- [ "--type_id" , "-t" , GetoptLong::REQUIRED_ARGUMENT ] ,
269
- [ "--processor_id" , "-o" , GetoptLong::REQUIRED_ARGUMENT ] ,
270
- [ "--release_notes" , "-n" , GetoptLong::REQUIRED_ARGUMENT ] ,
271
- [ "--release_changes" , "-a" , GetoptLong::REQUIRED_ARGUMENT ] ,
272
- [ "--preformatted" , "-f" , GetoptLong::NO_ARGUMENT ]
273
- ).enum_for.inject({}){|h,kv| h.update kv.first.delete('-') => kv.last}
274
-
275
- config = opts["config"] || CONFIG_F
276
- config = test(?e, config) ? IO::read(config) : CONFIG
277
- config = YAML::load config
278
-
279
- username = opts["username"] || config["username"]
280
- password = opts["password"] || config["password"]
281
- cookie_jar = opts["cookie_jar"] || config["defaults"]["cookie_jar"]
282
-
283
- abort "no <username>" unless username
284
- abort "no <password>" unless password
285
- abort "no <cookie_jar>" unless cookie_jar
286
-
287
- mode = "help" if opts["help"]
288
- #
289
- # run based on mode
290
- #
291
- msg, page, form, extheader = nil, nil, nil, {}
292
-
293
- case mode
294
- #
295
- # help mode
296
- #
297
- when %r/help/
298
- USAGE.display
299
- exit
300
- #
301
- # setup mode
302
- #
303
- when %r/setup/
304
- FileUtils::mkdir_p RUBYFORGE_D
305
- test ?e, CONFIG_F and FileUtils::mv CONFIG_F, "#{ CONFIG_F }.bak"
306
- open(CONFIG_F,"w"){|f| f.write CONFIG}
307
- FileUtils::touch COOKIE_F
308
- edit = (ENV["EDITOR"] || ENV["EDIT"] || "gvim") + " #{ CONFIG_F }"
309
- system edit or puts "edit #{ CONFIG_F }"
310
- exit
311
- #
312
- # login mode
313
- #
314
- when %r/login/
315
- page, msg = "/account/login.php", "post_content"
316
-
317
- form = {
318
- "return_to" => "",
319
- "form_loginname" => username,
320
- "form_pw" => password,
321
- "login" => "Login"
322
- }
323
- #
324
- # create_package mode
325
- #
326
- when %r/create_package/
327
- page, msg = "/frs/admin/index.php", "post_content"
328
-
329
- group_id, package_name = ARGV
330
-
331
- abort "no <group_id>" unless group_id
332
- abort "no <package_name>" unless package_name
333
-
334
- unless group_id.to_s =~ %r/^\d+$/
335
- key = group_id.to_s
336
- group_id = config["rubyforge"]["group_ids"][key]
337
- abort "no <group_id> configured for <#{ key }>" unless group_id
338
- end
339
-
340
- is_private = opts["is_private"] || config["defaults"]["is_private"]
341
- is_public = is_private ? 0 : 1
342
-
343
- form = {
344
- "func" => "add_package",
345
- "group_id" => group_id,
346
- "package_name" => package_name,
347
- "is_public" => is_public,
348
- "submit" => "Create This Package",
349
- }
350
- #
351
- # delete_package mode
352
- #
353
- when %r/delete_package/
354
- page, msg = "/frs/admin/index.php", "post_content"
355
-
356
- group_id, package_id = ARGV
357
-
358
- abort "no <group_id>" unless group_id
359
- abort "no <package_id>" unless package_id
360
-
361
- unless group_id.to_s =~ %r/^\d+$/
362
- key = group_id.to_s
363
- group_id = config["rubyforge"]["group_ids"][key]
364
- abort "no <group_id> configured for <#{ key }>" unless group_id
365
- end
366
-
367
- unless package_id.to_s =~ %r/^\d+$/
368
- key = package_id.to_s
369
- package_id = config["rubyforge"]["package_ids"][key]
370
- abort "no <package_id> configured for <#{ key }>" unless package_id
371
- end
372
-
373
- form = {
374
- "func" => "delete_package",
375
- "group_id" => group_id,
376
- "package_id" => package_id,
377
- "sure" => "1",
378
- "really_sure" => "1",
379
- "submit" => "Delete",
380
- }
381
- #
382
- # add_release mode
383
- #
384
- when %r/add_release/
385
- page, msg = "/frs/admin/qrs.php", "post_content"
386
-
387
- group_id, package_id, release_name, userfile = ARGV
388
-
389
- abort "no <group_id>" unless group_id
390
- abort "no <package_id>" unless package_id
391
- abort "no <release_name>" unless release_name
392
- abort "no <userfile>" unless userfile
393
-
394
- unless group_id.to_s =~ %r/^\d+$/
395
- key = group_id.to_s
396
- group_id = config["rubyforge"]["group_ids"][key]
397
- abort "no <group_id> configured for <#{ key }>" unless group_id
398
- end
399
-
400
- unless package_id.to_s =~ %r/^\d+$/
401
- key = package_id.to_s
402
- package_id = config["rubyforge"]["package_ids"][key]
403
- abort "no <package_id> configured for <#{ key }>" unless package_id
404
- end
405
-
406
- userfile = open userfile
407
-
408
- release_date = opts["release_date"]
409
- type_id = opts["type_id"]
410
- processor_id = opts["processor_id"]
411
- release_notes = opts["release_notes"]
412
- release_changes = opts["release_changes"]
413
- preformatted = opts["preformatted"]
414
-
415
- release_date ||= Time::now.strftime("%Y-%m-%d %H:%M")
416
-
417
- type_id ||= userfile.path[%r|\.[^\./]+$|]
418
- unless type_id.to_s =~ %r/^\d+$/
419
- key = type_id.to_s
420
- type_id = config["rubyforge"]["type_ids"][key]
421
- abort "no <type_id> configured for <#{ key }>" unless type_id
422
- end
423
-
424
- processor_id ||= "Any"
425
- unless processor_id.to_s =~ %r/^\d+$/
426
- key = processor_id.to_s
427
- processor_id = config["rubyforge"]["processor_ids"][key]
428
- abort "no <processor_id> configured for <#{ key }>" unless processor_id
429
- end
430
-
431
- release_notes = IO::read(release_notes) if release_notes and test(?e, release_notes)
432
-
433
- release_changes = IO::read(release_changes) if release_changes and test(?e, release_changes)
434
-
435
- preformatted = preformatted ? 1 : 0
436
-
437
- form = {
438
- "group_id" => group_id,
439
- "package_id" => package_id,
440
- "release_name" => release_name,
441
- "release_date" => release_date,
442
- "type_id" => type_id,
443
- "processor_id" => processor_id,
444
- "release_notes" => release_notes,
445
- "release_changes" => release_changes,
446
- "preformatted" => preformatted,
447
- "userfile" => userfile,
448
- "submit" => "Release File"
449
- }
450
-
451
- boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
452
- extheader['content-type'] = "multipart/form-data; boundary=___#{ boundary }___"
453
- #
454
- # bad mode
455
- #
456
- else
457
- abort USAGE
458
- end
459
- #
460
- # commit http transaction
461
- #
462
- if [msg, page, form].all?
463
- client = HTTPAccess2::Client::new ENV["HTTP_PROXY"]
464
- client.debug_dev = STDERR if ENV["RUBYFORGE_DEBUG"] || ENV["DEBUG"]
465
- client.set_cookie_store cookie_jar
466
- #
467
- # hack to fix http-access2 redirect bug/feature
468
- #
469
- client.redirect_uri_callback = lambda do |res|
470
- page = res.header['location'].first
471
- page =~ %r/http/ ? page : "#{ config['uri'] }/#{ page }"
472
- end
473
- response = client.send "#{ msg }", "#{ config['uri'] }/#{ page }", form, extheader
474
- client.save_cookie_store
475
- end
476
-
477
- exit 0
2
+
3
+ $VERBOSE = true
4
+
5
+ $:.unshift(File::join(File::dirname(File::dirname(__FILE__)), "lib"))
6
+
7
+ require 'getoptlong'
8
+ require 'rubyforge'
9
+
10
+ PROGRAM = File::basename $0
11
+
12
+ USAGE = <<-EOL
13
+ SYNOPSIS
14
+
15
+ #{ PROGRAM } [options]* mode [mode_args]*
16
+
17
+ DESCRIPTION
18
+
19
+ simplistic script which automates a limited set of rubyforge operations
20
+
21
+ MODES
22
+
23
+ setup()
24
+ initializes your .rubyforge directory. you need to run this first before
25
+ doing anything else.
26
+
27
+ example :
28
+ #{ PROGRAM } setup
29
+
30
+ config()
31
+ Helps you populate your config.yml file by scraping rubyforge and
32
+ getting your groups, projects, and releases.
33
+
34
+ example :
35
+ #{ PROGRAM } config
36
+
37
+ names()
38
+ Prints out the names of your configured groups and projects.
39
+
40
+ example :
41
+ #{ PROGRAM } names
42
+
43
+ login()
44
+ sends username and password from config.yml (or --username/--password
45
+ options) and stores login cookie in cookie.dat. this is required for
46
+ subsquent operations work.
47
+
48
+ example :
49
+ #{ PROGRAM } login
50
+ #{ PROGRAM } login --username zaphod --password 42
51
+
52
+ create_package(group_id, package_name)
53
+ creates the named package under the specified group.
54
+
55
+ example :
56
+ #{ PROGRAM } create_package 1024 traits
57
+ #{ PROGRAM } login && #{ PROGRAM } create_package codeforpeople.com traits
58
+
59
+ add_release(group_id, package_id, release_name, userfile)
60
+ release a file as release_name under the specified group_id and
61
+ package_id.
62
+
63
+ example :
64
+ #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.gem
65
+ #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.tgz
66
+ #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem
67
+ #{ PROGRAM } login && #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem
68
+
69
+ add_file(group_id, package_id, release_id, userfile)
70
+ add a file to an existing release under the specified group_id,
71
+ package_id, and release_id
72
+
73
+ example :
74
+ #{ PROGRAM } add_file codeforpeople.com traits 0.8.0 traits-0.8.0.gem
75
+ #{ PROGRAM } add_file codeforpeople.com traits 0.8.0 traits-0.8.0.tgz
76
+ #{ PROGRAM } add_file 1024 1242 0.8.0 traits-0.8.0.gem
77
+
78
+ delete_package(group_id, package_name)
79
+ deletes a package and all its files.
80
+
81
+ example :
82
+ #{ PROGRAM } delete_package codeforpeople.com traits
83
+ #{ PROGRAM } delete_package 1024 traits
84
+
85
+ NOTES
86
+
87
+ - In order to use group_id, package_id, or release_id by name,
88
+ rather than number, you must edit the rubyforge[group_ids] and
89
+ rubyforge[package_ids] translation tables in your config.yml. See
90
+ the config command for more information and help.
91
+
92
+ - don\'t forget to login! logging in will store a cookie in your
93
+ .rubyforge directory which expires after a time. always run the login
94
+ command before any operation that requires authentication, such as
95
+ uploading a package.
96
+
97
+ TODO
98
+
99
+ - add error checking. this requires screen scraping to see of an operation
100
+ succeeded since 200 is returned from rubyforge even for failed operations
101
+ and only the html text reveals the status.
102
+
103
+ OPTIONS
104
+
105
+ global :
106
+ --help , -h
107
+ this message
108
+ --config , -c
109
+ specify a config file (default #{ RubyForge::CONFIG_F })
110
+ --username , -u
111
+ specify username, taken from config otherwise
112
+ --password , -p
113
+ specify password, taken from config otherwise
114
+ --cookie_jar , -C
115
+ specify cookie storage file (default #{ RubyForge::COOKIE_F })
116
+
117
+ add_release :
118
+ --is_private , -P
119
+ if true, release is not public
120
+ --release_date , -r
121
+ specify time of release (default 'now')
122
+ --type_id , -t
123
+ specify filetype code (default determined by ext)
124
+ --processor_id , -o
125
+ specify processor (default 'Any')
126
+ --release_notes , -n
127
+ specify release notes as string or file
128
+ --release_changes , -a
129
+ specify release changes as string or file
130
+ --preformatted , -f
131
+ specify whether release_notes/changes are preformatted
132
+
133
+ EOL
134
+
135
+ mode = ARGV.shift
136
+
137
+ opts = GetoptLong::new(
138
+ [ "--help" , "-h" , GetoptLong::REQUIRED_ARGUMENT ] ,
139
+ [ "--config" , "-c" , GetoptLong::REQUIRED_ARGUMENT ] ,
140
+ [ "--username" , "-u" , GetoptLong::REQUIRED_ARGUMENT ] ,
141
+ [ "--password" , "-p" , GetoptLong::REQUIRED_ARGUMENT ] ,
142
+ [ "--cookie_jar" , "-C" , GetoptLong::REQUIRED_ARGUMENT ] ,
143
+ [ "--is_private" , "-P" , GetoptLong::REQUIRED_ARGUMENT ],
144
+ [ "--release_date" , "-r" , GetoptLong::REQUIRED_ARGUMENT ] ,
145
+ [ "--type_id" , "-t" , GetoptLong::REQUIRED_ARGUMENT ] ,
146
+ [ "--processor_id" , "-o" , GetoptLong::REQUIRED_ARGUMENT ] ,
147
+ [ "--release_notes" , "-n" , GetoptLong::REQUIRED_ARGUMENT ] ,
148
+ [ "--release_changes" , "-a" , GetoptLong::REQUIRED_ARGUMENT ] ,
149
+ [ "--preformatted" , "-f" , GetoptLong::NO_ARGUMENT ]
150
+ ).enum_for.inject({}){|h,kv| h.update kv.first.delete('-') => kv.last}
151
+
152
+ rubyforge = RubyForge.new(opts["config"] || RubyForge::CONFIG_F, opts)
153
+
154
+ mode = "help" if opts["help"]
155
+
156
+ case mode
157
+ when %r/help/
158
+ USAGE.display
159
+ when %r/setup/
160
+ rubyforge.setup
161
+ when %r/config/
162
+ puts "Add the following to #{RubyForge::CONFIG_F}"
163
+ puts
164
+ username = ARGV.shift || rubyforge.config['username']
165
+ y "rubyforge" => rubyforge.scrape_config(username)
166
+ when %r/names/
167
+ rf = rubyforge.config["rubyforge"]
168
+ puts "groups : #{rf["group_ids"].keys.sort.join(", ")}"
169
+ puts "packages: #{rf["package_ids"].keys.sort.join(", ")}"
170
+ when %r/login/
171
+ rubyforge.login
172
+ when %r/create_package/
173
+ page, msg = "/frs/admin/index.php", "post_content"
174
+
175
+ group_id, package_name = ARGV
176
+
177
+ abort "no <group_id>" unless group_id
178
+ abort "no <package_name>" unless package_name
179
+
180
+ group_id = Integer(group_id) rescue group_id
181
+
182
+ rubyforge.create_package group_id, package_name
183
+ when %r/delete_package/
184
+ group_id, package_id = ARGV
185
+
186
+ abort "no <group_id>" unless group_id
187
+ abort "no <package_id>" unless package_id
188
+
189
+ group_id = Integer(group_id) rescue group_id
190
+ package_id = Integer(package_id) rescue package_id
191
+
192
+ rubyforge.delete_package group_id, package_id
193
+ when %r/add_release/
194
+ group_id, package_id, release_name, userfile = ARGV
195
+
196
+ abort "no <group_id>" unless group_id
197
+ abort "no <package_id>" unless package_id
198
+ abort "no <release_name>" unless release_name
199
+ abort "no <userfile>" unless userfile
200
+
201
+ group_id = Integer(group_id) rescue group_id
202
+ package_id = Integer(package_id) rescue package_id
203
+
204
+ rubyforge.add_release group_id, package_id, release_name, userfile
205
+ when %r/add_file/
206
+ group_id, package_id, release_id, userfile = ARGV
207
+
208
+ abort "no <group_id>" unless group_id
209
+ abort "no <package_id>" unless package_id
210
+ abort "no <release_id>" unless release_id
211
+ abort "no <userfile>" unless userfile
212
+
213
+ group_id = Integer(group_id) rescue group_id
214
+ package_id = Integer(package_id) rescue package_id
215
+ release_id = Integer(release_id) rescue release_id
216
+
217
+ rubyforge.add_file group_id, package_id, release_id, userfile
218
+ else
219
+ abort USAGE
220
+ end