packetfu 1.1.11 → 1.1.12.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.rspec +2 -0
  4. data/.travis.yml +2 -3
  5. data/README.md +127 -0
  6. data/examples/100kpackets.rb +11 -10
  7. data/examples/ackscan.rb +4 -1
  8. data/examples/arp.rb +4 -5
  9. data/examples/arphood.rb +5 -4
  10. data/examples/dissect_thinger.rb +10 -7
  11. data/examples/ethernet.rb +8 -3
  12. data/examples/ids.rb +22 -4
  13. data/examples/idsv2.rb +25 -6
  14. data/examples/ifconfig.rb +6 -3
  15. data/examples/new-simple-stats.rb +5 -6
  16. data/examples/packetfu-shell.rb +11 -48
  17. data/examples/pcap2pcapng.rb +32 -0
  18. data/examples/simple-sniffer.rb +9 -4
  19. data/examples/simple-stats.rb +7 -8
  20. data/examples/slammer.rb +2 -2
  21. data/examples/uniqpcap.rb +17 -7
  22. data/lib/packetfu.rb +10 -175
  23. data/lib/packetfu/capture.rb +2 -2
  24. data/lib/packetfu/common.rb +142 -0
  25. data/lib/packetfu/config.rb +8 -8
  26. data/lib/packetfu/inject.rb +3 -3
  27. data/lib/packetfu/packet.rb +22 -18
  28. data/lib/packetfu/pcap.rb +2 -1
  29. data/lib/packetfu/pcapng.rb +37 -0
  30. data/lib/packetfu/pcapng/block.rb +25 -0
  31. data/lib/packetfu/pcapng/epb.rb +112 -0
  32. data/lib/packetfu/pcapng/file.rb +316 -0
  33. data/lib/packetfu/pcapng/idb.rb +125 -0
  34. data/lib/packetfu/pcapng/shb.rb +146 -0
  35. data/lib/packetfu/pcapng/spb.rb +83 -0
  36. data/lib/packetfu/pcapng/unknown_block.rb +60 -0
  37. data/lib/packetfu/protos.rb +3 -0
  38. data/lib/packetfu/protos/arp.rb +10 -10
  39. data/lib/packetfu/protos/icmpv6.rb +131 -0
  40. data/lib/packetfu/protos/icmpv6/header.rb +69 -0
  41. data/lib/packetfu/protos/icmpv6/mixin.rb +14 -0
  42. data/lib/packetfu/protos/ip.rb +4 -5
  43. data/lib/packetfu/protos/ipv6/header.rb +2 -0
  44. data/lib/packetfu/protos/udp.rb +24 -12
  45. data/lib/packetfu/structfu.rb +27 -0
  46. data/lib/packetfu/utils.rb +55 -9
  47. data/lib/packetfu/version.rb +1 -1
  48. data/packetfu.gemspec +13 -7
  49. data/spec/arp_spec.rb +11 -5
  50. data/spec/eth_spec.rb +20 -11
  51. data/spec/fake_packets.rb +28 -0
  52. data/spec/hsrp_spec.rb +15 -0
  53. data/spec/icmp_spec.rb +12 -5
  54. data/spec/icmpv6_spec.rb +98 -0
  55. data/spec/invalid_spec.rb +28 -0
  56. data/spec/ip_spec.rb +10 -5
  57. data/spec/ipv4_icmp.pcap +0 -0
  58. data/spec/ipv4_udp.pcap +0 -0
  59. data/spec/ipv6_icmp.pcap +0 -0
  60. data/spec/ipv6_spec.rb +4 -0
  61. data/spec/ipv6_udp.pcap +0 -0
  62. data/spec/lldp_spec.rb +36 -0
  63. data/spec/octets_spec.rb +43 -0
  64. data/spec/packet_spec.rb +24 -0
  65. data/spec/packetfu_spec.rb +6 -1
  66. data/spec/pcap_spec.rb +286 -0
  67. data/spec/pcapng/epb_spec.rb +81 -0
  68. data/spec/pcapng/file_spec.rb +295 -0
  69. data/spec/pcapng/file_spec_helper.rb +45 -0
  70. data/spec/pcapng/idb_spec.rb +53 -0
  71. data/spec/pcapng/shb_spec.rb +42 -0
  72. data/spec/pcapng/spb_spec.rb +43 -0
  73. data/spec/pcapng/unknown_block_spec.rb +36 -0
  74. data/spec/spec_helper.rb +3 -31
  75. data/spec/tcp_spec.rb +4 -1
  76. data/spec/udp_spec.rb +149 -1
  77. data/spec/utils_spec.rb +98 -15
  78. data/test/pcapng-test/output_be/advanced/test100.pcapng +0 -0
  79. data/test/pcapng-test/output_be/advanced/test100.txt +11 -0
  80. data/test/pcapng-test/output_be/advanced/test101.pcapng +0 -0
  81. data/test/pcapng-test/output_be/advanced/test101.txt +11 -0
  82. data/test/pcapng-test/output_be/advanced/test102.pcapng +0 -0
  83. data/test/pcapng-test/output_be/advanced/test102.txt +14 -0
  84. data/test/pcapng-test/output_be/basic/test001.pcapng +0 -0
  85. data/test/pcapng-test/output_be/basic/test001.txt +9 -0
  86. data/test/pcapng-test/output_be/basic/test002.pcapng +0 -0
  87. data/test/pcapng-test/output_be/basic/test002.txt +7 -0
  88. data/test/pcapng-test/output_be/basic/test003.pcapng +0 -0
  89. data/test/pcapng-test/output_be/basic/test003.txt +8 -0
  90. data/test/pcapng-test/output_be/basic/test004.pcapng +0 -0
  91. data/test/pcapng-test/output_be/basic/test004.txt +9 -0
  92. data/test/pcapng-test/output_be/basic/test005.pcapng +0 -0
  93. data/test/pcapng-test/output_be/basic/test005.txt +9 -0
  94. data/test/pcapng-test/output_be/basic/test006.pcapng +0 -0
  95. data/test/pcapng-test/output_be/basic/test006.txt +9 -0
  96. data/test/pcapng-test/output_be/basic/test007.pcapng +0 -0
  97. data/test/pcapng-test/output_be/basic/test007.txt +9 -0
  98. data/test/pcapng-test/output_be/basic/test008.pcapng +0 -0
  99. data/test/pcapng-test/output_be/basic/test008.txt +9 -0
  100. data/test/pcapng-test/output_be/basic/test009.pcapng +0 -0
  101. data/test/pcapng-test/output_be/basic/test009.txt +9 -0
  102. data/test/pcapng-test/output_be/basic/test010.pcapng +0 -0
  103. data/test/pcapng-test/output_be/basic/test010.txt +9 -0
  104. data/test/pcapng-test/output_be/basic/test011.pcapng +0 -0
  105. data/test/pcapng-test/output_be/basic/test011.txt +10 -0
  106. data/test/pcapng-test/output_be/basic/test012.pcapng +0 -0
  107. data/test/pcapng-test/output_be/basic/test012.txt +10 -0
  108. data/test/pcapng-test/output_be/basic/test013.pcapng +0 -0
  109. data/test/pcapng-test/output_be/basic/test013.txt +9 -0
  110. data/test/pcapng-test/output_be/basic/test014.pcapng +0 -0
  111. data/test/pcapng-test/output_be/basic/test014.txt +9 -0
  112. data/test/pcapng-test/output_be/basic/test015.pcapng +0 -0
  113. data/test/pcapng-test/output_be/basic/test015.txt +9 -0
  114. data/test/pcapng-test/output_be/basic/test016.pcapng +0 -0
  115. data/test/pcapng-test/output_be/basic/test016.txt +11 -0
  116. data/test/pcapng-test/output_be/basic/test017.pcapng +0 -0
  117. data/test/pcapng-test/output_be/basic/test017.txt +9 -0
  118. data/test/pcapng-test/output_be/basic/test018.pcapng +0 -0
  119. data/test/pcapng-test/output_be/basic/test018.txt +12 -0
  120. data/test/pcapng-test/output_be/difficult/test200.pcapng +0 -0
  121. data/test/pcapng-test/output_be/difficult/test200.txt +8 -0
  122. data/test/pcapng-test/output_be/difficult/test201.pcapng +0 -0
  123. data/test/pcapng-test/output_be/difficult/test201.txt +11 -0
  124. data/test/pcapng-test/output_be/difficult/test202.pcapng +0 -0
  125. data/test/pcapng-test/output_be/difficult/test202.txt +14 -0
  126. data/test/pcapng-test/output_le/advanced/test100.pcapng +0 -0
  127. data/test/pcapng-test/output_le/advanced/test100.txt +11 -0
  128. data/test/pcapng-test/output_le/advanced/test101.pcapng +0 -0
  129. data/test/pcapng-test/output_le/advanced/test101.txt +11 -0
  130. data/test/pcapng-test/output_le/advanced/test102.pcapng +0 -0
  131. data/test/pcapng-test/output_le/advanced/test102.txt +14 -0
  132. data/test/pcapng-test/output_le/basic/test001.pcapng +0 -0
  133. data/test/pcapng-test/output_le/basic/test001.txt +9 -0
  134. data/test/pcapng-test/output_le/basic/test002.pcapng +0 -0
  135. data/test/pcapng-test/output_le/basic/test002.txt +7 -0
  136. data/test/pcapng-test/output_le/basic/test003.pcapng +0 -0
  137. data/test/pcapng-test/output_le/basic/test003.txt +8 -0
  138. data/test/pcapng-test/output_le/basic/test004.pcapng +0 -0
  139. data/test/pcapng-test/output_le/basic/test004.txt +9 -0
  140. data/test/pcapng-test/output_le/basic/test005.pcapng +0 -0
  141. data/test/pcapng-test/output_le/basic/test005.txt +9 -0
  142. data/test/pcapng-test/output_le/basic/test006.pcapng +0 -0
  143. data/test/pcapng-test/output_le/basic/test006.txt +9 -0
  144. data/test/pcapng-test/output_le/basic/test007.pcapng +0 -0
  145. data/test/pcapng-test/output_le/basic/test007.txt +9 -0
  146. data/test/pcapng-test/output_le/basic/test008.pcapng +0 -0
  147. data/test/pcapng-test/output_le/basic/test008.txt +9 -0
  148. data/test/pcapng-test/output_le/basic/test009.pcapng +0 -0
  149. data/test/pcapng-test/output_le/basic/test009.txt +9 -0
  150. data/test/pcapng-test/output_le/basic/test010.pcapng +0 -0
  151. data/test/pcapng-test/output_le/basic/test010.txt +9 -0
  152. data/test/pcapng-test/output_le/basic/test011.pcapng +0 -0
  153. data/test/pcapng-test/output_le/basic/test011.txt +10 -0
  154. data/test/pcapng-test/output_le/basic/test012.pcapng +0 -0
  155. data/test/pcapng-test/output_le/basic/test012.txt +10 -0
  156. data/test/pcapng-test/output_le/basic/test013.pcapng +0 -0
  157. data/test/pcapng-test/output_le/basic/test013.txt +9 -0
  158. data/test/pcapng-test/output_le/basic/test014.pcapng +0 -0
  159. data/test/pcapng-test/output_le/basic/test014.txt +9 -0
  160. data/test/pcapng-test/output_le/basic/test015.pcapng +0 -0
  161. data/test/pcapng-test/output_le/basic/test015.txt +9 -0
  162. data/test/pcapng-test/output_le/basic/test016.pcapng +0 -0
  163. data/test/pcapng-test/output_le/basic/test016.txt +11 -0
  164. data/test/pcapng-test/output_le/basic/test017.pcapng +0 -0
  165. data/test/pcapng-test/output_le/basic/test017.txt +9 -0
  166. data/test/pcapng-test/output_le/basic/test018.pcapng +0 -0
  167. data/test/pcapng-test/output_le/basic/test018.txt +12 -0
  168. data/test/pcapng-test/output_le/difficult/test200.pcapng +0 -0
  169. data/test/pcapng-test/output_le/difficult/test200.txt +8 -0
  170. data/test/pcapng-test/output_le/difficult/test201.pcapng +0 -0
  171. data/test/pcapng-test/output_le/difficult/test201.txt +11 -0
  172. data/test/pcapng-test/output_le/difficult/test202.pcapng +0 -0
  173. data/test/pcapng-test/output_le/difficult/test202.txt +14 -0
  174. data/test/sample-ipv6.pcapng +0 -0
  175. data/test/sample-spb.pcapng +0 -0
  176. data/test/sample.pcapng +0 -0
  177. data/test/sample2.pcapng +0 -0
  178. metadata +190 -68
  179. checksums.yaml.gz.sig +0 -0
  180. data.tar.gz.sig +0 -2
  181. data/INSTALL.rdoc +0 -40
  182. data/README.rdoc +0 -64
  183. data/examples/examples.rb +0 -4
  184. data/setup.rb +0 -1586
  185. data/test/func_lldp.rb +0 -25
  186. data/test/ptest.rb +0 -16
  187. data/test/test_eth.rb +0 -93
  188. data/test/test_hsrp.rb +0 -20
  189. data/test/test_invalid.rb +0 -28
  190. data/test/test_octets.rb +0 -36
  191. data/test/test_pcap.rb +0 -211
  192. data/test/test_udp.rb +0 -100
  193. metadata.gz.sig +0 -2
Binary file
data.tar.gz.sig DELETED
@@ -1,2 +0,0 @@
1
- �zt����N@l
2
- <����)��;Q����4O9_цy�
@@ -1,40 +0,0 @@
1
- == INSTALL
2
-
3
- Installation is pretty straightforward -- it's a gem now!
4
-
5
- $ rvm gem install packetfu
6
-
7
- Not using rvm? For shame! Get it now, it will make your life 100x better.
8
-
9
- $ links http://rvm.beginrescueend.com/
10
-
11
- If you are installing from a source checkout, just run (as root / rvmsudo):
12
-
13
- $ rvmsudo ./setup.rb
14
- $ sudo ruby ./setup.rb # If not on rvm, and seriously what is wrong with you?
15
-
16
- == Testing
17
-
18
- The easiest way to test the installation is to run PacketFu via
19
- irb, using the example shell in the "examples" directory:
20
-
21
- % sudo irb -r packetfu-shell.rb
22
-
23
- After the banner, you should see something like:
24
-
25
- >>> Use $packetfu_default.config for salient networking details.
26
- IP: 192.168.1.100 Mac: 00:1d:e0:54:2f:7e Gateway: 00:03:2f:32:a5:3c
27
- Net: 192.168.1.0 Iface: wlan0
28
- >>> Packet capturing/injecting enabled.
29
- <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
30
-
31
- If not, then Something Went Wrong. It's most likely that you have either
32
- an older or broken version of pcaprub (try installing the version provided
33
- with Metasploit), or you have a very, very old version of libpcap (version
34
- 0.9.4 is the oldest tested version, and there's really no reason to not
35
- be at least on 1.0.0).
36
-
37
- == Complaints
38
-
39
- If things don't work out, please contact todb@planb-security.net, and I'll
40
- try to get you all sorted out.
@@ -1,64 +0,0 @@
1
- = PacketFu
2
-
3
- {<img src="https://travis-ci.org/packetfu/packetfu.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/packetfu/packetfu]
4
- {<img src="https://codeclimate.com/github/packetfu/packetfu.png" />}[https://codeclimate.com/github/packetfu/packetfu]
5
-
6
- A library for reading and writing packets to an interface or to a
7
- libpcap-formatted file.
8
-
9
- It is maintained at https://github.com/packetfu/packetfu .
10
-
11
- == Documentation
12
-
13
- PacketFu is yard-compatible (as well as sdoc/rdoc, if you prefer). You
14
- can generate local documentation easily with either `yard doc .` or
15
- `sdoc`, and view doc/index.html with your favored browser. Once that's
16
- done, navigate at the top, and read up on how to create a Packet or
17
- Capture from an interface with show_live or whatever.
18
-
19
- == Requirements
20
-
21
- PcapRub:
22
-
23
- $ rvm gem install pcaprub
24
-
25
- Marshall Beddoe's PcapRub is required only for packet reading and
26
- writing from a network interfaces (which is a pretty big only). PcapRub
27
- itself relies on libpcap 0.9.8 or later for packet injection. PcapRub
28
- also requires root privileges to access the interface directly.
29
-
30
- === Platforms
31
-
32
- Given the security issues with older Rubies and the long-past [EOL for
33
- 1.8.x](http://www.ruby-lang.org/en/news/2011/10/06/plans-for-1-8-7/),
34
- PacketFu is rather stuck on very recent versions of 1.9.3 (as of this
35
- moment, the version to trust is 1.9.3-p484).
36
-
37
- ==== 1.8.x
38
-
39
- EOL, no longer supported in any sense. PacketFu may or may not work.
40
-
41
- ==== 1.9.x
42
-
43
- 1.9.3-p484.
44
-
45
- ==== 2.x
46
-
47
- Not yet vetted. I don't believe there's anything exciting in these
48
- platforms, but there has been no attempt yet to perform formal testing.
49
- I know, I'm behind the times.
50
-
51
- == Examples
52
-
53
- PacketFu ships with dozens and dozens of tests, built on Test::Unit.
54
- These should give good pointers on how you're expected to use it. See
55
- the /tests directory. Furthermore, PacketFu also ships with
56
- packetfu-shell.rb, which should be run via IRB (as root, if you intend
57
- to use your interfaces).
58
-
59
- == Author
60
-
61
- PacketFu is maintained primarily by Tod Beardsley todb@packetfu.com and
62
- Jonathan Claudius claudijd@yahoo.com, with help from Open Source Land.
63
-
64
- See LICENSE for licensing details.
@@ -1,4 +0,0 @@
1
- # -*- coding: binary -*-
2
- # Sets the path appropriately when examples is adjacent to the real lib.
3
-
4
- $:.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib/"))
data/setup.rb DELETED
@@ -1,1586 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # setup.rb
4
- #
5
- # Copyright (c) 2000-2005 Minero Aoki
6
- #
7
- # This program is free software.
8
- # You can distribute/modify this program under the terms of
9
- # the GNU LGPL, Lesser General Public License version 2.1.
10
- #
11
-
12
- unless Enumerable.method_defined?(:map) # Ruby 1.4.6
13
- module Enumerable
14
- alias map collect
15
- end
16
- end
17
-
18
- unless File.respond_to?(:read) # Ruby 1.6
19
- def File.read(fname)
20
- open(fname) {|f|
21
- return f.read
22
- }
23
- end
24
- end
25
-
26
- unless Errno.const_defined?(:ENOTEMPTY) # Windows?
27
- module Errno
28
- class ENOTEMPTY
29
- # We do not raise this exception, implementation is not needed.
30
- end
31
- end
32
- end
33
-
34
- def File.binread(fname)
35
- open(fname, 'rb') {|f|
36
- return f.read
37
- }
38
- end
39
-
40
- # for corrupted Windows' stat(2)
41
- def File.dir?(path)
42
- File.directory?((path[-1,1] == '/') ? path : path + '/')
43
- end
44
-
45
-
46
- class ConfigTable
47
-
48
- include Enumerable
49
-
50
- def initialize(rbconfig)
51
- @rbconfig = rbconfig
52
- @items = []
53
- @table = {}
54
- # options
55
- @install_prefix = nil
56
- @config_opt = nil
57
- @verbose = true
58
- @no_harm = false
59
- end
60
-
61
- attr_accessor :install_prefix
62
- attr_accessor :config_opt
63
-
64
- attr_writer :verbose
65
-
66
- def verbose?
67
- @verbose
68
- end
69
-
70
- attr_writer :no_harm
71
-
72
- def no_harm?
73
- @no_harm
74
- end
75
-
76
- def [](key)
77
- lookup(key).resolve(self)
78
- end
79
-
80
- def []=(key, val)
81
- lookup(key).set val
82
- end
83
-
84
- def names
85
- @items.map {|i| i.name }
86
- end
87
-
88
- def each(&block)
89
- @items.each(&block)
90
- end
91
-
92
- def key?(name)
93
- @table.key?(name)
94
- end
95
-
96
- def lookup(name)
97
- @table[name] or setup_rb_error "no such config item: #{name}"
98
- end
99
-
100
- def add(item)
101
- @items.push item
102
- @table[item.name] = item
103
- end
104
-
105
- def remove(name)
106
- item = lookup(name)
107
- @items.delete_if {|i| i.name == name }
108
- @table.delete_if {|name, i| i.name == name }
109
- item
110
- end
111
-
112
- def load_script(path, inst = nil)
113
- if File.file?(path)
114
- MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
115
- end
116
- end
117
-
118
- def savefile
119
- '.config'
120
- end
121
-
122
- def load_savefile
123
- begin
124
- File.foreach(savefile()) do |line|
125
- k, v = *line.split(/=/, 2)
126
- self[k] = v.strip
127
- end
128
- rescue Errno::ENOENT
129
- setup_rb_error $!.message + "\n#{File.basename($0)} config first"
130
- end
131
- end
132
-
133
- def save
134
- @items.each {|i| i.value }
135
- File.open(savefile(), 'w') {|f|
136
- @items.each do |i|
137
- f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
138
- end
139
- }
140
- end
141
-
142
- def load_standard_entries
143
- standard_entries(@rbconfig).each do |ent|
144
- add ent
145
- end
146
- end
147
-
148
- def standard_entries(rbconfig)
149
- c = rbconfig
150
-
151
- rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
152
-
153
- major = c['MAJOR'].to_i
154
- minor = c['MINOR'].to_i
155
- teeny = c['TEENY'].to_i
156
- version = "#{major}.#{minor}"
157
-
158
- # ruby ver. >= 1.4.4?
159
- newpath_p = ((major >= 2) or
160
- ((major == 1) and
161
- ((minor >= 5) or
162
- ((minor == 4) and (teeny >= 4)))))
163
-
164
- if c['rubylibdir']
165
- # V > 1.6.3
166
- libruby = "#{c['prefix']}/lib/ruby"
167
- librubyver = c['rubylibdir']
168
- librubyverarch = c['archdir']
169
- siteruby = c['sitedir']
170
- siterubyver = c['sitelibdir']
171
- siterubyverarch = c['sitearchdir']
172
- elsif newpath_p
173
- # 1.4.4 <= V <= 1.6.3
174
- libruby = "#{c['prefix']}/lib/ruby"
175
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
176
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
177
- siteruby = c['sitedir']
178
- siterubyver = "$siteruby/#{version}"
179
- siterubyverarch = "$siterubyver/#{c['arch']}"
180
- else
181
- # V < 1.4.4
182
- libruby = "#{c['prefix']}/lib/ruby"
183
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
184
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
185
- siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
186
- siterubyver = siteruby
187
- siterubyverarch = "$siterubyver/#{c['arch']}"
188
- end
189
- parameterize = lambda {|path|
190
- path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
191
- }
192
-
193
- if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
194
- makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
195
- else
196
- makeprog = 'make'
197
- end
198
-
199
- [
200
- ExecItem.new('installdirs', 'std/site/home',
201
- 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
202
- {|val, table|
203
- case val
204
- when 'std'
205
- table['rbdir'] = '$librubyver'
206
- table['sodir'] = '$librubyverarch'
207
- when 'site'
208
- table['rbdir'] = '$siterubyver'
209
- table['sodir'] = '$siterubyverarch'
210
- when 'home'
211
- setup_rb_error '$HOME was not set' unless ENV['HOME']
212
- table['prefix'] = ENV['HOME']
213
- table['rbdir'] = '$libdir/ruby'
214
- table['sodir'] = '$libdir/ruby'
215
- end
216
- },
217
- PathItem.new('prefix', 'path', c['prefix'],
218
- 'path prefix of target environment'),
219
- PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
220
- 'the directory for commands'),
221
- PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
222
- 'the directory for libraries'),
223
- PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
224
- 'the directory for shared data'),
225
- PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
226
- 'the directory for man pages'),
227
- PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
228
- 'the directory for system configuration files'),
229
- PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
230
- 'the directory for local state data'),
231
- PathItem.new('libruby', 'path', libruby,
232
- 'the directory for ruby libraries'),
233
- PathItem.new('librubyver', 'path', librubyver,
234
- 'the directory for standard ruby libraries'),
235
- PathItem.new('librubyverarch', 'path', librubyverarch,
236
- 'the directory for standard ruby extensions'),
237
- PathItem.new('siteruby', 'path', siteruby,
238
- 'the directory for version-independent aux ruby libraries'),
239
- PathItem.new('siterubyver', 'path', siterubyver,
240
- 'the directory for aux ruby libraries'),
241
- PathItem.new('siterubyverarch', 'path', siterubyverarch,
242
- 'the directory for aux ruby binaries'),
243
- PathItem.new('rbdir', 'path', '$siterubyver',
244
- 'the directory for ruby scripts'),
245
- PathItem.new('sodir', 'path', '$siterubyverarch',
246
- 'the directory for ruby extentions'),
247
- PathItem.new('rubypath', 'path', rubypath,
248
- 'the path to set to #! line'),
249
- ProgramItem.new('rubyprog', 'name', rubypath,
250
- 'the ruby program using for installation'),
251
- ProgramItem.new('makeprog', 'name', makeprog,
252
- 'the make program to compile ruby extentions'),
253
- SelectItem.new('shebang', 'all/ruby/never', 'ruby',
254
- 'shebang line (#!) editing mode'),
255
- BoolItem.new('without-ext', 'yes/no', 'no',
256
- 'does not compile/install ruby extentions')
257
- ]
258
- end
259
- private :standard_entries
260
-
261
- def load_multipackage_entries
262
- multipackage_entries().each do |ent|
263
- add ent
264
- end
265
- end
266
-
267
- def multipackage_entries
268
- [
269
- PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
270
- 'package names that you want to install'),
271
- PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
272
- 'package names that you do not want to install')
273
- ]
274
- end
275
- private :multipackage_entries
276
-
277
- ALIASES = {
278
- 'std-ruby' => 'librubyver',
279
- 'stdruby' => 'librubyver',
280
- 'rubylibdir' => 'librubyver',
281
- 'archdir' => 'librubyverarch',
282
- 'site-ruby-common' => 'siteruby', # For backward compatibility
283
- 'site-ruby' => 'siterubyver', # For backward compatibility
284
- 'bin-dir' => 'bindir',
285
- 'bin-dir' => 'bindir',
286
- 'rb-dir' => 'rbdir',
287
- 'so-dir' => 'sodir',
288
- 'data-dir' => 'datadir',
289
- 'ruby-path' => 'rubypath',
290
- 'ruby-prog' => 'rubyprog',
291
- 'ruby' => 'rubyprog',
292
- 'make-prog' => 'makeprog',
293
- 'make' => 'makeprog'
294
- }
295
-
296
- def fixup
297
- ALIASES.each do |ali, name|
298
- @table[ali] = @table[name]
299
- end
300
- @items.freeze
301
- @table.freeze
302
- @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
303
- end
304
-
305
- def parse_opt(opt)
306
- m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
307
- m.to_a[1,2]
308
- end
309
-
310
- def dllext
311
- @rbconfig['DLEXT']
312
- end
313
-
314
- def value_config?(name)
315
- lookup(name).value?
316
- end
317
-
318
- class Item
319
- def initialize(name, template, default, desc)
320
- @name = name.freeze
321
- @template = template
322
- @value = default
323
- @default = default
324
- @description = desc
325
- end
326
-
327
- attr_reader :name
328
- attr_reader :description
329
-
330
- attr_accessor :default
331
- alias help_default default
332
-
333
- def help_opt
334
- "--#{@name}=#{@template}"
335
- end
336
-
337
- def value?
338
- true
339
- end
340
-
341
- def value
342
- @value
343
- end
344
-
345
- def resolve(table)
346
- @value.gsub(%r<\$([^/]+)>) { table[$1] }
347
- end
348
-
349
- def set(val)
350
- @value = check(val)
351
- end
352
-
353
- private
354
-
355
- def check(val)
356
- setup_rb_error "config: --#{name} requires argument" unless val
357
- val
358
- end
359
- end
360
-
361
- class BoolItem < Item
362
- def config_type
363
- 'bool'
364
- end
365
-
366
- def help_opt
367
- "--#{@name}"
368
- end
369
-
370
- private
371
-
372
- def check(val)
373
- return 'yes' unless val
374
- case val
375
- when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
376
- when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
377
- else
378
- setup_rb_error "config: --#{@name} accepts only yes/no for argument"
379
- end
380
- end
381
- end
382
-
383
- class PathItem < Item
384
- def config_type
385
- 'path'
386
- end
387
-
388
- private
389
-
390
- def check(path)
391
- setup_rb_error "config: --#{@name} requires argument" unless path
392
- path[0,1] == '$' ? path : File.expand_path(path)
393
- end
394
- end
395
-
396
- class ProgramItem < Item
397
- def config_type
398
- 'program'
399
- end
400
- end
401
-
402
- class SelectItem < Item
403
- def initialize(name, selection, default, desc)
404
- super
405
- @ok = selection.split('/')
406
- end
407
-
408
- def config_type
409
- 'select'
410
- end
411
-
412
- private
413
-
414
- def check(val)
415
- unless @ok.include?(val.strip)
416
- setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
417
- end
418
- val.strip
419
- end
420
- end
421
-
422
- class ExecItem < Item
423
- def initialize(name, selection, desc, &block)
424
- super name, selection, nil, desc
425
- @ok = selection.split('/')
426
- @action = block
427
- end
428
-
429
- def config_type
430
- 'exec'
431
- end
432
-
433
- def value?
434
- false
435
- end
436
-
437
- def resolve(table)
438
- setup_rb_error "$#{name()} wrongly used as option value"
439
- end
440
-
441
- undef set
442
-
443
- def evaluate(val, table)
444
- v = val.strip.downcase
445
- unless @ok.include?(v)
446
- setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
447
- end
448
- @action.call v, table
449
- end
450
- end
451
-
452
- class PackageSelectionItem < Item
453
- def initialize(name, template, default, help_default, desc)
454
- super name, template, default, desc
455
- @help_default = help_default
456
- end
457
-
458
- attr_reader :help_default
459
-
460
- def config_type
461
- 'package'
462
- end
463
-
464
- private
465
-
466
- def check(val)
467
- unless File.dir?("packages/#{val}")
468
- setup_rb_error "config: no such package: #{val}"
469
- end
470
- val
471
- end
472
- end
473
-
474
- class MetaConfigEnvironment
475
- def initialize(config, installer)
476
- @config = config
477
- @installer = installer
478
- end
479
-
480
- def config_names
481
- @config.names
482
- end
483
-
484
- def config?(name)
485
- @config.key?(name)
486
- end
487
-
488
- def bool_config?(name)
489
- @config.lookup(name).config_type == 'bool'
490
- end
491
-
492
- def path_config?(name)
493
- @config.lookup(name).config_type == 'path'
494
- end
495
-
496
- def value_config?(name)
497
- @config.lookup(name).config_type != 'exec'
498
- end
499
-
500
- def add_config(item)
501
- @config.add item
502
- end
503
-
504
- def add_bool_config(name, default, desc)
505
- @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
506
- end
507
-
508
- def add_path_config(name, default, desc)
509
- @config.add PathItem.new(name, 'path', default, desc)
510
- end
511
-
512
- def set_config_default(name, default)
513
- @config.lookup(name).default = default
514
- end
515
-
516
- def remove_config(name)
517
- @config.remove(name)
518
- end
519
-
520
- # For only multipackage
521
- def packages
522
- raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
523
- @installer.packages
524
- end
525
-
526
- # For only multipackage
527
- def declare_packages(list)
528
- raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
529
- @installer.packages = list
530
- end
531
- end
532
-
533
- end # class ConfigTable
534
-
535
-
536
- # This module requires: #verbose?, #no_harm?
537
- module FileOperations
538
-
539
- def mkdir_p(dirname, prefix = nil)
540
- dirname = prefix + File.expand_path(dirname) if prefix
541
- $stderr.puts "mkdir -p #{dirname}" if verbose?
542
- return if no_harm?
543
-
544
- # Does not check '/', it's too abnormal.
545
- dirs = File.expand_path(dirname).split(%r<(?=/)>)
546
- if /\A[a-z]:\z/i =~ dirs[0]
547
- disk = dirs.shift
548
- dirs[0] = disk + dirs[0]
549
- end
550
- dirs.each_index do |idx|
551
- path = dirs[0..idx].join('')
552
- Dir.mkdir path unless File.dir?(path)
553
- end
554
- end
555
-
556
- def rm_f(path)
557
- $stderr.puts "rm -f #{path}" if verbose?
558
- return if no_harm?
559
- force_remove_file path
560
- end
561
-
562
- def rm_rf(path)
563
- $stderr.puts "rm -rf #{path}" if verbose?
564
- return if no_harm?
565
- remove_tree path
566
- end
567
-
568
- def remove_tree(path)
569
- if File.symlink?(path)
570
- remove_file path
571
- elsif File.dir?(path)
572
- remove_tree0 path
573
- else
574
- force_remove_file path
575
- end
576
- end
577
-
578
- def remove_tree0(path)
579
- Dir.foreach(path) do |ent|
580
- next if ent == '.'
581
- next if ent == '..'
582
- entpath = "#{path}/#{ent}"
583
- if File.symlink?(entpath)
584
- remove_file entpath
585
- elsif File.dir?(entpath)
586
- remove_tree0 entpath
587
- else
588
- force_remove_file entpath
589
- end
590
- end
591
- begin
592
- Dir.rmdir path
593
- rescue Errno::ENOTEMPTY
594
- # directory may not be empty
595
- end
596
- end
597
-
598
- def move_file(src, dest)
599
- force_remove_file dest
600
- begin
601
- File.rename src, dest
602
- rescue
603
- File.open(dest, 'wb') {|f|
604
- f.write File.binread(src)
605
- }
606
- File.chmod File.stat(src).mode, dest
607
- File.unlink src
608
- end
609
- end
610
-
611
- def force_remove_file(path)
612
- begin
613
- remove_file path
614
- rescue
615
- end
616
- end
617
-
618
- def remove_file(path)
619
- File.chmod 0777, path
620
- File.unlink path
621
- end
622
-
623
- def install(from, dest, mode, prefix = nil)
624
- $stderr.puts "install #{from} #{dest}" if verbose?
625
- return if no_harm?
626
-
627
- realdest = prefix ? prefix + File.expand_path(dest) : dest
628
- realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
629
- str = File.binread(from)
630
- if diff?(str, realdest)
631
- verbose_off {
632
- rm_f realdest if File.exist?(realdest)
633
- }
634
- File.open(realdest, 'wb') {|f|
635
- f.write str
636
- }
637
- File.chmod mode, realdest
638
-
639
- File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
640
- if prefix
641
- f.puts realdest.sub(prefix, '')
642
- else
643
- f.puts realdest
644
- end
645
- }
646
- end
647
- end
648
-
649
- def diff?(new_content, path)
650
- return true unless File.exist?(path)
651
- new_content != File.binread(path)
652
- end
653
-
654
- def command(*args)
655
- $stderr.puts args.join(' ') if verbose?
656
- system(*args) or raise RuntimeError,
657
- "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
658
- end
659
-
660
- def ruby(*args)
661
- command config('rubyprog'), *args
662
- end
663
-
664
- def make(task = nil)
665
- command(*[config('makeprog'), task].compact)
666
- end
667
-
668
- def extdir?(dir)
669
- File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
670
- end
671
-
672
- def files_of(dir)
673
- Dir.open(dir) {|d|
674
- return d.select {|ent| File.file?("#{dir}/#{ent}") }
675
- }
676
- end
677
-
678
- DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
679
-
680
- def directories_of(dir)
681
- Dir.open(dir) {|d|
682
- return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
683
- }
684
- end
685
-
686
- end
687
-
688
-
689
- # This module requires: #srcdir_root, #objdir_root, #relpath
690
- module HookScriptAPI
691
-
692
- def get_config(key)
693
- @config[key]
694
- end
695
-
696
- alias config get_config
697
-
698
- # obsolete: use metaconfig to change configuration
699
- def set_config(key, val)
700
- @config[key] = val
701
- end
702
-
703
- #
704
- # srcdir/objdir (works only in the package directory)
705
- #
706
-
707
- def curr_srcdir
708
- "#{srcdir_root()}/#{relpath()}"
709
- end
710
-
711
- def curr_objdir
712
- "#{objdir_root()}/#{relpath()}"
713
- end
714
-
715
- def srcfile(path)
716
- "#{curr_srcdir()}/#{path}"
717
- end
718
-
719
- def srcexist?(path)
720
- File.exist?(srcfile(path))
721
- end
722
-
723
- def srcdirectory?(path)
724
- File.dir?(srcfile(path))
725
- end
726
-
727
- def srcfile?(path)
728
- File.file?(srcfile(path))
729
- end
730
-
731
- def srcentries(path = '.')
732
- Dir.open("#{curr_srcdir()}/#{path}") {|d|
733
- return d.to_a - %w(. ..)
734
- }
735
- end
736
-
737
- def srcfiles(path = '.')
738
- srcentries(path).select {|fname|
739
- File.file?(File.join(curr_srcdir(), path, fname))
740
- }
741
- end
742
-
743
- def srcdirectories(path = '.')
744
- srcentries(path).select {|fname|
745
- File.dir?(File.join(curr_srcdir(), path, fname))
746
- }
747
- end
748
-
749
- end
750
-
751
-
752
- class ToplevelInstaller
753
-
754
- Version = '3.4.1'
755
- Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
756
-
757
- TASKS = [
758
- [ 'all', 'do config, setup, then install' ],
759
- [ 'config', 'saves your configurations' ],
760
- [ 'show', 'shows current configuration' ],
761
- [ 'setup', 'compiles ruby extentions and others' ],
762
- [ 'install', 'installs files' ],
763
- [ 'test', 'run all tests in test/' ],
764
- [ 'clean', "does `make clean' for each extention" ],
765
- [ 'distclean',"does `make distclean' for each extention" ]
766
- ]
767
-
768
- def ToplevelInstaller.invoke
769
- config = ConfigTable.new(load_rbconfig())
770
- config.load_standard_entries
771
- config.load_multipackage_entries if multipackage?
772
- config.fixup
773
- klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
774
- klass.new(File.dirname($0), config).invoke
775
- end
776
-
777
- def ToplevelInstaller.multipackage?
778
- File.dir?(File.dirname($0) + '/packages')
779
- end
780
-
781
- def ToplevelInstaller.load_rbconfig
782
- if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
783
- ARGV.delete(arg)
784
- load File.expand_path(arg.split(/=/, 2)[1])
785
- $".push 'rbconfig.rb'
786
- else
787
- require 'rbconfig'
788
- end
789
- ::Config::CONFIG
790
- end
791
-
792
- def initialize(ardir_root, config)
793
- @ardir = File.expand_path(ardir_root)
794
- @config = config
795
- # cache
796
- @valid_task_re = nil
797
- end
798
-
799
- def config(key)
800
- @config[key]
801
- end
802
-
803
- def inspect
804
- "#<#{self.class} #{__id__()}>"
805
- end
806
-
807
- def invoke
808
- run_metaconfigs
809
- case task = parsearg_global()
810
- when nil, 'all'
811
- parsearg_config
812
- init_installers
813
- exec_config
814
- exec_setup
815
- exec_install
816
- else
817
- case task
818
- when 'config', 'test'
819
- ;
820
- when 'clean', 'distclean'
821
- @config.load_savefile if File.exist?(@config.savefile)
822
- else
823
- @config.load_savefile
824
- end
825
- __send__ "parsearg_#{task}"
826
- init_installers
827
- __send__ "exec_#{task}"
828
- end
829
- end
830
-
831
- def run_metaconfigs
832
- @config.load_script "#{@ardir}/metaconfig"
833
- end
834
-
835
- def init_installers
836
- @installer = Installer.new(@config, @ardir, File.expand_path('.'))
837
- end
838
-
839
- #
840
- # Hook Script API bases
841
- #
842
-
843
- def srcdir_root
844
- @ardir
845
- end
846
-
847
- def objdir_root
848
- '.'
849
- end
850
-
851
- def relpath
852
- '.'
853
- end
854
-
855
- #
856
- # Option Parsing
857
- #
858
-
859
- def parsearg_global
860
- while arg = ARGV.shift
861
- case arg
862
- when /\A\w+\z/
863
- setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
864
- return arg
865
- when '-q', '--quiet'
866
- @config.verbose = false
867
- when '--verbose'
868
- @config.verbose = true
869
- when '--help'
870
- print_usage $stdout
871
- exit 0
872
- when '--version'
873
- puts "#{File.basename($0)} version #{Version}"
874
- exit 0
875
- when '--copyright'
876
- puts Copyright
877
- exit 0
878
- else
879
- setup_rb_error "unknown global option '#{arg}'"
880
- end
881
- end
882
- nil
883
- end
884
-
885
- def valid_task?(t)
886
- valid_task_re() =~ t
887
- end
888
-
889
- def valid_task_re
890
- @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
891
- end
892
-
893
- def parsearg_no_options
894
- unless ARGV.empty?
895
- task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
896
- setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
897
- end
898
- end
899
-
900
- alias parsearg_show parsearg_no_options
901
- alias parsearg_setup parsearg_no_options
902
- alias parsearg_test parsearg_no_options
903
- alias parsearg_clean parsearg_no_options
904
- alias parsearg_distclean parsearg_no_options
905
-
906
- def parsearg_config
907
- evalopt = []
908
- set = []
909
- @config.config_opt = []
910
- while i = ARGV.shift
911
- if /\A--?\z/ =~ i
912
- @config.config_opt = ARGV.dup
913
- break
914
- end
915
- name, value = *@config.parse_opt(i)
916
- if @config.value_config?(name)
917
- @config[name] = value
918
- else
919
- evalopt.push [name, value]
920
- end
921
- set.push name
922
- end
923
- evalopt.each do |name, value|
924
- @config.lookup(name).evaluate value, @config
925
- end
926
- # Check if configuration is valid
927
- set.each do |n|
928
- @config[n] if @config.value_config?(n)
929
- end
930
- end
931
-
932
- def parsearg_install
933
- @config.no_harm = false
934
- @config.install_prefix = ''
935
- while a = ARGV.shift
936
- case a
937
- when '--no-harm'
938
- @config.no_harm = true
939
- when /\A--prefix=/
940
- path = a.split(/=/, 2)[1]
941
- path = File.expand_path(path) unless path[0,1] == '/'
942
- @config.install_prefix = path
943
- else
944
- setup_rb_error "install: unknown option #{a}"
945
- end
946
- end
947
- end
948
-
949
- def print_usage(out)
950
- out.puts 'Typical Installation Procedure:'
951
- out.puts " $ ruby #{File.basename $0} config"
952
- out.puts " $ ruby #{File.basename $0} setup"
953
- out.puts " # ruby #{File.basename $0} install (may require root privilege)"
954
- out.puts
955
- out.puts 'Detailed Usage:'
956
- out.puts " ruby #{File.basename $0} <global option>"
957
- out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
958
-
959
- fmt = " %-24s %s\n"
960
- out.puts
961
- out.puts 'Global options:'
962
- out.printf fmt, '-q,--quiet', 'suppress message outputs'
963
- out.printf fmt, ' --verbose', 'output messages verbosely'
964
- out.printf fmt, ' --help', 'print this message'
965
- out.printf fmt, ' --version', 'print version and quit'
966
- out.printf fmt, ' --copyright', 'print copyright and quit'
967
- out.puts
968
- out.puts 'Tasks:'
969
- TASKS.each do |name, desc|
970
- out.printf fmt, name, desc
971
- end
972
-
973
- fmt = " %-24s %s [%s]\n"
974
- out.puts
975
- out.puts 'Options for CONFIG or ALL:'
976
- @config.each do |item|
977
- out.printf fmt, item.help_opt, item.description, item.help_default
978
- end
979
- out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
980
- out.puts
981
- out.puts 'Options for INSTALL:'
982
- out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
983
- out.printf fmt, '--prefix=path', 'install path prefix', ''
984
- out.puts
985
- end
986
-
987
- #
988
- # Task Handlers
989
- #
990
-
991
- def exec_config
992
- @installer.exec_config
993
- @config.save # must be final
994
- end
995
-
996
- def exec_setup
997
- @installer.exec_setup
998
- end
999
-
1000
- def exec_install
1001
- @installer.exec_install
1002
- end
1003
-
1004
- def exec_test
1005
- @installer.exec_test
1006
- end
1007
-
1008
- def exec_show
1009
- @config.each do |i|
1010
- printf "%-20s %s\n", i.name, i.value if i.value?
1011
- end
1012
- end
1013
-
1014
- def exec_clean
1015
- @installer.exec_clean
1016
- end
1017
-
1018
- def exec_distclean
1019
- @installer.exec_distclean
1020
- end
1021
-
1022
- end # class ToplevelInstaller
1023
-
1024
-
1025
- class ToplevelInstallerMulti < ToplevelInstaller
1026
-
1027
- include FileOperations
1028
-
1029
- def initialize(ardir_root, config)
1030
- super
1031
- @packages = directories_of("#{@ardir}/packages")
1032
- raise 'no package exists' if @packages.empty?
1033
- @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1034
- end
1035
-
1036
- def run_metaconfigs
1037
- @config.load_script "#{@ardir}/metaconfig", self
1038
- @packages.each do |name|
1039
- @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
1040
- end
1041
- end
1042
-
1043
- attr_reader :packages
1044
-
1045
- def packages=(list)
1046
- raise 'package list is empty' if list.empty?
1047
- list.each do |name|
1048
- raise "directory packages/#{name} does not exist"\
1049
- unless File.dir?("#{@ardir}/packages/#{name}")
1050
- end
1051
- @packages = list
1052
- end
1053
-
1054
- def init_installers
1055
- @installers = {}
1056
- @packages.each do |pack|
1057
- @installers[pack] = Installer.new(@config,
1058
- "#{@ardir}/packages/#{pack}",
1059
- "packages/#{pack}")
1060
- end
1061
- with = extract_selection(config('with'))
1062
- without = extract_selection(config('without'))
1063
- @selected = @installers.keys.select {|name|
1064
- (with.empty? or with.include?(name)) \
1065
- and not without.include?(name)
1066
- }
1067
- end
1068
-
1069
- def extract_selection(list)
1070
- a = list.split(/,/)
1071
- a.each do |name|
1072
- setup_rb_error "no such package: #{name}" unless @installers.key?(name)
1073
- end
1074
- a
1075
- end
1076
-
1077
- def print_usage(f)
1078
- super
1079
- f.puts 'Inluded packages:'
1080
- f.puts ' ' + @packages.sort.join(' ')
1081
- f.puts
1082
- end
1083
-
1084
- #
1085
- # Task Handlers
1086
- #
1087
-
1088
- def exec_config
1089
- run_hook 'pre-config'
1090
- each_selected_installers {|inst| inst.exec_config }
1091
- run_hook 'post-config'
1092
- @config.save # must be final
1093
- end
1094
-
1095
- def exec_setup
1096
- run_hook 'pre-setup'
1097
- each_selected_installers {|inst| inst.exec_setup }
1098
- run_hook 'post-setup'
1099
- end
1100
-
1101
- def exec_install
1102
- run_hook 'pre-install'
1103
- each_selected_installers {|inst| inst.exec_install }
1104
- run_hook 'post-install'
1105
- end
1106
-
1107
- def exec_test
1108
- run_hook 'pre-test'
1109
- each_selected_installers {|inst| inst.exec_test }
1110
- run_hook 'post-test'
1111
- end
1112
-
1113
- def exec_clean
1114
- rm_f @config.savefile
1115
- run_hook 'pre-clean'
1116
- each_selected_installers {|inst| inst.exec_clean }
1117
- run_hook 'post-clean'
1118
- end
1119
-
1120
- def exec_distclean
1121
- rm_f @config.savefile
1122
- run_hook 'pre-distclean'
1123
- each_selected_installers {|inst| inst.exec_distclean }
1124
- run_hook 'post-distclean'
1125
- end
1126
-
1127
- #
1128
- # lib
1129
- #
1130
-
1131
- def each_selected_installers
1132
- Dir.mkdir 'packages' unless File.dir?('packages')
1133
- @selected.each do |pack|
1134
- $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1135
- Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1136
- Dir.chdir "packages/#{pack}"
1137
- yield @installers[pack]
1138
- Dir.chdir '../..'
1139
- end
1140
- end
1141
-
1142
- def run_hook(id)
1143
- @root_installer.run_hook id
1144
- end
1145
-
1146
- # module FileOperations requires this
1147
- def verbose?
1148
- @config.verbose?
1149
- end
1150
-
1151
- # module FileOperations requires this
1152
- def no_harm?
1153
- @config.no_harm?
1154
- end
1155
-
1156
- end # class ToplevelInstallerMulti
1157
-
1158
-
1159
- class Installer
1160
-
1161
- FILETYPES = %w( bin lib ext data conf man )
1162
-
1163
- include FileOperations
1164
- include HookScriptAPI
1165
-
1166
- def initialize(config, srcroot, objroot)
1167
- @config = config
1168
- @srcdir = File.expand_path(srcroot)
1169
- @objdir = File.expand_path(objroot)
1170
- @currdir = '.'
1171
- end
1172
-
1173
- def inspect
1174
- "#<#{self.class} #{File.basename(@srcdir)}>"
1175
- end
1176
-
1177
- def noop(rel)
1178
- end
1179
-
1180
- #
1181
- # Hook Script API base methods
1182
- #
1183
-
1184
- def srcdir_root
1185
- @srcdir
1186
- end
1187
-
1188
- def objdir_root
1189
- @objdir
1190
- end
1191
-
1192
- def relpath
1193
- @currdir
1194
- end
1195
-
1196
- #
1197
- # Config Access
1198
- #
1199
-
1200
- # module FileOperations requires this
1201
- def verbose?
1202
- @config.verbose?
1203
- end
1204
-
1205
- # module FileOperations requires this
1206
- def no_harm?
1207
- @config.no_harm?
1208
- end
1209
-
1210
- def verbose_off
1211
- begin
1212
- save, @config.verbose = @config.verbose?, false
1213
- yield
1214
- ensure
1215
- @config.verbose = save
1216
- end
1217
- end
1218
-
1219
- #
1220
- # TASK config
1221
- #
1222
-
1223
- def exec_config
1224
- exec_task_traverse 'config'
1225
- end
1226
-
1227
- alias config_dir_bin noop
1228
- alias config_dir_lib noop
1229
-
1230
- def config_dir_ext(rel)
1231
- extconf if extdir?(curr_srcdir())
1232
- end
1233
-
1234
- alias config_dir_data noop
1235
- alias config_dir_conf noop
1236
- alias config_dir_man noop
1237
-
1238
- def extconf
1239
- ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1240
- end
1241
-
1242
- #
1243
- # TASK setup
1244
- #
1245
-
1246
- def exec_setup
1247
- exec_task_traverse 'setup'
1248
- end
1249
-
1250
- def setup_dir_bin(rel)
1251
- files_of(curr_srcdir()).each do |fname|
1252
- update_shebang_line "#{curr_srcdir()}/#{fname}"
1253
- end
1254
- end
1255
-
1256
- alias setup_dir_lib noop
1257
-
1258
- def setup_dir_ext(rel)
1259
- make if extdir?(curr_srcdir())
1260
- end
1261
-
1262
- alias setup_dir_data noop
1263
- alias setup_dir_conf noop
1264
- alias setup_dir_man noop
1265
-
1266
- def update_shebang_line(path)
1267
- return if no_harm?
1268
- return if config('shebang') == 'never'
1269
- old = Shebang.load(path)
1270
- if old
1271
- $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1
1272
- new = new_shebang(old)
1273
- return if new.to_s == old.to_s
1274
- else
1275
- return unless config('shebang') == 'all'
1276
- new = Shebang.new(config('rubypath'))
1277
- end
1278
- $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
1279
- open_atomic_writer(path) {|output|
1280
- File.open(path, 'rb') {|f|
1281
- f.gets if old # discard
1282
- output.puts new.to_s
1283
- output.print f.read
1284
- }
1285
- }
1286
- end
1287
-
1288
- def new_shebang(old)
1289
- if /\Aruby/ =~ File.basename(old.cmd)
1290
- Shebang.new(config('rubypath'), old.args)
1291
- elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
1292
- Shebang.new(config('rubypath'), old.args[1..-1])
1293
- else
1294
- return old unless config('shebang') == 'all'
1295
- Shebang.new(config('rubypath'))
1296
- end
1297
- end
1298
-
1299
- def open_atomic_writer(path, &block)
1300
- tmpfile = File.basename(path) + '.tmp'
1301
- begin
1302
- File.open(tmpfile, 'wb', &block)
1303
- File.rename tmpfile, File.basename(path)
1304
- ensure
1305
- File.unlink tmpfile if File.exist?(tmpfile)
1306
- end
1307
- end
1308
-
1309
- class Shebang
1310
- def Shebang.load(path)
1311
- line = nil
1312
- File.open(path) {|f|
1313
- line = f.gets
1314
- }
1315
- return nil unless /\A#!/ =~ line
1316
- parse(line)
1317
- end
1318
-
1319
- def Shebang.parse(line)
1320
- cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
1321
- new(cmd, args)
1322
- end
1323
-
1324
- def initialize(cmd, args = [])
1325
- @cmd = cmd
1326
- @args = args
1327
- end
1328
-
1329
- attr_reader :cmd
1330
- attr_reader :args
1331
-
1332
- def to_s
1333
- "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
1334
- end
1335
- end
1336
-
1337
- #
1338
- # TASK install
1339
- #
1340
-
1341
- def exec_install
1342
- rm_f 'InstalledFiles'
1343
- exec_task_traverse 'install'
1344
- end
1345
-
1346
- def install_dir_bin(rel)
1347
- install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1348
- end
1349
-
1350
- def install_dir_lib(rel)
1351
- install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
1352
- end
1353
-
1354
- def install_dir_ext(rel)
1355
- return unless extdir?(curr_srcdir())
1356
- install_files rubyextentions('.'),
1357
- "#{config('sodir')}/#{File.dirname(rel)}",
1358
- 0555
1359
- end
1360
-
1361
- def install_dir_data(rel)
1362
- install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
1363
- end
1364
-
1365
- def install_dir_conf(rel)
1366
- # FIXME: should not remove current config files
1367
- # (rename previous file to .old/.org)
1368
- install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
1369
- end
1370
-
1371
- def install_dir_man(rel)
1372
- install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
1373
- end
1374
-
1375
- def install_files(list, dest, mode)
1376
- mkdir_p dest, @config.install_prefix
1377
- list.each do |fname|
1378
- install fname, dest, mode, @config.install_prefix
1379
- end
1380
- end
1381
-
1382
- def libfiles
1383
- glob_reject(%w(*.y *.output), targetfiles())
1384
- end
1385
-
1386
- def rubyextentions(dir)
1387
- ents = glob_select("*.#{@config.dllext}", targetfiles())
1388
- if ents.empty?
1389
- setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1390
- end
1391
- ents
1392
- end
1393
-
1394
- def targetfiles
1395
- mapdir(existfiles() - hookfiles())
1396
- end
1397
-
1398
- def mapdir(ents)
1399
- ents.map {|ent|
1400
- if File.exist?(ent)
1401
- then ent # objdir
1402
- else "#{curr_srcdir()}/#{ent}" # srcdir
1403
- end
1404
- }
1405
- end
1406
-
1407
- # picked up many entries from cvs-1.11.1/src/ignore.c
1408
- JUNK_FILES = %w(
1409
- core RCSLOG tags TAGS .make.state
1410
- .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1411
- *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1412
-
1413
- *.org *.in .*
1414
- )
1415
-
1416
- def existfiles
1417
- glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1418
- end
1419
-
1420
- def hookfiles
1421
- %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1422
- %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1423
- }.flatten
1424
- end
1425
-
1426
- def glob_select(pat, ents)
1427
- re = globs2re([pat])
1428
- ents.select {|ent| re =~ ent }
1429
- end
1430
-
1431
- def glob_reject(pats, ents)
1432
- re = globs2re(pats)
1433
- ents.reject {|ent| re =~ ent }
1434
- end
1435
-
1436
- GLOB2REGEX = {
1437
- '.' => '\.',
1438
- '$' => '\$',
1439
- '#' => '\#',
1440
- '*' => '.*'
1441
- }
1442
-
1443
- def globs2re(pats)
1444
- /\A(?:#{
1445
- pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
1446
- })\z/
1447
- end
1448
-
1449
- #
1450
- # TASK test
1451
- #
1452
-
1453
- TESTDIR = 'test'
1454
-
1455
- def exec_test
1456
- unless File.directory?('test')
1457
- $stderr.puts 'no test in this package' if verbose?
1458
- return
1459
- end
1460
- $stderr.puts 'Running tests...' if verbose?
1461
- begin
1462
- require 'test/unit'
1463
- rescue LoadError
1464
- setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
1465
- end
1466
- runner = Test::Unit::AutoRunner.new(true)
1467
- runner.to_run << TESTDIR
1468
- runner.run
1469
- end
1470
-
1471
- #
1472
- # TASK clean
1473
- #
1474
-
1475
- def exec_clean
1476
- exec_task_traverse 'clean'
1477
- rm_f @config.savefile
1478
- rm_f 'InstalledFiles'
1479
- end
1480
-
1481
- alias clean_dir_bin noop
1482
- alias clean_dir_lib noop
1483
- alias clean_dir_data noop
1484
- alias clean_dir_conf noop
1485
- alias clean_dir_man noop
1486
-
1487
- def clean_dir_ext(rel)
1488
- return unless extdir?(curr_srcdir())
1489
- make 'clean' if File.file?('Makefile')
1490
- end
1491
-
1492
- #
1493
- # TASK distclean
1494
- #
1495
-
1496
- def exec_distclean
1497
- exec_task_traverse 'distclean'
1498
- rm_f @config.savefile
1499
- rm_f 'InstalledFiles'
1500
- end
1501
-
1502
- alias distclean_dir_bin noop
1503
- alias distclean_dir_lib noop
1504
-
1505
- def distclean_dir_ext(rel)
1506
- return unless extdir?(curr_srcdir())
1507
- make 'distclean' if File.file?('Makefile')
1508
- end
1509
-
1510
- alias distclean_dir_data noop
1511
- alias distclean_dir_conf noop
1512
- alias distclean_dir_man noop
1513
-
1514
- #
1515
- # Traversing
1516
- #
1517
-
1518
- def exec_task_traverse(task)
1519
- run_hook "pre-#{task}"
1520
- FILETYPES.each do |type|
1521
- if type == 'ext' and config('without-ext') == 'yes'
1522
- $stderr.puts 'skipping ext/* by user option' if verbose?
1523
- next
1524
- end
1525
- traverse task, type, "#{task}_dir_#{type}"
1526
- end
1527
- run_hook "post-#{task}"
1528
- end
1529
-
1530
- def traverse(task, rel, mid)
1531
- dive_into(rel) {
1532
- run_hook "pre-#{task}"
1533
- __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1534
- directories_of(curr_srcdir()).each do |d|
1535
- traverse task, "#{rel}/#{d}", mid
1536
- end
1537
- run_hook "post-#{task}"
1538
- }
1539
- end
1540
-
1541
- def dive_into(rel)
1542
- return unless File.dir?("#{@srcdir}/#{rel}")
1543
-
1544
- dir = File.basename(rel)
1545
- Dir.mkdir dir unless File.dir?(dir)
1546
- prevdir = Dir.pwd
1547
- Dir.chdir dir
1548
- $stderr.puts '---> ' + rel if verbose?
1549
- @currdir = rel
1550
- yield
1551
- Dir.chdir prevdir
1552
- $stderr.puts '<--- ' + rel if verbose?
1553
- @currdir = File.dirname(rel)
1554
- end
1555
-
1556
- def run_hook(id)
1557
- path = [ "#{curr_srcdir()}/#{id}",
1558
- "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
1559
- return unless path
1560
- begin
1561
- instance_eval File.read(path), path, 1
1562
- rescue
1563
- raise if $DEBUG
1564
- setup_rb_error "hook #{path} failed:\n" + $!.message
1565
- end
1566
- end
1567
-
1568
- end # class Installer
1569
-
1570
-
1571
- class SetupError < StandardError; end
1572
-
1573
- def setup_rb_error(msg)
1574
- raise SetupError, msg
1575
- end
1576
-
1577
- if $0 == __FILE__
1578
- begin
1579
- ToplevelInstaller.invoke
1580
- rescue SetupError
1581
- raise if $DEBUG
1582
- $stderr.puts $!.message
1583
- $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1584
- exit 1
1585
- end
1586
- end