phys-units 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ddadae9db115ac3e41d98571a46a943fb6182dc7
4
- data.tar.gz: e94528fe3dc7ffd541e689c9a67d763ccbddd01a
3
+ metadata.gz: 48ba8e7c469513f119928a1daf902b3fb643cb58
4
+ data.tar.gz: e32cdd6308a29f9e12e2af394879630ed2ad604f
5
5
  SHA512:
6
- metadata.gz: ce78dca056127d01b771fb52a491ff6c79d79d7dcab6a155dcd1bc0de7a0991cf12721a97ee41851eddfdc24baed4065c2ba17e1506e54c591704d6a22b2f0c3
7
- data.tar.gz: f88501bb76b938085ddbdfcac7ccca6f98f93ea6260d6b513a4f88ed4d5a2863772d8b9fc7e02d130fdf920a0f65d04552de3ee679c900f95ab5dde504947268
6
+ metadata.gz: 0e27c9b8747f6352272254f42178f7e37de44ab1c1b39167f362f75529adef71c84f11b13dfd20045c7764a37e0f5dd48b35d674868903e90b6bb6bdb44777df
7
+ data.tar.gz: 006412bc92ac4afa28f81f30bef7b0c6564498be143e52ed9d0d2bc13e08dac10b4dc35a33e3224f18b7b89380f4b874796547cdd0c8229160d10ec50906b369
data/.gitignore CHANGED
@@ -5,6 +5,8 @@
5
5
  .yardoc
6
6
  Gemfile.lock
7
7
  InstalledFiles
8
+ SetupConfig
9
+ SetupReceipt
8
10
  _yardoc
9
11
  coverage
10
12
  doc/
@@ -75,6 +75,8 @@ module Phys
75
75
  # @return [Phys::Unit]
76
76
  def parse(x)
77
77
  find_unit(x) || Unit.cast(Parse.new.parse(x))
78
+ rescue UnitError,Racc::ParseError => e
79
+ raise UnitError,e.to_s.sub(/^\s+/,"")
78
80
  end
79
81
  alias [] parse
80
82
 
@@ -1,5 +1,5 @@
1
1
  module Phys
2
2
  class Unit
3
- VERSION = "0.9.8"
3
+ VERSION = "0.9.9"
4
4
  end
5
5
  end
data/setup.rb CHANGED
@@ -1,1585 +1,1295 @@
1
+ #!/usr/bin/env ruby
2
+ # Setup.rb v5.1.0
1
3
  #
2
- # setup.rb
4
+ # This is a stand-alone bundle of the setup.rb application.
5
+ # You can place it in your projects script/ directory, or
6
+ # call it 'setup.rb' and place it in your project's
7
+ # root directory (just like old times).
3
8
  #
4
- # Copyright (c) 2000-2005 Minero Aoki
9
+ # NOTE: As of version 5.1.0 this bundled rendition is also
10
+ # being used for the bin/setup.rb exe. Rather than the previous:
5
11
  #
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.
12
+ # require 'setup/command'
13
+ # Setup::Command.run
9
14
  #
10
-
11
- unless Enumerable.method_defined?(:map) # Ruby 1.4.6
12
- module Enumerable
13
- alias map collect
14
- end
15
+ # By doing so, +rvm+ should be able to use it across all rubies
16
+ # without issue and without needing to install it for each.
17
+ require 'yaml'
18
+ module Setup
19
+ VERSION = '5.2.0' #:erb: VERSION = '<%= version %>'
15
20
  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
- }
21
+ class << File #:nodoc: all
22
+ unless respond_to?(:read) # Ruby 1.6 and less
23
+ def read(fname)
24
+ open(fname){ |f| return f.read }
25
+ end
26
+ end
27
+ def dir?(path)
28
+ directory?((path[-1,1] == '/') ? path : path + '/')
22
29
  end
23
30
  end
24
-
25
31
  unless Errno.const_defined?(:ENOTEMPTY) # Windows?
26
- module Errno
27
- class ENOTEMPTY
28
- # We do not raise this exception, implementation is not needed.
32
+ module Errno #:nodoc:
33
+ class ENOTEMPTY #:nodoc:
29
34
  end
30
35
  end
31
36
  end
32
-
33
- def File.binread(fname)
34
- open(fname, 'rb') {|f|
35
- return f.read
36
- }
37
+ module Setup
38
+ META_EXTENSION_DIR = '.setup'
39
+ FILETYPES = %w( bin lib ext data etc man doc )
40
+ INSTALL_RECORD = 'SetupReceipt'
41
+ CONFIG_FILE = 'SetupConfig'
37
42
  end
38
-
39
- # for corrupted Windows' stat(2)
40
- def File.dir?(path)
41
- File.directory?((path[-1,1] == '/') ? path : path + '/')
42
- end
43
-
44
-
45
- class ConfigTable
46
-
47
- include Enumerable
48
-
49
- def initialize(rbconfig)
50
- @rbconfig = rbconfig
51
- @items = []
52
- @table = {}
53
- # options
54
- @install_prefix = nil
55
- @config_opt = nil
56
- @verbose = true
57
- @no_harm = false
58
- end
59
-
60
- attr_accessor :install_prefix
61
- attr_accessor :config_opt
62
-
63
- attr_writer :verbose
64
-
65
- def verbose?
66
- @verbose
67
- end
68
-
69
- attr_writer :no_harm
70
-
71
- def no_harm?
72
- @no_harm
73
- end
74
-
75
- def [](key)
76
- lookup(key).resolve(self)
77
- end
78
-
79
- def []=(key, val)
80
- lookup(key).set val
81
- end
82
-
83
- def names
84
- @items.map {|i| i.name }
85
- end
86
-
87
- def each(&block)
88
- @items.each(&block)
89
- end
90
-
91
- def key?(name)
92
- @table.key?(name)
93
- end
94
-
95
- def lookup(name)
96
- @table[name] or setup_rb_error "no such config item: #{name}"
97
- end
98
-
99
- def add(item)
100
- @items.push item
101
- @table[item.name] = item
102
- end
103
-
104
- def remove(name)
105
- item = lookup(name)
106
- @items.delete_if {|i| i.name == name }
107
- @table.delete_if {|name, i| i.name == name }
108
- item
109
- end
110
-
111
- def load_script(path, inst = nil)
112
- if File.file?(path)
113
- MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
114
- end
115
- end
116
-
117
- def savefile
118
- '.config'
119
- end
120
-
121
- def load_savefile
122
- begin
123
- File.foreach(savefile()) do |line|
124
- k, v = *line.split(/=/, 2)
125
- self[k] = v.strip
43
+ module Setup
44
+ class Project
45
+ ROOT_MARKER = '{.index,setup.rb,.setup,lib/}'
46
+ def initialize
47
+ @dotindex_file = find('.index')
48
+ @dotindex = YAML.load_file(@dotindex_file) if @dotindex_file
49
+ @name = nil
50
+ @version = nil
51
+ @loadpath = ['lib']
52
+ if @dotindex
53
+ @name = @dotindex['name']
54
+ @version = @dotindex['version']
55
+ @loadpath = (@dotindex['paths'] || {})['load']
56
+ else
57
+ if file = find('.setup/name')
58
+ @name = File.read(file).strip
59
+ end
60
+ if file = find('.setup/version')
61
+ @version = File.read(file).strip
62
+ end
63
+ if file = find('.setup/loadpath')
64
+ @loadpath = File.read(file).strip
65
+ end
126
66
  end
127
- rescue Errno::ENOENT
128
- setup_rb_error $!.message + "\n#{File.basename($0)} config first"
129
67
  end
130
- end
131
-
132
- def save
133
- @items.each {|i| i.value }
134
- File.open(savefile(), 'w') {|f|
135
- @items.each do |i|
136
- f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
137
- end
138
- }
139
- end
140
-
141
- def load_standard_entries
142
- standard_entries(@rbconfig).each do |ent|
143
- add ent
68
+ attr :dotindex
69
+ attr :name
70
+ attr :version
71
+ attr :loadpath
72
+ alias load_path loadpath
73
+ def rootdir
74
+ @rootdir ||= (
75
+ root = Dir.glob(File.join(Dir.pwd, ROOT_MARKER), File::FNM_CASEFOLD).first
76
+ if !root
77
+ raise Error, "not a project directory"
78
+ else
79
+ Dir.pwd
80
+ end
81
+ )
144
82
  end
145
- end
146
-
147
- def standard_entries(rbconfig)
148
- c = rbconfig
149
-
150
- rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
151
-
152
- major = c['MAJOR'].to_i
153
- minor = c['MINOR'].to_i
154
- teeny = c['TEENY'].to_i
155
- version = "#{major}.#{minor}"
156
-
157
- # ruby ver. >= 1.4.4?
158
- newpath_p = ((major >= 2) or
159
- ((major == 1) and
160
- ((minor >= 5) or
161
- ((minor == 4) and (teeny >= 4)))))
162
-
163
- if c['rubylibdir']
164
- # V > 1.6.3
165
- libruby = "#{c['prefix']}/lib/ruby"
166
- librubyver = c['rubylibdir']
167
- librubyverarch = c['archdir']
168
- siteruby = c['sitedir']
169
- siterubyver = c['sitelibdir']
170
- siterubyverarch = c['sitearchdir']
171
- elsif newpath_p
172
- # 1.4.4 <= V <= 1.6.3
173
- libruby = "#{c['prefix']}/lib/ruby"
174
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
175
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
176
- siteruby = c['sitedir']
177
- siterubyver = "$siteruby/#{version}"
178
- siterubyverarch = "$siterubyver/#{c['arch']}"
179
- else
180
- # V < 1.4.4
181
- libruby = "#{c['prefix']}/lib/ruby"
182
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
183
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
184
- siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
185
- siterubyver = siteruby
186
- siterubyverarch = "$siterubyver/#{c['arch']}"
187
- end
188
- parameterize = lambda {|path|
189
- path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
190
- }
191
-
192
- if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
193
- makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
194
- else
195
- makeprog = 'make'
196
- end
197
-
198
- [
199
- ExecItem.new('installdirs', 'std/site/home',
200
- 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
201
- {|val, table|
202
- case val
203
- when 'std'
204
- table['rbdir'] = '$librubyver'
205
- table['sodir'] = '$librubyverarch'
206
- when 'site'
207
- table['rbdir'] = '$siterubyver'
208
- table['sodir'] = '$siterubyverarch'
209
- when 'home'
210
- setup_rb_error '$HOME was not set' unless ENV['HOME']
211
- table['prefix'] = ENV['HOME']
212
- table['rbdir'] = '$libdir/ruby'
213
- table['sodir'] = '$libdir/ruby'
214
- end
215
- },
216
- PathItem.new('prefix', 'path', c['prefix'],
217
- 'path prefix of target environment'),
218
- PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
219
- 'the directory for commands'),
220
- PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
221
- 'the directory for libraries'),
222
- PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
223
- 'the directory for shared data'),
224
- PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
225
- 'the directory for man pages'),
226
- PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
227
- 'the directory for system configuration files'),
228
- PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
229
- 'the directory for local state data'),
230
- PathItem.new('libruby', 'path', libruby,
231
- 'the directory for ruby libraries'),
232
- PathItem.new('librubyver', 'path', librubyver,
233
- 'the directory for standard ruby libraries'),
234
- PathItem.new('librubyverarch', 'path', librubyverarch,
235
- 'the directory for standard ruby extensions'),
236
- PathItem.new('siteruby', 'path', siteruby,
237
- 'the directory for version-independent aux ruby libraries'),
238
- PathItem.new('siterubyver', 'path', siterubyver,
239
- 'the directory for aux ruby libraries'),
240
- PathItem.new('siterubyverarch', 'path', siterubyverarch,
241
- 'the directory for aux ruby binaries'),
242
- PathItem.new('rbdir', 'path', '$siterubyver',
243
- 'the directory for ruby scripts'),
244
- PathItem.new('sodir', 'path', '$siterubyverarch',
245
- 'the directory for ruby extentions'),
246
- PathItem.new('rubypath', 'path', rubypath,
247
- 'the path to set to #! line'),
248
- ProgramItem.new('rubyprog', 'name', rubypath,
249
- 'the ruby program using for installation'),
250
- ProgramItem.new('makeprog', 'name', makeprog,
251
- 'the make program to compile ruby extentions'),
252
- SelectItem.new('shebang', 'all/ruby/never', 'ruby',
253
- 'shebang line (#!) editing mode'),
254
- BoolItem.new('without-ext', 'yes/no', 'no',
255
- 'does not compile/install ruby extentions')
256
- ]
257
- end
258
- private :standard_entries
259
-
260
- def load_multipackage_entries
261
- multipackage_entries().each do |ent|
262
- add ent
83
+ def extconfs
84
+ @extconfs ||= Dir['ext/**/extconf.rb']
263
85
  end
264
- end
265
-
266
- def multipackage_entries
267
- [
268
- PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
269
- 'package names that you want to install'),
270
- PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
271
- 'package names that you do not want to install')
272
- ]
273
- end
274
- private :multipackage_entries
275
-
276
- ALIASES = {
277
- 'std-ruby' => 'librubyver',
278
- 'stdruby' => 'librubyver',
279
- 'rubylibdir' => 'librubyver',
280
- 'archdir' => 'librubyverarch',
281
- 'site-ruby-common' => 'siteruby', # For backward compatibility
282
- 'site-ruby' => 'siterubyver', # For backward compatibility
283
- 'bin-dir' => 'bindir',
284
- 'bin-dir' => 'bindir',
285
- 'rb-dir' => 'rbdir',
286
- 'so-dir' => 'sodir',
287
- 'data-dir' => 'datadir',
288
- 'ruby-path' => 'rubypath',
289
- 'ruby-prog' => 'rubyprog',
290
- 'ruby' => 'rubyprog',
291
- 'make-prog' => 'makeprog',
292
- 'make' => 'makeprog'
293
- }
294
-
295
- def fixup
296
- ALIASES.each do |ali, name|
297
- @table[ali] = @table[name]
298
- end
299
- @items.freeze
300
- @table.freeze
301
- @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
302
- end
303
-
304
- def parse_opt(opt)
305
- m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
306
- m.to_a[1,2]
307
- end
308
-
309
- def dllext
310
- @rbconfig['DLEXT']
311
- end
312
-
313
- def value_config?(name)
314
- lookup(name).value?
315
- end
316
-
317
- class Item
318
- def initialize(name, template, default, desc)
319
- @name = name.freeze
320
- @template = template
321
- @value = default
322
- @default = default
323
- @description = desc
324
- end
325
-
326
- attr_reader :name
327
- attr_reader :description
328
-
329
- attr_accessor :default
330
- alias help_default default
331
-
332
- def help_opt
333
- "--#{@name}=#{@template}"
334
- end
335
-
336
- def value?
337
- true
86
+ def extensions
87
+ @extensions ||= extconfs.collect{ |f| File.dirname(f) }
338
88
  end
339
-
340
- def value
341
- @value
89
+ def compiles?
90
+ !extensions.empty?
342
91
  end
343
-
344
- def resolve(table)
345
- @value.gsub(%r<\$([^/]+)>) { table[$1] }
92
+ def yardopts
93
+ Dir.glob(File.join(rootdir, '.yardopts')).first
346
94
  end
347
-
348
- def set(val)
349
- @value = check(val)
95
+ def document
96
+ Dir.glob(File.join(rootdir, '.document')).first
350
97
  end
351
-
352
- private
353
-
354
- def check(val)
355
- setup_rb_error "config: --#{name} requires argument" unless val
356
- val
98
+ def find(glob, flags=0)
99
+ case flags
100
+ when :casefold
101
+ flags = File::FNM_CASEFOLD
102
+ else
103
+ flags = flags.to_i
104
+ end
105
+ Dir.glob(File.join(rootdir, glob), flags).first
357
106
  end
358
107
  end
359
-
360
- class BoolItem < Item
361
- def config_type
362
- 'bool'
363
- end
364
-
365
- def help_opt
366
- "--#{@name}"
367
- end
368
-
369
- private
370
-
371
- def check(val)
372
- return 'yes' unless val
373
- case val
374
- when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
375
- when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
108
+ end
109
+ module Setup
110
+ class Session
111
+ attr :options
112
+ def initialize(options={})
113
+ @options = options
114
+ self.io ||= StringIO.new # log instead ?
115
+ end
116
+ def io
117
+ @options[:io]
118
+ end
119
+ def io=(anyio)
120
+ @options[:io] = anyio
121
+ end
122
+ def trace?; @options[:trace]; end
123
+ def trace=(val)
124
+ @options[:trace] = val
125
+ end
126
+ def trial?; @options[:trial]; end
127
+ alias_method :dryrun?, :trial?
128
+ def trial=(val)
129
+ @options[:trial] = val
130
+ end
131
+ alias_method :dryrun=, :trial=
132
+ def quiet?; @options[:quiet]; end
133
+ def quiet=(val)
134
+ @options[:quiet] = val
135
+ end
136
+ def force?; @options[:force]; end
137
+ def force=(val)
138
+ @options[:force] = val
139
+ end
140
+ def compile?
141
+ configuration.compile? && project.compiles?
142
+ end
143
+ def all
144
+ config
145
+ compile
146
+ if configuration.test?
147
+ ok = test
148
+ exit 1 unless ok
149
+ end
150
+ install
151
+ end
152
+ def config
153
+ log_header('Preconfig')
154
+ if configuration.save_config
155
+ io.print "#{CONFIG_FILE} was saved. " unless quiet?
376
156
  else
377
- setup_rb_error "config: --#{@name} accepts only yes/no for argument"
157
+ io.print "#{CONFIG_FILE} is current. " unless quiet?
158
+ end
159
+ io.puts "Edit to customize configuration." unless quiet?
160
+ puts configuration if trace? && !quiet?
161
+ end
162
+ def compile
163
+ if compile?
164
+ log_header('Compile')
165
+ compiler.configure
166
+ compiler.compile
378
167
  end
379
168
  end
380
- end
381
-
382
- class PathItem < Item
383
- def config_type
384
- 'path'
385
- end
386
-
387
- private
388
-
389
- def check(path)
390
- setup_rb_error "config: --#{@name} requires argument" unless path
391
- path[0,1] == '$' ? path : File.expand_path(path)
169
+ alias_method :make, :compile
170
+ alias_method :setup, :make
171
+ def install
172
+ log_header('Install')
173
+ installer.install
174
+ end
175
+ def test
176
+ return true unless tester.testable?
177
+ log_header('Test')
178
+ tester.test
179
+ end
180
+ def clean
181
+ log_header('Clean')
182
+ compiler.clean
183
+ end
184
+ def distclean
185
+ log_header('Distclean')
186
+ compiler.distclean
187
+ end
188
+ def uninstall
189
+ if !File.exist?(INSTALL_RECORD)
190
+ io.puts "Nothing is installed."
191
+ return
192
+ end
193
+ log_header('Uninstall')
194
+ uninstaller.uninstall
195
+ io.puts('Ok.')
392
196
  end
393
- end
394
-
395
- class ProgramItem < Item
396
- def config_type
397
- 'program'
197
+ def show
198
+ puts configuration
398
199
  end
399
- end
400
-
401
- class SelectItem < Item
402
- def initialize(name, selection, default, desc)
403
- super
404
- @ok = selection.split('/')
200
+ def project
201
+ @project ||= Project.new
405
202
  end
406
-
407
- def config_type
408
- 'select'
203
+ def configuration
204
+ @configuration ||= Configuration.new
409
205
  end
410
-
411
- private
412
-
413
- def check(val)
414
- unless @ok.include?(val.strip)
415
- setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
206
+ def compiler
207
+ @compiler ||= Compiler.new(project, configuration, options)
208
+ end
209
+ def installer
210
+ @installer ||= Installer.new(project, configuration, options)
211
+ end
212
+ def tester
213
+ @tester ||= Tester.new(project, configuration, options)
214
+ end
215
+ def uninstaller
216
+ @uninstaller ||= Uninstaller.new(project, configuration, options)
217
+ end
218
+ def log_header(phase)
219
+ return if quiet?
220
+ if trial?
221
+ str = "#{phase.upcase} (trail run)"
222
+ else
223
+ str = "#{phase.upcase}"
416
224
  end
417
- val.strip
225
+ line = "- " * 35
226
+ line[0..str.size+3] = str
227
+ io.puts("\n- - #{line}\n\n")
418
228
  end
419
229
  end
420
-
421
- class ExecItem < Item
422
- def initialize(name, selection, desc, &block)
423
- super name, selection, nil, desc
424
- @ok = selection.split('/')
425
- @action = block
426
- end
427
-
428
- def config_type
429
- 'exec'
430
- end
431
-
432
- def value?
433
- false
230
+ end
231
+ module Setup
232
+ class Base
233
+ attr :project
234
+ attr :config
235
+ attr_accessor :trial
236
+ attr_accessor :trace
237
+ attr_accessor :quiet
238
+ attr_accessor :force
239
+ attr_accessor :io
240
+ def initialize(project, configuration, options={})
241
+ @project = project
242
+ @config = configuration
243
+ initialize_hooks
244
+ options.each do |k,v|
245
+ __send__("#{k}=", v) if respond_to?("#{k}=")
246
+ end
434
247
  end
435
-
436
- def resolve(table)
437
- setup_rb_error "$#{name()} wrongly used as option value"
248
+ def initialize_hooks
249
+ file = META_EXTENSION_DIR + "/#{self.class.name.downcase}.rb"
250
+ if File.exist?(file)
251
+ script = File.read(file)
252
+ (class << self; self; end).class_eval(script)
253
+ end
438
254
  end
439
-
440
- undef set
441
-
442
- def evaluate(val, table)
443
- v = val.strip.downcase
444
- unless @ok.include?(v)
445
- setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
255
+ def trial? ; @trial ; end
256
+ def trace? ; @trace ; end
257
+ def quiet? ; @quiet ; end
258
+ def force? ; @force ; end
259
+ def rootdir
260
+ project.rootdir
261
+ end
262
+ def bash(*args)
263
+ $stderr.puts args.join(' ') if trace?
264
+ system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
265
+ end
266
+ alias_method :command, :bash
267
+ def ruby(*args)
268
+ bash(config.rubyprog, *args)
269
+ end
270
+ def trace_off #:yield:
271
+ begin
272
+ save, @trace = trace?, false
273
+ yield
274
+ ensure
275
+ @trace = save
446
276
  end
447
- @action.call v, table
448
277
  end
449
- end
450
-
451
- class PackageSelectionItem < Item
452
- def initialize(name, template, default, help_default, desc)
453
- super name, template, default, desc
454
- @help_default = help_default
455
- end
456
-
457
- attr_reader :help_default
458
-
459
- def config_type
460
- 'package'
461
- end
462
-
463
- private
464
-
465
- def check(val)
466
- unless File.dir?("packages/#{val}")
467
- setup_rb_error "config: no such package: #{val}"
468
- end
469
- val
278
+ def rm_f(path)
279
+ io.puts "rm -f #{path}" if trace? or trial?
280
+ return if trial?
281
+ force_remove_file(path)
470
282
  end
471
- end
472
-
473
- class MetaConfigEnvironment
474
- def initialize(config, installer)
475
- @config = config
476
- @installer = installer
477
- end
478
-
479
- def config_names
480
- @config.names
481
- end
482
-
483
- def config?(name)
484
- @config.key?(name)
485
- end
486
-
487
- def bool_config?(name)
488
- @config.lookup(name).config_type == 'bool'
489
- end
490
-
491
- def path_config?(name)
492
- @config.lookup(name).config_type == 'path'
493
- end
494
-
495
- def value_config?(name)
496
- @config.lookup(name).config_type != 'exec'
497
- end
498
-
499
- def add_config(item)
500
- @config.add item
501
- end
502
-
503
- def add_bool_config(name, default, desc)
504
- @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
505
- end
506
-
507
- def add_path_config(name, default, desc)
508
- @config.add PathItem.new(name, 'path', default, desc)
509
- end
510
-
511
- def set_config_default(name, default)
512
- @config.lookup(name).default = default
513
- end
514
-
515
- def remove_config(name)
516
- @config.remove(name)
517
- end
518
-
519
- # For only multipackage
520
- def packages
521
- raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
522
- @installer.packages
523
- end
524
-
525
- # For only multipackage
526
- def declare_packages(list)
527
- raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
528
- @installer.packages = list
283
+ def force_remove_file(path)
284
+ begin
285
+ remove_file(path)
286
+ rescue
287
+ end
529
288
  end
530
- end
531
-
532
- end # class ConfigTable
533
-
534
-
535
- # This module requires: #verbose?, #no_harm?
536
- module FileOperations
537
-
538
- def mkdir_p(dirname, prefix = nil)
539
- dirname = prefix + File.expand_path(dirname) if prefix
540
- $stderr.puts "mkdir -p #{dirname}" if verbose?
541
- return if no_harm?
542
-
543
- # Does not check '/', it's too abnormal.
544
- dirs = File.expand_path(dirname).split(%r<(?=/)>)
545
- if /\A[a-z]:\z/i =~ dirs[0]
546
- disk = dirs.shift
547
- dirs[0] = disk + dirs[0]
548
- end
549
- dirs.each_index do |idx|
550
- path = dirs[0..idx].join('')
551
- Dir.mkdir path unless File.dir?(path)
289
+ def remove_file(path)
290
+ File.chmod 0777, path
291
+ File.unlink(path)
292
+ end
293
+ def rmdir(path)
294
+ io.puts "rmdir #{path}" if trace? or trial?
295
+ return if trial?
296
+ Dir.rmdir(path)
552
297
  end
553
298
  end
554
-
555
- def rm_f(path)
556
- $stderr.puts "rm -f #{path}" if verbose?
557
- return if no_harm?
558
- force_remove_file path
559
- end
560
-
561
- def rm_rf(path)
562
- $stderr.puts "rm -rf #{path}" if verbose?
563
- return if no_harm?
564
- remove_tree path
299
+ class Error < StandardError
565
300
  end
566
-
567
- def remove_tree(path)
568
- if File.symlink?(path)
569
- remove_file path
570
- elsif File.dir?(path)
571
- remove_tree0 path
572
- else
573
- force_remove_file path
301
+ end
302
+ module Setup
303
+ class Compiler < Base
304
+ def compiles?
305
+ !extdirs.empty?
306
+ end
307
+ def configure
308
+ extdirs.each do |dir|
309
+ Dir.chdir(dir) do
310
+ if File.exist?('extconf.rb') && !FileUtils.uptodate?('Makefile', ['extconf.rb'])
311
+ ruby("extconf.rb")
312
+ end
313
+ end
314
+ end
574
315
  end
575
- end
576
-
577
- def remove_tree0(path)
578
- Dir.foreach(path) do |ent|
579
- next if ent == '.'
580
- next if ent == '..'
581
- entpath = "#{path}/#{ent}"
582
- if File.symlink?(entpath)
583
- remove_file entpath
584
- elsif File.dir?(entpath)
585
- remove_tree0 entpath
586
- else
587
- force_remove_file entpath
316
+ def compile
317
+ extdirs.each do |dir|
318
+ Dir.chdir(dir) do
319
+ make
320
+ end
588
321
  end
589
322
  end
590
- begin
591
- Dir.rmdir path
592
- rescue Errno::ENOTEMPTY
593
- # directory may not be empty
323
+ def clean
324
+ extdirs.each do |dir|
325
+ Dir.chdir(dir) do
326
+ make('clean')
327
+ end
328
+ end
594
329
  end
595
- end
596
-
597
- def move_file(src, dest)
598
- force_remove_file dest
599
- begin
600
- File.rename src, dest
601
- rescue
602
- File.open(dest, 'wb') {|f|
603
- f.write File.binread(src)
604
- }
605
- File.chmod File.stat(src).mode, dest
606
- File.unlink src
330
+ def distclean
331
+ extdirs.each do |dir|
332
+ Dir.chdir(dir) do
333
+ make('distclean')
334
+ end
335
+ end
607
336
  end
608
- end
609
-
610
- def force_remove_file(path)
611
- begin
612
- remove_file path
613
- rescue
337
+ def extdirs
338
+ Dir['ext/**/*/{MANIFEST,extconf.rb}'].map do |f|
339
+ File.dirname(f)
340
+ end.uniq
614
341
  end
615
- end
616
-
617
- def remove_file(path)
618
- File.chmod 0777, path
619
- File.unlink path
620
- end
621
-
622
- def install(from, dest, mode, prefix = nil)
623
- $stderr.puts "install #{from} #{dest}" if verbose?
624
- return if no_harm?
625
-
626
- realdest = prefix ? prefix + File.expand_path(dest) : dest
627
- realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
628
- str = File.binread(from)
629
- if diff?(str, realdest)
630
- verbose_off {
631
- rm_f realdest if File.exist?(realdest)
632
- }
633
- File.open(realdest, 'wb') {|f|
634
- f.write str
635
- }
636
- File.chmod mode, realdest
637
-
638
- File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
639
- if prefix
640
- f.puts realdest.sub(prefix, '')
641
- else
642
- f.puts realdest
643
- end
644
- }
342
+ def make(task=nil)
343
+ return unless File.exist?('Makefile')
344
+ bash(*[config.makeprog, task].compact)
645
345
  end
646
346
  end
647
-
648
- def diff?(new_content, path)
649
- return true unless File.exist?(path)
650
- new_content != File.binread(path)
651
- end
652
-
653
- def command(*args)
654
- $stderr.puts args.join(' ') if verbose?
655
- system(*args) or raise RuntimeError,
656
- "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
657
- end
658
-
659
- def ruby(*args)
660
- command config('rubyprog'), *args
661
- end
662
-
663
- def make(task = nil)
664
- command(*[config('makeprog'), task].compact)
665
- end
666
-
667
- def extdir?(dir)
668
- File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
669
- end
670
-
671
- def files_of(dir)
672
- Dir.open(dir) {|d|
673
- return d.select {|ent| File.file?("#{dir}/#{ent}") }
674
- }
675
- end
676
-
677
- DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
678
-
679
- def directories_of(dir)
680
- Dir.open(dir) {|d|
681
- return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
682
- }
683
- end
684
-
685
347
  end
686
-
687
-
688
- # This module requires: #srcdir_root, #objdir_root, #relpath
689
- module HookScriptAPI
690
-
691
- def get_config(key)
692
- @config[key]
693
- end
694
-
695
- alias config get_config
696
-
697
- # obsolete: use metaconfig to change configuration
698
- def set_config(key, val)
699
- @config[key] = val
700
- end
701
-
702
- #
703
- # srcdir/objdir (works only in the package directory)
704
- #
705
-
706
- def curr_srcdir
707
- "#{srcdir_root()}/#{relpath()}"
708
- end
709
-
710
- def curr_objdir
711
- "#{objdir_root()}/#{relpath()}"
712
- end
713
-
714
- def srcfile(path)
715
- "#{curr_srcdir()}/#{path}"
716
- end
717
-
718
- def srcexist?(path)
719
- File.exist?(srcfile(path))
720
- end
721
-
722
- def srcdirectory?(path)
723
- File.dir?(srcfile(path))
724
- end
725
-
726
- def srcfile?(path)
727
- File.file?(srcfile(path))
728
- end
729
-
730
- def srcentries(path = '.')
731
- Dir.open("#{curr_srcdir()}/#{path}") {|d|
732
- return d.to_a - %w(. ..)
733
- }
734
- end
735
-
736
- def srcfiles(path = '.')
737
- srcentries(path).select {|fname|
738
- File.file?(File.join(curr_srcdir(), path, fname))
739
- }
740
- end
741
-
742
- def srcdirectories(path = '.')
743
- srcentries(path).select {|fname|
744
- File.dir?(File.join(curr_srcdir(), path, fname))
745
- }
746
- end
747
-
748
- end
749
-
750
-
751
- class ToplevelInstaller
752
-
753
- Version = '3.4.1'
754
- Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
755
-
756
- TASKS = [
757
- [ 'all', 'do config, setup, then install' ],
758
- [ 'config', 'saves your configurations' ],
759
- [ 'show', 'shows current configuration' ],
760
- [ 'setup', 'compiles ruby extentions and others' ],
761
- [ 'install', 'installs files' ],
762
- [ 'test', 'run all tests in test/' ],
763
- [ 'clean', "does `make clean' for each extention" ],
764
- [ 'distclean',"does `make distclean' for each extention" ]
765
- ]
766
-
767
- def ToplevelInstaller.invoke
768
- config = ConfigTable.new(load_rbconfig())
769
- config.load_standard_entries
770
- config.load_multipackage_entries if multipackage?
771
- config.fixup
772
- klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
773
- klass.new(File.dirname($0), config).invoke
774
- end
775
-
776
- def ToplevelInstaller.multipackage?
777
- File.dir?(File.dirname($0) + '/packages')
778
- end
779
-
780
- def ToplevelInstaller.load_rbconfig
781
- if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
782
- ARGV.delete(arg)
783
- load File.expand_path(arg.split(/=/, 2)[1])
784
- $".push 'rbconfig.rb'
785
- else
786
- require 'rbconfig'
787
- end
788
- ::Config::CONFIG
789
- end
790
-
791
- def initialize(ardir_root, config)
792
- @ardir = File.expand_path(ardir_root)
793
- @config = config
794
- # cache
795
- @valid_task_re = nil
796
- end
797
-
798
- def config(key)
799
- @config[key]
800
- end
801
-
802
- def inspect
803
- "#<#{self.class} #{__id__()}>"
804
- end
805
-
806
- def invoke
807
- run_metaconfigs
808
- case task = parsearg_global()
809
- when nil, 'all'
810
- parsearg_config
811
- init_installers
812
- exec_config
813
- exec_setup
814
- exec_install
815
- else
816
- case task
817
- when 'config', 'test'
818
- ;
819
- when 'clean', 'distclean'
820
- @config.load_savefile if File.exist?(@config.savefile)
348
+ require 'rbconfig'
349
+ require 'fileutils'
350
+ require 'erb'
351
+ require 'yaml'
352
+ require 'shellwords'
353
+ module Setup
354
+ class Configuration
355
+ RBCONFIG = ::RbConfig::CONFIG
356
+ META_CONFIG_FILE = META_EXTENSION_DIR + '/metaconfig.rb'
357
+ def self.options
358
+ @@options ||= []
359
+ end
360
+ def self.option(name, *args) #type, description)
361
+ options << [name.to_s, *args] #type, description]
362
+ attr_accessor(name)
363
+ end
364
+ option :prefix , :path, 'path prefix of target environment'
365
+ option :bindir , :path, 'directory for commands'
366
+ option :libdir , :path, 'directory for libraries'
367
+ option :datadir , :path, 'directory for shared data'
368
+ option :mandir , :path, 'directory for man pages'
369
+ option :docdir , :path, 'directory for documentation'
370
+ option :rbdir , :path, 'directory for ruby scripts'
371
+ option :sodir , :path, 'directory for ruby extentions'
372
+ option :sysconfdir , :path, 'directory for system configuration files'
373
+ option :localstatedir , :path, 'directory for local state data'
374
+ option :libruby , :path, 'directory for ruby libraries'
375
+ option :librubyver , :path, 'directory for standard ruby libraries'
376
+ option :librubyverarch , :path, 'directory for standard ruby extensions'
377
+ option :siteruby , :path, 'directory for version-independent aux ruby libraries'
378
+ option :siterubyver , :path, 'directory for aux ruby libraries'
379
+ option :siterubyverarch , :path, 'directory for aux ruby binaries'
380
+ option :rubypath , :prog, 'path to set to #! line'
381
+ option :rubyprog , :prog, 'ruby program used for installation'
382
+ option :makeprog , :prog, 'make program to compile ruby extentions'
383
+ option :extconfopt , :opts, 'options to pass-thru to extconf.rb'
384
+ option :shebang , :pick, 'shebang line (#!) editing mode (all,ruby,never)'
385
+ option :no_test, :t , :bool, 'run pre-installation tests'
386
+ option :no_doc , :bool, 'install doc/ directory'
387
+ option :no_ext , :bool, 'compile/install ruby extentions'
388
+ option :install_prefix , :path, 'install to alternate root location'
389
+ option :root , :path, 'install to alternate root location'
390
+ option :installdirs , :pick, 'install location mode (site,std,home)' #, local)
391
+ option :type , :pick, 'install location mode (site,std,home)'
392
+ ::RbConfig::CONFIG.each do |key,val|
393
+ next if key == "configure_args"
394
+ name = key.to_s.downcase
395
+ define_method(name){ val }
396
+ end
397
+ config_args = Shellwords.shellwords(::RbConfig::CONFIG["configure_args"])
398
+ config_args.each do |ent|
399
+ if ent.index("=")
400
+ key, val = *ent.split("=")
821
401
  else
822
- @config.load_savefile
402
+ key, val = ent, true
403
+ end
404
+ name = key.downcase
405
+ name = name.sub(/^--/,'')
406
+ name = name.gsub(/-/,'_')
407
+ define_method(name){ val }
408
+ end
409
+ def options
410
+ self.class.options
411
+ end
412
+ def initialize(values={})
413
+ initialize_metaconfig
414
+ initialize_defaults
415
+ initialize_environment
416
+ initialize_configfile unless values[:reset]
417
+ values.each{ |k,v| __send__("#{k}=", v) }
418
+ yield(self) if block_given?
419
+ end
420
+ def initialize_metaconfig
421
+ if File.exist?(META_CONFIG_FILE)
422
+ script = File.read(META_CONFIG_FILE)
423
+ (class << self; self; end).class_eval(script)
823
424
  end
824
- __send__ "parsearg_#{task}"
825
- init_installers
826
- __send__ "exec_#{task}"
827
425
  end
828
- end
829
-
830
- def run_metaconfigs
831
- @config.load_script "#{@ardir}/metaconfig"
832
- end
833
-
834
- def init_installers
835
- @installer = Installer.new(@config, @ardir, File.expand_path('.'))
836
- end
837
-
838
- #
839
- # Hook Script API bases
840
- #
841
-
842
- def srcdir_root
843
- @ardir
844
- end
845
-
846
- def objdir_root
847
- '.'
848
- end
849
-
850
- def relpath
851
- '.'
852
- end
853
-
854
- #
855
- # Option Parsing
856
- #
857
-
858
- def parsearg_global
859
- while arg = ARGV.shift
860
- case arg
861
- when /\A\w+\z/
862
- setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
863
- return arg
864
- when '-q', '--quiet'
865
- @config.verbose = false
866
- when '--verbose'
867
- @config.verbose = true
868
- when '--help'
869
- print_usage $stdout
870
- exit 0
871
- when '--version'
872
- puts "#{File.basename($0)} version #{Version}"
873
- exit 0
874
- when '--copyright'
875
- puts Copyright
876
- exit 0
877
- else
878
- setup_rb_error "unknown global option '#{arg}'"
426
+ def initialize_defaults
427
+ self.type = 'site'
428
+ self.no_ri = true
429
+ self.no_test = true
430
+ self.no_doc = true
431
+ self.no_ext = false
432
+ end
433
+ def initialize_environment
434
+ options.each do |name, *args|
435
+ if value = ENV["RUBYSETUP_#{name.to_s.upcase}"]
436
+ __send__("#{name}=", value)
437
+ end
879
438
  end
880
439
  end
881
- nil
882
- end
883
-
884
- def valid_task?(t)
885
- valid_task_re() =~ t
886
- end
887
-
888
- def valid_task_re
889
- @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
890
- end
891
-
892
- def parsearg_no_options
893
- unless ARGV.empty?
894
- task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
895
- setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
440
+ def initialize_configfile
441
+ if exist?
442
+ erb = ERB.new(File.read(CONFIG_FILE))
443
+ txt = erb.result(binding)
444
+ dat = YAML.load(txt)
445
+ dat.each do |k, v|
446
+ next if 'type' == k
447
+ next if 'installdirs' == k
448
+ k = k.gsub('-','_')
449
+ __send__("#{k}=", v)
450
+ end
451
+ if dat['type']
452
+ self.type = dat['type']
453
+ end
454
+ if dat['installdirs']
455
+ self.installdirs = dat['installdirs']
456
+ end
457
+ end
896
458
  end
897
- end
898
-
899
- alias parsearg_show parsearg_no_options
900
- alias parsearg_setup parsearg_no_options
901
- alias parsearg_test parsearg_no_options
902
- alias parsearg_clean parsearg_no_options
903
- alias parsearg_distclean parsearg_no_options
904
-
905
- def parsearg_config
906
- evalopt = []
907
- set = []
908
- @config.config_opt = []
909
- while i = ARGV.shift
910
- if /\A--?\z/ =~ i
911
- @config.config_opt = ARGV.dup
912
- break
913
- end
914
- name, value = *@config.parse_opt(i)
915
- if @config.value_config?(name)
916
- @config[name] = value
459
+ attr_accessor :reset
460
+ def base_bindir
461
+ @base_bindir ||= subprefix('bindir')
462
+ end
463
+ def base_libdir
464
+ @base_libdir ||= subprefix('libdir')
465
+ end
466
+ def base_datadir
467
+ @base_datadir ||= subprefix('datadir')
468
+ end
469
+ def base_mandir
470
+ @base_mandir ||= subprefix('mandir')
471
+ end
472
+ def base_docdir
473
+ @base_docdir || File.dirname(subprefix('docdir'))
474
+ end
475
+ def base_rubylibdir
476
+ @rubylibdir ||= subprefix('rubylibdir')
477
+ end
478
+ def base_rubyarchdir
479
+ @base_rubyarchdir ||= subprefix('archdir')
480
+ end
481
+ def base_sysconfdir
482
+ @base_sysconfdir ||= subprefix('sysconfdir')
483
+ end
484
+ def base_localstatedir
485
+ @base_localstatedir ||= subprefix('localstatedir')
486
+ end
487
+ def type
488
+ @type ||= 'site'
489
+ end
490
+ def type=(val)
491
+ @type = val
492
+ case val.to_s
493
+ when 'std', 'ruby'
494
+ @rbdir = librubyver #'$librubyver'
495
+ @sodir = librubyverarch #'$librubyverarch'
496
+ when 'site'
497
+ @rbdir = siterubyver #'$siterubyver'
498
+ @sodir = siterubyverarch #'$siterubyverarch'
499
+ when 'home'
500
+ self.prefix = File.join(home, '.local') # TODO: Use XDG
501
+ @rbdir = nil #'$libdir/ruby'
502
+ @sodir = nil #'$libdir/ruby'
917
503
  else
918
- evalopt.push [name, value]
504
+ raise Error, "bad config: use type=(std|site|home) [#{val}]"
919
505
  end
920
- set.push name
921
506
  end
922
- evalopt.each do |name, value|
923
- @config.lookup(name).evaluate value, @config
507
+ alias_method :installdirs, :type
508
+ alias_method :installdirs=, :type=
509
+ alias_method :install_prefix, :root
510
+ alias_method :install_prefix=, :root=
511
+ def prefix
512
+ @prefix ||= RBCONFIG['prefix']
924
513
  end
925
- # Check if configuration is valid
926
- set.each do |n|
927
- @config[n] if @config.value_config?(n)
514
+ def prefix=(path)
515
+ @prefix = pathname(path)
928
516
  end
929
- end
930
-
931
- def parsearg_install
932
- @config.no_harm = false
933
- @config.install_prefix = ''
934
- while a = ARGV.shift
935
- case a
936
- when '--no-harm'
937
- @config.no_harm = true
938
- when /\A--prefix=/
939
- path = a.split(/=/, 2)[1]
940
- path = File.expand_path(path) unless path[0,1] == '/'
941
- @config.install_prefix = path
517
+ def libruby
518
+ @libruby ||= RBCONFIG['prefix'] + "/lib/ruby"
519
+ end
520
+ def libruby=(path)
521
+ path = pathname(path)
522
+ @librubyver = librubyver.sub(libruby, path)
523
+ @librubyverarch = librubyverarch.sub(libruby, path)
524
+ @libruby = path
525
+ end
526
+ def librubyver
527
+ @librubyver ||= RBCONFIG['rubylibdir']
528
+ end
529
+ def librubyver=(path)
530
+ @librubyver = pathname(path)
531
+ end
532
+ def librubyverarch
533
+ @librubyverarch ||= RBCONFIG['archdir']
534
+ end
535
+ def librubyverarch=(path)
536
+ @librubyverarch = pathname(path)
537
+ end
538
+ def siteruby
539
+ @siteruby ||= RBCONFIG['sitedir']
540
+ end
541
+ def siteruby=(path)
542
+ path = pathname(path)
543
+ @siterubyver = siterubyver.sub(siteruby, path)
544
+ @siterubyverarch = siterubyverarch.sub(siteruby, path)
545
+ @siteruby = path
546
+ end
547
+ def siterubyver
548
+ @siterubyver ||= RBCONFIG['sitelibdir']
549
+ end
550
+ def siterubyver=(path)
551
+ @siterubyver = pathname(path)
552
+ end
553
+ def siterubyverarch
554
+ @siterubyverarch ||= RBCONFIG['sitearchdir']
555
+ end
556
+ def siterubyverarch=(path)
557
+ @siterubyverarch = pathname(path)
558
+ end
559
+ def bindir
560
+ @bindir || File.join(prefix, base_bindir)
561
+ end
562
+ def bindir=(path)
563
+ @bindir = pathname(path)
564
+ end
565
+ def libdir
566
+ @libdir || File.join(prefix, base_libdir)
567
+ end
568
+ def libdir=(path)
569
+ @libdir = pathname(path)
570
+ end
571
+ def datadir
572
+ @datadir || File.join(prefix, base_datadir)
573
+ end
574
+ def datadir=(path)
575
+ @datadir = pathname(path)
576
+ end
577
+ def mandir
578
+ @mandir || File.join(prefix, base_mandir)
579
+ end
580
+ def mandir=(path)
581
+ @mandir = pathname(path)
582
+ end
583
+ def docdir
584
+ @docdir || File.join(prefix, base_docdir)
585
+ end
586
+ def docdir=(path)
587
+ @docdir = pathname(path)
588
+ end
589
+ def rbdir
590
+ @rbdir || File.join(prefix, base_rubylibdir)
591
+ end
592
+ def sodir
593
+ @sodir || File.join(prefix, base_rubyarchdir)
594
+ end
595
+ def sysconfdir
596
+ @sysconfdir ||= base_sysconfdir
597
+ end
598
+ def sysconfdir=(path)
599
+ @sysconfdir = pathname(path)
600
+ end
601
+ def localstatedir
602
+ @localstatedir ||= base_localstatedir
603
+ end
604
+ def localstatedir=(path)
605
+ @localstatedir = pathname(path)
606
+ end
607
+ def rubypath
608
+ @rubypath ||= File.join(RBCONFIG['bindir'], RBCONFIG['ruby_install_name'] + RBCONFIG['EXEEXT'])
609
+ end
610
+ def rubypath=(path)
611
+ @rubypath = pathname(path)
612
+ end
613
+ def rubyprog
614
+ @rubyprog || rubypath
615
+ end
616
+ def rubyprog=(command)
617
+ @rubyprog = command
618
+ end
619
+ def makeprog
620
+ @makeprog ||= (
621
+ if arg = RBCONFIG['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
622
+ arg.sub(/'/, '').split(/=/, 2)[1]
623
+ else
624
+ 'make'
625
+ end
626
+ )
627
+ end
628
+ def makeprog=(command)
629
+ @makeprog = command
630
+ end
631
+ def extconfopt
632
+ @extconfopt ||= ''
633
+ end
634
+ def extconfopt=(string)
635
+ @extconfopt = string
636
+ end
637
+ def shebang
638
+ @shebang ||= 'ruby'
639
+ end
640
+ def shebang=(val)
641
+ if %w(all ruby never).include?(val)
642
+ @shebang = val
942
643
  else
943
- setup_rb_error "install: unknown option #{a}"
644
+ raise Error, "bad config: use SHEBANG=(all|ruby|never) [#{val}]"
944
645
  end
945
646
  end
946
- end
947
-
948
- def print_usage(out)
949
- out.puts 'Typical Installation Procedure:'
950
- out.puts " $ ruby #{File.basename $0} config"
951
- out.puts " $ ruby #{File.basename $0} setup"
952
- out.puts " # ruby #{File.basename $0} install (may require root privilege)"
953
- out.puts
954
- out.puts 'Detailed Usage:'
955
- out.puts " ruby #{File.basename $0} <global option>"
956
- out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
957
-
958
- fmt = " %-24s %s\n"
959
- out.puts
960
- out.puts 'Global options:'
961
- out.printf fmt, '-q,--quiet', 'suppress message outputs'
962
- out.printf fmt, ' --verbose', 'output messages verbosely'
963
- out.printf fmt, ' --help', 'print this message'
964
- out.printf fmt, ' --version', 'print version and quit'
965
- out.printf fmt, ' --copyright', 'print copyright and quit'
966
- out.puts
967
- out.puts 'Tasks:'
968
- TASKS.each do |name, desc|
969
- out.printf fmt, name, desc
970
- end
971
-
972
- fmt = " %-24s %s [%s]\n"
973
- out.puts
974
- out.puts 'Options for CONFIG or ALL:'
975
- @config.each do |item|
976
- out.printf fmt, item.help_opt, item.description, item.help_default
977
- end
978
- out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
979
- out.puts
980
- out.puts 'Options for INSTALL:'
981
- out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
982
- out.printf fmt, '--prefix=path', 'install path prefix', ''
983
- out.puts
984
- end
985
-
986
- #
987
- # Task Handlers
988
- #
989
-
990
- def exec_config
991
- @installer.exec_config
992
- @config.save # must be final
993
- end
994
-
995
- def exec_setup
996
- @installer.exec_setup
997
- end
998
-
999
- def exec_install
1000
- @installer.exec_install
1001
- end
1002
-
1003
- def exec_test
1004
- @installer.exec_test
1005
- end
1006
-
1007
- def exec_show
1008
- @config.each do |i|
1009
- printf "%-20s %s\n", i.name, i.value if i.value?
647
+ def no_ext
648
+ @no_ext
1010
649
  end
1011
- end
1012
-
1013
- def exec_clean
1014
- @installer.exec_clean
1015
- end
1016
-
1017
- def exec_distclean
1018
- @installer.exec_distclean
1019
- end
1020
-
1021
- end # class ToplevelInstaller
1022
-
1023
-
1024
- class ToplevelInstallerMulti < ToplevelInstaller
1025
-
1026
- include FileOperations
1027
-
1028
- def initialize(ardir_root, config)
1029
- super
1030
- @packages = directories_of("#{@ardir}/packages")
1031
- raise 'no package exists' if @packages.empty?
1032
- @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1033
- end
1034
-
1035
- def run_metaconfigs
1036
- @config.load_script "#{@ardir}/metaconfig", self
1037
- @packages.each do |name|
1038
- @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
650
+ def no_ext=(val)
651
+ @no_ext = boolean(val)
1039
652
  end
1040
- end
1041
-
1042
- attr_reader :packages
1043
-
1044
- def packages=(list)
1045
- raise 'package list is empty' if list.empty?
1046
- list.each do |name|
1047
- raise "directory packages/#{name} does not exist"\
1048
- unless File.dir?("#{@ardir}/packages/#{name}")
1049
- end
1050
- @packages = list
1051
- end
1052
-
1053
- def init_installers
1054
- @installers = {}
1055
- @packages.each do |pack|
1056
- @installers[pack] = Installer.new(@config,
1057
- "#{@ardir}/packages/#{pack}",
1058
- "packages/#{pack}")
1059
- end
1060
- with = extract_selection(config('with'))
1061
- without = extract_selection(config('without'))
1062
- @selected = @installers.keys.select {|name|
1063
- (with.empty? or with.include?(name)) \
1064
- and not without.include?(name)
1065
- }
1066
- end
1067
-
1068
- def extract_selection(list)
1069
- a = list.split(/,/)
1070
- a.each do |name|
1071
- setup_rb_error "no such package: #{name}" unless @installers.key?(name)
653
+ def no_test
654
+ @no_test
1072
655
  end
1073
- a
1074
- end
1075
-
1076
- def print_usage(f)
1077
- super
1078
- f.puts 'Inluded packages:'
1079
- f.puts ' ' + @packages.sort.join(' ')
1080
- f.puts
1081
- end
1082
-
1083
- #
1084
- # Task Handlers
1085
- #
1086
-
1087
- def exec_config
1088
- run_hook 'pre-config'
1089
- each_selected_installers {|inst| inst.exec_config }
1090
- run_hook 'post-config'
1091
- @config.save # must be final
1092
- end
1093
-
1094
- def exec_setup
1095
- run_hook 'pre-setup'
1096
- each_selected_installers {|inst| inst.exec_setup }
1097
- run_hook 'post-setup'
1098
- end
1099
-
1100
- def exec_install
1101
- run_hook 'pre-install'
1102
- each_selected_installers {|inst| inst.exec_install }
1103
- run_hook 'post-install'
1104
- end
1105
-
1106
- def exec_test
1107
- run_hook 'pre-test'
1108
- each_selected_installers {|inst| inst.exec_test }
1109
- run_hook 'post-test'
1110
- end
1111
-
1112
- def exec_clean
1113
- rm_f @config.savefile
1114
- run_hook 'pre-clean'
1115
- each_selected_installers {|inst| inst.exec_clean }
1116
- run_hook 'post-clean'
1117
- end
1118
-
1119
- def exec_distclean
1120
- rm_f @config.savefile
1121
- run_hook 'pre-distclean'
1122
- each_selected_installers {|inst| inst.exec_distclean }
1123
- run_hook 'post-distclean'
1124
- end
1125
-
1126
- #
1127
- # lib
1128
- #
1129
-
1130
- def each_selected_installers
1131
- Dir.mkdir 'packages' unless File.dir?('packages')
1132
- @selected.each do |pack|
1133
- $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1134
- Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1135
- Dir.chdir "packages/#{pack}"
1136
- yield @installers[pack]
1137
- Dir.chdir '../..'
656
+ def no_test=(val)
657
+ @no_test = boolean(val)
1138
658
  end
1139
- end
1140
-
1141
- def run_hook(id)
1142
- @root_installer.run_hook id
1143
- end
1144
-
1145
- # module FileOperations requires this
1146
- def verbose?
1147
- @config.verbose?
1148
- end
1149
-
1150
- # module FileOperations requires this
1151
- def no_harm?
1152
- @config.no_harm?
1153
- end
1154
-
1155
- end # class ToplevelInstallerMulti
1156
-
1157
-
1158
- class Installer
1159
-
1160
- FILETYPES = %w( bin lib ext data conf man )
1161
-
1162
- include FileOperations
1163
- include HookScriptAPI
1164
-
1165
- def initialize(config, srcroot, objroot)
1166
- @config = config
1167
- @srcdir = File.expand_path(srcroot)
1168
- @objdir = File.expand_path(objroot)
1169
- @currdir = '.'
1170
- end
1171
-
1172
- def inspect
1173
- "#<#{self.class} #{File.basename(@srcdir)}>"
1174
- end
1175
-
1176
- def noop(rel)
1177
- end
1178
-
1179
- #
1180
- # Hook Script API base methods
1181
- #
1182
-
1183
- def srcdir_root
1184
- @srcdir
1185
- end
1186
-
1187
- def objdir_root
1188
- @objdir
1189
- end
1190
-
1191
- def relpath
1192
- @currdir
1193
- end
1194
-
1195
- #
1196
- # Config Access
1197
- #
1198
-
1199
- # module FileOperations requires this
1200
- def verbose?
1201
- @config.verbose?
1202
- end
1203
-
1204
- # module FileOperations requires this
1205
- def no_harm?
1206
- @config.no_harm?
1207
- end
1208
-
1209
- def verbose_off
1210
- begin
1211
- save, @config.verbose = @config.verbose?, false
1212
- yield
1213
- ensure
1214
- @config.verbose = save
659
+ def no_doc
660
+ @no_doc
1215
661
  end
1216
- end
1217
-
1218
- #
1219
- # TASK config
1220
- #
1221
-
1222
- def exec_config
1223
- exec_task_traverse 'config'
1224
- end
1225
-
1226
- alias config_dir_bin noop
1227
- alias config_dir_lib noop
1228
-
1229
- def config_dir_ext(rel)
1230
- extconf if extdir?(curr_srcdir())
1231
- end
1232
-
1233
- alias config_dir_data noop
1234
- alias config_dir_conf noop
1235
- alias config_dir_man noop
1236
-
1237
- def extconf
1238
- ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1239
- end
1240
-
1241
- #
1242
- # TASK setup
1243
- #
1244
-
1245
- def exec_setup
1246
- exec_task_traverse 'setup'
1247
- end
1248
-
1249
- def setup_dir_bin(rel)
1250
- files_of(curr_srcdir()).each do |fname|
1251
- update_shebang_line "#{curr_srcdir()}/#{fname}"
662
+ def no_doc=(val)
663
+ @no_doc = boolean(val)
1252
664
  end
1253
- end
1254
-
1255
- alias setup_dir_lib noop
1256
-
1257
- def setup_dir_ext(rel)
1258
- make if extdir?(curr_srcdir())
1259
- end
1260
-
1261
- alias setup_dir_data noop
1262
- alias setup_dir_conf noop
1263
- alias setup_dir_man noop
1264
-
1265
- def update_shebang_line(path)
1266
- return if no_harm?
1267
- return if config('shebang') == 'never'
1268
- old = Shebang.load(path)
1269
- if old
1270
- $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1
1271
- new = new_shebang(old)
1272
- return if new.to_s == old.to_s
1273
- else
1274
- return unless config('shebang') == 'all'
1275
- new = Shebang.new(config('rubypath'))
1276
- end
1277
- $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
1278
- open_atomic_writer(path) {|output|
1279
- File.open(path, 'rb') {|f|
1280
- f.gets if old # discard
1281
- output.puts new.to_s
1282
- output.print f.read
1283
- }
1284
- }
1285
- end
1286
-
1287
- def new_shebang(old)
1288
- if /\Aruby/ =~ File.basename(old.cmd)
1289
- Shebang.new(config('rubypath'), old.args)
1290
- elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
1291
- Shebang.new(config('rubypath'), old.args[1..-1])
1292
- else
1293
- return old unless config('shebang') == 'all'
1294
- Shebang.new(config('rubypath'))
665
+ def no_ri
666
+ @no_ri
1295
667
  end
1296
- end
1297
-
1298
- def open_atomic_writer(path, &block)
1299
- tmpfile = File.basename(path) + '.tmp'
1300
- begin
1301
- File.open(tmpfile, 'wb', &block)
1302
- File.rename tmpfile, File.basename(path)
1303
- ensure
1304
- File.unlink tmpfile if File.exist?(tmpfile)
668
+ def no_ri=(val)
669
+ @no_ri = boolean(val)
670
+ end
671
+ def compile?
672
+ !no_ext
673
+ end
674
+ def test?
675
+ !no_test
676
+ end
677
+ def doc?
678
+ !no_doc
679
+ end
680
+ def to_h
681
+ h = {}
682
+ options.each do |name, *args|
683
+ h[name.to_s] = __send__(name)
684
+ end
685
+ h
1305
686
  end
1306
- end
1307
-
1308
- class Shebang
1309
- def Shebang.load(path)
1310
- line = nil
1311
- File.open(path) {|f|
1312
- line = f.gets
1313
- }
1314
- return nil unless /\A#!/ =~ line
1315
- parse(line)
1316
- end
1317
-
1318
- def Shebang.parse(line)
1319
- cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
1320
- new(cmd, args)
1321
- end
1322
-
1323
- def initialize(cmd, args = [])
1324
- @cmd = cmd
1325
- @args = args
1326
- end
1327
-
1328
- attr_reader :cmd
1329
- attr_reader :args
1330
-
1331
687
  def to_s
1332
- "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
688
+ to_yaml.sub(/\A---\s*\n/,'')
1333
689
  end
1334
- end
1335
-
1336
- #
1337
- # TASK install
1338
- #
1339
-
1340
- def exec_install
1341
- rm_f 'InstalledFiles'
1342
- exec_task_traverse 'install'
1343
- end
1344
-
1345
- def install_dir_bin(rel)
1346
- install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1347
- end
1348
-
1349
- def install_dir_lib(rel)
1350
- install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
1351
- end
1352
-
1353
- def install_dir_ext(rel)
1354
- return unless extdir?(curr_srcdir())
1355
- install_files rubyextentions('.'),
1356
- "#{config('sodir')}/#{File.dirname(rel)}",
1357
- 0555
1358
- end
1359
-
1360
- def install_dir_data(rel)
1361
- install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
1362
- end
1363
-
1364
- def install_dir_conf(rel)
1365
- # FIXME: should not remove current config files
1366
- # (rename previous file to .old/.org)
1367
- install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
1368
- end
1369
-
1370
- def install_dir_man(rel)
1371
- install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
1372
- end
1373
-
1374
- def install_files(list, dest, mode)
1375
- mkdir_p dest, @config.install_prefix
1376
- list.each do |fname|
1377
- install fname, dest, mode, @config.install_prefix
690
+ def to_yaml(*args)
691
+ to_h.to_yaml(*args)
1378
692
  end
1379
- end
1380
-
1381
- def libfiles
1382
- glob_reject(%w(*.y *.output), targetfiles())
1383
- end
1384
-
1385
- def rubyextentions(dir)
1386
- ents = glob_select("*.#{@config.dllext}", targetfiles())
1387
- if ents.empty?
1388
- setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
693
+ def save_config
694
+ out = to_yaml
695
+ if not File.exist?(File.dirname(CONFIG_FILE))
696
+ FileUtils.mkdir_p(File.dirname(CONFIG_FILE))
697
+ end
698
+ if File.exist?(CONFIG_FILE)
699
+ txt = File.read(CONFIG_FILE)
700
+ return nil if txt == out
701
+ end
702
+ File.open(CONFIG_FILE, 'w'){ |f| f << out }
703
+ true
704
+ end
705
+ def exist?
706
+ File.exist?(CONFIG_FILE)
707
+ end
708
+ private
709
+ def pathname(path)
710
+ path.gsub(%r<\\$([^/]+)>){ self[$1] }
711
+ end
712
+ def boolean(val, name=nil)
713
+ case val
714
+ when true, false, nil
715
+ val
716
+ else
717
+ case val.to_s.downcase
718
+ when 'y', 'yes', 't', 'true'
719
+ true
720
+ when 'n', 'no', 'f', 'false'
721
+ false
722
+ else
723
+ raise Error, "bad config: use --#{name}=(yes|no) [\#{val}]"
724
+ end
725
+ end
726
+ end
727
+ def subprefix(path, with='')
728
+ val = RBCONFIG[path]
729
+ raise "Unknown path -- #{path}" if val.nil?
730
+ prefix = Regexp.quote(RBCONFIG['prefix'])
731
+ val.sub(/\A#{prefix}/, with)
732
+ end
733
+ def home
734
+ ENV['HOME'] || raise(Error, 'HOME is not set.')
735
+ end
736
+ end #class ConfigTable
737
+ end #module Setup
738
+ =begin
739
+ def inintialize_metaconfig
740
+ path = Dir.glob(METACONFIG_FILE).first
741
+ if path && File.file?(path)
742
+ MetaConfigEnvironment.new(self).instance_eval(File.read(path), path)
743
+ end
744
+ end
745
+ class MetaConfigEnvironment
746
+ def initialize(config) #, installer)
747
+ @config = config
748
+ end
749
+ def config_names
750
+ @config.descriptions.collect{ |n, t, d| n.to_s }
751
+ end
752
+ def config?(name)
753
+ @config.descriptions.find do |sym, type, desc|
754
+ sym.to_s == name.to_s
755
+ end
756
+ end
757
+ def bool_config?(name)
758
+ @config.descriptions.find do |sym, type, desc|
759
+ sym.to_s == name.to_s && type == :bool
760
+ end
761
+ end
762
+ def path_config?(name)
763
+ @config.descriptions.find do |sym, type, desc|
764
+ sym.to_s == name.to_s && type == :path
765
+ end
766
+ end
767
+ def value_config?(name)
768
+ @config.descriptions.find do |sym, type, desc|
769
+ sym.to_s == name.to_s && type != :prog
770
+ end
771
+ end
772
+ def add_config(name, default, desc)
773
+ @config.descriptions << [name.to_sym, nil, desc]
774
+ end
775
+ def add_bool_config(name, default, desc)
776
+ @config.descriptions << [name.to_sym, :bool, desc]
777
+ end
778
+ def add_path_config(name, default, desc)
779
+ @config.descriptions << [name.to_sym, :path, desc]
780
+ end
781
+ def set_config_default(name, default)
782
+ @config[name] = default
783
+ end
784
+ def remove_config(name)
785
+ item = @config.descriptions.find do |sym, type, desc|
786
+ sym.to_s == name.to_s
787
+ end
788
+ index = @config.descriptions.index(item)
789
+ @config.descriptions.delete(index)
790
+ end
791
+ end
792
+ =end
793
+ module Setup
794
+ class Installer < Base
795
+ def install_prefix
796
+ config.install_prefix
797
+ end
798
+ def install
799
+ Dir.chdir(rootdir) do
800
+ install_bin
801
+ install_ext
802
+ install_lib
803
+ install_data
804
+ install_man
805
+ install_doc
806
+ install_etc
807
+ prune_install_record
808
+ end
809
+ end
810
+ def install_bin
811
+ return unless directory?('bin')
812
+ report_transfer('bin', config.bindir)
813
+ files = files('bin')
814
+ install_files('bin', files, config.bindir, 0755)
815
+ end
816
+ def install_ext
817
+ return unless directory?('ext')
818
+ report_transfer('ext', config.sodir)
819
+ files = files('ext')
820
+ files = select_dllext(files)
821
+ files.each do |file|
822
+ name = File.join(File.dirname(File.dirname(file)), File.basename(file))
823
+ dest = destination(config.sodir, name)
824
+ install_file('ext', file, dest, 0555, install_prefix)
825
+ end
826
+ end
827
+ def install_lib
828
+ return unless directory?('lib')
829
+ report_transfer('lib', config.rbdir)
830
+ files = files('lib')
831
+ install_files('lib', files, config.rbdir, 0644)
832
+ end
833
+ def install_data
834
+ return unless directory?('data')
835
+ report_transfer('data', config.datadir)
836
+ files = files('data')
837
+ install_files('data', files, config.datadir, 0644)
838
+ end
839
+ def install_etc
840
+ return unless directory?('etc')
841
+ report_transfer('etc', config.sysconfdir)
842
+ files = files('etc')
843
+ install_files('etc', files, config.sysconfdir, 0644)
844
+ end
845
+ def install_man
846
+ return unless directory?('man')
847
+ report_transfer('man', config.mandir)
848
+ files = files('man')
849
+ install_files('man', files, config.mandir, 0644)
850
+ end
851
+ def install_doc
852
+ return unless config.doc?
853
+ return unless directory?('doc')
854
+ return unless project.name
855
+ dir = File.join(config.docdir, "ruby-#{project.name}")
856
+ report_transfer('doc', dir)
857
+ files = files('doc')
858
+ install_files('doc', files, dir, 0644)
859
+ end
860
+ private
861
+ def report_transfer(source, directory)
862
+ unless quiet?
863
+ if install_prefix
864
+ out = File.join(install_prefix, directory)
865
+ else
866
+ out = directory
867
+ end
868
+ io.puts "* #{source} -> #{out}"
869
+ end
870
+ end
871
+ def directory?(path)
872
+ File.directory?(path)
873
+ end
874
+ def files(dir)
875
+ files = Dir["#{dir}/**/*"]
876
+ files = files.select{ |f| File.file?(f) }
877
+ files = files.map{ |f| f.sub("#{dir}/", '') }
878
+ files
879
+ end
880
+ def select_dllext(files)
881
+ ents = files.select do |file|
882
+ File.extname(file) == ".#{dllext}"
883
+ end
884
+ if ents.empty? && !files.empty?
885
+ raise Error, "ruby extention not compiled: 'setup.rb compile' first"
886
+ end
887
+ ents
888
+ end
889
+ def dllext
890
+ config.dlext
891
+ end
892
+ def install_files(dir, list, dest, mode)
893
+ list.each do |fname|
894
+ rdest = destination(dest, fname)
895
+ install_file(dir, fname, rdest, mode, install_prefix)
896
+ end
897
+ end
898
+ def install_file(dir, from, dest, mode, prefix=nil)
899
+ mkdir_p(File.dirname(dest))
900
+ if trace? or trial?
901
+ io.puts "install #{dir}/#{from} #{dest}"
902
+ end
903
+ return if trial?
904
+ str = binread(File.join(dir, from))
905
+ if diff?(str, dest)
906
+ trace_off {
907
+ rm_f(dest) if File.exist?(dest)
908
+ }
909
+ File.open(dest, 'wb'){ |f| f.write(str) }
910
+ File.chmod(mode, dest)
911
+ end
912
+ record_installation(dest) # record file as installed
913
+ end
914
+ def mkdir_p(dirname) #, prefix=nil)
915
+ return if File.directory?(dirname)
916
+ io.puts "mkdir -p #{dirname}" if trace? or trial?
917
+ return if trial?
918
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
919
+ if /\A[a-z]:\z/i =~ dirs[0]
920
+ disk = dirs.shift
921
+ dirs[0] = disk + dirs[0]
922
+ end
923
+ dirs.each_index do |idx|
924
+ path = dirs[0..idx].join('')
925
+ unless File.dir?(path)
926
+ Dir.mkdir(path)
927
+ end
928
+ record_installation(path) # record directories made
929
+ end
930
+ end
931
+ def record_installation(path)
932
+ File.open(install_record, 'a') do |f|
933
+ f.puts(path)
934
+ end
935
+ end
936
+ def prune_install_record
937
+ entries = File.read(install_record).split("\n")
938
+ entries.uniq!
939
+ File.open(install_record, 'w') do |f|
940
+ f << entries.join("\n")
941
+ f << "\n"
942
+ end
943
+ end
944
+ def install_record
945
+ @install_record ||= (
946
+ file = INSTALL_RECORD
947
+ dir = File.dirname(file)
948
+ unless File.directory?(dir)
949
+ FileUtils.mkdir_p(dir)
950
+ end
951
+ file
952
+ )
953
+ end
954
+ def destination(dir, file)
955
+ dest = install_prefix ? File.join(install_prefix, File.expand_path(dir)) : dir
956
+ dest = File.join(dest, file) #if File.dir?(dest)
957
+ dest = File.expand_path(dest)
958
+ dest
959
+ end
960
+ def diff?(new_content, path)
961
+ return true unless File.exist?(path)
962
+ new_content != binread(path)
963
+ end
964
+ def binread(fname)
965
+ File.open(fname, 'rb') do |f|
966
+ return f.read
967
+ end
968
+ end
969
+ def install_shebang(files, dir)
970
+ files.each do |file|
971
+ path = File.join(dir, File.basename(file))
972
+ update_shebang_line(path)
973
+ end
974
+ end
975
+ def update_shebang_line(path)
976
+ return if trial?
977
+ return if config.shebang == 'never'
978
+ old = Shebang.load(path)
979
+ if old
980
+ if old.args.size > 1
981
+ $stderr.puts "warning: #{path}"
982
+ $stderr.puts "Shebang line has too many args."
983
+ $stderr.puts "It is not portable and your program may not work."
984
+ end
985
+ new = new_shebang(old)
986
+ return if new.to_s == old.to_s
987
+ else
988
+ return unless config.shebang == 'all'
989
+ new = Shebang.new(config.rubypath)
990
+ end
991
+ $stderr.puts "updating shebang: #{File.basename(path)}" if trace?
992
+ open_atomic_writer(path) do |output|
993
+ File.open(path, 'rb') do |f|
994
+ f.gets if old # discard
995
+ output.puts new.to_s
996
+ output.print f.read
997
+ end
998
+ end
999
+ end
1000
+ def new_shebang(old)
1001
+ if /\Aruby/ =~ File.basename(old.cmd)
1002
+ Shebang.new(config.rubypath, old.args)
1003
+ elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
1004
+ Shebang.new(config.rubypath, old.args[1..-1])
1005
+ else
1006
+ return old unless config.shebang == 'all'
1007
+ Shebang.new(config.rubypath)
1008
+ end
1009
+ end
1010
+ def open_atomic_writer(path, &block)
1011
+ tmpfile = File.basename(path) + '.tmp'
1012
+ begin
1013
+ File.open(tmpfile, 'wb', &block)
1014
+ File.rename tmpfile, File.basename(path)
1015
+ ensure
1016
+ File.unlink tmpfile if File.exist?(tmpfile)
1017
+ end
1018
+ end
1019
+ class Shebang
1020
+ def Shebang.load(path)
1021
+ line = nil
1022
+ File.open(path) {|f|
1023
+ line = f.gets
1024
+ }
1025
+ return nil unless /\A#!/ =~ line
1026
+ parse(line)
1027
+ end
1028
+ def Shebang.parse(line)
1029
+ cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
1030
+ new(cmd, args)
1031
+ end
1032
+ def initialize(cmd, args = [])
1033
+ @cmd = cmd
1034
+ @args = args
1035
+ end
1036
+ attr_reader :cmd
1037
+ attr_reader :args
1038
+ def to_s
1039
+ "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
1040
+ end
1389
1041
  end
1390
- ents
1391
- end
1392
-
1393
- def targetfiles
1394
- mapdir(existfiles() - hookfiles())
1395
- end
1396
-
1397
- def mapdir(ents)
1398
- ents.map {|ent|
1399
- if File.exist?(ent)
1400
- then ent # objdir
1401
- else "#{curr_srcdir()}/#{ent}" # srcdir
1402
- end
1403
- }
1404
- end
1405
-
1406
- # picked up many entries from cvs-1.11.1/src/ignore.c
1407
- JUNK_FILES = %w(
1408
- core RCSLOG tags TAGS .make.state
1409
- .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1410
- *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1411
-
1412
- *.org *.in .*
1413
- )
1414
-
1415
- def existfiles
1416
- glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1417
- end
1418
-
1419
- def hookfiles
1420
- %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1421
- %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1422
- }.flatten
1423
- end
1424
-
1425
- def glob_select(pat, ents)
1426
- re = globs2re([pat])
1427
- ents.select {|ent| re =~ ent }
1428
- end
1429
-
1430
- def glob_reject(pats, ents)
1431
- re = globs2re(pats)
1432
- ents.reject {|ent| re =~ ent }
1433
- end
1434
-
1435
- GLOB2REGEX = {
1436
- '.' => '\.',
1437
- '$' => '\$',
1438
- '#' => '\#',
1439
- '*' => '.*'
1440
- }
1441
-
1442
- def globs2re(pats)
1443
- /\A(?:#{
1444
- pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
1445
- })\z/
1446
- end
1447
-
1448
- #
1449
- # TASK test
1450
- #
1451
-
1452
- TESTDIR = 'test'
1453
-
1454
- def exec_test
1455
- unless File.directory?('test')
1456
- $stderr.puts 'no test in this package' if verbose?
1457
- return
1458
- end
1459
- $stderr.puts 'Running tests...' if verbose?
1460
- begin
1461
- require 'test/unit'
1462
- rescue LoadError
1463
- setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
1464
- end
1465
- runner = Test::Unit::AutoRunner.new(true)
1466
- runner.to_run << TESTDIR
1467
- runner.run
1468
- end
1469
-
1470
- #
1471
- # TASK clean
1472
- #
1473
-
1474
- def exec_clean
1475
- exec_task_traverse 'clean'
1476
- rm_f @config.savefile
1477
- rm_f 'InstalledFiles'
1478
- end
1479
-
1480
- alias clean_dir_bin noop
1481
- alias clean_dir_lib noop
1482
- alias clean_dir_data noop
1483
- alias clean_dir_conf noop
1484
- alias clean_dir_man noop
1485
-
1486
- def clean_dir_ext(rel)
1487
- return unless extdir?(curr_srcdir())
1488
- make 'clean' if File.file?('Makefile')
1489
- end
1490
-
1491
- #
1492
- # TASK distclean
1493
- #
1494
-
1495
- def exec_distclean
1496
- exec_task_traverse 'distclean'
1497
- rm_f @config.savefile
1498
- rm_f 'InstalledFiles'
1499
- end
1500
-
1501
- alias distclean_dir_bin noop
1502
- alias distclean_dir_lib noop
1503
-
1504
- def distclean_dir_ext(rel)
1505
- return unless extdir?(curr_srcdir())
1506
- make 'distclean' if File.file?('Makefile')
1507
- end
1508
-
1509
- alias distclean_dir_data noop
1510
- alias distclean_dir_conf noop
1511
- alias distclean_dir_man noop
1512
-
1513
- #
1514
- # Traversing
1515
- #
1516
-
1517
- def exec_task_traverse(task)
1518
- run_hook "pre-#{task}"
1519
- FILETYPES.each do |type|
1520
- if type == 'ext' and config('without-ext') == 'yes'
1521
- $stderr.puts 'skipping ext/* by user option' if verbose?
1522
- next
1523
- end
1524
- traverse task, type, "#{task}_dir_#{type}"
1525
- end
1526
- run_hook "post-#{task}"
1527
- end
1528
-
1529
- def traverse(task, rel, mid)
1530
- dive_into(rel) {
1531
- run_hook "pre-#{task}"
1532
- __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1533
- directories_of(curr_srcdir()).each do |d|
1534
- traverse task, "#{rel}/#{d}", mid
1535
- end
1536
- run_hook "post-#{task}"
1537
- }
1538
1042
  end
1539
-
1540
- def dive_into(rel)
1541
- return unless File.dir?("#{@srcdir}/#{rel}")
1542
-
1543
- dir = File.basename(rel)
1544
- Dir.mkdir dir unless File.dir?(dir)
1545
- prevdir = Dir.pwd
1546
- Dir.chdir dir
1547
- $stderr.puts '---> ' + rel if verbose?
1548
- @currdir = rel
1549
- yield
1550
- Dir.chdir prevdir
1551
- $stderr.puts '<--- ' + rel if verbose?
1552
- @currdir = File.dirname(rel)
1043
+ end
1044
+ module Setup
1045
+ class Tester < Base
1046
+ RUBYSCRIPT = META_EXTENSION_DIR + '/test.rb'
1047
+ SHELLSCRIPT = META_EXTENSION_DIR + '/test.sh'
1048
+ DEPRECATED_RUBYSCRIPT = META_EXTENSION_DIR + '/testrc.rb'
1049
+ def testable?
1050
+ if File.exist?(DEPRECATED_RUBYSCRIPT)
1051
+ warn "Must use `.setup/test.rb' instead or `.setup/testrc.rb' to support testing."
1052
+ end
1053
+ return false if config.no_test
1054
+ return true if File.exist?(RUBYSCRIPT)
1055
+ return true if File.exist?(SHELLSCRIPT)
1056
+ false
1057
+ end
1058
+ def test
1059
+ return true unless testable?
1060
+ if File.exist?(RUBYSCRIPT)
1061
+ test_rubyscript
1062
+ elsif File.exist?(SHELLSCRIPT)
1063
+ test_shellscript
1064
+ else
1065
+ true
1066
+ end
1067
+ end
1068
+ def test_shellscript
1069
+ bash(SHELLSCRIPT)
1070
+ end
1071
+ def test_rubyscript
1072
+ ruby(RUBYSCRIPT)
1073
+ end
1553
1074
  end
1554
-
1555
- def run_hook(id)
1556
- path = [ "#{curr_srcdir()}/#{id}",
1557
- "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
1558
- return unless path
1559
- begin
1560
- instance_eval File.read(path), path, 1
1561
- rescue
1562
- raise if $DEBUG
1563
- setup_rb_error "hook #{path} failed:\n" + $!.message
1075
+ end
1076
+ module Setup
1077
+ class Uninstaller < Base
1078
+ def uninstall
1079
+ return unless File.exist?(INSTALL_RECORD)
1080
+ files = []
1081
+ dirs = []
1082
+ paths.each do |path|
1083
+ dirs << path if File.dir?(path)
1084
+ files << path if File.file?(path)
1085
+ end
1086
+ if dirs.empty? && files.empty?
1087
+ io.outs "Nothing to remove."
1088
+ return
1089
+ end
1090
+ files.sort!{ |a,b| b.size <=> a.size }
1091
+ dirs.sort!{ |a,b| b.size <=> a.size }
1092
+ if !force? && !trial?
1093
+ puts (files + dirs).collect{ |f| "#{f}" }.join("\n")
1094
+ puts
1095
+ puts "Must use --force option to remove these files and directories that become empty."
1096
+ return
1097
+ end
1098
+ files.each do |file|
1099
+ rm_f(file)
1100
+ end
1101
+ dirs.each do |dir|
1102
+ entries = Dir.entries(dir)
1103
+ entries.delete('.')
1104
+ entries.delete('..')
1105
+ rmdir(dir) if entries.empty?
1106
+ end
1107
+ rm_f(INSTALL_RECORD)
1108
+ end
1109
+ private
1110
+ def paths
1111
+ @paths ||= (
1112
+ lines = File.read(INSTALL_RECORD).split(/\s*\n/)
1113
+ lines = lines.map{ |line| line.strip }
1114
+ lines = lines.uniq
1115
+ lines = lines.reject{ |line| line.empty? } # skip blank lines
1116
+ lines = lines.reject{ |line| line[0,1] == '#' } # skip blank lines
1117
+ lines
1118
+ )
1564
1119
  end
1565
1120
  end
1566
-
1567
- end # class Installer
1568
-
1569
-
1570
- class SetupError < StandardError; end
1571
-
1572
- def setup_rb_error(msg)
1573
- raise SetupError, msg
1574
1121
  end
1575
-
1576
- if $0 == __FILE__
1577
- begin
1578
- ToplevelInstaller.invoke
1579
- rescue SetupError
1580
- raise if $DEBUG
1581
- $stderr.puts $!.message
1582
- $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1583
- exit 1
1122
+ require 'optparse'
1123
+ module Setup
1124
+ class Command
1125
+ def self.run(*argv)
1126
+ new.run(*argv)
1127
+ end
1128
+ def self.tasks
1129
+ @tasks ||= {}
1130
+ end
1131
+ def self.order
1132
+ @order ||= []
1133
+ end
1134
+ def self.task(name, description)
1135
+ tasks[name] = description
1136
+ order << name
1137
+ end
1138
+ task 'show' , "show current configuration"
1139
+ task 'all' , "config, compile and install"
1140
+ task 'config' , "save/customize configuration settings"
1141
+ task 'compile' , "compile ruby extentions"
1142
+ task 'test' , "run test suite"
1143
+ task 'install' , "install project files"
1144
+ task 'clean' , "does `make clean' for each extention"
1145
+ task 'distclean', "does `make distclean' for each extention"
1146
+ task 'uninstall', "uninstall previously installed files"
1147
+ def run(*argv)
1148
+ ARGV.replace(argv) unless argv.empty?
1149
+ task = ARGV.find{ |a| a !~ /^[-]/ }
1150
+ task = 'all' unless task
1151
+ unless task_names.include?(task)
1152
+ $stderr.puts "Not a valid task -- #{task}"
1153
+ exit 1
1154
+ end
1155
+ parser = OptionParser.new
1156
+ options = {}
1157
+ parser.banner = "Usage: #{File.basename($0)} [TASK] [OPTIONS]"
1158
+ optparse_header(parser, options)
1159
+ case task
1160
+ when 'config'
1161
+ optparse_config(parser, options)
1162
+ when 'compile'
1163
+ optparse_compile(parser, options)
1164
+ when 'install'
1165
+ optparse_install(parser, options)
1166
+ when 'all'
1167
+ optparse_all(parser, options)
1168
+ end
1169
+ optparse_common(parser, options)
1170
+ begin
1171
+ parser.parse!(ARGV)
1172
+ rescue OptionParser::InvalidOption
1173
+ $stderr.puts $!.to_s.capitalize
1174
+ exit 1
1175
+ end
1176
+ rootdir = session.project.rootdir
1177
+ print_header
1178
+ begin
1179
+ $stderr.puts "(#{RUBY_ENGINE} #{RUBY_VERSION} #{RUBY_PLATFORM})"
1180
+ rescue
1181
+ $stderr.puts "(#{RUBY_VERSION} #{RUBY_PLATFORM})"
1182
+ end
1183
+ begin
1184
+ session.__send__(task)
1185
+ rescue Error => err
1186
+ raise err if $DEBUG
1187
+ $stderr.puts $!.message
1188
+ $stderr.puts "Try 'setup.rb --help' for detailed usage."
1189
+ abort $!.message #exit 1
1190
+ end
1191
+ puts unless session.quiet?
1192
+ end
1193
+ def session
1194
+ @session ||= Session.new(:io=>$stdout)
1195
+ end
1196
+ def configuration
1197
+ @configuration ||= session.configuration
1198
+ end
1199
+ def optparse_header(parser, options)
1200
+ parser.banner = "USAGE: #{File.basename($0)} [command] [options]"
1201
+ end
1202
+ def optparse_all(parser, options)
1203
+ optparse_config(parser, options)
1204
+ optparse_compile(parser, options)
1205
+ optparse_install(parser, options) # TODO: why was this remarked out ?
1206
+ end
1207
+ def optparse_config(parser, options)
1208
+ parser.separator ""
1209
+ parser.separator "Configuration options:"
1210
+ configuration.options.each do |args|
1211
+ args = args.dup
1212
+ desc = args.pop
1213
+ type = args.pop
1214
+ name, shortcut = *args
1215
+ optname = name.to_s.gsub('_', '-')
1216
+ case type
1217
+ when :bool
1218
+ if optname.index('no-') == 0
1219
+ optname = "[no-]" + optname.sub(/^no-/, '')
1220
+ opts = shortcut ? ["-#{shortcut}", "--#{optname}", desc] : ["--#{optname}", desc]
1221
+ parser.on(*opts) do |val|
1222
+ configuration.__send__("#{name}=", !val)
1223
+ end
1224
+ else
1225
+ optname = "[no-]" + optname.sub(/^no-/, '')
1226
+ opts = shortcut ? ["-#{shortcut}", "--#{optname}", desc] : ["--#{optname}", desc]
1227
+ parser.on(*opts) do |val|
1228
+ configuration.__send__("#{name}=", val)
1229
+ end
1230
+ end
1231
+ else
1232
+ opts = shortcut ? ["-#{shortcut}", "--#{optname} #{type.to_s.upcase}", desc] :
1233
+ ["--#{optname} #{type.to_s.upcase}", desc]
1234
+ parser.on(*opts) do |val|
1235
+ configuration.__send__("#{name}=", val)
1236
+ end
1237
+ end
1238
+ end
1239
+ end
1240
+ def optparse_compile(parser, options)
1241
+ end
1242
+ def optparse_install(parser, options)
1243
+ parser.separator ''
1244
+ parser.separator 'Install options:'
1245
+ parser.on('--prefix PATH', 'install to alternate root location') do |val|
1246
+ configuration.install_prefix = val
1247
+ end
1248
+ parser.on('--type TYPE', "install location mode (site,std,home)") do |val|
1249
+ configuration.type = val
1250
+ end
1251
+ parser.on('-t', '--[no-]test', "run pre-installation tests") do |bool|
1252
+ configuration.test = bool
1253
+ end
1254
+ end
1255
+ def optparse_common(parser, options)
1256
+ parser.separator ""
1257
+ parser.separator "General options:"
1258
+ parser.on("-q", "--quiet", "Suppress output") do
1259
+ session.quiet = true
1260
+ end
1261
+ parser.on("-f", "--force", "Force operation") do
1262
+ session.force = true
1263
+ end
1264
+ parser.on("--trace", "--verbose", "Watch execution") do |val|
1265
+ session.trace = true
1266
+ end
1267
+ parser.on("--trial", "--no-harm", "Do not write to disk") do |val|
1268
+ session.trial = true
1269
+ end
1270
+ parser.on("--debug", "Turn on debug mode") do |val|
1271
+ $DEBUG = true
1272
+ end
1273
+ parser.separator ""
1274
+ parser.separator "Inform options:"
1275
+ parser.on_tail("-h", "--help", "display this help information") do
1276
+ puts parser
1277
+ exit
1278
+ end
1279
+ parser.on_tail("--version", "-v", "Show version") do
1280
+ puts File.basename($0) + ' v' + Setup::VERSION #Version.join('.')
1281
+ exit
1282
+ end
1283
+ parser.on_tail("--copyright", "Show copyright") do
1284
+ puts Setup::COPYRIGHT #opyright
1285
+ exit
1286
+ end
1287
+ end
1288
+ def task_names
1289
+ self.class.tasks.keys
1290
+ end
1291
+ def print_header
1292
+ end
1584
1293
  end
1585
1294
  end
1295
+ Setup::Command.run