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
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>
|
|
7
|
+
Top Level Namespace
|
|
8
|
+
|
|
9
|
+
— Documentation by YARD 0.9.19
|
|
10
|
+
|
|
11
|
+
</title>
|
|
12
|
+
|
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
|
14
|
+
|
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
|
16
|
+
|
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
|
18
|
+
pathId = "";
|
|
19
|
+
relpath = '';
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
|
24
|
+
|
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
</head>
|
|
29
|
+
<body>
|
|
30
|
+
<div class="nav_wrap">
|
|
31
|
+
<iframe id="nav" src="class_list.html?1"></iframe>
|
|
32
|
+
<div id="resizer"></div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div id="main" tabindex="-1">
|
|
36
|
+
<div id="header">
|
|
37
|
+
<div id="menu">
|
|
38
|
+
|
|
39
|
+
<a href="_index.html">Index</a> »
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
<span class="title">Top Level Namespace</span>
|
|
43
|
+
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div id="search">
|
|
47
|
+
|
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
|
49
|
+
href="class_list.html">
|
|
50
|
+
|
|
51
|
+
<svg width="24" height="24">
|
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
|
55
|
+
</svg>
|
|
56
|
+
</a>
|
|
57
|
+
|
|
58
|
+
</div>
|
|
59
|
+
<div class="clear"></div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div id="content"><h1>Top Level Namespace
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
</h1>
|
|
67
|
+
<div class="box_info">
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<h2>Defined Under Namespace</h2>
|
|
82
|
+
<p class="children">
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Longleaf.html" title="Longleaf (module)">Longleaf</a></span>
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
</p>
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div id="footer">
|
|
103
|
+
Generated on Tue May 28 15:48:00 2019 by
|
|
104
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
105
|
+
0.9.19 (ruby-2.6.3).
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
</div>
|
|
109
|
+
</body>
|
|
110
|
+
</html>
|
|
@@ -4,7 +4,11 @@ module Longleaf
|
|
|
4
4
|
# Selects and allows for iteration over files which match a provided set of selection criteria
|
|
5
5
|
class FileSelector
|
|
6
6
|
include Longleaf::Logging
|
|
7
|
-
|
|
7
|
+
SPECIFICITY_PATH = 'path'
|
|
8
|
+
SPECIFICITY_STORAGE_LOCATION = 'storage_location'
|
|
9
|
+
|
|
10
|
+
attr_reader :specificity
|
|
11
|
+
|
|
8
12
|
# May only provide either file_paths or storage_locations
|
|
9
13
|
def initialize(file_paths: nil, storage_locations: nil, app_config:)
|
|
10
14
|
if nil_or_empty?(file_paths) && nil_or_empty?(storage_locations)
|
|
@@ -15,11 +19,28 @@ module Longleaf
|
|
|
15
19
|
end
|
|
16
20
|
@app_config = app_config
|
|
17
21
|
# The top level paths targeted by this selector
|
|
18
|
-
@target_paths = file_paths
|
|
22
|
+
@target_paths = file_paths&.map do |path|
|
|
23
|
+
# Resolve relative paths against pwd
|
|
24
|
+
pathname = Pathname.new(path)
|
|
25
|
+
if !pathname.absolute?
|
|
26
|
+
path = File.join(Dir.pwd, path)
|
|
27
|
+
end
|
|
28
|
+
path = File.expand_path(path)
|
|
29
|
+
|
|
30
|
+
# adding trailing /'s to directories
|
|
31
|
+
if Dir.exist?(path) && !path.end_with?('/')
|
|
32
|
+
path + '/'
|
|
33
|
+
else
|
|
34
|
+
path
|
|
35
|
+
end
|
|
36
|
+
end
|
|
19
37
|
# The set of storage locations to select file paths from
|
|
20
38
|
@storage_locations = storage_locations
|
|
21
39
|
# Validate that the selected storage locations are known
|
|
22
|
-
|
|
40
|
+
if @storage_locations.nil?
|
|
41
|
+
@specificity = SPECIFICITY_PATH
|
|
42
|
+
else
|
|
43
|
+
@specificity = SPECIFICITY_STORAGE_LOCATION
|
|
23
44
|
locations = @app_config.location_manager.locations
|
|
24
45
|
@storage_locations.each do |loc_name|
|
|
25
46
|
unless locations.key?(loc_name)
|
|
@@ -28,7 +49,7 @@ module Longleaf
|
|
|
28
49
|
end
|
|
29
50
|
end
|
|
30
51
|
end
|
|
31
|
-
|
|
52
|
+
|
|
32
53
|
# @return [Array] a list of top level paths from which files will be selected
|
|
33
54
|
def target_paths
|
|
34
55
|
# If starting from locations, initialize by expanding locations out to their actual paths
|
|
@@ -38,10 +59,10 @@ module Longleaf
|
|
|
38
59
|
@target_paths << @app_config.location_manager.locations[loc_name].path
|
|
39
60
|
end
|
|
40
61
|
end
|
|
41
|
-
|
|
62
|
+
|
|
42
63
|
@target_paths
|
|
43
64
|
end
|
|
44
|
-
|
|
65
|
+
|
|
45
66
|
# Get the next file path for this selector.
|
|
46
67
|
# @return [String] an absolute path to the next file targeted by this selector,
|
|
47
68
|
# or nil if no more files selected
|
|
@@ -54,17 +75,17 @@ module Longleaf
|
|
|
54
75
|
|
|
55
76
|
# No more paths to return
|
|
56
77
|
return nil if @paths&.empty?
|
|
57
|
-
|
|
78
|
+
|
|
58
79
|
# Get the most recently added path for depth first traversal of selected paths
|
|
59
80
|
path = @paths.pop
|
|
60
81
|
until path.nil? do
|
|
61
82
|
@app_config.location_manager.verify_path_in_location(path)
|
|
62
|
-
|
|
83
|
+
|
|
63
84
|
if File.exist?(path)
|
|
64
85
|
if File.directory?(path)
|
|
65
86
|
logger.debug("Expanding directory #{path}")
|
|
66
87
|
# For a directory, add all children to file_paths
|
|
67
|
-
Dir.entries(path).sort.
|
|
88
|
+
Dir.entries(path).sort.reverse_each do |child|
|
|
68
89
|
@paths << File.join(path, child) unless child == '.' or child == '..'
|
|
69
90
|
end
|
|
70
91
|
else
|
|
@@ -74,12 +95,23 @@ module Longleaf
|
|
|
74
95
|
else
|
|
75
96
|
raise InvalidStoragePathError.new("File #{path} does not exist.")
|
|
76
97
|
end
|
|
77
|
-
|
|
98
|
+
|
|
78
99
|
# Returned path was not a suitable file, try the next path
|
|
79
100
|
path = @paths.pop
|
|
80
101
|
end
|
|
81
102
|
end
|
|
82
|
-
|
|
103
|
+
|
|
104
|
+
# Iterate through the file paths for this selector and execute the provided block with each.
|
|
105
|
+
# A block is required.
|
|
106
|
+
def each
|
|
107
|
+
file_path = next_path
|
|
108
|
+
until file_path.nil?
|
|
109
|
+
yield file_path
|
|
110
|
+
|
|
111
|
+
file_path = next_path
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
83
115
|
# return [Array] a list of all storage locations being targeted by this selector
|
|
84
116
|
def storage_locations
|
|
85
117
|
# Determine what storage_locations are represented by the given file paths
|
|
@@ -91,17 +123,17 @@ module Longleaf
|
|
|
91
123
|
end
|
|
92
124
|
@storage_locations = loc_set.to_a
|
|
93
125
|
end
|
|
94
|
-
|
|
126
|
+
|
|
95
127
|
if @storage_locations.nil?
|
|
96
128
|
@storage_locations = Array.new
|
|
97
129
|
end
|
|
98
|
-
|
|
130
|
+
|
|
99
131
|
@storage_locations
|
|
100
132
|
end
|
|
101
|
-
|
|
133
|
+
|
|
102
134
|
private
|
|
103
135
|
def nil_or_empty?(value)
|
|
104
136
|
value.nil? || value.empty?
|
|
105
137
|
end
|
|
106
138
|
end
|
|
107
|
-
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'longleaf/candidates/file_selector'
|
|
2
|
+
require 'longleaf/logging'
|
|
3
|
+
|
|
4
|
+
module Longleaf
|
|
5
|
+
# Selects and allows for iteration over files which are registered and match a provided
|
|
6
|
+
# set of selection criteria
|
|
7
|
+
class RegisteredFileSelector < FileSelector
|
|
8
|
+
include Longleaf::Logging
|
|
9
|
+
|
|
10
|
+
# Get the next file path for this selector.
|
|
11
|
+
# @raise [InvalidStoragePathError] if any of the selected files do not exist
|
|
12
|
+
# @raise [StorageLocationUnavailableError] if any of the selected paths are not
|
|
13
|
+
# in a registered storage location.
|
|
14
|
+
# @return [String] an absolute path to the next file targeted by this selector,
|
|
15
|
+
# or nil if no more files selected
|
|
16
|
+
def next_path
|
|
17
|
+
if @md_paths.nil?
|
|
18
|
+
# Compute the starting paths by looking up the metadata paths for the provided targets,
|
|
19
|
+
# in reverse order since @md_paths is a LIFO stack structure.
|
|
20
|
+
@md_paths = target_paths.reverse_each.map do |file_path|
|
|
21
|
+
storage_loc = @app_config.location_manager.verify_path_in_location(file_path)
|
|
22
|
+
storage_loc.get_metadata_path_for(file_path)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# No more paths to return
|
|
27
|
+
return nil if @md_paths&.empty?
|
|
28
|
+
|
|
29
|
+
# Get the most recently added path for depth first traversal of selected paths
|
|
30
|
+
md_path = @md_paths.pop
|
|
31
|
+
until md_path.nil? do
|
|
32
|
+
if File.exist?(md_path)
|
|
33
|
+
if File.directory?(md_path)
|
|
34
|
+
logger.debug("Expanding metadata directory #{md_path}")
|
|
35
|
+
# For a directory, add all children to file_paths
|
|
36
|
+
Dir.entries(md_path).sort.reverse_each do |child|
|
|
37
|
+
@md_paths << File.join(md_path, child) unless child == '.' or child == '..'
|
|
38
|
+
end
|
|
39
|
+
elsif md_path.end_with?(MetadataSerializer::metadata_suffix)
|
|
40
|
+
# Convert metadata path to file path before returning
|
|
41
|
+
return file_path_for_metadata(md_path)
|
|
42
|
+
else
|
|
43
|
+
logger.debug("Skipping non-metadata file in metadata directory #{md_path}")
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
file_path = file_path_for_metadata(md_path)
|
|
47
|
+
if File.exist?(file_path)
|
|
48
|
+
raise RegistrationError.new("File #{file_path} is not registered.")
|
|
49
|
+
else
|
|
50
|
+
raise InvalidStoragePathError.new("File #{file_path} does not exist.")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Returned path was not a suitable file, try the next path
|
|
55
|
+
md_path = @md_paths.pop
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
def file_path_for_metadata(md_path)
|
|
61
|
+
storage_loc = @app_config.location_manager.get_location_by_metadata_path(md_path)
|
|
62
|
+
file_path = storage_loc.get_path_from_metadata_path(md_path)
|
|
63
|
+
logger.debug("Returning next file #{file_path} for metadata path #{md_path}")
|
|
64
|
+
return file_path
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'longleaf/services/service_manager'
|
|
2
|
-
require 'longleaf/services/metadata_deserializer'
|
|
3
2
|
require 'longleaf/events/event_names'
|
|
4
3
|
require 'longleaf/errors'
|
|
5
4
|
require 'longleaf/logging'
|
|
@@ -11,89 +10,84 @@ module Longleaf
|
|
|
11
10
|
# about service status.
|
|
12
11
|
class ServiceCandidateFilesystemIterator
|
|
13
12
|
include Longleaf::Logging
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
def initialize(file_selector, event, app_config, force = false)
|
|
16
15
|
@file_selector = file_selector
|
|
17
16
|
@event = event
|
|
18
17
|
@app_config = app_config
|
|
19
18
|
@force = force
|
|
20
19
|
end
|
|
21
|
-
|
|
22
|
-
# Get the file record for the next candidate which needs services run which match the
|
|
20
|
+
|
|
21
|
+
# Get the file record for the next candidate which needs services run which match the
|
|
23
22
|
# provided file_selector
|
|
24
23
|
# @return [FileRecord] file record of the next candidate with services needing to be run,
|
|
25
24
|
# or nil if there are no more candidates.
|
|
26
25
|
def next_candidate
|
|
27
26
|
loop do
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
next
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
file_rec.metadata_record = MetadataDeserializer.deserialize(file_path: file_rec.metadata_path,
|
|
43
|
-
digest_algs: storage_loc.metadata_digests)
|
|
44
|
-
|
|
45
|
-
# Return the file record if it needs any services run
|
|
46
|
-
return file_rec if needs_run?(file_rec)
|
|
47
|
-
rescue InvalidStoragePathError => e
|
|
48
|
-
logger.warn("Skipping candidate file: #{e.message}")
|
|
27
|
+
next_path = @file_selector.next_path
|
|
28
|
+
return nil if next_path.nil?
|
|
29
|
+
|
|
30
|
+
logger.debug("Evaluating candidate #{next_path}")
|
|
31
|
+
storage_loc = @app_config.location_manager.get_location_by_path(next_path)
|
|
32
|
+
file_rec = FileRecord.new(next_path, storage_loc)
|
|
33
|
+
|
|
34
|
+
# Skip over unregistered files
|
|
35
|
+
if !file_rec.metadata_present?
|
|
36
|
+
logger.debug("Ignoring unregistered file #{next_path}")
|
|
37
|
+
next
|
|
49
38
|
end
|
|
39
|
+
|
|
40
|
+
@app_config.md_manager.load(file_rec)
|
|
41
|
+
|
|
42
|
+
# Return the file record if it needs any services run
|
|
43
|
+
return file_rec if needs_run?(file_rec)
|
|
50
44
|
end
|
|
51
45
|
end
|
|
52
|
-
|
|
46
|
+
|
|
53
47
|
# Iterate through the candidates in this object and execute the provided block with each
|
|
54
48
|
# candidate. A block is required.
|
|
55
49
|
def each
|
|
56
50
|
file_rec = next_candidate
|
|
57
51
|
until file_rec.nil?
|
|
58
52
|
yield file_rec
|
|
59
|
-
|
|
53
|
+
|
|
60
54
|
file_rec = next_candidate
|
|
61
55
|
end
|
|
62
56
|
end
|
|
63
|
-
|
|
57
|
+
|
|
64
58
|
private
|
|
65
59
|
# Returns true if the file record contains any services which need to be run
|
|
66
60
|
def needs_run?(file_rec)
|
|
67
61
|
md_rec = file_rec.metadata_record
|
|
68
62
|
storage_loc = file_rec.storage_location
|
|
69
63
|
service_manager = @app_config.service_manager
|
|
70
|
-
|
|
64
|
+
|
|
71
65
|
# File is not a valid candidate for services if it is deregistered, unless performing cleanup
|
|
72
66
|
if @event != EventNames::CLEANUP && md_rec.deregistered?
|
|
73
67
|
logger.debug("Skipping deregistered file: #{file_rec.path}")
|
|
74
68
|
return false
|
|
75
69
|
end
|
|
76
|
-
|
|
70
|
+
|
|
77
71
|
expected_services = service_manager.list_services(
|
|
78
72
|
location: storage_loc.name,
|
|
79
73
|
event: @event)
|
|
80
|
-
|
|
74
|
+
|
|
81
75
|
# When in force mode, candidate needs a run as long as there are any services configured for it.
|
|
82
|
-
if @force && expected_services.
|
|
76
|
+
if @force && !expected_services.empty?
|
|
83
77
|
logger.debug("Forcing run needed for file: #{file_rec.path}")
|
|
84
78
|
return true
|
|
85
79
|
end
|
|
86
|
-
|
|
80
|
+
|
|
87
81
|
expected_services.each do |service_name|
|
|
88
82
|
if service_manager.service_needed?(service_name, md_rec)
|
|
89
83
|
logger.debug("Service #{service_name} needed for file: #{file_rec.path}")
|
|
90
84
|
return true
|
|
91
85
|
end
|
|
92
86
|
end
|
|
93
|
-
|
|
87
|
+
|
|
94
88
|
logger.debug("Run not needed for file: #{file_rec.path}")
|
|
95
89
|
# No services needed to be run for this file
|
|
96
90
|
false
|
|
97
91
|
end
|
|
98
92
|
end
|
|
99
|
-
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'longleaf/events/event_names'
|
|
2
|
+
require 'longleaf/errors'
|
|
3
|
+
require 'longleaf/logging'
|
|
4
|
+
require 'time'
|
|
5
|
+
|
|
6
|
+
module Longleaf
|
|
7
|
+
# Iterator for getting file candidates which have services which need to be run.
|
|
8
|
+
# Implementation uses an index of file metadata to determine if the file needs any
|
|
9
|
+
# services run.
|
|
10
|
+
class ServiceCandidateIndexIterator
|
|
11
|
+
include Longleaf::Logging
|
|
12
|
+
|
|
13
|
+
def initialize(file_selector, event, app_config, force = false)
|
|
14
|
+
@file_selector = file_selector
|
|
15
|
+
@event = event
|
|
16
|
+
@app_config = app_config
|
|
17
|
+
@force = force
|
|
18
|
+
@index_manager = @app_config.index_manager
|
|
19
|
+
@stale_datetime = Time.now.utc
|
|
20
|
+
@result_set = nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Get the file record for the next candidate which needs services run which match the
|
|
24
|
+
# provided file_selector
|
|
25
|
+
# @return [FileRecord] file record of the next candidate with services needing to be run,
|
|
26
|
+
# or nil if there are no more candidates.
|
|
27
|
+
def next_candidate
|
|
28
|
+
file_rec = nil
|
|
29
|
+
# loop until a candidate with metadata is retrieved
|
|
30
|
+
loop do
|
|
31
|
+
# Get the next page of results if the previous page has been processed
|
|
32
|
+
fetch_next_page if @result_set.nil? || @result_set.empty?
|
|
33
|
+
|
|
34
|
+
# Retrieve the next possible candidate path from the page
|
|
35
|
+
next_path = @result_set.shift
|
|
36
|
+
# given that the page was just retrieved, getting a nil path indicates that the retrieved page of
|
|
37
|
+
# candidates is empty and there are no more candidates to iterate at this time.
|
|
38
|
+
return nil if next_path.nil?
|
|
39
|
+
|
|
40
|
+
logger.debug("Retrieved candidate #{next_path}")
|
|
41
|
+
storage_loc = @app_config.location_manager.get_location_by_path(next_path)
|
|
42
|
+
file_rec = FileRecord.new(next_path, storage_loc)
|
|
43
|
+
|
|
44
|
+
# Keep seeking until a registered candidate is found, according to the file system.
|
|
45
|
+
if file_rec.metadata_present?
|
|
46
|
+
break
|
|
47
|
+
else
|
|
48
|
+
logger.warn("Encountered #{next_path} in index, but path is not registered. Clearing out of synch entry.")
|
|
49
|
+
@index_manager.remove(file_rec)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@app_config.md_manager.load(file_rec)
|
|
54
|
+
|
|
55
|
+
file_rec
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Iterate through the candidates in this object and execute the provided block with each
|
|
59
|
+
# candidate. A block is required.
|
|
60
|
+
def each
|
|
61
|
+
file_rec = next_candidate
|
|
62
|
+
until file_rec.nil?
|
|
63
|
+
yield file_rec
|
|
64
|
+
|
|
65
|
+
file_rec = next_candidate
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
def fetch_next_page
|
|
71
|
+
if @force
|
|
72
|
+
@result_set = @index_manager.registered_paths(@file_selector)
|
|
73
|
+
else
|
|
74
|
+
case @event
|
|
75
|
+
when EventNames::PRESERVE
|
|
76
|
+
@result_set = @index_manager.paths_with_stale_services(@file_selector, @stale_datetime)
|
|
77
|
+
when EventNames::CLEANUP
|
|
78
|
+
# TODO
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
logger.debug("Retrieve result set with #{@result_set&.length} entries")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|