svn 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +39 -0
- data/lib/svn.rb +19 -0
- data/lib/svn/apr_utils.rb +313 -0
- data/lib/svn/counted_strings.rb +38 -0
- data/lib/svn/diffs.rb +209 -0
- data/lib/svn/errors.rb +83 -0
- data/lib/svn/logs.rb +120 -0
- data/lib/svn/misc.rb +68 -0
- data/lib/svn/pools.rb +67 -0
- data/lib/svn/repos.rb +333 -0
- data/lib/svn/revisions.rb +133 -0
- data/lib/svn/roots.rb +161 -0
- data/lib/svn/streams.rb +149 -0
- data/lib/svn/transactions.rb +51 -0
- data/lib/svn/utils.rb +249 -0
- metadata +71 -0
data/lib/svn/utils.rb
ADDED
@@ -0,0 +1,249 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
module Svn #:nodoc:
|
5
|
+
|
6
|
+
# Utility functions for working with FFI
|
7
|
+
module Utils
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Returns a pointer to the object_id of +obj+
|
12
|
+
def wrap( obj )
|
13
|
+
ptr = FFI::MemoryPointer.new( :uint64 )
|
14
|
+
ptr.write_uint64( obj.object_id )
|
15
|
+
ptr
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the object for the object_id stored in +ptr+
|
19
|
+
def unwrap( ptr )
|
20
|
+
ObjectSpace._id2ref( ptr.read_uint64 )
|
21
|
+
end
|
22
|
+
|
23
|
+
# a generic factory class for use with FFI data types that adds default
|
24
|
+
# arguments to constructor calls
|
25
|
+
#
|
26
|
+
# # when NativeHash is created, the args are [ptr, :string, :string]
|
27
|
+
# bind :get_hash, :returning => NativeHash.factory( :string, :string )
|
28
|
+
class Factory
|
29
|
+
|
30
|
+
# factories also work as DataConverters so they can be used with FFI
|
31
|
+
include FFI::DataConverter
|
32
|
+
|
33
|
+
def initialize( klass, *args )
|
34
|
+
@klass = klass
|
35
|
+
@added_args = args
|
36
|
+
end
|
37
|
+
|
38
|
+
def new( *args )
|
39
|
+
@klass.new( *args, *@added_args )
|
40
|
+
end
|
41
|
+
|
42
|
+
def from_native( ptr, ctx )
|
43
|
+
@klass.new( ptr, *@added_args )
|
44
|
+
end
|
45
|
+
|
46
|
+
def native_type
|
47
|
+
@klass.native_type
|
48
|
+
end
|
49
|
+
|
50
|
+
def real_class
|
51
|
+
@klass
|
52
|
+
end
|
53
|
+
|
54
|
+
def size
|
55
|
+
@klass.size
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# returns the *contents* of the pointer as type
|
60
|
+
#
|
61
|
+
# for example:
|
62
|
+
# # void get_string( char **p ):
|
63
|
+
# get_string( out_ptr ); content_for( out_ptr, :string )
|
64
|
+
#
|
65
|
+
# # void get_hash( hash_t **p ):
|
66
|
+
# class Hash < FFI::AutoPointer; end
|
67
|
+
# get_hash( out_ptr ); content_for( out_ptr, Hash )
|
68
|
+
#
|
69
|
+
# if the type is a FFI::Pointer, this will try to instantiate it; to avoid
|
70
|
+
# instantiation, pass :pointer as the type
|
71
|
+
def content_from( pointer, type, len=nil )
|
72
|
+
return if pointer.nil?
|
73
|
+
if type.is_a? Array
|
74
|
+
type.inject( pointer ) do |ptr, subtype|
|
75
|
+
content_for( ptr, subtype, len )
|
76
|
+
end
|
77
|
+
elsif type.is_a? Factory
|
78
|
+
type.new( pointer.read_pointer ) unless pointer.null?
|
79
|
+
elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
|
80
|
+
type.new( pointer.read_pointer ) unless pointer.null?
|
81
|
+
elsif type.is_a?( FFI::Type::Mapped )
|
82
|
+
type.from_native( pointer.read_pointer, nil ) unless pointer.null?
|
83
|
+
elsif type == :string
|
84
|
+
pointer.read_pointer.read_string(
|
85
|
+
( len == -1 ) ? nil : len
|
86
|
+
) unless pointer.null?
|
87
|
+
else
|
88
|
+
pointer.send( :"read_#{type}" )
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# returns the the pointer's value as type
|
93
|
+
#
|
94
|
+
# for example:
|
95
|
+
# # char *get_string( void ):
|
96
|
+
# ptr = get_string()
|
97
|
+
# str = content_for( ptr, :string )
|
98
|
+
#
|
99
|
+
# # hash *get_hash( void ):
|
100
|
+
# class Hash < FFI::AutoPointer; end
|
101
|
+
# ptr = get_hash( out_ptr )
|
102
|
+
# hash = content_for( out_ptr, Hash )
|
103
|
+
def content_for( pointer, type, len=nil )
|
104
|
+
return if pointer.nil?
|
105
|
+
if type.is_a? Array
|
106
|
+
type.inject( pointer ) do |ptr, subtype|
|
107
|
+
content_for( ptr, subtype, len )
|
108
|
+
end
|
109
|
+
elsif type.is_a? Factory
|
110
|
+
type.new( pointer ) unless pointer.null?
|
111
|
+
elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
|
112
|
+
type.new( pointer ) unless pointer.null?
|
113
|
+
elsif type.is_a?( FFI::Type::Mapped )
|
114
|
+
type.from_native( pointer, nil ) unless pointer.null?
|
115
|
+
elsif type == :string
|
116
|
+
# if len is nil or -1, use it for reading instead of counting on it to
|
117
|
+
# be null-terminated
|
118
|
+
pointer.read_string( ( len == -1 ) ? nil : len ) unless pointer.null?
|
119
|
+
else
|
120
|
+
pointer.send( :"read_#{type}" ) unless pointer.null?
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def pointer_for( value, type )
|
125
|
+
if type.is_a? Array
|
126
|
+
type.reverse.inject( value ) do |val, subtype|
|
127
|
+
pointer_for( val, subtype )
|
128
|
+
end
|
129
|
+
elsif type.is_a? Factory
|
130
|
+
pointer_for( value, type.real_class )
|
131
|
+
elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
|
132
|
+
# use val directly
|
133
|
+
value
|
134
|
+
elsif type.is_a?( FFI::Type::Mapped )
|
135
|
+
# mapped types are really pointers to structs; they are read
|
136
|
+
# differently, but they should still be pointers we can use directly
|
137
|
+
value
|
138
|
+
elsif type == :string
|
139
|
+
# use from_string even if it isn't necessary to null-terminate
|
140
|
+
FFI::MemoryPointer.from_string( value )
|
141
|
+
else
|
142
|
+
# it must be a FFI type, use a new MemoryPointer
|
143
|
+
ptr = FFI::MemoryPointer.new( type )
|
144
|
+
ptr.send( :"write_#{type}", value )
|
145
|
+
ptr
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# this module contains extensions for classes that inherit from FFI::Struct
|
150
|
+
# and FFI::AutoPointer to make binding instance methods to C methods more
|
151
|
+
# concise
|
152
|
+
module Extensions
|
153
|
+
|
154
|
+
# convenience method that returns a Factory instance for self with the
|
155
|
+
# given args
|
156
|
+
#
|
157
|
+
# the following are equivalent:
|
158
|
+
# NativeHash.factory( :string, :string )
|
159
|
+
#
|
160
|
+
# Factory( NativeHash, :string, :string )
|
161
|
+
def factory( *args )
|
162
|
+
Factory.new( self, *args )
|
163
|
+
end
|
164
|
+
|
165
|
+
module_function
|
166
|
+
|
167
|
+
# sets the module that will be used for all bound methods, until bind_to
|
168
|
+
# is called again
|
169
|
+
def bind_to( target )
|
170
|
+
@@target = target
|
171
|
+
end
|
172
|
+
|
173
|
+
# binds a method on the current target to self
|
174
|
+
#
|
175
|
+
# == arguments
|
176
|
+
# +sym+ :: the method on the target (set by +bind_to+) to use
|
177
|
+
# +options+ :: a Hash of optional method aliases or returned arguments
|
178
|
+
#
|
179
|
+
# == options
|
180
|
+
# +:as+ :: method name to use for the bound method
|
181
|
+
# +:to+ :: function name to use from the target object
|
182
|
+
# +:returning+ :: an array of types for out parameters
|
183
|
+
# +:validate+ :: a validation to call on the bound method's return value
|
184
|
+
# +:before_return+ :: a function to call on the return value
|
185
|
+
#
|
186
|
+
# TODO: call to_proc on symbols that should be procs
|
187
|
+
def bind( sym, options={}, &block )
|
188
|
+
# look up the method in the target module
|
189
|
+
meth_name = ( options[:to] || sym ).to_sym
|
190
|
+
# get a method obj from the target receiver so that if @@target is
|
191
|
+
# changed by another call to :bind_to, the method/target will not be
|
192
|
+
# changed (and broken)
|
193
|
+
meth = @@target.method( meth_name )
|
194
|
+
name = ( options[:as] || sym ).to_sym
|
195
|
+
|
196
|
+
# get the return types as an Array and save a copy
|
197
|
+
single_return = !options[:returning].is_a?( Array )
|
198
|
+
return_types = Array( options[:returning] ).dup
|
199
|
+
|
200
|
+
# get the C function validation
|
201
|
+
validation = options[:validate]
|
202
|
+
|
203
|
+
# get the before_return filter
|
204
|
+
before_return = options[:before_return] || lambda { |x| x }
|
205
|
+
|
206
|
+
# create a new method; blocks are used to re-arrange arguments
|
207
|
+
define_method( name ) do |*args|
|
208
|
+
# create new pointers for the specified out arguments
|
209
|
+
return_ptrs = return_types.map { |type| FFI::MemoryPointer.new( type ) }
|
210
|
+
|
211
|
+
return_val = nil # keep it in scope
|
212
|
+
if block
|
213
|
+
# call the method with the arguments after re-arranging via block
|
214
|
+
return_val = meth.call( *instance_exec(
|
215
|
+
*return_ptrs, self, *args, &block
|
216
|
+
) )
|
217
|
+
else
|
218
|
+
# call the method with the standard argument order
|
219
|
+
return_val = meth.call( *return_ptrs, self, *args )
|
220
|
+
end
|
221
|
+
|
222
|
+
# call the return check, if present
|
223
|
+
instance_exec( return_val, &validation ) if validation
|
224
|
+
|
225
|
+
# if there are return types (out pointers), read the values out of
|
226
|
+
# the pointers and replace the return_val
|
227
|
+
unless return_types.empty?
|
228
|
+
return_val = return_ptrs.zip( return_types ).map do |ptr, type|
|
229
|
+
Utils.content_from( ptr, type )
|
230
|
+
end
|
231
|
+
return_val = return_val.first if single_return
|
232
|
+
end
|
233
|
+
|
234
|
+
# run the before_return filter and return the value from it; if no
|
235
|
+
# :before_return was in options, this will be the id function
|
236
|
+
instance_exec( return_val, &before_return )
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
# extend FFI objects with the new helper methods
|
244
|
+
#FFI::Struct.extend Extensions
|
245
|
+
FFI::AutoPointer.extend Extensions
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: svn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Blue
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-11 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ffi
|
16
|
+
requirement: &15276700 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *15276700
|
25
|
+
description:
|
26
|
+
email: rdblue@gmail.com
|
27
|
+
executables: []
|
28
|
+
extensions: []
|
29
|
+
extra_rdoc_files:
|
30
|
+
- README
|
31
|
+
files:
|
32
|
+
- lib/svn/misc.rb
|
33
|
+
- lib/svn/pools.rb
|
34
|
+
- lib/svn/apr_utils.rb
|
35
|
+
- lib/svn/diffs.rb
|
36
|
+
- lib/svn/utils.rb
|
37
|
+
- lib/svn/transactions.rb
|
38
|
+
- lib/svn/logs.rb
|
39
|
+
- lib/svn/roots.rb
|
40
|
+
- lib/svn/repos.rb
|
41
|
+
- lib/svn/streams.rb
|
42
|
+
- lib/svn/errors.rb
|
43
|
+
- lib/svn/revisions.rb
|
44
|
+
- lib/svn/counted_strings.rb
|
45
|
+
- lib/svn.rb
|
46
|
+
- README
|
47
|
+
homepage: http://github.com/codefoundry/svn
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.10
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Ruby bindings for SVN based on FFI
|
71
|
+
test_files: []
|