flight_config 0.1.1 → 0.2.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/lib/flight_config/accessor.rb +89 -0
- data/lib/flight_config/core.rb +68 -32
- data/lib/flight_config/deleter.rb +1 -2
- data/lib/flight_config/globber.rb +6 -5
- data/lib/flight_config/links.rb +54 -0
- data/lib/flight_config/reader.rb +22 -13
- data/lib/flight_config/updater.rb +3 -4
- data/lib/flight_config/version.rb +1 -1
- data/lib/flight_config.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8c36bdbe520695cb9d379d6038699c3529fb1fb8938af728fa50452ec0414ae
|
4
|
+
data.tar.gz: 58bf550037f38ede9db72516a5a70afd1b2fa1a47f1be8e7a3d7b95144d9d768
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf01421b86b937cfd4df7180398a81578723391cd26ac0f54e8c98d7ad741cc1315ff23f257460cb6e7474c652285e67cc5ffabf739fb1d3fda6e826847d6d21
|
7
|
+
data.tar.gz: 17768019155bd3e1621f0d597c89010b1403fe11f280ccec08f9e27c5685bb0435b0dbfdbc888b59bfcc84772146ebb153c2f624330505979d7c3b61b1bdbdc0
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#==============================================================================
|
2
|
+
# Copyright (C) 2019-present Alces Flight Ltd.
|
3
|
+
#
|
4
|
+
# This file is part of FlightConfig.
|
5
|
+
#
|
6
|
+
# This program and the accompanying materials are made available under
|
7
|
+
# the terms of the Eclipse Public License 2.0 which is available at
|
8
|
+
# <https://www.eclipse.org/legal/epl-2.0>, or alternative license
|
9
|
+
# terms made available by Alces Flight Ltd - please direct inquiries
|
10
|
+
# about licensing to licensing@alces-flight.com.
|
11
|
+
#
|
12
|
+
# FlightConfig is distributed in the hope that it will be useful, but
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
|
14
|
+
# IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS
|
15
|
+
# OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
|
16
|
+
# PARTICULAR PURPOSE. See the Eclipse Public License 2.0 for more
|
17
|
+
# details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the Eclipse Public License 2.0
|
20
|
+
# along with FlightConfig. If not, see:
|
21
|
+
#
|
22
|
+
# https://opensource.org/licenses/EPL-2.0
|
23
|
+
#
|
24
|
+
# For more information on FlightConfig, please visit:
|
25
|
+
# https://github.com/openflighthpc/flight_config
|
26
|
+
#==============================================================================
|
27
|
+
|
28
|
+
# NOTE: This is compatibility layer between the accessor and TTY::Config.
|
29
|
+
# TTY::Config isn't a good match with FlightConfig as they both try and preform
|
30
|
+
# the file handling. Instead a Hashie type object should be used.
|
31
|
+
#
|
32
|
+
# To facilitate the transition, the accessors use the standard [] and []= methods
|
33
|
+
# as these will be defined on most hashie objects. TTY::Config does not implement
|
34
|
+
# them however. Hence the need for the compatibility layer
|
35
|
+
|
36
|
+
module FlightConfig
|
37
|
+
module TTYConfigAccessor
|
38
|
+
def [](key)
|
39
|
+
fetch(key)
|
40
|
+
end
|
41
|
+
|
42
|
+
def []=(key, value)
|
43
|
+
if value.nil?
|
44
|
+
delete(key)
|
45
|
+
else
|
46
|
+
set(key, value: value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
TTY::Config.include(TTYConfigAccessor)
|
52
|
+
end
|
53
|
+
|
54
|
+
module FlightConfig
|
55
|
+
module Accessor
|
56
|
+
def self.included(base)
|
57
|
+
base.extend(ClassMethods)
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods
|
61
|
+
def data_accessor(key)
|
62
|
+
data_reader(key)
|
63
|
+
data_writer(key)
|
64
|
+
end
|
65
|
+
|
66
|
+
def data_reader(key, &b)
|
67
|
+
self.define_method(key) do
|
68
|
+
raw = __data__[key]
|
69
|
+
b ? instance_exec(raw, &b) : raw
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def data_writer(key, &b)
|
74
|
+
self.define_method("#{key}=") do |raw|
|
75
|
+
__data__[key] = b ? instance_exec(raw, &b) : raw
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def define_input_methods_from_path_parameters
|
80
|
+
self.method(:path)
|
81
|
+
.parameters
|
82
|
+
.select { |type, _| type == :req }
|
83
|
+
.each_with_index do |(_, arg), idx|
|
84
|
+
define_method(arg) { __inputs__[idx] }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/flight_config/core.rb
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
# For more information on FlightConfig, please visit:
|
25
25
|
# https://github.com/openflighthpc/flight_config
|
26
26
|
#==============================================================================
|
27
|
+
|
27
28
|
require 'flight_config/exceptions'
|
28
29
|
require 'flight_config/log'
|
29
30
|
require 'flight_config/patches/tty_config'
|
@@ -43,7 +44,8 @@ module FlightConfig
|
|
43
44
|
|
44
45
|
# Deprecated: The mode can be switched directly on the object
|
45
46
|
def self.read(obj)
|
46
|
-
obj.
|
47
|
+
obj.instance_variable_set(:@__read_mode__, true)
|
48
|
+
obj.instance_variable_set(:@__data__, nil)
|
47
49
|
obj.__data__
|
48
50
|
end
|
49
51
|
|
@@ -76,12 +78,32 @@ module FlightConfig
|
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
|
-
|
81
|
+
module ClassMethods
|
82
|
+
# NOTE: The _path method acts as adaptation layer to the two ways the path
|
83
|
+
# could be defined: on the class or instance. Moving forward, the path method
|
84
|
+
# should be defined on the class
|
85
|
+
# NOTE: DO NOT USE THIS METHOD PUBLICLY. Define a `path` method instead
|
86
|
+
def _path(*args)
|
87
|
+
if self.respond_to?(:path)
|
88
|
+
self.path(*args)
|
89
|
+
else
|
90
|
+
msg = <<~WARN.gsub("\n", ' ').chomp
|
91
|
+
FlightConfig Deprecation: #{self}.path is not defined. Falling back to
|
92
|
+
the instance method
|
93
|
+
WARN
|
94
|
+
Log.warn msg
|
95
|
+
$stderr.puts msg
|
96
|
+
self.new(*args).path
|
97
|
+
end
|
98
|
+
end
|
80
99
|
|
81
|
-
|
82
|
-
|
100
|
+
# *READ ME*: Hack Alart
|
101
|
+
# NOTE: Override this method in your class, and it should just work
|
102
|
+
# TODO: Eventually replace the _path method with this
|
103
|
+
# def path(*_args)
|
104
|
+
# raise NotImplementedError
|
105
|
+
# end
|
83
106
|
|
84
|
-
module ClassMethods
|
85
107
|
def allow_missing_read(fetch: false)
|
86
108
|
if fetch
|
87
109
|
@allow_missing_read ||= false
|
@@ -90,48 +112,62 @@ module FlightConfig
|
|
90
112
|
end
|
91
113
|
end
|
92
114
|
|
93
|
-
def
|
94
|
-
|
115
|
+
def data_core(klass = nil, &b)
|
116
|
+
@data_core ||= -> do
|
117
|
+
obj = (klass || TTY::Config).new
|
118
|
+
b ? b.call(obj) : obj
|
119
|
+
end
|
120
|
+
@data_core.call
|
95
121
|
end
|
96
122
|
end
|
97
123
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
Core.log(self, 'missing (skip read)')
|
107
|
-
else
|
108
|
-
raise MissingFile, "The file does not exist: #{path}"
|
109
|
-
end
|
124
|
+
attr_reader :__inputs__, :__read_mode__
|
125
|
+
|
126
|
+
def initialize(*input_args, registry: nil, read_mode: nil)
|
127
|
+
@__inputs__ = input_args
|
128
|
+
# TODO: Make this @path = self.class.path(*__inputs__)
|
129
|
+
self.path # Ensure the path can be established with the __inputs__
|
130
|
+
@__registry__ = registry
|
131
|
+
@__read_mode__ = read_mode
|
110
132
|
end
|
111
133
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
ERROR
|
118
|
-
else
|
119
|
-
@__data__mode = :read
|
120
|
-
end
|
134
|
+
def __registry__
|
135
|
+
@__registry__ ||= FlightConfig::Registry.new
|
136
|
+
end
|
137
|
+
|
138
|
+
def __data__initialize(_tty_config)
|
121
139
|
end
|
122
140
|
|
123
141
|
def __data__
|
124
|
-
@__data__ ||= self.class.
|
125
|
-
if
|
126
|
-
|
142
|
+
@__data__ ||= self.class.data_core.tap do |core|
|
143
|
+
if __read_mode__ && File.exists?(path)
|
144
|
+
Core.log(self, 'read')
|
145
|
+
str = File.read(path)
|
146
|
+
yaml_h = (str == Core::PLACEHOLDER ? nil : YAML.load(str))
|
147
|
+
core.merge(yaml_h) if yaml_h
|
148
|
+
elsif __read_mode__ && self.class.allow_missing_read(fetch: true)
|
149
|
+
Core.log(self, 'missing (skip read)')
|
150
|
+
elsif __read_mode__
|
151
|
+
raise MissingFile, "The file does not exist: #{path}"
|
127
152
|
else
|
128
153
|
__data__initialize(core)
|
129
154
|
end
|
130
155
|
end
|
131
156
|
end
|
132
157
|
|
158
|
+
# TODO: Eventually remove the error section as all the configs will have a
|
159
|
+
# class path method
|
160
|
+
# TODO: Set the path in initialize
|
133
161
|
def path
|
134
|
-
|
162
|
+
@path ||= begin
|
163
|
+
if self.class.respond_to?(:path)
|
164
|
+
self.class.path(*__inputs__)
|
165
|
+
else
|
166
|
+
raise FlightConfigError, <<~ERROR.chomp
|
167
|
+
#{self.class}.path has not been defined!
|
168
|
+
ERROR
|
169
|
+
end
|
170
|
+
end
|
135
171
|
end
|
136
172
|
end
|
137
173
|
end
|
@@ -42,11 +42,10 @@ module FlightConfig
|
|
42
42
|
|
43
43
|
module ClassMethods
|
44
44
|
def delete(*a)
|
45
|
-
new!(*a) do |config|
|
45
|
+
new!(*a, read_mode: true) do |config|
|
46
46
|
Deleter.delete_error_if_missing(config)
|
47
47
|
Core.log(config, 'delete')
|
48
48
|
Core.lock(config) do
|
49
|
-
config.__data__set_read_mode
|
50
49
|
config.__data__
|
51
50
|
if block_given? && !(yield config)
|
52
51
|
Core.log(config, 'delete (failed)')
|
@@ -29,11 +29,12 @@ require 'flight_config/reader'
|
|
29
29
|
module FlightConfig
|
30
30
|
module Globber
|
31
31
|
class Matcher
|
32
|
-
attr_reader :klass, :arity
|
32
|
+
attr_reader :klass, :arity, :registry
|
33
33
|
|
34
|
-
def initialize(klass, arity)
|
34
|
+
def initialize(klass, arity, registry)
|
35
35
|
@klass = klass
|
36
36
|
@arity = arity
|
37
|
+
@registry = (registry || FlightConfig::Registry.new)
|
37
38
|
end
|
38
39
|
|
39
40
|
def keys
|
@@ -50,7 +51,7 @@ module FlightConfig
|
|
50
51
|
def read(path)
|
51
52
|
data = regex.match(path)
|
52
53
|
init_args = keys.map { |key| data[key] }
|
53
|
-
klass.read(*init_args)
|
54
|
+
klass.read(*init_args, registry: registry)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -59,8 +60,8 @@ module FlightConfig
|
|
59
60
|
end
|
60
61
|
|
61
62
|
module ClassMethods
|
62
|
-
def glob_read(*a)
|
63
|
-
matcher = Globber::Matcher.new(self, a.length)
|
63
|
+
def glob_read(*a, registry: nil)
|
64
|
+
matcher = Globber::Matcher.new(self, a.length, registry)
|
64
65
|
glob_regex = self.new(*a).path
|
65
66
|
Dir.glob(glob_regex)
|
66
67
|
.map { |path| matcher.read(path) }
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#==============================================================================
|
2
|
+
# Copyright (C) 2019-present Alces Flight Ltd.
|
3
|
+
#
|
4
|
+
# This file is part of FlightConfig.
|
5
|
+
#
|
6
|
+
# This program and the accompanying materials are made available under
|
7
|
+
# the terms of the Eclipse Public License 2.0 which is available at
|
8
|
+
# <https://www.eclipse.org/legal/epl-2.0>, or alternative license
|
9
|
+
# terms made available by Alces Flight Ltd - please direct inquiries
|
10
|
+
# about licensing to licensing@alces-flight.com.
|
11
|
+
#
|
12
|
+
# FlightConfig is distributed in the hope that it will be useful, but
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
|
14
|
+
# IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS
|
15
|
+
# OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
|
16
|
+
# PARTICULAR PURPOSE. See the Eclipse Public License 2.0 for more
|
17
|
+
# details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the Eclipse Public License 2.0
|
20
|
+
# along with FlightConfig. If not, see:
|
21
|
+
#
|
22
|
+
# https://opensource.org/licenses/EPL-2.0
|
23
|
+
#
|
24
|
+
# For more information on FlightConfig, please visit:
|
25
|
+
# https://github.com/openflighthpc/flight_config
|
26
|
+
#==============================================================================
|
27
|
+
|
28
|
+
module FlightConfig
|
29
|
+
module Links
|
30
|
+
def self.included(base)
|
31
|
+
base.extend(ClassMethods)
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
include Globber::ClassMethods
|
36
|
+
|
37
|
+
def define_link(key, klass, glob: false, &b)
|
38
|
+
links_class.define_method(key) do
|
39
|
+
args = config.instance_exec(&b)
|
40
|
+
method = (glob ? :glob_read : :read)
|
41
|
+
klass.public_send(method, *args, registry: config.__registry__)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def links_class
|
46
|
+
@links_class ||= Struct.new(:config)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def links
|
51
|
+
@links ||= self.class.links_class.new(self)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/flight_config/reader.rb
CHANGED
@@ -24,9 +24,26 @@
|
|
24
24
|
# For more information on FlightConfig, please visit:
|
25
25
|
# https://github.com/openflighthpc/flight_config
|
26
26
|
#==============================================================================
|
27
|
+
|
27
28
|
require 'flight_config/core'
|
28
29
|
|
29
30
|
module FlightConfig
|
31
|
+
class Registry
|
32
|
+
def read(klass, *args)
|
33
|
+
class_hash = (cache[klass] ||= {})
|
34
|
+
arity_hash = (class_hash[args.length] ||= {})
|
35
|
+
last_arg = args.pop
|
36
|
+
last_hash = args.reduce(arity_hash) { |hash, arg| hash[arg] ||= {} }
|
37
|
+
last_hash[last_arg] ||= klass.new(*args, last_arg, registry: self, read_mode: true)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def cache
|
43
|
+
@cache ||= {}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
30
47
|
module Reader
|
31
48
|
include Core
|
32
49
|
|
@@ -37,27 +54,19 @@ module FlightConfig
|
|
37
54
|
module ClassMethods
|
38
55
|
include Core::ClassMethods
|
39
56
|
|
40
|
-
def new!(*a)
|
41
|
-
new(*a).tap do |config|
|
57
|
+
def new!(*a, **h)
|
58
|
+
new(*a, **h).tap do |config|
|
42
59
|
yield config if block_given?
|
43
60
|
end
|
44
61
|
end
|
45
62
|
|
46
|
-
def read(*a)
|
47
|
-
new
|
48
|
-
config.__data__set_read_mode
|
49
|
-
config.__data__
|
50
|
-
end
|
63
|
+
def read(*a, registry: nil)
|
64
|
+
(registry || Registry.new).read(self, *a)
|
51
65
|
end
|
52
66
|
alias_method :load, :read
|
53
67
|
|
54
68
|
def read_or_new(*a)
|
55
|
-
|
56
|
-
if File.exists?(config.path)
|
57
|
-
config.__data__set_read_mode
|
58
|
-
config.__data__
|
59
|
-
end
|
60
|
-
end
|
69
|
+
File.exists?(_path(*a)) ? read(*a) : new(*a)
|
61
70
|
end
|
62
71
|
end
|
63
72
|
end
|
@@ -64,16 +64,15 @@ module FlightConfig
|
|
64
64
|
include Reader::ClassMethods
|
65
65
|
|
66
66
|
def update(*a, &b)
|
67
|
-
new!(*a) do |config|
|
67
|
+
new!(*a, read_mode: true) do |config|
|
68
68
|
Updater.update_error_if_missing(config)
|
69
|
-
config.__data__set_read_mode
|
70
69
|
Updater.create_or_update(config, action: 'update', &b)
|
71
70
|
end
|
72
71
|
end
|
73
72
|
|
74
73
|
def create_or_update(*a, &b)
|
75
|
-
|
76
|
-
|
74
|
+
mode = File.exists?(_path(*a))
|
75
|
+
new!(*a, read_mode: mode) do |config|
|
77
76
|
Updater.create_or_update(config, action: 'create_or_update', &b)
|
78
77
|
end
|
79
78
|
end
|
data/lib/flight_config.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flight_config
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alces Flight Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-config
|
@@ -112,10 +112,12 @@ files:
|
|
112
112
|
- Rakefile
|
113
113
|
- flight_config.gemspec
|
114
114
|
- lib/flight_config.rb
|
115
|
+
- lib/flight_config/accessor.rb
|
115
116
|
- lib/flight_config/core.rb
|
116
117
|
- lib/flight_config/deleter.rb
|
117
118
|
- lib/flight_config/exceptions.rb
|
118
119
|
- lib/flight_config/globber.rb
|
120
|
+
- lib/flight_config/links.rb
|
119
121
|
- lib/flight_config/log.rb
|
120
122
|
- lib/flight_config/patches/tty_config.rb
|
121
123
|
- lib/flight_config/reader.rb
|