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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +94 -0
- data/.editorconfig +13 -0
- data/.gitignore +4 -1
- data/.rubocop.yml +44 -0
- data/.rubocop_todo.yml +834 -0
- data/.yardopts +1 -0
- data/Gemfile +16 -1
- data/README.md +98 -12
- 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 +139 -0
- data/lib/longleaf/candidates/manifest_digest_provider.rb +17 -0
- data/lib/longleaf/candidates/registered_file_selector.rb +67 -0
- data/lib/longleaf/candidates/service_candidate_filesystem_iterator.rb +93 -0
- data/lib/longleaf/candidates/service_candidate_index_iterator.rb +84 -0
- data/lib/longleaf/candidates/service_candidate_locator.rb +23 -0
- data/lib/longleaf/candidates/single_digest_provider.rb +13 -0
- data/lib/longleaf/cli.rb +237 -46
- data/lib/longleaf/commands/deregister_command.rb +51 -0
- data/lib/longleaf/commands/preserve_command.rb +50 -0
- data/lib/longleaf/commands/register_command.rb +32 -43
- data/lib/longleaf/commands/reindex_command.rb +92 -0
- data/lib/longleaf/commands/validate_config_command.rb +33 -8
- data/lib/longleaf/commands/validate_metadata_command.rb +51 -0
- data/lib/longleaf/errors.rb +26 -7
- data/lib/longleaf/events/deregister_event.rb +53 -0
- data/lib/longleaf/events/event_names.rb +9 -0
- data/lib/longleaf/events/event_status_tracking.rb +59 -0
- data/lib/longleaf/events/preserve_event.rb +81 -0
- data/lib/longleaf/events/register_event.rb +52 -51
- data/lib/longleaf/helpers/case_insensitive_hash.rb +38 -0
- data/lib/longleaf/helpers/digest_helper.rb +56 -0
- data/lib/longleaf/helpers/s3_uri_helper.rb +86 -0
- data/lib/longleaf/helpers/selection_options_parser.rb +189 -0
- data/lib/longleaf/helpers/service_date_helper.rb +78 -0
- data/lib/longleaf/indexing/index_manager.rb +101 -0
- data/lib/longleaf/indexing/sequel_index_driver.rb +306 -0
- data/lib/longleaf/logging.rb +5 -4
- data/lib/longleaf/logging/redirecting_logger.rb +26 -25
- data/lib/longleaf/models/app_fields.rb +7 -2
- data/lib/longleaf/models/file_record.rb +17 -8
- data/lib/longleaf/models/filesystem_metadata_location.rb +56 -0
- data/lib/longleaf/models/filesystem_storage_location.rb +52 -0
- data/lib/longleaf/models/md_fields.rb +2 -1
- data/lib/longleaf/models/metadata_location.rb +47 -0
- data/lib/longleaf/models/metadata_record.rb +39 -15
- data/lib/longleaf/models/s3_storage_location.rb +133 -0
- data/lib/longleaf/models/service_definition.rb +7 -6
- data/lib/longleaf/models/service_fields.rb +7 -1
- data/lib/longleaf/models/service_record.rb +10 -6
- data/lib/longleaf/models/storage_location.rb +24 -19
- data/lib/longleaf/models/storage_types.rb +9 -0
- 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 +123 -0
- data/lib/longleaf/preservation_services/rsync_replication_service.rb +182 -0
- data/lib/longleaf/preservation_services/s3_replication_service.rb +143 -0
- data/lib/longleaf/services/application_config_deserializer.rb +81 -24
- data/lib/longleaf/services/application_config_manager.rb +20 -6
- data/lib/longleaf/services/application_config_validator.rb +19 -9
- data/lib/longleaf/services/configuration_validator.rb +67 -4
- data/lib/longleaf/services/filesystem_location_validator.rb +16 -0
- data/lib/longleaf/services/metadata_deserializer.rb +113 -42
- data/lib/longleaf/services/metadata_persistence_manager.rb +47 -0
- data/lib/longleaf/services/metadata_serializer.rb +138 -25
- data/lib/longleaf/services/metadata_validator.rb +76 -0
- data/lib/longleaf/services/s3_location_validator.rb +19 -0
- data/lib/longleaf/services/service_class_cache.rb +112 -0
- data/lib/longleaf/services/service_definition_manager.rb +10 -7
- data/lib/longleaf/services/service_definition_validator.rb +25 -18
- data/lib/longleaf/services/service_manager.rb +86 -11
- data/lib/longleaf/services/service_mapping_manager.rb +13 -12
- data/lib/longleaf/services/service_mapping_validator.rb +36 -26
- data/lib/longleaf/services/storage_location_manager.rb +76 -15
- data/lib/longleaf/services/storage_location_validator.rb +49 -35
- data/lib/longleaf/specs/config_builder.rb +47 -23
- data/lib/longleaf/specs/config_validator_helpers.rb +16 -0
- data/lib/longleaf/specs/custom_matchers.rb +9 -0
- data/lib/longleaf/specs/file_helpers.rb +61 -0
- data/lib/longleaf/specs/metadata_builder.rb +92 -0
- data/lib/longleaf/specs/system_config_builder.rb +27 -0
- data/lib/longleaf/version.rb +1 -1
- data/longleaf.gemspec +20 -7
- data/mkdocs.yml +21 -0
- metadata +306 -23
- data/.travis.yml +0 -4
- data/lib/longleaf/commands/abstract_command.rb +0 -37
- data/lib/longleaf/services/storage_path_validator.rb +0 -16
data/lib/longleaf/logging.rb
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
require 'longleaf/logging/redirecting_logger'
|
|
2
2
|
|
|
3
3
|
module Longleaf
|
|
4
|
+
# Module for access logging within longleaf
|
|
4
5
|
module Logging
|
|
5
6
|
# Get the main logger for longleaf
|
|
6
7
|
def logger
|
|
7
8
|
Logging.logger
|
|
8
9
|
end
|
|
9
|
-
|
|
10
|
+
|
|
10
11
|
# Get the main logger for longleaf
|
|
11
12
|
def self.logger
|
|
12
13
|
@logger ||= RedirectingLogger.new
|
|
13
14
|
end
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
def initialize_logger(failure_only, log_level, log_format, datetime_format)
|
|
16
17
|
Logging.initialize_logger(failure_only, log_level, log_format, datetime_format)
|
|
17
18
|
end
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
def self.initialize_logger(failure_only, log_level, log_format, datetime_format)
|
|
20
21
|
@logger = RedirectingLogger.new(failure_only: failure_only,
|
|
21
22
|
log_level: log_level,
|
|
@@ -23,4 +24,4 @@ module Longleaf
|
|
|
23
24
|
datetime_format: datetime_format)
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
|
-
end
|
|
27
|
+
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
require 'logger'
|
|
2
2
|
|
|
3
|
-
# Logger which directs messages to stdout and/or stderr, depending on the nature of the message.
|
|
4
|
-
# Status logging, which includes standard logger methods, goes to STDERR.
|
|
5
|
-
# Operation success and failure messages go to STDOUT, and to STDERR at info level.
|
|
6
3
|
module Longleaf
|
|
7
4
|
module Logging
|
|
5
|
+
# Logger which directs messages to stdout and/or stderr, depending on the nature of the message.
|
|
6
|
+
# Status logging, which includes standard logger methods, goes to STDERR.
|
|
7
|
+
# Operation success and failure messages go to STDOUT, and to STDERR at info level.
|
|
8
8
|
class RedirectingLogger
|
|
9
|
-
# @param
|
|
9
|
+
# @param [Boolean] failure_only If set to true, only failure messages will be output to STDOUT
|
|
10
10
|
# @param log_level [String] logger level used for output to STDERR
|
|
11
|
-
# @param log_format [
|
|
11
|
+
# @param log_format [String] format string for log entries to STDERR. There are 4 variables available
|
|
12
12
|
# for inclusion in the output: severity, datetime, progname, msg. Variables must be wrapped in %{}.
|
|
13
13
|
# @param datetime_format [String] datetime formatting string used for logger dates appearing in STDERR.
|
|
14
14
|
def initialize(failure_only: false, log_level: 'WARN', log_format: nil, datetime_format: nil)
|
|
@@ -25,12 +25,12 @@ module Longleaf
|
|
|
25
25
|
@stderr_log.formatter = proc do |severity, datetime, progname, msg|
|
|
26
26
|
# Make sure the format ends with a newline
|
|
27
27
|
@log_format = @log_format + "\n" unless @log_format.end_with?("\n")
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
formatted_date = @stderr_log.datetime_format.nil? ? datetime : datetime.strftime(datetime_format)
|
|
30
30
|
@log_format % { :severity => severity, :datetime => formatted_date, :progname => progname, :msg => msg }
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
@stdout_log = Logger.new($stdout)
|
|
35
35
|
@stdout_log.formatter = proc do |severity, datetime, progname, msg|
|
|
36
36
|
"#{msg}\n"
|
|
@@ -41,33 +41,34 @@ module Longleaf
|
|
|
41
41
|
@stdout_log.level = 'info'
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
def debug(progname = nil, &block)
|
|
46
46
|
@stderr_log.debug(progname, &block)
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
def info(progname = nil, &block)
|
|
50
50
|
@stderr_log.info(progname, &block)
|
|
51
51
|
end
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
def warn(progname = nil, &block)
|
|
54
54
|
@stderr_log.warn(progname, &block)
|
|
55
55
|
end
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
def error(progname = nil, &block)
|
|
58
58
|
@stderr_log.error(progname, &block)
|
|
59
59
|
end
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
def fatal(progname = nil, &block)
|
|
62
62
|
@stderr_log.fatal(progname, &block)
|
|
63
63
|
end
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
def unknown(progname = nil, &block)
|
|
66
66
|
@stderr_log.unknown(progname, &block)
|
|
67
67
|
end
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
# Logs a success message to STDOUT, as well as STDERR at info level.
|
|
70
|
-
#
|
|
70
|
+
#
|
|
71
|
+
# @param [String] eventOrMessage name of the preservation event which succeeded,
|
|
71
72
|
# or the message to output if it is the only parameter. Required.
|
|
72
73
|
# @param file_name [String] file name which is the subject of this message.
|
|
73
74
|
# @param message [String] descriptive message to accompany this output
|
|
@@ -75,10 +76,10 @@ module Longleaf
|
|
|
75
76
|
def success(eventOrMessage, file_name = nil, message = nil, service = nil)
|
|
76
77
|
outcome('SUCCESS', eventOrMessage, file_name, message, service)
|
|
77
78
|
end
|
|
78
|
-
|
|
79
|
+
|
|
79
80
|
# Logs a failure message to STDOUT, as well as STDERR at info level.
|
|
80
81
|
# If an error was provided, it is logged to STDERR at error level.
|
|
81
|
-
# @param eventOrMessage [String] name of the preservation event which failed,
|
|
82
|
+
# @param eventOrMessage [String] name of the preservation event which failed,
|
|
82
83
|
# or the message to output if it is the only parameter.
|
|
83
84
|
# @param file_name [String] file name which is the subject of this message.
|
|
84
85
|
# @param message [String] descriptive message to accompany this output
|
|
@@ -87,17 +88,18 @@ module Longleaf
|
|
|
87
88
|
def failure(eventOrMessage, file_name = nil, message = nil, service = nil, error: nil)
|
|
88
89
|
text = outcome_text('FAILURE', eventOrMessage, file_name, message, service, error)
|
|
89
90
|
@stdout_log.warn(text)
|
|
90
|
-
|
|
91
|
+
|
|
91
92
|
@stderr_log.info(text)
|
|
92
93
|
@stderr_log.error("#{error.message}") unless error.nil?
|
|
94
|
+
@stderr_log.error("#{error.backtrace}") unless error.nil? || error.backtrace.nil?
|
|
93
95
|
end
|
|
94
|
-
|
|
96
|
+
|
|
95
97
|
# Logs an outcome message to STDOUT, as well as STDERR at info level.
|
|
96
98
|
# If file_name and message are nil, eventOrMessage will be used as the message.
|
|
97
99
|
#
|
|
98
100
|
# @param outcome [String] The status of the outcome. Required.
|
|
99
|
-
# @param eventOrMessage [String] name of the preservation event which was successful,
|
|
100
|
-
#
|
|
101
|
+
# @param eventOrMessage [String] name of the preservation event which was successful,
|
|
102
|
+
# or the message to output if it is the only parameter. Required.
|
|
101
103
|
# @param file_name [String] file name which is the subject of this message.
|
|
102
104
|
# @param message [String] descriptive message to accompany this output
|
|
103
105
|
# @param service [String] name of the service which executed.
|
|
@@ -107,14 +109,13 @@ module Longleaf
|
|
|
107
109
|
@stdout_log.info(text)
|
|
108
110
|
@stderr_log.info(text)
|
|
109
111
|
end
|
|
110
|
-
|
|
111
|
-
# FAILURE verify[cdr_fixity_check] /path/to/file: Something terrible
|
|
112
|
+
|
|
112
113
|
private
|
|
113
114
|
def outcome_text(outcome, eventOrMessage, file_name = nil, message = nil, service = nil, error = nil)
|
|
114
115
|
message_only = file_name.nil? && message.nil? && error.nil?
|
|
115
|
-
|
|
116
|
+
|
|
116
117
|
text = "#{outcome}"
|
|
117
|
-
|
|
118
|
+
|
|
118
119
|
if message_only
|
|
119
120
|
text << ": #{eventOrMessage}"
|
|
120
121
|
else
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
module Longleaf
|
|
2
|
+
# Application configuration field names
|
|
2
3
|
class AppFields
|
|
3
4
|
LOCATIONS = 'locations'
|
|
4
5
|
SERVICES = 'services'
|
|
5
6
|
SERVICE_MAPPINGS = 'service_mappings'
|
|
6
|
-
|
|
7
|
+
SYSTEM = 'system'
|
|
8
|
+
|
|
7
9
|
LOCATION_PATH = 'path'
|
|
8
|
-
|
|
10
|
+
METADATA_CONFIG = 'metadata'
|
|
11
|
+
METADATA_DIGESTS = 'digests'
|
|
12
|
+
|
|
13
|
+
STORAGE_TYPE = 'type'
|
|
9
14
|
end
|
|
10
15
|
end
|
|
@@ -1,25 +1,34 @@
|
|
|
1
|
-
# Record for an individual file and its associated information
|
|
2
1
|
module Longleaf
|
|
2
|
+
# Record for an individual file and its associated information
|
|
3
3
|
class FileRecord
|
|
4
|
-
|
|
5
4
|
attr_accessor :metadata_record
|
|
6
5
|
attr_reader :storage_location
|
|
7
6
|
attr_reader :path
|
|
8
|
-
|
|
7
|
+
|
|
9
8
|
# @param file_path [String] path to the file
|
|
10
|
-
# @param storage_location [
|
|
11
|
-
def initialize(file_path, storage_location)
|
|
9
|
+
# @param storage_location [StorageLocation] storage location containing the file
|
|
10
|
+
def initialize(file_path, storage_location, metadata_record = nil)
|
|
12
11
|
raise ArgumentError.new("FileRecord requires a path") if file_path.nil?
|
|
13
12
|
raise ArgumentError.new("FileRecord requires a storage_location") if storage_location.nil?
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
@path = file_path
|
|
16
15
|
@storage_location = storage_location
|
|
16
|
+
@metadata_record = metadata_record
|
|
17
17
|
end
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
# @return [String] path for the metadata file for this file
|
|
20
20
|
def metadata_path
|
|
21
21
|
@metadata_path = @storage_location.get_metadata_path_for(path) if @metadata_path.nil?
|
|
22
22
|
@metadata_path
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
def metadata_present?
|
|
26
|
+
File.exist?(metadata_path)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ==(other_obj)
|
|
30
|
+
return false unless other_obj.is_a?(FileRecord)
|
|
31
|
+
path == other_obj.path
|
|
32
|
+
end
|
|
24
33
|
end
|
|
25
|
-
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'longleaf/services/metadata_serializer'
|
|
2
|
+
require 'longleaf/models/metadata_location'
|
|
3
|
+
require 'longleaf/models/storage_types'
|
|
4
|
+
|
|
5
|
+
module Longleaf
|
|
6
|
+
# A filesystem based location in which metadata associated with registered files is stored.
|
|
7
|
+
class FilesystemMetadataLocation < MetadataLocation
|
|
8
|
+
AF ||= Longleaf::AppFields
|
|
9
|
+
|
|
10
|
+
def initialize(config)
|
|
11
|
+
super(config)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return the storage type for this location
|
|
15
|
+
def type
|
|
16
|
+
StorageTypes::FILESYSTEM_STORAGE_TYPE
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Get the absolute path for the metadata file for the given file path located in this storage location.
|
|
20
|
+
# @param file_path [String] path of the file relative its storage location
|
|
21
|
+
# @return absolute path to the metadata
|
|
22
|
+
# @raise [ArgumentError] if the file_path is not provided.
|
|
23
|
+
def metadata_path_for(file_path)
|
|
24
|
+
raise ArgumentError.new("A file_path parameter is required") if file_path.nil?
|
|
25
|
+
raise ArgumentError.new("File path must be relative") if Pathname.new(file_path).absolute?
|
|
26
|
+
|
|
27
|
+
md_path = File.join(@path, file_path)
|
|
28
|
+
# If the file_path is to a file, then add metadata suffix.
|
|
29
|
+
if md_path.end_with?('/')
|
|
30
|
+
md_path
|
|
31
|
+
else
|
|
32
|
+
md_path + MetadataSerializer::metadata_suffix
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Get the metadata path relative to this location
|
|
37
|
+
# @param md_path [String] metadata file path
|
|
38
|
+
# @return the metadata path relative to this location
|
|
39
|
+
# @raise [ArgumentError] if the metadata path is not contained by this location
|
|
40
|
+
def relativize(md_path)
|
|
41
|
+
return md_path if Pathname.new(md_path).relative?
|
|
42
|
+
|
|
43
|
+
raise ArgumentError.new("Metadata path must be contained by this location") if !md_path.start_with?(@path)
|
|
44
|
+
|
|
45
|
+
md_path.sub(@path, "")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Checks that the path defined in this metadata location are available
|
|
50
|
+
# @raise [StorageLocationUnavailableError] if the metadata location is not available
|
|
51
|
+
def available?
|
|
52
|
+
raise StorageLocationUnavailableError.new("Metadata path does not exist or is not a directory: #{@path}")\
|
|
53
|
+
unless Dir.exist?(@path)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'longleaf/models/storage_location'
|
|
2
|
+
require 'longleaf/models/storage_types'
|
|
3
|
+
|
|
4
|
+
module Longleaf
|
|
5
|
+
# A storage location in a local filesystem
|
|
6
|
+
class FilesystemStorageLocation < StorageLocation
|
|
7
|
+
# @param name [String] the name of this storage location
|
|
8
|
+
# @param config [Hash] hash containing the configuration options for this location
|
|
9
|
+
# @param md_loc [MetadataLocation] metadata location associated with this storage location
|
|
10
|
+
def initialize(name, config, md_loc)
|
|
11
|
+
super(name, config, md_loc)
|
|
12
|
+
@path += File::SEPARATOR unless @path.end_with?(File::SEPARATOR)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return the storage type for this location
|
|
16
|
+
def type
|
|
17
|
+
StorageTypes::FILESYSTEM_STORAGE_TYPE
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Get that absolute path to the file associated with the provided metadata path
|
|
21
|
+
# @param md_path [String] metadata file path
|
|
22
|
+
# @raise [ArgumentError] if the md_path is not in this storage location
|
|
23
|
+
# @return [String] the path for the file associated with this metadata
|
|
24
|
+
def get_path_from_metadata_path(md_path)
|
|
25
|
+
raise ArgumentError.new("A file_path parameter is required") if md_path.nil? || md_path.empty?
|
|
26
|
+
|
|
27
|
+
rel_path = @metadata_location.relative_file_path_for(md_path)
|
|
28
|
+
|
|
29
|
+
File.join(@path, rel_path)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Checks that the path and metadata path defined in this location are available
|
|
33
|
+
# @raise [StorageLocationUnavailableError] if the storage location is not available
|
|
34
|
+
def available?
|
|
35
|
+
raise StorageLocationUnavailableError.new("Path does not exist or is not a directory: #{@path}")\
|
|
36
|
+
unless Dir.exist?(@path)
|
|
37
|
+
@metadata_location.available?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get the file path relative to this location
|
|
41
|
+
# @param file_path [String] file path
|
|
42
|
+
# @return the file path relative to this location
|
|
43
|
+
# @raise [ArgumentError] if the file path is not contained by this location
|
|
44
|
+
def relativize(file_path)
|
|
45
|
+
return file_path if Pathname.new(file_path).relative?
|
|
46
|
+
|
|
47
|
+
raise ArgumentError.new("Metadata path must be contained by this location") if !file_path.start_with?(@path)
|
|
48
|
+
|
|
49
|
+
file_path.sub(@path, "")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'longleaf/models/app_fields'
|
|
2
|
+
|
|
3
|
+
module Longleaf
|
|
4
|
+
# A location in which metadata associated with registered files is stored.
|
|
5
|
+
class MetadataLocation
|
|
6
|
+
AF ||= Longleaf::AppFields
|
|
7
|
+
|
|
8
|
+
attr_reader :path
|
|
9
|
+
attr_reader :digests
|
|
10
|
+
|
|
11
|
+
def initialize(config)
|
|
12
|
+
raise ArgumentError.new("Config parameter is required") unless config
|
|
13
|
+
@path = config[AF::LOCATION_PATH]
|
|
14
|
+
raise ArgumentError.new("Parameter path is required") unless @path
|
|
15
|
+
@path += '/' unless @path.end_with?('/')
|
|
16
|
+
|
|
17
|
+
digests = config[AF::METADATA_DIGESTS]
|
|
18
|
+
if digests.nil?
|
|
19
|
+
@digests = []
|
|
20
|
+
elsif digests.is_a?(String)
|
|
21
|
+
@digests = [digests.downcase]
|
|
22
|
+
else
|
|
23
|
+
@digests = digests.map(&:downcase)
|
|
24
|
+
end
|
|
25
|
+
DigestHelper::validate_algorithms(@digests)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Transforms the given metadata path into a relative storage location path
|
|
29
|
+
# @param md_path [String] path of the metadata file or directory to compute file path for.
|
|
30
|
+
# @return
|
|
31
|
+
def relative_file_path_for(md_path)
|
|
32
|
+
rel_md_path = relativize(md_path)
|
|
33
|
+
|
|
34
|
+
if rel_md_path.end_with?(MetadataSerializer::metadata_suffix)
|
|
35
|
+
rel_md_path[0..-MetadataSerializer::metadata_suffix.length - 1]
|
|
36
|
+
else
|
|
37
|
+
rel_md_path
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @param [String] metadata path to check
|
|
42
|
+
# @return true if the metadata path is contained by the path for this location
|
|
43
|
+
def contains?(md_path)
|
|
44
|
+
md_path.start_with?(@path)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
require_relative 'md_fields'
|
|
2
2
|
require_relative 'service_record'
|
|
3
|
+
require 'longleaf/helpers/case_insensitive_hash'
|
|
3
4
|
|
|
4
|
-
# Metadata record for a single file
|
|
5
5
|
module Longleaf
|
|
6
|
+
# Metadata record for a single file
|
|
6
7
|
class MetadataRecord
|
|
7
|
-
attr_reader :
|
|
8
|
+
attr_reader :registered
|
|
9
|
+
attr_accessor :deregistered
|
|
8
10
|
attr_reader :checksums
|
|
9
11
|
attr_reader :properties
|
|
10
12
|
attr_accessor :file_size, :last_modified
|
|
11
|
-
|
|
13
|
+
|
|
12
14
|
# @param properties [Hash] initial data properties for this record
|
|
13
15
|
# @param services [Hash] initial service property tree
|
|
14
16
|
# @param deregistered [String] deregistered timestamp
|
|
@@ -16,42 +18,64 @@ module Longleaf
|
|
|
16
18
|
# @param checksums [Hash] hash of checksum values
|
|
17
19
|
# @param file_size [Integer] size of file in bytes
|
|
18
20
|
# @param last_modified [String] iso8601 representation of the last modified date of file
|
|
19
|
-
def initialize(properties:
|
|
21
|
+
def initialize(properties: nil, services: nil, deregistered: nil, registered: nil, checksums: nil,
|
|
20
22
|
file_size: nil, last_modified: nil)
|
|
21
|
-
@properties = properties
|
|
23
|
+
@properties = properties || Hash.new
|
|
22
24
|
@registered = registered
|
|
23
25
|
@deregistered = deregistered
|
|
24
|
-
@checksums =
|
|
25
|
-
@
|
|
26
|
+
@checksums = CaseInsensitiveHash.new
|
|
27
|
+
@checksums.merge!(checksums) unless checksums.nil?
|
|
28
|
+
@services = services || Hash.new
|
|
26
29
|
@file_size = file_size
|
|
27
30
|
@last_modified = last_modified
|
|
28
31
|
end
|
|
29
|
-
|
|
32
|
+
|
|
30
33
|
# @return [Boolean] true if the record is deregistered
|
|
31
34
|
def deregistered?
|
|
32
35
|
!@deregistered.nil?
|
|
33
36
|
end
|
|
34
|
-
|
|
37
|
+
|
|
35
38
|
# Adds a service to this record
|
|
36
39
|
#
|
|
37
40
|
# @param name [String] identifier for the service being added
|
|
38
|
-
# @param
|
|
39
|
-
|
|
41
|
+
# @param service [ServiceRecord] properties for populating the new service
|
|
42
|
+
# @return [ServiceRecord] the service added
|
|
43
|
+
def add_service(name, service = ServiceRecord.new)
|
|
40
44
|
raise ArgumentError.new("Value must be a ServiceRecord object when adding a service") unless service.class == Longleaf::ServiceRecord
|
|
41
45
|
raise IndexError.new("Service with name '#{name}' already exists") if @services.key?(name)
|
|
42
|
-
|
|
46
|
+
|
|
43
47
|
@services[name] = service
|
|
44
48
|
end
|
|
45
|
-
|
|
49
|
+
|
|
50
|
+
# Updates details of service record as if the service had been executed.
|
|
51
|
+
# @param service_name [String] name of the service run
|
|
52
|
+
# @return [ServiceRecord] the service record updated
|
|
53
|
+
def update_service_as_performed(service_name)
|
|
54
|
+
service_rec = service(service_name) || add_service(service_name)
|
|
55
|
+
service_rec.run_needed = false
|
|
56
|
+
service_rec.timestamp = ServiceDateHelper.formatted_timestamp
|
|
57
|
+
service_rec
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Updates details of service record as if the service had encountered a
|
|
61
|
+
# failure during execution.
|
|
62
|
+
# @param service_name [String] name of the service run
|
|
63
|
+
# @return [ServiceRecord] the service record updated
|
|
64
|
+
def update_service_as_failed(service_name)
|
|
65
|
+
service_rec = service(service_name) || add_service(service_name)
|
|
66
|
+
service_rec.failure_timestamp = ServiceDateHelper.formatted_timestamp
|
|
67
|
+
service_rec
|
|
68
|
+
end
|
|
69
|
+
|
|
46
70
|
# @param name [String] name identifier of the service to retrieve
|
|
47
71
|
# @return [ServiceRecord] the ServiceRecord for the service identified by name, or nil
|
|
48
72
|
def service(name)
|
|
49
73
|
@services[name]
|
|
50
74
|
end
|
|
51
|
-
|
|
75
|
+
|
|
52
76
|
# @return [Array<String>] a list of name identifiers for services registered to this record
|
|
53
77
|
def list_services
|
|
54
78
|
@services.keys
|
|
55
79
|
end
|
|
56
80
|
end
|
|
57
|
-
end
|
|
81
|
+
end
|