valodzka-valodzka-tmail 1.2.3.2

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