longleaf 0.1.0 → 0.2.0.pre.1

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +13 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +4 -0
  5. data/.rubocop_todo.yml +755 -0
  6. data/README.md +29 -7
  7. data/lib/longleaf/candidates/file_selector.rb +107 -0
  8. data/lib/longleaf/candidates/service_candidate_filesystem_iterator.rb +99 -0
  9. data/lib/longleaf/candidates/service_candidate_locator.rb +18 -0
  10. data/lib/longleaf/cli.rb +102 -6
  11. data/lib/longleaf/commands/deregister_command.rb +50 -0
  12. data/lib/longleaf/commands/preserve_command.rb +45 -0
  13. data/lib/longleaf/commands/register_command.rb +24 -38
  14. data/lib/longleaf/commands/validate_config_command.rb +6 -2
  15. data/lib/longleaf/commands/validate_metadata_command.rb +49 -0
  16. data/lib/longleaf/errors.rb +19 -0
  17. data/lib/longleaf/events/deregister_event.rb +55 -0
  18. data/lib/longleaf/events/event_names.rb +9 -0
  19. data/lib/longleaf/events/event_status_tracking.rb +59 -0
  20. data/lib/longleaf/events/preserve_event.rb +71 -0
  21. data/lib/longleaf/events/register_event.rb +37 -26
  22. data/lib/longleaf/helpers/digest_helper.rb +50 -0
  23. data/lib/longleaf/helpers/service_date_helper.rb +51 -0
  24. data/lib/longleaf/logging.rb +1 -0
  25. data/lib/longleaf/logging/redirecting_logger.rb +9 -8
  26. data/lib/longleaf/models/app_fields.rb +2 -0
  27. data/lib/longleaf/models/file_record.rb +8 -3
  28. data/lib/longleaf/models/md_fields.rb +1 -0
  29. data/lib/longleaf/models/metadata_record.rb +16 -4
  30. data/lib/longleaf/models/service_definition.rb +4 -3
  31. data/lib/longleaf/models/service_fields.rb +2 -0
  32. data/lib/longleaf/models/service_record.rb +4 -1
  33. data/lib/longleaf/models/storage_location.rb +18 -1
  34. data/lib/longleaf/preservation_services/fixity_check_service.rb +121 -0
  35. data/lib/longleaf/preservation_services/rsync_replication_service.rb +183 -0
  36. data/lib/longleaf/services/application_config_deserializer.rb +4 -6
  37. data/lib/longleaf/services/application_config_manager.rb +4 -2
  38. data/lib/longleaf/services/application_config_validator.rb +1 -1
  39. data/lib/longleaf/services/configuration_validator.rb +1 -0
  40. data/lib/longleaf/services/metadata_deserializer.rb +47 -10
  41. data/lib/longleaf/services/metadata_serializer.rb +42 -6
  42. data/lib/longleaf/services/service_class_cache.rb +112 -0
  43. data/lib/longleaf/services/service_definition_manager.rb +5 -1
  44. data/lib/longleaf/services/service_definition_validator.rb +4 -4
  45. data/lib/longleaf/services/service_manager.rb +72 -9
  46. data/lib/longleaf/services/service_mapping_manager.rb +4 -3
  47. data/lib/longleaf/services/service_mapping_validator.rb +4 -4
  48. data/lib/longleaf/services/storage_location_manager.rb +26 -5
  49. data/lib/longleaf/services/storage_location_validator.rb +1 -1
  50. data/lib/longleaf/services/storage_path_validator.rb +2 -2
  51. data/lib/longleaf/specs/config_builder.rb +9 -5
  52. data/lib/longleaf/specs/custom_matchers.rb +9 -0
  53. data/lib/longleaf/specs/file_helpers.rb +60 -0
  54. data/lib/longleaf/version.rb +1 -1
  55. data/longleaf.gemspec +1 -0
  56. metadata +39 -7
  57. data/lib/longleaf/commands/abstract_command.rb +0 -37
@@ -1,14 +1,16 @@
1
1
  require_relative '../models/app_fields'
2
2
  require_relative '../models/service_definition'
3
3
 
4
- # Manager which loads and provides access to Longleaf::ServiceDefinition objects
5
4
  module Longleaf
5
+ # Manager which loads and provides access to Longleaf::ServiceDefinition objects
6
6
  class ServiceDefinitionManager
7
7
  SF ||= Longleaf::ServiceFields
8
8
  AF ||= Longleaf::AppFields
9
9
 
10
+ # Hash containing the set of configured services, represented as {ServiceDefinition} objects
10
11
  attr_reader :services
11
12
 
13
+ # @param config [Hash] hash representation of the application configuration
12
14
  def initialize(config)
13
15
  raise ArgumentError.new("Configuration must be provided") if config.nil? || config.empty?
14
16
 
@@ -18,11 +20,13 @@ module Longleaf
18
20
  @services = Hash.new
19
21
  config[AF::SERVICES].each do |name, properties|
20
22
  work_script = properties.delete(SF::WORK_SCRIPT)
23
+ work_class = properties.delete(SF::WORK_CLASS)
21
24
  frequency = properties.delete(SF::FREQUENCY)
22
25
  delay = properties.delete(SF::DELAY)
23
26
  service = Longleaf::ServiceDefinition.new(
24
27
  name: name,
25
28
  work_script: work_script,
29
+ work_class: work_class,
26
30
  frequency: frequency,
27
31
  delay: delay,
28
32
  properties: properties)
@@ -1,11 +1,11 @@
1
1
  require 'pathname'
2
- require_relative '../models/service_fields'
3
- require_relative '../models/app_fields'
4
- require_relative '../errors'
2
+ require 'longleaf/models/service_fields'
3
+ require 'longleaf/models/app_fields'
4
+ require 'longleaf/errors'
5
5
  require_relative 'configuration_validator'
6
6
 
7
- # Validates application configuration of service definitions
8
7
  module Longleaf
8
+ # Validates application configuration of service definitions
9
9
  class ServiceDefinitionValidator < ConfigurationValidator
10
10
  SF ||= Longleaf::ServiceFields
11
11
  AF ||= Longleaf::AppFields
@@ -1,21 +1,84 @@
1
- # Manager which provides preservation service definitions based on their mappings
1
+ require 'longleaf/helpers/service_date_helper'
2
+ require 'longleaf/services/service_class_cache'
3
+
2
4
  module Longleaf
5
+ # Manager which provides preservation service definitions based on their mappings
3
6
  class ServiceManager
4
-
5
- def initialize(definition_manager:, mapping_manager:)
7
+ # @param definition_manager [ServiceDefinitionManager] the service definition manager
8
+ # @param mapping_manager [ServiceMappingManager] the mapping of services to locations
9
+ # @param app_manager [ApplicationConfigManager] manager for storage locations
10
+ def initialize(definition_manager:, mapping_manager:, app_manager:)
6
11
  raise ArgumentError.new('Service definition manager required') if definition_manager.nil?
7
12
  raise ArgumentError.new('Service mappings manager required') if mapping_manager.nil?
13
+ raise ArgumentError.new('Storage location manager required') if app_manager.nil?
8
14
  @definition_manager = definition_manager
9
15
  @mapping_manager = mapping_manager
16
+ @app_manager = app_manager
17
+ @service_class_cache = ServiceClassCache.new(app_manager)
10
18
  end
11
19
 
12
- # Gets a list of ServiceDefinition objects which match the given criteria
13
- # @param location [String] name of the location to lookup
14
- # @return [Array] a list of ServiceDefinition objects associated with the location,
15
- # or an empty list if no services match the criteria
16
- def list_service_definitions(location: nil)
20
+ # List the names of services which are applicable to the given criteria
21
+ # @param location [String] name of the locations to lookup
22
+ # @param event [String] name of the preservation event taking place
23
+ # @return [Array] a list of service names which match the provided criteria
24
+ def list_services(location: nil, event: nil)
17
25
  service_names = @mapping_manager.list_services(location)
18
- service_names.collect { |name| @definition_manager.services[name] }
26
+ if !event.nil?
27
+ # Filter service names down by event
28
+ service_names.select{ |name| applicable_for_event?(name, event) }
29
+ else
30
+ service_names
31
+ end
32
+ end
33
+
34
+ # Determines if a service is applicable for a specific preservation event
35
+ # @param service_name [String] name of the service being evaluated
36
+ # @param event [String] name of the event to check against
37
+ # @return [Boolean] true if the service is applicable for the event
38
+ def applicable_for_event?(service_name, event)
39
+ definition = @definition_manager.services[service_name]
40
+ service = @service_class_cache.service_instance(definition)
41
+
42
+ service.is_applicable?(event)
43
+ end
44
+
45
+ # Determine if a service should run for a particular file based on the service's definition and
46
+ # the file's service related metadata.
47
+ # @param service_name [String] name of the service being evaluated
48
+ # @param md_rec [MetadataRecord] metadata record for the file being evaluated
49
+ # @return [Boolean] true if the service should be run.
50
+ def service_needed?(service_name, md_rec)
51
+ # If service not recorded for file, then it is needed
52
+ present_services = md_rec.list_services
53
+ return true unless present_services.include?(service_name)
54
+
55
+ service_rec = md_rec.service(service_name)
56
+
57
+ return true if service_rec.run_needed
58
+ return true if service_rec.timestamp.nil?
59
+
60
+ definition = @definition_manager.services[service_name]
61
+
62
+ # Check if the amount of time defined in frequency has passed since the service timestamp
63
+ frequency = definition.frequency
64
+ unless frequency.nil?
65
+ service_timestamp = service_rec.timestamp
66
+ now = ServiceDateHelper.formatted_timestamp
67
+
68
+ return true if now > ServiceDateHelper.add_to_timestamp(service_timestamp, frequency)
69
+ end
70
+ false
71
+ end
72
+
73
+ # Perform the specified service on the file record, in the context of the specified event
74
+ # @param service_name [String] name of the service
75
+ # @param file_rec [FileRecord] file record to perform service upon
76
+ # @param event_name [String] name of the event service is being performed within.
77
+ def perform_service(service_name, file_rec, event)
78
+ definition = @definition_manager.services[service_name]
79
+
80
+ service = @service_class_cache.service_instance(definition)
81
+ service.perform(file_rec, event)
19
82
  end
20
83
  end
21
84
  end
@@ -1,11 +1,12 @@
1
- require_relative '../models/app_fields'
2
- require_relative '../models/service_definition'
1
+ require 'longleaf/models/app_fields'
2
+ require 'longleaf/models/service_definition'
3
3
 
4
- # Manager which loads and provides access to location to service mappings
5
4
  module Longleaf
5
+ # Manager which loads and provides access to location to service mappings
6
6
  class ServiceMappingManager
7
7
  AF ||= Longleaf::AppFields
8
8
 
9
+ # @param config [Hash] has representation of the application configuration
9
10
  def initialize(config)
10
11
  raise ArgumentError.new("Configuration must be provided") if config.nil? || config.empty?
11
12
 
@@ -1,11 +1,11 @@
1
1
  require 'pathname'
2
- require_relative '../models/service_fields'
3
- require_relative '../models/app_fields'
4
- require_relative '../errors'
2
+ require 'longleaf/models/service_fields'
3
+ require 'longleaf/models/app_fields'
4
+ require 'longleaf/errors'
5
5
  require_relative 'configuration_validator'
6
6
 
7
- # Validates application configuration of service to location mappings
8
7
  module Longleaf
8
+ # Validates application configuration of service to location mappings
9
9
  class ServiceMappingValidator < ConfigurationValidator
10
10
  AF ||= Longleaf::AppFields
11
11
 
@@ -1,13 +1,16 @@
1
- require_relative '../models/app_fields'
2
- require_relative '../models/storage_location'
1
+ require 'longleaf/models/app_fields'
2
+ require 'longleaf/models/storage_location'
3
+ require 'longleaf/errors'
3
4
 
4
- # Manager which loads and provides access to Longleaf::StorageLocation objects
5
5
  module Longleaf
6
+ # Manager which loads and provides access to {StorageLocation} objects
6
7
  class StorageLocationManager
7
8
  AF ||= Longleaf::AppFields
8
9
 
10
+ # Hash mapping storage location names to {StorageLocation} objects
9
11
  attr_reader :locations
10
12
 
13
+ # @param config [Hash] has representation of the application configuration
11
14
  def initialize(config)
12
15
  raise ArgumentError.new("Configuration must be provided") if config&.empty?
13
16
 
@@ -15,14 +18,18 @@ module Longleaf
15
18
  config[AF::LOCATIONS].each do |name, properties|
16
19
  path = properties[AF::LOCATION_PATH]
17
20
  md_path = properties[AF::METADATA_PATH]
18
- location = Longleaf::StorageLocation.new(name: name, path: path, metadata_path: md_path)
21
+ md_digests = properties[AF::METADATA_DIGESTS]
22
+ location = Longleaf::StorageLocation.new(name: name,
23
+ path: path,
24
+ metadata_path: md_path,
25
+ metadata_digests: md_digests)
19
26
 
20
27
  @locations[name] = location
21
28
  end
22
29
  @locations.freeze
23
30
  end
24
31
 
25
- # Get the StorageLocation object which should contain the given path
32
+ # Get the {StorageLocation} object which should contain the given path
26
33
  # @return [Longleaf::StorageLocation] location containing the given path
27
34
  # or nil if the path is not contained by a registered location.
28
35
  def get_location_by_path(path)
@@ -33,5 +40,19 @@ module Longleaf
33
40
 
34
41
  nil
35
42
  end
43
+
44
+ # Raises a {StorageLocationUnavailableError} if the given path is not in a known storage location,
45
+ # or if it is not within the expected location if provided
46
+ # @param path [String] file path
47
+ # @param expected_loc [String] name of the storage location which path should be contained by
48
+ # @raise [StorageLocationUnavailableError] if the path is not in a known/expected storage location
49
+ def verify_path_in_location(path, expected_loc = nil)
50
+ location = get_location_by_path(path)
51
+ if location.nil?
52
+ raise StorageLocationUnavailableError.new("Path #{path} is not from a known storage location.")
53
+ elsif !expected_loc.nil? && expected_loc != location.name
54
+ raise StorageLocationUnavailableError.new("Path #{path} is not contained by storage location #{expected_loc}.")
55
+ end
56
+ end
36
57
  end
37
58
  end
@@ -5,8 +5,8 @@ require 'longleaf/errors'
5
5
  require_relative 'configuration_validator'
6
6
  require 'longleaf/services/storage_path_validator'
7
7
 
8
- # Validates application configuration of storage locations
9
8
  module Longleaf
9
+ # Validates application configuration of storage locations
10
10
  class StorageLocationValidator < ConfigurationValidator
11
11
  AF ||= Longleaf::AppFields
12
12
 
@@ -1,11 +1,11 @@
1
1
  require 'longleaf/errors'
2
2
 
3
- # Validator for storage paths
4
3
  module Longleaf
4
+ # Validator for storage paths
5
5
  class StoragePathValidator
6
6
  # Checks that the given path is a syntactically valid storage path
7
7
  # @param path [String] file storage path to validate
8
- # @raises [InvalidStoragePathError]
8
+ # @raise [InvalidStoragePathError]
9
9
  def self.validate(path)
10
10
  raise InvalidStoragePathError.new("Path must not be empty") if path.to_s.strip.empty?
11
11
  raise InvalidStoragePathError.new("Path must be absolute") unless Pathname.new(path).absolute?
@@ -1,9 +1,9 @@
1
- require_relative '../models/app_fields'
2
- require_relative '../models/service_fields'
1
+ require 'longleaf/models/app_fields'
2
+ require 'longleaf/models/service_fields'
3
3
  require 'yaml'
4
4
 
5
- # Test helper for constructing application configuration hashes
6
5
  module Longleaf
6
+ # Test helper for constructing application configuration hashes
7
7
  class ConfigBuilder
8
8
  AF ||= Longleaf::AppFields
9
9
  SF ||= Longleaf::ServiceFields
@@ -27,13 +27,14 @@ module Longleaf
27
27
  # @param path [String] value for the 'path' field
28
28
  # @param md_path [String] value for the 'metadata_path' field
29
29
  # @return this builder
30
- def with_location(name:, path: '/file/path/', md_path: '/metadata/path/')
30
+ def with_location(name:, path: '/file/path/', md_path: '/metadata/path/', md_digests: nil)
31
31
  @config[AF::LOCATIONS] = Hash.new unless @config.key?(AF::LOCATIONS)
32
32
 
33
33
  location = {}
34
34
  @config[AF::LOCATIONS][name] = location
35
35
  location[AF::LOCATION_PATH] = path unless path.nil?
36
36
  location[AF::METADATA_PATH] = md_path unless md_path.nil?
37
+ location[AF::METADATA_DIGESTS] = md_digests unless md_digests.nil?
37
38
  self
38
39
  end
39
40
 
@@ -48,15 +49,18 @@ module Longleaf
48
49
  # Add a 'service' to the config
49
50
  # @param name [String] name of the service
50
51
  # @param work_script [String] value for the 'work_script' field
52
+ # @param work_class [String] value for the 'work_class' field
51
53
  # @param frequency [String] value for the 'frequency' field
52
54
  # @param delay [String] value for the 'delay' field
53
55
  # @param properties [Hash] hash of additional properties to include in the service
54
56
  # @return this builder
55
- def with_service(name:, work_script: 'some_pres_service.rb', frequency: nil, delay: nil, properties: nil)
57
+ def with_service(name:, work_script: 'some_pres_service.rb', work_class: nil,
58
+ frequency: nil, delay: nil, properties: nil)
56
59
  @config[AF::SERVICES] = Hash.new unless @config.key?(AF::SERVICES)
57
60
 
58
61
  service = {}
59
62
  service[SF::WORK_SCRIPT] = work_script
63
+ service[SF::WORK_CLASS] = work_class
60
64
  service[SF::FREQUENCY] = frequency unless frequency.nil?
61
65
  service[SF::DELAY] = delay unless delay.nil?
62
66
  service = service.merge(properties) unless properties.nil?
@@ -0,0 +1,9 @@
1
+ module Longleaf
2
+ # Match if the parameter is a {FileRecord} with the expected path
3
+ RSpec::Matchers.define :be_file_record_for do |expected|
4
+ match do |actual|
5
+ return false if actual.nil? || !actual.is_a?(Longleaf::FileRecord)
6
+ actual.path == expected
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,60 @@
1
+ require 'tempfile'
2
+ require 'tmpdir'
3
+
4
+ module Longleaf
5
+ # Test helper methods for creating test files
6
+ module FileHelpers
7
+ def make_test_dir(parent: nil, name: 'dir')
8
+ FileHelpers.make_test_dir(parent: parent, name: name)
9
+ end
10
+
11
+ def self.make_test_dir(parent: nil, name: 'dir')
12
+ if parent.nil?
13
+ Dir.mktmpdir(name)
14
+ else
15
+ path = File.join(parent, name)
16
+ Dir.mkdir(path)
17
+ path
18
+ end
19
+ end
20
+
21
+ def create_test_file(dir: nil, name: 'test_file', content: 'content')
22
+ FileHelpers.create_test_file(dir: dir, name: name, content: content)
23
+ end
24
+
25
+ def self.create_test_file(dir: nil, name: 'test_file', content: 'content')
26
+ if dir.nil?
27
+ file = Tempfile.create(name)
28
+ file << content
29
+ file.close
30
+ return file.path
31
+ else
32
+ path = File.join(dir, name)
33
+ File.open(path, 'w') { |f| f.write(content) }
34
+ path
35
+ end
36
+ end
37
+
38
+ def create_work_class(lib_dir, class_name, file_name, module_name = nil, is_applicable: true, perform: "")
39
+ FileHelpers.create_work_class(lib_dir, class_name, file_name, module_name, is_applicable: is_applicable,
40
+ perform: perform)
41
+ end
42
+
43
+ def self.create_work_class(lib_dir, class_name, file_name, module_name = nil, is_applicable: true, perform: "")
44
+ class_contents = %Q(
45
+ class #{class_name}
46
+ def initialize(service_def, app_manager)
47
+ end
48
+ def perform(file_rec, event)
49
+ #{perform}
50
+ end
51
+ def is_applicable?(event)
52
+ #{is_applicable}
53
+ end
54
+ end
55
+ )
56
+ class_contents = "module #{module_name}\n#{class_contents}\nend" unless module_name.nil?
57
+ create_test_file(dir: lib_dir, name: file_name, content: class_contents)
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module Longleaf
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0.pre.1"
3
3
  end
data/longleaf.gemspec CHANGED
@@ -31,4 +31,5 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "rspec", "~> 3.6.0"
32
32
  spec.add_development_dependency "factory_bot", "~> 4.0"
33
33
  spec.add_development_dependency "aruba", "~> 0.14.0"
34
+ spec.add_development_dependency "bixby", ">= 2.0.0.pre.beta1"
34
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: longleaf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - bbpennel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-17 00:00:00.000000000 Z
11
+ date: 2019-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: 0.14.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: bixby
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 2.0.0.pre.beta1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 2.0.0.pre.beta1
111
125
  description: Provides a framework for performing preservation services over sets of
112
126
  files.
113
127
  email:
@@ -117,8 +131,11 @@ executables:
117
131
  extensions: []
118
132
  extra_rdoc_files: []
119
133
  files:
134
+ - ".editorconfig"
120
135
  - ".gitignore"
121
136
  - ".rspec"
137
+ - ".rubocop.yml"
138
+ - ".rubocop_todo.yml"
122
139
  - ".travis.yml"
123
140
  - Gemfile
124
141
  - LICENSE.txt
@@ -128,12 +145,23 @@ files:
128
145
  - bin/setup
129
146
  - exe/longleaf
130
147
  - lib/longleaf.rb
148
+ - lib/longleaf/candidates/file_selector.rb
149
+ - lib/longleaf/candidates/service_candidate_filesystem_iterator.rb
150
+ - lib/longleaf/candidates/service_candidate_locator.rb
131
151
  - lib/longleaf/cli.rb
132
- - lib/longleaf/commands/abstract_command.rb
152
+ - lib/longleaf/commands/deregister_command.rb
153
+ - lib/longleaf/commands/preserve_command.rb
133
154
  - lib/longleaf/commands/register_command.rb
134
155
  - lib/longleaf/commands/validate_config_command.rb
156
+ - lib/longleaf/commands/validate_metadata_command.rb
135
157
  - lib/longleaf/errors.rb
158
+ - lib/longleaf/events/deregister_event.rb
159
+ - lib/longleaf/events/event_names.rb
160
+ - lib/longleaf/events/event_status_tracking.rb
161
+ - lib/longleaf/events/preserve_event.rb
136
162
  - lib/longleaf/events/register_event.rb
163
+ - lib/longleaf/helpers/digest_helper.rb
164
+ - lib/longleaf/helpers/service_date_helper.rb
137
165
  - lib/longleaf/logging.rb
138
166
  - lib/longleaf/logging/redirecting_logger.rb
139
167
  - lib/longleaf/models/app_fields.rb
@@ -144,12 +172,15 @@ files:
144
172
  - lib/longleaf/models/service_fields.rb
145
173
  - lib/longleaf/models/service_record.rb
146
174
  - lib/longleaf/models/storage_location.rb
175
+ - lib/longleaf/preservation_services/fixity_check_service.rb
176
+ - lib/longleaf/preservation_services/rsync_replication_service.rb
147
177
  - lib/longleaf/services/application_config_deserializer.rb
148
178
  - lib/longleaf/services/application_config_manager.rb
149
179
  - lib/longleaf/services/application_config_validator.rb
150
180
  - lib/longleaf/services/configuration_validator.rb
151
181
  - lib/longleaf/services/metadata_deserializer.rb
152
182
  - lib/longleaf/services/metadata_serializer.rb
183
+ - lib/longleaf/services/service_class_cache.rb
153
184
  - lib/longleaf/services/service_definition_manager.rb
154
185
  - lib/longleaf/services/service_definition_validator.rb
155
186
  - lib/longleaf/services/service_manager.rb
@@ -159,6 +190,8 @@ files:
159
190
  - lib/longleaf/services/storage_location_validator.rb
160
191
  - lib/longleaf/services/storage_path_validator.rb
161
192
  - lib/longleaf/specs/config_builder.rb
193
+ - lib/longleaf/specs/custom_matchers.rb
194
+ - lib/longleaf/specs/file_helpers.rb
162
195
  - lib/longleaf/version.rb
163
196
  - longleaf.gemspec
164
197
  homepage: https://github.com/UNC-Libraries/
@@ -176,12 +209,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
176
209
  version: '0'
177
210
  required_rubygems_version: !ruby/object:Gem::Requirement
178
211
  requirements:
179
- - - ">="
212
+ - - ">"
180
213
  - !ruby/object:Gem::Version
181
- version: '0'
214
+ version: 1.3.1
182
215
  requirements: []
183
- rubyforge_project:
184
- rubygems_version: 2.7.6
216
+ rubygems_version: 3.0.2
185
217
  signing_key:
186
218
  specification_version: 4
187
219
  summary: Longleaf preservation services tool