moab-versioning 5.2.0 → 6.0.0.alpha

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c20a012b9d9c481ddfeed15296e61aaf6648bed0cd1d0065a8b0662301e94a1b
4
- data.tar.gz: 8d5a96d608b7334f117b5ee9faa3cbe16f82f543bd3af0d23d11371df2181d76
3
+ metadata.gz: 6d208d4a3118a616d2ee2580e51d9a344438676755f5ef33ace82ed2dbc33bba
4
+ data.tar.gz: 7198c3f7450d8a6bb61d8b33d50404e9b0a07e52d47198f713b4400e1c2a4435
5
5
  SHA512:
6
- metadata.gz: 296fd7985772e8296f879e955066f7e3c71b00a6a83d9893aa124de5d900a427ca61d57b221f4227ae54210f3518111a5d99ae60db62ed9dbb25818871f8e87d
7
- data.tar.gz: 701adc9ee529e10fd608ed890f8f8a3f978cb3ec023f58d8a75bd11a0caa6e27f4631ec4f73c9280cf8de914da855d100be3cd077f029ec91fab4b07749c627c
6
+ metadata.gz: 884f1c7e2818e9bcb64de45939cda1ccc4a1aebf5015edd3bfefe707f3a4185253aaa629d4cc0340145be5fd2a72aac0931c7115e8a7929338dd362ff9aa894b
7
+ data.tar.gz: 2f23fc485263350eb667eed7871dc194972688151613d573227dfa3b2f5490d9f6ccc8f7625f0c4ac3fa66ac0ee01f3c470a24b6133443c89f080e90bae273aa
data/lib/moab/bagger.rb CHANGED
@@ -58,9 +58,9 @@ module Moab
58
58
  # @return [void] Generate the bagit.txt tag file
59
59
  def create_bagit_txt
60
60
  bag_pathname.mkpath
61
- bag_pathname.join("bagit.txt").open('w') do |f|
62
- f.puts "Tag-File-Character-Encoding: UTF-8"
63
- f.puts "BagIt-Version: 0.97"
61
+ bag_pathname.join('bagit.txt').open('w') do |f|
62
+ f.puts 'Tag-File-Character-Encoding: UTF-8'
63
+ f.puts 'BagIt-Version: 0.97'
64
64
  end
65
65
  end
66
66
 
@@ -209,7 +209,7 @@ module Moab
209
209
  if manifest_file[type]
210
210
  manifest_file[type].close
211
211
  manifest_pathname[type].delete if
212
- manifest_pathname[type].exist? && manifest_pathname[type].size == 0
212
+ manifest_pathname[type].exist? && manifest_pathname[type].empty?
213
213
  end
214
214
  end
215
215
  end
@@ -217,7 +217,7 @@ module Moab
217
217
  # @api internal
218
218
  # @return [void] Generate the bag-info.txt tag file
219
219
  def create_bag_info_txt
220
- bag_pathname.join("bag-info.txt").open('w') do |f|
220
+ bag_pathname.join('bag-info.txt').open('w') do |f|
221
221
  f.puts "External-Identifier: #{bag_inventory.package_id}"
222
222
  f.puts "Payload-Oxum: #{bag_inventory.byte_count}.#{bag_inventory.file_count}"
223
223
  f.puts "Bag-Size: #{bag_inventory.human_size}"
@@ -247,7 +247,7 @@ module Moab
247
247
  if manifest_file[type]
248
248
  manifest_file[type].close
249
249
  manifest_pathname[type].delete if
250
- manifest_pathname[type].exist? && manifest_pathname[type].size == 0
250
+ manifest_pathname[type].exist? && manifest_pathname[type].empty?
251
251
  end
252
252
  end
253
253
  end
@@ -23,7 +23,7 @@ module Moab
23
23
  # (see Serializable#initialize)
24
24
  def initialize(opts = {})
25
25
  @signature_hash = {}
26
- @data_source = ""
26
+ @data_source = ''
27
27
  @signatures_from_bag = nil # prevents later warning: instance variable @signatures_from_bag not initialized
28
28
  super(opts)
29
29
  end
@@ -158,14 +158,16 @@ module Moab
158
158
  end
159
159
  attr_reader :base_directory
160
160
 
161
+ # FIXME: shouldn't this method be named descendent_of_base?
161
162
  # @api internal
162
163
  # @param pathname [Pathname] The file path to be tested
163
164
  # @return [Boolean] Test whether the given path is contained within the {#base_directory}
164
165
  def is_descendent_of_base?(pathname)
165
- raise(MoabRuntimeError, "base_directory has not been set") if @base_directory.nil?
166
+ raise(MoabRuntimeError, 'base_directory has not been set') if @base_directory.nil?
166
167
 
167
168
  is_descendent = false
168
169
  pathname.expand_path.ascend { |ancestor| is_descendent ||= (ancestor == @base_directory) }
170
+ # FIXME: shouldn't it simply return false?
169
171
  raise(MoabRuntimeError, "#{pathname} is not a descendent of #{@base_directory}") unless is_descendent
170
172
 
171
173
  is_descendent
@@ -233,7 +233,7 @@ module Moab
233
233
  matching_paths.each do |path|
234
234
  fid = FileInstanceDifference.new(change: 'identical')
235
235
  fid.basis_path = path
236
- fid.other_path = "same"
236
+ fid.other_path = 'same'
237
237
  fid.signatures << signature
238
238
  subset_hash[:identical].files << fid
239
239
  end
@@ -286,7 +286,7 @@ module Moab
286
286
  matching_keys(basis_path_hash, other_path_hash).each do |path|
287
287
  fid = FileInstanceDifference.new(change: 'modified')
288
288
  fid.basis_path = path
289
- fid.other_path = "same"
289
+ fid.other_path = 'same'
290
290
  fid.signatures << basis_path_hash[path]
291
291
  fid.signatures << other_path_hash[path]
292
292
  subset_hash[:modified].files << fid
@@ -304,7 +304,7 @@ module Moab
304
304
  def tabulate_added_files(basis_path_hash, other_path_hash)
305
305
  other_only_keys(basis_path_hash, other_path_hash).each do |path|
306
306
  fid = FileInstanceDifference.new(change: 'added')
307
- fid.basis_path = ""
307
+ fid.basis_path = ''
308
308
  fid.other_path = path
309
309
  fid.signatures << other_path_hash[path]
310
310
  subset_hash[:added].files << fid
@@ -323,7 +323,7 @@ module Moab
323
323
  basis_only_keys(basis_path_hash, other_path_hash).each do |path|
324
324
  fid = FileInstanceDifference.new(change: 'deleted')
325
325
  fid.basis_path = path
326
- fid.other_path = ""
326
+ fid.other_path = ''
327
327
  fid.signatures << basis_path_hash[path]
328
328
  subset_hash[:deleted].files << fid
329
329
  end
@@ -234,9 +234,11 @@ module Moab
234
234
  count += 1
235
235
  end
236
236
  if count == 0
237
- format("%d B", size)
237
+ format('%d B', size)
238
238
  else
239
- format("%.2f %s", size, %w[B KB MB GB TB][count])
239
+ # rubocop:disable Style/FormatStringToken
240
+ format('%.2f %s', size, %w[B KB MB GB TB][count])
241
+ # rubocop:enable Style/FormatStringToken
240
242
  end
241
243
  end
242
244
 
@@ -245,13 +247,13 @@ module Moab
245
247
  # @return [String] The standard name for the serialized inventory file of the given type
246
248
  def self.xml_filename(type = nil)
247
249
  case type
248
- when "version"
250
+ when 'version'
249
251
  'versionInventory.xml'
250
- when "additions"
252
+ when 'additions'
251
253
  'versionAdditions.xml'
252
- when "manifests"
254
+ when 'manifests'
253
255
  'manifestInventory.xml'
254
- when "directory"
256
+ when 'directory'
255
257
  'directoryInventory.xml'
256
258
  else
257
259
  raise ArgumentError, "unknown inventory type: #{type}"
@@ -109,18 +109,18 @@ module Moab
109
109
 
110
110
  # @return [Hash] Serializes the data and then filters it to report only the changes
111
111
  def differences_detail
112
- #return self.summary if difference_count == 0
112
+ # return self.summary if difference_count == 0
113
113
  inv_diff = to_hash
114
- inv_diff["group_differences"].each_value do |group_diff|
114
+ inv_diff['group_differences'].each_value do |group_diff|
115
115
  delete_subsets = []
116
- group_diff["subsets"].each do |change_type, subset|
117
- delete_subsets << change_type if (change_type == "identical") || (subset["count"] == 0)
116
+ group_diff['subsets'].each do |change_type, subset|
117
+ delete_subsets << change_type if (change_type == 'identical') || (subset['count'] == 0)
118
118
  end
119
119
  delete_subsets.each do |change_type|
120
- group_diff["subsets"].delete(change_type)
121
- group_diff.delete(change_type) if change_type != "identical"
120
+ group_diff['subsets'].delete(change_type)
121
+ group_diff.delete(change_type) if change_type != 'identical'
122
122
  end
123
- group_diff.delete("subsets") if group_diff["subsets"].empty?
123
+ group_diff.delete('subsets') if group_diff['subsets'].empty?
124
124
  end
125
125
  inv_diff
126
126
  end
@@ -50,15 +50,15 @@ module Moab
50
50
 
51
51
  # @attribute
52
52
  # @return [String] The MD5 checksum value of the file
53
- attribute :md5, String, on_save: proc { |n| n.nil? ? "" : n.to_s }
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, on_save: proc { |n| n.nil? ? "" : n.to_s }
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, on_save: proc { |n| n.nil? ? "" : n.to_s }
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 },
@@ -79,7 +79,7 @@ module Moab
79
79
 
80
80
  signatures = algos_to_use.to_h { |k| [k, KNOWN_ALGOS[k].call] }
81
81
 
82
- pathname.open("r") do |stream|
82
+ pathname.open('r') do |stream|
83
83
  while (buffer = stream.read(8192))
84
84
  signatures.each_value { |digest| digest.update(buffer) }
85
85
  end
@@ -124,7 +124,7 @@ module Moab
124
124
  # @param version_id [Integer] The version identifier of an object version
125
125
  # @return [String] The directory name of the version, relative to the digital object home directory (e.g v0002)
126
126
  def self.version_dirname(version_id)
127
- format("v%04d", version_id)
127
+ format('v%04d', version_id)
128
128
  end
129
129
 
130
130
  # @return [Array<Integer>] The list of all version ids for this object
@@ -193,7 +193,7 @@ module Moab
193
193
  # * Version 0 is a special case used to generate empty manifests
194
194
  # * Current version + 1 is used for creation of a new version
195
195
  def storage_object_version(version_id)
196
- raise(MoabRuntimeError, "Version ID not specified") unless version_id
196
+ raise(MoabRuntimeError, 'Version ID not specified') unless version_id
197
197
 
198
198
  StorageObjectVersion.new(self, version_id)
199
199
  end
@@ -6,17 +6,17 @@ module Moab
6
6
  # Given a druid path, are the contents actually a well-formed Moab?
7
7
  # Shameless green: repetitious code included.
8
8
  class StorageObjectValidator
9
- METADATA_DIR = "metadata"
10
- CONTENT_DIR = "content"
9
+ METADATA_DIR = 'metadata'
10
+ CONTENT_DIR = 'content'
11
11
  EXPECTED_DATA_SUB_DIRS = [CONTENT_DIR, METADATA_DIR].freeze
12
12
  IMPLICIT_DIRS = ['.', '..'].freeze # unlike Find.find, Dir.entries returns the current/parent dirs
13
- DATA_DIR = "data"
13
+ DATA_DIR = 'data'
14
14
  MANIFESTS_DIR = 'manifests'
15
15
  EXPECTED_VERSION_SUB_DIRS = [DATA_DIR, MANIFESTS_DIR].freeze
16
- MANIFEST_INVENTORY_PATH = File.join(MANIFESTS_DIR, "manifestInventory.xml").freeze
17
- SIGNATURE_CATALOG_PATH = File.join(MANIFESTS_DIR, "signatureCatalog.xml").freeze
16
+ MANIFEST_INVENTORY_PATH = File.join(MANIFESTS_DIR, 'manifestInventory.xml').freeze
17
+ SIGNATURE_CATALOG_PATH = File.join(MANIFESTS_DIR, 'signatureCatalog.xml').freeze
18
18
 
19
- FORBIDDEN_CONTENT_SUB_DIRS = ([DATA_DIR, MANIFESTS_DIR] + EXPECTED_DATA_SUB_DIRS).freeze
19
+ VERSION_DIR_PATTERN = /^v\d{4}$/
20
20
 
21
21
  # error codes
22
22
  INCORRECT_DIR_CONTENTS = 0
@@ -26,13 +26,12 @@ module Moab
26
26
  NO_SIGNATURE_CATALOG = 4
27
27
  NO_MANIFEST_INVENTORY = 5
28
28
  NO_FILES_IN_MANIFEST_DIR = 6
29
- VERSIONS_NOT_IN_ORDER = 7
29
+ TEST_OBJECT_VERSIONS_NOT_IN_ORDER = 7
30
30
  METADATA_SUB_DIRS_DETECTED = 8
31
31
  FILES_IN_VERSION_DIR = 9
32
32
  NO_FILES_IN_METADATA_DIR = 10
33
33
  NO_FILES_IN_CONTENT_DIR = 11
34
34
  CONTENT_SUB_DIRS_DETECTED = 12
35
- BAD_SUB_DIR_IN_CONTENT_DIR = 13
36
35
 
37
36
  attr_reader :storage_obj_path
38
37
 
@@ -52,48 +51,43 @@ module Moab
52
51
  def self.error_code_to_messages
53
52
  @error_code_to_messages ||=
54
53
  {
55
- INCORRECT_DIR_CONTENTS => "Incorrect items under %{addl} directory",
56
- MISSING_DIR => "Missing directory: %{addl}",
57
- EXTRA_CHILD_DETECTED => "Unexpected item in path: %{addl}",
58
- VERSION_DIR_BAD_FORMAT => "Version directory name not in 'v00xx' format: %{addl}",
59
- FILES_IN_VERSION_DIR => "Version directory %{addl} should not contain files; only the manifests and data directories",
60
- NO_SIGNATURE_CATALOG => "Version %{addl}: Missing signatureCatalog.xml",
61
- NO_MANIFEST_INVENTORY => "Version %{addl}: Missing manifestInventory.xml",
62
- NO_FILES_IN_MANIFEST_DIR => "Version %{addl}: No files present in manifest dir",
63
- METADATA_SUB_DIRS_DETECTED => "Version %{version}: metadata directory should only contain files, not directories. Found directory: %{dir}",
64
- VERSIONS_NOT_IN_ORDER => "Should contain only sequential version directories. Current directories: %{addl}",
65
- NO_FILES_IN_METADATA_DIR => "Version %{addl}: No files present in metadata dir",
66
- NO_FILES_IN_CONTENT_DIR => "Version %{addl}: No files present in content dir",
67
- CONTENT_SUB_DIRS_DETECTED => "Version %{version}: content directory should only contain files, not directories. Found directory: %{dir}",
68
- BAD_SUB_DIR_IN_CONTENT_DIR => "Version %{addl}: content directory has forbidden sub-directory name: vnnnn or #{FORBIDDEN_CONTENT_SUB_DIRS}"
54
+ INCORRECT_DIR_CONTENTS => 'Incorrect items under %<addl>s directory',
55
+ MISSING_DIR => 'Missing directory: %<addl>s',
56
+ EXTRA_CHILD_DETECTED => 'Unexpected item in path: %<addl>s',
57
+ VERSION_DIR_BAD_FORMAT => "Version directory name not in 'v00xx' format: %<addl>s",
58
+ FILES_IN_VERSION_DIR => 'Version directory %<addl>s should not contain files; only the manifests and data directories',
59
+ NO_SIGNATURE_CATALOG => 'Version %<addl>s: Missing signatureCatalog.xml',
60
+ NO_MANIFEST_INVENTORY => 'Version %<addl>s: Missing manifestInventory.xml',
61
+ NO_FILES_IN_MANIFEST_DIR => 'Version %<addl>s: No files present in manifest dir',
62
+ METADATA_SUB_DIRS_DETECTED => 'Version %<version>s: metadata directory should only contain files, not directories. Found directory: %<dir>s',
63
+ TEST_OBJECT_VERSIONS_NOT_IN_ORDER => 'Should contain only sequential version directories. Current directories: %<addl>s',
64
+ NO_FILES_IN_METADATA_DIR => 'Version %<addl>s: No files present in metadata dir',
65
+ NO_FILES_IN_CONTENT_DIR => 'Version %<addl>s: No files present in content dir',
66
+ CONTENT_SUB_DIRS_DETECTED => 'Version %<version>s: content directory should only contain files, not directories. Found directory: %<dir>s'
69
67
  }.freeze
70
68
  end
71
69
 
72
70
  private
73
71
 
74
72
  def version_directories
75
- @vdirs ||= directory_entries(storage_obj_path)
73
+ @version_directories ||= directory_entries(storage_obj_path)
76
74
  end
77
75
 
78
76
  def check_correctly_named_version_dirs
79
77
  errors = []
80
78
  errors << result_hash(MISSING_DIR, 'no versions exist') unless version_directories.count > 0
81
79
  version_directories.each do |version_dir|
82
- errors << result_hash(VERSION_DIR_BAD_FORMAT, version_dir) unless version_dir_format?(version_dir)
80
+ errors << result_hash(VERSION_DIR_BAD_FORMAT, version_dir) unless VERSION_DIR_PATTERN.match?(version_dir)
83
81
  end
84
82
  errors
85
83
  end
86
84
 
87
- def version_dir_format?(dirname)
88
- dirname =~ /^v\d{4}$/
89
- end
90
-
91
85
  # call only if the version directories are "correctly named" vdddd
92
86
  def check_sequential_version_dirs
93
87
  version_directories.each_with_index do |dir_name, index|
94
88
  next if dir_name[1..].to_i == index + 1 # version numbering starts at 1, array indexing at 0
95
89
 
96
- return [result_hash(VERSIONS_NOT_IN_ORDER, version_directories)]
90
+ return [result_hash(TEST_OBJECT_VERSIONS_NOT_IN_ORDER, version_directories)]
97
91
  end
98
92
  []
99
93
  end
@@ -151,20 +145,9 @@ module Moab
151
145
  if content_sub_dir && !allow_content_subdirs
152
146
  errors << result_hash(CONTENT_SUB_DIRS_DETECTED, version: basename(version_path), dir: content_sub_dir)
153
147
  end
154
- if allow_content_subdirs && contains_sub_dir?(content_dir_path) && contains_forbidden_content_sub_dir?(content_dir_path)
155
- errors << result_hash(BAD_SUB_DIR_IN_CONTENT_DIR, basename(version_path))
156
- end
157
148
  errors
158
149
  end
159
150
 
160
- def contains_forbidden_content_sub_dir?(path)
161
- sub_dirs(path).detect { |sub_dir| content_sub_dir_forbidden?(sub_dir) }
162
- end
163
-
164
- def content_sub_dir_forbidden?(dirname)
165
- FORBIDDEN_CONTENT_SUB_DIRS.include?(dirname) || version_dir_format?(dirname)
166
- end
167
-
168
151
  def check_metadata_dir_files_only(version_path)
169
152
  errors = []
170
153
  metadata_dir_path = File.join(version_path, DATA_DIR, METADATA_DIR)
@@ -174,7 +174,7 @@ module Moab
174
174
  # @return [void] link or copy the specified file from source location to the version directory
175
175
  def ingest_file(source_file, target_dir, use_links = true)
176
176
  if use_links
177
- FileUtils.link(source_file.to_s, target_dir.to_s) #, :force => true)
177
+ FileUtils.link(source_file.to_s, target_dir.to_s)
178
178
  else
179
179
  FileUtils.copy(source_file.to_s, target_dir.to_s)
180
180
  end
@@ -225,7 +225,7 @@ module Moab
225
225
  # @return [VerificationResult] return true if the manifest inventory matches the actual files
226
226
  def verify_manifest_inventory
227
227
  # read/parse manifestInventory.xml
228
- result = VerificationResult.new("manifest_inventory")
228
+ result = VerificationResult.new('manifest_inventory')
229
229
  manifest_inventory = file_inventory('manifests')
230
230
  result.subentities << VerificationResult.verify_value('composite_key', composite_key, manifest_inventory.composite_key)
231
231
  result.subentities << VerificationResult.verify_truth('manifests_group', !manifest_inventory.group_empty?('manifests'))
@@ -233,7 +233,7 @@ module Moab
233
233
  directory_inventory = FileInventory.new.inventory_from_directory(@version_pathname.join('manifests'), 'manifests')
234
234
  directory_inventory.digital_object_id = storage_object.digital_object_id
235
235
  directory_group = directory_inventory.group('manifests')
236
- directory_group.remove_file_having_path("manifestInventory.xml")
236
+ directory_group.remove_file_having_path('manifestInventory.xml')
237
237
  # compare the measured signatures against the values in manifestInventory.xml
238
238
  diff = FileInventoryDifference.new
239
239
  diff.compare(manifest_inventory, directory_inventory)
@@ -247,7 +247,7 @@ module Moab
247
247
 
248
248
  # @return [VerificationResult]
249
249
  def verify_signature_catalog
250
- result = VerificationResult.new("signature_catalog")
250
+ result = VerificationResult.new('signature_catalog')
251
251
  signature_catalog = self.signature_catalog
252
252
  result.subentities << VerificationResult.verify_value('signature_key', composite_key, signature_catalog.composite_key)
253
253
  found = 0
@@ -261,7 +261,7 @@ module Moab
261
261
  missing << storage_location.to_s
262
262
  end
263
263
  end
264
- file_result = VerificationResult.new("storage_location")
264
+ file_result = VerificationResult.new('storage_location')
265
265
  file_result.verified = (found == signature_catalog.file_count)
266
266
  file_result.details = {
267
267
  'expected' => signature_catalog.file_count,
@@ -275,7 +275,7 @@ module Moab
275
275
 
276
276
  # @return [Boolean] true if files & signatures listed in version inventory can all be found
277
277
  def verify_version_inventory
278
- result = VerificationResult.new("version_inventory")
278
+ result = VerificationResult.new('version_inventory')
279
279
  version_inventory = file_inventory('version')
280
280
  result.subentities << VerificationResult.verify_value('inventory_key', composite_key, version_inventory.composite_key)
281
281
  signature_catalog = self.signature_catalog
@@ -295,7 +295,7 @@ module Moab
295
295
  end
296
296
  end
297
297
  end
298
- file_result = VerificationResult.new("catalog_entry")
298
+ file_result = VerificationResult.new('catalog_entry')
299
299
  file_result.verified = (found == version_inventory.file_count)
300
300
  file_result.details = {
301
301
  'expected' => version_inventory.file_count,
@@ -309,7 +309,7 @@ module Moab
309
309
 
310
310
  # @return [Boolean] returns true if files in data folder match files listed in version addtions inventory
311
311
  def verify_version_additions
312
- result = VerificationResult.new("version_additions")
312
+ result = VerificationResult.new('version_additions')
313
313
  version_additions = file_inventory('additions')
314
314
  result.subentities << VerificationResult.verify_value('composite_key', composite_key, version_additions.composite_key)
315
315
  data_directory = @version_pathname.join('data')
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'find' # for object_size
4
+
3
5
  module Moab
4
6
  # A class to represent the SDR repository store
5
7
  #
@@ -20,10 +22,10 @@ module Moab
20
22
  # @return [Array<Pathname>] The list of filesystem root paths in which objects are stored
21
23
  def storage_roots
22
24
  unless defined?(@storage_roots)
23
- raise(MoabRuntimeError, "Moab::Config.storage_roots not found in config file") if Moab::Config.storage_roots.nil?
25
+ raise(MoabRuntimeError, 'Moab::Config.storage_roots not found in config file') if Moab::Config.storage_roots.nil?
24
26
 
25
27
  @storage_roots = [Moab::Config.storage_roots].flatten.collect { |filesystem| Pathname(filesystem) }
26
- raise(MoabRuntimeError, "Moab::Config.storage_roots empty") if @storage_roots.empty?
28
+ raise(MoabRuntimeError, 'Moab::Config.storage_roots empty') if @storage_roots.empty?
27
29
 
28
30
  @storage_roots.each { |root| raise(MoabRuntimeError, "Storage root #{root} not found on system") unless root.exist? }
29
31
  end
@@ -33,7 +35,7 @@ module Moab
33
35
  # @return [String] The trunk segment of the object storage path
34
36
  def storage_trunk
35
37
  unless defined?(@storage_trunk)
36
- raise(MoabRuntimeError, "Moab::Config.storage_trunk not found in config file") if Moab::Config.storage_trunk.nil?
38
+ raise(MoabRuntimeError, 'Moab::Config.storage_trunk not found in config file') if Moab::Config.storage_trunk.nil?
37
39
 
38
40
  @storage_trunk = Moab::Config.storage_trunk
39
41
  end
@@ -43,7 +45,7 @@ module Moab
43
45
  # @param object_id [String] The identifier of the digital object
44
46
  # @return [String] The branch segment of the object storage path
45
47
  def storage_branch(object_id)
46
- #todo This method should be customized, or overridden in a subclass
48
+ # TODO: This method should be customized, or overridden in a subclass
47
49
  # split a object ID into 2-character segments, followed by a copy of the object ID
48
50
  # for a more sophisticated pairtree implementation see https://github.com/microservices/pairtree
49
51
  path_segments = object_id.scan(/..?/) << object_id
@@ -103,34 +105,6 @@ module Moab
103
105
  create_storage_object(object_id, root)
104
106
  end
105
107
 
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
132
- end
133
-
134
108
  # @param object_id [String] The identifier of the digital object whose size is desired
135
109
  # @param include_deposit [Boolean] specifies whether to look in deposit areas for objects in process of initial ingest
136
110
  # @return [Integer] the size occupied on disk by the storage object, in bytes. this is the entire moab (all versions).
@@ -13,81 +13,83 @@ module Moab
13
13
  # @note Copyright (c) 2012 by The Board of Trustees of the Leland Stanford Junior University.
14
14
  # All rights reserved. See {file:LICENSE.rdoc} for details.
15
15
  class StorageServices
16
- # @return [StorageRepository] an instance of the interface to SDR storage
16
+ # @note After some discussion, consensus was that this is a thread safe use of a
17
+ # class variable, as 1) it's never mutated after the class is initialized, and 2) the
18
+ # value of the StorageRepository instance is determined from configuration that
19
+ # rarely changes and is loaded once at app start time (at least in Stanford's
20
+ # consumers; see Moab::Config.configure calls in preservation_robots, preservation_catalog,
21
+ # and technical-metadata-service).
22
+ # Sidekiq requires thread safe code, so please preserve thread safety for multiple
23
+ # concurrent callers of this service if refactoring, so Sidekiq remains an option for
24
+ # ActiveJob backend for moab-versioning consumers.
17
25
  @@repository = Moab::StorageRepository.new
18
26
 
27
+ # @return [StorageRepository] an instance of the interface to SDR storage
19
28
  def self.repository
20
29
  @@repository
21
30
  end
22
31
 
23
32
  # @return [Array<Pathname>] A list of the filesystems currently used for storage
24
33
  def self.storage_roots
25
- @@repository.storage_roots
34
+ repository.storage_roots
26
35
  end
27
36
 
28
37
  # @return [String] The trunk segment of the object deposit path
29
38
  def self.deposit_trunk
30
- @@repository.deposit_trunk
39
+ repository.deposit_trunk
31
40
  end
32
41
 
33
42
  # @param object_id [String] The identifier of the digital object
34
43
  # @return [Pathname] The branch segment of the object deposit path
35
44
  def self.deposit_branch(object_id)
36
- @@repository.deposit_branch(object_id)
45
+ repository.deposit_branch(object_id)
37
46
  end
38
47
 
39
48
  # @param object_id [String] The identifier of the digital object
40
49
  # @param [Object] include_deposit
41
50
  # @return [StorageObject] The representation of a digitial object's storage directory, which might not exist yet.
42
51
  def self.find_storage_object(object_id, include_deposit = false)
43
- @@repository.find_storage_object(object_id, include_deposit)
44
- end
45
-
46
- # @param object_id [String] The identifier of the digital object
47
- # @param [Object] include_deposit
48
- # @return [Array<StorageObject>] Representations of a digitial object's storage directories, or an empty array if none found.
49
- def self.search_storage_objects(object_id, include_deposit = false)
50
- @@repository.search_storage_objects(object_id, include_deposit)
52
+ repository.find_storage_object(object_id, include_deposit)
51
53
  end
52
54
 
53
55
  # @param object_id [String] The identifier of the digital object whose size is desired
54
56
  # @param include_deposit [Boolean] specifies whether to look in deposit areas for objects in process of initial ingest
55
57
  # @return [Integer] the size occupied on disk by the storage object, in bytes. this is the entire moab (all versions).
56
58
  def self.object_size(object_id, include_deposit = false)
57
- @@repository.object_size(object_id, include_deposit)
59
+ repository.object_size(object_id, include_deposit)
58
60
  end
59
61
 
60
62
  # @param object_id [String] The identifier of the digital object whose version is desired
61
63
  # @param create [Boolean] If true, the object home directory should be created if it does not exist
62
64
  # @return [StorageObject] The representation of a digitial object's storage directory, which must exist.
63
65
  def self.storage_object(object_id, create = false)
64
- @@repository.storage_object(object_id, create)
66
+ repository.storage_object(object_id, create)
65
67
  end
66
68
 
67
69
  # @param object_id [String] The digital object identifier of the object
68
70
  # @return [String] the location of the storage object
69
71
  def self.object_path(object_id)
70
- @@repository.storage_object(object_id).object_pathname.to_s
72
+ repository.storage_object(object_id).object_pathname.to_s
71
73
  end
72
74
 
73
75
  # @param object_id [String] The digital object identifier of the object
74
76
  # @param [Integer] version_id The ID of the version, if nil use latest version
75
77
  # @return [String] the location of the storage object version
76
78
  def self.object_version_path(object_id, version_id = nil)
77
- @@repository.storage_object(object_id).find_object_version(version_id).version_pathname.to_s
79
+ repository.storage_object(object_id).find_object_version(version_id).version_pathname.to_s
78
80
  end
79
81
 
80
82
  # @param object_id [String] The digital object identifier
81
83
  # @return [Integer] The version number of the currently highest version
82
84
  def self.current_version(object_id)
83
- @@repository.storage_object(object_id).current_version_id
85
+ repository.storage_object(object_id).current_version_id
84
86
  end
85
87
 
86
88
  # @param [String] object_id The digital object identifier of the object
87
89
  # @param [Integer] version_id The ID of the version, if nil use latest version
88
90
  # @return [FileInventory] the file inventory for the specified object version
89
91
  def self.retrieve_file_group(file_category, object_id, version_id = nil)
90
- storage_object_version = @@repository.storage_object(object_id).find_object_version(version_id)
92
+ storage_object_version = repository.storage_object(object_id).find_object_version(version_id)
91
93
  inventory_type = if file_category =~ /manifest/
92
94
  file_category = 'manifests'
93
95
  else
@@ -103,7 +105,7 @@ module Moab
103
105
  # @param [Integer] version_id The ID of the version, if nil use latest version
104
106
  # @return [Pathname] Pathname object containing the full path for the specified file
105
107
  def self.retrieve_file(file_category, file_id, object_id, version_id = nil)
106
- storage_object_version = @@repository.storage_object(object_id).find_object_version(version_id)
108
+ storage_object_version = repository.storage_object(object_id).find_object_version(version_id)
107
109
  storage_object_version.find_filepath(file_category, file_id)
108
110
  end
109
111
 
@@ -113,7 +115,7 @@ module Moab
113
115
  # @param [Integer] version_id The ID of the version, if nil use latest version
114
116
  # @return [Pathname] Pathname object containing the full path for the specified file
115
117
  def self.retrieve_file_using_signature(file_category, file_signature, object_id, version_id = nil)
116
- storage_object_version = @@repository.storage_object(object_id).find_object_version(version_id)
118
+ storage_object_version = repository.storage_object(object_id).find_object_version(version_id)
117
119
  storage_object_version.find_filepath_using_signature(file_category, file_signature)
118
120
  end
119
121
 
@@ -123,7 +125,7 @@ module Moab
123
125
  # @param [Integer] version_id The ID of the version, if nil use latest version
124
126
  # @return [FileSignature] The signature of the file
125
127
  def self.retrieve_file_signature(file_category, file_id, object_id, version_id = nil)
126
- storage_object_version = @@repository.storage_object(object_id).find_object_version(version_id)
128
+ storage_object_version = repository.storage_object(object_id).find_object_version(version_id)
127
129
  storage_object_version.find_signature(file_category, file_id)
128
130
  end
129
131
 
@@ -132,8 +134,8 @@ module Moab
132
134
  # @param [Object] compare_version_id The identifier of the version to be compared to the base version
133
135
  # @return [FileInventoryDifference] The report of the version differences
134
136
  def self.version_differences(object_id, base_version_id, compare_version_id)
135
- base_version = @@repository.storage_object(object_id).storage_object_version(base_version_id)
136
- compare_version = @@repository.storage_object(object_id).storage_object_version(compare_version_id)
137
+ base_version = repository.storage_object(object_id).storage_object_version(base_version_id)
138
+ compare_version = repository.storage_object(object_id).storage_object_version(compare_version_id)
137
139
  base_inventory = base_version.file_inventory('version')
138
140
  compare_inventory = compare_version.file_inventory('version')
139
141
  FileInventoryDifference.new.compare(base_inventory, compare_inventory)
data/lib/moab/utc_time.rb CHANGED
@@ -7,7 +7,7 @@ module Moab
7
7
  # @return [void] Convert input datetime to a Time object, or nil if input is empty.
8
8
  def self.input(datetime)
9
9
  case datetime
10
- when nil, ""
10
+ when nil, ''
11
11
  nil
12
12
  when String
13
13
  Time.parse(datetime)
@@ -22,8 +22,8 @@ module Moab
22
22
  # @return [String] Convert the datetime into a ISO 8601 formatted string
23
23
  def self.output(datetime)
24
24
  case datetime
25
- when nil, ""
26
- ""
25
+ when nil, ''
26
+ ''
27
27
  when String
28
28
  Time.parse(datetime).utc.iso8601
29
29
  when Time
@@ -22,7 +22,7 @@ module Moab
22
22
  @entity = entity.to_s # force to string
23
23
  @verified = !!verified # rubocop:disable Style/DoubleNegation
24
24
  @details = details
25
- @subentities = Array.new
25
+ @subentities = []
26
26
  end
27
27
 
28
28
  # @param entity [#to_s] The name of the entity being verified
@@ -59,9 +59,9 @@ module Serializer
59
59
  def self.write_xml_file(xml_object, parent_dir, filename = nil)
60
60
  parent_dir.mkpath
61
61
  xml_pathname(parent_dir, filename).open('w') do |f|
62
- xmlBuilder = Nokogiri::XML::Builder.new(encoding: 'UTF-8')
63
- xmlBuilder = xml_object.to_xml(xmlBuilder)
64
- f << xmlBuilder.to_xml
62
+ xml_builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8')
63
+ xml_builder = xml_object.to_xml(xml_builder)
64
+ f << xml_builder.to_xml
65
65
  end
66
66
  nil
67
67
  end
@@ -120,7 +120,7 @@ module Serializer
120
120
  # @param other [Serializable] The other object being compared
121
121
  # @return [Hash] Generate a hash containing the differences between two objects of the same type
122
122
  def diff(other)
123
- raise(Moab::MoabRuntimeError, "Cannot compare different classes") if self.class != other.class
123
+ raise(Moab::MoabRuntimeError, 'Cannot compare different classes') if self.class != other.class
124
124
 
125
125
  left = other.to_hash
126
126
  right = to_hash
data/lib/serializer.rb CHANGED
@@ -19,7 +19,6 @@ require 'nokogiri'
19
19
  require 'happymapper'
20
20
  require 'json'
21
21
  require 'psych'
22
- #require 'json/pure'
23
22
  require 'pathname'
24
23
  require 'fileutils'
25
24
  require 'time'
@@ -23,7 +23,7 @@ module Stanford
23
23
  # Many of these objects have contentMetadata with no child elements, such as this:
24
24
  # <contentMetadata objectId="bd608mj3166" type="file"/>
25
25
  # but there are also objects that have no datasteam of this name at all
26
- cm_inventory = Moab::FileInventory.new(type: "version", digital_object_id: object_id, version_id: version_id)
26
+ cm_inventory = Moab::FileInventory.new(type: 'version', digital_object_id: object_id, version_id: version_id)
27
27
  content_group = group_from_cm(content_metadata, subset)
28
28
  cm_inventory.groups << content_group
29
29
  cm_inventory
@@ -45,7 +45,7 @@ module Stanford
45
45
  when 'shelve'
46
46
  ng_doc.xpath("//file[@shelve='yes']")
47
47
  when 'all'
48
- ng_doc.xpath("//file")
48
+ ng_doc.xpath('//file')
49
49
  else
50
50
  raise(Moab::MoabRuntimeError, "Unknown disposition subset (#{subset})")
51
51
  end
@@ -86,7 +86,7 @@ module Stanford
86
86
  instance.path = node.attributes['id'].content
87
87
  instance.datetime = begin
88
88
  node.attributes['datetime'].content
89
- rescue
89
+ rescue StandardError
90
90
  nil
91
91
  end
92
92
  instance
@@ -98,8 +98,8 @@ module Stanford
98
98
  # @example {include:file:spec/features/stanford/content_metadata_write_spec.rb}
99
99
  def generate_content_metadata(file_group, object_id, version_id)
100
100
  cm = Nokogiri::XML::Builder.new do |xml|
101
- xml.contentMetadata(type: "sample", objectId: object_id) do
102
- xml.resource(type: "version", sequence: "1", id: "version-#{version_id}") do
101
+ xml.contentMetadata(type: 'sample', objectId: object_id) do
102
+ xml.resource(type: 'version', sequence: '1', id: "version-#{version_id}") do
103
103
  file_group.files.each do |file_manifestation|
104
104
  signature = file_manifestation.signature
105
105
  file_manifestation.instances.each do |instance|
@@ -112,9 +112,9 @@ module Stanford
112
112
  preserve: 'yes'
113
113
  ) do
114
114
  fixity = signature.fixity
115
- xml.checksum(type: "MD5") { xml.text signature.md5 } if fixity[:md5]
116
- xml.checksum(type: "SHA-1") { xml.text signature.sha1 } if fixity[:sha1]
117
- xml.checksum(type: "SHA-256") { xml.text signature.sha256 } if fixity[:sha256]
115
+ xml.checksum(type: 'MD5') { xml.text signature.md5 } if fixity[:md5]
116
+ xml.checksum(type: 'SHA-1') { xml.text signature.sha1 } if fixity[:sha1]
117
+ xml.checksum(type: 'SHA-256') { xml.text signature.sha256 } if fixity[:sha256]
118
118
  end
119
119
  end
120
120
  end
@@ -139,16 +139,16 @@ module Stanford
139
139
  result = []
140
140
  content_metadata_doc =
141
141
  case content_metadata.class.name
142
- when "String"
142
+ when 'String'
143
143
  Nokogiri::XML(content_metadata)
144
- when "Pathname"
144
+ when 'Pathname'
145
145
  Nokogiri::XML(content_metadata.read)
146
- when "Nokogiri::XML::Document"
146
+ when 'Nokogiri::XML::Document'
147
147
  content_metadata
148
148
  else
149
- raise Moab::InvalidMetadataException, "Content Metadata is in unrecognized format"
149
+ raise Moab::InvalidMetadataException, 'Content Metadata is in unrecognized format'
150
150
  end
151
- nodeset = content_metadata_doc.xpath("//file")
151
+ nodeset = content_metadata_doc.xpath('//file')
152
152
  nodeset.each do |file_node|
153
153
  missing = %w[id size md5 sha1]
154
154
  missing.delete('id') if file_node.has_attribute?('id')
@@ -184,7 +184,7 @@ module Stanford
184
184
  @type_for_name = Moab::FileSignature.checksum_type_for_name
185
185
  @names_for_type = Moab::FileSignature.checksum_names_for_type
186
186
  ng_doc = Nokogiri::XML(content_metadata, &:noblanks)
187
- nodeset = ng_doc.xpath("//file")
187
+ nodeset = ng_doc.xpath('//file')
188
188
  nodeset.each do |file_node|
189
189
  filepath = file_node['id']
190
190
  signature = signature_for_path[filepath]
@@ -3,9 +3,22 @@
3
3
  module Stanford
4
4
  # An interface class to support access to SDR storage via a RESTful server
5
5
  class StorageServices < Moab::StorageServices
6
- # @return [StorageRepository] an instance of the interface to SDR storage
6
+ # @note After some discussion, consensus was that this is a thread safe use of a
7
+ # class variable, as 1) it's never mutated after the class is initialized, and 2) the
8
+ # value of the StorageRepository instance is determined from configuration that
9
+ # rarely changes and is loaded once at app start time (at least in Stanford's
10
+ # consumers; see Moab::Config.configure calls in preservation_robots, preservation_catalog,
11
+ # and technical-metadata-service).
12
+ # Sidekiq requires thread safe code, so please preserve thread safety for multiple
13
+ # concurrent callers of this service if refactoring, so Sidekiq remains an option for
14
+ # ActiveJob backend for moab-versioning consumers.
7
15
  @@repository = Stanford::StorageRepository.new
8
16
 
17
+ # @return [StorageRepository] an instance of the interface to SDR storage
18
+ def self.repository
19
+ @@repository
20
+ end
21
+
9
22
  # @param new_content_metadata [String] The content metadata to be compared to the base
10
23
  # @param object_id [String] The digital object identifier of the object whose version inventory is the basis of the
11
24
  # comparison
@@ -42,7 +55,7 @@ module Stanford
42
55
  begin
43
56
  # ObjectNotFoundException is raised if the object does not exist in storage
44
57
  version_id ||= current_version(object_id)
45
- storage_object_version = @@repository.storage_object(object_id).find_object_version(version_id)
58
+ storage_object_version = repository.storage_object(object_id).find_object_version(version_id)
46
59
  signature_catalog = storage_object_version.signature_catalog
47
60
  rescue Moab::ObjectNotFoundException
48
61
  storage_object = Moab::StorageObject.new(object_id, 'dummy')
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moab-versioning
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0
4
+ version: 6.0.0.alpha
5
5
  platform: ruby
6
6
  authors:
7
- - Darren Weber
8
- - Richard Anderson
9
- - Lynn McRae
10
- - Hannah Frost
11
- autorequire:
7
+ - Naomi Dushay
8
+ - Justin Coyne
9
+ - Tony Zanella
10
+ - Mike Giarlo
11
+ - John Martin
12
+ autorequire:
12
13
  bindir: bin
13
14
  cert_chain: []
14
- date: 2022-08-02 00:00:00.000000000 Z
15
+ date: 2023-01-17 00:00:00.000000000 Z
15
16
  dependencies:
16
17
  - !ruby/object:Gem::Dependency
17
18
  name: druid-tools
@@ -169,7 +170,11 @@ dependencies:
169
170
  version: '0'
170
171
  description: Contains classes to process digital object version content and metadata
171
172
  email:
172
- - darren.weber@stanford.edu
173
+ - ndushay@stanford.edu
174
+ - jcoyne85@stanford.edu
175
+ - azanella@stanford.edu
176
+ - mjgiarlo@stanford.edu
177
+ - suntzu@stanford.edu
173
178
  executables: []
174
179
  extensions: []
175
180
  extra_rdoc_files: []
@@ -210,7 +215,7 @@ licenses:
210
215
  - Apache-2.0
211
216
  metadata:
212
217
  rubygems_mfa_required: 'true'
213
- post_install_message:
218
+ post_install_message:
214
219
  rdoc_options: []
215
220
  require_paths:
216
221
  - lib
@@ -218,16 +223,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
223
  requirements:
219
224
  - - ">="
220
225
  - !ruby/object:Gem::Version
221
- version: '2.7'
226
+ version: '3.0'
222
227
  required_rubygems_version: !ruby/object:Gem::Requirement
223
228
  requirements:
224
- - - ">="
229
+ - - ">"
225
230
  - !ruby/object:Gem::Version
226
- version: '0'
231
+ version: 1.3.1
227
232
  requirements: []
228
- rubygems_version: 3.3.7
229
- signing_key:
233
+ rubygems_version: 3.2.32
234
+ signing_key:
230
235
  specification_version: 4
231
- summary: Ruby implementation of digital object versioning toolkit used by the SULAIR
232
- Digital Library
236
+ summary: Ruby implementation of digital object versioning toolkit used by Stanford
237
+ University Libraries
233
238
  test_files: []