RedCloth 3.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of RedCloth might be problematic. Click here for more details.

@@ -5,7 +5,9 @@ require 'yaml'
5
5
  Dir["tests/*.yml"].each do |testfile|
6
6
  YAML::load_documents( File.open( testfile ) ) do |doc|
7
7
  if doc['in'] and doc['out']
8
- red = RedCloth.new( doc['in'] )
8
+ opts = []
9
+ opts << :hard_breaks if testfile =~ /hard_breaks/
10
+ red = RedCloth.new( doc['in'], opts )
9
11
  html = if testfile =~ /markdown/
10
12
  red.to_html( :markdown )
11
13
  else
@@ -0,0 +1,1376 @@
1
+ #
2
+ # setup.rb
3
+ #
4
+ # Copyright (c) 2000-2004 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ #
10
+
11
+ unless Enumerable.method_defined?(:map) # Ruby 1.4.6
12
+ module Enumerable
13
+ alias map collect
14
+ end
15
+ end
16
+
17
+ unless File.respond_to?(:read) # Ruby 1.6
18
+ def File.read(fname)
19
+ open(fname) {|f|
20
+ return f.read
21
+ }
22
+ end
23
+ end
24
+
25
+ def File.binread(fname)
26
+ open(fname, 'rb') {|f|
27
+ return f.read
28
+ }
29
+ end
30
+
31
+ # for corrupted windows stat(2)
32
+ def File.dir?(path)
33
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
34
+ end
35
+
36
+
37
+ class SetupError < StandardError; end
38
+
39
+ def setup_rb_error(msg)
40
+ raise SetupError, msg
41
+ end
42
+
43
+ #
44
+ # Config
45
+ #
46
+
47
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
48
+ ARGV.delete(arg)
49
+ require arg.split(/=/, 2)[1]
50
+ $".push 'rbconfig.rb'
51
+ else
52
+ require 'rbconfig'
53
+ end
54
+
55
+ def multipackage_install?
56
+ FileTest.directory?(File.dirname($0) + '/packages')
57
+ end
58
+
59
+
60
+ class ConfigItem
61
+ def initialize(name, template, default, desc)
62
+ @name = name.freeze
63
+ @template = template
64
+ @value = default
65
+ @default = default.dup.freeze
66
+ @description = desc
67
+ end
68
+
69
+ attr_reader :name
70
+ attr_reader :description
71
+
72
+ attr_accessor :default
73
+ alias help_default default
74
+
75
+ def help_opt
76
+ "--#{@name}=#{@template}"
77
+ end
78
+
79
+ def value
80
+ @value
81
+ end
82
+
83
+ def eval(table)
84
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
85
+ end
86
+
87
+ def set(val)
88
+ @value = check(val)
89
+ end
90
+
91
+ private
92
+
93
+ def check(val)
94
+ setup_rb_error "config: --#{name} requires argument" unless val
95
+ val
96
+ end
97
+ end
98
+
99
+ class BoolItem < ConfigItem
100
+ def config_type
101
+ 'bool'
102
+ end
103
+
104
+ def help_opt
105
+ "--#{@name}"
106
+ end
107
+
108
+ private
109
+
110
+ def check(val)
111
+ return 'yes' unless val
112
+ unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
113
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
114
+ end
115
+ (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
116
+ end
117
+ end
118
+
119
+ class PathItem < ConfigItem
120
+ def config_type
121
+ 'path'
122
+ end
123
+
124
+ private
125
+
126
+ def check(path)
127
+ setup_rb_error "config: --#{@name} requires argument" unless path
128
+ path[0,1] == '$' ? path : File.expand_path(path)
129
+ end
130
+ end
131
+
132
+ class ProgramItem < ConfigItem
133
+ def config_type
134
+ 'program'
135
+ end
136
+ end
137
+
138
+ class SelectItem < ConfigItem
139
+ def initialize(name, template, default, desc)
140
+ super
141
+ @ok = template.split('/')
142
+ end
143
+
144
+ def config_type
145
+ 'select'
146
+ end
147
+
148
+ private
149
+
150
+ def check(val)
151
+ unless @ok.include?(val.strip)
152
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
153
+ end
154
+ val.strip
155
+ end
156
+ end
157
+
158
+ class PackageSelectionItem < ConfigItem
159
+ def initialize(name, template, default, help_default, desc)
160
+ super name, template, default, desc
161
+ @help_default = help_default
162
+ end
163
+
164
+ attr_reader :help_default
165
+
166
+ def config_type
167
+ 'package'
168
+ end
169
+
170
+ private
171
+
172
+ def check(val)
173
+ unless File.dir?("packages/#{val}")
174
+ setup_rb_error "config: no such package: #{val}"
175
+ end
176
+ val
177
+ end
178
+ end
179
+
180
+ class ConfigTable_class
181
+
182
+ def initialize(items)
183
+ @items = items
184
+ @table = {}
185
+ items.each do |i|
186
+ @table[i.name] = i
187
+ end
188
+ ALIASES.each do |ali, name|
189
+ @table[ali] = @table[name]
190
+ end
191
+ end
192
+
193
+ include Enumerable
194
+
195
+ def each(&block)
196
+ @items.each(&block)
197
+ end
198
+
199
+ def key?(name)
200
+ @table.key?(name)
201
+ end
202
+
203
+ def lookup(name)
204
+ @table[name] or raise ArgumentError, "no such config item: #{name}"
205
+ end
206
+
207
+ def add(item)
208
+ @items.push item
209
+ @table[item.name] = item
210
+ end
211
+
212
+ def remove(name)
213
+ item = lookup(name)
214
+ @items.delete_if {|i| i.name == name }
215
+ @table.delete_if {|name, i| i.name == name }
216
+ item
217
+ end
218
+
219
+ def new
220
+ dup()
221
+ end
222
+
223
+ def savefile
224
+ '.config'
225
+ end
226
+
227
+ def load
228
+ begin
229
+ t = dup()
230
+ File.foreach(savefile()) do |line|
231
+ k, v = *line.split(/=/, 2)
232
+ t[k] = v.strip
233
+ end
234
+ t
235
+ rescue Errno::ENOENT
236
+ setup_rb_error $!.message + "#{File.basename($0)} config first"
237
+ end
238
+ end
239
+
240
+ def save
241
+ @items.each {|i| i.value }
242
+ File.open(savefile(), 'w') {|f|
243
+ @items.each do |i|
244
+ f.printf "%s=%s\n", i.name, i.value if i.value
245
+ end
246
+ }
247
+ end
248
+
249
+ def [](key)
250
+ lookup(key).eval(self)
251
+ end
252
+
253
+ def []=(key, val)
254
+ lookup(key).set val
255
+ end
256
+
257
+ end
258
+
259
+ c = ::Config::CONFIG
260
+
261
+ rubypath = c['bindir'] + '/' + c['ruby_install_name']
262
+
263
+ major = c['MAJOR'].to_i
264
+ minor = c['MINOR'].to_i
265
+ teeny = c['TEENY'].to_i
266
+ version = "#{major}.#{minor}"
267
+
268
+ # ruby ver. >= 1.4.4?
269
+ newpath_p = ((major >= 2) or
270
+ ((major == 1) and
271
+ ((minor >= 5) or
272
+ ((minor == 4) and (teeny >= 4)))))
273
+
274
+ if c['rubylibdir']
275
+ # V < 1.6.3
276
+ _stdruby = c['rubylibdir']
277
+ _siteruby = c['sitedir']
278
+ _siterubyver = c['sitelibdir']
279
+ _siterubyverarch = c['sitearchdir']
280
+ elsif newpath_p
281
+ # 1.4.4 <= V <= 1.6.3
282
+ _stdruby = "$prefix/lib/ruby/#{version}"
283
+ _siteruby = c['sitedir']
284
+ _siterubyver = "$siteruby/#{version}"
285
+ _siterubyverarch = "$siterubyver/#{c['arch']}"
286
+ else
287
+ # V < 1.4.4
288
+ _stdruby = "$prefix/lib/ruby/#{version}"
289
+ _siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
290
+ _siterubyver = _siteruby
291
+ _siterubyverarch = "$siterubyver/#{c['arch']}"
292
+ end
293
+ libdir = '-* dummy libdir *-'
294
+ stdruby = '-* dummy rubylibdir *-'
295
+ siteruby = '-* dummy site_ruby *-'
296
+ siterubyver = '-* dummy site_ruby version *-'
297
+ parameterize = lambda {|path|
298
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
299
+ .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\
300
+ .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\
301
+ .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\
302
+ .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
303
+ }
304
+ libdir = parameterize.call(c['libdir'])
305
+ stdruby = parameterize.call(_stdruby)
306
+ siteruby = parameterize.call(_siteruby)
307
+ siterubyver = parameterize.call(_siterubyver)
308
+ siterubyverarch = parameterize.call(_siterubyverarch)
309
+
310
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
311
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
312
+ else
313
+ makeprog = 'make'
314
+ end
315
+
316
+ common_conf = [
317
+ PathItem.new('prefix', 'path', c['prefix'],
318
+ 'path prefix of target environment'),
319
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
320
+ 'the directory for commands'),
321
+ PathItem.new('libdir', 'path', libdir,
322
+ 'the directory for libraries'),
323
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
324
+ 'the directory for shared data'),
325
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
326
+ 'the directory for man pages'),
327
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
328
+ 'the directory for man pages'),
329
+ PathItem.new('stdruby', 'path', stdruby,
330
+ 'the directory for standard ruby libraries'),
331
+ PathItem.new('siteruby', 'path', siteruby,
332
+ 'the directory for version-independent aux ruby libraries'),
333
+ PathItem.new('siterubyver', 'path', siterubyver,
334
+ 'the directory for aux ruby libraries'),
335
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
336
+ 'the directory for aux ruby binaries'),
337
+ PathItem.new('rbdir', 'path', '$siterubyver',
338
+ 'the directory for ruby scripts'),
339
+ PathItem.new('sodir', 'path', '$siterubyverarch',
340
+ 'the directory for ruby extentions'),
341
+ PathItem.new('rubypath', 'path', rubypath,
342
+ 'the path to set to #! line'),
343
+ ProgramItem.new('rubyprog', 'name', rubypath,
344
+ 'the ruby program using for installation'),
345
+ ProgramItem.new('makeprog', 'name', makeprog,
346
+ 'the make program to compile ruby extentions'),
347
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
348
+ 'shebang line (#!) editing mode'),
349
+ BoolItem.new('without-ext', 'yes/no', 'no',
350
+ 'does not compile/install ruby extentions')
351
+ ]
352
+ class ConfigTable_class # open again
353
+ ALIASES = {
354
+ 'std-ruby' => 'stdruby',
355
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
356
+ 'site-ruby' => 'siterubyver', # For backward compatibility
357
+ 'bin-dir' => 'bindir',
358
+ 'bin-dir' => 'bindir',
359
+ 'rb-dir' => 'rbdir',
360
+ 'so-dir' => 'sodir',
361
+ 'data-dir' => 'datadir',
362
+ 'ruby-path' => 'rubypath',
363
+ 'ruby-prog' => 'rubyprog',
364
+ 'ruby' => 'rubyprog',
365
+ 'make-prog' => 'makeprog',
366
+ 'make' => 'makeprog'
367
+ }
368
+ end
369
+ multipackage_conf = [
370
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
371
+ 'package names that you want to install'),
372
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
373
+ 'package names that you do not want to install')
374
+ ]
375
+ if multipackage_install?
376
+ ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
377
+ else
378
+ ConfigTable = ConfigTable_class.new(common_conf)
379
+ end
380
+
381
+
382
+ module MetaConfigAPI
383
+
384
+ def eval_file_ifexist(fname)
385
+ instance_eval File.read(fname), fname, 1 if File.file?(fname)
386
+ end
387
+
388
+ def config_names
389
+ ConfigTable.map {|i| i.name }
390
+ end
391
+
392
+ def config?(name)
393
+ ConfigTable.key?(name)
394
+ end
395
+
396
+ def bool_config?(name)
397
+ ConfigTable.lookup(name).config_type == 'bool'
398
+ end
399
+
400
+ def path_config?(name)
401
+ ConfigTable.lookup(name).config_type == 'path'
402
+ end
403
+
404
+ def value_config?(name)
405
+ case ConfigTable.lookup(name).config_type
406
+ when 'bool', 'path'
407
+ true
408
+ else
409
+ false
410
+ end
411
+ end
412
+
413
+ def add_config(item)
414
+ ConfigTable.add item
415
+ end
416
+
417
+ def add_bool_config(name, default, desc)
418
+ ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
419
+ end
420
+
421
+ def add_path_config(name, default, desc)
422
+ ConfigTable.add PathItem.new(name, 'path', default, desc)
423
+ end
424
+
425
+ def set_config_default(name, default)
426
+ ConfigTable.lookup(name).default = default
427
+ end
428
+
429
+ def remove_config(name)
430
+ ConfigTable.remove(name)
431
+ end
432
+
433
+ end
434
+
435
+
436
+ #
437
+ # File Operations
438
+ #
439
+
440
+ module FileOperations
441
+
442
+ def mkdir_p(dirname, prefix = nil)
443
+ dirname = prefix + File.expand_path(dirname) if prefix
444
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
445
+ return if no_harm?
446
+
447
+ # does not check '/'... it's too abnormal case
448
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
449
+ if /\A[a-z]:\z/i =~ dirs[0]
450
+ disk = dirs.shift
451
+ dirs[0] = disk + dirs[0]
452
+ end
453
+ dirs.each_index do |idx|
454
+ path = dirs[0..idx].join('')
455
+ Dir.mkdir path unless File.dir?(path)
456
+ end
457
+ end
458
+
459
+ def rm_f(fname)
460
+ $stderr.puts "rm -f #{fname}" if verbose?
461
+ return if no_harm?
462
+
463
+ if File.exist?(fname) or File.symlink?(fname)
464
+ File.chmod 0777, fname
465
+ File.unlink fname
466
+ end
467
+ end
468
+
469
+ def rm_rf(dn)
470
+ $stderr.puts "rm -rf #{dn}" if verbose?
471
+ return if no_harm?
472
+
473
+ Dir.chdir dn
474
+ Dir.foreach('.') do |fn|
475
+ next if fn == '.'
476
+ next if fn == '..'
477
+ if File.dir?(fn)
478
+ verbose_off {
479
+ rm_rf fn
480
+ }
481
+ else
482
+ verbose_off {
483
+ rm_f fn
484
+ }
485
+ end
486
+ end
487
+ Dir.chdir '..'
488
+ Dir.rmdir dn
489
+ end
490
+
491
+ def move_file(src, dest)
492
+ File.unlink dest if File.exist?(dest)
493
+ begin
494
+ File.rename src, dest
495
+ rescue
496
+ File.open(dest, 'wb') {|f| f.write File.binread(src) }
497
+ File.chmod File.stat(src).mode, dest
498
+ File.unlink src
499
+ end
500
+ end
501
+
502
+ def install(from, dest, mode, prefix = nil)
503
+ $stderr.puts "install #{from} #{dest}" if verbose?
504
+ return if no_harm?
505
+
506
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
507
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
508
+ str = File.binread(from)
509
+ if diff?(str, realdest)
510
+ verbose_off {
511
+ rm_f realdest if File.exist?(realdest)
512
+ }
513
+ File.open(realdest, 'wb') {|f|
514
+ f.write str
515
+ }
516
+ File.chmod mode, realdest
517
+
518
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
519
+ if prefix
520
+ f.puts realdest.sub(prefix, '')
521
+ else
522
+ f.puts realdest
523
+ end
524
+ }
525
+ end
526
+ end
527
+
528
+ def diff?(new_content, path)
529
+ return true unless File.exist?(path)
530
+ new_content != File.binread(path)
531
+ end
532
+
533
+ def command(str)
534
+ $stderr.puts str if verbose?
535
+ system str or raise RuntimeError, "'system #{str}' failed"
536
+ end
537
+
538
+ def ruby(str)
539
+ command config('rubyprog') + ' ' + str
540
+ end
541
+
542
+ def make(task = '')
543
+ command config('makeprog') + ' ' + task
544
+ end
545
+
546
+ def extdir?(dir)
547
+ File.exist?(dir + '/MANIFEST')
548
+ end
549
+
550
+ def all_files_in(dirname)
551
+ Dir.open(dirname) {|d|
552
+ return d.select {|ent| File.file?("#{dirname}/#{ent}") }
553
+ }
554
+ end
555
+
556
+ REJECT_DIRS = %w(
557
+ CVS SCCS RCS CVS.adm .svn
558
+ )
559
+
560
+ def all_dirs_in(dirname)
561
+ Dir.open(dirname) {|d|
562
+ return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
563
+ }
564
+ end
565
+
566
+ end
567
+
568
+
569
+ #
570
+ # Main Installer
571
+ #
572
+
573
+ module HookUtils
574
+
575
+ def run_hook(name)
576
+ try_run_hook "#{curr_srcdir()}/#{name}" or
577
+ try_run_hook "#{curr_srcdir()}/#{name}.rb"
578
+ end
579
+
580
+ def try_run_hook(fname)
581
+ return false unless File.file?(fname)
582
+ begin
583
+ instance_eval File.read(fname), fname, 1
584
+ rescue
585
+ setup_rb_error "hook #{fname} failed:\n" + $!.message
586
+ end
587
+ true
588
+ end
589
+
590
+ end
591
+
592
+
593
+ module HookScriptAPI
594
+
595
+ def get_config(key)
596
+ @config[key]
597
+ end
598
+
599
+ alias config get_config
600
+
601
+ def set_config(key, val)
602
+ @config[key] = val
603
+ end
604
+
605
+ #
606
+ # srcdir/objdir (works only in the package directory)
607
+ #
608
+
609
+ #abstract srcdir_root
610
+ #abstract objdir_root
611
+ #abstract relpath
612
+
613
+ def curr_srcdir
614
+ "#{srcdir_root()}/#{relpath()}"
615
+ end
616
+
617
+ def curr_objdir
618
+ "#{objdir_root()}/#{relpath()}"
619
+ end
620
+
621
+ def srcfile(path)
622
+ "#{curr_srcdir()}/#{path}"
623
+ end
624
+
625
+ def srcexist?(path)
626
+ File.exist?(srcfile(path))
627
+ end
628
+
629
+ def srcdirectory?(path)
630
+ File.dir?(srcfile(path))
631
+ end
632
+
633
+ def srcfile?(path)
634
+ File.file? srcfile(path)
635
+ end
636
+
637
+ def srcentries(path = '.')
638
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
639
+ return d.to_a - %w(. ..)
640
+ }
641
+ end
642
+
643
+ def srcfiles(path = '.')
644
+ srcentries(path).select {|fname|
645
+ File.file?(File.join(curr_srcdir(), path, fname))
646
+ }
647
+ end
648
+
649
+ def srcdirectories(path = '.')
650
+ srcentries(path).select {|fname|
651
+ File.dir?(File.join(curr_srcdir(), path, fname))
652
+ }
653
+ end
654
+
655
+ end
656
+
657
+
658
+ class ToplevelInstaller
659
+
660
+ Version = '3.3.1'
661
+ Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
662
+
663
+ TASKS = [
664
+ [ 'all', 'do config, setup, then install' ],
665
+ [ 'config', 'saves your configurations' ],
666
+ [ 'show', 'shows current configuration' ],
667
+ [ 'setup', 'compiles ruby extentions and others' ],
668
+ [ 'install', 'installs files' ],
669
+ [ 'clean', "does `make clean' for each extention" ],
670
+ [ 'distclean',"does `make distclean' for each extention" ]
671
+ ]
672
+
673
+ def ToplevelInstaller.invoke
674
+ instance().invoke
675
+ end
676
+
677
+ @singleton = nil
678
+
679
+ def ToplevelInstaller.instance
680
+ @singleton ||= new(File.dirname($0))
681
+ @singleton
682
+ end
683
+
684
+ include MetaConfigAPI
685
+
686
+ def initialize(ardir_root)
687
+ @config = nil
688
+ @options = { 'verbose' => true }
689
+ @ardir = File.expand_path(ardir_root)
690
+ end
691
+
692
+ def inspect
693
+ "#<#{self.class} #{__id__()}>"
694
+ end
695
+
696
+ def invoke
697
+ run_metaconfigs
698
+ case task = parsearg_global()
699
+ when nil, 'all'
700
+ @config = load_config('config')
701
+ parsearg_config
702
+ init_installers
703
+ exec_config
704
+ exec_setup
705
+ exec_install
706
+ else
707
+ @config = load_config(task)
708
+ __send__ "parsearg_#{task}"
709
+ init_installers
710
+ __send__ "exec_#{task}"
711
+ end
712
+ end
713
+
714
+ def run_metaconfigs
715
+ eval_file_ifexist "#{@ardir}/metaconfig"
716
+ end
717
+
718
+ def load_config(task)
719
+ case task
720
+ when 'config'
721
+ ConfigTable.new
722
+ when 'clean', 'distclean'
723
+ if File.exist?(ConfigTable.savefile)
724
+ then ConfigTable.load
725
+ else ConfigTable.new
726
+ end
727
+ else
728
+ ConfigTable.load
729
+ end
730
+ end
731
+
732
+ def init_installers
733
+ @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
734
+ end
735
+
736
+ #
737
+ # Hook Script API bases
738
+ #
739
+
740
+ def srcdir_root
741
+ @ardir
742
+ end
743
+
744
+ def objdir_root
745
+ '.'
746
+ end
747
+
748
+ def relpath
749
+ '.'
750
+ end
751
+
752
+ #
753
+ # Option Parsing
754
+ #
755
+
756
+ def parsearg_global
757
+ valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
758
+
759
+ while arg = ARGV.shift
760
+ case arg
761
+ when /\A\w+\z/
762
+ setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
763
+ return arg
764
+
765
+ when '-q', '--quiet'
766
+ @options['verbose'] = false
767
+
768
+ when '--verbose'
769
+ @options['verbose'] = true
770
+
771
+ when '-h', '--help'
772
+ print_usage $stdout
773
+ exit 0
774
+
775
+ when '-v', '--version'
776
+ puts "#{File.basename($0)} version #{Version}"
777
+ exit 0
778
+
779
+ when '--copyright'
780
+ puts Copyright
781
+ exit 0
782
+
783
+ else
784
+ setup_rb_error "unknown global option '#{arg}'"
785
+ end
786
+ end
787
+
788
+ nil
789
+ end
790
+
791
+
792
+ def parsearg_no_options
793
+ unless ARGV.empty?
794
+ setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}"
795
+ end
796
+ end
797
+
798
+ alias parsearg_show parsearg_no_options
799
+ alias parsearg_setup parsearg_no_options
800
+ alias parsearg_clean parsearg_no_options
801
+ alias parsearg_distclean parsearg_no_options
802
+
803
+ def parsearg_config
804
+ re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
805
+ @options['config-opt'] = []
806
+
807
+ while i = ARGV.shift
808
+ if /\A--?\z/ =~ i
809
+ @options['config-opt'] = ARGV.dup
810
+ break
811
+ end
812
+ m = re.match(i) or setup_rb_error "config: unknown option #{i}"
813
+ name, value = *m.to_a[1,2]
814
+ @config[name] = value
815
+ end
816
+ end
817
+
818
+ def parsearg_install
819
+ @options['no-harm'] = false
820
+ @options['install-prefix'] = ''
821
+ while a = ARGV.shift
822
+ case a
823
+ when /\A--no-harm\z/
824
+ @options['no-harm'] = true
825
+ when /\A--prefix=(.*)\z/
826
+ path = $1
827
+ path = File.expand_path(path) unless path[0,1] == '/'
828
+ @options['install-prefix'] = path
829
+ else
830
+ setup_rb_error "install: unknown option #{a}"
831
+ end
832
+ end
833
+ end
834
+
835
+ def print_usage(out)
836
+ out.puts 'Typical Installation Procedure:'
837
+ out.puts " $ ruby #{File.basename $0} config"
838
+ out.puts " $ ruby #{File.basename $0} setup"
839
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
840
+ out.puts
841
+ out.puts 'Detailed Usage:'
842
+ out.puts " ruby #{File.basename $0} <global option>"
843
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
844
+
845
+ fmt = " %-24s %s\n"
846
+ out.puts
847
+ out.puts 'Global options:'
848
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
849
+ out.printf fmt, ' --verbose', 'output messages verbosely'
850
+ out.printf fmt, '-h,--help', 'print this message'
851
+ out.printf fmt, '-v,--version', 'print version and quit'
852
+ out.printf fmt, ' --copyright', 'print copyright and quit'
853
+ out.puts
854
+ out.puts 'Tasks:'
855
+ TASKS.each do |name, desc|
856
+ out.printf fmt, name, desc
857
+ end
858
+
859
+ fmt = " %-24s %s [%s]\n"
860
+ out.puts
861
+ out.puts 'Options for CONFIG or ALL:'
862
+ ConfigTable.each do |item|
863
+ out.printf fmt, item.help_opt, item.description, item.help_default
864
+ end
865
+ out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
866
+ out.puts
867
+ out.puts 'Options for INSTALL:'
868
+ out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
869
+ out.printf fmt, '--prefix=path', 'install path prefix', '$prefix'
870
+ out.puts
871
+ end
872
+
873
+ #
874
+ # Task Handlers
875
+ #
876
+
877
+ def exec_config
878
+ @installer.exec_config
879
+ @config.save # must be final
880
+ end
881
+
882
+ def exec_setup
883
+ @installer.exec_setup
884
+ end
885
+
886
+ def exec_install
887
+ @installer.exec_install
888
+ end
889
+
890
+ def exec_show
891
+ ConfigTable.each do |i|
892
+ printf "%-20s %s\n", i.name, i.value
893
+ end
894
+ end
895
+
896
+ def exec_clean
897
+ @installer.exec_clean
898
+ end
899
+
900
+ def exec_distclean
901
+ @installer.exec_distclean
902
+ end
903
+
904
+ end
905
+
906
+
907
+ class ToplevelInstallerMulti < ToplevelInstaller
908
+
909
+ include HookUtils
910
+ include HookScriptAPI
911
+ include FileOperations
912
+
913
+ def initialize(ardir)
914
+ super
915
+ @packages = all_dirs_in("#{@ardir}/packages")
916
+ raise 'no package exists' if @packages.empty?
917
+ end
918
+
919
+ def run_metaconfigs
920
+ eval_file_ifexist "#{@ardir}/metaconfig"
921
+ @packages.each do |name|
922
+ eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
923
+ end
924
+ end
925
+
926
+ def init_installers
927
+ @installers = {}
928
+ @packages.each do |pack|
929
+ @installers[pack] = Installer.new(@config, @options,
930
+ "#{@ardir}/packages/#{pack}",
931
+ "packages/#{pack}")
932
+ end
933
+
934
+ with = extract_selection(config('with'))
935
+ without = extract_selection(config('without'))
936
+ @selected = @installers.keys.select {|name|
937
+ (with.empty? or with.include?(name)) \
938
+ and not without.include?(name)
939
+ }
940
+ end
941
+
942
+ def extract_selection(list)
943
+ a = list.split(/,/)
944
+ a.each do |name|
945
+ setup_rb_error "no such package: #{name}" unless @installers.key?(name)
946
+ end
947
+ a
948
+ end
949
+
950
+ def print_usage(f)
951
+ super
952
+ f.puts 'Inluded packages:'
953
+ f.puts ' ' + @packages.sort.join(' ')
954
+ f.puts
955
+ end
956
+
957
+ #
958
+ # multi-package metaconfig API
959
+ #
960
+
961
+ attr_reader :packages
962
+
963
+ def declare_packages(list)
964
+ raise 'package list is empty' if list.empty?
965
+ list.each do |name|
966
+ raise "directory packages/#{name} does not exist"\
967
+ unless File.dir?("#{@ardir}/packages/#{name}")
968
+ end
969
+ @packages = list
970
+ end
971
+
972
+ #
973
+ # Task Handlers
974
+ #
975
+
976
+ def exec_config
977
+ run_hook 'pre-config'
978
+ each_selected_installers {|inst| inst.exec_config }
979
+ run_hook 'post-config'
980
+ @config.save # must be final
981
+ end
982
+
983
+ def exec_setup
984
+ run_hook 'pre-setup'
985
+ each_selected_installers {|inst| inst.exec_setup }
986
+ run_hook 'post-setup'
987
+ end
988
+
989
+ def exec_install
990
+ run_hook 'pre-install'
991
+ each_selected_installers {|inst| inst.exec_install }
992
+ run_hook 'post-install'
993
+ end
994
+
995
+ def exec_clean
996
+ rm_f ConfigTable.savefile
997
+ run_hook 'pre-clean'
998
+ each_selected_installers {|inst| inst.exec_clean }
999
+ run_hook 'post-clean'
1000
+ end
1001
+
1002
+ def exec_distclean
1003
+ rm_f ConfigTable.savefile
1004
+ run_hook 'pre-distclean'
1005
+ each_selected_installers {|inst| inst.exec_distclean }
1006
+ run_hook 'post-distclean'
1007
+ end
1008
+
1009
+ #
1010
+ # lib
1011
+ #
1012
+
1013
+ def each_selected_installers
1014
+ Dir.mkdir 'packages' unless File.dir?('packages')
1015
+ @selected.each do |pack|
1016
+ $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1017
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1018
+ Dir.chdir "packages/#{pack}"
1019
+ yield @installers[pack]
1020
+ Dir.chdir '../..'
1021
+ end
1022
+ end
1023
+
1024
+ def verbose?
1025
+ @options['verbose']
1026
+ end
1027
+
1028
+ def no_harm?
1029
+ @options['no-harm']
1030
+ end
1031
+
1032
+ end
1033
+
1034
+
1035
+ class Installer
1036
+
1037
+ FILETYPES = %w( bin lib ext share )
1038
+
1039
+ include HookScriptAPI
1040
+ include HookUtils
1041
+ include FileOperations
1042
+
1043
+ def initialize(config, opt, srcroot, objroot)
1044
+ @config = config
1045
+ @options = opt
1046
+ @srcdir = File.expand_path(srcroot)
1047
+ @objdir = File.expand_path(objroot)
1048
+ @currdir = '.'
1049
+ end
1050
+
1051
+ def inspect
1052
+ "#<#{self.class} #{File.basename(@srcdir)}>"
1053
+ end
1054
+
1055
+ #
1056
+ # Hook Script API base methods
1057
+ #
1058
+
1059
+ def srcdir_root
1060
+ @srcdir
1061
+ end
1062
+
1063
+ def objdir_root
1064
+ @objdir
1065
+ end
1066
+
1067
+ def relpath
1068
+ @currdir
1069
+ end
1070
+
1071
+ #
1072
+ # configs/options
1073
+ #
1074
+
1075
+ def no_harm?
1076
+ @options['no-harm']
1077
+ end
1078
+
1079
+ def verbose?
1080
+ @options['verbose']
1081
+ end
1082
+
1083
+ def verbose_off
1084
+ begin
1085
+ save, @options['verbose'] = @options['verbose'], false
1086
+ yield
1087
+ ensure
1088
+ @options['verbose'] = save
1089
+ end
1090
+ end
1091
+
1092
+ #
1093
+ # TASK config
1094
+ #
1095
+
1096
+ def exec_config
1097
+ exec_task_traverse 'config'
1098
+ end
1099
+
1100
+ def config_dir_bin(rel)
1101
+ end
1102
+
1103
+ def config_dir_lib(rel)
1104
+ end
1105
+
1106
+ def config_dir_ext(rel)
1107
+ extconf if extdir?(curr_srcdir())
1108
+ end
1109
+
1110
+ def extconf
1111
+ opt = @options['config-opt'].join(' ')
1112
+ command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
1113
+ end
1114
+
1115
+ def config_dir_share(rel)
1116
+ end
1117
+
1118
+ #
1119
+ # TASK setup
1120
+ #
1121
+
1122
+ def exec_setup
1123
+ exec_task_traverse 'setup'
1124
+ end
1125
+
1126
+ def setup_dir_bin(rel)
1127
+ all_files_in(curr_srcdir()).each do |fname|
1128
+ adjust_shebang "#{curr_srcdir()}/#{fname}"
1129
+ end
1130
+ end
1131
+
1132
+ def adjust_shebang(path)
1133
+ return if no_harm?
1134
+ tmpfile = File.basename(path) + '.tmp'
1135
+ begin
1136
+ File.open(path, 'rb') {|r|
1137
+ first = r.gets
1138
+ return unless File.basename(config('rubypath')) == 'ruby'
1139
+ return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
1140
+ $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1141
+ File.open(tmpfile, 'wb') {|w|
1142
+ w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1143
+ w.write r.read
1144
+ }
1145
+ move_file tmpfile, File.basename(path)
1146
+ }
1147
+ ensure
1148
+ File.unlink tmpfile if File.exist?(tmpfile)
1149
+ end
1150
+ end
1151
+
1152
+ def setup_dir_lib(rel)
1153
+ end
1154
+
1155
+ def setup_dir_ext(rel)
1156
+ make if extdir?(curr_srcdir())
1157
+ end
1158
+
1159
+ def setup_dir_share(rel)
1160
+ end
1161
+
1162
+ #
1163
+ # TASK install
1164
+ #
1165
+
1166
+ def exec_install
1167
+ rm_f 'InstalledFiles'
1168
+ exec_task_traverse 'install'
1169
+ end
1170
+
1171
+ def install_dir_bin(rel)
1172
+ install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
1173
+ end
1174
+
1175
+ def install_dir_lib(rel)
1176
+ install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
1177
+ return unless rel.empty?
1178
+ begin
1179
+ require 'rdoc/rdoc'
1180
+ ri_site = true
1181
+ if RDOC_VERSION =~ /^0\./
1182
+ require 'rdoc/options'
1183
+ unless Options::OptionList::OPTION_LIST.assoc('--ri-site')
1184
+ ri_site = false
1185
+ end
1186
+ end rescue nil
1187
+ if ri_site
1188
+ r = RDoc::RDoc.new
1189
+ r.document(%w{--ri-site})
1190
+ end
1191
+ rescue
1192
+ puts "** Unable to install Ri documentation for RedCloth **"
1193
+ end
1194
+ end
1195
+
1196
+ def install_dir_ext(rel)
1197
+ return unless extdir?(curr_srcdir())
1198
+ install_files ruby_extentions('.'),
1199
+ "#{config('sodir')}/#{File.dirname(rel)}",
1200
+ 0555
1201
+ end
1202
+
1203
+ def install_dir_share(rel)
1204
+ end
1205
+
1206
+ def install_files(list, dest, mode)
1207
+ mkdir_p dest, @options['install-prefix']
1208
+ list.each do |fname|
1209
+ install fname, dest, mode, @options['install-prefix']
1210
+ end
1211
+ end
1212
+
1213
+ def ruby_scripts
1214
+ collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
1215
+ end
1216
+
1217
+ # picked up many entries from cvs-1.11.1/src/ignore.c
1218
+ reject_patterns = %w(
1219
+ core RCSLOG tags TAGS .make.state
1220
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1221
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1222
+
1223
+ *.org *.in .*
1224
+ )
1225
+ mapping = {
1226
+ '.' => '\.',
1227
+ '$' => '\$',
1228
+ '#' => '\#',
1229
+ '*' => '.*'
1230
+ }
1231
+ REJECT_PATTERNS = Regexp.new('\A(?:' +
1232
+ reject_patterns.map {|pat|
1233
+ pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1234
+ }.join('|') +
1235
+ ')\z')
1236
+
1237
+ def collect_filenames_auto
1238
+ mapdir((existfiles() - hookfiles()).reject {|fname|
1239
+ REJECT_PATTERNS =~ fname
1240
+ })
1241
+ end
1242
+
1243
+ def existfiles
1244
+ all_files_in(curr_srcdir()) | all_files_in('.')
1245
+ end
1246
+
1247
+ def hookfiles
1248
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1249
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1250
+ }.flatten
1251
+ end
1252
+
1253
+ def mapdir(filelist)
1254
+ filelist.map {|fname|
1255
+ if File.exist?(fname) # objdir
1256
+ fname
1257
+ else # srcdir
1258
+ File.join(curr_srcdir(), fname)
1259
+ end
1260
+ }
1261
+ end
1262
+
1263
+ def ruby_extentions(dir)
1264
+ Dir.open(dir) {|d|
1265
+ ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
1266
+ if ents.empty?
1267
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1268
+ end
1269
+ return ents
1270
+ }
1271
+ end
1272
+
1273
+ #
1274
+ # TASK clean
1275
+ #
1276
+
1277
+ def exec_clean
1278
+ exec_task_traverse 'clean'
1279
+ rm_f ConfigTable.savefile
1280
+ rm_f 'InstalledFiles'
1281
+ end
1282
+
1283
+ def clean_dir_bin(rel)
1284
+ end
1285
+
1286
+ def clean_dir_lib(rel)
1287
+ end
1288
+
1289
+ def clean_dir_ext(rel)
1290
+ return unless extdir?(curr_srcdir())
1291
+ make 'clean' if File.file?('Makefile')
1292
+ end
1293
+
1294
+ def clean_dir_share(rel)
1295
+ end
1296
+
1297
+ #
1298
+ # TASK distclean
1299
+ #
1300
+
1301
+ def exec_distclean
1302
+ exec_task_traverse 'distclean'
1303
+ rm_f ConfigTable.savefile
1304
+ rm_f 'InstalledFiles'
1305
+ end
1306
+
1307
+ def distclean_dir_bin(rel)
1308
+ end
1309
+
1310
+ def distclean_dir_lib(rel)
1311
+ end
1312
+
1313
+ def distclean_dir_ext(rel)
1314
+ return unless extdir?(curr_srcdir())
1315
+ make 'distclean' if File.file?('Makefile')
1316
+ end
1317
+
1318
+ #
1319
+ # lib
1320
+ #
1321
+
1322
+ def exec_task_traverse(task)
1323
+ run_hook "pre-#{task}"
1324
+ FILETYPES.each do |type|
1325
+ if config('without-ext') == 'yes' and type == 'ext'
1326
+ $stderr.puts 'skipping ext/* by user option' if verbose?
1327
+ next
1328
+ end
1329
+ traverse task, type, "#{task}_dir_#{type}"
1330
+ end
1331
+ run_hook "post-#{task}"
1332
+ end
1333
+
1334
+ def traverse(task, rel, mid)
1335
+ dive_into(rel) {
1336
+ run_hook "pre-#{task}"
1337
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1338
+ all_dirs_in(curr_srcdir()).each do |d|
1339
+ traverse task, "#{rel}/#{d}", mid
1340
+ end
1341
+ run_hook "post-#{task}"
1342
+ }
1343
+ end
1344
+
1345
+ def dive_into(rel)
1346
+ return unless File.dir?("#{@srcdir}/#{rel}")
1347
+
1348
+ dir = File.basename(rel)
1349
+ Dir.mkdir dir unless File.dir?(dir)
1350
+ prevdir = Dir.pwd
1351
+ Dir.chdir dir
1352
+ $stderr.puts '---> ' + rel if verbose?
1353
+ @currdir = rel
1354
+ yield
1355
+ Dir.chdir prevdir
1356
+ $stderr.puts '<--- ' + rel if verbose?
1357
+ @currdir = File.dirname(rel)
1358
+ end
1359
+
1360
+ end
1361
+
1362
+
1363
+ if $0 == __FILE__
1364
+ begin
1365
+ if multipackage_install?
1366
+ ToplevelInstallerMulti.invoke
1367
+ else
1368
+ ToplevelInstaller.invoke
1369
+ end
1370
+ rescue SetupError
1371
+ raise if $DEBUG
1372
+ $stderr.puts $!.message
1373
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1374
+ exit 1
1375
+ end
1376
+ end