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