Module: BitGirder::Io

Extended by:
BitGirderMethods
Includes:
Core, BitGirderMethods
Included in:
Event::File, Event::Testing::TestCodec, Ops::Java::JavaEnvironment, Ops::Ruby::RubyIncludes
Defined in:
lib/bitgirder/io.rb,
lib/bitgirder/io/testing.rb

Defined Under Namespace

Modules: Testing Classes: BinaryConverter, BinaryIo, BinaryReader, BinaryWriter, DataSize, DataSizeError, DataUnit, DataUnitError, ProcessCheck, UnixProcessBuilder

Constant Summary collapse

ORDER_LITTLE_ENDIAN =
:little_endian
ORDER_BIG_ENDIAN =
:big_endian

Constants included from Core

Core::ENV_BITGIRDER_DEBUG, Core::EXIT_FAILURE, Core::EXIT_SUCCESS

Class Method Summary collapse

Class Method Details

.as_encoded(str, enc) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/bitgirder/io.rb', line 36

def as_encoded( str, enc )
    
    not_nil( str, :str )
    not_nil( enc, :enc )

    str.encoding == enc ? str : str.encode( enc )
end

.as_json(obj) ⇒ Object



220
# File 'lib/bitgirder/io.rb', line 220

def as_json( obj ); JSON.generate( not_nil( obj, :obj ) ); end

.as_read_src(obj) ⇒ Object



207
208
209
210
211
212
213
214
215
216
# File 'lib/bitgirder/io.rb', line 207

def as_read_src( obj )
    
    not_nil( obj, :obj )

    case obj
        when IO, Tempfile then yield( obj )
        when String then File.open( file_exists( obj ) ) { |io| yield( io ) }
        else raise TypeError, "Unkown read src: #{obj.class}"
    end
end

.as_write_dest(obj) ⇒ Object



194
195
196
197
198
199
200
201
202
203
# File 'lib/bitgirder/io.rb', line 194

def as_write_dest( obj )
    
    not_nil( obj, :obj )

    case obj
        when IO, Tempfile then yield( obj )
        when String then File.open( obj, "w" ) { |io| yield( io ) }
        else raise TypeError, "Unknown write dest: #{obj.class}"
    end
end

.can_connect?(*argv) ⇒ Boolean

Returns:

  • (Boolean)


387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/bitgirder/io.rb', line 387

def can_connect?( *argv )
    
    raise "Need at least a port" if argv.empty?

    host = argv.first.is_a?( String ) ? argv.shift : "127.0.0.1"

    raise "Need a port" if argv.empty?

    unless ( port = argv.shift ).is_a?( Integer )
        raise TypeError, "Invalid host or port value: #{port.class}" 
    end

    begin
        TCPSocket::new( host, port ).close
        true
    rescue Errno::ECONNREFUSED, Errno::ECONNRESET
        false
    end
end

.debug_kill(sig, pid, opts = {}) ⇒ Object



359
360
361
362
363
364
365
366
367
368
# File 'lib/bitgirder/io.rb', line 359

def debug_kill( sig, pid, opts = {} )
    
    not_nil( opts, "opts" )
    
    msg = "Sending #{sig} to #{pid}"
    msg += " (#{opts[ :name ]})" if opts.key?( :name )

    BitGirderLogger.get_logger.code( msg )
    Process.kill( sig, pid )
end

.debug_wait2(opts) ⇒ Object



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/bitgirder/io.rb', line 335

def debug_wait2( opts )
    
    not_nil( opts, "opts" )
    
    pid = has_key( opts, :pid )

    name = opts[ :name ]
    name_str = name ? "#{name} (pid #{pid})" : pid.to_s
    code( "Waiting on #{name_str}" )

    pid, status = Process::wait2( pid )
    msg = "Process #{pid} exited with status #{status.exitstatus}"

    if status.success?
        code( msg )
    else
        opts[ :check_status ] ? ( raise msg ) : warn( msg )
    end

    [ pid, status ]
end

.digest_file(opts) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/bitgirder/io.rb', line 71

def digest_file( opts )
    
    dig_cls, file = has_keys( opts, :digest_type, :file )
    buf_sz = opts[ :buffer_size ] || 50 * ( 1 << 10 )

    # Set this now so we can fail before reading file if need be
    out_func = case ot = opts[ :output_type ]
        when nil, :binary then lambda { |dig| dig }
        when :base64 then lambda { |dig| strict_encode64( dig ) }
        else raise "Unhandled output type: #{ot}"
    end

    dig = dig_cls.new

    File.open( file ) do |io|
        
        buf = ""
        while buf = io.read( buf_sz, buf ) 
            dig.update( buf ) 
        end
    end

    out_func.call( dig.digest )
end

.dump_json(obj, file) ⇒ Object



228
229
230
231
232
233
234
235
236
# File 'lib/bitgirder/io.rb', line 228

def dump_json( obj, file )
 
    not_nil( obj, :obj )
    not_nil( file, :file )

    json = as_json( obj )

    as_write_dest( file ) { |io| io.print( json ) }
end

.dump_yaml(obj, dest = nil) ⇒ Object



248
249
250
251
252
253
254
255
256
257
# File 'lib/bitgirder/io.rb', line 248

def dump_yaml( obj, dest = nil )
    
    not_nil( obj, :obj )

    if dest
        as_write_dest( dest ) { |io| YAML.dump( obj, io ) }
    else
        YAML.dump( obj )
    end
end

.enc_utf8Object

Lazily load and assert presence of utf8 encoding



22
23
24
25
26
# File 'lib/bitgirder/io.rb', line 22

def enc_utf8

    @@enc_utf8 ||= 
       ( Encoding.find( "utf-8" ) or raise "No utf-8 encoding found (?!)" )
end

.ensure_dir(d) ⇒ Object

Effectively enables mdkir_p as an inline function to enable statements like:

some_dir = ensure_dir( some_dir )


285
286
287
288
289
# File 'lib/bitgirder/io.rb', line 285

def ensure_dir( d )

    fu().mkdir_p( d ) unless File.exist?( d )
    d
end

.ensure_dirs(*dirs) ⇒ Object



301
302
303
# File 'lib/bitgirder/io.rb', line 301

def ensure_dirs( *dirs )
    dirs.each { |dir| ensure_dir( dir ) }
end

.ensure_parent(file) ⇒ Object

Ensures that the directory referred to as dirname( file ) exists, and returns file itself (not the parent). Fails if dirname does not return anything meaningful for file.



310
311
312
313
314
315
316
317
318
# File 'lib/bitgirder/io.rb', line 310

def ensure_parent( file )
    
    parent = File.dirname( file )
    raise "No parent exists for #{file}" unless parent
    
    ensure_dir( parent )

    file
end

.ensure_wiped(d) ⇒ Object



293
294
295
296
297
# File 'lib/bitgirder/io.rb', line 293

def ensure_wiped( d )
    
    fu().rm_rf( d )
    ensure_dir( d )
end

.file_exists(d) ⇒ Object



122
123
124
125
126
# File 'lib/bitgirder/io.rb', line 122

def file_exists( d )
    
    raise "File or directory #{d} does not exist" unless File.exist?( d )
    d
end

.first_line(file) ⇒ Object



166
167
168
# File 'lib/bitgirder/io.rb', line 166

def first_line( file )
    File.open( file ) { |io| io.readline.chomp }
end

.fsize(obj) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
# File 'lib/bitgirder/io.rb', line 142

def fsize( obj )
    
    stat =
        case obj
        when File, Tempfile then File.stat( obj.path )
        when String then File.stat( obj )
        else raise TypeError, "Unhandled type for fsize: #{obj.class}"
        end
    
    stat.size
end

.fuObject



30
31
32
# File 'lib/bitgirder/io.rb', line 30

def fu()
    BitGirderLogger.get_logger.is_debug? ? FileUtils::Verbose : FileUtils
end

.int_to_byte_array(i) ⇒ Object

Returns i as a little-endian 2’s complement byte array; Algorithm is from stackoverflow.com/questions/5284369/ruby-return-byte-array-containing-twos-complement-representation-of-bignum-fi (with some cosmetic differences, including the return val’s endianness).

Though not stated there, it’s worth noting that the reason for the end condition test of the 7th (sign) bit is to avoid stopping prematurely on inputs such as 0xff00, dropping the sign information from the result



106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/bitgirder/io.rb', line 106

def int_to_byte_array( i )
    
    not_nil( i, :i )

    res = []

    begin
        res << ( i & 0xff )
        i >>= 8
    end until ( i == 0 || i == -1 ) && ( res[ -1 ][ 7 ] == i[ 7 ] )

    res
end

.is_executable(file) ⇒ Object



270
271
272
273
274
275
276
# File 'lib/bitgirder/io.rb', line 270

def is_executable( file )
 
    file_exists( file )
    raise "Not an executable: #{file}" unless File.executable?( file )

    file
end

.load_json(file) ⇒ Object



240
241
242
243
244
# File 'lib/bitgirder/io.rb', line 240

def load_json( file )
 
    not_nil( file, :file )
    as_read_src( file ) { |io| parse_json( slurp( io ) ) }
end

.load_yaml(src) ⇒ Object



261
262
263
264
265
266
# File 'lib/bitgirder/io.rb', line 261

def load_yaml( src )
    
    not_nil( src, :src )

    as_read_src( src ) { |io| YAML.load( io ) }
end

.mktmpdir(*argv, &blk) ⇒ Object



136
137
138
# File 'lib/bitgirder/io.rb', line 136

def mktmpdir( *argv, &blk )
    Dir.mktmpdir( *argv, &blk )
end

.open_tempfile(basename = nil, *rest, &blk) ⇒ Object



130
131
132
133
134
# File 'lib/bitgirder/io.rb', line 130

def open_tempfile( basename = nil, *rest, &blk )
    
    basename ||= [ "bg-tmp-", ".tmp" ]
    Tempfile::open( basename, *rest, &blk )
end

.parse_json(str) ⇒ Object



224
# File 'lib/bitgirder/io.rb', line 224

def parse_json( str ); JSON.parse( not_nil( str, :str ) ); end

.read_full(io, len, buf = nil) ⇒ Object



372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/bitgirder/io.rb', line 372

def read_full( io, len, buf = nil )
    
    args = [ len ]
    args << buf if buf
    buf = io.read( *args )

    if ( sz = buf == nil ? 0 : buf.bytesize ) < len
        raise EOFError.new( "EOF after #{sz} bytes (wanted #{len})" )
    end

    buf
end

.slurp(io, blk_sz = 4096) ⇒ Object



183
184
185
186
187
188
189
190
# File 'lib/bitgirder/io.rb', line 183

def slurp( io, blk_sz = 4096 )
    
    case io
        when IO, Tempfile then slurp_io( io, blk_sz )
        when String then File.open( io ) { |io2| slurp_io( io2, blk_sz ) }
        else raise "Unknown slurp target: #{io} (#{io.class})"
    end
end

.slurp_io(io, blk_sz = 4096) ⇒ Object



172
173
174
175
176
177
178
179
# File 'lib/bitgirder/io.rb', line 172

def slurp_io( io, blk_sz = 4096 )
    
    not_nil( io, :io )

    while s = io.read( blk_sz ); res = res ? res << s : s; end
    
    res
end

.strict_decode64(str) ⇒ Object

Despite the name, this method only enforces strictness when running in a ruby >= 1.9 for now, though we may backport and handcode integrity checks at some point for other rubies



60
61
62
63
64
65
66
67
# File 'lib/bitgirder/io.rb', line 60

def strict_decode64( str )
    
    if RUBY_VERSION >= "1.9"
        Base64.strict_decode64( str )
    else
        Base64.decode64( str )
    end
end

.strict_encode64(str) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/bitgirder/io.rb', line 46

def strict_encode64( str )

    if RUBY_VERSION >= "1.9"
        Base64.strict_encode64( str )
    else
        Base64.encode64( str ).split( /\n/ ).join( "" )
    end
end

.which(cmd, fail_on_miss = false) ⇒ Object



322
323
324
325
326
327
328
329
330
331
# File 'lib/bitgirder/io.rb', line 322

def which( cmd, fail_on_miss = false )
    
    not_nil( cmd, "cmd" )

    if ( f = `which #{cmd}`.strip ) and f.empty? 
        raise "Cannot find command #{cmd.inspect} in path" if fail_on_miss
    else
        f
    end
end

.write_file(text, file) ⇒ Object



158
159
160
161
162
# File 'lib/bitgirder/io.rb', line 158

def write_file( text, file )
 
    fu().mkdir_p( File.dirname( file ) )
    File.open( file, "w" ) { |io| io.print text }
end