reap 4.3.3 → 4.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/COPYING +400 -8
  2. data/ProjectInfo +26 -26
  3. data/ProjectInfo.rb +88 -0
  4. data/bin/reap +1 -1
  5. data/bin/rubytest +1 -1
  6. data/data/reap/scaffold/standard/COPYING +403 -0
  7. data/data/reap/scaffold/{ChangeLog → standard/ChangeLog} +0 -0
  8. data/data/reap/scaffold/standard/INSTALL +14 -0
  9. data/data/reap/scaffold/{ProjectInfo → standard/ProjectInfo} +12 -12
  10. data/data/reap/scaffold/standard/README +3 -0
  11. data/data/reap/scaffold/standard/Rakefile +10 -0
  12. data/data/reap/scaffold/{INSTALL → standard/TODO} +0 -0
  13. data/data/reap/scaffold/subversion/trunk/COPYING +403 -0
  14. data/data/reap/scaffold/{README → subversion/trunk/ChangeLog} +0 -0
  15. data/data/reap/scaffold/subversion/trunk/INSTALL +14 -0
  16. data/data/reap/scaffold/subversion/trunk/ProjectInfo +78 -0
  17. data/data/reap/scaffold/subversion/trunk/README +3 -0
  18. data/data/reap/scaffold/subversion/trunk/Rakefile +10 -0
  19. data/data/reap/scaffold/{Todo → subversion/trunk/TODO} +0 -0
  20. data/data/reap/{setup-3.4.1/setup.rb → setup.rb} +181 -202
  21. data/{ChangeLog → doc/ChangeLog} +0 -0
  22. data/doc/doap.xml +27 -0
  23. data/doc/note/Rakefile.htm +69 -0
  24. data/{note/Rakefile → doc/note/aRakefile} +0 -0
  25. data/{note → doc/note}/composite_task.rb +0 -0
  26. data/{note → doc/note}/compositepublisher.rb +0 -0
  27. data/{note → doc/note}/ftptools.rb +0 -0
  28. data/{note → doc/note}/interface/interface.rb +0 -0
  29. data/{note → doc/note}/interface/rubyforge.rb +0 -0
  30. data/{note → doc/note}/license-each.rb +0 -0
  31. data/{note → doc/note}/package.rb.0 +0 -0
  32. data/{note → doc/note}/publisher.rb +0 -0
  33. data/{note → doc/note}/rubyforgepublisher.rb +0 -0
  34. data/{lib/reap/task → doc/note}/scaffold.rb +4 -3
  35. data/{lib/reap → doc/note}/setup.rb +7 -6
  36. data/{note → doc/note}/sshpublisher.rb +0 -0
  37. data/{note → doc/note}/suby-cvs.rb +0 -0
  38. data/{note → doc/note}/template.rb +0 -0
  39. data/lib/reap/bin/reap.rb +75 -51
  40. data/lib/reap/bin/{lint.rb → rubylint.rb} +0 -0
  41. data/lib/reap/projectinfo.rb +107 -50
  42. data/lib/reap/reap.rb +60 -0
  43. data/lib/reap/task.rb +46 -60
  44. data/lib/reap/task/doap.rb +67 -0
  45. data/lib/reap/task/info.rb +2 -2
  46. data/lib/reap/task/install.rb +29 -18
  47. data/lib/reap/task/package.rb +56 -56
  48. data/lib/reap/task/release.rb +34 -13
  49. data/package.rb +627 -0
  50. data/setup.rb +287 -272
  51. data/test/tc_reap.rb +1 -1
  52. metadata +64 -61
  53. data/ANN +0 -8
  54. data/data/reap/scaffold/COPYING +0 -11
  55. data/data/reap/scaffold/Rakefile +0 -146
  56. data/data/reap/scaffold/setup.rb +0 -1551
  57. data/data/reap/setup-3.4.1/COPYING +0 -515
  58. data/data/reap/setup-3.4.1/ChangeLog +0 -732
  59. data/data/reap/setup-3.4.1/Makefile +0 -56
  60. data/data/reap/setup-3.4.1/NEWS.en +0 -155
  61. data/data/reap/setup-3.4.1/NEWS.ja +0 -152
  62. data/data/reap/setup-3.4.1/README.en +0 -30
  63. data/data/reap/setup-3.4.1/README.ja +0 -34
  64. data/data/reap/setup-3.4.1/TODO +0 -14
  65. data/data/reap/setup-3.4.1/Template.README.en +0 -41
  66. data/data/reap/setup-3.4.1/Template.README.ja +0 -46
  67. data/data/reap/setup-3.4.1/Usage_en.txt +0 -231
  68. data/data/reap/setup-3.4.1/Usage_ja.txt +0 -250
  69. data/data/reap/setup-3.4.1/doc.en/hookapi.html +0 -91
  70. data/data/reap/setup-3.4.1/doc.en/index.html +0 -28
  71. data/data/reap/setup-3.4.1/doc.en/metaconfapi.html +0 -79
  72. data/data/reap/setup-3.4.1/doc.en/news.html +0 -189
  73. data/data/reap/setup-3.4.1/doc.en/usage.html +0 -297
  74. data/data/reap/setup-3.4.1/doc.ja/hookapi.html +0 -84
  75. data/data/reap/setup-3.4.1/doc.ja/index.html +0 -28
  76. data/data/reap/setup-3.4.1/doc.ja/metaconfapi.html +0 -80
  77. data/data/reap/setup-3.4.1/doc.ja/news.html +0 -186
  78. data/data/reap/setup-3.4.1/doc.ja/usage.html +0 -319
  79. data/data/reap/setup-3.4.1/sample/add-task.rb +0 -15
  80. data/data/reap/setup-3.4.1/test/test_installer.rb +0 -136
@@ -158,7 +158,7 @@ class Reap::Release < Reap::Task
158
158
  files = Dir.entries(dir).select { |f|
159
159
  f =~ re_rtypes or f == 'PKGBUILD'
160
160
  }
161
- files = files.collect { |f| File.join( rel.dir, f ) }
161
+ files = files.collect { |f| File.join( dir, f ) }
162
162
 
163
163
  if files.empty?
164
164
  puts "No files to release at #{dir}."
@@ -166,31 +166,49 @@ class Reap::Release < Reap::Task
166
166
  end
167
167
 
168
168
  # ask for password
169
- print "Password for #{rel.username}: "
170
- until passwd = $stdin.gets.strip ; sleep 1 ; end
171
- @password = passwd
169
+ unless $PASSWORD
170
+ print "Password for #{rel.username}: "
171
+ until passwd = $stdin.gets.strip ; sleep 1 ; end
172
+ @password = passwd
173
+ else
174
+ @password = $PASSWORD
175
+ end
172
176
 
173
177
  login {
174
178
 
175
179
  unless package?
176
- exit 0
180
+ puts "Package (#{rel.package}) does not exist."
181
+ puts "Use -f option to force package creation."
182
+ exit 0 unless $FORCE
177
183
  create_package
184
+ puts "Created package -- #{rel.package}"
178
185
  end
179
186
 
180
187
  if release?
181
- exit 0
188
+ puts "Release (#{rel.release}) already exists."
189
+ puts "Use -f option to force re-release."
190
+ exit 0 unless $FORCE
182
191
  files.each do |f|
183
192
  remove_file( f ) if file?( f )
184
193
  add_file( f )
185
194
  end
186
195
  else
187
- exit 0
188
- add_release( files.unshift )
189
- files.each { |f| add_file( f ) }
196
+ add_release( files.first )
197
+ unless release?
198
+ puts "Release creation failed -- #{rel.release}"
199
+ exit -1
200
+ end
201
+ puts "Added release -- #{ rel.release }"
202
+ puts "Added file -- #{ files.first }"
203
+ files[1..-1].each do |f|
204
+ add_file( f )
205
+ puts "Added file -- #{ f }"
206
+ end
190
207
  end
191
208
 
192
209
  }
193
210
 
211
+ puts "Release complete!"
194
212
  end
195
213
 
196
214
  private
@@ -254,7 +272,7 @@ private
254
272
 
255
273
  # logout
256
274
  page = "/account/logout.php"
257
- method = "" #"post_content"
275
+ method = "post_content"
258
276
  form = {}
259
277
  http_transaction( page, method, form )
260
278
  end
@@ -337,14 +355,14 @@ private
337
355
  notes = rel.notes ? rel.notes : ( rel.notelog ? open(rel.notelog) : nil )
338
356
  changes = rel.changes ? rel.changes : ( rel.changelog ? open(rel.changelog) : nil )
339
357
 
340
- userfile = open(rel.userfile)
358
+ userfile = open(userfile)
341
359
 
342
360
  preformatted = '1'
343
361
 
344
362
  form = {
345
363
  "group_id" => rel.groupid,
346
364
  "package_id" => rel.packageid,
347
- "release_name" => rel.name,
365
+ "release_name" => rel.release,
348
366
  "release_date" => rel.date,
349
367
  "type_id" => type_id,
350
368
  "processor_id" => proc_id,
@@ -429,7 +447,10 @@ private
429
447
  "submit" => "Add This File"
430
448
  }
431
449
 
432
- http_transaction( page, method, form ) #, extheader )
450
+ boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
451
+ extheader = { 'content-type'=>"multipart/form-data; boundary=___#{ boundary }___" }
452
+
453
+ http_transaction( page, method, form, extheader )
433
454
  end
434
455
 
435
456
  # http transaction
data/package.rb ADDED
@@ -0,0 +1,627 @@
1
+ require 'rbconfig'
2
+ require 'fileutils'
3
+ require 'pp'
4
+ require 'optparse'
5
+ require 'yaml'
6
+
7
+ module Package
8
+
9
+ class SpecificationError < StandardError; end
10
+ # forward declaration of the specification classes so we can keep all
11
+ # constants here
12
+ class PackageSpecification_1_0; end
13
+ # Default semantics
14
+ PackageSpecification = PackageSpecification_1_0
15
+
16
+ #TODO: could get this collected automatically with Class#inherited etc
17
+ SEMANTICS = { "1.0" => PackageSpecification_1_0 }
18
+
19
+ KINDS = [
20
+ :bin, :lib, :ext, :data, :conf, :doc
21
+ ]
22
+
23
+ #{{{ list of files to be ignored stolen from setup.rb
24
+ mapping = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' }
25
+ ignore_files = %w[core RCSLOG tags TAGS .make.state .nse_depinfo
26
+ #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$
27
+ *.org *.in .* ]
28
+ #end of robbery
29
+ IGNORE_FILES = ignore_files.map do |x|
30
+ Regexp.new('\A' + x.gsub(/[\.\$\#\*]/){|c| mapping[c]} + '\z')
31
+ end
32
+
33
+ def self.config(name)
34
+ # XXX use pathname
35
+ prefix = Regexp.quote(Config::CONFIG["prefix"])
36
+ exec_prefix = Regexp.quote(Config::CONFIG["exec_prefix"])
37
+ Config::CONFIG[name].gsub(/\A\/?(#{prefix}|#{exec_prefix})\/?/, '')
38
+ end
39
+
40
+ SITE_DIRS = {
41
+ :bin => config("bindir"),
42
+ :lib => config("sitelibdir"),
43
+ :ext => config("sitearchdir"),
44
+ :data => config("datadir"),
45
+ :conf => config("sysconfdir"),
46
+ :doc => File.join(config("datadir"), "doc"),
47
+ }
48
+
49
+ VENDOR_DIRS = {
50
+ :bin => config("bindir"),
51
+ :lib => config("rubylibdir"),
52
+ :ext => config("archdir"),
53
+ :data => config("datadir"),
54
+ :conf => config("sysconfdir"),
55
+ :doc => File.join(config("datadir"), "doc"),
56
+ }
57
+
58
+ MODES = {
59
+ :bin => 0755,
60
+ :lib => 0644,
61
+ :ext => 0755, # was: 0555,
62
+ :data => 0644,
63
+ :conf => 0644,
64
+ :doc => 0644,
65
+ }
66
+
67
+
68
+ SETUP_OPTIONS = {:parse_cmdline => true, :load_conf => true, :run_tasks => true}
69
+
70
+ def self.setup(version, options = {}, &instructions)
71
+ prefixes = dirs = nil
72
+ options = SETUP_OPTIONS.dup.update(options)
73
+
74
+ if options[:load_conf] && File.exist?("config.save")
75
+ config = YAML.load_file "config.save"
76
+ prefixes = config[:prefixes]
77
+ dirs = config[:dirs]
78
+ end
79
+
80
+ pkg = package_specification_with_semantics(version).new(prefixes, dirs)
81
+ pkg.parse_command_line if options[:parse_cmdline]
82
+ pkg.instance_eval(&instructions)
83
+
84
+ pkg.run_tasks if options[:run_tasks]
85
+
86
+ # pkg.install
87
+ pkg
88
+ end
89
+
90
+ def self.package_specification_with_semantics(version)
91
+ #XXX: implement the full x.y(.z)? semantics
92
+ r = SEMANTICS[version]
93
+ raise SpecificationError, "Unknown version #{version}." unless r
94
+ r
95
+ end
96
+
97
+
98
+ module Actions
99
+
100
+ class InstallFile
101
+
102
+ attr_reader :source, :destination, :mode
103
+
104
+ def initialize(source, destination, mode, options)
105
+ @source = source
106
+ @destination = destination
107
+ @mode = mode
108
+ @options = options
109
+ end
110
+
111
+ def install
112
+ FileUtils.install @source, File.join(@options.destdir, @destination),
113
+ {:verbose => @options.verbose,
114
+ :noop => @options.noop, :mode => @mode }
115
+ end
116
+
117
+ def hash
118
+ [@source.hash, @destination.hash].hash
119
+ end
120
+
121
+ def eql?(other)
122
+ self.class == other.class &&
123
+ @source == other.source &&
124
+ @destination == other.destination &&
125
+ @mode == other.mode
126
+ end
127
+
128
+ def <=>(other)
129
+ FULL_ORDER[self, other] || self.destination <=> other.destination
130
+ end
131
+ end
132
+
133
+ class MkDir
134
+
135
+ attr_reader :directory
136
+
137
+ def initialize(directory, options)
138
+ @directory = directory
139
+ @options = options
140
+ end
141
+
142
+ def install
143
+ FileUtils.mkdir_p File.join(@options.destdir, @directory),
144
+ {:verbose => @options.verbose,
145
+ :noop => @options.noop }
146
+ end
147
+
148
+ def <=>(other)
149
+ FULL_ORDER[self, other] || self.directory <=> other.directory
150
+ end
151
+ end
152
+
153
+ class FixShebang
154
+
155
+ attr_reader :destination
156
+
157
+ def initialize(destination, options)
158
+ @options = options
159
+ @destination = destination
160
+ end
161
+
162
+ def install
163
+ path = File.join(@options.destdir, @destination)
164
+ fix_shebang(path)
165
+ end
166
+
167
+ # taken from rpa-base, originally based on setup.rb's
168
+ # modify: #!/usr/bin/ruby
169
+ # modify: #! /usr/bin/ruby
170
+ # modify: #!ruby
171
+ # not modify: #!/usr/bin/env ruby
172
+ SHEBANG_RE = /\A\#!\s*\S*ruby\S*/
173
+
174
+ #TODO allow the ruby-prog to be placed in the shebang line to be passed as
175
+ # an option
176
+ def fix_shebang(path)
177
+ tmpfile = path + '.tmp'
178
+ begin
179
+ #XXX: needed at all?
180
+ # it seems that FileUtils doesn't expose its default output
181
+ # @fileutils_output = $stderr
182
+ # we might want to allow this to be redirected.
183
+ $stderr.puts "shebang:open #{tmpfile}" if @options.verbose
184
+ unless @options.noop
185
+ File.open(path) do |r|
186
+ File.open(tmpfile, 'w', 0755) do |w|
187
+ first = r.gets
188
+ return unless SHEBANG_RE =~ first
189
+ w.print first.sub(SHEBANG_RE, '#!' + Config::CONFIG['ruby-prog'])
190
+ w.write r.read
191
+ end
192
+ end
193
+ end
194
+ FileUtils.mv(tmpfile, path, :verbose => @options.verbose,
195
+ :noop => @options.noop)
196
+ ensure
197
+ FileUtils.rm_f(tmpfile, :verbose => @options.verbose,
198
+ :noop => @options.noop)
199
+ end
200
+ end
201
+
202
+ def <=>(other)
203
+ FULL_ORDER[self, other] || self.destination <=> other.destination
204
+ end
205
+
206
+ def hash
207
+ @destination.hash
208
+ end
209
+
210
+ def eql?(other)
211
+ self.class == other.class && self.destination == other.destination
212
+ end
213
+ end
214
+
215
+ order = [MkDir, InstallFile, FixShebang]
216
+ FULL_ORDER = lambda do |me, other|
217
+ a, b = order.index(me.class), order.index(other.class)
218
+ if a && b
219
+ (r = a - b) == 0 ? nil : r
220
+ else
221
+ -1 # arbitrary
222
+ end
223
+ end
224
+
225
+ class ActionList < Array
226
+
227
+ def directories!(options)
228
+ dirnames = []
229
+ map! { |d|
230
+ if d.kind_of?(InstallFile) && !dirnames.include?(File.dirname(d.destination))
231
+ dirnames << File.dirname(d.destination)
232
+ [MkDir.new(File.dirname(d.destination), options), d]
233
+ else
234
+ d
235
+ end
236
+ }
237
+ flatten!
238
+ end
239
+
240
+ def run(task)
241
+ each { |action| action.__send__ task }
242
+ end
243
+ end
244
+
245
+ end # module Actions
246
+
247
+ Options = Struct.new(:noop, :verbose, :destdir)
248
+
249
+ class PackageSpecification_1_0
250
+
251
+ TASKS = %w[config setup install test show]
252
+ # default options for translate(foo => bar)
253
+ TRANSLATE_DEFAULT_OPTIONS = { :inherit => true }
254
+
255
+ def self.declare_file_type(args, &handle_arg)
256
+ str_arr_p = lambda{|x| Array === x && x.all?{|y| String === y}}
257
+
258
+ # strict type checking --- we don't want this to be extended arbitrarily
259
+ unless args.size == 1 && Hash === args.first &&
260
+ args.first.all?{|f,r| [Proc, String, NilClass].include?(r.class) &&
261
+ (String === f || str_arr_p[f])} or
262
+ args.all?{|x| String === x || str_arr_p[x]}
263
+ raise SpecificationError,
264
+ "Unspecified semantics for the given arguments: #{args.inspect}"
265
+ end
266
+
267
+ if args.size == 1 && Hash === args.first
268
+ args.first.to_a.each do |file, rename_info|
269
+ if Array === file
270
+ # ignoring boring files
271
+ handle_arg.call(file, true, rename_info)
272
+ else
273
+ # we do want "boring" files given explicitly
274
+ handle_arg.call([file], false, rename_info)
275
+ end
276
+ end
277
+ else
278
+ args.each do |a|
279
+ if Array === a
280
+ a.each{|file| handle_arg.call(file, true, nil)}
281
+ else
282
+ handle_arg.call(a, false, nil)
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ #{{{ define the file tagging methods
289
+ KINDS.each { |kind|
290
+ define_method(kind) { |*args| # if this were 1.9 we could also take a block
291
+ bin_callback = lambda do |kind_, type, dest, options|
292
+ next if kind_ != :bin || type == :dir
293
+ @actions << Actions::FixShebang.new(dest, options)
294
+ end
295
+ #TODO: refactor
296
+ self.class.declare_file_type(args) do |files, ignore_p, opt_rename_info|
297
+ files.each do |file|
298
+ next if ignore_p && IGNORE_FILES.any?{|re| re.match(file)}
299
+ add_file(kind, file, opt_rename_info, &bin_callback)
300
+ end
301
+ end
302
+ }
303
+ }
304
+
305
+ def unit_test(*files)
306
+ @unit_tests.concat files.flatten
307
+ end
308
+
309
+ attr_accessor :actions, :options
310
+
311
+ def self.metadata(name)
312
+ define_method(name) { |*args|
313
+ if args.size == 1
314
+ @metadata[name] = args.first
315
+ end
316
+ @metadata[name]
317
+ }
318
+ end
319
+
320
+ metadata :name
321
+ metadata :version
322
+ metadata :author
323
+
324
+
325
+ def translate_dir(kind, dir)
326
+ replaced_dir_parts = dir.split(%r{/})
327
+ kept_dir_parts = []
328
+ loop do
329
+ replaced_path = replaced_dir_parts.join("/")
330
+ target, options = @translate[kind][replaced_path]
331
+ options ||= TRANSLATE_DEFAULT_OPTIONS
332
+ if target && (replaced_path == dir || options[:inherit])
333
+ dir = (target != '' ? File.join(target, *kept_dir_parts) :
334
+ File.join(*kept_dir_parts))
335
+ break
336
+ end
337
+ break if replaced_dir_parts.empty?
338
+ kept_dir_parts.unshift replaced_dir_parts.pop
339
+ end
340
+ dir
341
+ end
342
+
343
+ def add_file(kind, filename, new_filename_info, &callback)
344
+ #TODO: refactor!!!
345
+ if File.directory? filename #XXX setup.rb and rpa-base defined File.dir?
346
+ # to cope with some win32 issue
347
+ dir = filename.sub(/\A\.\//, "").sub(/\/\z/, "")
348
+ dest = File.join(@prefixes[kind], @dirs[kind], translate_dir(kind, dir))
349
+ @actions << Actions::MkDir.new(dest, @options)
350
+ callback.call(kind, :dir, dest, @options) if block_given?
351
+ else
352
+ if new_filename_info
353
+ case new_filename_info
354
+ when Proc
355
+ dest_name = new_filename_info.call(filename.dup)
356
+ else
357
+ dest_name = new_filename_info.dup
358
+ end
359
+ else
360
+ dest_name = filename.dup
361
+ end
362
+
363
+ dirname = File.dirname(dest_name)
364
+ dirname = "" if dirname == "."
365
+ dest_name = File.join(translate_dir(kind, dirname), File.basename(dest_name))
366
+
367
+ dest = File.join(@prefixes[kind], @dirs[kind], dest_name)
368
+ @actions << Actions::InstallFile.new(filename, dest, MODES[kind], @options)
369
+ callback.call(kind, :file, dest, @options) if block_given?
370
+ end
371
+ end
372
+
373
+ def initialize(prefixes = nil, dirs = nil)
374
+ @prefix = Config::CONFIG["prefix"].gsub(/\A\//, '')
375
+ @translate = {}
376
+ @prefixes = (prefixes || {}).dup
377
+ KINDS.each { |kind|
378
+ @prefixes[kind] = @prefix unless prefixes
379
+ @translate[kind] = {}
380
+ }
381
+
382
+ @dirs = (dirs || {}).dup
383
+ @dirs.update SITE_DIRS unless dirs
384
+
385
+ @actions = Actions::ActionList.new
386
+
387
+ @metadata = {}
388
+ @unit_tests = []
389
+
390
+ @options = Options.new
391
+ @options.verbose = true
392
+ @options.noop = true # XXX for testing
393
+ @options.destdir = ''
394
+
395
+ @tasks = []
396
+ end
397
+
398
+ def aoki
399
+ (KINDS - [:ext]).each { |kind|
400
+ translate(kind, kind.to_s => "", :inherit => true)
401
+ __send__ kind, Dir["#{kind}/**/*"]
402
+ }
403
+ translate(:ext, "ext/*" => "", :inherit => true)
404
+ ext Dir["ext/**/*.#{Config::CONFIG['DLEXT']}"]
405
+ end
406
+
407
+ def install
408
+ puts "Installing #{name || "unknown package"} #{version}..." if options.verbose
409
+
410
+ actions.uniq!
411
+ actions.sort!
412
+ actions.directories!(options)
413
+
414
+ #pp self
415
+
416
+ actions.run :install
417
+ end
418
+
419
+ def test
420
+ unless @unit_tests.empty?
421
+ puts "Testing #{name || "unknown package"} #{version}..." if options.verbose
422
+ require 'test/unit'
423
+ unless options.noop
424
+ t = Test::Unit::AutoRunner.new(true)
425
+ t.process_args(@unit_tests)
426
+ t.run
427
+ end
428
+ end
429
+ end
430
+
431
+ def config
432
+ File.open("config.save", "w") { |f|
433
+ YAML.dump({:prefixes => @prefixes, :dirs => @dirs}, f)
434
+ }
435
+ end
436
+
437
+ def show
438
+ KINDS.each { |kind|
439
+ puts "#{kind}\t#{File.join(options.destdir, @prefixes[kind], @dirs[kind])}"
440
+ }
441
+ end
442
+
443
+ def translate(kind, additional_translations)
444
+ default_opts = TRANSLATE_DEFAULT_OPTIONS.dup
445
+ key_val_pairs = additional_translations.to_a
446
+ option_pairs = key_val_pairs.select{|(k,v)| Symbol === k}
447
+ default_opts.update(Hash[*option_pairs.flatten])
448
+
449
+ (key_val_pairs - option_pairs).each do |key, val|
450
+ add_translation(kind, key, val, default_opts)
451
+ end
452
+ end
453
+
454
+ def add_translation(kind, src, dest, options)
455
+ if is_glob?(src)
456
+ dirs = expand_dir_glob(src)
457
+ else
458
+ dirs = [src]
459
+ end
460
+ dirs.each do |dirname|
461
+ dirname = dirname.sub(%r{\A\./}, "").sub(%r{/\z}, "")
462
+ @translate[kind].update({dirname => [dest, options]})
463
+ end
464
+ end
465
+
466
+ def is_glob?(x)
467
+ /(^|[^\\])[*?{\[]/.match(x)
468
+ end
469
+
470
+ def expand_dir_glob(src)
471
+ Dir[src].select{|x| File.directory?(x)}
472
+ end
473
+
474
+ def clean_path(path)
475
+ path.gsub(/\A\//, '').gsub(/\/+\Z/, '').squeeze("/")
476
+ end
477
+
478
+ def parse_command_line
479
+ opts = OptionParser.new(nil, 24, ' ') { |opts|
480
+ opts.banner = "Usage: setup.rb [options] [task]"
481
+
482
+ opts.separator ""
483
+ opts.separator "Tasks:"
484
+ opts.separator " config configures paths"
485
+ opts.separator " show shows paths"
486
+ opts.separator " setup compiles ruby extentions and others XXX"
487
+ opts.separator " install installs files"
488
+ opts.separator " test runs unit tests"
489
+
490
+ opts.separator ""
491
+ opts.separator "Specific options:"
492
+
493
+ opts.on "--prefix=PREFIX",
494
+ "path prefix of target environment [#@prefix]" do |prefix|
495
+ @prefix.replace clean_path(prefix) # Shared!
496
+ end
497
+
498
+ opts.separator ""
499
+
500
+ KINDS.each { |kind|
501
+ opts.on "--#{kind}prefix=PREFIX",
502
+ "path prefix for #{kind} files [#{@prefixes[kind]}]" do |prefix|
503
+ @prefixes[kind] = clean_path(prefix)
504
+ end
505
+ }
506
+
507
+ opts.separator ""
508
+
509
+ KINDS.each { |kind|
510
+ opts.on "--#{kind}dir=PREFIX",
511
+ "directory for #{kind} files [#{@dirs[kind]}]" do |prefix|
512
+ @dirs[kind] = clean_path(prefix)
513
+ end
514
+ }
515
+
516
+ opts.separator ""
517
+
518
+ KINDS.each { |kind|
519
+ opts.on "--#{kind}=PREFIX",
520
+ "absolute directory for #{kind} files [#{File.join(@prefixes[kind], @dirs[kind])}]" do |prefix|
521
+ @prefixes[kind] = clean_path(prefix)
522
+ end
523
+ }
524
+
525
+ opts.separator ""
526
+ opts.separator "Predefined path configurations:"
527
+ opts.on "--site", "install into site-local directories (default)" do
528
+ @dirs.update SITE_DIRS
529
+ end
530
+
531
+ opts.on "--vendor", "install into distribution directories (for packagers)" do
532
+ @dirs.update VENDOR_DIRS
533
+ end
534
+
535
+ opts.separator ""
536
+ opts.separator "General options:"
537
+
538
+ opts.on "--destdir=DESTDIR",
539
+ "install all files relative to DESTDIR (/)" do |destdir|
540
+ @options.destdir = destdir
541
+ end
542
+
543
+ opts.on "--dry-run", "only display what to do if given [#{@options.noop}]" do
544
+ @options.noop = true
545
+ end
546
+
547
+ opts.on "--no-harm", "only display what to do if given" do
548
+ @options.noop = true
549
+ end
550
+
551
+ opts.on "--[no-]verbose", "output messages verbosely [#{@options.verbose}]" do |verbose|
552
+ @options.verbose = verbose
553
+ end
554
+
555
+ opts.on_tail("-h", "--help", "Show this message") do
556
+ puts opts
557
+ exit
558
+ end
559
+ }
560
+
561
+ opts.parse! ARGV
562
+
563
+ if (ARGV - TASKS).empty? # Only existing tasks?
564
+ @tasks = ARGV
565
+ @tasks = ["install"] if @tasks.empty?
566
+ else
567
+ abort "Unknown task(s) #{(ARGV-TASKS).join ", "}."
568
+ end
569
+ end
570
+
571
+ def run_tasks
572
+ @tasks.each { |task| __send__ task }
573
+ end
574
+ end
575
+
576
+ end # module Package
577
+
578
+ #XXX incomplete setup.rb support for the hooks
579
+ require 'rbconfig'
580
+ def config(x)
581
+ Config::CONFIG[x]
582
+ end
583
+
584
+
585
+ if $0 == __FILE__
586
+
587
+ Package.setup("1.0") {
588
+
589
+ translate :bin, 'bin' => ''
590
+ bin *Dir['bin/**/*']
591
+
592
+ translate :lib, 'lib' => ''
593
+ lib *Dir['lib/**/*']
594
+
595
+ translate :doc, 'doc' => ''
596
+ doc *Dir['doc/**/*']
597
+
598
+ translate :ext, 'ext' => ''
599
+ ext *Dir['ext/**/*']
600
+
601
+ translate :data, 'data' => ''
602
+ data *Dir['data/**/*']
603
+
604
+ translate :conf, 'conf' => ''
605
+ conf *Dir['conf/**/*']
606
+
607
+ #translate(:lib, '' => 'fuutils', 'blerg' => '', 'blorg' => 'borg')
608
+ #lib "feeble.rb", "fooble.rb", "fuuble.rb"
609
+ #lib "fooble.rb"
610
+ #lib "blerg/foo.rb", "blorg/foo.rb"
611
+ #lib "fruubar.rb" => "fuubar.rb"
612
+ #lib "friibar.rb" => lambda{|x| "fiibar.rb"}
613
+ #lib ["stuff.orig", "core", ".bla.rb.swp"] # will be ignored
614
+ #doc "bla.orig" # will not be ignored
615
+ #doc "foo.orig" => "bla.txt" # ditto
616
+ #lib ["lfoo1", "lbar1"]
617
+ #lib ["lfoo", "lbar"] => lambda{|x| "#{x}.rb"}
618
+ #translate(:data, '_darcs' => 'DARCS')
619
+ #data "_darcs/" # just to test MkDir generation
620
+
621
+ #pp self
622
+ }
623
+
624
+ end
625
+
626
+
627
+ # vim: sw=2 sts=2 et ts=8