longleaf 0.1.0.pre.2 → 1.0.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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +94 -0
  3. data/.editorconfig +13 -0
  4. data/.gitignore +4 -1
  5. data/.rubocop.yml +44 -0
  6. data/.rubocop_todo.yml +834 -0
  7. data/.yardopts +1 -0
  8. data/Gemfile +16 -1
  9. data/README.md +98 -12
  10. data/Rakefile +6 -0
  11. data/bin/setup +16 -1
  12. data/docs/aboutlongleaf.md +28 -0
  13. data/docs/extra.css +32 -0
  14. data/docs/img/change-file.png +0 -0
  15. data/docs/img/ll-example-preserved.png +0 -0
  16. data/docs/index.md +19 -0
  17. data/docs/install.md +66 -0
  18. data/docs/ll-example/config-example-relative.yml +33 -0
  19. data/docs/ll-example/files-dir/LLexample-PDF.pdf +0 -0
  20. data/docs/ll-example/files-dir/LLexample-TOCHANGE.txt +15 -0
  21. data/docs/ll-example/files-dir/LLexample-tokeep.txt +10 -0
  22. data/docs/ll-example/metadata-dir/.gitkeep +0 -0
  23. data/docs/ll-example/replica-files/.gitkeep +0 -0
  24. data/docs/ll-example/replica-metadata/.gitkeep +0 -0
  25. data/docs/quickstart.md +270 -0
  26. data/docs/rdocs/Longleaf.html +135 -0
  27. data/docs/rdocs/Longleaf/AppFields.html +178 -0
  28. data/docs/rdocs/Longleaf/ApplicationConfigDeserializer.html +631 -0
  29. data/docs/rdocs/Longleaf/ApplicationConfigManager.html +610 -0
  30. data/docs/rdocs/Longleaf/ApplicationConfigValidator.html +238 -0
  31. data/docs/rdocs/Longleaf/CLI.html +909 -0
  32. data/docs/rdocs/Longleaf/ChecksumMismatchError.html +151 -0
  33. data/docs/rdocs/Longleaf/ConfigBuilder.html +1339 -0
  34. data/docs/rdocs/Longleaf/ConfigurationError.html +143 -0
  35. data/docs/rdocs/Longleaf/ConfigurationValidator.html +227 -0
  36. data/docs/rdocs/Longleaf/DeregisterCommand.html +420 -0
  37. data/docs/rdocs/Longleaf/DeregisterEvent.html +453 -0
  38. data/docs/rdocs/Longleaf/DeregistrationError.html +151 -0
  39. data/docs/rdocs/Longleaf/DigestHelper.html +419 -0
  40. data/docs/rdocs/Longleaf/EventError.html +147 -0
  41. data/docs/rdocs/Longleaf/EventNames.html +163 -0
  42. data/docs/rdocs/Longleaf/EventStatusTracking.html +656 -0
  43. data/docs/rdocs/Longleaf/FileCheckService.html +540 -0
  44. data/docs/rdocs/Longleaf/FileHelpers.html +520 -0
  45. data/docs/rdocs/Longleaf/FileRecord.html +716 -0
  46. data/docs/rdocs/Longleaf/FileSelector.html +901 -0
  47. data/docs/rdocs/Longleaf/FixityCheckService.html +691 -0
  48. data/docs/rdocs/Longleaf/IndexManager.html +1155 -0
  49. data/docs/rdocs/Longleaf/InvalidDigestAlgorithmError.html +143 -0
  50. data/docs/rdocs/Longleaf/InvalidStoragePathError.html +143 -0
  51. data/docs/rdocs/Longleaf/Logging.html +405 -0
  52. data/docs/rdocs/Longleaf/Logging/RedirectingLogger.html +1213 -0
  53. data/docs/rdocs/Longleaf/LongleafError.html +139 -0
  54. data/docs/rdocs/Longleaf/MDFields.html +193 -0
  55. data/docs/rdocs/Longleaf/MetadataBuilder.html +787 -0
  56. data/docs/rdocs/Longleaf/MetadataDeserializer.html +537 -0
  57. data/docs/rdocs/Longleaf/MetadataError.html +143 -0
  58. data/docs/rdocs/Longleaf/MetadataPersistenceManager.html +539 -0
  59. data/docs/rdocs/Longleaf/MetadataRecord.html +1411 -0
  60. data/docs/rdocs/Longleaf/MetadataSerializer.html +786 -0
  61. data/docs/rdocs/Longleaf/PreservationServiceError.html +147 -0
  62. data/docs/rdocs/Longleaf/PreserveCommand.html +410 -0
  63. data/docs/rdocs/Longleaf/PreserveEvent.html +491 -0
  64. data/docs/rdocs/Longleaf/RegisterCommand.html +428 -0
  65. data/docs/rdocs/Longleaf/RegisterEvent.html +628 -0
  66. data/docs/rdocs/Longleaf/RegisteredFileSelector.html +446 -0
  67. data/docs/rdocs/Longleaf/RegistrationError.html +151 -0
  68. data/docs/rdocs/Longleaf/ReindexCommand.html +576 -0
  69. data/docs/rdocs/Longleaf/RsyncReplicationService.html +1180 -0
  70. data/docs/rdocs/Longleaf/SequelIndexDriver.html +1978 -0
  71. data/docs/rdocs/Longleaf/ServiceCandidateFilesystemIterator.html +572 -0
  72. data/docs/rdocs/Longleaf/ServiceCandidateIndexIterator.html +532 -0
  73. data/docs/rdocs/Longleaf/ServiceCandidateLocator.html +333 -0
  74. data/docs/rdocs/Longleaf/ServiceClassCache.html +725 -0
  75. data/docs/rdocs/Longleaf/ServiceDateHelper.html +425 -0
  76. data/docs/rdocs/Longleaf/ServiceDefinition.html +683 -0
  77. data/docs/rdocs/Longleaf/ServiceDefinitionManager.html +371 -0
  78. data/docs/rdocs/Longleaf/ServiceDefinitionValidator.html +269 -0
  79. data/docs/rdocs/Longleaf/ServiceFields.html +173 -0
  80. data/docs/rdocs/Longleaf/ServiceManager.html +1229 -0
  81. data/docs/rdocs/Longleaf/ServiceMappingManager.html +410 -0
  82. data/docs/rdocs/Longleaf/ServiceMappingValidator.html +347 -0
  83. data/docs/rdocs/Longleaf/ServiceRecord.html +821 -0
  84. data/docs/rdocs/Longleaf/StorageLocation.html +985 -0
  85. data/docs/rdocs/Longleaf/StorageLocationManager.html +729 -0
  86. data/docs/rdocs/Longleaf/StorageLocationUnavailableError.html +143 -0
  87. data/docs/rdocs/Longleaf/StorageLocationValidator.html +373 -0
  88. data/docs/rdocs/Longleaf/StoragePathValidator.html +253 -0
  89. data/docs/rdocs/Longleaf/SystemConfigBuilder.html +441 -0
  90. data/docs/rdocs/Longleaf/SystemConfigFields.html +163 -0
  91. data/docs/rdocs/Longleaf/ValidateConfigCommand.html +451 -0
  92. data/docs/rdocs/Longleaf/ValidateMetadataCommand.html +408 -0
  93. data/docs/rdocs/_index.html +660 -0
  94. data/docs/rdocs/class_list.html +51 -0
  95. data/docs/rdocs/css/common.css +1 -0
  96. data/docs/rdocs/css/full_list.css +58 -0
  97. data/docs/rdocs/css/style.css +496 -0
  98. data/docs/rdocs/file.README.html +165 -0
  99. data/docs/rdocs/file_list.html +56 -0
  100. data/docs/rdocs/frames.html +17 -0
  101. data/docs/rdocs/index.html +165 -0
  102. data/docs/rdocs/js/app.js +303 -0
  103. data/docs/rdocs/js/full_list.js +216 -0
  104. data/docs/rdocs/js/jquery.js +4 -0
  105. data/docs/rdocs/method_list.html +2051 -0
  106. data/docs/rdocs/top-level-namespace.html +110 -0
  107. data/lib/longleaf/candidates/file_selector.rb +139 -0
  108. data/lib/longleaf/candidates/manifest_digest_provider.rb +17 -0
  109. data/lib/longleaf/candidates/registered_file_selector.rb +67 -0
  110. data/lib/longleaf/candidates/service_candidate_filesystem_iterator.rb +93 -0
  111. data/lib/longleaf/candidates/service_candidate_index_iterator.rb +84 -0
  112. data/lib/longleaf/candidates/service_candidate_locator.rb +23 -0
  113. data/lib/longleaf/candidates/single_digest_provider.rb +13 -0
  114. data/lib/longleaf/cli.rb +237 -46
  115. data/lib/longleaf/commands/deregister_command.rb +51 -0
  116. data/lib/longleaf/commands/preserve_command.rb +50 -0
  117. data/lib/longleaf/commands/register_command.rb +32 -43
  118. data/lib/longleaf/commands/reindex_command.rb +92 -0
  119. data/lib/longleaf/commands/validate_config_command.rb +33 -8
  120. data/lib/longleaf/commands/validate_metadata_command.rb +51 -0
  121. data/lib/longleaf/errors.rb +26 -7
  122. data/lib/longleaf/events/deregister_event.rb +53 -0
  123. data/lib/longleaf/events/event_names.rb +9 -0
  124. data/lib/longleaf/events/event_status_tracking.rb +59 -0
  125. data/lib/longleaf/events/preserve_event.rb +81 -0
  126. data/lib/longleaf/events/register_event.rb +52 -51
  127. data/lib/longleaf/helpers/case_insensitive_hash.rb +38 -0
  128. data/lib/longleaf/helpers/digest_helper.rb +56 -0
  129. data/lib/longleaf/helpers/s3_uri_helper.rb +86 -0
  130. data/lib/longleaf/helpers/selection_options_parser.rb +189 -0
  131. data/lib/longleaf/helpers/service_date_helper.rb +78 -0
  132. data/lib/longleaf/indexing/index_manager.rb +101 -0
  133. data/lib/longleaf/indexing/sequel_index_driver.rb +306 -0
  134. data/lib/longleaf/logging.rb +5 -4
  135. data/lib/longleaf/logging/redirecting_logger.rb +26 -25
  136. data/lib/longleaf/models/app_fields.rb +7 -2
  137. data/lib/longleaf/models/file_record.rb +17 -8
  138. data/lib/longleaf/models/filesystem_metadata_location.rb +56 -0
  139. data/lib/longleaf/models/filesystem_storage_location.rb +52 -0
  140. data/lib/longleaf/models/md_fields.rb +2 -1
  141. data/lib/longleaf/models/metadata_location.rb +47 -0
  142. data/lib/longleaf/models/metadata_record.rb +39 -15
  143. data/lib/longleaf/models/s3_storage_location.rb +133 -0
  144. data/lib/longleaf/models/service_definition.rb +7 -6
  145. data/lib/longleaf/models/service_fields.rb +7 -1
  146. data/lib/longleaf/models/service_record.rb +10 -6
  147. data/lib/longleaf/models/storage_location.rb +24 -19
  148. data/lib/longleaf/models/storage_types.rb +9 -0
  149. data/lib/longleaf/models/system_config_fields.rb +9 -0
  150. data/lib/longleaf/preservation_services/file_check_service.rb +58 -0
  151. data/lib/longleaf/preservation_services/fixity_check_service.rb +123 -0
  152. data/lib/longleaf/preservation_services/rsync_replication_service.rb +182 -0
  153. data/lib/longleaf/preservation_services/s3_replication_service.rb +143 -0
  154. data/lib/longleaf/services/application_config_deserializer.rb +81 -24
  155. data/lib/longleaf/services/application_config_manager.rb +20 -6
  156. data/lib/longleaf/services/application_config_validator.rb +19 -9
  157. data/lib/longleaf/services/configuration_validator.rb +67 -4
  158. data/lib/longleaf/services/filesystem_location_validator.rb +16 -0
  159. data/lib/longleaf/services/metadata_deserializer.rb +113 -42
  160. data/lib/longleaf/services/metadata_persistence_manager.rb +47 -0
  161. data/lib/longleaf/services/metadata_serializer.rb +138 -25
  162. data/lib/longleaf/services/metadata_validator.rb +76 -0
  163. data/lib/longleaf/services/s3_location_validator.rb +19 -0
  164. data/lib/longleaf/services/service_class_cache.rb +112 -0
  165. data/lib/longleaf/services/service_definition_manager.rb +10 -7
  166. data/lib/longleaf/services/service_definition_validator.rb +25 -18
  167. data/lib/longleaf/services/service_manager.rb +86 -11
  168. data/lib/longleaf/services/service_mapping_manager.rb +13 -12
  169. data/lib/longleaf/services/service_mapping_validator.rb +36 -26
  170. data/lib/longleaf/services/storage_location_manager.rb +76 -15
  171. data/lib/longleaf/services/storage_location_validator.rb +49 -35
  172. data/lib/longleaf/specs/config_builder.rb +47 -23
  173. data/lib/longleaf/specs/config_validator_helpers.rb +16 -0
  174. data/lib/longleaf/specs/custom_matchers.rb +9 -0
  175. data/lib/longleaf/specs/file_helpers.rb +61 -0
  176. data/lib/longleaf/specs/metadata_builder.rb +92 -0
  177. data/lib/longleaf/specs/system_config_builder.rb +27 -0
  178. data/lib/longleaf/version.rb +1 -1
  179. data/longleaf.gemspec +20 -7
  180. data/mkdocs.yml +21 -0
  181. metadata +306 -23
  182. data/.travis.yml +0 -4
  183. data/lib/longleaf/commands/abstract_command.rb +0 -37
  184. data/lib/longleaf/services/storage_path_validator.rb +0 -16
@@ -1,59 +1,48 @@
1
1
  require 'longleaf/services/application_config_deserializer'
2
2
  require 'longleaf/events/register_event'
3
3
  require 'longleaf/models/file_record'
4
- require 'longleaf/commands/abstract_command'
4
+ require 'longleaf/events/event_names'
5
+ require 'longleaf/events/event_status_tracking'
5
6
 
6
- # Command for registering files with longleaf
7
7
  module Longleaf
8
- class RegisterCommand < AbstractCommand
9
-
10
- def initialize(config_path)
11
- @config_path = config_path
8
+ # Command for registering files with longleaf
9
+ class RegisterCommand
10
+ include Longleaf::EventStatusTracking
11
+
12
+ def initialize(app_manager)
13
+ @app_manager = app_manager
12
14
  end
13
15
 
14
16
  # Execute the register command on the given parameters
15
- def execute(file_paths: nil, force: false, checksums: nil)
16
- if file_paths.nil? || file_paths.empty?
17
- record_failure("Must provide one or more file paths to register")
18
- return return_status
19
- end
20
-
17
+ # @param file_selector [FileSelector] selector for files to register
18
+ # @param force [Boolean] force flag
19
+ # @param digest_provider [DigestProvider] object which provides digests for files being registered
20
+ # @return [Integer] status code
21
+ def execute(file_selector:, force: false, digest_provider: nil)
22
+ start_time = Time.now
23
+ logger.info('Performing register command')
21
24
  begin
22
- # Retrieve the application configuration
23
- app_manager = Longleaf::ApplicationConfigDeserializer.deserialize(@config_path)
24
-
25
25
  # Perform register events on each of the file paths provided
26
- file_paths.each do |f_path|
27
- begin
28
- storage_location = app_manager.location_manager.get_location_by_path(f_path)
29
- if storage_location.nil?
30
- raise InvalidStoragePathError.new(
31
- "Unable to register '#{f_path}', it does not belong to any registered storage locations.")
32
- end
33
-
34
- raise InvalidStoragePathError.new("Unable to register '#{f_path}', file does not exist or is unreachable.") \
35
- unless File.file?(f_path)
36
-
37
- file_rec = FileRecord.new(f_path, storage_location)
38
-
39
- register_event = RegisterEvent.new(file_rec: file_rec, force: force, app_manager: app_manager,
40
- checksums: checksums)
41
- register_event.perform
42
-
43
- record_success(RegisterEvent::EVENT_NAME, f_path)
44
- rescue RegistrationError => err
45
- record_failure(RegisterEvent::EVENT_NAME, f_path, err.message)
46
- rescue InvalidStoragePathError => err
47
- record_failure(RegisterEvent::EVENT_NAME, f_path, err.message)
48
- end
26
+ loop do
27
+ f_path = file_selector.next_path
28
+ break if f_path.nil?
29
+
30
+ storage_location = @app_manager.location_manager.get_location_by_path(f_path)
31
+
32
+ file_rec = FileRecord.new(f_path, storage_location)
33
+
34
+ register_event = RegisterEvent.new(file_rec: file_rec, force: force, app_manager: @app_manager,
35
+ digest_provider: digest_provider)
36
+ track_status(register_event.perform)
49
37
  end
50
- rescue ConfigurationError => err
51
- record_failure("Failed to load application configuration due to the following issue:\n#{err.message}")
38
+ rescue InvalidStoragePathError, StorageLocationUnavailableError => err
39
+ record_failure(EventNames::REGISTER, nil, err.message)
52
40
  rescue => err
53
- record_failure(RegisterEvent::EVENT_NAME, error: err)
41
+ record_failure(EventNames::REGISTER, error: err)
54
42
  end
55
-
43
+
44
+ logger.info("Completed register command in #{Time.now - start_time}s")
56
45
  return_status
57
46
  end
58
47
  end
59
- 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
@@ -1,29 +1,54 @@
1
1
  require 'longleaf/services/application_config_deserializer'
2
- require 'longleaf/commands/abstract_command'
2
+ require 'longleaf/events/event_status_tracking'
3
3
 
4
4
  module Longleaf
5
- class ValidateConfigCommand < AbstractCommand
5
+ # Command for validating an application configuration file
6
+ class ValidateConfigCommand
7
+ include Longleaf::EventStatusTracking
8
+
6
9
  def initialize(config_path)
7
10
  @config_path = config_path
8
11
  end
9
-
12
+
13
+ # Execute the validate command on the specified configuration yml file
10
14
  def execute
15
+ start_time = Time.now
16
+ logger.info('Performing validate configuration command')
11
17
  begin
12
18
  app_config_manager = Longleaf::ApplicationConfigDeserializer.deserialize(@config_path)
13
-
19
+
14
20
  location_manager = app_config_manager.location_manager
15
21
  location_manager.locations.each do |name, location|
16
22
  location.available?
17
23
  end
18
-
24
+
25
+ validate_services(app_config_manager.service_manager)
26
+
19
27
  record_success("Application configuration passed validation: #{@config_path}")
20
28
  rescue Longleaf::ConfigurationError, Longleaf::StorageLocationUnavailableError => err
21
- record_failure("Application configuration invalid due to the following issue:\n#{err.message}")
29
+ record_failure("Application configuration invalid due to the following issue(s):\n#{err.message}")
22
30
  rescue => err
23
31
  record_failure("Failed to validate application configuration", error: err)
24
32
  end
25
-
33
+
34
+ logger.info("Completed validate configuration command in #{Time.now - start_time}s")
26
35
  return_status
27
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
28
53
  end
29
- end
54
+ end
@@ -0,0 +1,51 @@
1
+ require 'longleaf/services/application_config_deserializer'
2
+ require 'longleaf/models/file_record'
3
+ require 'longleaf/events/event_status_tracking'
4
+ require 'longleaf/errors'
5
+
6
+ module Longleaf
7
+ # Command for validating file metadata longleaf
8
+ class ValidateMetadataCommand
9
+ include Longleaf::EventStatusTracking
10
+
11
+ def initialize(app_manager)
12
+ @app_manager = app_manager
13
+ end
14
+
15
+ # Execute the validation command
16
+ # @param file_selector [FileSelector] selector for files to register
17
+ # @return [Integer] status code
18
+ def execute(file_selector:)
19
+ start_time = Time.now
20
+ logger.info('Performing validate metadata command')
21
+ begin
22
+ # Perform metadata validation on each of the file paths provided
23
+ loop do
24
+ f_path = file_selector.next_path
25
+ break if f_path.nil?
26
+
27
+ storage_location = @app_manager.location_manager.get_location_by_path(f_path)
28
+
29
+ begin
30
+ file_rec = FileRecord.new(f_path, storage_location)
31
+ unless file_rec.metadata_present?
32
+ raise MetadataError.new("Cannot validate metadata for #{f_path}, file is not registered.")
33
+ end
34
+
35
+ @app_manager.md_manager.load(file_rec)
36
+ record_success("Metadata for file passed validation: #{f_path}")
37
+ rescue LongleafError => err
38
+ record_failure(err.message)
39
+ end
40
+ end
41
+ rescue RegistrationError, InvalidStoragePathError, StorageLocationUnavailableError => err
42
+ record_failure(err.message)
43
+ rescue => err
44
+ record_failure("Encountered error while validating metadata files", error: err)
45
+ end
46
+
47
+ logger.info("Completed validate metadata command in #{Time.now - start_time}s")
48
+ return_status
49
+ end
50
+ end
51
+ end
@@ -1,15 +1,34 @@
1
1
  module Longleaf
2
+ # General Longleaf error
2
3
  class LongleafError < StandardError; end
3
-
4
+
5
+ # Invalid application configuration error
4
6
  class ConfigurationError < LongleafError; end
5
-
7
+
8
+ # Invalid storage path error
6
9
  class InvalidStoragePathError < LongleafError; end
7
-
10
+
11
+ # Metadata does not meet requirements error
8
12
  class MetadataError < LongleafError; end
9
-
13
+
14
+ # Unavailable storage location error
10
15
  class StorageLocationUnavailableError < LongleafError; end
11
-
16
+
17
+ # Error related to executing a preservation event
12
18
  class EventError < LongleafError; end
13
-
19
+
20
+ # Error with the registration state of a file or while attempting to perform a registration event
14
21
  class RegistrationError < EventError; end
15
- end
22
+
23
+ # Error while attempting to perform a deregistration event
24
+ class DeregistrationError < EventError; end
25
+
26
+ # Error while performing a preservation service
27
+ class PreservationServiceError < LongleafError; end
28
+
29
+ # Fixity check failure error
30
+ class ChecksumMismatchError < PreservationServiceError; end
31
+
32
+ # Error indicating an unknown or invalid digest algorithm was specified
33
+ class InvalidDigestAlgorithmError < LongleafError; end
34
+ end
@@ -0,0 +1,53 @@
1
+ require 'longleaf/errors'
2
+ require 'longleaf/events/event_names'
3
+ require 'longleaf/events/event_status_tracking'
4
+ require 'longleaf/services/metadata_serializer'
5
+
6
+ module Longleaf
7
+ # Event to deregister a file from longleaf
8
+ class DeregisterEvent
9
+ include Longleaf::EventStatusTracking
10
+
11
+ # @param file_rec [FileRecord] file record
12
+ # @param app_manager [ApplicationConfigManager] the application configuration
13
+ # @param force [boolean] if true, then already deregistered files will be deregistered again
14
+ def initialize(file_rec:, app_manager:, force: false)
15
+ raise ArgumentError.new('Must provide a file_rec parameter') if file_rec.nil?
16
+ raise ArgumentError.new('Parameter file_rec must be a FileRecord') \
17
+ unless file_rec.is_a?(FileRecord)
18
+ raise ArgumentError.new('Must provide an ApplicationConfigManager') if app_manager.nil?
19
+ raise ArgumentError.new('Parameter app_manager must be an ApplicationConfigManager') \
20
+ unless app_manager.is_a?(ApplicationConfigManager)
21
+
22
+ @app_manager = app_manager
23
+ @file_rec = file_rec
24
+ @force = force
25
+ end
26
+
27
+ # Perform a deregistration event on the given file record
28
+ # @raise DeregistrationError if a file cannot be deregistered
29
+ def perform
30
+ begin
31
+ md_rec = @file_rec.metadata_record
32
+
33
+ # Only need to deregister a deregistered file if the force flag is provided
34
+ if md_rec.deregistered? && !@force
35
+ raise DeregistrationError.new("Unable to deregister '#{@file_rec.path}', it is already deregistered.")
36
+ end
37
+
38
+ md_rec.deregistered = Time.now.utc.iso8601(3)
39
+
40
+ # persist the metadata
41
+ @app_manager.md_manager.persist(@file_rec)
42
+
43
+ record_success(EventNames::DEREGISTER, @file_rec.path)
44
+ rescue DeregistrationError => err
45
+ record_failure(EventNames::DEREGISTER, @file_rec.path, err.message)
46
+ rescue InvalidStoragePathError => err
47
+ record_failure(EventNames::DEREGISTER, @file_rec.path, err.message)
48
+ end
49
+
50
+ return_status
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,9 @@
1
+ module Longleaf
2
+ # Constants for preservation event names
3
+ class EventNames
4
+ REGISTER = 'register'
5
+ PRESERVE = 'preserve'
6
+ CLEANUP = 'cleanup'
7
+ DEREGISTER = 'deregister'
8
+ end
9
+ end
@@ -0,0 +1,59 @@
1
+ require 'longleaf/logging'
2
+
3
+ module Longleaf
4
+ # Helper methods for tracking and recording the overall outcome of a preservation event.
5
+ module EventStatusTracking
6
+ include Longleaf::Logging
7
+
8
+ # Record a successful operation to the output and the overall status of this event.
9
+ # @param args [Array] arguments to pass to logger
10
+ def record_success(*args)
11
+ logger.success(*args)
12
+ track_success
13
+ end
14
+
15
+ # Update the status of this action with a success outcome.
16
+ def track_success
17
+ if @return_status.nil? || @return_status == 0
18
+ @return_status = 0
19
+ else
20
+ @return_status = 2
21
+ end
22
+ end
23
+
24
+ # Record a failed operation to the output and the overall status of this event.
25
+ # @param args [Array] arguments to pass to logger
26
+ def record_failure(*args)
27
+ logger.failure(*args)
28
+ track_failure
29
+ end
30
+
31
+ # Update the status of this action with a failure outcome.
32
+ def track_failure
33
+ if @return_status.nil? || @return_status == 1
34
+ @return_status = 1
35
+ else
36
+ @return_status = 2
37
+ end
38
+ end
39
+
40
+ # Update the status of this action with the provided outcome status number.
41
+ # @param status [Integer] outcome status
42
+ def track_status(status)
43
+ if status == 2
44
+ @return_status = 2
45
+ elsif status == 0
46
+ track_success
47
+ elsif status == 1
48
+ track_failure
49
+ end
50
+ end
51
+
52
+ # @return [Integer] the return status for this event, where 0 indicates success,
53
+ # 1 indicates failure, and 2 indicates partial failure
54
+ def return_status
55
+ @return_status = 0 if @return_status.nil?
56
+ @return_status
57
+ end
58
+ end
59
+ end