longleaf 0.2.0.pre.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +84 -0
  3. data/.gitignore +4 -2
  4. data/.rubocop.yml +42 -2
  5. data/.rubocop_todo.yml +390 -311
  6. data/.yardopts +1 -0
  7. data/Gemfile +16 -1
  8. data/README.md +67 -13
  9. data/Rakefile +6 -0
  10. data/bin/setup +16 -1
  11. data/docs/aboutlongleaf.md +28 -0
  12. data/docs/extra.css +32 -0
  13. data/docs/img/change-file.png +0 -0
  14. data/docs/img/ll-example-preserved.png +0 -0
  15. data/docs/index.md +19 -0
  16. data/docs/install.md +66 -0
  17. data/docs/ll-example/config-example-relative.yml +33 -0
  18. data/docs/ll-example/files-dir/LLexample-PDF.pdf +0 -0
  19. data/docs/ll-example/files-dir/LLexample-TOCHANGE.txt +15 -0
  20. data/docs/ll-example/files-dir/LLexample-tokeep.txt +10 -0
  21. data/docs/ll-example/metadata-dir/.gitkeep +0 -0
  22. data/docs/ll-example/replica-files/.gitkeep +0 -0
  23. data/docs/ll-example/replica-metadata/.gitkeep +0 -0
  24. data/docs/quickstart.md +270 -0
  25. data/docs/rdocs/Longleaf.html +135 -0
  26. data/docs/rdocs/Longleaf/AppFields.html +178 -0
  27. data/docs/rdocs/Longleaf/ApplicationConfigDeserializer.html +631 -0
  28. data/docs/rdocs/Longleaf/ApplicationConfigManager.html +610 -0
  29. data/docs/rdocs/Longleaf/ApplicationConfigValidator.html +238 -0
  30. data/docs/rdocs/Longleaf/CLI.html +909 -0
  31. data/docs/rdocs/Longleaf/ChecksumMismatchError.html +151 -0
  32. data/docs/rdocs/Longleaf/ConfigBuilder.html +1339 -0
  33. data/docs/rdocs/Longleaf/ConfigurationError.html +143 -0
  34. data/docs/rdocs/Longleaf/ConfigurationValidator.html +227 -0
  35. data/docs/rdocs/Longleaf/DeregisterCommand.html +420 -0
  36. data/docs/rdocs/Longleaf/DeregisterEvent.html +453 -0
  37. data/docs/rdocs/Longleaf/DeregistrationError.html +151 -0
  38. data/docs/rdocs/Longleaf/DigestHelper.html +419 -0
  39. data/docs/rdocs/Longleaf/EventError.html +147 -0
  40. data/docs/rdocs/Longleaf/EventNames.html +163 -0
  41. data/docs/rdocs/Longleaf/EventStatusTracking.html +656 -0
  42. data/docs/rdocs/Longleaf/FileCheckService.html +540 -0
  43. data/docs/rdocs/Longleaf/FileHelpers.html +520 -0
  44. data/docs/rdocs/Longleaf/FileRecord.html +716 -0
  45. data/docs/rdocs/Longleaf/FileSelector.html +901 -0
  46. data/docs/rdocs/Longleaf/FixityCheckService.html +691 -0
  47. data/docs/rdocs/Longleaf/IndexManager.html +1155 -0
  48. data/docs/rdocs/Longleaf/InvalidDigestAlgorithmError.html +143 -0
  49. data/docs/rdocs/Longleaf/InvalidStoragePathError.html +143 -0
  50. data/docs/rdocs/Longleaf/Logging.html +405 -0
  51. data/docs/rdocs/Longleaf/Logging/RedirectingLogger.html +1213 -0
  52. data/docs/rdocs/Longleaf/LongleafError.html +139 -0
  53. data/docs/rdocs/Longleaf/MDFields.html +193 -0
  54. data/docs/rdocs/Longleaf/MetadataBuilder.html +787 -0
  55. data/docs/rdocs/Longleaf/MetadataDeserializer.html +537 -0
  56. data/docs/rdocs/Longleaf/MetadataError.html +143 -0
  57. data/docs/rdocs/Longleaf/MetadataPersistenceManager.html +539 -0
  58. data/docs/rdocs/Longleaf/MetadataRecord.html +1411 -0
  59. data/docs/rdocs/Longleaf/MetadataSerializer.html +786 -0
  60. data/docs/rdocs/Longleaf/PreservationServiceError.html +147 -0
  61. data/docs/rdocs/Longleaf/PreserveCommand.html +410 -0
  62. data/docs/rdocs/Longleaf/PreserveEvent.html +491 -0
  63. data/docs/rdocs/Longleaf/RegisterCommand.html +428 -0
  64. data/docs/rdocs/Longleaf/RegisterEvent.html +628 -0
  65. data/docs/rdocs/Longleaf/RegisteredFileSelector.html +446 -0
  66. data/docs/rdocs/Longleaf/RegistrationError.html +151 -0
  67. data/docs/rdocs/Longleaf/ReindexCommand.html +576 -0
  68. data/docs/rdocs/Longleaf/RsyncReplicationService.html +1180 -0
  69. data/docs/rdocs/Longleaf/SequelIndexDriver.html +1978 -0
  70. data/docs/rdocs/Longleaf/ServiceCandidateFilesystemIterator.html +572 -0
  71. data/docs/rdocs/Longleaf/ServiceCandidateIndexIterator.html +532 -0
  72. data/docs/rdocs/Longleaf/ServiceCandidateLocator.html +333 -0
  73. data/docs/rdocs/Longleaf/ServiceClassCache.html +725 -0
  74. data/docs/rdocs/Longleaf/ServiceDateHelper.html +425 -0
  75. data/docs/rdocs/Longleaf/ServiceDefinition.html +683 -0
  76. data/docs/rdocs/Longleaf/ServiceDefinitionManager.html +371 -0
  77. data/docs/rdocs/Longleaf/ServiceDefinitionValidator.html +269 -0
  78. data/docs/rdocs/Longleaf/ServiceFields.html +173 -0
  79. data/docs/rdocs/Longleaf/ServiceManager.html +1229 -0
  80. data/docs/rdocs/Longleaf/ServiceMappingManager.html +410 -0
  81. data/docs/rdocs/Longleaf/ServiceMappingValidator.html +347 -0
  82. data/docs/rdocs/Longleaf/ServiceRecord.html +821 -0
  83. data/docs/rdocs/Longleaf/StorageLocation.html +985 -0
  84. data/docs/rdocs/Longleaf/StorageLocationManager.html +729 -0
  85. data/docs/rdocs/Longleaf/StorageLocationUnavailableError.html +143 -0
  86. data/docs/rdocs/Longleaf/StorageLocationValidator.html +373 -0
  87. data/docs/rdocs/Longleaf/StoragePathValidator.html +253 -0
  88. data/docs/rdocs/Longleaf/SystemConfigBuilder.html +441 -0
  89. data/docs/rdocs/Longleaf/SystemConfigFields.html +163 -0
  90. data/docs/rdocs/Longleaf/ValidateConfigCommand.html +451 -0
  91. data/docs/rdocs/Longleaf/ValidateMetadataCommand.html +408 -0
  92. data/docs/rdocs/_index.html +660 -0
  93. data/docs/rdocs/class_list.html +51 -0
  94. data/docs/rdocs/css/common.css +1 -0
  95. data/docs/rdocs/css/full_list.css +58 -0
  96. data/docs/rdocs/css/style.css +496 -0
  97. data/docs/rdocs/file.README.html +165 -0
  98. data/docs/rdocs/file_list.html +56 -0
  99. data/docs/rdocs/frames.html +17 -0
  100. data/docs/rdocs/index.html +165 -0
  101. data/docs/rdocs/js/app.js +303 -0
  102. data/docs/rdocs/js/full_list.js +216 -0
  103. data/docs/rdocs/js/jquery.js +4 -0
  104. data/docs/rdocs/method_list.html +2051 -0
  105. data/docs/rdocs/top-level-namespace.html +110 -0
  106. data/lib/longleaf/candidates/file_selector.rb +47 -15
  107. data/lib/longleaf/candidates/registered_file_selector.rb +67 -0
  108. data/lib/longleaf/candidates/service_candidate_filesystem_iterator.rb +29 -35
  109. data/lib/longleaf/candidates/service_candidate_index_iterator.rb +84 -0
  110. data/lib/longleaf/candidates/service_candidate_locator.rb +9 -4
  111. data/lib/longleaf/cli.rb +162 -80
  112. data/lib/longleaf/commands/deregister_command.rb +12 -11
  113. data/lib/longleaf/commands/preserve_command.rb +13 -8
  114. data/lib/longleaf/commands/register_command.rb +9 -6
  115. data/lib/longleaf/commands/reindex_command.rb +92 -0
  116. data/lib/longleaf/commands/validate_config_command.rb +27 -6
  117. data/lib/longleaf/commands/validate_metadata_command.rb +11 -9
  118. data/lib/longleaf/errors.rb +12 -12
  119. data/lib/longleaf/events/deregister_event.rb +13 -15
  120. data/lib/longleaf/events/event_status_tracking.rb +7 -7
  121. data/lib/longleaf/events/preserve_event.rb +24 -14
  122. data/lib/longleaf/events/register_event.rb +21 -35
  123. data/lib/longleaf/helpers/digest_helper.rb +4 -4
  124. data/lib/longleaf/helpers/service_date_helper.rb +5 -6
  125. data/lib/longleaf/indexing/index_manager.rb +101 -0
  126. data/lib/longleaf/indexing/sequel_index_driver.rb +324 -0
  127. data/lib/longleaf/logging.rb +4 -4
  128. data/lib/longleaf/logging/redirecting_logger.rb +20 -20
  129. data/lib/longleaf/models/app_fields.rb +2 -1
  130. data/lib/longleaf/models/file_record.rb +10 -6
  131. data/lib/longleaf/models/md_fields.rb +1 -1
  132. data/lib/longleaf/models/metadata_record.rb +22 -12
  133. data/lib/longleaf/models/service_definition.rb +3 -3
  134. data/lib/longleaf/models/service_fields.rb +1 -1
  135. data/lib/longleaf/models/service_record.rb +6 -5
  136. data/lib/longleaf/models/storage_location.rb +26 -7
  137. data/lib/longleaf/models/system_config_fields.rb +9 -0
  138. data/lib/longleaf/preservation_services/file_check_service.rb +58 -0
  139. data/lib/longleaf/preservation_services/fixity_check_service.rb +16 -14
  140. data/lib/longleaf/preservation_services/rsync_replication_service.rb +32 -31
  141. data/lib/longleaf/services/application_config_deserializer.rb +55 -18
  142. data/lib/longleaf/services/application_config_manager.rb +16 -4
  143. data/lib/longleaf/services/application_config_validator.rb +1 -2
  144. data/lib/longleaf/services/configuration_validator.rb +6 -4
  145. data/lib/longleaf/services/metadata_deserializer.rb +40 -38
  146. data/lib/longleaf/services/metadata_persistence_manager.rb +46 -0
  147. data/lib/longleaf/services/metadata_serializer.rb +23 -22
  148. data/lib/longleaf/services/service_class_cache.rb +15 -15
  149. data/lib/longleaf/services/service_definition_manager.rb +5 -6
  150. data/lib/longleaf/services/service_definition_validator.rb +5 -6
  151. data/lib/longleaf/services/service_manager.rb +37 -17
  152. data/lib/longleaf/services/service_mapping_manager.rb +9 -9
  153. data/lib/longleaf/services/service_mapping_validator.rb +9 -10
  154. data/lib/longleaf/services/storage_location_manager.rb +22 -8
  155. data/lib/longleaf/services/storage_location_validator.rb +11 -8
  156. data/lib/longleaf/services/storage_path_validator.rb +1 -1
  157. data/lib/longleaf/specs/config_builder.rb +30 -17
  158. data/lib/longleaf/specs/custom_matchers.rb +1 -1
  159. data/lib/longleaf/specs/file_helpers.rb +15 -14
  160. data/lib/longleaf/specs/metadata_builder.rb +91 -0
  161. data/lib/longleaf/specs/system_config_builder.rb +27 -0
  162. data/lib/longleaf/version.rb +1 -1
  163. data/longleaf.gemspec +17 -7
  164. data/mkdocs.yml +20 -0
  165. metadata +233 -22
@@ -8,7 +8,7 @@ module Longleaf
8
8
  # Command for registering files with longleaf
9
9
  class RegisterCommand
10
10
  include Longleaf::EventStatusTracking
11
-
11
+
12
12
  def initialize(app_manager)
13
13
  @app_manager = app_manager
14
14
  end
@@ -19,16 +19,18 @@ module Longleaf
19
19
  # @param checksums [Array] array of checksums
20
20
  # @return [Integer] status code
21
21
  def execute(file_selector:, force: false, checksums: nil)
22
+ start_time = Time.now
23
+ logger.info('Performing register command')
22
24
  begin
23
25
  # Perform register events on each of the file paths provided
24
26
  loop do
25
27
  f_path = file_selector.next_path
26
28
  break if f_path.nil?
27
-
29
+
28
30
  storage_location = @app_manager.location_manager.get_location_by_path(f_path)
29
-
31
+
30
32
  file_rec = FileRecord.new(f_path, storage_location)
31
-
33
+
32
34
  register_event = RegisterEvent.new(file_rec: file_rec, force: force, app_manager: @app_manager,
33
35
  checksums: checksums)
34
36
  track_status(register_event.perform)
@@ -38,8 +40,9 @@ module Longleaf
38
40
  rescue => err
39
41
  record_failure(EventNames::REGISTER, error: err)
40
42
  end
41
-
43
+
44
+ logger.info("Completed register command in #{Time.now - start_time}s")
42
45
  return_status
43
46
  end
44
47
  end
45
- end
48
+ end
@@ -0,0 +1,92 @@
1
+ require 'longleaf/errors'
2
+ require 'longleaf/events/event_status_tracking'
3
+ require 'longleaf/logging'
4
+
5
+ module Longleaf
6
+ # Command for reindexing metadata
7
+ class ReindexCommand
8
+ include Longleaf::Logging
9
+ include Longleaf::EventStatusTracking
10
+
11
+ def initialize(app_manager)
12
+ @app_manager = app_manager
13
+ @index_manager = @app_manager.index_manager
14
+ end
15
+
16
+ # Execute the reindex command
17
+ # @param only_if_stale [boolean] if true, then the reindex command will perform no operation unless the index is stale.
18
+ # @return [Integer] status code
19
+ def execute(only_if_stale: false)
20
+ if !@index_manager.using_index?
21
+ record_failure("Cannot perform reindex, no index is configured")
22
+ return return_status
23
+ end
24
+
25
+ if only_if_stale && !@index_manager.index_stale?
26
+ record_success("Index is not stale, performing no action")
27
+ return return_status
28
+ end
29
+
30
+ start_time = Time.now
31
+ logger.info('Performing full reindex')
32
+ results = nil
33
+ begin
34
+ start_time = Time.now.utc
35
+
36
+ selector = all_storage_locations_selector
37
+
38
+ # Repopulate the index
39
+ results = index_all(selector)
40
+
41
+ # List and then clear all files which were not reindexed
42
+ @index_manager.each_registered_path(selector, older_than: start_time) do |file_path|
43
+ logger.warn("Clearing '#{file_path}' from index, file is no longer present.")
44
+ end
45
+ @index_manager.clear_index(start_time)
46
+
47
+ # Update the state of the index to indicate it has been reindexed
48
+ @index_manager.update_index_state
49
+ rescue => err
50
+ record_failure("Encountered error while reindexing", error: err)
51
+ end
52
+
53
+ if results['fail'] > 0
54
+ record_success("Completed reindexing, #{results['success']} successful, #{results['fail']} failed.")
55
+ else
56
+ record_success("Completed reindexing, #{results['success']} successful.")
57
+ end
58
+
59
+ logger.info("Completed full reindex in #{Time.now - start_time}s")
60
+ return_status
61
+ end
62
+
63
+ private
64
+ def index_all(selector)
65
+ count = 0
66
+ failures = 0
67
+
68
+ selector.each do |file_path|
69
+ begin
70
+ storage_loc = @app_manager.location_manager.get_location_by_path(file_path)
71
+ file_rec = FileRecord.new(file_path, storage_loc)
72
+
73
+ @app_manager.md_manager.load(file_rec)
74
+ @index_manager.index(file_rec)
75
+
76
+ record_success("Reindexed #{file_rec.path}")
77
+ count += 1
78
+ rescue LongleafError => err
79
+ record_failure("Failed to reindex #{file_rec.path}: #{err.message}")
80
+ failures += 1
81
+ end
82
+ end
83
+ {'success' => count, 'fail' => failures}
84
+ end
85
+
86
+ def all_storage_locations_selector
87
+ storage_loc_names = @app_manager.location_manager.locations.keys
88
+
89
+ RegisteredFileSelector.new(storage_locations: storage_loc_names, app_config: @app_manager)
90
+ end
91
+ end
92
+ end
@@ -5,29 +5,50 @@ module Longleaf
5
5
  # Command for validating an application configuration file
6
6
  class ValidateConfigCommand
7
7
  include Longleaf::EventStatusTracking
8
-
8
+
9
9
  def initialize(config_path)
10
10
  @config_path = config_path
11
11
  end
12
-
12
+
13
13
  # Execute the validate command on the specified configuration yml file
14
14
  def execute
15
+ start_time = Time.now
16
+ logger.info('Performing validate configuration command')
15
17
  begin
16
18
  app_config_manager = Longleaf::ApplicationConfigDeserializer.deserialize(@config_path)
17
-
19
+
18
20
  location_manager = app_config_manager.location_manager
19
21
  location_manager.locations.each do |name, location|
20
22
  location.available?
21
23
  end
22
-
24
+
25
+ validate_services(app_config_manager.service_manager)
26
+
23
27
  record_success("Application configuration passed validation: #{@config_path}")
24
28
  rescue Longleaf::ConfigurationError, Longleaf::StorageLocationUnavailableError => err
25
29
  record_failure("Application configuration invalid due to the following issue:\n#{err.message}")
26
30
  rescue => err
27
31
  record_failure("Failed to validate application configuration", error: err)
28
32
  end
29
-
33
+
34
+ logger.info("Completed validate configuration command in #{Time.now - start_time}s")
30
35
  return_status
31
36
  end
37
+
38
+ private
39
+ # Verify that all defined services are valid and may be instantiated with the given configuration,
40
+ # according to internal expectations.
41
+ # @raise ConfigurationError if any services may not be instantiated
42
+ def validate_services(service_manager)
43
+ def_manager = service_manager.definition_manager
44
+
45
+ def_manager.services.each do |service_name, service_def|
46
+ begin
47
+ service_manager.service(service_name)
48
+ rescue => e
49
+ raise ConfigurationError.new(e.message)
50
+ end
51
+ end
52
+ end
32
53
  end
33
- end
54
+ end
@@ -7,7 +7,7 @@ module Longleaf
7
7
  # Command for validating file metadata longleaf
8
8
  class ValidateMetadataCommand
9
9
  include Longleaf::EventStatusTracking
10
-
10
+
11
11
  def initialize(app_manager)
12
12
  @app_manager = app_manager
13
13
  end
@@ -16,34 +16,36 @@ module Longleaf
16
16
  # @param file_selector [FileSelector] selector for files to register
17
17
  # @return [Integer] status code
18
18
  def execute(file_selector:)
19
+ start_time = Time.now
20
+ logger.info('Performing validate metadata command')
19
21
  begin
20
22
  # Perform metadata validation on each of the file paths provided
21
23
  loop do
22
24
  f_path = file_selector.next_path
23
25
  break if f_path.nil?
24
-
26
+
25
27
  storage_location = @app_manager.location_manager.get_location_by_path(f_path)
26
-
28
+
27
29
  begin
28
30
  file_rec = FileRecord.new(f_path, storage_location)
29
31
  unless file_rec.metadata_present?
30
32
  raise MetadataError.new("Cannot validate metadata for #{f_path}, file is not registered.")
31
33
  end
32
-
33
- MetadataDeserializer::deserialize(file_path: file_rec.metadata_path,
34
- digest_algs: storage_location.metadata_digests)
34
+
35
+ @app_manager.md_manager.load(file_rec)
35
36
  record_success("Metadata for file passed validation: #{f_path}")
36
37
  rescue LongleafError => err
37
38
  record_failure(err.message)
38
39
  end
39
40
  end
40
- rescue InvalidStoragePathError, StorageLocationUnavailableError => err
41
+ rescue RegistrationError, InvalidStoragePathError, StorageLocationUnavailableError => err
41
42
  record_failure(err.message)
42
43
  rescue => err
43
44
  record_failure("Encountered error while validating metadata files", error: err)
44
45
  end
45
-
46
+
47
+ logger.info("Completed validate metadata command in #{Time.now - start_time}s")
46
48
  return_status
47
49
  end
48
50
  end
49
- end
51
+ end
@@ -1,34 +1,34 @@
1
1
  module Longleaf
2
2
  # General Longleaf error
3
3
  class LongleafError < StandardError; end
4
-
4
+
5
5
  # Invalid application configuration error
6
6
  class ConfigurationError < LongleafError; end
7
-
7
+
8
8
  # Invalid storage path error
9
9
  class InvalidStoragePathError < LongleafError; end
10
-
10
+
11
11
  # Metadata does not meet requirements error
12
12
  class MetadataError < LongleafError; end
13
-
13
+
14
14
  # Unavailable storage location error
15
15
  class StorageLocationUnavailableError < LongleafError; end
16
-
16
+
17
17
  # Error related to executing a preservation event
18
18
  class EventError < LongleafError; end
19
-
20
- # Error while attempting to perform a registration event
19
+
20
+ # Error with the registration state of a file or while attempting to perform a registration event
21
21
  class RegistrationError < EventError; end
22
-
22
+
23
23
  # Error while attempting to perform a deregistration event
24
24
  class DeregistrationError < EventError; end
25
-
25
+
26
26
  # Error while performing a preservation service
27
27
  class PreservationServiceError < LongleafError; end
28
-
28
+
29
29
  # Fixity check failure error
30
30
  class ChecksumMismatchError < PreservationServiceError; end
31
-
31
+
32
32
  # Error indicating an unknown or invalid digest algorithm was specified
33
33
  class InvalidDigestAlgorithmError < LongleafError; end
34
- end
34
+ end
@@ -7,7 +7,7 @@ module Longleaf
7
7
  # Event to deregister a file from longleaf
8
8
  class DeregisterEvent
9
9
  include Longleaf::EventStatusTracking
10
-
10
+
11
11
  # @param file_rec [FileRecord] file record
12
12
  # @param app_manager [ApplicationConfigManager] the application configuration
13
13
  # @param force [boolean] if true, then already deregistered files will be deregistered again
@@ -18,38 +18,36 @@ module Longleaf
18
18
  raise ArgumentError.new('Must provide an ApplicationConfigManager') if app_manager.nil?
19
19
  raise ArgumentError.new('Parameter app_manager must be an ApplicationConfigManager') \
20
20
  unless app_manager.is_a?(ApplicationConfigManager)
21
-
21
+
22
22
  @app_manager = app_manager
23
23
  @file_rec = file_rec
24
24
  @force = force
25
25
  end
26
-
26
+
27
27
  # Perform a deregistration event on the given file record
28
- # @raise DeregistrationError if a file cannot be deregistered
28
+ # @raise DeregistrationError if a file cannot be deregistered
29
29
  def perform
30
30
  begin
31
31
  md_rec = @file_rec.metadata_record
32
-
32
+
33
33
  # Only need to deregister a deregistered file if the force flag is provided
34
34
  if md_rec.deregistered? && !@force
35
35
  raise DeregistrationError.new("Unable to deregister '#{@file_rec.path}', it is already deregistered.")
36
36
  end
37
-
38
- md_rec.deregistered = Time.now.utc.iso8601
39
-
40
- # persist the metadata out to file
41
- MetadataSerializer::write(metadata: md_rec,
42
- file_path: @file_rec.metadata_path,
43
- digest_algs: @file_rec.storage_location.metadata_digests)
44
-
37
+
38
+ md_rec.deregistered = Time.now.utc.iso8601(3)
39
+
40
+ # persist the metadata
41
+ @app_manager.md_manager.persist(@file_rec)
42
+
45
43
  record_success(EventNames::DEREGISTER, @file_rec.path)
46
44
  rescue DeregistrationError => err
47
45
  record_failure(EventNames::DEREGISTER, @file_rec.path, err.message)
48
46
  rescue InvalidStoragePathError => err
49
47
  record_failure(EventNames::DEREGISTER, @file_rec.path, err.message)
50
48
  end
51
-
49
+
52
50
  return_status
53
51
  end
54
52
  end
55
- end
53
+ end
@@ -4,14 +4,14 @@ module Longleaf
4
4
  # Helper methods for tracking and recording the overall outcome of a preservation event.
5
5
  module EventStatusTracking
6
6
  include Longleaf::Logging
7
-
7
+
8
8
  # Record a successful operation to the output and the overall status of this event.
9
9
  # @param args [Array] arguments to pass to logger
10
10
  def record_success(*args)
11
11
  logger.success(*args)
12
12
  track_success
13
13
  end
14
-
14
+
15
15
  # Update the status of this action with a success outcome.
16
16
  def track_success
17
17
  if @return_status.nil? || @return_status == 0
@@ -20,14 +20,14 @@ module Longleaf
20
20
  @return_status = 2
21
21
  end
22
22
  end
23
-
23
+
24
24
  # Record a failed operation to the output and the overall status of this event.
25
25
  # @param args [Array] arguments to pass to logger
26
26
  def record_failure(*args)
27
27
  logger.failure(*args)
28
28
  track_failure
29
29
  end
30
-
30
+
31
31
  # Update the status of this action with a failure outcome.
32
32
  def track_failure
33
33
  if @return_status.nil? || @return_status == 1
@@ -36,7 +36,7 @@ module Longleaf
36
36
  @return_status = 2
37
37
  end
38
38
  end
39
-
39
+
40
40
  # Update the status of this action with the provided outcome status number.
41
41
  # @param status [Integer] outcome status
42
42
  def track_status(status)
@@ -48,7 +48,7 @@ module Longleaf
48
48
  track_failure
49
49
  end
50
50
  end
51
-
51
+
52
52
  # @return [Integer] the return status for this event, where 0 indicates success,
53
53
  # 1 indicates failure, and 2 indicates partial failure
54
54
  def return_status
@@ -56,4 +56,4 @@ module Longleaf
56
56
  @return_status
57
57
  end
58
58
  end
59
- end
59
+ end
@@ -8,30 +8,37 @@ module Longleaf
8
8
  class PreserveEvent
9
9
  include Longleaf::Logging
10
10
  include Longleaf::EventStatusTracking
11
-
11
+
12
12
  # @param file_rec [FileRecord] file record
13
13
  # @param app_manager [ApplicationConfigManager] the application configuration
14
14
  # @param force [boolean] if true, then services run regardless of whether they are flagged as needed
15
15
  def initialize(file_rec:, app_manager:, force: false)
16
16
  raise ArgumentError.new('Must provide a file_rec parameter') if file_rec.nil?
17
17
  raise ArgumentError.new('Must provide an ApplicationConfigManager') if app_manager.nil?
18
-
18
+
19
19
  @app_manager = app_manager
20
20
  @file_rec = file_rec
21
21
  @force = force
22
22
  end
23
-
23
+
24
24
  # Perform a preserve event on the given file, updating its metadata record if any services were executed.
25
25
  def perform
26
26
  storage_loc = @file_rec.storage_location
27
27
  service_manager = @app_manager.service_manager
28
28
  md_rec = @file_rec.metadata_record
29
29
  f_path = @file_rec.path
30
-
30
+
31
31
  logger.info("Performing preserve event on #{@file_rec.path}")
32
-
33
- service_performed = false
32
+
33
+ needs_persist = false
34
34
  begin
35
+ if !File.exist?(f_path)
36
+ # Need to persist metadata to avoid repeating processing of this file too soon.
37
+ needs_persist = true
38
+ record_failure(EventNames::PRESERVE, f_path, "File is registered but missing.")
39
+ return return_status
40
+ end
41
+
35
42
  # get the list of services applicable to this location and event
36
43
  service_manager.list_services(location: storage_loc.name, event: EventNames::PRESERVE).each do |service_name|
37
44
  # Skip over this service if it does not need to be run, unless force flag active
@@ -39,32 +46,35 @@ module Longleaf
39
46
  logger.debug("Service #{service_name} not needed for file '#{@file_rec.path}', skipping")
40
47
  next
41
48
  end
42
-
49
+
43
50
  begin
44
51
  logger.info("Performing preserve service #{service_name} for #{@file_rec.path}")
52
+ needs_persist = true
45
53
  # execute the service
46
54
  service_manager.perform_service(service_name, @file_rec, EventNames::PRESERVE)
47
-
55
+
48
56
  # record the outcome
49
57
  @file_rec.metadata_record.update_service_as_performed(service_name)
50
- service_performed = true
51
58
  record_success(EventNames::PRESERVE, f_path, nil, service_name)
52
59
  rescue PreservationServiceError => e
60
+ @file_rec.metadata_record.update_service_as_failed(service_name)
53
61
  record_failure(EventNames::PRESERVE, f_path, e.message, service_name)
62
+ rescue StorageLocationUnavailableError => e
63
+ raise e
54
64
  rescue StandardError => e
65
+ @file_rec.metadata_record.update_service_as_failed(service_name)
55
66
  record_failure(EventNames::PRESERVE, f_path, nil, service_name, error: e)
56
67
  return return_status
57
68
  end
58
69
  end
59
70
  ensure
60
71
  # persist the metadata out to file if any services were executed
61
- if service_performed
62
- MetadataSerializer::write(metadata: @file_rec.metadata_record,
63
- file_path: @file_rec.metadata_path,
64
- digest_algs: storage_loc.metadata_digests)
72
+ if needs_persist
73
+ # persist the metadata
74
+ @app_manager.md_manager.persist(@file_rec)
65
75
  end
66
76
  end
67
-
77
+
68
78
  return_status
69
79
  end
70
80
  end