alib 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,7 +5,8 @@
5
5
  #
6
6
  module ALib::Util
7
7
  #--{{{
8
- class << self
8
+
9
+ module Exporter
9
10
  #--{{{
10
11
  def export(*syms)
11
12
  #--{{{
@@ -16,12 +17,23 @@ module ALib::Util
16
17
  end
17
18
  #--}}}
18
19
  end
20
+ def self.included other
21
+ other.extend self
22
+ end
23
+ #--}}}
24
+ end
25
+
26
+ class << self
27
+ #--{{{
28
+ include Exporter
29
+
19
30
  def append_features c
20
31
  #--{{{
21
32
  super
22
33
  c.extend self
23
34
  #--}}}
24
35
  end
36
+ alias_method "included", "append_features"
25
37
  #--}}}
26
38
  end
27
39
  #
@@ -482,9 +494,17 @@ module ALib::Util
482
494
  def tmpnam(*argv)
483
495
  #--{{{
484
496
  args, opts = argv_split argv
485
- dirname = argv.shift || getopt(%w(dir base prefix), opts, '.')
497
+ dirname = (argv.shift || getopt(%w(dir base prefix), opts, '.')).to_s
486
498
  seed = getopt 'seed', opts, prognam
487
499
  reap = getopt 'reap', opts, true
500
+ dot = getopt 'dot', opts, true
501
+ nodot = getopt 'nodot', opts, false
502
+
503
+ dot = false if nodot
504
+
505
+ #p 'nodot' => nodot
506
+ #p 'dot' => dot
507
+ #p dirname
488
508
 
489
509
  dirname = File.expand_path dirname
490
510
 
@@ -493,16 +513,26 @@ module ALib::Util
493
513
 
494
514
  if reap
495
515
  begin
496
- baseglob = "%s__*__*__*__%s" % [ host, seed ]
497
- glob = File.join(dirname, baseglob)
498
- host_re = %r/^#{ host }$/
499
- candidates = Dir[glob]
500
- candidates.each do |candidate|
516
+ baseglob =
517
+ if nodot
518
+ "%s__*__*__*__%s" % [ host, seed ]
519
+ else
520
+ ".%s__*__*__*__%s" % [ host, seed ]
521
+ end
522
+ host_re =
523
+ if nodot
524
+ %r/^#{ host }$/
525
+ else
526
+ %r/^\.#{ host }$/
527
+ end
528
+ g = File.join dirname, baseglob
529
+ Dir.glob(g).each do |candidate|
501
530
  basename = File.basename candidate
502
531
  parts = basename.split %r/__/, 5
503
532
  if parts[0] =~ host_re
504
533
  pid = Integer parts[1]
505
534
  unless alive? pid
535
+ #STDERR.puts "FileUtils.rm_rf #{ candidate }"
506
536
  FileUtils.rm_rf candidate
507
537
  end
508
538
  end
@@ -513,13 +543,23 @@ module ALib::Util
513
543
  end
514
544
 
515
545
  basename =
516
- "%s__%s__%s__%s__%s" % [
517
- host,
518
- Process::pid,
519
- timestamp('nospace' => true),
520
- rand,
521
- seed,
522
- ]
546
+ if nodot
547
+ "%s__%s__%s__%s__%s" % [
548
+ host,
549
+ Process::pid,
550
+ timestamp('nospace' => true),
551
+ rand,
552
+ seed,
553
+ ]
554
+ else
555
+ ".%s__%s__%s__%s__%s" % [
556
+ host,
557
+ Process::pid,
558
+ timestamp('nospace' => true),
559
+ rand,
560
+ seed,
561
+ ]
562
+ end
523
563
 
524
564
  File.join(dirname, basename)
525
565
  #--}}}
@@ -754,7 +794,7 @@ module ALib::Util
754
794
  #
755
795
  def splitpath path
756
796
  #--{{{
757
- path = "#{ path }"
797
+ path = path.to_s
758
798
  dirname, basename = File::split path
759
799
  [ dirname, (%r/^([^\.]*)(.*)$/).match(basename)[1,2] ].flatten
760
800
  #--}}}
@@ -765,6 +805,7 @@ module ALib::Util
765
805
  #
766
806
  def unzipped path, z_pat = %r/\.(?:z|gz)$/io
767
807
  #--{{{
808
+ path = path.to_s
768
809
  zipped = zipped?(path, z_pat)
769
810
  unless zipped
770
811
  yield path
@@ -784,6 +825,7 @@ module ALib::Util
784
825
  #
785
826
  def zip path, z_ext = nil
786
827
  #--{{{
828
+ path = path.to_s
787
829
  z_ext ||= '.gz'
788
830
  z_ext.gsub! %r/^\s*\.+/, '.'
789
831
  spawn "gzip --suffix #{ z_ext } --force #{ path }"
@@ -804,6 +846,7 @@ module ALib::Util
804
846
  #
805
847
  def zipped_name path, z_ext = nil
806
848
  #--{{{
849
+ path = path.to_s
807
850
  z_ext ||= '.gz'
808
851
  z_ext.gsub! %r/^\s*\.+/, '.'
809
852
  "#{ path }#{ z_ext }"
@@ -815,6 +858,7 @@ module ALib::Util
815
858
  #
816
859
  def unzip path, z_pat = nil
817
860
  #--{{{
861
+ path = path.to_s
818
862
  z_pat ||= %r/\.(?:z|gz)$/io
819
863
  spawn "gzip --force --decompress #{ path }" if zipped?(path, z_pat)
820
864
  #spawn "gzip --force --decompress #{ path }"
@@ -834,6 +878,7 @@ module ALib::Util
834
878
  #
835
879
  def unzipped_name path, z_pat = nil
836
880
  #--{{{
881
+ path = path.to_s
837
882
  z_pat ||= %r/\.(?:z|gz)$/io
838
883
  path.gsub z_pat, ''
839
884
  #--}}}
@@ -844,6 +889,7 @@ module ALib::Util
844
889
  #
845
890
  def zipped? path, z_pat = %r/\.(?:z|gz)$/io
846
891
  #--{{{
892
+ path = path.to_s
847
893
  path =~ z_pat
848
894
  #--}}}
849
895
  end
@@ -938,12 +984,13 @@ module ALib::Util
938
984
  loop do
939
985
  changed = false
940
986
  vars.each do |var, value|
987
+ var = var.to_s
941
988
  var.gsub! %r/[^a-zA-Z0-9_]/, ''
942
989
  [
943
990
  %r/\$#{ var }\b/,
944
991
  %r/\@#{ var }\b/,
945
- %r/\${\s*#{ var }\s*}/,
946
- %r/\@{\s*#{ var }\s*}/
992
+ %r/\$\{\s*#{ var }\s*\}/,
993
+ %r/\@\{\s*#{ var }\s*\}/
947
994
  ].each do |pat|
948
995
  changed = string.gsub! pat, "#{ value }"
949
996
  end
@@ -1008,30 +1055,46 @@ module ALib::Util
1008
1055
  def parse_timespec spec
1009
1056
  #--{{{
1010
1057
  ret = nil
1011
- pat = %r/(\d+(?:\.\d+)?)\s*([sSmMhHdD][^\d]*)?/
1012
- begin
1013
- "#{ spec }".scan(pat) do |m|
1014
- n = Float m[0]
1015
- unit = m[1]
1016
- if unit
1017
- factor =
1018
- case unit
1019
- when %r/^m/i
1020
- 60
1021
- when %r/^h/i
1022
- 60 * 60
1023
- when %r/^d/i
1024
- 60 * 60 * 24
1025
- else
1026
- 1
1027
- end
1028
- n *= factor
1058
+ if((m = %r/^ (\d+(?:\.\d+)?) : (\d+(?:\.\d+)?) : (\d+(?:\.\d+)?) $/iox.match(spec.to_s)))
1059
+ m, h, m, s, ignored = m.to_a
1060
+ h, m, s = Float(h), Float(m), Float(s)
1061
+ #ret = h.hours + m.minutes + s.seconds
1062
+ ret = (h * 60 * 60) + (m * 60) + (s)
1063
+ else
1064
+ pat = %r/(\d+(?:\.\d+)?)\s*([sSmMhHdDwWyY][^\d]*)?/
1065
+ begin
1066
+ "#{ spec }".scan(pat) do |m|
1067
+ n = Float m[0]
1068
+ unit = m[1]
1069
+ if unit
1070
+ factor =
1071
+ case unit
1072
+ when %r/^m/i
1073
+ case unit
1074
+ when %r/^mo/i
1075
+ 7 * (60 * 60 * 24)
1076
+ else
1077
+ 60
1078
+ end
1079
+ when %r/^h/i
1080
+ 60 * 60
1081
+ when %r/^d/i
1082
+ 60 * 60 * 24
1083
+ when %r/^w/i
1084
+ 7 * (60 * 60 * 24)
1085
+ when %r/^y/i
1086
+ 365 * 7 * (60 * 60 * 24)
1087
+ else
1088
+ 1
1089
+ end
1090
+ n *= factor
1091
+ end
1092
+ ret ||= 0.0
1093
+ ret += n
1029
1094
  end
1030
- ret ||= 0.0
1031
- ret += n
1095
+ rescue
1096
+ raise "bad time spec <#{ spec }>"
1032
1097
  end
1033
- rescue
1034
- raise "bad time spec <#{ spec }>"
1035
1098
  end
1036
1099
  ret
1037
1100
  #--}}}
@@ -1056,36 +1119,104 @@ module ALib::Util
1056
1119
  end
1057
1120
  export 'camel_case'
1058
1121
 
1059
- def atomic_copy src, dst
1122
+ def __atomic_op op, src, dst, opts = {}
1060
1123
  #--{{{
1061
1124
  f, fu = File, FileUtils
1062
1125
  src_dirname, src_basename = f.split src
1126
+ src_stat = File.stat src
1063
1127
 
1064
1128
  dst = f.join dst, src_basename if test ?d, dst
1065
-
1066
1129
  dst_dirname, dst_basename = f.split dst
1067
1130
 
1068
- tmp = f.join dst_dirname, ".#{ src_basename }.#{ hostname }.tmp"
1131
+ pid = Process.pid
1132
+ tmp = f.join dst_dirname, ".#{ dst_basename }.#{ hostname }.#{ pid }.#{ rand(4242) }.alib.tmp"
1133
+
1134
+ timeout = getopt 'timeout', opts, 42
1135
+ utime = getopt 'utime', opts
1136
+ mtime = getopt 'mtime', opts
1137
+ atime = getopt 'atime', opts
1138
+
1139
+ safe_cp = lambda do |a, b|
1140
+ 4.times do
1141
+ begin
1142
+ break(fu.cp_r(a, b, :preserve => true))
1143
+ rescue => e
1144
+ STDERR.puts(errmsg(e))
1145
+ uncache a rescue nil
1146
+ uncache b rescue nil
1147
+ sleep timeout
1148
+ end
1149
+ end
1150
+ end
1151
+
1152
+ safe_mv = lambda do |a, b|
1153
+ 4.times do
1154
+ begin
1155
+ break(fu.mv(a, b))
1156
+ rescue => e
1157
+ STDERR.puts(errmsg(e))
1158
+ uncache a rescue nil
1159
+ uncache b rescue nil
1160
+ sleep timeout
1161
+ end
1162
+ end
1163
+ end
1164
+
1165
+ safe_rm = lambda do |a|
1166
+ 4.times do
1167
+ begin
1168
+ break(fu.rm_rf(a))
1169
+ rescue => e
1170
+ STDERR.puts(errmsg(e))
1171
+ uncache a rescue nil
1172
+ sleep timeout
1173
+ end
1174
+ end
1175
+ end
1069
1176
 
1070
1177
  begin
1071
- fu.cp_r src, tmp, :preserve => true
1072
- begin
1073
- fu.mv tmp, dst
1074
- rescue
1075
- uncache tmp rescue nil
1076
- uncache dst rescue nil
1077
- sleep 42
1078
- fu.mv tmp, dst
1178
+ case op
1179
+ when 'cp'
1180
+ safe_cp[src, tmp]
1181
+ safe_mv[tmp, dst]
1182
+ when 'mv'
1183
+ safe_cp[src, tmp]
1184
+ safe_mv[tmp, dst]
1185
+ safe_rm[src]
1186
+ else
1187
+ raise ArgumentError, op.to_s
1079
1188
  end
1080
1189
  ensure
1081
- fu.rm_f tmp
1190
+ safe_rm[tmp]
1191
+ end
1192
+
1193
+ if utime or mtime or atime
1194
+ a = (atime or utime or src_stat.atime)
1195
+ m = (mtime or utime or src_stat.mtime)
1196
+ a = src_stat.atime unless Time === a
1197
+ m = src_stat.mtime unless Time === m
1198
+ ALib::Util::find(dst){|e| File.utime a, m, e}
1082
1199
  end
1083
1200
 
1084
1201
  dst
1085
1202
  #--}}}
1086
1203
  end
1204
+ export '__atomic_op'
1205
+
1206
+ def atomic_copy src, dst, opts = {}
1207
+ __atomic_op 'cp', src, dst, opts
1208
+ end
1209
+ alias_method "atomic_cp", "atomic_copy"
1210
+ export 'atomic_cp'
1087
1211
  export 'atomic_copy'
1088
1212
 
1213
+ def atomic_move src, dst, opts = {}
1214
+ __atomic_op 'mv', src, dst, opts
1215
+ end
1216
+ alias_method "atomic_mv", "atomic_move"
1217
+ export 'atomic_mv'
1218
+ export 'atomic_move'
1219
+
1089
1220
  def child_object
1090
1221
  #--{{{
1091
1222
  r, w = IO.pipe
@@ -1163,5 +1294,275 @@ module ALib::Util
1163
1294
  export '#{ m }'
1164
1295
  code
1165
1296
  end
1297
+
1298
+ #
1299
+ # setup lspawn method/state
1300
+ #
1301
+ #--{{{
1302
+ __cmdno = 0 # static var
1303
+
1304
+ __c = Class.new{
1305
+ def initialize io, prefix
1306
+ @io, @prefix = io, prefix
1307
+ end
1308
+ def << buf
1309
+ @io << "#{ @prefix }__ "
1310
+ @io << buf
1311
+ end
1312
+ }
1313
+
1314
+ __logger = lambda{|io, prefix| __c.new io, prefix}
1315
+
1316
+ __lspawn = lambda do |cmd, *a|
1317
+ begin
1318
+ Thread.critical = true
1319
+ log = a.shift
1320
+ log = (logger rescue (@logger || Logger.new(STDERR)))
1321
+
1322
+ stdout = __logger[STDOUT, :o]
1323
+ stderr = __logger[STDERR, :e]
1324
+
1325
+ log.info{ "cmd[#{ __cmdno }] <#{ cmd }>" }
1326
+
1327
+ status = Alib::Util::spawn(cmd, 'quiet'=>true, 'raise'=>false, 'stdout'=>stdout, 'stderr'=>stderr)
1328
+
1329
+ if status and status == 0
1330
+ log.info{ "status[#{ __cmdno }] <#{ status }>" }
1331
+ else
1332
+ log.warn{ "status[#{ __cmdno }] <#{ status || 127 }>" }
1333
+ end
1334
+
1335
+ if status and status.signaled?
1336
+ if status.termsig
1337
+ log.warn{ "termsig[#{ __cmdno }] <#{ status.termsig }>" }
1338
+ end
1339
+ if status.stopsig
1340
+ log.warn{ "stopsig[#{ __cmdno }] <#{ status.stopsig }>" }
1341
+ end
1342
+ end
1343
+
1344
+ status ? status.exitstatus : 127
1345
+ ensure
1346
+ __cmdno += 1
1347
+ Thread.critical = false
1348
+ end
1349
+ end
1350
+
1351
+ define_method 'lspawn', &__lspawn
1352
+
1353
+ LSPAWN_CMDNO = [0]
1354
+ LSPAWN_LOG = Hash.new{|h,k| h[k] = alib.logging.default_logger}
1355
+ LSPAWN_IO = Class.new do
1356
+ def initialize log, prefix, io
1357
+ @log, @prefix, @io = log, prefix, io
1358
+ end
1359
+ def << buf
1360
+ @log << " #{ @prefix }__ #{ buf.chomp }\n"
1361
+ #@log << "#{ buf.chomp }\n"
1362
+ @io << buf if @io
1363
+ end
1364
+ end
1365
+ #--}}}
1366
+
1367
+ def lspawn cmd, opts = {}
1368
+ #--{{{
1369
+ begin
1370
+ Thread.critical = true
1371
+
1372
+ stdin = ALib::Util::getopt ['stdin', 'i', 'in', '0', 0], opts
1373
+ stdout = ALib::Util::getopt ['stdout', 'o', 'out', '1', 1], opts
1374
+ stderr = ALib::Util::getopt ['stderr', 'e', 'err', '2', 2], opts
1375
+ expect = ALib::Util::getopt ['expect', 'status', 'success'], opts, 0
1376
+ log = Alib::Util::getopt ['logger', 'log'], opts
1377
+
1378
+ log ||= (self.logger rescue (defined?(@logger) ? @logger : LSPAWN_LOG[0]))
1379
+
1380
+ stdout = LSPAWN_IO.new log, :o, stdout
1381
+ stderr = LSPAWN_IO.new log, :e, stderr
1382
+
1383
+ cmdno = LSPAWN_CMDNO[0]
1384
+
1385
+ log.info{ "cmd[#{ cmdno }] <#{ cmd }>" }
1386
+
1387
+ status = Alib::Util::spawn(cmd, 'quiet'=>true, 'raise'=>false, 'stdin'=>stdin, 'stdout'=>stdout, 'stderr'=>stderr)
1388
+
1389
+ exitstatus = ( (status ? (status.exitstatus || 127) : 127) rescue 127 )
1390
+
1391
+ log.send(exitstatus == 0 ? 'info' : 'warn'){ "status[#{ cmdno }] <#{ exitstatus }>" }
1392
+
1393
+ if expect
1394
+ codes = [*expect].flatten.compact.map{|code| Integer code}
1395
+ success = codes.detect{|code| exitstatus == code}
1396
+ unless success
1397
+ log.fatal{ "cmd[#{ cmdno }] failure" }
1398
+ exit exitstatus
1399
+ end
1400
+ end
1401
+
1402
+ if status and status.signaled?
1403
+ if status.termsig
1404
+ log.warn{ "termsig[#{ cmdno }] <#{ status.termsig }>" }
1405
+ end
1406
+ if status.stopsig
1407
+ log.warn{ "stopsig[#{ cmdno }] <#{ status.stopsig }>" }
1408
+ end
1409
+ end
1410
+
1411
+ exitstatus
1412
+ ensure
1413
+ LSPAWN_CMDNO[0] = LSPAWN_CMDNO[0] + 1
1414
+ Thread.critical = false
1415
+ end
1416
+ #--}}}
1417
+ end
1418
+ export 'lspawn'
1419
+
1420
+ def sweep hash
1421
+ #--{{{
1422
+ srcdir, dstdir, ignored = hash.to_a.first
1423
+ Dir.glob(File.join(srcdir, '*')) do |src|
1424
+ dirname, basename = File.split src
1425
+ dst = File.join dstdir, basename
1426
+ FileUtils.mv src, dst
1427
+ end
1428
+ #--}}}
1429
+ end
1430
+ export 'sweep'
1431
+
1432
+
1433
+ def threadify list, n = 4, &b
1434
+ #--{{{
1435
+ n = Integer n
1436
+ done = Object.new.freeze
1437
+ jobs = Queue.new
1438
+
1439
+ list.each_with_index{|elem, i| jobs.push [elem, i]}
1440
+ n.times{ jobs.push done} # mark the end
1441
+
1442
+ consumers = Array.new n
1443
+
1444
+ n.times do |i|
1445
+ consumers[i] = Thread.new do
1446
+ this = Thread.current
1447
+ this.abort_on_exception = true
1448
+
1449
+ loop{
1450
+ job = jobs.pop
1451
+ this.exit if job == done
1452
+ jobs << (job << bcall(b, job))
1453
+ }
1454
+ end
1455
+ end
1456
+
1457
+ consumers.map{|t| t.join}
1458
+ jobs.push done
1459
+
1460
+ #sleep 5
1461
+
1462
+ ret = Array.new list.size
1463
+ while((job = jobs.pop) != done)
1464
+ elem, i, value = job
1465
+ ret[i] = value
1466
+ end
1467
+ ret
1468
+ #--}}}
1469
+ end
1470
+ export 'threadify'
1471
+
1472
+ def block_argv b, argv
1473
+ #--{{{
1474
+ arity = b.arity
1475
+ if arity >= 0
1476
+ argv[0,arity]
1477
+ else
1478
+ head = []
1479
+ tail = []
1480
+ n = arity.abs - 1
1481
+ head = argv[0...n]
1482
+ tail = argv[n..-1]
1483
+ [*(head + tail)]
1484
+ end
1485
+ #--}}}
1486
+ end
1487
+ export 'block_argv'
1488
+
1489
+ def bcall b, argv
1490
+ #--{{{
1491
+ a = block_argv b, argv
1492
+ b[*a]
1493
+ #--}}}
1494
+ end
1495
+ export 'bcall'
1496
+
1497
+ #
1498
+ # casting methods
1499
+ #
1500
+ module Casting
1501
+ #--{{{
1502
+ include Exporter
1503
+
1504
+ def int_list *list
1505
+ #--{{{
1506
+ list.flatten.compact.map{|i| Util.atoi i}
1507
+ #--}}}
1508
+ end
1509
+ def float_list *list
1510
+ #--{{{
1511
+ list.flatten.compact.map{|f| Float f}
1512
+ #--}}}
1513
+ end
1514
+ def string_list *list
1515
+ #--{{{
1516
+ list.flatten.compact.map{|s| String s}
1517
+ #--}}}
1518
+ end
1519
+ def string_cast arg
1520
+ arg.to_s
1521
+ end
1522
+ def int_cast arg
1523
+ Integer arg.to_s
1524
+ end
1525
+ def float_cast arg
1526
+ Float arg
1527
+ end
1528
+ def bool_cast arg
1529
+ arg ? true : false
1530
+ end
1531
+ def bool_cast arg
1532
+ case arg
1533
+ when Numeric
1534
+ not arg.zero?
1535
+ when String
1536
+ case arg
1537
+ when %r/^(1|t|true)$/i
1538
+ true
1539
+ when %r/^(0|f|false)$/i
1540
+ false
1541
+ else
1542
+ raise ArgumentError, arg.inspect
1543
+ end
1544
+ else
1545
+ arg ? true : false
1546
+ end
1547
+ end
1548
+ def re_cast arg
1549
+ Regexp === arg ? arg : %r/#{ arg }/
1550
+ end
1551
+ def pathname_cast arg, opts = {}
1552
+ expand = opts['expand'] || opts[:expand]
1553
+ pn = (Pathname === arg ? arg : Pathname.new(arg.to_s))
1554
+ expand ? pn.expand_path : pn
1555
+ end
1556
+
1557
+ instance_methods.each{|m| export m}
1558
+ #--}}}
1559
+ end
1560
+
1561
+ # dump methods into Util
1562
+ include Casting
1563
+ Casting.instance_methods.each{|m| export m}
1564
+
1565
+ def self.casting() Casting end
1566
+
1166
1567
  #--}}}
1167
1568
  end # module Util