ffi-pcap 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.pkg_ignore +25 -0
- data/.rspec +1 -0
- data/.specopts +1 -0
- data/.yardopts +1 -0
- data/{ChangeLog.rdoc → ChangeLog.md} +15 -5
- data/LICENSE.txt +1 -4
- data/README.md +92 -0
- data/Rakefile +30 -20
- data/examples/em_selectable_pcap.rb +38 -0
- data/examples/em_timer.rb +26 -0
- data/examples/ipfw_divert.rb +28 -8
- data/examples/print_bytes.rb +5 -1
- data/examples/replay.rb +11 -0
- data/examples/selectable_pcap.rb +29 -0
- data/ffi-pcap.gemspec +60 -0
- data/gemspec.yml +23 -0
- data/lib/ffi/pcap.rb +7 -13
- data/lib/ffi/pcap/addr.rb +16 -15
- data/lib/ffi/pcap/bpf_instruction.rb +25 -0
- data/lib/ffi/pcap/bpf_program.rb +85 -0
- data/lib/ffi/pcap/bsd.rb +9 -98
- data/lib/ffi/pcap/bsd/af.rb +18 -0
- data/lib/ffi/pcap/bsd/in6_addr.rb +16 -0
- data/lib/ffi/pcap/bsd/in_addr.rb +18 -0
- data/lib/ffi/pcap/bsd/sock_addr.rb +19 -0
- data/lib/ffi/pcap/bsd/sock_addr_dl.rb +24 -0
- data/lib/ffi/pcap/bsd/sock_addr_family.rb +19 -0
- data/lib/ffi/pcap/bsd/sock_addr_in.rb +21 -0
- data/lib/ffi/pcap/bsd/sock_addr_in6.rb +20 -0
- data/lib/ffi/pcap/bsd/typedefs.rb +7 -0
- data/lib/ffi/pcap/capture_wrapper.rb +296 -256
- data/lib/ffi/pcap/common_wrapper.rb +152 -127
- data/lib/ffi/pcap/copy_handler.rb +32 -32
- data/lib/ffi/pcap/crt.rb +7 -10
- data/lib/ffi/pcap/data_link.rb +178 -153
- data/lib/ffi/pcap/dead.rb +42 -29
- data/lib/ffi/pcap/dumper.rb +39 -41
- data/lib/ffi/pcap/error_buffer.rb +21 -36
- data/lib/ffi/pcap/exceptions.rb +21 -15
- data/lib/ffi/pcap/file_header.rb +24 -18
- data/lib/ffi/pcap/in_addr.rb +4 -4
- data/lib/ffi/pcap/interface.rb +22 -20
- data/lib/ffi/pcap/live.rb +296 -252
- data/lib/ffi/pcap/offline.rb +50 -43
- data/lib/ffi/pcap/packet.rb +186 -143
- data/lib/ffi/pcap/packet_header.rb +20 -18
- data/lib/ffi/pcap/pcap.rb +269 -212
- data/lib/ffi/pcap/stat.rb +19 -49
- data/lib/ffi/pcap/stat_ex.rb +42 -0
- data/lib/ffi/pcap/time_val.rb +52 -38
- data/lib/ffi/pcap/typedefs.rb +16 -20
- data/spec/data_link_spec.rb +39 -35
- data/spec/dead_spec.rb +0 -4
- data/spec/error_buffer_spec.rb +7 -9
- data/spec/file_header_spec.rb +17 -14
- data/spec/live_spec.rb +12 -5
- data/spec/offline_spec.rb +10 -11
- data/spec/packet_behaviors.rb +20 -6
- data/spec/packet_injection_spec.rb +9 -8
- data/spec/packet_spec.rb +22 -26
- data/spec/pcap_spec.rb +52 -40
- data/spec/spec_helper.rb +16 -5
- data/spec/wrapper_behaviors.rb +0 -3
- data/tasks/doc.rake +69 -0
- data/tasks/gem.rake +200 -0
- data/tasks/git.rake +40 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +286 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- metadata +142 -92
- data/README.rdoc +0 -30
- data/VERSION +0 -1
- data/lib/ffi/pcap/bpf.rb +0 -106
- data/lib/ffi/pcap/version.rb +0 -6
- data/tasks/rcov.rb +0 -6
- data/tasks/rdoc.rb +0 -17
- data/tasks/spec.rb +0 -9
- data/tasks/yard.rb +0 -21
data/.gitignore
CHANGED
data/.pkg_ignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
## This File...
|
2
|
+
.pkg_ignore
|
3
|
+
## MAC OS X
|
4
|
+
.DS_Store
|
5
|
+
## TEXTMATE
|
6
|
+
*.tmproj
|
7
|
+
tmtags
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
## VIM
|
13
|
+
*.swp
|
14
|
+
.*.swp
|
15
|
+
## MISC
|
16
|
+
.git
|
17
|
+
.gitignore
|
18
|
+
.yardoc
|
19
|
+
.document
|
20
|
+
coverage
|
21
|
+
rdoc
|
22
|
+
pkg
|
23
|
+
## PROJECT::SPECIFIC
|
24
|
+
*.gemspec
|
25
|
+
.justrake
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.specopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format specdoc
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title 'FFI PCap Documentation' --protected --files ChangeLog.md,LICENSE.txt
|
@@ -1,14 +1,23 @@
|
|
1
|
-
|
1
|
+
### 0.2.1 / 2010-08-04
|
2
|
+
* Experimental selectable IO support
|
3
|
+
* Added Marshal support to Packet objects
|
4
|
+
* Irrelevent tweaks made to project dev environment/pkg mgmt
|
5
|
+
|
6
|
+
### 0.2.0 / 2010-04-22
|
7
|
+
|
2
8
|
* emonti fork merged back into sophsec/ffi-pcap
|
3
9
|
* ... ignore that whole "caper" thing. It will return as another lib entirely.
|
4
10
|
|
5
|
-
|
11
|
+
### 0.1.4 / 2010-04-20 (emonti/ffi-pcap)
|
12
|
+
|
6
13
|
* Fixes and example for pcap dumper
|
7
14
|
|
8
|
-
|
15
|
+
### 0.1.3 / 2010-03-05 (emonti/ffi-pcap)
|
16
|
+
|
9
17
|
* Minor fixes for ruby 1.9 compatability
|
10
18
|
|
11
|
-
|
19
|
+
### 0.1.2 / 2010-01-03 (emonti/ffi-pcap)
|
20
|
+
|
12
21
|
* Branched from sophsec/ffi-pcap by emonti
|
13
22
|
* Using ffi_dry for common struct interface
|
14
23
|
* Redesigned the pcap-specific pcap_pkthdr struct.
|
@@ -23,5 +32,6 @@
|
|
23
32
|
* Lots of other stuff I'm probably forgetting.
|
24
33
|
* specs all pass on OS X, Linux, and Win32(except 1 which is a known issue)
|
25
34
|
|
26
|
-
|
35
|
+
### 0.1.0 / 2009-04-29 (sophsec/ffi-pcap)
|
36
|
+
|
27
37
|
* Initial release.
|
data/LICENSE.txt
CHANGED
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# ffi-pcap
|
2
|
+
|
3
|
+
* [Source](https://github.com/sophsec/ffi-pcap/)
|
4
|
+
* [Issues](https://github.com/sophsec/ffi-pcap/issues)
|
5
|
+
* [Documentation](http://rubydoc.info/gems/ffi-pcap/frames)
|
6
|
+
* Postmodern (postmodern.mod3 at gmail.com)
|
7
|
+
* Eric Monti (esmonti at gmail.com)
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
Ruby FFI bindings for libpcap.
|
12
|
+
|
13
|
+
## Features
|
14
|
+
|
15
|
+
Exposes all features of the libpcap library including live packet capture,
|
16
|
+
offline packet capture, live packet injection, etc..
|
17
|
+
|
18
|
+
Currently, FFI::PCap does _not_ supply any packet dissection routines.
|
19
|
+
The choice of what to use is left up to you.
|
20
|
+
|
21
|
+
Packet dissection libraries:
|
22
|
+
|
23
|
+
* [ffi-packets] - Maps raw packets to `FFI::Struct` objects.
|
24
|
+
|
25
|
+
## Examples
|
26
|
+
|
27
|
+
Reading ICMP packets from a live interface.
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'ffi/pcap'
|
31
|
+
|
32
|
+
pcap =
|
33
|
+
FFI::PCap::Live.new(:dev => 'lo0',
|
34
|
+
:timeout => 1,
|
35
|
+
:promisc => true,
|
36
|
+
:handler => FFI::PCap::Handler)
|
37
|
+
|
38
|
+
pcap.setfilter("icmp")
|
39
|
+
|
40
|
+
pcap.loop() do |this,pkt|
|
41
|
+
puts "#{pkt.time}:"
|
42
|
+
|
43
|
+
pkt.body.each_byte {|x| print "%0.2x " % x }
|
44
|
+
putc "\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
Reading packets from a pcap dump file:
|
48
|
+
|
49
|
+
require 'rubygems'
|
50
|
+
require 'ffi/pcap'
|
51
|
+
|
52
|
+
pcap = FFI::PCap::Offline.new("./foo.cap")
|
53
|
+
|
54
|
+
pcap.loop() do |this,pkt|
|
55
|
+
puts "#{pkt.time}:"
|
56
|
+
|
57
|
+
pkt.body.each_byte {|x| print "%0.2x " % x }
|
58
|
+
putc "\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
Replaying packets from a pcap dump file on a live interface:
|
62
|
+
|
63
|
+
require 'rubygems'
|
64
|
+
require 'ffi/pcap'
|
65
|
+
|
66
|
+
live = FFI::PCap::Live.new(:device => 'en0')
|
67
|
+
offline = FFI::PCap::Offline.new("./foo.cap")
|
68
|
+
|
69
|
+
if live.datalink == offline.datalink
|
70
|
+
offline.loop() {|this,pkt| live.inject(pkt) }
|
71
|
+
end
|
72
|
+
|
73
|
+
## Requirements
|
74
|
+
|
75
|
+
* [libpcap] or [winpcap] >= 1.0.0
|
76
|
+
* [ffi] ~> 0.6.0
|
77
|
+
* [ffi_dry] ~> 0.1.9
|
78
|
+
|
79
|
+
## Install
|
80
|
+
|
81
|
+
$ sudo gem install ffi-pcap
|
82
|
+
|
83
|
+
## License
|
84
|
+
|
85
|
+
See {file:LICENSE.txt} for license information.
|
86
|
+
|
87
|
+
[libpcap]: http://www.tcpdump.org/
|
88
|
+
[winpcap]: http://winpcap.org/
|
89
|
+
|
90
|
+
[ffi]: https://github.com/ffi/ffi#readme
|
91
|
+
[ffi_dry]: https://github.com/emonti/ffi_dry#readme
|
92
|
+
[ffi-packets]: http://github.com/emonti/ffi-packets#readme
|
data/Rakefile
CHANGED
@@ -1,26 +1,36 @@
|
|
1
|
-
# -*- ruby -*-
|
2
|
-
|
3
1
|
require 'rubygems'
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
gem 'rubygems-tasks', '~> 0.2'
|
6
|
+
require 'rubygems/tasks'
|
7
|
+
|
8
|
+
Gem::Tasks.new
|
9
|
+
rescue LoadError => e
|
10
|
+
warn e.message
|
11
|
+
warn "Run `gem install rubygems-tasks` to install 'rubygems/tasks'."
|
12
|
+
end
|
7
13
|
|
8
|
-
# Generate a gem using jeweler
|
9
14
|
begin
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
gemspec.description = "Bindings to libpcap via FFI interface in Ruby."
|
18
|
-
gemspec.authors = ["Postmodern", "Dakrone", "Eric Monti"]
|
19
|
-
gemspec.add_dependency "ffi", ">= 0.5.0"
|
20
|
-
gemspec.add_dependency "ffi_dry", ">= 0.1.9"
|
15
|
+
gem 'rspec', '~> 2.0'
|
16
|
+
require 'rspec/core/rake_task'
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new
|
19
|
+
rescue LoadError => e
|
20
|
+
task :spec do
|
21
|
+
abort "Please run `gem install rspec` to install RSpec."
|
21
22
|
end
|
22
|
-
rescue LoadError
|
23
|
-
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
24
23
|
end
|
24
|
+
task :test => :spec
|
25
|
+
task :default => :spec
|
26
|
+
|
27
|
+
begin
|
28
|
+
gem 'yard', '~> 0.8'
|
29
|
+
require 'yard'
|
25
30
|
|
26
|
-
|
31
|
+
YARD::Rake::YardocTask.new
|
32
|
+
rescue LoadError => e
|
33
|
+
task :yard do
|
34
|
+
abort "Please run `gem install yard` to install YARD."
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.expand_path( File.join(File.dirname(__FILE__), '../lib'))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'ffi/pcap'
|
7
|
+
require 'eventmachine'
|
8
|
+
|
9
|
+
class PcapWatcher < EM::Connection
|
10
|
+
def initialize(pcap)
|
11
|
+
@pcap = pcap
|
12
|
+
end
|
13
|
+
|
14
|
+
def notify_readable(*args)
|
15
|
+
puts "Dispatch!"
|
16
|
+
@pcap.dispatch() do |this, pkt|
|
17
|
+
puts "#{pkt.time}:"
|
18
|
+
puts pkt.body.bytes.to_a.map{|c| "%0.2x" % c }.join(" ")
|
19
|
+
end
|
20
|
+
puts "end dispatch"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
dev = ARGV.shift || 'lo0'
|
26
|
+
if ARGV[0]
|
27
|
+
filter = ARGV.join(' ')
|
28
|
+
end
|
29
|
+
|
30
|
+
EM.run{
|
31
|
+
pcap = FFI::PCap::Live.new(:device => dev, :timeout => 1)
|
32
|
+
pcap.nonblocking=true
|
33
|
+
pcap.setfilter filter if filter
|
34
|
+
|
35
|
+
conn = EM.watch pcap.selectable_fd, PcapWatcher, pcap
|
36
|
+
conn.notify_readable = true
|
37
|
+
}
|
38
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.expand_path( File.join(File.dirname(__FILE__), '../lib'))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'ffi/pcap'
|
6
|
+
require 'eventmachine'
|
7
|
+
|
8
|
+
dev = ARGV.shift || 'lo0'
|
9
|
+
if ARGV[0]
|
10
|
+
filter = ARGV.join(' ')
|
11
|
+
end
|
12
|
+
|
13
|
+
EM.run{
|
14
|
+
pcap = FFI::PCap::Live.new(:device => dev, :timeout => 1)
|
15
|
+
pcap.setfilter filter if filter
|
16
|
+
|
17
|
+
timer = EM::PeriodicTimer.new(0.0001) do
|
18
|
+
puts "Dispatch!" if $DEBUG
|
19
|
+
pcap.dispatch(:count => -1) do |this, pkt|
|
20
|
+
puts "#{pkt.time}:"
|
21
|
+
puts pkt.body.bytes.to_a.map{|c| "%0.2x" % c }.join(" ")
|
22
|
+
end
|
23
|
+
puts "end dispatch" if $DEBUG
|
24
|
+
end
|
25
|
+
}
|
26
|
+
|
data/examples/ipfw_divert.rb
CHANGED
@@ -3,35 +3,55 @@
|
|
3
3
|
# Thanks to justfalter(Mike Ryan) for turning me onto Divert Sockets for
|
4
4
|
# this example.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# This example was written to demonstrate a workaround for a specific
|
7
|
+
# problem using pcap on VMWare Fusion vmnet interfaces.
|
8
|
+
#
|
9
|
+
# It demos the ability to use PCAP dump to write a pcap file with
|
10
|
+
# packets captured using a divert socket. In order to generate
|
11
|
+
# packets that are diverted you need a system that supports IPFW
|
12
|
+
# with divert sockets and you need to establish some ipfw rules that
|
13
|
+
# divert packets to a chosen port.
|
14
|
+
#
|
15
|
+
# Below are some example IPFW rules that will capture tcp packets to
|
16
|
+
# or from 192.168.63.128 using port 6666:
|
17
|
+
#
|
18
|
+
# ipfw add tee 6666 tcp from 192.168.63.128 to any
|
19
|
+
# ipfw add tee 6666 tcp from any to 192.168.63.128
|
20
|
+
#
|
21
|
+
$: << File.expand_path( File.join(File.dirname(__FILE__), '../lib'))
|
8
22
|
|
23
|
+
require 'rubygems'
|
9
24
|
require 'ffi/pcap'
|
10
25
|
require "socket"
|
11
26
|
require 'pp'
|
12
27
|
|
28
|
+
IPPROTO_DIVERT = 254
|
29
|
+
|
13
30
|
unless Process::Sys.getuid == 0
|
14
31
|
$stderr.puts "Must run #{$0} as root."
|
15
32
|
exit!
|
16
33
|
end
|
17
34
|
|
18
|
-
|
19
|
-
|
35
|
+
# First argument is an output pcap file
|
20
36
|
outfile = ARGV.shift
|
21
|
-
#outfile = "test_#{$$}.pcap"
|
22
37
|
|
23
|
-
#
|
38
|
+
# Second argument is optional for an alternate divert port
|
39
|
+
my_divert_port = ARGV.shift || 6666
|
40
|
+
|
41
|
+
# Create a dummy pcap handle for dumping
|
42
|
+
puts "Dumping packets to #{outfile}"
|
24
43
|
pcap = FFI::PCap.open_dead(:datalink => :raw)
|
25
44
|
pcap_dumper = pcap.open_dump(outfile)
|
26
45
|
|
27
46
|
begin
|
28
47
|
divert_sock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW, IPPROTO_DIVERT)
|
29
|
-
sockaddr = Socket.pack_sockaddr_in(
|
48
|
+
sockaddr = Socket.pack_sockaddr_in( my_divert_port, '0.0.0.0' )
|
30
49
|
divert_sock.bind(sockaddr)
|
31
50
|
|
32
|
-
puts "
|
51
|
+
puts "IPFW divert socket is listening. Press ctrl-C to end capture"
|
33
52
|
|
34
53
|
while IO.select([divert_sock], nil, nil)
|
54
|
+
|
35
55
|
data = divert_sock.recv(65535) # or MTU?
|
36
56
|
pp data
|
37
57
|
pcap_dumper.write_pkt( FFI::PCap::Packet.from_string(data) )
|
data/examples/print_bytes.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
$: << File.expand_path( File.join(File.dirname(__FILE__), '../lib'))
|
2
3
|
|
3
4
|
require 'rubygems'
|
4
5
|
require 'ffi/pcap'
|
5
6
|
|
7
|
+
dev = ARGV.shift || 'lo0'
|
8
|
+
|
6
9
|
pcap =
|
7
|
-
FFI::PCap::Live.new(:dev =>
|
10
|
+
FFI::PCap::Live.new(:dev => dev,
|
11
|
+
:timeout => 1,
|
8
12
|
:promisc => true,
|
9
13
|
:handler => FFI::PCap::Handler)
|
10
14
|
|
data/examples/replay.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ffi/pcap'
|
4
|
+
$: << File.expand_path( File.join(File.dirname(__FILE__), '../lib'))
|
5
|
+
|
6
|
+
live = FFI::PCap::Live.new(:device => 'en0')
|
7
|
+
offline = FFI::PCap::Offline.new("./foo.cap")
|
8
|
+
|
9
|
+
if live.datalink == offline.datalink
|
10
|
+
offline.loop() {|this,pkt| live.inject(pkt) }
|
11
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.expand_path( File.join(File.dirname(__FILE__), '../lib'))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'ffi/pcap'
|
7
|
+
require 'eventmachine'
|
8
|
+
|
9
|
+
dev = ARGV.shift || 'lo0'
|
10
|
+
if ARGV[0]
|
11
|
+
filter = ARGV.join(' ')
|
12
|
+
end
|
13
|
+
|
14
|
+
EM.run{
|
15
|
+
pcap = FFI::PCap::Live.new(:device => dev, :timeout => 1)
|
16
|
+
pcap.nonblocking=true
|
17
|
+
pcap.setfilter filter if filter
|
18
|
+
|
19
|
+
fd = pcap.fileno
|
20
|
+
io=IO.new(fd)
|
21
|
+
while Kernel.select([io],nil,nil)
|
22
|
+
p :meep
|
23
|
+
pcap.dispatch() do |this,pkt|
|
24
|
+
puts pkt.time
|
25
|
+
puts pkt.body.bytes.map{|x| "%0.2x" % x}.join(' ')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
}
|
29
|
+
|
data/ffi-pcap.gemspec
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gemspec = YAML.load_file('gemspec.yml')
|
7
|
+
|
8
|
+
gem.name = gemspec.fetch('name')
|
9
|
+
gem.version = gemspec.fetch('version') do
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
11
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
12
|
+
|
13
|
+
require 'ffi/pcap/version'
|
14
|
+
FFI::PCap::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
gem.summary = gemspec['summary']
|
18
|
+
gem.description = gemspec['description']
|
19
|
+
gem.licenses = Array(gemspec['license'])
|
20
|
+
gem.authors = Array(gemspec['authors'])
|
21
|
+
gem.email = gemspec['email']
|
22
|
+
gem.homepage = gemspec['homepage']
|
23
|
+
|
24
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
25
|
+
|
26
|
+
gem.files = `git ls-files`.split($/)
|
27
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
28
|
+
|
29
|
+
gem.executables = gemspec.fetch('executables') do
|
30
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
31
|
+
end
|
32
|
+
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
33
|
+
|
34
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
35
|
+
gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
|
36
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
37
|
+
|
38
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
39
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
40
|
+
})
|
41
|
+
|
42
|
+
gem.requirements = gemspec['requirements']
|
43
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
44
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
45
|
+
gem.post_install_message = gemspec['post_install_message']
|
46
|
+
|
47
|
+
split = lambda { |string| string.split(/,\s*/) }
|
48
|
+
|
49
|
+
if gemspec['dependencies']
|
50
|
+
gemspec['dependencies'].each do |name,versions|
|
51
|
+
gem.add_dependency(name,split[versions])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if gemspec['development_dependencies']
|
56
|
+
gemspec['development_dependencies'].each do |name,versions|
|
57
|
+
gem.add_development_dependency(name,split[versions])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|