longleaf 0.2.0.pre.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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