Module: ASUtils
- Defined in:
- common/asutils.rb
Overview
Some basic helpers that are used in all parts of the application, both
development and packaged.
Note: ASUtils gets pulled in all over the place, and in some places prior to
any gems having been loaded. Be careful about loading gems here, as the gem
path might not yet be configured. For example, loading the ‘json’ gem can
cause you to pull in the version that ships with JRuby, rather than the one in
your Gemfile.
Defined Under Namespace
Classes: PluginDependency
Class Method Summary
collapse
Class Method Details
.as_array(thing) ⇒ Object
25
26
27
28
|
# File 'common/asutils.rb', line 25
def self.as_array(thing)
return [] if thing.nil?
thing.is_a?(Array) ? thing : [thing]
end
|
.blank?(obj) ⇒ Boolean
315
316
317
318
319
320
321
322
323
|
# File 'common/asutils.rb', line 315
def self.blank?(obj)
if obj.nil?
true
elsif obj.respond_to?(:empty?)
!!obj.empty?
else
!obj
end
end
|
.deep_merge(hash1, hash2) ⇒ Object
Recursively overlays hash2 onto hash 1
176
177
178
179
180
181
182
183
184
185
186
|
# File 'common/asutils.rb', line 176
def self.deep_merge(hash1, hash2)
target = hash1.dup
hash2.each_key do |key|
if hash2[key].is_a?(Hash) && hash1[key].is_a?(Hash)
target[key] = self.deep_merge(target[key], hash2[key])
next
end
target[key] = hash2[key]
end
target
end
|
.deep_merge_concat(hash1, hash2) ⇒ Object
Recursively concatenates hash2 onto hash 1
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
# File 'common/asutils.rb', line 189
def self.deep_merge_concat(hash1, hash2)
target = hash1.dup
hash2.keys.each do |key|
if hash2[key].is_a? Hash and hash1[key].is_a? Hash
target[key] = self.deep_merge_concat(target[key], hash2[key])
next
end
if hash2[key].is_a? Array and hash1[key].is_a? Array
if hash1[key] === []
target[key] = hash2[key]
elsif hash2[key] === []
target[key] = target[key]
else
target_array = []
target[key].zip(hash2[key]).each do |target_a, hash2_a|
if target_a.nil?
target_array << hash2_a
elsif hash2_a.nil?
target_array << target_a
else
target_array << self.deep_merge_concat(target_a, hash2_a)
end
end
target[key] = target_array
end
next
end
if hash1[key] === true and key != "is_display_name" and key != "authorized"
hash1[key] = "true"
elsif hash1[key] === false and key != "is_display_name" and key != "authorized"
hash1[key] = "false"
end
if hash2[key] === true and key != "is_display_name" and key != "authorized"
hash2[key] = "1"
elsif hash2[key] === false and key != "is_display_name" and key != "authorized"
hash2[key] = "0"
end
if hash1[key].is_a? String
if hash1[key] == hash2[key]
target[key] = hash2[key]
else
if key == "jsonmodel_type" and hash1[key].include?("note") and hash2[key].include?("note")
raise "Required Note Types must not conflict with Default Note Types"
elsif key == "jsonmodel_type" and hash1[key].include?("relationship") and hash2[key].include?("relationship")
raise "Required Relationship Types must not conflict with Default Relationship Types"
else
target[key] = hash1[key] + '_' + hash2[key]
end
end
else
target[key] = hash2[key]
end
end
target
end
|
.diagnostic_trace_msg(filename) ⇒ Object
148
149
150
|
# File 'common/asutils.rb', line 148
def self.diagnostic_trace_msg(filename)
" \#{'=' * 72}\n A trace file has been written to the following location: \#{filename}\n\n This file contains information that will assist developers in diagnosing\n problems with your ArchivesSpace installation. Please review the file's\n contents for sensitive information (such as passwords) that you might not\n want to share.\n \#{'=' * 72}\n"
end
|
.dump_diagnostics(exception = nil) ⇒ Object
162
163
164
165
166
167
168
169
170
171
172
173
|
# File 'common/asutils.rb', line 162
def self.dump_diagnostics(exception = nil)
unless defined?(JSON)
require 'json'
end
diagnostics = get_diagnostics(exception)
tmp = File.join(Dir.tmpdir, "aspace_diagnostic_#{Time.now.to_i}.txt")
File.open(tmp, 'w') { |fh| fh.write(JSON.pretty_generate(diagnostics)) }
$stderr.puts diagnostic_trace_msg(tmp)
raise exception if exception
end
|
126
127
128
129
130
131
132
133
134
|
# File 'common/asutils.rb', line 126
def self.(coll)
if coll.is_a?(Hash)
coll.values.map { |v| self.(v) }.flatten.compact
elsif coll.is_a?(Array)
coll.map { |v| self.(v) }.flatten.compact
else
coll
end
end
|
.find_base_directory(root = nil) ⇒ Object
89
90
91
92
93
94
95
96
97
98
|
# File 'common/asutils.rb', line 89
def self.find_base_directory(root = nil)
res = [java.lang.System.get_property('ASPACE_LAUNCHER_BASE'),
java.lang.System.get_property('catalina.base'),
fixed_jruby_path(root)]
.find { |dir| dir && Dir.exist?(dir) }
res
end
|
.find_local_directories(base = nil, *plugins) ⇒ Object
113
114
115
116
117
118
119
120
|
# File 'common/asutils.rb', line 113
def self.find_local_directories(base = nil, *plugins)
plugins = AppConfig[:plugins] if plugins.empty?
base_directory = self.plugin_base_directory
Array(plugins).map do |plugin|
File.join(*[base_directory, plugin, base].compact)
end
end
|
.find_locales_directories(base = nil) ⇒ Object
122
123
124
|
# File 'common/asutils.rb', line 122
def self.find_locales_directories(base = nil)
[File.join(*[self.find_base_directory('common'), 'locales', base].compact)]
end
|
.fixed_jruby_path(root = nil) ⇒ Object
80
81
82
83
84
85
86
87
|
# File 'common/asutils.rb', line 80
def self.fixed_jruby_path(root = nil)
this_dir = __dir__.gsub(%r{uri:classloader:(\/)?}, '')
this_dir = this_dir.length.zero? ? '.' : this_dir
[
File.join(*[this_dir, '..', root].compact),
File.join(*[File.realpath(this_dir), '..', root].compact)
].find { |dir| dir && Dir.exist?(dir) }
end
|
.get_diagnostics(exception = nil) ⇒ Object
136
137
138
139
140
141
142
143
144
145
146
|
# File 'common/asutils.rb', line 136
def self.get_diagnostics(exception = nil)
runtime = java.lang.Runtime.getRuntime
{
version: ASConstants.VERSION,
appconfig: defined?(AppConfig) ? AppConfig.dump_sanitized : 'not loaded',
memory: { free: runtime.freeMemory, max: runtime.maxMemory,
total: runtime.totalMemory },
cpu_count: runtime.availableProcessors,
exception: exception && { msg: exception, backtrace: exception.backtrace }
}
end
|
.json_parse(s) ⇒ Object
44
45
46
|
# File 'common/asutils.rb', line 44
def self.json_parse(s)
JSON.parse(s, max_nesting: false, create_additions: false)
end
|
.jsonmodels_to_hashes(elt) ⇒ Object
30
31
32
33
34
35
36
37
38
39
40
41
42
|
# File 'common/asutils.rb', line 30
def self.jsonmodels_to_hashes(elt)
if elt.is_a?(JSONModelType)
elt = elt.to_hash(:raw)
end
if elt.is_a?(Hash)
Hash[elt.map { |k, v| [k, self.jsonmodels_to_hashes(v)] }]
elsif elt.is_a?(Array)
elt.map { |v| self.jsonmodels_to_hashes(v) }
else
elt
end
end
|
.keys_as_strings(hash) ⇒ Object
15
16
17
18
19
20
21
22
23
|
# File 'common/asutils.rb', line 15
def self.keys_as_strings(hash)
result = {}
hash.each do |key, value|
result[key.to_s] = value.is_a?(Date) ? value.to_s : value
end
result
end
|
.load_plugin_dependencies ⇒ Object
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
|
# File 'common/asutils.rb', line 332
def self.load_plugin_dependencies
require 'yaml'
result = {}
ASUtils.find_local_directories('config.yml').each do |f|
next unless File.exist?(f)
config = YAML.load_file(f)
plugin_name = File.basename(File.dirname(f))
result[plugin_name] = PluginDependency.new(config.fetch('depends_on_plugins', []),
config.fetch('recommends_plugins', []))
end
all_plugins = ASUtils.wrap(AppConfig[:plugins])
all_plugins.each do |plugin|
result[plugin] ||= PluginDependency.new([], [])
end
all_plugins.each do |plugin|
plugin_deps = result.fetch(plugin)
unless (plugin_deps.depends_on - all_plugins).empty?
raise "Plugin #{plugin} is missing dependency plugin(s): #{(plugin_deps.depends_on - all_plugins).join(', ')}"
end
unless (plugin_deps.recommends - all_plugins).empty?
$stderr.puts("INFO: Plugin #{plugin} recommends additional plugin(s): #{(plugin_deps.recommends - all_plugins).join(', ')}")
end
end
result
end
|
.load_plugin_gems(context) ⇒ Object
246
247
248
249
250
251
252
253
254
|
# File 'common/asutils.rb', line 246
def self.load_plugin_gems(context)
ASUtils.find_local_directories.each do |plugin|
gemfile = File.join(plugin, 'Gemfile')
if File.exist?(gemfile)
context.instance_eval(File.read(gemfile), gemfile, 1)
end
end
end
|
.load_pry_aliases ⇒ Object
424
425
426
427
428
429
430
431
|
# File 'common/asutils.rb', line 424
def self.load_pry_aliases
if defined?(PryDebuggerJRuby)
Pry.commands.alias_command 'c', 'continue'
Pry.commands.alias_command 's', 'step'
Pry.commands.alias_command 'n', 'next'
Pry.commands.alias_command 'f', 'finish'
end
end
|
.order_plugins(plugin_dirs) ⇒ Object
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
|
# File 'common/asutils.rb', line 376
def self.order_plugins(plugin_dirs)
all_plugins = ASUtils.wrap(AppConfig[:plugins])
all_deps = self.load_plugin_dependencies
to_process = all_plugins.clone
ordered_plugins = []
while !to_process.empty?
next_plugins = to_process.select {|plugin|
plugin_deps = all_deps.fetch(plugin)
((plugin_deps.depends_on + plugin_deps.recommends) - ordered_plugins).empty?
}
if next_plugins.empty?
next_plugins = to_process.select {|plugin|
plugin_deps = all_deps.fetch(plugin)
(plugin_deps.depends_on - ordered_plugins).empty?
}
end
if next_plugins.empty?
raise "Plugin dependency cycle detected among the following plugins: #{to_process.join(', ')}"
end
ordered_plugins.concat(next_plugins)
to_process -= next_plugins
end
plugin_base_dir = File.join(File.absolute_path(self.plugin_base_directory),
"")
plugin_dirs.map {|f| File.absolute_path(f)}.sort_by {|plugin_dir|
unless plugin_dir.start_with?(plugin_base_dir)
raise "Assertion failure: Unexpected plugin dir: '#{plugin_dir}' was expected to begin with '#{plugin_base_dir}'"
end
plugin_name = (plugin_dir.gsub(plugin_base_dir, "")).split(File::SEPARATOR).find {|segment| segment != '.'}
ordered_plugins.index(plugin_name) or raise "Expected to find #{plugin_name} but didn't!"
}
end
|
.plugin_base_directory ⇒ Object
100
101
102
103
104
105
106
107
108
109
110
111
|
# File 'common/asutils.rb', line 100
def self.plugin_base_directory
if AppConfig.changed?(:plugins_directory)
File.absolute_path(AppConfig[:plugins_directory], self.find_base_directory)
else
File.join( *[ self.find_base_directory, 'plugins'])
end
end
|
.present?(obj) ⇒ Boolean
325
326
327
|
# File 'common/asutils.rb', line 325
def self.present?(obj)
!blank?(obj)
end
|
.recursive_reject_key(obj, &block) ⇒ Object
recursively walk obj
and remove any hash entry whose key returns true
for block.call(key)
.
obj
can be an arbitrarily nested combination of array-like and hash-like
things.
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
# File 'common/asutils.rb', line 297
def self.recursive_reject_key(obj, &block)
if obj.nil? || block.nil?
obj
elsif obj.respond_to?(:each_pair)
result = {}
obj.each_pair do |k, v|
if !block.call(k)
result[k] = recursive_reject_key(v, &block)
end
end
result
elsif obj.respond_to?(:map)
obj.map { |elt| recursive_reject_key(elt, &block) }
else
obj
end
end
|
.search_nested(elt, keys, ignore_keys = [], &block) ⇒ Object
Recursively find any hash entry whose key is in keys
. When we find a
match, call block
with the key and value as arguments.
Skips descending into any hash entry whose key is in ignore_keys
(allowing
us to avoid walking ‘_resolved’ subtrees, for example)
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
|
# File 'common/asutils.rb', line 272
def self.search_nested(elt, keys, ignore_keys = [], &block)
if elt.respond_to?(:key?)
keys.each do |key|
if elt.key?(key)
block.call(key, elt.fetch(key))
end
end
elt.each.each do |next_key, value|
unless ignore_keys.include?(next_key)
search_nested(value, keys, ignore_keys, &block)
end
end
elsif elt.respond_to?(:each)
elt.each do |value|
search_nested(value, keys, ignore_keys, &block)
end
end
end
|
.tempfile(base) ⇒ Object
A bit funny to wrap this ourselves, but there’s an interesting case when
running under rspec.
Rspec reseeds the random number generator at the beginning of every suite
run, which means that Tempfile’s “random” filenames are often IDENTICAL
between subsequent Tempfile invocations across test runs.
This shouldn’t really matter, except when this happens:
-
Test1 runs and produces tempfile “somerandomfile”, which gets closed and
unlinked.
-
Test2 runs and gets given “somerandomfile” too. It starts working with it.
-
Then, bam! Garbage collection runs, and finalizes the object from Test1.
This unlinks the underlying temp file while Test2 is still using it!
So yeah, not cool. We try to inject a little randomness into “base” to
avoid these sort of shenanigans, even though it really shouldn’t matter in
production.
68
69
70
|
# File 'common/asutils.rb', line 68
def self.tempfile(base)
Tempfile.new("#{base}_#{java.lang.System.currentTimeMillis}")
end
|
.to_json(obj, opts = {}) ⇒ Object
72
73
74
75
76
77
78
|
# File 'common/asutils.rb', line 72
def self.to_json(obj, opts = {})
if obj.respond_to?(:jsonize)
obj.jsonize(opts.merge(max_nesting: false))
else
obj.to_json(opts.merge(max_nesting: false))
end
end
|
.wrap(object) ⇒ Object
Borrowed from:activesupport/lib/active_support/core_ext/array/wrap.rb:36
257
258
259
260
261
262
263
264
265
|
# File 'common/asutils.rb', line 257
def self.wrap(object)
if object.nil?
[]
elsif object.respond_to?(:to_ary)
object.to_ary || [object]
else
[object]
end
end
|