easy_app_helper 1.0.14 → 2.0.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.
- checksums.yaml +4 -4
- data/.gitignore +48 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/README.md +90 -447
- data/Rakefile +1 -8
- data/easy_app_helper.gemspec +6 -6
- data/lib/easy_app_helper/config/compatibility.rb +22 -0
- data/lib/easy_app_helper/config/initializer.rb +15 -0
- data/lib/easy_app_helper/config.rb +11 -0
- data/lib/easy_app_helper/logger/initializer.rb +46 -0
- data/lib/easy_app_helper/logger/wrapper.rb +12 -0
- data/lib/easy_app_helper/managed_logger.rb +9 -0
- data/lib/easy_app_helper/version.rb +1 -8
- data/lib/easy_app_helper.rb +23 -14
- data/spec/config_spec.rb +18 -188
- data/spec/easy_app_helper_spec.rb +28 -0
- data/spec/logger_spec.rb +8 -27
- data/spec/spec_helper.rb +92 -0
- metadata +27 -18
- data/etc/test_internal.conf +0 -3
- data/lib/easy_app_helper/core/base.rb +0 -228
- data/lib/easy_app_helper/core/config.rb +0 -220
- data/lib/easy_app_helper/core/logger.rb +0 -111
- data/lib/easy_app_helper/core/merge_policies.rb +0 -40
- data/lib/easy_app_helper/core/places.rb +0 -87
- data/lib/easy_app_helper/module_manager.rb +0 -68
- data/test/test.yml +0 -7
@@ -1,228 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# EasyAppHelper
|
3
|
-
#
|
4
|
-
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
-
# http://opensource.org/licenses/MIT
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
require 'slop'
|
9
|
-
|
10
|
-
# This class is the base class for the {EasyAppHelper::Core::Config config} object.
|
11
|
-
# It handles the internal_configs hash that actually contains all configurations read from
|
12
|
-
# various sources: command line, config files etc...
|
13
|
-
|
14
|
-
class EasyAppHelper::Core::Base
|
15
|
-
CHANGED_BY_CODE = 'Changed by code'
|
16
|
-
INTRODUCED_SORTED_LAYERS = [:modified, :command_line]
|
17
|
-
|
18
|
-
attr_reader :script_filename, :app_name, :app_version, :app_description, :internal_configs, :logger
|
19
|
-
|
20
|
-
def initialize(logger)
|
21
|
-
@app_name = @app_version = @app_description = ""
|
22
|
-
@script_filename = File.basename $0, '.*'
|
23
|
-
@internal_configs = {modified: {content: {}, source: CHANGED_BY_CODE}}
|
24
|
-
@logger = logger
|
25
|
-
@slop_definition = Slop.new
|
26
|
-
build_command_line_options
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
# @return [String] The formatted command line help
|
31
|
-
def help
|
32
|
-
@slop_definition.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
# sets the filename while maintaining the slop definition upto date
|
36
|
-
# @param [String] filename
|
37
|
-
def script_filename=(filename)
|
38
|
-
@script_filename = filename
|
39
|
-
@slop_definition.banner = build_banner
|
40
|
-
end
|
41
|
-
# sets the application name used for logging while maintaining the slop definition upto date
|
42
|
-
# @param [String] fname
|
43
|
-
def app_name=(name)
|
44
|
-
@app_name = name
|
45
|
-
@slop_definition.banner = build_banner
|
46
|
-
end
|
47
|
-
# sets the version while maintaining the slop definition upto date
|
48
|
-
# @param [String] version
|
49
|
-
def app_version=(version)
|
50
|
-
@app_version = version
|
51
|
-
@slop_definition.banner = build_banner
|
52
|
-
end
|
53
|
-
# sets the filename while maintaining the slop definition upto date
|
54
|
-
# @param [String] description
|
55
|
-
def app_description=(description)
|
56
|
-
@app_description = description
|
57
|
-
@slop_definition.banner = build_banner
|
58
|
-
end
|
59
|
-
|
60
|
-
# helper to add in one command any of the four base properties used
|
61
|
-
# by the logger and the config objects.
|
62
|
-
# @param [String] app_name
|
63
|
-
# @param [String] script_filename
|
64
|
-
# @param [String] app_version
|
65
|
-
# @param [String] app_description
|
66
|
-
def describes_application(options = {})
|
67
|
-
app_name = options.fetch(:app_name, nil)
|
68
|
-
script_filename = options.fetch(:script_filename, nil)
|
69
|
-
app_version = options.fetch(:app_version, nil)
|
70
|
-
app_description = options.fetch(:app_description, nil)
|
71
|
-
self.app_name = app_name unless app_name.nil?
|
72
|
-
self.app_version = app_version unless app_version.nil?
|
73
|
-
self.app_description = app_description unless app_description.nil?
|
74
|
-
self.script_filename = script_filename unless script_filename.nil?
|
75
|
-
end
|
76
|
-
|
77
|
-
# @return [Hash] This hash built from slop definition correspond to the :command_line layer of internal_configs
|
78
|
-
def command_line_config
|
79
|
-
@slop_definition.parse
|
80
|
-
@slop_definition.to_hash
|
81
|
-
end
|
82
|
-
|
83
|
-
# Yields a slop definition to modify the command line parameters
|
84
|
-
# @param [String] title used to insert a slop separator
|
85
|
-
def add_command_line_section(title='Script specific')
|
86
|
-
raise "Incorrect usage" unless block_given?
|
87
|
-
@slop_definition.separator build_separator(title)
|
88
|
-
yield @slop_definition
|
89
|
-
ensure
|
90
|
-
sync!
|
91
|
-
end
|
92
|
-
|
93
|
-
# Sets the :command_line layer of internal_configs to the computed {#command_line_config}
|
94
|
-
def load_config
|
95
|
-
sync!
|
96
|
-
self
|
97
|
-
end
|
98
|
-
|
99
|
-
# Convenient method to set a value in a particular layer
|
100
|
-
# If the layer does not exist it is correctly created and filled in with the key/value couple
|
101
|
-
def set_value key, value, layer = nil
|
102
|
-
if layer.nil?
|
103
|
-
self[key] = value
|
104
|
-
return
|
105
|
-
end
|
106
|
-
unless layers.include? layer
|
107
|
-
internal_configs[layer] = {content: {}, source: 'Unknown source'}
|
108
|
-
logger.warn "Trying to modify a non existing config layer: \"#{layer.to_s}\". Automatically creating it..."
|
109
|
-
end
|
110
|
-
internal_configs[layer][:content][key] = value
|
111
|
-
end
|
112
|
-
|
113
|
-
def get_value key, layer = nil
|
114
|
-
if layer.nil?
|
115
|
-
return self[key]
|
116
|
-
end
|
117
|
-
res = nil
|
118
|
-
begin
|
119
|
-
res = internal_configs[layer][:content][key]
|
120
|
-
rescue => e
|
121
|
-
logger.warn "Trying to reading from a non existing config layer: \"#{layer}\". Returning nil for the key \"#{key}\"..."
|
122
|
-
end
|
123
|
-
res
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
# Any modification done to the config is in fact stored in the :modified layer of internal_configs
|
129
|
-
# @param [String] key
|
130
|
-
# @param [String] value
|
131
|
-
def []=(key,value)
|
132
|
-
internal_configs[:modified][:content][key] = value unless check_hardcoded_properties key, value
|
133
|
-
end
|
134
|
-
|
135
|
-
# Reset the :modified layer of internal_configs rolling back any change done to the config
|
136
|
-
def reset
|
137
|
-
internal_configs[:modified] = {content: {}, source: CHANGED_BY_CODE}
|
138
|
-
self
|
139
|
-
end
|
140
|
-
|
141
|
-
|
142
|
-
# @return [Array] List of layers
|
143
|
-
def layers
|
144
|
-
res = self.class.layers
|
145
|
-
internal_configs.keys.each do |layer|
|
146
|
-
next if res.include? layer
|
147
|
-
res << layer
|
148
|
-
end
|
149
|
-
res
|
150
|
-
end
|
151
|
-
|
152
|
-
def self.layers
|
153
|
-
res = []
|
154
|
-
self.ancestors.each do |klass|
|
155
|
-
next unless klass.is_a? Class
|
156
|
-
break if EasyAppHelper::Core::Base < klass
|
157
|
-
res << klass::INTRODUCED_SORTED_LAYERS.reverse
|
158
|
-
end
|
159
|
-
res.flatten.reverse
|
160
|
-
end
|
161
|
-
|
162
|
-
|
163
|
-
def find_layer(key)
|
164
|
-
layers.each do |layer|
|
165
|
-
return layer if internal_configs[layer][:content][key]
|
166
|
-
end
|
167
|
-
nil
|
168
|
-
end
|
169
|
-
|
170
|
-
|
171
|
-
# Executes code (block given) unless :simulate is in the config.
|
172
|
-
# If :simulate specified then display message instead of executing the code (block).
|
173
|
-
def safely_exec(message, *args)
|
174
|
-
raise "No block given" unless block_given?
|
175
|
-
if self[:simulate]
|
176
|
-
logger.puts_and_logs "SIMULATING: #{message}" unless message.nil?
|
177
|
-
else
|
178
|
-
logger.puts_and_logs message
|
179
|
-
yield(*args)
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
|
184
|
-
private
|
185
|
-
|
186
|
-
def sync!
|
187
|
-
internal_configs[:command_line] = {content: command_line_config, source: 'Command line'}
|
188
|
-
end
|
189
|
-
|
190
|
-
|
191
|
-
# Performs actions related the very specific config parameters
|
192
|
-
# @param [String] key The parameter to check
|
193
|
-
# @param [Object] value The value it expects to be set to
|
194
|
-
# @param [Symbol] layer Optional layer, default is :modified
|
195
|
-
# @return [Boolean] Whether or not the internal state has been changed
|
196
|
-
def check_hardcoded_properties(key, value, layer = :modified)
|
197
|
-
processed = false
|
198
|
-
case key
|
199
|
-
when :'log-level'
|
200
|
-
logger.send :level=, value, false
|
201
|
-
when :'config-file'
|
202
|
-
set_value key, value, layer
|
203
|
-
force_reload
|
204
|
-
processed = true
|
205
|
-
end
|
206
|
-
processed
|
207
|
-
end
|
208
|
-
|
209
|
-
# Builds a nice separator
|
210
|
-
def build_separator(title, width = 80, filler = '-')
|
211
|
-
"#{filler * 2} #{title} ".ljust width, filler
|
212
|
-
end
|
213
|
-
|
214
|
-
# Builds common used command line options
|
215
|
-
def build_command_line_options
|
216
|
-
add_command_line_section('Generic options') do |slop|
|
217
|
-
slop.on :auto, 'Auto mode. Bypasses questions to user.', :argument => false
|
218
|
-
slop.on :simulate, 'Do not perform the actual underlying actions.', :argument => false
|
219
|
-
slop.on :v, :verbose, 'Enable verbose mode.', :argument => false
|
220
|
-
slop.on :h, :help, 'Displays this help.', :argument => false
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def build_banner
|
225
|
-
"\nUsage: #{script_filename} [options]\n#{app_name} Version: #{app_version}\n\n#{app_description}"
|
226
|
-
end
|
227
|
-
|
228
|
-
end
|
@@ -1,220 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# EasyAppHelper
|
3
|
-
#
|
4
|
-
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
-
# http://opensource.org/licenses/MIT
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
require 'yaml'
|
9
|
-
# This is the class that will handle the configuration.
|
10
|
-
# Configuration is read from different sources:
|
11
|
-
# - config files (system, global, user, specified on the command line)
|
12
|
-
# - command line options
|
13
|
-
# - any extra config you provide programmatically
|
14
|
-
#
|
15
|
-
# == Config files:
|
16
|
-
# system, global, and user config files are searched in the file system according to
|
17
|
-
# complex rules. First the place where to search them depends on the OS
|
18
|
-
# (Provided by {EasyAppHelper::Core::Config::Places}), and then multiple file extensions are
|
19
|
-
# tested ({EasyAppHelper::Core::Config::CONFIG_FILE_POSSIBLE_EXTENSIONS}). This is basically
|
20
|
-
# performed by the private method {#find_file}. The config specified on command line (if any)
|
21
|
-
# is loaded the same way.
|
22
|
-
#
|
23
|
-
# == Command line:
|
24
|
-
# Any option can be declared as being callable from the command line. Modules add already some
|
25
|
-
# command line options, but the application can obviously add its own (see
|
26
|
-
# {EasyAppHelper::Core::Base#add_command_line_section}).
|
27
|
-
#
|
28
|
-
# Each of the config sources are kept in a separated "layer" and addressed this way using the
|
29
|
-
# #internal_configs attribute reader. But of course the config object provides a "merged" config
|
30
|
-
# result of the computation of all the sources. See the {#to_hash} method to see the order for the
|
31
|
-
# merge.
|
32
|
-
# Any option can be accessed or modified directly using the {#[]} and {#[]=} methods.
|
33
|
-
# Any change to the global config should be done using the {#[]=} method and is kept in the last separated
|
34
|
-
# layer called "modified". Therefore the config can be easily reset using the {#reset}
|
35
|
-
# method.
|
36
|
-
class EasyAppHelper::Core::Config < EasyAppHelper::Core::Base
|
37
|
-
end
|
38
|
-
|
39
|
-
require 'easy_app_helper/core/places'
|
40
|
-
require 'easy_app_helper/core/merge_policies'
|
41
|
-
|
42
|
-
|
43
|
-
class EasyAppHelper::Core::Config
|
44
|
-
include EasyAppHelper::Core::HashesMergePolicies
|
45
|
-
|
46
|
-
ADMIN_CONFIG_FILENAME = EasyAppHelper.name
|
47
|
-
INTRODUCED_SORTED_LAYERS = [:specific_file, :user, :global, :internal, :system]
|
48
|
-
|
49
|
-
# Potential extensions a config file can have
|
50
|
-
CONFIG_FILE_POSSIBLE_EXTENSIONS = %w(conf yml cfg yaml CFG YML YAML Yaml)
|
51
|
-
|
52
|
-
# @param [EasyAppHelper::Core::Logger] logger
|
53
|
-
# The logger passed to this constructor should be a temporary logger until the full config is loaded.
|
54
|
-
def initialize(logger)
|
55
|
-
super
|
56
|
-
add_cmd_line_options
|
57
|
-
load_config
|
58
|
-
end
|
59
|
-
|
60
|
-
# After calling the super method, triggers a forced reload of the file based config.
|
61
|
-
# @param [String] name of the config file
|
62
|
-
# @see Base#script_filename=
|
63
|
-
def script_filename=(name)
|
64
|
-
super
|
65
|
-
force_reload
|
66
|
-
end
|
67
|
-
|
68
|
-
# Sets the Application name and passes it to the logger.
|
69
|
-
# @param [String] name
|
70
|
-
# @see Base#app_name=
|
71
|
-
def app_name=(name)
|
72
|
-
super
|
73
|
-
logger.progname = name
|
74
|
-
end
|
75
|
-
|
76
|
-
# Loads all config (command line and config files)
|
77
|
-
# Do not reload a file if already loaded unless forced too.
|
78
|
-
# It *does not flush the "modified" layer*. Use {#reset} instead
|
79
|
-
# @param [Boolean] force to force the reload
|
80
|
-
def load_config(force=false)
|
81
|
-
super()
|
82
|
-
load_layer_config :system, ADMIN_CONFIG_FILENAME, force
|
83
|
-
load_layer_config :internal, script_filename, force
|
84
|
-
load_layer_config :global, script_filename, force
|
85
|
-
load_layer_config :user, script_filename, force
|
86
|
-
load_layer_config :specific_file, internal_configs[:command_line][:content][:'config-file'], force
|
87
|
-
self
|
88
|
-
end
|
89
|
-
|
90
|
-
# @see #load_config
|
91
|
-
def force_reload
|
92
|
-
load_config true
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
# This is the main method that provides the config as a hash.
|
97
|
-
#
|
98
|
-
# Every layer is kept untouched (and could accessed independently
|
99
|
-
# using {#internal_configs}), while this methods provides a merged config.
|
100
|
-
# @return [Hash] The hash of the merged config.
|
101
|
-
def to_hash
|
102
|
-
|
103
|
-
merged_config = {}
|
104
|
-
|
105
|
-
# Process any other level as a low priority unmanaged layer
|
106
|
-
internal_configs.keys.each do |layer|
|
107
|
-
next if self.class.layers.include? layer
|
108
|
-
hashes_second_level_merge merged_config, internal_configs[layer][:content]
|
109
|
-
end
|
110
|
-
|
111
|
-
# Process Config-level layers
|
112
|
-
merged_config = [:system, :internal, :global, :user].inject(merged_config) do |temp_config, config_level|
|
113
|
-
hashes_second_level_merge temp_config, internal_configs[config_level][:content]
|
114
|
-
end
|
115
|
-
if get_value :'config-file', :command_line
|
116
|
-
if get_value :'config-override', :command_line
|
117
|
-
override_merge merged_config, internal_configs[:specific_file][:content]
|
118
|
-
else
|
119
|
-
hashes_second_level_merge merged_config, internal_configs[:specific_file][:content]
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
# Process Base-level layers with highest priority (last processed the highest)
|
125
|
-
[:command_line, :modified].each { |base_layer| hashes_second_level_merge merged_config, internal_configs[base_layer][:content]}
|
126
|
-
merged_config
|
127
|
-
|
128
|
-
end
|
129
|
-
|
130
|
-
# @param [Object] key: The key to access the data in the merged_config hash (see {#to_hash})
|
131
|
-
# @return [String] Value for this key in the merged config.
|
132
|
-
def [](key = nil)
|
133
|
-
key.nil? ? to_hash : to_hash[key]
|
134
|
-
end
|
135
|
-
|
136
|
-
|
137
|
-
# @return [String] The merged config (see {#to_hash}) rendered as Yaml
|
138
|
-
def to_yaml
|
139
|
-
to_hash.to_yaml
|
140
|
-
end
|
141
|
-
|
142
|
-
alias_method :to_s, :to_yaml
|
143
|
-
alias_method :inspect, :internal_configs
|
144
|
-
|
145
|
-
#############################################################################
|
146
|
-
private
|
147
|
-
|
148
|
-
# Command line options specific to config manipulation
|
149
|
-
def add_cmd_line_options
|
150
|
-
add_command_line_section('Configuration options') do |slop|
|
151
|
-
slop.on 'config-file', 'Specify a config file.', :argument => true
|
152
|
-
slop.on 'config-override', 'If specified override all other config.', :argument => false
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
# Tries to find a config file to be loaded into the config layer cake unless cached.
|
157
|
-
def load_layer_config(layer, filename_or_pattern, force=false)
|
158
|
-
unless_cached(layer, filename_or_pattern, force) do |layer, filename_or_pattern|
|
159
|
-
fetch_config_layer layer, filename_or_pattern
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
# Actual loads
|
164
|
-
def fetch_config_layer(layer, filename_or_pattern)
|
165
|
-
if filename_or_pattern.nil?
|
166
|
-
internal_configs[layer] = {content: {}}
|
167
|
-
filename = nil
|
168
|
-
else
|
169
|
-
if File.exists? filename_or_pattern and !File.directory? filename_or_pattern
|
170
|
-
filename = filename_or_pattern
|
171
|
-
else
|
172
|
-
places = Places.possible_config_places[layer]
|
173
|
-
filename = find_file places, filename_or_pattern
|
174
|
-
end
|
175
|
-
internal_configs[layer] = {content: load_config_file(filename, layer), source: filename, origin: filename_or_pattern}
|
176
|
-
end
|
177
|
-
ensure
|
178
|
-
logger.info "No config file found for layer #{layer}." if filename.nil?
|
179
|
-
end
|
180
|
-
|
181
|
-
def unless_cached(layer, filename_or_pattern, forced)
|
182
|
-
cached = false
|
183
|
-
if internal_configs[layer]
|
184
|
-
cached = true unless internal_configs[layer][:origin] == filename_or_pattern
|
185
|
-
end
|
186
|
-
if forced or not cached
|
187
|
-
yield layer, filename_or_pattern
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# Tries to find config files according to places (array) given and possible extensions
|
192
|
-
def find_file(places, filename)
|
193
|
-
return nil if places.nil? or filename.nil? or filename.empty?
|
194
|
-
places.each do |dir|
|
195
|
-
CONFIG_FILE_POSSIBLE_EXTENSIONS.each do |ext|
|
196
|
-
filename_with_path = dir + '/' + filename + '.' + ext
|
197
|
-
if File.exists? filename_with_path and !File.directory? filename_with_path
|
198
|
-
return filename_with_path
|
199
|
-
else
|
200
|
-
logger.debug "Trying \"#{filename_with_path}\" as config file."
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
nil
|
205
|
-
end
|
206
|
-
|
207
|
-
def load_config_file(conf_filename, layer=nil)
|
208
|
-
conf = {}
|
209
|
-
return conf if conf_filename.nil?
|
210
|
-
ext = layer.nil? ? '' : " as layer #{layer}"
|
211
|
-
begin
|
212
|
-
logger.debug "Loading config file \"#{conf_filename}\"#{ext}"
|
213
|
-
conf = Hash[YAML::load(open(conf_filename)).map { |k, v| [k.to_sym, v] }]
|
214
|
-
rescue => e
|
215
|
-
logger.error "Invalid config file \"#{conf_filename}\"#{ext}. Skipped as not respecting YAML syntax!\n#{e.message}"
|
216
|
-
end
|
217
|
-
conf
|
218
|
-
end
|
219
|
-
|
220
|
-
end
|
@@ -1,111 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# EasyAppHelper
|
3
|
-
#
|
4
|
-
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
-
# http://opensource.org/licenses/MIT
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
require 'logger'
|
9
|
-
require 'singleton'
|
10
|
-
|
11
|
-
# Official Ruby Logger re-opened to introduce a method to hand-over the temporary history from a temporary logger
|
12
|
-
# to the definitive one.
|
13
|
-
# TODO: Ensure only the messages that are above the current level are displayed when handing over to the definitive logger.
|
14
|
-
class Logger
|
15
|
-
def hand_over_to(log)
|
16
|
-
history = []
|
17
|
-
history = @logdev.dev.history if @logdev.dev.respond_to? :history
|
18
|
-
@logdev.close
|
19
|
-
@logdev = LogDevice.new log
|
20
|
-
history.each do |msg|
|
21
|
-
@logdev.write msg if ENV['DEBUG_EASY_MODULES'] or (msg =~ /^[WE]/)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# This is the logger that will be used by the application and any class that include {EasyAppHelper} module. It is
|
27
|
-
# configured by the {EasyAppHelper::Core::Config Config} object, and provides a temporary logger until the config
|
28
|
-
# is fully loaded.
|
29
|
-
class EasyAppHelper::Core::Logger < Logger
|
30
|
-
include Singleton
|
31
|
-
|
32
|
-
|
33
|
-
def initialize
|
34
|
-
@config = {}
|
35
|
-
super(TempLogger.new)
|
36
|
-
self.level = Severity::DEBUG
|
37
|
-
debug "Temporary initialisation logger created..."
|
38
|
-
end
|
39
|
-
|
40
|
-
# Change the log level while keeping the config in sync.
|
41
|
-
def level=(level, update_config = true)
|
42
|
-
super(level)
|
43
|
-
@config[:'log-level'] = level if update_config
|
44
|
-
end
|
45
|
-
|
46
|
-
# Displays the message according to application verbosity and logs it as info.
|
47
|
-
def puts_and_logs(msg)
|
48
|
-
puts msg if @config[:verbose]
|
49
|
-
info(msg)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Reset the logger regarding the config provided
|
53
|
-
def set_app_config(config)
|
54
|
-
@config = config
|
55
|
-
add_cmd_line_options
|
56
|
-
@config.load_config
|
57
|
-
debug "Config layers:\n#{@config.internal_configs.to_yaml}"
|
58
|
-
debug "Merged config:\n#{@config.to_yaml}"
|
59
|
-
if config[:debug]
|
60
|
-
if config[:'log-file']
|
61
|
-
hand_over_to config[:'log-file']
|
62
|
-
elsif config[:"debug-on-err"]
|
63
|
-
hand_over_to STDERR
|
64
|
-
else
|
65
|
-
hand_over_to STDOUT
|
66
|
-
end
|
67
|
-
else
|
68
|
-
close
|
69
|
-
end
|
70
|
-
self.level = config[:'log-level'] ? config[:'log-level'] : Severity::WARN
|
71
|
-
self
|
72
|
-
end
|
73
|
-
|
74
|
-
private
|
75
|
-
|
76
|
-
|
77
|
-
def add_cmd_line_options
|
78
|
-
@config.add_command_line_section('Debug and logging options') do |slop|
|
79
|
-
slop.on :debug, 'Run in debug mode.', :argument => false
|
80
|
-
slop.on 'debug-on-err', 'Run in debug mode with output to stderr.', :argument => false
|
81
|
-
slop.on 'log-level', "Log level from 0 to 5, default #{Severity::WARN}.", :argument => true, :as => Integer
|
82
|
-
slop.on 'log-file', 'File to log to.', :argument => true
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# This class will act as a temporary logger, actually just keeping the history until the real
|
87
|
-
# configuration for the logger is known. Then the history is displayed or not regarding the
|
88
|
-
# definitive logger configuration.
|
89
|
-
class TempLogger
|
90
|
-
attr_reader :history
|
91
|
-
|
92
|
-
def initialize
|
93
|
-
@history = []
|
94
|
-
end
|
95
|
-
|
96
|
-
def write(data)
|
97
|
-
return if closed?
|
98
|
-
@history << data if @history
|
99
|
-
end
|
100
|
-
|
101
|
-
def close
|
102
|
-
@closed = true
|
103
|
-
end
|
104
|
-
|
105
|
-
def opened?() not @closed ; end
|
106
|
-
def closed?() @closed ; end
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
|
@@ -1,40 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# EasyAppHelper
|
3
|
-
#
|
4
|
-
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
-
# http://opensource.org/licenses/MIT
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
# This module proposes different merge policies for two hashes.
|
9
|
-
module EasyAppHelper::Core::HashesMergePolicies
|
10
|
-
|
11
|
-
# Performs a merge at the second level of hashes.
|
12
|
-
# simple entries and arrays are overridden.
|
13
|
-
def hashes_second_level_merge(h1, h2)
|
14
|
-
return [] if h1.nil? && h2.nil?
|
15
|
-
return h1 if h2.nil?
|
16
|
-
return h2 if h1.nil?
|
17
|
-
h2.each do |key, v|
|
18
|
-
if h1[key] and h1[key].is_a?(Hash)
|
19
|
-
# Merges hashes
|
20
|
-
h1[key].merge! h2[key]
|
21
|
-
else
|
22
|
-
# Overrides the rest
|
23
|
-
h1[key] = h2[key] unless h2[key].nil?
|
24
|
-
end
|
25
|
-
end
|
26
|
-
h1
|
27
|
-
end
|
28
|
-
|
29
|
-
# Uses the standard "merge!" method
|
30
|
-
def simple_merge(h1, h2)
|
31
|
-
h1.merge! h2
|
32
|
-
end
|
33
|
-
|
34
|
-
# Brutal override
|
35
|
-
def override_merge(h1, h2)
|
36
|
-
h1 = nil
|
37
|
-
h1 = h2
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# EasyAppHelper
|
3
|
-
#
|
4
|
-
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
-
# http://opensource.org/licenses/MIT
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
# The goal of this class is to return a module containing the POSSIBLE_PLACES hash
|
9
|
-
# that provides a list of OS dependant paths.
|
10
|
-
# The only method that should be used is the #get_os_module method that returns this module.
|
11
|
-
# TODO: Add equivalent for Mac
|
12
|
-
|
13
|
-
module EasyAppHelper
|
14
|
-
module Core
|
15
|
-
class Config
|
16
|
-
module Places
|
17
|
-
|
18
|
-
OS_FLAVOURS = {
|
19
|
-
mingw32: :windows,
|
20
|
-
linux: :unix
|
21
|
-
}
|
22
|
-
DEFAULT_OS_FLAVOUR = :unix
|
23
|
-
|
24
|
-
FLAVOUR_PLACES = {
|
25
|
-
unix: {
|
26
|
-
internal: [],
|
27
|
-
|
28
|
-
system: ['/etc'],
|
29
|
-
|
30
|
-
# Where could be stored global wide configuration
|
31
|
-
global: %w(/etc /usr/local/etc),
|
32
|
-
|
33
|
-
# Where could be stored user configuration
|
34
|
-
user: ["#{ENV['HOME']}/.config"]
|
35
|
-
},
|
36
|
-
windows: {
|
37
|
-
internal: [],
|
38
|
-
|
39
|
-
system: ["#{ENV['systemRoot']}/Config"],
|
40
|
-
|
41
|
-
# Where could be stored global configuration
|
42
|
-
global: ["#{ENV['systemRoot']}/Config",
|
43
|
-
"#{ENV['ALLUSERSPROFILE']}/Application Data"],
|
44
|
-
|
45
|
-
# Where could be stored user configuration
|
46
|
-
user: [ENV['APPDATA']]
|
47
|
-
}
|
48
|
-
}
|
49
|
-
|
50
|
-
|
51
|
-
def self.os_flavour
|
52
|
-
flavour = OS_FLAVOURS[RbConfig::CONFIG['target_os'].to_sym]
|
53
|
-
flavour.nil? ? DEFAULT_OS_FLAVOUR : flavour
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.gem_root_path(file=__FILE__)
|
57
|
-
file=__FILE__ if file.nil?
|
58
|
-
searcher = if Gem::Specification.respond_to? :find
|
59
|
-
# ruby 2.0
|
60
|
-
Gem::Specification
|
61
|
-
elsif Gem.respond_to? :searcher
|
62
|
-
# ruby 1.8/1.9
|
63
|
-
Gem.searcher.init_gemspecs
|
64
|
-
end
|
65
|
-
spec = unless searcher.nil?
|
66
|
-
searcher.find do |spec|
|
67
|
-
File.fnmatch(File.join(spec.full_gem_path,'*'), file)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
spec.gem_dir
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
def self.possible_config_places(file_of_gem=nil)
|
76
|
-
root = gem_root_path file_of_gem
|
77
|
-
places = FLAVOUR_PLACES[os_flavour].dup
|
78
|
-
places[:internal] = %w(etc config).map do |place|
|
79
|
-
File.join root, place
|
80
|
-
end
|
81
|
-
places
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|