longleaf 0.1.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +13 -0
  7. data/README.md +43 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/exe/longleaf +3 -0
  12. data/lib/longleaf/cli.rb +78 -0
  13. data/lib/longleaf/commands/abstract_command.rb +37 -0
  14. data/lib/longleaf/commands/register_command.rb +59 -0
  15. data/lib/longleaf/commands/validate_config_command.rb +29 -0
  16. data/lib/longleaf/errors.rb +15 -0
  17. data/lib/longleaf/events/register_event.rb +98 -0
  18. data/lib/longleaf/logging/redirecting_logger.rb +131 -0
  19. data/lib/longleaf/logging.rb +26 -0
  20. data/lib/longleaf/models/app_fields.rb +10 -0
  21. data/lib/longleaf/models/file_record.rb +25 -0
  22. data/lib/longleaf/models/md_fields.rb +18 -0
  23. data/lib/longleaf/models/metadata_record.rb +57 -0
  24. data/lib/longleaf/models/service_definition.rb +21 -0
  25. data/lib/longleaf/models/service_fields.rb +10 -0
  26. data/lib/longleaf/models/service_record.rb +27 -0
  27. data/lib/longleaf/models/storage_location.rb +37 -0
  28. data/lib/longleaf/services/application_config_deserializer.rb +46 -0
  29. data/lib/longleaf/services/application_config_manager.rb +24 -0
  30. data/lib/longleaf/services/application_config_validator.rb +18 -0
  31. data/lib/longleaf/services/configuration_validator.rb +8 -0
  32. data/lib/longleaf/services/metadata_deserializer.rb +68 -0
  33. data/lib/longleaf/services/metadata_serializer.rb +76 -0
  34. data/lib/longleaf/services/service_definition_manager.rb +36 -0
  35. data/lib/longleaf/services/service_definition_validator.rb +32 -0
  36. data/lib/longleaf/services/service_manager.rb +21 -0
  37. data/lib/longleaf/services/service_mapping_manager.rb +47 -0
  38. data/lib/longleaf/services/service_mapping_validator.rb +49 -0
  39. data/lib/longleaf/services/storage_location_manager.rb +37 -0
  40. data/lib/longleaf/services/storage_location_validator.rb +60 -0
  41. data/lib/longleaf/services/storage_path_validator.rb +16 -0
  42. data/lib/longleaf/specs/config_builder.rb +102 -0
  43. data/lib/longleaf/version.rb +3 -0
  44. data/lib/longleaf.rb +4 -0
  45. data/longleaf.gemspec +34 -0
  46. metadata +188 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 41b149cc264dcc00b79558d1acc06fd42c7810e8b06fe62627baf359fb23a784
4
+ data.tar.gz: f4634c72c87d9858faace5e8c480d96b85365a37e989addfac8d2a044b957d08
5
+ SHA512:
6
+ metadata.gz: 07aa3758499e04ff45f1fcbf1bd9e51af22b0d64ef4314ba784dc1eb0fae78bffeb6faf285e0fbe107761cf6c0c89dd024b814eb6a130821718a53d985eebe47
7
+ data.tar.gz: 4546b08c4e3119f783bd7134b0a49ee7cb0f022509829122b136f872fad95b38c8c31a4db1eed021d51adb639e4cf63c2972cfeeeeaeda8cef194b026fd9051b
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in longleaf.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2018 UNC Libraries
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Longleaf
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/longleaf`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'longleaf'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install longleaf
22
+
23
+ ## Usage
24
+
25
+ #### Validate configuration files
26
+ Application configuration files can be validated prior to usage with the following command:
27
+ `longleaf validate_config <config.yml>`
28
+
29
+ ## Development
30
+
31
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
32
+
33
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/longleaf.
38
+
39
+
40
+ ## License
41
+
42
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
43
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "longleaf"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/longleaf ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'longleaf/cli'
3
+ Longleaf::CLI.start
@@ -0,0 +1,78 @@
1
+ require 'thor'
2
+ require 'yaml'
3
+ require 'longleaf/logging'
4
+ require 'longleaf/errors'
5
+ require 'longleaf/commands/validate_config_command'
6
+ require 'longleaf/commands/register_command'
7
+
8
+ module Longleaf
9
+ class CLI < Thor
10
+ 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
+
28
+ 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.')
32
+ method_option(:force,
33
+ :type => :boolean,
34
+ :default => false,
35
+ :desc => 'Force the registration of already registered files.')
36
+ 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:
38
+ '--checksums "md5:d8e8fca2dc0f896fd7cb4cb0031ba249,sha1:4e1243bd22c66e76c2ba9eddc1f91394e57f9f83"'})
39
+ # Register event command
40
+ def register
41
+ 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)
59
+ end
60
+
61
+ desc "validate_config [CONFIG_PATH]", "Validate an application configuration file"
62
+ # Application configuration validation command
63
+ def validate_config(config_path)
64
+ setup_logger(options)
65
+
66
+ exit Longleaf::ValidateConfigCommand.new(config_path).execute
67
+ end
68
+
69
+ no_commands do
70
+ def setup_logger(options)
71
+ initialize_logger(options[:failure_only],
72
+ options[:log_level],
73
+ options[:log_format],
74
+ options[:log_datetime])
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,37 @@
1
+ require 'longleaf/logging'
2
+
3
+ # Parent class for longleaf commands
4
+ module Longleaf
5
+ class AbstractCommand
6
+ include Longleaf::Logging
7
+
8
+ # Record a successful operation to the output and the overall status of this command.
9
+ # @param args [Array] arguments to pass to logger
10
+ def record_success(*args)
11
+ logger.success(*args)
12
+ if @return_status.nil? || @return_status == 0
13
+ @return_status = 0
14
+ else
15
+ @return_status = 2
16
+ end
17
+ end
18
+
19
+ # Record a failed operation to the output and the overall status of this command.
20
+ # @param args [Array] arguments to pass to logger
21
+ def record_failure(*args)
22
+ logger.failure(*args)
23
+ if @return_status.nil? || @return_status == 1
24
+ @return_status = 1
25
+ else
26
+ @return_status = 2
27
+ end
28
+ end
29
+
30
+ # @return [Integer] the return status for this command, where 0 indicates success,
31
+ # 1 indicates failure, and 2 indicates partial failure
32
+ def return_status
33
+ @return_status = 0 if @return_status.nil?
34
+ @return_status
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,59 @@
1
+ require 'longleaf/services/application_config_deserializer'
2
+ require 'longleaf/events/register_event'
3
+ require 'longleaf/models/file_record'
4
+ require 'longleaf/commands/abstract_command'
5
+
6
+ # Command for registering files with longleaf
7
+ module Longleaf
8
+ class RegisterCommand < AbstractCommand
9
+
10
+ def initialize(config_path)
11
+ @config_path = config_path
12
+ end
13
+
14
+ # Execute the register command on the given parameters
15
+ def execute(file_paths: nil, force: false, checksums: nil)
16
+ if file_paths.nil? || file_paths.empty?
17
+ record_failure("Must provide one or more file paths to register")
18
+ return return_status
19
+ end
20
+
21
+ begin
22
+ # Retrieve the application configuration
23
+ app_manager = Longleaf::ApplicationConfigDeserializer.deserialize(@config_path)
24
+
25
+ # Perform register events on each of the file paths provided
26
+ file_paths.each do |f_path|
27
+ begin
28
+ storage_location = app_manager.location_manager.get_location_by_path(f_path)
29
+ if storage_location.nil?
30
+ raise InvalidStoragePathError.new(
31
+ "Unable to register '#{f_path}', it does not belong to any registered storage locations.")
32
+ end
33
+
34
+ raise InvalidStoragePathError.new("Unable to register '#{f_path}', file does not exist or is unreachable.") \
35
+ unless File.file?(f_path)
36
+
37
+ file_rec = FileRecord.new(f_path, storage_location)
38
+
39
+ register_event = RegisterEvent.new(file_rec: file_rec, force: force, app_manager: app_manager,
40
+ checksums: checksums)
41
+ register_event.perform
42
+
43
+ record_success(RegisterEvent::EVENT_NAME, f_path)
44
+ rescue RegistrationError => err
45
+ record_failure(RegisterEvent::EVENT_NAME, f_path, err.message)
46
+ rescue InvalidStoragePathError => err
47
+ record_failure(RegisterEvent::EVENT_NAME, f_path, err.message)
48
+ end
49
+ end
50
+ rescue ConfigurationError => err
51
+ record_failure("Failed to load application configuration due to the following issue:\n#{err.message}")
52
+ rescue => err
53
+ record_failure(RegisterEvent::EVENT_NAME, error: err)
54
+ end
55
+
56
+ return_status
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,29 @@
1
+ require 'longleaf/services/application_config_deserializer'
2
+ require 'longleaf/commands/abstract_command'
3
+
4
+ module Longleaf
5
+ class ValidateConfigCommand < AbstractCommand
6
+ def initialize(config_path)
7
+ @config_path = config_path
8
+ end
9
+
10
+ def execute
11
+ begin
12
+ app_config_manager = Longleaf::ApplicationConfigDeserializer.deserialize(@config_path)
13
+
14
+ location_manager = app_config_manager.location_manager
15
+ location_manager.locations.each do |name, location|
16
+ location.available?
17
+ end
18
+
19
+ record_success("Application configuration passed validation: #{@config_path}")
20
+ rescue Longleaf::ConfigurationError, Longleaf::StorageLocationUnavailableError => err
21
+ record_failure("Application configuration invalid due to the following issue:\n#{err.message}")
22
+ rescue => err
23
+ record_failure("Failed to validate application configuration", error: err)
24
+ end
25
+
26
+ return_status
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ module Longleaf
2
+ class LongleafError < StandardError; end
3
+
4
+ class ConfigurationError < LongleafError; end
5
+
6
+ class InvalidStoragePathError < LongleafError; end
7
+
8
+ class MetadataError < LongleafError; end
9
+
10
+ class StorageLocationUnavailableError < LongleafError; end
11
+
12
+ class EventError < LongleafError; end
13
+
14
+ class RegistrationError < EventError; end
15
+ end
@@ -0,0 +1,98 @@
1
+ require 'longleaf/errors'
2
+ require 'longleaf/models/metadata_record'
3
+ require 'longleaf/services/metadata_deserializer'
4
+ require 'longleaf/services/metadata_serializer'
5
+ require 'time'
6
+
7
+ # Event to register a file with longleaf
8
+ module Longleaf
9
+ class RegisterEvent
10
+ EVENT_NAME = 'register'
11
+
12
+ # @param file_rec [FileRecord] file record
13
+ # @param app_manager [ApplicationConfigManager] the application configuration
14
+ # @param force [boolean] if true, then already registered files will be re-registered
15
+ def initialize(file_rec:, app_manager:, force: false, checksums: nil)
16
+ raise ArgumentError.new('Must provide a file_rec parameter') if file_rec.nil?
17
+ raise ArgumentError.new('Parameter file_rec must be a FileRecord') \
18
+ unless file_rec.is_a?(FileRecord)
19
+ raise ArgumentError.new('Must provide an ApplicationConfigManager') if app_manager.nil?
20
+ raise ArgumentError.new('Parameter app_manager must be an ApplicationConfigManager') \
21
+ unless app_manager.is_a?(ApplicationConfigManager)
22
+
23
+ @app_manager = app_manager
24
+ @file_rec = file_rec
25
+ @force = force
26
+ @checksums = checksums
27
+ end
28
+
29
+ # Perform a registration event on the given file
30
+ # @raises RegistrationError if a file cannot be registered
31
+ def perform
32
+ metadata_exists = File.file?(@file_rec.metadata_path)
33
+ # If the file's metadata exists, only need to register it if the force flag is provided
34
+ if metadata_exists && !@force
35
+ raise RegistrationError.new("Unable to register '#{@file_rec.path}', it is already registered.")
36
+ end
37
+
38
+ # create metadata record
39
+ md_rec = MetadataRecord.new(registered: Time.now.utc.iso8601)
40
+ @file_rec.metadata_record = md_rec
41
+
42
+ # retain significant details from former record
43
+ if metadata_exists
44
+ retain_existing_properties
45
+ end
46
+
47
+ populate_file_properties
48
+
49
+ md_rec.checksums.merge!(@checksums) unless @checksums.nil?
50
+
51
+ populate_services
52
+
53
+ # persist the metadata out to file
54
+ MetadataSerializer::write(metadata: md_rec, file_path: @file_rec.metadata_path)
55
+ end
56
+
57
+ private
58
+ def populate_file_properties
59
+ md_rec = @file_rec.metadata_record
60
+
61
+ # Set file properties
62
+ md_rec.last_modified = File.mtime(@file_rec.path).utc.iso8601
63
+ md_rec.file_size = File.size(@file_rec.path)
64
+ end
65
+
66
+ def populate_services
67
+ md_rec = @file_rec.metadata_record
68
+
69
+ service_manager = @app_manager.service_manager
70
+ definitions = service_manager.list_service_definitions(location: @file_rec.storage_location.name)
71
+
72
+ # Add service section
73
+ definitions.each do |serv_def|
74
+ serv_name = serv_def.name
75
+ md_rec.add_service(serv_name)
76
+ end
77
+ end
78
+
79
+ # Copy a subset of properties from an existing metadata record to the new record
80
+ def retain_existing_properties
81
+ md_rec = @file_rec.metadata_record
82
+
83
+ old_md = MetadataDeserializer.deserialize(file_path: @file_rec.metadata_path)
84
+ # Copy custom properties
85
+ old_md.properties.each { |name, value| md_rec.properties[name] = value }
86
+ # Copy stale-replicas flag per service
87
+ old_md.list_services.each do |serv_name|
88
+ serv_rec = old_md.service(serv_name)
89
+
90
+ stale_replicas = serv_rec.stale_replicas
91
+ if stale_replicas
92
+ new_service = md_rec.service(serv_name)
93
+ new_service.stale_replicas = stale_replicas unless new_service.nil?
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,131 @@
1
+ require 'logger'
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
+ module Longleaf
7
+ module Logging
8
+ class RedirectingLogger
9
+ # @param failure_only [Boolean] If set to true, only failure messages will be output to STDOUT
10
+ # @param log_level [String] logger level used for output to STDERR
11
+ # @param log_format [Strfailure_onlying] format string for log entries to STDERR. There are 4 variables available
12
+ # for inclusion in the output: severity, datetime, progname, msg. Variables must be wrapped in %{}.
13
+ # @param datetime_format [String] datetime formatting string used for logger dates appearing in STDERR.
14
+ def initialize(failure_only: false, log_level: 'WARN', log_format: nil, datetime_format: nil)
15
+ @stderr_log = Logger.new($stderr)
16
+ @stderr_log.level = log_level
17
+ @stderr_log.datetime_format = datetime_format
18
+ @log_format = log_format
19
+ if @log_format.nil?
20
+ @stderr_log.formatter = proc do |severity, datetime, progname, msg|
21
+ formatted_date = @stderr_log.datetime_format.nil? ? datetime : datetime.strftime(datetime_format)
22
+ "#{severity} [#{formatted_date}]: #{msg}\n"
23
+ end
24
+ elsif @log_format.is_a?(String)
25
+ @stderr_log.formatter = proc do |severity, datetime, progname, msg|
26
+ # Make sure the format ends with a newline
27
+ @log_format = @log_format + "\n" unless @log_format.end_with?("\n")
28
+
29
+ formatted_date = @stderr_log.datetime_format.nil? ? datetime : datetime.strftime(datetime_format)
30
+ @log_format % { :severity => severity, :datetime => formatted_date, :progname => progname, :msg => msg }
31
+ end
32
+ end
33
+
34
+ @stdout_log = Logger.new($stdout)
35
+ @stdout_log.formatter = proc do |severity, datetime, progname, msg|
36
+ "#{msg}\n"
37
+ end
38
+ if failure_only
39
+ @stdout_log.level = 'warn'
40
+ else
41
+ @stdout_log.level = 'info'
42
+ end
43
+ end
44
+
45
+ def debug(progname = nil, &block)
46
+ @stderr_log.debug(progname, &block)
47
+ end
48
+
49
+ def info(progname = nil, &block)
50
+ @stderr_log.info(progname, &block)
51
+ end
52
+
53
+ def warn(progname = nil, &block)
54
+ @stderr_log.warn(progname, &block)
55
+ end
56
+
57
+ def error(progname = nil, &block)
58
+ @stderr_log.error(progname, &block)
59
+ end
60
+
61
+ def fatal(progname = nil, &block)
62
+ @stderr_log.fatal(progname, &block)
63
+ end
64
+
65
+ def unknown(progname = nil, &block)
66
+ @stderr_log.unknown(progname, &block)
67
+ end
68
+
69
+ # Logs a success message to STDOUT, as well as STDERR at info level.
70
+ # @param eventOrMessage [String] name of the preservation event which succeeded,
71
+ # or the message to output if it is the only parameter. Required.
72
+ # @param file_name [String] file name which is the subject of this message.
73
+ # @param message [String] descriptive message to accompany this output
74
+ # @param service [String] name of the service which executed.
75
+ def success(eventOrMessage, file_name = nil, message = nil, service = nil)
76
+ outcome('SUCCESS', eventOrMessage, file_name, message, service)
77
+ end
78
+
79
+ # Logs a failure message to STDOUT, as well as STDERR at info level.
80
+ # 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
+ # or the message to output if it is the only parameter.
83
+ # @param file_name [String] file name which is the subject of this message.
84
+ # @param message [String] descriptive message to accompany this output
85
+ # @param service [String] name of the service which executed.
86
+ # @param error [Error] error which occurred
87
+ def failure(eventOrMessage, file_name = nil, message = nil, service = nil, error: nil)
88
+ text = outcome_text('FAILURE', eventOrMessage, file_name, message, service, error)
89
+ @stdout_log.warn(text)
90
+
91
+ @stderr_log.info(text)
92
+ @stderr_log.error("#{error.message}") unless error.nil?
93
+ end
94
+
95
+ # Logs an outcome message to STDOUT, as well as STDERR at info level.
96
+ # If file_name and message are nil, eventOrMessage will be used as the message.
97
+ #
98
+ # @param outcome [String] The status of the outcome. Required.
99
+ # @param eventOrMessage [String] name of the preservation event which was successful,
100
+ # or the message to output if it is the only parameter. Required.
101
+ # @param file_name [String] file name which is the subject of this message.
102
+ # @param message [String] descriptive message to accompany this output
103
+ # @param service [String] name of the service which executed.
104
+ # @param error [Error] error which occurred
105
+ def outcome(outcome, eventOrMessage, file_name = nil, message = nil, service = nil, error = nil)
106
+ text = outcome_text(outcome, eventOrMessage, file_name, message, service, error)
107
+ @stdout_log.info(text)
108
+ @stderr_log.info(text)
109
+ end
110
+
111
+ # FAILURE verify[cdr_fixity_check] /path/to/file: Something terrible
112
+ private
113
+ def outcome_text(outcome, eventOrMessage, file_name = nil, message = nil, service = nil, error = nil)
114
+ message_only = file_name.nil? && message.nil? && error.nil?
115
+
116
+ text = "#{outcome}"
117
+
118
+ if message_only
119
+ text << ": #{eventOrMessage}"
120
+ else
121
+ text << " #{eventOrMessage}"
122
+ text << "[#{service}]" unless service.nil?
123
+ text << " #{file_name}" unless file_name.nil?
124
+ msg = message || error&.message
125
+ text << ": #{msg}" unless msg.nil?
126
+ end
127
+ text
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,26 @@
1
+ require 'longleaf/logging/redirecting_logger'
2
+
3
+ module Longleaf
4
+ module Logging
5
+ # Get the main logger for longleaf
6
+ def logger
7
+ Logging.logger
8
+ end
9
+
10
+ # Get the main logger for longleaf
11
+ def self.logger
12
+ @logger ||= RedirectingLogger.new
13
+ end
14
+
15
+ def initialize_logger(failure_only, log_level, log_format, datetime_format)
16
+ Logging.initialize_logger(failure_only, log_level, log_format, datetime_format)
17
+ end
18
+
19
+ def self.initialize_logger(failure_only, log_level, log_format, datetime_format)
20
+ @logger = RedirectingLogger.new(failure_only: failure_only,
21
+ log_level: log_level,
22
+ log_format: log_format,
23
+ datetime_format: datetime_format)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ module Longleaf
2
+ class AppFields
3
+ LOCATIONS = 'locations'
4
+ SERVICES = 'services'
5
+ SERVICE_MAPPINGS = 'service_mappings'
6
+
7
+ LOCATION_PATH = 'path'
8
+ METADATA_PATH = 'metadata_path'
9
+ end
10
+ end
@@ -0,0 +1,25 @@
1
+ # Record for an individual file and its associated information
2
+ module Longleaf
3
+ class FileRecord
4
+
5
+ attr_accessor :metadata_record
6
+ attr_reader :storage_location
7
+ attr_reader :path
8
+
9
+ # @param file_path [String] path to the file
10
+ # @param storage_location [Longleaf::StorageLocation] storage location containing the file
11
+ def initialize(file_path, storage_location)
12
+ raise ArgumentError.new("FileRecord requires a path") if file_path.nil?
13
+ raise ArgumentError.new("FileRecord requires a storage_location") if storage_location.nil?
14
+
15
+ @path = file_path
16
+ @storage_location = storage_location
17
+ end
18
+
19
+ # @return [String] path for the metadata file for this file
20
+ def metadata_path
21
+ @metadata_path = @storage_location.get_metadata_path_for(path) if @metadata_path.nil?
22
+ @metadata_path
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module Longleaf
2
+ class MDFields
3
+ DATA = 'data'
4
+ SERVICES = 'services'
5
+
6
+ REGISTERED_TIMESTAMP = 'registered'
7
+ DEREGISTERED_TIMESTAMP = 'deregistered'
8
+
9
+ LAST_MODIFIED = 'last-modified'
10
+ FILE_SIZE = 'size'
11
+
12
+ CHECKSUMS = 'checksums'
13
+
14
+ STALE_REPLICAS = 'stale-replicas'
15
+ SERVICE_TIMESTAMP = 'timestamp'
16
+ RUN_NEEDED = 'run-needed'
17
+ end
18
+ end