ruport 0.1.0 → 0.2.0

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