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,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Moab
|
4
4
|
# Compares two {FileInventory} instances based primarily on file signatures and secondarily on file pathnames.
|
@@ -24,17 +24,17 @@ module Moab
|
|
24
24
|
|
25
25
|
# (see Serializable#initialize)
|
26
26
|
def initialize(opts = {})
|
27
|
-
@group_differences =
|
27
|
+
@group_differences = []
|
28
28
|
super(opts)
|
29
29
|
end
|
30
30
|
|
31
31
|
# @attribute
|
32
32
|
# @return [String] The digital object ID (druid)
|
33
|
-
attribute :digital_object_id, String, :
|
33
|
+
attribute :digital_object_id, String, tag: 'objectId'
|
34
34
|
|
35
35
|
# @attribute
|
36
36
|
# @return [Integer] the number of differences found between the two inventories that were compared (dynamically calculated)
|
37
|
-
attribute :difference_count, Integer, :
|
37
|
+
attribute :difference_count, Integer, tag: 'differenceCount', on_save: proc { |i| i.to_s }
|
38
38
|
|
39
39
|
def difference_count
|
40
40
|
@group_differences.inject(0) { |sum, group| sum + group.difference_count }
|
@@ -50,7 +50,7 @@ module Moab
|
|
50
50
|
|
51
51
|
# @attribute
|
52
52
|
# @return [String] The datetime at which the report was run
|
53
|
-
attribute :report_datetime, String, :
|
53
|
+
attribute :report_datetime, String, tag: 'reportDatetime'
|
54
54
|
|
55
55
|
def report_datetime=(datetime)
|
56
56
|
@report_datetime = Moab::UtcTime.input(datetime)
|
@@ -62,11 +62,11 @@ module Moab
|
|
62
62
|
|
63
63
|
# @attribute
|
64
64
|
# @return [Array<FileGroupDifference>] The set of data groups comprising the version
|
65
|
-
has_many :group_differences, FileGroupDifference, :
|
65
|
+
has_many :group_differences, FileGroupDifference, tag: 'fileGroupDifference'
|
66
66
|
|
67
67
|
# @return [Array<String>] The data fields to include in summary reports
|
68
68
|
def summary_fields
|
69
|
-
%w
|
69
|
+
%w[digital_object_id difference_count basis other report_datetime group_differences]
|
70
70
|
end
|
71
71
|
|
72
72
|
# @param [String] group_id The identifer of the group to be selected
|
@@ -89,8 +89,8 @@ module Moab
|
|
89
89
|
group_ids = basis_inventory.group_ids | other_inventory.group_ids
|
90
90
|
group_ids.each do |group_id|
|
91
91
|
# get a pair of groups to compare, creating a empty group if not present in the inventory
|
92
|
-
basis_group = basis_inventory.group(group_id) || FileGroup.new(:
|
93
|
-
other_group = other_inventory.group(group_id) || FileGroup.new(:
|
92
|
+
basis_group = basis_inventory.group(group_id) || FileGroup.new(group_id: group_id)
|
93
|
+
other_group = other_inventory.group(group_id) || FileGroup.new(group_id: group_id)
|
94
94
|
@group_differences << FileGroupDifference.new.compare_file_groups(basis_group, other_group)
|
95
95
|
end
|
96
96
|
self
|
@@ -110,11 +110,11 @@ module Moab
|
|
110
110
|
# @return [Hash] Serializes the data and then filters it to report only the changes
|
111
111
|
def differences_detail
|
112
112
|
#return self.summary if difference_count == 0
|
113
|
-
inv_diff =
|
113
|
+
inv_diff = to_hash
|
114
114
|
inv_diff["group_differences"].each_value do |group_diff|
|
115
115
|
delete_subsets = []
|
116
116
|
group_diff["subsets"].each do |change_type, subset|
|
117
|
-
delete_subsets << change_type if change_type == "identical"
|
117
|
+
delete_subsets << change_type if (change_type == "identical") || (subset["count"] == 0)
|
118
118
|
end
|
119
119
|
delete_subsets.each do |change_type|
|
120
120
|
group_diff["subsets"].delete(change_type)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Moab
|
4
4
|
# A container for a file signature and all the physical file instances that have that signature
|
@@ -24,13 +24,13 @@ module Moab
|
|
24
24
|
|
25
25
|
# (see Serializable#initialize)
|
26
26
|
def initialize(opts = {})
|
27
|
-
@instances =
|
27
|
+
@instances = []
|
28
28
|
super(opts)
|
29
29
|
end
|
30
30
|
|
31
31
|
# @attribute
|
32
32
|
# @return [FileSignature] The fixity data of the file instance
|
33
|
-
element :signature, FileSignature, :
|
33
|
+
element :signature, FileSignature, tag: 'fileSignature'
|
34
34
|
|
35
35
|
def signature
|
36
36
|
@signature.is_a?(Array) ? @signature[0] : @signature
|
@@ -42,12 +42,12 @@ module Moab
|
|
42
42
|
|
43
43
|
# @attribute
|
44
44
|
# @return [Array<FileInstance>] The location(s) of the file manifestation's file instances
|
45
|
-
has_many :instances, FileInstance, :
|
45
|
+
has_many :instances, FileInstance, tag: 'fileInstance'
|
46
46
|
|
47
47
|
# @api internal
|
48
48
|
# @return [Array<String>] Create an array from all the file paths of the child {FileInstance} objects
|
49
49
|
def paths
|
50
|
-
instances.collect
|
50
|
+
instances.collect(&:path)
|
51
51
|
end
|
52
52
|
|
53
53
|
# @api internal
|
@@ -76,8 +76,9 @@ module Moab
|
|
76
76
|
# @param other [FileManifestation] The {FileManifestation} object to compare with self
|
77
77
|
# @return [Boolean] True if {FileManifestation} objects have same content
|
78
78
|
def ==(other)
|
79
|
-
return false unless
|
80
|
-
|
79
|
+
return false unless other.respond_to?(:signature) && other.respond_to?(:instances) # Cannot equal an incomparable type!
|
80
|
+
|
81
|
+
(signature == other.signature) && (instances == other.instances)
|
81
82
|
end
|
82
83
|
end
|
83
84
|
end
|
data/lib/moab/file_signature.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Moab
|
4
4
|
# The fixity properties of a file, used to determine file content equivalence regardless of filename.
|
@@ -46,19 +46,19 @@ module Moab
|
|
46
46
|
|
47
47
|
# @attribute
|
48
48
|
# @return [Integer] The size of the file in bytes
|
49
|
-
attribute :size, Integer, :
|
49
|
+
attribute :size, Integer, on_save: proc { |n| n.to_s }
|
50
50
|
|
51
51
|
# @attribute
|
52
52
|
# @return [String] The MD5 checksum value of the file
|
53
|
-
attribute :md5, String, :
|
53
|
+
attribute :md5, String, on_save: proc { |n| n.nil? ? "" : n.to_s }
|
54
54
|
|
55
55
|
# @attribute
|
56
56
|
# @return [String] The SHA1 checksum value of the file
|
57
|
-
attribute :sha1, String, :
|
57
|
+
attribute :sha1, String, on_save: proc { |n| n.nil? ? "" : n.to_s }
|
58
58
|
|
59
59
|
# @attribute
|
60
60
|
# @return [String] The SHA256 checksum value of the file
|
61
|
-
attribute :sha256, String, :
|
61
|
+
attribute :sha256, String, on_save: proc { |n| n.nil? ? "" : n.to_s }
|
62
62
|
|
63
63
|
KNOWN_ALGOS = {
|
64
64
|
md5: proc { Digest::MD5.new },
|
@@ -75,7 +75,7 @@ module Moab
|
|
75
75
|
# @param [Array<Symbol>] one or more keys of KNOWN_ALGOS to be computed
|
76
76
|
# @return [Moab::FileSignature] object populated with (requested) checksums
|
77
77
|
def self.from_file(pathname, algos_to_use = active_algos)
|
78
|
-
raise 'Unrecognized algorithm requested' unless algos_to_use.all? { |a| KNOWN_ALGOS.include?(a) }
|
78
|
+
raise(MoabRuntimeError, 'Unrecognized algorithm requested') unless algos_to_use.all? { |a| KNOWN_ALGOS.include?(a) }
|
79
79
|
|
80
80
|
signatures = algos_to_use.map { |k| [k, KNOWN_ALGOS[k].call] }.to_h
|
81
81
|
|
@@ -85,7 +85,7 @@ module Moab
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
new(signatures.
|
88
|
+
new(signatures.transform_values(&:hexdigest).merge(size: pathname.size))
|
89
89
|
end
|
90
90
|
|
91
91
|
# @param type [Symbol,String] The type of checksum
|
@@ -106,12 +106,11 @@ module Moab
|
|
106
106
|
|
107
107
|
# @return [Hash<Symbol,String>] A hash of the checksum data
|
108
108
|
def checksums
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
checksum_hash
|
109
|
+
{
|
110
|
+
md5: md5,
|
111
|
+
sha1: sha1,
|
112
|
+
sha256: sha256
|
113
|
+
}.reject { |_key, value| value.nil? || value.empty? }
|
115
114
|
end
|
116
115
|
|
117
116
|
# @return [Boolean] The signature contains all of the 3 desired checksums
|
@@ -120,24 +119,23 @@ module Moab
|
|
120
119
|
end
|
121
120
|
|
122
121
|
# @api internal
|
123
|
-
# @return [Hash<Symbol
|
122
|
+
# @return [Hash<Symbol => String>] A hash of fixity data from this signataure object
|
124
123
|
def fixity
|
125
|
-
|
126
|
-
fixity_hash[:size] = @size.to_s
|
127
|
-
fixity_hash.merge!(checksums)
|
128
|
-
fixity_hash
|
124
|
+
{ size: size.to_s }.merge(checksums)
|
129
125
|
end
|
130
126
|
|
131
127
|
# @api internal
|
132
128
|
# @param other [FileSignature] The other file signature being compared to this signature
|
133
129
|
# @return [Boolean] Returns true if self and other have comparable fixity data.
|
134
130
|
def eql?(other)
|
135
|
-
return false unless
|
136
|
-
return false if
|
137
|
-
|
131
|
+
return false unless other.respond_to?(:size) && other.respond_to?(:checksums)
|
132
|
+
return false if size.to_i != other.size.to_i
|
133
|
+
|
134
|
+
self_checksums = checksums
|
138
135
|
other_checksums = other.checksums
|
139
136
|
matching_keys = self_checksums.keys & other_checksums.keys
|
140
|
-
return false if matching_keys.
|
137
|
+
return false if matching_keys.empty?
|
138
|
+
|
141
139
|
matching_keys.each do |key|
|
142
140
|
return false if self_checksums[key] != other_checksums[key]
|
143
141
|
end
|
@@ -181,31 +179,27 @@ module Moab
|
|
181
179
|
# @return [FileSignature] The full signature derived from the file, unless the fixity is inconsistent with current values
|
182
180
|
def normalized_signature(pathname)
|
183
181
|
sig_from_file = FileSignature.new.signature_from_file(pathname)
|
184
|
-
if
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
raise "Signature inconsistent between inventory and file for #{pathname}: #{self.diff(sig_from_file).inspect}"
|
190
|
-
end
|
182
|
+
return sig_from_file if eql?(sig_from_file)
|
183
|
+
|
184
|
+
# The full signature from file is consistent with current values, or...
|
185
|
+
# One or more of the fixity values is inconsistent, so raise an exception
|
186
|
+
raise(MoabRuntimeError, "Signature inconsistent between inventory and file for #{pathname}: #{diff(sig_from_file).inspect}")
|
191
187
|
end
|
192
188
|
|
193
189
|
# @return [Hash<Symbol,String>] Key is type (e.g. :sha1), value is checksum names (e.g. ['SHA-1', 'SHA1'])
|
194
|
-
def
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
190
|
+
def self.checksum_names_for_type
|
191
|
+
{
|
192
|
+
md5: ['MD5'],
|
193
|
+
sha1: %w[SHA-1 SHA1],
|
194
|
+
sha256: %w[SHA-256 SHA256]
|
195
|
+
}
|
200
196
|
end
|
201
197
|
|
202
198
|
# @return [Hash<String, Symbol>] Key is checksum name (e.g. MD5), value is checksum type (e.g. :md5)
|
203
|
-
def
|
204
|
-
type_for_name =
|
205
|
-
|
206
|
-
names.each
|
207
|
-
type_for_name[name] = type
|
208
|
-
end
|
199
|
+
def self.checksum_type_for_name
|
200
|
+
type_for_name = {}
|
201
|
+
checksum_names_for_type.each do |type, names|
|
202
|
+
names.each { |name| type_for_name[name] = type }
|
209
203
|
end
|
210
204
|
type_for_name
|
211
205
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Moab
|
4
4
|
# A digital object's Signature Catalog is derived from an filtered aggregation of the file inventories
|
@@ -32,27 +32,27 @@ module Moab
|
|
32
32
|
|
33
33
|
# (see Serializable#initialize)
|
34
34
|
def initialize(opts = {})
|
35
|
-
@entries =
|
36
|
-
@signature_hash =
|
35
|
+
@entries = []
|
36
|
+
@signature_hash = {}
|
37
37
|
super(opts)
|
38
38
|
end
|
39
39
|
|
40
40
|
# @attribute
|
41
41
|
# @return [String] The object ID (druid)
|
42
|
-
attribute :digital_object_id, String, :
|
42
|
+
attribute :digital_object_id, String, tag: 'objectId'
|
43
43
|
|
44
44
|
# @attribute
|
45
45
|
# @return [Integer] The ordinal version number
|
46
|
-
attribute :version_id, Integer, :
|
46
|
+
attribute :version_id, Integer, tag: 'versionId', key: true, on_save: proc { |n| n.to_s }
|
47
47
|
|
48
48
|
# @return [String] The unique identifier concatenating digital object id with version id
|
49
49
|
def composite_key
|
50
|
-
@digital_object_id
|
50
|
+
"#{@digital_object_id}-#{StorageObject.version_dirname(@version_id)}"
|
51
51
|
end
|
52
52
|
|
53
53
|
# @attribute
|
54
54
|
# @return [String] The datetime at which the catalog was updated
|
55
|
-
attribute :catalog_datetime, Time, :
|
55
|
+
attribute :catalog_datetime, Time, tag: 'catalogDatetime'
|
56
56
|
|
57
57
|
def catalog_datetime=(datetime)
|
58
58
|
@catalog_datetime = Moab::UtcTime.input(datetime)
|
@@ -64,7 +64,7 @@ module Moab
|
|
64
64
|
|
65
65
|
# @attribute
|
66
66
|
# @return [Integer] The total number of data files (dynamically calculated)
|
67
|
-
attribute :file_count, Integer, :
|
67
|
+
attribute :file_count, Integer, tag: 'fileCount', on_save: proc { |t| t.to_s }
|
68
68
|
|
69
69
|
def file_count
|
70
70
|
entries.size
|
@@ -72,7 +72,7 @@ module Moab
|
|
72
72
|
|
73
73
|
# @attribute
|
74
74
|
# @return [Integer] The total size (in bytes) of all data files (dynamically calculated)
|
75
|
-
attribute :byte_count, Integer, :
|
75
|
+
attribute :byte_count, Integer, tag: 'byteCount', on_save: proc { |t| t.to_s }
|
76
76
|
|
77
77
|
def byte_count
|
78
78
|
entries.inject(0) { |sum, entry| sum + entry.signature.size.to_i }
|
@@ -80,7 +80,7 @@ module Moab
|
|
80
80
|
|
81
81
|
# @attribute
|
82
82
|
# @return [Integer] The total disk usage (in 1 kB blocks) of all data files (estimating du -k result) (dynamically calculated)
|
83
|
-
attribute :block_count, Integer, :
|
83
|
+
attribute :block_count, Integer, tag: 'blockCount', on_save: proc { |t| t.to_s }
|
84
84
|
|
85
85
|
def block_count
|
86
86
|
block_size = 1024
|
@@ -89,12 +89,12 @@ module Moab
|
|
89
89
|
|
90
90
|
# @return [Array<String>] The data fields to include in summary reports
|
91
91
|
def summary_fields
|
92
|
-
%w
|
92
|
+
%w[digital_object_id version_id catalog_datetime file_count byte_count block_count]
|
93
93
|
end
|
94
94
|
|
95
95
|
# @attribute
|
96
96
|
# @return [Array<SignatureCatalogEntry>] The set of data groups comprising the version
|
97
|
-
has_many :entries, SignatureCatalogEntry, :
|
97
|
+
has_many :entries, SignatureCatalogEntry, tag: 'entry'
|
98
98
|
|
99
99
|
def entries=(entry_array)
|
100
100
|
entry_array.each do |entry|
|
@@ -130,11 +130,11 @@ module Moab
|
|
130
130
|
def normalize_group_signatures(group, group_pathname = nil)
|
131
131
|
unless group_pathname.nil?
|
132
132
|
group_pathname = Pathname(group_pathname)
|
133
|
-
raise "Could not locate #{group_pathname}" unless group_pathname.exist?
|
133
|
+
raise(MoabRuntimeError, "Could not locate #{group_pathname}") unless group_pathname.exist?
|
134
134
|
end
|
135
135
|
group.files.each do |file|
|
136
136
|
unless file.signature.complete?
|
137
|
-
if @signature_hash.
|
137
|
+
if @signature_hash.key?(file.signature)
|
138
138
|
file.signature = @signature_hash.find { |k, _v| k == file.signature }[0]
|
139
139
|
elsif group_pathname
|
140
140
|
file_pathname = group_pathname.join(file.instances[0].path)
|
@@ -153,7 +153,7 @@ module Moab
|
|
153
153
|
def update(version_inventory, data_pathname)
|
154
154
|
version_inventory.groups.each do |group|
|
155
155
|
group.files.each do |file|
|
156
|
-
unless @signature_hash.
|
156
|
+
unless @signature_hash.key?(file.signature)
|
157
157
|
entry = SignatureCatalogEntry.new
|
158
158
|
entry.version_id = version_inventory.version_id
|
159
159
|
entry.group_id = group.group_id
|
@@ -178,16 +178,14 @@ module Moab
|
|
178
178
|
# containing only those files that were added in this version
|
179
179
|
# @example {include:file:spec/features/catalog/version_additions_spec.rb}
|
180
180
|
def version_additions(version_inventory)
|
181
|
-
version_additions = FileInventory.new(:
|
181
|
+
version_additions = FileInventory.new(type: 'additions')
|
182
182
|
version_additions.copy_ids(version_inventory)
|
183
183
|
version_inventory.groups.each do |group|
|
184
|
-
group_addtions = FileGroup.new(:
|
184
|
+
group_addtions = FileGroup.new(group_id: group.group_id)
|
185
185
|
group.files.each do |file|
|
186
|
-
unless @signature_hash.
|
187
|
-
group_addtions.add_file_instance(file.signature, file.instances[0])
|
188
|
-
end
|
186
|
+
group_addtions.add_file_instance(file.signature, file.instances[0]) unless @signature_hash.key?(file.signature)
|
189
187
|
end
|
190
|
-
version_additions.groups << group_addtions
|
188
|
+
version_additions.groups << group_addtions unless group_addtions.files.empty?
|
191
189
|
end
|
192
190
|
version_additions
|
193
191
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Moab
|
4
4
|
# A file-level entry in a digital object's {SignatureCatalog}.
|
@@ -25,19 +25,19 @@ module Moab
|
|
25
25
|
|
26
26
|
# @attribute
|
27
27
|
# @return [Integer] The ordinal version number
|
28
|
-
attribute :version_id, Integer, :
|
28
|
+
attribute :version_id, Integer, tag: 'originalVersion', key: true, on_save: proc { |n| n.to_s }
|
29
29
|
|
30
30
|
# @attribute
|
31
31
|
# @return [String] The name of the file group
|
32
|
-
attribute :group_id, String, :
|
32
|
+
attribute :group_id, String, tag: 'groupId', key: true
|
33
33
|
|
34
34
|
# @attribute
|
35
35
|
# @return [String] The id is the filename path, relative to the file group's base directory
|
36
|
-
attribute :path, String, :
|
36
|
+
attribute :path, String, key: true, tag: 'storagePath'
|
37
37
|
|
38
38
|
# @attribute
|
39
39
|
# @return [FileSignature] The fixity data of the file instance
|
40
|
-
element :signature, FileSignature, :
|
40
|
+
element :signature, FileSignature, tag: 'fileSignature'
|
41
41
|
|
42
42
|
def signature
|
43
43
|
# HappyMapper's parser tries to put an array of signatures in the signature field
|
data/lib/moab/stanford.rb
CHANGED
data/lib/moab/storage_object.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Moab
|
4
4
|
# A class to represent a digital object's repository storage location
|
@@ -84,10 +84,10 @@ module Moab
|
|
84
84
|
# @return [FileInventory] The file inventory of the specified type for this version
|
85
85
|
def versionize_bag(bag_dir, current_version, new_version)
|
86
86
|
new_inventory = FileInventory.new(
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
90
|
-
:
|
87
|
+
type: 'version',
|
88
|
+
digital_object_id: @digital_object_id,
|
89
|
+
version_id: new_version.version_id,
|
90
|
+
inventory_datetime: Time.now
|
91
91
|
)
|
92
92
|
new_inventory.inventory_from_bagit_bag(bag_dir)
|
93
93
|
new_inventory.write_xml_file(bag_dir)
|
@@ -115,6 +115,7 @@ module Moab
|
|
115
115
|
storage_filepath = @object_pathname.join(catalog_filepath)
|
116
116
|
errmsg = "#{catalog_filepath} missing from storage location #{storage_filepath}"
|
117
117
|
raise FileNotFoundException, errmsg unless storage_filepath.exist?
|
118
|
+
|
118
119
|
storage_filepath
|
119
120
|
end
|
120
121
|
|
@@ -122,27 +123,26 @@ module Moab
|
|
122
123
|
# @param version_id [Integer] The version identifier of an object version
|
123
124
|
# @return [String] The directory name of the version, relative to the digital object home directory (e.g v0002)
|
124
125
|
def self.version_dirname(version_id)
|
125
|
-
("v%04d"
|
126
|
+
format("v%04d", version_id)
|
126
127
|
end
|
127
128
|
|
128
129
|
# @return [Array<Integer>] The list of all version ids for this object
|
129
130
|
def version_id_list
|
130
|
-
list =
|
131
|
+
list = []
|
131
132
|
return list unless @object_pathname.exist?
|
133
|
+
|
132
134
|
@object_pathname.children.each do |dirname|
|
133
135
|
vnum = dirname.basename.to_s
|
134
|
-
if vnum =~ /^v(\d+)$/
|
135
|
-
list << vnum[1..-1].to_i
|
136
|
-
end
|
136
|
+
list << vnum[1..].to_i if vnum =~ /^v(\d+)$/
|
137
137
|
end
|
138
138
|
list.sort
|
139
139
|
end
|
140
140
|
|
141
141
|
# @return [Array<StorageObjectVersion>] The list of all versions in this storage object
|
142
142
|
def version_list
|
143
|
-
version_id_list.collect { |id|
|
143
|
+
version_id_list.collect { |id| storage_object_version(id) }
|
144
144
|
end
|
145
|
-
alias
|
145
|
+
alias versions version_list
|
146
146
|
|
147
147
|
# @return [Boolean] true if there are no versions yet in this object
|
148
148
|
def empty?
|
@@ -152,12 +152,12 @@ module Moab
|
|
152
152
|
# @api external
|
153
153
|
# @return [Integer] The identifier of the latest version of this object, or 0 if no versions exist
|
154
154
|
def current_version_id
|
155
|
-
@current_version_id ||=
|
155
|
+
@current_version_id ||= version_id_list.last || 0
|
156
156
|
end
|
157
157
|
|
158
158
|
# @return [StorageObjectVersion] The most recent version in the storage object
|
159
159
|
def current_version
|
160
|
-
|
160
|
+
storage_object_version(current_version_id)
|
161
161
|
end
|
162
162
|
|
163
163
|
# @api internal
|
@@ -165,8 +165,9 @@ module Moab
|
|
165
165
|
# @return [Boolean] Tests whether the new version number is one higher than the current version number
|
166
166
|
def validate_new_inventory(version_inventory)
|
167
167
|
if version_inventory.version_id != (current_version_id + 1)
|
168
|
-
raise "version mismatch - current: #{current_version_id} new: #{version_inventory.version_id}"
|
168
|
+
raise(MoabRuntimeError, "version mismatch - current: #{current_version_id} new: #{version_inventory.version_id}")
|
169
169
|
end
|
170
|
+
|
170
171
|
true
|
171
172
|
end
|
172
173
|
|
@@ -181,7 +182,7 @@ module Moab
|
|
181
182
|
when 1..current
|
182
183
|
StorageObjectVersion.new(self, version_id)
|
183
184
|
else
|
184
|
-
raise "Version ID #{version_id} does not exist"
|
185
|
+
raise(MoabRuntimeError, "Version ID #{version_id} does not exist")
|
185
186
|
end
|
186
187
|
end
|
187
188
|
|
@@ -191,21 +192,19 @@ module Moab
|
|
191
192
|
# * Version 0 is a special case used to generate empty manifests
|
192
193
|
# * Current version + 1 is used for creation of a new version
|
193
194
|
def storage_object_version(version_id)
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
raise "Version ID not specified"
|
198
|
-
end
|
195
|
+
raise(MoabRuntimeError, "Version ID not specified") unless version_id
|
196
|
+
|
197
|
+
StorageObjectVersion.new(self, version_id)
|
199
198
|
end
|
200
199
|
|
201
200
|
# @return [VerificationResult] Return result of storage verification
|
202
201
|
def verify_object_storage
|
203
202
|
result = VerificationResult.new(digital_object_id)
|
204
|
-
|
203
|
+
version_list.each do |version|
|
205
204
|
result.subentities << version.verify_version_storage
|
206
205
|
end
|
207
206
|
result.subentities << current_version.verify_signature_catalog
|
208
|
-
result.verified = result.subentities.all?
|
207
|
+
result.verified = result.subentities.all?(&:verified)
|
209
208
|
result
|
210
209
|
end
|
211
210
|
|
@@ -216,7 +215,7 @@ module Moab
|
|
216
215
|
recovery_object = StorageObject.new(@digital_object_id, recovery_path, false)
|
217
216
|
recovery_object.versions.each do |recovery_version|
|
218
217
|
version_id = recovery_version.version_id
|
219
|
-
storage_version =
|
218
|
+
storage_version = storage_object_version(version_id)
|
220
219
|
# rename/save the original
|
221
220
|
storage_version.deactivate(timestamp)
|
222
221
|
# copy the recovered version into place
|