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.
- checksums.yaml +5 -5
- data/lib/moab.rb +3 -2
- data/lib/moab/bagger.rb +25 -20
- data/lib/moab/config.rb +39 -8
- data/lib/moab/deposit_bag_validator.rb +22 -17
- data/lib/moab/exceptions.rb +10 -8
- data/lib/moab/file_group.rb +23 -22
- data/lib/moab/file_group_difference.rb +35 -35
- data/lib/moab/file_group_difference_subset.rb +5 -5
- data/lib/moab/file_instance.rb +4 -3
- data/lib/moab/file_instance_difference.rb +5 -5
- data/lib/moab/file_inventory.rb +25 -31
- data/lib/moab/file_inventory_difference.rb +11 -11
- data/lib/moab/file_manifestation.rb +8 -7
- data/lib/moab/file_signature.rb +35 -41
- data/lib/moab/signature_catalog.rb +19 -21
- data/lib/moab/signature_catalog_entry.rb +5 -5
- data/lib/moab/stanford.rb +2 -0
- data/lib/moab/storage_object.rb +23 -24
- data/lib/moab/storage_object_validator.rb +44 -16
- data/lib/moab/storage_object_version.rb +45 -40
- data/lib/moab/storage_repository.rb +59 -24
- data/lib/moab/storage_services.rb +17 -10
- data/lib/moab/utc_time.rb +3 -3
- data/lib/moab/verification_result.rb +3 -4
- data/lib/moab/version_metadata.rb +4 -4
- data/lib/moab/version_metadata_entry.rb +6 -6
- data/lib/moab/version_metadata_event.rb +1 -1
- data/lib/serializer.rb +2 -0
- data/lib/serializer/manifest.rb +9 -7
- data/lib/serializer/serializable.rb +41 -35
- data/lib/stanford/active_fedora_object.rb +1 -1
- data/lib/stanford/content_inventory.rb +40 -34
- data/lib/stanford/dor_metadata.rb +4 -3
- data/lib/stanford/moab_storage_directory.rb +4 -2
- data/lib/stanford/storage_object_validator.rb +1 -1
- data/lib/stanford/storage_repository.rb +9 -6
- data/lib/stanford/storage_services.rb +6 -6
- metadata +23 -38
@@ -1,16 +1,17 @@
|
|
1
|
-
|
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"
|
9
|
-
CONTENT_DIR = "content"
|
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"
|
13
|
-
MANIFESTS_DIR = 'manifests'
|
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 %{
|
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 %{
|
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 =~ /^
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
208
|
-
|
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
|
-
|
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
|
-
|
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)
|
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 =
|
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
|
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.
|
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 = [
|
118
|
+
groups = %w[content metadata].collect { |id| FileGroup.new(group_id: id) }
|
117
119
|
FileInventory.new(
|
118
|
-
:
|
119
|
-
:
|
120
|
-
:
|
121
|
-
:
|
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(:
|
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
|
-
:
|
202
|
-
:
|
203
|
-
:
|
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(:
|
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(
|
213
|
-
result.subentities <<
|
214
|
-
result.subentities <<
|
215
|
-
result.subentities <<
|
216
|
-
result.verified = result.subentities.all?
|
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 =
|
225
|
-
result.subentities << VerificationResult.verify_value('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?
|
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',
|
251
|
+
result.subentities << VerificationResult.verify_value('signature_key', composite_key, signature_catalog.composite_key)
|
248
252
|
found = 0
|
249
|
-
missing =
|
250
|
-
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?
|
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 =
|
275
|
-
result.subentities << VerificationResult.verify_value('inventory_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',
|
281
|
+
result.subentities << VerificationResult.verify_value('signature_key', composite_key, signature_catalog.composite_key)
|
278
282
|
found = 0
|
279
|
-
missing =
|
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?
|
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 =
|
309
|
-
result.subentities << VerificationResult.verify_value('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(:
|
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?
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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 [
|
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
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
123
|
-
|
124
|
-
|
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
|
136
|
-
|
137
|
-
|
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
|