scout-gear 1.2.0 → 5.1.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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +4 -0
  3. data/.vimproject +663 -4
  4. data/Rakefile +1 -0
  5. data/VERSION +1 -1
  6. data/bin/scout +235 -0
  7. data/lib/scout/cmd.rb +344 -0
  8. data/lib/scout/concurrent_stream.rb +259 -0
  9. data/lib/scout/exceptions.rb +15 -8
  10. data/lib/scout/indiferent_hash/options.rb +8 -26
  11. data/lib/scout/indiferent_hash.rb +0 -30
  12. data/lib/scout/log/color.rb +2 -2
  13. data/lib/scout/log/fingerprint.rb +11 -1
  14. data/lib/scout/log/progress/report.rb +0 -1
  15. data/lib/scout/log/progress/util.rb +1 -1
  16. data/lib/scout/log/progress.rb +4 -4
  17. data/lib/scout/log.rb +10 -2
  18. data/lib/scout/meta_extension.rb +15 -1
  19. data/lib/scout/misc/digest.rb +56 -0
  20. data/lib/scout/misc/filesystem.rb +26 -0
  21. data/lib/scout/misc/format.rb +226 -0
  22. data/lib/scout/misc/insist.rb +56 -0
  23. data/lib/scout/misc.rb +5 -11
  24. data/lib/scout/open/lock.rb +61 -0
  25. data/lib/scout/open/remote.rb +120 -0
  26. data/lib/scout/open/stream.rb +372 -0
  27. data/lib/scout/open/util.rb +225 -0
  28. data/lib/scout/open.rb +169 -0
  29. data/lib/scout/path/find.rb +78 -26
  30. data/lib/scout/path/tmpfile.rb +8 -0
  31. data/lib/scout/path/util.rb +17 -5
  32. data/lib/scout/path.rb +13 -31
  33. data/lib/scout/persist/open.rb +17 -0
  34. data/lib/scout/persist/path.rb +15 -0
  35. data/lib/scout/persist/serialize.rb +140 -0
  36. data/lib/scout/persist.rb +54 -0
  37. data/lib/scout/resource/path.rb +15 -0
  38. data/lib/scout/resource/produce/rake.rb +69 -0
  39. data/lib/scout/resource/produce.rb +246 -0
  40. data/lib/scout/resource/scout.rb +3 -0
  41. data/lib/scout/resource.rb +37 -0
  42. data/lib/scout/simple_opt/accessor.rb +54 -0
  43. data/lib/scout/simple_opt/doc.rb +102 -0
  44. data/lib/scout/simple_opt/get.rb +57 -0
  45. data/lib/scout/simple_opt/parse.rb +67 -0
  46. data/lib/scout/simple_opt/setup.rb +26 -0
  47. data/lib/scout/simple_opt.rb +5 -0
  48. data/lib/scout/tmpfile.rb +39 -1
  49. data/lib/scout/workflow/definition.rb +72 -0
  50. data/lib/scout/workflow/documentation.rb +77 -0
  51. data/lib/scout/workflow/step/info.rb +77 -0
  52. data/lib/scout/workflow/step.rb +96 -0
  53. data/lib/scout/workflow/task/inputs.rb +112 -0
  54. data/lib/scout/workflow/task.rb +141 -0
  55. data/lib/scout/workflow/usage.rb +294 -0
  56. data/lib/scout/workflow/util.rb +11 -0
  57. data/lib/scout/workflow.rb +39 -0
  58. data/lib/scout-gear.rb +5 -0
  59. data/lib/scout.rb +1 -0
  60. data/lib/workflow-scout.rb +2 -0
  61. data/scout-gear.gemspec +78 -5
  62. data/scout_commands/alias +48 -0
  63. data/scout_commands/find +83 -0
  64. data/scout_commands/glob +0 -0
  65. data/scout_commands/rbbt +23 -0
  66. data/scout_commands/workflow/task +707 -0
  67. data/test/scout/indiferent_hash/test_case_insensitive.rb +16 -0
  68. data/test/scout/indiferent_hash/test_options.rb +11 -1
  69. data/test/scout/misc/test_digest.rb +30 -0
  70. data/test/scout/misc/test_filesystem.rb +30 -0
  71. data/test/scout/misc/test_insist.rb +13 -0
  72. data/test/scout/open/test_lock.rb +52 -0
  73. data/test/scout/open/test_remote.rb +25 -0
  74. data/test/scout/open/test_stream.rb +515 -0
  75. data/test/scout/open/test_util.rb +73 -0
  76. data/test/scout/path/test_find.rb +37 -1
  77. data/test/scout/persist/test_open.rb +37 -0
  78. data/test/scout/persist/test_path.rb +37 -0
  79. data/test/scout/persist/test_serialize.rb +114 -0
  80. data/test/scout/resource/test_path.rb +40 -0
  81. data/test/scout/resource/test_produce.rb +62 -0
  82. data/test/scout/simple_opt/test_get.rb +11 -0
  83. data/test/scout/simple_opt/test_parse.rb +10 -0
  84. data/test/scout/simple_opt/test_setup.rb +77 -0
  85. data/test/scout/test_cmd.rb +85 -0
  86. data/test/scout/test_concurrent_stream.rb +29 -0
  87. data/test/scout/test_misc.rb +0 -7
  88. data/test/scout/test_open.rb +146 -0
  89. data/test/scout/test_path.rb +3 -1
  90. data/test/scout/test_persist.rb +83 -0
  91. data/test/scout/test_resource.rb +26 -0
  92. data/test/scout/test_workflow.rb +87 -0
  93. data/test/scout/workflow/step/test_info.rb +28 -0
  94. data/test/scout/workflow/task/test_inputs.rb +182 -0
  95. data/test/scout/workflow/test_step.rb +36 -0
  96. data/test/scout/workflow/test_task.rb +178 -0
  97. data/test/scout/workflow/test_usage.rb +26 -0
  98. data/test/scout/workflow/test_util.rb +17 -0
  99. data/test/test_helper.rb +17 -0
  100. data/test/test_scout-gear.rb +0 -0
  101. metadata +76 -3
@@ -0,0 +1,259 @@
1
+ require_relative 'indiferent_hash'
2
+
3
+ module AbortedStream
4
+ attr_accessor :exception
5
+ def self.setup(obj, exception = nil)
6
+ obj.extend AbortedStream
7
+ obj.exception = exception
8
+ end
9
+ end
10
+
11
+ module ConcurrentStream
12
+ attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined, :aborted, :autojoin, :lockfile, :no_fail, :pair, :thread, :stream_exception, :log, :std_err
13
+
14
+ def self.setup(stream, options = {}, &block)
15
+
16
+ threads, pids, callback, abort_callback, filename, autojoin, lockfile, no_fail, pair = IndiferentHash.process_options options, :threads, :pids, :callback, :abort_callback, :filename, :autojoin, :lockfile, :no_fail, :pair
17
+ stream.extend ConcurrentStream unless ConcurrentStream === stream
18
+
19
+ stream.threads ||= []
20
+ stream.pids ||= []
21
+ stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
22
+ stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
23
+ stream.autojoin = autojoin unless autojoin.nil?
24
+ stream.no_fail = no_fail unless no_fail.nil?
25
+ stream.std_err = ""
26
+
27
+ stream.pair = pair unless pair.nil?
28
+
29
+ callback = block if block_given?
30
+ if callback
31
+ if stream.callback
32
+ old_callback = stream.callback
33
+ stream.callback = Proc.new do
34
+ old_callback.call
35
+ callback.call
36
+ end
37
+ else
38
+ stream.callback = callback
39
+ end
40
+ end
41
+
42
+ if abort_callback
43
+ if stream.abort_callback
44
+ old_abort_callback = stream.abort_callback
45
+ stream.abort_callback = Proc.new do
46
+ old_abort_callback.call
47
+ abort_callback.call
48
+ end
49
+ else
50
+ stream.abort_callback = abort_callback
51
+ end
52
+ end
53
+
54
+ stream.filename = filename.nil? ? stream.inspect.split(":").last[0..-2] : filename
55
+
56
+ stream.lockfile = lockfile unless lockfile.nil?
57
+
58
+ stream.aborted = false
59
+
60
+ stream
61
+ end
62
+
63
+ def annotate(stream)
64
+ ConcurrentStream.setup(stream, :threads => threads, :pids => pids, :callback => callback, :abort_callback => abort_callback, :filename => filename, :autojoin => autojoin, :lockfile => lockfile)
65
+ stream
66
+ end
67
+
68
+ def clear
69
+ @threads = @pids = @callback = @abort_callback = @joined = nil
70
+ end
71
+
72
+ def joined?
73
+ @joined
74
+ end
75
+
76
+ def aborted?
77
+ @aborted
78
+ end
79
+
80
+ def join_threads
81
+ if @threads
82
+ @threads.each do |t|
83
+ next if t == Thread.current
84
+ begin
85
+ t.join
86
+ if Process::Status === t.value
87
+ if ! (t.value.success? || no_fail)
88
+
89
+ if log
90
+ msg = "Error joining #{self.filename || self.inspect}. Last log line: #{log}"
91
+ else
92
+ msg = "Error joining #{self.filename || self.inspect}"
93
+ end
94
+
95
+ raise ConcurrentStreamProcessFailed.new t.pid, msg, self
96
+ end
97
+ end
98
+ rescue Exception
99
+ if no_fail
100
+ Log.low "Not failing on exception joining thread in ConcurrenStream - #{filename} - #{$!.message}"
101
+ else
102
+ Log.low "Exception joining thread in ConcurrenStream #{Log.fingerprint self} - #{Log.fingerprint t} - #{$!.message}"
103
+ stream_raise_exception $!
104
+ end
105
+ end
106
+ end
107
+ end
108
+ @threads = []
109
+ end
110
+
111
+ def join_pids
112
+ if @pids and @pids.any?
113
+ @pids.each do |pid|
114
+ begin
115
+ Process.waitpid(pid, Process::WUNTRACED)
116
+ stream_raise_exception ConcurrentStreamProcessFailed.new(pid, "Error in waitpid", self) unless $?.success? or no_fail
117
+ rescue Errno::ECHILD
118
+ end
119
+ end
120
+ @pids = []
121
+ end
122
+ end
123
+
124
+ def join_callback
125
+ if @callback and not joined?
126
+ begin
127
+ @callback.call
128
+ ensure
129
+ @callback = nil
130
+ end
131
+ end
132
+ end
133
+
134
+ def join
135
+ begin
136
+ join_threads
137
+ join_pids
138
+ join_callback
139
+ close unless closed?
140
+ ensure
141
+ @joined = true
142
+ lockfile.unlock if lockfile and lockfile.locked?
143
+ raise stream_exception if stream_exception
144
+ end
145
+ end
146
+
147
+ def abort_threads(exception = nil)
148
+ return unless @threads and @threads.any?
149
+ name = Log.fingerprint(Thread.current)
150
+ name += " - file:#{filename}" if filename
151
+ Log.low "Aborting threads (#{name}) - #{@threads.collect{|t| Log.fingerprint(t) } * ", "}"
152
+
153
+ @threads.each do |t|
154
+ next if t == Thread.current
155
+ Log.debug "Aborting thread #{Log.fingerprint(t)} with exception: #{exception}"
156
+ t.raise((exception.nil? ? Aborted.new : exception))
157
+ end
158
+
159
+ @threads.each do |t|
160
+ next if t == Thread.current
161
+ begin
162
+ t.join unless t == Thread.current
163
+ rescue Aborted
164
+ rescue Exception
165
+ Log.debug "Thread (#{name}) exception: #{$!.message}"
166
+ end
167
+ end
168
+ end
169
+
170
+ def abort_pids
171
+ @pids.each do |pid|
172
+ begin
173
+ Log.low "Killing PID #{pid} in ConcurrentStream #{filename}"
174
+ Process.kill :INT, pid
175
+ rescue Errno::ESRCH
176
+ end
177
+ end if @pids
178
+ @pids = []
179
+ end
180
+
181
+ def abort(exception = nil)
182
+ self.stream_exception ||= exception
183
+ if @aborted
184
+ Log.medium "Already aborted stream #{Log.fingerprint self} [#{@aborted}]"
185
+ return
186
+ else
187
+ Log.medium "Aborting stream #{Log.fingerprint self} [#{@aborted}]"
188
+ end
189
+ AbortedStream.setup(self, exception)
190
+ @aborted = true
191
+ begin
192
+ @abort_callback.call exception if @abort_callback
193
+
194
+ abort_threads(exception)
195
+ abort_pids
196
+
197
+ @callback = nil
198
+ @abort_callback = nil
199
+
200
+ if @pair && @pair.respond_to?(:abort) && ! @pair.aborted?
201
+ Log.medium "Aborting pair stream #{Log.fingerprint self}: #{Log.fingerprint @pair }"
202
+ @pair.abort exception
203
+ end
204
+ ensure
205
+ close unless closed?
206
+
207
+ if lockfile and lockfile.locked?
208
+ lockfile.unlock
209
+ end
210
+ end
211
+ end
212
+
213
+ def close(*args)
214
+ if autojoin
215
+ begin
216
+ super(*args)
217
+ rescue
218
+ Log.exception $!
219
+ self.abort
220
+ self.join
221
+ stream_raise_exception $!
222
+ ensure
223
+ self.join if self.closed? or self.eof?
224
+ end
225
+ else
226
+ super(*args)
227
+ end
228
+ end
229
+
230
+ def read(*args)
231
+ begin
232
+ super(*args)
233
+ ensure
234
+ begin
235
+ close unless closed?
236
+ rescue Exception
237
+ raise $! if ConcurrentStreamProcessFailed === $!
238
+ end if autojoin && ! closed? && eof?
239
+ end
240
+ end
241
+
242
+ def add_callback(&block)
243
+ old_callback = callback
244
+ @callback = Proc.new do
245
+ old_callback.call if old_callback
246
+ block.call
247
+ end
248
+ end
249
+
250
+ def stream_raise_exception(exception)
251
+ threads.each do |thread|
252
+ thread.raise exception
253
+ end
254
+ self.stream_exception = exception
255
+
256
+ self.abort
257
+ end
258
+
259
+ end
@@ -13,6 +13,12 @@ end
13
13
 
14
14
  class Aborted < StandardError; end
15
15
 
16
+ class ParameterException < ScoutException; end
17
+ class MissingParameterException < ParameterException
18
+ def initialize(parameter)
19
+ super("Missing parameter '#{parameter}'")
20
+ end
21
+ end
16
22
  class ProcessFailed < StandardError;
17
23
  attr_accessor :pid, :msg
18
24
  def initialize(pid = Process.pid, msg = nil)
@@ -41,7 +47,13 @@ end
41
47
 
42
48
  class OpenURLError < StandardError; end
43
49
 
44
- class DontClose < Exception; end
50
+ class DontClose < Exception
51
+ attr_accessor :payload
52
+ def initialize(payload = nil)
53
+ @payload = payload
54
+ end
55
+ end
56
+
45
57
 
46
58
  class KeepLocked < Exception
47
59
  attr_accessor :payload
@@ -57,13 +69,9 @@ class KeepBar < Exception
57
69
  end
58
70
  end
59
71
 
60
- #class ParameterException < ScoutException; end
72
+ class LockInterrupted < TryAgain; end
73
+
61
74
  #
62
- #class MissingParameterException < ParameterException
63
- # def initialize(parameter)
64
- # super("Missing parameter '#{parameter}'")
65
- # end
66
- #end
67
75
  #class ClosedStream < StandardError; end
68
76
  #class OpenGzipError < StandardError; end
69
77
  #
@@ -76,7 +84,6 @@ end
76
84
  #end
77
85
  #
78
86
  #class SemaphoreInterrupted < TryAgain; end
79
- #class LockInterrupted < TryAgain; end
80
87
  #
81
88
  #class RemoteServerError < StandardError; end
82
89
  #
@@ -1,32 +1,24 @@
1
1
  module IndiferentHash
2
2
  def self.add_defaults(options, defaults = {})
3
- options ||= {}
3
+ options = string2hash options if String === options
4
4
  IndiferentHash.setup(options)
5
- case
6
- when Hash === options
7
- new_options = options.dup
8
- when String === options
9
- new_options = string2hash options
10
- else
11
- raise "Format of '#{options.inspect}' not understood. It should be a hash"
12
- end
5
+
6
+ defaults = string2hash defaults if String === defaults
13
7
 
14
8
  defaults.each do |key, value|
15
9
  next if options.include? key
16
10
 
17
- new_options[key] = value
11
+ options[key] = value
18
12
  end
19
13
 
20
- new_options
21
-
22
- options.replace new_options
14
+ options
23
15
  end
24
16
 
25
17
  def self.process_options(hash, *keys)
26
18
  IndiferentHash.setup(hash)
27
19
 
28
20
  defaults = keys.pop if Hash === keys.last
29
- hahs = IndiferentHash.add_defaults hash, defaults if defaults
21
+ hash = IndiferentHash.add_defaults hash, defaults if defaults
30
22
 
31
23
  if keys.length == 1
32
24
  hash.include?(keys.first.to_sym) ? hash.delete(keys.first.to_sym) : hash.delete(keys.first.to_s)
@@ -102,7 +94,7 @@ module IndiferentHash
102
94
  options = {}
103
95
 
104
96
  string.split('#').each do |str|
105
- key, sep, value = str.partition "="
97
+ key, _, value = str.partition "="
106
98
 
107
99
  key = key[1..-1].to_sym if key[0] == ":"
108
100
 
@@ -114,17 +106,7 @@ module IndiferentHash
114
106
  options[key] = value.to_f and next if value =~ /^\d*\.\d+$/
115
107
  options[key] = true and next if value == "true"
116
108
  options[key] = false and next if value == "false"
117
- options[key] = value and next
118
-
119
- options[key] = begin
120
- saved_safe = $SAFE
121
- $SAFE = 0
122
- eval(value)
123
- rescue Exception
124
- value
125
- ensure
126
- $SAFE = saved_safe
127
- end
109
+ options[key] = value
128
110
  end
129
111
 
130
112
  IndiferentHash.setup(options)
@@ -75,33 +75,3 @@ module IndiferentHash
75
75
  end
76
76
  end
77
77
 
78
- module CaseInsensitiveHash
79
-
80
- def self.setup(hash)
81
- hash.extend CaseInsensitiveHash
82
- end
83
-
84
- def downcase_keys
85
- @downcase_keys ||= begin
86
- down = {}
87
- keys.collect{|key|
88
- down[key.to_s.downcase] = key
89
- }
90
- down
91
- end
92
- end
93
-
94
- def [](key, *rest)
95
- value = super(key, *rest)
96
- return value unless value.nil?
97
- key_downcase = key.to_s.downcase
98
- super(downcase_keys[key_downcase])
99
- end
100
-
101
- def values_at(*keys)
102
- keys.collect do |key|
103
- self[key]
104
- end
105
- end
106
-
107
- end
@@ -63,7 +63,7 @@ module Colorize
63
63
  if percent
64
64
  array = array.collect{|v| n = v.to_f; n = n > 100 ? 100 : n; n < 0.001 ? 0.001 : n}
65
65
  else
66
- array = array.collect{|v| n = v.to_f; }
66
+ array = array.collect{|v| v.to_f }
67
67
  end
68
68
  max = array.max
69
69
  min = array.min
@@ -103,7 +103,7 @@ module Colorize
103
103
 
104
104
  value_color = Hash[*array.uniq.zip(all_colors).flatten]
105
105
 
106
- value_color.values_at *array
106
+ value_color.values_at(*array)
107
107
  end
108
108
 
109
109
  def self.tsv(tsv, options = {})
@@ -19,8 +19,12 @@ module Log
19
19
  else
20
20
  "'" << obj << "'"
21
21
  end
22
+ when ConcurrentStream
23
+ name = obj.inspect + " " + obj.object_id.to_s
24
+ name += " #{obj.filename}" if obj.filename
25
+ name
22
26
  when IO
23
- (obj.respond_to?(:filename) and obj.filename ) ? "<IO:" + (obj.filename || obj.inspect + rand(100000)) + ">" : obj.inspect
27
+ (obj.respond_to?(:filename) and obj.filename ) ? "<IO:" + (obj.filename || obj.inspect + rand(100000)) + ">" : obj.inspect + " " + obj.object_id.to_s
24
28
  when File
25
29
  "<File:" + obj.path + ">"
26
30
  when Array
@@ -52,6 +56,12 @@ module Log
52
56
  else
53
57
  "%.6f" % obj
54
58
  end
59
+ when Thread
60
+ if obj["name"]
61
+ obj["name"]
62
+ else
63
+ obj.inspect
64
+ end
55
65
  else
56
66
  obj.to_s
57
67
  end
@@ -169,7 +169,6 @@ module Log
169
169
  bar = bars.sort_by{|b| b.depth }.first
170
170
  print(io, Log.color(:magenta ,bar.report_msg) << "\n")
171
171
  else
172
- length = Log::ProgressBar.cleanup_bars
173
172
  print(io, Log.color(:magenta, "···Progress\n"))
174
173
  bars.sort_by{|b| b.depth }.reverse.each do |bar|
175
174
  if SILENCED.include? bar
@@ -91,7 +91,7 @@ module Log
91
91
  error = true
92
92
  raise $!
93
93
  ensure
94
- remove_bar(bar, error) if bar
94
+ remove_bar(bar, error) if bar && ! keep
95
95
  end
96
96
  end
97
97
  end
@@ -17,12 +17,12 @@ module Log
17
17
  attr_accessor :default_file
18
18
  end
19
19
 
20
- attr_accessor :max, :ticks, :frequency, :depth, :desc, :file, :bytes, :process, :callback
20
+ attr_accessor :max, :ticks, :frequency, :depth, :desc, :file, :bytes, :process, :callback, :severity
21
21
 
22
22
  def initialize(max = nil, options = {})
23
- depth, num_reports, desc, io, severity, file, bytes, frequency, process, callback =
24
- IndiferentHash.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes, :frequency, :process, :callback,
25
- :depth => 0, :num_reports => 100, :io => STDERR, :severity => Log.severity, :frequency => 2
23
+ depth, desc, file, bytes, frequency, process, callback =
24
+ IndiferentHash.process_options options, :depth, :desc, :file, :bytes, :frequency, :process, :callback,
25
+ :depth => 0, :frequency => 2
26
26
 
27
27
  @max = max
28
28
  @ticks = 0
data/lib/scout/log.rb CHANGED
@@ -14,8 +14,8 @@ module Log
14
14
  end
15
15
 
16
16
  class << self
17
- attr_accessor :logfile, :severity
18
- attr_writer :tty_size
17
+ attr_accessor :severity
18
+ attr_writer :tty_size, :logfile
19
19
  end
20
20
 
21
21
 
@@ -360,3 +360,11 @@ def eef(obj=nil, file = $stdout)
360
360
  Log.log_obj_fingerprint(obj, :error, file)
361
361
  end
362
362
 
363
+ def sss(level, &block)
364
+ if block_given?
365
+ Log.with_severity level, &block
366
+ else
367
+ Log.severity = level
368
+ end
369
+ end
370
+
@@ -11,7 +11,13 @@ module MetaExtension
11
11
  end
12
12
  end
13
13
 
14
- meta.define_method(:setup) do |obj,*rest|
14
+ meta.define_method(:setup) do |*args,&block|
15
+ if block_given?
16
+ obj, rest = block, args
17
+ else
18
+ obj, *rest = args
19
+ end
20
+ obj = block if obj.nil?
15
21
  obj.extend base
16
22
  attrs = self.class_variable_get("@@extension_attrs")
17
23
 
@@ -33,6 +39,14 @@ module MetaExtension
33
39
  obj
34
40
  end
35
41
 
42
+ base.define_method(:extension_attr_hash) do
43
+ attr_hash = {}
44
+ meta.class_variable_get("@@extension_attrs").each do |name|
45
+ attr_hash[name] = self.instance_variable_get("@#{name}")
46
+ end
47
+ attr_hash
48
+ end
49
+
36
50
  base.define_method(:annotate) do |other|
37
51
  attr_values = meta.class_variable_get("@@extension_attrs").collect do |a|
38
52
  self.instance_variable_get("@#{a}")
@@ -0,0 +1,56 @@
1
+ module Misc
2
+ def self.digest_str(obj)
3
+ if obj.respond_to?(:digest_str)
4
+ obj.digest_str
5
+ else
6
+ case obj
7
+ when String
8
+ #'\'' << obj << '\''
9
+ if Path === obj || ! Open.exists?(obj)
10
+ '\'' << obj << '\''
11
+ else
12
+ Misc.file_md5(obj)
13
+ end
14
+ when Integer, Symbol
15
+ obj.to_s
16
+ when Array
17
+ '[' << obj.inject(""){|acc,o| acc.empty? ? Misc.digest_str(o) : acc << ', ' << Misc.digest_str(o) } << ']'
18
+ when Hash
19
+ '{' << obj.inject(""){|acc,p| s = Misc.digest_str(p.first) << "=" << Misc.digest_str(p.last); acc.empty? ? s : acc << ', ' << s } << '}'
20
+ when Integer
21
+ obj.to_s
22
+ when Float
23
+ if obj % 1 == 0
24
+ obj.to_i
25
+ elsif obj.abs > 10
26
+ "%.1f" % obj
27
+ elsif obj.abs > 1
28
+ "%.3f" % obj
29
+ else
30
+ "%.6f" % obj
31
+ end
32
+ when TrueClass
33
+ "true"
34
+ when FalseClass
35
+ "false"
36
+ else
37
+ obj.inspect
38
+ end
39
+ end
40
+ end
41
+
42
+ def self.digest(obj)
43
+ str = Misc.digest_str(obj)
44
+ hash = Digest::MD5.hexdigest(str)
45
+ Log.debug "Digest #{hash} - #{str}"
46
+ hash
47
+ end
48
+
49
+ def self.file_md5(file)
50
+ file = file.find if Path === file
51
+ #md5file = file + '.md5'
52
+ Persist.persist("MD5:#{file}", :string) do
53
+ Digest::MD5.file(file).hexdigest
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,26 @@
1
+ module Misc
2
+ def self.in_dir(dir)
3
+ old_pwd = FileUtils.pwd
4
+ begin
5
+ FileUtils.mkdir_p dir unless File.exist?(dir)
6
+ FileUtils.cd dir
7
+ yield
8
+ ensure
9
+ FileUtils.cd old_pwd
10
+ end
11
+ end
12
+
13
+ def self.path_relative_to(basedir, path)
14
+ path = File.expand_path(path) unless path.slice(0,1) == "/"
15
+ basedir = File.expand_path(basedir) unless basedir.slice(0,1) == "/"
16
+
17
+ basedir += "/" unless basedir.slice(-2,-1) == "/"
18
+
19
+ if path.index(basedir) == 0
20
+ return path[basedir.length..-1]
21
+ else
22
+ return nil
23
+ end
24
+ end
25
+
26
+ end