moab-versioning 4.2.1 → 4.4.2

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 (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