fwissr 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/fotonauts/fwissr.png)](https://travis-ci.org/fotonauts/fwissr)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/fotonauts/fwissr.png)](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|
|