reap 6.0.2 → 9.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/CHANGES +6 -0
  2. data/COPYING +666 -395
  3. data/MANIFEST +139 -0
  4. data/NOTES +12 -0
  5. data/README +19 -163
  6. data/bin/reap-announce +7 -0
  7. data/bin/reap-check-load +8 -0
  8. data/bin/reap-check-syntax +7 -0
  9. data/bin/reap-clean +7 -0
  10. data/bin/reap-clobber +7 -0
  11. data/bin/reap-doc +7 -0
  12. data/bin/reap-doc-rdoc +7 -0
  13. data/bin/reap-doc-ri +7 -0
  14. data/bin/reap-init +69 -0
  15. data/bin/reap-inspect +7 -0
  16. data/bin/reap-install +8 -0
  17. data/bin/reap-install-gem +8 -0
  18. data/bin/reap-log +7 -0
  19. data/bin/reap-log-changes +8 -0
  20. data/bin/reap-log-notes +8 -0
  21. data/bin/reap-make +7 -0
  22. data/bin/reap-make-clean +7 -0
  23. data/bin/reap-make-distclean +7 -0
  24. data/bin/reap-make-extconf +7 -0
  25. data/bin/reap-make-static +8 -0
  26. data/bin/reap-package +8 -0
  27. data/bin/reap-package-gem +7 -0
  28. data/bin/reap-package-tgz +7 -0
  29. data/bin/reap-package-zip +7 -0
  30. data/bin/reap-prepare +7 -0
  31. data/bin/reap-publish +7 -0
  32. data/bin/reap-release +7 -0
  33. data/bin/reap-scaffold +8 -0
  34. data/bin/reap-scm-branch +7 -0
  35. data/bin/reap-scm-tag +7 -0
  36. data/bin/reap-spec +7 -0
  37. data/bin/reap-spec-doc +8 -0
  38. data/bin/reap-stamp +7 -0
  39. data/bin/reap-stats +7 -0
  40. data/bin/reap-test +7 -0
  41. data/bin/reap-test-cross +7 -0
  42. data/bin/reap-test-load +9 -0
  43. data/bin/reap-test-solo +7 -0
  44. data/bin/reap-uninstall +7 -0
  45. data/bin/reap-uninstall-gem +7 -0
  46. data/data/reap/base/CHANGES +19 -0
  47. data/data/reap/base/COPYING +674 -0
  48. data/data/reap/base/NOTES +12 -0
  49. data/data/reap/base/README +8 -0
  50. data/data/reap/build/rake/Rakefile +130 -0
  51. data/{forge/reference/installers → data/reap/build/rake}/setup.rb +155 -97
  52. data/data/reap/build/rake-lite/install.rb +79 -0
  53. data/data/reap/build/tasks/task/rdoc +211 -0
  54. data/data/reap/{setup.rb → build/tasks/task/setup} +248 -200
  55. data/data/reap/build/tasks/task/test +38 -0
  56. data/data/reap/init/meta/project.yaml +21 -0
  57. data/demo/README +15 -0
  58. data/demo/lib/foo/foo.rb +7 -0
  59. data/demo/meta/VERSION +1 -0
  60. data/demo/meta/project.yaml +21 -0
  61. data/lib/reap/application.rb +80 -0
  62. data/lib/reap/default.yaml +77 -0
  63. data/lib/reap/extensions/array.rb +50 -0
  64. data/lib/reap/extensions/hash.rb +63 -0
  65. data/lib/reap/extensions/string.rb +31 -0
  66. data/lib/reap/extensions.rb +6 -0
  67. data/lib/reap/iobject.rb +264 -0
  68. data/lib/reap/manager/announce.rb +193 -0
  69. data/lib/reap/manager/check.rb +109 -0
  70. data/lib/reap/manager/clean.rb +58 -0
  71. data/lib/reap/manager/gem.rb +200 -0
  72. data/lib/reap/manager/html.rb +69 -0
  73. data/lib/reap/manager/log.rb +214 -0
  74. data/lib/reap/manager/make.rb +109 -0
  75. data/lib/reap/manager/pack.rb +232 -0
  76. data/lib/reap/manager/publish.rb +72 -0
  77. data/lib/reap/manager/rdoc.rb +194 -0
  78. data/lib/reap/manager/release.rb +78 -0
  79. data/lib/reap/manager/rubyforge.rb +44 -0
  80. data/lib/reap/manager/scaffold.rb +138 -0
  81. data/lib/reap/manager/scm.rb +66 -0
  82. data/lib/reap/manager/site.rb +27 -0
  83. data/lib/reap/manager/spec.rb +94 -0
  84. data/lib/reap/manager/stats.rb +145 -0
  85. data/lib/reap/manager/svn.rb +76 -0
  86. data/lib/reap/manager/test.rb +389 -0
  87. data/lib/reap/manager.rb +74 -0
  88. data/lib/reap/metadata.rb +603 -0
  89. data/lib/reap/project.rb +165 -0
  90. data/lib/reap/settings.rb +67 -0
  91. data/lib/reap/systems/rubyforge.rb +737 -0
  92. data/lib/reap/systems/subversion.rb +333 -0
  93. data/lib/reap/utilities/fileutils.rb +304 -0
  94. data/lib/reap/utilities/netutils.rb +221 -0
  95. data/lib/reap/utilities/setuputils.rb +124 -0
  96. data/lib/reap/utilities/shellutils.rb +175 -0
  97. data/log/Changelog.txt +107 -0
  98. data/log/FIXME.txt +25 -0
  99. data/log/TODO.txt +72 -0
  100. data/meta/VERSION +1 -0
  101. data/meta/description +4 -0
  102. data/meta/project.yaml +20 -0
  103. data/task/man +14 -0
  104. data/task/rdoc +20 -0
  105. data/{data/reap/scaffold/standard/setup.rb → task/setup} +248 -200
  106. metadata +225 -153
  107. data/ProjectInfo +0 -105
  108. data/bin/reap +0 -5
  109. data/bin/rubytest +0 -5
  110. data/data/reap/install.rb +0 -62
  111. data/data/reap/scaffold/standard/COPYING +0 -403
  112. data/data/reap/scaffold/standard/ChangeLog +0 -0
  113. data/data/reap/scaffold/standard/INSTALL +0 -14
  114. data/data/reap/scaffold/standard/ProjectInfo +0 -77
  115. data/data/reap/scaffold/standard/README +0 -3
  116. data/data/reap/scaffold/standard/Rakefile +0 -10
  117. data/data/reap/scaffold/standard/TODO +0 -0
  118. data/data/reap/scaffold/subversion/trunk/COPYING +0 -403
  119. data/data/reap/scaffold/subversion/trunk/ChangeLog +0 -0
  120. data/data/reap/scaffold/subversion/trunk/INSTALL +0 -14
  121. data/data/reap/scaffold/subversion/trunk/ProjectInfo +0 -76
  122. data/data/reap/scaffold/subversion/trunk/README +0 -3
  123. data/data/reap/scaffold/subversion/trunk/Rakefile +0 -10
  124. data/data/reap/scaffold/subversion/trunk/TODO +0 -0
  125. data/data/reap/scaffold/subversion/trunk/setup.rb +0 -1568
  126. data/forge/ProjectInfo +0 -38
  127. data/forge/ProjectInfo.rb +0 -76
  128. data/forge/TODO +0 -10
  129. data/forge/installer.rb +0 -250
  130. data/forge/reference/Rakefile +0 -124
  131. data/forge/reference/Rakefile.htm +0 -69
  132. data/forge/reference/aRakefile +0 -60
  133. data/forge/reference/compositepublisher.rb +0 -24
  134. data/forge/reference/ftptools.rb +0 -139
  135. data/forge/reference/installers/package.rb +0 -629
  136. data/forge/reference/license-each.rb +0 -85
  137. data/forge/reference/publisher.rb +0 -75
  138. data/forge/reference/rubyforge.rb +0 -247
  139. data/forge/reference/rubyforgepublisher.rb +0 -18
  140. data/forge/reference/sshpublisher.rb +0 -47
  141. data/forge/reference/suby-cvs.rb +0 -46
  142. data/forge/scaffold.rb +0 -126
  143. data/forge/unit_runner/README +0 -6
  144. data/forge/unit_runner/commentrunner.rb +0 -62
  145. data/forge/unit_runner/cunit.rb +0 -17
  146. data/forge/unit_runner/forkedrunner.rb +0 -91
  147. data/forge/unit_runner/sample.rb +0 -16
  148. data/lib/reap/bin/reap.rb +0 -230
  149. data/lib/reap/bin/rubytest.rb +0 -53
  150. data/lib/reap/class/announce.rb +0 -220
  151. data/lib/reap/class/doap.rb +0 -80
  152. data/lib/reap/class/extest.rb +0 -146
  153. data/lib/reap/class/filer.rb +0 -62
  154. data/lib/reap/class/manifest.rb +0 -68
  155. data/lib/reap/class/package.rb +0 -576
  156. data/lib/reap/class/publish.rb +0 -152
  157. data/lib/reap/class/rdoc.rb +0 -123
  158. data/lib/reap/class/test.rb +0 -264
  159. data/lib/reap/projectinfo.rb +0 -208
  160. data/lib/reap/rake.rb +0 -42
  161. data/lib/reap/reap.rb +0 -89
  162. data/lib/reap/tasks.rb +0 -756
  163. data/lib/reap/taskutils.rb +0 -122
  164. data/note/LATEST +0 -44
  165. data/note/doap.xml +0 -28
  166. data/note/history/Rakefile-0.1 +0 -308
  167. data/sample/ProjectInfo +0 -96
  168. data/sample/Rakefile +0 -9
  169. data/sample/Reapfile +0 -11
  170. data/sample/task/demo.rb +0 -15
  171. data/setup.rb +0 -1568
  172. data/web/ProjectInfo.html +0 -75
  173. data/web/images/grape.jpg +0 -0
  174. data/web/index.html +0 -312
@@ -0,0 +1,737 @@
1
+ require 'enumerator'
2
+ require 'fileutils'
3
+ require 'open-uri'
4
+ require 'openssl'
5
+ require 'ostruct'
6
+ require 'httpclient'
7
+ require 'tmpdir'
8
+
9
+ require 'facets/hash/rekey'
10
+ require 'facets/kernel/ask'
11
+
12
+ #require 'reap/utilities/uploadutils'
13
+
14
+ # def self.factory(name)
15
+ # ["proutils/icli/#{name.downcase}.rb"].each{ |x| require x } # only did it this way to shut rdoc up!
16
+ # ICli::const_get(name.capitalize)
17
+ # end
18
+
19
+ module Reap
20
+
21
+ # Interface with the RubyForge hosting service.
22
+ # Currently supports functions:
23
+ #
24
+ # * release - Upload release packages.
25
+ # * publish - Upload website files.
26
+ # * announce - Post news announcement.
27
+ # * touch - Test connection.
28
+
29
+ class Rubyforge
30
+
31
+ include FileUtils
32
+
33
+ #HOME = ENV["HOME"] || ENV["HOMEPATH"] || File.expand_path("~")
34
+
35
+ COOKIEJAR = File::join(Dir.tmpdir, 'reap', 'cookie.dat')
36
+
37
+ REPORT = /<h\d><span style="color:red">(.*?)<\/span><\/h\d>/
38
+
39
+ # URI = http:// + domain name
40
+ # TODO Deal with https, and possible other protocols too.
41
+ attr :uri
42
+
43
+ # Many sites will require logging in so these are available by
44
+ # for use even if they arn't used.
45
+ attr :username
46
+ attr :password
47
+
48
+ # Domain name of host. Must be overriden by adapter.
49
+ def domain
50
+ raise "Missing Domain"
51
+ end
52
+
53
+ # New RubyForge tasks.
54
+ def initialize(options)
55
+ options = options.dup.rekey
56
+
57
+ @dryrun = options[:dryrun]
58
+ @trace = options[:trace]
59
+
60
+ #@domain = options[:domain] || default_domain
61
+ @uri = URI.parse("http://" + domain)
62
+
63
+ @username = options[:username] || ENV['RUBYFORGE_USERNAME']
64
+ @password = options[:password]
65
+
66
+ mkdir_p(File.dirname(COOKIEJAR))
67
+ @cookie_jar = COOKIEJAR
68
+
69
+ @project = options[:project]
70
+ @group_id = options[:group_id] || options[:groupid]
71
+
72
+ @package_ids = {}
73
+ @release_ids = {}
74
+ @file_ids = {}
75
+
76
+ load_project
77
+ end
78
+
79
+ def dryrun?
80
+ @dryrun
81
+ end
82
+
83
+ def trace?
84
+ @trace
85
+ end
86
+
87
+ public
88
+
89
+ #
90
+ def domain
91
+ "rubyforge.org"
92
+ end
93
+
94
+ # Website location on server.
95
+ def siteroot
96
+ "/var/www/gforge-projects"
97
+ end
98
+
99
+ # What commands does this host support.
100
+
101
+ def commands
102
+ %w{ touch release publish post }
103
+ end
104
+
105
+ # Project name.
106
+ attr_accessor :project
107
+
108
+ # Project's group id number.
109
+ attr_accessor :group_id
110
+
111
+ # Username to use for project account.
112
+ attr_accessor :username
113
+
114
+ # Login to website.
115
+
116
+ def login # :yield:
117
+ page = @uri + "/account/login.php"
118
+ page.scheme = 'https'
119
+ page = URI.parse(page.to_s) # set SSL port correctly
120
+
121
+ form = {
122
+ "return_to" => "",
123
+ "form_loginname" => username,
124
+ "form_pw" => password,
125
+ "login" => "Login with SSL"
126
+ }
127
+ html = http_post(page, form)
128
+
129
+ unless html[/Personal Page/]
130
+ puts "Login failed."
131
+ re1 = Regexp.escape(%{<h2 style="color:red">})
132
+ re2 = Regexp.escape(%{</h2>})
133
+ html[/#{re1}(.*?)#{re2}/]
134
+ raise $1
135
+ end
136
+
137
+ if block_given?
138
+ begin
139
+ yield
140
+ ensure
141
+ logout
142
+ end
143
+ end
144
+ end
145
+
146
+ # Logout of website.
147
+
148
+ def logout
149
+ page = "/account/logout.php"
150
+ form = {}
151
+ http_post(page, form)
152
+ end
153
+
154
+ # Touch base with server -- login and logout.
155
+
156
+ def touch(options={})
157
+ login
158
+ puts "Group ID: #{group_id}"
159
+ puts "Login/Logout successful."
160
+ logout
161
+ end
162
+
163
+ # Upload release packages to hosting service.
164
+ #
165
+ # This task releases files to RubyForge --it should work with other
166
+ # GForge instaces or SourceForge clones too.
167
+ #
168
+ # While defaults are nice, you may want a little more control. You can
169
+ # specify additional attributes:
170
+ #
171
+ # files package files to release.
172
+ # exclude Package formats to exclude from files.
173
+ # (from those created by pack)
174
+ # project Project name on host.
175
+ # package Package to which this release belongs (defaults to project)
176
+ # release Release name (default is version number)
177
+ # version Version of release
178
+ # date Date of release (defaults to Time.now)
179
+ # processor Processor/Architecture (any, i386, PPC, etc.)
180
+ # is_public Public release? (defualts to true)
181
+ # changelog Change log file
182
+ # notelog Release notes file
183
+ #
184
+ # The release option can be a template by using %s in the
185
+ # string. The version number of your project will be sub'd
186
+ # in for the %s. This saves you from having to update
187
+ # the release name before every release.
188
+ #
189
+ #--
190
+ # What about releasing a pacman PKGBUILD?
191
+ #++
192
+
193
+ def release(options)
194
+ options = options.rekey
195
+
196
+ version = options[:version]
197
+ changelog = options[:changelog]
198
+ notelog = options[:notelog]
199
+
200
+ project = options[:project] || @project
201
+ package = options[:package] || project
202
+ release = options[:release] || version
203
+ name = options[:name] || package
204
+ files = options[:file] || []
205
+ date = options[:date] || Time::now.strftime('%Y-%m-%d %H:%M')
206
+ processor = options[:processor] || 'Any'
207
+ store = options[:store] || 'pkg'
208
+
209
+ is_public = options[:is_public].nil? ? true : options[:is_public]
210
+
211
+ raise ArgumentError, "missing group_id" unless group_id
212
+ raise ArgumentError, "missing project" unless project
213
+ raise ArgumentError, "missing package" unless package
214
+ raise ArgumentError, "missing release" unless release
215
+
216
+ if files.empty?
217
+ files = Dir[File.join(store, '*')].select do |file|
218
+ /#{version}[.]/ =~ file
219
+ end
220
+ #files = Dir.glob(File.join(store,"#{name}-#{version}*"))
221
+ end
222
+
223
+ files = files.select{ |f| File.file?(f) }
224
+
225
+ abort "No package files." if files.empty?
226
+
227
+ files.each do |file|
228
+ abort "Not a file -- #{file}" unless File.exist?(file)
229
+ puts "Release file: #{file}"
230
+ end
231
+
232
+ # which package types
233
+ #rtypes = [ 'tgz', 'tbz', 'tar.gz', 'tar.bz2', 'deb', 'gem', 'ebuild', 'zip' ]
234
+ #rtypes -= exclude
235
+ #rtypes = rtypes.collect{ |rt| Regexp.escape( rt ) }
236
+ #re_rtypes = Regexp.new('[.](' << rtypes.join('|') << ')$')
237
+
238
+ puts "Releasing #{package} #{release}..." #unless options['quiet']
239
+
240
+ login do
241
+
242
+ unless package_id = package?(package)
243
+ #unless options['force']
244
+ q = "Package '#{package}' does not exist. Create?"
245
+ a = ask(q, 'yN')
246
+ abort "Task canceled." unless ['y', 'yes', 'okay'].include?(a.downcase)
247
+ #end
248
+ puts "Creating package #{package}..."
249
+ abort "Cannot continue in dry-run mode." if dryrun?
250
+ create_package(package, is_public)
251
+ unless package_id = package?(package)
252
+ raise "Package creation failed."
253
+ end
254
+ end
255
+ if release_id = release?(release, package_id)
256
+ #unless options[:force]
257
+ q = "Release #{release} already exists. Re-release?"
258
+ a = ask(q, 'yN')
259
+ abort "Task canceled." unless ['y', 'yes', 'okay'].include?(a.downcase)
260
+ #puts "Use -f option to force re-release."
261
+ #return
262
+ #end
263
+ files.each do |file|
264
+ fname = File.basename(file)
265
+ if file_id = file?(fname, package)
266
+ puts "Removing file #{fname}..."
267
+ remove_file(file_id, release_id, package_id) unless dryrun?
268
+ end
269
+ puts "Adding file #{fname}..."
270
+ add_file(file, release_id, package_id, processor) unless dryrun?
271
+ end
272
+ else
273
+ puts "Adding release #{release}..."
274
+ unless dryrun?
275
+ add_release(release, package_id, files,
276
+ :processor => processor,
277
+ :release_date => date,
278
+ :release_changes => changelog,
279
+ :release_notes => notelog,
280
+ :preformatted => '1'
281
+ )
282
+ unless release_id = release?(release, package_id)
283
+ raise "Release creation failed."
284
+ end
285
+ end
286
+ #files.each do |file|
287
+ # puts "Added file #{File.basename(file)}."
288
+ #end
289
+ end
290
+ end
291
+ puts "Release complete!"
292
+ end
293
+
294
+ # #
295
+ # # Publish documents to website.
296
+ # #
297
+ # # TODO Fix publish method for Rubyforge tool.
298
+ #
299
+ # def publish(options)
300
+ # options = options.rekey
301
+ #
302
+ # #domain = options[:domain] || DOMAIN
303
+ # root = File.join(siteroot, project)
304
+ # root = File.join(root, options[:root]) if options[:root]
305
+ #
306
+ # options.update(
307
+ # :host => domain,
308
+ # :root => root
309
+ # )
310
+ #
311
+ # UploadUtils.rsync(options)
312
+ # end
313
+
314
+ # Submit a news item.
315
+
316
+ def post(options)
317
+ options = options.rekey
318
+
319
+ if file = options[:file]
320
+ text = File.read(file).strip
321
+ i = text.index("\n")
322
+ subject = text[0...i].strip
323
+ message = text[i..-1].strip
324
+ else
325
+ subject = options[:subject]
326
+ message = options[:message] || options[:body]
327
+ end
328
+
329
+ if dryrun?
330
+ puts "\nSUBJECT: #{subject}"
331
+ puts "\n#{message}\n\n"
332
+ else
333
+ post_news(subject, message)
334
+ puts "News item posted!"
335
+ end
336
+ end
337
+
338
+
339
+ private
340
+
341
+ # HTTP POST transaction.
342
+
343
+ def http_post(page, form, extheader={})
344
+ client = HTTPClient::new ENV["HTTP_PROXY"]
345
+ client.debug_dev = STDERR if ENV["ICLI_DEBUG"] || ENV["DEBUG"] || $DEBUG
346
+ client.set_cookie_store(@cookie_jar)
347
+ client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
348
+
349
+ # HACK to fix http-client redirect bug/feature
350
+ client.redirect_uri_callback = lambda do |uri, res|
351
+ page = res.header['location'].first
352
+ page =~ %r/http/ ? page : @uri + page
353
+ end
354
+
355
+ uri = @uri + page
356
+ if $DEBUG then
357
+ puts "POST #{uri.inspect}"
358
+ puts "#{form.inspect}"
359
+ puts "#{extheader.inspect}" unless extheader.empty?
360
+ puts
361
+ end
362
+
363
+ response = client.post_content uri, form, extheader
364
+
365
+ if response[REPORT]
366
+ puts "(" + $1 + ")"
367
+ end
368
+
369
+ client.save_cookie_store
370
+
371
+ return response
372
+ end
373
+
374
+ # Loads information for project: group_id, package_ids and release_ids.
375
+
376
+ def load_project
377
+ puts "Project: #{project}"
378
+
379
+ html = URI.parse("http://#{domain}/projects/#{project}/index.html").read
380
+
381
+ group_id = html[/(frs|tracker)\/\?group_id=\d+/][/\d+/].to_i
382
+ @group_id = group_id
383
+
384
+ if $DEBUG
385
+ puts "GROUP_ID = #{group_id}"
386
+ end
387
+
388
+ html = URI.parse("http://rubyforge.org/frs/?group_id=#{group_id}").read
389
+
390
+ package = nil
391
+ html.scan(/<h3>[^<]+|release_id=\d+">[^>]+|filemodule_id=\d+/).each do |s|
392
+ case s
393
+ when /<h3>([^<]+)/ then
394
+ package = $1.strip
395
+ when /filemodule_id=(\d+)/ then
396
+ @package_ids[package] = $1.to_i
397
+ when /release_id=(\d+)">([^<]+)/ then
398
+ package_id = @package_ids[package]
399
+ @release_ids[[package_id,$2]] = $1.to_i
400
+ end
401
+ end
402
+
403
+ if $DEBUG
404
+ p @package_ids, @release_ids
405
+ end
406
+ end
407
+
408
+ # Returns password. If not already set, will ask for it.
409
+
410
+ def password
411
+ @password ||= ENV['RUBYFORGE_PASSWORD']
412
+ @password ||= (
413
+ print "Password for #{username}: "
414
+ until inp = $stdin.gets ; sleep 1 ; end ; puts
415
+ inp.strip
416
+ )
417
+ end
418
+
419
+ # Package exists? Returns package-id number.
420
+
421
+ def package?(package_name)
422
+ id = @package_ids[package_name]
423
+ return id if id
424
+
425
+ package_id = nil
426
+
427
+ page = "/frs/"
428
+
429
+ form = {
430
+ "group_id" => group_id
431
+ }
432
+ scrape = http_post(page, form)
433
+
434
+ restr = ''
435
+ restr << Regexp.escape( package_name )
436
+ restr << '\s*'
437
+ restr << Regexp.escape( %{<a href="/frs/monitor.php?filemodule_id=} )
438
+ restr << '(\d+)'
439
+ restr << Regexp.escape( %{&group_id=#{group_id}} )
440
+ re = Regexp.new( restr )
441
+
442
+ md = re.match( scrape )
443
+ if md
444
+ package_id = md[1]
445
+ end
446
+
447
+ @package_ids[package_name] = package_id
448
+ end
449
+
450
+ # Create a new package.
451
+
452
+ def create_package( package_name, is_public=true )
453
+ page = "/frs/admin/index.php"
454
+
455
+ form = {
456
+ "func" => "add_package",
457
+ "group_id" => group_id,
458
+ "package_name" => package_name,
459
+ "is_public" => (is_public ? 1 : 0),
460
+ "submit" => "Create This Package"
461
+ }
462
+
463
+ http_post(page, form)
464
+ end
465
+
466
+ # Delete package.
467
+
468
+ def delete_package(package_id)
469
+ page = "/frs/admin/index.php"
470
+
471
+ form = {
472
+ "func" => "delete_package",
473
+ "group_id" => group_id,
474
+ "package_id" => package_id,
475
+ "sure" => "1",
476
+ "really_sure" => "1",
477
+ "submit" => "Delete",
478
+ }
479
+
480
+ http_post(page, form)
481
+ end
482
+
483
+ # Release exits? Returns release-id number.
484
+
485
+ def release?(release_name, package_id)
486
+ id = @release_ids[[release_name,package_id]]
487
+ return id if id
488
+
489
+ release_id = nil
490
+
491
+ page = "/frs/admin/showreleases.php"
492
+
493
+ form = {
494
+ "package_id" => package_id,
495
+ "group_id" => group_id
496
+ }
497
+ scrape = http_post( page, form )
498
+
499
+ restr = ''
500
+ restr << Regexp.escape( %{"editrelease.php?group_id=#{group_id}} )
501
+ restr << Regexp.escape( %{&amp;package_id=#{package_id}} )
502
+ restr << Regexp.escape( %{&amp;release_id=} )
503
+ restr << '(\d+)'
504
+ restr << Regexp.escape( %{">#{release_name}} )
505
+ re = Regexp.new( restr )
506
+
507
+ md = re.match( scrape )
508
+ if md
509
+ release_id = md[1]
510
+ end
511
+
512
+ @release_ids[[release_name,package_id]] = release_id
513
+ end
514
+
515
+ # Add a new release.
516
+
517
+ def add_release(release_name, package_id, *files)
518
+ page = "/frs/admin/qrs.php"
519
+
520
+ options = (Hash===files.last ? files.pop : {}).rekey
521
+ files = files.flatten
522
+
523
+ processor = options[:processor]
524
+ release_date = options[:release_date]
525
+ release_changes = options[:release_changes]
526
+ release_notes = options[:release_notes]
527
+
528
+ release_date ||= Time::now.strftime("%Y-%m-%d %H:%M")
529
+
530
+ file = files.shift
531
+ puts "Adding file #{File.basename(file)}..."
532
+ userfile = open(file, 'rb')
533
+
534
+ type_id = userfile.path[%r|\.[^\./]+$|]
535
+ type_id = FILETYPES[type_id]
536
+ processor_id = PROCESSORS[processor.downcase]
537
+
538
+ # TODO IS THIS WORKING?
539
+ release_notes = IO::read(release_notes) if release_notes and test(?f, release_notes)
540
+ release_changes = IO::read(release_changes) if release_changes and test(?f, release_changes)
541
+
542
+ preformatted = '1'
543
+
544
+ form = {
545
+ "group_id" => group_id,
546
+ "package_id" => package_id,
547
+ "release_name" => release_name,
548
+ "release_date" => release_date,
549
+ "type_id" => type_id,
550
+ "processor_id" => processor_id,
551
+ "release_notes" => release_notes,
552
+ "release_changes" => release_changes,
553
+ "preformatted" => preformatted,
554
+ "userfile" => userfile,
555
+ "submit" => "Release File"
556
+ }
557
+
558
+ boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
559
+ boundary = "multipart/form-data; boundary=___#{ boundary }___"
560
+
561
+ html = http_post(page, form, 'content-type' => boundary)
562
+
563
+ release_id = html[/release_id=\d+/][/\d+/].to_i
564
+ puts "RELEASE ID = #{release_id}" if $DEBUG
565
+
566
+ files.each do |file|
567
+ puts "Adding file #{File.basename(file)}..."
568
+ add_file(file, release_id, package_id, processor)
569
+ end
570
+
571
+ release_id
572
+ end
573
+
574
+ # File exists?
575
+ #
576
+ # NOTE this is a bit fragile. If two releases have the same exact
577
+ # file name in them there could be a problem --that's probably not
578
+ # likely, but I can't yet rule it out.
579
+ #
580
+ # TODO Remove package argument, it is no longer needed.
581
+
582
+ def file?(file, package)
583
+ id = @file_ids[[file, package]]
584
+ return id if id
585
+
586
+ file_id = nil
587
+
588
+ page = "/frs/"
589
+
590
+ form = {
591
+ "group_id" => group_id
592
+ }
593
+ scrape = http_post(page, form)
594
+
595
+ restr = ''
596
+ #restr << Regexp.escape( package )
597
+ #restr << '\s*'
598
+ restr << Regexp.escape( %{<a href="/frs/download.php/} )
599
+ restr << '(\d+)'
600
+ restr << Regexp.escape( %{/#{file}} )
601
+ re = Regexp.new(restr)
602
+
603
+ md = re.match(scrape)
604
+ if md
605
+ file_id = md[1]
606
+ end
607
+
608
+ @file_ids[[file, package]] = file_id
609
+ end
610
+
611
+ # Remove file from release.
612
+
613
+ def remove_file(file_id, release_id, package_id)
614
+ page="/frs/admin/editrelease.php"
615
+
616
+ form = {
617
+ "group_id" => group_id,
618
+ "package_id" => package_id,
619
+ "release_id" => release_id,
620
+ "file_id" => file_id,
621
+ "step3" => "Delete File",
622
+ "im_sure" => '1',
623
+ "submit" => "Delete File "
624
+ }
625
+
626
+ http_post(page, form)
627
+ end
628
+
629
+ #
630
+ # Add file to release.
631
+ #
632
+
633
+ def add_file(file, release_id, package_id, processor=nil)
634
+ page = '/frs/admin/editrelease.php'
635
+
636
+ userfile = open file, 'rb'
637
+
638
+ type_id = userfile.path[%r|\.[^\./]+$|]
639
+ type_id = FILETYPES[type_id]
640
+ processor_id = PROCESSORS[processor.downcase]
641
+
642
+ form = {
643
+ "step2" => '1',
644
+ "group_id" => group_id,
645
+ "package_id" => package_id,
646
+ "release_id" => release_id,
647
+ "userfile" => userfile,
648
+ "type_id" => type_id,
649
+ "processor_id" => processor_id,
650
+ "submit" => "Add This File"
651
+ }
652
+
653
+ boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
654
+ boundary = "multipart/form-data; boundary=___#{ boundary }___"
655
+
656
+ http_post(page, form, 'content-type' => boundary)
657
+ end
658
+
659
+ # Posts news item to +group_id+ (can be name) with +subject+ and +body+
660
+
661
+ def post_news(subject, body)
662
+ page = "/news/submit.php"
663
+
664
+ form = {
665
+ "group_id" => group_id,
666
+ "post_changes" => "y",
667
+ "summary" => subject,
668
+ "details" => body,
669
+ "submit" => "Submit"
670
+ }
671
+
672
+ http_post(page, form)
673
+ end
674
+
675
+ # Constant for file types accepted by Rubyforge
676
+
677
+ FILETYPES = {
678
+ ".deb" => 1000,
679
+ ".rpm" => 2000,
680
+ ".zip" => 3000,
681
+ ".bz2" => 3100,
682
+ ".gz" => 3110,
683
+ ".src.zip" => 5000,
684
+ ".src.bz2" => 5010,
685
+ ".src.tar.bz2" => 5010,
686
+ ".src.gz" => 5020,
687
+ ".src.tar.gz" => 5020,
688
+ ".src.rpm" => 5100,
689
+ ".src" => 5900,
690
+ ".jpg" => 8000,
691
+ ".txt" => 8100,
692
+ ".text" => 8100,
693
+ ".htm" => 8200,
694
+ ".html" => 8200,
695
+ ".pdf" => 8300,
696
+ ".oth" => 9999,
697
+ ".ebuild" => 1300,
698
+ ".exe" => 1100,
699
+ ".dmg" => 1200,
700
+ ".tar.gz" => 3110,
701
+ ".tgz" => 3110,
702
+ ".gem" => 1400,
703
+ ".pgp" => 8150,
704
+ ".sig" => 8150
705
+ }
706
+
707
+ # Constant for processor types accepted by Rubyforge
708
+
709
+ PROCESSORS = {
710
+ "i386" => 1000,
711
+ "IA64" => 6000,
712
+ "Alpha" => 7000,
713
+ "Any" => 8000,
714
+ "PPC" => 2000,
715
+ "MIPS" => 3000,
716
+ "Sparc" => 4000,
717
+ "UltraSparc" => 5000,
718
+ "Other" => 9999,
719
+
720
+ "i386" => 1000,
721
+ "ia64" => 6000,
722
+ "alpha" => 7000,
723
+ "any" => 8000,
724
+ "ppc" => 2000,
725
+ "mips" => 3000,
726
+ "sparc" => 4000,
727
+ "ultrasparc" => 5000,
728
+ "other" => 9999,
729
+
730
+ "all" => 8000,
731
+ nil => 8000
732
+ }
733
+
734
+ end
735
+
736
+ end
737
+