guid 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (7) hide show
  1. data/CHANGES +2 -0
  2. data/FAQ +82 -0
  3. data/README +70 -0
  4. data/Rakefile +70 -0
  5. data/install.rb +1298 -0
  6. data/lib/guid.rb +153 -0
  7. metadata +62 -0
data/CHANGES ADDED
@@ -0,0 +1,2 @@
1
+ 0.1.0
2
+ - Forked uuid project - http://rubyforge.org/projects/uuid
data/FAQ ADDED
@@ -0,0 +1,82 @@
1
+ What is GUID/UUID?
2
+ ==================
3
+
4
+ A GUID (Globally Unique Identifier) or UUID (Universally Unique Identifer)
5
+ is a 128-bit value that is supposed to be unique across time and space
6
+ dimension. This means that if you create a GUID, it will be different from
7
+ another GUID previously created, or from GUID created by someone else on a
8
+ different computer, even at the same time.
9
+
10
+ A GUID is usually represented by hexadecimal notation like this:
11
+
12
+ {24cb2bdc-e604-809f-fb74-077c201e009e}
13
+ 24cb2bdc-e604-809f-fb74-077c201e009e
14
+ 24cb2bdce604809ffb74077c201e009e
15
+
16
+ There are various algorithms to generate GUID, including one that uses MAC
17
+ address and current timestamp, and one that uses random number. The Ruby
18
+ Guid library uses the latter.
19
+
20
+
21
+ What is the difference between GUID and UUID?
22
+ =============================================
23
+
24
+ None except the name. GUID is how Microsoft calls UUID, and it seems to be
25
+ the more popular one because Microsoft uses GUID/UUID extensively.
26
+
27
+
28
+ What is GUID good for?
29
+ ======================
30
+
31
+ It is primarily used to generate primary key for database tables, or for
32
+ some sort of ID that needs to be globally unique (like in P2P applications
33
+ or in distributed computing).
34
+
35
+ What makes GUID especially useful is that you can create it autonomously. If
36
+ instead of GUID you use a two-part ID (local ID + node ID), or a
37
+ hierarchical ID (like DNS or public IP address), then you need to contact
38
+ another node or some sort of numbering authority.
39
+
40
+
41
+ Is GUID really globally unique?
42
+ ===============================
43
+
44
+ Yes, you can say it's statistically unique, meaning that the chance of
45
+ duplicate GUIDs are very, very, very small. The chance of generating two
46
+ same GUIDs consecutively are 2^-128 (2.9e-39). Even If your table contains a
47
+ billion rows, the chance of creating a GUID that collides with an existing
48
+ primary key is 2.9e-30. To appreciate the scale, the chance of GUID
49
+ collision is:
50
+
51
+ * about the same as 16 random people that you put into a room all having the
52
+ same birthday (assuming the birthday distribution is uniform);
53
+ * smaller than your computer parts (harddisk, RAM) failing;
54
+ * smaller than you winning a multistate lottery;
55
+ * smaller than you winning a multistate lottery twice!
56
+ * smaller than you being struck by a lightning multiple times!
57
+
58
+ So for most practical purposes, you can assume it's unique. If you are still
59
+ not convinced, try generating 1 million (or 100 millions) of GUIDs using the
60
+ Ruby Guid library and try finding a duplicate. If you do find one, consider
61
+ yourself very, very, very lucky (or unlucky :-).
62
+
63
+ But actually, GUID is not mathematically unique. Meaning the probability of
64
+ duplication is not exactly zero, just a very small number.
65
+
66
+
67
+ But isn't GUID produced using MAC address really unique?
68
+ ========================================================
69
+
70
+ Not really. MAC addresses have been known to be not unique. Many cards also
71
+ allow their MAC addresses to be set. This, along with the problem of clock
72
+ rewinding, is probably one of the reasons why Microsoft switched their GUID
73
+ algorithm to using random number instead. (Another reason is the complaint
74
+ that using MAC address raises privacy concern).
75
+
76
+
77
+ Why do you use /dev/urandom instead of /dev/random?
78
+ ===================================================
79
+
80
+ Because /dev/random blocks.
81
+
82
+
data/README ADDED
@@ -0,0 +1,70 @@
1
+ NAME
2
+
3
+ Guid - Produce GUID/UUID from Ruby
4
+
5
+
6
+ SYNOPSIS
7
+
8
+ require 'guid'
9
+
10
+ # generate a GUID
11
+ g = Guid.new
12
+ puts g # 79328095-636a-6cc5-2bbb-606df7228a01
13
+ puts g.to_s # 79328095-636a-6cc5-2bbb-606df7228a01
14
+ puts g.hexdigest # 79328095636a6cc52bbb606df7228a01
15
+ puts g.raw.inspect # "\227#\010Y6\246\306\\\262\273\006\326\177\"\250\020"
16
+ puts g.raw.length # 16
17
+
18
+ # generate another GUID, should be different everytime
19
+ g2 = Guid.new
20
+ puts g == g2 # false (it better be! :-)
21
+
22
+ # convert a hexstring into Guid object
23
+ g3 = Guid.from_s("79328095-636a-6cc5-2bbb-606df7228a01")
24
+ puts g3 # 79328095-636a-6cc5-2bbb-606df7228a01
25
+ puts g == g3 # true
26
+
27
+ # convert a raw 16-byte string into Guid object
28
+ g4 = Guid.from_raw("\227#\010Y6\246\306\\\262\273\006\326\177\"\250\020")
29
+ puts g4 # 79328095-636a-6cc5-2bbb-606df7228a01
30
+ puts g == g4 # true
31
+
32
+
33
+ DESCRIPTION
34
+
35
+ This library can produce GUID/UUID on Windows (except first release of
36
+ Win95 and older version) and on Unix using random number. I have only
37
+ tested this library under Win2k and Redhat 7.3; please report if you fail
38
+ to use it on other platforms. On Windows, it uses CryptGenRandom(). On
39
+ Unix, it uses /dev/urandom (and if fail, try to use /dev/random). No other
40
+ external program or library is needed.
41
+
42
+ The latest version of this library can be obtained from:
43
+
44
+ http://rubyforge.org/projects/uuid/
45
+
46
+ To install:
47
+
48
+ % ruby install.rb config
49
+ % ruby install.rb setup
50
+ # ruby install.rb install
51
+
52
+
53
+ SEE ALSO
54
+
55
+ * FAQ
56
+
57
+
58
+ CREDITS
59
+
60
+ * Thanks to Stephen Veit <sveit at earthlink net> for pointing out how to
61
+ use Win32API.
62
+
63
+
64
+ LICENSE
65
+
66
+ Copyright (c) 2004 David Garamond <davegaramond at icqmail com>.
67
+
68
+ This library is free software; you can redistribute it and/or modify it
69
+ under the same terms as Ruby itself.
70
+
@@ -0,0 +1,70 @@
1
+ require "rake"
2
+ require 'rake/gempackagetask'
3
+ require 'rake/contrib/rubyforgepublisher'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rake/rdoctask'
7
+
8
+ desc "Runs the Rspec suite"
9
+ task(:default) do
10
+ run_suite
11
+ end
12
+
13
+ desc "Runs the Rspec suite"
14
+ task(:spec) do
15
+ run_suite
16
+ end
17
+
18
+ desc "Copies the trunk to a tag with the name of the current release"
19
+ task(:tag_release) do
20
+ tag_release
21
+ end
22
+
23
+ def run_suite
24
+ dir = File.dirname(__FILE__)
25
+ system("ruby #{dir}/spec/spec_suite.rb") || raise("Example Suite failed")
26
+ end
27
+
28
+ PKG_NAME = "guid"
29
+ PKG_VERSION = "0.1.0"
30
+ PKG_FILES = FileList[
31
+ '[A-Z]*',
32
+ '*.rb',
33
+ 'lib/**/*.rb',
34
+ 'core/**',
35
+ 'bin/**',
36
+ 'spec/**/*.rb'
37
+ ]
38
+
39
+ spec = Gem::Specification.new do |s|
40
+ s.name = PKG_NAME
41
+ s.version = PKG_VERSION
42
+ s.summary = "Guid is a Ruby library for portable GUID/UUID generation. At the moment it can be used on Windows (except first release of Win95 and older) and on Unix. This is a fork of David Garamond's ruby-uuid library."
43
+ s.test_files = "spec/spec_suite.rb"
44
+ s.description = s.summary
45
+
46
+ s.files = PKG_FILES.to_a
47
+ s.require_path = 'lib'
48
+
49
+ s.has_rdoc = true
50
+ s.extra_rdoc_files = [ "README", "CHANGES" ]
51
+ s.rdoc_options = ["--main", "README", "--inline-source", "--line-numbers"]
52
+
53
+ s.test_files = Dir.glob('spec/*_spec.rb')
54
+ s.require_path = 'lib'
55
+ s.author = "Brian Takita, Ross Hale, & David Garamond"
56
+ s.email = "opensource@pivotallabs.com"
57
+ s.homepage = "http://pivotallabs.com"
58
+ s.rubyforge_project = "pivotalrb"
59
+ end
60
+
61
+ Rake::GemPackageTask.new(spec) do |pkg|
62
+ pkg.need_zip = true
63
+ pkg.need_tar = true
64
+ end
65
+
66
+ def tag_release
67
+ dashed_version = PKG_VERSION.gsub('.', '-')
68
+ svn_user = "#{ENV["SVN_USER"]}@" || ""
69
+ `svn cp svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/guid/trunk svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/guid/tags/REL-#{dashed_version} -m 'Version #{PKG_VERSION}'`
70
+ end
@@ -0,0 +1,1298 @@
1
+ #
2
+ # This file is automatically generated. DO NOT MODIFY!
3
+ #
4
+ # setup.rb
5
+ #
6
+ # Copyright (c) 2000-2003 Minero Aoki <aamine@loveruby.net>
7
+ #
8
+ # This program is free software.
9
+ # You can distribute/modify this program under the terms of
10
+ # the GNU Lesser General Public License version 2.
11
+ #
12
+
13
+ def multipackage_install?
14
+ FileTest.directory?(File.dirname($0) + '/packages')
15
+ end
16
+
17
+ #
18
+ # compat.rb
19
+ #
20
+
21
+ module Enumerable
22
+ methods = instance_methods(true)
23
+
24
+ unless methods.include?('map')
25
+ alias map collect
26
+ end
27
+
28
+ unless methods.include?('select')
29
+ alias select find_all
30
+ end
31
+
32
+ unless methods.include?('reject')
33
+ def reject
34
+ result = []
35
+ each do |i|
36
+ result.push i unless yield(i)
37
+ end
38
+ result
39
+ end
40
+ end
41
+
42
+ unless methods.include?('inject')
43
+ def inject( result )
44
+ each do |i|
45
+ result = yield(result, i)
46
+ end
47
+ result
48
+ end
49
+ end
50
+
51
+ unless methods.include?('any?')
52
+ def any?
53
+ each do |i|
54
+ return true if yield(i)
55
+ end
56
+ false
57
+ end
58
+ end
59
+ end
60
+ #
61
+ # fileop.rb
62
+ #
63
+
64
+ module FileOperations
65
+
66
+ def mkdir_p( dirname, prefix = nil )
67
+ dirname = prefix + dirname if prefix
68
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
69
+ return if no_harm?
70
+
71
+ # does not check '/'... it's too abnormal case
72
+ dirs = dirname.split(%r<(?=/)>)
73
+ if /\A[a-z]:\z/i === dirs[0]
74
+ disk = dirs.shift
75
+ dirs[0] = disk + dirs[0]
76
+ end
77
+ dirs.each_index do |idx|
78
+ path = dirs[0..idx].join('')
79
+ Dir.mkdir path unless dir?(path)
80
+ end
81
+ end
82
+
83
+ def rm_f( fname )
84
+ $stderr.puts "rm -f #{fname}" if verbose?
85
+ return if no_harm?
86
+
87
+ if FileTest.exist?(fname) or FileTest.symlink?(fname)
88
+ File.chmod 0777, fname
89
+ File.unlink fname
90
+ end
91
+ end
92
+
93
+ def rm_rf( dn )
94
+ $stderr.puts "rm -rf #{dn}" if verbose?
95
+ return if no_harm?
96
+
97
+ Dir.chdir dn
98
+ Dir.foreach('.') do |fn|
99
+ next if fn == '.'
100
+ next if fn == '..'
101
+ if dir?(fn)
102
+ verbose_off {
103
+ rm_rf fn
104
+ }
105
+ else
106
+ verbose_off {
107
+ rm_f fn
108
+ }
109
+ end
110
+ end
111
+ Dir.chdir '..'
112
+ Dir.rmdir dn
113
+ end
114
+
115
+ def move_file( src, dest )
116
+ File.unlink dest if FileTest.exist?(dest)
117
+ begin
118
+ File.rename src, dest
119
+ rescue
120
+ File.open(dest, 'wb') {|f| f.write read_file(src) }
121
+ File.chmod File.stat(src).mode, dest
122
+ File.unlink src
123
+ end
124
+ end
125
+
126
+ def install( from, dest, mode, prefix = nil )
127
+ $stderr.puts "install #{from} #{dest}" if verbose?
128
+ return if no_harm?
129
+
130
+ realdest = prefix + dest if prefix
131
+ realdest += '/' + File.basename(from) if dir?(realdest)
132
+ str = read_file(from)
133
+ if diff?(str, realdest)
134
+ verbose_off {
135
+ rm_f realdest if File.exist?(realdest)
136
+ }
137
+ File.open(realdest, 'wb') {|f| f.write str }
138
+ File.chmod mode, realdest
139
+
140
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| f.puts realdest }
141
+ end
142
+ end
143
+
144
+ def diff?( orig, targ )
145
+ return true unless File.exist?(targ)
146
+ orig != read_file(targ)
147
+ end
148
+
149
+ def command( str )
150
+ $stderr.puts str if verbose?
151
+ system str or raise RuntimeError, "'system #{str}' failed"
152
+ end
153
+
154
+ def ruby( str )
155
+ command config('ruby-prog') + ' ' + str
156
+ end
157
+
158
+ def make( task = '' )
159
+ command config('make-prog') + ' ' + task
160
+ end
161
+
162
+ def extdir?( dir )
163
+ File.exist?(dir + '/MANIFEST')
164
+ end
165
+
166
+ def dir?( path )
167
+ # for corrupted windows stat()
168
+ FileTest.directory?((path[-1,1] == '/') ? path : path + '/')
169
+ end
170
+
171
+ def all_files_in( dirname )
172
+ Dir.open(dirname) {|d|
173
+ return d.select {|ent| FileTest.file?("#{dirname}/#{ent}") }
174
+ }
175
+ end
176
+
177
+ REJECT_DIRS = %w(
178
+ CVS SCCS RCS CVS.adm
179
+ )
180
+
181
+ def all_dirs_in( dirname )
182
+ Dir.open(dirname) {|d|
183
+ return d.select {|n| dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
184
+ }
185
+ end
186
+
187
+ def read_file( fname )
188
+ File.open(fname, 'rb') {|f| return f.read }
189
+ end
190
+
191
+ end
192
+ #
193
+ # config.rb
194
+ #
195
+
196
+ if i = ARGV.index(/\A--rbconfig=/)
197
+ file = $'
198
+ ARGV.delete_at(i)
199
+ require file
200
+ else
201
+ require 'rbconfig'
202
+ end
203
+
204
+
205
+ class ConfigTable
206
+
207
+ c = ::Config::CONFIG
208
+
209
+ rubypath = c['bindir'] + '/' + c['ruby_install_name']
210
+
211
+ major = c['MAJOR'].to_i
212
+ minor = c['MINOR'].to_i
213
+ teeny = c['TEENY'].to_i
214
+ version = "#{major}.#{minor}"
215
+
216
+ # ruby ver. >= 1.4.4?
217
+ newpath_p = ((major >= 2) or
218
+ ((major == 1) and
219
+ ((minor >= 5) or
220
+ ((minor == 4) and (teeny >= 4)))))
221
+
222
+ re = Regexp.new('\A' + Regexp.quote(c['prefix']))
223
+ subprefix = lambda {|path|
224
+ re === path and path.sub(re, '$prefix')
225
+ }
226
+
227
+ if c['rubylibdir']
228
+ # V < 1.6.3
229
+ stdruby = subprefix.call(c['rubylibdir'])
230
+ siteruby = subprefix.call(c['sitedir'])
231
+ versite = subprefix.call(c['sitelibdir'])
232
+ sodir = subprefix.call(c['sitearchdir'])
233
+ elsif newpath_p
234
+ # 1.4.4 <= V <= 1.6.3
235
+ stdruby = "$prefix/lib/ruby/#{version}"
236
+ siteruby = subprefix.call(c['sitedir'])
237
+ versite = siteruby + '/' + version
238
+ sodir = "$site-ruby/#{c['arch']}"
239
+ else
240
+ # V < 1.4.4
241
+ stdruby = "$prefix/lib/ruby/#{version}"
242
+ siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
243
+ versite = siteruby
244
+ sodir = "$site-ruby/#{c['arch']}"
245
+ end
246
+
247
+ common_descripters = [
248
+ [ 'prefix', [ c['prefix'],
249
+ 'path',
250
+ 'path prefix of target environment' ] ],
251
+ [ 'std-ruby', [ stdruby,
252
+ 'path',
253
+ 'the directory for standard ruby libraries' ] ],
254
+ [ 'site-ruby-common', [ siteruby,
255
+ 'path',
256
+ 'the directory for version-independent non-standard ruby libraries' ] ],
257
+ [ 'site-ruby', [ versite,
258
+ 'path',
259
+ 'the directory for non-standard ruby libraries' ] ],
260
+ [ 'bin-dir', [ '$prefix/bin',
261
+ 'path',
262
+ 'the directory for commands' ] ],
263
+ [ 'rb-dir', [ '$site-ruby',
264
+ 'path',
265
+ 'the directory for ruby scripts' ] ],
266
+ [ 'so-dir', [ sodir,
267
+ 'path',
268
+ 'the directory for ruby extentions' ] ],
269
+ [ 'data-dir', [ '$prefix/share',
270
+ 'path',
271
+ 'the directory for shared data' ] ],
272
+ [ 'ruby-path', [ rubypath,
273
+ 'path',
274
+ 'path to set to #! line' ] ],
275
+ [ 'ruby-prog', [ rubypath,
276
+ 'name',
277
+ 'the ruby program using for installation' ] ],
278
+ [ 'make-prog', [ 'make',
279
+ 'name',
280
+ 'the make program to compile ruby extentions' ] ],
281
+ [ 'without-ext', [ 'no',
282
+ 'yes/no',
283
+ 'does not compile/install ruby extentions' ] ]
284
+ ]
285
+ multipackage_descripters = [
286
+ [ 'with', [ '',
287
+ 'name,name...',
288
+ 'package names that you want to install',
289
+ 'ALL' ] ],
290
+ [ 'without', [ '',
291
+ 'name,name...',
292
+ 'package names that you do not want to install',
293
+ 'NONE' ] ]
294
+ ]
295
+ if multipackage_install?
296
+ DESCRIPTER = common_descripters + multipackage_descripters
297
+ else
298
+ DESCRIPTER = common_descripters
299
+ end
300
+
301
+ SAVE_FILE = 'config.save'
302
+
303
+ def ConfigTable.each_name( &block )
304
+ keys().each(&block)
305
+ end
306
+
307
+ def ConfigTable.keys
308
+ DESCRIPTER.map {|name, *dummy| name }
309
+ end
310
+
311
+ def ConfigTable.each_definition( &block )
312
+ DESCRIPTER.each(&block)
313
+ end
314
+
315
+ def ConfigTable.get_entry( name )
316
+ name, ent = DESCRIPTER.assoc(name)
317
+ ent
318
+ end
319
+
320
+ def ConfigTable.get_entry!( name )
321
+ get_entry(name) or raise ArgumentError, "no such config: #{name}"
322
+ end
323
+
324
+ def ConfigTable.add_entry( name, vals )
325
+ ConfigTable::DESCRIPTER.push [name,vals]
326
+ end
327
+
328
+ def ConfigTable.remove_entry( name )
329
+ get_entry(name) or raise ArgumentError, "no such config: #{name}"
330
+ DESCRIPTER.delete_if {|n, arr| n == name }
331
+ end
332
+
333
+ def ConfigTable.config_key?( name )
334
+ get_entry(name) ? true : false
335
+ end
336
+
337
+ def ConfigTable.bool_config?( name )
338
+ ent = get_entry(name) or return false
339
+ ent[1] == 'yes/no'
340
+ end
341
+
342
+ def ConfigTable.value_config?( name )
343
+ ent = get_entry(name) or return false
344
+ ent[1] != 'yes/no'
345
+ end
346
+
347
+ def ConfigTable.path_config?( name )
348
+ ent = get_entry(name) or return false
349
+ ent[1] == 'path'
350
+ end
351
+
352
+
353
+ class << self
354
+ alias newobj new
355
+ end
356
+
357
+ def ConfigTable.new
358
+ c = newobj()
359
+ c.initialize_from_table
360
+ c
361
+ end
362
+
363
+ def ConfigTable.load
364
+ c = newobj()
365
+ c.initialize_from_file
366
+ c
367
+ end
368
+
369
+ def initialize_from_table
370
+ @table = {}
371
+ DESCRIPTER.each do |k, (default, vname, desc, default2)|
372
+ @table[k] = default
373
+ end
374
+ end
375
+
376
+ def initialize_from_file
377
+ raise InstallError, "#{File.basename $0} config first"\
378
+ unless FileTest.file?(SAVE_FILE)
379
+ @table = {}
380
+ File.foreach(SAVE_FILE) do |line|
381
+ k, v = line.split(/=/, 2)
382
+ @table[k] = v.strip
383
+ end
384
+ end
385
+
386
+ def save
387
+ File.open(SAVE_FILE, 'w') {|f|
388
+ @table.each do |k, v|
389
+ f.printf "%s=%s\n", k, v if v
390
+ end
391
+ }
392
+ end
393
+
394
+ def []=( k, v )
395
+ raise InstallError, "unknown config option #{k}"\
396
+ unless ConfigTable.config_key?(k)
397
+ if ConfigTable.path_config?(k)
398
+ @table[k] = ((v[0,1] != '$') ? File.expand_path(v) : v)
399
+ else
400
+ @table[k] = v
401
+ end
402
+ end
403
+
404
+ def []( key )
405
+ return nil unless @table[key]
406
+ @table[key].gsub(%r<\$([^/]+)>) { self[$1] }
407
+ end
408
+
409
+ def set_raw( key, val )
410
+ @table[key] = val
411
+ end
412
+
413
+ def get_raw( key )
414
+ @table[key]
415
+ end
416
+
417
+ end
418
+
419
+
420
+ module MetaConfigAPI
421
+
422
+ def eval_file_ifexist( fname )
423
+ instance_eval read_file(fname), fname, 1 if FileTest.file?(fname)
424
+ end
425
+
426
+ def config_names
427
+ ConfigTable.keys
428
+ end
429
+
430
+ def config?( name )
431
+ ConfigTable.config_key?(name)
432
+ end
433
+
434
+ def bool_config?( name )
435
+ ConfigTable.bool_config?(name)
436
+ end
437
+
438
+ def value_config?( name )
439
+ ConfigTable.value_config?(name)
440
+ end
441
+
442
+ def path_config?( name )
443
+ ConfigTable.path_config?(name)
444
+ end
445
+
446
+ def add_config( name, argname, default, desc )
447
+ ConfigTable.add_entry name,[default,argname,desc]
448
+ end
449
+
450
+ def add_path_config( name, default, desc )
451
+ add_config name, 'path', default, desc
452
+ end
453
+
454
+ def add_bool_config( name, default, desc )
455
+ add_config name, 'yes/no', default ? 'yes' : 'no', desc
456
+ end
457
+
458
+ def set_config_default( name, default )
459
+ if bool_config?(name)
460
+ ConfigTable.get_entry!(name)[0] = (default ? 'yes' : 'no')
461
+ else
462
+ ConfigTable.get_entry!(name)[0] = default
463
+ end
464
+ end
465
+
466
+ def remove_config( name )
467
+ ent = ConfigTable.get_entry(name)
468
+ ConfigTable.remove_entry name
469
+ ent
470
+ end
471
+
472
+ end
473
+ #
474
+ # base.rb
475
+ #
476
+
477
+ require 'rbconfig'
478
+
479
+
480
+ class InstallError < StandardError; end
481
+
482
+
483
+ module HookUtils
484
+
485
+ def run_hook( name )
486
+ try_run_hook "#{curr_srcdir()}/#{name}" or
487
+ try_run_hook "#{curr_srcdir()}/#{name}.rb"
488
+ end
489
+
490
+ def try_run_hook( fname )
491
+ return false unless FileTest.file?(fname)
492
+ begin
493
+ instance_eval read_file(fname), fname, 1
494
+ rescue
495
+ raise InstallError, "hook #{fname} failed:\n" + $!.message
496
+ end
497
+ true
498
+ end
499
+
500
+ end
501
+
502
+
503
+ module HookScriptAPI
504
+
505
+ def get_config( key )
506
+ @config[key]
507
+ end
508
+
509
+ alias config get_config
510
+
511
+ def set_config( key, val )
512
+ @config[key] = val
513
+ end
514
+
515
+ #
516
+ # srcdir/objdir (works only in the package directory)
517
+ #
518
+
519
+ #abstract srcdir_root
520
+ #abstract objdir_root
521
+ #abstract relpath
522
+
523
+ def curr_srcdir
524
+ "#{srcdir_root()}/#{relpath()}"
525
+ end
526
+
527
+ def curr_objdir
528
+ "#{objdir_root()}/#{relpath()}"
529
+ end
530
+
531
+ def srcfile( path )
532
+ "#{curr_srcdir()}/#{path}"
533
+ end
534
+
535
+ def srcexist?( path )
536
+ FileTest.exist? srcfile(path)
537
+ end
538
+
539
+ def srcdirectory?( path )
540
+ dir? srcfile(path)
541
+ end
542
+
543
+ def srcfile?( path )
544
+ FileTest.file? srcfile(path)
545
+ end
546
+
547
+ def srcentries( path = '.' )
548
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
549
+ return d.to_a - %w(. ..)
550
+ }
551
+ end
552
+
553
+ def srcfiles( path = '.' )
554
+ srcentries(path).select {|fname|
555
+ FileTest.file?(File.join(curr_srcdir(), path, fname))
556
+ }
557
+ end
558
+
559
+ def srcdirectories( path = '.' )
560
+ srcentries(path).select {|fname|
561
+ dir?(File.join(curr_srcdir(), path, fname))
562
+ }
563
+ end
564
+
565
+ end
566
+
567
+
568
+ class Installer
569
+
570
+ FILETYPES = %w( bin lib ext data )
571
+
572
+ include HookScriptAPI
573
+ include HookUtils
574
+ include FileOperations
575
+
576
+ def initialize( config, opt, srcroot, objroot )
577
+ @config = config
578
+ @options = opt
579
+ @srcdir = File.expand_path(srcroot)
580
+ @objdir = File.expand_path(objroot)
581
+ @currdir = '.'
582
+ end
583
+
584
+ def inspect
585
+ "#<#{self.class} #{File.basename(@srcdir)}>"
586
+ end
587
+
588
+ #
589
+ # Hook Script API bases
590
+ #
591
+
592
+ def srcdir_root
593
+ @srcdir
594
+ end
595
+
596
+ def objdir_root
597
+ @objdir
598
+ end
599
+
600
+ def relpath
601
+ @currdir
602
+ end
603
+
604
+ #
605
+ # configs/options
606
+ #
607
+
608
+ def no_harm?
609
+ @options['no-harm']
610
+ end
611
+
612
+ def verbose?
613
+ @options['verbose']
614
+ end
615
+
616
+ def verbose_off
617
+ begin
618
+ save, @options['verbose'] = @options['verbose'], false
619
+ yield
620
+ ensure
621
+ @options['verbose'] = save
622
+ end
623
+ end
624
+
625
+ #
626
+ # TASK config
627
+ #
628
+
629
+ def exec_config
630
+ exec_task_traverse 'config'
631
+ end
632
+
633
+ def config_dir_bin( rel )
634
+ end
635
+
636
+ def config_dir_lib( rel )
637
+ end
638
+
639
+ def config_dir_ext( rel )
640
+ extconf if extdir?(curr_srcdir())
641
+ end
642
+
643
+ def extconf
644
+ opt = @options['config-opt'].join(' ')
645
+ command "#{config('ruby-prog')} #{curr_srcdir()}/extconf.rb #{opt}"
646
+ end
647
+
648
+ def config_dir_data( rel )
649
+ end
650
+
651
+ #
652
+ # TASK setup
653
+ #
654
+
655
+ def exec_setup
656
+ exec_task_traverse 'setup'
657
+ end
658
+
659
+ def setup_dir_bin( rel )
660
+ all_files_in(curr_srcdir()).each do |fname|
661
+ adjust_shebang "#{curr_srcdir()}/#{fname}"
662
+ end
663
+ end
664
+
665
+ # modify: #!/usr/bin/ruby
666
+ # modify: #! /usr/bin/ruby
667
+ # modify: #!ruby
668
+ # not modify: #!/usr/bin/env ruby
669
+ SHEBANG_RE = /\A\#!\s*\S*ruby\S*/
670
+
671
+ def adjust_shebang( path )
672
+ return if no_harm?
673
+
674
+ tmpfile = File.basename(path) + '.tmp'
675
+ begin
676
+ File.open(path) {|r|
677
+ File.open(tmpfile, 'w') {|w|
678
+ first = r.gets
679
+ return unless SHEBANG_RE === first
680
+
681
+ $stderr.puts "adjusting shebang: #{File.basename path}" if verbose?
682
+ w.print first.sub(SHEBANG_RE, '#!' + config('ruby-path'))
683
+ w.write r.read
684
+ }
685
+ }
686
+ move_file tmpfile, File.basename(path)
687
+ ensure
688
+ File.unlink tmpfile if File.exist?(tmpfile)
689
+ end
690
+ end
691
+
692
+ def setup_dir_lib( rel )
693
+ end
694
+
695
+ def setup_dir_ext( rel )
696
+ make if extdir?(curr_srcdir())
697
+ end
698
+
699
+ def setup_dir_data( rel )
700
+ end
701
+
702
+ #
703
+ # TASK install
704
+ #
705
+
706
+ def exec_install
707
+ exec_task_traverse 'install'
708
+ end
709
+
710
+ def install_dir_bin( rel )
711
+ install_files collect_filenames_auto(), config('bin-dir') + '/' + rel, 0755
712
+ end
713
+
714
+ def install_dir_lib( rel )
715
+ install_files ruby_scripts(), config('rb-dir') + '/' + rel, 0644
716
+ end
717
+
718
+ def install_dir_ext( rel )
719
+ return unless extdir?(curr_srcdir())
720
+ install_files ruby_extentions('.'),
721
+ config('so-dir') + '/' + File.dirname(rel),
722
+ 0555
723
+ end
724
+
725
+ def install_dir_data( rel )
726
+ install_files collect_filenames_auto(), config('data-dir') + '/' + rel, 0644
727
+ end
728
+
729
+ def install_files( list, dest, mode )
730
+ mkdir_p dest, @options['install-prefix']
731
+ list.each do |fname|
732
+ install fname, dest, mode, @options['install-prefix']
733
+ end
734
+ end
735
+
736
+ def ruby_scripts
737
+ collect_filenames_auto().select {|n| /\.rb\z/ === n }
738
+ end
739
+
740
+ # picked up many entries from cvs-1.11.1/src/ignore.c
741
+ reject_patterns = %w(
742
+ core RCSLOG tags TAGS .make.state
743
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.a *.olb *.o *.obj
744
+ *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$
745
+
746
+ *.org *.in .*
747
+ )
748
+ maptab = {
749
+ '.' => '\\.',
750
+ '$' => '\\$',
751
+ '*' => '.*'
752
+ }
753
+ REJECT_PATTERNS = Regexp.new('\A(?:' +
754
+ reject_patterns.map {|pat|
755
+ pat.gsub(/[\.\$\*]/) {|s| maptab[s] }
756
+ }.join('|') +
757
+ ')\z')
758
+
759
+ def collect_filenames_auto
760
+ mapdir((existfiles() - hookfiles()).reject {|fname|
761
+ REJECT_PATTERNS === fname
762
+ })
763
+ end
764
+
765
+ def existfiles
766
+ all_files_in(curr_srcdir()) | all_files_in('.')
767
+ end
768
+
769
+ def hookfiles
770
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
771
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
772
+ }.flatten
773
+ end
774
+
775
+ def mapdir( filelist )
776
+ filelist.map {|fname|
777
+ if File.exist?(fname) # objdir
778
+ fname
779
+ else # srcdir
780
+ File.join(curr_srcdir(), fname)
781
+ end
782
+ }
783
+ end
784
+
785
+ def ruby_extentions( dir )
786
+ _ruby_extentions(dir) or
787
+ raise InstallError, "no ruby extention exists: 'ruby #{$0} setup' first"
788
+ end
789
+
790
+ DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/
791
+
792
+ def _ruby_extentions( dir )
793
+ Dir.open(dir) {|d|
794
+ return d.select {|fname| DLEXT === fname }
795
+ }
796
+ end
797
+
798
+ #
799
+ # TASK clean
800
+ #
801
+
802
+ def exec_clean
803
+ exec_task_traverse 'clean'
804
+ rm_f 'config.save'
805
+ rm_f 'InstalledFiles'
806
+ end
807
+
808
+ def clean_dir_bin( rel )
809
+ end
810
+
811
+ def clean_dir_lib( rel )
812
+ end
813
+
814
+ def clean_dir_ext( rel )
815
+ return unless extdir?(curr_srcdir())
816
+ make 'clean' if FileTest.file?('Makefile')
817
+ end
818
+
819
+ def clean_dir_data( rel )
820
+ end
821
+
822
+ #
823
+ # TASK distclean
824
+ #
825
+
826
+ def exec_distclean
827
+ exec_task_traverse 'distclean'
828
+ rm_f 'config.save'
829
+ rm_f 'InstalledFiles'
830
+ end
831
+
832
+ def distclean_dir_bin( rel )
833
+ end
834
+
835
+ def distclean_dir_lib( rel )
836
+ end
837
+
838
+ def distclean_dir_ext( rel )
839
+ return unless extdir?(curr_srcdir())
840
+ make 'distclean' if FileTest.file?('Makefile')
841
+ end
842
+
843
+ #
844
+ # lib
845
+ #
846
+
847
+ def exec_task_traverse( task )
848
+ run_hook 'pre-' + task
849
+ FILETYPES.each do |type|
850
+ if config('without-ext') == 'yes' and type == 'ext'
851
+ $stderr.puts 'skipping ext/* by user option' if verbose?
852
+ next
853
+ end
854
+ traverse task, type, task + '_dir_' + type
855
+ end
856
+ run_hook 'post-' + task
857
+ end
858
+
859
+ def traverse( task, rel, mid )
860
+ dive_into(rel) {
861
+ run_hook 'pre-' + task
862
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
863
+ all_dirs_in(curr_srcdir()).each do |d|
864
+ traverse task, rel + '/' + d, mid
865
+ end
866
+ run_hook 'post-' + task
867
+ }
868
+ end
869
+
870
+ def dive_into( rel )
871
+ return unless dir?("#{@srcdir}/#{rel}")
872
+
873
+ dir = File.basename(rel)
874
+ Dir.mkdir dir unless dir?(dir)
875
+ prevdir = Dir.pwd
876
+ Dir.chdir dir
877
+ $stderr.puts '---> ' + rel if verbose?
878
+ @currdir = rel
879
+ yield
880
+ Dir.chdir prevdir
881
+ $stderr.puts '<--- ' + rel if verbose?
882
+ @currdir = File.dirname(rel)
883
+ end
884
+
885
+ end
886
+ #
887
+ # toplevel.rb
888
+ #
889
+
890
+ class ToplevelInstaller
891
+
892
+ Version = '3.2.1'
893
+ Copyright = 'Copyright (c) 2000-2003 Minero Aoki'
894
+
895
+ TASKS = [
896
+ [ 'config', 'saves your configurations' ],
897
+ [ 'show', 'shows current configuration' ],
898
+ [ 'setup', 'compiles ruby extentions and others' ],
899
+ [ 'install', 'installs files' ],
900
+ [ 'clean', "does `make clean' for each extention" ],
901
+ [ 'distclean',"does `make distclean' for each extention" ]
902
+ ]
903
+
904
+ def ToplevelInstaller.invoke
905
+ instance().invoke
906
+ end
907
+
908
+ @singleton = nil
909
+
910
+ def ToplevelInstaller.instance
911
+ @singleton ||= new(File.dirname($0))
912
+ @singleton
913
+ end
914
+
915
+ include MetaConfigAPI
916
+
917
+ def initialize( ardir_root )
918
+ @config = nil
919
+ @options = { 'verbose' => true }
920
+ @ardir = File.expand_path(ardir_root)
921
+ end
922
+
923
+ def inspect
924
+ "#<#{self.class} #{__id__()}>"
925
+ end
926
+
927
+ def invoke
928
+ run_metaconfigs
929
+ task = parsearg_global()
930
+ @config = load_config(task)
931
+ __send__ "parsearg_#{task}"
932
+ init_installers
933
+ __send__ "exec_#{task}"
934
+ end
935
+
936
+ def run_metaconfigs
937
+ eval_file_ifexist "#{@ardir}/metaconfig"
938
+ end
939
+
940
+ def load_config( task )
941
+ case task
942
+ when 'config'
943
+ ConfigTable.new
944
+ when 'clean', 'distclean'
945
+ if File.exist?('config.save')
946
+ then ConfigTable.load
947
+ else ConfigTable.new
948
+ end
949
+ else
950
+ ConfigTable.load
951
+ end
952
+ end
953
+
954
+ def init_installers
955
+ @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
956
+ end
957
+
958
+ #
959
+ # Hook Script API bases
960
+ #
961
+
962
+ def srcdir_root
963
+ @ardir
964
+ end
965
+
966
+ def objdir_root
967
+ '.'
968
+ end
969
+
970
+ def relpath
971
+ '.'
972
+ end
973
+
974
+ #
975
+ # Option Parsing
976
+ #
977
+
978
+ def parsearg_global
979
+ valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
980
+
981
+ while arg = ARGV.shift
982
+ case arg
983
+ when /\A\w+\z/
984
+ raise InstallError, "invalid task: #{arg}" unless valid_task === arg
985
+ return arg
986
+
987
+ when '-q', '--quiet'
988
+ @options['verbose'] = false
989
+
990
+ when '--verbose'
991
+ @options['verbose'] = true
992
+
993
+ when '-h', '--help'
994
+ print_usage $stdout
995
+ exit 0
996
+
997
+ when '-v', '--version'
998
+ puts "#{File.basename($0)} version #{Version}"
999
+ exit 0
1000
+
1001
+ when '--copyright'
1002
+ puts Copyright
1003
+ exit 0
1004
+
1005
+ else
1006
+ raise InstallError, "unknown global option '#{arg}'"
1007
+ end
1008
+ end
1009
+
1010
+ raise InstallError, <<EOS
1011
+ No task or global option given.
1012
+ Typical installation procedure is:
1013
+ $ ruby #{File.basename($0)} config
1014
+ $ ruby #{File.basename($0)} setup
1015
+ # ruby #{File.basename($0)} install (may require root privilege)
1016
+ EOS
1017
+ end
1018
+
1019
+
1020
+ def parsearg_no_options
1021
+ raise InstallError, "#{task}: unknown options: #{ARGV.join ' '}"\
1022
+ unless ARGV.empty?
1023
+ end
1024
+
1025
+ alias parsearg_show parsearg_no_options
1026
+ alias parsearg_setup parsearg_no_options
1027
+ alias parsearg_clean parsearg_no_options
1028
+ alias parsearg_distclean parsearg_no_options
1029
+
1030
+ def parsearg_config
1031
+ re = /\A--(#{ConfigTable.keys.join '|'})(?:=(.*))?\z/
1032
+ @options['config-opt'] = []
1033
+
1034
+ while i = ARGV.shift
1035
+ if /\A--?\z/ === i
1036
+ @options['config-opt'] = ARGV.dup
1037
+ break
1038
+ end
1039
+ m = re.match(i) or raise InstallError, "config: unknown option #{i}"
1040
+ name, value = m.to_a[1,2]
1041
+ if value
1042
+ if ConfigTable.bool_config?(name)
1043
+ raise InstallError, "config: --#{name} allows only yes/no for argument"\
1044
+ unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i === value
1045
+ value = (/\Ay(es)?|\At(rue)/i === value) ? 'yes' : 'no'
1046
+ end
1047
+ else
1048
+ raise InstallError, "config: --#{name} requires argument"\
1049
+ unless ConfigTable.bool_config?(name)
1050
+ value = 'yes'
1051
+ end
1052
+ @config[name] = value
1053
+ end
1054
+ end
1055
+
1056
+ def parsearg_install
1057
+ @options['no-harm'] = false
1058
+ @options['install-prefix'] = ''
1059
+ while a = ARGV.shift
1060
+ case a
1061
+ when /\A--no-harm\z/
1062
+ @options['no-harm'] = true
1063
+ when /\A--prefix=(.*)\z/
1064
+ path = $1
1065
+ path = File.expand_path(path) unless path[0,1] == '/'
1066
+ @options['install-prefix'] = path
1067
+ else
1068
+ raise InstallError, "install: unknown option #{a}"
1069
+ end
1070
+ end
1071
+ end
1072
+
1073
+ def print_usage( out )
1074
+ out.puts 'Typical Installation Procedure:'
1075
+ out.puts " $ ruby #{File.basename $0} config"
1076
+ out.puts " $ ruby #{File.basename $0} setup"
1077
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
1078
+ out.puts
1079
+ out.puts 'Detailed Usage:'
1080
+ out.puts " ruby #{File.basename $0} <global option>"
1081
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
1082
+
1083
+ fmt = " %-20s %s\n"
1084
+ out.puts
1085
+ out.puts 'Global options:'
1086
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
1087
+ out.printf fmt, ' --verbose', 'output messages verbosely'
1088
+ out.printf fmt, '-h,--help', 'print this message'
1089
+ out.printf fmt, '-v,--version', 'print version and quit'
1090
+ out.printf fmt, ' --copyright', 'print copyright and quit'
1091
+
1092
+ out.puts
1093
+ out.puts 'Tasks:'
1094
+ TASKS.each do |name, desc|
1095
+ out.printf " %-10s %s\n", name, desc
1096
+ end
1097
+
1098
+ out.puts
1099
+ out.puts 'Options for config:'
1100
+ ConfigTable.each_definition do |name, (default, arg, desc, default2)|
1101
+ out.printf " %-20s %s [%s]\n",
1102
+ '--'+ name + (ConfigTable.bool_config?(name) ? '' : '='+arg),
1103
+ desc,
1104
+ default2 || default
1105
+ end
1106
+ out.printf " %-20s %s [%s]\n",
1107
+ '--rbconfig=path', 'your rbconfig.rb to load', "running ruby's"
1108
+
1109
+ out.puts
1110
+ out.puts 'Options for install:'
1111
+ out.printf " %-20s %s [%s]\n",
1112
+ '--no-harm', 'only display what to do if given', 'off'
1113
+ out.printf " %-20s %s [%s]\n",
1114
+ '--prefix', 'install path prefix', '$prefix'
1115
+
1116
+ out.puts
1117
+ end
1118
+
1119
+ #
1120
+ # Task Handlers
1121
+ #
1122
+
1123
+ def exec_config
1124
+ @config.save
1125
+ @installer.exec_config
1126
+ end
1127
+
1128
+ def exec_setup
1129
+ @installer.exec_setup
1130
+ end
1131
+
1132
+ def exec_install
1133
+ @installer.exec_install
1134
+ end
1135
+
1136
+ def exec_show
1137
+ ConfigTable.each_name do |k|
1138
+ v = @config.get_raw(k)
1139
+ if not v or v.empty?
1140
+ v = '(not specified)'
1141
+ end
1142
+ printf "%-10s %s\n", k, v
1143
+ end
1144
+ end
1145
+
1146
+ def exec_clean
1147
+ @installer.exec_clean
1148
+ end
1149
+
1150
+ def exec_distclean
1151
+ @installer.exec_distclean
1152
+ end
1153
+
1154
+ end
1155
+
1156
+
1157
+ class ToplevelInstallerMulti < ToplevelInstaller
1158
+
1159
+ include HookUtils
1160
+ include HookScriptAPI
1161
+ include FileOperations
1162
+
1163
+ def initialize( ardir )
1164
+ super
1165
+ @packages = all_dirs_in("#{@ardir}/packages")
1166
+ raise 'no package exists' if @packages.empty?
1167
+ end
1168
+
1169
+ def run_metaconfigs
1170
+ eval_file_ifexist "#{@ardir}/metaconfig"
1171
+ @packages.each do |name|
1172
+ eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
1173
+ end
1174
+ end
1175
+
1176
+ def init_installers
1177
+ @installers = {}
1178
+ @packages.each do |pack|
1179
+ @installers[pack] = Installer.new(@config, @options,
1180
+ "#{@ardir}/packages/#{pack}",
1181
+ "packages/#{pack}")
1182
+ end
1183
+
1184
+ with = extract_selection(config('with'))
1185
+ without = extract_selection(config('without'))
1186
+ @selected = @installers.keys.select {|name|
1187
+ (with.empty? or with.include?(name)) \
1188
+ and not without.include?(name)
1189
+ }
1190
+ end
1191
+
1192
+ def extract_selection( list )
1193
+ a = list.split(/,/)
1194
+ a.each do |name|
1195
+ raise InstallError, "no such package: #{name}" \
1196
+ unless @installers.key?(name)
1197
+ end
1198
+ a
1199
+ end
1200
+
1201
+ def print_usage( f )
1202
+ super
1203
+ f.puts 'Inluded packages:'
1204
+ f.puts ' ' + @packages.sort.join(' ')
1205
+ f.puts
1206
+ end
1207
+
1208
+ #
1209
+ # multi-package metaconfig API
1210
+ #
1211
+
1212
+ attr_reader :packages
1213
+
1214
+ def declare_packages( list )
1215
+ raise 'package list is empty' if list.empty?
1216
+ list.each do |name|
1217
+ raise "directory packages/#{name} does not exist"\
1218
+ unless dir?("#{@ardir}/packages/#{name}")
1219
+ end
1220
+ @packages = list
1221
+ end
1222
+
1223
+ #
1224
+ # Task Handlers
1225
+ #
1226
+
1227
+ def exec_config
1228
+ run_hook 'pre-config'
1229
+ @config.save
1230
+ each_selected_installers {|inst| inst.exec_config }
1231
+ run_hook 'post-config'
1232
+ end
1233
+
1234
+ def exec_setup
1235
+ run_hook 'pre-setup'
1236
+ each_selected_installers {|inst| inst.exec_setup }
1237
+ run_hook 'post-setup'
1238
+ end
1239
+
1240
+ def exec_install
1241
+ run_hook 'pre-install'
1242
+ each_selected_installers {|inst| inst.exec_install }
1243
+ run_hook 'post-install'
1244
+ end
1245
+
1246
+ def exec_clean
1247
+ rm_f 'config.save'
1248
+ run_hook 'pre-clean'
1249
+ each_selected_installers {|inst| inst.exec_clean }
1250
+ run_hook 'post-clean'
1251
+ end
1252
+
1253
+ def exec_distclean
1254
+ rm_f 'config.save'
1255
+ run_hook 'pre-distclean'
1256
+ each_selected_installers {|inst| inst.exec_distclean }
1257
+ run_hook 'post-distclean'
1258
+ end
1259
+
1260
+ #
1261
+ # lib
1262
+ #
1263
+
1264
+ def each_selected_installers
1265
+ Dir.mkdir 'packages' unless dir?('packages')
1266
+ @selected.each do |pack|
1267
+ $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1268
+ Dir.mkdir "packages/#{pack}" unless dir?("packages/#{pack}")
1269
+ Dir.chdir "packages/#{pack}"
1270
+ yield @installers[pack]
1271
+ Dir.chdir '../..'
1272
+ end
1273
+ end
1274
+
1275
+ def verbose?
1276
+ @options['verbose']
1277
+ end
1278
+
1279
+ def no_harm?
1280
+ @options['no-harm']
1281
+ end
1282
+
1283
+ end
1284
+
1285
+ if $0 == __FILE__
1286
+ begin
1287
+ if multipackage_install?
1288
+ ToplevelInstallerMulti.invoke
1289
+ else
1290
+ ToplevelInstaller.invoke
1291
+ end
1292
+ rescue
1293
+ raise if $DEBUG
1294
+ $stderr.puts $!.message
1295
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1296
+ exit 1
1297
+ end
1298
+ end