fwissr 1.0.0 → 1.0.1
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/README.md +13 -3
- data/lib/fwissr/registry.rb +22 -1
- data/lib/fwissr/source/file.rb +13 -0
- data/lib/fwissr/source/mongodb.rb +17 -6
- data/lib/fwissr/source.rb +12 -5
- data/lib/fwissr/version.rb +1 -1
- data/lib/fwissr.rb +69 -41
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
|
4
|
-
|
3
|
+
metadata.gz: 7b60e1c93fd5fdd4b3d8b81f044bf954eebe4983
|
4
|
+
data.tar.gz: 540b15881e2030ec311ea5872e77e8704a98f4d4
|
5
5
|
SHA512:
|
6
|
-
|
7
|
-
|
6
|
+
metadata.gz: f66e1dc7a1ceca8a2ca76b45ea97a02d2eaaf28d25f6e12b20e1789c83ea039fa13192502fd3bb2bbc70e1c07c2d2c5e90efa084bd82ca5b9a4d3db5f9be1ea1
|
7
|
+
data.tar.gz: 147b2802a910e2aba9ae169c6bd8769ec6c584699ad337e005039d339f9a0a6e155745bc206be8acac5e37bbd1299ec0d92d2a6e22b34eeeda5a3a3e2976b3fe
|
data/README.md
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
Fwissr
|
2
2
|
======
|
3
3
|
|
4
|
-
A simple configuration registry tool by Fotonauts.
|
4
|
+
A simple configuration registry tool by [Fotonauts](http://www.fotopedia.com).
|
5
|
+
|
6
|
+
[](https://travis-ci.org/fotonauts/fwissr)
|
7
|
+
[](https://codeclimate.com/github/fotonauts/fwissr)
|
8
|
+
|
9
|
+
- More information [on our tumblr](http://fotopedia-code.tumblr.com)
|
10
|
+
- Source code [on github](http://github.com/fotonauts/fwissr)
|
11
|
+
- Code documentation [on rubydoc](http://rubydoc.info/github/fotonauts/fwissr/frames)
|
5
12
|
|
6
13
|
|
7
14
|
Install
|
@@ -152,7 +159,7 @@ If the `filepath` setting is a directory then all the configuration files in tha
|
|
152
159
|
{
|
153
160
|
"fwissr_sources": [
|
154
161
|
{ "filepath": "/mnt/my_app/conf/" },
|
155
|
-
]
|
162
|
+
]
|
156
163
|
}
|
157
164
|
```
|
158
165
|
|
@@ -379,6 +386,9 @@ registry['/foo']
|
|
379
386
|
Credits
|
380
387
|
=======
|
381
388
|
|
382
|
-
|
389
|
+
From Fotonauts:
|
390
|
+
|
391
|
+
- Aymerick Jéhanne [@aymerick](https://twitter.com/aymerick)
|
392
|
+
- Pierre Baillet [@octplane](https://twitter.com/octplane)
|
383
393
|
|
384
394
|
Copyright (c) 2013 Fotonauts released under the MIT license.
|
data/lib/fwissr/registry.rb
CHANGED
@@ -25,6 +25,9 @@ module Fwissr
|
|
25
25
|
@refresh_thread = nil
|
26
26
|
end
|
27
27
|
|
28
|
+
# Add a source to registry
|
29
|
+
#
|
30
|
+
# @param source [Fwissr::Source] Concrete source instance
|
28
31
|
def add_source(source)
|
29
32
|
@semaphore.synchronize do
|
30
33
|
@sources << source
|
@@ -42,11 +45,15 @@ module Fwissr
|
|
42
45
|
self.ensure_refresh_thread
|
43
46
|
end
|
44
47
|
|
48
|
+
# Reload the registry
|
45
49
|
def reload!
|
46
50
|
self.reset!
|
47
51
|
self.load!
|
48
52
|
end
|
49
53
|
|
54
|
+
# Get a registry key value
|
55
|
+
#
|
56
|
+
# @param key [String] Key
|
50
57
|
def get(key)
|
51
58
|
# split key
|
52
59
|
key_ary = key.split('/')
|
@@ -65,12 +72,18 @@ module Fwissr
|
|
65
72
|
|
66
73
|
alias :[] :get
|
67
74
|
|
75
|
+
# Get all keys in registry
|
76
|
+
#
|
77
|
+
# @return [Array] Keys list
|
68
78
|
def keys
|
69
79
|
result = [ ]
|
70
80
|
_keys(result, [ ], self.registry)
|
71
81
|
result.sort
|
72
82
|
end
|
73
83
|
|
84
|
+
# Dump the registry
|
85
|
+
#
|
86
|
+
# @return [Hash] The entire registry
|
74
87
|
def dump
|
75
88
|
self.registry
|
76
89
|
end
|
@@ -80,16 +93,19 @@ module Fwissr
|
|
80
93
|
# PRIVATE
|
81
94
|
#
|
82
95
|
|
96
|
+
# @api private
|
83
97
|
def refresh_thread
|
84
98
|
@refresh_thread
|
85
99
|
end
|
86
100
|
|
101
|
+
# @api private
|
87
102
|
def have_refreshable_source?
|
88
103
|
@semaphore.synchronize do
|
89
104
|
!@sources.find { |source| source.can_refresh? }.nil?
|
90
105
|
end
|
91
106
|
end
|
92
107
|
|
108
|
+
# @api private
|
93
109
|
def ensure_refresh_thread
|
94
110
|
# check refresh thread state
|
95
111
|
if ((@refresh_period > 0) && self.have_refreshable_source?) && (!@refresh_thread || !@refresh_thread.alive?)
|
@@ -103,6 +119,7 @@ module Fwissr
|
|
103
119
|
end
|
104
120
|
end
|
105
121
|
|
122
|
+
# @api private
|
106
123
|
def ensure_frozen
|
107
124
|
if !@registry.frozen?
|
108
125
|
@semaphore.synchronize do
|
@@ -111,6 +128,7 @@ module Fwissr
|
|
111
128
|
end
|
112
129
|
end
|
113
130
|
|
131
|
+
# @api private
|
114
132
|
def reset!
|
115
133
|
@semaphore.synchronize do
|
116
134
|
@registry = { }
|
@@ -121,6 +139,7 @@ module Fwissr
|
|
121
139
|
end
|
122
140
|
end
|
123
141
|
|
142
|
+
# @api private
|
124
143
|
def load!
|
125
144
|
@semaphore.synchronize do
|
126
145
|
@registry = { }
|
@@ -132,6 +151,7 @@ module Fwissr
|
|
132
151
|
end
|
133
152
|
end
|
134
153
|
|
154
|
+
# @api private
|
135
155
|
def registry
|
136
156
|
self.ensure_refresh_thread
|
137
157
|
self.ensure_frozen
|
@@ -139,7 +159,8 @@ module Fwissr
|
|
139
159
|
@registry
|
140
160
|
end
|
141
161
|
|
142
|
-
#
|
162
|
+
# Helper for #keys
|
163
|
+
# @api private
|
143
164
|
def _keys(result, key_ary, hash)
|
144
165
|
hash.each do |key, value|
|
145
166
|
key_ary << key
|
data/lib/fwissr/source/file.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
# File based source
|
1
2
|
class Fwissr::Source::File < Fwissr::Source
|
2
3
|
|
3
4
|
class << self
|
4
5
|
|
6
|
+
# Instanciate source from path
|
7
|
+
#
|
8
|
+
# @param path [path] File path
|
9
|
+
# @param options [Hash] Source options
|
10
|
+
# @return [Fwissr::Source::File] Instance
|
5
11
|
def from_path(path, options = { })
|
6
12
|
if path.nil? || (path == '')
|
7
13
|
raise "Unexpected file source path: #{path.inspect}"
|
@@ -10,6 +16,10 @@ class Fwissr::Source::File < Fwissr::Source
|
|
10
16
|
self.new(path, options)
|
11
17
|
end
|
12
18
|
|
19
|
+
# Instanciate source from settings
|
20
|
+
#
|
21
|
+
# @param settings [Hash] Source settings
|
22
|
+
# @return [Fwissr::Source::File] Instance
|
13
23
|
def from_settings(settings)
|
14
24
|
options = settings.dup
|
15
25
|
options.delete('filepath')
|
@@ -28,6 +38,7 @@ class Fwissr::Source::File < Fwissr::Source
|
|
28
38
|
# API
|
29
39
|
#
|
30
40
|
|
41
|
+
# Subclass {Fwissr::Source#initialize}
|
31
42
|
def initialize(path, options = { })
|
32
43
|
super(options)
|
33
44
|
|
@@ -36,6 +47,7 @@ class Fwissr::Source::File < Fwissr::Source
|
|
36
47
|
@path = path
|
37
48
|
end
|
38
49
|
|
50
|
+
# Implements {Fwissr::Source#fetch_conf}
|
39
51
|
def fetch_conf
|
40
52
|
result = { }
|
41
53
|
|
@@ -59,6 +71,7 @@ class Fwissr::Source::File < Fwissr::Source
|
|
59
71
|
# PRIVATE
|
60
72
|
#
|
61
73
|
|
74
|
+
# @api private
|
62
75
|
def merge_conf_file!(result, conf_file_path)
|
63
76
|
# parse conf file
|
64
77
|
conf = Fwissr.parse_conf_file(conf_file_path)
|
@@ -10,13 +10,15 @@ rescue LoadError
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
# Mongodb based source
|
13
14
|
class Fwissr::Source::Mongodb < Fwissr::Source
|
14
15
|
|
16
|
+
# A mongodb connection
|
17
|
+
# @api private
|
15
18
|
class Connection
|
16
19
|
|
17
20
|
attr_reader :db_name
|
18
21
|
|
19
|
-
# init
|
20
22
|
def initialize(uri)
|
21
23
|
raise "URI is missing: #{uri}" if (uri.nil? || uri == '')
|
22
24
|
|
@@ -44,6 +46,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
49
|
+
# Database connection
|
47
50
|
def conn
|
48
51
|
@conn ||= begin
|
49
52
|
case @kind
|
@@ -55,6 +58,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
55
58
|
end
|
56
59
|
end
|
57
60
|
|
61
|
+
# Database collection
|
58
62
|
def collection(col_name)
|
59
63
|
@collections[col_name] ||= begin
|
60
64
|
case @kind
|
@@ -66,7 +70,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
69
|
-
#
|
73
|
+
# Returns an Enumerator for all documents from given collection
|
70
74
|
def fetch(col_name)
|
71
75
|
case @kind
|
72
76
|
when :moped, :mongo
|
@@ -74,7 +78,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
77
|
-
#
|
81
|
+
# Insert document in collection
|
78
82
|
def insert(col_name, doc)
|
79
83
|
case @kind
|
80
84
|
when :moped, :mongo
|
@@ -82,7 +86,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
85
|
-
#
|
89
|
+
# Create a collection
|
86
90
|
def create_collection(col_name)
|
87
91
|
case @kind
|
88
92
|
when :moped
|
@@ -92,7 +96,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
95
|
-
#
|
99
|
+
# Drop database
|
96
100
|
def drop_database(db_name)
|
97
101
|
case @kind
|
98
102
|
when :moped
|
@@ -105,6 +109,10 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
105
109
|
|
106
110
|
class << self
|
107
111
|
|
112
|
+
# Instanciate source
|
113
|
+
#
|
114
|
+
# @param settings [Hash] Mongodb settings
|
115
|
+
# @return [Fwissr::Source::Mongodb] Instance
|
108
116
|
def from_settings(settings)
|
109
117
|
if settings['mongodb'].nil? || (settings['mongodb'] == '') || settings['collection'].nil? || (settings['collection'] == '')
|
110
118
|
raise "Erroneous mongodb settings: #{settings.inspect}"
|
@@ -119,6 +127,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
119
127
|
self.new(conn, settings['collection'], options)
|
120
128
|
end
|
121
129
|
|
130
|
+
# @api private
|
122
131
|
def connection_for_uri(uri)
|
123
132
|
@connections ||= { }
|
124
133
|
@connections[uri] ||= Fwissr::Source::Mongodb::Connection.new(uri)
|
@@ -135,6 +144,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
135
144
|
# API
|
136
145
|
#
|
137
146
|
|
147
|
+
# Subclass {Fwissr::Source#initialize}
|
138
148
|
def initialize(conn, collection_name, options = { })
|
139
149
|
super(options)
|
140
150
|
|
@@ -142,6 +152,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
142
152
|
@collection_name = collection_name
|
143
153
|
end
|
144
154
|
|
155
|
+
# Implements {Fwissr::Source#fetch_conf}
|
145
156
|
def fetch_conf
|
146
157
|
result = { }
|
147
158
|
result_part = result
|
@@ -158,7 +169,7 @@ class Fwissr::Source::Mongodb < Fwissr::Source
|
|
158
169
|
end
|
159
170
|
end
|
160
171
|
|
161
|
-
#
|
172
|
+
# Build conf hash from collection's documents
|
162
173
|
conf = { }
|
163
174
|
self.conn.fetch(@collection_name).each do |doc|
|
164
175
|
key = doc['_id']
|
data/lib/fwissr/source.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# @abstract Subclass and override {#fetch_conf} to implement a configuration source.
|
1
2
|
class Fwissr::Source
|
2
3
|
|
3
4
|
autoload :File, 'fwissr/source/file'
|
@@ -30,17 +31,21 @@ class Fwissr::Source
|
|
30
31
|
@conf = nil
|
31
32
|
end
|
32
33
|
|
33
|
-
#
|
34
|
+
# Reset source
|
34
35
|
def reset!
|
35
36
|
@conf = nil
|
36
37
|
end
|
37
38
|
|
38
|
-
#
|
39
|
+
# Source can be refreshed ?
|
40
|
+
#
|
41
|
+
# @return [Boolean] Is it a refreshable source ?
|
39
42
|
def can_refresh?
|
40
43
|
@options && (@options['refresh'] == true)
|
41
44
|
end
|
42
45
|
|
43
|
-
#
|
46
|
+
# Get source conf
|
47
|
+
#
|
48
|
+
# @return [Hash] The source's configuration
|
44
49
|
def get_conf
|
45
50
|
if (@conf && !self.can_refresh?)
|
46
51
|
# return already fetched conf if refresh is not allowed
|
@@ -51,9 +56,11 @@ class Fwissr::Source
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
#
|
59
|
+
# Fetch conf from source
|
60
|
+
#
|
61
|
+
# @abstract MUST be implemented by child class
|
62
|
+
# @return [Hash] The source's configuration
|
55
63
|
def fetch_conf
|
56
|
-
# MUST be implemented by child class
|
57
64
|
raise "not implemented"
|
58
65
|
end
|
59
66
|
|
data/lib/fwissr/version.rb
CHANGED
data/lib/fwissr.rb
CHANGED
@@ -16,6 +16,30 @@ require 'fwissr/version'
|
|
16
16
|
require 'fwissr/source'
|
17
17
|
require 'fwissr/registry'
|
18
18
|
|
19
|
+
#
|
20
|
+
# Global Registry
|
21
|
+
# ===============
|
22
|
+
#
|
23
|
+
# Fwissr loads all conf files in main directories: +/etc/fwissr/+ and +~/.fwissr/+
|
24
|
+
#
|
25
|
+
# Two conf files are treated differently: +/etc/fwissr/fwissr.json+ and +~/.fwissr/fwissr.json+
|
26
|
+
#
|
27
|
+
# These two main conf files are 'top_level' ones and so their settings are added to global registry root. They can
|
28
|
+
# too contain a +fwissr_sources+ setting that is then used to setup additional sources.
|
29
|
+
#
|
30
|
+
# Global registry is accessed with Fwissr#[] method
|
31
|
+
#
|
32
|
+
# @example +/etc/fwissr/fwissr.json+ file:
|
33
|
+
#
|
34
|
+
# {
|
35
|
+
# 'fwissr_sources': [
|
36
|
+
# { 'filepath': '/mnt/my_app/conf/' },
|
37
|
+
# { 'filepath': '/etc/my_app.json' },
|
38
|
+
# { 'mongodb': 'mongodb://db1.example.net/my_app', 'collection': 'config', 'refresh': true },
|
39
|
+
# ],
|
40
|
+
# 'fwissr_refresh_period': 30
|
41
|
+
# }
|
42
|
+
#
|
19
43
|
module Fwissr
|
20
44
|
|
21
45
|
# default path where main conf file is located
|
@@ -30,19 +54,22 @@ module Fwissr
|
|
30
54
|
class << self
|
31
55
|
attr_writer :main_conf_path, :main_user_conf_path
|
32
56
|
|
33
|
-
#
|
57
|
+
# Main config files directory
|
58
|
+
# @api private
|
34
59
|
def main_conf_path
|
35
60
|
@main_conf_path ||= DEFAULT_MAIN_CONF_PATH
|
36
61
|
end
|
37
62
|
|
38
|
-
#
|
63
|
+
# User's specific config files directory
|
64
|
+
# @api private
|
39
65
|
def main_user_conf_path
|
40
66
|
@main_user_conf_path ||= File.join(Fwissr.find_home, DEFAULT_MAIN_USER_CONF_DIR)
|
41
67
|
end
|
42
68
|
|
43
|
-
#
|
69
|
+
# Finds the user's home directory
|
44
70
|
#
|
45
|
-
# Borrowed from rubygems
|
71
|
+
# @note Borrowed from rubygems
|
72
|
+
# @api private
|
46
73
|
def find_home
|
47
74
|
['HOME', 'USERPROFILE'].each do |homekey|
|
48
75
|
return ENV[homekey] if ENV[homekey]
|
@@ -64,6 +91,7 @@ module Fwissr
|
|
64
91
|
end
|
65
92
|
|
66
93
|
# Parse command line arguments
|
94
|
+
# @api private
|
67
95
|
def parse_args!(argv)
|
68
96
|
args = {
|
69
97
|
:inspect => false,
|
@@ -121,26 +149,8 @@ module Fwissr
|
|
121
149
|
args
|
122
150
|
end
|
123
151
|
|
124
|
-
|
125
|
-
#
|
126
|
-
# Global Registry
|
127
|
-
#
|
128
|
-
#
|
129
|
-
# NOTE: Parses main conf files (/etc/fwissr/fwissr.json and ~/.fwissr/fwissr.json) then uses 'fwissr_sources' setting to setup additional sources
|
130
|
-
#
|
131
|
-
# Example of /etc/fwissr/fwissr.json file:
|
132
|
-
#
|
133
|
-
# {
|
134
|
-
# 'fwissr_sources': [
|
135
|
-
# { 'filepath': '/mnt/my_app/conf/' },
|
136
|
-
# { 'filepath': '/etc/my_app.json' },
|
137
|
-
# { 'mongodb': 'mongodb://db1.example.net/my_app', 'collection': 'config', 'refresh': true },
|
138
|
-
# ],
|
139
|
-
# 'fwissr_refresh_period': 30,
|
140
|
-
# }
|
141
|
-
#
|
142
|
-
|
143
|
-
# access global registry with Fwissr['/foo/bar']
|
152
|
+
# Load global registry
|
153
|
+
# @api private
|
144
154
|
def global_registry
|
145
155
|
@global_registry ||= begin
|
146
156
|
result = Fwissr::Registry.new('refresh_period' => self.main_conf['fwissr_refresh_period'])
|
@@ -168,7 +178,8 @@ module Fwissr
|
|
168
178
|
end
|
169
179
|
end
|
170
180
|
|
171
|
-
#
|
181
|
+
# Main config
|
182
|
+
# @api private
|
172
183
|
def main_conf
|
173
184
|
@main_conf ||= begin
|
174
185
|
result = { }
|
@@ -185,29 +196,38 @@ module Fwissr
|
|
185
196
|
end
|
186
197
|
end
|
187
198
|
|
199
|
+
# Main config file
|
200
|
+
# @api private
|
188
201
|
def main_conf_file
|
189
202
|
@main_conf_file ||= File.join(self.main_conf_path, MAIN_CONF_FILE)
|
190
203
|
end
|
191
204
|
|
205
|
+
# Main user's config file
|
206
|
+
# @api private
|
192
207
|
def main_user_conf_file
|
193
208
|
@main_user_conf_file ||= File.join(self.main_user_conf_path, MAIN_CONF_FILE)
|
194
209
|
end
|
195
210
|
|
196
|
-
#
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
EOS
|
211
|
+
# Global registry accessor
|
212
|
+
#
|
213
|
+
# @param key [String] setting key
|
214
|
+
# @return [Object] setting value
|
215
|
+
def [](key)
|
216
|
+
self.global_registry[key]
|
203
217
|
end
|
204
218
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
219
|
+
alias :get :[]
|
220
|
+
|
221
|
+
# Dumps global registry keys
|
222
|
+
#
|
223
|
+
# @return [Array] Keys list
|
224
|
+
def keys
|
225
|
+
self.global_registry.keys
|
226
|
+
end
|
227
|
+
|
228
|
+
# @return [Hash] The entire registry
|
229
|
+
def dump
|
230
|
+
self.global_registry.dump
|
211
231
|
end
|
212
232
|
|
213
233
|
|
@@ -215,6 +235,11 @@ module Fwissr
|
|
215
235
|
# Utils
|
216
236
|
#
|
217
237
|
|
238
|
+
# Parse a configuration file
|
239
|
+
#
|
240
|
+
# @param conf_file_path [String] Configuration file path
|
241
|
+
# @return [Hash] Parse configuration
|
242
|
+
# @api private
|
218
243
|
def parse_conf_file(conf_file_path)
|
219
244
|
conf_file_ext = File.extname(conf_file_path)
|
220
245
|
|
@@ -234,12 +259,14 @@ module Fwissr
|
|
234
259
|
end
|
235
260
|
end
|
236
261
|
|
237
|
-
#
|
262
|
+
# @note Borrowed from rails
|
263
|
+
# @api private
|
238
264
|
def merge_conf(to_hash, other_hash)
|
239
265
|
self.merge_conf!(to_hash.dup, other_hash)
|
240
266
|
end
|
241
267
|
|
242
|
-
#
|
268
|
+
# @note Borrowed from rails
|
269
|
+
# @api private
|
243
270
|
def merge_conf!(to_hash, other_hash)
|
244
271
|
other_hash.each_pair do |k,v|
|
245
272
|
tv = to_hash[k]
|
@@ -248,7 +275,8 @@ module Fwissr
|
|
248
275
|
to_hash
|
249
276
|
end
|
250
277
|
|
251
|
-
#
|
278
|
+
# Simple deep freezer
|
279
|
+
# @api private
|
252
280
|
def deep_freeze(obj)
|
253
281
|
if obj.is_a?(Hash)
|
254
282
|
obj.each do |k, v|
|