sow 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/COPYING +622 -0
  2. data/HISTORY +14 -0
  3. data/MANIFEST +138 -0
  4. data/NOTES +86 -0
  5. data/README +157 -0
  6. data/bin/sow +4 -0
  7. data/lib/sow.rb +12 -0
  8. data/lib/sow/command.rb +201 -0
  9. data/lib/sow/context.rb +29 -0
  10. data/lib/sow/core_ext.rb +47 -0
  11. data/lib/sow/generators/base.rb +321 -0
  12. data/lib/sow/generators/create.rb +111 -0
  13. data/lib/sow/generators/delete.rb +50 -0
  14. data/lib/sow/generators/update.rb +47 -0
  15. data/lib/sow/logger.rb +73 -0
  16. data/lib/sow/manager.rb +101 -0
  17. data/lib/sow/metadata.rb +115 -0
  18. data/lib/sow/plugin.rb +484 -0
  19. data/lib/sow/script.rb +186 -0
  20. data/lib/sow/session.rb +150 -0
  21. data/meta/authors +1 -0
  22. data/meta/contact +1 -0
  23. data/meta/description +1 -0
  24. data/meta/homepage +1 -0
  25. data/meta/loadpath +2 -0
  26. data/meta/package +1 -0
  27. data/meta/project +1 -0
  28. data/meta/repository +1 -0
  29. data/meta/requires +2 -0
  30. data/meta/ruby +2 -0
  31. data/meta/version +1 -0
  32. data/plug/sow/seeds/bin/.meta/created +1 -0
  33. data/plug/sow/seeds/bin/.meta/description +1 -0
  34. data/plug/sow/seeds/bin/.meta/license +1 -0
  35. data/plug/sow/seeds/bin/.meta/package +1 -0
  36. data/plug/sow/seeds/bin/.meta/requires +1 -0
  37. data/plug/sow/seeds/bin/.meta/title +1 -0
  38. data/plug/sow/seeds/bin/.meta/version +1 -0
  39. data/plug/sow/seeds/bin/SCRIPT.rb +22 -0
  40. data/plug/sow/seeds/bin/template/bin/command.rb +12 -0
  41. data/plug/sow/seeds/hoe/SCRIPT.rb +28 -0
  42. data/plug/sow/seeds/hoe/template/History.txt +7 -0
  43. data/plug/sow/seeds/hoe/template/Manifest.txt +8 -0
  44. data/plug/sow/seeds/hoe/template/README.txt +49 -0
  45. data/plug/sow/seeds/hoe/template/Rakefile +13 -0
  46. data/plug/sow/seeds/hoe/template/bin/__name__ +0 -0
  47. data/plug/sow/seeds/hoe/template/lib/__name__.rb +4 -0
  48. data/plug/sow/seeds/hoe/template/test/test___name__.rb +1 -0
  49. data/plug/sow/seeds/license/SCRIPT.rb +27 -0
  50. data/plug/sow/seeds/license/template/META/license +1 -0
  51. data/plug/sow/seeds/license/template/gpl/LICENSE +622 -0
  52. data/plug/sow/seeds/license/template/lgpl/LICENSE +789 -0
  53. data/plug/sow/seeds/license/template/mit/LICENSE +22 -0
  54. data/plug/sow/seeds/ruby/COPY.yml +14 -0
  55. data/plug/sow/seeds/ruby/DATA.yml +8 -0
  56. data/plug/sow/seeds/ruby/USAGE.txt +8 -0
  57. data/plug/sow/seeds/ruby/script.sow.rb +17 -0
  58. data/plug/sow/seeds/ruby/template/COPYING +622 -0
  59. data/plug/sow/seeds/ruby/template/History.rdoc +18 -0
  60. data/plug/sow/seeds/ruby/template/README.rdoc +43 -0
  61. data/plug/sow/seeds/ruby/template/README.rdoc.till +43 -0
  62. data/plug/sow/seeds/ruby/template/Rakefile +1 -0
  63. data/plug/sow/seeds/ruby/template/bin/__package__ +2 -0
  64. data/plug/sow/seeds/ruby/template/lib/__package__.rb +3 -0
  65. data/plug/sow/seeds/ruby/template/meta/created +1 -0
  66. data/plug/sow/seeds/ruby/template/meta/description +1 -0
  67. data/plug/sow/seeds/ruby/template/meta/license +1 -0
  68. data/plug/sow/seeds/ruby/template/meta/package +1 -0
  69. data/plug/sow/seeds/ruby/template/meta/requires +1 -0
  70. data/plug/sow/seeds/ruby/template/meta/title +1 -0
  71. data/plug/sow/seeds/ruby/template/meta/version +1 -0
  72. data/plug/sow/seeds/ruby/template/setup.rb +1467 -0
  73. data/plug/sow/seeds/ruby/template/test/template.rb +17 -0
  74. data/plug/sow/seeds/testunit/COPY.yml +12 -0
  75. data/plug/sow/seeds/testunit/DATA.yml +23 -0
  76. data/plug/sow/seeds/testunit/USAGE.txt +11 -0
  77. data/plug/sow/seeds/testunit/_SCRIPT.rb +42 -0
  78. data/plug/sow/seeds/testunit/template/form/testunit +24 -0
  79. data/plug/sow/seeds/testunit/template/test/test_template.rb +15 -0
  80. data/plug/sow/seeds/website/template/assets/styles/color.css +0 -0
  81. data/plug/sow/seeds/website/template/assets/styles/font.css +0 -0
  82. data/plug/sow/seeds/website/template/assets/styles/index.css +4 -0
  83. data/plug/sow/seeds/website/template/assets/styles/reset.css +0 -0
  84. data/plug/sow/seeds/website/template/assets/styles/struct.css +0 -0
  85. data/plug/sow/seeds/website/template/index.html +15 -0
  86. data/test/features/scaffold.feature +13 -0
  87. data/test/features/step_definitions/cli_steps.rb +0 -0
  88. data/test/features/step_definitions/fixture_steps.rb +72 -0
  89. data/test/features/support/env.rb +41 -0
  90. data/test/unit/fixtures/README +5 -0
  91. data/test/unit/helper.rb +23 -0
  92. data/test/unit/test_metadata.rb +17 -0
  93. data/test/unit/test_scaffold.rb +37 -0
  94. metadata +178 -0
@@ -0,0 +1,18 @@
1
+ == ChangeLog
2
+
3
+ == 0.0.0 // 2008-03-04
4
+
5
+ * Started project.
6
+
7
+
8
+ # Keep a running list of changes by version and date here.
9
+ # This is uploaded as the ChangeLog in the release process.
10
+ # It's better to keep a manual log, rather then use the log
11
+ # generated by the SCM because the SCM log will have gritty
12
+ # details with which end-users will not be concerned.
13
+ #
14
+ # If you want to use the SCM log anyway, you can of course
15
+ # do so. Just "cp log/Changelog.txt CHANGES" prior to release.
16
+ # (We might provide an automated option for this in the
17
+ # future, but for now its a manual task.)
18
+
@@ -0,0 +1,43 @@
1
+ = <%= title %>
2
+
3
+ * <%= homepage %>
4
+
5
+
6
+ == DESCRIPTION
7
+
8
+ <%= description %>
9
+
10
+
11
+ == RELEASE NOTES
12
+
13
+ Please see HISTORY file.
14
+
15
+
16
+ == HOW TO INSTALL
17
+
18
+ To install with RubyGems simply open a console and type:
19
+
20
+ gem install <%= package %>
21
+
22
+ To manually installation, download the tgz package and type:
23
+
24
+ tar -xvzf <%= package %>-x.y.z.tgz
25
+ cd <%= package %>-x.y.z.tgz
26
+ sudo ruby setup.rb config
27
+ sudo ruby setup.rb setup
28
+ sudo ruby setup.rb install
29
+
30
+
31
+ == SYNOPSIS
32
+
33
+ Describe how to use your library or application here. __FIX__
34
+
35
+
36
+ == LICENSE
37
+
38
+ Copyright (c) 2008 <%= author %>
39
+
40
+ This program is ditributed unser the terms of the <%= license %> license.
41
+
42
+ Please see COPYING file.
43
+
@@ -0,0 +1,43 @@
1
+ = <%= title %>
2
+
3
+ * <%= homepage %>
4
+
5
+
6
+ == DESCRIPTION
7
+
8
+ <%= description %>
9
+
10
+
11
+ == RELEASE NOTES
12
+
13
+ Please see HISTORY file.
14
+
15
+
16
+ == HOW TO INSTALL
17
+
18
+ To install with RubyGems simply open a console and type:
19
+
20
+ gem install <%= package %>
21
+
22
+ To manually installation, download the tgz package and type:
23
+
24
+ tar -xvzf <%= package %>-x.y.z.tgz
25
+ cd <%= package %>-x.y.z.tgz
26
+ sudo ruby setup.rb config
27
+ sudo ruby setup.rb setup
28
+ sudo ruby setup.rb install
29
+
30
+
31
+ == SYNOPSIS
32
+
33
+ Describe how to use your library or application here. __FIX__
34
+
35
+
36
+ == LICENSE
37
+
38
+ Copyright (c) 2008 <%= author %>
39
+
40
+ This program is ditributed unser the terms of the <%= license %> license.
41
+
42
+ Please see COPYING file.
43
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+
@@ -0,0 +1,3 @@
1
+ module <%= title %>
2
+ # start coding ...
3
+ end
@@ -0,0 +1 @@
1
+ <%= Time.now.strftime("%Y-%M-%D") %>
@@ -0,0 +1 @@
1
+ <%= package %> is a __FIX__.
@@ -0,0 +1 @@
1
+ GPL
@@ -0,0 +1 @@
1
+ <%= package %>
@@ -0,0 +1 @@
1
+ <%= package.capitalize %>
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -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
+