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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +84 -0
- data/.gitignore +4 -2
- data/.rubocop.yml +42 -2
- data/.rubocop_todo.yml +390 -311
- data/.yardopts +1 -0
- data/Gemfile +16 -1
- data/README.md +67 -13
- data/Rakefile +6 -0
- data/bin/setup +16 -1
- data/docs/aboutlongleaf.md +28 -0
- data/docs/extra.css +32 -0
- data/docs/img/change-file.png +0 -0
- data/docs/img/ll-example-preserved.png +0 -0
- data/docs/index.md +19 -0
- data/docs/install.md +66 -0
- data/docs/ll-example/config-example-relative.yml +33 -0
- data/docs/ll-example/files-dir/LLexample-PDF.pdf +0 -0
- data/docs/ll-example/files-dir/LLexample-TOCHANGE.txt +15 -0
- data/docs/ll-example/files-dir/LLexample-tokeep.txt +10 -0
- data/docs/ll-example/metadata-dir/.gitkeep +0 -0
- data/docs/ll-example/replica-files/.gitkeep +0 -0
- data/docs/ll-example/replica-metadata/.gitkeep +0 -0
- data/docs/quickstart.md +270 -0
- data/docs/rdocs/Longleaf.html +135 -0
- data/docs/rdocs/Longleaf/AppFields.html +178 -0
- data/docs/rdocs/Longleaf/ApplicationConfigDeserializer.html +631 -0
- data/docs/rdocs/Longleaf/ApplicationConfigManager.html +610 -0
- data/docs/rdocs/Longleaf/ApplicationConfigValidator.html +238 -0
- data/docs/rdocs/Longleaf/CLI.html +909 -0
- data/docs/rdocs/Longleaf/ChecksumMismatchError.html +151 -0
- data/docs/rdocs/Longleaf/ConfigBuilder.html +1339 -0
- data/docs/rdocs/Longleaf/ConfigurationError.html +143 -0
- data/docs/rdocs/Longleaf/ConfigurationValidator.html +227 -0
- data/docs/rdocs/Longleaf/DeregisterCommand.html +420 -0
- data/docs/rdocs/Longleaf/DeregisterEvent.html +453 -0
- data/docs/rdocs/Longleaf/DeregistrationError.html +151 -0
- data/docs/rdocs/Longleaf/DigestHelper.html +419 -0
- data/docs/rdocs/Longleaf/EventError.html +147 -0
- data/docs/rdocs/Longleaf/EventNames.html +163 -0
- data/docs/rdocs/Longleaf/EventStatusTracking.html +656 -0
- data/docs/rdocs/Longleaf/FileCheckService.html +540 -0
- data/docs/rdocs/Longleaf/FileHelpers.html +520 -0
- data/docs/rdocs/Longleaf/FileRecord.html +716 -0
- data/docs/rdocs/Longleaf/FileSelector.html +901 -0
- data/docs/rdocs/Longleaf/FixityCheckService.html +691 -0
- data/docs/rdocs/Longleaf/IndexManager.html +1155 -0
- data/docs/rdocs/Longleaf/InvalidDigestAlgorithmError.html +143 -0
- data/docs/rdocs/Longleaf/InvalidStoragePathError.html +143 -0
- data/docs/rdocs/Longleaf/Logging.html +405 -0
- data/docs/rdocs/Longleaf/Logging/RedirectingLogger.html +1213 -0
- data/docs/rdocs/Longleaf/LongleafError.html +139 -0
- data/docs/rdocs/Longleaf/MDFields.html +193 -0
- data/docs/rdocs/Longleaf/MetadataBuilder.html +787 -0
- data/docs/rdocs/Longleaf/MetadataDeserializer.html +537 -0
- data/docs/rdocs/Longleaf/MetadataError.html +143 -0
- data/docs/rdocs/Longleaf/MetadataPersistenceManager.html +539 -0
- data/docs/rdocs/Longleaf/MetadataRecord.html +1411 -0
- data/docs/rdocs/Longleaf/MetadataSerializer.html +786 -0
- data/docs/rdocs/Longleaf/PreservationServiceError.html +147 -0
- data/docs/rdocs/Longleaf/PreserveCommand.html +410 -0
- data/docs/rdocs/Longleaf/PreserveEvent.html +491 -0
- data/docs/rdocs/Longleaf/RegisterCommand.html +428 -0
- data/docs/rdocs/Longleaf/RegisterEvent.html +628 -0
- data/docs/rdocs/Longleaf/RegisteredFileSelector.html +446 -0
- data/docs/rdocs/Longleaf/RegistrationError.html +151 -0
- data/docs/rdocs/Longleaf/ReindexCommand.html +576 -0
- data/docs/rdocs/Longleaf/RsyncReplicationService.html +1180 -0
- data/docs/rdocs/Longleaf/SequelIndexDriver.html +1978 -0
- data/docs/rdocs/Longleaf/ServiceCandidateFilesystemIterator.html +572 -0
- data/docs/rdocs/Longleaf/ServiceCandidateIndexIterator.html +532 -0
- data/docs/rdocs/Longleaf/ServiceCandidateLocator.html +333 -0
- data/docs/rdocs/Longleaf/ServiceClassCache.html +725 -0
- data/docs/rdocs/Longleaf/ServiceDateHelper.html +425 -0
- data/docs/rdocs/Longleaf/ServiceDefinition.html +683 -0
- data/docs/rdocs/Longleaf/ServiceDefinitionManager.html +371 -0
- data/docs/rdocs/Longleaf/ServiceDefinitionValidator.html +269 -0
- data/docs/rdocs/Longleaf/ServiceFields.html +173 -0
- data/docs/rdocs/Longleaf/ServiceManager.html +1229 -0
- data/docs/rdocs/Longleaf/ServiceMappingManager.html +410 -0
- data/docs/rdocs/Longleaf/ServiceMappingValidator.html +347 -0
- data/docs/rdocs/Longleaf/ServiceRecord.html +821 -0
- data/docs/rdocs/Longleaf/StorageLocation.html +985 -0
- data/docs/rdocs/Longleaf/StorageLocationManager.html +729 -0
- data/docs/rdocs/Longleaf/StorageLocationUnavailableError.html +143 -0
- data/docs/rdocs/Longleaf/StorageLocationValidator.html +373 -0
- data/docs/rdocs/Longleaf/StoragePathValidator.html +253 -0
- data/docs/rdocs/Longleaf/SystemConfigBuilder.html +441 -0
- data/docs/rdocs/Longleaf/SystemConfigFields.html +163 -0
- data/docs/rdocs/Longleaf/ValidateConfigCommand.html +451 -0
- data/docs/rdocs/Longleaf/ValidateMetadataCommand.html +408 -0
- data/docs/rdocs/_index.html +660 -0
- data/docs/rdocs/class_list.html +51 -0
- data/docs/rdocs/css/common.css +1 -0
- data/docs/rdocs/css/full_list.css +58 -0
- data/docs/rdocs/css/style.css +496 -0
- data/docs/rdocs/file.README.html +165 -0
- data/docs/rdocs/file_list.html +56 -0
- data/docs/rdocs/frames.html +17 -0
- data/docs/rdocs/index.html +165 -0
- data/docs/rdocs/js/app.js +303 -0
- data/docs/rdocs/js/full_list.js +216 -0
- data/docs/rdocs/js/jquery.js +4 -0
- data/docs/rdocs/method_list.html +2051 -0
- data/docs/rdocs/top-level-namespace.html +110 -0
- data/lib/longleaf/candidates/file_selector.rb +47 -15
- data/lib/longleaf/candidates/registered_file_selector.rb +67 -0
- data/lib/longleaf/candidates/service_candidate_filesystem_iterator.rb +29 -35
- data/lib/longleaf/candidates/service_candidate_index_iterator.rb +84 -0
- data/lib/longleaf/candidates/service_candidate_locator.rb +9 -4
- data/lib/longleaf/cli.rb +162 -80
- data/lib/longleaf/commands/deregister_command.rb +12 -11
- data/lib/longleaf/commands/preserve_command.rb +13 -8
- data/lib/longleaf/commands/register_command.rb +9 -6
- data/lib/longleaf/commands/reindex_command.rb +92 -0
- data/lib/longleaf/commands/validate_config_command.rb +27 -6
- data/lib/longleaf/commands/validate_metadata_command.rb +11 -9
- data/lib/longleaf/errors.rb +12 -12
- data/lib/longleaf/events/deregister_event.rb +13 -15
- data/lib/longleaf/events/event_status_tracking.rb +7 -7
- data/lib/longleaf/events/preserve_event.rb +24 -14
- data/lib/longleaf/events/register_event.rb +21 -35
- data/lib/longleaf/helpers/digest_helper.rb +4 -4
- data/lib/longleaf/helpers/service_date_helper.rb +5 -6
- data/lib/longleaf/indexing/index_manager.rb +101 -0
- data/lib/longleaf/indexing/sequel_index_driver.rb +324 -0
- data/lib/longleaf/logging.rb +4 -4
- data/lib/longleaf/logging/redirecting_logger.rb +20 -20
- data/lib/longleaf/models/app_fields.rb +2 -1
- data/lib/longleaf/models/file_record.rb +10 -6
- data/lib/longleaf/models/md_fields.rb +1 -1
- data/lib/longleaf/models/metadata_record.rb +22 -12
- data/lib/longleaf/models/service_definition.rb +3 -3
- data/lib/longleaf/models/service_fields.rb +1 -1
- data/lib/longleaf/models/service_record.rb +6 -5
- data/lib/longleaf/models/storage_location.rb +26 -7
- data/lib/longleaf/models/system_config_fields.rb +9 -0
- data/lib/longleaf/preservation_services/file_check_service.rb +58 -0
- data/lib/longleaf/preservation_services/fixity_check_service.rb +16 -14
- data/lib/longleaf/preservation_services/rsync_replication_service.rb +32 -31
- data/lib/longleaf/services/application_config_deserializer.rb +55 -18
- data/lib/longleaf/services/application_config_manager.rb +16 -4
- data/lib/longleaf/services/application_config_validator.rb +1 -2
- data/lib/longleaf/services/configuration_validator.rb +6 -4
- data/lib/longleaf/services/metadata_deserializer.rb +40 -38
- data/lib/longleaf/services/metadata_persistence_manager.rb +46 -0
- data/lib/longleaf/services/metadata_serializer.rb +23 -22
- data/lib/longleaf/services/service_class_cache.rb +15 -15
- data/lib/longleaf/services/service_definition_manager.rb +5 -6
- data/lib/longleaf/services/service_definition_validator.rb +5 -6
- data/lib/longleaf/services/service_manager.rb +37 -17
- data/lib/longleaf/services/service_mapping_manager.rb +9 -9
- data/lib/longleaf/services/service_mapping_validator.rb +9 -10
- data/lib/longleaf/services/storage_location_manager.rb +22 -8
- data/lib/longleaf/services/storage_location_validator.rb +11 -8
- data/lib/longleaf/services/storage_path_validator.rb +1 -1
- data/lib/longleaf/specs/config_builder.rb +30 -17
- data/lib/longleaf/specs/custom_matchers.rb +1 -1
- data/lib/longleaf/specs/file_helpers.rb +15 -14
- data/lib/longleaf/specs/metadata_builder.rb +91 -0
- data/lib/longleaf/specs/system_config_builder.rb +27 -0
- data/lib/longleaf/version.rb +1 -1
- data/longleaf.gemspec +17 -7
- data/mkdocs.yml +20 -0
- metadata +233 -22
|
@@ -8,42 +8,41 @@ module Longleaf
|
|
|
8
8
|
# Validates application configuration of service to location mappings
|
|
9
9
|
class ServiceMappingValidator < ConfigurationValidator
|
|
10
10
|
AF ||= Longleaf::AppFields
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
# Validates service mapping configuration to ensure that it is syntactically and referentially correct.
|
|
13
13
|
# @param config [Hash] hash containing the application configuration
|
|
14
14
|
def self.validate_config(config)
|
|
15
|
-
|
|
16
15
|
assert("Configuration must be a hash, but a #{config.class} was provided", config.class == Hash)
|
|
17
16
|
assert("Configuration must contain a root '#{AF::SERVICE_MAPPINGS}' key", config.key?(AF::SERVICE_MAPPINGS))
|
|
18
17
|
mappings = config[AF::SERVICE_MAPPINGS]
|
|
19
18
|
return if mappings.nil? || mappings.empty?
|
|
20
19
|
assert("'#{AF::SERVICE_MAPPINGS}' must be an array of mappings", mappings.is_a?(Array))
|
|
21
|
-
|
|
20
|
+
|
|
22
21
|
service_names = config[AF::SERVICES].keys
|
|
23
22
|
location_names = config[AF::LOCATIONS].keys
|
|
24
|
-
|
|
25
|
-
existing_paths = Array.new
|
|
23
|
+
|
|
26
24
|
mappings.each do |mapping|
|
|
27
25
|
assert("Mapping must be a hash, but received #{mapping.inspect} instead", mapping.is_a?(Hash))
|
|
28
|
-
|
|
26
|
+
|
|
29
27
|
validate_mapping_field(AF::LOCATIONS, mapping, location_names)
|
|
30
28
|
validate_mapping_field(AF::SERVICES, mapping, service_names)
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
|
-
|
|
34
|
-
private
|
|
31
|
+
|
|
35
32
|
def self.validate_mapping_field(field, mapping, valid_values)
|
|
36
33
|
assert("Mapping must contain a '#{field}' field", mapping.key?(field))
|
|
37
34
|
field_values = mapping[field]
|
|
38
35
|
assert("Mapping '#{field}' field must be either a string or an array, but received '#{field_values.inspect}' instead",
|
|
39
36
|
field_values.is_a?(Array) || field_values.is_a?(String))
|
|
40
37
|
assert("Mapping must specify one or more value in the '#{field}' field", !field_values.empty?)
|
|
41
|
-
|
|
38
|
+
|
|
42
39
|
check_values = field_values.is_a?(String) ? [field_values] : field_values
|
|
43
40
|
check_values.each do |value|
|
|
44
41
|
assert("Mapping '#{field}' specifies value '#{value}', but no #{field} with that name exist",
|
|
45
42
|
valid_values.include?(value))
|
|
46
43
|
end
|
|
47
44
|
end
|
|
45
|
+
|
|
46
|
+
private_class_method :validate_mapping_field
|
|
48
47
|
end
|
|
49
|
-
end
|
|
48
|
+
end
|
|
@@ -6,10 +6,10 @@ module Longleaf
|
|
|
6
6
|
# Manager which loads and provides access to {StorageLocation} objects
|
|
7
7
|
class StorageLocationManager
|
|
8
8
|
AF ||= Longleaf::AppFields
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
# Hash mapping storage location names to {StorageLocation} objects
|
|
11
11
|
attr_reader :locations
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
# @param config [Hash] has representation of the application configuration
|
|
14
14
|
def initialize(config)
|
|
15
15
|
raise ArgumentError.new("Configuration must be provided") if config&.empty?
|
|
@@ -23,29 +23,42 @@ module Longleaf
|
|
|
23
23
|
path: path,
|
|
24
24
|
metadata_path: md_path,
|
|
25
25
|
metadata_digests: md_digests)
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
@locations[name] = location
|
|
28
28
|
end
|
|
29
29
|
@locations.freeze
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
# Get the {StorageLocation} object which should contain the given path
|
|
33
33
|
# @return [Longleaf::StorageLocation] location containing the given path
|
|
34
34
|
# or nil if the path is not contained by a registered location.
|
|
35
35
|
def get_location_by_path(path)
|
|
36
36
|
raise ArgumentError.new("Path parameter is required") if path.nil? || path.empty?
|
|
37
37
|
@locations.each do |name, location|
|
|
38
|
-
return location if path.start_with?(location.path)
|
|
38
|
+
return location if path.start_with?(location.path)
|
|
39
39
|
end
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
nil
|
|
42
42
|
end
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
# Get the {StorageLocation} object which should contain the given metadata path
|
|
45
|
+
# @return [Longleaf::StorageLocation] location containing the given metadata path
|
|
46
|
+
# or nil if the path is not contained by a registered location.
|
|
47
|
+
def get_location_by_metadata_path(md_path)
|
|
48
|
+
raise ArgumentError.new("Metadata path parameter is required") if md_path.nil? || md_path.empty?
|
|
49
|
+
@locations.each do |name, location|
|
|
50
|
+
return location if md_path.start_with?(location.metadata_path)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
nil
|
|
54
|
+
end
|
|
55
|
+
|
|
44
56
|
# Raises a {StorageLocationUnavailableError} if the given path is not in a known storage location,
|
|
45
57
|
# or if it is not within the expected location if provided
|
|
46
58
|
# @param path [String] file path
|
|
47
59
|
# @param expected_loc [String] name of the storage location which path should be contained by
|
|
48
60
|
# @raise [StorageLocationUnavailableError] if the path is not in a known/expected storage location
|
|
61
|
+
# @return [StorageLocation] the storage location which contains path, if it was within one.
|
|
49
62
|
def verify_path_in_location(path, expected_loc = nil)
|
|
50
63
|
location = get_location_by_path(path)
|
|
51
64
|
if location.nil?
|
|
@@ -53,6 +66,7 @@ module Longleaf
|
|
|
53
66
|
elsif !expected_loc.nil? && expected_loc != location.name
|
|
54
67
|
raise StorageLocationUnavailableError.new("Path #{path} is not contained by storage location #{expected_loc}.")
|
|
55
68
|
end
|
|
69
|
+
location
|
|
56
70
|
end
|
|
57
71
|
end
|
|
58
|
-
end
|
|
72
|
+
end
|
|
@@ -9,8 +9,8 @@ module Longleaf
|
|
|
9
9
|
# Validates application configuration of storage locations
|
|
10
10
|
class StorageLocationValidator < ConfigurationValidator
|
|
11
11
|
AF ||= Longleaf::AppFields
|
|
12
|
-
|
|
13
|
-
# Validates configuration to ensure that it is syntactically correct and does not violate
|
|
12
|
+
|
|
13
|
+
# Validates configuration to ensure that it is syntactically correct and does not violate
|
|
14
14
|
# schema and uniqueness requirements.
|
|
15
15
|
# @param config [Hash] hash containing the application configuration
|
|
16
16
|
def self.validate_config(config)
|
|
@@ -18,18 +18,17 @@ module Longleaf
|
|
|
18
18
|
assert("Configuration must contain a root '#{AF::LOCATIONS}' key", config.key?(AF::LOCATIONS))
|
|
19
19
|
locations = config[AF::LOCATIONS]
|
|
20
20
|
assert("'#{AF::LOCATIONS}' must be a hash of locations", locations.class == Hash)
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
existing_paths = Array.new
|
|
23
23
|
locations.each do |name, properties|
|
|
24
24
|
assert("Name of storage location must be a string, but was of type #{name.class}", name.instance_of?(String))
|
|
25
25
|
assert("Storage location '#{name}' must be a hash, but a #{properties.class} was provided", properties.is_a?(Hash))
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
assert_path_property_valid(name, AF::LOCATION_PATH, properties, existing_paths)
|
|
28
28
|
assert_path_property_valid(name, AF::METADATA_PATH, properties, existing_paths)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
|
-
|
|
32
|
-
private
|
|
31
|
+
|
|
33
32
|
def self.assert_path_property_valid(name, path_prop, properties, existing_paths)
|
|
34
33
|
path = properties[path_prop]
|
|
35
34
|
begin
|
|
@@ -41,6 +40,8 @@ module Longleaf
|
|
|
41
40
|
assert("Storage location '#{name}' must specify a '#{path_prop}' property", !path.nil? && !path.empty?)
|
|
42
41
|
assert("Storage location '#{name}' must specify an absolute path for property '#{path_prop}'",
|
|
43
42
|
Pathname.new(path).absolute? && !path.include?('/..'))
|
|
43
|
+
assert("Storage location '#{name}' specifies a '#{path_prop}' directory which does not exist", Dir.exist?(path))
|
|
44
|
+
|
|
44
45
|
# Ensure paths have trailing slash to avoid matching on partial directory names
|
|
45
46
|
path += '/' unless path.end_with?('/')
|
|
46
47
|
# Verify that the (metadata_)path property's value is not inside of another storage location or vice versa
|
|
@@ -53,8 +54,10 @@ module Longleaf
|
|
|
53
54
|
raise ConfigurationError.new(msg)
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
existing_paths << path
|
|
58
59
|
end
|
|
60
|
+
|
|
61
|
+
private_class_method :assert_path_property_valid
|
|
59
62
|
end
|
|
60
|
-
end
|
|
63
|
+
end
|
|
@@ -7,13 +7,13 @@ module Longleaf
|
|
|
7
7
|
class ConfigBuilder
|
|
8
8
|
AF ||= Longleaf::AppFields
|
|
9
9
|
SF ||= Longleaf::ServiceFields
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
attr_accessor :config
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def initialize
|
|
14
14
|
@config = Hash.new
|
|
15
15
|
end
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
# Add a root 'locations' field to the config
|
|
18
18
|
# @param locations [Hash] value for the locations fields. Default is {}
|
|
19
19
|
# @return this builder
|
|
@@ -21,7 +21,7 @@ module Longleaf
|
|
|
21
21
|
@config[AF::LOCATIONS] = locations
|
|
22
22
|
self
|
|
23
23
|
end
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
# Add a 'location' to the config
|
|
26
26
|
# @param name [String] name of the location
|
|
27
27
|
# @param path [String] value for the 'path' field
|
|
@@ -29,7 +29,7 @@ module Longleaf
|
|
|
29
29
|
# @return this builder
|
|
30
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?
|
|
@@ -37,7 +37,7 @@ module Longleaf
|
|
|
37
37
|
location[AF::METADATA_DIGESTS] = md_digests unless md_digests.nil?
|
|
38
38
|
self
|
|
39
39
|
end
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
# Add a root 'services' field to the config
|
|
42
42
|
# @param services [Hash] value for the services field. Default is {}
|
|
43
43
|
# @return this builder
|
|
@@ -45,7 +45,7 @@ module Longleaf
|
|
|
45
45
|
@config[AF::SERVICES] = services
|
|
46
46
|
self
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
# Add a 'service' to the config
|
|
50
50
|
# @param name [String] name of the service
|
|
51
51
|
# @param work_script [String] value for the 'work_script' field
|
|
@@ -57,7 +57,7 @@ module Longleaf
|
|
|
57
57
|
def with_service(name:, work_script: 'some_pres_service.rb', work_class: nil,
|
|
58
58
|
frequency: nil, delay: nil, properties: nil)
|
|
59
59
|
@config[AF::SERVICES] = Hash.new unless @config.key?(AF::SERVICES)
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
service = {}
|
|
62
62
|
service[SF::WORK_SCRIPT] = work_script
|
|
63
63
|
service[SF::WORK_CLASS] = work_class
|
|
@@ -67,7 +67,7 @@ module Longleaf
|
|
|
67
67
|
@config[AF::SERVICES][name] = service
|
|
68
68
|
self
|
|
69
69
|
end
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
# Adds a 'service_mappings' section to the config
|
|
72
72
|
# @param mappings [Object] the mappings config
|
|
73
73
|
# @return this builder
|
|
@@ -75,32 +75,45 @@ module Longleaf
|
|
|
75
75
|
@config[AF::SERVICE_MAPPINGS] = mappings
|
|
76
76
|
self
|
|
77
77
|
end
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
# Add a mapping from one or more services to one or more location
|
|
80
80
|
# @param loc_names [Object] one or more location names. Can be a string or array.
|
|
81
81
|
# @param service_names [Object] one or more service names. Can be a string or array.
|
|
82
82
|
def map_services(loc_names, service_names)
|
|
83
83
|
@config[AF::SERVICE_MAPPINGS] = Array.new unless @config.key?(AF::SERVICE_MAPPINGS)
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
mapping = Hash.new
|
|
86
86
|
mapping[AF::LOCATIONS] = loc_names unless loc_names.nil?
|
|
87
87
|
mapping[AF::SERVICES] = service_names unless service_names.nil?
|
|
88
88
|
@config[AF::SERVICE_MAPPINGS].push(mapping)
|
|
89
89
|
self
|
|
90
90
|
end
|
|
91
|
-
|
|
91
|
+
|
|
92
|
+
# Add a system config section to the config
|
|
93
|
+
def with_system(sys_config)
|
|
94
|
+
@config[AF::SYSTEM] = sys_config
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
92
98
|
# @return the constructed configuration
|
|
93
99
|
def get
|
|
94
100
|
@config
|
|
95
101
|
end
|
|
96
|
-
|
|
102
|
+
|
|
97
103
|
# Writes the configuration from this builder into a temporary file
|
|
98
104
|
# @return the file path of the config file
|
|
99
|
-
def write_to_yaml_file
|
|
100
|
-
|
|
105
|
+
def write_to_yaml_file(dest_path = nil)
|
|
106
|
+
if dest_path.nil?
|
|
107
|
+
file = Tempfile.new('config')
|
|
108
|
+
file.close
|
|
109
|
+
dest_path = file.path
|
|
110
|
+
# deleting temp file but reusing file name. This is to avoid premature garbage collection.
|
|
111
|
+
file.unlink
|
|
112
|
+
end
|
|
113
|
+
File.open(dest_path, 'w') do |f|
|
|
101
114
|
f.write(@config.to_yaml)
|
|
102
|
-
return f.path
|
|
103
115
|
end
|
|
116
|
+
dest_path
|
|
104
117
|
end
|
|
105
118
|
end
|
|
106
|
-
end
|
|
119
|
+
end
|
|
@@ -7,7 +7,7 @@ module Longleaf
|
|
|
7
7
|
def make_test_dir(parent: nil, name: 'dir')
|
|
8
8
|
FileHelpers.make_test_dir(parent: parent, name: name)
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
def self.make_test_dir(parent: nil, name: 'dir')
|
|
12
12
|
if parent.nil?
|
|
13
13
|
Dir.mktmpdir(name)
|
|
@@ -17,14 +17,15 @@ module Longleaf
|
|
|
17
17
|
path
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
|
-
|
|
21
|
-
def create_test_file(dir: nil, name:
|
|
20
|
+
|
|
21
|
+
def create_test_file(dir: nil, name: nil, content: 'content')
|
|
22
22
|
FileHelpers.create_test_file(dir: dir, name: name, content: content)
|
|
23
23
|
end
|
|
24
|
-
|
|
25
|
-
def self.create_test_file(dir: nil, name:
|
|
26
|
-
if dir.nil?
|
|
27
|
-
|
|
24
|
+
|
|
25
|
+
def self.create_test_file(dir: nil, name: nil, content: 'content')
|
|
26
|
+
if dir.nil? || name.nil?
|
|
27
|
+
name = 'test_file' if name.nil?
|
|
28
|
+
file = Tempfile.create(name, dir)
|
|
28
29
|
file << content
|
|
29
30
|
file.close
|
|
30
31
|
return file.path
|
|
@@ -34,16 +35,16 @@ module Longleaf
|
|
|
34
35
|
path
|
|
35
36
|
end
|
|
36
37
|
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
|
|
40
|
-
perform: perform)
|
|
38
|
+
|
|
39
|
+
def create_work_class(lib_dir, class_name, file_name, module_name = nil, is_applicable: true, init_body: "", perform: "")
|
|
40
|
+
FileHelpers.create_work_class(lib_dir, class_name, file_name, module_name, is_applicable, init_body, perform)
|
|
41
41
|
end
|
|
42
|
-
|
|
43
|
-
def self.create_work_class(lib_dir, class_name, file_name, module_name
|
|
42
|
+
|
|
43
|
+
def self.create_work_class(lib_dir, class_name, file_name, module_name, is_applicable, init_body, perform)
|
|
44
44
|
class_contents = %Q(
|
|
45
45
|
class #{class_name}
|
|
46
46
|
def initialize(service_def, app_manager)
|
|
47
|
+
#{init_body}
|
|
47
48
|
end
|
|
48
49
|
def perform(file_rec, event)
|
|
49
50
|
#{perform}
|
|
@@ -57,4 +58,4 @@ module Longleaf
|
|
|
57
58
|
create_test_file(dir: lib_dir, name: file_name, content: class_contents)
|
|
58
59
|
end
|
|
59
60
|
end
|
|
60
|
-
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require 'longleaf/models/md_fields'
|
|
2
|
+
require 'longleaf/helpers/service_date_helper'
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Longleaf
|
|
6
|
+
# Test helper for constructing file metadata records
|
|
7
|
+
class MetadataBuilder
|
|
8
|
+
MF ||= Longleaf::MDFields
|
|
9
|
+
|
|
10
|
+
def initialize(file_path: nil, registered: ServiceDateHelper::formatted_timestamp)
|
|
11
|
+
@data = Hash.new
|
|
12
|
+
@services = Hash.new
|
|
13
|
+
|
|
14
|
+
unless file_path.nil?
|
|
15
|
+
@last_modified = File.mtime(file_path).utc.iso8601(3)
|
|
16
|
+
@file_size = File.size(file_path)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@registered = registered
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def deregistered(timestamp = ServiceDateHelper::formatted_timestamp)
|
|
23
|
+
@deregistered = timestamp
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def with_checksum(alg, value)
|
|
28
|
+
@checksums = Hash.new unless @data.key?(MF::CHECKSUMS)
|
|
29
|
+
@checksums[alg] = value
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def with_service(name, timestamp: ServiceDateHelper::formatted_timestamp, run_needed: false, properties: nil,
|
|
34
|
+
failure_timestamp: nil)
|
|
35
|
+
timestamp = format_timestamp(timestamp)
|
|
36
|
+
failure_timestamp = format_timestamp(failure_timestamp) unless failure_timestamp.nil?
|
|
37
|
+
|
|
38
|
+
@services[name] = ServiceRecord.new(
|
|
39
|
+
properties: properties.nil? ? Hash.new : nil,
|
|
40
|
+
timestamp: timestamp,
|
|
41
|
+
run_needed: run_needed)
|
|
42
|
+
@services[name].failure_timestamp = failure_timestamp
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def with_properties(properties)
|
|
47
|
+
@properties = properties
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @return the constructed metadata record
|
|
51
|
+
def get_metadata_record
|
|
52
|
+
MetadataRecord.new(properties: @properties,
|
|
53
|
+
services: @services,
|
|
54
|
+
deregistered: @deregistered,
|
|
55
|
+
registered: @registered,
|
|
56
|
+
checksums: @checksums,
|
|
57
|
+
file_size: @file_size,
|
|
58
|
+
last_modified: @last_modified)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Add the generated metadata record to the given file record
|
|
62
|
+
def register_to(file_rec)
|
|
63
|
+
file_rec.metadata_record = get_metadata_record
|
|
64
|
+
self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Writes the metadata record from this builder into a temporary file, or if a file
|
|
68
|
+
# record is provided, then to the expected metadata path for the record, and assigns
|
|
69
|
+
# the result as the metadata record for the file record.
|
|
70
|
+
# @return the file path of the config file
|
|
71
|
+
def write_to_yaml_file(file_rec: nil)
|
|
72
|
+
md_path = nil
|
|
73
|
+
if file_rec.nil?
|
|
74
|
+
md_path = TempFile.new(['metadata', 'yml']).path
|
|
75
|
+
else
|
|
76
|
+
md_path = file_rec.metadata_path
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
md_rec = get_metadata_record
|
|
80
|
+
MetadataSerializer::write(metadata: md_rec, file_path: md_path)
|
|
81
|
+
file_rec.metadata_record = md_rec
|
|
82
|
+
|
|
83
|
+
md_path
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
def format_timestamp(timestamp)
|
|
88
|
+
timestamp.kind_of?(Time) ? ServiceDateHelper::formatted_timestamp(timestamp) : timestamp
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|