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
@@ -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: []