longleaf 0.1.0.pre.2

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.
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
@@ -0,0 +1,60 @@
1
+ require 'pathname'
2
+ require 'longleaf/models/storage_location'
3
+ require 'longleaf/models/app_fields'
4
+ require 'longleaf/errors'
5
+ require_relative 'configuration_validator'
6
+ require 'longleaf/services/storage_path_validator'
7
+
8
+ # Validates application configuration of storage locations
9
+ module Longleaf
10
+ class StorageLocationValidator < ConfigurationValidator
11
+ AF ||= Longleaf::AppFields
12
+
13
+ # Validates configuration to ensure that it is syntactically correct and does not violate
14
+ # schema and uniqueness requirements.
15
+ # @param config [Hash] hash containing the application configuration
16
+ def self.validate_config(config)
17
+ assert("Configuration must be a hash, but a #{config.class} was provided", config.class == Hash)
18
+ assert("Configuration must contain a root '#{AF::LOCATIONS}' key", config.key?(AF::LOCATIONS))
19
+ locations = config[AF::LOCATIONS]
20
+ assert("'#{AF::LOCATIONS}' must be a hash of locations", locations.class == Hash)
21
+
22
+ existing_paths = Array.new
23
+ locations.each do |name, properties|
24
+ assert("Name of storage location must be a string, but was of type #{name.class}", name.instance_of?(String))
25
+ assert("Storage location '#{name}' must be a hash, but a #{properties.class} was provided", properties.is_a?(Hash))
26
+
27
+ assert_path_property_valid(name, AF::LOCATION_PATH, properties, existing_paths)
28
+ assert_path_property_valid(name, AF::METADATA_PATH, properties, existing_paths)
29
+ end
30
+ end
31
+
32
+ private
33
+ def self.assert_path_property_valid(name, path_prop, properties, existing_paths)
34
+ path = properties[path_prop]
35
+ begin
36
+ StoragePathValidator::validate(path)
37
+ rescue InvalidStoragePathError => err
38
+ raise ConfigurationError.new(
39
+ "Storage location '#{name}' specifies invalid '#{path_prop}' property: #{err.message}")
40
+ end
41
+ assert("Storage location '#{name}' must specify a '#{path_prop}' property", !path.nil? && !path.empty?)
42
+ assert("Storage location '#{name}' must specify an absolute path for property '#{path_prop}'",
43
+ Pathname.new(path).absolute? && !path.include?('/..'))
44
+ # Ensure paths have trailing slash to avoid matching on partial directory names
45
+ path += '/' unless path.end_with?('/')
46
+ # Verify that the (metadata_)path property's value is not inside of another storage location or vice versa
47
+ existing_paths.each do |existing|
48
+ if existing.start_with?(path) || path.start_with?(existing)
49
+ msg = "Location '#{name}' defines property #{path_prop} with value '#{path}'" \
50
+ " which overlaps with another configured path '#{existing}'." \
51
+ " Storage locations must not define #{AF::LOCATION_PATH} or #{AF::METADATA_PATH}" \
52
+ " properties which are contained by another location property"
53
+ raise ConfigurationError.new(msg)
54
+ end
55
+ end
56
+
57
+ existing_paths << path
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,16 @@
1
+ require 'longleaf/errors'
2
+
3
+ # Validator for storage paths
4
+ module Longleaf
5
+ class StoragePathValidator
6
+ # Checks that the given path is a syntactically valid storage path
7
+ # @param path [String] file storage path to validate
8
+ # @raises [InvalidStoragePathError]
9
+ def self.validate(path)
10
+ raise InvalidStoragePathError.new("Path must not be empty") if path.to_s.strip.empty?
11
+ raise InvalidStoragePathError.new("Path must be absolute") unless Pathname.new(path).absolute?
12
+ raise InvalidStoragePathError.new("Path must not contain any relative modifiers (/..)") \
13
+ if path.include?('/..')
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,102 @@
1
+ require_relative '../models/app_fields'
2
+ require_relative '../models/service_fields'
3
+ require 'yaml'
4
+
5
+ # Test helper for constructing application configuration hashes
6
+ module Longleaf
7
+ class ConfigBuilder
8
+ AF ||= Longleaf::AppFields
9
+ SF ||= Longleaf::ServiceFields
10
+
11
+ attr_accessor :config
12
+
13
+ def initialize
14
+ @config = Hash.new
15
+ end
16
+
17
+ # Add a root 'locations' field to the config
18
+ # @param locations [Hash] value for the locations fields. Default is {}
19
+ # @return this builder
20
+ def with_locations(locations = Hash.new)
21
+ @config[AF::LOCATIONS] = locations
22
+ self
23
+ end
24
+
25
+ # Add a 'location' to the config
26
+ # @param name [String] name of the location
27
+ # @param path [String] value for the 'path' field
28
+ # @param md_path [String] value for the 'metadata_path' field
29
+ # @return this builder
30
+ def with_location(name:, path: '/file/path/', md_path: '/metadata/path/')
31
+ @config[AF::LOCATIONS] = Hash.new unless @config.key?(AF::LOCATIONS)
32
+
33
+ location = {}
34
+ @config[AF::LOCATIONS][name] = location
35
+ location[AF::LOCATION_PATH] = path unless path.nil?
36
+ location[AF::METADATA_PATH] = md_path unless md_path.nil?
37
+ self
38
+ end
39
+
40
+ # Add a root 'services' field to the config
41
+ # @param services [Hash] value for the services field. Default is {}
42
+ # @return this builder
43
+ def with_services(services = Hash.new)
44
+ @config[AF::SERVICES] = services
45
+ self
46
+ end
47
+
48
+ # Add a 'service' to the config
49
+ # @param name [String] name of the service
50
+ # @param work_script [String] value for the 'work_script' field
51
+ # @param frequency [String] value for the 'frequency' field
52
+ # @param delay [String] value for the 'delay' field
53
+ # @param properties [Hash] hash of additional properties to include in the service
54
+ # @return this builder
55
+ def with_service(name:, work_script: 'some_pres_service.rb', frequency: nil, delay: nil, properties: nil)
56
+ @config[AF::SERVICES] = Hash.new unless @config.key?(AF::SERVICES)
57
+
58
+ service = {}
59
+ service[SF::WORK_SCRIPT] = work_script
60
+ service[SF::FREQUENCY] = frequency unless frequency.nil?
61
+ service[SF::DELAY] = delay unless delay.nil?
62
+ service = service.merge(properties) unless properties.nil?
63
+ @config[AF::SERVICES][name] = service
64
+ self
65
+ end
66
+
67
+ # Adds a 'service_mappings' section to the config
68
+ # @param mappings [Object] the mappings config
69
+ # @return this builder
70
+ def with_mappings(mappings = Hash.new)
71
+ @config[AF::SERVICE_MAPPINGS] = mappings
72
+ self
73
+ end
74
+
75
+ # Add a mapping from one or more services to one or more location
76
+ # @param loc_names [Object] one or more location names. Can be a string or array.
77
+ # @param service_names [Object] one or more service names. Can be a string or array.
78
+ def map_services(loc_names, service_names)
79
+ @config[AF::SERVICE_MAPPINGS] = Array.new unless @config.key?(AF::SERVICE_MAPPINGS)
80
+
81
+ mapping = Hash.new
82
+ mapping[AF::LOCATIONS] = loc_names unless loc_names.nil?
83
+ mapping[AF::SERVICES] = service_names unless service_names.nil?
84
+ @config[AF::SERVICE_MAPPINGS].push(mapping)
85
+ self
86
+ end
87
+
88
+ # @return the constructed configuration
89
+ def get
90
+ @config
91
+ end
92
+
93
+ # Writes the configuration from this builder into a temporary file
94
+ # @return the file path of the config file
95
+ def write_to_yaml_file
96
+ Tempfile.open('config') do |f|
97
+ f.write(@config.to_yaml)
98
+ return f.path
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,3 @@
1
+ module Longleaf
2
+ VERSION = "0.1.0.pre.2"
3
+ end
data/lib/longleaf.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "longleaf/version"
2
+
3
+ module Longleaf
4
+ end
data/longleaf.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'longleaf/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "longleaf"
8
+ spec.version = Longleaf::VERSION
9
+ spec.authors = ["bbpennel"]
10
+ spec.email = ["bbpennel@email.unc.edu"]
11
+
12
+ spec.summary = %q{Longleaf preservation services tool}
13
+ spec.description = %q{Provides a framework for performing preservation services over sets of files.}
14
+ spec.homepage = "https://github.com/UNC-Libraries/"
15
+ spec.license = "Apache-2.0"
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = "longleaf"
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "thor", "~> 0.20.0"
27
+ spec.add_dependency "yard", "~> 0.9.16"
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.16"
30
+ spec.add_development_dependency "rake", "~> 12.0"
31
+ spec.add_development_dependency "rspec", "~> 3.6.0"
32
+ spec.add_development_dependency "factory_bot", "~> 4.0"
33
+ spec.add_development_dependency "aruba", "~> 0.14.0"
34
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: longleaf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre.2
5
+ platform: ruby
6
+ authors:
7
+ - bbpennel
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-10-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.20.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.20.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.16
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.16
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '12.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '12.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.6.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.6.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: factory_bot
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '4.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '4.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: aruba
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.14.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.14.0
111
+ description: Provides a framework for performing preservation services over sets of
112
+ files.
113
+ email:
114
+ - bbpennel@email.unc.edu
115
+ executables:
116
+ - longleaf
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - ".gitignore"
121
+ - ".rspec"
122
+ - ".travis.yml"
123
+ - Gemfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - bin/console
128
+ - bin/setup
129
+ - exe/longleaf
130
+ - lib/longleaf.rb
131
+ - lib/longleaf/cli.rb
132
+ - lib/longleaf/commands/abstract_command.rb
133
+ - lib/longleaf/commands/register_command.rb
134
+ - lib/longleaf/commands/validate_config_command.rb
135
+ - lib/longleaf/errors.rb
136
+ - lib/longleaf/events/register_event.rb
137
+ - lib/longleaf/logging.rb
138
+ - lib/longleaf/logging/redirecting_logger.rb
139
+ - lib/longleaf/models/app_fields.rb
140
+ - lib/longleaf/models/file_record.rb
141
+ - lib/longleaf/models/md_fields.rb
142
+ - lib/longleaf/models/metadata_record.rb
143
+ - lib/longleaf/models/service_definition.rb
144
+ - lib/longleaf/models/service_fields.rb
145
+ - lib/longleaf/models/service_record.rb
146
+ - lib/longleaf/models/storage_location.rb
147
+ - lib/longleaf/services/application_config_deserializer.rb
148
+ - lib/longleaf/services/application_config_manager.rb
149
+ - lib/longleaf/services/application_config_validator.rb
150
+ - lib/longleaf/services/configuration_validator.rb
151
+ - lib/longleaf/services/metadata_deserializer.rb
152
+ - lib/longleaf/services/metadata_serializer.rb
153
+ - lib/longleaf/services/service_definition_manager.rb
154
+ - lib/longleaf/services/service_definition_validator.rb
155
+ - lib/longleaf/services/service_manager.rb
156
+ - lib/longleaf/services/service_mapping_manager.rb
157
+ - lib/longleaf/services/service_mapping_validator.rb
158
+ - lib/longleaf/services/storage_location_manager.rb
159
+ - lib/longleaf/services/storage_location_validator.rb
160
+ - lib/longleaf/services/storage_path_validator.rb
161
+ - lib/longleaf/specs/config_builder.rb
162
+ - lib/longleaf/version.rb
163
+ - longleaf.gemspec
164
+ homepage: https://github.com/UNC-Libraries/
165
+ licenses:
166
+ - Apache-2.0
167
+ metadata: {}
168
+ post_install_message:
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">"
180
+ - !ruby/object:Gem::Version
181
+ version: 1.3.1
182
+ requirements: []
183
+ rubyforge_project:
184
+ rubygems_version: 2.7.6
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: Longleaf preservation services tool
188
+ test_files: []