Project

General

Profile

« Previous | Next » 

Revision ff29708e

Added by Marc Dequènes over 12 years ago

  • ID ff29708e32f0fbad2b284b6cc0a53d078c13e5a1

Initial code

View differences:

.gitignore
1
# backup files (mostly made by editors)
2
*~
3
\#*#
4
# generated by installer
5
.config
ext/debian_apt/debian_apt.i
1

  
2
%module "debian_apt"
3

  
4
%include "std_string.i"
5

  
6
%{
7
#include <apt-pkg/pkgcache.h>
8
#include <apt-pkg/debversion.h>
9
%}
10

  
11
using namespace std;
12

  
13
class pkgCache
14
{
15
   public:
16

  
17
   static const char *CompTypeDeb(unsigned char Comp);
18
   static const char *CompType(unsigned char Comp);
19
   static const char *DepType(unsigned char Dep);
20

  
21
   pkgCache(MMap *Map,bool DoMap = true);
22
};
23

  
24
class debVersioningSystem : public pkgVersioningSystem
25
{     
26
   public:
27

  
28
   int CmpVersion(string A,string B);
29
   bool CheckDep(const char *PkgVer,int Op,const char *DepVer);
30
   string UpstreamVersion(const char *A);
31

  
32
   debVersioningSystem();
33
};
34

  
35
extern debVersioningSystem debVS;
36

  
ext/debian_apt/extconf.rb
1
require 'mkmf'
2
have_library('apt-pkg')
3
create_makefile("debian_apt")
ext/debian_apt/post-clean.rb
1

  
2
system("rm -f *_wrap.cxx")
3

  
ext/debian_apt/pre-setup.rb
1

  
2
system("swig -c++ -ruby -Wall -autorename debian_apt.i")
3

  
lib/debian/version.rb
1
#!/usr/bin/ruby
2

  
3
require 'debian_apt'
4

  
5
module Debian_apt
6
  def self.included(base)
7
    @@op_to_opcode = {}
8
    i = 1
9
    while true 
10
      op = Debian_apt::PkgCache.comp_type_deb(i)
11
      break if op == ""
12
      @@op_to_opcode[op] = i
13
      i += 1
14
    end
15
  end
16

  
17
  def compare_versions(lver, rver)
18
    Debian_apt.debVS.cmp_version(lver, rver)
19
  end
20

  
21
  def check_version_constraint(lver, op, rver)
22
    Debian_apt.debVS.check_dep(lver, @@op_to_opcode[op], rver)
23
  end
24
end
25

  
26
module Debian
27
  class DebianVersion
28
    include Comparable
29
    include Debian_apt
30

  
31
    attr_accessor :epoch, :upstream, :revision
32

  
33
    DEB_TILDE = /~(.*)$/
34

  
35
    def initialize(version = nil)
36
      if version.nil? or version == ""
37
        @epoch = 0
38
        @upstream = nil
39
        @revision = nil
40
      else
41
        @upstream = Debian_apt.debVS.upstream_version(version)
42
        version =~ /^(?:(\d+):)?#{@upstream}(?:-(.+))?$/
43
	@epoch = $1 ? $1 : 0
44
	@revision = $2
45
      end
46
    end
47

  
48
    def version
49
      if @upstream.nil?
50
        ver = nil
51
      else
52
        ver = "#{@upstream}"
53
        # @revision can be nil for native packages
54
        ver += "-#{@revision}" unless @revision.nil?
55
        ver = "#{@epoch}:#{ver}" unless @epoch == 0
56
      end
57
      ver
58
    end
59

  
60
    def to_s
61
      ver = self.version
62
      (ver.nil?) ? "none" : ver
63
    end
64

  
65
    def <=>(rver)
66
      compare_versions(self.version, rver.version)
67
    end
68

  
69
    def is_native?
70
      @revision.nil?
71
    end
72

  
73
    def compare(op, rver)
74
      check_version_constraint(self.version, op, rver.version)
75
    end
76

  
77
    def compare_epochless(op, rver)
78
      v1 = self.dup
79
      v2 = rver.dup
80
      v1.epoch = 0
81
      v2.epoch = 0
82
      check_version_constraint(v1.version, op, v2.version)
83
    end
84

  
85
    def compare_upstream(op, rver, remove_tilde_part = false)
86
      v1 = self.dup
87
      v2 = rver.dup
88
      if remove_tilde_part
89
        v1.remove_upstream_tilde_part
90
        v2.remove_upstream_tilde_part
91
      end
92
      check_version_constraint(v1.upstream, op, v2.upstream)
93
    end
94

  
95
    def compare_revision(op, rver)
96
      check_version_constraint(self.revision, op, rver.revision)
97
    end
98

  
99
    def compare_epoch(op, rver)
100
      check_version_constraint(self.epoch, op, rver.epoch)
101
    end
102

  
103
    def upstream_tilde_part
104
      @upstream =~ DEB_TILDE
105
      $1
106
    end
107

  
108
    def remove_upstream_tilde_part
109
      # trigger a bug with dupped objects
110
      #@upstream.gsub!(DEB_TILDE, "")
111
      @upstream = @upstream.gsub(DEB_TILDE, "")
112
    end
113

  
114
    def set_upstream_tilde_part(str)
115
      remove_upstream_tilde_part
116
      @upstream += "~#{str}"
117
    end
118

  
119
    def revision_tilde_part
120
      @revision =~ DEB_TILDE
121
      $1
122
    end
123

  
124
    def remove_revision_tilde_part
125
      # trigger a bug with dupped objects
126
      #@revision.gsub!(DEB_TILDE, "")
127
      @revision = @revision.gsub(DEB_TILDE, "")
128
    end
129

  
130
    def set_revision_tilde_part(str)
131
      remove_revision_tilde_part
132
      @revision += "~#{str}"
133
    end
134
  end
135
end
136

  
setup.rb
1
#
2
# setup.rb
3
#
4
# Copyright (c) 2000-2005 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
unless Errno.const_defined?(:ENOTEMPTY)   # Windows?
26
  module Errno
27
    class ENOTEMPTY
28
      # We do not raise this exception, implementation is not needed.
29
    end
30
  end
31
end
32

  
33
def File.binread(fname)
34
  open(fname, 'rb') {|f|
35
    return f.read
36
  }
37
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
126
      end
127
    rescue Errno::ENOENT
128
      setup_rb_error $!.message + "\n#{File.basename($0)} config first"
129
    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
144
    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
263
    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
  end
300

  
301
  def options_re
302
    /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
303
  end
304

  
305
  def parse_opt(opt)
306
    m = options_re().match(opt) or setup_rb_error "config: unknown option #{opt}"
307
    m.to_a[1,2]
308
  end
309

  
310
  def dllext
311
    @rbconfig['DLEXT']
312
  end
313

  
314
  def value_config?(name)
315
    lookup(name).value?
316
  end
317

  
318
  class Item
319
    def initialize(name, template, default, desc)
320
      @name = name.freeze
321
      @template = template
322
      @value = default
323
      @default = default
324
      @description = desc
325
    end
326

  
327
    attr_reader :name
328
    attr_reader :description
329

  
330
    attr_accessor :default
331
    alias help_default default
332

  
333
    def help_opt
334
      "--#{@name}=#{@template}"
335
    end
336

  
337
    def value?
338
      true
339
    end
340

  
341
    def value
342
      @value
343
    end
344

  
345
    def resolve(table)
346
      @value.gsub(%r<\$([^/]+)>) { table[$1] }
347
    end
348

  
349
    def set(val)
350
      @value = check(val)
351
    end
352

  
353
    private
354

  
355
    def check(val)
356
      setup_rb_error "config: --#{name} requires argument" unless val
357
      val
358
    end
359
  end
360

  
361
  class BoolItem < Item
362
    def config_type
363
      'bool'
364
    end
365

  
366
    def help_opt
367
      "--#{@name}"
368
    end
369

  
370
    private
371

  
372
    def check(val)
373
      return 'yes' unless val
374
      case val
375
      when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
376
      when /\An(o)?\z/i, /\Af(alse)\z/i  then 'no'
377
      else
378
        setup_rb_error "config: --#{@name} accepts only yes/no for argument"
379
      end
380
    end
381
  end
382

  
383
  class PathItem < Item
384
    def config_type
385
      'path'
386
    end
387

  
388
    private
389

  
390
    def check(path)
391
      setup_rb_error "config: --#{@name} requires argument"  unless path
392
      path[0,1] == '$' ? path : File.expand_path(path)
393
    end
394
  end
395

  
396
  class ProgramItem < Item
397
    def config_type
398
      'program'
399
    end
400
  end
401

  
402
  class SelectItem < Item
403
    def initialize(name, selection, default, desc)
404
      super
405
      @ok = selection.split('/')
406
    end
407

  
408
    def config_type
409
      'select'
410
    end
411

  
412
    private
413

  
414
    def check(val)
415
      unless @ok.include?(val.strip)
416
        setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
417
      end
418
      val.strip
419
    end
420
  end
421

  
422
  class ExecItem < Item
423
    def initialize(name, selection, desc, &block)
424
      super name, selection, nil, desc
425
      @ok = selection.split('/')
426
      @action = block
427
    end
428

  
429
    def config_type
430
      'exec'
431
    end
432

  
433
    def value?
434
      false
435
    end
436

  
437
    def resolve(table)
438
      setup_rb_error "$#{name()} wrongly used as option value"
439
    end
440

  
441
    undef set
442

  
443
    def evaluate(val, table)
444
      v = val.strip.downcase
445
      unless @ok.include?(v)
446
        setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
447
      end
448
      @action.call v, table
449
    end
450
  end
451

  
452
  class PackageSelectionItem < Item
453
    def initialize(name, template, default, help_default, desc)
454
      super name, template, default, desc
455
      @help_default = help_default
456
    end
457

  
458
    attr_reader :help_default
459

  
460
    def config_type
461
      'package'
462
    end
463

  
464
    private
465

  
466
    def check(val)
467
      unless File.dir?("packages/#{val}")
468
        setup_rb_error "config: no such package: #{val}"
469
      end
470
      val
471
    end
472
  end
473

  
474
  class MetaConfigEnvironment
475
    def initialize(config, installer)
476
      @config = config
477
      @installer = installer
478
    end
479

  
480
    def config_names
481
      @config.names
482
    end
483

  
484
    def config?(name)
485
      @config.key?(name)
486
    end
487

  
488
    def bool_config?(name)
489
      @config.lookup(name).config_type == 'bool'
490
    end
491

  
492
    def path_config?(name)
493
      @config.lookup(name).config_type == 'path'
494
    end
495

  
496
    def value_config?(name)
497
      @config.lookup(name).config_type != 'exec'
498
    end
499

  
500
    def add_config(item)
501
      @config.add item
502
    end
503

  
504
    def add_bool_config(name, default, desc)
505
      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
506
    end
507

  
508
    def add_path_config(name, default, desc)
509
      @config.add PathItem.new(name, 'path', default, desc)
510
    end
511

  
512
    def set_config_default(name, default)
513
      @config.lookup(name).default = default
514
    end
515

  
516
    def remove_config(name)
517
      @config.remove(name)
518
    end
519

  
520
    # For only multipackage
521
    def packages
522
      raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
523
      @installer.packages
524
    end
525

  
526
    # For only multipackage
527
    def declare_packages(list)
528
      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
529
      @installer.packages = list
530
    end
531
  end
532

  
533
end   # class ConfigTable
534

  
535

  
536
# This module requires: #verbose?, #no_harm?
537
module FileOperations
538

  
539
  def mkdir_p(dirname, prefix = nil)
540
    dirname = prefix + File.expand_path(dirname) if prefix
541
    $stderr.puts "mkdir -p #{dirname}" if verbose?
542
    return if no_harm?
543

  
544
    # Does not check '/', it's too abnormal.
545
    dirs = File.expand_path(dirname).split(%r<(?=/)>)
546
    if /\A[a-z]:\z/i =~ dirs[0]
547
      disk = dirs.shift
548
      dirs[0] = disk + dirs[0]
549
    end
550
    dirs.each_index do |idx|
551
      path = dirs[0..idx].join('')
552
      Dir.mkdir path unless File.dir?(path)
553
    end
554
  end
555

  
556
  def rm_f(path)
557
    $stderr.puts "rm -f #{path}" if verbose?
558
    return if no_harm?
559
    force_remove_file path
560
  end
561

  
562
  def rm_rf(path)
563
    $stderr.puts "rm -rf #{path}" if verbose?
564
    return if no_harm?
565
    remove_tree path
566
  end
567

  
568
  def remove_tree(path)
569
    if File.symlink?(path)
570
      remove_file path
571
    elsif File.dir?(path)
572
      remove_tree0 path
573
    else
574
      force_remove_file path
575
    end
576
  end
577

  
578
  def remove_tree0(path)
579
    Dir.foreach(path) do |ent|
580
      next if ent == '.'
581
      next if ent == '..'
582
      entpath = "#{path}/#{ent}"
583
      if File.symlink?(entpath)
584
        remove_file entpath
585
      elsif File.dir?(entpath)
586
        remove_tree0 entpath
587
      else
588
        force_remove_file entpath
589
      end
590
    end
591
    begin
592
      Dir.rmdir path
593
    rescue Errno::ENOTEMPTY
594
      # directory may not be empty
595
    end
596
  end
597

  
598
  def move_file(src, dest)
599
    force_remove_file dest
600
    begin
601
      File.rename src, dest
602
    rescue
603
      File.open(dest, 'wb') {|f|
604
        f.write File.binread(src)
605
      }
606
      File.chmod File.stat(src).mode, dest
607
      File.unlink src
608
    end
609
  end
610

  
611
  def force_remove_file(path)
612
    begin
613
      remove_file path
614
    rescue
615
    end
616
  end
617

  
618
  def remove_file(path)
619
    File.chmod 0777, path
620
    File.unlink path
621
  end
622

  
623
  def install(from, dest, mode, prefix = nil)
624
    $stderr.puts "install #{from} #{dest}" if verbose?
625
    return if no_harm?
626

  
627
    realdest = prefix ? prefix + File.expand_path(dest) : dest
628
    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
629
    str = File.binread(from)
630
    if diff?(str, realdest)
631
      verbose_off {
632
        rm_f realdest if File.exist?(realdest)
633
      }
634
      File.open(realdest, 'wb') {|f|
635
        f.write str
636
      }
637
      File.chmod mode, realdest
638

  
639
      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
640
        if prefix
641
          f.puts realdest.sub(prefix, '')
642
        else
643
          f.puts realdest
644
        end
645
      }
646
    end
647
  end
648

  
649
  def diff?(new_content, path)
650
    return true unless File.exist?(path)
651
    new_content != File.binread(path)
652
  end
653

  
654
  def command(*args)
655
    $stderr.puts args.join(' ') if verbose?
656
    system(*args) or raise RuntimeError,
657
        "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
658
  end
659

  
660
  def ruby(*args)
661
    command config('rubyprog'), *args
662
  end
663
  
664
  def make(task = nil)
665
    command(*[config('makeprog'), task].compact)
666
  end
667

  
668
  def extdir?(dir)
669
    File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
670
  end
671

  
672
  def files_of(dir)
673
    Dir.open(dir) {|d|
674
      return d.select {|ent| File.file?("#{dir}/#{ent}") }
675
    }
676
  end
677

  
678
  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
679

  
680
  def directories_of(dir)
681
    Dir.open(dir) {|d|
682
      return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
683
    }
684
  end
685

  
686
end
687

  
688

  
689
# This module requires: #srcdir_root, #objdir_root, #relpath
690
module HookScriptAPI
691

  
692
  def get_config(key)
693
    @config[key]
694
  end
695

  
696
  alias config get_config
697

  
698
  # obsolete: use metaconfig to change configuration
699
  def set_config(key, val)
700
    @config[key] = val
701
  end
702

  
703
  #
704
  # srcdir/objdir (works only in the package directory)
705
  #
706

  
707
  def curr_srcdir
708
    "#{srcdir_root()}/#{relpath()}"
709
  end
710

  
711
  def curr_objdir
712
    "#{objdir_root()}/#{relpath()}"
713
  end
714

  
715
  def srcfile(path)
716
    "#{curr_srcdir()}/#{path}"
717
  end
718

  
719
  def srcexist?(path)
720
    File.exist?(srcfile(path))
721
  end
722

  
723
  def srcdirectory?(path)
724
    File.dir?(srcfile(path))
725
  end
726
  
727
  def srcfile?(path)
728
    File.file?(srcfile(path))
729
  end
730

  
731
  def srcentries(path = '.')
732
    Dir.open("#{curr_srcdir()}/#{path}") {|d|
733
      return d.to_a - %w(. ..)
734
    }
735
  end
736

  
737
  def srcfiles(path = '.')
738
    srcentries(path).select {|fname|
739
      File.file?(File.join(curr_srcdir(), path, fname))
740
    }
741
  end
742

  
743
  def srcdirectories(path = '.')
744
    srcentries(path).select {|fname|
745
      File.dir?(File.join(curr_srcdir(), path, fname))
746
    }
747
  end
748

  
749
end
750

  
751

  
752
class ToplevelInstaller
753

  
754
  Version   = '3.4.1'
755
  Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
756

  
757
  TASKS = [
758
    [ 'all',      'do config, setup, then install' ],
759
    [ 'config',   'saves your configurations' ],
760
    [ 'show',     'shows current configuration' ],
761
    [ 'setup',    'compiles ruby extentions and others' ],
762
    [ 'install',  'installs files' ],
763
    [ 'test',     'run all tests in test/' ],
764
    [ 'clean',    "does `make clean' for each extention" ],
765
    [ 'distclean',"does `make distclean' for each extention" ]
766
  ]
767

  
768
  def ToplevelInstaller.invoke
769
    config = ConfigTable.new(load_rbconfig())
770
    config.load_standard_entries
771
    config.load_multipackage_entries if multipackage?
772
    config.fixup
773
    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
774
    klass.new(File.dirname($0), config).invoke
775
  end
776

  
777
  def ToplevelInstaller.multipackage?
778
    File.dir?(File.dirname($0) + '/packages')
779
  end
780

  
781
  def ToplevelInstaller.load_rbconfig
782
    if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
783
      ARGV.delete(arg)
784
      load File.expand_path(arg.split(/=/, 2)[1])
785
      $".push 'rbconfig.rb'
786
    else
787
      require 'rbconfig'
788
    end
789
    ::Config::CONFIG
790
  end
791

  
792
  def initialize(ardir_root, config)
793
    @ardir = File.expand_path(ardir_root)
794
    @config = config
795
    # cache
796
    @valid_task_re = nil
797
  end
798

  
799
  def config(key)
800
    @config[key]
801
  end
802

  
803
  def inspect
804
    "#<#{self.class} #{__id__()}>"
805
  end
806

  
807
  def invoke
808
    run_metaconfigs
809
    case task = parsearg_global()
810
    when nil, 'all'
811
      parsearg_config
812
      init_installers
813
      exec_config
814
      exec_setup
815
      exec_install
816
    else
817
      case task
818
      when 'config', 'test'
819
        ;
820
      when 'clean', 'distclean'
821
        @config.load_savefile if File.exist?(@config.savefile)
822
      else
823
        @config.load_savefile
824
      end
825
      __send__ "parsearg_#{task}"
826
      init_installers
827
      __send__ "exec_#{task}"
828
    end
829
  end
830
  
831
  def run_metaconfigs
832
    @config.load_script "#{@ardir}/metaconfig"
833
  end
834

  
835
  def init_installers
836
    @installer = Installer.new(@config, @ardir, File.expand_path('.'))
837
  end
838

  
839
  #
840
  # Hook Script API bases
841
  #
842

  
843
  def srcdir_root
844
    @ardir
845
  end
846

  
847
  def objdir_root
848
    '.'
849
  end
850

  
851
  def relpath
852
    '.'
853
  end
854

  
855
  #
856
  # Option Parsing
857
  #
858

  
859
  def parsearg_global
860
    while arg = ARGV.shift
861
      case arg
862
      when /\A\w+\z/
863
        setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
864
        return arg
865
      when '-q', '--quiet'
866
        @config.verbose = false
867
      when '--verbose'
868
        @config.verbose = true
869
      when '--help'
870
        print_usage $stdout
871
        exit 0
872
      when '--version'
873
        puts "#{File.basename($0)} version #{Version}"
874
        exit 0
875
      when '--copyright'
876
        puts Copyright
877
        exit 0
878
      else
879
        setup_rb_error "unknown global option '#{arg}'"
880
      end
881
    end
882
    nil
883
  end
884

  
885
  def valid_task?(t)
886
    valid_task_re() =~ t
887
  end
888

  
889
  def valid_task_re
890
    @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
891
  end
892

  
893
  def parsearg_no_options
894
    unless ARGV.empty?
895
      task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
896
      setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
897
    end
898
  end
899

  
900
  alias parsearg_show       parsearg_no_options
901
  alias parsearg_setup      parsearg_no_options
902
  alias parsearg_test       parsearg_no_options
903
  alias parsearg_clean      parsearg_no_options
904
  alias parsearg_distclean  parsearg_no_options
905

  
906
  def parsearg_config
907
    evalopt = []
908
    set = []
909
    @config.config_opt = []
910
    while i = ARGV.shift
911
      if /\A--?\z/ =~ i
912
        @config.config_opt = ARGV.dup
913
        break
914
      end
915
      name, value = *@config.parse_opt(i)
916
      if @config.value_config?(name)
917
        @config[name] = value
918
      else
919
        evalopt.push [name, value]
920
      end
921
      set.push name
922
    end
923
    evalopt.each do |name, value|
924
      @config.lookup(name).evaluate value, @config
925
    end
926
    # Check if configuration is valid
927
    set.each do |n|
928
      @config[n] if @config.value_config?(n)
929
    end
930
  end
931

  
932
  def parsearg_install
933
    @config.no_harm = false
934
    @config.install_prefix = ''
935
    while a = ARGV.shift
936
      case a
937
      when '--no-harm'
938
        @config.no_harm = true
939
      when /\A--prefix=/
940
        path = a.split(/=/, 2)[1]
941
        path = File.expand_path(path) unless path[0,1] == '/'
942
        @config.install_prefix = path
943
      else
944
        setup_rb_error "install: unknown option #{a}"
945
      end
946
    end
947
  end
948

  
949
  def print_usage(out)
950
    out.puts 'Typical Installation Procedure:'
951
    out.puts "  $ ruby #{File.basename $0} config"
952
    out.puts "  $ ruby #{File.basename $0} setup"
953
    out.puts "  # ruby #{File.basename $0} install (may require root privilege)"
954
    out.puts
955
    out.puts 'Detailed Usage:'
956
    out.puts "  ruby #{File.basename $0} <global option>"
957
    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
958

  
959
    fmt = "  %-24s %s\n"
960
    out.puts
961
    out.puts 'Global options:'
962
    out.printf fmt, '-q,--quiet',   'suppress message outputs'
963
    out.printf fmt, '   --verbose', 'output messages verbosely'
964
    out.printf fmt, '   --help',    'print this message'
965
    out.printf fmt, '   --version', 'print version and quit'
966
    out.printf fmt, '   --copyright',  'print copyright and quit'
967
    out.puts
968
    out.puts 'Tasks:'
969
    TASKS.each do |name, desc|
970
      out.printf fmt, name, desc
971
    end
972

  
973
    fmt = "  %-24s %s [%s]\n"
974
    out.puts
975
    out.puts 'Options for CONFIG or ALL:'
976
    @config.each do |item|
977
      out.printf fmt, item.help_opt, item.description, item.help_default
978
    end
979
    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
980
    out.puts
981
    out.puts 'Options for INSTALL:'
982
    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
983
    out.printf fmt, '--prefix=path',  'install path prefix', ''
984
    out.puts
985
  end
986

  
987
  #
988
  # Task Handlers
989
  #
990

  
991
  def exec_config
992
    @installer.exec_config
993
    @config.save   # must be final
994
  end
995

  
996
  def exec_setup
997
    @installer.exec_setup
998
  end
999

  
1000
  def exec_install
1001
    @installer.exec_install
1002
  end
1003

  
1004
  def exec_test
1005
    @installer.exec_test
1006
  end
1007

  
1008
  def exec_show
1009
    @config.each do |i|
1010
      printf "%-20s %s\n", i.name, i.value if i.value?
1011
    end
1012
  end
1013

  
1014
  def exec_clean
1015
    @installer.exec_clean
1016
  end
1017

  
1018
  def exec_distclean
1019
    @installer.exec_distclean
1020
  end
1021

  
1022
end   # class ToplevelInstaller
1023

  
1024

  
1025
class ToplevelInstallerMulti < ToplevelInstaller
1026

  
1027
  include FileOperations
1028

  
1029
  def initialize(ardir_root, config)
1030
    super
1031
    @packages = directories_of("#{@ardir}/packages")
1032
    raise 'no package exists' if @packages.empty?
1033
    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1034
  end
1035

  
1036
  def run_metaconfigs
1037
    @config.load_script "#{@ardir}/metaconfig", self
1038
    @packages.each do |name|
1039
      @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
1040
    end
1041
  end
1042

  
1043
  attr_reader :packages
1044

  
1045
  def packages=(list)
1046
    raise 'package list is empty' if list.empty?
1047
    list.each do |name|
1048
      raise "directory packages/#{name} does not exist"\
1049
              unless File.dir?("#{@ardir}/packages/#{name}")
1050
    end
1051
    @packages = list
1052
  end
1053

  
1054
  def init_installers
1055
    @installers = {}
1056
    @packages.each do |pack|
1057
      @installers[pack] = Installer.new(@config,
1058
                                       "#{@ardir}/packages/#{pack}",
1059
                                       "packages/#{pack}")
1060
    end
1061
    with    = extract_selection(config('with'))
1062
    without = extract_selection(config('without'))
1063
    @selected = @installers.keys.select {|name|
1064
                  (with.empty? or with.include?(name)) \
1065
                      and not without.include?(name)
1066
                }
1067
  end
1068

  
1069
  def extract_selection(list)
1070
    a = list.split(/,/)
1071
    a.each do |name|
1072
      setup_rb_error "no such package: #{name}"  unless @installers.key?(name)
1073
    end
1074
    a
1075
  end
1076

  
1077
  def print_usage(f)
1078
    super
1079
    f.puts 'Inluded packages:'
1080
    f.puts '  ' + @packages.sort.join(' ')
1081
    f.puts
1082
  end
1083

  
1084
  #
1085
  # Task Handlers
1086
  #
1087

  
1088
  def exec_config
1089
    run_hook 'pre-config'
1090
    each_selected_installers {|inst| inst.exec_config }
1091
    run_hook 'post-config'
1092
    @config.save   # must be final
1093
  end
1094

  
1095
  def exec_setup
1096
    run_hook 'pre-setup'
1097
    each_selected_installers {|inst| inst.exec_setup }
1098
    run_hook 'post-setup'
1099
  end
1100

  
1101
  def exec_install
1102
    run_hook 'pre-install'
1103
    each_selected_installers {|inst| inst.exec_install }
1104
    run_hook 'post-install'
1105
  end
1106

  
1107
  def exec_test
1108
    run_hook 'pre-test'
1109
    each_selected_installers {|inst| inst.exec_test }
1110
    run_hook 'post-test'
1111
  end
1112

  
1113
  def exec_clean
1114
    rm_f @config.savefile
1115
    run_hook 'pre-clean'
1116
    each_selected_installers {|inst| inst.exec_clean }
1117
    run_hook 'post-clean'
1118
  end
1119

  
1120
  def exec_distclean
1121
    rm_f @config.savefile
1122
    run_hook 'pre-distclean'
1123
    each_selected_installers {|inst| inst.exec_distclean }
1124
    run_hook 'post-distclean'
1125
  end
1126

  
1127
  #
1128
  # lib
1129
  #
1130

  
1131
  def each_selected_installers
1132
    Dir.mkdir 'packages' unless File.dir?('packages')
1133
    @selected.each do |pack|
1134
      $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1135
      Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1136
      Dir.chdir "packages/#{pack}"
1137
      yield @installers[pack]
1138
      Dir.chdir '../..'
1139
    end
1140
  end
1141

  
1142
  def run_hook(id)
1143
    @root_installer.run_hook id
1144
  end
1145

  
1146
  # module FileOperations requires this
1147
  def verbose?
1148
    @config.verbose?
1149
  end
1150

  
1151
  # module FileOperations requires this
1152
  def no_harm?
1153
    @config.no_harm?
1154
  end
1155

  
1156
end   # class ToplevelInstallerMulti
1157

  
1158

  
1159
class Installer
1160

  
1161
  FILETYPES = %w( bin lib ext data conf man )
1162

  
1163
  include FileOperations
1164
  include HookScriptAPI
1165

  
1166
  def initialize(config, srcroot, objroot)
1167
    @config = config
1168
    @srcdir = File.expand_path(srcroot)
1169
    @objdir = File.expand_path(objroot)
1170
    @currdir = '.'
1171
  end
1172

  
1173
  def inspect
1174
    "#<#{self.class} #{File.basename(@srcdir)}>"
1175
  end
1176

  
1177
  def noop(rel)
1178
  end
1179

  
1180
  #
1181
  # Hook Script API base methods
1182
  #
1183

  
1184
  def srcdir_root
1185
    @srcdir
1186
  end
1187

  
1188
  def objdir_root
1189
    @objdir
1190
  end
1191

  
1192
  def relpath
1193
    @currdir
1194
  end
1195

  
1196
  #
1197
  # Config Access
1198
  #
1199

  
1200
  # module FileOperations requires this
1201
  def verbose?
1202
    @config.verbose?
1203
  end
1204

  
1205
  # module FileOperations requires this
1206
  def no_harm?
1207
    @config.no_harm?
1208
  end
1209

  
1210
  def verbose_off
1211
    begin
1212
      save, @config.verbose = @config.verbose?, false
1213
      yield
1214
    ensure
1215
      @config.verbose = save
1216
    end
1217
  end
1218

  
1219
  #
1220
  # TASK config
1221
  #
1222

  
1223
  def exec_config
1224
    exec_task_traverse 'config'
1225
  end
1226

  
1227
  alias config_dir_bin noop
1228
  alias config_dir_lib noop
1229

  
1230
  def config_dir_ext(rel)
1231
    extconf if extdir?(curr_srcdir())
1232
  end
1233

  
1234
  alias config_dir_data noop
1235
  alias config_dir_conf noop
1236
  alias config_dir_man noop
1237

  
1238
  def extconf
1239
    ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1240
  end
1241

  
1242
  #
1243
  # TASK setup
1244
  #
1245

  
1246
  def exec_setup
1247
    exec_task_traverse 'setup'
1248
  end
1249

  
1250
  def setup_dir_bin(rel)
1251
    files_of(curr_srcdir()).each do |fname|
1252
      update_shebang_line "#{curr_srcdir()}/#{fname}"
1253
    end
1254
  end
1255

  
1256
  alias setup_dir_lib noop
1257

  
1258
  def setup_dir_ext(rel)
1259
    make if extdir?(curr_srcdir())
1260
  end
1261

  
1262
  alias setup_dir_data noop
1263
  alias setup_dir_conf noop
1264
  alias setup_dir_man noop
1265

  
1266
  def update_shebang_line(path)
1267
    return if no_harm?
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff