moab-versioning 4.2.1 → 4.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +5 -5
  2. data/lib/moab.rb +3 -2
  3. data/lib/moab/bagger.rb +25 -20
  4. data/lib/moab/config.rb +39 -8
  5. data/lib/moab/deposit_bag_validator.rb +22 -17
  6. data/lib/moab/exceptions.rb +10 -8
  7. data/lib/moab/file_group.rb +23 -22
  8. data/lib/moab/file_group_difference.rb +35 -35
  9. data/lib/moab/file_group_difference_subset.rb +5 -5
  10. data/lib/moab/file_instance.rb +4 -3
  11. data/lib/moab/file_instance_difference.rb +5 -5
  12. data/lib/moab/file_inventory.rb +25 -31
  13. data/lib/moab/file_inventory_difference.rb +11 -11
  14. data/lib/moab/file_manifestation.rb +8 -7
  15. data/lib/moab/file_signature.rb +35 -41
  16. data/lib/moab/signature_catalog.rb +19 -21
  17. data/lib/moab/signature_catalog_entry.rb +5 -5
  18. data/lib/moab/stanford.rb +2 -0
  19. data/lib/moab/storage_object.rb +23 -24
  20. data/lib/moab/storage_object_validator.rb +44 -16
  21. data/lib/moab/storage_object_version.rb +45 -40
  22. data/lib/moab/storage_repository.rb +59 -24
  23. data/lib/moab/storage_services.rb +17 -10
  24. data/lib/moab/utc_time.rb +3 -3
  25. data/lib/moab/verification_result.rb +3 -4
  26. data/lib/moab/version_metadata.rb +4 -4
  27. data/lib/moab/version_metadata_entry.rb +6 -6
  28. data/lib/moab/version_metadata_event.rb +1 -1
  29. data/lib/serializer.rb +2 -0
  30. data/lib/serializer/manifest.rb +9 -7
  31. data/lib/serializer/serializable.rb +41 -35
  32. data/lib/stanford/active_fedora_object.rb +1 -1
  33. data/lib/stanford/content_inventory.rb +40 -34
  34. data/lib/stanford/dor_metadata.rb +4 -3
  35. data/lib/stanford/moab_storage_directory.rb +4 -2
  36. data/lib/stanford/storage_object_validator.rb +1 -1
  37. data/lib/stanford/storage_repository.rb +9 -6
  38. data/lib/stanford/storage_services.rb +6 -6
  39. metadata +23 -38
@@ -1,16 +1,17 @@
1
- require 'moab'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'set'
3
4
 
4
5
  module Moab
5
6
  # Given a druid path, are the contents actually a well-formed Moab?
6
7
  # Shameless green: repetitious code included.
7
8
  class StorageObjectValidator
8
- METADATA_DIR = "metadata".freeze
9
- CONTENT_DIR = "content".freeze
9
+ METADATA_DIR = "metadata"
10
+ CONTENT_DIR = "content"
10
11
  EXPECTED_DATA_SUB_DIRS = [CONTENT_DIR, METADATA_DIR].freeze
11
12
  IMPLICIT_DIRS = ['.', '..'].freeze # unlike Find.find, Dir.entries returns the current/parent dirs
12
- DATA_DIR = "data".freeze
13
- MANIFESTS_DIR = 'manifests'.freeze
13
+ DATA_DIR = "data"
14
+ MANIFESTS_DIR = 'manifests'
14
15
  EXPECTED_VERSION_SUB_DIRS = [DATA_DIR, MANIFESTS_DIR].freeze
15
16
  MANIFEST_INVENTORY_PATH = File.join(MANIFESTS_DIR, "manifestInventory.xml").freeze
16
17
  SIGNATURE_CATALOG_PATH = File.join(MANIFESTS_DIR, "signatureCatalog.xml").freeze
@@ -59,11 +60,11 @@ module Moab
59
60
  NO_SIGNATURE_CATALOG => "Version %{addl}: Missing signatureCatalog.xml",
60
61
  NO_MANIFEST_INVENTORY => "Version %{addl}: Missing manifestInventory.xml",
61
62
  NO_FILES_IN_MANIFEST_DIR => "Version %{addl}: No files present in manifest dir",
62
- METADATA_SUB_DIRS_DETECTED => "Version %{addl}: metadata directory should only contain files, not directories",
63
+ METADATA_SUB_DIRS_DETECTED => "Version %{version}: metadata directory should only contain files, not directories. Found directory: %{dir}",
63
64
  VERSIONS_NOT_IN_ORDER => "Should contain only sequential version directories. Current directories: %{addl}",
64
65
  NO_FILES_IN_METADATA_DIR => "Version %{addl}: No files present in metadata dir",
65
66
  NO_FILES_IN_CONTENT_DIR => "Version %{addl}: No files present in content dir",
66
- CONTENT_SUB_DIRS_DETECTED => "Version %{addl}: content directory should only contain files, not directories",
67
+ CONTENT_SUB_DIRS_DETECTED => "Version %{version}: content directory should only contain files, not directories. Found directory: %{dir}",
67
68
  BAD_SUB_DIR_IN_CONTENT_DIR => "Version %{addl}: content directory has forbidden sub-directory name: vnnnn or #{FORBIDDEN_CONTENT_SUB_DIRS}"
68
69
  }.freeze
69
70
  end
@@ -84,13 +85,14 @@ module Moab
84
85
  end
85
86
 
86
87
  def version_dir_format?(dirname)
87
- dirname =~ /^[v]\d{4}$/
88
+ dirname =~ /^v\d{4}$/
88
89
  end
89
90
 
90
91
  # call only if the version directories are "correctly named" vdddd
91
92
  def check_sequential_version_dirs
92
93
  version_directories.each_with_index do |dir_name, index|
93
- next if dir_name[1..-1].to_i == index + 1 # version numbering starts at 1, array indexing at 0
94
+ next if dir_name[1..].to_i == index + 1 # version numbering starts at 1, array indexing at 0
95
+
94
96
  return [result_hash(VERSIONS_NOT_IN_ORDER, version_directories)]
95
97
  end
96
98
  []
@@ -114,6 +116,7 @@ module Moab
114
116
  return expected_version_sub_dirs(version_path, version) if count == EXPECTED_VERSION_SUB_DIRS.size
115
117
  return found_unexpected(version_sub_dirs, version, EXPECTED_VERSION_SUB_DIRS) if count > EXPECTED_VERSION_SUB_DIRS.size
116
118
  return missing_dir(version_sub_dirs, version, EXPECTED_VERSION_SUB_DIRS) if count < EXPECTED_VERSION_SUB_DIRS.size
119
+
117
120
  []
118
121
  end
119
122
 
@@ -123,15 +126,20 @@ module Moab
123
126
  data_sub_dirs = directory_entries(data_dir_path)
124
127
  errors.concat check_data_sub_dirs(version, data_sub_dirs)
125
128
  errors.concat check_metadata_dir_files_only(version_path) if errors.empty?
126
- errors.concat check_optional_content_dir(version_path, allow_content_subdirs) if data_sub_dirs.include?('content') && errors.empty?
129
+ if data_sub_dirs.include?('content') && errors.empty?
130
+ errors.concat check_optional_content_dir(version_path, allow_content_subdirs)
131
+ end
127
132
  errors
128
133
  end
129
134
 
130
135
  def check_data_sub_dirs(version, data_sub_dirs)
131
136
  return found_unexpected(data_sub_dirs, version, EXPECTED_DATA_SUB_DIRS) if data_sub_dirs.size > EXPECTED_DATA_SUB_DIRS.size
137
+
132
138
  errors = []
133
139
  errors.concat missing_dir(data_sub_dirs, version, [METADATA_DIR]) unless data_sub_dirs.include?(METADATA_DIR)
134
- errors.concat found_unexpected(data_sub_dirs, version, EXPECTED_DATA_SUB_DIRS) unless data_sub_dirs.to_set.subset?(EXPECTED_DATA_SUB_DIRS.to_set)
140
+ unless data_sub_dirs.to_set.subset?(EXPECTED_DATA_SUB_DIRS.to_set)
141
+ errors.concat found_unexpected(data_sub_dirs, version, EXPECTED_DATA_SUB_DIRS)
142
+ end
135
143
  errors
136
144
  end
137
145
 
@@ -139,7 +147,10 @@ module Moab
139
147
  errors = []
140
148
  content_dir_path = File.join(version_path, DATA_DIR, CONTENT_DIR)
141
149
  errors << result_hash(NO_FILES_IN_CONTENT_DIR, basename(version_path)) if directory_entries(content_dir_path).empty?
142
- errors << result_hash(CONTENT_SUB_DIRS_DETECTED, basename(version_path)) if contains_sub_dir?(content_dir_path) && !allow_content_subdirs
150
+ content_sub_dir = contains_sub_dir?(content_dir_path)
151
+ if content_sub_dir && !allow_content_subdirs
152
+ errors << result_hash(CONTENT_SUB_DIRS_DETECTED, version: basename(version_path), dir: content_sub_dir)
153
+ end
143
154
  if allow_content_subdirs && contains_sub_dir?(content_dir_path) && contains_forbidden_content_sub_dir?(content_dir_path)
144
155
  errors << result_hash(BAD_SUB_DIR_IN_CONTENT_DIR, basename(version_path))
145
156
  end
@@ -158,7 +169,10 @@ module Moab
158
169
  errors = []
159
170
  metadata_dir_path = File.join(version_path, DATA_DIR, METADATA_DIR)
160
171
  errors << result_hash(NO_FILES_IN_METADATA_DIR, basename(version_path)) if directory_entries(metadata_dir_path).empty?
161
- errors << result_hash(METADATA_SUB_DIRS_DETECTED, basename(version_path)) if contains_sub_dir?(metadata_dir_path)
172
+ metadata_sub_dir = contains_sub_dir?(metadata_dir_path)
173
+ if metadata_sub_dir
174
+ errors << result_hash(METADATA_SUB_DIRS_DETECTED, version: basename(version_path), dir: metadata_sub_dir)
175
+ end
162
176
  errors
163
177
  end
164
178
 
@@ -204,16 +218,30 @@ module Moab
204
218
  path.split(File::SEPARATOR)[-1]
205
219
  end
206
220
 
207
- def result_hash(response_code, addl = nil)
208
- { response_code => error_code_msg(response_code, addl) }
221
+ # @param [Integer] response_code one of the recognized values in error_code_to_messages
222
+ # @param [Hash<Symbol => String>, String] msg_args Value(s) folded into the error message
223
+ # @return [Hash<Integer => String>] single key/value Hash
224
+ # @example Usage
225
+ # sov.result_hash(10, '/some/dir')
226
+ # sov.result_hash(10, addl: '/some/dir') # equivalent
227
+ # sov.result_hash(8, version: '3', dir: '/other/dir')
228
+ def result_hash(response_code, msg_args = nil)
229
+ { response_code => error_code_msg(response_code, msg_args) }
209
230
  end
210
231
 
211
232
  def error_code_msg(response_code, addl = nil)
212
- format(self.class.error_code_to_messages[response_code], addl: addl)
233
+ arg_hash = {}
234
+ if addl.is_a?(Hash)
235
+ arg_hash.merge!(addl)
236
+ else
237
+ arg_hash[:addl] = addl
238
+ end
239
+ self.class.error_code_to_messages[response_code] % arg_hash
213
240
  end
214
241
 
215
242
  def check_required_manifest_files(dir, version)
216
243
  return [result_hash(NO_FILES_IN_MANIFEST_DIR, version)] unless contains_file?(File.join(dir, MANIFESTS_DIR))
244
+
217
245
  errors = []
218
246
  errors << result_hash(NO_MANIFEST_INVENTORY, version) unless File.exist?(File.join(dir, MANIFEST_INVENTORY_PATH))
219
247
  errors << result_hash(NO_SIGNATURE_CATALOG, version) unless File.exist?(File.join(dir, SIGNATURE_CATALOG_PATH))
@@ -1,4 +1,4 @@
1
- require 'moab'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Moab
4
4
  # A class to represent a version subdirectory within an object's home directory in preservation storage
@@ -32,20 +32,20 @@ module Moab
32
32
  def initialize(storage_object, version_id)
33
33
  if version_id.is_a?(Integer)
34
34
  @version_id = version_id
35
- elsif version_id.is_a?(String) and version_id =~ /^v(\d+)$/
35
+ elsif version_id.is_a?(String) && version_id =~ /^v(\d+)$/
36
36
  @version_id = version_id.sub(/^v/, '').to_i
37
37
  else
38
- raise "version_id (#{version_id}) is not in a recognized format"
38
+ raise(MoabRuntimeError, "version_id (#{version_id}) is not in a recognized format")
39
39
  end
40
40
  @version_name = StorageObject.version_dirname(@version_id)
41
41
  @version_pathname = storage_object.object_pathname.join(@version_name)
42
42
  @storage_object = storage_object
43
- @inventory_cache = Hash.new
43
+ @inventory_cache = {}
44
44
  end
45
45
 
46
46
  # @return [String] The unique identifier concatenating digital object id with version id
47
47
  def composite_key
48
- @storage_object.digital_object_id + '-' + StorageObject.version_dirname(@version_id)
48
+ "#{@storage_object.digital_object_id}-#{StorageObject.version_dirname(@version_id)}"
49
49
  end
50
50
 
51
51
  # @return [Boolean] true if the object version directory exists
@@ -70,6 +70,7 @@ module Moab
70
70
  def find_filepath(file_category, file_id)
71
71
  this_version_filepath = file_pathname(file_category, file_id)
72
72
  return this_version_filepath if this_version_filepath.exist?
73
+
73
74
  if file_category == 'manifest'
74
75
  msg = "manifest file #{file_id} not found for #{@storage_object.digital_object_id} - #{@version_id}"
75
76
  raise FileNotFoundException, msg
@@ -110,15 +111,16 @@ module Moab
110
111
  # @see FileInventory#read_xml_file
111
112
  def file_inventory(type)
112
113
  if version_id > 0
113
- return @inventory_cache[type] if @inventory_cache.has_key?(type)
114
+ return @inventory_cache[type] if @inventory_cache.key?(type)
115
+
114
116
  @inventory_cache[type] = FileInventory.read_xml_file(@version_pathname.join('manifests'), type)
115
117
  else
116
- groups = ['content', 'metadata'].collect { |id| FileGroup.new(:group_id => id) }
118
+ groups = %w[content metadata].collect { |id| FileGroup.new(group_id: id) }
117
119
  FileInventory.new(
118
- :type => 'version',
119
- :digital_object_id => @storage_object.digital_object_id,
120
- :version_id => @version_id,
121
- :groups => groups
120
+ type: 'version',
121
+ digital_object_id: @storage_object.digital_object_id,
122
+ version_id: @version_id,
123
+ groups: groups
122
124
  )
123
125
  end
124
126
  end
@@ -129,7 +131,7 @@ module Moab
129
131
  if version_id > 0
130
132
  SignatureCatalog.read_xml_file(@version_pathname.join('manifests'))
131
133
  else
132
- SignatureCatalog.new(:digital_object_id => @storage_object.digital_object_id)
134
+ SignatureCatalog.new(digital_object_id: @storage_object.digital_object_id)
133
135
  end
134
136
  end
135
137
 
@@ -137,7 +139,8 @@ module Moab
137
139
  # @param bag_dir [Pathname,String] The location of the bag to be ingested
138
140
  # @return [void] Create the version subdirectory and move files into it
139
141
  def ingest_bag_data(bag_dir)
140
- raise "Version already exists: #{@version_pathname}" if @version_pathname.exist?
142
+ raise(MoabRuntimeError, "Version already exists: #{@version_pathname}") if @version_pathname.exist?
143
+
141
144
  @version_pathname.join('manifests').mkpath
142
145
  bag_dir = Pathname(bag_dir)
143
146
  ingest_dir(bag_dir.join('data'), @version_pathname.join('data'))
@@ -151,7 +154,8 @@ module Moab
151
154
  # @param use_links [Boolean] If true, use hard links; if false, make copies
152
155
  # @return [void] recursively link or copy the source directory contents to the target directory
153
156
  def ingest_dir(source_dir, target_dir, use_links = true)
154
- raise "cannot copy - target already exists: #{target_dir.expand_path}" if target_dir.exist?
157
+ raise(MoabRuntimeError, "cannot copy - target already exists: #{target_dir.expand_path}") if target_dir.exist?
158
+
155
159
  target_dir.mkpath
156
160
  source_dir.children.each do |child|
157
161
  if child.directory?
@@ -198,22 +202,22 @@ module Moab
198
202
  # @return [void] examine the version's directory and create/serialize a {FileInventory} containing the manifest files
199
203
  def generate_manifest_inventory
200
204
  manifest_inventory = FileInventory.new(
201
- :type => 'manifests',
202
- :digital_object_id => @storage_object.digital_object_id,
203
- :version_id => @version_id
205
+ type: 'manifests',
206
+ digital_object_id: @storage_object.digital_object_id,
207
+ version_id: @version_id
204
208
  )
205
209
  pathname = @version_pathname.join('manifests')
206
- manifest_inventory.groups << FileGroup.new(:group_id => 'manifests').group_from_directory(pathname, false)
210
+ manifest_inventory.groups << FileGroup.new(group_id: 'manifests').group_from_directory(pathname, false)
207
211
  manifest_inventory.write_xml_file(pathname)
208
212
  end
209
213
 
210
214
  # @return [VerificationResult] return result of testing correctness of version manifests
211
- def verify_version_storage()
212
- result = VerificationResult.new(self.composite_key)
213
- result.subentities << self.verify_manifest_inventory
214
- result.subentities << self.verify_version_inventory
215
- result.subentities << self.verify_version_additions
216
- result.verified = result.subentities.all? { |entity| entity.verified }
215
+ def verify_version_storage
216
+ result = VerificationResult.new(composite_key)
217
+ result.subentities << verify_manifest_inventory
218
+ result.subentities << verify_version_inventory
219
+ result.subentities << verify_version_additions
220
+ result.verified = result.subentities.all?(&:verified)
217
221
  result
218
222
  end
219
223
 
@@ -221,8 +225,8 @@ module Moab
221
225
  def verify_manifest_inventory
222
226
  # read/parse manifestInventory.xml
223
227
  result = VerificationResult.new("manifest_inventory")
224
- manifest_inventory = self.file_inventory('manifests')
225
- result.subentities << VerificationResult.verify_value('composite_key', self.composite_key, manifest_inventory.composite_key)
228
+ manifest_inventory = file_inventory('manifests')
229
+ result.subentities << VerificationResult.verify_value('composite_key', composite_key, manifest_inventory.composite_key)
226
230
  result.subentities << VerificationResult.verify_truth('manifests_group', !manifest_inventory.group_empty?('manifests'))
227
231
  # measure the manifest signatures of the files in the directory (excluding manifestInventory.xml)
228
232
  directory_inventory = FileInventory.new.inventory_from_directory(@version_pathname.join('manifests'), 'manifests')
@@ -236,7 +240,7 @@ module Moab
236
240
  compare_result.verified = (diff.difference_count == 0)
237
241
  compare_result.details = diff.differences_detail
238
242
  result.subentities << compare_result
239
- result.verified = result.subentities.all? { |entity| entity.verified }
243
+ result.verified = result.subentities.all?(&:verified)
240
244
  result
241
245
  end
242
246
 
@@ -244,10 +248,10 @@ module Moab
244
248
  def verify_signature_catalog
245
249
  result = VerificationResult.new("signature_catalog")
246
250
  signature_catalog = self.signature_catalog
247
- result.subentities << VerificationResult.verify_value('signature_key', self.composite_key, signature_catalog.composite_key)
251
+ result.subentities << VerificationResult.verify_value('signature_key', composite_key, signature_catalog.composite_key)
248
252
  found = 0
249
- missing = Array.new
250
- object_pathname = self.storage_object.object_pathname
253
+ missing = []
254
+ object_pathname = storage_object.object_pathname
251
255
  signature_catalog.entries.each do |catalog_entry|
252
256
  storage_location = object_pathname.join(catalog_entry.storage_path)
253
257
  if storage_location.exist?
@@ -264,19 +268,19 @@ module Moab
264
268
  }
265
269
  file_result.details['missing'] = missing unless missing.empty?
266
270
  result.subentities << file_result
267
- result.verified = result.subentities.all? { |entity| entity.verified }
271
+ result.verified = result.subentities.all?(&:verified)
268
272
  result
269
273
  end
270
274
 
271
275
  # @return [Boolean] true if files & signatures listed in version inventory can all be found
272
276
  def verify_version_inventory
273
277
  result = VerificationResult.new("version_inventory")
274
- version_inventory = self.file_inventory('version')
275
- result.subentities << VerificationResult.verify_value('inventory_key', self.composite_key, version_inventory.composite_key)
278
+ version_inventory = file_inventory('version')
279
+ result.subentities << VerificationResult.verify_value('inventory_key', composite_key, version_inventory.composite_key)
276
280
  signature_catalog = self.signature_catalog
277
- result.subentities << VerificationResult.verify_value('signature_key', self.composite_key, signature_catalog.composite_key)
281
+ result.subentities << VerificationResult.verify_value('signature_key', composite_key, signature_catalog.composite_key)
278
282
  found = 0
279
- missing = Array.new
283
+ missing = []
280
284
  version_inventory.groups.each do |group|
281
285
  group.files.each do |file|
282
286
  file.instances.each do |instance|
@@ -298,24 +302,24 @@ module Moab
298
302
  }
299
303
  file_result.details['missing'] = missing unless missing.empty?
300
304
  result.subentities << file_result
301
- result.verified = result.subentities.all? { |entity| entity.verified }
305
+ result.verified = result.subentities.all?(&:verified)
302
306
  result
303
307
  end
304
308
 
305
309
  # @return [Boolean] returns true if files in data folder match files listed in version addtions inventory
306
310
  def verify_version_additions
307
311
  result = VerificationResult.new("version_additions")
308
- version_additions = self.file_inventory('additions')
309
- result.subentities << VerificationResult.verify_value('composite_key', self.composite_key, version_additions.composite_key)
312
+ version_additions = file_inventory('additions')
313
+ result.subentities << VerificationResult.verify_value('composite_key', composite_key, version_additions.composite_key)
310
314
  data_directory = @version_pathname.join('data')
311
- directory_inventory = FileInventory.new(:type => 'directory').inventory_from_directory(data_directory)
315
+ directory_inventory = FileInventory.new(type: 'directory').inventory_from_directory(data_directory)
312
316
  diff = FileInventoryDifference.new
313
317
  diff.compare(version_additions, directory_inventory)
314
318
  compare_result = VerificationResult.new('file_differences')
315
319
  compare_result.verified = (diff.difference_count == 0)
316
320
  compare_result.details = diff.differences_detail
317
321
  result.subentities << compare_result
318
- result.verified = result.subentities.all? { |entity| entity.verified }
322
+ result.verified = result.subentities.all?(&:verified)
319
323
  result
320
324
  end
321
325
 
@@ -323,6 +327,7 @@ module Moab
323
327
  # @return [null] Deactivate this object version by moving it to another directory. (Used by restore operation)
324
328
  def deactivate(timestamp)
325
329
  return unless @version_pathname.exist?
330
+
326
331
  timestamp_pathname = @version_pathname.parent.join(timestamp.utc.iso8601.gsub(/[-:]/, ''))
327
332
  timestamp_pathname.mkpath
328
333
  demote_pathame = timestamp_pathname.join(@version_pathname.basename)
@@ -1,4 +1,4 @@
1
- require 'moab'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Moab
4
4
  # A class to represent the SDR repository store
@@ -20,10 +20,12 @@ module Moab
20
20
  # @return [Array<Pathname>] The list of filesystem root paths in which objects are stored
21
21
  def storage_roots
22
22
  unless defined?(@storage_roots)
23
- raise "Moab::Config.storage_roots not found in config file" if Moab::Config.storage_roots.nil?
23
+ raise(MoabRuntimeError, "Moab::Config.storage_roots not found in config file") if Moab::Config.storage_roots.nil?
24
+
24
25
  @storage_roots = [Moab::Config.storage_roots].flatten.collect { |filesystem| Pathname(filesystem) }
25
- raise "Moab::Config.storage_roots empty" if @storage_roots.empty?
26
- @storage_roots.each { |root| raise "Storage root #{root} not found on system" unless root.exist? }
26
+ raise(MoabRuntimeError, "Moab::Config.storage_roots empty") if @storage_roots.empty?
27
+
28
+ @storage_roots.each { |root| raise(MoabRuntimeError, "Storage root #{root} not found on system") unless root.exist? }
27
29
  end
28
30
  @storage_roots
29
31
  end
@@ -31,8 +33,9 @@ module Moab
31
33
  # @return [String] The trunk segment of the object storage path
32
34
  def storage_trunk
33
35
  unless defined?(@storage_trunk)
34
- raise "Moab::Config.storage_trunk not found in config file" if Moab::Config.storage_trunk.nil?
35
- @storage_trunk = Moab::Config.storage_trunk
36
+ raise(MoabRuntimeError, "Moab::Config.storage_trunk not found in config file") if Moab::Config.storage_trunk.nil?
37
+
38
+ @storage_trunk = Moab::Config.storage_trunk
36
39
  end
37
40
  @storage_trunk
38
41
  end
@@ -52,15 +55,15 @@ module Moab
52
55
  unless defined?(@deposit_trunk)
53
56
  # do not raise error. this parameter will be ignored if missing
54
57
  # raise "Moab::Config.deposit_trunk not found in config file" if Moab::Config.deposit_trunk.nil?
55
- @deposit_trunk = Moab::Config.deposit_trunk
58
+ @deposit_trunk = Moab::Config.deposit_trunk
56
59
  end
57
60
  @deposit_trunk
58
61
  end
59
62
 
60
63
  # @param object_id [String] The identifier of the digital object
61
- # @return [Pathname] The branch segment of the object deposit path
64
+ # @return [String] The branch segment of the object deposit path
65
+ # @note Override this method in a subclass
62
66
  def deposit_branch(object_id)
63
- #todo This method should be customized, or overridden in a subclass
64
67
  object_id
65
68
  end
66
69
 
@@ -72,16 +75,18 @@ module Moab
72
75
  branch = storage_branch(object_id)
73
76
  storage_roots.each do |root|
74
77
  root_trunk = root.join(storage_trunk)
75
- raise "Storage area not found at #{root_trunk}" unless root_trunk.exist?
78
+ raise(MoabRuntimeError, "Storage area not found at #{root_trunk}") unless root_trunk.exist?
79
+
76
80
  root_trunk_branch = root_trunk.join(branch)
77
81
  return root if root_trunk_branch.exist?
78
82
  end
79
83
  # Search for the object's directory in the deposit areas
80
- if include_deposit and deposit_trunk
84
+ if include_deposit && deposit_trunk
81
85
  branch = deposit_branch(object_id)
82
86
  storage_roots.each do |root|
83
87
  root_trunk = root.join(deposit_trunk)
84
- raise "Deposit area not found at #{root_trunk}" unless root_trunk.exist?
88
+ raise(MoabRuntimeError, "Deposit area not found at #{root_trunk}") unless root_trunk.exist?
89
+
85
90
  root_trunk_branch = root_trunk.join(branch)
86
91
  return root if root_trunk_branch.exist?
87
92
  end
@@ -95,10 +100,35 @@ module Moab
95
100
  # @return [StorageObject] The representation of a digitial object's storage directory, which might not exist yet.
96
101
  def find_storage_object(object_id, include_deposit = false)
97
102
  root = find_storage_root(object_id, include_deposit)
98
- storage_pathname = root.join(storage_trunk, storage_branch(object_id))
99
- storage_object = StorageObject.new(object_id, storage_pathname)
100
- storage_object.storage_root = root
101
- storage_object
103
+ create_storage_object(object_id, root)
104
+ end
105
+
106
+ # @param object_id [String] The identifier of the digital object
107
+ # @param include_deposit [Boolean] specifies whether to look in deposit areas for objects in process of initial ingest
108
+ # @return [Array<StorageObject>] Representations of a digitial object's storage directories, or an empty array if none found.
109
+ def search_storage_objects(object_id, include_deposit = false)
110
+ storage_objects = []
111
+ # Search for the object's home directory in the storage areas
112
+ branch = storage_branch(object_id)
113
+ storage_roots.each do |root|
114
+ root_trunk = root.join(storage_trunk)
115
+ raise(MoabRuntimeError, "Storage area not found at #{root_trunk}") unless root_trunk.exist?
116
+
117
+ root_trunk_branch = root_trunk.join(branch)
118
+ storage_objects << create_storage_object(object_id, root) if root_trunk_branch.exist?
119
+ end
120
+ # Search for the object's directory in the deposit areas
121
+ if include_deposit && deposit_trunk
122
+ branch = deposit_branch(object_id)
123
+ storage_roots.each do |root|
124
+ root_trunk = root.join(deposit_trunk)
125
+ raise(MoabRuntimeError, "Deposit area not found at #{root_trunk}") unless root_trunk.exist?
126
+
127
+ root_trunk_branch = root_trunk.join(branch)
128
+ storage_objects << create_storage_object(object_id, root) if root_trunk_branch.exist?
129
+ end
130
+ end
131
+ storage_objects
102
132
  end
103
133
 
104
134
  # @param object_id [String] The identifier of the digital object whose size is desired
@@ -119,11 +149,9 @@ module Moab
119
149
  def storage_object(object_id, create = false)
120
150
  storage_object = find_storage_object(object_id)
121
151
  unless storage_object.object_pathname.exist?
122
- if create
123
- storage_object.object_pathname.mkpath
124
- else
125
- raise Moab::ObjectNotFoundException, "No storage object found for #{object_id}"
126
- end
152
+ raise ObjectNotFoundException, "No storage object found for #{object_id}" unless create
153
+
154
+ storage_object.object_pathname.mkpath
127
155
  end
128
156
  storage_object
129
157
  end
@@ -132,9 +160,16 @@ module Moab
132
160
  # @param druid [String] The object identifier
133
161
  # @return [void] transfer the object to the preservation repository
134
162
  def store_new_object_version(druid, bag_pathname)
135
- storage_object = self.storage_object(druid, create = true)
136
- new_version = storage_object.ingest_bag(bag_pathname)
137
- new_version
163
+ storage_object(druid, true).ingest_bag(bag_pathname)
164
+ end
165
+
166
+ private
167
+
168
+ def create_storage_object(object_id, root)
169
+ storage_pathname = root.join(storage_trunk, storage_branch(object_id))
170
+ storage_object = StorageObject.new(object_id, storage_pathname)
171
+ storage_object.storage_root = root
172
+ storage_object
138
173
  end
139
174
  end
140
175
  end