tmail 1.2.1 → 1.2.2

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