longleaf 0.1.0.pre.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +94 -0
  3. data/.editorconfig +13 -0
  4. data/.gitignore +4 -1
  5. data/.rubocop.yml +44 -0
  6. data/.rubocop_todo.yml +834 -0
  7. data/.yardopts +1 -0
  8. data/Gemfile +16 -1
  9. data/README.md +98 -12
  10. data/Rakefile +6 -0
  11. data/bin/setup +16 -1
  12. data/docs/aboutlongleaf.md +28 -0
  13. data/docs/extra.css +32 -0
  14. data/docs/img/change-file.png +0 -0
  15. data/docs/img/ll-example-preserved.png +0 -0
  16. data/docs/index.md +19 -0
  17. data/docs/install.md +66 -0
  18. data/docs/ll-example/config-example-relative.yml +33 -0
  19. data/docs/ll-example/files-dir/LLexample-PDF.pdf +0 -0
  20. data/docs/ll-example/files-dir/LLexample-TOCHANGE.txt +15 -0
  21. data/docs/ll-example/files-dir/LLexample-tokeep.txt +10 -0
  22. data/docs/ll-example/metadata-dir/.gitkeep +0 -0
  23. data/docs/ll-example/replica-files/.gitkeep +0 -0
  24. data/docs/ll-example/replica-metadata/.gitkeep +0 -0
  25. data/docs/quickstart.md +270 -0
  26. data/docs/rdocs/Longleaf.html +135 -0
  27. data/docs/rdocs/Longleaf/AppFields.html +178 -0
  28. data/docs/rdocs/Longleaf/ApplicationConfigDeserializer.html +631 -0
  29. data/docs/rdocs/Longleaf/ApplicationConfigManager.html +610 -0
  30. data/docs/rdocs/Longleaf/ApplicationConfigValidator.html +238 -0
  31. data/docs/rdocs/Longleaf/CLI.html +909 -0
  32. data/docs/rdocs/Longleaf/ChecksumMismatchError.html +151 -0
  33. data/docs/rdocs/Longleaf/ConfigBuilder.html +1339 -0
  34. data/docs/rdocs/Longleaf/ConfigurationError.html +143 -0
  35. data/docs/rdocs/Longleaf/ConfigurationValidator.html +227 -0
  36. data/docs/rdocs/Longleaf/DeregisterCommand.html +420 -0
  37. data/docs/rdocs/Longleaf/DeregisterEvent.html +453 -0
  38. data/docs/rdocs/Longleaf/DeregistrationError.html +151 -0
  39. data/docs/rdocs/Longleaf/DigestHelper.html +419 -0
  40. data/docs/rdocs/Longleaf/EventError.html +147 -0
  41. data/docs/rdocs/Longleaf/EventNames.html +163 -0
  42. data/docs/rdocs/Longleaf/EventStatusTracking.html +656 -0
  43. data/docs/rdocs/Longleaf/FileCheckService.html +540 -0
  44. data/docs/rdocs/Longleaf/FileHelpers.html +520 -0
  45. data/docs/rdocs/Longleaf/FileRecord.html +716 -0
  46. data/docs/rdocs/Longleaf/FileSelector.html +901 -0
  47. data/docs/rdocs/Longleaf/FixityCheckService.html +691 -0
  48. data/docs/rdocs/Longleaf/IndexManager.html +1155 -0
  49. data/docs/rdocs/Longleaf/InvalidDigestAlgorithmError.html +143 -0
  50. data/docs/rdocs/Longleaf/InvalidStoragePathError.html +143 -0
  51. data/docs/rdocs/Longleaf/Logging.html +405 -0
  52. data/docs/rdocs/Longleaf/Logging/RedirectingLogger.html +1213 -0
  53. data/docs/rdocs/Longleaf/LongleafError.html +139 -0
  54. data/docs/rdocs/Longleaf/MDFields.html +193 -0
  55. data/docs/rdocs/Longleaf/MetadataBuilder.html +787 -0
  56. data/docs/rdocs/Longleaf/MetadataDeserializer.html +537 -0
  57. data/docs/rdocs/Longleaf/MetadataError.html +143 -0
  58. data/docs/rdocs/Longleaf/MetadataPersistenceManager.html +539 -0
  59. data/docs/rdocs/Longleaf/MetadataRecord.html +1411 -0
  60. data/docs/rdocs/Longleaf/MetadataSerializer.html +786 -0
  61. data/docs/rdocs/Longleaf/PreservationServiceError.html +147 -0
  62. data/docs/rdocs/Longleaf/PreserveCommand.html +410 -0
  63. data/docs/rdocs/Longleaf/PreserveEvent.html +491 -0
  64. data/docs/rdocs/Longleaf/RegisterCommand.html +428 -0
  65. data/docs/rdocs/Longleaf/RegisterEvent.html +628 -0
  66. data/docs/rdocs/Longleaf/RegisteredFileSelector.html +446 -0
  67. data/docs/rdocs/Longleaf/RegistrationError.html +151 -0
  68. data/docs/rdocs/Longleaf/ReindexCommand.html +576 -0
  69. data/docs/rdocs/Longleaf/RsyncReplicationService.html +1180 -0
  70. data/docs/rdocs/Longleaf/SequelIndexDriver.html +1978 -0
  71. data/docs/rdocs/Longleaf/ServiceCandidateFilesystemIterator.html +572 -0
  72. data/docs/rdocs/Longleaf/ServiceCandidateIndexIterator.html +532 -0
  73. data/docs/rdocs/Longleaf/ServiceCandidateLocator.html +333 -0
  74. data/docs/rdocs/Longleaf/ServiceClassCache.html +725 -0
  75. data/docs/rdocs/Longleaf/ServiceDateHelper.html +425 -0
  76. data/docs/rdocs/Longleaf/ServiceDefinition.html +683 -0
  77. data/docs/rdocs/Longleaf/ServiceDefinitionManager.html +371 -0
  78. data/docs/rdocs/Longleaf/ServiceDefinitionValidator.html +269 -0
  79. data/docs/rdocs/Longleaf/ServiceFields.html +173 -0
  80. data/docs/rdocs/Longleaf/ServiceManager.html +1229 -0
  81. data/docs/rdocs/Longleaf/ServiceMappingManager.html +410 -0
  82. data/docs/rdocs/Longleaf/ServiceMappingValidator.html +347 -0
  83. data/docs/rdocs/Longleaf/ServiceRecord.html +821 -0
  84. data/docs/rdocs/Longleaf/StorageLocation.html +985 -0
  85. data/docs/rdocs/Longleaf/StorageLocationManager.html +729 -0
  86. data/docs/rdocs/Longleaf/StorageLocationUnavailableError.html +143 -0
  87. data/docs/rdocs/Longleaf/StorageLocationValidator.html +373 -0
  88. data/docs/rdocs/Longleaf/StoragePathValidator.html +253 -0
  89. data/docs/rdocs/Longleaf/SystemConfigBuilder.html +441 -0
  90. data/docs/rdocs/Longleaf/SystemConfigFields.html +163 -0
  91. data/docs/rdocs/Longleaf/ValidateConfigCommand.html +451 -0
  92. data/docs/rdocs/Longleaf/ValidateMetadataCommand.html +408 -0
  93. data/docs/rdocs/_index.html +660 -0
  94. data/docs/rdocs/class_list.html +51 -0
  95. data/docs/rdocs/css/common.css +1 -0
  96. data/docs/rdocs/css/full_list.css +58 -0
  97. data/docs/rdocs/css/style.css +496 -0
  98. data/docs/rdocs/file.README.html +165 -0
  99. data/docs/rdocs/file_list.html +56 -0
  100. data/docs/rdocs/frames.html +17 -0
  101. data/docs/rdocs/index.html +165 -0
  102. data/docs/rdocs/js/app.js +303 -0
  103. data/docs/rdocs/js/full_list.js +216 -0
  104. data/docs/rdocs/js/jquery.js +4 -0
  105. data/docs/rdocs/method_list.html +2051 -0
  106. data/docs/rdocs/top-level-namespace.html +110 -0
  107. data/lib/longleaf/candidates/file_selector.rb +139 -0
  108. data/lib/longleaf/candidates/manifest_digest_provider.rb +17 -0
  109. data/lib/longleaf/candidates/registered_file_selector.rb +67 -0
  110. data/lib/longleaf/candidates/service_candidate_filesystem_iterator.rb +93 -0
  111. data/lib/longleaf/candidates/service_candidate_index_iterator.rb +84 -0
  112. data/lib/longleaf/candidates/service_candidate_locator.rb +23 -0
  113. data/lib/longleaf/candidates/single_digest_provider.rb +13 -0
  114. data/lib/longleaf/cli.rb +237 -46
  115. data/lib/longleaf/commands/deregister_command.rb +51 -0
  116. data/lib/longleaf/commands/preserve_command.rb +50 -0
  117. data/lib/longleaf/commands/register_command.rb +32 -43
  118. data/lib/longleaf/commands/reindex_command.rb +92 -0
  119. data/lib/longleaf/commands/validate_config_command.rb +33 -8
  120. data/lib/longleaf/commands/validate_metadata_command.rb +51 -0
  121. data/lib/longleaf/errors.rb +26 -7
  122. data/lib/longleaf/events/deregister_event.rb +53 -0
  123. data/lib/longleaf/events/event_names.rb +9 -0
  124. data/lib/longleaf/events/event_status_tracking.rb +59 -0
  125. data/lib/longleaf/events/preserve_event.rb +81 -0
  126. data/lib/longleaf/events/register_event.rb +52 -51
  127. data/lib/longleaf/helpers/case_insensitive_hash.rb +38 -0
  128. data/lib/longleaf/helpers/digest_helper.rb +56 -0
  129. data/lib/longleaf/helpers/s3_uri_helper.rb +86 -0
  130. data/lib/longleaf/helpers/selection_options_parser.rb +189 -0
  131. data/lib/longleaf/helpers/service_date_helper.rb +78 -0
  132. data/lib/longleaf/indexing/index_manager.rb +101 -0
  133. data/lib/longleaf/indexing/sequel_index_driver.rb +306 -0
  134. data/lib/longleaf/logging.rb +5 -4
  135. data/lib/longleaf/logging/redirecting_logger.rb +26 -25
  136. data/lib/longleaf/models/app_fields.rb +7 -2
  137. data/lib/longleaf/models/file_record.rb +17 -8
  138. data/lib/longleaf/models/filesystem_metadata_location.rb +56 -0
  139. data/lib/longleaf/models/filesystem_storage_location.rb +52 -0
  140. data/lib/longleaf/models/md_fields.rb +2 -1
  141. data/lib/longleaf/models/metadata_location.rb +47 -0
  142. data/lib/longleaf/models/metadata_record.rb +39 -15
  143. data/lib/longleaf/models/s3_storage_location.rb +133 -0
  144. data/lib/longleaf/models/service_definition.rb +7 -6
  145. data/lib/longleaf/models/service_fields.rb +7 -1
  146. data/lib/longleaf/models/service_record.rb +10 -6
  147. data/lib/longleaf/models/storage_location.rb +24 -19
  148. data/lib/longleaf/models/storage_types.rb +9 -0
  149. data/lib/longleaf/models/system_config_fields.rb +9 -0
  150. data/lib/longleaf/preservation_services/file_check_service.rb +58 -0
  151. data/lib/longleaf/preservation_services/fixity_check_service.rb +123 -0
  152. data/lib/longleaf/preservation_services/rsync_replication_service.rb +182 -0
  153. data/lib/longleaf/preservation_services/s3_replication_service.rb +143 -0
  154. data/lib/longleaf/services/application_config_deserializer.rb +81 -24
  155. data/lib/longleaf/services/application_config_manager.rb +20 -6
  156. data/lib/longleaf/services/application_config_validator.rb +19 -9
  157. data/lib/longleaf/services/configuration_validator.rb +67 -4
  158. data/lib/longleaf/services/filesystem_location_validator.rb +16 -0
  159. data/lib/longleaf/services/metadata_deserializer.rb +113 -42
  160. data/lib/longleaf/services/metadata_persistence_manager.rb +47 -0
  161. data/lib/longleaf/services/metadata_serializer.rb +138 -25
  162. data/lib/longleaf/services/metadata_validator.rb +76 -0
  163. data/lib/longleaf/services/s3_location_validator.rb +19 -0
  164. data/lib/longleaf/services/service_class_cache.rb +112 -0
  165. data/lib/longleaf/services/service_definition_manager.rb +10 -7
  166. data/lib/longleaf/services/service_definition_validator.rb +25 -18
  167. data/lib/longleaf/services/service_manager.rb +86 -11
  168. data/lib/longleaf/services/service_mapping_manager.rb +13 -12
  169. data/lib/longleaf/services/service_mapping_validator.rb +36 -26
  170. data/lib/longleaf/services/storage_location_manager.rb +76 -15
  171. data/lib/longleaf/services/storage_location_validator.rb +49 -35
  172. data/lib/longleaf/specs/config_builder.rb +47 -23
  173. data/lib/longleaf/specs/config_validator_helpers.rb +16 -0
  174. data/lib/longleaf/specs/custom_matchers.rb +9 -0
  175. data/lib/longleaf/specs/file_helpers.rb +61 -0
  176. data/lib/longleaf/specs/metadata_builder.rb +92 -0
  177. data/lib/longleaf/specs/system_config_builder.rb +27 -0
  178. data/lib/longleaf/version.rb +1 -1
  179. data/longleaf.gemspec +20 -7
  180. data/mkdocs.yml +21 -0
  181. metadata +306 -23
  182. data/.travis.yml +0 -4
  183. data/lib/longleaf/commands/abstract_command.rb +0 -37
  184. data/lib/longleaf/services/storage_path_validator.rb +0 -16
@@ -0,0 +1,23 @@
1
+ require 'longleaf/candidates/service_candidate_filesystem_iterator'
2
+ require 'longleaf/candidates/service_candidate_index_iterator'
3
+
4
+ module Longleaf
5
+ # Service which locates files that have services which need to be performed on them.
6
+ class ServiceCandidateLocator
7
+ def initialize(app_config)
8
+ @app_config = app_config
9
+ end
10
+
11
+ # Get a iterator of the candidates matching the given FileSelector which need services run.
12
+ # @param file_selector [FileSelector] selector identifying the files to pull candidates from.
13
+ # @return an iterator
14
+ def candidate_iterator(file_selector, event, force = false)
15
+ if @app_config.index_manager.using_index?
16
+ ServiceCandidateIndexIterator.new(file_selector, event, @app_config, force)
17
+ else
18
+ # Get filesystem based implementation
19
+ ServiceCandidateFilesystemIterator.new(file_selector, event, @app_config, force)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module Longleaf
2
+ # Provides a single set of digests for files
3
+ class SingleDigestProvider
4
+ def initialize(digests)
5
+ @digests = digests
6
+ end
7
+
8
+ def get_digests(file_path)
9
+ return nil if @digests.nil?
10
+ @digests
11
+ end
12
+ end
13
+ end
@@ -2,70 +2,241 @@ require 'thor'
2
2
  require 'yaml'
3
3
  require 'longleaf/logging'
4
4
  require 'longleaf/errors'
5
+ require 'longleaf/version'
6
+ require 'longleaf/commands/deregister_command'
5
7
  require 'longleaf/commands/validate_config_command'
8
+ require 'longleaf/commands/validate_metadata_command'
6
9
  require 'longleaf/commands/register_command'
10
+ require 'longleaf/commands/reindex_command'
11
+ require 'longleaf/commands/preserve_command'
12
+ require 'longleaf/helpers/selection_options_parser'
7
13
 
8
14
  module Longleaf
15
+ # Main commandline interface setup for Longleaf using Thor.
9
16
  class CLI < Thor
10
17
  include Longleaf::Logging
11
-
12
- class_option(:config, :aliases => "-c",
13
- :default => ENV['LONGLEAF_CFG'],
14
- :desc => 'Absolute path to the application configuration used for this command. By default, the value of the environment variable LONGLEAF_CFG is used.')
15
- # Logging/output options
16
- class_option(:failure_only,
17
- :type => :boolean,
18
- :default => false,
19
- :desc => 'Only display failure messages to STDOUT.')
20
- class_option(:log_level,
21
- :default => 'WARN',
22
- :desc => 'Level of logging to send to STDERR, following standard ruby Logger levels. This includes: DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN. Default is WARN.')
23
- class_option(:log_format,
24
- :desc => 'Format to use for log information sent to STDERR. Can contain the following parameters, which must be wrapped in %{}: severity, datetime, progname, msg. Default is "%{severity} [%{datetime}]: %{msg}"')
25
- class_option(:log_datetime,
26
- :desc => 'Format to use for timestamps used in logging to STDERR, following strftime syntax.')
27
-
18
+
19
+ # Register a shared method option in a shared option group
20
+ def self.add_shared_option(name, group, options = {})
21
+ @shared_groups = {} if @shared_groups.nil?
22
+ @shared_groups[group] = {} if @shared_groups[group].nil?
23
+ @shared_groups[group][name] = options
24
+ end
25
+
26
+ # Add all of the shared options in the specified group as method options
27
+ def self.shared_options_group(group_name)
28
+ @shared_groups[group_name].each do |opt_name, opt|
29
+ option opt_name, opt
30
+ end
31
+ end
32
+
33
+ # Config options
34
+ add_shared_option(
35
+ :config, :common, {
36
+ :aliases => "-c",
37
+ :default => ENV['LONGLEAF_CFG'],
38
+ :required => false,
39
+ :desc => 'Path to the application configuration used for this command. By default, the value of the environment variable LONGLEAF_CFG is used. A config path is required for most commands.' })
40
+ add_shared_option(
41
+ :load_path, :common, {
42
+ :aliases => "-I",
43
+ :desc => 'Specify comma seperated directories to add to the $LOAD_PATH, which can be used to specify additional paths from which to load preservation services.' })
44
+
45
+ # Logging options
46
+ add_shared_option(
47
+ :failure_only, :common, {
48
+ :type => :boolean,
49
+ :default => false,
50
+ :desc => 'Only display failure messages to STDOUT.' })
51
+ add_shared_option(
52
+ :log_level, :common, {
53
+ :default => 'WARN',
54
+ :desc => 'Level of logging to send to STDERR, following standard ruby Logger levels. This includes: DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN.' })
55
+ add_shared_option(
56
+ :log_format, :common, {
57
+ :desc => 'Format to use for log information sent to STDERR. Can contain the following parameters, which must be wrapped in %{}: severity, datetime, progname, msg. Default is "%{severity} [%{datetime}]: %{msg}"' })
58
+ add_shared_option(
59
+ :log_datetime, :common, {
60
+ :desc => 'Format to use for timestamps used in logging to STDERR, following strftime syntax.' })
61
+
62
+ # File selection options
63
+ add_shared_option(
64
+ :file, :file_selection, {
65
+ :aliases => "-f",
66
+ :required => false,
67
+ :desc => 'File or files to perform this operation on. If multiple files are provided, they must be comma separated.' })
68
+ add_shared_option(
69
+ :location, :file_selection, {
70
+ :aliases => "-s",
71
+ :required => false,
72
+ :desc => 'Name or comma separated names of storage locations to perform this operation over.' })
73
+
74
+ add_shared_option(
75
+ :from_list, :registered_selection, {
76
+ :aliases => "-l",
77
+ :required => false,
78
+ :desc => %q{Provide a list of files to perform this operation on. The list must be new line separated, one file per line.
79
+ To provide a list from a file:
80
+ '-l /path/to/file_list.txt'
81
+ To provide a list from STDIN:
82
+ '-l @-'}})
83
+
84
+ # Commands
85
+ map %w[--version] => :__print_version
86
+ desc "--version", "Prints the Longleaf version number."
87
+ def __print_version
88
+ puts "longleaf version #{Longleaf::VERSION}"
89
+ end
90
+
28
91
  desc "register", "Register files with Longleaf"
29
- method_option(:file, :aliases => "-f",
30
- :required => true,
31
- :desc => 'File or files to register. Paths must be absolute. If multiple files are provided, they must be comma separated.')
92
+ shared_options_group(:file_selection)
93
+ method_option(:manifest,
94
+ :aliases => "-m",
95
+ :type => :array,
96
+ :desc => %q{Checksum manifests of files to register. Supports the following formats:
97
+ To submit a md5 manifest from a file
98
+ '-m md5:/path/to/manifest.txt'
99
+
100
+ To provide a sha1 manifest from STDIN
101
+ '-m sha1:@-'
102
+ Where the content in STDIN adheres to the format:
103
+ <digest> <path>
104
+ <digest> <path>
105
+ ...
106
+
107
+ To submit multiple manifests from files
108
+ '-m md5:/path/to/manifest1.txt sha1:/path/to/manifest2.txt'
109
+
110
+ To provide multiple digests via STDIN
111
+ '-m @-'
112
+ Where the content in STDIN adheres to the following format:
113
+ sha1:
114
+ <digest> <path>
115
+ ...
116
+ md5:
117
+ <digest> <path>
118
+ ...})
32
119
  method_option(:force,
33
- :type => :boolean,
120
+ :type => :boolean,
34
121
  :default => false,
35
122
  :desc => 'Force the registration of already registered files.')
36
123
  method_option(:checksums,
37
- :desc => %q{Checksums for the submitted file. Each checksum must be prefaced with an algorithm prefix. Multiple checksums must be comma separated. If multiple files were submitted, they will be provided with the same checksums. For example:
124
+ :desc => %q{Checksums for the submitted file. Only applicable with the -f option.
125
+ Each checksum must be prefaced with an algorithm prefix. Multiple checksums must be comma separated. If multiple files were submitted, they will be provided with the same checksums. For example:
38
126
  '--checksums "md5:d8e8fca2dc0f896fd7cb4cb0031ba249,sha1:4e1243bd22c66e76c2ba9eddc1f91394e57f9f83"'})
127
+ shared_options_group(:common)
39
128
  # Register event command
40
129
  def register
130
+ verify_config_provided(options)
41
131
  setup_logger(options)
42
-
43
- config_path = options[:config]
44
- file_paths = options[:file]&.split(/\s*,\s*/)
45
- if options[:checksums]
46
- checksums = options[:checksums]
47
- # validate checksum list format, must a comma delimited list of prefix:checksums
48
- if /^[^:,]+:[^:,]+(,[^:,]+:[^:,]+)*$/.match(checksums)
49
- # convert checksum list into hash with prefix as key
50
- checksums = Hash[*checksums.split(/\s*[:,]\s*/)]
51
- else
52
- logger.failure("Invalid checksums parameter format, see `longleaf help <command>` for more information")
53
- exit 1
54
- end
55
- end
56
-
57
- command = Longleaf::RegisterCommand.new(config_path)
58
- exit command.execute(file_paths: file_paths, force: options[:force], checksums: checksums)
132
+
133
+ app_config_manager = load_application_config(options)
134
+
135
+ file_selector, digest_provider = SelectionOptionsParser.parse_registration_selection_options(
136
+ options, app_config_manager)
137
+
138
+ command = RegisterCommand.new(app_config_manager)
139
+ exit command.execute(file_selector: file_selector, force: options[:force], digest_provider: digest_provider)
59
140
  end
60
-
61
- desc "validate_config [CONFIG_PATH]", "Validate an application configuration file"
141
+
142
+ desc "deregister", "Deregister files with Longleaf"
143
+ shared_options_group(:file_selection)
144
+ shared_options_group(:registered_selection)
145
+ method_option(:force,
146
+ :type => :boolean,
147
+ :default => false,
148
+ :desc => 'Force the deregistration of already deregistered files.')
149
+ shared_options_group(:common)
150
+ # Deregister event command
151
+ def deregister
152
+ verify_config_provided(options)
153
+ setup_logger(options)
154
+
155
+ app_config_manager = load_application_config(options)
156
+ file_selector = SelectionOptionsParser.create_registered_selector(options, app_config_manager)
157
+
158
+ command = DeregisterCommand.new(app_config_manager)
159
+ exit command.execute(file_selector: file_selector, force: options[:force])
160
+ end
161
+
162
+ desc "preserve", "Perform preservation services on files with Longleaf"
163
+ shared_options_group(:file_selection)
164
+ shared_options_group(:registered_selection)
165
+ method_option(:force,
166
+ :type => :boolean,
167
+ :default => false,
168
+ :desc => 'Force the execution of preservation services, disregarding scheduling information.')
169
+ shared_options_group(:common)
170
+ def preserve
171
+ verify_config_provided(options)
172
+ setup_logger(options)
173
+
174
+ extend_load_path(options[:load_path])
175
+ app_config_manager = load_application_config(options)
176
+ file_selector = SelectionOptionsParser.create_registered_selector(options, app_config_manager)
177
+
178
+ command = PreserveCommand.new(app_config_manager)
179
+ exit command.execute(file_selector: file_selector, force: options[:force])
180
+ end
181
+
182
+ desc "validate_config", "Validate an application configuration file, provided using --config."
183
+ shared_options_group(:common)
62
184
  # Application configuration validation command
63
- def validate_config(config_path)
185
+ def validate_config
186
+ verify_config_provided(options)
187
+ setup_logger(options)
188
+ extend_load_path(options[:load_path])
189
+
190
+ exit Longleaf::ValidateConfigCommand.new(options[:config]).execute
191
+ end
192
+
193
+ desc "validate_metadata", "Validate metadata files."
194
+ shared_options_group(:file_selection)
195
+ shared_options_group(:registered_selection)
196
+ shared_options_group(:common)
197
+ # File metadata validation command
198
+ def validate_metadata
199
+ verify_config_provided(options)
200
+ setup_logger(options)
201
+
202
+ app_config_manager = load_application_config(options)
203
+ file_selector = SelectionOptionsParser.create_registered_selector(options, app_config_manager)
204
+
205
+ exit Longleaf::ValidateMetadataCommand.new(app_config_manager).execute(file_selector: file_selector)
206
+ end
207
+
208
+ desc "setup_index", "Sets up the structure of the metadata index, if one is configured using the system configuration file provided using the --system_config option. Some index types may require additional steps to be taken by an administrator before hand, such as creating users and databases."
209
+ shared_options_group(:common)
210
+ def setup_index
211
+ verify_config_provided(options)
212
+ setup_logger(options)
213
+
214
+ app_config_manager = load_application_config(options)
215
+
216
+ if app_config_manager.index_manager.using_index?
217
+ app_config_manager.index_manager.setup_index
218
+ logger.success("Setup of index complete")
219
+ exit 0
220
+ else
221
+ logger.failure("No index configured, unable to perform setup.")
222
+ exit 1
223
+ end
224
+ end
225
+
226
+ desc "reindex", "Perform a full reindex of file metadata stored within the configured storage locations."
227
+ method_option(:if_stale,
228
+ :type => :boolean,
229
+ :default => false,
230
+ :desc => 'Only perform the reindex if the index is known to be stale, generally after an config file change.')
231
+ shared_options_group(:common)
232
+ def reindex
233
+ verify_config_provided(options)
64
234
  setup_logger(options)
65
-
66
- exit Longleaf::ValidateConfigCommand.new(config_path).execute
235
+ app_config_manager = load_application_config(options)
236
+
237
+ exit Longleaf::ReindexCommand.new(app_config_manager).execute(only_if_stale: options[:if_stale])
67
238
  end
68
-
239
+
69
240
  no_commands do
70
241
  def setup_logger(options)
71
242
  initialize_logger(options[:failure_only],
@@ -73,6 +244,26 @@ module Longleaf
73
244
  options[:log_format],
74
245
  options[:log_datetime])
75
246
  end
247
+
248
+ def load_application_config(options)
249
+ begin
250
+ app_manager = ApplicationConfigDeserializer.deserialize(options[:config])
251
+ rescue ConfigurationError => err
252
+ logger.failure("Failed to load application configuration due to the following issue(s):\n#{err.message}")
253
+ exit 1
254
+ end
255
+ end
256
+
257
+ def verify_config_provided(options)
258
+ if options[:config].nil? || options[:config].empty?
259
+ raise "No value provided for required options '--config'"
260
+ end
261
+ end
262
+
263
+ def extend_load_path(load_paths)
264
+ load_paths = load_paths&.split(/\s*,\s*/)
265
+ load_paths&.each { |path| $LOAD_PATH.unshift(path) }
266
+ end
76
267
  end
77
268
  end
78
- end
269
+ end
@@ -0,0 +1,51 @@
1
+ require 'longleaf/services/application_config_deserializer'
2
+ require 'longleaf/events/deregister_event'
3
+ require 'longleaf/models/file_record'
4
+ require 'longleaf/events/event_names'
5
+ require 'longleaf/events/event_status_tracking'
6
+
7
+ module Longleaf
8
+ # Command for deregistering files with longleaf
9
+ class DeregisterCommand
10
+ include Longleaf::EventStatusTracking
11
+
12
+ def initialize(app_manager)
13
+ @app_manager = app_manager
14
+ end
15
+
16
+ # Execute the deregister command on the given parameters
17
+ # @param file_selector [FileSelector] selector for files to deregister
18
+ # @param force [Boolean] force flag
19
+ # @return [Integer] status code
20
+ def execute(file_selector:, force: false)
21
+ start_time = Time.now
22
+ logger.info('Performing deregister command')
23
+ begin
24
+ # Perform deregister events on each of the file paths provided
25
+ loop do
26
+ f_path = file_selector.next_path
27
+ break if f_path.nil?
28
+
29
+ storage_location = @app_manager.location_manager.get_location_by_path(f_path)
30
+
31
+ file_rec = FileRecord.new(f_path, storage_location)
32
+ unless file_rec.metadata_present?
33
+ raise DeregistrationError.new("Cannot deregister #{f_path}, file is not registered.")
34
+ end
35
+
36
+ @app_manager.md_manager.load(file_rec)
37
+
38
+ event = DeregisterEvent.new(file_rec: file_rec, force: force, app_manager: @app_manager)
39
+ track_status(event.perform)
40
+ end
41
+ rescue RegistrationError, DeregistrationError, InvalidStoragePathError, StorageLocationUnavailableError => err
42
+ record_failure(EventNames::DEREGISTER, nil, err.message)
43
+ rescue => err
44
+ record_failure(EventNames::DEREGISTER, error: err)
45
+ end
46
+
47
+ logger.info("Completed deregister command in #{Time.now - start_time}s")
48
+ return_status
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,50 @@
1
+ require 'longleaf/errors'
2
+ require 'longleaf/events/event_status_tracking'
3
+ require 'longleaf/events/preserve_event'
4
+ require 'longleaf/services/application_config_deserializer'
5
+ require 'longleaf/candidates/file_selector'
6
+ require 'longleaf/candidates/service_candidate_locator'
7
+ require 'longleaf/events/event_names'
8
+ require 'longleaf/logging'
9
+
10
+ module Longleaf
11
+ # Command for preserving files
12
+ class PreserveCommand
13
+ include Longleaf::Logging
14
+ include Longleaf::EventStatusTracking
15
+
16
+ def initialize(app_manager)
17
+ @app_manager = app_manager
18
+ end
19
+
20
+ # Execute the preserve command on the given parameters
21
+ # @param file_selector [FileSelector] selector for files to preserve
22
+ # @param force [Boolean] force flag
23
+ # @return [Integer] status code
24
+ def execute(file_selector:, force: false)
25
+ start_time = Time.now
26
+ logger.info('Performing preserve command')
27
+ begin
28
+ # Perform preserve events on each of the file paths provided
29
+ candidate_locator = ServiceCandidateLocator.new(@app_manager)
30
+ candidate_it = candidate_locator.candidate_iterator(file_selector, EventNames::PRESERVE, force)
31
+ candidate_it.each do |file_rec|
32
+ begin
33
+ logger.debug("Selected candidate #{file_rec.path} for a preserve event")
34
+ preserve_event = PreserveEvent.new(file_rec: file_rec, force: force, app_manager: @app_manager)
35
+ track_status(preserve_event.perform)
36
+ rescue InvalidStoragePathError => e
37
+ record_failure(EventNames::PRESERVE, nil, e.message)
38
+ end
39
+ end
40
+ rescue LongleafError => e
41
+ record_failure(EventNames::PRESERVE, nil, e.message)
42
+ rescue => err
43
+ record_failure(EventNames::PRESERVE, error: err)
44
+ end
45
+
46
+ logger.info("Completed preserve command in #{Time.now - start_time}s")
47
+ return_status
48
+ end
49
+ end
50
+ end