vhskit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e430d0d0e31a503a95c60b807545dc1a3a94fc5e
4
+ data.tar.gz: 7a6a6ecc2b83794d50d64564fcb3bf29a3bc85df
5
+ SHA512:
6
+ metadata.gz: c9289b1c0329abe97406c8d8f63afcbf47cedb9494933b7d9c69a96979542ac7937bad712873ee0b52c08f627fafa51b85c5ed4bda1aad9034ee6d7bcf8f158c
7
+ data.tar.gz: 4021bc6ad57ccb61caec90c20b39706a7a2280b76927e9cccbdbfb991b5a5936ad51379be92967f44051d5344475cd9bfd0b7da81db48ae297c3a0a201e96124
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+ # vim: set sw=2 et:
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # VHSKit
2
+
3
+ VHSKit is a server that speaks like a real Postgres server.
4
+
5
+ See [example](example) for a sample.
6
+
7
+ `cert` (and its `key`) is a self-signed SSL certificate for 127.0.0.1, for your
8
+ convenience.
9
+
10
+ ## license
11
+
12
+ MIT.
13
+
14
+ ## copyright
15
+
16
+ © Amelia Cuss, 2013.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/core/rake_task'
4
+ require 'bundler/gem_tasks'
5
+
6
+ task :default => :spec
7
+
8
+ RSpec::Core::RakeTask.new
9
+
10
+ # vim: set sw=2 et:
data/cert ADDED
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDOzCCAiOgAwIBAgIJALKaTzk+J1xAMA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
3
+ BAYTAkFVMREwDwYDVQQIDAhWaWN0b3JpYTESMBAGA1UEAwwJMTI3LjAuMC4xMB4X
4
+ DTEzMTAwMTAyNDU0NVoXDTEzMTAzMTAyNDU0NVowNDELMAkGA1UEBhMCQVUxETAP
5
+ BgNVBAgMCFZpY3RvcmlhMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3
6
+ DQEBAQUAA4IBDwAwggEKAoIBAQDDBfIIsdVepCbi/sB+EP747kBS4YLLJBhPvV3W
7
+ zpBn45nSjikfEJmxGKE8oqVZSHfxMESWfdAJCwRQ+UhwiXIyiveZ8Dg0PsMDMLws
8
+ QljK0Qlmc8ZzBFKfqIT6wBVGks0u8RjE8KI0SA9QcKLSHBpmBktoaRQETnwYU222
9
+ oo3Z8cmYaIWmL/Zw0Hj3mGG3+nqFZEktk1xFo/COJ3gVGPJl7Gs9ESy60HWqEV1F
10
+ eTuGAak+5R3pmnyLrkV7UWKatWbWxGcIQ88G/BRsrR605OTH9HGZMj3ZtwDl60DF
11
+ /LDwRa9rA5X36L4Y/hUXXn/DAC5Qa2CAz2yQri8loLOXp0ExAgMBAAGjUDBOMB0G
12
+ A1UdDgQWBBQV2qgcTkj9NTGKpTBbK63D4IE62zAfBgNVHSMEGDAWgBQV2qgcTkj9
13
+ NTGKpTBbK63D4IE62zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCy
14
+ 9WcFT6WUspF1t4SHNG2i6Xhbv9i8KeAhgwYakANmx10iJse4Ssn5+i9/Hx34cYlt
15
+ dLmhxF8pGBeQtuh5kBQtLVQHkdJYmfjKSf4Ny2daF2kRpDSbh8jhwmu1FxPOO/T2
16
+ 86PyyBRRlEnfdTRrmz4UvHGVc8AWenJUcVHWqwiFwrOV6qE7sNwwXbXA9w16RnOg
17
+ M5jH+knVxqJT9ZNo2dmvM9b4jsmvtPDTElkWJ2D6ttPeHI0A8WtVU4Bf5mVlgq3O
18
+ n/n08+/Q1Z3hYUhibTfW1sKq9U3OKKo9zx6Whia3C3H+dbGkgO0J/jyiSc5Ns9/1
19
+ 54qrouInAjWJe5Ki8tbb
20
+ -----END CERTIFICATE-----
data/example ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ $: << "./lib"
5
+
6
+ require 'vhskit'
7
+
8
+ VHSKit.run(port: 15432) do
9
+ =begin
10
+ on_auth do |user, database|
11
+ puts "auth got user #{user}, database #{database}"
12
+ # return the password for this user, or nil if none
13
+ "hello"
14
+ end
15
+ =end
16
+
17
+ on_query do |user, database, query|
18
+ puts "user #{user}, database #{database}, query #{query}"
19
+
20
+ if query =~ /^insert /i
21
+ {insert: 4}
22
+ elsif query =~ /^delete /i
23
+ {delete: 4}
24
+ elsif query =~ /^update /i
25
+ {update: 4}
26
+ elsif query =~ /^select /i
27
+ {select:
28
+ {columns: ["id", "int4",
29
+ "name", "text"],
30
+ rows: ["1", "Joanne",
31
+ "2", "Yorick"]}}
32
+ else
33
+ nil
34
+ end
35
+ end
36
+ end
37
+
38
+ # vim: set sw=2 et:
data/key ADDED
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEAwwXyCLHVXqQm4v7AfhD++O5AUuGCyyQYT71d1s6QZ+OZ0o4p
3
+ HxCZsRihPKKlWUh38TBEln3QCQsEUPlIcIlyMor3mfA4ND7DAzC8LEJYytEJZnPG
4
+ cwRSn6iE+sAVRpLNLvEYxPCiNEgPUHCi0hwaZgZLaGkUBE58GFNttqKN2fHJmGiF
5
+ pi/2cNB495hht/p6hWRJLZNcRaPwjid4FRjyZexrPREsutB1qhFdRXk7hgGpPuUd
6
+ 6Zp8i65Fe1FimrVm1sRnCEPPBvwUbK0etOTkx/RxmTI92bcA5etAxfyw8EWvawOV
7
+ 9+i+GP4VF15/wwAuUGtggM9skK4vJaCzl6dBMQIDAQABAoIBAH3knqNiOPzJNpke
8
+ HqDC0/VZx4g5Lzd3a4I+Gg+KdMm7sRas0nrNOomJ/runutlx4It/vybuvJa51+V1
9
+ pn+PGnrqHn/vBDklsrmigjaH9c2nN0w9vIOO7M9H99/uk01lgrKkzHqFZBAf3FLv
10
+ AwxjO99UfOU/v74v9Ae4A4D8WlmvjFKCGzQJh+NywECnonU6YJzH+CNo2j//6lv5
11
+ LCvMSNooCffDoEdkwakFGyglha8xf0SaiaUsB7YFx4Yp0e5RQeSRC7ubtqK3QjRJ
12
+ WeESWyQPJMbpHps0NfFei5dgmGlqIqFncbQwHrHtQNsagM1eFWF+GoTp9xxrU4I5
13
+ PGKxi+ECgYEA8ISAsrGMsa5eex9CDBIclefLt7NrFlFaE2JEkwa0zE/DqfbUQJ28
14
+ 6NRcO5gLrIRA7uAnbstNVeTSNqiMkWbQhSAw9dhH4FiAEw0e/ZSsyZRFWFa6/W7T
15
+ ck6WI45Cn/QBavq5xkejMBFwGBIHtarzirw0sC4OP0FikeN+LU6fXyUCgYEAz5O9
16
+ VajcXiHU7gG6USozTMkD+HvPMLWlYR+eDlTPzpJ3+dRhySG6v8luYWN0X4yk0TsQ
17
+ hdbTv1iiJrB8qabMWVuMgXYJHDtnfIRWNzv0yr5HH2tcMZ1NWS+sXazNqUfdzxj1
18
+ KTxYRY+GOd57fwxgnMF90F0vENSo++asWp7fch0CgYEA1sEo/OUlv/z2pa7aVVbS
19
+ qVMIBiWwp4PKDua+Xh0t0AQkrB0VlgCCDc6X8Copukd4hxIkg3wJuHkQ7fb/VFDe
20
+ PQ/qR4lvXDUJXnlnw3o98dtvM5p1ahbLvBPJYUQD3ziLD4+B0zZh0mivkv5+Xcqf
21
+ nK/Bx9HHrNlf/u2G20OJb/UCgYAL5+5xLllNcOVUrXaxVxlQKyt2IivVIGYW9whK
22
+ zCSLNa15/+uH7M5YV8ZkAZ9YJ6oAckHVW2gTzpKmY3MTDAUmjvC1MD7/hoy+AJ0t
23
+ V9wHkPhlXfQQyHP6TJi3WsUFE6EuUsElF1f8zWmmghNVSzFzbEm6HM4pSflTUXzL
24
+ SdeJJQKBgQDcVB1n29fOX3icpADox3u9IMFNh0vPASa6MVbGhPq5NkDT7xHFRGVn
25
+ ECsS8H1MlLa4WG3UHsiUptk8K2hS71BqFlVUa2hbwY+NfthIFp2VDq33hAdLak2f
26
+ 3DdPDrVgJNPAPtyBIOw4YN6/96w6u/GEDjAy27MgOOK8T2bXj0W4JQ==
27
+ -----END RSA PRIVATE KEY-----
data/lib/vhskit.rb ADDED
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module VHSKit
4
+ require 'vhskit/server'
5
+
6
+ def self.run(opts, &block)
7
+ port = opts.delete(:port) || 5432
8
+
9
+ if opts.length > 0
10
+ raise ArgumentError.new("Unknown options: #{opts.keys.join ", "}")
11
+ end
12
+
13
+ conf = VHSKit::Configurator.new
14
+ if block
15
+ conf.instance_exec(&block)
16
+ end
17
+
18
+ VHSKit::Server.new(port, conf).run
19
+ end
20
+ end
21
+
22
+ # vim: set sw=2 et:
@@ -0,0 +1,255 @@
1
+ # encoding: utf-8
2
+
3
+ # References:
4
+ # http://www.postgresql.org/docs/9.1/static/protocol-flow.html
5
+ # http://www.postgresql.org/docs/9.1/static/protocol-message-formats.html
6
+ # http://www.postgresql.org/docs/9.1/static/catalog-pg-type.html
7
+ # http://www.postgresql.org/docs/9.1/static/catalog-pg-attribute.html
8
+ # http://ruby-doc.org/core-2.0.0/Array.html#method-i-pack
9
+ # http://www.postgresql.org/docs/9.1/static/protocol-error-fields.html
10
+ # http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
11
+
12
+ require 'openssl'
13
+ require 'vhskit/oid'
14
+
15
+ class VHSKit::Handler
16
+ def initialize(sock, conf)
17
+ @sock = sock
18
+ @conf = conf.fns
19
+ end
20
+
21
+ def run
22
+ start
23
+ @sock.close rescue false
24
+ rescue Exception => e
25
+ STDERR.puts "error in VHSKit::Handler: #{e}"
26
+ STDERR.puts e.backtrace
27
+ @sock.close rescue false
28
+ end
29
+
30
+ private
31
+
32
+ def start
33
+ startup = read_msg()
34
+ ver = startup.unpack('L>')[0]
35
+
36
+ if ver == 80877103 && startup.length == 4
37
+ @sock.write 'S' # accept the request
38
+
39
+ ctx = OpenSSL::SSL::SSLContext.new(:SSLv23_server)
40
+ ctx.cert = OpenSSL::X509::Certificate.new(File.read('cert'))
41
+ ctx.key = OpenSSL::PKey::RSA.new(File.read('key'))
42
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
43
+ @sock = OpenSSL::SSL::SSLSocket.new(@sock.to_io, ctx)
44
+ @sock.accept
45
+
46
+ startup = read_msg()
47
+ ver = startup.unpack('L>')[0]
48
+ end
49
+
50
+ if ver != 196608
51
+ STDERR.puts "unknown version #{ver}; bye"
52
+ return
53
+ end
54
+
55
+ handle_opts(startup[4..-1])
56
+ end
57
+
58
+ def handle_opts(opts)
59
+ hash = {}
60
+ while opts.length > 1
61
+ key, val, opts = opts.unpack('Z*Z*a*')
62
+ hash[key] = val
63
+ end
64
+
65
+ if opts != "\0"
66
+ STDERR.puts "options terminated poorly; bye"
67
+ return
68
+ end
69
+
70
+ if !hash["user"]
71
+ STDERR.puts "no user specified; bye"
72
+ return
73
+ end
74
+
75
+ @user = hash["user"]
76
+ @database = hash["database"] || @user
77
+
78
+ if @conf[:on_auth]
79
+ pwd = @conf[:on_auth].call(@user, @database)
80
+
81
+ salt = Random::DEFAULT.bytes(4)
82
+ STDERR.puts salt.bytes.length
83
+ write_msg 'R', [5, salt].pack('L>a*') # AuthenticationMD5
84
+ tag = read_tag
85
+
86
+ if tag != 'p'
87
+ STDERR.puts "expected 'p', got #{tag}; bye"
88
+ return
89
+ end
90
+
91
+ enc = read_msg().unpack('Z*')[0]
92
+
93
+ if !pwd
94
+ comp = nil
95
+ else
96
+ comp = 'md5' + Digest::MD5.hexdigest(
97
+ Digest::MD5.hexdigest(pwd + @user) + salt)
98
+ end
99
+
100
+ if enc != comp
101
+ write_msg 'E', notice_error_body(
102
+ 'S' => 'FATAL',
103
+ 'C' => '28P01',
104
+ 'M' => "password authentication failed for user \"#@user\"")
105
+ return
106
+ end
107
+ end
108
+
109
+ write_msg 'R', [0].pack('L>') # AuthenticationOk
110
+
111
+ mainloop
112
+ end
113
+
114
+ def mainloop
115
+ @abort = false
116
+ while !@abort
117
+ main
118
+ end
119
+ end
120
+
121
+ def main
122
+ # ReadyForQuery
123
+ write_msg 'Z', (!@transaction ? 'I' : 'T') # 'E' for failed txn block
124
+
125
+ kind = @sock.read(1)
126
+
127
+ case kind
128
+ when 'Q'
129
+ query
130
+ when 'X'
131
+ puts "client terminated"
132
+ @abort = true
133
+ else
134
+ STDERR.puts "unknown kind #{kind}"
135
+ @abort = true
136
+ end
137
+ end
138
+
139
+ def query
140
+ query = read_msg()
141
+ on_query = @conf[:on_query]
142
+ if !on_query
143
+ write_msg 'E', notice_error_body(
144
+ 'S' => 'ERROR',
145
+ 'C' => 'XX000',
146
+ 'M' => 'Internal error: no query handler available')
147
+ return
148
+ end
149
+
150
+ each_query(query.strip, on_query)
151
+ end
152
+
153
+ def each_query(query, on_query)
154
+ result = on_query.call(@user, @database, query)
155
+ if !result || result.keys.length != 1
156
+ STDERR.puts "result.keys not unary for #{query.inspect}: #{result.inspect}"
157
+ write_msg 'E', notice_error_body(
158
+ 'S' => 'ERROR',
159
+ 'C' => 'XX000',
160
+ 'M' => "Internal error: query handler didn't return sensible data")
161
+ return
162
+ end
163
+
164
+ key, value = result.to_a[0]
165
+
166
+ case key
167
+ when :insert
168
+ # CommandComplete
169
+ write_msg 'C', ["INSERT 0 #{value}"].pack('Z*')
170
+ when :delete
171
+ # CommandComplete
172
+ write_msg 'C', ["DELETE #{value}"].pack('Z*')
173
+ when :update
174
+ # CommandComplete
175
+ write_msg 'C', ["UPDATE #{value}"].pack('Z*')
176
+ when :select
177
+ rows = value[:columns].each_slice(2).map {|name, type|
178
+ [name, 0, 0, VHSKit::OID.by_name(type),
179
+ 4, # XXX this is wrong
180
+ -1, 0]}
181
+ # RowDescription
182
+ write_msg 'T', row_descriptions(rows)
183
+
184
+ count = 0
185
+ value[:rows].each_slice(rows.length).each do |row|
186
+ # DataRow
187
+ write_msg 'D', data_row(row)
188
+ count += 1
189
+ end
190
+
191
+ # CommandComplete
192
+ write_msg 'C', ["SELECT #{count}"].pack('Z*')
193
+ # when :move
194
+ # when :fetch
195
+ # when :copy
196
+ else
197
+ raise StandardError.new("unknown key #{key.inspect}")
198
+ end
199
+ end
200
+
201
+ def read_tag()
202
+ r = @sock.read(1)
203
+ if !r || r.length < 1
204
+ raise EOFError
205
+ end
206
+ r
207
+ end
208
+
209
+ def read_msg()
210
+ len = @sock.read(4).unpack('L>')[0]
211
+ r = @sock.read(len - 4)
212
+ if !r || r.length < len - 4
213
+ raise EOFError
214
+ end
215
+ r
216
+ end
217
+
218
+ def write_msg(tag, data)
219
+ @sock.write tag
220
+ @sock.write [data.length + 4].pack('L>')
221
+ @sock.write data
222
+ @sock.flush
223
+ end
224
+
225
+ def notice_error_body(pairs)
226
+ pairs.map do |k,v|
227
+ if k.length != 1
228
+ raise ArgumentError.new("notice_error_body got key #{k.inspect}")
229
+ end
230
+
231
+ [k, v].pack('aZ*')
232
+ end.join.force_encoding('US-ASCII') + "\00"
233
+ end
234
+
235
+ # rows should be an Array of Arrays of:
236
+ # - field name (String)
237
+ # - table OID or zero (Integer)
238
+ # - column OID or zero (Integer)
239
+ # - data type OID (Integer)
240
+ # - data type size (Integer)
241
+ # - type modifier (Integer)
242
+ # - format code (Integer: 0 text, 1 binary)
243
+ def row_descriptions(rows)
244
+ [rows.length,
245
+ rows.map {|e| e.pack('Z*L>S>L>S>L>S>')}.join].pack('S>a*')
246
+ end
247
+
248
+ # columns should be an Array of Strings
249
+ def data_row(columns)
250
+ [columns.length,
251
+ columns.map {|e| [e.length + 1, e].pack('L>Z*')}.join].pack('S>a*')
252
+ end
253
+ end
254
+
255
+ # vim: set sw=2 et:
data/lib/vhskit/oid.rb ADDED
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+
3
+ # Source for OIDs:
4
+ # http://jdbc.postgresql.org/development/privateapi/constant-values.html#org.postgresql.core.Oid.INT4
5
+
6
+ module VHSKit::OID
7
+ BIT = 1560
8
+ BIT_ARRAY = 1561
9
+ BOOL = 16
10
+ BOOL_ARRAY = 1000
11
+ BPCHAR = 1042
12
+ BPCHAR_ARRAY = 1014
13
+ BYTEA = 17
14
+ BYTEA_ARRAY = 1001
15
+ CHAR = 18
16
+ CHAR_ARRAY = 1002
17
+ DATE = 1082
18
+ DATE_ARRAY = 1182
19
+ FLOAT4 = 700
20
+ FLOAT4_ARRAY = 1021
21
+ FLOAT8 = 701
22
+ FLOAT8_ARRAY = 1022
23
+ INT2 = 21
24
+ INT2_ARRAY = 1005
25
+ INT4 = 23
26
+ INT4_ARRAY = 1007
27
+ INT8 = 20
28
+ INT8_ARRAY = 1016
29
+ INTERVAL = 1186
30
+ INTERVAL_ARRAY = 1187
31
+ MONEY = 790
32
+ MONEY_ARRAY = 791
33
+ NAME = 19
34
+ NAME_ARRAY = 1003
35
+ NUMERIC = 1700
36
+ NUMERIC_ARRAY = 1231
37
+ OID = 26
38
+ OID_ARRAY = 1028
39
+ TEXT = 25
40
+ TEXT_ARRAY = 1009
41
+ TIME = 1083
42
+ TIME_ARRAY = 1183
43
+ TIMESTAMP = 1114
44
+ TIMESTAMP_ARRAY = 1115
45
+ TIMESTAMPTZ = 1184
46
+ TIMESTAMPTZ_ARRAY = 1185
47
+ TIMETZ = 1266
48
+ TIMETZ_ARRAY = 1270
49
+ UNSPECIFIED = 0
50
+ UUID = 2950
51
+ UUID_ARRAY = 2951
52
+ VARBIT = 1562
53
+ VARBIT_ARRAY = 1563
54
+ VARCHAR = 1043
55
+ VARCHAR_ARRAY = 1015
56
+ VOID = 2278
57
+ XML = 142
58
+ XML_ARRAY = 143
59
+
60
+ def self.by_name(name)
61
+ name = name.upcase
62
+
63
+ array = false
64
+ if name =~ /^(.+)\[\]$/
65
+ name = $1
66
+ array = true
67
+ end
68
+
69
+ if name =~ /^(.+) WITHOUT TIME ZONE$/
70
+ name = $1
71
+ end
72
+
73
+ if name =~ /^(.+) WITH TIME ZONE$/
74
+ name = "#{$1}TZ"
75
+ end
76
+
77
+ if array
78
+ name << "_ARRAY"
79
+ end
80
+
81
+ const_get name
82
+ end
83
+ end
84
+
85
+ # vim: set sw=2 et:
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'socket'
4
+ require 'vhskit/handler'
5
+
6
+ class VHSKit::Server
7
+ def initialize(port, conf)
8
+ @serv = TCPServer.new port
9
+ @conf = conf
10
+ end
11
+
12
+ def run
13
+ while true
14
+ sock = @serv.accept
15
+ Thread.start do
16
+ VHSKit::Handler.new(sock, @conf).run
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class VHSKit::Configurator
23
+ def initialize
24
+ @fns = {}
25
+ end
26
+
27
+ attr_reader :fns
28
+
29
+ FNS = [:on_auth, :on_query]
30
+
31
+ FNS.each do |fn|
32
+ define_method(fn) do |&block|
33
+ @fns[fn] = block
34
+ end
35
+ end
36
+ end
37
+
38
+ # vim: set sw=2 et:
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ module VHSKit
4
+ VERSION = "0.0.1"
5
+ end
6
+
7
+ # vim: set sw=2 et:
data/vhskit.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../lib/vhskit/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ["Amelia Cuss"]
7
+ gem.email = ["amelia@kivikakk.ee"]
8
+ gem.description = %q{Just like a Postgres server, only fake}
9
+ gem.summary = %q{A Postgres server protocol implementation you can configure with a DSL.}
10
+ gem.homepage = "https://github.com/kivikakk/vhskit"
11
+
12
+ gem.add_development_dependency('rake')
13
+ gem.add_development_dependency('rspec')
14
+
15
+ gem.files = `git ls-files`.split($\)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.name = "vhskit"
19
+ gem.require_paths = ["lib"]
20
+ gem.version = VHSKit::VERSION
21
+ end
22
+
23
+ # vim: set sw=2 et:
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vhskit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Amelia Cuss
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Just like a Postgres server, only fake
42
+ email:
43
+ - amelia@kivikakk.ee
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .rspec
50
+ - .travis.yml
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - cert
55
+ - example
56
+ - key
57
+ - lib/vhskit.rb
58
+ - lib/vhskit/handler.rb
59
+ - lib/vhskit/oid.rb
60
+ - lib/vhskit/server.rb
61
+ - lib/vhskit/version.rb
62
+ - vhskit.gemspec
63
+ homepage: https://github.com/kivikakk/vhskit
64
+ licenses: []
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.0.3
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: A Postgres server protocol implementation you can configure with a DSL.
86
+ test_files: []