ffi-pcap 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|