cuts 0.0.1
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.
- data/CHANGES +16 -0
- data/COPYING +674 -0
- data/NOTES +6 -0
- data/README +51 -0
- data/Rakefile +2 -0
- data/lib/cuts.rb +2 -0
- data/lib/cuts/aop.rb +205 -0
- data/lib/cuts/cut.rb +190 -0
- data/meta/project.yaml +23 -0
- data/meta/unixname +1 -0
- data/meta/version +1 -0
- data/setup.rb +1467 -0
- data/test/template.rb +16 -0
- metadata +72 -0
data/meta/project.yaml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
project : cuts
|
3
|
+
|
4
|
+
contact : Trans <transfire@gmail.com>
|
5
|
+
license : MIT
|
6
|
+
created : 2008-02-21
|
7
|
+
homepage : http://cuts.rubyforge.org
|
8
|
+
repository : http://cuts.rubyforge.org/svn
|
9
|
+
|
10
|
+
# Title. This defaults to project capitalized, if not given.
|
11
|
+
title : Cuts
|
12
|
+
|
13
|
+
# One line description.
|
14
|
+
brief : Cut-based AOP for Ruby
|
15
|
+
|
16
|
+
# Detailed description.
|
17
|
+
description: >
|
18
|
+
Cuts is an expiremental implementation of cut-based
|
19
|
+
AOP for Ruby.
|
20
|
+
|
21
|
+
# Directories to exclude from package.
|
22
|
+
exclude : [ work, doc, ri ]
|
23
|
+
|
data/meta/unixname
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
cuts
|
data/meta/version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1 alpha (2008-02-21)
|
data/setup.rb
ADDED
@@ -0,0 +1,1467 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Setup.rb v3.5.0
|
3
|
+
# Copyright (c) 2008 Minero Aoki, Trans
|
4
|
+
#
|
5
|
+
# This program is free software.
|
6
|
+
# You can distribute/modify this program under the terms of
|
7
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
8
|
+
|
9
|
+
# Need the package name, and whether to generate documentation.
|
10
|
+
PACKAGE = File.read(Dir.glob('{.,meta/}unixname{,.txt}', File::FNM_CASEFOLD).first).strip
|
11
|
+
GENERATE_RDOCS = true # package developer may need to deactivate
|
12
|
+
|
13
|
+
require 'optparse'
|
14
|
+
require 'rbconfig'
|
15
|
+
|
16
|
+
class SetupError < StandardError; end
|
17
|
+
|
18
|
+
# Typical installation procedure:
|
19
|
+
#
|
20
|
+
# $ ./setup.rb
|
21
|
+
#
|
22
|
+
# -- or --
|
23
|
+
#
|
24
|
+
# $ ./setup.rb config
|
25
|
+
# $ ./setup.rb setup
|
26
|
+
# $ ./setup.rb install
|
27
|
+
#
|
28
|
+
# @all@ and @install@ may require root privileges.
|
29
|
+
#
|
30
|
+
# This update only works with Ruby 1.6.3 and above.
|
31
|
+
#
|
32
|
+
# TODO: Update shebangs on install of binaries.
|
33
|
+
# TODO: Make cleaning more comprehensive (?)
|
34
|
+
|
35
|
+
module Setup
|
36
|
+
Version = "3.5.0"
|
37
|
+
|
38
|
+
Copyright = "Copyright (c) 2000,2008 Minero Aoki, Trans"
|
39
|
+
|
40
|
+
# ConfigTable stores platform information.
|
41
|
+
|
42
|
+
class ConfigTable
|
43
|
+
|
44
|
+
RBCONFIG = ::Config::CONFIG
|
45
|
+
|
46
|
+
CONFIGFILE = '.config'
|
47
|
+
|
48
|
+
DESCRIPTIONS = [
|
49
|
+
[:prefix , :path, 'path prefix of target environment'],
|
50
|
+
[:bindir , :path, 'directory for commands'],
|
51
|
+
[:libdir , :path, 'directory for libraries'],
|
52
|
+
[:datadir , :path, 'directory for shared data'],
|
53
|
+
[:mandir , :path, 'directory for man pages'],
|
54
|
+
[:docdir , :path, 'Directory for documentation'],
|
55
|
+
[:sysconfdir , :path, 'directory for system configuration files'],
|
56
|
+
[:localstatedir , :path, 'directory for local state data'],
|
57
|
+
[:libruby , :path, 'directory for ruby libraries'],
|
58
|
+
[:librubyver , :path, 'directory for standard ruby libraries'],
|
59
|
+
[:librubyverarch , :path, 'directory for standard ruby extensions'],
|
60
|
+
[:siteruby , :path, 'directory for version-independent aux ruby libraries'],
|
61
|
+
[:siterubyver , :path, 'directory for aux ruby libraries'],
|
62
|
+
[:siterubyverarch , :path, 'directory for aux ruby binaries'],
|
63
|
+
[:rbdir , :path, 'directory for ruby scripts'],
|
64
|
+
[:sodir , :path, 'directory for ruby extentions'],
|
65
|
+
[:rubypath , :prog, 'path to set to #! line'],
|
66
|
+
[:rubyprog , :prog, 'ruby program using for installation'],
|
67
|
+
[:makeprog , :prog, 'make program to compile ruby extentions'],
|
68
|
+
[:without_ext , :bool, 'do not compile/install ruby extentions'],
|
69
|
+
[:without_doc , :bool, 'do not generate html documentation'],
|
70
|
+
[:shebang , :pick, 'shebang line (#!) editing mode (all,ruby,never)'],
|
71
|
+
[:doctemplate , :pick, 'document template to use (html|xml)'],
|
72
|
+
[:testrunner , :pick, 'Runner to use for testing (auto|console|tk|gtk|gtk2)'],
|
73
|
+
[:installdirs , :pick, 'install location mode (std,site,home :: libruby,site_ruby,$HOME)']
|
74
|
+
]
|
75
|
+
|
76
|
+
# List of configurable options.
|
77
|
+
OPTIONS = DESCRIPTIONS.collect{ |(k,t,v)| k.to_s }
|
78
|
+
|
79
|
+
# Pathname attribute. Pathnames are automatically expanded
|
80
|
+
# unless they start with '$', a path variable.
|
81
|
+
def self.attr_pathname(name)
|
82
|
+
class_eval %{
|
83
|
+
def #{name}
|
84
|
+
@#{name}.gsub(%r<\\$([^/]+)>){ self[$1] }
|
85
|
+
end
|
86
|
+
def #{name}=(path)
|
87
|
+
raise SetupError, "bad config: #{name.to_s.upcase} requires argument" unless path
|
88
|
+
@#{name} = (path[0,1] == '$' ? path : File.expand_path(path))
|
89
|
+
end
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
# List of pathnames. These are not expanded though.
|
94
|
+
def self.attr_pathlist(name)
|
95
|
+
class_eval %{
|
96
|
+
def #{name}
|
97
|
+
@#{name}
|
98
|
+
end
|
99
|
+
def #{name}=(pathlist)
|
100
|
+
case pathlist
|
101
|
+
when Array
|
102
|
+
@#{name} = pathlist
|
103
|
+
else
|
104
|
+
@#{name} = pathlist.to_s.split(/[:;,]/)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
# Adds boolean support.
|
111
|
+
def self.attr_accessor(*names)
|
112
|
+
bools, attrs = names.partition{ |name| name.to_s =~ /\?$/ }
|
113
|
+
attr_boolean *bools
|
114
|
+
super *attrs
|
115
|
+
end
|
116
|
+
|
117
|
+
# Boolean attribute. Can be assigned true, false, nil, or
|
118
|
+
# a string matching yes|true|y|t or no|false|n|f.
|
119
|
+
def self.attr_boolean(*names)
|
120
|
+
names.each do |name|
|
121
|
+
name = name.to_s.chomp('?')
|
122
|
+
attr_reader name # MAYBE: Deprecate
|
123
|
+
code = %{
|
124
|
+
def #{name}?; @#{name}; end
|
125
|
+
def #{name}=(val)
|
126
|
+
case val
|
127
|
+
when true, false, nil
|
128
|
+
@#{name} = val
|
129
|
+
else
|
130
|
+
case val.to_s.downcase
|
131
|
+
when 'y', 'yes', 't', 'true'
|
132
|
+
@#{name} = true
|
133
|
+
when 'n', 'no', 'f', 'false'
|
134
|
+
@#{name} = false
|
135
|
+
else
|
136
|
+
raise SetupError, "bad config: use #{name.upcase}=(yes|no) [\#{val}]"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
}
|
141
|
+
class_eval code
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
DESCRIPTIONS.each do |k,t,d|
|
146
|
+
case t
|
147
|
+
when :path
|
148
|
+
attr_pathname k
|
149
|
+
when :bool
|
150
|
+
attr_boolean k
|
151
|
+
else
|
152
|
+
attr_accessor k
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# # provide verbosity (default is true)
|
157
|
+
# attr_accessor :verbose?
|
158
|
+
|
159
|
+
# # don't actually write files to system
|
160
|
+
# attr_accessor :no_harm?
|
161
|
+
|
162
|
+
# shebang has only three options.
|
163
|
+
def shebang=(val)
|
164
|
+
if %w(all ruby never).include?(val)
|
165
|
+
@shebang = val
|
166
|
+
else
|
167
|
+
raise SetupError, "bad config: use SHEBANG=(all|ruby|never) [#{val}]"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# installdirs has only three options; and it has side-effects.
|
172
|
+
def installdirs=(val)
|
173
|
+
@installdirs = val
|
174
|
+
case val.to_s
|
175
|
+
when 'std'
|
176
|
+
self.rbdir = '$librubyver'
|
177
|
+
self.sodir = '$librubyverarch'
|
178
|
+
when 'site'
|
179
|
+
self.rbdir = '$siterubyver'
|
180
|
+
self.sodir = '$siterubyverarch'
|
181
|
+
when 'home'
|
182
|
+
raise SetupError, 'HOME is not set.' unless ENV['HOME']
|
183
|
+
self.prefix = ENV['HOME']
|
184
|
+
self.rbdir = '$libdir/ruby'
|
185
|
+
self.sodir = '$libdir/ruby'
|
186
|
+
else
|
187
|
+
raise SetupError, "bad config: use INSTALLDIRS=(std|site|home|local) [#{val}]"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# New ConfigTable
|
192
|
+
def initialize(values=nil)
|
193
|
+
initialize_defaults
|
194
|
+
if values
|
195
|
+
values.each{ |k,v| __send__("#{k}=", v) }
|
196
|
+
end
|
197
|
+
yeild(self) if block_given?
|
198
|
+
load_config if File.file?(CONFIGFILE)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Assign CONFIG defaults
|
202
|
+
#
|
203
|
+
# TODO: Does this handle 'nmake' on windows?
|
204
|
+
def initialize_defaults
|
205
|
+
prefix = RBCONFIG['prefix']
|
206
|
+
|
207
|
+
rubypath = File.join(RBCONFIG['bindir'], RBCONFIG['ruby_install_name'] + RBCONFIG['EXEEXT'])
|
208
|
+
|
209
|
+
major = RBCONFIG['MAJOR'].to_i
|
210
|
+
minor = RBCONFIG['MINOR'].to_i
|
211
|
+
teeny = RBCONFIG['TEENY'].to_i
|
212
|
+
version = "#{major}.#{minor}"
|
213
|
+
|
214
|
+
# ruby ver. >= 1.4.4?
|
215
|
+
newpath_p = ((major >= 2) or
|
216
|
+
((major == 1) and
|
217
|
+
((minor >= 5) or
|
218
|
+
((minor == 4) and (teeny >= 4)))))
|
219
|
+
|
220
|
+
if RBCONFIG['rubylibdir']
|
221
|
+
# V > 1.6.3
|
222
|
+
libruby = "#{prefix}/lib/ruby"
|
223
|
+
librubyver = RBCONFIG['rubylibdir']
|
224
|
+
librubyverarch = RBCONFIG['archdir']
|
225
|
+
siteruby = RBCONFIG['sitedir']
|
226
|
+
siterubyver = RBCONFIG['sitelibdir']
|
227
|
+
siterubyverarch = RBCONFIG['sitearchdir']
|
228
|
+
elsif newpath_p
|
229
|
+
# 1.4.4 <= V <= 1.6.3
|
230
|
+
libruby = "#{prefix}/lib/ruby"
|
231
|
+
librubyver = "#{prefix}/lib/ruby/#{version}"
|
232
|
+
librubyverarch = "#{prefix}/lib/ruby/#{version}/#{c['arch']}"
|
233
|
+
siteruby = RBCONFIG['sitedir']
|
234
|
+
siterubyver = "$siteruby/#{version}"
|
235
|
+
siterubyverarch = "$siterubyver/#{RBCONFIG['arch']}"
|
236
|
+
else
|
237
|
+
# V < 1.4.4
|
238
|
+
libruby = "#{prefix}/lib/ruby"
|
239
|
+
librubyver = "#{prefix}/lib/ruby/#{version}"
|
240
|
+
librubyverarch = "#{prefix}/lib/ruby/#{version}/#{c['arch']}"
|
241
|
+
siteruby = "#{prefix}/lib/ruby/#{version}/site_ruby"
|
242
|
+
siterubyver = siteruby
|
243
|
+
siterubyverarch = "$siterubyver/#{RBCONFIG['arch']}"
|
244
|
+
end
|
245
|
+
|
246
|
+
if arg = RBCONFIG['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
|
247
|
+
makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
|
248
|
+
else
|
249
|
+
makeprog = 'make'
|
250
|
+
end
|
251
|
+
|
252
|
+
parameterize = lambda do |path|
|
253
|
+
val = RBCONFIG[path]
|
254
|
+
val.sub(/\A#{Regexp.quote(prefix)}/, '$prefix')
|
255
|
+
end
|
256
|
+
|
257
|
+
self.prefix = prefix
|
258
|
+
self.bindir = parameterize['bindir']
|
259
|
+
self.libdir = parameterize['libdir']
|
260
|
+
self.datadir = parameterize['datadir']
|
261
|
+
self.mandir = parameterize['mandir']
|
262
|
+
self.docdir = File.dirname(parameterize['docdir']) # b/c of trailing $(PACKAGE)
|
263
|
+
self.sysconfdir = parameterize['sysconfdir']
|
264
|
+
self.localstatedir = parameterize['localstatedir']
|
265
|
+
self.libruby = libruby
|
266
|
+
self.librubyver = librubyver
|
267
|
+
self.librubyverarch = librubyverarch
|
268
|
+
self.siteruby = siteruby
|
269
|
+
self.siterubyver = siterubyver
|
270
|
+
self.siterubyverarch = siterubyverarch
|
271
|
+
self.rbdir = '$siterubyver'
|
272
|
+
self.sodir = '$siterubyverarch'
|
273
|
+
self.rubypath = rubypath
|
274
|
+
self.rubyprog = rubypath
|
275
|
+
self.makeprog = makeprog
|
276
|
+
self.shebang = 'ruby'
|
277
|
+
self.without_ext = 'no'
|
278
|
+
self.without_doc = 'yes'
|
279
|
+
self.doctemplate = 'html'
|
280
|
+
self.testrunner = 'auto'
|
281
|
+
self.installdirs = 'site'
|
282
|
+
end
|
283
|
+
|
284
|
+
# Get configuration from environment.
|
285
|
+
def env_config
|
286
|
+
OPTIONS.each do |name|
|
287
|
+
if value = ENV[name]
|
288
|
+
__send__("#{name}=",value)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Load configuration.
|
294
|
+
def load_config
|
295
|
+
#if File.file?(CONFIGFILE)
|
296
|
+
begin
|
297
|
+
File.foreach(CONFIGFILE) do |line|
|
298
|
+
k, v = *line.split(/=/, 2)
|
299
|
+
__send__("#{k}=",v.strip) #self[k] = v.strip
|
300
|
+
end
|
301
|
+
rescue Errno::ENOENT
|
302
|
+
raise SetupError, $!.message + "\n#{File.basename($0)} config first"
|
303
|
+
end
|
304
|
+
#end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Save configuration.
|
308
|
+
def save_config
|
309
|
+
File.open(CONFIGFILE, 'w') do |f|
|
310
|
+
OPTIONS.each do |name|
|
311
|
+
val = self[name]
|
312
|
+
f << "#{name}=#{val}\n"
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def show
|
318
|
+
fmt = "%-20s %s\n"
|
319
|
+
OPTIONS.each do |name|
|
320
|
+
value = self[name]
|
321
|
+
printf fmt, name, __send__(name) if value
|
322
|
+
end
|
323
|
+
#printf fmt, 'verbose', verbose? ? 'yes' : 'no'
|
324
|
+
#printf fmt, 'no-write', no_harm? ? 'yes' : 'no'
|
325
|
+
end
|
326
|
+
|
327
|
+
#
|
328
|
+
|
329
|
+
def extconfs
|
330
|
+
@extconfs ||= Dir['ext/**/extconf.rb']
|
331
|
+
end
|
332
|
+
|
333
|
+
def extensions
|
334
|
+
@extensions ||= extconfs.collect{ |f| File.dirname(f) }
|
335
|
+
end
|
336
|
+
|
337
|
+
def compiles?
|
338
|
+
!extensions.empty?
|
339
|
+
end
|
340
|
+
|
341
|
+
private
|
342
|
+
|
343
|
+
# Get unresloved attribute.
|
344
|
+
def [](name)
|
345
|
+
instance_variable_get("@#{name}")
|
346
|
+
end
|
347
|
+
|
348
|
+
# Set attribute.
|
349
|
+
def []=(name, value)
|
350
|
+
instance_variable_set("@#{name}", value)
|
351
|
+
end
|
352
|
+
|
353
|
+
# Resolved attribute. (for paths)
|
354
|
+
#def resolve(name)
|
355
|
+
# self[name].gsub(%r<\\$([^/]+)>){ self[$1] }
|
356
|
+
#end
|
357
|
+
|
358
|
+
end
|
359
|
+
|
360
|
+
# Installer class handles the actual install procedure,
|
361
|
+
# as well as the other tasks, such as testing.
|
362
|
+
|
363
|
+
class Installer
|
364
|
+
|
365
|
+
MANIFEST = '.installedfiles'
|
366
|
+
|
367
|
+
FILETYPES = %w( bin lib ext data conf man doc )
|
368
|
+
|
369
|
+
TASK_DESCRIPTIONS = [
|
370
|
+
[ 'all', 'do config, setup, then install' ],
|
371
|
+
[ 'config', 'saves your configurations' ],
|
372
|
+
[ 'show', 'shows current configuration' ],
|
373
|
+
[ 'setup', 'compiles ruby extentions and others' ],
|
374
|
+
[ 'doc', 'generate html documentation' ],
|
375
|
+
[ 'index', 'generate index documentation' ],
|
376
|
+
[ 'install', 'installs files' ],
|
377
|
+
[ 'test', 'run all tests in test/' ],
|
378
|
+
[ 'clean', "does `make clean' for each extention" ],
|
379
|
+
[ 'distclean',"does `make distclean' for each extention" ]
|
380
|
+
]
|
381
|
+
|
382
|
+
TASKS = %w(all config show setup test install uninstall doc index clean distclean)
|
383
|
+
|
384
|
+
# Configuration
|
385
|
+
attr :config
|
386
|
+
|
387
|
+
attr_writer :no_harm
|
388
|
+
attr_writer :verbose
|
389
|
+
attr_writer :quiet
|
390
|
+
|
391
|
+
attr_accessor :install_prefix
|
392
|
+
|
393
|
+
# New Installer.
|
394
|
+
def initialize #:yield:
|
395
|
+
srcroot = '.'
|
396
|
+
objroot = '.'
|
397
|
+
|
398
|
+
@config = ConfigTable.new
|
399
|
+
|
400
|
+
@srcdir = File.expand_path(srcroot)
|
401
|
+
@objdir = File.expand_path(objroot)
|
402
|
+
@currdir = '.'
|
403
|
+
|
404
|
+
self.quiet = ENV['quiet'] if ENV['quiet']
|
405
|
+
self.verbose = ENV['verbose'] if ENV['verbose']
|
406
|
+
self.no_harm = ENV['nowrite'] if ENV['nowrite']
|
407
|
+
|
408
|
+
yield(self) if block_given?
|
409
|
+
end
|
410
|
+
|
411
|
+
def inspect
|
412
|
+
"#<#{self.class} #{File.basename(@srcdir)}>"
|
413
|
+
end
|
414
|
+
|
415
|
+
# Are we running an installation?
|
416
|
+
def installation?; @installation; end
|
417
|
+
def installation!; @installation = true; end
|
418
|
+
|
419
|
+
def no_harm?; @no_harm; end
|
420
|
+
def verbose?; @verbose; end
|
421
|
+
def quiet?; @quiet; end
|
422
|
+
|
423
|
+
def verbose_off #:yield:
|
424
|
+
begin
|
425
|
+
save, @verbose = verbose?, false
|
426
|
+
yield
|
427
|
+
ensure
|
428
|
+
@verbose = save
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
# Rake task handlers
|
433
|
+
def rake_define
|
434
|
+
require 'rake/clean'
|
435
|
+
|
436
|
+
desc 'Config, setup and then install'
|
437
|
+
task :all => [:config, :setup, :install]
|
438
|
+
|
439
|
+
desc 'Saves your configurations'
|
440
|
+
task :config do exec_config end
|
441
|
+
|
442
|
+
desc 'Compiles ruby extentions'
|
443
|
+
task :setup do exec_setup end
|
444
|
+
|
445
|
+
desc 'Generate html api docs'
|
446
|
+
task :doc do exec_doc end
|
447
|
+
|
448
|
+
desc 'Generate api index docs'
|
449
|
+
task :index do exec_index end
|
450
|
+
|
451
|
+
desc 'Installs files'
|
452
|
+
task :install do exec_install end
|
453
|
+
|
454
|
+
desc 'Uninstalls files'
|
455
|
+
task :uninstall do exec_uninstall end
|
456
|
+
|
457
|
+
#desc "Does `make clean' for each extention"
|
458
|
+
task :makeclean do exec_clean end
|
459
|
+
|
460
|
+
task :clean => [:makeclean]
|
461
|
+
|
462
|
+
#desc "Does `make distclean' for each extention"
|
463
|
+
task :distclean do exec_distclean end
|
464
|
+
|
465
|
+
task :clobber => [:distclean]
|
466
|
+
|
467
|
+
desc 'Shows current configuration'
|
468
|
+
task :show do exec_show end
|
469
|
+
end
|
470
|
+
|
471
|
+
# Added these for future use in simplificaiton of design.
|
472
|
+
|
473
|
+
def extensions
|
474
|
+
@extensions ||= Dir['ext/**/extconf.rb']
|
475
|
+
end
|
476
|
+
|
477
|
+
def compiles?
|
478
|
+
!extensions.empty?
|
479
|
+
end
|
480
|
+
|
481
|
+
#
|
482
|
+
def noop(rel); end
|
483
|
+
|
484
|
+
#
|
485
|
+
# Hook Script API bases
|
486
|
+
#
|
487
|
+
|
488
|
+
def srcdir_root
|
489
|
+
@srcdir
|
490
|
+
end
|
491
|
+
|
492
|
+
def objdir_root
|
493
|
+
@objdir
|
494
|
+
end
|
495
|
+
|
496
|
+
def relpath
|
497
|
+
@currdir
|
498
|
+
end
|
499
|
+
|
500
|
+
#
|
501
|
+
# Task all
|
502
|
+
#
|
503
|
+
|
504
|
+
def exec_all
|
505
|
+
exec_config
|
506
|
+
exec_setup
|
507
|
+
exec_test # TODO: we need to stop here if tests fail (how?)
|
508
|
+
exec_doc if GENERATE_RDOCS && !config.without_doc?
|
509
|
+
exec_install
|
510
|
+
end
|
511
|
+
|
512
|
+
#
|
513
|
+
# TASK config
|
514
|
+
#
|
515
|
+
|
516
|
+
def exec_config
|
517
|
+
config.env_config
|
518
|
+
config.save_config
|
519
|
+
exec_task_traverse 'config'
|
520
|
+
config.show unless quiet?
|
521
|
+
puts("Configuration saved.") unless quiet?
|
522
|
+
end
|
523
|
+
|
524
|
+
alias config_dir_bin noop
|
525
|
+
alias config_dir_lib noop
|
526
|
+
|
527
|
+
def config_dir_ext(rel)
|
528
|
+
extconf if extdir?(curr_srcdir())
|
529
|
+
end
|
530
|
+
|
531
|
+
alias config_dir_data noop
|
532
|
+
alias config_dir_conf noop
|
533
|
+
alias config_dir_man noop
|
534
|
+
alias config_dir_doc noop
|
535
|
+
|
536
|
+
def extconf
|
537
|
+
ruby "#{curr_srcdir()}/extconf.rb", config_opt
|
538
|
+
end
|
539
|
+
|
540
|
+
#
|
541
|
+
# TASK show
|
542
|
+
#
|
543
|
+
|
544
|
+
def exec_show
|
545
|
+
config.show
|
546
|
+
end
|
547
|
+
|
548
|
+
#
|
549
|
+
# TASK setup
|
550
|
+
#
|
551
|
+
# FIXME: Update shebang at time of install not before.
|
552
|
+
# for now I've commented it out the shebang.
|
553
|
+
|
554
|
+
def exec_setup
|
555
|
+
exec_task_traverse 'setup'
|
556
|
+
end
|
557
|
+
|
558
|
+
def setup_dir_bin(rel)
|
559
|
+
files_of(curr_srcdir()).each do |fname|
|
560
|
+
#update_shebang_line "#{curr_srcdir()}/#{fname}"
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
alias setup_dir_lib noop
|
565
|
+
|
566
|
+
def setup_dir_ext(rel)
|
567
|
+
make if extdir?(curr_srcdir())
|
568
|
+
end
|
569
|
+
|
570
|
+
alias setup_dir_data noop
|
571
|
+
alias setup_dir_conf noop
|
572
|
+
alias setup_dir_man noop
|
573
|
+
alias setup_dir_doc noop
|
574
|
+
|
575
|
+
def update_shebang_line(path)
|
576
|
+
return if no_harm?
|
577
|
+
return if config.shebang == 'never'
|
578
|
+
old = Shebang.load(path)
|
579
|
+
if old
|
580
|
+
if old.args.size > 1
|
581
|
+
$stderr.puts "warning: #{path}"
|
582
|
+
$stderr.puts "Shebang line has too many args."
|
583
|
+
$stderr.puts "It is not portable and your program may not work."
|
584
|
+
end
|
585
|
+
new = new_shebang(old)
|
586
|
+
return if new.to_s == old.to_s
|
587
|
+
else
|
588
|
+
return unless config.shebang == 'all'
|
589
|
+
new = Shebang.new(config.rubypath)
|
590
|
+
end
|
591
|
+
$stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
|
592
|
+
open_atomic_writer(path) {|output|
|
593
|
+
File.open(path, 'rb') {|f|
|
594
|
+
f.gets if old # discard
|
595
|
+
output.puts new.to_s
|
596
|
+
output.print f.read
|
597
|
+
}
|
598
|
+
}
|
599
|
+
end
|
600
|
+
|
601
|
+
def new_shebang(old)
|
602
|
+
if /\Aruby/ =~ File.basename(old.cmd)
|
603
|
+
Shebang.new(config.rubypath, old.args)
|
604
|
+
elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
|
605
|
+
Shebang.new(config.rubypath, old.args[1..-1])
|
606
|
+
else
|
607
|
+
return old unless config.shebang == 'all'
|
608
|
+
Shebang.new(config.rubypath)
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
def open_atomic_writer(path, &block)
|
613
|
+
tmpfile = File.basename(path) + '.tmp'
|
614
|
+
begin
|
615
|
+
File.open(tmpfile, 'wb', &block)
|
616
|
+
File.rename tmpfile, File.basename(path)
|
617
|
+
ensure
|
618
|
+
File.unlink tmpfile if File.exist?(tmpfile)
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
class Shebang
|
623
|
+
def Shebang.load(path)
|
624
|
+
line = nil
|
625
|
+
File.open(path) {|f|
|
626
|
+
line = f.gets
|
627
|
+
}
|
628
|
+
return nil unless /\A#!/ =~ line
|
629
|
+
parse(line)
|
630
|
+
end
|
631
|
+
|
632
|
+
def Shebang.parse(line)
|
633
|
+
cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
|
634
|
+
new(cmd, args)
|
635
|
+
end
|
636
|
+
|
637
|
+
def initialize(cmd, args = [])
|
638
|
+
@cmd = cmd
|
639
|
+
@args = args
|
640
|
+
end
|
641
|
+
|
642
|
+
attr_reader :cmd
|
643
|
+
attr_reader :args
|
644
|
+
|
645
|
+
def to_s
|
646
|
+
"#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
#
|
651
|
+
# TASK test
|
652
|
+
#
|
653
|
+
# TODO: Add spec support.
|
654
|
+
|
655
|
+
def exec_test
|
656
|
+
$stderr.puts 'Running tests...' if verbose?
|
657
|
+
|
658
|
+
runner = config.testrunner
|
659
|
+
|
660
|
+
case runner
|
661
|
+
when 'auto'
|
662
|
+
unless File.directory?('test')
|
663
|
+
$stderr.puts 'no test in this package' if verbose?
|
664
|
+
return
|
665
|
+
end
|
666
|
+
begin
|
667
|
+
require 'test/unit'
|
668
|
+
rescue LoadError
|
669
|
+
setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
|
670
|
+
end
|
671
|
+
autorunner = Test::Unit::AutoRunner.new(true)
|
672
|
+
autorunner.to_run << 'test'
|
673
|
+
autorunner.run
|
674
|
+
else # use testrb
|
675
|
+
opt = []
|
676
|
+
opt << " -v" if verbose?
|
677
|
+
opt << " --runner #{runner}"
|
678
|
+
if File.file?('test/suite.rb')
|
679
|
+
notests = false
|
680
|
+
opt << "test/suite.rb"
|
681
|
+
else
|
682
|
+
notests = Dir["test/**/*.rb"].empty?
|
683
|
+
lib = ["lib"] + config.extensions.collect{ |d| File.dirname(d) }
|
684
|
+
opt << "-I" + lib.join(':')
|
685
|
+
opt << Dir["test/**/{test,tc}*.rb"]
|
686
|
+
end
|
687
|
+
opt = opt.flatten.join(' ').strip
|
688
|
+
# run tests
|
689
|
+
if notests
|
690
|
+
$stderr.puts 'no test in this package' if verbose?
|
691
|
+
else
|
692
|
+
cmd = "testrb #{opt}"
|
693
|
+
$stderr.puts cmd if verbose?
|
694
|
+
system cmd #config.ruby "-S tesrb", opt
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
# MAYBE: We could traverse and run each test independently (?)
|
700
|
+
#def test_dir_test
|
701
|
+
#end
|
702
|
+
|
703
|
+
#
|
704
|
+
# TASK doc
|
705
|
+
#
|
706
|
+
|
707
|
+
def exec_doc
|
708
|
+
output = File.join('doc', PACKAGE, 'rdoc')
|
709
|
+
title = (PACKAGE.capitalize + " API").strip
|
710
|
+
main = Dir.glob("README{,.txt}", File::FNM_CASEFOLD).first
|
711
|
+
template = config.doctemplate || 'html'
|
712
|
+
|
713
|
+
opt = []
|
714
|
+
opt << "-U"
|
715
|
+
opt << "-S"
|
716
|
+
opt << "--op=#{output}"
|
717
|
+
opt << "--template=#{template}"
|
718
|
+
opt << "--title=#{title}"
|
719
|
+
opt << "--main=#{main}" if main
|
720
|
+
|
721
|
+
if File.exist?('.document')
|
722
|
+
files = File.read('.document').split("\n")
|
723
|
+
files.reject!{ |l| l =~ /^\s*[#]/ || l !~ /\S/ }
|
724
|
+
files.collect!{ |f| f.strip }
|
725
|
+
opt << files
|
726
|
+
else
|
727
|
+
opt << main if main
|
728
|
+
opt << ["lib", "ext"]
|
729
|
+
end
|
730
|
+
|
731
|
+
opt = opt.flatten
|
732
|
+
|
733
|
+
if no_harm?
|
734
|
+
puts "rdoc " + opt.join(' ').strip
|
735
|
+
else
|
736
|
+
#sh "rdoc {opt.join(' ').strip}"
|
737
|
+
require 'rdoc/rdoc'
|
738
|
+
::RDoc::RDoc.new.document(opt)
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
#
|
743
|
+
# TASK index
|
744
|
+
#
|
745
|
+
# TODO: Totally deprecate stadard ri support in favor of fastri.
|
746
|
+
|
747
|
+
def exec_index
|
748
|
+
begin
|
749
|
+
require 'fastri/version'
|
750
|
+
fastri = true
|
751
|
+
rescue LoadError
|
752
|
+
fastri = false
|
753
|
+
end
|
754
|
+
if fastri
|
755
|
+
if no_harm?
|
756
|
+
$stderr.puts "fastri-server -b"
|
757
|
+
else
|
758
|
+
system "fastri-server -b"
|
759
|
+
end
|
760
|
+
else
|
761
|
+
case config.installdirs
|
762
|
+
when 'std'
|
763
|
+
output = "--ri-system"
|
764
|
+
when 'site'
|
765
|
+
output = "--ri-site"
|
766
|
+
when 'home'
|
767
|
+
output = "--ri"
|
768
|
+
else
|
769
|
+
abort "bad config: sould not be possible -- installdirs = #{config.installdirs}"
|
770
|
+
end
|
771
|
+
|
772
|
+
if File.exist?('.document')
|
773
|
+
files = File.read('.document').split("\n")
|
774
|
+
files.reject!{ |l| l =~ /^\s*[#]/ || l !~ /\S/ }
|
775
|
+
files.collect!{ |f| f.strip }
|
776
|
+
else
|
777
|
+
files = ["lib", "ext"]
|
778
|
+
end
|
779
|
+
|
780
|
+
opt = []
|
781
|
+
opt << "-U"
|
782
|
+
opt << output
|
783
|
+
opt << files
|
784
|
+
opt = opt.flatten
|
785
|
+
|
786
|
+
if no_harm?
|
787
|
+
puts "rdoc #{opt.join(' ').strip}"
|
788
|
+
else
|
789
|
+
#sh "rdoc #{opt.join(' ').strip}"
|
790
|
+
require 'rdoc/rdoc'
|
791
|
+
::RDoc::RDoc.new.document(opt)
|
792
|
+
end
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
#
|
797
|
+
# TASK install
|
798
|
+
#
|
799
|
+
|
800
|
+
def exec_install
|
801
|
+
installation! # were are installing
|
802
|
+
#rm_f MANIFEST # we'll append rather then delete!
|
803
|
+
exec_task_traverse 'install'
|
804
|
+
end
|
805
|
+
|
806
|
+
def install_dir_bin(rel)
|
807
|
+
install_files targetfiles(), "#{config.bindir}/#{rel}", 0755
|
808
|
+
end
|
809
|
+
|
810
|
+
def install_dir_lib(rel)
|
811
|
+
install_files libfiles(), "#{config.rbdir}/#{rel}", 0644
|
812
|
+
end
|
813
|
+
|
814
|
+
def install_dir_ext(rel)
|
815
|
+
return unless extdir?(curr_srcdir())
|
816
|
+
install_files rubyextentions('.'),
|
817
|
+
"#{config.sodir}/#{File.dirname(rel)}", 0555
|
818
|
+
end
|
819
|
+
|
820
|
+
def install_dir_data(rel)
|
821
|
+
install_files targetfiles(), "#{config.datadir}/#{rel}", 0644
|
822
|
+
end
|
823
|
+
|
824
|
+
def install_dir_conf(rel)
|
825
|
+
# FIXME: should not remove current config files
|
826
|
+
# (rename previous file to .old/.org)
|
827
|
+
install_files targetfiles(), "#{config.sysconfdir}/#{rel}", 0644
|
828
|
+
end
|
829
|
+
|
830
|
+
def install_dir_man(rel)
|
831
|
+
install_files targetfiles(), "#{config.mandir}/#{rel}", 0644
|
832
|
+
end
|
833
|
+
|
834
|
+
def install_dir_doc(rel)
|
835
|
+
return if config.without_doc?
|
836
|
+
install_files targetfiles(), "#{config.docdir}/#{rel}", 0644
|
837
|
+
end
|
838
|
+
|
839
|
+
def install_files(list, dest, mode)
|
840
|
+
mkdir_p dest, install_prefix
|
841
|
+
list.each do |fname|
|
842
|
+
install fname, dest, mode, install_prefix
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
def libfiles
|
847
|
+
glob_reject(%w(*.y *.output), targetfiles())
|
848
|
+
end
|
849
|
+
|
850
|
+
def rubyextentions(dir)
|
851
|
+
ents = glob_select("*.#{dllext}", targetfiles())
|
852
|
+
if ents.empty?
|
853
|
+
setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
|
854
|
+
end
|
855
|
+
ents
|
856
|
+
end
|
857
|
+
|
858
|
+
def dllext
|
859
|
+
RBCONFIG['DLEXT']
|
860
|
+
end
|
861
|
+
|
862
|
+
def targetfiles
|
863
|
+
mapdir(existfiles() - hookfiles())
|
864
|
+
end
|
865
|
+
|
866
|
+
def mapdir(ents)
|
867
|
+
ents.map {|ent|
|
868
|
+
if File.exist?(ent)
|
869
|
+
then ent # objdir
|
870
|
+
else "#{curr_srcdir()}/#{ent}" # srcdir
|
871
|
+
end
|
872
|
+
}
|
873
|
+
end
|
874
|
+
|
875
|
+
# picked up many entries from cvs-1.11.1/src/ignore.c
|
876
|
+
JUNK_FILES = %w(
|
877
|
+
core RCSLOG tags TAGS .make.state
|
878
|
+
.nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
|
879
|
+
*~ *.old *.bak *.BAK *.orig *.rej _$* *$
|
880
|
+
|
881
|
+
*.org *.in .*
|
882
|
+
)
|
883
|
+
|
884
|
+
def existfiles
|
885
|
+
glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
|
886
|
+
end
|
887
|
+
|
888
|
+
def hookfiles
|
889
|
+
%w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
|
890
|
+
%w( config setup install clean ).map {|t| sprintf(fmt, t) }
|
891
|
+
}.flatten
|
892
|
+
end
|
893
|
+
|
894
|
+
def glob_select(pat, ents)
|
895
|
+
re = globs2re([pat])
|
896
|
+
ents.select {|ent| re =~ ent }
|
897
|
+
end
|
898
|
+
|
899
|
+
def glob_reject(pats, ents)
|
900
|
+
re = globs2re(pats)
|
901
|
+
ents.reject {|ent| re =~ ent }
|
902
|
+
end
|
903
|
+
|
904
|
+
GLOB2REGEX = {
|
905
|
+
'.' => '\.',
|
906
|
+
'$' => '\$',
|
907
|
+
'#' => '\#',
|
908
|
+
'*' => '.*'
|
909
|
+
}
|
910
|
+
|
911
|
+
def globs2re(pats)
|
912
|
+
/\A(?:#{
|
913
|
+
pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
|
914
|
+
})\z/
|
915
|
+
end
|
916
|
+
|
917
|
+
#
|
918
|
+
# TASK uninstall
|
919
|
+
#
|
920
|
+
|
921
|
+
def exec_uninstall
|
922
|
+
paths = File.read(MANIFEST).split("\n")
|
923
|
+
dirs, files = paths.partition{ |f| File.dir?(f) }
|
924
|
+
|
925
|
+
files.each do |file|
|
926
|
+
next if /^\#/ =~ file # skip comments
|
927
|
+
rm_f(file) if File.exist?(file)
|
928
|
+
end
|
929
|
+
|
930
|
+
dirs.each do |dir|
|
931
|
+
# okay this is over kill, but playing it safe...
|
932
|
+
empty = Dir[File.join(dir,'*')].empty?
|
933
|
+
begin
|
934
|
+
if no_harm?
|
935
|
+
$stderr.puts "rmdir #{dir}"
|
936
|
+
else
|
937
|
+
rmdir(dir) if empty
|
938
|
+
end
|
939
|
+
rescue Errno::ENOTEMPTY
|
940
|
+
$stderr.puts "may not be empty -- #{dir}" if verbose?
|
941
|
+
end
|
942
|
+
end
|
943
|
+
|
944
|
+
rm_f(MANIFEST)
|
945
|
+
end
|
946
|
+
|
947
|
+
#
|
948
|
+
# TASK clean
|
949
|
+
#
|
950
|
+
|
951
|
+
def exec_clean
|
952
|
+
exec_task_traverse 'clean'
|
953
|
+
rm_f ConfigTable::CONFIGFILE
|
954
|
+
#rm_f MANIFEST # only on clobber!
|
955
|
+
end
|
956
|
+
|
957
|
+
alias clean_dir_bin noop
|
958
|
+
alias clean_dir_lib noop
|
959
|
+
alias clean_dir_data noop
|
960
|
+
alias clean_dir_conf noop
|
961
|
+
alias clean_dir_man noop
|
962
|
+
alias clean_dir_doc noop
|
963
|
+
|
964
|
+
def clean_dir_ext(rel)
|
965
|
+
return unless extdir?(curr_srcdir())
|
966
|
+
make 'clean' if File.file?('Makefile')
|
967
|
+
end
|
968
|
+
|
969
|
+
#
|
970
|
+
# TASK distclean
|
971
|
+
#
|
972
|
+
|
973
|
+
def exec_distclean
|
974
|
+
exec_task_traverse 'distclean'
|
975
|
+
rm_f ConfigTable::CONFIGFILE
|
976
|
+
rm_f MANIFEST
|
977
|
+
end
|
978
|
+
|
979
|
+
alias distclean_dir_bin noop
|
980
|
+
alias distclean_dir_lib noop
|
981
|
+
|
982
|
+
def distclean_dir_ext(rel)
|
983
|
+
return unless extdir?(curr_srcdir())
|
984
|
+
make 'distclean' if File.file?('Makefile')
|
985
|
+
end
|
986
|
+
|
987
|
+
alias distclean_dir_data noop
|
988
|
+
alias distclean_dir_conf noop
|
989
|
+
alias distclean_dir_man noop
|
990
|
+
|
991
|
+
def distclean_dir_doc(rel)
|
992
|
+
if GENERATE_RDOCS
|
993
|
+
rm_rf('rdoc') if File.directory?('rdoc')
|
994
|
+
end
|
995
|
+
end
|
996
|
+
|
997
|
+
#
|
998
|
+
# Traversing
|
999
|
+
#
|
1000
|
+
|
1001
|
+
def exec_task_traverse(task)
|
1002
|
+
run_hook "pre-#{task}"
|
1003
|
+
FILETYPES.each do |type|
|
1004
|
+
if type == 'ext' and config.without_ext == 'yes'
|
1005
|
+
$stderr.puts 'skipping ext/* by user option' if verbose?
|
1006
|
+
next
|
1007
|
+
end
|
1008
|
+
traverse task, type, "#{task}_dir_#{type}"
|
1009
|
+
end
|
1010
|
+
run_hook "post-#{task}"
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def traverse(task, rel, mid)
|
1014
|
+
dive_into(rel) {
|
1015
|
+
run_hook "pre-#{task}"
|
1016
|
+
__send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
|
1017
|
+
directories_of(curr_srcdir()).each do |d|
|
1018
|
+
traverse task, "#{rel}/#{d}", mid
|
1019
|
+
end
|
1020
|
+
run_hook "post-#{task}"
|
1021
|
+
}
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
def dive_into(rel)
|
1025
|
+
return unless File.dir?("#{@srcdir}/#{rel}")
|
1026
|
+
|
1027
|
+
dir = File.basename(rel)
|
1028
|
+
Dir.mkdir dir unless File.dir?(dir)
|
1029
|
+
prevdir = Dir.pwd
|
1030
|
+
Dir.chdir dir
|
1031
|
+
$stderr.puts '---> ' + rel if verbose?
|
1032
|
+
@currdir = rel
|
1033
|
+
yield
|
1034
|
+
Dir.chdir prevdir
|
1035
|
+
$stderr.puts '<--- ' + rel if verbose?
|
1036
|
+
@currdir = File.dirname(rel)
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
def run_hook(id)
|
1040
|
+
path = [ "#{curr_srcdir()}/#{id}",
|
1041
|
+
"#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
|
1042
|
+
return unless path
|
1043
|
+
begin
|
1044
|
+
instance_eval File.read(path), path, 1
|
1045
|
+
rescue
|
1046
|
+
raise if $DEBUG
|
1047
|
+
setup_rb_error "hook #{path} failed:\n" + $!.message
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
# File Operations
|
1052
|
+
#
|
1053
|
+
# This module requires: #verbose?, #no_harm?
|
1054
|
+
|
1055
|
+
def binread(fname)
|
1056
|
+
File.open(fname, 'rb'){ |f|
|
1057
|
+
return f.read
|
1058
|
+
}
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
def mkdir_p(dirname, prefix = nil)
|
1062
|
+
dirname = prefix + File.expand_path(dirname) if prefix
|
1063
|
+
$stderr.puts "mkdir -p #{dirname}" if verbose?
|
1064
|
+
return if no_harm?
|
1065
|
+
|
1066
|
+
# Does not check '/', it's too abnormal.
|
1067
|
+
dirs = File.expand_path(dirname).split(%r<(?=/)>)
|
1068
|
+
if /\A[a-z]:\z/i =~ dirs[0]
|
1069
|
+
disk = dirs.shift
|
1070
|
+
dirs[0] = disk + dirs[0]
|
1071
|
+
end
|
1072
|
+
dirs.each_index do |idx|
|
1073
|
+
path = dirs[0..idx].join('')
|
1074
|
+
Dir.mkdir path unless File.dir?(path)
|
1075
|
+
record_installation(path) # also record directories made
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
def rm_f(path)
|
1080
|
+
$stderr.puts "rm -f #{path}" if verbose?
|
1081
|
+
return if no_harm?
|
1082
|
+
force_remove_file path
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
def rm_rf(path)
|
1086
|
+
$stderr.puts "rm -rf #{path}" if verbose?
|
1087
|
+
return if no_harm?
|
1088
|
+
remove_tree path
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
def rmdir(path)
|
1092
|
+
$stderr.puts "rmdir #{path}" if verbose?
|
1093
|
+
return if no_harm?
|
1094
|
+
Dir.rmdir path
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
def remove_tree(path)
|
1098
|
+
if File.symlink?(path)
|
1099
|
+
remove_file path
|
1100
|
+
elsif File.dir?(path)
|
1101
|
+
remove_tree0 path
|
1102
|
+
else
|
1103
|
+
force_remove_file path
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
def remove_tree0(path)
|
1108
|
+
Dir.foreach(path) do |ent|
|
1109
|
+
next if ent == '.'
|
1110
|
+
next if ent == '..'
|
1111
|
+
entpath = "#{path}/#{ent}"
|
1112
|
+
if File.symlink?(entpath)
|
1113
|
+
remove_file entpath
|
1114
|
+
elsif File.dir?(entpath)
|
1115
|
+
remove_tree0 entpath
|
1116
|
+
else
|
1117
|
+
force_remove_file entpath
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
begin
|
1121
|
+
Dir.rmdir path
|
1122
|
+
rescue Errno::ENOTEMPTY
|
1123
|
+
# directory may not be empty
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
def move_file(src, dest)
|
1128
|
+
force_remove_file dest
|
1129
|
+
begin
|
1130
|
+
File.rename src, dest
|
1131
|
+
rescue
|
1132
|
+
File.open(dest, 'wb') {|f|
|
1133
|
+
f.write binread(src)
|
1134
|
+
}
|
1135
|
+
File.chmod File.stat(src).mode, dest
|
1136
|
+
File.unlink src
|
1137
|
+
end
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
def force_remove_file(path)
|
1141
|
+
begin
|
1142
|
+
remove_file path
|
1143
|
+
rescue
|
1144
|
+
end
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def remove_file(path)
|
1148
|
+
File.chmod 0777, path
|
1149
|
+
File.unlink path
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
def install(from, dest, mode, prefix = nil)
|
1153
|
+
$stderr.puts "install #{from} #{dest}" if verbose?
|
1154
|
+
return if no_harm?
|
1155
|
+
|
1156
|
+
realdest = prefix ? prefix + File.expand_path(dest) : dest
|
1157
|
+
realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
|
1158
|
+
str = binread(from)
|
1159
|
+
if diff?(str, realdest)
|
1160
|
+
verbose_off {
|
1161
|
+
rm_f realdest if File.exist?(realdest)
|
1162
|
+
}
|
1163
|
+
File.open(realdest, 'wb') {|f|
|
1164
|
+
f.write str
|
1165
|
+
}
|
1166
|
+
File.chmod mode, realdest
|
1167
|
+
|
1168
|
+
if prefix
|
1169
|
+
path = realdest.sub(prefix, '')
|
1170
|
+
else
|
1171
|
+
path = realdest
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
record_installation(path)
|
1175
|
+
end
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
def record_installation(path)
|
1179
|
+
File.open("#{objdir_root()}/#{MANIFEST}", 'a') do |f|
|
1180
|
+
f.puts(path)
|
1181
|
+
end
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
def diff?(new_content, path)
|
1185
|
+
return true unless File.exist?(path)
|
1186
|
+
new_content != binread(path)
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
def command(*args)
|
1190
|
+
$stderr.puts args.join(' ') if verbose?
|
1191
|
+
system(*args) or raise RuntimeError,
|
1192
|
+
"system(#{args.map{|a| a.inspect }.join(' ')}) failed"
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def ruby(*args)
|
1196
|
+
command config.rubyprog, *args
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
def make(task = nil)
|
1200
|
+
command(*[config.makeprog, task].compact)
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
def extdir?(dir)
|
1204
|
+
File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
def files_of(dir)
|
1208
|
+
Dir.open(dir) {|d|
|
1209
|
+
return d.select {|ent| File.file?("#{dir}/#{ent}") }
|
1210
|
+
}
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
|
1214
|
+
|
1215
|
+
def directories_of(dir)
|
1216
|
+
Dir.open(dir) {|d|
|
1217
|
+
return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
|
1218
|
+
}
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
#
|
1222
|
+
# Hook Script API
|
1223
|
+
#
|
1224
|
+
# These require: #srcdir_root, #objdir_root, #relpath
|
1225
|
+
#
|
1226
|
+
|
1227
|
+
#
|
1228
|
+
def get_config(key)
|
1229
|
+
config.__send__(key)
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
# obsolete: use metaconfig to change configuration
|
1233
|
+
# TODO: what to do with?
|
1234
|
+
def set_config(key, val)
|
1235
|
+
config[key] = val
|
1236
|
+
end
|
1237
|
+
|
1238
|
+
#
|
1239
|
+
# srcdir/objdir (works only in the package directory)
|
1240
|
+
#
|
1241
|
+
|
1242
|
+
def curr_srcdir
|
1243
|
+
"#{srcdir_root()}/#{relpath()}"
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
def curr_objdir
|
1247
|
+
"#{objdir_root()}/#{relpath()}"
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
def srcfile(path)
|
1251
|
+
"#{curr_srcdir()}/#{path}"
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
def srcexist?(path)
|
1255
|
+
File.exist?(srcfile(path))
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
def srcdirectory?(path)
|
1259
|
+
File.dir?(srcfile(path))
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
def srcfile?(path)
|
1263
|
+
File.file?(srcfile(path))
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
def srcentries(path = '.')
|
1267
|
+
Dir.open("#{curr_srcdir()}/#{path}") {|d|
|
1268
|
+
return d.to_a - %w(. ..)
|
1269
|
+
}
|
1270
|
+
end
|
1271
|
+
|
1272
|
+
def srcfiles(path = '.')
|
1273
|
+
srcentries(path).select {|fname|
|
1274
|
+
File.file?(File.join(curr_srcdir(), path, fname))
|
1275
|
+
}
|
1276
|
+
end
|
1277
|
+
|
1278
|
+
def srcdirectories(path = '.')
|
1279
|
+
srcentries(path).select {|fname|
|
1280
|
+
File.dir?(File.join(curr_srcdir(), path, fname))
|
1281
|
+
}
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
# CLI runner.
|
1287
|
+
def self.run_cli
|
1288
|
+
installer = Setup::Installer.new
|
1289
|
+
|
1290
|
+
task = ARGV.find{ |a| a !~ /^[-]/ }
|
1291
|
+
task = 'all' unless task
|
1292
|
+
|
1293
|
+
unless Setup::Installer::TASKS.include?(task)
|
1294
|
+
$stderr.puts "Not a valid task -- #{task}"
|
1295
|
+
exit 1
|
1296
|
+
end
|
1297
|
+
|
1298
|
+
opts = OptionParser.new
|
1299
|
+
|
1300
|
+
opts.banner = "Usage: #{File.basename($0)} [task] [options]"
|
1301
|
+
|
1302
|
+
if task == 'config' or task == 'all'
|
1303
|
+
opts.separator ""
|
1304
|
+
opts.separator "Config options:"
|
1305
|
+
Setup::ConfigTable::DESCRIPTIONS.each do |name, type, desc|
|
1306
|
+
opts.on("--#{name} #{type.to_s.upcase}", desc) do |val|
|
1307
|
+
ENV[name.to_s] = val.to_s
|
1308
|
+
end
|
1309
|
+
end
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
if task == 'install'
|
1313
|
+
opts.separator ""
|
1314
|
+
opts.separator "Install options:"
|
1315
|
+
|
1316
|
+
opts.on("--prefix PATH", "Installation prefix") do |val|
|
1317
|
+
installer.install_prefix = val
|
1318
|
+
end
|
1319
|
+
end
|
1320
|
+
|
1321
|
+
if task == 'test'
|
1322
|
+
opts.separator ""
|
1323
|
+
opts.separator "Install options:"
|
1324
|
+
|
1325
|
+
opts.on("--runner TYPE", "Test runner (auto|console|gtk|gtk2|tk)") do |val|
|
1326
|
+
installer.config.testrunner = val
|
1327
|
+
end
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
# common options
|
1331
|
+
opts.separator ""
|
1332
|
+
opts.separator "General options:"
|
1333
|
+
|
1334
|
+
opts.on("-q", "--quiet", "Silence output") do |val|
|
1335
|
+
installer.quiet = val
|
1336
|
+
end
|
1337
|
+
|
1338
|
+
opts.on("--verbose", "Provide verbose output") do |val|
|
1339
|
+
installer.verbose = val
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
opts.on("-n", "--no-write", "Do not write to disk") do |val|
|
1343
|
+
installer.no_harm = !val
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
opts.on("--dryrun", "Same as --no-write") do |val|
|
1347
|
+
installer.no_harm = val
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
# common options
|
1351
|
+
opts.separator ""
|
1352
|
+
opts.separator "Inform options:"
|
1353
|
+
|
1354
|
+
# Tail options (eg. commands in option form)
|
1355
|
+
opts.on_tail("-h", "--help", "display this help information") do
|
1356
|
+
puts Setup.help
|
1357
|
+
exit
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
opts.on_tail("--version", "Show version") do
|
1361
|
+
puts File.basename($0) + ' v' + Setup::Version.join('.')
|
1362
|
+
exit
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
opts.on_tail("--copyright", "Show copyright") do
|
1366
|
+
puts Setup::Copyright
|
1367
|
+
exit
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
begin
|
1371
|
+
opts.parse!(ARGV)
|
1372
|
+
rescue OptionParser::InvalidOption
|
1373
|
+
$stderr.puts $!.to_s.capitalize
|
1374
|
+
exit 1
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
begin
|
1378
|
+
installer.__send__("exec_#{task}")
|
1379
|
+
rescue SetupError
|
1380
|
+
raise if $DEBUG
|
1381
|
+
$stderr.puts $!.message
|
1382
|
+
$stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
|
1383
|
+
exit 1
|
1384
|
+
end
|
1385
|
+
end
|
1386
|
+
|
1387
|
+
# Generate help text.
|
1388
|
+
def self.help
|
1389
|
+
fmt = " " * 10 + "%-10s %s"
|
1390
|
+
commands = Installer::TASK_DESCRIPTIONS.collect do |k,d|
|
1391
|
+
(fmt % ["#{k}", d])
|
1392
|
+
end.join("\n").strip
|
1393
|
+
|
1394
|
+
fmt = " " * 13 + "%-20s %s"
|
1395
|
+
configs = ConfigTable::DESCRIPTIONS.collect do |k,t,d|
|
1396
|
+
(fmt % ["--#{k}", d])
|
1397
|
+
end.join("\n").strip
|
1398
|
+
|
1399
|
+
text = <<-END
|
1400
|
+
USAGE: #{File.basename($0)} [command] [options]
|
1401
|
+
|
1402
|
+
Commands:
|
1403
|
+
#{commands}
|
1404
|
+
|
1405
|
+
Options for CONFIG:
|
1406
|
+
#{configs}
|
1407
|
+
|
1408
|
+
Options for INSTALL:
|
1409
|
+
--prefix Set the install prefix
|
1410
|
+
|
1411
|
+
Options in common:
|
1412
|
+
-q --quiet Silence output
|
1413
|
+
--verbose Provide verbose output
|
1414
|
+
-n --no-write Do not write to disk
|
1415
|
+
|
1416
|
+
END
|
1417
|
+
|
1418
|
+
text.gsub(/^ \ \ \ \ \ /, '')
|
1419
|
+
end
|
1420
|
+
|
1421
|
+
#
|
1422
|
+
def self.run_rake
|
1423
|
+
installer = Setup::Installer.new
|
1424
|
+
installer.rake_define
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
#
|
1430
|
+
# Ruby Extensions
|
1431
|
+
#
|
1432
|
+
|
1433
|
+
unless File.respond_to?(:read) # Ruby 1.6 and less
|
1434
|
+
def File.read(fname)
|
1435
|
+
open(fname) {|f|
|
1436
|
+
return f.read
|
1437
|
+
}
|
1438
|
+
end
|
1439
|
+
end
|
1440
|
+
|
1441
|
+
unless Errno.const_defined?(:ENOTEMPTY) # Windows?
|
1442
|
+
module Errno
|
1443
|
+
class ENOTEMPTY
|
1444
|
+
# We do not raise this exception, implementation is not needed.
|
1445
|
+
end
|
1446
|
+
end
|
1447
|
+
end
|
1448
|
+
|
1449
|
+
# for corrupted Windows' stat(2)
|
1450
|
+
def File.dir?(path)
|
1451
|
+
File.directory?((path[-1,1] == '/') ? path : path + '/')
|
1452
|
+
end
|
1453
|
+
|
1454
|
+
#
|
1455
|
+
# Runners
|
1456
|
+
#
|
1457
|
+
|
1458
|
+
if $0 == __FILE__
|
1459
|
+
|
1460
|
+
Setup.run_cli
|
1461
|
+
|
1462
|
+
elsif defined?(Rake)
|
1463
|
+
|
1464
|
+
Setup.run_rake
|
1465
|
+
|
1466
|
+
end
|
1467
|
+
|