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